Documentation


quaternion.h

Go to the documentation of this file.
00001 #ifndef _ANIMAL_GEOMETRY_QUATERNION_H_
00002 #define _ANIMAL_GEOMETRY_QUATERNION_H_
00003 
00004 #include <animal/vec3.h>
00005 //#include <animal/numerics.h>
00006 #include <cmath>
00007 #include <limits.h>
00008 
00009 
00010 
00011 namespace animal
00012 {
00013 
00014   template <class RealT> class Quaternion_Traits;
00015 
00016   // -----------------------------------------------------------
00017   //
00018   //  Quaternion class.
00029   //
00030   // -----------------------------------------------------------
00031 
00032   template <
00033   class RealT = double,
00034   class TraitsT = Quaternion_Traits<RealT>
00035   >
00036 
00037   class Quaternion
00038   {
00039 
00040   public:
00041 
00044 
00046     typedef TraitsT Traits;
00047 
00049     typedef RealT Real;
00050 
00052     //typedef typename Traits::Vec3 Vec3;
00053 
00056     //typedef Numerics<Real> NumTraits;
00057 
00059 
00062 
00064     Quaternion();
00065 
00067     Quaternion(const Real w, const Real x, const Real y, const Real z);
00068 
00070     Quaternion(const Vec3& axis, const Real angle);
00071 
00073     Quaternion(const Real angle, const Vec3& axis);
00074 
00076     Quaternion(const Quaternion& );
00077 
00079     ~Quaternion();
00080 
00082     template< class Vect >
00083     static Quaternion eulerIncrement ( const Vect&, const Real dt );
00084 
00086     static Quaternion eulerIncrement( const Real, const Real, const Real, const Real );
00087 
00089     template< class Vect >
00090     static Quaternion  elementaryRotation( const Vect& );
00091 
00093     static Quaternion elementaryRotation( const Real, const Real, const Real );
00094 
00096 
00097 
00100 
00101     void getAxisAngle(Real& x, Real& y, Real& z, Real& angle) const;
00102 
00104     void getAxisAngle(Vec3& v, Real& a) const ;
00105 
00107     const Real& w() const;
00108 
00110     const Real& x() const;
00111 
00113     const Real& y() const;
00114 
00116     const Real& z() const;
00118 
00119 
00125     void setAxisAngle(const Real x, const Real y, const Real z, const Real angle);
00126 
00130     void setAxisAngle(const Vec3& axis, const Real angle);
00131 
00133     Quaternion& setwxyz(const Real w, const Real x, const Real y, const Real z);
00134 
00136 
00138 
00139     Quaternion& setEulerXYZ(const Real x, const Real y, const Real z);
00140 
00142     Quaternion& setEulerXYX(const Real x, const Real y, const Real xx);
00143 
00145     Quaternion& setEulerXZY(const Real x, const Real z, const Real y);
00146 
00148     Quaternion& setEulerXZX(const Real x, const Real z, const Real xx);
00149 
00151     Quaternion& setEulerYZX(const Real y, const Real z, const Real x);
00152 
00154     Quaternion& setEulerYZY(const Real y, const Real z, const Real yy);
00155 
00157     Quaternion& setEulerYXY(const Real y, const Real x, const Real yy);
00158 
00160     Quaternion& setEulerYXZ(const Real y, const Real x, const Real z);
00161 
00163     Quaternion& setEulerZXY(const Real z, const Real x, const Real y);
00164 
00166     Quaternion& setEulerZXZ(const Real z, const Real x, const Real zz);
00167 
00169     Quaternion& setEulerZYX(const Real z, const Real y, const Real x);
00170 
00172     Quaternion& setEulerZYZ(const Real z, const Real y, const Real zz);
00174 
00175 
00178 
00179     Quaternion& operator = (const Quaternion& );
00180 
00182     Quaternion& operator *= (const Quaternion& );
00183 
00185     Quaternion& operator /= (const Quaternion& );
00186 
00188     Quaternion operator * (const Quaternion& ) const;
00189 
00191     Quaternion operator / (const Quaternion& ) const ;
00192 
00194     Quaternion inverse() const ;
00195 
00197     Quaternion operator * ( const Real u ) const;
00198     //<<<<<<< quaternion.h
00199     //  //@}
00200 
00201 
00202     //  /*! @name Operations on vectors */
00203     //  //@{
00204     //  //! Apply rotation to a vector
00205     //  Vec3 operator * (const Quaternion::Vec3& ) const;
00206 
00207     //  //! Apply inverse rotation to a vector
00208     //  Vec3 operator / (const Vec3& ) const;
00209     //  //@}
00210 
00211 
00212     //  /*! @name Input/Output */
00213     //  //@{
00214     //  //! Text output: axis angle
00215     //  template < class R, class T>
00216     //  friend std::ostream& operator << (std::ostream& , const Quaternion<R,T>& );
00217     //=======
00219 
00220 
00223 
00224     Vec3 operator * (const Vec3& ) const;
00225 
00227     Vec3 operator / (const Vec3& ) const;
00229 
00230 
00233 
00234     template < class R, class T>
00235     friend std::ostream& operator << (std::ostream& , const Quaternion<R,T>& );
00236 
00238     template < class R, class T>
00239     friend std::istream& operator >> (std::istream& , Quaternion<R,T>& );
00241 
00242 
00245 
00246     Real norm() const;
00247 
00249     Quaternion& normalize();
00251 
00252 
00255 
00256     static const Quaternion identity();
00258     //>>>>>>> 1.3
00259 
00260 
00261 
00262   private:
00263 
00264     Real v[4];   
00265 
00266 
00267   }
00268   ; // class Quaternion
00272   // -----------------------------------------------------------
00273   //
00277   //
00278   // -----------------------------------------------------------
00280 
00282   template <class Real, class Traits>
00283   inline std::ostream&
00284   operator << (std::ostream& stream, const Quaternion<Real,Traits>& q)
00285   {
00286     Real x, y, z, angle;
00287     q.getAxisAngle(x,y,z,angle);
00288     //   stream << "(" << q.x() << " " << q.y() << " " << q.z() << " " << q.w() << ")";
00289     stream << x << " " << y << " " << z << " " << angle;
00290 
00291     return stream;
00292   }
00293 
00295   template <class Real, class Traits>
00296   inline std::istream&
00297   operator >> (std::istream& stream, Quaternion<Real,Traits>& q)
00298   {
00299     Real x, y, z, angle;
00300     stream >> x >> y >> z >> angle;
00301     q.setAxisAngle(x,y,z,angle);
00302 
00303     return stream;
00304   }
00305 
00307   template < class Real, class Traits>
00308   Vec3
00309   operator*
00310   (
00311     const typename Quaternion<Real,Traits>::Vec3&,
00312     const Quaternion<Real,Traits>&
00313   );
00314 
00316   template < class Real, class Traits>
00317   Vec3
00318   operator/
00319   (
00320     const typename Quaternion<Real,Traits>::Vec3&,
00321     const Quaternion<Real,Traits>&
00322   );
00323 
00324 
00327   template <class Real, class Traits, class Mat33>
00328   void
00329   writeRotMatrix
00330   (
00331     const Quaternion<Real,Traits>& q,
00332     Mat33& m
00333   );
00334 
00337   template <class Real, class Traits, class Mat44>
00338   void
00339   writeOpenGLRotMatrix
00340   (
00341     const Quaternion<Real,Traits>& q,
00342     Mat44& m
00343   );
00344 
00346 
00347 
00348 
00349   // -----------------------------------------------------------
00350   //
00351   //  Quaternion_Traits class.
00361   //
00362   // -----------------------------------------------------------
00363 
00364   template <class RealT> class Quaternion_Traits
00365   {
00366 
00367   public:
00368 
00371 
00372     typedef RealT Real;
00374     typedef animal::Vec3 Vec3;
00376 
00377 
00378 
00381 
00382     static const Real x(const Vec3& v) { return v[0]; }
00383 
00385     static const Real y(const Vec3& v) { return v[1]; }
00386 
00388     static const Real z(const Vec3& v) { return v[2]; }
00390 
00391 
00393     static Vec3& normalize(Vec3& v) { v_normalize(v); return v; }
00394 
00396     static Real nullAxis() { return 1.0e-5; }
00397 
00398   }
00399   ; // class Quaternion_Traits
00400 
00401 
00402 
00403 
00404 
00405 
00406 
00407 
00408 
00409 
00410   // -------------------------------------------------------------
00411   //
00412   //   D E F I N I T I O N   O F   I N L I N E D   M E T H O D S
00413   //
00414   // -------------------------------------------------------------
00415 
00416 
00417 
00418 
00419 
00420   template<class Real, class Traits>
00421   inline
00422   Quaternion<Real,Traits>::
00423   Quaternion()
00424   {}
00425 
00426   template<class Real, class Traits>
00427   inline
00428   Quaternion<Real,Traits>::
00429   Quaternion(const Real w, const Real x, const Real y, const Real z)
00430   {
00431     v[3]=w; v[0]=x; v[1]=y; v[2]=z;
00432   }
00433 
00434   template<class Real, class Traits>
00435   inline
00436   Quaternion<Real,Traits>::
00437   Quaternion(const Vec3& axis, const Real angle)
00438   {
00439     setAxisAngle(axis, angle);
00440   }
00441 
00442   template<class Real, class Traits>
00443   inline
00444   Quaternion<Real,Traits>::
00445   Quaternion(const Real angle, const Vec3& axis)
00446   {
00447     setAxisAngle(axis, angle);
00448   }
00449 
00450   template<class Real, class Traits>
00451   inline
00452   Quaternion<Real,Traits>::
00453   Quaternion(const Quaternion& q)
00454   {
00455     v[3]=q.v[3]; v[0]=q.v[0]; v[1]=q.v[1]; v[2]=q.v[2];
00456   }
00457 
00458   template<class Real, class Traits>
00459   inline
00460   Quaternion<Real,Traits>::
00461   ~Quaternion()
00462   {}
00463 
00464 
00465 
00466 
00467 
00468   template<class Real, class Traits>
00469   inline void
00470   Quaternion<Real,Traits>::
00471   getAxisAngle(Real& x, Real& y, Real& z, Real& an) const
00472   {
00473 #ifdef DEBUG
00474     Real v_0 = ( v[3]>1.0 ? 1.0 : v[3]<-1.0 ? -1.0 : v[3] );
00475 
00476     an = 2.0*std::acos(v_0);
00477     //  std::cerr << "v_0 = " << v_0 <<std::endl;
00478     //  std::cerr << "angle = " << an <<std::endl;
00479     //  std::cerr << "threshold = " << NumTraits::numthreshold() <<std::endl;
00480     Real cos_an_2 = std::cos(an/2);
00481     Real epsilon =  std::numeric_limits<Real>::epsilon();
00482     if ( std::abs( v_0 - cos_an_2 ) > epsilon )
00483     {
00484       std::cerr << "Operation getAxisAngle(x, y, z, angle) beyond threshold!" << std::endl;
00485       assert(false);
00486     }
00487 #else
00488     an = 2.0*acos( v[3]>1.0 ? 1.0 : v[3]<-1.0 ? -1.0 : v[3] );
00489 #endif
00490 
00491     //  if ( an > NumTraits::numthreshold() )
00492     if ( an > Traits::nullAxis() )
00493     {
00494       Real tmp = 1.0/sin(an/2.0);
00495       //            std::cerr << " tmp = " << tmp <<std::endl;
00496       x=v[0]*tmp;
00497       y=v[1]*tmp;
00498       z=v[2]*tmp;
00499     }
00500     else
00501     {
00502       x = 1.0; // Arbitrary!
00503       y = 0.0;
00504       z = 0.0;
00505       an = 0;
00506     }
00507   }
00508 
00509   template<class Real, class Traits>
00510   inline void
00511   Quaternion<Real,Traits>::
00512   getAxisAngle(Vec3& ax, Real& an) const
00513   {
00514     // #if DEBUG
00515     //   Real v_0 = ( v[3]>1.0 ? 1.0 : v[3]<-1.0 ? -1.0 : v[3] );
00516     //
00517     //   an = 2.0*NumTraits::acosine(v_0);
00518     //   Real cos_an_2 = NumTraits::cosine(an/2);
00519     //
00520     //   if ( NumTraits::fpabs( v_0 - cos_an_2 ) > NumTraits::numthreshold() )
00521     //     {
00522     //       std::cerr << "Operation getAxisAngle(axe, angle) beyond threshold!" << std::endl;
00523     //       assert(false);
00524     //     }
00525     // #else
00526     //   an = 2.0*NumTraits::acosine( v[3]>1.0 ? 1.0 : v[3]<-1.0 ? -1.0 : v[3] );
00527     // #endif
00528 
00529     an = 2.0*acos( v[3]>1.0 ? 1.0 : v[3]<-1.0 ? -1.0 : v[3] );
00530 
00531     if ( an > Traits::nullAxis() )
00532       //   if ( an > NumTraits::numthreshold() )
00533     {
00534       Real tmp = 1.0/sin(an/2.0);
00535       ax = Vec3(v[0]*tmp, v[1]*tmp, v[2]*tmp);
00536     }
00537     else // Arbitrary!
00538     {
00539       ax = Vec3(1.0, 0.0, 0.0);
00540       an = 0;
00541     }
00542   }
00543 
00544   template<class Real, class Traits>
00545   inline const Real&
00546   Quaternion<Real,Traits>::w() const
00547   {
00548     return v[3];
00549   }
00550 
00551   template<class Real, class Traits>
00552   inline const Real&
00553   Quaternion<Real,Traits>::x() const
00554   {
00555     return v[0];
00556   }
00557 
00558   template<class Real, class Traits>
00559   inline const Real&
00560   Quaternion<Real,Traits>::y() const
00561   {
00562     return v[1];
00563   }
00564 
00565   template<class Real, class Traits>
00566   inline const Real&
00567   Quaternion<Real,Traits>::z() const
00568   {
00569     return v[2];
00570   }
00571 
00572 
00573 
00574 
00575 
00576   template<class Real, class Traits>
00577   inline void
00578   Quaternion<Real,Traits>::
00579   setAxisAngle(const Vec3& ax, const Real an)
00580   {
00581     v[3] = cos(an/2.0);
00582 
00583     Vec3 axn = ax;
00584     Traits::normalize(axn);
00585     Real tmp = sin(an/2.0);
00586 
00587     v[0] = Traits::x(axn)*tmp;
00588     v[1] = Traits::y(axn)*tmp;
00589     v[2] = Traits::z(axn)*tmp;
00590   }
00591 
00592   template<class Real, class Traits>
00593   inline void
00594   Quaternion<Real,Traits>::
00595   setAxisAngle(const Real x, const Real y, const Real z, const Real an)
00596   {
00597     v[3] = cos(an/2.0);
00598 
00599     Vec3 axn(x, y, z);
00600     Traits::normalize(axn);
00601     Real tmp = sin(an/2.0);
00602 
00603     v[0] = Traits::x(axn)*tmp;
00604     v[1] = Traits::y(axn)*tmp;
00605     v[2] = Traits::z(axn)*tmp;
00606   }
00607 
00608   template <class Real, class Traits>
00609   inline Quaternion<Real,Traits>&
00610   Quaternion<Real,Traits>::
00611   setwxyz(const Real w, const Real x, const Real y, const Real z)
00612   {
00613     v[3]=w; v[0]=x; v[1]=y; v[2]=z;
00614     return *this;
00615   }
00616 
00617   template <class Real, class Traits>
00618   inline Quaternion<Real,Traits>&
00619   Quaternion<Real,Traits>::
00620   setEulerXYZ(const Real x, const Real y, const Real z)
00621   {
00622     Quaternion qx; qx.setAxisAngle(1,0,0, x);
00623     Quaternion qy; qy.setAxisAngle(0,1,0, y);
00624     Quaternion qz; qz.setAxisAngle(0,0,1, z);
00625 
00626     return (*this = qx*qy*qz);
00627   }
00628 
00629   template <class Real, class Traits>
00630   inline Quaternion<Real,Traits>&
00631   Quaternion<Real,Traits>::
00632   setEulerXYX(const Real x, const Real y, const Real xx)
00633   {
00634     Quaternion qx;  qx.setAxisAngle (1,0,0, x );
00635     Quaternion qy;  qy.setAxisAngle (0,1,0, y );
00636     Quaternion qxx; qxx.setAxisAngle(1,0,0, xx);
00637 
00638     return (*this = qx*qy*qxx);
00639   }
00640 
00641   template <class Real, class Traits>
00642   inline Quaternion<Real,Traits>&
00643   Quaternion<Real,Traits>::
00644   setEulerXZY(const Real x, const Real z, const Real y)
00645   {
00646     Quaternion qx; qx.setAxisAngle(1,0,0, x);
00647     Quaternion qz; qz.setAxisAngle(0,0,1, z);
00648     Quaternion qy; qy.setAxisAngle(0,1,0, y);
00649 
00650     return (*this = qx*qz*qy);
00651   }
00652 
00653   template <class Real, class Traits>
00654   inline Quaternion<Real,Traits>&
00655   Quaternion<Real,Traits>::
00656   setEulerXZX(const Real x, const Real z, const Real xx)
00657   {
00658     Quaternion qx;  qx.setAxisAngle (1,0,0, x );
00659     Quaternion qz;  qz.setAxisAngle (0,0,1, z );
00660     Quaternion qxx; qxx.setAxisAngle(1,0,0, xx);
00661 
00662     return (*this = qx*qz*qxx);
00663   }
00664 
00665   template <class Real, class Traits>
00666   inline Quaternion<Real,Traits>&
00667   Quaternion<Real,Traits>::
00668   setEulerYZX(const Real y, const Real z, const Real x)
00669   {
00670     Quaternion qy; qy.setAxisAngle(0,1,0, y);
00671     Quaternion qz; qz.setAxisAngle(0,0,1, z);
00672     Quaternion qx; qx.setAxisAngle(1,0,0, x);
00673 
00674     return (*this = qy*qz*qx);
00675   }
00676 
00677   template <class Real, class Traits>
00678   inline Quaternion<Real,Traits>&
00679   Quaternion<Real,Traits>::
00680   setEulerYZY(const Real y, const Real z, const Real yy)
00681   {
00682     Quaternion qy;  qy.setAxisAngle (0,1,0, y );
00683     Quaternion qz;  qz.setAxisAngle (0,0,1, z );
00684     Quaternion qyy; qyy.setAxisAngle(0,1,0, yy);
00685 
00686     return (*this = qy*qz*qyy);
00687   }
00688 
00689   template <class Real, class Traits>
00690   inline Quaternion<Real,Traits>&
00691   Quaternion<Real,Traits>::
00692   setEulerYXY(const Real y, const Real x, const Real yy)
00693   {
00694     Quaternion qy;  qy.setAxisAngle (0,1,0, y );
00695     Quaternion qx;  qx.setAxisAngle (1,0,0, x );
00696     Quaternion qyy; qyy.setAxisAngle(0,1,0, yy);
00697 
00698     return (*this = qy*qx*qyy);
00699   }
00700 
00701   template <class Real, class Traits>
00702   inline Quaternion<Real,Traits>&
00703   Quaternion<Real,Traits>::
00704   setEulerYXZ(const Real y, const Real x, const Real z)
00705   {
00706     Quaternion qy;  qy.setAxisAngle(0,1,0, y);
00707     Quaternion qx;  qx.setAxisAngle(1,0,0, x);
00708     Quaternion qz;  qz.setAxisAngle(0,0,1, z);
00709 
00710     return (*this = qy*qx*qz);
00711   }
00712 
00713   template <class Real, class Traits>
00714   inline Quaternion<Real,Traits>&
00715   Quaternion<Real,Traits>::
00716   setEulerZXY(const Real z, const Real x, const Real y)
00717   {
00718     Quaternion qz; qz.setAxisAngle(0,0,1, z);
00719     Quaternion qx; qx.setAxisAngle(1,0,0, x);
00720     Quaternion qy; qy.setAxisAngle(0,1,0, y);
00721 
00722     return (*this = qz*qx*qy);
00723   }
00724 
00725   template <class Real, class Traits>
00726   inline Quaternion<Real,Traits>&
00727   Quaternion<Real,Traits>::
00728   setEulerZXZ(const Real z, const Real x, const Real zz)
00729   {
00730     Quaternion qz;  qz.setAxisAngle (0,0,1, z );
00731     Quaternion qx;  qx.setAxisAngle (1,0,0, x );
00732     Quaternion qzz; qzz.setAxisAngle(0,0,1, zz);
00733 
00734     return (*this = qz*qx*qzz);
00735   }
00736 
00737   template <class Real, class Traits>
00738   inline Quaternion<Real,Traits>&
00739   Quaternion<Real,Traits>::
00740   setEulerZYX(const Real z, const Real y, const Real x)
00741   {
00742     Quaternion qz; qz.setAxisAngle(0,0,1, z);
00743     Quaternion qy; qy.setAxisAngle(0,1,0, y);
00744     Quaternion qx; qx.setAxisAngle(1,0,0, x);
00745 
00746     return (*this = qz*qy*qx);
00747   }
00748 
00749   template <class Real, class Traits>
00750   inline Quaternion<Real,Traits>&
00751   Quaternion<Real,Traits>::
00752   setEulerZYZ(const Real z, const Real y, const Real zz)
00753   {
00754     Quaternion qz;  qz.setAxisAngle (0,0,1, z );
00755     Quaternion qy;  qy.setAxisAngle (0,1,0, y );
00756     Quaternion qzz; qzz.setAxisAngle(0,0,1, zz);
00757 
00758     return (*this = qz*qy*qzz);
00759   }
00760 
00761 
00762 
00763 
00764 
00765   template<class Real, class Traits>
00766   inline Quaternion<Real,Traits>&
00767   Quaternion<Real,Traits>::
00768   operator=(const Quaternion& q)
00769   {
00770     v[3] = q.v[3];
00771     v[0] = q.v[0];
00772     v[1] = q.v[1];
00773     v[2] = q.v[2];
00774 
00775     return *this;
00776   }
00777 
00778   template<class Real, class Traits>
00779   inline Quaternion<Real,Traits>&
00780   Quaternion<Real,Traits>::
00781   operator*=(const Quaternion& q)
00782   {
00783     Real w = q.v[3]*v[3] - q.v[0]*v[0] - q.v[1]*v[1] - q.v[2]*v[2];
00784     Real x = q.v[3]*v[0] + q.v[0]*v[3] + q.v[1]*v[2] - q.v[2]*v[1];
00785     Real y = q.v[3]*v[1] - q.v[0]*v[2] + q.v[1]*v[3] + q.v[2]*v[0];
00786     Real z = q.v[3]*v[2] + q.v[0]*v[1] - q.v[1]*v[0] + q.v[2]*v[3];
00787     v[3] = w; v[0] = x; v[1] = y; v[2] = z;
00788 
00789     return *this;
00790   }
00791 
00792   template<class Real, class Traits>
00793   inline Quaternion<Real,Traits>&
00794   Quaternion<Real,Traits>::
00795   operator/=(const Quaternion& q)
00796   {
00797     Real w = q.v[3]*v[3] + q.v[0]*v[0] + q.v[1]*v[1] + q.v[2]*v[2];
00798     Real x = q.v[3]*v[0] - q.v[0]*v[3] - q.v[1]*v[2] + q.v[2]*v[1];
00799     Real y = q.v[3]*v[1] + q.v[0]*v[2] - q.v[1]*v[3] - q.v[2]*v[0];
00800     Real z = q.v[3]*v[2] - q.v[0]*v[1] + q.v[1]*v[0] - q.v[2]*v[3];
00801     v[3] = w; v[0] = x; v[1] = y; v[2] = z;
00802 
00803     return *this;
00804   }
00805 
00806   template<class Real, class Traits>
00807   inline Quaternion<Real,Traits>
00808   Quaternion<Real,Traits>::
00809   operator*(const Quaternion& q) const
00810   {
00811     return Quaternion
00812            (
00813              q.v[3]*v[3] - q.v[0]*v[0] - q.v[1]*v[1] - q.v[2]*v[2],
00814              q.v[3]*v[0] + q.v[0]*v[3] + q.v[1]*v[2] - q.v[2]*v[1],
00815              q.v[3]*v[1] - q.v[0]*v[2] + q.v[1]*v[3] + q.v[2]*v[0],
00816              q.v[3]*v[2] + q.v[0]*v[1] - q.v[1]*v[0] + q.v[2]*v[3]
00817            );
00818   }
00819 
00820   template<class Real, class Traits>
00821   inline Quaternion<Real,Traits>
00822   Quaternion<Real,Traits>::
00823   operator/(const Quaternion& q) const
00824   {
00825     return Quaternion
00826            (
00827              q.v[3]*v[3] + q.v[0]*v[0] + q.v[1]*v[1] + q.v[2]*v[2],
00828              q.v[3]*v[0] - q.v[0]*v[3] - q.v[1]*v[2] + q.v[2]*v[1],
00829              q.v[3]*v[1] + q.v[0]*v[2] - q.v[1]*v[3] - q.v[2]*v[0],
00830              q.v[3]*v[2] - q.v[0]*v[1] + q.v[1]*v[0] - q.v[2]*v[3]
00831            );
00832   }
00833 
00834   template<class Real, class Traits>
00835   inline Quaternion<Real,Traits>
00836   Quaternion<Real,Traits>::inverse() const
00837   {
00838     return Quaternion(v[3], -v[0], -v[1], -v[2]);
00839   }
00840 
00842   template < class Real, class Traits>
00843   inline Quaternion<Real,Traits>
00844   Quaternion<Real,Traits>::operator *
00845   (
00846     const Real u
00847   )
00848   const
00849   {
00850     Vec3 axis;
00851     Real angle;
00852     getAxisAngle( axis, angle );
00853     return Quaternion( axis, u * angle );
00854   }
00855 
00856 
00857 
00858 
00860   template <class Real, class Traits>
00861   Vec3
00862   Quaternion<Real,Traits>::
00863   operator * (const Vec3& p) const
00864   {
00865     Real r[4];
00866     r[0] =  Traits::x(p)*v[0] + Traits::y(p)*v[1] + Traits::z(p)*v[2];
00867     r[1] =  Traits::x(p)*v[3] - Traits::y(p)*v[2] + Traits::z(p)*v[1];
00868     r[2] =  Traits::x(p)*v[2] + Traits::y(p)*v[3] - Traits::z(p)*v[0];
00869     r[3] = -Traits::x(p)*v[1] + Traits::y(p)*v[0] + Traits::z(p)*v[3];
00870 
00871     return Vec3//Quaternion<Real,Traits>::Vec3
00872            (
00873              v[3]*r[1] + v[0]*r[0] + v[1]*r[3] - v[2]*r[2],
00874              v[3]*r[2] - v[0]*r[3] + v[1]*r[0] + v[2]*r[1],
00875              v[3]*r[3] + v[0]*r[2] - v[1]*r[1] + v[2]*r[0]
00876            );
00877 
00878   }
00879 
00881   template < class Real, class Traits>
00882   Vec3
00883   operator * (const typename Quaternion<Real,Traits>::Vec3& p, const Quaternion<Real,Traits>& q )
00884   {
00885     return q*p;
00886   }
00887 
00888 
00889   template <class Real, class Traits>
00890   Vec3
00891   Quaternion<Real,Traits>::
00892   operator/(const Vec3& p) const
00893   {
00894     Real r[4];
00895     r[0] = -Traits::x(p)*v[0] - Traits::y(p)*v[1] - Traits::z(p)*v[2];
00896     r[1] =  Traits::x(p)*v[3] + Traits::y(p)*v[2] - Traits::z(p)*v[1];
00897     r[2] = -Traits::x(p)*v[2] + Traits::y(p)*v[3] + Traits::z(p)*v[0];
00898     r[3] =  Traits::x(p)*v[1] - Traits::y(p)*v[0] + Traits::z(p)*v[3];
00899 
00900     return Vec3
00901            (
00902              v[3]*r[1] - v[0]*r[0] - v[1]*r[3] + v[2]*r[2],
00903              v[3]*r[2] + v[0]*r[3] - v[1]*r[0] - v[2]*r[1],
00904              v[3]*r[3] - v[0]*r[2] + v[1]*r[1] - v[2]*r[0]
00905            );
00906   }
00907 
00908   //template < class Real, class Traits>
00909   //Vec3
00910   //operator/( const typename Quaternion<Real,Traits>::Vec3& p, const Quaternion<Real,Traits>& q)
00911   //{
00912   //  return q/p;
00913   //}
00914 
00915 
00916 
00917 
00918 
00919 
00920 
00921   template<class Real, class Traits>
00922   inline Real
00923   Quaternion<Real,Traits>::norm() const
00924   {
00925     return sqrt( v[3]*v[3] + v[0]*v[0] + v[1]*v[1] + v[2]*v[2] );
00926   }
00927 
00928   template<class Real, class Traits>
00929   inline Quaternion<Real,Traits>&
00930   Quaternion<Real,Traits>::normalize()
00931   {
00932     Real nrm = (*this).norm();
00933     Real tmp = 1.0/nrm;
00934 
00935 #ifndef DEBUG
00936     if ( !finite(tmp) )
00937     {
00938       std::cerr << "Quaternion normalization with 1/norm not finite!" << std::endl;
00939       assert(false);
00940     }
00941 
00942     v[3]*=tmp; v[0]*=tmp; v[1]*=tmp; v[2]*=tmp;
00943     nrm = (*this).norm();
00944 
00945     int nb = 0;
00946     Real epsilon =  std::numeric_limits<Real>::epsilon();
00947     while ( std::abs(nrm - 1.0) > epsilon )
00948     {
00949       tmp = 1.0/nrm;
00950       v[3]*=tmp; v[0]*=tmp; v[1]*=tmp; v[2]*=tmp;
00951       nrm = (*this).norm();
00952       nb++;
00953 
00954       if ( nb == 5 )
00955       {
00956         std::cerr << "Quaternion normalization beyond threshold!" << std::endl;
00957         assert(false);
00958         break;
00959       }
00960     }
00961 #else
00962     v[3]*=tmp; v[0]*=tmp; v[1]*=tmp; v[2]*=tmp;
00963 #endif
00964 
00965     return *this;
00966   }
00967 
00968 
00969 
00970 
00971 
00972   template<class Real, class Traits>
00973   inline const Quaternion<Real,Traits>
00974   Quaternion<Real,Traits>::identity()
00975   {
00976     return Quaternion(1.0, 0.0, 0.0, 0.0);
00977   }
00978 
00979 
00980 
00981 
00982 
00983   template <class Real, class Traits, class Mat33>
00984   inline void
00985   writeRotMatrix(const Quaternion<Real,Traits>& q, Mat33& m)
00986   {
00987     Real qw = q.w();
00988     Real qx = q.x();
00989     Real qy = q.y();
00990     Real qz = q.z();
00991 
00992     Real qww = qw*qw;
00993     Real qwx = qw*qx;
00994     Real qwy = qw*qy;
00995     Real qwz = qw*qz;
00996 
00997     Real qxx = qx*qx;
00998     Real qxy = qx*qy;
00999     Real qxz = qx*qz;
01000 
01001     Real qyy = qy*qy;
01002     Real qyz = qy*qz;
01003 
01004     Real qzz = qz*qz;
01005 
01006     m[0][0] = qww+qxx - (qyy + qzz);
01007     m[0][1] =       2.0*(qxy - qwz);
01008     m[0][2] =       2.0*(qxz + qwy);
01009 
01010     m[1][0] =       2.0*(qxy + qwz);
01011     m[1][1] = qww+qyy - (qzz + qxx);
01012     m[1][2] =       2.0*(qyz - qwx);
01013 
01014     m[2][0] =       2.0*(qxz - qwy);
01015     m[2][1] =       2.0*(qyz + qwx);
01016     m[2][2] = qww+qzz - (qyy + qxx);
01017   }
01018 
01019 
01020 
01021   //template <class Real, class Traits, class Mat33>
01022   //inline void
01023   //writeRotMatrix(const Quaternion<Real,Traits>& q, Mat33& m)
01024   //{
01025   //  Real qw = q.w();
01026   //  Real qx = q.x();
01027   //  Real qy = q.y();
01028   //  Real qz = q.z();
01029   //
01030   //  Real qww = qw*qw;
01031   //  Real qwx = qw*qx;
01032   //  Real qwy = qw*qy;
01033   //  Real qwz = qw*qz;
01034   //
01035   //  Real qxx = qx*qx;
01036   //  Real qxy = qx*qy;
01037   //  Real qxz = qx*qz;
01038   //
01039   //  Real qyy = qy*qy;
01040   //  Real qyz = qy*qz;
01041   //
01042   //  Real qzz = qz*qz;
01043   //
01044   //  m[0][0] = qww+qxx - (qyy + qzz);
01045   //  m[1][0] =       2.0*(qxy - qwz);
01046   //  m[2][0] =       2.0*(qxz + qwy);
01047   //
01048   //  m[0][1] =       2.0*(qxy + qwz);
01049   //  m[1][1] = qww+qyy - (qzz + qxx);
01050   //  m[2][1] =       2.0*(qyz - qwx);
01051   //
01052   //  m[0][2] =       2.0*(qxz - qwy);
01053   //  m[1][2] =       2.0*(qyz + qwx);
01054   //  m[2][2] = qww+qzz - (qyy + qxx);
01055   //}
01056 
01057   //template <class Real, class Traits, class Mat44>
01058   //inline void
01059   //writeOpenGLRotMatrix(const Quaternion<Real,Traits>& q, Mat44& m)
01060   //{
01061   //  Real qw = q.w();
01062   //  Real qx = q.x();
01063   //  Real qy = q.y();
01064   //  Real qz = q.z();
01065   //
01066   //  Real qwx = qw*qx;
01067   //  Real qwy = qw*qy;
01068   //  Real qwz = qw*qz;
01069   //
01070   //  Real qxx = qx*qx;
01071   //  Real qxy = qx*qy;
01072   //  Real qxz = qx*qz;
01073   //
01074   //  Real qyy = qy*qy;
01075   //  Real qyz = qy*qz;
01076   //
01077   //  Real qzz = qz*qz;
01078   //
01079   //  m[0][0] = 1.0 - 2.0*(qyy + qzz);
01080   //  m[0][1] =       2.0*(qxy - qwz);
01081   //  m[0][2] =       2.0*(qxz + qwy);
01082   //  m[0][3] = 0.0;
01083   //
01084   //  m[1][0] =       2.0*(qxy + qwz);
01085   //  m[1][1] = 1.0 - 2.0*(qzz + qxx);
01086   //  m[1][2] =       2.0*(qyz - qwx);
01087   //  m[1][3] = 0.0;
01088   //
01089   //  m[2][0] =       2.0*(qxz - qwy);
01090   //  m[2][1] =       2.0*(qyz + qwx);
01091   //  m[2][2] = 1.0 - 2.0*(qyy + qxx);
01092   //  m[2][3] = 0.0;
01093   //
01094   //  m[3][0] = 0.0;
01095   //  m[3][1] = 0.0;
01096   //  m[3][2] = 0.0;
01097   //  m[3][3] = 1.0;
01098   //}
01099 
01100   template <class Real, class Traits, class Mat44>
01101   inline void
01102   writeOpenGLRotMatrix(const Quaternion<Real,Traits>& q, Mat44& m)
01103   {
01104     Real qw = q.w();
01105     Real qx = q.x();
01106     Real qy = q.y();
01107     Real qz = q.z();
01108 
01109     Real qwx = qw*qx;
01110     Real qwy = qw*qy;
01111     Real qwz = qw*qz;
01112 
01113     Real qxx = qx*qx;
01114     Real qxy = qx*qy;
01115     Real qxz = qx*qz;
01116 
01117     Real qyy = qy*qy;
01118     Real qyz = qy*qz;
01119 
01120     Real qzz = qz*qz;
01121 
01122     m[0][0] = 1.0 - 2.0*(qyy + qzz);
01123     m[1][0] =     2.0*(qxy - qwz);
01124     m[2][0] =     2.0*(qxz + qwy);
01125     m[3][0] = 0.0;
01126 
01127     m[0][1] =     2.0*(qxy + qwz);
01128     m[1][1] = 1.0 - 2.0*(qzz + qxx);
01129     m[2][1] =     2.0*(qyz - qwx);
01130     m[3][1] = 0.0;
01131 
01132     m[0][2] =     2.0*(qxz - qwy);
01133     m[1][2] =     2.0*(qyz + qwx);
01134     m[2][2] = 1.0 - 2.0*(qyy + qxx);
01135     m[3][2] = 0.0;
01136 
01137     m[0][3] = 0.0;
01138     m[1][3] = 0.0;
01139     m[2][3] = 0.0;
01140     m[3][3] = 1.0;
01141   }
01142 
01143   // Time integration of a rotation velocity
01144   template <class Real, class Traits>
01145   template <class Vect >
01146   inline Quaternion<Real,Traits>
01147   Quaternion<Real,Traits>::eulerIncrement
01148   (
01149     const Vect& omega, // vector omega
01150     const Real dt   // time step
01151   )
01152   {
01153     return eulerIncrement( omega[0], omega[1], omega[2], dt );
01154   }
01155 
01156 
01157   // Time integration of a rotation velocity
01158   template <class Real, class Traits>
01159   inline Quaternion<Real,Traits>
01160   Quaternion<Real,Traits>::eulerIncrement
01161   (
01162     const Real xa, const Real ya, const Real za, // vector omega
01163     const Real dt   // time step
01164   )
01165   {
01166     // Create quaternion q with null rotation
01167     Quaternion<Real,Traits> q = Quaternion<Real,Traits>::identity();
01168 
01169     // If the rotation velocity is big enough,
01170     // then set q accordingly.
01171     Real norm = sqrt( xa*xa + ya*ya + za*za );
01172     if( norm > Traits::nullAxis() )
01173     {
01174       q.setAxisAngle( xa, ya, za, norm * dt );
01175     }
01176 
01177     // return quaternion q
01178     return q;
01179   }
01180 
01181   // Time integration of a rotation velocity during a unit time step
01182   template <class Real, class Traits>
01183   template <class Vect >
01184   inline Quaternion<Real,Traits>
01185   Quaternion<Real,Traits>::elementaryRotation
01186   (
01187     const Vect& omega // vector omega
01188   )
01189   {
01190     return elementaryRotation( omega[0], omega[1], omega[2] );
01191   }
01192 
01193   // Time integration of a rotation velocity during a unit time step
01194   template <class Real, class Traits>
01195   inline Quaternion<Real,Traits>
01196   Quaternion<Real,Traits>::elementaryRotation
01197   (
01198     const Real xa, const Real ya, const Real za // vector omega
01199   )
01200   {
01201     // Create quaternion q with null rotation
01202     Quaternion<Real,Traits> q = Quaternion<Real,Traits>::identity();
01203 
01204     // If the rotation velocity is big enough,
01205     // then set q accordingly.
01206     Real norm = sqrt( xa*xa + ya*ya + za*za );
01207     if( norm > Traits::nullAxis() )
01208     {
01209       q.setAxisAngle( xa, ya, za, 1 );
01210     }
01211 
01212     // return quaternion q
01213     return q;
01214   }
01215 
01216 } // end namespace animal
01217 
01218 
01219 
01220 #endif // _ANIMAL_GEOMETRY_QUATERNION_H_

Generated on Thu Dec 23 13:52:27 2004 by doxygen 1.3.6