Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

base/Orient.cpp

Go to the documentation of this file.
00001 /****************************************************************************
00002   Copyright (C)1996 David Jung <opensim@pobox.com>
00003 
00004   This program/file is free software; you can redistribute it and/or modify
00005   it under the terms of the GNU General Public License as published by
00006   the Free Software Foundation; either version 2 of the License, or
00007   (at your option) any later version.
00008   
00009   This program is distributed in the hope that it will be useful,
00010   but WITHOUT ANY WARRANTY; without even the implied warranty of
00011   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012   GNU General Public License for more details. (http://www.gnu.org)
00013   
00014   You should have received a copy of the GNU General Public License
00015   along with this program; if not, write to the Free Software
00016   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00017   
00018   $Id: Orient.cpp 1029 2004-02-11 20:45:54Z jungd $
00019   $Revision: 1.21 $
00020   $Date: 2004-02-11 15:45:54 -0500 (Wed, 11 Feb 2004) $
00021   $Author: jungd $
00022  
00023 ****************************************************************************/
00024 
00025 #include <base/Orient>
00026 
00027 using base::Orient;
00028 
00029 #include <base/Math>
00030 #include <base/Serializer>
00031 
00032 
00033 using base::Byte;
00034 using base::Math;
00035 using base::Matrix3;
00036 using base::Matrix4;
00037 using base::Vector3;
00038 using base::Point4;
00039 using base::Quat4;
00040 using base::Vector;
00041 using base::Matrix;
00042 
00043 Byte Orient::EulSafe[4] = { 0,1,2,0 };
00044 Byte Orient::EulNext[4] = { 1,2,0,1 };
00045 
00046 const Orient::Representation Orient::EulerXYZs = eulerRep(X,Even, NonRepeating,Static);
00047 const Orient::Representation Orient::EulerXYXs = eulerRep(X,Even,    Repeating,Static);
00048 const Orient::Representation Orient::EulerXZYs = eulerRep(X,Odd , NonRepeating,Static);
00049 const Orient::Representation Orient::EulerXZXs = eulerRep(X,Odd ,    Repeating,Static);
00050 const Orient::Representation Orient::EulerYZXs = eulerRep(Y,Even, NonRepeating,Static);
00051 const Orient::Representation Orient::EulerYZYs = eulerRep(Y,Even,    Repeating,Static);
00052 const Orient::Representation Orient::EulerYXZs = eulerRep(Y,Odd , NonRepeating,Static);
00053 const Orient::Representation Orient::EulerYXYs = eulerRep(Y,Odd ,    Repeating,Static);
00054 const Orient::Representation Orient::EulerZXYs = eulerRep(Z,Even, NonRepeating,Static);
00055 const Orient::Representation Orient::EulerZXZs = eulerRep(Z,Even,    Repeating,Static);
00056 const Orient::Representation Orient::EulerZYXs = eulerRep(Z,Odd , NonRepeating,Static);
00057 const Orient::Representation Orient::EulerZYZs = eulerRep(Z,Odd ,    Repeating,Static);
00058 
00059 const Orient::Representation Orient::EulerZYXr = eulerRep(X,Even, NonRepeating,Rotating);
00060 const Orient::Representation Orient::EulerXYXr = eulerRep(X,Even,    Repeating,Rotating);
00061 const Orient::Representation Orient::EulerYZXr = eulerRep(X,Odd , NonRepeating,Rotating);
00062 const Orient::Representation Orient::EulerXZXr = eulerRep(X,Odd ,    Repeating,Rotating);
00063 const Orient::Representation Orient::EulerXZYr = eulerRep(Y,Even, NonRepeating,Rotating);
00064 const Orient::Representation Orient::EulerYZYr = eulerRep(Y,Even,    Repeating,Rotating);
00065 const Orient::Representation Orient::EulerZXYr = eulerRep(Y,Odd , NonRepeating,Rotating);
00066 const Orient::Representation Orient::EulerYXYr = eulerRep(Y,Odd ,    Repeating,Rotating);
00067 const Orient::Representation Orient::EulerYXZr = eulerRep(Z,Even, NonRepeating,Rotating);
00068 const Orient::Representation Orient::EulerZXZr = eulerRep(Z,Even,    Repeating,Rotating);
00069 const Orient::Representation Orient::EulerXYZr = eulerRep(Z,Odd , NonRepeating,Rotating);
00070 const Orient::Representation Orient::EulerZYZr = eulerRep(Z,Odd ,    Repeating,Rotating);
00071 
00072 const Orient::Representation Orient::EulerRPY  = eulerRep(X,Even, NonRepeating,Static); // XYZs
00073 
00074 
00075 
00076 
00077 
00078 Orient::Orient() 
00079   : rep(EulerRPY), v(zeroVector(3)) 
00080 {
00081 }
00082 
00083 
00084 Orient::Orient(Representation representation)
00085   : rep(representation), v(zeroVector(3))
00086 {
00087   Assert(rep < RepEnd);
00088   if (rep == Mat) {
00089     m = MatrixRef(NewObj Matrix(3,3));
00090     *m = identityMatrix(3,3);
00091   }
00092   else {
00093     if (rep == Quat) {
00094       Quat4 q;
00095       v.resize(4); 
00096       v[0]=q.v.x; v[1]=q.v.y; v[2]=q.v.z; v[3]=q.w;
00097     }
00098   }
00099 }
00100 
00101 
00102 Orient::Orient(const Quat4& q)
00103  : rep(Quat), v(4) 
00104 {
00105   v[0]=q.v.x; v[1]=q.v.y; v[2]=q.v.z; v[3]=q.w; 
00106 }
00107 
00108   
00109 Orient::Orient(Real roll, Real pitch, Real yaw) 
00110  : rep(EulerRPY), v(3)
00111 {
00112   v[0]=roll; v[1]=pitch; v[2]=yaw; 
00113 }
00114 
00115 
00116   
00117 Orient::Orient(const Vector& v, Representation representation)
00118   : rep(representation)
00119 {
00120   Assert(rep < RepEnd);
00121   Assertm( (rep==Quat)?(v.size()==4):true, "Quaternion has 4 components");
00122   if (rep==Mat) {
00123     Assertm( v.size() == 9, "Rotation matrix has 9 components");
00124     m = MatrixRef(NewObj Matrix(3,3));
00125     (*m)(0,0) = v[0]; (*m)(0,1) = v[1]; (*m)(0,2) = v[2];
00126     (*m)(1,0) = v[3]; (*m)(1,1) = v[4]; (*m)(1,2) = v[5];
00127     (*m)(2,0) = v[6]; (*m)(2,1) = v[7]; (*m)(2,2) = v[8];
00128   }
00129   else {
00130     if (rep!=Quat) {
00131       Assertm( v.size()==3, "vector should have 3 components");
00132       this->v.reset(v);
00133     }
00134     else { // normalize Quat
00135       Quat4 q(v[0],v[1],v[2],v[3]);
00136       q.normalize();
00137       this->v.resize(4);
00138       this->v[0]=q.v.x; this->v[1]=q.v.y; this->v[2]=q.v.z; this->v[3]=q.w;
00139     }
00140   }
00141 }
00142 
00143 
00144 Orient::Orient(const Matrix3& m3)
00145  : rep(Mat), m(NewObj Matrix(3,3)) 
00146 {
00147   (*m)(0,0) = m3(1,1);
00148   (*m)(0,1) = m3(1,2);
00149   (*m)(0,2) = m3(1,3);
00150   (*m)(1,0) = m3(2,1);
00151   (*m)(1,1) = m3(2,2);
00152   (*m)(1,2) = m3(2,3);
00153   (*m)(2,0) = m3(3,1);
00154   (*m)(2,1) = m3(3,2);
00155   (*m)(2,2) = m3(3,3);
00156 }
00157 
00158 
00159 Orient::Orient(const Matrix& m)
00160   : rep(Mat), m(NewObj Matrix(3,3)) 
00161 {
00162   Assert(m.size1()==3);
00163   Assert(m.size2()==3);
00164   *(this->m) = m;
00165 }
00166 
00167 
00168 Orient::Orient(const Orient& copy)
00169  : rep(copy.rep) 
00170 {
00171   if (rep!=Mat) {
00172     v.resize(copy.v.size());
00173     v = copy.v;
00174   }
00175   else {
00176     m = MatrixRef(NewObj Matrix(*copy.m));
00177     *m = *copy.m;
00178   }
00179 }
00180 
00181 
00182 Orient::~Orient() 
00183 {
00184   if (rep==Mat)
00185     delete &(*m);
00186 }
00187 
00188   
00189 Orient& Orient::operator=(const Matrix3& mt)
00190 {
00191   if (rep != Mat)
00192     m = MatrixRef(NewObj Matrix(3,3));
00193   rep = Mat;
00194   (*m)(0,0) = mt(1,1); (*m)(0,1) = mt(1,2);  (*m)(0,2) = mt(1,3); 
00195   (*m)(1,0) = mt(2,1); (*m)(1,1) = mt(2,2);  (*m)(1,2) = mt(2,3);
00196   (*m)(2,0) = mt(3,1); (*m)(2,1) = mt(3,2);  (*m)(2,2) = mt(3,3);
00197   return *this;
00198 }
00199   
00200 
00201 
00202 
00203 base::String Orient::representationString(Representation rep)
00204 {
00205   if (rep == Quat) return String("Quat");
00206   else if (rep == Mat) return String("Matrix");
00207   else if (rep == Rodriguez) return String("Rodriguez");
00208   else if (rep == EulerXYZs) return String("EulerXYZs");
00209   else if (rep == EulerXYXs) return String("EulerXYXs");
00210   else if (rep == EulerXZYs) return String("EulerXZYs");
00211   else if (rep == EulerXZXs) return String("EulerXZXs");
00212   else if (rep == EulerYZXs) return String("EulerYZXs");
00213   else if (rep == EulerYZYs) return String("EulerYZYs");
00214   else if (rep == EulerYXZs) return String("EulerYXZs");
00215   else if (rep == EulerYXYs) return String("EulerYXYs");
00216   else if (rep == EulerZXYs) return String("EulerZXYs");
00217   else if (rep == EulerZXZs) return String("EulerZXZs");
00218   else if (rep == EulerZYXs) return String("EulerZYXs");
00219   else if (rep == EulerZYZs) return String("EulerZYZs");
00220   else if (rep == EulerZYXr) return String("EulerZYXr");
00221   else if (rep == EulerXYXr) return String("EulerXYXr");
00222   else if (rep == EulerYZXr) return String("EulerYZXr");
00223   else if (rep == EulerXZXr) return String("EulerXZXr");
00224   else if (rep == EulerXZYr) return String("EulerXZYr");
00225   else if (rep == EulerYZYr) return String("EulerYZYr");
00226   else if (rep == EulerZXYr) return String("EulerZXYr");
00227   else if (rep == EulerYXYr) return String("EulerYXYr");
00228   else if (rep == EulerYXZr) return String("EulerYXZr");
00229   else if (rep == EulerZXZr) return String("EulerZXZr");
00230   else if (rep == EulerXYZr) return String("EulerXYZr");
00231   else if (rep == EulerZYZr) return String("EulerZYZr");
00232   else throw std::invalid_argument(Exception("unknown representation"));
00233 }
00234 
00235 
00236   
00237 
00238 
00239 Matrix Orient::getRotationMatrix() const
00240 {
00241   Orient r(*this); r.changeRep(Mat);
00242   return Matrix(*r.m);
00243 }
00244 
00245 
00246 Matrix3 Orient::getRotationMatrix3() const
00247 {
00248   Orient r(*this); r.changeRep(Mat);
00249   Matrix& m(*r.m);
00250   Matrix3 m3(m(0,0), m(0,1), m(0,2),
00251              m(1,0), m(1,1), m(1,2),
00252              m(2,0), m(2,1), m(2,2));
00253   return m3;
00254 }
00255 
00256 Quat4 Orient::getQuat4() const 
00257 {
00258   if (rep == Quat)
00259     return Quat4(v[0],v[1],v[2],v[3]);
00260   else {
00261     Orient r(*this);
00262     r.changeRep(Quat);
00263     return Quat4(r.v[0],r.v[1],r.v[2],r.v[3]);
00264   }
00265 }
00266 
00267 Vector Orient::getVector(Representation representation) const 
00268 {
00269   Orient c;
00270   const Orient* r(this);
00271   if (rep != representation) {
00272     c = *this;
00273     c.changeRep(representation);
00274     r = &c;
00275   }
00276 
00277   if (representation!=Mat) {
00278     return r->v;
00279   }
00280   else {
00281     Vector v(9);
00282     const Matrix& m(*(r->m));
00283     v[0] = m(0,0); v[1] = m(0,1); v[2] = m(0,2);
00284     v[3] = m(1,0); v[4] = m(1,1); v[5] = m(1,2);
00285     v[6] = m(2,0); v[7] = m(2,1); v[8] = m(2,2);
00286     return v;
00287    }
00288 }
00289 
00290 
00291 Vector3 Orient::getVector3(Representation representation) const 
00292 {
00293   Vector v( getVector(representation) );
00294   return Vector3(v[0],v[1],v[2]);
00295 }
00296 
00297 
00298 
00299 Orient& Orient::operator=(const Orient& copy) throw()
00300 { 
00301   if (&copy != this) {
00302     Assert(copy.rep < RepEnd);
00303     if (rep!=Mat) {
00304       if (copy.rep!=Mat) {
00305         rep=copy.rep;
00306         v.reset(copy.v);
00307       }
00308       else {
00309         rep=copy.rep;
00310         m = MatrixRef(NewObj Matrix(*copy.m));
00311       }
00312     }
00313     else {
00314       if (copy.rep!=Mat) {
00315         delete &(*m);
00316         rep=copy.rep;
00317         v.reset(copy.v);
00318       }
00319       else {
00320         *m = *copy.m;
00321       }
00322     }
00323   }
00324   return *this;
00325 }
00326 
00327 
00328 void Orient::setIdentity(Orient::Representation representation)
00329 {
00330   Assert(representation < RepEnd)
00331   if (representation == Quat) {
00332     if (rep == Mat)
00333       delete &(*m);
00334     rep = Quat;
00335     Quat4 q; // zero Quat
00336     v.resize(4); 
00337     v[0]=q.v.x; v[1]=q.v.y; v[2]=q.v.z; v[3]=q.w;
00338   }
00339   else if (representation == Mat) {
00340     if (rep != Mat)
00341       m = MatrixRef(NewObj Matrix(3,3));
00342     rep = Mat;
00343     (*m)(0,0) = 1; (*m)(0,1) = 0;  (*m)(0,2) = 0; // identity
00344     (*m)(1,0) = 0; (*m)(1,1) = 1;  (*m)(1,2) = 0;
00345     (*m)(2,0) = 0; (*m)(2,1) = 0;  (*m)(2,2) = 1;
00346   }
00347   else {
00348     rep = representation;
00349     v.resize(3);
00350     v[0]=v[1]=v[2]=0;      
00351   }
00352     
00353 }
00354 
00355 
00356 void Orient::setFromRotationComponent(const Matrix4& mt)
00357 {
00358   if (rep != Mat) {
00359     m = MatrixRef(NewObj Matrix(3,3));
00360     rep = Mat;
00361   }
00362   (*m)(0,0) = mt(1,1); (*m)(0,1) = mt(1,2);  (*m)(0,2) = mt(1,3); 
00363   (*m)(1,0) = mt(2,1); (*m)(1,1) = mt(2,2);  (*m)(1,2) = mt(2,3);
00364   (*m)(2,0) = mt(3,1); (*m)(2,1) = mt(3,2);  (*m)(2,2) = mt(3,3);
00365 }  
00366  
00367 
00368 /// \todo consider trucky cases, like the fact that quats can have two representation for a single orientation (perhaps even covert all the reps to quats for comparison?)
00369 ///       same with matrices etc
00370 bool Orient::operator==(const Orient& o) const throw()
00371 {
00372   if (&o == this) return true;
00373   
00374   Assert(o.rep < RepEnd);
00375   
00376   if (rep == o.rep) { // fast path
00377     if (rep!=Mat) {
00378       if (v.size() == o.v.size())
00379         return v == o.v;
00380       else
00381         return false;
00382     }
00383     return *m == *o.m;
00384   }
00385 
00386   // try converting each to the other first
00387   Orient tthis(*this);
00388   try {
00389     tthis.changeRep(o.rep);
00390     if (o.rep!=Mat) 
00391       return tthis.v == o.v;
00392     return *tthis.m == *o.m;
00393   } catch (std::exception&) {}
00394   Orient to(o);
00395   try {
00396     to.changeRep(rep);
00397     if (rep!=Mat)
00398       return v == to.v;
00399     return *m == *to.m;
00400   } catch (std::exception&) {
00401     return false; 
00402   }
00403 }
00404 
00405 
00406 /// \todo consider tricky cases, like the fact that quats can have two representation for a single orientation (perhaps even covert all the reps to quats for comparison?)
00407 ///       same with matrices etc
00408 bool Orient::equals(const Orient& o, Real epsilon) const throw()
00409 {
00410   if (&o == this) return true;
00411   
00412   Assert(o.rep < RepEnd);
00413   
00414   if (rep == o.rep) { // fast path
00415     if (rep!=Mat) {
00416       if (v.size() == o.v.size())
00417         return base::equals(v, o.v, epsilon);
00418       else
00419         return false;
00420     }
00421     return base::equals(*m, *o.m, epsilon);
00422   }  
00423 
00424   // try converting each to the other first
00425   Orient tthis(*this);
00426   try {
00427     tthis.changeRep(o.rep);
00428     if (o.rep!=Mat)
00429       return base::equals(tthis.v, o.v, epsilon);
00430     return base::equals(*(tthis.m), *o.m, epsilon);
00431   } catch (std::exception&) {}
00432   Orient to(o);
00433   try {
00434     to.changeRep(rep);
00435     if (rep!=Mat)
00436       return base::equals(v, to.v, epsilon);
00437     return base::equals(*m, *to.m, epsilon);
00438   } catch (std::exception&) {
00439     return false; 
00440   }
00441   
00442 }
00443 
00444 
00445 
00446 void Orient::changeRep(Representation newRep) const
00447 {
00448   Assert(rep < RepEnd);
00449   Assert(newRep < RepEnd);
00450   
00451   if (rep == newRep) return; // no conversion necessary
00452   
00453 
00454   // convert from EulerIJKf  
00455   if (isEuler()) {
00456     
00457     if (newRep == Quat) { // to Quat
00458       
00459       Quat4 qu;
00460       Real a[3], ti, tj, th, ci, cj, ch, si, sj, sh, cc, cs, sc, ss;
00461       Axis i,j,k,h;
00462       Parity n;
00463       Repetition s;
00464       Frame f;
00465       getRep(rep,i,j,k,h,n,s,f);
00466       if (f==Rotating) {Real t = v[X]; v[X] = v[Z]; v[Z] = t;}
00467       if (n==Odd) v[Y] = -v[Y];
00468       ti = v[X]*0.5; tj = v[Y]*0.5; th = v[Z]*0.5;
00469       ci = Math::cos(ti);  cj = Math::cos(tj);  ch = Math::cos(th);
00470       si = Math::sin(ti);  sj = Math::sin(tj);  sh = Math::sin(th);
00471       cc = ci*ch; cs = ci*sh; sc = si*ch; ss = si*sh;
00472       if (s==Repeating) {
00473           a[i] = cj*(cs + sc);  // Could speed up with 
00474           a[j] = sj*(cc + ss);  // trig identities. 
00475           a[k] = sj*(cs - sc);
00476           qu.w = cj*(cc - ss);
00477       } else {
00478           a[i] = cj*sc - sj*cs;
00479           a[j] = cj*ss + sj*cc;
00480           a[k] = cj*cs - sj*sc;
00481           qu.w = cj*cc + sj*ss;
00482       }
00483       if (n==Odd) a[j] = -a[j];
00484       qu.v.x = a[X]; qu.v.y = a[Y]; qu.v.z = a[Z];
00485       v.resize(4);
00486       v[X]=qu.v.x; v[Y]=qu.v.y; v[Z]=qu.v.z; v[W]=qu.w;
00487       rep=Quat;
00488       return;
00489       
00490     }
00491     else if (newRep == Mat) { // to Mat
00492 
00493       m = MatrixRef(NewObj Matrix(3,3));
00494       Matrix& M(*this->m);
00495       
00496       Real ti, tj, th, ci, cj, ch, si, sj, sh, cc, cs, sc, ss;
00497       Axis i,j,k,h;
00498       Parity n;
00499       Repetition s;
00500       Frame f;
00501       getRep(rep,i,j,k,h,n,s,f);
00502       if (f==Rotating) {Real t = v[X]; v[X] = v[Z]; v[Z] = t;}
00503       if (n==Odd) { v[X] = -v[X]; v[Y] = -v[Y]; v[Z] = -v[Z];}
00504       ti = v[X]; tj = v[Y]; th = v[Z];
00505       ci = Math::cos(ti); cj = Math::cos(tj); ch = Math::cos(th);
00506       si = Math::sin(ti); sj = Math::sin(tj); sh = Math::sin(th);
00507       cc = ci*ch; cs = ci*sh; sc = si*ch; ss = si*sh;
00508       if (s==Repeating) {
00509           M(i,i) = cj;     M(i,j) =  sj*si;    M(i,k) =  sj*ci;
00510           M(j,i) = sj*sh;  M(j,j) = -cj*ss+cc; M(j,k) = -cj*cs-sc;
00511           M(k,i) = -sj*ch; M(k,j) =  cj*sc+cs; M(k,k) =  cj*cc-ss;
00512       } else {
00513           M(i,i) = cj*ch; M(i,j) = sj*sc-cs; M(i,k) = sj*cc+ss;
00514           M(j,i) = cj*sh; M(j,j) = sj*ss+cc; M(j,k) = sj*cs-sc;
00515           M(k,i) = -sj;   M(k,j) = cj*si;    M(k,k) = cj*ci;
00516       }
00517       
00518       rep=Mat;
00519       return;
00520     }
00521     else {
00522       // try to convert whatever to a Quat first
00523       changeRep(Quat);
00524       changeRep(newRep);
00525       return;
00526     }
00527     
00528   }
00529   else if (rep == Quat) { // convert from Quat
00530     
00531     if (isEuler(newRep)) { // to EulerIJKf
00532       
00533       changeRep(Mat); // via Mat
00534       changeRep(newRep);
00535       return;
00536       
00537     }
00538     else if (newRep == Mat) { // to Mat
00539       
00540       Real nq = v[0]*v[0]+v[1]*v[1]+v[2]*v[2]+v[3]*v[3];
00541       //!!! NB: the Graphics Gems impl. is identical except for not taking the srqt of nq opn the next line(!?)
00542       Real s = (nq> Real(0))? (Real(2)/base::sqrt(nq)):Real(0); 
00543       
00544       Real xs = v[0]*s, ys = v[1]*s, zs = v[2]*s;
00545       Real wx = v[3]*xs,wy = v[3]*ys,wz = v[3]*zs;
00546       Real xx = v[0]*xs,xy = v[0]*ys,xz = v[0]*zs;
00547       Real yy = v[1]*ys,yz = v[1]*zs,zz = v[2]*zs;
00548 
00549       m = MatrixRef(NewObj Matrix(3,3));
00550       
00551       (*m)(0,0) = Real(1) - (yy+zz);
00552       (*m)(1,0) = xy+wz;
00553       (*m)(2,0) = xz-wy;
00554       (*m)(0,1) = xy - wz;
00555       (*m)(1,1) = Real(1) - (xx+zz);
00556       (*m)(2,1) = yz+wx;
00557       (*m)(0,2) = xz+wy;
00558       (*m)(1,2) = yz-wx;
00559       (*m)(2,2) = Real(1) - (xx+yy);
00560       rep = Mat;
00561       return;
00562     }
00563     else if (newRep == Quat) 
00564     {
00565       return; // nothing to do
00566     }
00567     
00568   }
00569   else if (rep == Mat) { // convert from Mat
00570 
00571     if (isEuler(newRep)) { // to EulerIJKf
00572 
00573       const Matrix& M(*this->m);
00574       v.resize(3);
00575       Axis i,j,k,h;
00576       Parity n;
00577       Repetition s;
00578       Frame f;
00579       getRep(newRep,i,j,k,h,n,s,f);
00580       if (s==Repeating) {
00581           Real sy = Math::sqrt(M(i,j)*M(i,j) + M(i,k)*M(i,k));
00582           if (sy > 16*consts::minReal) {
00583               v[X] = Math::atan2(M(i,j), M(i,k));
00584               v[Y] = Math::atan2(sy, M(i,i));
00585               v[Z] = Math::atan2(M(j,i), -M(k,i));
00586           } else {
00587               v[X] = Math::atan2(-M(j,k), M(j,j));
00588               v[Y] = Math::atan2(sy, M(i,i));
00589               v[Z] = 0;
00590           }
00591       } else {
00592           Real cy = Math::sqrt(M(i,i)*M(i,i) + M(j,i)*M(j,i));
00593           if (cy > 16*consts::minReal) {
00594               v[X] = Math::atan2(M(k,j), M(k,k));
00595               v[Y] = Math::atan2(-M(k,i), cy);
00596               v[Z] = Math::atan2(M(j,i), M(i,i));
00597           } else {
00598               v[X] = Math::atan2(-M(j,k), M(j,j));
00599               v[Y] = Math::atan2(-M(k,i), cy);
00600               v[Z] = 0;
00601           }
00602       }
00603       if (n==Odd) {v[X] = -v[X]; v[Y] = - v[Y]; v[Z] = -v[Z];}
00604       if (f==Rotating) {Real t = v[X]; v[X] = v[Z]; v[Z] = t;}
00605 
00606       rep=newRep;
00607       return;      
00608       
00609     }
00610     else if (newRep == Quat) { // to Quat
00611 
00612       // Algorithm is from the Matrix and Quaternion FAQ
00613       //  ( currently http://www.cs.ualberta.ca/~andreas/math/matrfaq_latest.html )
00614       const Matrix& m(*this->m);
00615       v.resize(4);
00616   
00617       Real tr = 1 + m(0,0) + m(1,1) + m(2,2);
00618       if (tr > consts::epsilon) {
00619         Real s = sqrt(tr)*2.0;
00620         v[0] = (m(2,1) - m(1,2))/s;
00621         v[1] = (m(0,2) - m(2,0))/s;
00622         v[2] = (m(1,0) - m(0,1))/s;
00623         v[3] = 0.25*s;
00624       } 
00625       else {
00626         
00627         if ((m(0,0) > m(1,1)) && (m(0,0) > m(2,2))) {
00628           Real s = sqrt(1+m(0,0)-m(1,1)-m(2,2))*2.0;
00629           v[0] = 0.25*s;
00630           v[1] = (m(1,0)+m(0,1))/s;
00631           v[2] = (m(0,2)+m(2,0))/s;
00632           v[3] = (m(2,1)-m(1,2))/s;
00633         }
00634         else if (m(1,1) > m(2,2)) {
00635           Real s = sqrt(1+m(1,1)-m(0,0)-m(2,2))*2.0;
00636           v[0] = (m(1,0)+m(0,1))/s;
00637           v[1] = 0.25*s;
00638           v[2] = (m(2,1)+m(1,2))/s;
00639           v[3] = (m(0,2)-m(2,0))/s;
00640         }
00641         else {
00642           Real s = sqrt(1+m(2,2)-m(0,0)-m(1,1))*2.0;
00643           v[0] = (m(0,2)+m(2,0))/s;
00644           v[1] = (m(2,1)+m(1,2))/s;
00645           v[2] = 0.25*s;
00646           v[3] = (m(1,0)-m(0,1))/s;
00647         }
00648       }
00649       
00650       rep=Quat;
00651       return;
00652     }
00653     else if (newRep == Mat) { 
00654       return; // nothing to do
00655     }
00656 
00657 
00658   }
00659 
00660   throw std::runtime_error(Exception("conversion from "+representationString(rep)+" to "+representationString(newRep)+" unsupported"));
00661 
00662 }
00663         
00664 
00665 
00666 
00667 
00668 Matrix Orient::getBinv() const
00669 {
00670   Matrix Binv;
00671 
00672   if (rep == EulerRPY) {
00673 
00674     // implementation taken from IKORv2 Euler_to_Velocities() function
00675     Binv.resize(3,3);
00676 
00677     //const Real& alpha(v[0]); 
00678     const Real& beta(v[1]);  
00679     const Real& gamma(v[2]); 
00680     Real cb = Math::cos(beta);
00681     Real cg = Math::cos(gamma);
00682     Real sb = Math::sin(beta);
00683     Real sg = Math::sin(gamma);
00684 
00685     Binv(0,0) = cg*cb; Binv(0,1) = -sg; Binv(0,2) = 0;
00686     Binv(1,0) = sg*cb; Binv(1,1) = cg;  Binv(1,2) = 0;
00687     Binv(2,0) = -sb;   Binv(2,1) = 0;   Binv(2,2) = 1;
00688   }
00689   else if (rep == Quat) {
00690 
00691     Binv.resize(3,4);
00692     
00693     // this comes from Brian Mirtich's thesis (Univ. of California, Berkeley, 1996, p235), 
00694     // !!! check it is correct (as Brian doesn't use the B notation, compare with
00695     //     a book that does!)
00696     const Real& qx(v[0]);
00697     const Real& qy(v[1]);
00698     const Real& qz(v[2]);
00699     const Real& qw(v[3]); // scalar component
00700     
00701     Binv(0,0) = -qx; Binv(0,1) = +qw; Binv(0,2) = +qz; Binv(0,3) = -qy;
00702     Binv(1,0) = -qy; Binv(1,1) = -qz; Binv(1,2) = +qw; Binv(1,3) = +qx;
00703     Binv(2,0) = -qz; Binv(2,1) = +qy; Binv(2,2) = -qx; Binv(2,3) = +qw;
00704     Binv = 2.0*Binv;
00705     
00706   }
00707   else {
00708     throw std::runtime_error(Exception("Binv generation from current orientation representation unsupported"));
00709   }
00710 
00711   return Binv;
00712 }
00713 
00714 
00715 
00716 Orient Orient::interpolate(const Orient& lower, const Orient& upper, Real t) 
00717 {
00718   Math::bound(t, 0.0, 1.0);
00719 
00720   if (t == 0.0) return lower;
00721   if (t == 1.0) return upper;
00722 
00723   // we convert both orientations to Quats and use the Quat4::interpolate() method
00724   //  which uses SLERP (Spherical Linear intERPolation)
00725   Orient ofrom(lower); ofrom.changeRep(Quat); // copy & change rep
00726   Orient oto(upper); oto.changeRep(Quat);
00727   Quat4 from(ofrom[0], ofrom[1], ofrom[2], ofrom[3]); // convert to Quat4
00728   Quat4 to(oto[0], oto[1], oto[2], oto[3]);
00729 
00730   Quat4 interp(Quat4::interpolate(from,to,t)); // SLERP
00731 
00732   return Orient(interp);
00733 }
00734 
00735 
00736 Orient& Orient::invert()
00737 {
00738   if (rep == Mat) {
00739     Matrix3 m3( base::toMatrix3(*m) );
00740     m3.invert();
00741     *m = base::fromMatrix3(m3);
00742   }
00743   else {
00744     Quat4 q( getQuat4() );
00745     q.invert();
00746     *this = q;
00747   }
00748   return *this;
00749 }
00750 
00751 
00752 
00753 
00754 void Orient::serialize(Serializer& s)
00755 {
00756   Representation oldrep(rep);
00757   s(rep,"rep");
00758 
00759   if (s.isOutput()) {
00760     if (rep!=Mat)
00761       s(v,"v");
00762     else
00763       s(*m,"m");
00764   }
00765   else {
00766     if (rep!=Mat) {
00767       if (oldrep==Mat) {
00768         delete &(*m);
00769         m=MatrixRef(0);
00770       }
00771       s(v,"v");
00772     }
00773     else {
00774       if (oldrep!=Mat)
00775         m = MatrixRef(NewObj Matrix(3,3));
00776       s(*m,"m");
00777     }
00778   }
00779   Assert(rep < RepEnd);
00780 }
00781 
00782 
00783 
00784 
00785 

Generated on Thu Jul 29 15:56:08 2004 for OpenSim by doxygen 1.3.6