Main Page | Namespace List | Class Hierarchy | Class List | File List | Namespace Members | Class Members | File Members

coordsys.h

Go to the documentation of this file.
00001 // -*-c++-*-
00002 #ifndef IG_COORDSYS_H
00003 #define IG_COORDSYS_H
00004 
00005 // $Id: coordsys.h,v 1.25 2005/05/30 09:13:02 hkuiper Exp $
00006 
00007 // CwMtx matrix and vector math library
00008 // Copyright (C) 1999-2001  Harry Kuiper
00009 // Copyright (C) 2000  Will DeVore (template conversion)
00010 
00011 // This library is free software; you can redistribute it and/or
00012 // modify it under the terms of the GNU Lesser General Public
00013 // License as published by the Free Software Foundation; either
00014 // version 2 of the License, or (at your option) any later version.
00015 
00016 // This library is distributed in the hope that it will be useful,
00017 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00018 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00019 // Lesser General Public License for more details.
00020 
00021 // You should have received a copy of the GNU Lesser General Public
00022 // License along with this library; if not, write to the Free Software
00023 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
00024 // USA
00025 
00026 #ifndef IG_SMATRIX_H
00027 #include "smatrix.h"
00028 #endif
00029 
00030 #ifndef IG_QUATERNION_H
00031 #include "quatern.h"
00032 #endif
00033 
00034 #ifndef IG_SVECTOR_H
00035 #include "svector.h"
00036 #endif
00037 
00038 // CWTSquareMatrix utilities for use in coordinate systems
00039 
00040 namespace CwMtx
00041 {
00042 
00043   //
00044   // NOTE: These template functions only work with floating point
00045   // template arguments due to the use of sin(3), cos(3), tan(3), etc.
00046   //
00047 
00048   // PLEASE, READ THIS!!!
00049 
00050   // Function smatFromEuler321(sclrAbout3, sclrAbout2, sclrAbout1)
00051   // returns a transformation matrix which transforms coordinates from
00052   // the reference axis system to coordinates in an axis system with
00053   // Euler angles: sclrAbout3, sclrAbout2, sclrAbout1 relative to that
00054   // reference axis system DO NOT CHANGE THIS DEFINITION!!!
00055 
00056   // rotation about axis 3 (yaw angle), axis 2 (pitch angle) axis 1
00057   // (roll angle)
00058   template < class T >
00059   CWTSquareMatrix<T> smatFromEuler321Angles(T sclrAbout3,
00060                                             T sclrAbout2,
00061                                             T sclrAbout1)
00062   {
00063     CWTSquareMatrix<T> smat(3U);
00064 
00065     // to reduce the number of calls to CPU expensive sin(..) and
00066     // cos(..) functions
00067     T sin3 = sin(sclrAbout3);
00068     T sin2 = sin(sclrAbout2);
00069     T sin1 = sin(sclrAbout1);
00070 
00071     T cos3 = cos(sclrAbout3);
00072     T cos2 = cos(sclrAbout2);
00073     T cos1 = cos(sclrAbout1);
00074 
00075     // first row
00076     smat[0][0] =  cos3*cos2;
00077     smat[0][1] =  sin3*cos2;
00078     smat[0][2] = -sin2;
00079 
00080     // second row
00081     smat[1][0] = -sin3*cos1 + cos3*sin2*sin1;
00082     smat[1][1] =  cos3*cos1 + sin3*sin2*sin1;
00083     smat[1][2] =  cos2*sin1;
00084 
00085     // third row
00086     smat[2][0] =  sin3*sin1 + cos3*sin2*cos1;
00087     smat[2][1] = -cos3*sin1 + sin3*sin2*cos1;
00088     smat[2][2] =  cos2*cos1;
00089 
00090     return smat;
00091   }
00092 
00093   // Next three functions calculate Euler angles from a transformation matrix
00094   // WARNING!!! They suffer from the ubiquitos singularities at 0, pi, 2*pi,
00095   // etc.
00096 
00097   // yaw angle, rotation angle about Z-axis
00098   template < class T >
00099   T euler321Angle3FromSmat(const CWTSquareMatrix<T> &smat)
00100   {
00101     return atan2(smat[0][1], smat[0][0]);
00102   }
00103 
00104   // pitch angle, rotation angle about Y-axis
00105   template < class T >
00106   T euler321Angle2FromSmat(const CWTSquareMatrix<T> &smat)
00107   {
00108     return asin(-smat[0][2]);
00109   }
00110 
00111   // roll angle, rotation angle about X-axis
00112   template < class T >
00113   T euler321Angle1FromSmat(const CWTSquareMatrix<T> &smat)
00114   {
00115     return atan2(smat[1][2], smat[2][2]);
00116   }
00117 
00118   // CWTQuaternion utilities for use in coordinate systems
00119 
00120   // PLEASE, READ THIS!!!
00121 
00122   // next three functions calculate Euler angles from a quaternion
00123   // that represents a rigid body's attitude WARNING!!! They do suffer
00124   // from the ubiquitos singularities around 0, pi and 2*pi.
00125 
00126   // yaw angle, rotation angle about Z-axis
00127   template < class T >
00128   T euler321Angle3FromQtn(const CWTQuaternion<T> &qtn)
00129   {
00130     // to reduce the number of calls to the subscript operator
00131     T qtn0 = qtn[0];
00132     T qtn1 = qtn[1];
00133     T qtn2 = qtn[2];
00134     T qtn3 = qtn[3];
00135 
00136     // NOTE: Speed tip from Jeffrey T Duncan: use the identity: 1 =
00137     // q0^2 + q1^2 + q2^2 + q3^2 which simplifies: q0^2 - q1^2 -
00138     // q2^2 + q3^2 down to: 2*(q0^2 + q3^2) - 1
00139     return atan2(2*(qtn0*qtn1 + qtn2*qtn3),
00140                  2*(qtn0*qtn0 + qtn3*qtn3) - 1);
00141   }
00142 
00143   // pitch angle, rotation angle about Y-axis
00144   template < class T >
00145   T euler321Angle2FromQtn(const CWTQuaternion<T> &qtn)
00146   {
00147     return asin(-2*(qtn[0]*qtn[2] - qtn[1]*qtn[3]));
00148   }
00149 
00150   // roll angle, rotation angle about X-axis
00151   template < class T >
00152   T euler321Angle1FromQtn(const CWTQuaternion<T> &qtn)
00153   {
00154     // to reduce the number of calls to the subscript operator
00155     T qtn0 = qtn[0];
00156     T qtn1 = qtn[1];
00157     T qtn2 = qtn[2];
00158     T qtn3 = qtn[3];
00159 
00160     return atan2(2*(qtn1*qtn2 + qtn0*qtn3),
00161                  2*(qtn2*qtn2 + qtn3*qtn3) - 1);
00162   }
00163 
00164   // Function QtnFromEulerAxisAndAngle returns a quaternion
00165   // representing a rigid body's attitude from its Euler axis and
00166   // angle. NOTE: Argument vector svecEulerAxis MUST be a unit vector.
00167   template < class T >
00168   CWTQuaternion<T>
00169   qtnFromEulerAxisAndAngle(const CWTSpaceVector<T> &svecEulerAxis,
00170                            const T &sclrEulerAngle)
00171   {
00172     return CWTQuaternion<T>(1, svecEulerAxis, 0.5*sclrEulerAngle);
00173   }
00174 
00175   // returns Euler axis
00176   template < class T >
00177   CWTSpaceVector<T> eulerAxisFromQtn(const CWTQuaternion<T> &qtn)
00178   {
00179     T sclrTmp = sqrt(1 - qtn[3]*qtn[3]);
00180 
00181     return CWTSpaceVector<T>(qtn[0]/sclrTmp,
00182                              qtn[1]/sclrTmp,
00183                              qtn[2]/sclrTmp);
00184   }
00185 
00186   // returns Euler angle
00187   template < class T >
00188   T eulerAngleFromQtn(const CWTQuaternion<T> &qtn)
00189   {
00190     return 2*acos(qtn[3]);
00191   }
00192 
00193   // Function QtnFromEuler321 returns a quaternion representing a
00194   // rigid body's attitude. The quaternion elements correspond to the
00195   // Euler symmetric parameters of the body. The body's attitude must
00196   // be entered in Euler angle representation with rotation order
00197   // 3-2-1, i.e. first about Z-axis next about Y-axis and finally
00198   // about X-axis.
00199 
00200   // rotation about axis 3 (yaw angle), axis 2 (pitch angle) axis 1
00201   // (roll angle)
00202   template < class T >
00203   CWTQuaternion<T> qtnFromEuler321Angles(T sclrAbout3,
00204                                          T sclrAbout2,
00205                                          T sclrAbout1)
00206   {
00207     return
00208       CWTQuaternion<T>(1, CWTSpaceVector<T>(0, 0, 1), 0.5*sclrAbout3)
00209       *CWTQuaternion<T>(1, CWTSpaceVector<T>(0, 1, 0), 0.5*sclrAbout2)
00210       *CWTQuaternion<T>(1, CWTSpaceVector<T>(1, 0, 0), 0.5*sclrAbout1);
00211   }
00212 
00213   // SmatFromQtn returns the transformation matrix corresponding to a
00214   // quaternion
00215   template < class T >
00216   CWTSquareMatrix<T> smatFromQtn(const CWTQuaternion<T> &qtn)
00217   {
00218     CWTSquareMatrix<T> smat(3U);
00219 
00220     // to reduce the number of calls to the subscript operator
00221     T qtn0 = qtn[0];
00222     T qtn1 = qtn[1];
00223     T qtn2 = qtn[2];
00224     T qtn3 = qtn[3];
00225 
00226     smat[0][0] = 1 - 2*(qtn1*qtn1 + qtn2*qtn2);
00227     smat[0][1] = 2*(qtn0*qtn1 + qtn2*qtn3);
00228     smat[0][2] = 2*(qtn0*qtn2 - qtn1*qtn3);
00229 
00230     smat[1][0] = 2*(qtn0*qtn1 - qtn2*qtn3);
00231     smat[1][1] = 1 - 2*(qtn0*qtn0 + qtn2*qtn2);
00232     smat[1][2] = 2*(qtn1*qtn2 + qtn0*qtn3);
00233 
00234     smat[2][0] = 2*(qtn0*qtn2 + qtn1*qtn3);
00235     smat[2][1] = 2*(qtn1*qtn2 - qtn0*qtn3);
00236     smat[2][2] = 1 - 2*(qtn0*qtn0 + qtn1*qtn1);
00237 
00238     return smat;
00239   }
00240 
00241   // QtnFromSmat returns the quaternion corresponding to a
00242   // transformation matrix
00243   template < class T >
00244   CWTQuaternion<T> qtnFromSmat(const CWTSquareMatrix<T> &smat)
00245   {
00246     // Check trace to prevent loss of accuracy
00247     T sclrTmp = tr(smat);
00248     CWTQuaternion<T> qtn;
00249 
00250     if(sclrTmp > 0)
00251       {
00252         // No trouble, we can use standard expression
00253         sclrTmp = 0.5*sqrt(1 + sclrTmp);
00254         qtn[0] = 0.25*(smat[1][2] - smat[2][1])/sclrTmp;
00255         qtn[1] = 0.25*(smat[2][0] - smat[0][2])/sclrTmp;
00256         qtn[2] = 0.25*(smat[0][1] - smat[1][0])/sclrTmp;
00257         qtn[3] = sclrTmp;
00258       }
00259     else
00260       {
00261         // We could be in trouble, so we have to take
00262         // precautions. NOTE: Parts of this piece of code were taken
00263         // from the example in the article "Rotating Objects Using
00264         // Quaternions" in Game Developer Magazine written by Nick
00265         // Bobick, july 3, 1998, vol. 2, issue 26.
00266         int i = 0;
00267         if (smat[1][1] > smat[0][0]) i = 1;
00268         if (smat[2][2] > smat[i][i]) i = 2;
00269 
00270         switch (i)
00271           {
00272           case 0:
00273             sclrTmp = 0.5*sqrt(1 + smat[0][0] - smat[1][1] - smat[2][2]);
00274             qtn[0] = sclrTmp;
00275             qtn[1] = 0.25*(smat[0][1] + smat[1][0])/sclrTmp;
00276             qtn[2] = 0.25*(smat[0][2] + smat[2][0])/sclrTmp;
00277             qtn[3] = 0.25*(smat[1][2] - smat[2][1])/sclrTmp;
00278             break;
00279 
00280           case 1:
00281             sclrTmp = 0.5*sqrt(1 - smat[0][0] + smat[1][1] - smat[2][2]);
00282             qtn[0] = 0.25*(smat[1][0] + smat[0][1])/sclrTmp;
00283             qtn[1] = sclrTmp;
00284             qtn[2] = 0.25*(smat[1][2] + smat[2][1])/sclrTmp;
00285             qtn[3] = 0.25*(smat[2][0] - smat[0][2])/sclrTmp;
00286             break;
00287 
00288           case 2:
00289             sclrTmp = 0.5*sqrt(1 - smat[0][0] - smat[1][1] + smat[2][2]);
00290             qtn[0] = 0.25*(smat[2][0] + smat[0][2])/sclrTmp;
00291             qtn[1] = 0.25*(smat[2][1] + smat[1][2])/sclrTmp;
00292             qtn[2] = sclrTmp;
00293             qtn[3] = 0.25*(smat[0][1] - smat[1][0])/sclrTmp;
00294 
00295             break;
00296           }
00297       }
00298 
00299     return qtn;
00300   }
00301 
00302   // NOTE: This function duplicates eulerAxisFromQtn(qtn) it only has
00303   // a different return type.
00304   template < class T >
00305   CWTVector<T> axisAngleFromQtn( const CWTQuaternion<T> &qtn )
00306   {
00307     return eulerAxisFromQtn(qtn);
00308   }
00309 
00310   // NOTE: This function duplicates qtnFromEulerAxisAndAngle(..) it
00311   // only has a different function profile.
00312   template < class T >
00313   CWTQuaternion<T> qtnFromAxisAngle( const CWTVector<T> &vAxis,
00314                                      const T sAngle )
00315   {
00316     return qtnFromEulerAxisAndAngle(CWTSpaceVector<T>(vAxis), sAngle);
00317   }
00318 
00319   template < class T >
00320   CWTSquareMatrix<T> changeOfBasis(CWTSpaceVector< CWTSpaceVector<T> >&from, 
00321                                    CWTSpaceVector< CWTSpaceVector<T> >&to)
00322   {
00323     CWTSquareMatrix<T> A( 3 );
00324 
00325     // This is a "change of basis" from the "from" frame to the "to"
00326     // frame.  the "to" frame is typically the "Standard basis"
00327     // frame.  The "from" is a frame that represents the current
00328     // orientation of the object in the shape of an orthonormal
00329     // tripod.
00330 
00331     enum { x , y , z };
00332 
00333     // _X,_Y,_Z is typically the standard basis frame.
00334 
00335     //  | x^_X , y^_X , z^_X |
00336     //  | x^_Y , y^_Y , z^_Y |
00337     //  | x^_Z , y^_Z , z^_Z |
00338         
00339     A[0][0] = from[x]*to[x];
00340     A[0][1] = from[y]*to[x];
00341     A[0][2] = from[z]*to[x];
00342 
00343     A[1][0] = from[x]*to[y];
00344     A[1][1] = from[y]*to[y];
00345     A[1][2] = from[z]*to[y];
00346 
00347     A[2][0] = from[x]*to[z];
00348     A[2][1] = from[y]*to[z];
00349     A[2][2] = from[z]*to[z];
00350         
00351     // This is simply the transpose done manually which would save
00352     // and inverse call.
00353     //  | x ^ _X , x ^ _Y , x ^ _Z |
00354     //  | y ^ _X , y ^ _Y , y ^ _Z |
00355     //  | z ^ _X , z ^ _Y , z ^ _Z |
00356         
00357     // And finally we return the matrix that takes the "from" frame
00358     // to the "to"/"Standard basis" frame.
00359     return A;
00360   }
00361 
00362 }
00363 
00364 #endif   // IG_COORDSYS_H

Generated on Sun Jul 3 12:18:14 2005 for Matrix and vector library by  doxygen 1.4.2