void SphereApproximator::generateGraph(SphereApproximation& storeResult, EPolyhedronType baseType, int levels, float radius) { GraphData gd; initBasePolyhedron(baseType, gd); projectToSphere(radius, gd); for (int L = 0 ; L < levels ; L++) { subDivide(gd); projectToSphere(radius, gd); } // copy contents storeResult.vertices = gd.vertices; storeResult.faces = gd.faces; buildVertexFaceMapping(storeResult); }
//-------------------------------------------------------------------------------------------------- /// Compute quaternion rotation /// /// \param oldPosX x coordinate of the last position of the mouse, in the range [-1.0, 1.0] /// \param oldPosY y coordinate of the last position of the mouse, in the range [-1.0, 1.0] /// \param newPosX x coordinate of current position of the mouse, in the range [-1.0, 1.0] /// \param newPosY y coordinate of current position of the mouse, in the range [-1.0, 1.0] /// \param currViewMatrix Current transformation matrix. The inverse is used when calculating the rotation /// \param sensitivityFactor Mouse sensitivity factor /// /// Simulate a track-ball. Project the points onto the virtual trackball, then figure out the axis /// of rotation. This is a deformed trackball-- is a trackball in the center, but is deformed into a /// hyperbolic sheet of rotation away from the center. //-------------------------------------------------------------------------------------------------- Quatd ManipulatorTrackball::trackballRotation(double oldPosX, double oldPosY, double newPosX, double newPosY, const Mat4d& currViewMatrix, double sensitivityFactor) { // This particular function was chosen after trying out several variations. // Implemented by Gavin Bell, lots of ideas from Thant Tessman and the August '88 // issue of Siggraph's "Computer Graphics," pp. 121-129. // This size should really be based on the distance from the center of rotation to the point on // the object underneath the mouse. That point would then track the mouse as closely as possible. const double TRACKBALL_RADIUS = 0.8f; // Clamp to valid range oldPosX = Math::clamp(oldPosX, -1.0, 1.0); oldPosY = Math::clamp(oldPosY, -1.0, 1.0); newPosX = Math::clamp(newPosX, -1.0, 1.0); newPosY = Math::clamp(newPosY, -1.0, 1.0); // First, figure out z-coordinates for projection of P1 and P2 to deformed sphere Vec3d p1 = projectToSphere(TRACKBALL_RADIUS, oldPosX, oldPosY); Vec3d p2 = projectToSphere(TRACKBALL_RADIUS, newPosX, newPosY); // Axis of rotation is the cross product of P1 and P2 Vec3d a = p1 ^ p2; // Figure out how much to rotate around that axis. Vec3d d = p1 - p2; double t = d.length()/(2.0*TRACKBALL_RADIUS); // Avoid problems with out-of-control values... t = Math::clamp(t, -1.0, 1.0); double phi = 2.0*asin(t); // Scale by sensitivity factor phi *= sensitivityFactor; // Use inverted matrix to find rotation axis Mat4d invMatr = currViewMatrix.getInverted(); a.transformVector(invMatr); // Get quaternion to be returned by pointer Quatd quat = Quatd::fromAxisAngle(a, phi); return quat; }
void CameraArcBallDemo::calculateArcBall( cocos2d::Vec3 & axis, float & angle, float p1x, float p1y, float p2x, float p2y ) { Mat4 rotation_matrix; Mat4::createRotation(_rotationQuat, &rotation_matrix); Vec3 uv = rotation_matrix * Vec3(0.0f,1.0f,0.0f); //rotation y Vec3 sv = rotation_matrix * Vec3(1.0f,0.0f,0.0f); //rotation x Vec3 lv = rotation_matrix * Vec3(0.0f,0.0f,-1.0f);//rotation z Vec3 p1 = sv * p1x + uv * p1y - lv * projectToSphere(_radius, p1x, p1y); //start point screen transform to 3d Vec3 p2 = sv * p2x + uv * p2y - lv * projectToSphere(_radius, p2x, p2y); //end point screen transform to 3d Vec3::cross(p2, p1, &axis); //calculate rotation axis axis.normalize(); float t = (p2 - p1).length() / (2.0 * _radius); //clamp -1 to 1 if (t > 1.0) t = 1.0; if (t < -1.0) t = -1.0; angle = asin(t); //rotation angle }
void QuatTrackBall::calcRotation(const Vec2f& new_pos) { // Check for zero rotation if (new_pos == last_pos) qinc = Quatf(0.0f, 0.0f, 0.0f, 1.0f); else { // Form two vectors based on input points, find rotation axis Vec3f p1 = Vec3f(new_pos[0], new_pos[1], projectToSphere(new_pos)); Vec3f p2 = Vec3f(last_pos[0], last_pos[1], projectToSphere(last_pos)); qinc.make_rot(normalize(p1), normalize(p2)); /* Vec3f q = cross(p1, p2); // axis of rotation from p1 and p2 float L = sqrt(1.0f-dot(q,q) / (dot(p1,p1) * dot(p2,p2))); q.normalize(); // q' = axis of rotation q *= sqrt((1 - L)/2); // q' = q' * sin(phi) qinc.set(q[0],q[1],q[2],sqrt((1 + L)/2)); */ } }
/* virtual */ void av::utils::Trackball::evaluate() { av::FieldContainer::evaluate(); if(!Enable.getValue()) return; if(mReset) reset(); const bool newDragging = (RotateTrigger.getValue() || ZoomTrigger.getValue() || PanTrigger.getValue()); const ::osg::Vec3 projected = projectToSphere(Direction.getValue()); if (mDragging && newDragging) { if (RotateTrigger.getValue()) { ::osg::Matrix rotMat = ::osg::Matrix::rotate(projected, mLastProjected); float fac = SpinningWeightingCoefficient.getValue(); mRotation = rotMat * ::osg::Matrix::scale(fac,fac,fac) * mRotation; Matrix.setValue(mCenterTransInv * rotMat * CenterTransform.getValue() * Matrix.getValue()); } else if (ZoomTrigger.getValue()) { const ::osg::Vec2 offset = mLastDirection - Direction.getValue(); float zoomFactor = offset.y(); zoomFactor *= BoundingSphere.getValue()->Radius.getValue()*ZoomPanFactor.getValue(); if(AutoAdjustCenterTransform.getValue()) { ::osg::Matrix mat = CenterTransform.getValue() * ::osg::Matrix::translate(0.0, 0.0, zoomFactor); CenterTransform.setValue(mat); } Matrix.setValue(mCenterTransInv * ::osg::Matrix::translate(0.0, 0.0, -zoomFactor) * CenterTransform.getValue() * Matrix.getValue()); } else if (PanTrigger.getValue()) { const ::osg::Vec2 offset = mLastDirection - Direction.getValue(); float xPanFactor = offset.x() * BoundingSphere.getValue()->Radius.getValue()*ZoomPanFactor.getValue(); float yPanFactor = offset.y() * BoundingSphere.getValue()->Radius.getValue()*ZoomPanFactor.getValue(); Matrix.setValue(mCenterTransInv * ::osg::Matrix::translate(xPanFactor, yPanFactor, 0.0) * CenterTransform.getValue() * Matrix.getValue()); } mSpinning = false; } else if (!mDragging && newDragging) { mRotation = ::osg::Matrix::identity(); mTimeLastMovement = TimeIn.getValue(); } else if (mDragging && !newDragging) { float timeSinceLastRecordEvent = TimeIn.getValue() - mTimeLastMovement; if (timeSinceLastRecordEvent < SpinningTimeThreshold.getValue()) { mSpinning = true; } } if (mSpinning) { ::osg::Quat rot = mRotation.getRotate(); Matrix.setValue(mCenterTransInv * ::osg::Matrix::rotate(rot) * CenterTransform.getValue() * Matrix.getValue()); } if (ResetTrigger.getValue()) { reset(); mSpinning = false; } mDragging = newDragging; mLastDirection = Direction.getValue(); mLastProjected = projected; }
/* virtual */ void av::utils::Trackball::evaluate() { av::FieldContainer::evaluate(); if(!Enable.getValue()) return; if(mReset) reset(); const bool newDragging = RotateTrigger.getValue() || ZoomTrigger.getValue() || PanTrigger.getValue(); const ::gua::math::vec3 projected = projectToSphere(Direction.getValue()); if(mDragging && newDragging) { if(RotateTrigger.getValue()) { auto quat = ::scm::math::quat<double>::from_arc(projected, mLastProjected); ::gua::math::mat4 rotMat = quat.to_matrix(); double fac = double(SpinningWeightingCoefficient.getValue()); mRotation = rotMat * ::scm::math::make_scale(fac, fac, fac) * mRotation; Matrix.setValue(mCenterTransInv * rotMat * CenterTransform.getValue() * Matrix.getValue()); } else if(ZoomTrigger.getValue()) { const ::gua::math::vec2 offset = mLastDirection - Direction.getValue(); float zoomFactor = offset.y; zoomFactor *= BoundingSphere.getValue()->Radius.getValue() * ZoomPanFactor.getValue(); if(AutoAdjustCenterTransform.getValue()) { ::gua::math::mat4 mat = CenterTransform.getValue() * ::scm::math::make_translation(double(0.0), double(0.0), double(zoomFactor)); CenterTransform.setValue(mat); } Matrix.setValue(mCenterTransInv * ::scm::math::make_translation(double(0.0), double(0.0), double(-zoomFactor)) * CenterTransform.getValue() * Matrix.getValue()); } else if(PanTrigger.getValue()) { const ::gua::math::vec2 offset = mLastDirection - Direction.getValue(); float xPanFactor = offset.x * BoundingSphere.getValue()->Radius.getValue() * ZoomPanFactor.getValue(); float yPanFactor = offset.y * BoundingSphere.getValue()->Radius.getValue() * ZoomPanFactor.getValue(); Matrix.setValue(mCenterTransInv * ::scm::math::make_translation(double(xPanFactor), double(yPanFactor), double(0.0)) * CenterTransform.getValue() * Matrix.getValue()); } mSpinning = false; } else if(!mDragging && newDragging) { mRotation = ::gua::math::mat4::identity(); mTimeLastMovement = TimeIn.getValue(); } else if(mDragging && !newDragging) { float timeSinceLastRecordEvent = TimeIn.getValue() - mTimeLastMovement; if(timeSinceLastRecordEvent < SpinningTimeThreshold.getValue()) { mSpinning = true; } } if(mSpinning) { ::gua::math::quat rot = ::scm::math::quat<double>::from_matrix(mRotation); Matrix.setValue(mCenterTransInv * rot.to_matrix() * CenterTransform.getValue() * Matrix.getValue()); } if(ResetTrigger.getValue()) { reset(); mSpinning = false; } mDragging = newDragging; mLastDirection = Direction.getValue(); mLastProjected = projected; }
void Trackball::updateRotation(Real32 rLastX, Real32 rLastY, Real32 rCurrentX, Real32 rCurrentY) { Quaternion qCurrVal; Vec3f gAxis; /* Axis of rotation */ Real32 rPhi = 0.f; /* how much to rotate about axis */ Vec3f gP1; Vec3f gP2; Vec3f gDiff; Real32 rTmp; if( (osgAbs(rLastX - rCurrentX) > TypeTraits<Real32>::getDefaultEps()) || (osgAbs(rLastY - rCurrentY) > TypeTraits<Real32>::getDefaultEps()) ) { /* * First, figure out z-coordinates for projection of P1 and P2 to * deformed sphere */ gP1.setValues( rLastX, rLastY, projectToSphere(_rTrackballSize, rLastX, rLastY)); gP2.setValues( rCurrentX, rCurrentY, projectToSphere(_rTrackballSize, rCurrentX, rCurrentY)); /* * Now, we want the cross product of P1 and P2 */ gAxis = gP2; gAxis.crossThis(gP1); /* * Figure out how much to rotate around that axis. */ gDiff = gP2; gDiff -= gP1; rTmp = gDiff.length() / (2.0f * _rTrackballSize); /* * Avoid problems with out-of-control values... */ if(rTmp > 1.0) rTmp = 1.0; if(rTmp < -1.0) rTmp = -1.0; if(_gMode == OSGObject) rPhi = Real32(-2.0) * osgASin(rTmp); else rPhi = Real32( 2.0) * osgASin(rTmp); } rPhi *= _rRotScale; if(_bSum == false) { _qVal.setValueAsAxisRad(gAxis, rPhi); } else { qCurrVal.setValueAsAxisRad(gAxis, rPhi); _qVal *= qCurrVal; // _qVal.multLeft(qCurrVal); } }
void Trackball::updateTrackball(float p1x, float p1y, float p2x, float p2y) { vector3D axis; // Axis of rotation float phi; // Angle of rotation vector3D p1, p2; float t; // // If no difference in position, it's a zero rotation // if (p1x == p2x && p1y == p2y) { _quat->reset(); return; } // // Determine coordinate of z in the hemisphere from x and y // p1 = getVector3D(p1x, p1y, projectToSphere(TRACKBALL_RADIUS, p1x, p1y)); p2 = getVector3D(p2x, p2y, projectToSphere(TRACKBALL_RADIUS, p2x, p2y)); // // Get the cross product of the 2 vectors to find // the axis of rotation (normal) // axis = getCrossProduct(p2, p1); // // Find a vector that goes from the last position point to // current position // vector3D d; d.x = p1.x - p2.x; d.y = p1.y - p2.y; d.z = p1.z - p2.z; // // Find angle based on the fact that : // arc sin(theta) = a / d // where // a = vector length of 2 points in the hemisphere // d = diameter of hemisphere // // x,y could be outside the hemisphere, // in which case t could be > 1. That's why // we have to place a bound here // t = getVector3DLength(d) / (2.0 * TRACKBALL_RADIUS); if (t < -1) { t = -1; } else if (t > 1) { t = 1; } phi = 2.0 * asin (t); _quat->CreateFromAxisAngle(axis.x, axis.y, axis.z, phi); }