1 | // This file is part of Eigen, a lightweight C++ template library |
2 | // for linear algebra. |
3 | // |
4 | // Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr> |
5 | // Copyright (C) 2009 Benoit Jacob <jacob.benoit.1@gmail.com> |
6 | // Copyright (C) 2010 Hauke Heibel <hauke.heibel@gmail.com> |
7 | // |
8 | // This Source Code Form is subject to the terms of the Mozilla |
9 | // Public License v. 2.0. If a copy of the MPL was not distributed |
10 | // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. |
11 | |
12 | #ifndef EIGEN_TRANSFORM_H |
13 | #define EIGEN_TRANSFORM_H |
14 | |
15 | namespace Eigen { |
16 | |
17 | namespace internal { |
18 | |
19 | template<typename Transform> |
20 | struct transform_traits |
21 | { |
22 | enum |
23 | { |
24 | Dim = Transform::Dim, |
25 | HDim = Transform::HDim, |
26 | Mode = Transform::Mode, |
27 | IsProjective = (int(Mode)==int(Projective)) |
28 | }; |
29 | }; |
30 | |
31 | template< typename TransformType, |
32 | typename MatrixType, |
33 | int Case = transform_traits<TransformType>::IsProjective ? 0 |
34 | : int(MatrixType::RowsAtCompileTime) == int(transform_traits<TransformType>::HDim) ? 1 |
35 | : 2, |
36 | int RhsCols = MatrixType::ColsAtCompileTime> |
37 | struct transform_right_product_impl; |
38 | |
39 | template< typename Other, |
40 | int Mode, |
41 | int Options, |
42 | int Dim, |
43 | int HDim, |
44 | int OtherRows=Other::RowsAtCompileTime, |
45 | int OtherCols=Other::ColsAtCompileTime> |
46 | struct transform_left_product_impl; |
47 | |
48 | template< typename Lhs, |
49 | typename Rhs, |
50 | bool AnyProjective = |
51 | transform_traits<Lhs>::IsProjective || |
52 | transform_traits<Rhs>::IsProjective> |
53 | struct transform_transform_product_impl; |
54 | |
55 | template< typename Other, |
56 | int Mode, |
57 | int Options, |
58 | int Dim, |
59 | int HDim, |
60 | int OtherRows=Other::RowsAtCompileTime, |
61 | int OtherCols=Other::ColsAtCompileTime> |
62 | struct transform_construct_from_matrix; |
63 | |
64 | template<typename TransformType> struct transform_take_affine_part; |
65 | |
66 | template<typename _Scalar, int _Dim, int _Mode, int _Options> |
67 | struct traits<Transform<_Scalar,_Dim,_Mode,_Options> > |
68 | { |
69 | typedef _Scalar Scalar; |
70 | typedef Eigen::Index StorageIndex; |
71 | typedef Dense StorageKind; |
72 | enum { |
73 | Dim1 = _Dim==Dynamic ? _Dim : _Dim + 1, |
74 | RowsAtCompileTime = _Mode==Projective ? Dim1 : _Dim, |
75 | ColsAtCompileTime = Dim1, |
76 | MaxRowsAtCompileTime = RowsAtCompileTime, |
77 | MaxColsAtCompileTime = ColsAtCompileTime, |
78 | Flags = 0 |
79 | }; |
80 | }; |
81 | |
82 | template<int Mode> struct transform_make_affine; |
83 | |
84 | } // end namespace internal |
85 | |
86 | /** \geometry_module \ingroup Geometry_Module |
87 | * |
88 | * \class Transform |
89 | * |
90 | * \brief Represents an homogeneous transformation in a N dimensional space |
91 | * |
92 | * \tparam _Scalar the scalar type, i.e., the type of the coefficients |
93 | * \tparam _Dim the dimension of the space |
94 | * \tparam _Mode the type of the transformation. Can be: |
95 | * - #Affine: the transformation is stored as a (Dim+1)^2 matrix, |
96 | * where the last row is assumed to be [0 ... 0 1]. |
97 | * - #AffineCompact: the transformation is stored as a (Dim)x(Dim+1) matrix. |
98 | * - #Projective: the transformation is stored as a (Dim+1)^2 matrix |
99 | * without any assumption. |
100 | * \tparam _Options has the same meaning as in class Matrix. It allows to specify DontAlign and/or RowMajor. |
101 | * These Options are passed directly to the underlying matrix type. |
102 | * |
103 | * The homography is internally represented and stored by a matrix which |
104 | * is available through the matrix() method. To understand the behavior of |
105 | * this class you have to think a Transform object as its internal |
106 | * matrix representation. The chosen convention is right multiply: |
107 | * |
108 | * \code v' = T * v \endcode |
109 | * |
110 | * Therefore, an affine transformation matrix M is shaped like this: |
111 | * |
112 | * \f$ \left( \begin{array}{cc} |
113 | * linear & translation\\ |
114 | * 0 ... 0 & 1 |
115 | * \end{array} \right) \f$ |
116 | * |
117 | * Note that for a projective transformation the last row can be anything, |
118 | * and then the interpretation of different parts might be sightly different. |
119 | * |
120 | * However, unlike a plain matrix, the Transform class provides many features |
121 | * simplifying both its assembly and usage. In particular, it can be composed |
122 | * with any other transformations (Transform,Translation,RotationBase,DiagonalMatrix) |
123 | * and can be directly used to transform implicit homogeneous vectors. All these |
124 | * operations are handled via the operator*. For the composition of transformations, |
125 | * its principle consists to first convert the right/left hand sides of the product |
126 | * to a compatible (Dim+1)^2 matrix and then perform a pure matrix product. |
127 | * Of course, internally, operator* tries to perform the minimal number of operations |
128 | * according to the nature of each terms. Likewise, when applying the transform |
129 | * to points, the latters are automatically promoted to homogeneous vectors |
130 | * before doing the matrix product. The conventions to homogeneous representations |
131 | * are performed as follow: |
132 | * |
133 | * \b Translation t (Dim)x(1): |
134 | * \f$ \left( \begin{array}{cc} |
135 | * I & t \\ |
136 | * 0\,...\,0 & 1 |
137 | * \end{array} \right) \f$ |
138 | * |
139 | * \b Rotation R (Dim)x(Dim): |
140 | * \f$ \left( \begin{array}{cc} |
141 | * R & 0\\ |
142 | * 0\,...\,0 & 1 |
143 | * \end{array} \right) \f$ |
144 | *<!-- |
145 | * \b Linear \b Matrix L (Dim)x(Dim): |
146 | * \f$ \left( \begin{array}{cc} |
147 | * L & 0\\ |
148 | * 0\,...\,0 & 1 |
149 | * \end{array} \right) \f$ |
150 | * |
151 | * \b Affine \b Matrix A (Dim)x(Dim+1): |
152 | * \f$ \left( \begin{array}{c} |
153 | * A\\ |
154 | * 0\,...\,0\,1 |
155 | * \end{array} \right) \f$ |
156 | *--> |
157 | * \b Scaling \b DiagonalMatrix S (Dim)x(Dim): |
158 | * \f$ \left( \begin{array}{cc} |
159 | * S & 0\\ |
160 | * 0\,...\,0 & 1 |
161 | * \end{array} \right) \f$ |
162 | * |
163 | * \b Column \b point v (Dim)x(1): |
164 | * \f$ \left( \begin{array}{c} |
165 | * v\\ |
166 | * 1 |
167 | * \end{array} \right) \f$ |
168 | * |
169 | * \b Set \b of \b column \b points V1...Vn (Dim)x(n): |
170 | * \f$ \left( \begin{array}{ccc} |
171 | * v_1 & ... & v_n\\ |
172 | * 1 & ... & 1 |
173 | * \end{array} \right) \f$ |
174 | * |
175 | * The concatenation of a Transform object with any kind of other transformation |
176 | * always returns a Transform object. |
177 | * |
178 | * A little exception to the "as pure matrix product" rule is the case of the |
179 | * transformation of non homogeneous vectors by an affine transformation. In |
180 | * that case the last matrix row can be ignored, and the product returns non |
181 | * homogeneous vectors. |
182 | * |
183 | * Since, for instance, a Dim x Dim matrix is interpreted as a linear transformation, |
184 | * it is not possible to directly transform Dim vectors stored in a Dim x Dim matrix. |
185 | * The solution is either to use a Dim x Dynamic matrix or explicitly request a |
186 | * vector transformation by making the vector homogeneous: |
187 | * \code |
188 | * m' = T * m.colwise().homogeneous(); |
189 | * \endcode |
190 | * Note that there is zero overhead. |
191 | * |
192 | * Conversion methods from/to Qt's QMatrix and QTransform are available if the |
193 | * preprocessor token EIGEN_QT_SUPPORT is defined. |
194 | * |
195 | * This class can be extended with the help of the plugin mechanism described on the page |
196 | * \ref TopicCustomizing_Plugins by defining the preprocessor symbol \c EIGEN_TRANSFORM_PLUGIN. |
197 | * |
198 | * \sa class Matrix, class Quaternion |
199 | */ |
200 | template<typename _Scalar, int _Dim, int _Mode, int _Options> |
201 | class Transform |
202 | { |
203 | public: |
204 | EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(_Scalar,_Dim==Dynamic ? Dynamic : (_Dim+1)*(_Dim+1)) |
205 | enum { |
206 | Mode = _Mode, |
207 | Options = _Options, |
208 | Dim = _Dim, ///< space dimension in which the transformation holds |
209 | HDim = _Dim+1, ///< size of a respective homogeneous vector |
210 | Rows = int(Mode)==(AffineCompact) ? Dim : HDim |
211 | }; |
212 | /** the scalar type of the coefficients */ |
213 | typedef _Scalar Scalar; |
214 | typedef Eigen::Index StorageIndex; |
215 | typedef Eigen::Index Index; ///< \deprecated since Eigen 3.3 |
216 | /** type of the matrix used to represent the transformation */ |
217 | typedef typename internal::make_proper_matrix_type<Scalar,Rows,HDim,Options>::type MatrixType; |
218 | /** constified MatrixType */ |
219 | typedef const MatrixType ConstMatrixType; |
220 | /** type of the matrix used to represent the linear part of the transformation */ |
221 | typedef Matrix<Scalar,Dim,Dim,Options> LinearMatrixType; |
222 | /** type of read/write reference to the linear part of the transformation */ |
223 | typedef Block<MatrixType,Dim,Dim,int(Mode)==(AffineCompact) && (Options&RowMajor)==0> LinearPart; |
224 | /** type of read reference to the linear part of the transformation */ |
225 | typedef const Block<ConstMatrixType,Dim,Dim,int(Mode)==(AffineCompact) && (Options&RowMajor)==0> ConstLinearPart; |
226 | /** type of read/write reference to the affine part of the transformation */ |
227 | typedef typename internal::conditional<int(Mode)==int(AffineCompact), |
228 | MatrixType&, |
229 | Block<MatrixType,Dim,HDim> >::type AffinePart; |
230 | /** type of read reference to the affine part of the transformation */ |
231 | typedef typename internal::conditional<int(Mode)==int(AffineCompact), |
232 | const MatrixType&, |
233 | const Block<const MatrixType,Dim,HDim> >::type ConstAffinePart; |
234 | /** type of a vector */ |
235 | typedef Matrix<Scalar,Dim,1> VectorType; |
236 | /** type of a read/write reference to the translation part of the rotation */ |
237 | typedef Block<MatrixType,Dim,1,!(internal::traits<MatrixType>::Flags & RowMajorBit)> TranslationPart; |
238 | /** type of a read reference to the translation part of the rotation */ |
239 | typedef const Block<ConstMatrixType,Dim,1,!(internal::traits<MatrixType>::Flags & RowMajorBit)> ConstTranslationPart; |
240 | /** corresponding translation type */ |
241 | typedef Translation<Scalar,Dim> TranslationType; |
242 | |
243 | // this intermediate enum is needed to avoid an ICE with gcc 3.4 and 4.0 |
244 | enum { TransformTimeDiagonalMode = ((Mode==int(Isometry))?Affine:int(Mode)) }; |
245 | /** The return type of the product between a diagonal matrix and a transform */ |
246 | typedef Transform<Scalar,Dim,TransformTimeDiagonalMode> TransformTimeDiagonalReturnType; |
247 | |
248 | protected: |
249 | |
250 | MatrixType m_matrix; |
251 | |
252 | public: |
253 | |
254 | /** Default constructor without initialization of the meaningful coefficients. |
255 | * If Mode==Affine, then the last row is set to [0 ... 0 1] */ |
256 | EIGEN_DEVICE_FUNC inline Transform() |
257 | { |
258 | check_template_params(); |
259 | internal::transform_make_affine<(int(Mode)==Affine) ? Affine : AffineCompact>::run(m_matrix); |
260 | } |
261 | |
262 | EIGEN_DEVICE_FUNC inline Transform(const Transform& other) |
263 | { |
264 | check_template_params(); |
265 | m_matrix = other.m_matrix; |
266 | } |
267 | |
268 | EIGEN_DEVICE_FUNC inline explicit Transform(const TranslationType& t) |
269 | { |
270 | check_template_params(); |
271 | *this = t; |
272 | } |
273 | EIGEN_DEVICE_FUNC inline explicit Transform(const UniformScaling<Scalar>& s) |
274 | { |
275 | check_template_params(); |
276 | *this = s; |
277 | } |
278 | template<typename Derived> |
279 | EIGEN_DEVICE_FUNC inline explicit Transform(const RotationBase<Derived, Dim>& r) |
280 | { |
281 | check_template_params(); |
282 | *this = r; |
283 | } |
284 | |
285 | EIGEN_DEVICE_FUNC inline Transform& operator=(const Transform& other) |
286 | { m_matrix = other.m_matrix; return *this; } |
287 | |
288 | typedef internal::transform_take_affine_part<Transform> take_affine_part; |
289 | |
290 | /** Constructs and initializes a transformation from a Dim^2 or a (Dim+1)^2 matrix. */ |
291 | template<typename OtherDerived> |
292 | EIGEN_DEVICE_FUNC inline explicit Transform(const EigenBase<OtherDerived>& other) |
293 | { |
294 | EIGEN_STATIC_ASSERT((internal::is_same<Scalar,typename OtherDerived::Scalar>::value), |
295 | YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY); |
296 | |
297 | check_template_params(); |
298 | internal::transform_construct_from_matrix<OtherDerived,Mode,Options,Dim,HDim>::run(this, other.derived()); |
299 | } |
300 | |
301 | /** Set \c *this from a Dim^2 or (Dim+1)^2 matrix. */ |
302 | template<typename OtherDerived> |
303 | EIGEN_DEVICE_FUNC inline Transform& operator=(const EigenBase<OtherDerived>& other) |
304 | { |
305 | EIGEN_STATIC_ASSERT((internal::is_same<Scalar,typename OtherDerived::Scalar>::value), |
306 | YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY); |
307 | |
308 | internal::transform_construct_from_matrix<OtherDerived,Mode,Options,Dim,HDim>::run(this, other.derived()); |
309 | return *this; |
310 | } |
311 | |
312 | template<int OtherOptions> |
313 | EIGEN_DEVICE_FUNC inline Transform(const Transform<Scalar,Dim,Mode,OtherOptions>& other) |
314 | { |
315 | check_template_params(); |
316 | // only the options change, we can directly copy the matrices |
317 | m_matrix = other.matrix(); |
318 | } |
319 | |
320 | template<int OtherMode,int OtherOptions> |
321 | EIGEN_DEVICE_FUNC inline Transform(const Transform<Scalar,Dim,OtherMode,OtherOptions>& other) |
322 | { |
323 | check_template_params(); |
324 | // prevent conversions as: |
325 | // Affine | AffineCompact | Isometry = Projective |
326 | EIGEN_STATIC_ASSERT(EIGEN_IMPLIES(OtherMode==int(Projective), Mode==int(Projective)), |
327 | YOU_PERFORMED_AN_INVALID_TRANSFORMATION_CONVERSION) |
328 | |
329 | // prevent conversions as: |
330 | // Isometry = Affine | AffineCompact |
331 | EIGEN_STATIC_ASSERT(EIGEN_IMPLIES(OtherMode==int(Affine)||OtherMode==int(AffineCompact), Mode!=int(Isometry)), |
332 | YOU_PERFORMED_AN_INVALID_TRANSFORMATION_CONVERSION) |
333 | |
334 | enum { ModeIsAffineCompact = Mode == int(AffineCompact), |
335 | OtherModeIsAffineCompact = OtherMode == int(AffineCompact) |
336 | }; |
337 | |
338 | if(ModeIsAffineCompact == OtherModeIsAffineCompact) |
339 | { |
340 | // We need the block expression because the code is compiled for all |
341 | // combinations of transformations and will trigger a compile time error |
342 | // if one tries to assign the matrices directly |
343 | m_matrix.template block<Dim,Dim+1>(0,0) = other.matrix().template block<Dim,Dim+1>(0,0); |
344 | makeAffine(); |
345 | } |
346 | else if(OtherModeIsAffineCompact) |
347 | { |
348 | typedef typename Transform<Scalar,Dim,OtherMode,OtherOptions>::MatrixType OtherMatrixType; |
349 | internal::transform_construct_from_matrix<OtherMatrixType,Mode,Options,Dim,HDim>::run(this, other.matrix()); |
350 | } |
351 | else |
352 | { |
353 | // here we know that Mode == AffineCompact and OtherMode != AffineCompact. |
354 | // if OtherMode were Projective, the static assert above would already have caught it. |
355 | // So the only possibility is that OtherMode == Affine |
356 | linear() = other.linear(); |
357 | translation() = other.translation(); |
358 | } |
359 | } |
360 | |
361 | template<typename OtherDerived> |
362 | EIGEN_DEVICE_FUNC Transform(const ReturnByValue<OtherDerived>& other) |
363 | { |
364 | check_template_params(); |
365 | other.evalTo(*this); |
366 | } |
367 | |
368 | template<typename OtherDerived> |
369 | EIGEN_DEVICE_FUNC Transform& operator=(const ReturnByValue<OtherDerived>& other) |
370 | { |
371 | other.evalTo(*this); |
372 | return *this; |
373 | } |
374 | |
375 | #ifdef EIGEN_QT_SUPPORT |
376 | inline Transform(const QMatrix& other); |
377 | inline Transform& operator=(const QMatrix& other); |
378 | inline QMatrix toQMatrix(void) const; |
379 | inline Transform(const QTransform& other); |
380 | inline Transform& operator=(const QTransform& other); |
381 | inline QTransform toQTransform(void) const; |
382 | #endif |
383 | |
384 | EIGEN_DEVICE_FUNC Index rows() const { return int(Mode)==int(Projective) ? m_matrix.cols() : (m_matrix.cols()-1); } |
385 | EIGEN_DEVICE_FUNC Index cols() const { return m_matrix.cols(); } |
386 | |
387 | /** shortcut for m_matrix(row,col); |
388 | * \sa MatrixBase::operator(Index,Index) const */ |
389 | EIGEN_DEVICE_FUNC inline Scalar operator() (Index row, Index col) const { return m_matrix(row,col); } |
390 | /** shortcut for m_matrix(row,col); |
391 | * \sa MatrixBase::operator(Index,Index) */ |
392 | EIGEN_DEVICE_FUNC inline Scalar& operator() (Index row, Index col) { return m_matrix(row,col); } |
393 | |
394 | /** \returns a read-only expression of the transformation matrix */ |
395 | EIGEN_DEVICE_FUNC inline const MatrixType& matrix() const { return m_matrix; } |
396 | /** \returns a writable expression of the transformation matrix */ |
397 | EIGEN_DEVICE_FUNC inline MatrixType& matrix() { return m_matrix; } |
398 | |
399 | /** \returns a read-only expression of the linear part of the transformation */ |
400 | EIGEN_DEVICE_FUNC inline ConstLinearPart linear() const { return ConstLinearPart(m_matrix,0,0); } |
401 | /** \returns a writable expression of the linear part of the transformation */ |
402 | EIGEN_DEVICE_FUNC inline LinearPart linear() { return LinearPart(m_matrix,0,0); } |
403 | |
404 | /** \returns a read-only expression of the Dim x HDim affine part of the transformation */ |
405 | EIGEN_DEVICE_FUNC inline ConstAffinePart affine() const { return take_affine_part::run(m_matrix); } |
406 | /** \returns a writable expression of the Dim x HDim affine part of the transformation */ |
407 | EIGEN_DEVICE_FUNC inline AffinePart affine() { return take_affine_part::run(m_matrix); } |
408 | |
409 | /** \returns a read-only expression of the translation vector of the transformation */ |
410 | EIGEN_DEVICE_FUNC inline ConstTranslationPart translation() const { return ConstTranslationPart(m_matrix,0,Dim); } |
411 | /** \returns a writable expression of the translation vector of the transformation */ |
412 | EIGEN_DEVICE_FUNC inline TranslationPart translation() { return TranslationPart(m_matrix,0,Dim); } |
413 | |
414 | /** \returns an expression of the product between the transform \c *this and a matrix expression \a other. |
415 | * |
416 | * The right-hand-side \a other can be either: |
417 | * \li an homogeneous vector of size Dim+1, |
418 | * \li a set of homogeneous vectors of size Dim+1 x N, |
419 | * \li a transformation matrix of size Dim+1 x Dim+1. |
420 | * |
421 | * Moreover, if \c *this represents an affine transformation (i.e., Mode!=Projective), then \a other can also be: |
422 | * \li a point of size Dim (computes: \code this->linear() * other + this->translation()\endcode), |
423 | * \li a set of N points as a Dim x N matrix (computes: \code (this->linear() * other).colwise() + this->translation()\endcode), |
424 | * |
425 | * In all cases, the return type is a matrix or vector of same sizes as the right-hand-side \a other. |
426 | * |
427 | * If you want to interpret \a other as a linear or affine transformation, then first convert it to a Transform<> type, |
428 | * or do your own cooking. |
429 | * |
430 | * Finally, if you want to apply Affine transformations to vectors, then explicitly apply the linear part only: |
431 | * \code |
432 | * Affine3f A; |
433 | * Vector3f v1, v2; |
434 | * v2 = A.linear() * v1; |
435 | * \endcode |
436 | * |
437 | */ |
438 | // note: this function is defined here because some compilers cannot find the respective declaration |
439 | template<typename OtherDerived> |
440 | EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename internal::transform_right_product_impl<Transform, OtherDerived>::ResultType |
441 | operator * (const EigenBase<OtherDerived> &other) const |
442 | { return internal::transform_right_product_impl<Transform, OtherDerived>::run(*this,other.derived()); } |
443 | |
444 | /** \returns the product expression of a transformation matrix \a a times a transform \a b |
445 | * |
446 | * The left hand side \a other can be either: |
447 | * \li a linear transformation matrix of size Dim x Dim, |
448 | * \li an affine transformation matrix of size Dim x Dim+1, |
449 | * \li a general transformation matrix of size Dim+1 x Dim+1. |
450 | */ |
451 | template<typename OtherDerived> friend |
452 | EIGEN_DEVICE_FUNC inline const typename internal::transform_left_product_impl<OtherDerived,Mode,Options,_Dim,_Dim+1>::ResultType |
453 | operator * (const EigenBase<OtherDerived> &a, const Transform &b) |
454 | { return internal::transform_left_product_impl<OtherDerived,Mode,Options,Dim,HDim>::run(a.derived(),b); } |
455 | |
456 | /** \returns The product expression of a transform \a a times a diagonal matrix \a b |
457 | * |
458 | * The rhs diagonal matrix is interpreted as an affine scaling transformation. The |
459 | * product results in a Transform of the same type (mode) as the lhs only if the lhs |
460 | * mode is no isometry. In that case, the returned transform is an affinity. |
461 | */ |
462 | template<typename DiagonalDerived> |
463 | EIGEN_DEVICE_FUNC inline const TransformTimeDiagonalReturnType |
464 | operator * (const DiagonalBase<DiagonalDerived> &b) const |
465 | { |
466 | TransformTimeDiagonalReturnType res(*this); |
467 | res.linearExt() *= b; |
468 | return res; |
469 | } |
470 | |
471 | /** \returns The product expression of a diagonal matrix \a a times a transform \a b |
472 | * |
473 | * The lhs diagonal matrix is interpreted as an affine scaling transformation. The |
474 | * product results in a Transform of the same type (mode) as the lhs only if the lhs |
475 | * mode is no isometry. In that case, the returned transform is an affinity. |
476 | */ |
477 | template<typename DiagonalDerived> |
478 | EIGEN_DEVICE_FUNC friend inline TransformTimeDiagonalReturnType |
479 | operator * (const DiagonalBase<DiagonalDerived> &a, const Transform &b) |
480 | { |
481 | TransformTimeDiagonalReturnType res; |
482 | res.linear().noalias() = a*b.linear(); |
483 | res.translation().noalias() = a*b.translation(); |
484 | if (Mode!=int(AffineCompact)) |
485 | res.matrix().row(Dim) = b.matrix().row(Dim); |
486 | return res; |
487 | } |
488 | |
489 | template<typename OtherDerived> |
490 | EIGEN_DEVICE_FUNC inline Transform& operator*=(const EigenBase<OtherDerived>& other) { return *this = *this * other; } |
491 | |
492 | /** Concatenates two transformations */ |
493 | EIGEN_DEVICE_FUNC inline const Transform operator * (const Transform& other) const |
494 | { |
495 | return internal::transform_transform_product_impl<Transform,Transform>::run(*this,other); |
496 | } |
497 | |
498 | #if EIGEN_COMP_ICC |
499 | private: |
500 | // this intermediate structure permits to workaround a bug in ICC 11: |
501 | // error: template instantiation resulted in unexpected function type of "Eigen::Transform<double, 3, 32, 0> |
502 | // (const Eigen::Transform<double, 3, 2, 0> &) const" |
503 | // (the meaning of a name may have changed since the template declaration -- the type of the template is: |
504 | // "Eigen::internal::transform_transform_product_impl<Eigen::Transform<double, 3, 32, 0>, |
505 | // Eigen::Transform<double, 3, Mode, Options>, <expression>>::ResultType (const Eigen::Transform<double, 3, Mode, Options> &) const") |
506 | // |
507 | template<int OtherMode,int OtherOptions> struct icc_11_workaround |
508 | { |
509 | typedef internal::transform_transform_product_impl<Transform,Transform<Scalar,Dim,OtherMode,OtherOptions> > ProductType; |
510 | typedef typename ProductType::ResultType ResultType; |
511 | }; |
512 | |
513 | public: |
514 | /** Concatenates two different transformations */ |
515 | template<int OtherMode,int OtherOptions> |
516 | inline typename icc_11_workaround<OtherMode,OtherOptions>::ResultType |
517 | operator * (const Transform<Scalar,Dim,OtherMode,OtherOptions>& other) const |
518 | { |
519 | typedef typename icc_11_workaround<OtherMode,OtherOptions>::ProductType ProductType; |
520 | return ProductType::run(*this,other); |
521 | } |
522 | #else |
523 | /** Concatenates two different transformations */ |
524 | template<int OtherMode,int OtherOptions> |
525 | EIGEN_DEVICE_FUNC inline typename internal::transform_transform_product_impl<Transform,Transform<Scalar,Dim,OtherMode,OtherOptions> >::ResultType |
526 | operator * (const Transform<Scalar,Dim,OtherMode,OtherOptions>& other) const |
527 | { |
528 | return internal::transform_transform_product_impl<Transform,Transform<Scalar,Dim,OtherMode,OtherOptions> >::run(*this,other); |
529 | } |
530 | #endif |
531 | |
532 | /** \sa MatrixBase::setIdentity() */ |
533 | EIGEN_DEVICE_FUNC void setIdentity() { m_matrix.setIdentity(); } |
534 | |
535 | /** |
536 | * \brief Returns an identity transformation. |
537 | * \todo In the future this function should be returning a Transform expression. |
538 | */ |
539 | EIGEN_DEVICE_FUNC static const Transform Identity() |
540 | { |
541 | return Transform(MatrixType::Identity()); |
542 | } |
543 | |
544 | template<typename OtherDerived> |
545 | EIGEN_DEVICE_FUNC |
546 | inline Transform& scale(const MatrixBase<OtherDerived> &other); |
547 | |
548 | template<typename OtherDerived> |
549 | EIGEN_DEVICE_FUNC |
550 | inline Transform& prescale(const MatrixBase<OtherDerived> &other); |
551 | |
552 | EIGEN_DEVICE_FUNC inline Transform& scale(const Scalar& s); |
553 | EIGEN_DEVICE_FUNC inline Transform& prescale(const Scalar& s); |
554 | |
555 | template<typename OtherDerived> |
556 | EIGEN_DEVICE_FUNC |
557 | inline Transform& translate(const MatrixBase<OtherDerived> &other); |
558 | |
559 | template<typename OtherDerived> |
560 | EIGEN_DEVICE_FUNC |
561 | inline Transform& pretranslate(const MatrixBase<OtherDerived> &other); |
562 | |
563 | template<typename RotationType> |
564 | EIGEN_DEVICE_FUNC |
565 | inline Transform& rotate(const RotationType& rotation); |
566 | |
567 | template<typename RotationType> |
568 | EIGEN_DEVICE_FUNC |
569 | inline Transform& prerotate(const RotationType& rotation); |
570 | |
571 | EIGEN_DEVICE_FUNC Transform& shear(const Scalar& sx, const Scalar& sy); |
572 | EIGEN_DEVICE_FUNC Transform& preshear(const Scalar& sx, const Scalar& sy); |
573 | |
574 | EIGEN_DEVICE_FUNC inline Transform& operator=(const TranslationType& t); |
575 | |
576 | EIGEN_DEVICE_FUNC |
577 | inline Transform& operator*=(const TranslationType& t) { return translate(t.vector()); } |
578 | |
579 | EIGEN_DEVICE_FUNC inline Transform operator*(const TranslationType& t) const; |
580 | |
581 | EIGEN_DEVICE_FUNC |
582 | inline Transform& operator=(const UniformScaling<Scalar>& t); |
583 | |
584 | EIGEN_DEVICE_FUNC |
585 | inline Transform& operator*=(const UniformScaling<Scalar>& s) { return scale(s.factor()); } |
586 | |
587 | EIGEN_DEVICE_FUNC |
588 | inline TransformTimeDiagonalReturnType operator*(const UniformScaling<Scalar>& s) const |
589 | { |
590 | TransformTimeDiagonalReturnType res = *this; |
591 | res.scale(s.factor()); |
592 | return res; |
593 | } |
594 | |
595 | EIGEN_DEVICE_FUNC |
596 | inline Transform& operator*=(const DiagonalMatrix<Scalar,Dim>& s) { linearExt() *= s; return *this; } |
597 | |
598 | template<typename Derived> |
599 | EIGEN_DEVICE_FUNC inline Transform& operator=(const RotationBase<Derived,Dim>& r); |
600 | template<typename Derived> |
601 | EIGEN_DEVICE_FUNC inline Transform& operator*=(const RotationBase<Derived,Dim>& r) { return rotate(r.toRotationMatrix()); } |
602 | template<typename Derived> |
603 | EIGEN_DEVICE_FUNC inline Transform operator*(const RotationBase<Derived,Dim>& r) const; |
604 | |
605 | EIGEN_DEVICE_FUNC const LinearMatrixType rotation() const; |
606 | template<typename RotationMatrixType, typename ScalingMatrixType> |
607 | EIGEN_DEVICE_FUNC |
608 | void computeRotationScaling(RotationMatrixType *rotation, ScalingMatrixType *scaling) const; |
609 | template<typename ScalingMatrixType, typename RotationMatrixType> |
610 | EIGEN_DEVICE_FUNC |
611 | void computeScalingRotation(ScalingMatrixType *scaling, RotationMatrixType *rotation) const; |
612 | |
613 | template<typename PositionDerived, typename OrientationType, typename ScaleDerived> |
614 | EIGEN_DEVICE_FUNC |
615 | Transform& fromPositionOrientationScale(const MatrixBase<PositionDerived> &position, |
616 | const OrientationType& orientation, const MatrixBase<ScaleDerived> &scale); |
617 | |
618 | EIGEN_DEVICE_FUNC |
619 | inline Transform inverse(TransformTraits traits = (TransformTraits)Mode) const; |
620 | |
621 | /** \returns a const pointer to the column major internal matrix */ |
622 | EIGEN_DEVICE_FUNC const Scalar* data() const { return m_matrix.data(); } |
623 | /** \returns a non-const pointer to the column major internal matrix */ |
624 | EIGEN_DEVICE_FUNC Scalar* data() { return m_matrix.data(); } |
625 | |
626 | /** \returns \c *this with scalar type casted to \a NewScalarType |
627 | * |
628 | * Note that if \a NewScalarType is equal to the current scalar type of \c *this |
629 | * then this function smartly returns a const reference to \c *this. |
630 | */ |
631 | template<typename NewScalarType> |
632 | EIGEN_DEVICE_FUNC inline typename internal::cast_return_type<Transform,Transform<NewScalarType,Dim,Mode,Options> >::type cast() const |
633 | { return typename internal::cast_return_type<Transform,Transform<NewScalarType,Dim,Mode,Options> >::type(*this); } |
634 | |
635 | /** Copy constructor with scalar type conversion */ |
636 | template<typename OtherScalarType> |
637 | EIGEN_DEVICE_FUNC inline explicit Transform(const Transform<OtherScalarType,Dim,Mode,Options>& other) |
638 | { |
639 | check_template_params(); |
640 | m_matrix = other.matrix().template cast<Scalar>(); |
641 | } |
642 | |
643 | /** \returns \c true if \c *this is approximately equal to \a other, within the precision |
644 | * determined by \a prec. |
645 | * |
646 | * \sa MatrixBase::isApprox() */ |
647 | EIGEN_DEVICE_FUNC bool isApprox(const Transform& other, const typename NumTraits<Scalar>::Real& prec = NumTraits<Scalar>::dummy_precision()) const |
648 | { return m_matrix.isApprox(other.m_matrix, prec); } |
649 | |
650 | /** Sets the last row to [0 ... 0 1] |
651 | */ |
652 | EIGEN_DEVICE_FUNC void makeAffine() |
653 | { |
654 | internal::transform_make_affine<int(Mode)>::run(m_matrix); |
655 | } |
656 | |
657 | /** \internal |
658 | * \returns the Dim x Dim linear part if the transformation is affine, |
659 | * and the HDim x Dim part for projective transformations. |
660 | */ |
661 | EIGEN_DEVICE_FUNC inline Block<MatrixType,int(Mode)==int(Projective)?HDim:Dim,Dim> linearExt() |
662 | { return m_matrix.template block<int(Mode)==int(Projective)?HDim:Dim,Dim>(0,0); } |
663 | /** \internal |
664 | * \returns the Dim x Dim linear part if the transformation is affine, |
665 | * and the HDim x Dim part for projective transformations. |
666 | */ |
667 | EIGEN_DEVICE_FUNC inline const Block<MatrixType,int(Mode)==int(Projective)?HDim:Dim,Dim> linearExt() const |
668 | { return m_matrix.template block<int(Mode)==int(Projective)?HDim:Dim,Dim>(0,0); } |
669 | |
670 | /** \internal |
671 | * \returns the translation part if the transformation is affine, |
672 | * and the last column for projective transformations. |
673 | */ |
674 | EIGEN_DEVICE_FUNC inline Block<MatrixType,int(Mode)==int(Projective)?HDim:Dim,1> translationExt() |
675 | { return m_matrix.template block<int(Mode)==int(Projective)?HDim:Dim,1>(0,Dim); } |
676 | /** \internal |
677 | * \returns the translation part if the transformation is affine, |
678 | * and the last column for projective transformations. |
679 | */ |
680 | EIGEN_DEVICE_FUNC inline const Block<MatrixType,int(Mode)==int(Projective)?HDim:Dim,1> translationExt() const |
681 | { return m_matrix.template block<int(Mode)==int(Projective)?HDim:Dim,1>(0,Dim); } |
682 | |
683 | |
684 | #ifdef EIGEN_TRANSFORM_PLUGIN |
685 | #include EIGEN_TRANSFORM_PLUGIN |
686 | #endif |
687 | |
688 | protected: |
689 | #ifndef EIGEN_PARSED_BY_DOXYGEN |
690 | EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void check_template_params() |
691 | { |
692 | EIGEN_STATIC_ASSERT((Options & (DontAlign|RowMajor)) == Options, INVALID_MATRIX_TEMPLATE_PARAMETERS) |
693 | } |
694 | #endif |
695 | |
696 | }; |
697 | |
698 | /** \ingroup Geometry_Module */ |
699 | typedef Transform<float,2,Isometry> Isometry2f; |
700 | /** \ingroup Geometry_Module */ |
701 | typedef Transform<float,3,Isometry> Isometry3f; |
702 | /** \ingroup Geometry_Module */ |
703 | typedef Transform<double,2,Isometry> Isometry2d; |
704 | /** \ingroup Geometry_Module */ |
705 | typedef Transform<double,3,Isometry> Isometry3d; |
706 | |
707 | /** \ingroup Geometry_Module */ |
708 | typedef Transform<float,2,Affine> Affine2f; |
709 | /** \ingroup Geometry_Module */ |
710 | typedef Transform<float,3,Affine> Affine3f; |
711 | /** \ingroup Geometry_Module */ |
712 | typedef Transform<double,2,Affine> Affine2d; |
713 | /** \ingroup Geometry_Module */ |
714 | typedef Transform<double,3,Affine> Affine3d; |
715 | |
716 | /** \ingroup Geometry_Module */ |
717 | typedef Transform<float,2,AffineCompact> AffineCompact2f; |
718 | /** \ingroup Geometry_Module */ |
719 | typedef Transform<float,3,AffineCompact> AffineCompact3f; |
720 | /** \ingroup Geometry_Module */ |
721 | typedef Transform<double,2,AffineCompact> AffineCompact2d; |
722 | /** \ingroup Geometry_Module */ |
723 | typedef Transform<double,3,AffineCompact> AffineCompact3d; |
724 | |
725 | /** \ingroup Geometry_Module */ |
726 | typedef Transform<float,2,Projective> Projective2f; |
727 | /** \ingroup Geometry_Module */ |
728 | typedef Transform<float,3,Projective> Projective3f; |
729 | /** \ingroup Geometry_Module */ |
730 | typedef Transform<double,2,Projective> Projective2d; |
731 | /** \ingroup Geometry_Module */ |
732 | typedef Transform<double,3,Projective> Projective3d; |
733 | |
734 | /************************** |
735 | *** Optional QT support *** |
736 | **************************/ |
737 | |
738 | #ifdef EIGEN_QT_SUPPORT |
739 | /** Initializes \c *this from a QMatrix assuming the dimension is 2. |
740 | * |
741 | * This function is available only if the token EIGEN_QT_SUPPORT is defined. |
742 | */ |
743 | template<typename Scalar, int Dim, int Mode,int Options> |
744 | Transform<Scalar,Dim,Mode,Options>::Transform(const QMatrix& other) |
745 | { |
746 | check_template_params(); |
747 | *this = other; |
748 | } |
749 | |
750 | /** Set \c *this from a QMatrix assuming the dimension is 2. |
751 | * |
752 | * This function is available only if the token EIGEN_QT_SUPPORT is defined. |
753 | */ |
754 | template<typename Scalar, int Dim, int Mode,int Options> |
755 | Transform<Scalar,Dim,Mode,Options>& Transform<Scalar,Dim,Mode,Options>::operator=(const QMatrix& other) |
756 | { |
757 | EIGEN_STATIC_ASSERT(Dim==2, YOU_MADE_A_PROGRAMMING_MISTAKE) |
758 | if (Mode == int(AffineCompact)) |
759 | m_matrix << other.m11(), other.m21(), other.dx(), |
760 | other.m12(), other.m22(), other.dy(); |
761 | else |
762 | m_matrix << other.m11(), other.m21(), other.dx(), |
763 | other.m12(), other.m22(), other.dy(), |
764 | 0, 0, 1; |
765 | return *this; |
766 | } |
767 | |
768 | /** \returns a QMatrix from \c *this assuming the dimension is 2. |
769 | * |
770 | * \warning this conversion might loss data if \c *this is not affine |
771 | * |
772 | * This function is available only if the token EIGEN_QT_SUPPORT is defined. |
773 | */ |
774 | template<typename Scalar, int Dim, int Mode, int Options> |
775 | QMatrix Transform<Scalar,Dim,Mode,Options>::toQMatrix(void) const |
776 | { |
777 | check_template_params(); |
778 | EIGEN_STATIC_ASSERT(Dim==2, YOU_MADE_A_PROGRAMMING_MISTAKE) |
779 | return QMatrix(m_matrix.coeff(0,0), m_matrix.coeff(1,0), |
780 | m_matrix.coeff(0,1), m_matrix.coeff(1,1), |
781 | m_matrix.coeff(0,2), m_matrix.coeff(1,2)); |
782 | } |
783 | |
784 | /** Initializes \c *this from a QTransform assuming the dimension is 2. |
785 | * |
786 | * This function is available only if the token EIGEN_QT_SUPPORT is defined. |
787 | */ |
788 | template<typename Scalar, int Dim, int Mode,int Options> |
789 | Transform<Scalar,Dim,Mode,Options>::Transform(const QTransform& other) |
790 | { |
791 | check_template_params(); |
792 | *this = other; |
793 | } |
794 | |
795 | /** Set \c *this from a QTransform assuming the dimension is 2. |
796 | * |
797 | * This function is available only if the token EIGEN_QT_SUPPORT is defined. |
798 | */ |
799 | template<typename Scalar, int Dim, int Mode, int Options> |
800 | Transform<Scalar,Dim,Mode,Options>& Transform<Scalar,Dim,Mode,Options>::operator=(const QTransform& other) |
801 | { |
802 | check_template_params(); |
803 | EIGEN_STATIC_ASSERT(Dim==2, YOU_MADE_A_PROGRAMMING_MISTAKE) |
804 | if (Mode == int(AffineCompact)) |
805 | m_matrix << other.m11(), other.m21(), other.dx(), |
806 | other.m12(), other.m22(), other.dy(); |
807 | else |
808 | m_matrix << other.m11(), other.m21(), other.dx(), |
809 | other.m12(), other.m22(), other.dy(), |
810 | other.m13(), other.m23(), other.m33(); |
811 | return *this; |
812 | } |
813 | |
814 | /** \returns a QTransform from \c *this assuming the dimension is 2. |
815 | * |
816 | * This function is available only if the token EIGEN_QT_SUPPORT is defined. |
817 | */ |
818 | template<typename Scalar, int Dim, int Mode, int Options> |
819 | QTransform Transform<Scalar,Dim,Mode,Options>::toQTransform(void) const |
820 | { |
821 | EIGEN_STATIC_ASSERT(Dim==2, YOU_MADE_A_PROGRAMMING_MISTAKE) |
822 | if (Mode == int(AffineCompact)) |
823 | return QTransform(m_matrix.coeff(0,0), m_matrix.coeff(1,0), |
824 | m_matrix.coeff(0,1), m_matrix.coeff(1,1), |
825 | m_matrix.coeff(0,2), m_matrix.coeff(1,2)); |
826 | else |
827 | return QTransform(m_matrix.coeff(0,0), m_matrix.coeff(1,0), m_matrix.coeff(2,0), |
828 | m_matrix.coeff(0,1), m_matrix.coeff(1,1), m_matrix.coeff(2,1), |
829 | m_matrix.coeff(0,2), m_matrix.coeff(1,2), m_matrix.coeff(2,2)); |
830 | } |
831 | #endif |
832 | |
833 | /********************* |
834 | *** Procedural API *** |
835 | *********************/ |
836 | |
837 | /** Applies on the right the non uniform scale transformation represented |
838 | * by the vector \a other to \c *this and returns a reference to \c *this. |
839 | * \sa prescale() |
840 | */ |
841 | template<typename Scalar, int Dim, int Mode, int Options> |
842 | template<typename OtherDerived> |
843 | EIGEN_DEVICE_FUNC Transform<Scalar,Dim,Mode,Options>& |
844 | Transform<Scalar,Dim,Mode,Options>::scale(const MatrixBase<OtherDerived> &other) |
845 | { |
846 | EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(OtherDerived,int(Dim)) |
847 | EIGEN_STATIC_ASSERT(Mode!=int(Isometry), THIS_METHOD_IS_ONLY_FOR_SPECIFIC_TRANSFORMATIONS) |
848 | linearExt().noalias() = (linearExt() * other.asDiagonal()); |
849 | return *this; |
850 | } |
851 | |
852 | /** Applies on the right a uniform scale of a factor \a c to \c *this |
853 | * and returns a reference to \c *this. |
854 | * \sa prescale(Scalar) |
855 | */ |
856 | template<typename Scalar, int Dim, int Mode, int Options> |
857 | EIGEN_DEVICE_FUNC inline Transform<Scalar,Dim,Mode,Options>& Transform<Scalar,Dim,Mode,Options>::scale(const Scalar& s) |
858 | { |
859 | EIGEN_STATIC_ASSERT(Mode!=int(Isometry), THIS_METHOD_IS_ONLY_FOR_SPECIFIC_TRANSFORMATIONS) |
860 | linearExt() *= s; |
861 | return *this; |
862 | } |
863 | |
864 | /** Applies on the left the non uniform scale transformation represented |
865 | * by the vector \a other to \c *this and returns a reference to \c *this. |
866 | * \sa scale() |
867 | */ |
868 | template<typename Scalar, int Dim, int Mode, int Options> |
869 | template<typename OtherDerived> |
870 | EIGEN_DEVICE_FUNC Transform<Scalar,Dim,Mode,Options>& |
871 | Transform<Scalar,Dim,Mode,Options>::prescale(const MatrixBase<OtherDerived> &other) |
872 | { |
873 | EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(OtherDerived,int(Dim)) |
874 | EIGEN_STATIC_ASSERT(Mode!=int(Isometry), THIS_METHOD_IS_ONLY_FOR_SPECIFIC_TRANSFORMATIONS) |
875 | affine().noalias() = (other.asDiagonal() * affine()); |
876 | return *this; |
877 | } |
878 | |
879 | /** Applies on the left a uniform scale of a factor \a c to \c *this |
880 | * and returns a reference to \c *this. |
881 | * \sa scale(Scalar) |
882 | */ |
883 | template<typename Scalar, int Dim, int Mode, int Options> |
884 | EIGEN_DEVICE_FUNC inline Transform<Scalar,Dim,Mode,Options>& Transform<Scalar,Dim,Mode,Options>::prescale(const Scalar& s) |
885 | { |
886 | EIGEN_STATIC_ASSERT(Mode!=int(Isometry), THIS_METHOD_IS_ONLY_FOR_SPECIFIC_TRANSFORMATIONS) |
887 | m_matrix.template topRows<Dim>() *= s; |
888 | return *this; |
889 | } |
890 | |
891 | /** Applies on the right the translation matrix represented by the vector \a other |
892 | * to \c *this and returns a reference to \c *this. |
893 | * \sa pretranslate() |
894 | */ |
895 | template<typename Scalar, int Dim, int Mode, int Options> |
896 | template<typename OtherDerived> |
897 | EIGEN_DEVICE_FUNC Transform<Scalar,Dim,Mode,Options>& |
898 | Transform<Scalar,Dim,Mode,Options>::translate(const MatrixBase<OtherDerived> &other) |
899 | { |
900 | EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(OtherDerived,int(Dim)) |
901 | translationExt() += linearExt() * other; |
902 | return *this; |
903 | } |
904 | |
905 | /** Applies on the left the translation matrix represented by the vector \a other |
906 | * to \c *this and returns a reference to \c *this. |
907 | * \sa translate() |
908 | */ |
909 | template<typename Scalar, int Dim, int Mode, int Options> |
910 | template<typename OtherDerived> |
911 | EIGEN_DEVICE_FUNC Transform<Scalar,Dim,Mode,Options>& |
912 | Transform<Scalar,Dim,Mode,Options>::pretranslate(const MatrixBase<OtherDerived> &other) |
913 | { |
914 | EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(OtherDerived,int(Dim)) |
915 | if(int(Mode)==int(Projective)) |
916 | affine() += other * m_matrix.row(Dim); |
917 | else |
918 | translation() += other; |
919 | return *this; |
920 | } |
921 | |
922 | /** Applies on the right the rotation represented by the rotation \a rotation |
923 | * to \c *this and returns a reference to \c *this. |
924 | * |
925 | * The template parameter \a RotationType is the type of the rotation which |
926 | * must be known by internal::toRotationMatrix<>. |
927 | * |
928 | * Natively supported types includes: |
929 | * - any scalar (2D), |
930 | * - a Dim x Dim matrix expression, |
931 | * - a Quaternion (3D), |
932 | * - a AngleAxis (3D) |
933 | * |
934 | * This mechanism is easily extendable to support user types such as Euler angles, |
935 | * or a pair of Quaternion for 4D rotations. |
936 | * |
937 | * \sa rotate(Scalar), class Quaternion, class AngleAxis, prerotate(RotationType) |
938 | */ |
939 | template<typename Scalar, int Dim, int Mode, int Options> |
940 | template<typename RotationType> |
941 | EIGEN_DEVICE_FUNC Transform<Scalar,Dim,Mode,Options>& |
942 | Transform<Scalar,Dim,Mode,Options>::rotate(const RotationType& rotation) |
943 | { |
944 | linearExt() *= internal::toRotationMatrix<Scalar,Dim>(rotation); |
945 | return *this; |
946 | } |
947 | |
948 | /** Applies on the left the rotation represented by the rotation \a rotation |
949 | * to \c *this and returns a reference to \c *this. |
950 | * |
951 | * See rotate() for further details. |
952 | * |
953 | * \sa rotate() |
954 | */ |
955 | template<typename Scalar, int Dim, int Mode, int Options> |
956 | template<typename RotationType> |
957 | EIGEN_DEVICE_FUNC Transform<Scalar,Dim,Mode,Options>& |
958 | Transform<Scalar,Dim,Mode,Options>::prerotate(const RotationType& rotation) |
959 | { |
960 | m_matrix.template block<Dim,HDim>(0,0) = internal::toRotationMatrix<Scalar,Dim>(rotation) |
961 | * m_matrix.template block<Dim,HDim>(0,0); |
962 | return *this; |
963 | } |
964 | |
965 | /** Applies on the right the shear transformation represented |
966 | * by the vector \a other to \c *this and returns a reference to \c *this. |
967 | * \warning 2D only. |
968 | * \sa preshear() |
969 | */ |
970 | template<typename Scalar, int Dim, int Mode, int Options> |
971 | EIGEN_DEVICE_FUNC Transform<Scalar,Dim,Mode,Options>& |
972 | Transform<Scalar,Dim,Mode,Options>::shear(const Scalar& sx, const Scalar& sy) |
973 | { |
974 | EIGEN_STATIC_ASSERT(int(Dim)==2, YOU_MADE_A_PROGRAMMING_MISTAKE) |
975 | EIGEN_STATIC_ASSERT(Mode!=int(Isometry), THIS_METHOD_IS_ONLY_FOR_SPECIFIC_TRANSFORMATIONS) |
976 | VectorType tmp = linear().col(0)*sy + linear().col(1); |
977 | linear() << linear().col(0) + linear().col(1)*sx, tmp; |
978 | return *this; |
979 | } |
980 | |
981 | /** Applies on the left the shear transformation represented |
982 | * by the vector \a other to \c *this and returns a reference to \c *this. |
983 | * \warning 2D only. |
984 | * \sa shear() |
985 | */ |
986 | template<typename Scalar, int Dim, int Mode, int Options> |
987 | EIGEN_DEVICE_FUNC Transform<Scalar,Dim,Mode,Options>& |
988 | Transform<Scalar,Dim,Mode,Options>::preshear(const Scalar& sx, const Scalar& sy) |
989 | { |
990 | EIGEN_STATIC_ASSERT(int(Dim)==2, YOU_MADE_A_PROGRAMMING_MISTAKE) |
991 | EIGEN_STATIC_ASSERT(Mode!=int(Isometry), THIS_METHOD_IS_ONLY_FOR_SPECIFIC_TRANSFORMATIONS) |
992 | m_matrix.template block<Dim,HDim>(0,0) = LinearMatrixType(1, sx, sy, 1) * m_matrix.template block<Dim,HDim>(0,0); |
993 | return *this; |
994 | } |
995 | |
996 | /****************************************************** |
997 | *** Scaling, Translation and Rotation compatibility *** |
998 | ******************************************************/ |
999 | |
1000 | template<typename Scalar, int Dim, int Mode, int Options> |
1001 | EIGEN_DEVICE_FUNC inline Transform<Scalar,Dim,Mode,Options>& Transform<Scalar,Dim,Mode,Options>::operator=(const TranslationType& t) |
1002 | { |
1003 | linear().setIdentity(); |
1004 | translation() = t.vector(); |
1005 | makeAffine(); |
1006 | return *this; |
1007 | } |
1008 | |
1009 | template<typename Scalar, int Dim, int Mode, int Options> |
1010 | EIGEN_DEVICE_FUNC inline Transform<Scalar,Dim,Mode,Options> Transform<Scalar,Dim,Mode,Options>::operator*(const TranslationType& t) const |
1011 | { |
1012 | Transform res = *this; |
1013 | res.translate(t.vector()); |
1014 | return res; |
1015 | } |
1016 | |
1017 | template<typename Scalar, int Dim, int Mode, int Options> |
1018 | EIGEN_DEVICE_FUNC inline Transform<Scalar,Dim,Mode,Options>& Transform<Scalar,Dim,Mode,Options>::operator=(const UniformScaling<Scalar>& s) |
1019 | { |
1020 | m_matrix.setZero(); |
1021 | linear().diagonal().fill(s.factor()); |
1022 | makeAffine(); |
1023 | return *this; |
1024 | } |
1025 | |
1026 | template<typename Scalar, int Dim, int Mode, int Options> |
1027 | template<typename Derived> |
1028 | EIGEN_DEVICE_FUNC inline Transform<Scalar,Dim,Mode,Options>& Transform<Scalar,Dim,Mode,Options>::operator=(const RotationBase<Derived,Dim>& r) |
1029 | { |
1030 | linear() = internal::toRotationMatrix<Scalar,Dim>(r); |
1031 | translation().setZero(); |
1032 | makeAffine(); |
1033 | return *this; |
1034 | } |
1035 | |
1036 | template<typename Scalar, int Dim, int Mode, int Options> |
1037 | template<typename Derived> |
1038 | EIGEN_DEVICE_FUNC inline Transform<Scalar,Dim,Mode,Options> Transform<Scalar,Dim,Mode,Options>::operator*(const RotationBase<Derived,Dim>& r) const |
1039 | { |
1040 | Transform res = *this; |
1041 | res.rotate(r.derived()); |
1042 | return res; |
1043 | } |
1044 | |
1045 | /************************ |
1046 | *** Special functions *** |
1047 | ************************/ |
1048 | |
1049 | /** \returns the rotation part of the transformation |
1050 | * |
1051 | * |
1052 | * \svd_module |
1053 | * |
1054 | * \sa computeRotationScaling(), computeScalingRotation(), class SVD |
1055 | */ |
1056 | template<typename Scalar, int Dim, int Mode, int Options> |
1057 | EIGEN_DEVICE_FUNC const typename Transform<Scalar,Dim,Mode,Options>::LinearMatrixType |
1058 | Transform<Scalar,Dim,Mode,Options>::rotation() const |
1059 | { |
1060 | LinearMatrixType result; |
1061 | computeRotationScaling(&result, (LinearMatrixType*)0); |
1062 | return result; |
1063 | } |
1064 | |
1065 | |
1066 | /** decomposes the linear part of the transformation as a product rotation x scaling, the scaling being |
1067 | * not necessarily positive. |
1068 | * |
1069 | * If either pointer is zero, the corresponding computation is skipped. |
1070 | * |
1071 | * |
1072 | * |
1073 | * \svd_module |
1074 | * |
1075 | * \sa computeScalingRotation(), rotation(), class SVD |
1076 | */ |
1077 | template<typename Scalar, int Dim, int Mode, int Options> |
1078 | template<typename RotationMatrixType, typename ScalingMatrixType> |
1079 | EIGEN_DEVICE_FUNC void Transform<Scalar,Dim,Mode,Options>::computeRotationScaling(RotationMatrixType *rotation, ScalingMatrixType *scaling) const |
1080 | { |
1081 | JacobiSVD<LinearMatrixType> svd(linear(), ComputeFullU | ComputeFullV); |
1082 | |
1083 | Scalar x = (svd.matrixU() * svd.matrixV().adjoint()).determinant(); // so x has absolute value 1 |
1084 | VectorType sv(svd.singularValues()); |
1085 | sv.coeffRef(0) *= x; |
1086 | if(scaling) scaling->lazyAssign(svd.matrixV() * sv.asDiagonal() * svd.matrixV().adjoint()); |
1087 | if(rotation) |
1088 | { |
1089 | LinearMatrixType m(svd.matrixU()); |
1090 | m.col(0) /= x; |
1091 | rotation->lazyAssign(m * svd.matrixV().adjoint()); |
1092 | } |
1093 | } |
1094 | |
1095 | /** decomposes the linear part of the transformation as a product scaling x rotation, the scaling being |
1096 | * not necessarily positive. |
1097 | * |
1098 | * If either pointer is zero, the corresponding computation is skipped. |
1099 | * |
1100 | * |
1101 | * |
1102 | * \svd_module |
1103 | * |
1104 | * \sa computeRotationScaling(), rotation(), class SVD |
1105 | */ |
1106 | template<typename Scalar, int Dim, int Mode, int Options> |
1107 | template<typename ScalingMatrixType, typename RotationMatrixType> |
1108 | EIGEN_DEVICE_FUNC void Transform<Scalar,Dim,Mode,Options>::computeScalingRotation(ScalingMatrixType *scaling, RotationMatrixType *rotation) const |
1109 | { |
1110 | JacobiSVD<LinearMatrixType> svd(linear(), ComputeFullU | ComputeFullV); |
1111 | |
1112 | Scalar x = (svd.matrixU() * svd.matrixV().adjoint()).determinant(); // so x has absolute value 1 |
1113 | VectorType sv(svd.singularValues()); |
1114 | sv.coeffRef(0) *= x; |
1115 | if(scaling) scaling->lazyAssign(svd.matrixU() * sv.asDiagonal() * svd.matrixU().adjoint()); |
1116 | if(rotation) |
1117 | { |
1118 | LinearMatrixType m(svd.matrixU()); |
1119 | m.col(0) /= x; |
1120 | rotation->lazyAssign(m * svd.matrixV().adjoint()); |
1121 | } |
1122 | } |
1123 | |
1124 | /** Convenient method to set \c *this from a position, orientation and scale |
1125 | * of a 3D object. |
1126 | */ |
1127 | template<typename Scalar, int Dim, int Mode, int Options> |
1128 | template<typename PositionDerived, typename OrientationType, typename ScaleDerived> |
1129 | EIGEN_DEVICE_FUNC Transform<Scalar,Dim,Mode,Options>& |
1130 | Transform<Scalar,Dim,Mode,Options>::fromPositionOrientationScale(const MatrixBase<PositionDerived> &position, |
1131 | const OrientationType& orientation, const MatrixBase<ScaleDerived> &scale) |
1132 | { |
1133 | linear() = internal::toRotationMatrix<Scalar,Dim>(orientation); |
1134 | linear() *= scale.asDiagonal(); |
1135 | translation() = position; |
1136 | makeAffine(); |
1137 | return *this; |
1138 | } |
1139 | |
1140 | namespace internal { |
1141 | |
1142 | template<int Mode> |
1143 | struct transform_make_affine |
1144 | { |
1145 | template<typename MatrixType> |
1146 | EIGEN_DEVICE_FUNC static void run(MatrixType &mat) |
1147 | { |
1148 | static const int Dim = MatrixType::ColsAtCompileTime-1; |
1149 | mat.template block<1,Dim>(Dim,0).setZero(); |
1150 | mat.coeffRef(Dim,Dim) = typename MatrixType::Scalar(1); |
1151 | } |
1152 | }; |
1153 | |
1154 | template<> |
1155 | struct transform_make_affine<AffineCompact> |
1156 | { |
1157 | template<typename MatrixType> EIGEN_DEVICE_FUNC static void run(MatrixType &) { } |
1158 | }; |
1159 | |
1160 | // selector needed to avoid taking the inverse of a 3x4 matrix |
1161 | template<typename TransformType, int Mode=TransformType::Mode> |
1162 | struct projective_transform_inverse |
1163 | { |
1164 | EIGEN_DEVICE_FUNC static inline void run(const TransformType&, TransformType&) |
1165 | {} |
1166 | }; |
1167 | |
1168 | template<typename TransformType> |
1169 | struct projective_transform_inverse<TransformType, Projective> |
1170 | { |
1171 | EIGEN_DEVICE_FUNC static inline void run(const TransformType& m, TransformType& res) |
1172 | { |
1173 | res.matrix() = m.matrix().inverse(); |
1174 | } |
1175 | }; |
1176 | |
1177 | } // end namespace internal |
1178 | |
1179 | |
1180 | /** |
1181 | * |
1182 | * \returns the inverse transformation according to some given knowledge |
1183 | * on \c *this. |
1184 | * |
1185 | * \param hint allows to optimize the inversion process when the transformation |
1186 | * is known to be not a general transformation (optional). The possible values are: |
1187 | * - #Projective if the transformation is not necessarily affine, i.e., if the |
1188 | * last row is not guaranteed to be [0 ... 0 1] |
1189 | * - #Affine if the last row can be assumed to be [0 ... 0 1] |
1190 | * - #Isometry if the transformation is only a concatenations of translations |
1191 | * and rotations. |
1192 | * The default is the template class parameter \c Mode. |
1193 | * |
1194 | * \warning unless \a traits is always set to NoShear or NoScaling, this function |
1195 | * requires the generic inverse method of MatrixBase defined in the LU module. If |
1196 | * you forget to include this module, then you will get hard to debug linking errors. |
1197 | * |
1198 | * \sa MatrixBase::inverse() |
1199 | */ |
1200 | template<typename Scalar, int Dim, int Mode, int Options> |
1201 | EIGEN_DEVICE_FUNC Transform<Scalar,Dim,Mode,Options> |
1202 | Transform<Scalar,Dim,Mode,Options>::inverse(TransformTraits hint) const |
1203 | { |
1204 | Transform res; |
1205 | if (hint == Projective) |
1206 | { |
1207 | internal::projective_transform_inverse<Transform>::run(*this, res); |
1208 | } |
1209 | else |
1210 | { |
1211 | if (hint == Isometry) |
1212 | { |
1213 | res.matrix().template topLeftCorner<Dim,Dim>() = linear().transpose(); |
1214 | } |
1215 | else if(hint&Affine) |
1216 | { |
1217 | res.matrix().template topLeftCorner<Dim,Dim>() = linear().inverse(); |
1218 | } |
1219 | else |
1220 | { |
1221 | eigen_assert(false && "Invalid transform traits in Transform::Inverse" ); |
1222 | } |
1223 | // translation and remaining parts |
1224 | res.matrix().template topRightCorner<Dim,1>() |
1225 | = - res.matrix().template topLeftCorner<Dim,Dim>() * translation(); |
1226 | res.makeAffine(); // we do need this, because in the beginning res is uninitialized |
1227 | } |
1228 | return res; |
1229 | } |
1230 | |
1231 | namespace internal { |
1232 | |
1233 | /***************************************************** |
1234 | *** Specializations of take affine part *** |
1235 | *****************************************************/ |
1236 | |
1237 | template<typename TransformType> struct transform_take_affine_part { |
1238 | typedef typename TransformType::MatrixType MatrixType; |
1239 | typedef typename TransformType::AffinePart AffinePart; |
1240 | typedef typename TransformType::ConstAffinePart ConstAffinePart; |
1241 | static inline AffinePart run(MatrixType& m) |
1242 | { return m.template block<TransformType::Dim,TransformType::HDim>(0,0); } |
1243 | static inline ConstAffinePart run(const MatrixType& m) |
1244 | { return m.template block<TransformType::Dim,TransformType::HDim>(0,0); } |
1245 | }; |
1246 | |
1247 | template<typename Scalar, int Dim, int Options> |
1248 | struct transform_take_affine_part<Transform<Scalar,Dim,AffineCompact, Options> > { |
1249 | typedef typename Transform<Scalar,Dim,AffineCompact,Options>::MatrixType MatrixType; |
1250 | static inline MatrixType& run(MatrixType& m) { return m; } |
1251 | static inline const MatrixType& run(const MatrixType& m) { return m; } |
1252 | }; |
1253 | |
1254 | /***************************************************** |
1255 | *** Specializations of construct from matrix *** |
1256 | *****************************************************/ |
1257 | |
1258 | template<typename Other, int Mode, int Options, int Dim, int HDim> |
1259 | struct transform_construct_from_matrix<Other, Mode,Options,Dim,HDim, Dim,Dim> |
1260 | { |
1261 | static inline void run(Transform<typename Other::Scalar,Dim,Mode,Options> *transform, const Other& other) |
1262 | { |
1263 | transform->linear() = other; |
1264 | transform->translation().setZero(); |
1265 | transform->makeAffine(); |
1266 | } |
1267 | }; |
1268 | |
1269 | template<typename Other, int Mode, int Options, int Dim, int HDim> |
1270 | struct transform_construct_from_matrix<Other, Mode,Options,Dim,HDim, Dim,HDim> |
1271 | { |
1272 | static inline void run(Transform<typename Other::Scalar,Dim,Mode,Options> *transform, const Other& other) |
1273 | { |
1274 | transform->affine() = other; |
1275 | transform->makeAffine(); |
1276 | } |
1277 | }; |
1278 | |
1279 | template<typename Other, int Mode, int Options, int Dim, int HDim> |
1280 | struct transform_construct_from_matrix<Other, Mode,Options,Dim,HDim, HDim,HDim> |
1281 | { |
1282 | static inline void run(Transform<typename Other::Scalar,Dim,Mode,Options> *transform, const Other& other) |
1283 | { transform->matrix() = other; } |
1284 | }; |
1285 | |
1286 | template<typename Other, int Options, int Dim, int HDim> |
1287 | struct transform_construct_from_matrix<Other, AffineCompact,Options,Dim,HDim, HDim,HDim> |
1288 | { |
1289 | static inline void run(Transform<typename Other::Scalar,Dim,AffineCompact,Options> *transform, const Other& other) |
1290 | { transform->matrix() = other.template block<Dim,HDim>(0,0); } |
1291 | }; |
1292 | |
1293 | /********************************************************** |
1294 | *** Specializations of operator* with rhs EigenBase *** |
1295 | **********************************************************/ |
1296 | |
1297 | template<int LhsMode,int RhsMode> |
1298 | struct transform_product_result |
1299 | { |
1300 | enum |
1301 | { |
1302 | Mode = |
1303 | (LhsMode == (int)Projective || RhsMode == (int)Projective ) ? Projective : |
1304 | (LhsMode == (int)Affine || RhsMode == (int)Affine ) ? Affine : |
1305 | (LhsMode == (int)AffineCompact || RhsMode == (int)AffineCompact ) ? AffineCompact : |
1306 | (LhsMode == (int)Isometry || RhsMode == (int)Isometry ) ? Isometry : Projective |
1307 | }; |
1308 | }; |
1309 | |
1310 | template< typename TransformType, typename MatrixType, int RhsCols> |
1311 | struct transform_right_product_impl< TransformType, MatrixType, 0, RhsCols> |
1312 | { |
1313 | typedef typename MatrixType::PlainObject ResultType; |
1314 | |
1315 | static EIGEN_STRONG_INLINE ResultType run(const TransformType& T, const MatrixType& other) |
1316 | { |
1317 | return T.matrix() * other; |
1318 | } |
1319 | }; |
1320 | |
1321 | template< typename TransformType, typename MatrixType, int RhsCols> |
1322 | struct transform_right_product_impl< TransformType, MatrixType, 1, RhsCols> |
1323 | { |
1324 | enum { |
1325 | Dim = TransformType::Dim, |
1326 | HDim = TransformType::HDim, |
1327 | OtherRows = MatrixType::RowsAtCompileTime, |
1328 | OtherCols = MatrixType::ColsAtCompileTime |
1329 | }; |
1330 | |
1331 | typedef typename MatrixType::PlainObject ResultType; |
1332 | |
1333 | static EIGEN_STRONG_INLINE ResultType run(const TransformType& T, const MatrixType& other) |
1334 | { |
1335 | EIGEN_STATIC_ASSERT(OtherRows==HDim, YOU_MIXED_MATRICES_OF_DIFFERENT_SIZES); |
1336 | |
1337 | typedef Block<ResultType, Dim, OtherCols, int(MatrixType::RowsAtCompileTime)==Dim> TopLeftLhs; |
1338 | |
1339 | ResultType res(other.rows(),other.cols()); |
1340 | TopLeftLhs(res, 0, 0, Dim, other.cols()).noalias() = T.affine() * other; |
1341 | res.row(OtherRows-1) = other.row(OtherRows-1); |
1342 | |
1343 | return res; |
1344 | } |
1345 | }; |
1346 | |
1347 | template< typename TransformType, typename MatrixType, int RhsCols> |
1348 | struct transform_right_product_impl< TransformType, MatrixType, 2, RhsCols> |
1349 | { |
1350 | enum { |
1351 | Dim = TransformType::Dim, |
1352 | HDim = TransformType::HDim, |
1353 | OtherRows = MatrixType::RowsAtCompileTime, |
1354 | OtherCols = MatrixType::ColsAtCompileTime |
1355 | }; |
1356 | |
1357 | typedef typename MatrixType::PlainObject ResultType; |
1358 | |
1359 | static EIGEN_STRONG_INLINE ResultType run(const TransformType& T, const MatrixType& other) |
1360 | { |
1361 | EIGEN_STATIC_ASSERT(OtherRows==Dim, YOU_MIXED_MATRICES_OF_DIFFERENT_SIZES); |
1362 | |
1363 | typedef Block<ResultType, Dim, OtherCols, true> TopLeftLhs; |
1364 | ResultType res(Replicate<typename TransformType::ConstTranslationPart, 1, OtherCols>(T.translation(),1,other.cols())); |
1365 | TopLeftLhs(res, 0, 0, Dim, other.cols()).noalias() += T.linear() * other; |
1366 | |
1367 | return res; |
1368 | } |
1369 | }; |
1370 | |
1371 | template< typename TransformType, typename MatrixType > |
1372 | struct transform_right_product_impl< TransformType, MatrixType, 2, 1> // rhs is a vector of size Dim |
1373 | { |
1374 | typedef typename TransformType::MatrixType TransformMatrix; |
1375 | enum { |
1376 | Dim = TransformType::Dim, |
1377 | HDim = TransformType::HDim, |
1378 | OtherRows = MatrixType::RowsAtCompileTime, |
1379 | WorkingRows = EIGEN_PLAIN_ENUM_MIN(TransformMatrix::RowsAtCompileTime,HDim) |
1380 | }; |
1381 | |
1382 | typedef typename MatrixType::PlainObject ResultType; |
1383 | |
1384 | static EIGEN_STRONG_INLINE ResultType run(const TransformType& T, const MatrixType& other) |
1385 | { |
1386 | EIGEN_STATIC_ASSERT(OtherRows==Dim, YOU_MIXED_MATRICES_OF_DIFFERENT_SIZES); |
1387 | |
1388 | Matrix<typename ResultType::Scalar, Dim+1, 1> rhs; |
1389 | rhs.template head<Dim>() = other; rhs[Dim] = typename ResultType::Scalar(1); |
1390 | Matrix<typename ResultType::Scalar, WorkingRows, 1> res(T.matrix() * rhs); |
1391 | return res.template head<Dim>(); |
1392 | } |
1393 | }; |
1394 | |
1395 | /********************************************************** |
1396 | *** Specializations of operator* with lhs EigenBase *** |
1397 | **********************************************************/ |
1398 | |
1399 | // generic HDim x HDim matrix * T => Projective |
1400 | template<typename Other,int Mode, int Options, int Dim, int HDim> |
1401 | struct transform_left_product_impl<Other,Mode,Options,Dim,HDim, HDim,HDim> |
1402 | { |
1403 | typedef Transform<typename Other::Scalar,Dim,Mode,Options> TransformType; |
1404 | typedef typename TransformType::MatrixType MatrixType; |
1405 | typedef Transform<typename Other::Scalar,Dim,Projective,Options> ResultType; |
1406 | static ResultType run(const Other& other,const TransformType& tr) |
1407 | { return ResultType(other * tr.matrix()); } |
1408 | }; |
1409 | |
1410 | // generic HDim x HDim matrix * AffineCompact => Projective |
1411 | template<typename Other, int Options, int Dim, int HDim> |
1412 | struct transform_left_product_impl<Other,AffineCompact,Options,Dim,HDim, HDim,HDim> |
1413 | { |
1414 | typedef Transform<typename Other::Scalar,Dim,AffineCompact,Options> TransformType; |
1415 | typedef typename TransformType::MatrixType MatrixType; |
1416 | typedef Transform<typename Other::Scalar,Dim,Projective,Options> ResultType; |
1417 | static ResultType run(const Other& other,const TransformType& tr) |
1418 | { |
1419 | ResultType res; |
1420 | res.matrix().noalias() = other.template block<HDim,Dim>(0,0) * tr.matrix(); |
1421 | res.matrix().col(Dim) += other.col(Dim); |
1422 | return res; |
1423 | } |
1424 | }; |
1425 | |
1426 | // affine matrix * T |
1427 | template<typename Other,int Mode, int Options, int Dim, int HDim> |
1428 | struct transform_left_product_impl<Other,Mode,Options,Dim,HDim, Dim,HDim> |
1429 | { |
1430 | typedef Transform<typename Other::Scalar,Dim,Mode,Options> TransformType; |
1431 | typedef typename TransformType::MatrixType MatrixType; |
1432 | typedef TransformType ResultType; |
1433 | static ResultType run(const Other& other,const TransformType& tr) |
1434 | { |
1435 | ResultType res; |
1436 | res.affine().noalias() = other * tr.matrix(); |
1437 | res.matrix().row(Dim) = tr.matrix().row(Dim); |
1438 | return res; |
1439 | } |
1440 | }; |
1441 | |
1442 | // affine matrix * AffineCompact |
1443 | template<typename Other, int Options, int Dim, int HDim> |
1444 | struct transform_left_product_impl<Other,AffineCompact,Options,Dim,HDim, Dim,HDim> |
1445 | { |
1446 | typedef Transform<typename Other::Scalar,Dim,AffineCompact,Options> TransformType; |
1447 | typedef typename TransformType::MatrixType MatrixType; |
1448 | typedef TransformType ResultType; |
1449 | static ResultType run(const Other& other,const TransformType& tr) |
1450 | { |
1451 | ResultType res; |
1452 | res.matrix().noalias() = other.template block<Dim,Dim>(0,0) * tr.matrix(); |
1453 | res.translation() += other.col(Dim); |
1454 | return res; |
1455 | } |
1456 | }; |
1457 | |
1458 | // linear matrix * T |
1459 | template<typename Other,int Mode, int Options, int Dim, int HDim> |
1460 | struct transform_left_product_impl<Other,Mode,Options,Dim,HDim, Dim,Dim> |
1461 | { |
1462 | typedef Transform<typename Other::Scalar,Dim,Mode,Options> TransformType; |
1463 | typedef typename TransformType::MatrixType MatrixType; |
1464 | typedef TransformType ResultType; |
1465 | static ResultType run(const Other& other, const TransformType& tr) |
1466 | { |
1467 | TransformType res; |
1468 | if(Mode!=int(AffineCompact)) |
1469 | res.matrix().row(Dim) = tr.matrix().row(Dim); |
1470 | res.matrix().template topRows<Dim>().noalias() |
1471 | = other * tr.matrix().template topRows<Dim>(); |
1472 | return res; |
1473 | } |
1474 | }; |
1475 | |
1476 | /********************************************************** |
1477 | *** Specializations of operator* with another Transform *** |
1478 | **********************************************************/ |
1479 | |
1480 | template<typename Scalar, int Dim, int LhsMode, int LhsOptions, int RhsMode, int RhsOptions> |
1481 | struct transform_transform_product_impl<Transform<Scalar,Dim,LhsMode,LhsOptions>,Transform<Scalar,Dim,RhsMode,RhsOptions>,false > |
1482 | { |
1483 | enum { ResultMode = transform_product_result<LhsMode,RhsMode>::Mode }; |
1484 | typedef Transform<Scalar,Dim,LhsMode,LhsOptions> Lhs; |
1485 | typedef Transform<Scalar,Dim,RhsMode,RhsOptions> Rhs; |
1486 | typedef Transform<Scalar,Dim,ResultMode,LhsOptions> ResultType; |
1487 | static ResultType run(const Lhs& lhs, const Rhs& rhs) |
1488 | { |
1489 | ResultType res; |
1490 | res.linear() = lhs.linear() * rhs.linear(); |
1491 | res.translation() = lhs.linear() * rhs.translation() + lhs.translation(); |
1492 | res.makeAffine(); |
1493 | return res; |
1494 | } |
1495 | }; |
1496 | |
1497 | template<typename Scalar, int Dim, int LhsMode, int LhsOptions, int RhsMode, int RhsOptions> |
1498 | struct transform_transform_product_impl<Transform<Scalar,Dim,LhsMode,LhsOptions>,Transform<Scalar,Dim,RhsMode,RhsOptions>,true > |
1499 | { |
1500 | typedef Transform<Scalar,Dim,LhsMode,LhsOptions> Lhs; |
1501 | typedef Transform<Scalar,Dim,RhsMode,RhsOptions> Rhs; |
1502 | typedef Transform<Scalar,Dim,Projective> ResultType; |
1503 | static ResultType run(const Lhs& lhs, const Rhs& rhs) |
1504 | { |
1505 | return ResultType( lhs.matrix() * rhs.matrix() ); |
1506 | } |
1507 | }; |
1508 | |
1509 | template<typename Scalar, int Dim, int LhsOptions, int RhsOptions> |
1510 | struct transform_transform_product_impl<Transform<Scalar,Dim,AffineCompact,LhsOptions>,Transform<Scalar,Dim,Projective,RhsOptions>,true > |
1511 | { |
1512 | typedef Transform<Scalar,Dim,AffineCompact,LhsOptions> Lhs; |
1513 | typedef Transform<Scalar,Dim,Projective,RhsOptions> Rhs; |
1514 | typedef Transform<Scalar,Dim,Projective> ResultType; |
1515 | static ResultType run(const Lhs& lhs, const Rhs& rhs) |
1516 | { |
1517 | ResultType res; |
1518 | res.matrix().template topRows<Dim>() = lhs.matrix() * rhs.matrix(); |
1519 | res.matrix().row(Dim) = rhs.matrix().row(Dim); |
1520 | return res; |
1521 | } |
1522 | }; |
1523 | |
1524 | template<typename Scalar, int Dim, int LhsOptions, int RhsOptions> |
1525 | struct transform_transform_product_impl<Transform<Scalar,Dim,Projective,LhsOptions>,Transform<Scalar,Dim,AffineCompact,RhsOptions>,true > |
1526 | { |
1527 | typedef Transform<Scalar,Dim,Projective,LhsOptions> Lhs; |
1528 | typedef Transform<Scalar,Dim,AffineCompact,RhsOptions> Rhs; |
1529 | typedef Transform<Scalar,Dim,Projective> ResultType; |
1530 | static ResultType run(const Lhs& lhs, const Rhs& rhs) |
1531 | { |
1532 | ResultType res(lhs.matrix().template leftCols<Dim>() * rhs.matrix()); |
1533 | res.matrix().col(Dim) += lhs.matrix().col(Dim); |
1534 | return res; |
1535 | } |
1536 | }; |
1537 | |
1538 | } // end namespace internal |
1539 | |
1540 | } // end namespace Eigen |
1541 | |
1542 | #endif // EIGEN_TRANSFORM_H |
1543 | |