File: [Development] / inventor / apps / samples / manip / constrainManip.c++ (download)
Revision 1.2, Sun Oct 29 15:04:16 2000 UTC (16 years, 11 months ago) by jlim
Branch: MAIN
CVS Tags: release-2_1_5-9, release-2_1_5-8, release-2_1_5-10, HEAD Changes since 1.1: +1 -0
lines
Eliminated or reduced compiler errors and warnings, as tested with
egcs-2.91.66 (on Red Hat 6.0) and gcc 2.96 (on Red Hat 6.2).
|
/*
*
* Copyright (C) 2000 Silicon Graphics, Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* Further, this software is distributed without any warranty that it is
* free of the rightful claim of any third person regarding infringement
* or the like. Any license provided herein, whether implied or
* otherwise, applies only to this software file. Patent licenses, if
* any, provided herein do not apply to combinations of this program with
* other software, or any other product whatsoever.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
* Mountain View, CA 94043, or:
*
* http://www.sgi.com
*
* For further information regarding this notice, see:
*
* http://oss.sgi.com/projects/GenInfo/NoticeExplan/
*
*/
/*----------------------------------------------------------------
*
* Read in a scene. Search for draggers and manipulators,
* adding constraints to them when found.
*
* Display the scene in a viewer.
*----------------------------------------------------------------*/
#include <stdlib.h>
#include <Inventor/SoDB.h>
#include <Inventor/actions/SoSearchAction.h>
#include <Inventor/nodes/SoSeparator.h>
#include <Inventor/nodes/SoTransform.h>
#include <Inventor/Xt/SoXt.h>
#include <Inventor/Xt/viewers/SoXtExaminerViewer.h>
#include <Inventor/draggers/SoDragger.h>
#include <Inventor/draggers/SoCenterballDragger.h>
#include <Inventor/manips/SoTransformManip.h>
#include <Inventor/manips/SoCenterballManip.h>
#include <Inventor/nodekits/SoSceneKit.h>
typedef struct MyCBStruct {
SbVec3f translateMin;
SbVec3f translateMax;
SbVec3f scaleMin;
SbVec3f scaleMax;
float rotateMin;
float rotateMax;
float prevAngle;
SbVec3f axis;
SbRotation startRotation;
SoTransformManip *manip;
};
#define CLAMP(v,min,max) v = (v < min) ? min : ((v > max) ? max : v)
// Limits translation between translateMin and translateMax
void
limitTranslation( SoSFVec3f *translation, MyCBStruct *stuff )
{
SbVec3f xl = translation->getValue();
CLAMP( xl[0], stuff->translateMin[0], stuff->translateMax[0] );
CLAMP( xl[1], stuff->translateMin[1], stuff->translateMax[1] );
CLAMP( xl[2], stuff->translateMin[2], stuff->translateMax[2] );
if ( xl != translation->getValue() )
(*translation) = xl;
}
// Limits center between translateMin and translateMax
void
limitCenter( SoSFVec3f *center, MyCBStruct *stuff )
{
SbVec3f xl = center->getValue();
CLAMP( xl[0], stuff->translateMin[0], stuff->translateMax[0] );
CLAMP( xl[1], stuff->translateMin[1], stuff->translateMax[1] );
CLAMP( xl[2], stuff->translateMin[2], stuff->translateMax[2] );
if ( xl != center->getValue() )
(*center) = xl;
}
// Limits scale between scaleMin and scaleMax
// Also doesn't let scale go below 0.0
void
limitScale( SoSFVec3f *scaleFactor, MyCBStruct *stuff )
{
SbVec3f scl = scaleFactor->getValue();
CLAMP( scl[0], stuff->scaleMin[0], stuff->scaleMax[0] );
CLAMP( scl[1], stuff->scaleMin[1], stuff->scaleMax[1] );
CLAMP( scl[2], stuff->scaleMin[2], stuff->scaleMax[2] );
CLAMP( scl[0], 0, stuff->scaleMax[0] );
CLAMP( scl[1], 0, stuff->scaleMax[1] );
CLAMP( scl[2], 0, stuff->scaleMax[2] );
if ( scl != scaleFactor->getValue() )
(*scaleFactor) = scl;
}
// Constrains the rotation to go around the initial direction of rotation
// until the dragging is complete.
// Limits amount of rotation from starting point to within range
// rotateMin < theta < rotateMax
void
limitRotate( SoSFRotation *rotation, MyCBStruct *stuff )
{
// First, see if we need to determine the axis of rotation.
// We need to do this the first time the dragger rotates, when axis==(0,0,0)
if ( stuff->axis == SbVec3f(0,0,0) ) {
SbRotation increment
= stuff->startRotation.inverse() * rotation->getValue();
increment.getValue( stuff->axis, stuff->prevAngle );
if (stuff->prevAngle == 0.0) {
stuff->axis.setValue(0,0,0);
return;
}
}
// Now we have an axis of rotation.
// Constrain whatever the rotation is to be a rotation about this axis.
SbBool madeAChange = FALSE;
SbRotation rotSinceStart
= stuff->startRotation.inverse() * rotation->getValue();
SbRotation newRotSinceStart;
// First, append a rotation that will undo any wobble of our axis.
SbVec3f wobbledAxis;
rotSinceStart.multVec( stuff->axis, wobbledAxis );
SbRotation undoWobble( wobbledAxis, stuff->axis );
float testAngle;
SbVec3f testAxis;
undoWobble.getValue( testAxis, testAngle );
if (testAngle > .001) {
newRotSinceStart = rotSinceStart * undoWobble;
madeAChange = TRUE;
}
else
newRotSinceStart = rotSinceStart;
// Next, see what the angle of rotation has been.
newRotSinceStart.getValue( testAxis, testAngle );
if ( testAxis.dot( stuff->axis ) < 0.0 )
testAngle *= -1.0;
// Make this angle as close as possible to prevAngle
while ( stuff->prevAngle - testAngle > 2 * M_PI )
testAngle += M_PI;
while ( testAngle - stuff->prevAngle > 2 * M_PI )
testAngle -= M_PI;
float clampAngle = testAngle;
CLAMP( clampAngle, stuff->rotateMin, stuff->rotateMax );
if ( clampAngle != testAngle ) {
newRotSinceStart.setValue( stuff->axis, clampAngle );
madeAChange = TRUE;
}
stuff->prevAngle = clampAngle;
if ( madeAChange ) {
SbRotation newFinalRot = stuff->startRotation * newRotSinceStart;
(*rotation) = newFinalRot;
}
}
// Dragger Start CB
// If there's a rotation field, records the starting rotation.
// Clears out the axis.
void
dragStartCB( void *stuff, SoDragger *dragger )
{
MyCBStruct *myStuff = (MyCBStruct *) stuff;
myStuff->axis.setValue(0,0,0);
myStuff->prevAngle = 0.0;
SoField *rotField = dragger->getField( "rotation" );
if ( rotField != NULL )
myStuff->startRotation = ((SoSFRotation *) rotField)->getValue();
else
myStuff->startRotation = SbRotation::identity();
}
// Manip Value Changed CB
// Tells the dragger to limit each of the parent manip's fields:
// translation, scaleFactor, and rotation.
void
manipValueChangedCB( void *stuff, SoDragger *)
{
MyCBStruct *myStuff = (MyCBStruct *) stuff;
SoTransformManip *m = myStuff->manip;
if ( !m->isOfType( SoCenterballManip::getClassTypeId() ))
limitTranslation( &(m->translation), myStuff );
else
limitCenter( &(m->center), myStuff );
limitScale( &(m->scaleFactor), myStuff );
limitRotate( &(m->rotation), myStuff );
}
// Dragger Value Changed CB
// Limits each of the fields: translation, scaleFactor, and rotation
// if they are present.
void
valueChangedCB( void *stuff, SoDragger *dragger )
{
MyCBStruct *myStuff = (MyCBStruct *) stuff;
SoField *myField;
if ( !dragger->isOfType( SoCenterballDragger::getClassTypeId() )) {
myField = dragger->getField( "translation" );
if ( myField != NULL )
limitTranslation( (SoSFVec3f *)myField, myStuff );
}
else {
myField = dragger->getField( "center" );
if ( myField != NULL )
limitCenter( (SoSFVec3f *)myField, myStuff );
}
myField = dragger->getField( "scaleFactor" );
if ( myField != NULL )
limitScale( (SoSFVec3f *)myField, myStuff );
myField = dragger->getField( "rotation" );
if ( myField != NULL )
limitRotate( (SoSFRotation *)myField, myStuff );
}
void
main(int argc, char **argv)
{
int curArg = 0;
SbBool doConstraints = TRUE;
float translateMin = -3.0;
float translateMax = 3.0;
float scaleMin = 0.0001;
float scaleMax = 3.0;
float rotateMin = -2.0;
float rotateMax = 2.0;
char *fileName = NULL;
// Try to read the command line...
curArg = 1;
while (curArg < argc ) {
if ( !strcmp(argv[curArg], "-noConstraints")) {
curArg++;
doConstraints = FALSE;
}
else if ( !strcmp(argv[curArg], "-translateMin")) {
curArg++;
sscanf( argv[curArg++], "%f", &translateMin );
}
else if ( !strcmp(argv[curArg], "-translateMax")) {
curArg++;
sscanf( argv[curArg++], "%f", &translateMax );
}
else if ( !strcmp(argv[curArg], "-scaleMin")) {
curArg++;
sscanf( argv[curArg++], "%f", &scaleMin );
}
else if ( !strcmp(argv[curArg], "-scaleMax")) {
curArg++;
sscanf( argv[curArg++], "%f", &scaleMax );
}
else {
// get the filename
fileName = argv[curArg++];
}
}
Widget myWindow = SoXt::init(argv[0]);
if (myWindow == NULL) exit(1);
SoSeparator *root = new SoSeparator;
root->ref();
SoInput myInput;
if (fileName == NULL)
fileName = "simpleDraggers.iv";
if ( !myInput.openFile( fileName ) ) {
fprintf(stderr, "ERROR - could not open file %s\n", fileName );
fprintf(stderr, "usage-- constrainManip [-noConstraints] ] [-translateMin x] [-translateMax x] [-scaleMin x] [-scaleMax x] [-rotateMin] [-rotateMax] fileName\n");
fprintf(stderr, " where translateMin, translateMax, scaleMin, scaleMax, rotateMin, and rotateMax are constraints to be put on the draggers and manips.\n");
exit(1);
}
SoSeparator *fileContents = SoDB::readAll( &myInput );
root->addChild(fileContents);
// Search for draggers and add constraints.
SoSearchAction sa;
SoPathList pathList;
int i;
// Set up values for callback.
MyCBStruct *myCBStruct = new MyCBStruct;
myCBStruct->translateMin.setValue( translateMin, translateMin, translateMin);
myCBStruct->translateMax.setValue( translateMax, translateMax, translateMax);
myCBStruct->scaleMin.setValue( scaleMin, scaleMin, scaleMin);
myCBStruct->scaleMax.setValue( scaleMax, scaleMax, scaleMax);
myCBStruct->rotateMin = rotateMin;
myCBStruct->rotateMax = rotateMax;
if (doConstraints) {
// Add callbacks to all draggers that constrain motion:
sa.setType( SoDragger::getClassTypeId() );
sa.setInterest( SoSearchAction::ALL );
sa.apply( root );
pathList = sa.getPaths();
for ( i = 0; i < pathList.getLength(); i++ ) {
SoDragger *d = (SoDragger *) (pathList[i])->getTail();
d->addStartCallback(&dragStartCB, myCBStruct);
d->addValueChangedCallback(&valueChangedCB, myCBStruct);
}
// Add callbacks to all transform manips that constrain motion:
sa.setType( SoTransformManip::getClassTypeId() );
sa.setInterest( SoSearchAction::ALL );
sa.apply( root );
pathList = sa.getPaths();
for ( i = 0; i < pathList.getLength(); i++ ) {
SoTransformManip *m = (SoTransformManip *) (pathList[i])->getTail();
MyCBStruct *cbs = new MyCBStruct;
cbs->translateMin.setValue( translateMin, translateMin, translateMin);
cbs->translateMax.setValue( translateMax, translateMax, translateMax);
cbs->scaleMin.setValue( scaleMin, scaleMin, scaleMin);
cbs->scaleMax.setValue( scaleMax, scaleMax, scaleMax);
cbs->rotateMin = rotateMin;
cbs->rotateMax = rotateMax;
cbs->manip = m;
SoDragger *d = m->getDragger();
d->addStartCallback(&dragStartCB, cbs);
d->addValueChangedCallback(&manipValueChangedCB, cbs);
}
}
SoXtExaminerViewer *myVwr = new SoXtExaminerViewer(myWindow);
myVwr->setSceneGraph(root);
myVwr->setTitle("Manip Test");
myVwr->viewAll();
myVwr->show();
SoXt::show(myWindow);
SoXt::mainLoop();
}