Menu

SoTransformer2Dragger.cpp

There is a newer version of this page. You can find it here.
/*!
  \class SoTransformer2Dragger SoTransformer2Dragger.h Inventor/draggers/SoTransformer2Dragger.h
  \brief The SoTransformer2Dragger provides geometry for translation, scaling and rotations.
  \ingroup draggers

  \DRAGGER_DEFAULT_SCREENSHOT


  ![](http://doc.coin3d.org/images/Coin/draggers/transformer.png)


  Translate the dragger by clicking and dragging any of the
  (invisible) sides. Translation will default be done in the plane of
  the side the end-user selected. The user can hold down a \c SHIFT
  key to lock translation to a single of the axes in the plane. By
  holding down a \c CTRL key instead, translation can be done along
  the plane's normal vector.

  Scaling is done by dragging the corner cubes. By default, uniform
  scaling will be done. Hold down \c SHIFT before selecting any of the
  corners to do non-uniform scaling. Uniform scaling towards a
  corner-point can be accomplished by holding down \c CTRL before
  clicking and dragging one of the cubes.

  Rotation is done by dragging any of the 6 end-markers of the axis
  cross. The initial drag direction decides which orientation the
  rotation will be done in. Hold down \c SHIFT to do free-form
  rotation around the sphere instead.


  This is a big and complex dragger which needs a fair amount of
  proper documentation when provided in end-user applications. If what
  you are trying to accomplish in your application does not really
  demand most of the features of this dragger, you are advised to
  investigate whether or not any of the less complex draggers can
  fulfill your requirements -- so you can provide an as simple as
  possible user interface to your end-users.


  For the application programmer's convenience, the Coin library also
  provides a manipulator class called SoTransformer2Manip, which wraps
  the SoTransformer2Dragger into the necessary mechanisms for making
  direct insertion of this dragger into a scenegraph possible with
  very little effort.

  \sa SoTransformer2Manip
*/

#include <string.h>

#include <Inventor/draggers/SoTransformer2Dragger.h>
//#include <Inventor/nodekits/SoSubKitP.h>
#include "nodekits/SoSubKitP.h"
#include <Inventor/nodes/SoAntiSquish.h>
#include <Inventor/nodes/SoLocateHighlight.h>
#include <Inventor/nodes/SoRotation.h>
#include <Inventor/nodes/SoSurroundScale.h>
#include <Inventor/nodes/SoSwitch.h>
#include <Inventor/nodes/SoTransform.h>
#include <Inventor/nodes/SoTranslation.h>
#include <Inventor/nodes/SoMatrixTransform.h>
#include <Inventor/sensors/SoFieldSensor.h>
#include <Inventor/SbVec3f.h>
#include <Inventor/SbMatrix.h>
#include <Inventor/projectors/SbPlaneProjector.h>
#include <Inventor/projectors/SbLineProjector.h>
#include <Inventor/projectors/SbSphereSectionProjector.h>
#include <Inventor/projectors/SbCylinderPlaneProjector.h>
#include <Inventor/events/SoKeyboardEvent.h>
#include <Inventor/actions/SoSearchAction.h>
#include <Inventor/actions/SoGetMatrixAction.h>
#include <Inventor/lists/SoPathList.h>

#include <data/draggerDefaults/transformer2Dragger.h>

#include <coindefs.h> // COIN_STUB() & COIN_OBSOLETED()

// FIXME, bugs or missing features (pederb, 20000224):
// o some feedback is missing (mostly crosshair)
// o detect if disc or cylinder rotator should be used (disc-only right now)
//
// Also the translation feedback is a bit different from OIV. Coin
// always places the feedback axes at the center of the face being
// translated. OIV places them at the picked point. I think our
// strategy is better, since when switching between constrained
// translations and unconstrained translation, the OIV feedback axes
// can easily be positioned outside the face being dragged.
//
// MATRICES AND SPACES:
// There are many matrices and spaces that can take some time to get
// understand. The matrices calculated are:
//
// localToWorld = motionMatrix * draggerToWorld
// worldToLocal = worldToDragger * motionMatrix^-1
// draggerToWorld = worldToDragger^-1
//
// localToWorking = surroundScaleMatrix^-1
// workingToLocal = surroundScaleMatrix
//
// workingToWorld = surroundScaleMatrix * localToWorld
// worldToWorking = worldToLocal * surroundScaleMatrix
// 
// boxPointInWorldSpace = p * surroundScaleMatrix * localToWorld
// worldPointInBoxSpace = p * worldToLocal * surroundScaleMatrix

/*!
  \enum SoTransformer2Dragger::State

  The various possible states the dragger might be in at any given
  time. That is: either SoTransformer2Dragger::INACTIVE if there's no
  interaction, or any of the other values to indicate what operation
  the end-user is currently executing.
*/

/*!
  \var SoSFRotation SoTransformer2Dragger::rotation

  This field is continuously updated to contain the orientation of the
  dragger.
*/
/*!
  \var SoSFVec3f SoTransformer2Dragger::translation

  The dragger's offset position from the local origo.
*/
/*!
  \var SoSFVec3f SoTransformer2Dragger::scaleFactor

  Continuously updated to contain the current vector of scaling along
  the X, Y and Z axes.
*/
/*!
  \var SoSFVec3f SoTransformer2Dragger::center

  The dragger's center position from the local origo.
*/

// FIXME: can't see what this is for -- investigate. 20011208 mortene.
//  /*!
//    \var SoSFFloat SoTransformer2Dragger::minDiscRotDot
//  */

/*!
  \var SoFieldSensor * SoTransformer2Dragger::translFieldSensor
  \COININTERNAL
*/
/*!
  \var SoFieldSensor * SoTransformer2Dragger::scaleFieldSensor
  \COININTERNAL
*/
/*!
  \var SoFieldSensor * SoTransformer2Dragger::rotateFieldSensor
  \COININTERNAL
*/
/*!
  \var SoFieldSensor * SoTransformer2Dragger::centerFieldSensor
  \COININTERNAL
*/
/*!
  \var SoNodeList SoTransformer2Dragger::antiSquishList
  \COININTERNAL
*/

#define WHATKIND_NONE      0
#define WHATKIND_SCALE     1
#define WHATKIND_TRANSLATE 2
#define WHATKIND_ROTATE    3

#define CONSTRAINT_OFF  0
#define CONSTRAINT_WAIT 1
#define CONSTRAINT_X    2
#define CONSTRAINT_Y    3
#define CONSTRAINT_Z    4

#define KNOB_DISTANCE 1.25f   // distance from center to rotate-knobs


#ifndef DOXYGEN_SKIP_THIS

class SoTransformer2DraggerP {
public:
  SbMatrix prevMotionMatrix;
  SbVec3f prevWorldHitPt;
  SbVec3f ctrlOffset;
  SbBool ctrlDown;
  SbBool shiftDown;
  SbVec2f normalizedStartLocaterPosition;

  SbBool locateHighlighting;
  static int colinearThreshold;
  int constraintState;

  int whatkind;
  int whatnum;
  int dimension;
};

