////////////////////////////////////////////////////////////////////////
//
// Description:
//    Set up the highlighting, projector, and the initial hit on
//    the dragger
//
// Use: private
//
void
SoTranslate2Dragger::dragStart()
//
////////////////////////////////////////////////////////////////////////
{
    // Set the switches to 1...
    setSwitchValue( translatorSwitch.getValue(), 1 );
    setSwitchValue( feedbackSwitch.getValue(), 1 );

    // Set the axis feedback switch to display both.
    // They're displayed while dragging
    setSwitchValue( axisFeedbackSwitch.getValue(), SO_SWITCH_ALL );

    // There is no constrained direction...
    translateDir = -1;

    // Make a note of which modifier keys are down.
    shftDown = getEvent()->wasShiftDown();

    // This is the point we'll use if a metaKey callback makes us re-start.
	worldRestartPt = getWorldStartingPoint();

    // Establish the projector plane in working space.
    // Working space is space at end of motion matrix.
    // Plane normal is defined relative to the translatorPart, so 
    // use z-axis to construct the projector plane.
	SbVec3f startLocalHitPt = getLocalStartingPoint();
	planeProj->setPlane( SbPlane(SbVec3f(0,0,1), startLocalHitPt ) );
}
////////////////////////////////////////////////////////////////////////
//
// Description:
//    Rotate the rotateDiscDragger based on mouse motion.
//
// Use: private
//
void
SoRotateDiscDragger::drag()
//
////////////////////////////////////////////////////////////////////////
{
    // Set up the projector space and view.
    // Working space is space at end of motion matrix.
	planeProj->setViewVolume( getViewVolume() );    
	planeProj->setWorkingSpace( getLocalToWorldMatrix() );

    // Get newHitPt and startHitPt in workspace.
	SbVec3f newHitPt 
	    = planeProj->project( getNormalizedLocaterPosition()); 
	SbVec3f startHitPt = getLocalStartingPoint();

    // Find the amount of rotation
    SbVec3f oldVec = startHitPt;
    SbVec3f newVec = newHitPt;
    // Remove the part of these vectors that is parallel to the normal
    oldVec -= SbVec3f( 0, 0, oldVec[2] );
    newVec -= SbVec3f( 0, 0, newVec[2] );

    // deltaRot is how much we rotated since the mouse button went down.
    SbRotation deltaRot = SbRotation( oldVec, newVec );
	
    // Append this to the startMotionMatrix, which we saved at the beginning
    // of the drag, to find the current motion matrix.
	setMotionMatrix( 
	    appendRotation( getStartMotionMatrix(), deltaRot, SbVec3f(0,0,0)));
}
////////////////////////////////////////////////////////////////////////
//
// Description:
//    Stretch the dragger according to the motion along the plane
//    projector
//
// Use: private
//
void
SoTranslate2Dragger::drag()
//
////////////////////////////////////////////////////////////////////////
{
    // Set up the projector space and view.
    // Working space is space at end of motion matrix.
	planeProj->setViewVolume( getViewVolume() );    
	planeProj->setWorkingSpace( getLocalToWorldMatrix() );

    // Get newHitPt and startHitPt in workspace.
	SbVec3f newHitPt = planeProj->project( getNormalizedLocaterPosition()); 
	SbVec3f startHitPt = getLocalStartingPoint();

    // Convert newHitPt to world space and save this as our new worldRestartPt
	getLocalToWorldMatrix().multVecMatrix( newHitPt, worldRestartPt );

    // Figure out the translation relative to start position.
        SbVec3f motion = newHitPt - startHitPt;

    // Maybe we need to constrain the motion...
    if ( !shftDown )
	translateDir = -1;
    else {
	// The shift key is pressed. This means 1-D translation.
	if ( translateDir == -1 ) {
	    // The 1-D direction is not defined. Calculate it based on which
	    // direction got the maximum locater motion.
            if ( isAdequateConstraintMotion() ) {
		if ( fabs( motion[0]) > fabs( motion[1]))
		    translateDir = 0;
		else 
		    translateDir = 1;

		// Set the axis feedback switch to the given direction.
		setSwitchValue( axisFeedbackSwitch.getValue(), translateDir );
	    }
	    else {
		// Not ready to pick a direction yet. Don't move.
		return;
	    }
	}
	// get the projection of 'motion' onto the preferred axis.
	SbVec3f constrainedMotion(0,0,0);
	constrainedMotion[translateDir] = motion[translateDir];
	motion = constrainedMotion;
    }

    // Append this to the startMotionMatrix, which we saved at the beginning
    // of the drag, to find the current motion matrix.
	setMotionMatrix( appendTranslation( getStartMotionMatrix(), motion ) );
}
////////////////////////////////////////////////////////////////////////
//
// Description:
//    Rotate the rotateDiscDragger based on mouse motion.
//
// Use: private
//
void
SoRotateDiscDragger::dragStart()
//
////////////////////////////////////////////////////////////////////////
{
    // Set the switches to 1...
    setSwitchValue( rotatorSwitch.getValue(), 1 );
    setSwitchValue( feedbackSwitch.getValue(), 1 );

    // Establish the projector plane in working space.
    // Working space is space at end of motion matrix.
    // The plane used should be the x-y plane.
	SbVec3f startLocalHitPt = getLocalStartingPoint();
	SbLine  workSpaceAxis( SbVec3f(0,0,0), SbVec3f(0,0,1) );
	SbVec3f planeOrigin = workSpaceAxis.getClosestPoint(startLocalHitPt);
	planeProj->setPlane(SbPlane(SbVec3f(0,0,1), planeOrigin));
}
////////////////////////////////////////////////////////////////////////
//
// Description:
//    Called by a child dragger after dragStart.
//
//   Figures out which dragger is active, then updates the feedback
//   accordingly
//
// Use: protected
//
void
SoDragPointDragger::dragStart()
//
////////////////////////////////////////////////////////////////////////
{
    currentDragger = getActiveChildDragger();

    // If there is no active child dragger, then we should just return.
    if ( currentDragger == NULL)
	return;

    shftDown = getEvent()->wasShiftDown();

    // Save the starting point as expressed in local space.
    // We need to do this so that our feedback will work nicely.
    startLocalHitPt = getLocalStartingPoint();

    updateLimitBoxAndFeedback();
}
void TranslateRadialDragger::
dragStart()
{
  // Display the 'active' parts...
  SoSwitch *sw;
  sw = SO_GET_ANY_PART(this, "translatorSwitch", SoSwitch);
  setSwitchValue(sw, 1);
  sw = SO_GET_ANY_PART(this, "feedbackSwitch", SoSwitch);
  setSwitchValue(sw, 1);

  // Establish the projector line.
  // The direction of translation goes from the center of the
  // dragger toward the point that was hit, in local space.
  // For the center, use (0,0,0).
  SbVec3f startLocalHitPt = getLocalStartingPoint();
  lineProj->setLine(SbLine(SbVec3f(0, 0, 0), startLocalHitPt));

  // orient the feedback geometry.
  orientFeedbackGeometry(startLocalHitPt);
}
void TranslateRadialDragger::
drag()
{
  // Things can change between renderings. To be safe, update
  // the projector with the current values.
  lineProj->setViewVolume(getViewVolume());
  lineProj->setWorkingSpace(getLocalToWorldMatrix());

  // Find the new intersection on the projector.
  SbVec3f newHitPt
    = lineProj->project(getNormalizedLocaterPosition());

  // Get initial point expressed in our current local space.
  SbVec3f startHitPt = getLocalStartingPoint();

  // Motion in local space is difference between old and
  // new positions.
  SbVec3f motion = newHitPt - startHitPt;

  // Append this to the startMotionMatrix, which was saved
  // automatically at the beginning of the drag, to find
  // the current motion matrix.
  setMotionMatrix( appendTranslation(getStartMotionMatrix(), motion));
}