Home | History | Annotate | Download | only in Geometry
      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 (at) inria.fr>
      5 // Copyright (C) 2009 Benoit Jacob <jacob.benoit.1 (at) gmail.com>
      6 // Copyright (C) 2010 Hauke Heibel <hauke.heibel (at) 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