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