ML Reference
MeVis/Foundation/Sources/MLLinearAlgebra/mlQuaternion.h
Go to the documentation of this file.
00001 // **InsertLicense** code 
00002 //----------------------------------------------------------------------------------
00014 //----------------------------------------------------------------------------------
00015 
00016 #ifndef __mlQuaternion_H
00017 #define __mlQuaternion_H
00018 
00019 // Resolves system dependencies and load project settings.
00020 #ifndef __mlLinearAlgebraSystem_H
00021 #include "mlLinearAlgebraSystem.h"
00022 #endif
00023 
00024 // 3D double vector.
00025 #ifndef __mlVector3_H
00026 #include "mlVector3.h"
00027 #endif
00028 
00029 
00030 ML_LA_START_NAMESPACE
00031 
00032 //--------------------------------------------------------
00036 //--------------------------------------------------------
00037 template <typename DT>
00038 class TQuaternion {
00039 
00040 public:
00041   //------------------------------------------------------
00043 
00044   //------------------------------------------------------
00045   union {
00046     // We use a union to make the members accessible
00047     // either
00048     // - as named members qx, qy, qz and qw,
00049     // - as array[0..3] and
00050     // - vector (qv,qw) via an access method qv().
00051     // We also provide indexing operators [] on the array.
00052     // Note:
00053     //   The real part qw is stored in the last component.
00054 
00055     //------------------------------------------------------
00058     //------------------------------------------------------
00059     struct {
00060       DT qx;  
00061       DT qy;  
00062       DT qz;  
00063       DT qw;  
00064     };
00065 
00066     //------------------------------------------------------
00073     //------------------------------------------------------
00074     DT array[4];
00075   };
00077 
00078 
00079   //------------------------------------------------------
00081 
00082   //------------------------------------------------------
00084   inline TQuaternion() :
00085     qx(0), qy(0), qz(0), qw(0) { }
00086 
00089   inline explicit TQuaternion(DT d) :
00090     qx(0), qy(0), qz(0), qw(d)
00091   {
00092     ML_TRACE_IN_TIME_CRITICAL("TQuaternion(DT d)");
00093   }
00094 
00099   template <typename DT2>
00100   inline explicit TQuaternion(const TQuaternion<DT2> &q2)
00101   {
00102     ML_TRACE_IN_TIME_CRITICAL("TQuaternion(const TQuaternion<DT2> &q2)");
00103 
00104     qx = static_cast<DT>(q2.qx);
00105     qy = static_cast<DT>(q2.qy);
00106     qz = static_cast<DT>(q2.qz);
00107     qw = static_cast<DT>(q2.qw);
00108   }
00109 
00117   inline explicit TQuaternion(DT x, DT y, DT z, DT w)
00118   {
00119     ML_TRACE_IN_TIME_CRITICAL("TQuaternion(DT x, DT y, DT z, DT w)");
00120 
00121     qx = x;
00122     qy = y;
00123     qz = z;
00124     qw = w;
00125   }
00126 
00135   inline explicit TQuaternion(const FloatingPointVector<DT,4> &v)
00136   {
00137     ML_TRACE_IN_TIME_CRITICAL("TQuaternion(const FloatingPointVector<DT,4> &v)");
00138     qx = v[1];
00139     qy = v[2];
00140     qz = v[3];
00141     qw = v[0];
00142   }
00143 
00148   inline explicit TQuaternion(const FloatingPointVector<DT, 3, Vector3DataContainer<DT> > &v, DT w) :
00149     qx(v[0]), qy(v[1]), qz(v[2]), qw(w)
00150   {
00151     ML_TRACE_IN_TIME_CRITICAL("TQuaternion(const FloatingPointVector<DT, 3> &v, DT w)");
00152   }
00153 
00155 
00156 
00157   //-------------------------------------------------------------------------
00159 
00160   //-------------------------------------------------------------------------
00161 
00164   inline FloatingPointVector<DT, 3, Vector3DataContainer<DT> > getImaginaryPart() const 
00165   { 
00166     return qv(); 
00167   }
00168 
00170   inline DT getRealPart() const 
00171   { 
00172     return qw; 
00173   }  
00174 
00182   inline const FloatingPointVector<DT, 3, Vector3DataContainer<DT> > &qv() const 
00183   { 
00184     return reinterpret_cast<const FloatingPointVector<DT, 3, Vector3DataContainer<DT> >&>(qx); 
00185   }
00186 
00191   inline FloatingPointVector<DT, 3, Vector3DataContainer<DT> > &qv()
00192   {
00193     return reinterpret_cast<FloatingPointVector<DT, 3, Vector3DataContainer<DT> >&>(qx); 
00194   }
00195 
00199   inline void  set(const FloatingPointVector<DT, 3, Vector3DataContainer<DT> > &v, const DT w)
00200   {
00201     ML_TRACE_IN_TIME_CRITICAL("TQuaternion::set(const FloatingPointVector<DT, 3> &v, const DT w)");
00202     
00203     qx = v[0];
00204     qy = v[1];
00205     qz = v[2];
00206     qw = w;
00207   }
00208 
00211   inline void  set(const DT x, const DT y, const DT z, const DT w)
00212   {
00213     ML_TRACE_IN_TIME_CRITICAL("TQuaternion::set(const DT x, const DT y, const DT z, const DT w)");
00214     
00215     qx = x;
00216     qy = y;
00217     qz = z;
00218     qw = w;
00219   }
00220 
00226   inline Tmat4<DT> getAsMat4(bool *isConvertible=NULL) const
00227   {
00228     ML_TRACE_IN("TQuaternion::getAsMat4() const");
00229 
00230     // Create return value.
00231     Tmat4<DT> m;
00232     ML_TRY
00233     {
00234       // Check whether conversion is possible.
00235       const DT n=norm();
00236       if (0==n) {
00237         if (!isConvertible){
00238           ML_PRINT_ERROR("TQuaternion::getAsMat4() const, quaternion is not convertible to 4x4 matrix",
00239                          ML_BAD_PARAMETER,
00240                          "Returning Quaterion");
00241         }
00242         else{
00243           *isConvertible = false;
00244         }
00245         m = Tmat4<DT>::getIdentity();
00246       }
00247       else{
00248         // Conversion is possible.
00249         const DT s = 2./n;
00250         //s is a compressed factor
00251         //it originates from the constant factor 2 and the normalization
00252         //factor for the vector "1/sqrt(norm(vector))"
00253         //To normalize the vector each component is divided by "1/sqrt(norm(vector))"
00254         //So each vector component qx,qy,qz has to get its own factor to normalize
00255         //the vector while calculating the matrix. However, as s is multiplied
00256         //always to a pair of 2 multiplied vector components, the factor can be
00257         //pulled in front of the addition (c.f. m11). As pairs of vector components
00258         //are added, the sqrt vanishes and what is left is the factor 2./norm(vector)
00259         //where norm is what is defined as "norm()" inside the mlQuaternion.h.
00260 
00261         // q0 = qw, first column.
00262         const DT qxqx = qx*qx;
00263         const DT qyqy = qy*qy;
00264         const DT qzqz = qz*qz;
00265 
00266         const DT qxqy = qx*qy;
00267         const DT qxqz = qx*qz;
00268         const DT qxqw = qx*qw;
00269 
00270         const DT qyqz = qy*qz;
00271         const DT qyqw = qy*qw;
00272 
00273         const DT qzqw = qz*qw;
00274 
00275         const DT m11 = 1 - s * (qyqy + qzqz);
00276         const DT m12 =     s * (qxqy - qzqw);
00277         const DT m13 =     s * (qxqz + qyqw);
00278 
00279         const DT m21 =     s * (qxqy + qzqw);
00280         const DT m22 = 1 - s * (qxqx + qzqz);
00281         const DT m23 =     s * (qyqz - qxqw);
00282 
00283         const DT m31 =     s * (qxqz - qyqw);
00284         const DT m32 =     s * (qyqz + qxqw);
00285         const DT m33 = 1 - s * (qxqx + qyqy);
00286 
00287         // Construct matrix from precomputed values
00288         m.set(0);
00289         m[0][0] = m11;
00290         m[0][1] = m12;
00291         m[0][2] = m13;
00292         m[0][3] = 0.0;
00293 
00294         m[1][0] = m21;
00295         m[1][1] = m22;
00296         m[1][2] = m23;
00297         m[1][3] = 0.0;
00298 
00299         m[2][0] = m31;
00300         m[2][1] = m32;
00301         m[2][2] = m33;
00302         m[2][3] = 0.0;
00303 
00304         m[3][0] = 0.0;
00305         m[3][1] = 0.0;
00306         m[3][2] = 0.0;
00307         m[3][3] = 1.0;
00308 
00309         if (isConvertible){ *isConvertible = true; }
00310 
00311       } // else
00312 
00313     }
00314     ML_CATCH_RETHROW;
00315     return m;
00316   }
00317 
00319 
00320 
00321   //-------------------------------------------------------------------------
00323 
00324   //-------------------------------------------------------------------------
00325 
00329   inline DT operator[](const size_t i) const { return array[i]; }
00330 
00334   inline DT &operator[](const size_t i)      { return array[i]; }
00335 
00337   inline TQuaternion<DT> &operator=(const TQuaternion<DT> &q)
00338   {
00339     if (this != &q){
00340       qx = q.qx;
00341       qy = q.qy;
00342       qz = q.qz;
00343       qw = q.qw;
00344     }
00345     return *this;
00346   }
00348 
00349 
00350   //------------------------------------------------------
00352 
00353   //------------------------------------------------------
00354 
00356   inline TQuaternion<DT>  operator +   (const TQuaternion<DT> &b) const { return TQuaternion<DT>(qx+b.qx, qy+b.qy, qz+b.qz, qw+b.qw); }
00358   inline TQuaternion<DT> &operator +=  (const TQuaternion<DT> &b)       { qx+=b.qx; qy+=b.qy; qz+=b.qz; qw+=b.qw; return *this;       }
00359 
00361   inline TQuaternion<DT>  operator -   (const TQuaternion<DT> &b) const { return TQuaternion<DT>(qx-b.qx, qy-b.qy, qz-b.qz, qw-b.qw); }
00363   inline TQuaternion<DT> &operator -=  (const TQuaternion<DT> &b)       { qx-=b.qx; qy-=b.qy; qz-=b.qz; qw-=b.qw; return *this;       }
00364 
00366   inline TQuaternion<DT>  operator *   (const TQuaternion<DT> &b) const { return mult(b);                                             }
00368   inline TQuaternion<DT> &operator *=  (const TQuaternion<DT> &b)       { *this = mult(b); return *this;                              }
00369 
00371   inline TQuaternion<DT>  operator /   (DT d) const
00372   {
00373     ML_TRACE_IN("TQuaternion::operator/");
00374 
00375     TQuaternion<DT> retVal(*this);
00376     ML_TRY
00377     {
00378       ML_CHECK_FLOAT(d);
00379       retVal /= d;
00380     }
00381     ML_CATCH_RETHROW;
00382     return retVal;
00383   }
00384 
00386   inline TQuaternion<DT> &operator /=  (DT d)
00387   {
00388     ML_TRACE_IN("TQuaternion::operator/=");
00389     ML_TRY
00390     {
00391       ML_CHECK_FLOAT(d);
00392       qx/=d; qy/=d; qz/=d; qw/=d;
00393     }
00394     ML_CATCH_RETHROW;
00395     return *this;
00396   }
00397 
00398 
00400   inline TQuaternion<DT>  operator / (const TQuaternion<DT> &q) const
00401   {
00402     return TQuaternion<DT>(div(q));
00403   }
00404 
00409   inline TQuaternion<DT> compDiv(const TQuaternion<DT> &b, bool *isError=NULL) const
00410   {
00411     ML_TRACE_IN( "TQuaternion::compDiv/  " );
00412 
00413     // Initialize return value with default quaternion.
00414     TQuaternion<DT> retVal(0,0,0,1);
00415     ML_TRY
00416     {
00417       if (!isError){
00418         // No error flag passed. Handle error if necessary.
00419         ML_CHECK_FLOAT(b.qx);
00420         ML_CHECK_FLOAT(b.qy);
00421         ML_CHECK_FLOAT(b.qz);
00422         ML_CHECK_FLOAT(b.qw);
00423         retVal.set(qx/b.qx, qy/b.qy, qz/b.qz, qw/b.qw);
00424       }
00425       else{
00426         // Error flag is available. Return *isError as true in case of error
00427         *isError = (b.qx == 0) ||
00428                    (b.qy == 0) ||
00429                    (b.qz == 0) ||
00430                    (b.qw == 0);
00431 
00432         retVal = *isError ?
00433                     TQuaternion<DT>(b.qx != 0 ? qx/b.qx : qx,
00434                                     b.qy != 0 ? qy/b.qy : qy,
00435                                     b.qz != 0 ? qz/b.qz : qz,
00436                                     b.qw != 0 ? qw/b.qw : qw) :
00437                     TQuaternion<DT>(qx/b.qx,
00438                                     qy/b.qy,
00439                                     qz/b.qz,
00440                                     qw/b.qw);
00441       }
00442     }
00443     ML_CATCH_RETHROW;
00444     return retVal;
00445   }
00446 
00449   inline bool    operator ==  (const TQuaternion<DT> &b)          const { return MLValuesAreEqualWOM(qx, b.qx) && 
00450                                                                                  MLValuesAreEqualWOM(qy, b.qy) && 
00451                                                                                  MLValuesAreEqualWOM(qz, b.qz) && 
00452                                                                                  MLValuesAreEqualWOM(qw, b.qw); }
00455   inline bool    operator !=  (const TQuaternion<DT> &b)          const { return !operator==(b); }
00457 
00458 
00459 
00461   inline DT               dot(const TQuaternion<DT> &p)           const { return qx*p.qx + qy*p.qy + qz*p.qz + qw*p.qw; }
00462 
00465   inline TQuaternion<DT>  odd(const TQuaternion<DT> &p)           const { return TQuaternion<DT>(qy*p.qz - qz*p.qy,
00466                                                                                                  qz*p.qx - qx*p.qz,
00467                                                                                                  qx*p.qy - qy*p.qx,
00468                                                                                                  0); }
00469 
00472   inline TQuaternion<DT>  even(const TQuaternion<DT> &p)          const { return TQuaternion<DT>(qw*p.qx + qx*p.qw,
00473                                                                                                  qw*p.qy + qy*p.qw,
00474                                                                                                  qw*p.qz + qz*p.qw,
00475                                                                                                  qw*p.qw - qx*p.qx - qy*p.qy - qz*p.qz); }
00476 
00478   inline TQuaternion<DT>  mult(const TQuaternion<DT> &q)          const { Tvec3<DT> img(qv()); Tvec3<DT> qimg(q.qv()); return TQuaternion<DT>(img.cross(qimg) + img*q.qw + qw*qimg, qw*q.qw - img.dot(qimg)); }
00479 
00481   inline TQuaternion<DT>  euclideanMult(const TQuaternion<DT> &q) const { return conjugate().mult(q); }
00482 
00484   inline TQuaternion<DT>  outer(const TQuaternion<DT> &q)         const { return (euclideanMult(q) - q.euclideanMult(*this)) / 2; }
00485 
00486 
00495   inline TQuaternion<DT> div(const TQuaternion<DT> &d, bool *isError=NULL) const
00496   {
00497     ML_TRACE_IN("TQuaternion::div()");
00498 
00499     // Initialize return value with default quaternion.
00500     TQuaternion<DT> retVal(0,0,0,1);
00501     ML_TRY
00502     {
00503       if (d == TQuaternion<DT>(0,0,0,0)){
00504         if (isError == NULL){
00505           // No error flag passed. Handle error if necessary.
00506           ML_PRINT_ERROR("TQuaternion::div() const, quaternion is not divisible",
00507                          ML_BAD_PARAMETER,
00508                          "Returning unchanged quaternion");
00509           retVal.set(qx,qy,qz,qw);
00510         }
00511         else{
00512           // Error flag pointer is available. Return *isError as true in case of error
00513           *isError = true;
00514           retVal.set(qx,qy,qz,qw);
00515         }
00516       }
00517       else{
00518         if (isError != NULL){ *isError = false; }
00519         retVal.set((d.qw*qx - d.qx*qw - d.qy*qz + d.qz*qy)/(d.qw*d.qw + d.qx*d.qx + d.qy*d.qy + d.qz*d.qz),
00520                    (d.qw*qy + d.qx*qz - d.qy*qw - d.qz*qx)/(d.qw*d.qw + d.qx*d.qx + d.qy*d.qy + d.qz*d.qz),
00521                    (d.qw*qz - d.qx*qy + d.qy*qx - d.qz*qw)/(d.qw*d.qw + d.qx*d.qx + d.qy*d.qy + d.qz*d.qz),
00522                    (d.qw*qw + d.qx*qx + d.qy*qy + d.qz*qz)/(d.qw*d.qw + d.qx*d.qx + d.qy*d.qy + d.qz*d.qz));
00523       }
00524     }
00525     ML_CATCH_RETHROW;
00526     return retVal;
00527   }
00528 
00529 
00531   inline TQuaternion<DT>  mult(DT s)                              const { return TQuaternion<DT>(qx*s,  qy*s,  qz*s,  qw*s);             }
00532 
00534   inline TQuaternion<DT>  add(const TQuaternion<DT> &b)           const { return TQuaternion<DT>(qx+b.qx, qy+b.qy, qz+b.qz, qw+b.qw);    }
00535 
00537   inline TQuaternion<DT>  add(DT s)                               const { return TQuaternion<DT>(qx, qy, qz, qw+s);                      }
00538 
00540   inline TQuaternion<DT>  conjugate()                             const { return TQuaternion<DT>(-qx, -qy, -qz, qw);                     }
00541 
00543   inline TQuaternion<DT>  negate()                                const { return TQuaternion<DT>(-qx, -qy, -qz, -qw);                    }
00544 
00546   inline DT               norm()                                  const { return qx*qx + qy*qy + qz*qz + qw*qw;                          }
00547 
00548 
00551   inline DT               norm2()                                 const { return static_cast<DT>(::sqrt(qx*qx + qy*qy + qz*qz + qw*qw)); }
00552 
00555   inline DT               absoluteValue()                         const { return static_cast<DT>(::sqrt(norm()));                        }
00556 
00561   inline TQuaternion<DT> normalize(bool *isError=NULL) const
00562   {
00563     ML_TRACE_IN("TQuaternion::normalize()");
00564 
00565     // Initialize return value with default quaternion.
00566     TQuaternion<DT> retVal(0,0,0,1);
00567     ML_TRY
00568     {
00569       const DT n=norm2();
00570       if (MLValueIs0WOM(n)){
00571         // Error! Check whether we have a pointer to a return error code value.
00572         if (isError == NULL){
00573           // No, post an error.
00574           ML_PRINT_ERROR("TQuaternion::normalize() const, quaternion can not be normalized",
00575                          ML_BAD_PARAMETER,
00576                          "Returning default quaternion");
00577         }
00578         else{
00579           // Yes, set return code.
00580           *isError = true;
00581         }
00582       }
00583       else{
00584         // Non zero => no error.
00585         if (isError){ *isError = false; }
00586         retVal.set(qx/n, qy/n, qz/n, qw/n);
00587       }
00588     }
00589     ML_CATCH_RETHROW;
00590 
00591     return retVal;
00592   }
00593 
00600   inline TQuaternion<DT>  arg(bool *isError=NULL) const 
00601   {
00602     ML_TRACE_IN("TQuaternion::arg() const");
00603 
00604     // Initialize return value with default quaternion.
00605     TQuaternion<DT> retVal(0,0,0,1);
00606     ML_TRY
00607     {
00608       // Norm2 must be non-zero to avoid divisions by zero.
00609       const DT n=norm2();
00610       if (MLValueIs0WOM(n)){
00611         // Error! Check whether we have a pointer to a return error code value.
00612         if (isError == NULL){
00613           // No, post an error.
00614           ML_PRINT_ERROR("TQuaternion::arg() const, quaternion can not be normalized",
00615                          ML_BAD_PARAMETER,
00616                          "Returning default quaternion");
00617         }
00618         else{
00619           // Yes, set return code.
00620           *isError = true;
00621         }
00622       }
00623       else{
00624         // Non zero => no error.
00625         if (isError != NULL){ *isError = false; }
00626         retVal = acos(qw/n);
00627       }
00628     }
00629     ML_CATCH_RETHROW;
00630     return retVal;
00631   }
00632 
00637   inline TQuaternion<DT> sgn(bool *isError=NULL) const
00638   {
00639     ML_TRACE_IN("TQuaternion::sgn()");
00640 
00641     // Initialize return value with default quaternion.
00642     TQuaternion<DT> retVal(0,0,0,1);
00643     ML_TRY
00644     {
00645       const DT absVal = absoluteValue();
00646       if (isError != NULL){
00647         // Set error return value.
00648         if (absVal==0){
00649           *isError = true;
00650         }
00651         else{
00652           // No error.
00653           *isError = false;
00654           retVal = *this / absVal;
00655         }
00656       }
00657       else{
00658         // Post error is absVal == 0.
00659         ML_CHECK_FLOAT(absVal);
00660         retVal = *this / absVal;
00661       }
00662     }
00663     ML_CATCH_RETHROW;
00664     return retVal;
00665   }
00666 
00672   inline TQuaternion<DT> inverse(bool* isInvertible=NULL) const
00673   {
00674     ML_TRACE_IN("TQuaternion::inverse()");
00675 
00676     // Initialize return value with default quaternion.
00677     TQuaternion<DT> retVal(0,0,0,1);
00678     ML_TRY
00679     {
00680       const DT n=norm();
00681       if (MLValueIs0WOM(n)) {
00682         if (isInvertible==NULL){
00683           ML_PRINT_ERROR("TQuaternion::() const, quaternion is not invertable",
00684                          ML_BAD_PARAMETER,
00685                          "Returning default quaternion");
00686         }
00687         else{
00688           *isInvertible = false;
00689         }
00690         retVal = TQuaternion<DT>();
00691       }
00692       else{
00693         if (isInvertible != NULL){ *isInvertible = true; }
00694         retVal = conjugate().mult(1/n);
00695       }
00696     }
00697     ML_CATCH_RETHROW;
00698     return retVal;
00699   }
00700 
00706   // return TQuaternion(::sqrt(norm2())*::sin(0.5*acos(qw/norm2()))*(1/qv().length())*Tvec3<DT>(qx,qy,qz),
00707   inline TQuaternion<DT> sqrt(bool *isError=NULL)  const
00708   {
00709     ML_TRACE_IN("TQuaternion::sqrt() const");
00710 
00711     // Initialize return value with default quaternion.
00712     TQuaternion<DT> retVal(0,0,0,1);
00713     ML_TRY
00714     {
00715       // Precalculate constants and check for 0 division.
00716       const DT n2  = norm2();
00717       const DT lqv = qv().length();
00718       if (MLValueIs0WOM(n2) || MLValueIs0WOM(lqv)){
00719         // Error! Check whether we have a pointer to a return error code value.
00720         if (isError == NULL){
00721           // No, post an error.
00722           ML_PRINT_ERROR("TQuaternion::sqrt() const, sqrt of quaternion cannot be calculated",
00723                          ML_BAD_PARAMETER,
00724                          "Returning default quaternion");
00725         }
00726         else{
00727           // Yes, set return code.
00728           *isError = true;
00729         }
00730       }
00731       else{
00732         // Calculate sqrt, lqv and n2 are non 0 here.
00733         const DT sqrtSin  = ::sqrt(n2)*::sin(0.5*acos(qw/n2));
00734         const DT sqrtSinF = sqrtSin*(1/lqv);
00735         retVal.set(sqrtSinF*qx, sqrtSinF*qy, sqrtSinF*qz, ::sqrt(n2) * ::cos(0.5*acos(qw/n2)));
00736 
00737         // Non zero => no error.
00738         if (isError != NULL){ *isError = false; }
00739       }
00740     }
00741     ML_CATCH_RETHROW;
00742     return retVal;
00743   }
00744 
00745 
00750 
00752   inline TQuaternion<DT> exp() const
00753   {
00754     ML_TRACE_IN("TQuaternion::exp() const");
00755 
00756     // Initialize return value with default quaternion.
00757     TQuaternion<DT> retVal(0,0,0,1);
00758     ML_TRY
00759     {
00760       const DT len = qv().length();
00761       if (MLValueIs0WOM(len)){
00762         retVal = TQuaternion<DT>(0,0,0,::cos(len)).mult(::exp(qw));
00763       }
00764       else{
00765         retVal = TQuaternion<DT>((qv()/len) * static_cast<DT>(::sin(len)), ::cos(len)).mult(::exp(qw));
00766       }
00767     }
00768     ML_CATCH_RETHROW;
00769     return retVal;
00770   }
00771 
00772 
00774   inline TQuaternion<DT> ln() const
00775   {
00776     ML_TRACE_IN("TQuaternion::exp() const");
00777 
00778     // Initialize return value with default quaternion.
00779     TQuaternion<DT> retVal(0,0,0,1);
00780     ML_TRY
00781     {
00782       const DT n2    = norm2();
00783       const DT qvLen = qv().length();
00784       if (MLValueIs0WOM(qvLen)){
00785         retVal.set(0, 0, 0, log10(n2));
00786       }
00787       else{
00788         // n2 is always non 0 if qvLen is non-zero, thus no check is necessary.
00789         retVal.set(qv()/qvLen * static_cast<DT>(acos(qw/n2)), log10(n2));
00790       }
00791     }
00792     ML_CATCH_RETHROW;
00793     return retVal;
00794   }
00795 
00796 
00798   inline TQuaternion<DT> pow(const TQuaternion<DT> &quat)      const {return ln().mult(quat).exp(); }
00799 
00800 
00805 
00807   TQuaternion<DT> sin() const
00808   {
00809     ML_TRACE_IN("TQuaternion<DT>::sinh() const");
00810 
00811     TQuaternion<DT> retVal;
00812     ML_TRY
00813     {
00814       const Tvec3<DT> &v  = qv();
00815       const DT        len = v.length();
00816       // In case of len == 0 be sure not to divide by zero but setting vector to 0 vector.
00817       // Then the quaternion method behaves like the normal function on real values.
00818       retVal.set((!MLValueIs0WOM(len) ?
00819                     static_cast<DT>(::cos(qw)) * v / len * static_cast<DT>(::sinh(len)) :
00820                     Tvec3<DT>(0.0)), 
00821                  ::sin(qw)*::cosh(len)
00822                 );
00823     }
00824     ML_CATCH_RETHROW;
00825     return retVal;
00826   }
00827 
00829   TQuaternion<DT> cos() const
00830   {
00831     ML_TRACE_IN("TQuaternion<DT>::sinh() const");
00832 
00833     TQuaternion<DT> retVal;
00834     ML_TRY
00835     {
00836       const Tvec3<DT> &v  = qv();
00837       const DT        len = v.length();
00838       // In case of len == 0 be sure not to divide by zero but setting vector to 0 vector.
00839       // Then the quaternion method behaves like the normal function on real values.
00840       retVal.set((!MLValueIs0WOM(len) ? 
00841                     static_cast<DT>(-1)*static_cast<DT>(::sin(qw))*qv()/len*static_cast<DT>(::sinh(len)) :
00842                     Tvec3<DT>(0.0)), 
00843                  ::cos(qw)*::cosh(len)
00844                 );
00845 
00846     }
00847     ML_CATCH_RETHROW;
00848     return retVal;
00849   }
00850 
00852   inline TQuaternion<DT> tan(bool *isError=NULL)    const { return sin().div(cos(), isError);  }
00853 
00855   inline TQuaternion<DT> cotan(bool *isError=NULL)  const { return cos().div(sin(), isError);  }
00856 
00857 
00858 
00863 
00865   TQuaternion<DT> sinh() const
00866   {
00867     ML_TRACE_IN("TQuaternion<DT>::sinh() const");
00868 
00869     TQuaternion<DT> retVal;
00870     ML_TRY
00871     {
00872       const Tvec3<DT> &v  = qv();
00873       const DT        len = v.length();
00874       // In case of len == 0 be sure not to divide by zero but setting vector to 0 vector.
00875       // Then the quaternion method behaves like the normal function on real values.
00876       retVal.set((!MLValueIs0WOM(len) ? 
00877                      static_cast<DT>(::cosh(qw))*v/len*static_cast<DT>(::sin(len)) :
00878                      Tvec3<DT>(0.0)), 
00879                  ::sinh(qw)*::cos(len)
00880                 );
00881     }
00882     ML_CATCH_RETHROW;
00883     return retVal;
00884   }
00885 
00887   TQuaternion<DT> cosh() const
00888   {
00889     ML_TRACE_IN("TQuaternion<DT>::cosh() const");
00890 
00891     TQuaternion<DT> retVal;
00892     ML_TRY
00893     {
00894       const Tvec3<DT> &v  = qv();
00895       const DT        len = v.length();
00896       // In case of len == 0 be sure not to divide by zero but setting vector to 0 vector.
00897       // Then the quaternion method behaves like the normal function on real values.
00898       retVal.set((!MLValueIs0WOM(len) ? 
00899                      static_cast<DT>(::sinh(qw))*v/len*static_cast<DT>(::sin(len)) :
00900                      Tvec3<DT>(0.0)), 
00901                  ::cosh(qw)*::cos(len)
00902                 );
00903     }
00904     ML_CATCH_RETHROW;
00905     return retVal;
00906   }
00907 
00909   inline TQuaternion<DT> tanh(bool *isError=NULL) const
00910   {
00911     ML_TRACE_IN("TQuaternion<DT>::tanh(bool *isError=NULL) const");
00912 
00913     TQuaternion<DT> retVal;
00914     ML_TRY
00915     {
00916       retVal = sinh().div(cosh(), isError);
00917     }
00918     ML_CATCH_RETHROW;
00919     return retVal;
00920   }
00921 
00923   inline TQuaternion<DT> cotanh(bool *isError=NULL) const
00924   { 
00925     ML_TRACE_IN("TQuaternion<DT>::cotanh(bool *isError=NULL) const");
00926 
00927     TQuaternion<DT> retVal;
00928     ML_TRY
00929     {
00930       retVal = cosh().div(sinh(), isError);
00931     }
00932     ML_CATCH_RETHROW;
00933     return retVal;
00934   }
00935 
00936 
00937 
00942 
00944   inline TQuaternion<DT> arcsinh()                             const { return add(mult(*this).add(TQuaternion<DT>( 1)).sqrt()).ln(); }
00945 
00947   inline TQuaternion<DT> arccosh()                             const { return add(mult(*this).add(TQuaternion<DT>(-1)).sqrt()).ln(); }
00948 
00950   inline TQuaternion<DT> arctanh()                             const { return TQuaternion<DT>((TQuaternion<DT>(qx,qy,qz,qw+1).ln()-TQuaternion<DT>(-qx, -qy, -qz, 1-qw).ln())/0.5);                                                   }
00951 
00952 
00962   #define _ML_QUATERNION_CALC_CHECKED(FUNC_NAME, CALC_EXPR)                          \
00963       ML_TRACE_IN("TQuaternion<DT>::" FUNC_NAME "() const");                         \
00964                                                                                      \
00965       TQuaternion<DT> retVal;                                                        \
00966       ML_TRY                                                                         \
00967       {                                                                              \
00968         const Tvec3<DT> &v  = qv();                                                  \
00969         const DT        len = v.length();                                            \
00970         if (MLValueIs0WOM(len)){                                                     \
00971           /* Error! Check whether we have a pointer to a return error code value. */ \
00972           if (isError == NULL){                                                      \
00973             /* No, post an error. */                                                 \
00974             ML_PRINT_ERROR("TQuaternion::" FUNC_NAME "() const, " FUNC_NAME          \
00975                            " of quaternion cannot be calculated",                    \
00976                            ML_BAD_PARAMETER,                                         \
00977                            "Returning default quaternion");                          \
00978           }                                                                          \
00979           else{                                                                      \
00980             /* Yes, set return code, retVal is left on default. */                   \
00981             *isError = true;                                                         \
00982           }                                                                          \
00983         }                                                                            \
00984         else{                                                                        \
00985           /* Define return values. */                                                \
00986           if (isError != NULL){ *isError = false; }                                  \
00987           retVal = CALC_EXPR;                                                        \
00988         }                                                                            \
00989       }                                                                              \
00990       ML_CATCH_RETHROW;                                                              \
00991       return retVal;                                                                 \
00992 
00993 
00994 
00996   #define _ML_QUAT_CALC_EXP TQuaternion<DT>(-v/len,0).mult(mult(TQuaternion<DT>(-v/len,0)).arcsinh());
00997 
00998 
00999 
01000 
01001 
01003   TQuaternion<DT> arcsin(bool *isError=NULL) const
01004   {
01005     _ML_QUATERNION_CALC_CHECKED("arcsin", _ML_QUAT_CALC_EXP);
01006   }
01007   #undef _ML_QUAT_CALC_EXP
01008 
01009 
01010 
01012   #define _ML_QUAT_CALC_EXP TQuaternion<DT>(-v/len,0).mult(arccosh());
01013 
01014   TQuaternion<DT> arccos(bool *isError=NULL) const
01015   {
01016     _ML_QUATERNION_CALC_CHECKED("arccos", _ML_QUAT_CALC_EXP);
01017   }
01018   #undef _ML_QUAT_CALC_EXP
01019 
01020 
01021 
01023   #define _ML_QUAT_CALC_EXP TQuaternion<DT>(-v/len,0).mult(mult(TQuaternion<DT>(-v/len,0)).arctanh());
01024 
01025   TQuaternion<DT> arctan(bool *isError=NULL) const
01026   {
01027     _ML_QUATERNION_CALC_CHECKED("arctan", _ML_QUAT_CALC_EXP);
01028   }
01029   #undef _ML_QUAT_CALC_EXP
01030 
01031 
01032   // Undefine _ML_QUATERNION_CALC_CHECKED, it is not needed any more.
01033   #undef _ML_QUATERNION_CALC_CHECKED
01034 };
01035 
01036 
01037 //-----------------------------------------------------------------------------------
01039 
01040 //-----------------------------------------------------------------------------------
01042 typedef TQuaternion<MLfloat>   Quaternionf;
01043 
01045 typedef TQuaternion<MLdouble>  Quaterniond;
01046 
01048 typedef TQuaternion<MLldouble> Quaternionld;
01049 
01051 typedef TQuaternion<MLdouble>  Quaternion;
01053 
01054 
01055 ML_LA_END_NAMESPACE
01056 
01057 
01058 
01059 
01060 //-------------------------------------------------------------------------
01062 
01063 
01064 
01065 
01066 
01067 //-------------------------------------------------------------------------
01068 #ifdef  _ML_IMPLEMENT_GLOBAL_QUATERNION_OPERATORS
01069 #ifndef _ML_IMPLEMENT_GLOBAL_QUATERNION_FUNCS_AND_OPS_IN_GLOBAL_NAMESPACE
01070 ML_LA_START_NAMESPACE
01071 #endif
01072 
01073 //-----------------------------
01074 // Addition
01075 //-----------------------------
01077 template <typename DT>
01078 inline ML_LA_NAMESPACE::TQuaternion<DT> operator+(DT d, const ML_LA_NAMESPACE::TQuaternion<DT> &q){
01079   return ML_LA_NAMESPACE::TQuaternion<DT>(q.qx, q.qy, q.qz, q.qw+d);
01080 }
01081 
01083 template <typename DT>
01084 inline ML_LA_NAMESPACE::TQuaternion<DT> operator+(const ML_LA_NAMESPACE::TQuaternion<DT> &q, DT d){
01085   return ML_LA_NAMESPACE::TQuaternion<DT>(q.qx, q.qy, q.qz, q.qw+d);
01086 }
01087 
01089 template <typename DT>
01090 inline ML_LA_NAMESPACE::TQuaternion<DT> operator+(const ML_LA_NAMESPACE::TQuaternion<DT> &qa,
01091                                                   const ML_LA_NAMESPACE::TQuaternion<DT> &qb){
01092   return qa.operator+(qb);
01093 }
01094 
01095 
01096 
01097 //-----------------------------
01098 // Subtraction
01099 //-----------------------------
01101 template <typename DT>
01102 inline ML_LA_NAMESPACE::TQuaternion<DT> operator-(DT d, const ML_LA_NAMESPACE::TQuaternion<DT> &q){
01103   return ML_LA_NAMESPACE::TQuaternion<DT>(-q.qx, -q.qy, -q.qz, d-q.qw);
01104 }
01105 
01107 template <typename DT>
01108 inline ML_LA_NAMESPACE::TQuaternion<DT> operator-(const ML_LA_NAMESPACE::TQuaternion<DT> &q, DT d){
01109   return ML_LA_NAMESPACE::TQuaternion<DT>(q.qx, q.qy, q.qz, q.qw-d);
01110 }
01111 
01113 template <typename DT>
01114 inline ML_LA_NAMESPACE::TQuaternion<DT> operator-(const ML_LA_NAMESPACE::TQuaternion<DT> &qa,
01115                                                   const ML_LA_NAMESPACE::TQuaternion<DT> &qb){
01116   return qa.operator-(qb);
01117 }
01118 
01119 
01121 template <typename DT>
01122 inline ML_LA_NAMESPACE::TQuaternion<DT> operator*(DT d, const ML_LA_NAMESPACE::TQuaternion<DT> &q){
01123   return q.mult(d);
01124 }
01125 
01127 template <typename DT>
01128 inline ML_LA_NAMESPACE::TQuaternion<DT> operator*(const ML_LA_NAMESPACE::TQuaternion<DT> &q, DT d){
01129   return q.mult(d);
01130 }
01131 
01133 template <typename DT>
01134 inline ML_LA_NAMESPACE::TQuaternion<DT> operator*(const ML_LA_NAMESPACE::TQuaternion<DT> &qa,
01135                                                   const ML_LA_NAMESPACE::TQuaternion<DT> &qb){
01136   return qa.operator*(qb);
01137 }
01139 
01140 #ifndef _ML_IMPLEMENT_GLOBAL_QUATERNION_FUNCS_AND_OPS_IN_GLOBAL_NAMESPACE
01141 ML_LA_END_NAMESPACE
01142 #endif
01143 
01144 #endif  // _ML_IMPLEMENT_GLOBAL_QUATERNION_OPERATORS
01145 
01146 
01147 
01148 //-------------------------------------------------------------------------
01150 
01151 
01152 
01153 
01154 
01155 //-------------------------------------------------------------------------
01156 #ifdef  _ML_IMPLEMENT_GLOBAL_QUATERNION_FUNCTIONS
01157 #ifndef _ML_IMPLEMENT_GLOBAL_QUATERNION_FUNCS_AND_OPS_IN_GLOBAL_NAMESPACE
01158 ML_LA_START_NAMESPACE
01159 #endif
01160 
01163 #ifdef _ML_IMPLEMENT_QUATERNION_SQRT
01164 template <typename DT>
01165 inline ML_LA_NAMESPACE::TQuaternion<DT> sqrt   (const ML_LA_NAMESPACE::TQuaternion<DT> &q) { return q.sqrt();    }
01166 #endif
01167 
01169 template <typename DT>
01170 inline ML_LA_NAMESPACE::TQuaternion<DT> exp    (const ML_LA_NAMESPACE::TQuaternion<DT> &q) { return q.exp();     }
01171 
01173 template <typename DT>
01174 inline ML_LA_NAMESPACE::TQuaternion<DT> ln     (const ML_LA_NAMESPACE::TQuaternion<DT> &q) { return q.ln();      }
01175 
01177 template <typename DT>
01178 inline ML_LA_NAMESPACE::TQuaternion<DT> sin    (const ML_LA_NAMESPACE::TQuaternion<DT> &q) { return q.sin();     }
01179 
01181 template <typename DT>
01182 inline ML_LA_NAMESPACE::TQuaternion<DT> cos    (const ML_LA_NAMESPACE::TQuaternion<DT> &q) { return q.cos();     }
01183 
01185 template <typename DT>
01186 inline ML_LA_NAMESPACE::TQuaternion<DT> tan    (const ML_LA_NAMESPACE::TQuaternion<DT> &q) { return q.tan();     }
01187 
01189 template <typename DT>
01190 inline ML_LA_NAMESPACE::TQuaternion<DT> cotan  (const ML_LA_NAMESPACE::TQuaternion<DT> &q) { return q.cotan();   }
01191 
01193 template <typename DT>
01194 inline ML_LA_NAMESPACE::TQuaternion<DT> sinh   (const ML_LA_NAMESPACE::TQuaternion<DT> &q) { return q.sinh();    }
01195 
01197 template <typename DT>
01198 inline ML_LA_NAMESPACE::TQuaternion<DT> cosh   (const ML_LA_NAMESPACE::TQuaternion<DT> &q) { return q.cosh();    }
01199 
01201 template <typename DT>
01202 inline ML_LA_NAMESPACE::TQuaternion<DT> tanh   (const ML_LA_NAMESPACE::TQuaternion<DT> &q) { return q.tanh();    }
01203 
01205 template <typename DT>
01206 inline ML_LA_NAMESPACE::TQuaternion<DT> cotanh (const ML_LA_NAMESPACE::TQuaternion<DT> &q) { return q.cotanh();  }
01207 
01209 template <typename DT>
01210 inline ML_LA_NAMESPACE::TQuaternion<DT> arcsinh(const ML_LA_NAMESPACE::TQuaternion<DT> &q) { return q.arcsinh(); }
01211 
01213 template <typename DT>
01214 inline ML_LA_NAMESPACE::TQuaternion<DT> arccosh(const ML_LA_NAMESPACE::TQuaternion<DT> &q) { return q.arccosh(); }
01215 
01217 template <typename DT>
01218 inline ML_LA_NAMESPACE::TQuaternion<DT> arctanh(const ML_LA_NAMESPACE::TQuaternion<DT> &q) { return q.arctanh(); }
01219 
01221 template <typename DT>
01222 inline ML_LA_NAMESPACE::TQuaternion<DT> arcsin (const ML_LA_NAMESPACE::TQuaternion<DT> &q) { return q.arcsin();  }
01223 
01225 template <typename DT>
01226 inline ML_LA_NAMESPACE::TQuaternion<DT> arccos (const ML_LA_NAMESPACE::TQuaternion<DT> &q) { return q.arccos();  }
01227 
01229 template <typename DT>
01230 inline ML_LA_NAMESPACE::TQuaternion<DT> arctan (const ML_LA_NAMESPACE::TQuaternion<DT> &q) { return q.arctan();  }
01231 
01232 
01233 #ifndef _ML_IMPLEMENT_GLOBAL_QUATERNION_FUNCS_AND_OPS_IN_GLOBAL_NAMESPACE
01234 ML_LA_END_NAMESPACE
01235 #endif
01236 
01237 #endif // _ML_IMPLEMENT_GLOBAL_QUATERNION_FUNCTIONS
01238 
01239 
01240 
01241 //-----------------------------------------------------------------------------------
01242 // Stream output for std::ostream and dyadic multiplication of TQuaternion and scalar.
01243 //-----------------------------------------------------------------------------------
01244 namespace std {
01245 
01247   template <typename DT>
01248   inline ostream& operator<<(ostream& s, const ML_NAMESPACE::TQuaternion<DT> &v){
01249     return s << "(" << v.qx << "," << v.qy << "," << v.qz << "," << v.qw << ")";
01250   };
01251 
01252 }
01253 
01254 
01255 #endif // __mlQuaternion_H