int SoTransformer2DraggerP::colinearThreshold = 3; // FIXME: find default value from somewhere

#endif // DOXYGEN_SKIP_THIS

SO_KIT_SOURCE(SoTransformer2Dragger);

// doc in superclass
void
SoTransformer2Dragger::initClass(void)
{
  SO_KIT_INTERNAL_INIT_CLASS(SoTransformer2Dragger, SO_FROM_INVENTOR_1);
}

void
SoTransformer2Dragger::build_catalog1(void)
{
  SO_KIT_ADD_CATALOG_ENTRY(surroundScale, SoSurroundScale, TRUE, topSeparator, overallStyle, TRUE);
  SO_KIT_ADD_CATALOG_ENTRY(overallStyle, SoGroup, TRUE, topSeparator, geomSeparator, FALSE);
  SO_KIT_ADD_CATALOG_ENTRY(translatorSep, SoSeparator, TRUE, topSeparator, rotatorSep, FALSE);
}

void
SoTransformer2Dragger::build_catalog2(void)
{
  SO_KIT_ADD_CATALOG_ENTRY(translator1Switch, SoSwitch, TRUE, translatorSep, translator2Switch, FALSE);
  SO_KIT_ADD_CATALOG_ENTRY(translator1LocateGroup, SoLocateHighlight, TRUE, translator1Switch, translator1Active, FALSE);
  SO_KIT_ADD_CATALOG_ENTRY(translator1, SoSeparator, TRUE, translator1LocateGroup, "", TRUE);
  SO_KIT_ADD_CATALOG_ENTRY(translator1Active, SoSeparator, TRUE, translator1Switch, "", TRUE);
  SO_KIT_ADD_CATALOG_ENTRY(translator2Switch, SoSwitch, TRUE, translatorSep, translator3Switch, FALSE);
  SO_KIT_ADD_CATALOG_ENTRY(translator2LocateGroup, SoLocateHighlight, TRUE, translator2Switch, translator2Active, FALSE);
  SO_KIT_ADD_CATALOG_ENTRY(translator2, SoSeparator, TRUE, translator2LocateGroup, "", TRUE);
  SO_KIT_ADD_CATALOG_ENTRY(translator2Active, SoSeparator, TRUE, translator2Switch, "", TRUE);
  SO_KIT_ADD_CATALOG_ENTRY(translator3Switch, SoSwitch, TRUE, translatorSep, translator4Switch, FALSE);
  SO_KIT_ADD_CATALOG_ENTRY(translator3LocateGroup, SoLocateHighlight, TRUE, translator3Switch, translator3Active, FALSE);
  SO_KIT_ADD_CATALOG_ENTRY(translator3, SoSeparator, TRUE, translator3LocateGroup, "", TRUE);
  SO_KIT_ADD_CATALOG_ENTRY(translator3Active, SoSeparator, TRUE, translator3Switch, "", TRUE);
  SO_KIT_ADD_CATALOG_ENTRY(translator4Switch, SoSwitch, TRUE, translatorSep, translator5Switch, FALSE);
  SO_KIT_ADD_CATALOG_ENTRY(translator4LocateGroup, SoLocateHighlight, TRUE, translator4Switch, translator4Active, FALSE);
  SO_KIT_ADD_CATALOG_ENTRY(translator4, SoSeparator, TRUE, translator4LocateGroup, "", TRUE);
  SO_KIT_ADD_CATALOG_ENTRY(translator4Active, SoSeparator, TRUE, translator4Switch, "", TRUE);
  SO_KIT_ADD_CATALOG_ENTRY(translator5Switch, SoSwitch, TRUE, translatorSep, translator6Switch, FALSE);
  SO_KIT_ADD_CATALOG_ENTRY(translator5LocateGroup, SoLocateHighlight, TRUE, translator5Switch, translator5Active, FALSE);
  SO_KIT_ADD_CATALOG_ENTRY(translator5, SoSeparator, TRUE, translator5LocateGroup, "", TRUE);
  SO_KIT_ADD_CATALOG_ENTRY(translator5Active, SoSeparator, TRUE, translator5Switch, "", TRUE);
  SO_KIT_ADD_CATALOG_ENTRY(translator6Switch, SoSwitch, TRUE, translatorSep, "", FALSE);
  SO_KIT_ADD_CATALOG_ENTRY(translator6LocateGroup, SoLocateHighlight, TRUE, translator6Switch, translator6Active, FALSE);
  SO_KIT_ADD_CATALOG_ENTRY(translator6, SoSeparator, TRUE, translator6LocateGroup, "", TRUE);
  SO_KIT_ADD_CATALOG_ENTRY(translator6Active, SoSeparator, TRUE, translator6Switch, "", TRUE);
}

void
SoTransformer2Dragger::build_catalog3(void)
{
  SO_KIT_ADD_CATALOG_ENTRY(translateToCenter, SoMatrixTransform, TRUE, topSeparator, rotatorSep, TRUE);

  SO_KIT_ADD_CATALOG_ENTRY(rotatorSep, SoSeparator, TRUE, topSeparator, scaleSep, FALSE);
  SO_KIT_ADD_CATALOG_ENTRY(rotator1Switch, SoSwitch, TRUE, rotatorSep, rotator2Switch, FALSE);
  SO_KIT_ADD_CATALOG_ENTRY(rotator1LocateGroup, SoLocateHighlight, TRUE, rotator1Switch, rotator1Active, FALSE);
  SO_KIT_ADD_CATALOG_ENTRY(rotator1, SoSeparator, TRUE, rotator1LocateGroup, "", TRUE);
  SO_KIT_ADD_CATALOG_ENTRY(rotator1Active, SoSeparator, TRUE, rotator1Switch, "", TRUE);
  SO_KIT_ADD_CATALOG_ENTRY(rotator2Switch, SoSwitch, TRUE, rotatorSep, rotator3Switch, FALSE);
  SO_KIT_ADD_CATALOG_ENTRY(rotator2LocateGroup, SoLocateHighlight, TRUE, rotator2Switch, rotator2Active, FALSE);
  SO_KIT_ADD_CATALOG_ENTRY(rotator2, SoSeparator, TRUE, rotator2LocateGroup, "", TRUE);
  SO_KIT_ADD_CATALOG_ENTRY(rotator2Active, SoSeparator, TRUE, rotator2Switch, "", TRUE);
  SO_KIT_ADD_CATALOG_ENTRY(rotator3Switch, SoSwitch, TRUE, rotatorSep, rotator4Switch, FALSE);
  SO_KIT_ADD_CATALOG_ENTRY(rotator3LocateGroup, SoLocateHighlight, TRUE, rotator3Switch, rotator3Active, FALSE);
  SO_KIT_ADD_CATALOG_ENTRY(rotator3, SoSeparator, TRUE, rotator3LocateGroup, "", TRUE);
  SO_KIT_ADD_CATALOG_ENTRY(rotator3Active, SoSeparator, TRUE, rotator3Switch, "", TRUE);
  SO_KIT_ADD_CATALOG_ENTRY(rotator4Switch, SoSwitch, TRUE, rotatorSep, rotator5Switch, FALSE);
  SO_KIT_ADD_CATALOG_ENTRY(rotator4LocateGroup, SoLocateHighlight, TRUE, rotator4Switch, rotator4Active, FALSE);
  SO_KIT_ADD_CATALOG_ENTRY(rotator4, SoSeparator, TRUE, rotator4LocateGroup, "", TRUE);
  SO_KIT_ADD_CATALOG_ENTRY(rotator4Active, SoSeparator, TRUE, rotator4Switch, "", TRUE);
  SO_KIT_ADD_CATALOG_ENTRY(rotator5Switch, SoSwitch, TRUE, rotatorSep, rotator6Switch, FALSE);
  SO_KIT_ADD_CATALOG_ENTRY(rotator5LocateGroup, SoLocateHighlight, TRUE, rotator5Switch, rotator5Active, FALSE);
  SO_KIT_ADD_CATALOG_ENTRY(rotator5, SoSeparator, TRUE, rotator5LocateGroup, "", TRUE);
  SO_KIT_ADD_CATALOG_ENTRY(rotator5Active, SoSeparator, TRUE, rotator5Switch, "", TRUE);
  SO_KIT_ADD_CATALOG_ENTRY(rotator6Switch, SoSwitch, TRUE, rotatorSep, "", FALSE);
  SO_KIT_ADD_CATALOG_ENTRY(rotator6LocateGroup, SoLocateHighlight, TRUE, rotator6Switch, rotator6Active, FALSE);
  SO_KIT_ADD_CATALOG_ENTRY(rotator6, SoSeparator, TRUE, rotator6LocateGroup, "", TRUE);
  SO_KIT_ADD_CATALOG_ENTRY(rotator6Active, SoSeparator, TRUE, rotator6Switch, "", TRUE);
}

