00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #ifndef CQuaternion_H
00030 #define CQuaternion_H
00031
00032 #include <mrpt/math/CMatrixTemplateNumeric.h>
00033 #include <mrpt/math/CVectorTemplate.h>
00034 #include <mrpt/math/CArray.h>
00035
00036 namespace mrpt
00037 {
00038 namespace math
00039 {
00040
00041
00042 #define UNINITIALIZED_QUATERNION false,false
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058 template <class T>
00059 class CQuaternion : public CArrayNumeric<T,4>
00060 {
00061 typedef CArrayNumeric<T,4> BASE;
00062 public:
00063
00064
00065
00066
00067 inline CQuaternion(bool, bool ) { }
00068
00069
00070 inline CQuaternion()
00071 {
00072 (*this)[0] = 1;
00073 (*this)[1] = 0;
00074 (*this)[2] = 0;
00075 (*this)[3] = 0;
00076 }
00077
00078
00079 inline CQuaternion(const T r,const T x,const T y,const T z)
00080 {
00081 (*this)[0] = r;
00082 (*this)[1] = x;
00083 (*this)[2] = y;
00084 (*this)[3] = z;
00085 ASSERTDEBMSG_(std::abs(normSqr()-1.0)<1e-5, format("Initialization data for quaternion is not normalized: %f %f %f %f -> sqrNorm=%f",r,x,y,z,normSqr()) );
00086 }
00087
00088
00089
00090
00091
00092 inline T r()const {return (*this)[0];}
00093 inline T x()const {return (*this)[1];}
00094 inline T y()const {return (*this)[2];}
00095 inline T z()const {return (*this)[3];}
00096 inline void r(const T r) {(*this)[0]=r;}
00097 inline void x(const T x) {(*this)[1]=x;}
00098 inline void y(const T y) {(*this)[2]=y;}
00099 inline void z(const T z) {(*this)[3]=z;}
00100
00101
00102
00103 template <class ARRAYLIKE>
00104 void fromRodriguesVector(const ARRAYLIKE &in)
00105 {
00106 if (in.size()!=3) THROW_EXCEPTION("Wrong Dimension in input vector for quaternion Constructor");
00107
00108 const T x = in[0];
00109 const T y = in[1];
00110 const T z = in[2];
00111 if ((x==0)&&(y==0)&&(z==0))
00112 {
00113 (*this)[0] = 1;
00114 (*this)[1] = 0;
00115 (*this)[2] = 0;
00116 (*this)[3] = 0;
00117 }
00118 else
00119 {
00120 const T angle = sqrt(x*x+y*y+z*z);
00121 const T s = (sin(angle/2))/angle;
00122 const T c = cos(angle/2);
00123 (*this)[0] = c;
00124 (*this)[1] = x * s;
00125 (*this)[2] = y * s;
00126 (*this)[3] = z * s;
00127 }
00128 }
00129
00130
00131
00132
00133 inline void crossProduct(const CQuaternion &q1, const CQuaternion &q2)
00134 {
00135 this->r( q1.r()*q2.r() - q1.x()*q2.x() - q1.y()*q2.y() - q1.z()*q2.z() );
00136 this->x( q1.r()*q2.x() + q2.r()*q1.x() + q1.y()*q2.z() - q2.y()*q1.z() );
00137 this->y( q1.r()*q2.y() + q2.r()*q1.y() + q1.z()*q2.x() - q2.z()*q1.x() );
00138 this->z( q1.r()*q2.z() + q2.r()*q1.z() + q1.x()*q2.y() - q2.x()*q1.y() );
00139 this->normalize();
00140 }
00141
00142
00143
00144 void rotatePoint(const double lx,const double ly,const double lz, double &gx,double &gy,double &gz ) const
00145 {
00146 const double t2 = r()*x(); const double t3 = r()*y(); const double t4 = r()*z(); const double t5 =-x()*x(); const double t6 = x()*y();
00147 const double t7 = x()*z(); const double t8 =-y()*y(); const double t9 = y()*z(); const double t10=-z()*z();
00148 gx = 2*((t8+ t10)*lx+(t6 - t4)*ly+(t3+t7)*lz)+lx;
00149 gy = 2*((t4+ t6)*lx+(t5 +t10)*ly+(t9-t2)*lz)+ly;
00150 gz = 2*((t7- t3)*lx+(t2 + t9)*ly+(t5+t8)*lz)+lz;
00151 }
00152
00153
00154
00155 void inverseRotatePoint(const double lx,const double ly,const double lz, double &gx,double &gy,double &gz ) const
00156 {
00157 const double t2 =-r()*x(); const double t3 =-r()*y(); const double t4 =-r()*z(); const double t5 =-x()*x(); const double t6 = x()*y();
00158 const double t7 = x()*z(); const double t8 =-y()*y(); const double t9 = y()*z(); const double t10=-z()*z();
00159 gx = 2*((t8+ t10)*lx+(t6 - t4)*ly+(t3+t7)*lz)+lx;
00160 gy = 2*((t4+ t6)*lx+(t5 +t10)*ly+(t9-t2)*lz)+ly;
00161 gz = 2*((t7- t3)*lx+(t2 + t9)*ly+(t5+t8)*lz)+lz;
00162 }
00163
00164
00165 inline double normSqr() const { return square(r()) + square(x()) + square(y()) + square(z()); }
00166
00167
00168
00169 inline void normalize()
00170 {
00171 const T qq = 1.0/sqrt( normSqr() );
00172 for (unsigned int i=0;i<4;i++)
00173 (*this)[i] *= qq;
00174 }
00175
00176
00177
00178
00179 template <class MATRIXLIKE>
00180 void normalizationJacobian(MATRIXLIKE &J) const
00181 {
00182 const T n = 1.0/pow(normSqr(),T(1.5));
00183 J.setSize(4,4);
00184 J.get_unsafe(0,0)=x()*x()+y()*y()+z()*z();
00185 J.get_unsafe(0,1)=-r()*x();
00186 J.get_unsafe(0,2)=-r()*y();
00187 J.get_unsafe(0,3)=-r()*z();
00188
00189 J.get_unsafe(1,0)=-x()*r();
00190 J.get_unsafe(1,1)=r()*r()+y()*y()+z()*z();
00191 J.get_unsafe(1,2)=-x()*y();
00192 J.get_unsafe(1,3)=-x()*z();
00193
00194 J.get_unsafe(2,0)=-y()*r();
00195 J.get_unsafe(2,1)=-y()*x();
00196 J.get_unsafe(2,2)=r()*r()+x()*x()+z()*z();
00197 J.get_unsafe(2,3)=-y()*z();
00198
00199 J.get_unsafe(3,0)=-z()*r();
00200 J.get_unsafe(3,1)=-z()*x();
00201 J.get_unsafe(3,2)=-z()*y();
00202 J.get_unsafe(3,3)=r()*r()+x()*x()+y()*y();
00203 J *=n;
00204 }
00205
00206
00207
00208
00209 template <class MATRIXLIKE>
00210 inline void rotationJacobian(MATRIXLIKE &J) const
00211 {
00212 J.setSize(4,4);
00213 J.get_unsafe(0,0)=r(); J.get_unsafe(0,1)=-x(); J.get_unsafe(0,2)=-y(); J.get_unsafe(0,3)=-z();
00214 J.get_unsafe(1,0)=x(); J.get_unsafe(1,1)= r(); J.get_unsafe(1,2)=-z(); J.get_unsafe(1,3)= y();
00215 J.get_unsafe(2,0)=y(); J.get_unsafe(2,1)= z(); J.get_unsafe(2,2)= r(); J.get_unsafe(2,3)=-x();
00216 J.get_unsafe(3,0)=z(); J.get_unsafe(3,1)=-y(); J.get_unsafe(3,2)= x(); J.get_unsafe(3,3)= r();
00217 }
00218
00219
00220 template <class MATRIXLIKE>
00221 inline void rotationMatrix(MATRIXLIKE &M) const
00222 {
00223 M.setSize(3,3);
00224 rotationMatrixNoResize(M);
00225 }
00226
00227
00228 template <class MATRIXLIKE>
00229 inline void rotationMatrixNoResize(MATRIXLIKE &M) const
00230 {
00231 M.get_unsafe(0,0)=r()*r()+x()*x()-y()*y()-z()*z(); M.get_unsafe(0,1)=2*(x()*y() -r()*z()); M.get_unsafe(0,2)=2*(z()*x()+r()*y());
00232 M.get_unsafe(1,0)=2*(x()*y()+r()*z()); M.get_unsafe(1,1)=r()*r()-x()*x()+y()*y()-z()*z(); M.get_unsafe(1,2)=2*(y()*z()-r()*x());
00233 M.get_unsafe(2,0)=2*(z()*x()-r()*y()); M.get_unsafe(2,1)=2*(y()*z()+r()*x()); M.get_unsafe(2,2)=r()*r()-x()*x()-y()*y()+z()*z();
00234 }
00235
00236
00237
00238 inline void conj(CQuaternion &q_out) const
00239 {
00240 q_out.r( r() );
00241 q_out.x(-x() );
00242 q_out.y(-y() );
00243 q_out.z(-z() );
00244 }
00245
00246
00247 inline CQuaternion conj() const
00248 {
00249 CQuaternion q_aux;
00250 conj(q_aux);
00251 return q_aux;
00252 }
00253
00254
00255
00256
00257
00258 inline void rpy(T &roll, T &pitch, T &yaw) const
00259 {
00260 rpy_and_jacobian(roll,pitch,yaw,static_cast<mrpt::math::CMatrixDouble*>(NULL));
00261 }
00262
00263
00264
00265
00266
00267
00268 template <class MATRIXLIKE>
00269 void rpy_and_jacobian(T &roll, T &pitch, T &yaw, MATRIXLIKE *out_dr_dq = NULL, bool resize_out_dr_dq_to3x4 = true ) const
00270 {
00271 if (out_dr_dq && resize_out_dr_dq_to3x4)
00272 out_dr_dq->setSize(3,4);
00273 const T discr = r()*y()-x()*z();
00274 if (fabs(discr)>0.49999)
00275 {
00276 pitch = 0.5*M_PI;
00277 yaw =-2*atan2(x(),r());
00278 roll = 0;
00279 if (out_dr_dq) {
00280 out_dr_dq->zeros();
00281 out_dr_dq->get_unsafe(0,0) = +2/x();
00282 out_dr_dq->get_unsafe(0,2) = -2*r()/(x()*x());
00283 }
00284 }
00285 else if (discr<-0.49999)
00286 {
00287 pitch = -0.5*M_PI;
00288 yaw =+2*atan2(x(),r());
00289 roll = 0;
00290 if (out_dr_dq) {
00291 out_dr_dq->zeros();
00292 out_dr_dq->get_unsafe(0,0) = -2/x();
00293 out_dr_dq->get_unsafe(0,2) = +2*r()/(x()*x());
00294 }
00295 }
00296 else
00297 {
00298 yaw = atan2( 2*(r()*z()+x()*y()), 1-2*(y()*y()+z()*z()) );
00299 pitch = asin ( 2*discr );
00300 roll = atan2( 2*(r()*x()+y()*z()), 1-2*(x()*x()+y()*y()) );
00301 if (out_dr_dq) {
00302
00303 const double val1=(2*x()*x() + 2*y()*y() - 1);
00304 const double val12=square(val1);
00305 const double val2=(2*r()*x() + 2*y()*z());
00306 const double val22=square(val2);
00307 const double xy2 = 2*x()*y();
00308 const double rz2 = 2*r()*z();
00309 const double ry2 = 2*r()*y();
00310 const double val3 = (2*y()*y() + 2*z()*z() - 1);
00311 const double val4 = ((square(rz2 + xy2)/square(val3) + 1)*val3);
00312 const double val5 = (4*(rz2 + xy2))/square(val3);
00313 const double val6 = 1.0/(square(rz2 + xy2)/square(val3) + 1);
00314 const double val7 = 2.0/ sqrt(1 - square(ry2 - 2*x()*z()));
00315 const double val8 = (val22/val12 + 1);
00316 const double val9 = -2.0/val8;
00317
00318 out_dr_dq->get_unsafe(0,0) = -2*z()/val4;
00319 out_dr_dq->get_unsafe(0,1) = -2*y()/val4;
00320 out_dr_dq->get_unsafe(0,2) = -(2*x()/val3 - y()*val5)*val6 ;
00321 out_dr_dq->get_unsafe(0,3) = -(2*r()/val3 - z()*val5)*val6;
00322
00323 out_dr_dq->get_unsafe(1,0) = y()*val7 ;
00324 out_dr_dq->get_unsafe(1,1) = -z()*val7 ;
00325 out_dr_dq->get_unsafe(1,2) = r()*val7 ;
00326 out_dr_dq->get_unsafe(1,3) = -x()*val7 ;
00327
00328 out_dr_dq->get_unsafe(2,0) = val9*x()/val1 ;
00329 out_dr_dq->get_unsafe(2,1) = val9*(r()/val1 - (2*x()*val2)/val12) ;
00330 out_dr_dq->get_unsafe(2,2) = val9*(z()/val1 - (2*y()*val2)/val12) ;
00331 out_dr_dq->get_unsafe(2,3) = val9*y()/val1 ;
00332 }
00333 }
00334 }
00335
00336 inline CQuaternion operator * (const T &factor)
00337 {
00338 CQuaternion q = *this;
00339 q*=factor;
00340 return q;
00341 }
00342
00343 };
00344
00345 typedef CQuaternion<double> CQuaternionDouble;
00346 typedef CQuaternion<float> CQuaternionFloat;
00347
00348 }
00349
00350 }
00351
00352 #endif