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_