void
SoTransformer2Dragger::build_catalog4(void)
{
  SO_KIT_ADD_CATALOG_ENTRY(scaleSep, SoSeparator, TRUE, topSeparator, circleFeedbackSep, FALSE);
  SO_KIT_ADD_CATALOG_ENTRY(scale1Switch, SoSwitch, TRUE, scaleSep, scale2Switch, FALSE);
  SO_KIT_ADD_CATALOG_ENTRY(scale1LocateGroup, SoLocateHighlight, TRUE, scale1Switch, scale1Active, FALSE);
  SO_KIT_ADD_CATALOG_ENTRY(scale1, SoSeparator, TRUE, scale1LocateGroup, "", TRUE);
  SO_KIT_ADD_CATALOG_ENTRY(scale1Active, SoSeparator, TRUE, scale1Switch, "", TRUE);
  SO_KIT_ADD_CATALOG_ENTRY(scale2Switch, SoSwitch, TRUE, scaleSep, scale3Switch, FALSE);
  SO_KIT_ADD_CATALOG_ENTRY(scale2LocateGroup, SoLocateHighlight, TRUE, scale2Switch, scale2Active, FALSE);
  SO_KIT_ADD_CATALOG_ENTRY(scale2, SoSeparator, TRUE, scale2LocateGroup, "", TRUE);
  SO_KIT_ADD_CATALOG_ENTRY(scale2Active, SoSeparator, TRUE, scale2Switch, "", TRUE);
  SO_KIT_ADD_CATALOG_ENTRY(scale3Switch, SoSwitch, TRUE, scaleSep, scale4Switch, FALSE);
  SO_KIT_ADD_CATALOG_ENTRY(scale3LocateGroup, SoLocateHighlight, TRUE, scale3Switch, scale3Active, FALSE);
  SO_KIT_ADD_CATALOG_ENTRY(scale3, SoSeparator, TRUE, scale3LocateGroup, "", TRUE);
  SO_KIT_ADD_CATALOG_ENTRY(scale3Active, SoSeparator, TRUE, scale3Switch, "", TRUE);
  SO_KIT_ADD_CATALOG_ENTRY(scale4Switch, SoSwitch, TRUE, scaleSep, scale5Switch, FALSE);
  SO_KIT_ADD_CATALOG_ENTRY(scale4LocateGroup, SoLocateHighlight, TRUE, scale4Switch, scale4Active, FALSE);
  SO_KIT_ADD_CATALOG_ENTRY(scale4, SoSeparator, TRUE, scale4LocateGroup, "", TRUE);
  SO_KIT_ADD_CATALOG_ENTRY(scale4Active, SoSeparator, TRUE, scale4Switch, "", TRUE);
  SO_KIT_ADD_CATALOG_ENTRY(scale5Switch, SoSwitch, TRUE, scaleSep, scale6Switch, FALSE);
  SO_KIT_ADD_CATALOG_ENTRY(scale5LocateGroup, SoLocateHighlight, TRUE, scale5Switch, scale5Active, FALSE);
  SO_KIT_ADD_CATALOG_ENTRY(scale5, SoSeparator, TRUE, scale5LocateGroup, "", TRUE);
  SO_KIT_ADD_CATALOG_ENTRY(scale5Active, SoSeparator, TRUE, scale5Switch, "", TRUE);
  SO_KIT_ADD_CATALOG_ENTRY(scale6Switch, SoSwitch, TRUE, scaleSep, scale7Switch, FALSE);
  SO_KIT_ADD_CATALOG_ENTRY(scale6LocateGroup, SoLocateHighlight, TRUE, scale6Switch, scale6Active, FALSE);
  SO_KIT_ADD_CATALOG_ENTRY(scale6, SoSeparator, TRUE, scale6LocateGroup, "", TRUE);
  SO_KIT_ADD_CATALOG_ENTRY(scale6Active, SoSeparator, TRUE, scale6Switch, "", TRUE);
  SO_KIT_ADD_CATALOG_ENTRY(scale7Switch, SoSwitch, TRUE, scaleSep, scale8Switch, FALSE);
  SO_KIT_ADD_CATALOG_ENTRY(scale7LocateGroup, SoLocateHighlight, TRUE, scale7Switch, scale7Active, FALSE);
  SO_KIT_ADD_CATALOG_ENTRY(scale7, SoSeparator, TRUE, scale7LocateGroup, "", TRUE);
  SO_KIT_ADD_CATALOG_ENTRY(scale7Active, SoSeparator, TRUE, scale7Switch, "", TRUE);
  SO_KIT_ADD_CATALOG_ENTRY(scale8Switch, SoSwitch, TRUE, scaleSep, "", FALSE);
  SO_KIT_ADD_CATALOG_ENTRY(scale8LocateGroup, SoLocateHighlight, TRUE, scale8Switch, scale8Active, FALSE);
  SO_KIT_ADD_CATALOG_ENTRY(scale8, SoSeparator, TRUE, scale8LocateGroup, "", TRUE);
  SO_KIT_ADD_CATALOG_ENTRY(scale8Active, SoSeparator, TRUE, scale8Switch, "", TRUE);
}

