# Home    # nevrax.com   
Nevrax
Nevrax.org
#News
#Mailing-list
#Documentation
#CVS
#Bugs
#License
Docs
 
Documentation  
Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages   Search  

quat.h

Go to the documentation of this file.
00001 
00007 /* Copyright, 2000 Nevrax Ltd.
00008  *
00009  * This file is part of NEVRAX NEL.
00010  * NEVRAX NEL is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2, or (at your option)
00013  * any later version.
00014 
00015  * NEVRAX NEL is distributed in the hope that it will be useful, but
00016  * WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00018  * General Public License for more details.
00019 
00020  * You should have received a copy of the GNU General Public License
00021  * along with NEVRAX NEL; see the file COPYING. If not, write to the
00022  * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
00023  * MA 02111-1307, USA.
00024  */
00025 
00026 #ifndef NL_QUAT_H 
00027 #define NL_QUAT_H 
00028 
00029 #include "nel/misc/types_nl.h"
00030 #include "nel/misc/vector.h"
00031 #include "nel/misc/stream.h"
00032 #include <math.h>
00033 
00034 namespace       NLMISC
00035 {
00036 
00037 
00038 // ***************************************************************************
00039 const   double  QuatEpsilon= 0.000001;
00040 
00041 
00042 
00043 // ***************************************************************************
00050 struct  CAngleAxis
00051 {
00052         CVector         Axis;           
00053         float           Angle;          
00054 
00055         CAngleAxis() {}
00056         CAngleAxis(CVector axis, float ang) : Axis(axis), Angle(ang) {}
00057 
00059         void    serial(IStream &f)
00060         {
00061                 f.serial(Axis);
00062                 f.serial(Angle);
00063         }
00064 };
00065 
00066 
00067 // ***************************************************************************
00074 template <class T> class CQuatT
00075 {
00076 public:
00077         T x,y,z,w;
00078 
00079 
00080 public:
00081 
00083         // @{
00084         CQuatT() : x((T)0.0),y((T)0.0),z((T)0.0),w((T)1.0) {}
00085         CQuatT(T X, T Y, T Z, T W) : x(X), y(Y), z(Z), w(W) {}
00087         CQuatT(const CVector &axis, float angle) {setAngleAxis(axis, angle);}
00089         CQuatT(const CAngleAxis &aa) {setAngleAxis(aa);}
00090         // @}
00091 
00092     
00094         // @{
00095         void    set(T X, T Y, T Z, T W)         {x= X; y= Y; z= Z; w= W;}
00096         // @}
00097 
00099         // @{
00100         bool    operator==(const CQuatT& a) const               {return (x==0 && y==0 && z==0 && w==1.0f);}
00101         bool    equal(const CQuatT& a, float epsilon = 1E-6f) const;
00102         void    identity()                                              {x = y = z = 0.0f ;     w = 1.0f; }
00103         bool    isIdentity() const                              {return (x==0.0f && y==0.0f && z==0.0f && w==1.0f);}
00104         // @}
00105 
00107         // @{
00108         CQuatT& operator+=(const CQuatT&o)              {x+=o.x; y+=o.y; z+=o.z; w+=o.w; return *this;}
00109         CQuatT& operator-=(const CQuatT&o)              {x-=o.x; y-=o.y; z-=o.z; w-=o.w; return *this;}
00110         CQuatT& operator*=(T f)                                 {x*=f;y*=f;z*=f;w*=f; return *this;}
00111         CQuatT& operator/=(T f)                                 {double oof= 1.0/f; x=(T)(x*oof); y=(T)(y*oof); z= (T)(z*oof); w=(T)(w*oof); return *this;}
00112         CQuatT  operator+(const CQuatT&o) const {return CQuatT(x+o.x,y+o.y,z+o.z,w+o.w);}
00113         CQuatT  operator-(const CQuatT&o) const {return CQuatT(x-o.x,y-o.y,z-o.z,w-o.w);}
00114         CQuatT  operator*(T f) const                    {return CQuatT(x*f,y*f,z*f,w*f);}
00115         CQuatT  operator/(T f) const                    {double oof= 1.0/f; return CQuatT(x*oof,y*oof,z*oof,w*oof);}
00116         CQuatT  operator-() const                               {return(CQuatT(-x,-y,-z,-w)); }
00117         CQuatT  operator+() const                               {return *this; }
00119         T               sqrnorm() const                                 {return (x*x + y*y + z*z + w*w);}
00121         T               norm() const                                    {return (T)sqrt(sqrnorm());}
00123         void    normalize();
00125         CQuatT  normed() const                                  {CQuatT ret= *this; ret.normalize(); return ret;}
00126         // @}
00127 
00128 
00130         // @{
00132         CQuatT  operator*(const CQuatT&) const; 
00133         CQuatT& operator*=(const CQuatT&);
00135         void    invert();
00137         CQuatT  inverted() const                                {CQuatT ret= *this; ret.invert(); return ret;}
00139         CQuatT  conjugate() const                               {return CQuatT(-x, -y, -z, w);}
00140         // @}
00141 
00142 
00144         // @{
00146         CVector getAxis() const {CVector ret((float)x,(float)y,(float)z); return ret.normed();}
00148         float   getAngle() const {return (float)(2*acos(w/norm()));}
00150         CAngleAxis      getAngleAxis() const {return CAngleAxis(getAxis(), getAngle());}
00151 
00153         void    setAngleAxis(const CVector &axis, float angle);
00155         void    setAngleAxis(const CAngleAxis &angAxis) {setAngleAxis(angAxis.Axis, angAxis.Angle);}
00156         // @}
00157 
00158 
00160         // @{
00162         CQuatT  log();
00164         CQuatT  exp();
00166         void    makeClosest(const CQuatT &o);
00168         void    serial(IStream &f)
00169         {
00170                 f.serial(x,y,z,w);
00171         }
00172         // @}
00173 
00174 
00175 public:
00176 
00178         // @{
00180         static  T               dotProduct(const CQuatT<T> &q0, const CQuatT<T> &q1);
00184         static  CQuatT  slerp(const CQuatT<T>& q0, const CQuatT<T>& q1, float t);
00188         static  CQuatT  squad(const CQuatT<T>& q0, const CQuatT<T>& tgtQ0, const CQuatT<T>& tgtQ1, const CQuatT<T>& q1, float t);
00191         static  CQuatT  squadrev(const CAngleAxis &rot, const CQuatT<T>& q0, const CQuatT<T>& tgtQ0, const CQuatT<T>& tgtQ1, const CQuatT<T>& q1, float t);
00192 
00194         static  CQuatT  lnDif(const CQuatT &q0, const CQuatT &q1);
00195 
00196         // @}
00197 
00198 
00199 };
00200 
00201 
00202 
00203 // ***************************************************************************
00204 
00205 
00207 // @{
00208 
00210 template <class T> 
00211 inline  CQuatT<T>       operator*(T f, const CQuatT<T> &o) {return o*f;}
00212 
00213 // @}
00214 
00215 
00216 
00217 // ***************************************************************************
00218 // ***************************************************************************
00219 // Template implementation.
00220 // ***************************************************************************
00221 // ***************************************************************************
00222 
00223 
00224 
00225 // ***************************************************************************
00226 template <class T> 
00227 inline bool     CQuatT<T>::equal(const CQuatT<T>& a, float epsilon) const
00228 {
00229         if (fabs(x-a.x)<epsilon &&
00230                 fabs(y-a.y)<epsilon &&
00231                 fabs(z-a.z)<epsilon &&
00232                 fabs(w-a.w)<epsilon )
00233         {
00234                 return true;
00235         }
00236         return false;
00237 }
00238 
00239 
00240 // ***************************************************************************
00241 template <class T> 
00242 inline CQuatT<T>        CQuatT<T>::operator*(const CQuatT<T>& o) const
00243 {
00244         // wres= ww´ - v·v´
00245         // vres= wv´ + w´v + v^v´ ] 
00246         return  CQuatT<T>(
00247                                         (w*o.x) +(x*o.w) + (y*o.z)-(z*o.y),
00248                                         (w*o.y) +(y*o.w) + (z*o.x)-(x*o.z),
00249                                         (w*o.z) +(z*o.w) + (x*o.y)-(y*o.x),
00250                                         (w*o.w)-(x*o.x)-(y*o.y)-(z*o.z) );
00251 
00252 }
00253 
00254 // ***************************************************************************
00255 template <class T> 
00256 inline CQuatT<T>&       CQuatT<T>::operator*=(const CQuatT<T>& o)
00257 {
00258         *this= *this * o;
00259         return *this;
00260 }
00261 
00262 
00263 // ***************************************************************************
00264 template <class T> 
00265 inline void     CQuatT<T>::invert()
00266 {
00267         // Must invert the norm.
00268         T       f= sqrnorm();
00269         if(f!=0)
00270         {
00271                 *this/=f;
00272         }
00273 
00274         *this= conjugate();
00275 }
00276 
00277 
00278 // ***************************************************************************
00279 template <class T> 
00280 inline void     CQuatT<T>::normalize()
00281 {
00282         T       f= norm();
00283         if(f==0)
00284                 identity();
00285         else
00286         {
00287                 *this/=f;
00288         }
00289 }
00290 
00291 
00292 // ***************************************************************************
00293 template <class T> 
00294 inline void     CQuatT<T>::setAngleAxis(const CVector &axis, float angle)
00295 {
00296         CVector         v= axis;
00297         v.normalize();
00298         double  ca= cos(angle/2);
00299         double  sa= sin(angle/2);
00300         x= (T)(v.x*sa);
00301         y= (T)(v.y*sa);
00302         z= (T)(v.z*sa);
00303         w= (T)(ca);
00304 }
00305 
00306 
00307 // ***************************************************************************
00308 template <class T> 
00309 T       CQuatT<T>::dotProduct(const CQuatT<T> &q0, const CQuatT<T> &q1)
00310 {
00311         return q0.x*q1.x + q0.y*q1.y + q0.z*q1.z + q0.w*q1.w;
00312 }
00313 
00314 
00315 // ***************************************************************************
00316 template <class T> 
00317 CQuatT<T>       CQuatT<T>::slerp(const CQuatT<T>& q0, const CQuatT<T>& q1, float t)
00318 {
00319         // omega is the 4D angle between q0 and q1.
00320         double  omega, cosom,sinom;
00321         T       factq0= 1;
00322         T       s0,s1;
00323 
00324         cosom = CQuatT<T>::dotProduct(q0, q1);
00325 
00326         // Make q0 and q1 on the same hemisphere.
00327         /*if(cosom<0)
00328         {
00329                 cosom= -cosom;
00330                 factq0= -1;
00331         }*/
00332         // ????
00333 
00334         if ( cosom < 1.0 - NLMISC::QuatEpsilon)
00335         { 
00336                 omega = acos(cosom);
00337                 sinom = sin(omega);
00338                 s0 = (T) (sin((1.0f - t)*omega) / sinom);
00339                 s1 = (T) (sin(t*omega) / sinom);
00340         }
00341         else
00342         {       // q0 and q1 are nearly the same => sinom nearly 0. We can't slerp.
00343                 // just linear interpolate.
00344                 s0 = (T)(1.0 - t);
00345                 s1 = t;
00346         }
00347 
00348         return  q0*(factq0*s0) + q1*s1;
00349 
00350 }
00351 
00352 
00353 // ***************************************************************************
00354 template <class T> 
00355 CQuatT<T>       CQuatT<T>::squad(const CQuatT<T>& q0, const CQuatT<T>& tgtQ0, const CQuatT<T>& tgtQ1, const CQuatT<T>& q1, float t)
00356 {
00357         return CQuatT<T>::slerp(
00358                 CQuatT<T>::slerp(q0, q1, t),
00359                 CQuatT<T>::slerp(tgtQ0, tgtQ1, t),
00360                 2.f*(1.f-t)*t);
00361 }
00362 
00363 
00364 // ***************************************************************************
00365 template <class T> 
00366 CQuatT<T>       CQuatT<T>::squadrev(const CAngleAxis &rot, const CQuatT<T>& q0, const CQuatT<T>& tgtQ0, const CQuatT<T>& tgtQ1, const CQuatT<T>& q1, float t)
00367 {
00368         float s,v;
00369         float omega = rot.Angle* 0.5f;
00370         float nrevs = 0.0f;
00371         CQuatT<T>       ret,qaxis,pp,qq;
00372 
00373         // just one rev?
00374         //==============
00375         if (omega<Pi-QuatEpsilon)
00376         {
00377                 ret = CQuatT<T>::squad(q0,tgtQ0,tgtQ1,q1,t);
00378                 return ret; 
00379         }
00380 
00381 
00382         // multirev.
00383         //==============
00384 
00385         // rotation of 180° around rot.Axis.  (=> sin(a/2)==sin(Pi/2)==1, and c(a/2)=0).
00386         qaxis.set(rot.Axis.x, rot.Axis.y, rot.Axis.z, 0);
00387 
00388         // the number of revisions (float!)
00389         nrevs= (float)(omega/Pi);
00390         // Angle>2Pi. squad from 0 to Pi, slerp from Pi to Angle-Pi, squad from Angle-Pi to Angle.
00391         s = t*2*nrevs;
00392         
00393 
00394         // So for s, squad from 0 to 1, slerp from 1 to 2*nrevs-1, squad from 2*nrevs-1 to 2*nrevs.
00395         if (s < 1.0f)
00396         {
00397                 // first part.
00398                 pp = q0*qaxis;
00399                 ret = CQuatT<T>::squad(q0,tgtQ0,pp,pp,s);
00400         }
00401         else
00402         {
00403                 v = s - (2.0f*nrevs - 1.0f);
00404                 if( v <= 0.0f)
00405                 {
00406                         // middle part
00407                         while (s >= 2.0f) s -= 2.0f;
00408                         pp = q0*qaxis;
00409                         // s vary from 1 to 2. This is still correct for slerp().
00410                         ret = CQuatT<T>::slerp(q0,pp,s);
00411                 }
00412                 else
00413                 {
00414                         // Last part.
00415                         qq = - q1*qaxis;
00416                         ret= CQuatT<T>::squad(qq,qq,tgtQ1,q1,v);
00417                 }
00418         }
00419 
00420         return ret;
00421 }
00422 
00423 
00424 
00425 // ***************************************************************************
00426 template <class T> 
00427 CQuatT<T>       CQuatT<T>::log()
00428 {
00429         double  len;
00430         len = sqrt (x*x + y*y + z*z);
00431 
00432         if (len < QuatEpsilon)
00433                 return CQuatT<T>(0.f, 0.f, 0.f, 0.f);
00434         else
00435         {
00436                 double div = (float) acos (w) / len;
00437                 return CQuatT<T>( (T)(x*div), (T)(y*div), (T)(z*div), 0.f);
00438         }
00439 
00440 }
00441 
00442 
00443 // ***************************************************************************
00444 template <class T> 
00445 CQuatT<T>       CQuatT<T>::exp()
00446 {
00447         double  len;
00448         len = sqrt (x*x + y*y + z*z);
00449 
00450         if (len < QuatEpsilon)
00451                 return CQuatT<T>(0.f, 0.f, 0.f, 1.f);
00452         else
00453         {
00454                 double len1 = sin(len) / len; 
00455                 return CQuatT<T>( (T)(x*len1), (T)(y*len1), (T)(z*len1), (T)cos(len));
00456         }
00457 }
00458 
00459 
00460 // ***************************************************************************
00461 template <class T> 
00462 CQuatT<T>       CQuatT<T>::lnDif(const CQuatT<T> &q0, const CQuatT<T> &q1)
00463 {
00464         CQuatT<T>       dif = q0.inverted()*q1;
00465         dif.normalize();
00466 
00467         return dif.log();
00468 }
00469 
00470 
00471 // ***************************************************************************
00472 template <class T> 
00473 void    CQuatT<T>::makeClosest(const CQuatT<T> &o)
00474 {
00475         if( dotProduct(*this, o) < 0 )
00476                 *this= -(*this);
00477 }
00478 
00479 
00480 
00481 // ***************************************************************************
00482 // ***************************************************************************
00483 // CQuat/CQuatD
00484 // ***************************************************************************
00485 // ***************************************************************************
00486 
00487 
00488 
00489 // ***************************************************************************
00496 class   CQuat : public CQuatT<float>
00497 {
00498 public:
00499         static const CQuat              Identity;
00500 
00502         // @{
00503         CQuat   &operator=(const CQuatT<float> &o) {x=o.x; y=o.y; z=o.z; w=o.w; return *this;}
00504         CQuat(const CQuatT<float> &o) : CQuatT<float>(o) {}
00505         CQuat() {}
00506         CQuat(float X, float Y, float Z, float W) : CQuatT<float>(X,Y,Z,W) {}
00508         CQuat(const CVector &axis, float angle) : CQuatT<float>(axis, angle) {}
00510         CQuat(const CAngleAxis &aa) : CQuatT<float>(aa) {}
00511         // @}
00512 
00513 };
00514 
00515 
00516 // ***************************************************************************
00523 class   CQuatD : public CQuatT<double>
00524 {
00525 public:
00526         static const CQuatD             Identity;
00527 
00529         // @{
00530         CQuatD  &operator=(const CQuatT<double> &o) {x=o.x; y=o.y; z=o.z; w=o.w; return *this;}
00531         CQuatD(const CQuatT<double> &o) : CQuatT<double>(o) {}
00532         CQuatD() {}
00533         CQuatD(double X, double Y, double Z, double W) : CQuatT<double>(X,Y,Z,W) {}
00535         CQuatD(const CVector &axis, float angle) : CQuatT<double>(axis, angle) {}
00537         CQuatD(const CAngleAxis &aa) : CQuatT<double>(aa) {}
00538         // @}
00539 
00540         
00542         // @{
00543         CQuatD(const CQuat &o) {x=o.x; y=o.y; z=o.z; w=o.w;}
00544         CQuatD  &operator=(const CQuatT<float> &o) {x=o.x; y=o.y; z=o.z; w=o.w; return *this;}
00545         operator        CQuat() const {return CQuat((float)x, (float)y, (float)z, (float)w);} 
00546         // @}
00547 
00548 };
00549 
00550 
00551 
00552 
00553 
00554 } // NLMISC
00555 
00556 #endif // NL_QUAT_H 
00557