float Transform3D::norm(Transform3D T){
     float pos_norm = arma::norm(T.translation());
     UnitQuaternion q = UnitQuaternion(Rotation3D(T.submat(0,0,2,2)));
     float angle = q.getAngle();
     //TODO: how to weight these two?
     return pos_norm + Rotation3D::norm(T.rotation());
 }
    UnitQuaternion UnitQuaternion::slerp(const UnitQuaternion& p, const double& t) {
        // See http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/
        // Where qa = *this and qb = p

        double cosHalfTheta = kW() * p.kW() + kX() * p.kX() + kY() * p.kY() + kZ() * p.kZ();

        // If qa=qb or qa=-qb then theta = 0 and we can return qa
        if (std::abs(cosHalfTheta) >= 1.0) {
            return *this;
        }

        double halfTheta = utility::math::angle::acos_clamped(cosHalfTheta);
        double sinHalfTheta = sqrt(1.0 - cosHalfTheta * cosHalfTheta);

        // If theta = 180 degrees then result is not fully defined
        // We could rotate around any axis normal to qa or qb
        if (std::abs(sinHalfTheta) < 0.001) {
            return *this * 0.5 + p * 0.5;
        }

        // Interpolate
        double ratioA = std::sin((1 - t) * halfTheta) / sinHalfTheta;
        double ratioB = std::sin(t * halfTheta) / sinHalfTheta;

        return *this * ratioA + p * ratioB;
    }
示例#3
0
 float Rotation3D::norm(Rotation3D T) {
     UnitQuaternion q = UnitQuaternion(T);
     // Get angle between -2Pi and 2pi
     float angle = q.getAngle();
     // Just want magnitude
     float theta = std::fabs(angle);
     // But rotating more that Pi in one direction is equivalent to a rotation in the other direction
     return std::fmin(2 * M_PI - theta, theta);
 }
示例#4
0
UnitQuaternion&
	UnitQuaternion::LnDif(
		const UnitQuaternion& p, 
		const UnitQuaternion& q
	)
{
	UnitQuaternion r;
	r.Divide(q,p);
	return(LogN(r));
}
	UnitQuaternion UnitQuaternion::operator * (const UnitQuaternion& p) const {
		//From http://en.wikipedia.org/wiki/Quaternion#Quaternions_and_the_geometry_of_R3
        double realPart = real() * p.real() - arma::dot(imaginary(), p.imaginary());

        arma::vec3 imaginaryPart = arma::cross(imaginary(), p.imaginary())
                                 + p.real() *   imaginary()
                                 +   real() * p.imaginary();

        return UnitQuaternion(realPart, imaginaryPart);
	}