void
SoTransformer2Dragger::build_catalog5(void)
{
  SO_KIT_ADD_CATALOG_ENTRY(axisFeedbackSep, SoSeparator, TRUE, geomSeparator, translateBoxFeedbackSep, FALSE);
  SO_KIT_ADD_CATALOG_ENTRY(axisFeedbackLocation, SoTranslation, TRUE, axisFeedbackSep, xAxisFeedbackSwitch, FALSE);
  SO_KIT_ADD_CATALOG_ENTRY(xAxisFeedbackSwitch, SoSwitch, TRUE, axisFeedbackSep, yAxisFeedbackSwitch, FALSE);
  SO_KIT_ADD_CATALOG_ENTRY(xAxisFeedbackActive, SoSeparator, TRUE, xAxisFeedbackSwitch, xAxisFeedbackSelect, TRUE);
  SO_KIT_ADD_CATALOG_ENTRY(xAxisFeedbackSelect, SoSeparator, TRUE, xAxisFeedbackSwitch, xCrosshairFeedback, TRUE);
  SO_KIT_ADD_CATALOG_ENTRY(xCrosshairFeedback, SoSeparator, TRUE, xAxisFeedbackSwitch, "", TRUE);
  SO_KIT_ADD_CATALOG_ENTRY(yAxisFeedbackSwitch, SoSwitch, TRUE, axisFeedbackSep, zAxisFeedbackSwitch, FALSE);
  SO_KIT_ADD_CATALOG_ENTRY(yAxisFeedbackActive, SoSeparator, TRUE, yAxisFeedbackSwitch, yAxisFeedbackSelect, TRUE);
  SO_KIT_ADD_CATALOG_ENTRY(yAxisFeedbackSelect, SoSeparator, TRUE, yAxisFeedbackSwitch, yCrosshairFeedback, TRUE);
  SO_KIT_ADD_CATALOG_ENTRY(yCrosshairFeedback, SoSeparator, TRUE, yAxisFeedbackSwitch, "", TRUE);
  SO_KIT_ADD_CATALOG_ENTRY(zAxisFeedbackSwitch, SoSwitch, TRUE, axisFeedbackSep, "", FALSE);
  SO_KIT_ADD_CATALOG_ENTRY(zAxisFeedbackActive, SoSeparator, TRUE, zAxisFeedbackSwitch, zAxisFeedbackSelect, TRUE);
  SO_KIT_ADD_CATALOG_ENTRY(zAxisFeedbackSelect, SoSeparator, TRUE, zAxisFeedbackSwitch, zCrosshairFeedback, TRUE);
  SO_KIT_ADD_CATALOG_ENTRY(zCrosshairFeedback, SoSeparator, TRUE, zAxisFeedbackSwitch, "", TRUE);
  SO_KIT_ADD_CATALOG_ENTRY(translateBoxFeedbackSep, SoSeparator, TRUE, geomSeparator, scaleBoxFeedbackSwitch, FALSE);
  SO_KIT_ADD_CATALOG_ENTRY(translateBoxFeedbackSwitch, SoSwitch, TRUE, translateBoxFeedbackSep, "", FALSE);
  SO_KIT_ADD_CATALOG_ENTRY(translateBoxFeedbackRotation, SoRotation, TRUE, translateBoxFeedbackSwitch, translateBoxFeedback, FALSE);
  SO_KIT_ADD_CATALOG_ENTRY(translateBoxFeedback, SoSeparator, TRUE, translateBoxFeedbackSwitch, "", TRUE);
  SO_KIT_ADD_CATALOG_ENTRY(scaleBoxFeedbackSwitch, SoSwitch, TRUE, geomSeparator, posXWallFeedbackSwitch, FALSE);
  SO_KIT_ADD_CATALOG_ENTRY(scaleBoxFeedback, SoSeparator, TRUE, scaleBoxFeedbackSwitch, "", TRUE);
  SO_KIT_ADD_CATALOG_ENTRY(posXWallFeedbackSwitch, SoSwitch, TRUE, geomSeparator, posYWallFeedbackSwitch, FALSE);
  SO_KIT_ADD_CATALOG_ENTRY(posXWallFeedback, SoSeparator, TRUE, posXWallFeedbackSwitch, posXRoundWallFeedback, TRUE);
  SO_KIT_ADD_CATALOG_ENTRY(posXRoundWallFeedback, SoSeparator, TRUE, posXWallFeedbackSwitch, "", TRUE);
  SO_KIT_ADD_CATALOG_ENTRY(posYWallFeedbackSwitch, SoSwitch, TRUE, geomSeparator, posZWallFeedbackSwitch, FALSE);
  SO_KIT_ADD_CATALOG_ENTRY(posYWallFeedback, SoSeparator, TRUE, posYWallFeedbackSwitch, posYRoundWallFeedback, TRUE);
  SO_KIT_ADD_CATALOG_ENTRY(posYRoundWallFeedback, SoSeparator, TRUE, posYWallFeedbackSwitch, "", TRUE);
  SO_KIT_ADD_CATALOG_ENTRY(posZWallFeedbackSwitch, SoSwitch, TRUE, geomSeparator, negXWallFeedbackSwitch, FALSE);
  SO_KIT_ADD_CATALOG_ENTRY(posZWallFeedback, SoSeparator, TRUE, posZWallFeedbackSwitch, posZRoundWallFeedback, TRUE);
  SO_KIT_ADD_CATALOG_ENTRY(posZRoundWallFeedback, SoSeparator, TRUE, posZWallFeedbackSwitch, "", TRUE);
}

