Transform.h
Go to the documentation of this file.
00001 // This file is part of Eigen, a lightweight C++ template library
00002 // for linear algebra.
00003 //
00004 // Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
00005 // Copyright (C) 2009 Benoit Jacob <jacob.benoit.1@gmail.com>
00006 // Copyright (C) 2010 Hauke Heibel <hauke.heibel@gmail.com>
00007 //
00008 // Eigen is free software; you can redistribute it and/or
00009 // modify it under the terms of the GNU Lesser General Public
00010 // License as published by the Free Software Foundation; either
00011 // version 3 of the License, or (at your option) any later version.
00012 //
00013 // Alternatively, you can redistribute it and/or
00014 // modify it under the terms of the GNU General Public License as
00015 // published by the Free Software Foundation; either version 2 of
00016 // the License, or (at your option) any later version.
00017 //
00018 // Eigen is distributed in the hope that it will be useful, but WITHOUT ANY
00019 // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00020 // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the
00021 // GNU General Public License for more details.
00022 //
00023 // You should have received a copy of the GNU Lesser General Public
00024 // License and a copy of the GNU General Public License along with
00025 // Eigen. If not, see <http://www.gnu.org/licenses/>.
00026 
00027 #ifndef EIGEN_TRANSFORM_H
00028 #define EIGEN_TRANSFORM_H
00029 
00030 namespace Eigen { 
00031 
00032 namespace internal {
00033 
00034 template<typename Transform>
00035 struct transform_traits
00036 {
00037   enum
00038   {
00039     Dim = Transform::Dim,
00040     HDim = Transform::HDim,
00041     Mode = Transform::Mode,
00042     IsProjective = (Mode==Projective)
00043   };
00044 };
00045 
00046 template< typename TransformType,
00047           typename MatrixType,
00048           int Case = transform_traits<TransformType>::IsProjective ? 0
00049                    : int(MatrixType::RowsAtCompileTime) == int(transform_traits<TransformType>::HDim) ? 1
00050                    : 2>
00051 struct transform_right_product_impl;
00052 
00053 template< typename Other,
00054           int Mode,
00055           int Options,
00056           int Dim,
00057           int HDim,
00058           int OtherRows=Other::RowsAtCompileTime,
00059           int OtherCols=Other::ColsAtCompileTime>
00060 struct transform_left_product_impl;
00061 
00062 template< typename Lhs,
00063           typename Rhs,
00064           bool AnyProjective = 
00065             transform_traits<Lhs>::IsProjective ||
00066             transform_traits<Rhs>::IsProjective>
00067 struct transform_transform_product_impl;
00068 
00069 template< typename Other,
00070           int Mode,
00071           int Options,
00072           int Dim,
00073           int HDim,
00074           int OtherRows=Other::RowsAtCompileTime,
00075           int OtherCols=Other::ColsAtCompileTime>
00076 struct transform_construct_from_matrix;
00077 
00078 template<typename TransformType> struct transform_take_affine_part;
00079 
00080 } // end namespace internal
00081 
00190 template<typename _Scalar, int _Dim, int _Mode, int _Options>
00191 class Transform
00192 {
00193 public:
00194   EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(_Scalar,_Dim==Dynamic ? Dynamic : (_Dim+1)*(_Dim+1))
00195   enum {
00196     Mode = _Mode,
00197     Options = _Options,
00198     Dim = _Dim,     
00199     HDim = _Dim+1,  
00200     Rows = int(Mode)==(AffineCompact) ? Dim : HDim
00201   };
00203   typedef _Scalar Scalar;
00204   typedef DenseIndex Index;
00206   typedef typename internal::make_proper_matrix_type<Scalar,Rows,HDim,Options>::type MatrixType;
00208   typedef const MatrixType ConstMatrixType;
00210   typedef Matrix<Scalar,Dim,Dim,Options> LinearMatrixType;
00212   typedef Block<MatrixType,Dim,Dim,int(Mode)==(AffineCompact)> LinearPart;
00214   typedef const Block<ConstMatrixType,Dim,Dim,int(Mode)==(AffineCompact)> ConstLinearPart;
00216   typedef typename internal::conditional<int(Mode)==int(AffineCompact),
00217                               MatrixType&,
00218                               Block<MatrixType,Dim,HDim> >::type AffinePart;
00220   typedef typename internal::conditional<int(Mode)==int(AffineCompact),
00221                               const MatrixType&,
00222                               const Block<const MatrixType,Dim,HDim> >::type ConstAffinePart;
00224   typedef Matrix<Scalar,Dim,1> VectorType;
00226   typedef Block<MatrixType,Dim,1,int(Mode)==(AffineCompact)> TranslationPart;
00228   typedef const Block<ConstMatrixType,Dim,1,int(Mode)==(AffineCompact)> ConstTranslationPart;
00230   typedef Translation<Scalar,Dim> TranslationType;
00231   
00232   // this intermediate enum is needed to avoid an ICE with gcc 3.4 and 4.0
00233   enum { TransformTimeDiagonalMode = ((Mode==int(Isometry))?Affine:int(Mode)) };
00235   typedef Transform<Scalar,Dim,TransformTimeDiagonalMode> TransformTimeDiagonalReturnType;
00236 
00237 protected:
00238 
00239   MatrixType m_matrix;
00240 
00241 public:
00242 
00245   inline Transform()
00246   {
00247     check_template_params();
00248     if (int(Mode)==Affine)
00249       makeAffine();
00250   }
00251 
00252   inline Transform(const Transform& other)
00253   {
00254     check_template_params();
00255     m_matrix = other.m_matrix;
00256   }
00257 
00258   inline explicit Transform(const TranslationType& t)
00259   {
00260     check_template_params();
00261     *this = t;
00262   }
00263   inline explicit Transform(const UniformScaling<Scalar>& s)
00264   {
00265     check_template_params();
00266     *this = s;
00267   }
00268   template<typename Derived>
00269   inline explicit Transform(const RotationBase<Derived, Dim>& r)
00270   {
00271     check_template_params();
00272     *this = r;
00273   }
00274 
00275   inline Transform& operator=(const Transform& other)
00276   { m_matrix = other.m_matrix; return *this; }
00277 
00278   typedef internal::transform_take_affine_part<Transform> take_affine_part;
00279 
00281   template<typename OtherDerived>
00282   inline explicit Transform(const EigenBase<OtherDerived>& other)
00283   {
00284     EIGEN_STATIC_ASSERT((internal::is_same<Scalar,typename OtherDerived::Scalar>::value),
00285       YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY);
00286 
00287     check_template_params();
00288     internal::transform_construct_from_matrix<OtherDerived,Mode,Options,Dim,HDim>::run(this, other.derived());
00289   }
00290 
00292   template<typename OtherDerived>
00293   inline Transform& operator=(const EigenBase<OtherDerived>& other)
00294   {
00295     EIGEN_STATIC_ASSERT((internal::is_same<Scalar,typename OtherDerived::Scalar>::value),
00296       YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY);
00297 
00298     internal::transform_construct_from_matrix<OtherDerived,Mode,Options,Dim,HDim>::run(this, other.derived());
00299     return *this;
00300   }
00301   
00302   template<int OtherOptions>
00303   inline Transform(const Transform<Scalar,Dim,Mode,OtherOptions>& other)
00304   {
00305     check_template_params();
00306     // only the options change, we can directly copy the matrices
00307     m_matrix = other.matrix();
00308   }
00309 
00310   template<int OtherMode,int OtherOptions>
00311   inline Transform(const Transform<Scalar,Dim,OtherMode,OtherOptions>& other)
00312   {
00313     check_template_params();
00314     // prevent conversions as:
00315     // Affine | AffineCompact | Isometry = Projective
00316     EIGEN_STATIC_ASSERT(EIGEN_IMPLIES(OtherMode==int(Projective), Mode==int(Projective)),
00317                         YOU_PERFORMED_AN_INVALID_TRANSFORMATION_CONVERSION)
00318 
00319     // prevent conversions as:
00320     // Isometry = Affine | AffineCompact
00321     EIGEN_STATIC_ASSERT(EIGEN_IMPLIES(OtherMode==int(Affine)||OtherMode==int(AffineCompact), Mode!=int(Isometry)),
00322                         YOU_PERFORMED_AN_INVALID_TRANSFORMATION_CONVERSION)
00323 
00324     enum { ModeIsAffineCompact = Mode == int(AffineCompact),
00325            OtherModeIsAffineCompact = OtherMode == int(AffineCompact)
00326     };
00327 
00328     if(ModeIsAffineCompact == OtherModeIsAffineCompact)
00329     {
00330       // We need the block expression because the code is compiled for all
00331       // combinations of transformations and will trigger a compile time error
00332       // if one tries to assign the matrices directly
00333       m_matrix.template block<Dim,Dim+1>(0,0) = other.matrix().template block<Dim,Dim+1>(0,0);
00334       makeAffine();
00335     }
00336     else if(OtherModeIsAffineCompact)
00337     {
00338       typedef typename Transform<Scalar,Dim,OtherMode,OtherOptions>::MatrixType OtherMatrixType;
00339       internal::transform_construct_from_matrix<OtherMatrixType,Mode,Options,Dim,HDim>::run(this, other.matrix());
00340     }
00341     else
00342     {
00343       // here we know that Mode == AffineCompact and OtherMode != AffineCompact.
00344       // if OtherMode were Projective, the static assert above would already have caught it.
00345       // So the only possibility is that OtherMode == Affine
00346       linear() = other.linear();
00347       translation() = other.translation();
00348     }
00349   }
00350 
00351   template<typename OtherDerived>
00352   Transform(const ReturnByValue<OtherDerived>& other)
00353   {
00354     check_template_params();
00355     other.evalTo(*this);
00356   }
00357 
00358   template<typename OtherDerived>
00359   Transform& operator=(const ReturnByValue<OtherDerived>& other)
00360   {
00361     other.evalTo(*this);
00362     return *this;
00363   }
00364 
00365   #ifdef EIGEN_QT_SUPPORT
00366   inline Transform(const QMatrix& other);
00367   inline Transform& operator=(const QMatrix& other);
00368   inline QMatrix toQMatrix(void) const;
00369   inline Transform(const QTransform& other);
00370   inline Transform& operator=(const QTransform& other);
00371   inline QTransform toQTransform(void) const;
00372   #endif
00373 
00376   inline Scalar operator() (Index row, Index col) const { return m_matrix(row,col); }
00379   inline Scalar& operator() (Index row, Index col) { return m_matrix(row,col); }
00380 
00382   inline const MatrixType& matrix() const { return m_matrix; }
00384   inline MatrixType& matrix() { return m_matrix; }
00385 
00387   inline ConstLinearPart linear() const { return ConstLinearPart(m_matrix,0,0); }
00389   inline LinearPart linear() { return LinearPart(m_matrix,0,0); }
00390 
00392   inline ConstAffinePart affine() const { return take_affine_part::run(m_matrix); }
00394   inline AffinePart affine() { return take_affine_part::run(m_matrix); }
00395 
00397   inline ConstTranslationPart translation() const { return ConstTranslationPart(m_matrix,0,Dim); }
00399   inline TranslationPart translation() { return TranslationPart(m_matrix,0,Dim); }
00400 
00412   // note: this function is defined here because some compilers cannot find the respective declaration
00413   template<typename OtherDerived>
00414   EIGEN_STRONG_INLINE const typename internal::transform_right_product_impl<Transform, OtherDerived>::ResultType
00415   operator * (const EigenBase<OtherDerived> &other) const
00416   { return internal::transform_right_product_impl<Transform, OtherDerived>::run(*this,other.derived()); }
00417 
00425   template<typename OtherDerived> friend
00426   inline const typename internal::transform_left_product_impl<OtherDerived,Mode,Options,_Dim,_Dim+1>::ResultType
00427     operator * (const EigenBase<OtherDerived> &a, const Transform &b)
00428   { return internal::transform_left_product_impl<OtherDerived,Mode,Options,Dim,HDim>::run(a.derived(),b); }
00429 
00436   template<typename DiagonalDerived>
00437   inline const TransformTimeDiagonalReturnType
00438     operator * (const DiagonalBase<DiagonalDerived> &b) const
00439   {
00440     TransformTimeDiagonalReturnType res(*this);
00441     res.linear() *= b;
00442     return res;
00443   }
00444 
00451   template<typename DiagonalDerived>
00452   friend inline TransformTimeDiagonalReturnType
00453     operator * (const DiagonalBase<DiagonalDerived> &a, const Transform &b)
00454   {
00455     TransformTimeDiagonalReturnType res;
00456     res.linear().noalias() = a*b.linear();
00457     res.translation().noalias() = a*b.translation();
00458     if (Mode!=int(AffineCompact))
00459       res.matrix().row(Dim) = b.matrix().row(Dim);
00460     return res;
00461   }
00462 
00463   template<typename OtherDerived>
00464   inline Transform& operator*=(const EigenBase<OtherDerived>& other) { return *this = *this * other; }
00465 
00467   inline const Transform operator * (const Transform& other) const
00468   {
00469     return internal::transform_transform_product_impl<Transform,Transform>::run(*this,other);
00470   }
00471 
00473   template<int OtherMode,int OtherOptions>
00474   inline const typename internal::transform_transform_product_impl<
00475     Transform,Transform<Scalar,Dim,OtherMode,OtherOptions> >::ResultType
00476     operator * (const Transform<Scalar,Dim,OtherMode,OtherOptions>& other) const
00477   {
00478     return internal::transform_transform_product_impl<Transform,Transform<Scalar,Dim,OtherMode,OtherOptions> >::run(*this,other);
00479   }
00480 
00482   void setIdentity() { m_matrix.setIdentity(); }
00483 
00488   static const Transform Identity()
00489   {
00490     return Transform(MatrixType::Identity());
00491   }
00492 
00493   template<typename OtherDerived>
00494   inline Transform& scale(const MatrixBase<OtherDerived> &other);
00495 
00496   template<typename OtherDerived>
00497   inline Transform& prescale(const MatrixBase<OtherDerived> &other);
00498 
00499   inline Transform& scale(Scalar s);
00500   inline Transform& prescale(Scalar s);
00501 
00502   template<typename OtherDerived>
00503   inline Transform& translate(const MatrixBase<OtherDerived> &other);
00504 
00505   template<typename OtherDerived>
00506   inline Transform& pretranslate(const MatrixBase<OtherDerived> &other);
00507 
00508   template<typename RotationType>
00509   inline Transform& rotate(const RotationType& rotation);
00510 
00511   template<typename RotationType>
00512   inline Transform& prerotate(const RotationType& rotation);
00513 
00514   Transform& shear(Scalar sx, Scalar sy);
00515   Transform& preshear(Scalar sx, Scalar sy);
00516 
00517   inline Transform& operator=(const TranslationType& t);
00518   inline Transform& operator*=(const TranslationType& t) { return translate(t.vector()); }
00519   inline Transform operator*(const TranslationType& t) const;
00520 
00521   inline Transform& operator=(const UniformScaling<Scalar>& t);
00522   inline Transform& operator*=(const UniformScaling<Scalar>& s) { return scale(s.factor()); }
00523   inline Transform operator*(const UniformScaling<Scalar>& s) const;
00524 
00525   inline Transform& operator*=(const DiagonalMatrix<Scalar,Dim>& s) { linear() *= s; return *this; }
00526 
00527   template<typename Derived>
00528   inline Transform& operator=(const RotationBase<Derived,Dim>& r);
00529   template<typename Derived>
00530   inline Transform& operator*=(const RotationBase<Derived,Dim>& r) { return rotate(r.toRotationMatrix()); }
00531   template<typename Derived>
00532   inline Transform operator*(const RotationBase<Derived,Dim>& r) const;
00533 
00534   const LinearMatrixType rotation() const;
00535   template<typename RotationMatrixType, typename ScalingMatrixType>
00536   void computeRotationScaling(RotationMatrixType *rotation, ScalingMatrixType *scaling) const;
00537   template<typename ScalingMatrixType, typename RotationMatrixType>
00538   void computeScalingRotation(ScalingMatrixType *scaling, RotationMatrixType *rotation) const;
00539 
00540   template<typename PositionDerived, typename OrientationType, typename ScaleDerived>
00541   Transform& fromPositionOrientationScale(const MatrixBase<PositionDerived> &position,
00542     const OrientationType& orientation, const MatrixBase<ScaleDerived> &scale);
00543 
00544   inline Transform inverse(TransformTraits traits = (TransformTraits)Mode) const;
00545 
00547   const Scalar* data() const { return m_matrix.data(); }
00549   Scalar* data() { return m_matrix.data(); }
00550 
00556   template<typename NewScalarType>
00557   inline typename internal::cast_return_type<Transform,Transform<NewScalarType,Dim,Mode,Options> >::type cast() const
00558   { return typename internal::cast_return_type<Transform,Transform<NewScalarType,Dim,Mode,Options> >::type(*this); }
00559 
00561   template<typename OtherScalarType>
00562   inline explicit Transform(const Transform<OtherScalarType,Dim,Mode,Options>& other)
00563   {
00564     check_template_params();
00565     m_matrix = other.matrix().template cast<Scalar>();
00566   }
00567 
00572   bool isApprox(const Transform& other, typename NumTraits<Scalar>::Real prec = NumTraits<Scalar>::dummy_precision()) const
00573   { return m_matrix.isApprox(other.m_matrix, prec); }
00574 
00577   void makeAffine()
00578   {
00579     if(int(Mode)!=int(AffineCompact))
00580     {
00581       matrix().template block<1,Dim>(Dim,0).setZero();
00582       matrix().coeffRef(Dim,Dim) = 1;
00583     }
00584   }
00585 
00590   inline Block<MatrixType,int(Mode)==int(Projective)?HDim:Dim,Dim> linearExt()
00591   { return m_matrix.template block<int(Mode)==int(Projective)?HDim:Dim,Dim>(0,0); }
00596   inline const Block<MatrixType,int(Mode)==int(Projective)?HDim:Dim,Dim> linearExt() const
00597   { return m_matrix.template block<int(Mode)==int(Projective)?HDim:Dim,Dim>(0,0); }
00598 
00603   inline Block<MatrixType,int(Mode)==int(Projective)?HDim:Dim,1> translationExt()
00604   { return m_matrix.template block<int(Mode)==int(Projective)?HDim:Dim,1>(0,Dim); }
00609   inline const Block<MatrixType,int(Mode)==int(Projective)?HDim:Dim,1> translationExt() const
00610   { return m_matrix.template block<int(Mode)==int(Projective)?HDim:Dim,1>(0,Dim); }
00611 
00612 
00613   #ifdef EIGEN_TRANSFORM_PLUGIN
00614   #include EIGEN_TRANSFORM_PLUGIN
00615   #endif
00616   
00617 protected:
00618   #ifndef EIGEN_PARSED_BY_DOXYGEN
00619     static EIGEN_STRONG_INLINE void check_template_params()
00620     {
00621       EIGEN_STATIC_ASSERT((Options & (DontAlign|RowMajor)) == Options, INVALID_MATRIX_TEMPLATE_PARAMETERS)
00622     }
00623   #endif
00624 
00625 };
00626 
00628 typedef Transform<float,2,Isometry> Isometry2f;
00630 typedef Transform<float,3,Isometry> Isometry3f;
00632 typedef Transform<double,2,Isometry> Isometry2d;
00634 typedef Transform<double,3,Isometry> Isometry3d;
00635 
00637 typedef Transform<float,2,Affine> Affine2f;
00639 typedef Transform<float,3,Affine> Affine3f;
00641 typedef Transform<double,2,Affine> Affine2d;
00643 typedef Transform<double,3,Affine> Affine3d;
00644 
00646 typedef Transform<float,2,AffineCompact> AffineCompact2f;
00648 typedef Transform<float,3,AffineCompact> AffineCompact3f;
00650 typedef Transform<double,2,AffineCompact> AffineCompact2d;
00652 typedef Transform<double,3,AffineCompact> AffineCompact3d;
00653 
00655 typedef Transform<float,2,Projective> Projective2f;
00657 typedef Transform<float,3,Projective> Projective3f;
00659 typedef Transform<double,2,Projective> Projective2d;
00661 typedef Transform<double,3,Projective> Projective3d;
00662 
00663 /**************************
00664 *** Optional QT support ***
00665 **************************/
00666 
00667 #ifdef EIGEN_QT_SUPPORT
00668 
00672 template<typename Scalar, int Dim, int Mode,int Options>
00673 Transform<Scalar,Dim,Mode,Options>::Transform(const QMatrix& other)
00674 {
00675   check_template_params();
00676   *this = other;
00677 }
00678 
00683 template<typename Scalar, int Dim, int Mode,int Options>
00684 Transform<Scalar,Dim,Mode,Options>& Transform<Scalar,Dim,Mode,Options>::operator=(const QMatrix& other)
00685 {
00686   EIGEN_STATIC_ASSERT(Dim==2, YOU_MADE_A_PROGRAMMING_MISTAKE)
00687   m_matrix << other.m11(), other.m21(), other.dx(),
00688               other.m12(), other.m22(), other.dy(),
00689               0, 0, 1;
00690   return *this;
00691 }
00692 
00699 template<typename Scalar, int Dim, int Mode, int Options>
00700 QMatrix Transform<Scalar,Dim,Mode,Options>::toQMatrix(void) const
00701 {
00702   check_template_params();
00703   EIGEN_STATIC_ASSERT(Dim==2, YOU_MADE_A_PROGRAMMING_MISTAKE)
00704   return QMatrix(m_matrix.coeff(0,0), m_matrix.coeff(1,0),
00705                  m_matrix.coeff(0,1), m_matrix.coeff(1,1),
00706                  m_matrix.coeff(0,2), m_matrix.coeff(1,2));
00707 }
00708 
00713 template<typename Scalar, int Dim, int Mode,int Options>
00714 Transform<Scalar,Dim,Mode,Options>::Transform(const QTransform& other)
00715 {
00716   check_template_params();
00717   *this = other;
00718 }
00719 
00724 template<typename Scalar, int Dim, int Mode, int Options>
00725 Transform<Scalar,Dim,Mode,Options>& Transform<Scalar,Dim,Mode,Options>::operator=(const QTransform& other)
00726 {
00727   check_template_params();
00728   EIGEN_STATIC_ASSERT(Dim==2, YOU_MADE_A_PROGRAMMING_MISTAKE)
00729   if (Mode == int(AffineCompact))
00730     m_matrix << other.m11(), other.m21(), other.dx(),
00731                 other.m12(), other.m22(), other.dy();
00732   else
00733     m_matrix << other.m11(), other.m21(), other.dx(),
00734                 other.m12(), other.m22(), other.dy(),
00735                 other.m13(), other.m23(), other.m33();
00736   return *this;
00737 }
00738 
00743 template<typename Scalar, int Dim, int Mode, int Options>
00744 QTransform Transform<Scalar,Dim,Mode,Options>::toQTransform(void) const
00745 {
00746   EIGEN_STATIC_ASSERT(Dim==2, YOU_MADE_A_PROGRAMMING_MISTAKE)
00747   if (Mode == int(AffineCompact))
00748     return QTransform(m_matrix.coeff(0,0), m_matrix.coeff(1,0),
00749                       m_matrix.coeff(0,1), m_matrix.coeff(1,1),
00750                       m_matrix.coeff(0,2), m_matrix.coeff(1,2));
00751   else
00752     return QTransform(m_matrix.coeff(0,0), m_matrix.coeff(1,0), m_matrix.coeff(2,0),
00753                       m_matrix.coeff(0,1), m_matrix.coeff(1,1), m_matrix.coeff(2,1),
00754                       m_matrix.coeff(0,2), m_matrix.coeff(1,2), m_matrix.coeff(2,2));
00755 }
00756 #endif
00757 
00758 /*********************
00759 *** Procedural API ***
00760 *********************/
00761 
00766 template<typename Scalar, int Dim, int Mode, int Options>
00767 template<typename OtherDerived>
00768 Transform<Scalar,Dim,Mode,Options>&
00769 Transform<Scalar,Dim,Mode,Options>::scale(const MatrixBase<OtherDerived> &other)
00770 {
00771   EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(OtherDerived,int(Dim))
00772   EIGEN_STATIC_ASSERT(Mode!=int(Isometry), THIS_METHOD_IS_ONLY_FOR_SPECIFIC_TRANSFORMATIONS)
00773   linearExt().noalias() = (linearExt() * other.asDiagonal());
00774   return *this;
00775 }
00776 
00781 template<typename Scalar, int Dim, int Mode, int Options>
00782 inline Transform<Scalar,Dim,Mode,Options>& Transform<Scalar,Dim,Mode,Options>::scale(Scalar s)
00783 {
00784   EIGEN_STATIC_ASSERT(Mode!=int(Isometry), THIS_METHOD_IS_ONLY_FOR_SPECIFIC_TRANSFORMATIONS)
00785   linearExt() *= s;
00786   return *this;
00787 }
00788 
00793 template<typename Scalar, int Dim, int Mode, int Options>
00794 template<typename OtherDerived>
00795 Transform<Scalar,Dim,Mode,Options>&
00796 Transform<Scalar,Dim,Mode,Options>::prescale(const MatrixBase<OtherDerived> &other)
00797 {
00798   EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(OtherDerived,int(Dim))
00799   EIGEN_STATIC_ASSERT(Mode!=int(Isometry), THIS_METHOD_IS_ONLY_FOR_SPECIFIC_TRANSFORMATIONS)
00800   m_matrix.template block<Dim,HDim>(0,0).noalias() = (other.asDiagonal() * m_matrix.template block<Dim,HDim>(0,0));
00801   return *this;
00802 }
00803 
00808 template<typename Scalar, int Dim, int Mode, int Options>
00809 inline Transform<Scalar,Dim,Mode,Options>& Transform<Scalar,Dim,Mode,Options>::prescale(Scalar s)
00810 {
00811   EIGEN_STATIC_ASSERT(Mode!=int(Isometry), THIS_METHOD_IS_ONLY_FOR_SPECIFIC_TRANSFORMATIONS)
00812   m_matrix.template topRows<Dim>() *= s;
00813   return *this;
00814 }
00815 
00820 template<typename Scalar, int Dim, int Mode, int Options>
00821 template<typename OtherDerived>
00822 Transform<Scalar,Dim,Mode,Options>&
00823 Transform<Scalar,Dim,Mode,Options>::translate(const MatrixBase<OtherDerived> &other)
00824 {
00825   EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(OtherDerived,int(Dim))
00826   translationExt() += linearExt() * other;
00827   return *this;
00828 }
00829 
00834 template<typename Scalar, int Dim, int Mode, int Options>
00835 template<typename OtherDerived>
00836 Transform<Scalar,Dim,Mode,Options>&
00837 Transform<Scalar,Dim,Mode,Options>::pretranslate(const MatrixBase<OtherDerived> &other)
00838 {
00839   EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(OtherDerived,int(Dim))
00840   if(int(Mode)==int(Projective))
00841     affine() += other * m_matrix.row(Dim);
00842   else
00843     translation() += other;
00844   return *this;
00845 }
00846 
00864 template<typename Scalar, int Dim, int Mode, int Options>
00865 template<typename RotationType>
00866 Transform<Scalar,Dim,Mode,Options>&
00867 Transform<Scalar,Dim,Mode,Options>::rotate(const RotationType& rotation)
00868 {
00869   linearExt() *= internal::toRotationMatrix<Scalar,Dim>(rotation);
00870   return *this;
00871 }
00872 
00880 template<typename Scalar, int Dim, int Mode, int Options>
00881 template<typename RotationType>
00882 Transform<Scalar,Dim,Mode,Options>&
00883 Transform<Scalar,Dim,Mode,Options>::prerotate(const RotationType& rotation)
00884 {
00885   m_matrix.template block<Dim,HDim>(0,0) = internal::toRotationMatrix<Scalar,Dim>(rotation)
00886                                          * m_matrix.template block<Dim,HDim>(0,0);
00887   return *this;
00888 }
00889 
00895 template<typename Scalar, int Dim, int Mode, int Options>
00896 Transform<Scalar,Dim,Mode,Options>&
00897 Transform<Scalar,Dim,Mode,Options>::shear(Scalar sx, Scalar sy)
00898 {
00899   EIGEN_STATIC_ASSERT(int(Dim)==2, YOU_MADE_A_PROGRAMMING_MISTAKE)
00900   EIGEN_STATIC_ASSERT(Mode!=int(Isometry), THIS_METHOD_IS_ONLY_FOR_SPECIFIC_TRANSFORMATIONS)
00901   VectorType tmp = linear().col(0)*sy + linear().col(1);
00902   linear() << linear().col(0) + linear().col(1)*sx, tmp;
00903   return *this;
00904 }
00905 
00911 template<typename Scalar, int Dim, int Mode, int Options>
00912 Transform<Scalar,Dim,Mode,Options>&
00913 Transform<Scalar,Dim,Mode,Options>::preshear(Scalar sx, Scalar sy)
00914 {
00915   EIGEN_STATIC_ASSERT(int(Dim)==2, YOU_MADE_A_PROGRAMMING_MISTAKE)
00916   EIGEN_STATIC_ASSERT(Mode!=int(Isometry), THIS_METHOD_IS_ONLY_FOR_SPECIFIC_TRANSFORMATIONS)
00917   m_matrix.template block<Dim,HDim>(0,0) = LinearMatrixType(1, sx, sy, 1) * m_matrix.template block<Dim,HDim>(0,0);
00918   return *this;
00919 }
00920 
00921 /******************************************************
00922 *** Scaling, Translation and Rotation compatibility ***
00923 ******************************************************/
00924 
00925 template<typename Scalar, int Dim, int Mode, int Options>
00926 inline Transform<Scalar,Dim,Mode,Options>& Transform<Scalar,Dim,Mode,Options>::operator=(const TranslationType& t)
00927 {
00928   linear().setIdentity();
00929   translation() = t.vector();
00930   makeAffine();
00931   return *this;
00932 }
00933 
00934 template<typename Scalar, int Dim, int Mode, int Options>
00935 inline Transform<Scalar,Dim,Mode,Options> Transform<Scalar,Dim,Mode,Options>::operator*(const TranslationType& t) const
00936 {
00937   Transform res = *this;
00938   res.translate(t.vector());
00939   return res;
00940 }
00941 
00942 template<typename Scalar, int Dim, int Mode, int Options>
00943 inline Transform<Scalar,Dim,Mode,Options>& Transform<Scalar,Dim,Mode,Options>::operator=(const UniformScaling<Scalar>& s)
00944 {
00945   m_matrix.setZero();
00946   linear().diagonal().fill(s.factor());
00947   makeAffine();
00948   return *this;
00949 }
00950 
00951 template<typename Scalar, int Dim, int Mode, int Options>
00952 inline Transform<Scalar,Dim,Mode,Options> Transform<Scalar,Dim,Mode,Options>::operator*(const UniformScaling<Scalar>& s) const
00953 {
00954   Transform res = *this;
00955   res.scale(s.factor());
00956   return res;
00957 }
00958 
00959 template<typename Scalar, int Dim, int Mode, int Options>
00960 template<typename Derived>
00961 inline Transform<Scalar,Dim,Mode,Options>& Transform<Scalar,Dim,Mode,Options>::operator=(const RotationBase<Derived,Dim>& r)
00962 {
00963   linear() = internal::toRotationMatrix<Scalar,Dim>(r);
00964   translation().setZero();
00965   makeAffine();
00966   return *this;
00967 }
00968 
00969 template<typename Scalar, int Dim, int Mode, int Options>
00970 template<typename Derived>
00971 inline Transform<Scalar,Dim,Mode,Options> Transform<Scalar,Dim,Mode,Options>::operator*(const RotationBase<Derived,Dim>& r) const
00972 {
00973   Transform res = *this;
00974   res.rotate(r.derived());
00975   return res;
00976 }
00977 
00978 /************************
00979 *** Special functions ***
00980 ************************/
00981 
00989 template<typename Scalar, int Dim, int Mode, int Options>
00990 const typename Transform<Scalar,Dim,Mode,Options>::LinearMatrixType
00991 Transform<Scalar,Dim,Mode,Options>::rotation() const
00992 {
00993   LinearMatrixType result;
00994   computeRotationScaling(&result, (LinearMatrixType*)0);
00995   return result;
00996 }
00997 
00998 
01010 template<typename Scalar, int Dim, int Mode, int Options>
01011 template<typename RotationMatrixType, typename ScalingMatrixType>
01012 void Transform<Scalar,Dim,Mode,Options>::computeRotationScaling(RotationMatrixType *rotation, ScalingMatrixType *scaling) const
01013 {
01014   JacobiSVD<LinearMatrixType> svd(linear(), ComputeFullU | ComputeFullV);
01015 
01016   Scalar x = (svd.matrixU() * svd.matrixV().adjoint()).determinant(); // so x has absolute value 1
01017   VectorType sv(svd.singularValues());
01018   sv.coeffRef(0) *= x;
01019   if(scaling) scaling->lazyAssign(svd.matrixV() * sv.asDiagonal() * svd.matrixV().adjoint());
01020   if(rotation)
01021   {
01022     LinearMatrixType m(svd.matrixU());
01023     m.col(0) /= x;
01024     rotation->lazyAssign(m * svd.matrixV().adjoint());
01025   }
01026 }
01027 
01039 template<typename Scalar, int Dim, int Mode, int Options>
01040 template<typename ScalingMatrixType, typename RotationMatrixType>
01041 void Transform<Scalar,Dim,Mode,Options>::computeScalingRotation(ScalingMatrixType *scaling, RotationMatrixType *rotation) const
01042 {
01043   JacobiSVD<LinearMatrixType> svd(linear(), ComputeFullU | ComputeFullV);
01044 
01045   Scalar x = (svd.matrixU() * svd.matrixV().adjoint()).determinant(); // so x has absolute value 1
01046   VectorType sv(svd.singularValues());
01047   sv.coeffRef(0) *= x;
01048   if(scaling) scaling->lazyAssign(svd.matrixU() * sv.asDiagonal() * svd.matrixU().adjoint());
01049   if(rotation)
01050   {
01051     LinearMatrixType m(svd.matrixU());
01052     m.col(0) /= x;
01053     rotation->lazyAssign(m * svd.matrixV().adjoint());
01054   }
01055 }
01056 
01060 template<typename Scalar, int Dim, int Mode, int Options>
01061 template<typename PositionDerived, typename OrientationType, typename ScaleDerived>
01062 Transform<Scalar,Dim,Mode,Options>&
01063 Transform<Scalar,Dim,Mode,Options>::fromPositionOrientationScale(const MatrixBase<PositionDerived> &position,
01064   const OrientationType& orientation, const MatrixBase<ScaleDerived> &scale)
01065 {
01066   linear() = internal::toRotationMatrix<Scalar,Dim>(orientation);
01067   linear() *= scale.asDiagonal();
01068   translation() = position;
01069   makeAffine();
01070   return *this;
01071 }
01072 
01073 namespace internal {
01074 
01075 // selector needed to avoid taking the inverse of a 3x4 matrix
01076 template<typename TransformType, int Mode=TransformType::Mode>
01077 struct projective_transform_inverse
01078 {
01079   static inline void run(const TransformType&, TransformType&)
01080   {}
01081 };
01082 
01083 template<typename TransformType>
01084 struct projective_transform_inverse<TransformType, Projective>
01085 {
01086   static inline void run(const TransformType& m, TransformType& res)
01087   {
01088     res.matrix() = m.matrix().inverse();
01089   }
01090 };
01091 
01092 } // end namespace internal
01093 
01094 
01115 template<typename Scalar, int Dim, int Mode, int Options>
01116 Transform<Scalar,Dim,Mode,Options>
01117 Transform<Scalar,Dim,Mode,Options>::inverse(TransformTraits hint) const
01118 {
01119   Transform res;
01120   if (hint == Projective)
01121   {
01122     internal::projective_transform_inverse<Transform>::run(*this, res);
01123   }
01124   else
01125   {
01126     if (hint == Isometry)
01127     {
01128       res.matrix().template topLeftCorner<Dim,Dim>() = linear().transpose();
01129     }
01130     else if(hint&Affine)
01131     {
01132       res.matrix().template topLeftCorner<Dim,Dim>() = linear().inverse();
01133     }
01134     else
01135     {
01136       eigen_assert(false && "Invalid transform traits in Transform::Inverse");
01137     }
01138     // translation and remaining parts
01139     res.matrix().template topRightCorner<Dim,1>()
01140       = - res.matrix().template topLeftCorner<Dim,Dim>() * translation();
01141     res.makeAffine(); // we do need this, because in the beginning res is uninitialized
01142   }
01143   return res;
01144 }
01145 
01146 namespace internal {
01147 
01148 /*****************************************************
01149 *** Specializations of take affine part            ***
01150 *****************************************************/
01151 
01152 template<typename TransformType> struct transform_take_affine_part {
01153   typedef typename TransformType::MatrixType MatrixType;
01154   typedef typename TransformType::AffinePart AffinePart;
01155   typedef typename TransformType::ConstAffinePart ConstAffinePart;
01156   static inline AffinePart run(MatrixType& m)
01157   { return m.template block<TransformType::Dim,TransformType::HDim>(0,0); }
01158   static inline ConstAffinePart run(const MatrixType& m)
01159   { return m.template block<TransformType::Dim,TransformType::HDim>(0,0); }
01160 };
01161 
01162 template<typename Scalar, int Dim, int Options>
01163 struct transform_take_affine_part<Transform<Scalar,Dim,AffineCompact, Options> > {
01164   typedef typename Transform<Scalar,Dim,AffineCompact,Options>::MatrixType MatrixType;
01165   static inline MatrixType& run(MatrixType& m) { return m; }
01166   static inline const MatrixType& run(const MatrixType& m) { return m; }
01167 };
01168 
01169 /*****************************************************
01170 *** Specializations of construct from matrix       ***
01171 *****************************************************/
01172 
01173 template<typename Other, int Mode, int Options, int Dim, int HDim>
01174 struct transform_construct_from_matrix<Other, Mode,Options,Dim,HDim, Dim,Dim>
01175 {
01176   static inline void run(Transform<typename Other::Scalar,Dim,Mode,Options> *transform, const Other& other)
01177   {
01178     transform->linear() = other;
01179     transform->translation().setZero();
01180     transform->makeAffine();
01181   }
01182 };
01183 
01184 template<typename Other, int Mode, int Options, int Dim, int HDim>
01185 struct transform_construct_from_matrix<Other, Mode,Options,Dim,HDim, Dim,HDim>
01186 {
01187   static inline void run(Transform<typename Other::Scalar,Dim,Mode,Options> *transform, const Other& other)
01188   {
01189     transform->affine() = other;
01190     transform->makeAffine();
01191   }
01192 };
01193 
01194 template<typename Other, int Mode, int Options, int Dim, int HDim>
01195 struct transform_construct_from_matrix<Other, Mode,Options,Dim,HDim, HDim,HDim>
01196 {
01197   static inline void run(Transform<typename Other::Scalar,Dim,Mode,Options> *transform, const Other& other)
01198   { transform->matrix() = other; }
01199 };
01200 
01201 template<typename Other, int Options, int Dim, int HDim>
01202 struct transform_construct_from_matrix<Other, AffineCompact,Options,Dim,HDim, HDim,HDim>
01203 {
01204   static inline void run(Transform<typename Other::Scalar,Dim,AffineCompact,Options> *transform, const Other& other)
01205   { transform->matrix() = other.template block<Dim,HDim>(0,0); }
01206 };
01207 
01208 /**********************************************************
01209 ***   Specializations of operator* with rhs EigenBase   ***
01210 **********************************************************/
01211 
01212 template<int LhsMode,int RhsMode>
01213 struct transform_product_result
01214 {
01215   enum 
01216   { 
01217     Mode =
01218       (LhsMode == (int)Projective    || RhsMode == (int)Projective    ) ? Projective :
01219       (LhsMode == (int)Affine        || RhsMode == (int)Affine        ) ? Affine :
01220       (LhsMode == (int)AffineCompact || RhsMode == (int)AffineCompact ) ? AffineCompact :
01221       (LhsMode == (int)Isometry      || RhsMode == (int)Isometry      ) ? Isometry : Projective
01222   };
01223 };
01224 
01225 template< typename TransformType, typename MatrixType >
01226 struct transform_right_product_impl< TransformType, MatrixType, 0 >
01227 {
01228   typedef typename MatrixType::PlainObject ResultType;
01229 
01230   static EIGEN_STRONG_INLINE ResultType run(const TransformType& T, const MatrixType& other)
01231   {
01232     return T.matrix() * other;
01233   }
01234 };
01235 
01236 template< typename TransformType, typename MatrixType >
01237 struct transform_right_product_impl< TransformType, MatrixType, 1 >
01238 {
01239   enum { 
01240     Dim = TransformType::Dim, 
01241     HDim = TransformType::HDim,
01242     OtherRows = MatrixType::RowsAtCompileTime,
01243     OtherCols = MatrixType::ColsAtCompileTime
01244   };
01245 
01246   typedef typename MatrixType::PlainObject ResultType;
01247 
01248   static EIGEN_STRONG_INLINE ResultType run(const TransformType& T, const MatrixType& other)
01249   {
01250     EIGEN_STATIC_ASSERT(OtherRows==HDim, YOU_MIXED_MATRICES_OF_DIFFERENT_SIZES);
01251 
01252     typedef Block<ResultType, Dim, OtherCols, int(MatrixType::RowsAtCompileTime)==Dim> TopLeftLhs;
01253 
01254     ResultType res(other.rows(),other.cols());
01255     TopLeftLhs(res, 0, 0, Dim, other.cols()).noalias() = T.affine() * other;
01256     res.row(OtherRows-1) = other.row(OtherRows-1);
01257     
01258     return res;
01259   }
01260 };
01261 
01262 template< typename TransformType, typename MatrixType >
01263 struct transform_right_product_impl< TransformType, MatrixType, 2 >
01264 {
01265   enum { 
01266     Dim = TransformType::Dim, 
01267     HDim = TransformType::HDim,
01268     OtherRows = MatrixType::RowsAtCompileTime,
01269     OtherCols = MatrixType::ColsAtCompileTime
01270   };
01271 
01272   typedef typename MatrixType::PlainObject ResultType;
01273 
01274   static EIGEN_STRONG_INLINE ResultType run(const TransformType& T, const MatrixType& other)
01275   {
01276     EIGEN_STATIC_ASSERT(OtherRows==Dim, YOU_MIXED_MATRICES_OF_DIFFERENT_SIZES);
01277 
01278     typedef Block<ResultType, Dim, OtherCols, true> TopLeftLhs;
01279     ResultType res(Replicate<typename TransformType::ConstTranslationPart, 1, OtherCols>(T.translation(),1,other.cols()));
01280     TopLeftLhs(res, 0, 0, Dim, other.cols()).noalias() += T.linear() * other;
01281 
01282     return res;
01283   }
01284 };
01285 
01286 /**********************************************************
01287 ***   Specializations of operator* with lhs EigenBase   ***
01288 **********************************************************/
01289 
01290 // generic HDim x HDim matrix * T => Projective
01291 template<typename Other,int Mode, int Options, int Dim, int HDim>
01292 struct transform_left_product_impl<Other,Mode,Options,Dim,HDim, HDim,HDim>
01293 {
01294   typedef Transform<typename Other::Scalar,Dim,Mode,Options> TransformType;
01295   typedef typename TransformType::MatrixType MatrixType;
01296   typedef Transform<typename Other::Scalar,Dim,Projective,Options> ResultType;
01297   static ResultType run(const Other& other,const TransformType& tr)
01298   { return ResultType(other * tr.matrix()); }
01299 };
01300 
01301 // generic HDim x HDim matrix * AffineCompact => Projective
01302 template<typename Other, int Options, int Dim, int HDim>
01303 struct transform_left_product_impl<Other,AffineCompact,Options,Dim,HDim, HDim,HDim>
01304 {
01305   typedef Transform<typename Other::Scalar,Dim,AffineCompact,Options> TransformType;
01306   typedef typename TransformType::MatrixType MatrixType;
01307   typedef Transform<typename Other::Scalar,Dim,Projective,Options> ResultType;
01308   static ResultType run(const Other& other,const TransformType& tr)
01309   {
01310     ResultType res;
01311     res.matrix().noalias() = other.template block<HDim,Dim>(0,0) * tr.matrix();
01312     res.matrix().col(Dim) += other.col(Dim);
01313     return res;
01314   }
01315 };
01316 
01317 // affine matrix * T
01318 template<typename Other,int Mode, int Options, int Dim, int HDim>
01319 struct transform_left_product_impl<Other,Mode,Options,Dim,HDim, Dim,HDim>
01320 {
01321   typedef Transform<typename Other::Scalar,Dim,Mode,Options> TransformType;
01322   typedef typename TransformType::MatrixType MatrixType;
01323   typedef TransformType ResultType;
01324   static ResultType run(const Other& other,const TransformType& tr)
01325   {
01326     ResultType res;
01327     res.affine().noalias() = other * tr.matrix();
01328     res.matrix().row(Dim) = tr.matrix().row(Dim);
01329     return res;
01330   }
01331 };
01332 
01333 // affine matrix * AffineCompact
01334 template<typename Other, int Options, int Dim, int HDim>
01335 struct transform_left_product_impl<Other,AffineCompact,Options,Dim,HDim, Dim,HDim>
01336 {
01337   typedef Transform<typename Other::Scalar,Dim,AffineCompact,Options> TransformType;
01338   typedef typename TransformType::MatrixType MatrixType;
01339   typedef TransformType ResultType;
01340   static ResultType run(const Other& other,const TransformType& tr)
01341   {
01342     ResultType res;
01343     res.matrix().noalias() = other.template block<Dim,Dim>(0,0) * tr.matrix();
01344     res.translation() += other.col(Dim);
01345     return res;
01346   }
01347 };
01348 
01349 // linear matrix * T
01350 template<typename Other,int Mode, int Options, int Dim, int HDim>
01351 struct transform_left_product_impl<Other,Mode,Options,Dim,HDim, Dim,Dim>
01352 {
01353   typedef Transform<typename Other::Scalar,Dim,Mode,Options> TransformType;
01354   typedef typename TransformType::MatrixType MatrixType;
01355   typedef TransformType ResultType;
01356   static ResultType run(const Other& other, const TransformType& tr)
01357   {
01358     TransformType res;
01359     if(Mode!=int(AffineCompact))
01360       res.matrix().row(Dim) = tr.matrix().row(Dim);
01361     res.matrix().template topRows<Dim>().noalias()
01362       = other * tr.matrix().template topRows<Dim>();
01363     return res;
01364   }
01365 };
01366 
01367 /**********************************************************
01368 *** Specializations of operator* with another Transform ***
01369 **********************************************************/
01370 
01371 template<typename Scalar, int Dim, int LhsMode, int LhsOptions, int RhsMode, int RhsOptions>
01372 struct transform_transform_product_impl<Transform<Scalar,Dim,LhsMode,LhsOptions>,Transform<Scalar,Dim,RhsMode,RhsOptions>,false >
01373 {
01374   enum { ResultMode = transform_product_result<LhsMode,RhsMode>::Mode };
01375   typedef Transform<Scalar,Dim,LhsMode,LhsOptions> Lhs;
01376   typedef Transform<Scalar,Dim,RhsMode,RhsOptions> Rhs;
01377   typedef Transform<Scalar,Dim,ResultMode,LhsOptions> ResultType;
01378   static ResultType run(const Lhs& lhs, const Rhs& rhs)
01379   {
01380     ResultType res;
01381     res.linear() = lhs.linear() * rhs.linear();
01382     res.translation() = lhs.linear() * rhs.translation() + lhs.translation();
01383     res.makeAffine();
01384     return res;
01385   }
01386 };
01387 
01388 template<typename Scalar, int Dim, int LhsMode, int LhsOptions, int RhsMode, int RhsOptions>
01389 struct transform_transform_product_impl<Transform<Scalar,Dim,LhsMode,LhsOptions>,Transform<Scalar,Dim,RhsMode,RhsOptions>,true >
01390 {
01391   typedef Transform<Scalar,Dim,LhsMode,LhsOptions> Lhs;
01392   typedef Transform<Scalar,Dim,RhsMode,RhsOptions> Rhs;
01393   typedef Transform<Scalar,Dim,Projective> ResultType;
01394   static ResultType run(const Lhs& lhs, const Rhs& rhs)
01395   {
01396     return ResultType( lhs.matrix() * rhs.matrix() );
01397   }
01398 };
01399 
01400 template<typename Scalar, int Dim, int LhsOptions, int RhsOptions>
01401 struct transform_transform_product_impl<Transform<Scalar,Dim,AffineCompact,LhsOptions>,Transform<Scalar,Dim,Projective,RhsOptions>,true >
01402 {
01403   typedef Transform<Scalar,Dim,AffineCompact,LhsOptions> Lhs;
01404   typedef Transform<Scalar,Dim,Projective,RhsOptions> Rhs;
01405   typedef Transform<Scalar,Dim,Projective> ResultType;
01406   static ResultType run(const Lhs& lhs, const Rhs& rhs)
01407   {
01408     ResultType res;
01409     res.matrix().template topRows<Dim>() = lhs.matrix() * rhs.matrix();
01410     res.matrix().row(Dim) = rhs.matrix().row(Dim);
01411     return res;
01412   }
01413 };
01414 
01415 template<typename Scalar, int Dim, int LhsOptions, int RhsOptions>
01416 struct transform_transform_product_impl<Transform<Scalar,Dim,Projective,LhsOptions>,Transform<Scalar,Dim,AffineCompact,RhsOptions>,true >
01417 {
01418   typedef Transform<Scalar,Dim,Projective,LhsOptions> Lhs;
01419   typedef Transform<Scalar,Dim,AffineCompact,RhsOptions> Rhs;
01420   typedef Transform<Scalar,Dim,Projective> ResultType;
01421   static ResultType run(const Lhs& lhs, const Rhs& rhs)
01422   {
01423     ResultType res(lhs.matrix().template leftCols<Dim>() * rhs.matrix());
01424     res.matrix().col(Dim) += lhs.matrix().col(Dim);
01425     return res;
01426   }
01427 };
01428 
01429 } // end namespace internal
01430 
01431 } // end namespace Eigen
01432 
01433 #endif // EIGEN_TRANSFORM_H