xref: /aosp_15_r20/external/eigen/doc/TutorialGeometry.dox (revision bf2c37156dfe67e5dfebd6d394bad8b2ab5804d4)
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