void
SoTransformer2Dragger::build_catalog6(void)
{
  SO_KIT_ADD_CATALOG_ENTRY(negXWallFeedbackSwitch, SoSwitch, TRUE, geomSeparator, negYWallFeedbackSwitch, FALSE);
  SO_KIT_ADD_CATALOG_ENTRY(negXWallFeedback, SoSeparator, TRUE, negXWallFeedbackSwitch, negXRoundWallFeedback, TRUE);
  SO_KIT_ADD_CATALOG_ENTRY(negXRoundWallFeedback, SoSeparator, TRUE, negXWallFeedbackSwitch, "", TRUE);
  SO_KIT_ADD_CATALOG_ENTRY(negYWallFeedbackSwitch, SoSwitch, TRUE, geomSeparator, negZWallFeedbackSwitch, FALSE);
  SO_KIT_ADD_CATALOG_ENTRY(negYWallFeedback, SoSeparator, TRUE, negYWallFeedbackSwitch, negYRoundWallFeedback, TRUE);
  SO_KIT_ADD_CATALOG_ENTRY(negYRoundWallFeedback, SoSeparator, TRUE, negYWallFeedbackSwitch, "", TRUE);
  SO_KIT_ADD_CATALOG_ENTRY(negZWallFeedbackSwitch, SoSwitch, TRUE, geomSeparator, radialFeedbackSwitch, FALSE);
  SO_KIT_ADD_CATALOG_ENTRY(negZWallFeedback, SoSeparator, TRUE, negZWallFeedbackSwitch, negZRoundWallFeedback, TRUE);
  SO_KIT_ADD_CATALOG_ENTRY(negZRoundWallFeedback, SoSeparator, TRUE, negZWallFeedbackSwitch, "", TRUE);
  SO_KIT_ADD_CATALOG_ENTRY(radialFeedbackSwitch, SoSwitch, TRUE, geomSeparator, "", FALSE);
  SO_KIT_ADD_CATALOG_ENTRY(radialFeedback, SoSeparator, TRUE, radialFeedbackSwitch, "", TRUE);
  SO_KIT_ADD_CATALOG_ENTRY(circleFeedbackSep, SoSeparator, TRUE, topSeparator, "", FALSE);
  SO_KIT_ADD_CATALOG_ENTRY(circleFeedbackTransformSwitch, SoSwitch, TRUE, circleFeedbackSep, xCircleFeedbackSwitch, FALSE);
  SO_KIT_ADD_CATALOG_ENTRY(circleFeedbackAntiSquish, SoAntiSquish, TRUE, circleFeedbackTransformSwitch, circleFeedbackTransform, FALSE);
  SO_KIT_ADD_CATALOG_ENTRY(circleFeedbackTransform, SoTransform, TRUE, circleFeedbackTransformSwitch, "", FALSE);
  SO_KIT_ADD_CATALOG_ENTRY(xCircleFeedbackSwitch, SoSwitch, TRUE, circleFeedbackSep, yCircleFeedbackSwitch, FALSE);
  SO_KIT_ADD_CATALOG_ENTRY(xCircleFeedback, SoSeparator, TRUE, xCircleFeedbackSwitch, "", TRUE);
  SO_KIT_ADD_CATALOG_ENTRY(yCircleFeedbackSwitch, SoSwitch, TRUE, circleFeedbackSep, zCircleFeedbackSwitch, FALSE);
  SO_KIT_ADD_CATALOG_ENTRY(yCircleFeedback, SoSeparator, TRUE, yCircleFeedbackSwitch, "", TRUE);
  SO_KIT_ADD_CATALOG_ENTRY(zCircleFeedbackSwitch, SoSwitch, TRUE, circleFeedbackSep, "", FALSE);
  SO_KIT_ADD_CATALOG_ENTRY(zCircleFeedback, SoSeparator, TRUE, zCircleFeedbackSwitch, "", TRUE);
}

#undef THIS
#define THIS this->pimpl
#undef THISP
#define THISP thisp->pimpl

