Gael Guennebaud | 9946297 | 2008-08-31 17:30:09 +0000 | [diff] [blame] | 1 | namespace Eigen { |
| 2 | |
Gael Guennebaud | 41ea92d | 2010-07-04 10:14:47 +0200 | [diff] [blame] | 3 | /** \page TutorialGeometry Tutorial page 8 - Geometry |
Gael Guennebaud | 9946297 | 2008-08-31 17:30:09 +0000 | [diff] [blame] | 4 | \ingroup Tutorial |
| 5 | |
Jitse Niesen | 26cfe5a | 2010-07-09 11:59:29 +0100 | [diff] [blame] | 6 | \li \b Previous: \ref TutorialReductionsVisitorsBroadcasting |
Gael Guennebaud | 41ea92d | 2010-07-04 10:14:47 +0200 | [diff] [blame] | 7 | \li \b Next: \ref TutorialSparse |
Gael Guennebaud | 9946297 | 2008-08-31 17:30:09 +0000 | [diff] [blame] | 8 | |
Tim Holy | 16a2d89 | 2011-06-20 22:47:58 -0500 | [diff] [blame] | 9 | In this tutorial, we will briefly introduce the many possibilities offered by the \ref Geometry_Module "geometry module", namely 2D and 3D rotations and projective or affine transformations. |
Gael Guennebaud | 9946297 | 2008-08-31 17:30:09 +0000 | [diff] [blame] | 10 | |
| 11 | \b Table \b of \b contents |
| 12 | - \ref TutorialGeoElementaryTransformations |
| 13 | - \ref TutorialGeoCommontransformationAPI |
| 14 | - \ref TutorialGeoTransform |
| 15 | - \ref TutorialGeoEulerAngles |
| 16 | |
Benoit Jacob | 789ea9d | 2008-12-22 20:50:47 +0000 | [diff] [blame] | 17 | Eigen's Geometry module provides two different kinds of geometric transformations: |
| 18 | - 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. |
Gael Guennebaud | 41ea92d | 2010-07-04 10:14:47 +0200 | [diff] [blame] | 19 | - Projective or affine transformation matrices: see the Transform class. These are really matrices. |
Benoit Jacob | 789ea9d | 2008-12-22 20:50:47 +0000 | [diff] [blame] | 20 | |
Hauke Heibel | 85fdcdf | 2010-08-17 20:03:50 +0200 | [diff] [blame] | 21 | \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. |
Benoit Jacob | 789ea9d | 2008-12-22 20:50:47 +0000 | [diff] [blame] | 22 | |
| 23 | You can construct a Transform from an abstract transformation, like this: |
| 24 | \code |
| 25 | Transform t(AngleAxis(angle,axis)); |
| 26 | \endcode |
| 27 | or like this: |
| 28 | \code |
| 29 | Transform t; |
| 30 | t = AngleAxis(angle,axis); |
| 31 | \endcode |
| 32 | But note that unfortunately, because of how C++ works, you can \b not do this: |
| 33 | \code |
| 34 | Transform t = AngleAxis(angle,axis); |
| 35 | \endcode |
| 36 | <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. |
| 37 | </span> |
| 38 | |
Gael Guennebaud | 9946297 | 2008-08-31 17:30:09 +0000 | [diff] [blame] | 39 | \section TutorialGeoElementaryTransformations Transformation types |
| 40 | |
Gael Guennebaud | f66fe26 | 2010-10-19 11:40:49 +0200 | [diff] [blame] | 41 | <table class="manual"> |
| 42 | <tr><th>Transformation type</th><th>Typical initialization code</th></tr> |
Gael Guennebaud | 9946297 | 2008-08-31 17:30:09 +0000 | [diff] [blame] | 43 | <tr><td> |
Gael Guennebaud | 6825c8d | 2008-09-01 06:33:19 +0000 | [diff] [blame] | 44 | \ref Rotation2D "2D rotation" from an angle</td><td>\code |
Gael Guennebaud | 9946297 | 2008-08-31 17:30:09 +0000 | [diff] [blame] | 45 | Rotation2D<float> rot2(angle_in_radian);\endcode</td></tr> |
Gael Guennebaud | f66fe26 | 2010-10-19 11:40:49 +0200 | [diff] [blame] | 46 | <tr class="alt"><td> |
Gael Guennebaud | 6825c8d | 2008-09-01 06:33:19 +0000 | [diff] [blame] | 47 | 3D rotation as an \ref AngleAxis "angle + axis"</td><td>\code |
Gael Guennebaud | 5720723 | 2011-11-01 09:40:51 +0100 | [diff] [blame] | 48 | AngleAxis<float> aa(angle_in_radian, Vector3f(ax,ay,az));\endcode |
| 49 | <span class="note">The axis vector must be normalized.</span></td></tr> |
Gael Guennebaud | 9946297 | 2008-08-31 17:30:09 +0000 | [diff] [blame] | 50 | <tr><td> |
Gael Guennebaud | 6825c8d | 2008-09-01 06:33:19 +0000 | [diff] [blame] | 51 | 3D rotation as a \ref Quaternion "quaternion"</td><td>\code |
Gael Guennebaud | 5b71d44 | 2011-05-28 22:12:15 +0200 | [diff] [blame] | 52 | Quaternion<float> q; q = AngleAxis<float>(angle_in_radian, axis);\endcode</td></tr> |
Gael Guennebaud | f66fe26 | 2010-10-19 11:40:49 +0200 | [diff] [blame] | 53 | <tr class="alt"><td> |
Gael Guennebaud | 9946297 | 2008-08-31 17:30:09 +0000 | [diff] [blame] | 54 | N-D Scaling</td><td>\code |
Gael Guennebaud | 1727373 | 2012-06-18 22:07:13 +0200 | [diff] [blame] | 55 | Scaling(sx, sy) |
| 56 | Scaling(sx, sy, sz) |
| 57 | Scaling(s) |
| 58 | Scaling(vecN)\endcode</td></tr> |
Gael Guennebaud | 9946297 | 2008-08-31 17:30:09 +0000 | [diff] [blame] | 59 | <tr><td> |
| 60 | N-D Translation</td><td>\code |
| 61 | Translation<float,2>(tx, ty) |
| 62 | Translation<float,3>(tx, ty, tz) |
| 63 | Translation<float,N>(s) |
| 64 | Translation<float,N>(vecN)\endcode</td></tr> |
Gael Guennebaud | f66fe26 | 2010-10-19 11:40:49 +0200 | [diff] [blame] | 65 | <tr class="alt"><td> |
Gael Guennebaud | 9946297 | 2008-08-31 17:30:09 +0000 | [diff] [blame] | 66 | N-D \ref TutorialGeoTransform "Affine transformation"</td><td>\code |
Gael Guennebaud | b5f3283 | 2010-10-06 13:27:14 +0200 | [diff] [blame] | 67 | Transform<float,N,Affine> t = concatenation_of_any_transformations; |
Gael Guennebaud | 1727373 | 2012-06-18 22:07:13 +0200 | [diff] [blame] | 68 | Transform<float,3,Affine> t = Translation3f(p) * AngleAxisf(a,axis) * Scaling(s);\endcode</td></tr> |
Gael Guennebaud | 9946297 | 2008-08-31 17:30:09 +0000 | [diff] [blame] | 69 | <tr><td> |
| 70 | N-D Linear transformations \n |
| 71 | <em class=note>(pure rotations, \n scaling, etc.)</em></td><td>\code |
| 72 | Matrix<float,N> t = concatenation_of_rotations_and_scalings; |
Gael Guennebaud | 1727373 | 2012-06-18 22:07:13 +0200 | [diff] [blame] | 73 | Matrix<float,2> t = Rotation2Df(a) * Scaling(s); |
| 74 | Matrix<float,3> t = AngleAxisf(a,axis) * Scaling(s);\endcode</td></tr> |
Gael Guennebaud | 9946297 | 2008-08-31 17:30:09 +0000 | [diff] [blame] | 75 | </table> |
| 76 | |
| 77 | <strong>Notes on rotations</strong>\n To transform more than a single vector the preferred |
| 78 | representations are rotation matrices, while for other usages Quaternion is the |
| 79 | representation of choice as they are compact, fast and stable. Finally Rotation2D and |
| 80 | AngleAxis are mainly convenient types to create other rotation objects. |
| 81 | |
Tim Holy | 16a2d89 | 2011-06-20 22:47:58 -0500 | [diff] [blame] | 82 | <strong>Notes on Translation and Scaling</strong>\n Like AngleAxis, these classes were |
Gael Guennebaud | 9946297 | 2008-08-31 17:30:09 +0000 | [diff] [blame] | 83 | designed to simplify the creation/initialization of linear (Matrix) and affine (Transform) |
| 84 | transformations. Nevertheless, unlike AngleAxis which is inefficient to use, these classes |
| 85 | might still be interesting to write generic and efficient algorithms taking as input any |
| 86 | kind of transformations. |
| 87 | |
| 88 | Any of the above transformation types can be converted to any other types of the same nature, |
Gael Guennebaud | 582c1f9 | 2008-11-22 19:51:05 +0000 | [diff] [blame] | 89 | or to a more generic type. Here are some additional examples: |
Gael Guennebaud | f66fe26 | 2010-10-19 11:40:49 +0200 | [diff] [blame] | 90 | <table class="manual"> |
Gael Guennebaud | 9946297 | 2008-08-31 17:30:09 +0000 | [diff] [blame] | 91 | <tr><td>\code |
Gael Guennebaud | 5b71d44 | 2011-05-28 22:12:15 +0200 | [diff] [blame] | 92 | Rotation2Df r; r = Matrix2f(..); // assumes a pure rotation matrix |
| 93 | AngleAxisf aa; aa = Quaternionf(..); |
| 94 | AngleAxisf aa; aa = Matrix3f(..); // assumes a pure rotation matrix |
| 95 | Matrix2f m; m = Rotation2Df(..); |
Gael Guennebaud | 1727373 | 2012-06-18 22:07:13 +0200 | [diff] [blame] | 96 | Matrix3f m; m = Quaternionf(..); Matrix3f m; m = Scaling(..); |
| 97 | Affine3f m; m = AngleAxis3f(..); Affine3f m; m = Scaling(..); |
Gael Guennebaud | 5b71d44 | 2011-05-28 22:12:15 +0200 | [diff] [blame] | 98 | Affine3f m; m = Translation3f(..); Affine3f m; m = Matrix3f(..); |
Gael Guennebaud | 9946297 | 2008-08-31 17:30:09 +0000 | [diff] [blame] | 99 | \endcode</td></tr> |
| 100 | </table> |
| 101 | |
| 102 | |
| 103 | <a href="#" class="top">top</a>\section TutorialGeoCommontransformationAPI Common API across transformation types |
| 104 | |
Gael Guennebaud | a4487ef | 2009-02-05 21:19:40 +0000 | [diff] [blame] | 105 | To some extent, Eigen's \ref Geometry_Module "geometry module" allows you to write |
Gael Guennebaud | 9946297 | 2008-08-31 17:30:09 +0000 | [diff] [blame] | 106 | generic algorithms working on any kind of transformation representations: |
Gael Guennebaud | f66fe26 | 2010-10-19 11:40:49 +0200 | [diff] [blame] | 107 | <table class="manual"> |
Gael Guennebaud | 9946297 | 2008-08-31 17:30:09 +0000 | [diff] [blame] | 108 | <tr><td> |
| 109 | Concatenation of two transformations</td><td>\code |
| 110 | gen1 * gen2;\endcode</td></tr> |
Gael Guennebaud | f66fe26 | 2010-10-19 11:40:49 +0200 | [diff] [blame] | 111 | <tr class="alt"><td>Apply the transformation to a vector</td><td>\code |
Gael Guennebaud | 9946297 | 2008-08-31 17:30:09 +0000 | [diff] [blame] | 112 | vec2 = gen1 * vec1;\endcode</td></tr> |
| 113 | <tr><td>Get the inverse of the transformation</td><td>\code |
| 114 | gen2 = gen1.inverse();\endcode</td></tr> |
Gael Guennebaud | f66fe26 | 2010-10-19 11:40:49 +0200 | [diff] [blame] | 115 | <tr class="alt"><td>Spherical interpolation \n (Rotation2D and Quaternion only)</td><td>\code |
Gael Guennebaud | 9946297 | 2008-08-31 17:30:09 +0000 | [diff] [blame] | 116 | rot3 = rot1.slerp(alpha,rot2);\endcode</td></tr> |
| 117 | </table> |
| 118 | |
| 119 | |
| 120 | |
| 121 | <a href="#" class="top">top</a>\section TutorialGeoTransform Affine transformations |
| 122 | Generic affine transformations are represented by the Transform class which internaly |
| 123 | is a (Dim+1)^2 matrix. In Eigen we have chosen to not distinghish between points and |
| 124 | vectors such that all points are actually represented by displacement vectors from the |
| 125 | origin ( \f$ \mathbf{p} \equiv \mathbf{p}-0 \f$ ). With that in mind, real points and |
| 126 | vector distinguish when the transformation is applied. |
Gael Guennebaud | f66fe26 | 2010-10-19 11:40:49 +0200 | [diff] [blame] | 127 | <table class="manual"> |
Gael Guennebaud | 9946297 | 2008-08-31 17:30:09 +0000 | [diff] [blame] | 128 | <tr><td> |
| 129 | Apply the transformation to a \b point </td><td>\code |
| 130 | VectorNf p1, p2; |
| 131 | p2 = t * p1;\endcode</td></tr> |
Gael Guennebaud | f66fe26 | 2010-10-19 11:40:49 +0200 | [diff] [blame] | 132 | <tr class="alt"><td> |
Gael Guennebaud | 9946297 | 2008-08-31 17:30:09 +0000 | [diff] [blame] | 133 | Apply the transformation to a \b vector </td><td>\code |
| 134 | VectorNf vec1, vec2; |
| 135 | vec2 = t.linear() * vec1;\endcode</td></tr> |
| 136 | <tr><td> |
| 137 | Apply a \em general transformation \n to a \b normal \b vector |
| 138 | (<a href="http://www.cgafaq.info/wiki/Transforming_normals">explanations</a>)</td><td>\code |
| 139 | VectorNf n1, n2; |
| 140 | MatrixNf normalMatrix = t.linear().inverse().transpose(); |
| 141 | n2 = (normalMatrix * n1).normalized();\endcode</td></tr> |
Gael Guennebaud | f66fe26 | 2010-10-19 11:40:49 +0200 | [diff] [blame] | 142 | <tr class="alt"><td> |
Gael Guennebaud | 9946297 | 2008-08-31 17:30:09 +0000 | [diff] [blame] | 143 | Apply a transformation with \em pure \em rotation \n to a \b normal \b vector |
| 144 | (no scaling, no shear)</td><td>\code |
| 145 | n2 = t.linear() * n1;\endcode</td></tr> |
| 146 | <tr><td> |
| 147 | OpenGL compatibility \b 3D </td><td>\code |
| 148 | glLoadMatrixf(t.data());\endcode</td></tr> |
Gael Guennebaud | f66fe26 | 2010-10-19 11:40:49 +0200 | [diff] [blame] | 149 | <tr class="alt"><td> |
Gael Guennebaud | 9946297 | 2008-08-31 17:30:09 +0000 | [diff] [blame] | 150 | OpenGL compatibility \b 2D </td><td>\code |
Jitse Niesen | e0a6ce5 | 2011-09-19 21:57:26 +0100 | [diff] [blame] | 151 | Affine3f aux(Affine3f::Identity()); |
Benoit Jacob | 9962c59 | 2010-04-22 14:11:18 -0400 | [diff] [blame] | 152 | aux.linear().topLeftCorner<2,2>() = t.linear(); |
Gael Guennebaud | 9946297 | 2008-08-31 17:30:09 +0000 | [diff] [blame] | 153 | aux.translation().start<2>() = t.translation(); |
| 154 | glLoadMatrixf(aux.data());\endcode</td></tr> |
| 155 | </table> |
| 156 | |
Gael Guennebaud | f66fe26 | 2010-10-19 11:40:49 +0200 | [diff] [blame] | 157 | \b Component \b accessors |
| 158 | <table class="manual"> |
Gael Guennebaud | 9946297 | 2008-08-31 17:30:09 +0000 | [diff] [blame] | 159 | <tr><td> |
| 160 | full read-write access to the internal matrix</td><td>\code |
| 161 | t.matrix() = matN1xN1; // N1 means N+1 |
| 162 | matN1xN1 = t.matrix(); |
| 163 | \endcode</td></tr> |
Gael Guennebaud | f66fe26 | 2010-10-19 11:40:49 +0200 | [diff] [blame] | 164 | <tr class="alt"><td> |
Gael Guennebaud | 9946297 | 2008-08-31 17:30:09 +0000 | [diff] [blame] | 165 | coefficient accessors</td><td>\code |
| 166 | t(i,j) = scalar; <=> t.matrix()(i,j) = scalar; |
| 167 | scalar = t(i,j); <=> scalar = t.matrix()(i,j); |
| 168 | \endcode</td></tr> |
| 169 | <tr><td> |
| 170 | translation part</td><td>\code |
| 171 | t.translation() = vecN; |
| 172 | vecN = t.translation(); |
| 173 | \endcode</td></tr> |
Gael Guennebaud | f66fe26 | 2010-10-19 11:40:49 +0200 | [diff] [blame] | 174 | <tr class="alt"><td> |
Gael Guennebaud | 9946297 | 2008-08-31 17:30:09 +0000 | [diff] [blame] | 175 | linear part</td><td>\code |
| 176 | t.linear() = matNxN; |
| 177 | matNxN = t.linear(); |
| 178 | \endcode</td></tr> |
| 179 | <tr><td> |
| 180 | extract the rotation matrix</td><td>\code |
| 181 | matNxN = t.extractRotation(); |
| 182 | \endcode</td></tr> |
| 183 | </table> |
| 184 | |
| 185 | |
| 186 | \b Transformation \b creation \n |
| 187 | While transformation objects can be created and updated concatenating elementary transformations, |
| 188 | the Transform class also features a procedural API: |
Gael Guennebaud | f66fe26 | 2010-10-19 11:40:49 +0200 | [diff] [blame] | 189 | <table class="manual"> |
Tim Holy | 16a2d89 | 2011-06-20 22:47:58 -0500 | [diff] [blame] | 190 | <tr><th></th><th>procedural API</th><th>equivalent natural API </th></tr> |
Gael Guennebaud | 9946297 | 2008-08-31 17:30:09 +0000 | [diff] [blame] | 191 | <tr><td>Translation</td><td>\code |
| 192 | t.translate(Vector_(tx,ty,..)); |
| 193 | t.pretranslate(Vector_(tx,ty,..)); |
| 194 | \endcode</td><td>\code |
| 195 | t *= Translation_(tx,ty,..); |
| 196 | t = Translation_(tx,ty,..) * t; |
| 197 | \endcode</td></tr> |
Gael Guennebaud | f66fe26 | 2010-10-19 11:40:49 +0200 | [diff] [blame] | 198 | <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 |
Gael Guennebaud | 9946297 | 2008-08-31 17:30:09 +0000 | [diff] [blame] | 199 | t.rotate(any_rotation); |
| 200 | t.prerotate(any_rotation); |
| 201 | \endcode</td><td>\code |
| 202 | t *= any_rotation; |
| 203 | t = any_rotation * t; |
| 204 | \endcode</td></tr> |
| 205 | <tr><td>Scaling</td><td>\code |
| 206 | t.scale(Vector_(sx,sy,..)); |
| 207 | t.scale(s); |
| 208 | t.prescale(Vector_(sx,sy,..)); |
| 209 | t.prescale(s); |
| 210 | \endcode</td><td>\code |
Gael Guennebaud | 1727373 | 2012-06-18 22:07:13 +0200 | [diff] [blame] | 211 | t *= Scaling(sx,sy,..); |
| 212 | t *= Scaling(s); |
| 213 | t = Scaling(sx,sy,..) * t; |
| 214 | t = Scaling(s) * t; |
Gael Guennebaud | 9946297 | 2008-08-31 17:30:09 +0000 | [diff] [blame] | 215 | \endcode</td></tr> |
Gael Guennebaud | f66fe26 | 2010-10-19 11:40:49 +0200 | [diff] [blame] | 216 | <tr class="alt"><td>Shear transformation \n ( \b 2D \b only ! )</td><td>\code |
Gael Guennebaud | 9946297 | 2008-08-31 17:30:09 +0000 | [diff] [blame] | 217 | t.shear(sx,sy); |
| 218 | t.preshear(sx,sy); |
| 219 | \endcode</td><td></td></tr> |
| 220 | </table> |
| 221 | |
| 222 | Note that in both API, any many transformations can be concatenated in a single expression as shown in the two following equivalent examples: |
Gael Guennebaud | f66fe26 | 2010-10-19 11:40:49 +0200 | [diff] [blame] | 223 | <table class="manual"> |
Gael Guennebaud | 9946297 | 2008-08-31 17:30:09 +0000 | [diff] [blame] | 224 | <tr><td>\code |
| 225 | t.pretranslate(..).rotate(..).translate(..).scale(..); |
| 226 | \endcode</td></tr> |
| 227 | <tr><td>\code |
Gael Guennebaud | 1727373 | 2012-06-18 22:07:13 +0200 | [diff] [blame] | 228 | t = Translation_(..) * t * RotationType(..) * Translation_(..) * Scaling(..); |
Gael Guennebaud | 9946297 | 2008-08-31 17:30:09 +0000 | [diff] [blame] | 229 | \endcode</td></tr> |
| 230 | </table> |
| 231 | |
| 232 | |
| 233 | |
| 234 | <a href="#" class="top">top</a>\section TutorialGeoEulerAngles Euler angles |
Gael Guennebaud | f66fe26 | 2010-10-19 11:40:49 +0200 | [diff] [blame] | 235 | <table class="manual"> |
Gael Guennebaud | 9946297 | 2008-08-31 17:30:09 +0000 | [diff] [blame] | 236 | <tr><td style="max-width:30em;"> |
| 237 | Euler angles might be convenient to create rotation objects. |
Tim Holy | 16a2d89 | 2011-06-20 22:47:58 -0500 | [diff] [blame] | 238 | On the other hand, since there exist 24 different conventions, they are pretty confusing to use. This example shows how |
Gael Guennebaud | 9946297 | 2008-08-31 17:30:09 +0000 | [diff] [blame] | 239 | to create a rotation matrix according to the 2-1-2 convention.</td><td>\code |
| 240 | Matrix3f m; |
| 241 | m = AngleAxisf(angle1, Vector3f::UnitZ()) |
| 242 | * * AngleAxisf(angle2, Vector3f::UnitY()) |
| 243 | * * AngleAxisf(angle3, Vector3f::UnitZ()); |
| 244 | \endcode</td></tr> |
| 245 | </table> |
| 246 | |
Gael Guennebaud | 41ea92d | 2010-07-04 10:14:47 +0200 | [diff] [blame] | 247 | \li \b Next: \ref TutorialSparse |
| 248 | |
Gael Guennebaud | 9946297 | 2008-08-31 17:30:09 +0000 | [diff] [blame] | 249 | */ |
| 250 | |
| 251 | } |