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;
}
Exemple #3
0
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
}
Exemple #4
0
 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));
          */
     }
 }
Exemple #5
0
/* 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;
}
Exemple #6
0
/* 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);
}