![]() |
TAPs 0.7.7.3
|
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----+----