1*bf2c3715SXin Linamespace Eigen { 2*bf2c3715SXin Li 3*bf2c3715SXin Li/** \eigenManualPage TutorialGeometry Space transformations 4*bf2c3715SXin Li 5*bf2c3715SXin LiIn this page, we will introduce the many possibilities offered by the \ref Geometry_Module "geometry module" to deal with 2D and 3D rotations and projective or affine transformations. 6*bf2c3715SXin Li 7*bf2c3715SXin Li\eigenAutoToc 8*bf2c3715SXin Li 9*bf2c3715SXin LiEigen's Geometry module provides two different kinds of geometric transformations: 10*bf2c3715SXin Li - Abstract transformations, such as rotations (represented by \ref AngleAxis "angle and axis" or by a \ref Quaternion "quaternion"), \ref Translation "translations", \ref Scaling "scalings". These transformations are NOT represented as matrices, but you can nevertheless mix them with matrices and vectors in expressions, and convert them to matrices if you wish. 11*bf2c3715SXin Li - Projective or affine transformation matrices: see the Transform class. These are really matrices. 12*bf2c3715SXin Li 13*bf2c3715SXin Li\note If you are working with OpenGL 4x4 matrices then Affine3f and Affine3d are what you want. Since Eigen defaults to column-major storage, you can directly use the Transform::data() method to pass your transformation matrix to OpenGL. 14*bf2c3715SXin Li 15*bf2c3715SXin LiYou can construct a Transform from an abstract transformation, like this: 16*bf2c3715SXin Li\code 17*bf2c3715SXin Li Transform t(AngleAxis(angle,axis)); 18*bf2c3715SXin Li\endcode 19*bf2c3715SXin Lior like this: 20*bf2c3715SXin Li\code 21*bf2c3715SXin Li Transform t; 22*bf2c3715SXin Li t = AngleAxis(angle,axis); 23*bf2c3715SXin Li\endcode 24*bf2c3715SXin LiBut note that unfortunately, because of how C++ works, you can \b not do this: 25*bf2c3715SXin Li\code 26*bf2c3715SXin Li Transform t = AngleAxis(angle,axis); 27*bf2c3715SXin Li\endcode 28*bf2c3715SXin Li<span class="note">\b Explanation: In the C++ language, this would require Transform to have a non-explicit conversion constructor from AngleAxis, but we really don't want to allow implicit casting here. 29*bf2c3715SXin Li</span> 30*bf2c3715SXin Li 31*bf2c3715SXin Li\section TutorialGeoElementaryTransformations Transformation types 32*bf2c3715SXin Li 33*bf2c3715SXin Li<table class="manual"> 34*bf2c3715SXin Li<tr><th>Transformation type</th><th>Typical initialization code</th></tr> 35*bf2c3715SXin Li<tr><td> 36*bf2c3715SXin Li\ref Rotation2D "2D rotation" from an angle</td><td>\code 37*bf2c3715SXin LiRotation2D<float> rot2(angle_in_radian);\endcode</td></tr> 38*bf2c3715SXin Li<tr class="alt"><td> 39*bf2c3715SXin Li3D rotation as an \ref AngleAxis "angle + axis"</td><td>\code 40*bf2c3715SXin LiAngleAxis<float> aa(angle_in_radian, Vector3f(ax,ay,az));\endcode 41*bf2c3715SXin Li<span class="note">The axis vector must be normalized.</span></td></tr> 42*bf2c3715SXin Li<tr><td> 43*bf2c3715SXin Li3D rotation as a \ref Quaternion "quaternion"</td><td>\code 44*bf2c3715SXin LiQuaternion<float> q; q = AngleAxis<float>(angle_in_radian, axis);\endcode</td></tr> 45*bf2c3715SXin Li<tr class="alt"><td> 46*bf2c3715SXin LiN-D Scaling</td><td>\code 47*bf2c3715SXin LiScaling(sx, sy) 48*bf2c3715SXin LiScaling(sx, sy, sz) 49*bf2c3715SXin LiScaling(s) 50*bf2c3715SXin LiScaling(vecN)\endcode</td></tr> 51*bf2c3715SXin Li<tr><td> 52*bf2c3715SXin LiN-D Translation</td><td>\code 53*bf2c3715SXin LiTranslation<float,2>(tx, ty) 54*bf2c3715SXin LiTranslation<float,3>(tx, ty, tz) 55*bf2c3715SXin LiTranslation<float,N>(s) 56*bf2c3715SXin LiTranslation<float,N>(vecN)\endcode</td></tr> 57*bf2c3715SXin Li<tr class="alt"><td> 58*bf2c3715SXin LiN-D \ref TutorialGeoTransform "Affine transformation"</td><td>\code 59*bf2c3715SXin LiTransform<float,N,Affine> t = concatenation_of_any_transformations; 60*bf2c3715SXin LiTransform<float,3,Affine> t = Translation3f(p) * AngleAxisf(a,axis) * Scaling(s);\endcode</td></tr> 61*bf2c3715SXin Li<tr><td> 62*bf2c3715SXin LiN-D Linear transformations \n 63*bf2c3715SXin Li<em class=note>(pure rotations, \n scaling, etc.)</em></td><td>\code 64*bf2c3715SXin LiMatrix<float,N> t = concatenation_of_rotations_and_scalings; 65*bf2c3715SXin LiMatrix<float,2> t = Rotation2Df(a) * Scaling(s); 66*bf2c3715SXin LiMatrix<float,3> t = AngleAxisf(a,axis) * Scaling(s);\endcode</td></tr> 67*bf2c3715SXin Li</table> 68*bf2c3715SXin Li 69*bf2c3715SXin Li<strong>Notes on rotations</strong>\n To transform more than a single vector the preferred 70*bf2c3715SXin Lirepresentations are rotation matrices, while for other usages Quaternion is the 71*bf2c3715SXin Lirepresentation of choice as they are compact, fast and stable. Finally Rotation2D and 72*bf2c3715SXin LiAngleAxis are mainly convenient types to create other rotation objects. 73*bf2c3715SXin Li 74*bf2c3715SXin Li<strong>Notes on Translation and Scaling</strong>\n Like AngleAxis, these classes were 75*bf2c3715SXin Lidesigned to simplify the creation/initialization of linear (Matrix) and affine (Transform) 76*bf2c3715SXin Litransformations. Nevertheless, unlike AngleAxis which is inefficient to use, these classes 77*bf2c3715SXin Limight still be interesting to write generic and efficient algorithms taking as input any 78*bf2c3715SXin Likind of transformations. 79*bf2c3715SXin Li 80*bf2c3715SXin LiAny of the above transformation types can be converted to any other types of the same nature, 81*bf2c3715SXin Lior to a more generic type. Here are some additional examples: 82*bf2c3715SXin Li<table class="manual"> 83*bf2c3715SXin Li<tr><td>\code 84*bf2c3715SXin LiRotation2Df r; r = Matrix2f(..); // assumes a pure rotation matrix 85*bf2c3715SXin LiAngleAxisf aa; aa = Quaternionf(..); 86*bf2c3715SXin LiAngleAxisf aa; aa = Matrix3f(..); // assumes a pure rotation matrix 87*bf2c3715SXin LiMatrix2f m; m = Rotation2Df(..); 88*bf2c3715SXin LiMatrix3f m; m = Quaternionf(..); Matrix3f m; m = Scaling(..); 89*bf2c3715SXin LiAffine3f m; m = AngleAxis3f(..); Affine3f m; m = Scaling(..); 90*bf2c3715SXin LiAffine3f m; m = Translation3f(..); Affine3f m; m = Matrix3f(..); 91*bf2c3715SXin Li\endcode</td></tr> 92*bf2c3715SXin Li</table> 93*bf2c3715SXin Li 94*bf2c3715SXin Li 95*bf2c3715SXin Li<a href="#" class="top">top</a>\section TutorialGeoCommontransformationAPI Common API across transformation types 96*bf2c3715SXin Li 97*bf2c3715SXin LiTo some extent, Eigen's \ref Geometry_Module "geometry module" allows you to write 98*bf2c3715SXin Ligeneric algorithms working on any kind of transformation representations: 99*bf2c3715SXin Li<table class="manual"> 100*bf2c3715SXin Li<tr><td> 101*bf2c3715SXin LiConcatenation of two transformations</td><td>\code 102*bf2c3715SXin Ligen1 * gen2;\endcode</td></tr> 103*bf2c3715SXin Li<tr class="alt"><td>Apply the transformation to a vector</td><td>\code 104*bf2c3715SXin Livec2 = gen1 * vec1;\endcode</td></tr> 105*bf2c3715SXin Li<tr><td>Get the inverse of the transformation</td><td>\code 106*bf2c3715SXin Ligen2 = gen1.inverse();\endcode</td></tr> 107*bf2c3715SXin Li<tr class="alt"><td>Spherical interpolation \n (Rotation2D and Quaternion only)</td><td>\code 108*bf2c3715SXin Lirot3 = rot1.slerp(alpha,rot2);\endcode</td></tr> 109*bf2c3715SXin Li</table> 110*bf2c3715SXin Li 111*bf2c3715SXin Li 112*bf2c3715SXin Li 113*bf2c3715SXin Li<a href="#" class="top">top</a>\section TutorialGeoTransform Affine transformations 114*bf2c3715SXin LiGeneric affine transformations are represented by the Transform class which internally 115*bf2c3715SXin Liis a (Dim+1)^2 matrix. In Eigen we have chosen to not distinghish between points and 116*bf2c3715SXin Livectors such that all points are actually represented by displacement vectors from the 117*bf2c3715SXin Liorigin ( \f$ \mathbf{p} \equiv \mathbf{p}-0 \f$ ). With that in mind, real points and 118*bf2c3715SXin Livector distinguish when the transformation is applied. 119*bf2c3715SXin Li<table class="manual"> 120*bf2c3715SXin Li<tr><td> 121*bf2c3715SXin LiApply the transformation to a \b point </td><td>\code 122*bf2c3715SXin LiVectorNf p1, p2; 123*bf2c3715SXin Lip2 = t * p1;\endcode</td></tr> 124*bf2c3715SXin Li<tr class="alt"><td> 125*bf2c3715SXin LiApply the transformation to a \b vector </td><td>\code 126*bf2c3715SXin LiVectorNf vec1, vec2; 127*bf2c3715SXin Livec2 = t.linear() * vec1;\endcode</td></tr> 128*bf2c3715SXin Li<tr><td> 129*bf2c3715SXin LiApply a \em general transformation \n to a \b normal \b vector \n 130*bf2c3715SXin Li</td><td>\code 131*bf2c3715SXin LiVectorNf n1, n2; 132*bf2c3715SXin LiMatrixNf normalMatrix = t.linear().inverse().transpose(); 133*bf2c3715SXin Lin2 = (normalMatrix * n1).normalized();\endcode</td></tr> 134*bf2c3715SXin Li<tr><td colspan="2">(See subject 5.27 of this <a href="http://www.faqs.org/faqs/graphics/algorithms-faq">faq</a> for the explanations)</td></tr> 135*bf2c3715SXin Li<tr class="alt"><td> 136*bf2c3715SXin LiApply a transformation with \em pure \em rotation \n to a \b normal \b vector 137*bf2c3715SXin Li(no scaling, no shear)</td><td>\code 138*bf2c3715SXin Lin2 = t.linear() * n1;\endcode</td></tr> 139*bf2c3715SXin Li<tr><td> 140*bf2c3715SXin LiOpenGL compatibility \b 3D </td><td>\code 141*bf2c3715SXin LiglLoadMatrixf(t.data());\endcode</td></tr> 142*bf2c3715SXin Li<tr class="alt"><td> 143*bf2c3715SXin LiOpenGL compatibility \b 2D </td><td>\code 144*bf2c3715SXin LiAffine3f aux(Affine3f::Identity()); 145*bf2c3715SXin Liaux.linear().topLeftCorner<2,2>() = t.linear(); 146*bf2c3715SXin Liaux.translation().start<2>() = t.translation(); 147*bf2c3715SXin LiglLoadMatrixf(aux.data());\endcode</td></tr> 148*bf2c3715SXin Li</table> 149*bf2c3715SXin Li 150*bf2c3715SXin Li\b Component \b accessors 151*bf2c3715SXin Li<table class="manual"> 152*bf2c3715SXin Li<tr><td> 153*bf2c3715SXin Lifull read-write access to the internal matrix</td><td>\code 154*bf2c3715SXin Lit.matrix() = matN1xN1; // N1 means N+1 155*bf2c3715SXin LimatN1xN1 = t.matrix(); 156*bf2c3715SXin Li\endcode</td></tr> 157*bf2c3715SXin Li<tr class="alt"><td> 158*bf2c3715SXin Licoefficient accessors</td><td>\code 159*bf2c3715SXin Lit(i,j) = scalar; <=> t.matrix()(i,j) = scalar; 160*bf2c3715SXin Liscalar = t(i,j); <=> scalar = t.matrix()(i,j); 161*bf2c3715SXin Li\endcode</td></tr> 162*bf2c3715SXin Li<tr><td> 163*bf2c3715SXin Litranslation part</td><td>\code 164*bf2c3715SXin Lit.translation() = vecN; 165*bf2c3715SXin LivecN = t.translation(); 166*bf2c3715SXin Li\endcode</td></tr> 167*bf2c3715SXin Li<tr class="alt"><td> 168*bf2c3715SXin Lilinear part</td><td>\code 169*bf2c3715SXin Lit.linear() = matNxN; 170*bf2c3715SXin LimatNxN = t.linear(); 171*bf2c3715SXin Li\endcode</td></tr> 172*bf2c3715SXin Li<tr><td> 173*bf2c3715SXin Liextract the rotation matrix</td><td>\code 174*bf2c3715SXin LimatNxN = t.rotation(); 175*bf2c3715SXin Li\endcode</td></tr> 176*bf2c3715SXin Li</table> 177*bf2c3715SXin Li 178*bf2c3715SXin Li 179*bf2c3715SXin Li\b Transformation \b creation \n 180*bf2c3715SXin LiWhile transformation objects can be created and updated concatenating elementary transformations, 181*bf2c3715SXin Lithe Transform class also features a procedural API: 182*bf2c3715SXin Li<table class="manual"> 183*bf2c3715SXin Li<tr><th></th><th>procedural API</th><th>equivalent natural API </th></tr> 184*bf2c3715SXin Li<tr><td>Translation</td><td>\code 185*bf2c3715SXin Lit.translate(Vector_(tx,ty,..)); 186*bf2c3715SXin Lit.pretranslate(Vector_(tx,ty,..)); 187*bf2c3715SXin Li\endcode</td><td>\code 188*bf2c3715SXin Lit *= Translation_(tx,ty,..); 189*bf2c3715SXin Lit = Translation_(tx,ty,..) * t; 190*bf2c3715SXin Li\endcode</td></tr> 191*bf2c3715SXin Li<tr class="alt"><td>\b Rotation \n <em class="note">In 2D and for the procedural API, any_rotation can also \n be an angle in radian</em></td><td>\code 192*bf2c3715SXin Lit.rotate(any_rotation); 193*bf2c3715SXin Lit.prerotate(any_rotation); 194*bf2c3715SXin Li\endcode</td><td>\code 195*bf2c3715SXin Lit *= any_rotation; 196*bf2c3715SXin Lit = any_rotation * t; 197*bf2c3715SXin Li\endcode</td></tr> 198*bf2c3715SXin Li<tr><td>Scaling</td><td>\code 199*bf2c3715SXin Lit.scale(Vector_(sx,sy,..)); 200*bf2c3715SXin Lit.scale(s); 201*bf2c3715SXin Lit.prescale(Vector_(sx,sy,..)); 202*bf2c3715SXin Lit.prescale(s); 203*bf2c3715SXin Li\endcode</td><td>\code 204*bf2c3715SXin Lit *= Scaling(sx,sy,..); 205*bf2c3715SXin Lit *= Scaling(s); 206*bf2c3715SXin Lit = Scaling(sx,sy,..) * t; 207*bf2c3715SXin Lit = Scaling(s) * t; 208*bf2c3715SXin Li\endcode</td></tr> 209*bf2c3715SXin Li<tr class="alt"><td>Shear transformation \n ( \b 2D \b only ! )</td><td>\code 210*bf2c3715SXin Lit.shear(sx,sy); 211*bf2c3715SXin Lit.preshear(sx,sy); 212*bf2c3715SXin Li\endcode</td><td></td></tr> 213*bf2c3715SXin Li</table> 214*bf2c3715SXin Li 215*bf2c3715SXin LiNote that in both API, any many transformations can be concatenated in a single expression as shown in the two following equivalent examples: 216*bf2c3715SXin Li<table class="manual"> 217*bf2c3715SXin Li<tr><td>\code 218*bf2c3715SXin Lit.pretranslate(..).rotate(..).translate(..).scale(..); 219*bf2c3715SXin Li\endcode</td></tr> 220*bf2c3715SXin Li<tr><td>\code 221*bf2c3715SXin Lit = Translation_(..) * t * RotationType(..) * Translation_(..) * Scaling(..); 222*bf2c3715SXin Li\endcode</td></tr> 223*bf2c3715SXin Li</table> 224*bf2c3715SXin Li 225*bf2c3715SXin Li 226*bf2c3715SXin Li 227*bf2c3715SXin Li<a href="#" class="top">top</a>\section TutorialGeoEulerAngles Euler angles 228*bf2c3715SXin Li<table class="manual"> 229*bf2c3715SXin Li<tr><td style="max-width:30em;"> 230*bf2c3715SXin LiEuler angles might be convenient to create rotation objects. 231*bf2c3715SXin LiOn the other hand, since there exist 24 different conventions, they are pretty confusing to use. This example shows how 232*bf2c3715SXin Lito create a rotation matrix according to the 2-1-2 convention.</td><td>\code 233*bf2c3715SXin LiMatrix3f m; 234*bf2c3715SXin Lim = AngleAxisf(angle1, Vector3f::UnitZ()) 235*bf2c3715SXin Li * * AngleAxisf(angle2, Vector3f::UnitY()) 236*bf2c3715SXin Li * * AngleAxisf(angle3, Vector3f::UnitZ()); 237*bf2c3715SXin Li\endcode</td></tr> 238*bf2c3715SXin Li</table> 239*bf2c3715SXin Li 240*bf2c3715SXin Li*/ 241*bf2c3715SXin Li 242*bf2c3715SXin Li} 243