Biomechanical Joint Model
 Author: Anderson Maciel

quaternion.cpp

Go to the documentation of this file.
00001 /****************************************************************************
00002  * Quaternion code by BLACKAXE / kolor aka Laurent Schmalen
00003  * Version 0.9
00004  * Read QUAT.DOC for further informations
00005  */
00006 #include <iostream>
00007 #include <math.h>
00008 #include <float.h>
00009 #include <algebra/quaternion.h>
00010 #include <algebra/comevector3d.h>
00011 
00012 
00013 Quaternion::Quaternion()
00014 {
00015   W = 1.0;
00016   X = 0.0;
00017   Y = 0.0;
00018   Z = 0.0;
00019 }
00020 
00021 Quaternion::Quaternion(const double w, const double x, const double y, const double z)
00022 {
00023   W = w;
00024   X = x;
00025   Y = y;
00026   Z = z;
00027 }
00028 
00029 
00030 Quaternion operator * (const Quaternion &a, const Quaternion &b)
00031 {
00032   double w,x,y,z;
00033 
00034   w = a.W*b.W - (a.X*b.X + a.Y*b.Y + a.Z*b.Z);
00035   
00036   x = a.W*b.X + b.W*a.X + a.Y*b.Z - a.Z*b.Y;
00037   y = a.W*b.Y + b.W*a.Y + a.Z*b.X - a.X*b.Z;
00038   z = a.W*b.Z + b.W*a.Z + a.X*b.Y - a.Y*b.X;
00039 
00040   return Quaternion(w,x,y,z); 
00041 }
00042 
00043 const Quaternion& Quaternion::operator *= (const Quaternion &q)
00044 {
00045   double w = W*q.W - (X*q.X + Y*q.Y + Z*q.Z);
00046 
00047   double x = W*q.X + q.W*X + Y*q.Z - Z*q.Y;
00048   double y = W*q.Y + q.W*Y + Z*q.X - X*q.Z;
00049   double z = W*q.Z + q.W*Z + X*q.Y - Y*q.X;
00050 
00051   W = w;
00052   X = x;
00053   Y = y;
00054   Z = z;
00055   return *this;
00056 }
00057 
00058 const Quaternion& Quaternion::operator ~ ()
00059 {
00060   X = -X;
00061   Y = -Y;
00062   Z = -Z;
00063   return *this;
00064 }
00065 
00066 const Quaternion& Quaternion::operator - ()
00067 {
00068   double norme = sqrt(W*W + X*X + Y*Y + Z*Z);
00069   if (norme == 0.0)
00070     norme = 1.0;
00071 
00072   double recip = 1.0 / norme;
00073 
00074   W =  W * recip;
00075   X = -X * recip;
00076   Y = -Y * recip;
00077   Z = -Z * recip;
00078 
00079   return *this;
00080 }
00081 
00082 const Quaternion& Quaternion::Normalize()
00083 {
00084   double norme = sqrt(W*W + X*X + Y*Y + Z*Z);
00085   if (norme == 0.0)
00086     {
00087           W = 1.0; 
00088           X = Y = Z = 0.0;
00089         }
00090   else
00091     {
00092           double recip = 1.0/norme;
00093 
00094           W *= recip;
00095           X *= recip;
00096           Y *= recip;
00097           Z *= recip;
00098         }
00099   return *this;
00100 }
00101 
00102 const Quaternion& Quaternion::FromAxis(const double Angle, double x, double y, double z)
00103 {
00104   double omega, s, c;
00105     
00106   s = sqrt(x*x + y*y + z*z);
00107 
00108   // amaciel debug
00109   //if( s == 0.0 ) s = 1.0;
00110   
00111   if (fabs(s) > FLT_EPSILON)
00112     {
00113           c = 1.0/s;
00114           
00115           x *= c;
00116           y *= c;
00117           z *= c;
00118 
00119           omega = -0.5f * Angle;
00120           s = (double)sin(omega);
00121 
00122           X = s*x;
00123           Y = s*y;
00124           Z = s*z;
00125           W = (double)cos(omega);
00126         }
00127   else
00128     {
00129           X = Y = 0.0f;
00130           Z = 0.0f;
00131           W = 1.0f;
00132         }
00133   Normalize();
00134   return *this;
00135 }
00136 
00137 
00138 void Quaternion::ToMatrix(double matrix[3][3]) const
00139 {
00140   matrix[0][0] = 1.0 - 2*Y*Y - 2*Z*Z;
00141   matrix[1][0] = 2*X*Y + 2*W*Z;
00142   matrix[2][0] = 2*X*Z - 2*W*Y;
00143 
00144   matrix[0][1] = 2*X*Y - 2*W*Z;
00145   matrix[1][1] = 1.0 - 2*X*X - 2*Z*Z;
00146   matrix[2][1] = 2*Y*Z + 2*W*X;
00147 
00148   matrix[0][2] = 2*X*Z + 2*W*Y;
00149   matrix[1][2] = 2*Y*Z - 2*W*X;
00150   matrix[2][2] = 1.0 - 2*X*X - 2*Y*Y;
00151 }
00152 
00153 
00154 void Quaternion::Slerp(const Quaternion &a,const Quaternion &b, const double t)
00155 {
00156   double omega, cosom, sinom, sclp, sclq;
00157 
00158 
00159   cosom = a.X*b.X + a.Y*b.Y + a.Z*b.Z + a.W*b.W;
00160 
00161 
00162   if ((1.0f+cosom) > FLT_EPSILON)
00163         {
00164           if ((1.0f-cosom) > FLT_EPSILON)
00165                 {
00166                   omega = acos(cosom);
00167                   sinom = sin(omega);
00168 
00169                   // amaciel debug
00170                   //if( sinom == 0.0 ) sinom = 1.0;
00171 
00172                   sclp = sin((1.0f-t)*omega) / sinom;
00173                   sclq = sin(t*omega) / sinom;
00174                 }
00175           else
00176                 {
00177                   sclp = 1.0f - t;
00178                   sclq = t;
00179                 }
00180 
00181       X = sclp*a.X + sclq*b.X;
00182           Y = sclp*a.Y + sclq*b.Y;
00183           Z = sclp*a.Z + sclq*b.Z;
00184           W = sclp*a.W + sclq*b.W;
00185 
00186         }
00187   else
00188         {
00189           X =-a.Y;
00190           Y = a.X;
00191           Z =-a.W;
00192           W = a.Z;
00193 
00194           sclp = sin((1.0f-t) * PI * 0.5);
00195           sclq = sin(t * PI * 0.5);
00196 
00197           X = sclp*a.X + sclq*b.X;
00198           Y = sclp*a.Y + sclq*b.Y;
00199           Z = sclp*a.Z + sclq*b.Z;
00200 
00201         }
00202 }
00203 
00204 const Quaternion& Quaternion::exp()
00205 {                               
00206   double Mul;
00207   double Length = sqrt(X*X + Y*Y + Z*Z);
00208 
00209   if (Length > 1.0e-4)
00210     Mul = sin(Length)/Length;
00211   else
00212     Mul = 1.0;
00213 
00214   W = cos(Length);
00215 
00216   X *= Mul;
00217   Y *= Mul;
00218   Z *= Mul; 
00219 
00220   return *this;
00221 }
00222 /*
00223 const Quaternion& Quaternion::log()
00224 {
00225   double Length;
00226 
00227   Length = sqrt(X*X + Y*Y + Z*Z);
00228 
00229   // amaciel debug
00230   if( W == 0.0 ) W = 1.0;
00231 
00232   Length = atan(Length/W);
00233 
00234   W = 0.0;
00235 
00236   X *= Length;
00237   Y *= Length;
00238   Z *= Length;
00239 
00240   return *this;
00241 }
00242 */
00243 
00244 void Quaternion::setAxisAngle(COME_Vector3D axis, double angle)  // radians
00245 {       
00246         double* aa = new double[4];
00247     aa[0] = axis.x;
00248     aa[1] = axis.y;
00249     aa[2] = axis.z;
00250     aa[3] = -angle;
00251     setAxisAngle(aa);
00252 }
00253 
00254 
00255 void Quaternion::setAxisAngle(double axis_angle[])  // radians - tested ok
00256 {
00257 
00258     double Mysin;
00259     double length_sqr;
00260     double one_over_length;
00261         
00262     if (axis_angle[3] == 0.0f)
00263         {
00264                 W = 1.0;
00265                 X = 0.0;
00266                 Y = 0.0;
00267                 Z = 0.0;
00268         }
00269         
00270     length_sqr = axis_angle[0]*axis_angle[0] + axis_angle[1]*axis_angle[1] + axis_angle[2]*axis_angle[2];
00271     if (length_sqr < 0.0001)
00272         {
00273                 W = 1.0;
00274                 X = 0.0;
00275                 Y = 0.0;
00276                 Z = 0.0;
00277                 
00278                 // amaciel debug
00279                 return;
00280         }
00281 
00282         // amaciel debug
00283         //if( length_sqr == 0.0 ) length_sqr = 1.0;
00284         
00285     one_over_length = 1.0f/(double)sqrt(length_sqr);
00286     axis_angle[0] = axis_angle[0] * one_over_length;
00287     axis_angle[1] = axis_angle[1] * one_over_length;
00288     axis_angle[2] = axis_angle[2] * one_over_length;
00289         
00290     Mysin = (double)sin(axis_angle[3]*0.5f);
00291     X = axis_angle[0]*Mysin;
00292     Y = axis_angle[1]*Mysin;
00293     Z = axis_angle[2]*Mysin;
00294     W = (double)cos(axis_angle[3]*0.5f);
00295 }
00296 
00297 void Quaternion::makeFromVecs(COME_Vector3D vec1, COME_Vector3D vec2) // modified Ken Shoemake - tested ok
00298 {    
00299         COME_Vector3D axis;
00300         COME_Vector3D temp;
00301    
00302     
00303         double dot;
00304     double angle;
00305     double abs_angle;
00306 
00307     vec1.vpNormalize();
00308     vec2.vpNormalize();
00309 
00310     dot = vec1.vpDotProduct(vec2);
00311     angle = (double)acos(dot);       // -PI < angle < +PI
00312     if (angle > 0) abs_angle = angle;// 0 <= angle < PI
00313         else abs_angle= -angle;
00314                 
00315 
00316     if (abs_angle < 0.0001f)             // vec's parallel
00317       {
00318                 W = 1.0;
00319                 X = 0.0;
00320                 Y = 0.0;
00321                 Z = 0.0;
00322                 return;
00323       }
00324 
00325     if (abs_angle > ((double)PI)- 0.0001f ) // vec's oppose
00326       {
00327                   // Can't use cross product for axis.  Find arbitrary axis.
00328                   // First try cross with X-axis, else just use Z-axis.
00329                   axis.setXYZ(1.0f, 0.0f, 0.0f);
00330                   if (axis.vpDotProduct(vec1) < 0.1f)
00331                         {
00332                         temp = axis.vpCrossProduct(vec1);
00333                         temp.vpNormalize();
00334                         }
00335                   else
00336                         {
00337                         temp.setXYZ(0.0f, 0.0f, 1.0f);
00338                         }
00339                   setAxisAngle(temp, angle);
00340                   return;
00341       }
00342 
00343     // normal case
00344     temp = vec1.vpCrossProduct(vec2);
00345     temp.vpNormalize();
00346     setAxisAngle(temp, angle);
00347 }

Generated on Thu Dec 1 10:13:40 2005 for COME - Biomechanical Joint Model by  doxygen 1.4.5