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/CArray.h>
00034
00035 namespace mrpt
00036 {
00037 namespace math
00038 {
00039
00040 enum TConstructorFlags_Quaternions
00041 {
00042 UNINITIALIZED_QUATERNION = 0
00043 };
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060 template <class T>
00061 class CQuaternion : public CArrayNumeric<T,4>
00062 {
00063 typedef CArrayNumeric<T,4> Base;
00064 public:
00065
00066
00067
00068
00069 inline CQuaternion(TConstructorFlags_Quaternions constructor_dummy_param) { }
00070
00071
00072 inline CQuaternion()
00073 {
00074 (*this)[0] = 1;
00075 (*this)[1] = 0;
00076 (*this)[2] = 0;
00077 (*this)[3] = 0;
00078 }
00079
00080
00081 inline CQuaternion(const T r,const T x,const T y,const T z)
00082 {
00083 (*this)[0] = r;
00084 (*this)[1] = x;
00085 (*this)[2] = y;
00086 (*this)[3] = z;
00087 ASSERTDEBMSG_(std::abs(normSqr()-1.0)<1e-5, mrpt::format("Initialization data for quaternion is not normalized: %f %f %f %f -> sqrNorm=%f",r,x,y,z,normSqr()) );
00088 }
00089
00090
00091
00092
00093
00094 inline T r()const {return (*this)[0];}
00095 inline T x()const {return (*this)[1];}
00096 inline T y()const {return (*this)[2];}
00097 inline T z()const {return (*this)[3];}
00098 inline void r(const T r) {(*this)[0]=r;}
00099 inline void x(const T x) {(*this)[1]=x;}
00100 inline void y(const T y) {(*this)[2]=y;}
00101 inline void z(const T z) {(*this)[3]=z;}
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114 template <class ARRAYLIKE3>
00115 void fromRodriguesVector(const ARRAYLIKE3 &v)
00116 {
00117 if (v.size()!=3) THROW_EXCEPTION("Vector v must have a length=3");
00118
00119 const T x = v[0];
00120 const T y = v[1];
00121 const T z = v[2];
00122 const T angle = std::sqrt(x*x+y*y+z*z);
00123 if (angle<1e-7)
00124 {
00125 (*this)[0] = 1;
00126 (*this)[1] = static_cast<T>(0.5)*x;
00127 (*this)[2] = static_cast<T>(0.5)*y;
00128 (*this)[3] = static_cast<T>(0.5)*z;
00129 }
00130 else
00131 {
00132 const T s = (::sin(angle/2))/angle;
00133 const T c = ::cos(angle/2);
00134 (*this)[0] = c;
00135 (*this)[1] = x * s;
00136 (*this)[2] = y * s;
00137 (*this)[3] = z * s;
00138 }
00139 }
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150 template <class ARRAYLIKE3>
00151 inline void ln(ARRAYLIKE3 &out_ln) const
00152 {
00153 if (out_ln.size()!=3) out_ln.resize(3);
00154 this->ln_noresize(out_ln);
00155 }
00156
00157 template <class ARRAYLIKE3>
00158 inline ARRAYLIKE3 ln() const
00159 {
00160 ARRAYLIKE3 out_ln;
00161 this->ln(out_ln);
00162 return out_ln;
00163 }
00164
00165 template <class ARRAYLIKE3>
00166 void ln_noresize(ARRAYLIKE3 &out_ln) const
00167 {
00168 using mrpt::utils::square;
00169 const T xyz_norm = std::sqrt(square(x())+square(y())+square(z()));
00170 const T K = (xyz_norm<1e-7) ? 2 : 2*::acos(r())/xyz_norm;
00171 out_ln[0] = K*x();
00172 out_ln[1] = K*y();
00173 out_ln[2] = K*z();
00174 }
00175
00176
00177
00178 template <class ARRAYLIKE3>
00179 inline static CQuaternion<T> exp(const ARRAYLIKE3 & v)
00180 {
00181 CQuaternion<T> q(UNINITIALIZED_QUATERNION);
00182 q.fromRodriguesVector(v);
00183 return q;
00184 }
00185
00186 template <class ARRAYLIKE3>
00187 inline static void exp(const ARRAYLIKE3 & v, CQuaternion<T> & out_quat)
00188 {
00189 out_quat.fromRodriguesVector(v);
00190 }
00191
00192
00193
00194
00195
00196
00197
00198 inline void crossProduct(const CQuaternion &q1, const CQuaternion &q2)
00199 {
00200 this->r( q1.r()*q2.r() - q1.x()*q2.x() - q1.y()*q2.y() - q1.z()*q2.z() );
00201 this->x( q1.r()*q2.x() + q2.r()*q1.x() + q1.y()*q2.z() - q2.y()*q1.z() );
00202 this->y( q1.r()*q2.y() + q2.r()*q1.y() + q1.z()*q2.x() - q2.z()*q1.x() );
00203 this->z( q1.r()*q2.z() + q2.r()*q1.z() + q1.x()*q2.y() - q2.x()*q1.y() );
00204 this->normalize();
00205 }
00206
00207
00208
00209 void rotatePoint(const double lx,const double ly,const double lz, double &gx,double &gy,double &gz ) const
00210 {
00211 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();
00212 const double t7 = x()*z(); const double t8 =-y()*y(); const double t9 = y()*z(); const double t10=-z()*z();
00213 gx = 2*((t8+ t10)*lx+(t6 - t4)*ly+(t3+t7)*lz)+lx;
00214 gy = 2*((t4+ t6)*lx+(t5 +t10)*ly+(t9-t2)*lz)+ly;
00215 gz = 2*((t7- t3)*lx+(t2 + t9)*ly+(t5+t8)*lz)+lz;
00216 }
00217
00218
00219
00220 void inverseRotatePoint(const double lx,const double ly,const double lz, double &gx,double &gy,double &gz ) const
00221 {
00222 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();
00223 const double t7 = x()*z(); const double t8 =-y()*y(); const double t9 = y()*z(); const double t10=-z()*z();
00224 gx = 2*((t8+ t10)*lx+(t6 - t4)*ly+(t3+t7)*lz)+lx;
00225 gy = 2*((t4+ t6)*lx+(t5 +t10)*ly+(t9-t2)*lz)+ly;
00226 gz = 2*((t7- t3)*lx+(t2 + t9)*ly+(t5+t8)*lz)+lz;
00227 }
00228
00229
00230 inline double normSqr() const {
00231 using mrpt::utils::square;
00232 return square(r()) + square(x()) + square(y()) + square(z());
00233 }
00234
00235
00236
00237 inline void normalize()
00238 {
00239 const T qq = 1.0/std::sqrt( normSqr() );
00240 for (unsigned int i=0;i<4;i++)
00241 (*this)[i] *= qq;
00242 }
00243
00244
00245
00246
00247 template <class MATRIXLIKE>
00248 void normalizationJacobian(MATRIXLIKE &J) const
00249 {
00250 const T n = 1.0/std::pow(normSqr(),T(1.5));
00251 J.setSize(4,4);
00252 J.get_unsafe(0,0)=x()*x()+y()*y()+z()*z();
00253 J.get_unsafe(0,1)=-r()*x();
00254 J.get_unsafe(0,2)=-r()*y();
00255 J.get_unsafe(0,3)=-r()*z();
00256
00257 J.get_unsafe(1,0)=-x()*r();
00258 J.get_unsafe(1,1)=r()*r()+y()*y()+z()*z();
00259 J.get_unsafe(1,2)=-x()*y();
00260 J.get_unsafe(1,3)=-x()*z();
00261
00262 J.get_unsafe(2,0)=-y()*r();
00263 J.get_unsafe(2,1)=-y()*x();
00264 J.get_unsafe(2,2)=r()*r()+x()*x()+z()*z();
00265 J.get_unsafe(2,3)=-y()*z();
00266
00267 J.get_unsafe(3,0)=-z()*r();
00268 J.get_unsafe(3,1)=-z()*x();
00269 J.get_unsafe(3,2)=-z()*y();
00270 J.get_unsafe(3,3)=r()*r()+x()*x()+y()*y();
00271 J *=n;
00272 }
00273
00274
00275
00276
00277 template <class MATRIXLIKE>
00278 inline void rotationJacobian(MATRIXLIKE &J) const
00279 {
00280 J.setSize(4,4);
00281 J.get_unsafe(0,0)=r(); J.get_unsafe(0,1)=-x(); J.get_unsafe(0,2)=-y(); J.get_unsafe(0,3)=-z();
00282 J.get_unsafe(1,0)=x(); J.get_unsafe(1,1)= r(); J.get_unsafe(1,2)=-z(); J.get_unsafe(1,3)= y();
00283 J.get_unsafe(2,0)=y(); J.get_unsafe(2,1)= z(); J.get_unsafe(2,2)= r(); J.get_unsafe(2,3)=-x();
00284 J.get_unsafe(3,0)=z(); J.get_unsafe(3,1)=-y(); J.get_unsafe(3,2)= x(); J.get_unsafe(3,3)= r();
00285 }
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296 template <class MATRIXLIKE>
00297 inline void rotationMatrix(MATRIXLIKE &M) const
00298 {
00299 M.setSize(3,3);
00300 rotationMatrixNoResize(M);
00301 }
00302
00303
00304 template <class MATRIXLIKE>
00305 inline void rotationMatrixNoResize(MATRIXLIKE &M) const
00306 {
00307 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());
00308 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());
00309 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();
00310 }
00311
00312
00313
00314 inline void conj(CQuaternion &q_out) const
00315 {
00316 q_out.r( r() );
00317 q_out.x(-x() );
00318 q_out.y(-y() );
00319 q_out.z(-z() );
00320 }
00321
00322
00323 inline CQuaternion conj() const
00324 {
00325 CQuaternion q_aux;
00326 conj(q_aux);
00327 return q_aux;
00328 }
00329
00330
00331
00332
00333
00334 inline void rpy(T &roll, T &pitch, T &yaw) const
00335 {
00336 rpy_and_jacobian(roll,pitch,yaw,static_cast<mrpt::math::CMatrixDouble*>(NULL));
00337 }
00338
00339
00340
00341
00342
00343
00344 template <class MATRIXLIKE>
00345 void rpy_and_jacobian(T &roll, T &pitch, T &yaw, MATRIXLIKE *out_dr_dq = NULL, bool resize_out_dr_dq_to3x4 = true ) const
00346 {
00347 using mrpt::utils::square;
00348 using std::sqrt;
00349
00350 if (out_dr_dq && resize_out_dr_dq_to3x4)
00351 out_dr_dq->setSize(3,4);
00352 const T discr = r()*y()-x()*z();
00353 if (fabs(discr)>0.49999)
00354 {
00355 pitch = 0.5*M_PI;
00356 yaw =-2*atan2(x(),r());
00357 roll = 0;
00358 if (out_dr_dq) {
00359 out_dr_dq->zeros();
00360 out_dr_dq->get_unsafe(0,0) = +2/x();
00361 out_dr_dq->get_unsafe(0,2) = -2*r()/(x()*x());
00362 }
00363 }
00364 else if (discr<-0.49999)
00365 {
00366 pitch = -0.5*M_PI;
00367 yaw =+2*atan2(x(),r());
00368 roll = 0;
00369 if (out_dr_dq) {
00370 out_dr_dq->zeros();
00371 out_dr_dq->get_unsafe(0,0) = -2/x();
00372 out_dr_dq->get_unsafe(0,2) = +2*r()/(x()*x());
00373 }
00374 }
00375 else
00376 {
00377 yaw = ::atan2( 2*(r()*z()+x()*y()), 1-2*(y()*y()+z()*z()) );
00378 pitch = ::asin ( 2*discr );
00379 roll = ::atan2( 2*(r()*x()+y()*z()), 1-2*(x()*x()+y()*y()) );
00380 if (out_dr_dq) {
00381
00382 const double val1=(2*x()*x() + 2*y()*y() - 1);
00383 const double val12=square(val1);
00384 const double val2=(2*r()*x() + 2*y()*z());
00385 const double val22=square(val2);
00386 const double xy2 = 2*x()*y();
00387 const double rz2 = 2*r()*z();
00388 const double ry2 = 2*r()*y();
00389 const double val3 = (2*y()*y() + 2*z()*z() - 1);
00390 const double val4 = ((square(rz2 + xy2)/square(val3) + 1)*val3);
00391 const double val5 = (4*(rz2 + xy2))/square(val3);
00392 const double val6 = 1.0/(square(rz2 + xy2)/square(val3) + 1);
00393 const double val7 = 2.0/ sqrt(1 - square(ry2 - 2*x()*z()));
00394 const double val8 = (val22/val12 + 1);
00395 const double val9 = -2.0/val8;
00396
00397 out_dr_dq->get_unsafe(0,0) = -2*z()/val4;
00398 out_dr_dq->get_unsafe(0,1) = -2*y()/val4;
00399 out_dr_dq->get_unsafe(0,2) = -(2*x()/val3 - y()*val5)*val6 ;
00400 out_dr_dq->get_unsafe(0,3) = -(2*r()/val3 - z()*val5)*val6;
00401
00402 out_dr_dq->get_unsafe(1,0) = y()*val7 ;
00403 out_dr_dq->get_unsafe(1,1) = -z()*val7 ;
00404 out_dr_dq->get_unsafe(1,2) = r()*val7 ;
00405 out_dr_dq->get_unsafe(1,3) = -x()*val7 ;
00406
00407 out_dr_dq->get_unsafe(2,0) = val9*x()/val1 ;
00408 out_dr_dq->get_unsafe(2,1) = val9*(r()/val1 - (2*x()*val2)/val12) ;
00409 out_dr_dq->get_unsafe(2,2) = val9*(z()/val1 - (2*y()*val2)/val12) ;
00410 out_dr_dq->get_unsafe(2,3) = val9*y()/val1 ;
00411 }
00412 }
00413 }
00414
00415 inline CQuaternion operator * (const T &factor)
00416 {
00417 CQuaternion q = *this;
00418 q*=factor;
00419 return q;
00420 }
00421
00422 };
00423
00424 typedef CQuaternion<double> CQuaternionDouble;
00425 typedef CQuaternion<float> CQuaternionFloat;
00426
00427 }
00428
00429 }
00430
00431 #endif