// FIXME: document which parts need to be present in the geometry
// scenegraph, and what role they play in the dragger. 20010913 mortene.
/*!
  \DRAGGER_CONSTRUCTOR

  \NODEKIT_PRE_DIAGRAM

  \verbatim
  CLASS SoTransformer2Dragger
  -->"this"
        "callbackList"
        "topSeparator"
           "motionMatrix"
  -->      "surroundScale"
  -->      "overallStyle"
           "geomSeparator"
  -->         "axisFeedbackSep"
  -->            "axisFeedbackLocation"
  -->            "xAxisFeedbackSwitch"
  -->               "xAxisFeedbackActive"
  -->               "xAxisFeedbackSelect"
  -->               "xCrosshairFeedback"
  -->            "yAxisFeedbackSwitch"
  -->               "yAxisFeedbackActive"
  -->               "yAxisFeedbackSelect"
  -->               "yCrosshairFeedback"
  -->            "zAxisFeedbackSwitch"
  -->               "zAxisFeedbackActive"
  -->               "zAxisFeedbackSelect"
  -->               "zCrosshairFeedback"
  -->         "translateBoxFeedbackSep"
  -->            "translateBoxFeedbackSwitch"
  -->               "translateBoxFeedbackRotation"
  -->               "translateBoxFeedback"
  -->         "scaleBoxFeedbackSwitch"
  -->            "scaleBoxFeedback"
  -->         "posXWallFeedbackSwitch"
  -->            "posXWallFeedback"
  -->            "posXRoundWallFeedback"
  -->         "posYWallFeedbackSwitch"
  -->            "posYWallFeedback"
  -->            "posYRoundWallFeedback"
  -->         "posZWallFeedbackSwitch"
  -->            "posZWallFeedback"
  -->            "posZRoundWallFeedback"
  -->         "negXWallFeedbackSwitch"
  -->            "negXWallFeedback"
  -->            "negXRoundWallFeedback"
  -->         "negYWallFeedbackSwitch"
  -->            "negYWallFeedback"
  -->            "negYRoundWallFeedback"
  -->         "negZWallFeedbackSwitch"
  -->            "negZWallFeedback"
  -->            "negZRoundWallFeedback"
  -->         "radialFeedbackSwitch"
  -->            "radialFeedback"
  -->      "translatorSep"
  -->         "translator1Switch"
  -->            "translator1LocateGroup"
  -->               "translator1"
  -->            "translator1Active"
  -->         "translator2Switch"
  -->            "translator2LocateGroup"
  -->               "translator2"
  -->            "translator2Active"
  -->         "translator3Switch"
  -->            "translator3LocateGroup"
  -->               "translator3"
  -->            "translator3Active"
  -->         "translator4Switch"
  -->            "translator4LocateGroup"
  -->               "translator4"
  -->            "translator4Active"
  -->         "translator5Switch"
  -->            "translator5LocateGroup"
  -->               "translator5"
  -->            "translator5Active"
  -->         "translator6Switch"
  -->            "translator6LocateGroup"
  -->               "translator6"
  -->            "translator6Active"
  -->      "translateToCenter"
  -->      "rotatorSep"
  -->         "rotator1Switch"
  -->            "rotator1LocateGroup"
  -->               "rotator1"
  -->            "rotator1Active"
  -->         "rotator2Switch"
  -->            "rotator2LocateGroup"
  -->               "rotator2"
  -->            "rotator2Active"
  -->         "rotator3Switch"
  -->            "rotator3LocateGroup"
  -->               "rotator3"
  -->            "rotator3Active"
  -->         "rotator4Switch"
  -->            "rotator4LocateGroup"
  -->               "rotator4"
  -->            "rotator4Active"
  -->         "rotator5Switch"
  -->            "rotator5LocateGroup"
  -->               "rotator5"
  -->            "rotator5Active"
  -->         "rotator6Switch"
  -->            "rotator6LocateGroup"
  -->               "rotator6"
  -->            "rotator6Active"
  -->      "scaleSep"
  -->         "scale1Switch"
  -->            "scale1LocateGroup"
  -->               "scale1"
  -->            "scale1Active"
  -->         "scale2Switch"
  -->            "scale2LocateGroup"
  -->               "scale2"
  -->            "scale2Active"
  -->         "scale3Switch"
  -->            "scale3LocateGroup"
  -->               "scale3"
  -->            "scale3Active"
  -->         "scale4Switch"
  -->            "scale4LocateGroup"
  -->               "scale4"
  -->            "scale4Active"
  -->         "scale5Switch"
  -->            "scale5LocateGroup"
  -->               "scale5"
  -->            "scale5Active"
  -->         "scale6Switch"
  -->            "scale6LocateGroup"
  -->               "scale6"
  -->            "scale6Active"
  -->         "scale7Switch"
  -->            "scale7LocateGroup"
  -->               "scale7"
  -->            "scale7Active"
  -->         "scale8Switch"
  -->            "scale8LocateGroup"
  -->               "scale8"
  -->            "scale8Active"
  -->      "circleFeedbackSep"
  -->         "circleFeedbackTransformSwitch"
  -->            "circleFeedbackAntiSquish"
  -->            "circleFeedbackTransform"
  -->         "xCircleFeedbackSwitch"
  -->            "xCircleFeedback"
  -->         "yCircleFeedbackSwitch"
  -->            "yCircleFeedback"
  -->         "zCircleFeedbackSwitch"
  -->            "zCircleFeedback"
  \endverbatim

  \NODEKIT_POST_DIAGRAM


  \NODEKIT_PRE_TABLE

  \verbatim
  CLASS SoTransformer2Dragger
  PVT   "this",  SoTransformer2Dragger  --- 
        "callbackList",  SoNodeKitListPart [ SoCallback, SoEventCallback ] 
  PVT   "topSeparator",  SoSeparator  --- 
  PVT   "motionMatrix",  SoMatrixTransform  --- 
        "surroundScale",  SoSurroundScale  --- 
  PVT   "overallStyle",  SoGroup  --- 
  PVT   "geomSeparator",  SoSeparator  --- 
  PVT   "translatorSep",  SoSeparator  --- 
  PVT   "translator1Switch",  SoSwitch  --- 
  PVT   "translator1LocateGroup",  SoLocateHighlight  --- 
        "translator1",  SoSeparator  --- 
        "translator1Active",  SoSeparator  --- 
  PVT   "translator2Switch",  SoSwitch  --- 
  PVT   "translator2LocateGroup",  SoLocateHighlight  --- 
        "translator2",  SoSeparator  --- 
        "translator2Active",  SoSeparator  --- 
  PVT   "translator3Switch",  SoSwitch  --- 
  PVT   "translator3LocateGroup",  SoLocateHighlight  --- 
        "translator3",  SoSeparator  --- 
        "translator3Active",  SoSeparator  --- 
  PVT   "translator4Switch",  SoSwitch  --- 
  PVT   "translator4LocateGroup",  SoLocateHighlight  --- 
        "translator4",  SoSeparator  --- 
        "translator4Active",  SoSeparator  --- 
  PVT   "translator5Switch",  SoSwitch  --- 
  PVT   "translator5LocateGroup",  SoLocateHighlight  --- 
        "translator5",  SoSeparator  --- 
        "translator5Active",  SoSeparator  --- 
  PVT   "translator6Switch",  SoSwitch  --- 
  PVT   "translator6LocateGroup",  SoLocateHighlight  --- 
        "translator6",  SoSeparator  --- 
        "translator6Active",  SoSeparator  --- 
  PVT   "translateToCenter", SoMatrixTransform  ---
  PVT   "rotatorSep",  SoSeparator  --- 
  PVT   "rotator1Switch",  SoSwitch  --- 
  PVT   "rotator1LocateGroup",  SoLocateHighlight  --- 
        "rotator1",  SoSeparator  --- 
        "rotator1Active",  SoSeparator  --- 
  PVT   "rotator2Switch",  SoSwitch  --- 
  PVT   "rotator2LocateGroup",  SoLocateHighlight  --- 
        "rotator2",  SoSeparator  --- 
        "rotator2Active",  SoSeparator  --- 
  PVT   "rotator3Switch",  SoSwitch  --- 
  PVT   "rotator3LocateGroup",  SoLocateHighlight  --- 
        "rotator3",  SoSeparator  --- 
        "rotator3Active",  SoSeparator  --- 
  PVT   "rotator4Switch",  SoSwitch  --- 
  PVT   "rotator4LocateGroup",  SoLocateHighlight  --- 
        "rotator4",  SoSeparator  --- 
        "rotator4Active",  SoSeparator  --- 
  PVT   "rotator5Switch",  SoSwitch  --- 
  PVT   "rotator5LocateGroup",  SoLocateHighlight  --- 
        "rotator5",  SoSeparator  --- 
        "rotator5Active",  SoSeparator  --- 
  PVT   "rotator6Switch",  SoSwitch  --- 
  PVT   "rotator6LocateGroup",  SoLocateHighlight  --- 
        "rotator6",  SoSeparator  --- 
        "rotator6Active",  SoSeparator  --- 
  PVT   "scaleSep",  SoSeparator  --- 
  PVT   "scale1Switch",  SoSwitch  --- 
  PVT   "scale1LocateGroup",  SoLocateHighlight  --- 
        "scale1",  SoSeparator  --- 
        "scale1Active",  SoSeparator  --- 
  PVT   "scale2Switch",  SoSwitch  --- 
  PVT   "scale2LocateGroup",  SoLocateHighlight  --- 
        "scale2",  SoSeparator  --- 
        "scale2Active",  SoSeparator  --- 
  PVT   "scale3Switch",  SoSwitch  --- 
  PVT   "scale3LocateGroup",  SoLocateHighlight  --- 
        "scale3",  SoSeparator  --- 
        "scale3Active",  SoSeparator  --- 
  PVT   "scale4Switch",  SoSwitch  --- 
  PVT   "scale4LocateGroup",  SoLocateHighlight  --- 
        "scale4",  SoSeparator  --- 
        "scale4Active",  SoSeparator  --- 
  PVT   "scale5Switch",  SoSwitch  --- 
  PVT   "scale5LocateGroup",  SoLocateHighlight  --- 
        "scale5",  SoSeparator  --- 
        "scale5Active",  SoSeparator  --- 
  PVT   "scale6Switch",  SoSwitch  --- 
  PVT   "scale6LocateGroup",  SoLocateHighlight  --- 
        "scale6",  SoSeparator  --- 
        "scale6Active",  SoSeparator  --- 
  PVT   "scale7Switch",  SoSwitch  --- 
  PVT   "scale7LocateGroup",  SoLocateHighlight  --- 
        "scale7",  SoSeparator  --- 
        "scale7Active",  SoSeparator  --- 
  PVT   "scale8Switch",  SoSwitch  --- 
  PVT   "scale8LocateGroup",  SoLocateHighlight  --- 
        "scale8",  SoSeparator  --- 
        "scale8Active",  SoSeparator  --- 
  PVT   "circleFeedbackSep",  SoSeparator  --- 
  PVT   "circleFeedbackTransformSwitch",  SoSwitch  --- 
  PVT   "circleFeedbackAntiSquish",  SoAntiSquish  --- 
  PVT   "circleFeedbackTransform",  SoTransform  --- 
  PVT   "xCircleFeedbackSwitch",  SoSwitch  --- 
        "xCircleFeedback",  SoSeparator  --- 
  PVT   "yCircleFeedbackSwitch",  SoSwitch  --- 
        "yCircleFeedback",  SoSeparator  --- 
  PVT   "zCircleFeedbackSwitch",  SoSwitch  --- 
        "zCircleFeedback",  SoSeparator  --- 
  PVT   "axisFeedbackSep",  SoSeparator  --- 
  PVT   "axisFeedbackLocation",  SoTranslation  --- 
  PVT   "xAxisFeedbackSwitch",  SoSwitch  --- 
        "xAxisFeedbackActive",  SoSeparator  --- 
        "xAxisFeedbackSelect",  SoSeparator  --- 
        "xCrosshairFeedback",  SoSeparator  --- 
  PVT   "yAxisFeedbackSwitch",  SoSwitch  --- 
        "yAxisFeedbackActive",  SoSeparator  --- 
        "yAxisFeedbackSelect",  SoSeparator  --- 
        "yCrosshairFeedback",  SoSeparator  --- 
  PVT   "zAxisFeedbackSwitch",  SoSwitch  --- 
        "zAxisFeedbackActive",  SoSeparator  --- 
        "zAxisFeedbackSelect",  SoSeparator  --- 
        "zCrosshairFeedback",  SoSeparator  --- 
  PVT   "translateBoxFeedbackSep",  SoSeparator  --- 
  PVT   "translateBoxFeedbackSwitch",  SoSwitch  --- 
  PVT   "translateBoxFeedbackRotation",  SoRotation  --- 
        "translateBoxFeedback",  SoSeparator  --- 
  PVT   "scaleBoxFeedbackSwitch",  SoSwitch  --- 
        "scaleBoxFeedback",  SoSeparator  --- 
  PVT   "posXWallFeedbackSwitch",  SoSwitch  --- 
        "posXWallFeedback",  SoSeparator  --- 
        "posXRoundWallFeedback",  SoSeparator  --- 
  PVT   "posYWallFeedbackSwitch",  SoSwitch  --- 
        "posYWallFeedback",  SoSeparator  --- 
        "posYRoundWallFeedback",  SoSeparator  --- 
  PVT   "posZWallFeedbackSwitch",  SoSwitch  --- 
        "posZWallFeedback",  SoSeparator  --- 
        "posZRoundWallFeedback",  SoSeparator  --- 
  PVT   "negXWallFeedbackSwitch",  SoSwitch  --- 
        "negXWallFeedback",  SoSeparator  --- 
        "negXRoundWallFeedback",  SoSeparator  --- 
  PVT   "negYWallFeedbackSwitch",  SoSwitch  --- 
        "negYWallFeedback",  SoSeparator  --- 
        "negYRoundWallFeedback",  SoSeparator  --- 
  PVT   "negZWallFeedbackSwitch",  SoSwitch  --- 
        "negZWallFeedback",  SoSeparator  --- 
        "negZRoundWallFeedback",  SoSeparator  --- 
  PVT   "radialFeedbackSwitch",  SoSwitch  --- 
        "radialFeedback",  SoSeparator  --- 
  \endverbatim

  \NODEKIT_POST_TABLE
*/
SoTransformer2Dragger::SoTransformer2Dragger(void)
{
  THIS = new SoTransformer2DraggerP;

  SO_KIT_INTERNAL_CONSTRUCTOR(SoTransformer2Dragger);

  // split-up to avoid one huge method
  this->build_catalog1();
  this->build_catalog2();
  this->build_catalog3();
  this->build_catalog4();
  this->build_catalog5();
  this->build_catalog6();

  if (SO_KIT_IS_FIRST_INSTANCE()) {
    SoInteractionKit::readDefaultParts("transformerDragger.iv",
                                       TRANSFORMER2DRAGGER_draggergeometry,
                                       (int)strlen(TRANSFORMER2DRAGGER_draggergeometry));
  }

  SO_KIT_ADD_FIELD(rotation, (SbRotation(SbVec3f(0.0f, 0.0f, 1.0f), 0.0f)));
  SO_KIT_ADD_FIELD(translation, (0.0f, 0.0f, 0.0f));
  SO_KIT_ADD_FIELD(scaleFactor, (1.0f, 1.0f, 1.0f));
  SO_KIT_ADD_FIELD(center, (0.0f, 0.0f, 0.0f));
  // FIXME: it doesn't look like this field is actually used or set
  // anywhere else but here. Investigate. 20011208 mortene.
  SO_KIT_ADD_FIELD(minDiscRotDot, (0.025f));

  SO_KIT_INIT_INSTANCE();

  this->setPartAsDefault("overallStyle", "transformerOverallStyle");
  this->setPartAsDefault("translator1", "transformerTranslator1");
  this->setPartAsDefault("translator2", "transformerTranslator2");
  this->setPartAsDefault("translator3", "transformerTranslator3");
  this->setPartAsDefault("translator4", "transformerTranslator4");
  this->setPartAsDefault("translator5", "transformerTranslator5");
  this->setPartAsDefault("translator6", "transformerTranslator6");
  this->setPartAsDefault("translator1Active", "transformerTranslator1Active");
  this->setPartAsDefault("translator2Active", "transformerTranslator2Active");
  this->setPartAsDefault("translator3Active", "transformerTranslator3Active");
  this->setPartAsDefault("translator4Active", "transformerTranslator4Active");
  this->setPartAsDefault("translator5Active", "transformerTranslator5Active");
  this->setPartAsDefault("translator6Active", "transformerTranslator6Active");
  this->setPartAsDefault("rotator1", "transformerRotator1");
  this->setPartAsDefault("rotator2", "transformerRotator2");
  this->setPartAsDefault("rotator3", "transformerRotator3");
  this->setPartAsDefault("rotator4", "transformerRotator4");
  this->setPartAsDefault("rotator5", "transformerRotator5");
  this->setPartAsDefault("rotator6", "transformerRotator6");
  this->setPartAsDefault("rotator1Active", "transformerRotator1Active");
  this->setPartAsDefault("rotator2Active", "transformerRotator2Active");
  this->setPartAsDefault("rotator3Active", "transformerRotator3Active");
  this->setPartAsDefault("rotator4Active", "transformerRotator4Active");
  this->setPartAsDefault("rotator5Active", "transformerRotator5Active");
  this->setPartAsDefault("rotator6Active", "transformerRotator6Active");
  this->setPartAsDefault("scale1", "transformerScale1");
  this->setPartAsDefault("scale2", "transformerScale2");
  this->setPartAsDefault("scale3", "transformerScale3");
  this->setPartAsDefault("scale4", "transformerScale4");
  this->setPartAsDefault("scale5", "transformerScale5");
  this->setPartAsDefault("scale6", "transformerScale6");
  this->setPartAsDefault("scale7", "transformerScale7");
  this->setPartAsDefault("scale8", "transformerScale8");
  this->setPartAsDefault("scale1Active", "transformerScale1Active");
  this->setPartAsDefault("scale2Active", "transformerScale2Active");
  this->setPartAsDefault("scale3Active", "transformerScale3Active");
  this->setPartAsDefault("scale4Active", "transformerScale4Active");
  this->setPartAsDefault("scale5Active", "transformerScale5Active");
  this->setPartAsDefault("scale6Active", "transformerScale6Active");
  this->setPartAsDefault("scale7Active", "transformerScale7Active");
  this->setPartAsDefault("scale8Active", "transformerScale8Active");
  this->setPartAsDefault("xAxisFeedbackActive", "transformerXAxisFeedbackActive");
  this->setPartAsDefault("xAxisFeedbackSelect", "transformerXAxisFeedbackSelect");
  this->setPartAsDefault("yAxisFeedbackActive", "transformerYAxisFeedbackActive");
  this->setPartAsDefault("yAxisFeedbackSelect", "transformerYAxisFeedbackSelect");
  this->setPartAsDefault("zAxisFeedbackActive", "transformerZAxisFeedbackActive");
  this->setPartAsDefault("zAxisFeedbackSelect", "transformerZAxisFeedbackSelect");
  this->setPartAsDefault("xCrosshairFeedback", "transformerXCrosshairFeedback");
  this->setPartAsDefault("yCrosshairFeedback", "transformerYCrosshairFeedback");
  this->setPartAsDefault("zCrosshairFeedback", "transformerZCrosshairFeedback");
  this->setPartAsDefault("xCircleFeedback", "transformerXCircleFeedback");
  this->setPartAsDefault("yCircleFeedback", "transformerYCircleFeedback");
  this->setPartAsDefault("zCircleFeedback", "transformerZCircleFeedback");
  this->setPartAsDefault("radialFeedback", "transformerRadialFeedback");
  this->setPartAsDefault("translateBoxFeedback", "transformerTranslateBoxFeedback");

  this->setPartAsDefault("scaleBoxFeedback", "transformerScaleBoxFeedback");
  this->setPartAsDefault("posXWallFeedback", "transformerPosXWallFeedback");
  this->setPartAsDefault("posYWallFeedback", "transformerPosYWallFeedback");
  this->setPartAsDefault("posZWallFeedback", "transformerPosZWallFeedback");
  this->setPartAsDefault("negXWallFeedback", "transformerNegXWallFeedback");
  this->setPartAsDefault("negYWallFeedback", "transformerNegYWallFeedback");
  this->setPartAsDefault("negZWallFeedback", "transformerNegZWallFeedback");
  this->setPartAsDefault("posXRoundWallFeedback", "transformerPosXRoundWallFeedback");
  this->setPartAsDefault("posYRoundWallFeedback", "transformerPosYRoundWallFeedback");
  this->setPartAsDefault("posZRoundWallFeedback", "transformerPosZRoundWallFeedback");
  this->setPartAsDefault("negXRoundWallFeedback", "transformerNegXRoundWallFeedback");
  this->setPartAsDefault("negYRoundWallFeedback", "transformerNegYRoundWallFeedback");
  this->setPartAsDefault("negZRoundWallFeedback", "transformerNegZRoundWallFeedback");

  this->state = INACTIVE;
  THIS->constraintState = CONSTRAINT_OFF;
  // FIXME: according to SGI classdoc, this flag is supposed to be
  // default TRUE?  Investigate. 20011208 mortene.
  THIS->locateHighlighting = FALSE;
  THIS->whatkind = WHATKIND_NONE;
  THIS->whatnum = -1;

  this->setAllPartSwitches(0, 0, 0);

  this->addStartCallback(SoTransformer2Dragger::startCB);
  this->addMotionCallback(SoTransformer2Dragger::motionCB);
  this->addFinishCallback(SoTransformer2Dragger::finishCB);
  this->addValueChangedCallback(SoTransformer2Dragger::valueChangedCB);
  this->addOtherEventCallback(SoTransformer2Dragger::metaKeyChangeCB);

  this->planeProj = new SbPlaneProjector;
  this->lineProj = new SbLineProjector;
  this->sphereProj = new SbSphereSectionProjector;
  this->cylProj = new SbCylinderPlaneProjector;

  this->translFieldSensor = new SoFieldSensor(SoTransformer2Dragger::fieldSensorCB, this);
  this->translFieldSensor->setPriority(0);
  this->scaleFieldSensor = new SoFieldSensor(SoTransformer2Dragger::fieldSensorCB, this);
  this->scaleFieldSensor->setPriority(0);
  this->rotateFieldSensor = new SoFieldSensor(SoTransformer2Dragger::fieldSensorCB, this);
  this->rotateFieldSensor->setPriority(0);
  this->centerFieldSensor = new SoFieldSensor(SoTransformer2Dragger::fieldSensorCB, this);
  this->centerFieldSensor->setPriority(0);

  this->setUpConnections(TRUE, TRUE);

  // make sure these are not written if they have the default value.
  // FIXME: investigate why this is needed. There must be a
  // notification that is sent somewhere that causes the fields to
  // become non-default. pederb, 2003-04-01
  this->translatorSep.setDefault(TRUE);
  this->rotatorSep.setDefault(TRUE);
  this->scaleSep.setDefault(TRUE);
  this->translateBoxFeedbackSep.setDefault(TRUE);
  this->axisFeedbackSep.setDefault(TRUE);
  this->scale8LocateGroup.setDefault(TRUE);
  this->scale7LocateGroup.setDefault(TRUE);
  this->circleFeedbackSep.setDefault(TRUE);
}

