Main MRPT website > C++ reference
MRPT logo
CQuaternion.h
Go to the documentation of this file.
00001 /* +---------------------------------------------------------------------------+
00002    |          The Mobile Robot Programming Toolkit (MRPT) C++ library          |
00003    |                                                                           |
00004    |                       http://www.mrpt.org/                                |
00005    |                                                                           |
00006    |   Copyright (C) 2005-2011  University of Malaga                           |
00007    |                                                                           |
00008    |    This software was written by the Machine Perception and Intelligent    |
00009    |      Robotics Lab, University of Malaga (Spain).                          |
00010    |    Contact: Jose-Luis Blanco  <jlblanco@ctima.uma.es>                     |
00011    |                                                                           |
00012    |  This file is part of the MRPT project.                                   |
00013    |                                                                           |
00014    |     MRPT is free software: you can redistribute it and/or modify          |
00015    |     it under the terms of the GNU General Public License as published by  |
00016    |     the Free Software Foundation, either version 3 of the License, or     |
00017    |     (at your option) any later version.                                   |
00018    |                                                                           |
00019    |   MRPT is distributed in the hope that it will be useful,                 |
00020    |     but WITHOUT ANY WARRANTY; without even the implied warranty of        |
00021    |     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         |
00022    |     GNU General Public License for more details.                          |
00023    |                                                                           |
00024    |     You should have received a copy of the GNU General Public License     |
00025    |     along with MRPT.  If not, see <http://www.gnu.org/licenses/>.         |
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                 // For use with a constructor of CQuaternion
00040                 enum TConstructorFlags_Quaternions
00041                 {
00042                         UNINITIALIZED_QUATERNION = 0
00043                 };
00044 
00045                 /** A quaternion, which can represent a 3D rotation as pair \f$ (r,\mathbf{u}) \f$, with a real part "r" and a 3D vector \f$ \mathbf{u} = (x,y,z) \f$, or alternatively, q = r + ix + jy + kz.
00046                  *
00047                  *  The elements of the quaternion can be accessed by either:
00048                  *              - r(), x(), y(), z(), or
00049                  *              - the operator [] with indices running from 0 (=r) to 3 (=z).
00050                  *
00051                  *  Users will usually employ the typedef "CQuaternionDouble" instead of this template.
00052                  *
00053                  * For more information about quaternions, see:
00054                  *  - http://people.csail.mit.edu/bkph/articles/Quaternions.pdf
00055                  *  - http://en.wikipedia.org/wiki/Quaternions_and_spatial_rotation
00056                  *
00057                  * \ingroup mrpt_base_grp
00058                  * \sa mrpt::poses::CPose3D
00059                  */
00060                 template <class T>
00061                 class CQuaternion : public CArrayNumeric<T,4>
00062                 {
00063                         typedef CArrayNumeric<T,4> Base;
00064                 public:
00065         /* @{ Constructors
00066          */
00067 
00068                 /**     Can be used with UNINITIALIZED_QUATERNION as argument, does not initialize the 4 elements of the quaternion (use this constructor when speed is critical). */
00069                 inline CQuaternion(TConstructorFlags_Quaternions constructor_dummy_param) { }
00070 
00071                 /**     Default constructor: construct a (1, (0,0,0) ) quaternion representing no rotation. */
00072                 inline CQuaternion()
00073                 {
00074                         (*this)[0] = 1;
00075                         (*this)[1] = 0;
00076                         (*this)[2] = 0;
00077                         (*this)[3] = 0;
00078                 }
00079 
00080                 /**     Construct a quaternion from its parameters 'r', 'x', 'y', 'z', with q = r + ix + jy + kz. */
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];} //!< Return r coordinate of the quaternion
00095                 inline T  x()const {return (*this)[1];} //!< Return x coordinate of the quaternion
00096                 inline T  y()const {return (*this)[2];} //!< Return y coordinate of the quaternion
00097                 inline T  z()const {return (*this)[3];} //!< Return z coordinate of the quaternion
00098                 inline void  r(const T r) {(*this)[0]=r;}       //!< Set r coordinate of the quaternion
00099                 inline void  x(const T x) {(*this)[1]=x;}       //!< Set x coordinate of the quaternion
00100                 inline void  y(const T y) {(*this)[2]=y;}       //!< Set y coordinate of the quaternion
00101                 inline void  z(const T z) {(*this)[3]=z;}       //!< Set z coordinate of the quaternion
00102 
00103                 /**     Set this quaternion to the rotation described by a 3D (Rodrigues) rotation vector \f$ \mathbf{v} \f$:
00104                   *   If \f$ \mathbf{v}=0 \f$, then the quaternion is \f$ \mathbf{q} = [1 ~ 0 ~ 0 ~ 0]^\top \f$, otherwise:
00105                   *    \f[ \mathbf{q} = \left[ \begin{array}{c}
00106                   *       \cos(\frac{\theta}{2}) \\
00107                   *       v_x \frac{\sin(\frac{\theta}{2})}{\theta} \\
00108                   *       v_y \frac{\sin(\frac{\theta}{2})}{\theta} \\
00109                   *       v_z \frac{\sin(\frac{\theta}{2})}{\theta}
00110                   *    \end{array} \right] \f]
00111                   *    where \f$ \theta = |\mathbf{v}| = \sqrt{v_x^2+v_y^2+v_z^2} \f$.
00112                   *  \sa "Representing Attitude: Euler Angles, Unit Quaternions, and Rotation Vectors (2006)", James Diebel.
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                 /** @name Lie Algebra methods
00143                     @{ */
00144 
00145 
00146                 /** Logarithm of the 3x3 matrix defined by this pose, generating the corresponding vector in the SO(3) Lie Algebra,
00147                   *  which coincides with the so-called "rotation vector" (I don't have space here for the proof ;-).
00148                   *  \param[out] out_ln The target vector, which can be: std::vector<>, or mrpt::vector_double or any row or column Eigen::Matrix<>.
00149                   *  \sa exp,  mrpt::poses::SE_traits  */
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                 /** \overload that returns by value */
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                 /** Like ln() but does not try to resize the output vector. */
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                 /** Exponential map from the SO(3) Lie Algebra to unit quaternions.
00177                   *  \sa ln,  mrpt::poses::SE_traits  */
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                 /** \overload */
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                 /** @} */  // end of Lie algebra
00193 
00194 
00195                 /**     Calculate the "cross" product (or "composed rotation") of two quaternion: this = q1 x q2
00196                   *   After the operation, "this" will represent the composed rotations of q1 and q2 (q2 applied "after" q1).
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                 /** Rotate a 3D point (lx,ly,lz) -> (gx,gy,gz) as described by this quaternion
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                 /** Rotate a 3D point (lx,ly,lz) -> (gx,gy,gz) as described by the inverse (conjugate) of this quaternion
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                 /** Return the squared norm of the quaternion */
00230                 inline double normSqr() const {
00231                         using mrpt::utils::square;
00232                         return square(r()) + square(x()) + square(y()) + square(z());
00233                 }
00234 
00235                 /**     Normalize this quaternion, so its norm becomes the unitity.
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                 /** Calculate the 4x4 Jacobian of the normalization operation of this quaternion.
00245                   *  The output matrix can be a dynamic or fixed size (4x4) matrix.
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                 /** Compute the Jacobian of the rotation composition operation \f$ p = f(\cdot) = q_{this} \times r \f$, that is the 4x4 matrix \f$ \frac{\partial f}{\partial q_{this} }  \f$.
00275                   *  The output matrix can be a dynamic or fixed size (4x4) matrix.
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                 /** Calculate the 3x3 rotation matrix associated to this quaternion: \f[ \mathbf{R} = \left(
00288                   *    \begin{array}{ccc}
00289                   *     q_r^2+q_x^2-q_y^2-q_z^2         &  2(q_x q_y - q_r q_z) &       2(q_z q_x+q_r q_y) \\
00290                   *     2(q_x q_y+q_r q_z)              & q_r^2-q_x^2+q_y^2-q_z^2       & 2(q_y q_z-q_r q_x) \\
00291                   *     2(q_z q_x-q_r q_y) & 2(q_y q_z+q_r q_x)  & q_r^2- q_x^2 - q_y^2 + q_z^2
00292                   *    \end{array}
00293                   *  \right)\f]
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                 /** Fill out the top-left 3x3 block of the given matrix with the rotation matrix associated to this quaternion (does not resize the matrix, for that, see rotationMatrix). */
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                 /**     Return the conjugate quaternion  */
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                 /**     Return the conjugate quaternion  */
00323                 inline CQuaternion conj() const
00324                 {
00325                         CQuaternion q_aux;
00326                         conj(q_aux);
00327                         return q_aux;
00328                 }
00329 
00330                 /**     Return the yaw, pitch & roll angles associated to quaternion
00331                   *  \sa For the equations, see The MRPT Book, or see http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToEuler/Quaternions.pdf
00332                   *  \sa rpy_and_jacobian
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                 /**     Return the yaw, pitch & roll angles associated to quaternion, and (optionally) the 3x4 Jacobian of the transformation.
00340                   *  Note that both the angles and the Jacobian have one set of normal equations, plus other special formulas for the degenerated cases of |pitch|=90 degrees.
00341                   *  \sa For the equations, see The MRPT Book, or http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToEuler/Quaternions.pdf
00342                   * \sa rpy
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                         {       // pitch = 90 deg
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                         {       // pitch =-90 deg
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                         {       // Non-degenerate case:
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                                         // Auxiliary terms:
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                                         // row 1:
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                                         // row 2:
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                                         // row 3:
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                 };      // end class
00423 
00424                 typedef CQuaternion<double> CQuaternionDouble;  //!< A quaternion of data type "double"
00425                 typedef CQuaternion<float>  CQuaternionFloat;   //!< A quaternion of data type "float"
00426 
00427         }       // end namespace
00428 
00429 } // end namespace mrpt
00430 
00431 #endif



Page generated by Doxygen 1.7.4 for MRPT 0.9.5 SVN:2717 at Sun Oct 16 16:08:03 PDT 2011 Hosted on:
SourceForge.net Logo