// Testing of UnitQuaternion multiplication
TYPED_TEST (UnitQuaternionsSingleTest, testUnitQuaternionSingleMultiplication) {
    typedef typename TestFixture::UnitQuaternion UnitQuaternion;
    typedef typename TestFixture::UnitQuaternionScalar UnitQuaternionScalar;
    typedef typename TestFixture::EigenQuat EigenQuat;
    UnitQuaternion testQuat;

    // Check multiplication of two generic quaternions and compare with eigen results
    UnitQuaternion quat12 = this->quat1*this->quat2;
    EigenQuat eigenQuat12 = this->eigenQuat1*this->eigenQuat2;
    ASSERT_EQ(quat12.w(),eigenQuat12.w());
    ASSERT_EQ(quat12.x(),eigenQuat12.x());
    ASSERT_EQ(quat12.y(),eigenQuat12.y());
    ASSERT_EQ(quat12.z(),eigenQuat12.z());

    // Check result of multiplication of a generic quaternion with identity
    testQuat = this->quat1*this->quatIdentity;
    ASSERT_EQ(testQuat.w(),this->quat1.w());
    ASSERT_EQ(testQuat.x(),this->quat1.x());
    ASSERT_EQ(testQuat.y(),this->quat1.y());
    ASSERT_EQ(testQuat.z(),this->quat1.z());
    testQuat = this->quatIdentity*this->quat1;
    ASSERT_EQ(testQuat.w(),this->quat1.w());
    ASSERT_EQ(testQuat.x(),this->quat1.x());
    ASSERT_EQ(testQuat.y(),this->quat1.y());
    ASSERT_EQ(testQuat.z(),this->quat1.z());
}
示例#7
0
UnitQuaternion&
	UnitQuaternion::Divide(
		const UnitQuaternion& p, 
		const UnitQuaternion& q
	)
{
	UnitQuaternion i;
	i.Inverse(q);
	Multiply(i, p);
	
	return *this;
}
// Testing of Norm and Normalization for UnitQuaternion
TYPED_TEST (UnitQuaternionsSingleTest, testUnitQuaternionSingleNormalization) {
    typedef typename TestFixture::UnitQuaternion UnitQuaternion;
    typedef typename TestFixture::UnitQuaternionScalar UnitQuaternionScalar;
    typedef typename TestFixture::EigenQuat EigenQuat;
    UnitQuaternion testQuat;
    UnitQuaternionScalar scalar;

    // Check norm and normalization
    testQuat = this->quat1;
    scalar = testQuat.norm();
    ASSERT_NEAR(scalar,1.0,1e-6);
}
// Testing vector() and constructor from vector
TYPED_TEST (UnitQuaternionsSingleTest, testQuaternionSingleVectorAndVectorConstructor) {
    typedef typename TestFixture::UnitQuaternion UnitQuaternion;
    typedef typename TestFixture::UnitQuaternionScalar UnitQuaternionScalar;
    typedef Eigen::Matrix<UnitQuaternionScalar, 4, 1> Vector4;
    UnitQuaternion quat = this->quat1;

    // vector()
    Vector4 vector = quat.vector();
    ASSERT_NEAR(quat.w(),vector(0), 1e-3);
    ASSERT_NEAR(quat.x(),vector(1), 1e-3);
    ASSERT_NEAR(quat.y(),vector(2), 1e-3);
    ASSERT_NEAR(quat.z(),vector(3), 1e-3);

    // constructor from vector
    UnitQuaternion quatFromVector(vector);
    ASSERT_NEAR(quat.w(),quatFromVector.w(), 1e-3);
    ASSERT_NEAR(quat.x(),quatFromVector.x(), 1e-3);
    ASSERT_NEAR(quat.y(),quatFromVector.y(), 1e-3);
    ASSERT_NEAR(quat.z(),quatFromVector.z(), 1e-3);
}
// Testing of UnitQuaternion Constructor and Access Operator
TYPED_TEST (UnitQuaternionsSingleTest, testUnitQuaternionSingleConstructor) {
    typedef typename TestFixture::UnitQuaternion UnitQuaternion;
    typedef typename TestFixture::UnitQuaternionScalar UnitQuaternionScalar;
    typedef typename TestFixture::EigenQuat EigenQuat;

    // Default constructor of quaternion needs to set all coefficients to zero
    UnitQuaternion testQuat;
    ASSERT_EQ(testQuat.w(),UnitQuaternionScalar(1));
    ASSERT_EQ(testQuat.x(),UnitQuaternionScalar(0));
    ASSERT_EQ(testQuat.y(),UnitQuaternionScalar(0));
    ASSERT_EQ(testQuat.z(),UnitQuaternionScalar(0));

    // Constructor of quaternion using 4 scalars
    UnitQuaternion testQuat1(this->eigenQuat1.w(), this->eigenQuat1.x(), this->eigenQuat1.y(), this->eigenQuat1.z());
    ASSERT_EQ(testQuat1.w(),this->eigenQuat1.w());
    ASSERT_EQ(testQuat1.x(),this->eigenQuat1.x());
    ASSERT_EQ(testQuat1.y(),this->eigenQuat1.y());
    ASSERT_EQ(testQuat1.z(),this->eigenQuat1.z());

    // Constructor of quaternion using real and imaginary part
    UnitQuaternion testQuat2(this->eigenQuat1.w(),typename UnitQuaternion::Imaginary(this->eigenQuat1.x(), this->eigenQuat1.y(), this->eigenQuat1.z()));
    ASSERT_EQ(testQuat2.w(),this->eigenQuat1.w());
    ASSERT_EQ(testQuat2.x(),this->eigenQuat1.x());
    ASSERT_EQ(testQuat2.y(),this->eigenQuat1.y());
    ASSERT_EQ(testQuat2.z(),this->eigenQuat1.z());
    ASSERT_EQ(testQuat2.real(),this->eigenQuat1.w());
    ASSERT_EQ(testQuat2.imaginary()(0),this->eigenQuat1.x());
    ASSERT_EQ(testQuat2.imaginary()(1),this->eigenQuat1.y());
    ASSERT_EQ(testQuat2.imaginary()(2),this->eigenQuat1.z());

    // Constructor of quaternion using eigen quaternion
    UnitQuaternion testQuat3(this->eigenQuat1);
    ASSERT_EQ(testQuat3.w(),this->eigenQuat1.w());
    ASSERT_EQ(testQuat3.x(),this->eigenQuat1.x());
    ASSERT_EQ(testQuat3.y(),this->eigenQuat1.y());
    ASSERT_EQ(testQuat3.z(),this->eigenQuat1.z());
}
示例#11
0
UnitQuaternion&
	UnitQuaternion::FastLerp(
		const UnitQuaternion& p, 
		const UnitQuaternion& q, 
		Scalar t
	)
{


	if (!UseFastLerp)
		return Lerp(p,q,t);


	Start_Timer(SlerpTime);

	Set_Statistic(SlerpCount, SlerpCount+1);

	Verify(quaternionFastLerpTableBuilt);

	Scalar cosom,sclp,sclq;
	
	cosom = p.x*q.x + p.y*q.y + p.z*q.z + p.w*q.w;


	if ( (1.0f + cosom) > 0.01f)
	{
		// usual case 
	

		
		if ( (1.0f - cosom) > 0.00001f ) 
		{ 
			//usual case
			
			

			//table_entry = (int)Scaled_Float_To_Bits(cosom, MinCosom, MaxCosom, 10);


			float tabled_float =  cosom - MinCosom;
			int cos_table_entry = Truncate_Float_To_Word(((tabled_float*CosomRangeOverOne) * CosBiggestNumber));
			
			Verify(cos_table_entry >= 0);
			Verify(cos_table_entry <= QuaternionLerpTableSize);


#if 0
			sclp = Sin((1.0f - t)*Omega_Table[cos_table_entry]) * SinomOverOne_Table[cos_table_entry];
			sclq = Sin(t*Omega_Table[cos_table_entry]) * SinomOverOne_Table[cos_table_entry];
	
#else
		
			float difference, percent, lerped_sin;


			tabled_float =  ((1.0f - t)*Omega_Table[cos_table_entry]) - MinSin;
			int sclp_table_entry = Truncate_Float_To_Word(((tabled_float*SinRangeOverOne) * SinBiggestNumber));


			if (!(sclp_table_entry < SinTableSize))
			{
				Max_Clamp(sclp_table_entry, SinTableSize-1);
			}


			Verify(sclp_table_entry >= 0 && sclp_table_entry < SinTableSize);
			difference = tabled_float - (SinIncrement * sclp_table_entry);
			percent = difference / SinIncrement;
			int lerp_to_entry = sclp_table_entry + 1;
			Max_Clamp(lerp_to_entry, SinTableSize-1);
			lerped_sin = Stuff::Lerp(Sin_Table[sclp_table_entry], Sin_Table[lerp_to_entry], percent);
			sclp = lerped_sin * SinomOverOne_Table[cos_table_entry];



			tabled_float =  (t*Omega_Table[cos_table_entry]) - MinSin;
			int sclq_table_entry = Truncate_Float_To_Word(((tabled_float*SinRangeOverOne) * SinBiggestNumber));
			Verify(sclq_table_entry >= 0 && sclq_table_entry < SinTableSize);
			difference = tabled_float - (SinIncrement * sclq_table_entry);
			percent = difference / SinIncrement;
			lerp_to_entry = sclq_table_entry + 1;
			Max_Clamp(lerp_to_entry, SinTableSize-1);
			lerped_sin = Stuff::Lerp(Sin_Table[sclq_table_entry], Sin_Table[lerp_to_entry], percent);
			sclq = lerped_sin * SinomOverOne_Table[cos_table_entry];
#endif
			
		}
		else 
		{ 
			// ends very close -- just lerp
			sclp = 1.0f - t;
			sclq = t;

			
		}


		x = sclp*p.x + sclq*q.x;
		y = sclp*p.y + sclq*q.y;
		z = sclp*p.z + sclq*q.z;
		w = sclp*p.w + sclq*q.w;

		
	}
	else 
	{



		//SPEW(("jerryeds","SPECIAL CASE"));
		/* p and q nearly opposite on sphere-- this is a 360 degree
		   rotation, but the axis of rotation is undefined, so
		   slerp really is undefined too.  So this apparently picks 
		   an arbitrary plane of rotation. However, I think this 
		   code is incorrect.
		   */

		//really we want the shortest distance.  They are almost on top of each other.
	
		UnitQuaternion r;
		r.Subtract(q, p);

		Vector3D scaled_rotation;
		scaled_rotation = r;
		scaled_rotation *= t;
		UnitQuaternion scaled_quat;
		scaled_quat = scaled_rotation;

		Multiply(scaled_quat, p);

		Normalize();

	}


	Stop_Timer(SlerpTime);

	return *this;

}
示例#12
0
UnitQuaternion &UnitQuaternion::Lerp(const UnitQuaternion& p, const UnitQuaternion& q, Scalar t)
{

	Start_Timer(SlerpTime);

	Set_Statistic(SlerpCount, SlerpCount+1);

	Scalar omega,cosom,sinom,sclp,sclq;
	//UnitQuaternion qt;


	//UnitQuaternion q = q_temp;
	//UnitQuaternion p = p_temp;

	cosom = p.x*q.x + p.y*q.y + p.z*q.z + p.w*q.w;


	if ( (1.0f + cosom) > 0.01f)
	{
		// usual case 
	
		
		if ( (1.0f - cosom) > 0.00001f ) 
		{ 
			//usual case 
			omega = Arccos(cosom);
			sinom = Sin(omega);
			
			//SPEW(("jerryeds","omega:%f sinom:%f", omega, sinom));

			sclp = Sin((1.0f - t)*omega) / sinom;
			sclq = Sin(t*omega) / sinom;
		
			//SPEW(("jerryeds", "* %f %f", sclp, sclq));
		}
		else 
		{ 
			// ends very close -- just lerp
			sclp = 1.0f - t;
			sclq = t;

			//SPEW(("jerryeds", "# %f %f", sclp, sclq));
		}


		x = sclp*p.x + sclq*q.x;
		y = sclp*p.y + sclq*q.y;
		z = sclp*p.z + sclq*q.z;
		w = sclp*p.w + sclq*q.w;

		//SPEW(("jerryeds", "r:<%f,%f,%f,%f>",x,y,z,w));
	}
	else 
	{
		//SPEW(("jerryeds","SPECIAL CASE"));
		/* p and q nearly opposite on sphere-- this is a 360 degree
		   rotation, but the axis of rotation is undefined, so
		   slerp really is undefined too.  So this apparently picks 
		   an arbitrary plane of rotation. However, I think this 
		   code is incorrect.
		   */

		//really we want the shortest distance.  They are almost on top of each other.

		UnitQuaternion r;
		r.Subtract(q, p);

		Vector3D scaled_rotation;
		scaled_rotation = r;
		scaled_rotation *= t;
		UnitQuaternion scaled_quat;
		scaled_quat = scaled_rotation;

		Multiply(scaled_quat, p);

	}

	Stop_Timer(SlerpTime);

	return *this;
}
示例#13
0
 Rotation3D::Rotation(const UnitQuaternion& q) {
     // quaternion to rotation conversion
     // http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToMatrix/
     // http://en.wikipedia.org/wiki/Rotation_group_SO(3)#Quaternions_of_unit_norm
     *this << 1 - 2 * q.kY() * q.kY() - 2 * q.kZ() * q.kZ() << 2 * q.kX() * q.kY() - 2 * q.kZ() * q.kW()
           << 2 * q.kX() * q.kZ() + 2 * q.kY() * q.kW() << arma::endr
           << 2 * q.kX() * q.kY() + 2 * q.kZ() * q.kW() << 1 - 2 * q.kX() * q.kX() - 2 * q.kZ() * q.kZ()
           << 2 * q.kY() * q.kZ() - 2 * q.kX() * q.kW() << arma::endr
           << 2 * q.kX() * q.kZ() - 2 * q.kY() * q.kW() << 2 * q.kY() * q.kZ() + 2 * q.kX() * q.kW()
           << 1 - 2 * q.kX() * q.kX() - 2 * q.kY() * q.kY();
 }
 UnitQuaternion UnitQuaternion::i() const {
 	UnitQuaternion qi = *this;
     // take the congugate, as it is equal to the inverse when a unit vector
 	qi.imaginary() *= -1;
 	return qi;
 }
 UnitQuaternion UnitQuaternion::operator - (const UnitQuaternion& p) const {
     return *this * p.i();
 }
 arma::vec3 UnitQuaternion::rotateVector(const arma::vec3& v) const {
 	UnitQuaternion vRotated = *this * UnitQuaternion(v) * i();
     return vRotated.imaginary();
 }