GEL  2
GEL is a library for Geometry and Linear Algebra
/Users/jab/Documents/Teaching/02585/GEL2_and_demos/GEL/src/CGLA/ArithQuat.h
00001 #ifndef __CGLA_ARITHQUAT_H__
00002 #define __CGLA_ARITHQUAT_H__
00003 
00004 #include "CGLA.h"
00005 #include "ArithVecFloat.h"
00006 #include "ArithSqMatFloat.h"
00007 #include <cmath>
00008 
00009 namespace CGLA {
00010 
00015         template<class T, class V, class Q>
00016   class ArithQuat
00017   {
00018   public:
00019 
00021     V qv;
00022 
00024     T qw;
00025 
00027 #ifndef NDEBUG
00028     ArithQuat() : qw(CGLA_INIT_VALUE) {}
00029 #else
00030     ArithQuat() {}
00031 #endif
00032 
00034     ArithQuat(const V& imaginary, T real = 1.0f) : qv(imaginary) , qw(real) {}
00035 
00037     ArithQuat(T x, T y, T z, T _qw) : qv(x,y,z), qw(_qw) {}
00038 
00039    
00041     void set(const V& imaginary, T real=1.0f)
00042     {
00043       qv = imaginary;
00044       qw = real;
00045     }
00046 
00047     void set(T x, T y, T z, T _qw) 
00048     {
00049       qv.set(x,y,z);
00050       qw = _qw;
00051     }
00052 
00053     /*void set(const Vec4f& v)
00054     {
00055       qv.set(v[0], v[1], v[2]);
00056       qw = v[3];                  
00057     }*/
00058 
00060     void get(T& x, T& y, T& z, T& _qw) const
00061     {
00062       x  = qv[0];
00063       y  = qv[1];
00064       z  = qv[2];
00065       _qw = qw;
00066     }
00067 
00069     V get_imaginary_part() const { return qv; }
00070 
00072     T get_real_part() const { return qw; }
00073 
00074 
00075 
00077     void get_rot(T& angle, V& v)
00078     {
00079       angle = 2*std::acos(qw);
00080 
00081       if(angle < TINY) 
00082                                 v = V(static_cast<T>(1.0), static_cast<T>(0.0), static_cast<T>(0.0));
00083       else 
00084                                 v = qv*(static_cast<T>(1.0)/std::sin(angle));
00085 
00086       if(angle > M_PI)
00087                                 v = -v;
00088       
00089       v.normalize();      
00090     }
00091 
00093     void make_rot(T angle, const V& v)
00094     {
00095       angle /= static_cast<T>(2.0);
00096       qv = CGLA::normalize(v)*std::sin(angle);
00097       qw = std::cos(angle);
00098     }
00099 
00102     void make_rot(const V& s,const V& t)
00103     {
00104       T tmp = std::sqrt(2*(1 + dot(s, t)));
00105       qv = cross(s, t)*(1.0/tmp);
00106       qw = tmp/2.0;    
00107     }
00108 
00110     template <class VT, class MT, unsigned int ROWS>
00111     void make_rot(ArithSqMatFloat<VT,MT,ROWS>& m)
00112     {
00113       assert(ROWS==3 || ROWS==4);
00114       T trace = m[0][0] + m[1][1] + m[2][2]  + static_cast<T>(1.0);
00115 
00116       //If the trace of the matrix is greater than zero, then
00117       //perform an "instant" calculation.
00118       if ( trace > TINY ) 
00119       {
00120         T S = sqrt(trace) * static_cast<T>(2.0);
00121         qv = V(m[2][1] - m[1][2], m[0][2] - m[2][0], m[1][0] - m[0][1] );
00122         qv /= S;
00123         qw = static_cast<T>(0.25) * S;
00124       }
00125       else
00126       {
00127         //If the trace of the matrix is equal to zero (or negative...) then identify
00128         //which major diagonal element has the greatest value.
00129         //Depending on this, calculate the following:
00130 
00131         if ( m[0][0] > m[1][1] && m[0][0] > m[2][2] )  {        // Column 0: 
00132           T S  = sqrt( static_cast<T>(1.0) + m[0][0] - m[1][1] - m[2][2] ) * static_cast<T>(2.0);
00133           qv[0] = 0.25f * S;
00134           qv[1] = (m[1][0] + m[0][1] ) / S;
00135           qv[2] = (m[0][2] + m[2][0] ) / S;
00136           qw = (m[2][1] - m[1][3] ) / S;
00137         } else if ( m[1][1] > m[2][2] ) {                       // Column 1: 
00138           T S  = sqrt( 1.0 + m[1][1] - m[0][0] - m[2][2] ) * 2.0;
00139           qv[0] = (m[1][0] + m[0][1] ) / S;
00140           qv[1] = 0.25 * S;
00141           qv[2] = (m[2][1] + m[1][2] ) / S;
00142           qw = (m[0][2] - m[2][0] ) / S;
00143         } else {                                                // Column 2:
00144           T S  = sqrt( 1.0 + m[2][2] - m[0][0] - m[1][1] ) * 2.0;
00145           qv[0] = (m[0][2] + m[2][0] ) / S;
00146           qv[1] = (m[2][1] + m[1][2] ) / S;
00147           qv[2] = 0.25 * S;
00148           qw = (m[1][0] - m[0][1] ) / S;
00149         }
00150       }
00151       //The quaternion is then defined as:
00152       //  Q = | X Y Z W |
00153     }
00154 
00155     //----------------------------------------------------------------------
00156     // Binary operators
00157     //----------------------------------------------------------------------
00158     
00159     bool operator==(const ArithQuat<T,V,Q>& q) const
00160     {
00161       return qw == q.qw && qv == q.qv;
00162     }
00163 
00164     bool operator!=(const ArithQuat<T,V,Q>& q) const
00165     {
00166       return qw != q.qw || qv != q.qv;
00167     }
00168 
00170     Q operator*(const ArithQuat<T,V,Q>& q) const
00171     {
00172       return Q(cross(qv, q.qv) + qv*q.qw + q.qv*qw, 
00173                          qw*q.qw - dot(qv, q.qv));      
00174     }
00175 
00177     Q operator*(T scalar) const
00178     {
00179       return Q(qv*scalar, qw*scalar);
00180     }
00181 
00183     Q operator+(const ArithQuat<T,V,Q>& q) const
00184     {
00185       return Q(qv + q.qv, qw + q.qw);
00186     }
00187 
00188     //----------------------------------------------------------------------
00189     // Unary operators
00190     //----------------------------------------------------------------------
00191 
00193     Q operator-() const { return Q(-qv, -qw); }
00194 
00196     T norm() const { return dot(qv, qv) + qw*qw; }
00197 
00199     Q conjugate() const { return Q(-qv, qw); }
00200 
00202     Q inverse() const { return Q(conjugate()*(1/norm())); }
00203     
00205     Q normalize() { return Q((*this)*(1/norm())); }
00206 
00207     //----------------------------------------------------------------------
00208     // Application
00209     //----------------------------------------------------------------------
00210 
00212     V apply(const V& vec) const 
00213     {
00214       return ((*this)*Q(vec)*inverse()).qv;
00215     }
00216 
00218     V apply_unit(const V& vec) const
00219     {
00220           assert(fabs(norm() - 1.0) < SMALL);
00221       return ((*this)*Q(vec)*conjugate()).qv;
00222     }
00223   };
00224 
00225   template<class T, class V, class Q>
00226   inline Q operator*(T scalar, const ArithQuat<T,V,Q>& q)
00227   {
00228     return q*scalar;
00229   }
00230 
00237         template<class T, class V, class Q>
00238   inline Q slerp(const ArithQuat<T,V,Q>& q0, const ArithQuat<T,V,Q>& q1, T t)
00239   {
00240     T angle = std::acos(q0.qv[0]*q1.qv[0] + q0.qv[1]*q1.qv[1] 
00241                             + q0.qv[2]*q1.qv[2] + q0.qw*q1.qw);
00242     return (q0*std::sin((1 - t)*angle) + q1*std::sin(t*angle))*(1/std::sin(angle));
00243   }
00244 
00246   template<class T, class V, class Q>
00247   inline std::ostream& operator<<(std::ostream&os, const ArithQuat<T,V,Q>& v)
00248   {
00249     os << "[ ";
00250     for(unsigned int i=0;i<3;i++) os << v.qv[i] << " ";
00251     os << "~ " << v.qw << " ";
00252     os << "]";
00253 
00254     return os;
00255   }
00256 }
00257 
00258 
00259 
00260 
00261 
00262 
00263 
00264 
00265 
00266 
00267 
00268 
00269 
00270 
00271 
00272 
00273 
00274 #endif // __CGLA_ARITHQUAT_H__
 All Classes Namespaces Files Functions Variables Typedefs Enumerations