/*!
  Protected destructor.

  (Dragger classes are derived from SoBase, so they are reference
  counted and automatically destroyed when their reference count goes
  to 0.)
 */
SoTransformer2Dragger::~SoTransformer2Dragger()
{
  delete this->translFieldSensor;
  delete this->scaleFieldSensor;
  delete this->rotateFieldSensor;
  delete this->centerFieldSensor;

  delete THIS;
}

// Doc in super.
SbBool
SoTransformer2Dragger::setUpConnections(SbBool onoff, SbBool doitalways)
{
  if (!doitalways && this->connectionsSetUp == onoff) return onoff;

  if (onoff) {
    inherited::setUpConnections(onoff, doitalways);

    SoTransformer2Dragger::fieldSensorCB(this, NULL);

    if (this->translFieldSensor->getAttachedField() != &this->translation) {
      this->translFieldSensor->attach(&this->translation);
    }
    if (this->scaleFieldSensor->getAttachedField() != &this->scaleFactor) {
      this->scaleFieldSensor->attach(&this->scaleFactor);
    }
    if (this->rotateFieldSensor->getAttachedField() != &this->rotation) {
      this->rotateFieldSensor->attach(&this->rotation);
    }
    if (this->centerFieldSensor->getAttachedField() != &this->center) {
      this->centerFieldSensor->attach(&this->center);
    }
  }
  else {
    if (this->translFieldSensor->getAttachedField() != NULL) {
      this->translFieldSensor->detach();
    }
    if (this->scaleFieldSensor->getAttachedField() != NULL) {
      this->scaleFieldSensor->detach();
    }
    if (this->rotateFieldSensor->getAttachedField() != NULL) {
      this->rotateFieldSensor->detach();
    }
    if (this->centerFieldSensor->getAttachedField() != NULL) {
      this->centerFieldSensor->detach();
    }
    inherited::setUpConnections(onoff, doitalways);
  }
  return !(this->connectionsSetUp = onoff);
}

// Convenience method used to call setDefault on similar fields.
//
// Note: keep the function name prefix to avoid name clashes with
// other dragger .cpp files for "--enable-compact" builds.
//
// FIXME: should collect these methods in a common method visible to
// all draggers implementing the exact same functionality. 20010826 mortene.
static void
SoTransformer2Dragger_set_default(SoDragger * dragger, const char * fmt,
                                 int minval, int maxval)
{
  SbString str;
  for (int i = minval; i

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.