Index: src/frames.hpp =================================================================== --- src/frames.hpp (revision 30002) +++ src/frames.hpp (working copy) @@ -391,6 +391,10 @@ //! the norm of (x,y,z,w) should be equal to 1 static Rotation Quaternion(double x,double y,double z, double w); + //! Get the quaternion of this matrix + //! \post the norm of (x,y,z,w) is 1 + void GetQuaternion(double& x,double& y,double& z, double& w); + //! Sets the value of this object to a rotation specified with RPY convention: //! first rotate around X with roll, then around the //! old Y with pitch, then around old Z with alfa Index: src/frames.cpp =================================================================== --- src/frames.cpp (revision 30002) +++ src/frames.cpp (working copy) @@ -187,6 +187,51 @@ 2*x*z-2*w*y, 2*y*z+2*w*x, w2-x2-y2+z2); } +/* From the following sources: +http://web.archive.org/web/20041029003853/http:/www.j3d.org/matrix_faq/matrfaq_latest.html +http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm +RobOOP::quaternion.cpp + */ +void Rotation::GetQuaternion(double& x,double& y,double& z, double& w) +{ + double trace = (*this)(0,0) + (*this)(1,1) + (*this)(2,2) + 1.0f; + if( trace > epsilon ) + { + double s = 0.5f / sqrt(trace); + w = 0.25f / s; + x = ( (*this)(2,1) - (*this)(1,2) ) * s; + y = ( (*this)(0,2) - (*this)(2,0) ) * s; + z = ( (*this)(1,0) - (*this)(0,1) ) * s; + } + else + { + if ( (*this)(0,0) > (*this)(1,1) && (*this)(0,0) > (*this)(2,2) ) + { + float s = 2.0f * sqrtf( 1.0f + (*this)(0,0) - (*this)(1,1) - (*this)(2,2)); + w = ((*this)(2,1) - (*this)(1,2) ) / s; + x = 0.25f * s; + y = ((*this)(0,1) + (*this)(1,0) ) / s; + z = ((*this)(0,2) + (*this)(2,0) ) / s; + } + else if ((*this)(1,1) > (*this)(2,2)) + { + float s = 2.0f * sqrtf( 1.0f + (*this)(1,1) - (*this)(0,0) - (*this)(2,2)); + w = ((*this)(0,2) - (*this)(2,0) ) / s; + x = ((*this)(0,1) + (*this)(1,0) ) / s; + y = 0.25f * s; + z = ((*this)(1,2) + (*this)(2,1) ) / s; + } + else + { + float s = 2.0f * sqrtf( 1.0f + (*this)(2,2) - (*this)(0,0) - (*this)(1,1) ); + w = ((*this)(1,0) - (*this)(0,1) ) / s; + x = ((*this)(0,2) + (*this)(2,0) ) / s; + y = ((*this)(1,2) + (*this)(2,1) ) / s; + z = 0.25f * s; + } + } +} + Rotation Rotation::RPY(double roll,double pitch,double yaw) { double ca1,cb1,cc1,sa1,sb1,sc1; Index: tests/framestest.cpp =================================================================== --- tests/framestest.cpp (revision 30002) +++ tests/framestest.cpp (working copy) @@ -151,7 +151,49 @@ TestRotation2(Vector(3,4,5),10*deg2rad,20*deg2rad,30*deg2rad); } +void FramesTest::TestQuaternion() { + Rotation R; + Rotation R2; + double x,y,z,w; + double x2,y2,z2,w2; + // identity R -> quat -> R2 + R.GetQuaternion(x,y,z,w); + R2.Quaternion(x,y,z,w); + CPPUNIT_ASSERT_EQUAL(R,R2); + + // 45 deg rotation in X + R = Rotation::EulerZYX(0,0,45*deg2rad); + R.GetQuaternion(x,y,z,w); + CPPUNIT_ASSERT_DOUBLES_EQUAL(x, sin((45*deg2rad)/2), epsilon); + CPPUNIT_ASSERT_DOUBLES_EQUAL(y, 0, epsilon); + CPPUNIT_ASSERT_DOUBLES_EQUAL(z, 0, epsilon); + CPPUNIT_ASSERT_DOUBLES_EQUAL(w, cos((45*deg2rad)/2), epsilon); + R2 = Rotation::Quaternion(x,y,z,w); + CPPUNIT_ASSERT_EQUAL(R,R2); + + // direct 45 deg rotation in X + R2 = Rotation::Quaternion(sin((45*deg2rad)/2), 0, 0, cos((45*deg2rad)/2)); + CPPUNIT_ASSERT_EQUAL(R,R2); + R2.GetQuaternion(x2,y2,z2,w2); + CPPUNIT_ASSERT_DOUBLES_EQUAL(x, x2, epsilon); + CPPUNIT_ASSERT_DOUBLES_EQUAL(y, y2, epsilon); + CPPUNIT_ASSERT_DOUBLES_EQUAL(z, z2, epsilon); + CPPUNIT_ASSERT_DOUBLES_EQUAL(w, w2, epsilon); + + // 45 deg rotation in X and in Z + R = Rotation::EulerZYX(45*deg2rad,0,45*deg2rad); + R.GetQuaternion(x,y,z,w); + R2 = Rotation::Quaternion(x,y,z,w); + CPPUNIT_ASSERT_EQUAL(R,R2); + R2.GetQuaternion(x2,y2,z2,w2); + CPPUNIT_ASSERT_DOUBLES_EQUAL(x, x2, epsilon); + CPPUNIT_ASSERT_DOUBLES_EQUAL(y, y2, epsilon); + CPPUNIT_ASSERT_DOUBLES_EQUAL(z, z2, epsilon); + CPPUNIT_ASSERT_DOUBLES_EQUAL(w, w2, epsilon); +} + + void FramesTest::TestFrame() { Vector v(3,4,5); Wrench w(Vector(7,-1,3),Vector(2,-3,3)) ; Index: tests/framestest.hpp =================================================================== --- tests/framestest.hpp (revision 30002) +++ tests/framestest.hpp (working copy) @@ -14,6 +14,7 @@ CPPUNIT_TEST(TestTwist); CPPUNIT_TEST(TestWrench); CPPUNIT_TEST(TestRotation); + CPPUNIT_TEST(TestQuaternion); CPPUNIT_TEST(TestFrame); CPPUNIT_TEST(TestJntArray); @@ -27,6 +28,7 @@ void TestTwist(); void TestWrench(); void TestRotation(); + void TestQuaternion(); void TestFrame(); void TestJntArray(); void TestJntArrayWhenEmpty();