TAPs 0.7.7.3
TAPsQuaternion.cpp
Go to the documentation of this file.
00001 /******************************************************************************
00002 TAPsQuaternion.cpp
00003 
00004 Quaternion class (cpp file).
00005 
00006 SUKITTI PUNAK   (07/12/2009)
00007 UPDATE          (08/20/2010)
00008 ******************************************************************************/
00009 #include "TAPsQuaternion.hpp"
00010 // Using Inclusion Model (i.e. definitions are included in declarations)
00011 //                       (this name.cpp is included in name.hpp)
00012 // Each friend is defined directly inside its declaration.
00013 
00014 BEGIN_NAMESPACE_TAPs
00015 //=============================================================================
00016 
00017 // Default Constructor
00018 template <typename T>
00019 Quaternion<T>::Quaternion ()
00020     : m_r( 1 ), m_i( 0 ), m_j( 0 ), m_k( 0 )
00021 {}
00022 
00023 // Initialize Constructor
00024 template <typename T>
00025 Quaternion<T>::Quaternion ( T r, T i, T j, T k )
00026     : m_r( r ), m_i( i ), m_j( j ), m_k( k )
00027 {}
00028 
00029 // Initialize Constructor
00030 template <typename T>
00031 Quaternion<T>::Quaternion ( T q[4] )
00032     : m_r( q[0] ), m_i( q[1] ), m_j( q[2] ), m_k( q[3] )
00033 {}
00034 
00035 // Initialize Constructor
00036 template <typename T>
00037 Quaternion<T>::Quaternion ( Vector3<T> const & P )
00038     : m_r( 0 ), m_i( P[1] ), m_j( P[2] ), m_k( P[3] )
00039 {}
00040 
00041 // Copy Constructor
00042 template <typename T>
00043 Quaternion<T>::Quaternion ( Quaternion<T> const &Q )
00044     : m_r( Q.m_r ), m_i( Q.m_i ), m_j( Q.m_j ), m_k( Q.m_k )
00045 {}
00046 
00047 // Destructor
00048 template <typename T>
00049 Quaternion<T>::~Quaternion ()
00050 {}
00051 
00052 // String Info
00053 template <typename T>
00054 std::string Quaternion<T>::StrInfo () const
00055 {
00056     std::ostringstream ss;
00057     ss << "Quaternion<" << typeid(T).name() << ">< ";
00058     ss << m_r << ", " << m_i << "i, " << m_j << "j, " << m_k << "k >";
00059     return ss.str();
00060 }
00061 
00062 // Conjugate Operator
00063 template <typename T>
00064 Quaternion<T> Quaternion<T>::operator! ()
00065 {   
00066     return Quaternion( m_r, -m_i, -m_j, -m_k );
00067 }
00068 
00069 // Conjugated
00070 template <typename T>
00071 void Quaternion<T>::Conjugated ()
00072 {
00073     m_i=-m_i;  m_j=-m_j;  m_k=-m_k;
00074 }
00075 
00076 // Get Conjugate
00077 template <typename T>
00078 Quaternion<T> Quaternion<T>::GetConjugate () const
00079 {   
00080     return Quaternion<T>( m_r, -m_i, -m_j, -m_k );
00081 }
00082 
00083 // Assignment Operator
00084 template <typename T>
00085 Quaternion<T> & Quaternion<T>::operator= ( Quaternion<T> const &Q )
00086 {   
00087     m_r=Q.m_r;  m_i=Q.m_i;  m_j=Q.m_j;  m_k=Q.m_k;
00088     return *this;
00089 }
00090 
00091 // Addition Operator
00092 template <typename T>
00093 Quaternion<T> Quaternion<T>::operator+ ( Quaternion<T> const &Q ) const
00094 {   
00095     return Quaternion<T>( m_r+Q.m_r, m_i+Q.m_i, m_j+Q.m_j, m_k+Q.m_k );
00096 }
00097 
00098 // Addition and Assignment Operator
00099 template <typename T>
00100 Quaternion<T> & Quaternion<T>::operator+= ( Quaternion<T> const &Q )
00101 {   
00102     m_r+=Q.m_r;  m_i+=Q.m_i;  m_j+=Q.m_j;  m_k+=Q.m_k;
00103     return *this;
00104 }
00105 
00106 // Subtraction Operator
00107 template <typename T>
00108 Quaternion<T> Quaternion<T>::operator- ( Quaternion<T> const &Q ) const
00109 {   
00110     return Quaternion<T>( m_r-Q.m_r, m_i-Q.m_i, m_j-Q.m_j, m_k-Q.m_k );
00111 }
00112 
00113 // Subtraction and Assignment Operator
00114 template <typename T>
00115 Quaternion<T> & Quaternion<T>::operator-= ( Quaternion<T> const &Q )
00116 {   
00117     m_r-=Q.m_r;  m_i-=Q.m_i;  m_j-=Q.m_j;  m_k-=Q.m_k;
00118     return *this;
00119 }
00120 
00121 // Multiplication Operator
00122 template <typename T>
00123 Quaternion<T> Quaternion<T>::operator* ( Quaternion<T> const &Q ) const
00124 {   
00125     return Quaternion<T>( 
00126         m_r*Q.m_r - m_i*Q.m_i - m_j*Q.m_j - m_k*Q.m_k,
00127         m_r*Q.m_i + m_i*Q.m_r + m_j*Q.m_k - m_k*Q.m_j,
00128         m_r*Q.m_j + m_j*Q.m_r + m_k*Q.m_i - m_i*Q.m_k,
00129         m_r*Q.m_k + m_k*Q.m_r + m_i*Q.m_j - m_j*Q.m_i
00130     );
00131 }
00132 
00133 // Multiplication Operator
00134 template <typename T>
00135 Quaternion<T> Quaternion<T>::operator* ( Vector3<T> const &V ) const
00136 {   
00137     return Quaternion<T>( 
00138         m_r*0     - m_i*V[0]  - m_j*V[1]  - m_k*V[2] ,
00139         m_r*V[0]  + m_i*0     + m_j*V[2]  - m_k*V[1] ,
00140         m_r*V[1]  + m_j*0     + m_k*V[0]  - m_i*V[2] ,
00141         m_r*V[2]  + m_k*0     + m_i*V[1]  - m_j*V[0] 
00142     );
00143 }
00144 
00146 template <typename T>
00147 T   Quaternion<T>::InnerProduct ( Quaternion<T> const &Q ) const
00148 {
00149     return m_r*Q.m_r + m_i*Q.m_i + m_j*Q.m_j + m_k*Q.m_k;
00150 }
00151 
00152 
00153 // Multiplication and Assignment Operator
00154 template <typename T>
00155 Quaternion<T> & Quaternion<T>::operator*= ( Quaternion<T> const &Q )
00156 {   
00157     T r = m_r*Q.m_r - m_i*Q.m_i - m_j*Q.m_j - m_k*Q.m_k;
00158     T i = m_r*Q.m_i + m_i*Q.m_r + m_j*Q.m_k - m_k*Q.m_j;
00159     T j = m_r*Q.m_j + m_j*Q.m_r + m_k*Q.m_i - m_i*Q.m_k;
00160     T k = m_r*Q.m_k + m_k*Q.m_r + m_i*Q.m_j - m_j*Q.m_i;
00161     m_r=r;  m_i=i;  m_j=j;  m_k=k;
00162     return *this;
00163 }
00164 
00165 // Multiplication Operator
00166 template <typename T>
00167 Quaternion<T> Quaternion<T>::operator* ( T a ) const
00168 {   
00169     return Quaternion<T>( m_r*a, m_i*a, m_j*a, m_k*a );
00170 }
00171 
00172 // Multiplication and Assignment Operator
00173 template <typename T>
00174 Quaternion<T> & Quaternion<T>::operator*= ( T a )
00175 {   
00176     m_r*=a;  m_i*=a;  m_j*=a;  m_k*=a;
00177     return *this;
00178 }
00179 
00180 // Get the square of norm
00181 template <typename T>
00182 T Quaternion<T>::GetNormSquare () const
00183 {
00184     return m_r*m_r + m_i*m_i + m_j*m_j + m_k*m_k;
00185 }
00186 
00187 // Get the norm
00188 template <typename T>
00189 T Quaternion<T>::GetNorm () const
00190 {
00191     return sqrt( GetNormSquare() );
00192 }
00193 
00194 // Normalized
00195 template <typename T>
00196 Quaternion<T> & Quaternion<T>::Normalized ()
00197 {
00198     T norm = GetNorm();
00199     m_r /= norm;  m_i /= norm;  m_j /= norm;  m_k /= norm;
00200     return *this;
00201 }
00202 
00203 // Get inverse
00204 template <typename T>
00205 Quaternion<T> Quaternion<T>::GetInverse () const
00206 {
00207     T normSqrt = GetNormSquare();
00208     return Quaternion( m_r/normSqrt, -m_i/normSqrt, -m_j/normSqrt, -m_k/normSqrt );
00209 }
00210 
00211 // Inversed
00212 template <typename T>
00213 void Quaternion<T>::Inversed ()
00214 {
00215     Conjugated();
00216     Normalized();
00217 }
00218 
00219 // Get the 3x3 rotation matrix from this quaternion
00220 template <typename T>
00221 Matrix3x3<T> Quaternion<T>::GetRotationMatrix3x3 () const
00222 {
00223     T rr = m_r*m_r;
00224     T ii = m_i*m_i;
00225     T jj = m_j*m_j;
00226     T kk = m_k*m_k;
00227     T ri = m_r*m_i;
00228     T rj = m_r*m_j;
00229     T rk = m_r*m_k;
00230     T ij = m_i*m_j;
00231     T jk = m_j*m_k;
00232     T ik = m_i*m_k;
00233 
00234     // Ref: Schwab, Meijaard, "How to draw Euler angles and utilize 
00235     //      Euler parameters, ASME, 2006.
00236     // Remark: Works only for a unit quaternion, i.e. when r^2+i^2+j^2+k^2=1.
00237     return Matrix3x3<T>( 
00238             rr+ii-jj-kk,    2*(ij-rk),    2*(ik+rj),
00239               2*(ij+rk),  rr-ii+jj-kk,    2*(jk-ri),
00240               2*(ik-rj),    2*(jk+ri),  rr-ii-jj+kk
00241         );
00242 
00243     // Ref: Shoemake, "Animating rotation with quaternion curves", SIGGRAPH, 1985.
00244     // Remark: Works only for a unit quaternion, i.e. when r^2+i^2+j^2+k^2=1.
00245     //return Matrix3x3<T>( 
00246     //      1-2*jj-2*kk,      ij2-rk2,      ik2+rj2,
00247     //          ij2+rk2,  1-2*ii-2*kk,      jk2-ri2,
00248     //          ik2-rj2,      jk2+ri2,  1-2*ii-2*jj
00249     //  );
00250 }
00251 
00252 // Get the 4x4 rotation matrix from this quaternion
00253 template <typename T>
00254 Matrix4x4<T> Quaternion<T>::GetRotationMatrix4x4 () const
00255 {
00256     T rr = m_r*m_r;
00257     T ii = m_i*m_i;
00258     T jj = m_j*m_j;
00259     T kk = m_k*m_k;
00260     T ri = m_r*m_i;
00261     T rj = m_r*m_j;
00262     T rk = m_r*m_k;
00263     T ij = m_i*m_j;
00264     T jk = m_j*m_k;
00265     T ik = m_i*m_k;
00266 
00267     // Ref: Schwab, Meijaard, "How to draw Euler angles and utilize 
00268     //      Euler parameters, ASME, 2006.
00269     // Remark: Works only for a unit quaternion, i.e. when r^2+i^2+j^2+k^2=1.
00270     return Matrix4x4<T>( 
00271             rr+ii-jj-kk,    2*(ij-rk),    2*(ik+rj),  0,
00272               2*(ij+rk),  rr-ii+jj-kk,    2*(jk-ri),  0,
00273               2*(ik-rj),    2*(jk+ri),  rr-ii-jj+kk,  0,
00274                  0,            0,            0,       1
00275         );
00276 }
00277 
00278 // Conversion from a 3x3 rotation matrix
00279 template <typename T>
00280 void Quaternion<T>::SetByRotationMatrix3x3 ( Matrix3x3<T> const & R3x3 )
00281 {
00282     // Converse rotation matrix to Euler rotation axis and angle
00283     //  Ref: http://en.wikipedia.org/wiki/Rotation_representation_%28mathematics%29
00284     T rotationAngle = acos( (R3x3(0,0) + R3x3(1,1) + R3x3(2,2) - 1)*0.5 );
00285     T s2 = 2 * sin( rotationAngle );
00286     Vector3<T> rotationAxis(
00287         ( R3x3(2,1) - R3x3(1,2) ) / s2,
00288         ( R3x3(0,2) - R3x3(2,0) ) / s2,
00289         ( R3x3(1,0) - R3x3(0,1) ) / s2
00290     );
00291 
00292     // Converse Euler rotation axis and angle to quaternion
00293     Vector3<T> axis( rotationAxis.GetUnit() );
00294     T halfAngle = rotationAngle * T(0.5);
00295     m_r = cos( halfAngle );
00296     T s = sin( halfAngle );
00297     m_i = axis[0] * s;
00298     m_j = axis[1] * s;
00299     m_k = axis[2] * s;
00300 }
00301 
00302 /*
00303 // Conversion from a 3x3 rotation matrix
00304 template <typename T>
00305 void Quaternion<T>::SetFromRotationMatrix3x3 ( Matrix3x3<T> const & R3x3 )
00306 {
00309     //m_r = 0.5 * sqrt( 1 + R3x3(0,0) - R3x3(1,1) - R3x3(2,2) );
00310     //T r4 = 4*m_r;
00311     //m_i = ( R3x3(0,1) - R3x3(1,0) ) / r4;
00312     //m_j = ( R3x3(0,2) - R3x3(2,0) ) / r4;
00313     //m_k = ( R3x3(2,1) - R3x3(1,2) ) / r4;
00314     //Normalized();
00315 
00316     //return;
00317 
00318     // Does not work well for a lot of cases!
00319 
00320     // Ref: Shoemake, "Animating rotation with quaternion curves", SIGGRAPH, 1985.
00321 
00322     // Remark: 
00323     //   From testing conversions from Quaternion<double> to 
00324     //   Matrix3x3<double> and back to Quaternion<double>:
00325     //     Case 1 works very well, since the square of the real value is greater 
00326     //     than the round-off error.
00327     //     Case 2, 3, and 4 don't work at all!
00328     //       where Case 2 sets the m_r to zero.
00329     //       where Case 3 sets the m_r and m_i to zero.
00330     //       where Case 4 sets the m_r, m_i, and m_j to zero and m_k to one.
00331 
00332     T rr = 0.25 * ( 1 + R3x3(0,0) + R3x3(1,1) + R3x3(2,2) );
00333     // Case r^2 > \epsilon; where \epsilon is (the machine precision) of zero.
00334     if ( rr > Math<T>::ROUND_ERROR ) {
00335         //std::cout << "Case 1\n";
00336 
00338         //  Here we choose to get a quaternion with positive real part from this conversion.
00339         //  If we choose the real part to be negative, then the vector part of the quaternion 
00340         //  will be the conjugated of the quaternion with the positive real part.
00341         //  That means the vector, which is an axis of rotation, is reversed.
00342         m_r = sqrt( rr );
00343         T r4 = 4*m_r;
00344         m_i = ( R3x3(2,1) - R3x3(1,2) ) / r4;   // In the Shoemake's paper --> R3x3(1,2)-R3x3(2,1)
00345         m_j = ( R3x3(0,2) - R3x3(2,0) ) / r4;   // In the Shoemake's paper --> R3x3(2,0)-R3x3(0,2)
00346         m_k = ( R3x3(1,0) - R3x3(0,1) ) / r4;   // In the Shoemake's paper --> R3x3(0,1)-R3x3(1,0)
00347                                                 // However, after the tests, these have to be swapped.
00348     }
00349     // Case r^2 <= \epsilon, i.e., r^2 is considered to be zero by the m/c precision.
00350     else {
00351         //std::cout << "Case 2\n";
00352         m_r = 0;
00353         T ii = -0.5 * ( R3x3(1,1) + R3x3(2,2) );
00354         if ( ii > Math<T>::ROUND_ERROR ) {
00355             m_i = sqrt( ii );
00356             T i2 = 2*m_i;
00357             m_j = R3x3(0,1) / i2;
00358             m_k = R3x3(0,2) / i2;
00359         }
00360         else {
00361             //std::cout << "Case 3\n";
00362             m_i = 0;
00363             T jj = 0.5 * ( 1 - R3x3(2,2) );
00364             if ( jj > Math<T>::ROUND_ERROR ) {
00365                 m_j = sqrt( jj );
00366                 m_k = R3x3(1,2) / (2*m_j);
00367             }
00368             else {
00369                 //std::cout << "Case 4\n";
00370                 m_j = 0;
00371                 m_k = 1;
00372             }
00373         }
00374     }
00375 }
00376 //*/
00377 
00378 // Get the quaternion matrix
00379 template <typename T>
00380 Matrix4x4<T> Quaternion<T>::GetQuaternionMatrix () const
00381 {
00382     return Matrix4x4<T>(
00383         m_r, -m_i, -m_j, -m_k,
00384         m_i,  m_r, -m_k,  m_j,
00385         m_j,  m_k,  m_r, -m_i,
00386         m_k, -m_j,  m_i,  m_r
00387     );
00388 }
00389 
00390 // Get the quaternion conjugate matrix
00391 template <typename T>
00392 Matrix4x4<T> Quaternion<T>::GetQuaternionConjugateMatrix () const
00393 {
00394     return Matrix4x4<T>(
00395         m_r, -m_i, -m_j, -m_k,
00396         m_i,  m_r,  m_k, -m_j,
00397         m_j, -m_k,  m_r,  m_i,
00398         m_k,  m_j, -m_i,  m_r
00399     );
00400 }
00401 
00403 template <typename T>
00404 void Quaternion<T>::SetByRotationAxisAndAngle ( Vector3<T> const & rotAxis, T angle )
00405 {
00406     Vector3<T> axis( rotAxis.GetUnit() );
00407     T halfAngle = angle * T(0.5) * Math<T>::DEG_TO_RAD;
00408     m_r = cos( halfAngle );
00409     T s = sin( halfAngle );
00410     m_i = axis[0] * s;
00411     m_j = axis[1] * s;
00412     m_k = axis[2] * s;
00413     //Normalized();
00414 }
00415 
00417 template <typename T>
00418 void Quaternion<T>::SetByRotationAxisAndAngle ( T rotAxis_x, T rotAxis_y, T rotAxis_z, T angle )
00419 {
00420     SetByRotationAxisAndAngle( Vector3<T>( rotAxis_x, rotAxis_y, rotAxis_z ), angle );
00421 }
00422 
00424 template <typename T>
00425 void Quaternion<T>::GetRotationAxisAndAngle ( Vector3<T> & rotAxis, T & angle )
00426 {
00427     angle = 2 * acos( m_r );
00428     if ( angle != 0 ) {
00429         T s = T(1) / sqrt(1 - m_r*m_r);
00430         rotAxis[0] = m_i * s;
00431         rotAxis[1] = m_j * s;
00432         rotAxis[2] = m_k * s;
00433     }
00434     angle *= Math<T>::RAD_TO_DEG;
00435 }
00436 
00438 template <typename T>
00439 void Quaternion<T>::GetRotationAxisAndAngle ( T& rotAxis_x, T& rotAxis_y, T& rotAxis_z, T& angle )
00440 {
00441     angle = 2 * acos( m_r );
00442     if ( angle != 0 ) {
00443         T s = T(1) / sqrt(1 - m_r*m_r);
00444         rotAxis_x = m_i * s;
00445         rotAxis_y = m_j * s;
00446         rotAxis_z = m_k * s;
00447     }
00448     angle *= Math<T>::RAD_TO_DEG;
00449 }
00450 
00452 template <typename T>
00453 void Quaternion<T>::RotatePt ( Vector3<T> & P ) const
00454 {
00455     Quaternion<T> R( (*this) * Quaternion<T>(P) * this->GetConjugate() );
00456     P[0] = R.m_i;
00457     P[1] = R.m_j;
00458     P[2] = R.m_k;
00459 }
00460 
00462 template <typename T>
00463 void Quaternion<T>::RotatePt ( T & P_x, T & P_y, T & P_z ) const
00464 {
00465     Quaternion<T> R( (*this) * Quaternion<T>(0,P_x,P_y,P_z) * this->GetConjugate() );
00466     P[0] = R.m_i;
00467     P[1] = R.m_j;
00468     P[2] = R.m_k;
00469 }
00470 
00472 template <typename T>
00473 Vector3<T> Quaternion<T>::CalRotatedPtOfPt ( Vector3<T> const & P ) const
00474 {
00475     Quaternion<T> R( (*this) * Quaternion<T>(P) * this->GetConjugate() );
00476     return Vector3<T>( R.m_i, R.m_j, R.m_k );
00477 }
00478 
00480 template <typename T>
00481 Vector3<T> Quaternion<T>::CalRotatedPtOfPt ( T P_x, T P_y, T P_z ) const
00482 {
00483     Quaternion<T> R( (*this) * Quaternion<T>(0,P_x,P_y,P_z) * this->GetConjugate() );
00484     return Vector3<T>( R.m_i, R.m_j, R.m_k );
00485 }
00486 
00487 
00488 //=============================================================================
00489 #if defined(__gl_h_) || defined(__GL_H__)
00490 //-----------------------------------------------------------------------------
00491 template <typename T>
00492 void Quaternion<T>::TransformByOpenGLForDrawing () const
00493 {
00494     Matrix4x4<T> orientation = GetRotationMatrix4x4();
00495     GLfloat m[16] = {
00496         static_cast<GLfloat>(orientation[ 0]), static_cast<GLfloat>(orientation[ 4]), static_cast<GLfloat>(orientation[ 8]), static_cast<GLfloat>(orientation[ 12]), 
00497         static_cast<GLfloat>(orientation[ 1]), static_cast<GLfloat>(orientation[ 5]), static_cast<GLfloat>(orientation[ 9]), static_cast<GLfloat>(orientation[ 13]), 
00498         static_cast<GLfloat>(orientation[ 2]), static_cast<GLfloat>(orientation[ 6]), static_cast<GLfloat>(orientation[10]), static_cast<GLfloat>(orientation[ 14]), 
00499         static_cast<GLfloat>(orientation[ 3]), static_cast<GLfloat>(orientation[ 7]), static_cast<GLfloat>(orientation[11]), static_cast<GLfloat>(orientation[ 15])
00500     };
00501     glMultMatrixf( m );
00502 }
00503 //-----------------------------------------------------------------------------
00504 #endif
00505 //=============================================================================
00506 
00507 //=============================================================================
00508 END_NAMESPACE_TAPs
00509 //34567890123456789012345678901234567890123456789012345678901234567890123456789
00510 //--+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines