//////////////////////////////////////////////////////////////////////// // // 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::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))); }
void Emitter::emitParticles(double dt) { int n = mCounter->numParticlesToCreate(dt); if (n == 0) return; osg::Matrix worldToPs; // maybe this could be optimized by halting at the lowest common ancestor of the particle and emitter nodes osg::NodePathList partsysNodePaths = getParticleSystem()->getParentalNodePaths(); if (!partsysNodePaths.empty()) { osg::Matrix psToWorld = osg::computeLocalToWorld(partsysNodePaths[0]); worldToPs = osg::Matrix::inverse(psToWorld); } const osg::Matrix& ltw = getLocalToWorldMatrix(); osg::Matrix emitterToPs = ltw * worldToPs; if (!mTargets.empty()) { int randomRecIndex = mTargets[(std::rand() / (static_cast<double>(RAND_MAX)+1.0)) * mTargets.size()]; // we could use a map here for faster lookup FindGroupByRecIndex visitor(randomRecIndex); getParent(0)->accept(visitor); if (!visitor.mFound) { std::cerr << "Emitter: Can't find emitter node" << randomRecIndex << std::endl; return; } osg::NodePath path = visitor.mFoundPath; path.erase(path.begin()); emitterToPs = osg::computeLocalToWorld(path) * emitterToPs; } emitterToPs.orthoNormalize(emitterToPs); for (int i=0; i<n; ++i) { osgParticle::Particle* P = getParticleSystem()->createParticle(0); if (P) { mPlacer->place(P); mShooter->shoot(P); P->transformPositionVelocity(emitterToPs); } } }
void osgParticleHPS::ModularEmitter::emit(double dt) { int n = counter_->numParticlesToCreate(dt); for (int i=0; i<n; ++i) { Particle *P = getParticleSystem()->createParticle(); if (P) { placer_->place(P); shooter_->shoot(P); if (getReferenceFrame() == RELATIVE_TO_PARENTS) { P->transformPositionVelocity(getLocalToWorldMatrix()); } } } }
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)); }
void SoDragPointDragger::checkBoxLimits() // //////////////////////////////////////////////////////////////////////// { // The limit box is defined in a space aligned and scaled as LOCAL // space, but with it's center remaining fixed in WORLD space. // We need to do this work in LOCAL space, so to begin with, // get the location of the center of this box in LOCAL space. SbMatrix worldToLocal = getWorldToLocalMatrix(); SbVec3f limitBoxCenterInLocal = limitBox.getCenter(); worldToLocal.multVecMatrix( limitBoxCenterInLocal, limitBoxCenterInLocal ); // Now, if our current position is out of range, we need to move // the limit box center accordingly. We continue to do our work // in LOCAL space. SbBool changed = FALSE; SbVec3f boxSize = limitBox.getMax() - limitBox.getMin(); for (int i = 0; i < 3; i++) { float length = boxSize[i]; float halfLength = length * 0.5; // Check the location of startLocalHitPt against boundaries of the limit // box (keeping in mind the jump limit as a % of the total length). // Have we gone too far in the positive direction? float high = limitBoxCenterInLocal[i] + halfLength; while ( (high - startLocalHitPt[i]) / length < jumpLimit ) { limitBoxCenterInLocal[i] += halfLength; high += halfLength; changed = TRUE; } // Have we gone too far in the negative direction? float low = limitBoxCenterInLocal[i] - halfLength; while (( startLocalHitPt[i] - low ) / length < jumpLimit ) { limitBoxCenterInLocal[i] -= halfLength; low -= halfLength; changed = TRUE; } } if (changed == TRUE ) { // First, convert the changed limitBoxCenterInLocal // into WORLD space... SbMatrix localToWorld = getLocalToWorldMatrix(); SbVec3f newCenter; localToWorld.multVecMatrix(limitBoxCenterInLocal,newCenter); // Next, set the bounds of the limit box to have the same size // as before, but centered about this new point. SbVec3f diag = limitBox.getMax() - limitBox.getCenter(); limitBox.setBounds( newCenter - diag, newCenter + diag ); } }
//////////////////////////////////////////////////////////////////////// // // Description: // This routine sets the limitBox. // The limit box is defined in a space aligned and scaled as // LOCAL space, but with it's center remaining fixed in WORLD // space. // // Use: static private // void SoDragPointDragger::updateLimitBoxAndFeedback() // //////////////////////////////////////////////////////////////////////// { // This gets called in the constructor, while the ref count is still 0. // Since there will be some ref'ing and unref'ing done inside here, // add a temporary ref and undo it at the end. ref(); if ( xFeedback.getValue() != oldXAxisNode || yFeedback.getValue() != oldYAxisNode || zFeedback.getValue() != oldZAxisNode ) { oldXAxisNode = SO_GET_ANY_PART(this,"xFeedback",SoSeparator); oldYAxisNode = SO_GET_ANY_PART(this,"yFeedback",SoSeparator); oldZAxisNode = SO_GET_ANY_PART(this,"zFeedback",SoSeparator); // Get the bounds of the axis parts. static SoGetBoundingBoxAction *bba = NULL; if (bba == NULL) bba = new SoGetBoundingBoxAction(getViewportRegion()); else bba->setViewportRegion(getViewportRegion()); float xMin, yMin, zMin, xMax, yMax, zMax; SbVec3f min, max; bba->apply(xFeedback.getValue()); bba->getBoundingBox().getBounds( xMin, yMin, zMin, xMax, yMax, zMax ); min[0] = xMin; max[0] = xMax; bba->apply(yFeedback.getValue()); bba->getBoundingBox().getBounds( xMin, yMin, zMin, xMax, yMax, zMax ); min[1] = yMin; max[1] = yMax; bba->apply(zFeedback.getValue()); bba->getBoundingBox().getBounds( xMin, yMin, zMin, xMax, yMax, zMax ); min[2] = zMin; max[2] = zMax; // The limit box is defined in a space aligned and scaled as // LOCAL space, but with it's center remaining fixed in WORLD // space. SbVec3f newDiag = (max - min) / 2.0; // Give a default size of 1, in case no axis parts exist. for (int i = 0; i < 3; i++) { if (newDiag[i] <= getMinScale()) newDiag[i] = 1.0; } SbVec3f oldDiag = limitBox.getMax() - limitBox.getCenter(); // If the size of the boundingBox has changed... if ( newDiag != oldDiag ) { // curEdit point needs to be the current origin expressed in world // space (i.e., this bizarro space). SbMatrix localToWorld = getLocalToWorldMatrix(); SbVec3f zeroPt(0,0,0); localToWorld.multVecMatrix( zeroPt, zeroPt ); limitBox.setBounds(zeroPt - newDiag, zeroPt + newDiag ); } } setFeedbackGeometry(); // undo the temporary ref. unrefNoDelete(); }