00001 #ifndef _ANIMAL_GEOMETRY_QUATERNION_H_
00002 #define _ANIMAL_GEOMETRY_QUATERNION_H_
00003 
00004 #include <animal/vec3.h>
00005 
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   
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     
00053 
00056     
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     
00199     
00200 
00201 
00202     
00203     
00204     
00205     
00206 
00207     
00208     
00209     
00210 
00211 
00212     
00213     
00214     
00215     
00216     
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     
00259 
00260 
00261 
00262   private:
00263 
00264     Real v[4];   
00265 
00266 
00267   }
00268   ; 
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     
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   
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   ; 
00400 
00401 
00402 
00403 
00404 
00405 
00406 
00407 
00408 
00409 
00410   
00411   
00412   
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     
00478     
00479     
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     
00492     if ( an > Traits::nullAxis() )
00493     {
00494       Real tmp = 1.0/sin(an/2.0);
00495       
00496       x=v[0]*tmp;
00497       y=v[1]*tmp;
00498       z=v[2]*tmp;
00499     }
00500     else
00501     {
00502       x = 1.0; 
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     
00515     
00516     
00517     
00518     
00519     
00520     
00521     
00522     
00523     
00524     
00525     
00526     
00527     
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       
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 
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
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   
00909   
00910   
00911   
00912   
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   
01022   
01023   
01024   
01025   
01026   
01027   
01028   
01029   
01030   
01031   
01032   
01033   
01034   
01035   
01036   
01037   
01038   
01039   
01040   
01041   
01042   
01043   
01044   
01045   
01046   
01047   
01048   
01049   
01050   
01051   
01052   
01053   
01054   
01055   
01056 
01057   
01058   
01059   
01060   
01061   
01062   
01063   
01064   
01065   
01066   
01067   
01068   
01069   
01070   
01071   
01072   
01073   
01074   
01075   
01076   
01077   
01078   
01079   
01080   
01081   
01082   
01083   
01084   
01085   
01086   
01087   
01088   
01089   
01090   
01091   
01092   
01093   
01094   
01095   
01096   
01097   
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   
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, 
01150     const Real dt   
01151   )
01152   {
01153     return eulerIncrement( omega[0], omega[1], omega[2], dt );
01154   }
01155 
01156 
01157   
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, 
01163     const Real dt   
01164   )
01165   {
01166     
01167     Quaternion<Real,Traits> q = Quaternion<Real,Traits>::identity();
01168 
01169     
01170     
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     
01178     return q;
01179   }
01180 
01181   
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 
01188   )
01189   {
01190     return elementaryRotation( omega[0], omega[1], omega[2] );
01191   }
01192 
01193   
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 
01199   )
01200   {
01201     
01202     Quaternion<Real,Traits> q = Quaternion<Real,Traits>::identity();
01203 
01204     
01205     
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     
01213     return q;
01214   }
01215 
01216 } 
01217 
01218 
01219 
01220 #endif // _ANIMAL_GEOMETRY_QUATERNION_H_