rtcQuaternion.h
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2008
00003  * Robert Bosch LLC
00004  * Research and Technology Center North America
00005  * Palo Alto, California
00006  *
00007  * All rights reserved.
00008  *
00009  *------------------------------------------------------------------------------
00010  * project ....: Autonomous Technologies
00011  * file .......: rtcQuaternion.h
00012  * authors ....: Benjamin Pitzer
00013  * organization: Robert Bosch LLC
00014  * creation ...: 08/16/2006
00015  * modified ...: $Date: 2009-01-21 18:19:16 -0800 (Wed, 21 Jan 2009) $
00016  * changed by .: $Author: benjaminpitzer $
00017  * revision ...: $Revision: 14 $
00018  */
00019 #ifndef RTC_QUATERNION_H
00020 #define RTC_QUATERNION_H
00021 
00022 //== INCLUDES ==================================================================
00023 #include "rtc/rtcMath.h"
00024 #include "rtc/rtcEulerAngles.h"
00025 #include "rtc/rtcRotation.h"
00026 #include "rtc/rtcTransform.h"
00027 #include "rtc/rtcSMat3.h"
00028 #include "rtc/rtcSMat4.h"
00029 #include "rtc/rtcVec3.h"
00030 #include "rtc/rtcVec4.h"
00031 
00032 //== NAMESPACES ================================================================
00033 namespace rtc {
00034 
00035 // Forward declarations
00036 template <class T> class EulerAngles;   // Euler angles
00037 template <class T> class Rotation;      // Rotation matrix (3x3)
00038 template <class T> class Transform;     // Rigid tranform matrix (4x4)
00039 template <class T> class Quaternion;    // Quaternion
00040 template <class T> class SMat3;         // 3x3 Matrix
00041 template <class T> class SMat4;         // 4x4 Matrix
00042 template <class T> class Vec3;          // 3d Vector
00043 
00052 template <class T>
00053 class Quaternion: public Vec4<T> {
00054 public:
00055   // Inherited from parent
00056   using Vec4<T>::x;
00057   using Vec4<T>::set;
00058   using Vec4<T>::normalize;
00059   using Vec4<T>::operator *=;
00060   using Vec4<T>::operator *;
00061 
00063   Quaternion();
00064   Quaternion(const T w, const T x, const T y, const T z);
00065   Quaternion(const Vec<T,4>& v);
00066 
00067   Quaternion(const Vec<T,3>& n, const T theta); // axis angle
00068   Quaternion(const EulerAngles<T>& e);
00069   Quaternion(const Rotation<T>& r);
00070 
00072   void set(const Vec<T,3>& n, const T theta); // axis angle
00073   void set(const EulerAngles<T>& e);
00074   void set(const Rotation<T>& r);
00075   
00077   T angle() const;
00078   T w() const;
00079   Vec<T,3> axis() const;
00080 
00082   Quaternion<T> operator * (const Quaternion<T>& q) const;
00083   void operator *= (const Quaternion<T>& q);
00084   Quaternion<T> conjugated() const;
00085   void conjugate();
00086   Quaternion<T> inverted() const;
00087   void invert();
00088   T angle(const Quaternion<T>& q) const;
00089   Quaternion<T> slerp(const Quaternion<T>& q, const T& t) const;
00090 
00092   SMat3<T> drot_dqj(const int j) const;
00093   static SMat3<T> d2rot_dqkdqj(int k, int j);
00094   static SMat4<T> dquatMat_dqj(const int j);
00095   SMat4<T> quatMat();
00096   SMat4<T> quatMatT();
00097   SMat4<T> quatMatBar();
00098   SMat4<T> quatMatBarT();
00099 
00101   void rotate(Vec<T,3>& v) const;
00102   Vec<T,3> rotated(const Vec<T,3>& v) const;
00103 };
00104 
00105 // Declare a few common typdefs
00106 typedef Quaternion<float> Quaternionf;
00107 typedef Quaternion<double> Quaterniond;
00108 
00109 //==============================================================================
00110 // Quaternion<T>
00111 //==============================================================================
00112 
00113 // Constructors
00114 
00117 template <class T>
00118 inline Quaternion<T>::Quaternion() {
00119   set(T(1),T(0),T(0),T(0));
00120 }
00121 
00124 template <class T>
00125 inline Quaternion<T>::Quaternion(const T w, const T _x, const T y, const T z) {
00126   set(w,_x,y,z);
00127 }
00128 
00131 template <class T>
00132 inline Quaternion<T>::Quaternion(const Vec<T,4>& v) : Vec4<T>(v) {}
00133 
00138 template <class T>
00139 inline Quaternion<T>::Quaternion(const Vec<T,3>& n, const T theta) {
00140   set(n,theta);
00141 }
00142 
00146 template <class T>
00147 inline Quaternion<T>::Quaternion(const EulerAngles<T>& e) {
00148   set(e);
00149 }
00150 
00155 template <class T>
00156 inline Quaternion<T>::Quaternion(const Rotation<T>& r) {
00157   set(r);
00158 }
00159 
00160 // Mutators
00161 
00166 template <class T>
00167 inline void Quaternion<T>::set(const Vec<T,3>& n, const T theta) {
00168   T s = sin(theta/T(2));
00169   Vec<T,3> nn = n.normalized();
00170   set(cos(theta/T(2)),s*nn.x[0],s*nn.x[1],s*nn.x[2]);
00171   normalize();
00172 }
00173 
00177 template <class T>
00178 inline void Quaternion<T>::set(const EulerAngles<T>& e) {
00179   using namespace std;
00180   T cr = cos(T(0.5)*e.x[0]); T sr = sin(T(0.5)*e.x[0]);
00181   T cp = cos(T(0.5)*e.x[1]); T sp = sin(T(0.5)*e.x[1]);
00182   T cy = cos(T(0.5)*e.x[2]); T sy = sin(T(0.5)*e.x[2]);
00183   T w = cy*cp*cr + sy*sp*sr;
00184   if (w<0) set(-w,sy*sp*cr-cy*cp*sr,-cy*sp*cr-sy*cp*sr,cy*sp*sr-sy*cp*cr);
00185   else set(w,cy*cp*sr-sy*sp*cr,cy*sp*cr+sy*cp*sr,sy*cp*cr-cy*sp*sr);
00186 }
00187 
00192 template <class T>
00193 inline void Quaternion<T>::set(const Rotation<T>& r) {
00194   T n4;
00195   T tr = r.trace();
00196   if (tr > T(0)) {
00197     set(tr + T(1), -(r(1,2) - r(2,1)),
00198   -(r(2,0) - r(0,2)), -(r(0,1) - r(1,0)));
00199     n4 = x[0];
00200   } else if ((r(0,0) > r(1,1)) && (r(0,0) > r(2,2))) {
00201     set(r(1,2) - r(2,1), -(1.0f + r(0,0) - r(1,1) - r(2,2)),
00202   -(r(1,0) + r(0,1)), -(r(2,0) + r(0,2)));
00203     n4 = -x[1];
00204   } else if (r(1,1) > r(2,2)) {
00205     set(r(2,0) - r(0,2), -(r(1,0) + r(0,1)),
00206   -(1.0f + r(1,1) - r(0,0) - r(2,2)), -(r(2,1) + r(1,2)));
00207     n4 = -x[2];
00208   } else {
00209     set(r(0,1) - r(1,0), -(r(2,0) + r(0,2)), -(r(2,1) + r(1,2)),
00210   -(1.0f + r(2,2) - r(0,0) - r(1,1)));
00211     n4 = -x[3];
00212   }
00213   if (x[0] < T(0)) operator *= (T(-0.5)/T(sqrt(n4)));
00214   else operator *= (T(0.5)/T(sqrt(n4)));
00215 }
00216 
00222 template <class T>
00223 Quaternion<T> Quaternion<T>::slerp(const Quaternion<T>& q, const T& t) const 
00224 { 
00225   T theta = angle(q); 
00226   if (theta != T(0.0)) 
00227   { 
00228           T d = T(1.0) / rtc_sin(theta); 
00229           T s0 = rtc_sin((T(1.0) - t) * theta); 
00230           T s1 = rtc_sin(t * theta);   
00231           if (dot(q) < 0) // Take care of long angle case see http://en.wikipedia.org/wiki/Slerp 
00232             return Quaternion<T>((x[0] * s0 + -q.x[0] * s1) * d, 
00233                                  (x[1] * s0 + -q.x[1] * s1) * d, 
00234                                  (x[2] * s0 + -q.x[2] * s1) * d, 
00235                                  (x[3] * s0 + -q.x[3] * s1) * d); 
00236           else 
00237             return Quaternion<T>((x[0] * s0 + q.x[0] * s1) * d, 
00238                                  (x[1] * s0 + q.x[1] * s1) * d, 
00239                                  (x[2] * s0 + q.x[2] * s1) * d, 
00240                                  (x[3] * s0 + q.x[3] * s1) * d); 
00241           
00242   } 
00243   else 
00244   { 
00245           return *this; 
00246   } 
00247 } 
00248 
00249 // Accessors
00250 
00253 template <class T>
00254 inline T Quaternion<T>::w() const {
00255   return x[0];
00256 }
00257 
00260 template <class T>
00261 inline T Quaternion<T>::angle() const {
00262   return T(2.0)*acos(x[0]);
00263 }
00264 
00267 template <class T>
00268 inline Vec<T,3> Quaternion<T>::axis() const {
00269   Vec3<T> n(x[1],x[2],x[3]);
00270   n.normalize();
00271   return n;
00272 }
00273 
00274 // Quaternion operations
00275 
00278 template <class T>
00279 inline Quaternion<T> Quaternion<T>::operator*(const Quaternion<T>& q) const {
00280   return Quaternion<T>(x[0]*q.x[0] - x[1]*q.x[1] - x[2]*q.x[2] - x[3]*q.x[3],
00281                        x[0]*q.x[1] + x[1]*q.x[0] + x[2]*q.x[3] - x[3]*q.x[2],
00282                        x[0]*q.x[2] - x[1]*q.x[3] + x[2]*q.x[0] + x[3]*q.x[1],
00283                        x[0]*q.x[3] + x[1]*q.x[2] - x[2]*q.x[1] + x[3]*q.x[0]);
00284 }
00285 
00286 
00289 template <class T>
00290 inline void Quaternion<T>::operator *= (const Quaternion<T>& q) {
00291   set(x[0]*q.x[0] - x[1]*q.x[1] - x[2]*q.x[2] - x[3]*q.x[3],
00292 x[0]*q.x[1] + x[1]*q.x[0] + x[2]*q.x[3] - x[3]*q.x[2],
00293 x[0]*q.x[2] - x[1]*q.x[3] + x[2]*q.x[0] + x[3]*q.x[1],
00294 x[0]*q.x[3] + x[1]*q.x[2] - x[2]*q.x[1] + x[3]*q.x[0]);
00295 }
00296 
00300 template <class T>
00301 inline Quaternion<T> Quaternion<T>::conjugated() const {
00302   return Quaternion<T>(x[0],-x[1],-x[2],-x[3]);
00303 }
00304 
00308 template <class T>
00309 inline void Quaternion<T>::conjugate() {
00310   x[1] = -x[1]; x[2] = -x[2]; x[3] = -x[3];
00311 }
00312 
00316 template <class T>
00317 inline Quaternion<T> Quaternion<T>::inverted() const {
00318   T l2 = x[0]*x[0] + x[1]*x[1] + x[2]*x[2] + x[3]*x[3];
00319   return Quaternion<T>(x[0]/l2,-x[1]/l2,-x[2]/l2,-x[3]/l2);
00320 }
00321 
00325 template <class T>
00326 inline void Quaternion<T>::invert() {
00327   T l2 = x[0]*x[0] + x[1]*x[1] + x[2]*x[2] + x[3]*x[3];
00328   x[0] = x[0]/l2; x[1] = -x[1]/l2; x[2] = -x[2]/l2; x[3] = -x[3]/l2;
00329 }
00330 
00333 template <class T>
00334 inline T Quaternion<T>::angle(const Quaternion<T>& q) const
00335 {
00336   T s = rtc_sqrt(this->normSqr() * q.normSqr());
00337   if(s == T(0)) return 0.0; 
00338   T retval; 
00339   if (dot(q) < 0) // Take care of long angle case see http://en.wikipedia.org/wiki/Slerp 
00340     retval = rtc_acos(rtc_clamp(dot(-q) / s, (T)-1.0, (T)1.0)); //Clamped to prevent floating point precision crashes
00341 
00342   else 
00343     retval = rtc_acos(rtc_clamp(dot(q) / s, (T)-1.0, (T)1.0)); //Clamped to prevent floating point precision crashes
00344 
00345   return retval; 
00346 } 
00347 
00348 // Quaternion derivatives and matrices
00349 
00353 template <class T>
00354 inline SMat3<T> Quaternion<T>::drot_dqj(const int j) const {
00355   switch(j) {
00356   case 0: return SMat3<T>(2*x[0], -2*x[3],  2*x[2],
00357                           2*x[3],  2*x[0], -2*x[1],
00358                          -2*x[2], 2*x[1], 2*x[0]);
00359   case 1: return SMat3<T>( 2*x[1],  2*x[2],  2*x[3],
00360                            2*x[2], -2*x[1], -2*x[0],
00361                            2*x[3],  2*x[0], -2*x[1]);
00362   case 2: return SMat3<T>(-2*x[2],  2*x[1],  2*x[0],
00363                            2*x[1],   2*x[2],  2*x[3],
00364                           -2*x[0],  2*x[3], -2*x[2]);
00365   case 3: return SMat3<T>(-2*x[3], -2*x[0],  2*x[1],
00366                            2*x[0],  -2*x[3],  2*x[2],
00367                            2*x[1],   2*x[2],  2*x[3]);
00368   }
00369   return SMat3<T>(T(0));
00370 }
00371 
00375 template <class T>
00376 inline SMat3<T> Quaternion<T>::d2rot_dqkdqj(int k, int j) {
00377   if (j>k) { int temp = j; j=k; k=temp; }
00378   if (j==0 && k==0) return SMat3<T>(1,0,0,  0,1,0,  0,0,1);
00379   if (j==0 && k==1) return SMat3<T>(0,0,0,  0,0,-1,  0,1,0);
00380   if (j==0 && k==2) return SMat3<T>(0,0,1,  0,0,0,  -1,0,0);
00381   if (j==0 && k==3) return SMat3<T>(0,-1,0,  1,0,0,  0,0,0);
00382 
00383   if (j==1 && k==1) return SMat3<T>(1,0,0,  0,-1,0,  0,0,-1);
00384   if (j==1 && k==2) return SMat3<T>(0,1,0,  1,0,0,  0,0,0);
00385   if (j==1 && k==3) return SMat3<T>(0,0,1,  0,0,0,  1,0,0);
00386 
00387   if (j==2 && k==2) return SMat3<T>(-1,0,0,  0,1,0,  0,0,-1);
00388   if (j==2 && k==3) return SMat3<T>(0,0,0,  0,0,1,  0,1,0);
00389 
00390   if (j==3 && k==3) return SMat3<T>(-1,0,0,  0,-1,0,  0,0,1);
00391 
00392   return SMat3<T>(T(0));
00393 }
00394 
00398 template <class T>
00399 inline SMat4<T> Quaternion<T>::quatMat() {
00400   return SMat4<T>(x[0], -x[1], -x[2], -x[3],
00401       x[1],  x[0], -x[3],  x[2],
00402       x[2],  x[3],  x[0], -x[1],
00403       x[3], -x[2],  x[1],  x[0]);
00404 }
00405 
00408 template <class T>
00409 inline SMat4<T> Quaternion<T>::quatMatT() {
00410   return  SMat4<T>(x[0],   x[1],  x[2],  x[3],
00411        -x[1],  x[0],  x[3], -x[2],
00412        -x[2], -x[3],  x[0],  x[1],
00413        -x[3],  x[2], -x[1],  x[0]);
00414 }
00415 
00418 template <class T>
00419 inline SMat4<T> Quaternion<T>::quatMatBar() {
00420   return SMat4<T>(x[0], -x[1], -x[2], -x[3],
00421       x[1],  x[0],  x[3], -x[2],
00422       x[2], -x[3],  x[0],  x[1],
00423       x[3],  x[2], -x[1],  x[0]);
00424 }
00425 
00428 template <class T>
00429 inline SMat4<T> Quaternion<T>::quatMatBarT() {
00430   return  SMat4<T>(x[0],   x[1],  x[2],  x[3],
00431        -x[1],  x[0], -x[3],  x[2],
00432        -x[2],  x[3],  x[0], -x[1],
00433        -x[3], -x[2],  x[1],  x[0]);
00434 }
00435 
00438 template <class T>
00439 inline SMat4<T> Quaternion<T>::dquatMat_dqj(const int j) {
00440   switch(j) {
00441   case 0: return SMat4<T>(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1);
00442   case 1: return SMat4<T>(0,-1,0,0,1,0,0,0,0,0,0,-1,0,0,1,0);
00443   case 2: return SMat4<T>(0,0,-1,0,0,0,0,1,1,0,0,0,0,-1,0,0);
00444   case 4: return SMat4<T>(0,0,0,-1,0,0,-1,0,0,1,0,0,1,0,0,0);
00445   }
00446   return SMat4<T>(T(0));
00447 }
00448 
00451 template <class T>
00452 inline void Quaternion<T>::rotate(Vec<T,3>& v) const {
00453   T a = T(2)*x[0]*x[0] - T(1);
00454   T b = T(2)*(x[1]*v.x[0] + x[2]*v.x[1] + x[3]*v.x[2]);
00455   T u0 = a*v.x[0] + b*x[1] + T(2)*x[0]*(x[2]*v.x[2] - x[3]*v.x[1]);
00456   T u1 = a*v.x[1] + b*x[2] + T(2)*x[0]*(x[3]*v.x[0] - x[1]*v.x[2]);
00457   T u2 = a*v.x[2] + b*x[3] + T(2)*x[0]*(x[1]*v.x[1] - x[2]*v.x[0]);
00458   v.x[0] = u0; v.x[1] = u1; v.x[2] = u2;
00459 }
00460 
00463 template <class T>
00464 inline Vec<T,3> Quaternion<T>::rotated(const Vec<T,3>& v) const {
00465   T a = T(2)*x[0]*x[0] - T(1);
00466   T b = T(2)*(x[1]*v.x[0] + x[2]*v.x[1] + x[3]*v.x[2]);
00467   return Vec3<T>(a*v.x[0] + b*x[1] + 2*x[0]*(x[2]*v.x[2] - x[3]*v.x[1]),
00468       a*v.x[1] + b*x[2] + 2*x[0]*(x[3]*v.x[0] - x[1]*v.x[2]),
00469       a*v.x[2] + b*x[3] + 2*x[0]*(x[1]*v.x[1] - x[2]*v.x[0]));
00470 }
00471 
00472 //==============================================================================
00473 } // namespace rtc
00474 //==============================================================================
00475 #endif // RTC_QUATERNION_H defined
00476 //==============================================================================


rtc
Author(s): Benjamin Pitzer
autogenerated on Mon Oct 6 2014 10:07:35