diff --git a/Eigen/Geometry b/Eigen/Geometry index b5037306d..ab3a9b9d6 100644 --- a/Eigen/Geometry +++ b/Eigen/Geometry @@ -25,6 +25,7 @@ namespace Eigen { // the Geometry module use cwiseCos and cwiseSin which are defined in the Array module #include "src/Array/CwiseOperators.h" #include "src/Array/Functors.h" +#include "src/Array/PartialRedux.h" #include "src/Geometry/OrthoMethods.h" #include "src/Geometry/Quaternion.h" diff --git a/Eigen/src/Geometry/Scaling.h b/Eigen/src/Geometry/Scaling.h index fcf1c0437..73938ac8b 100644 --- a/Eigen/src/Geometry/Scaling.h +++ b/Eigen/src/Geometry/Scaling.h @@ -35,18 +35,23 @@ * \param _Dim the dimension of the space, can be a compile time value or Dynamic * * - * \sa class Translate, class Transform + * \sa class Translation, class Transform */ template class Scaling { public: + /** dimension of the space */ enum { Dim = _Dim }; /** the scalar type of the coefficients */ typedef _Scalar Scalar; - typedef Matrix LinearMatrixType; + /** corresponding vector type */ typedef Matrix VectorType; + /** corresponding linear transformation matrix type */ + typedef Matrix LinearMatrixType; + /** corresponding translation type */ typedef Translation TranslationType; + /** corresponding affine transformation type */ typedef Transform TransformType; protected: diff --git a/Eigen/src/Geometry/Transform.h b/Eigen/src/Geometry/Transform.h index f32577e88..fd5fd66ba 100644 --- a/Eigen/src/Geometry/Transform.h +++ b/Eigen/src/Geometry/Transform.h @@ -25,6 +25,14 @@ #ifndef EIGEN_TRANSFORM_H #define EIGEN_TRANSFORM_H +/** Represents some traits of a transformation */ +enum TransformationKnowledge { + NoScaling, ///< the transformation is a concatenation of translations, rotations + NoShear, ///< the transformation is a concatenation of translations, rotations and scalings + GenericAffine, ///< the transformation is affine (linear transformation + translation) + NonAffine ///< the transformation might not be affine +}; + // Note that we have to pass Dim and HDim because it is not allowed to use a template // parameter to define a template specialization. To be more precise, in the following // specializations, it is not allowed to use Dim+1 instead of HDim. @@ -73,7 +81,9 @@ public: typedef Matrix VectorType; /** type of a read/write reference to the translation part of the rotation */ typedef Block TranslationPart; + /** corresponding translation type */ typedef Translation TranslationType; + /** corresponding scaling transformation type */ typedef Scaling ScalingType; protected: @@ -193,8 +203,11 @@ public: Transform& shear(Scalar sx, Scalar sy); Transform& preshear(Scalar sx, Scalar sy); + inline Transform& operator=(const TranslationType& t); inline Transform& operator*=(const TranslationType& t) { return translate(t.vector()); } inline Transform operator*(const TranslationType& t) const; + + inline Transform& operator=(const ScalingType& t); inline Transform& operator*=(const ScalingType& s) { return scale(s.coeffs()); } inline Transform operator*(const ScalingType& s) const; friend inline Transform operator*(const LinearMatrixType& mat, const Transform& t) @@ -212,9 +225,7 @@ public: Transform& fromPositionOrientationScale(const MatrixBase &position, const OrientationType& orientation, const MatrixBase &scale); - /** \sa MatrixBase::inverse() */ - const MatrixType inverse() const - { return m_matrix.inverse(); } + inline const MatrixType inverse(TransformationKnowledge knowledge = GenericAffine) const; const Scalar* data() const { return m_matrix.data(); } Scalar* data() { return m_matrix.data(); } @@ -232,6 +243,10 @@ typedef Transform Transform2d; /** \ingroup GeometryModule */ typedef Transform Transform3d; +/************************** +*** Optional QT support *** +**************************/ + #ifdef EIGEN_QT_SUPPORT /** Initialises \c *this from a QMatrix assuming the dimension is 2. * @@ -271,6 +286,10 @@ QMatrix Transform::toQMatrix(void) const } #endif +/********************* +*** Procedural API *** +*********************/ + /** Applies on the right the non uniform scale transformation represented * by the vector \a other to \c *this and returns a reference to \c *this. * \sa prescale() @@ -399,6 +418,18 @@ Transform::preshear(Scalar sx, Scalar sy) return *this; } +/****************************************************** +*** Scaling, Translation and Rotation compatibility *** +******************************************************/ + +template +inline Transform& Transform::operator=(const TranslationType& t) +{ + setIdentity(); + translation() = t.vector(); + return *this; +} + template inline Transform Transform::operator*(const TranslationType& t) const { @@ -407,6 +438,15 @@ inline Transform Transform::operator*(const TranslationT return res; } +template +inline Transform& Transform::operator=(const ScalingType& s) +{ + m_matrix.setZero(); + linear().diagonal() = s.coeffs(); + m_matrix(Dim,Dim) = Scalar(1); + return *this; +} + template inline Transform Transform::operator*(const ScalingType& s) const { @@ -415,6 +455,10 @@ inline Transform Transform::operator*(const ScalingType& return res; } +/*************************** +*** Specialial functions *** +***************************/ + /** \returns the rotation part of the transformation using a QR decomposition. * \sa extractRotationNoShear(), class QR */ @@ -454,6 +498,65 @@ Transform::fromPositionOrientationScale(const MatrixBase +inline const typename Transform::MatrixType +Transform::inverse(TransformationKnowledge knowledge) const +{ + if (knowledge == NonAffine) + { + return m_matrix.inverse(); + } + else + { + MatrixType res; + if (knowledge == GenericAffine) + { + res.template corner(TopLeft) = linear().inverse(); + } + else if (knowledge == NoShear) + { + // extract linear = rotation * scaling + // then inv(linear) = inv(scaling) * inv(rotation) + // = inv(scaling) * trans(rotation) + // = inv(scaling) * trans(inv(scaling)) * trans(A) + // = inv(scaling) * inv(scaling) * trans(A) + // = inv(scaling)^2 * trans(A) + // = scaling^-2 * trans(A) + // with scaling[i] = A.col(i).norm() + VectorType invScaling2 = linear().colwise().norm2().cwise().inverse(); + res.template corner(TopLeft) = (invScaling2.asDiagonal() * linear().transpose()).lazy(); + } + else if (knowledge == NoScaling) + { + res.template corner(TopLeft) = linear().transpose(); + } + else + { + ei_assert("invalid knowledge value in Transform::inverse()"); + } + // translation and remaining parts + res.template corner(TopRight) = - res.template corner(TopLeft) * translation(); + res.template corner<1,Dim>(BottomLeft).setZero(); + res.coeffRef(Dim,Dim) = Scalar(1); + return res; + } +} + /*********************************** *** Specializations of operator* *** ***********************************/ diff --git a/Eigen/src/Geometry/Translation.h b/Eigen/src/Geometry/Translation.h index ad63b835f..b65aca9eb 100644 --- a/Eigen/src/Geometry/Translation.h +++ b/Eigen/src/Geometry/Translation.h @@ -41,12 +41,17 @@ template class Translation { public: + /** dimension of the space */ enum { Dim = _Dim }; /** the scalar type of the coefficients */ typedef _Scalar Scalar; - typedef Matrix LinearMatrixType; + /** corresponding vector type */ typedef Matrix VectorType; + /** corresponding linear transformation matrix type */ + typedef Matrix LinearMatrixType; + /** corresponding scaling transformation type */ typedef Scaling ScalingType; + /** corresponding affine transformation type */ typedef Transform TransformType; protected: diff --git a/doc/QuickStartGuide.dox b/doc/QuickStartGuide.dox index 62be8ec21..cf37f02be 100644 --- a/doc/QuickStartGuide.dox +++ b/doc/QuickStartGuide.dox @@ -569,8 +569,8 @@ m = AngleAxisf(angle1, Vector3f::UnitZ()) top\section TutorialGeoTransformation Affine transformations In Eigen we have chosen to not distinghish between points and vectors such that all points are -actually represented by displacement vector from the origine (pt \~ pt-0). With that in mind, -real points and vector distinguish when the rotation is applied. +actually represented by displacement vectors from the origine ( \f$ \mathbf{p} \equiv \mathbf{p}-0 \f$ ). +With that in mind, real points and vector distinguish when the rotation is applied. + + - - - - -
\b 3D \b 2D
Creation \n rot2D can also be an angle in radian\code @@ -606,6 +606,17 @@ aux.linear().corner<2,2>(TopLeft) = t.linear(); aux.translation().start<2>() = t.translation(); glLoadMatrixf(aux.data());\endcode
\b Component \b accessors
full read-write access to the internal matrix\code +t.matrix() = mat4x4; +mat4x4 = t.matrix(); +\endcode\code +t.matrix() = mat3x3; +mat3x3 = t.matrix(); +\endcode
coefficient accessors\code +t(i,j) = scalar; <=> t.matrix()(i,j) = scalar; +scalar = t(i,j); <=> scalar = t.matrix()(i,j); +\endcode
translation part\code t.translation() = vec3; vec3 = t.translation(); @@ -620,36 +631,50 @@ mat3x3 = t.linear(); t.linear() = mat2x2; mat2x2 = t.linear(); \endcode
\b Editing \b shortcuts
Applies a translation\code -t.translate(Vector3f(tx, ty, tz)); -t.pretranslate(Vector3f(tx, ty, tz)); -\endcode\code -t.translate(Vector2f(tx, ty)); -t.pretranslate(Vector2f(tx, ty)); -\endcode
Applies a rotation \n rot2D can also be an angle in radian\code -t.rotate(rot3D); -t.prerotate(rot3D); -\endcode\code -t.rotate(rot2D); -t.prerotate(rot2D); -\endcode
Applies a scaling\code -t.scale(Vector3f(sx, sy, sz)); -t.scale(Vector3f::Constant(s)); -t.prescale(Vector3f(sx, sy, sz)); -\endcode\code -t.scale(Vector2f(sx, sy)); -t.scale(Vector2f::Constant(s)); -t.prescale(Vector2f(sx, sy)); -\endcode
Applies a shear transformation \n(2D only)\code -t.shear(sx,sy); -t.preshear(sx,sy); -\endcode
+\b Transformation \b creation \n +Eigen's geometry module offer two different ways to build and update transformation objects. + + + + + + +
\b procedurale \b API \b natural \b API
Applies a translation\code +t.translate(Vector3(tx, ty, ...)); +t.pretranslate(Vector3(tx, ty, ...)); +\endcode\code +t *= Translation(tx, ty, ...); +t = Translation(tx, ty, ...) * t; +\endcode
Applies a rotation \n In 2D, any_rotation can also be \n an angle in radian\code +t.rotate(any_rotation); +t.prerotate(any_rotation); +\endcode\code +t *= any_rotation; +t = any_rotation * t; +\endcode
Applies a scaling\code +t.scale(Vector(sx, sy, ...)); +t.scale(Vector::Constant(s)); +t.prescale(Vector3f(sx, sy, ...)); +\endcode\code +t *= Scaling(sx, sy, ...); +t *= Scaling(s); +t = Scaling(sx, sy, ...) * t; +\endcode
Applies a shear transformation \n ( \b 2D \b only ! )\code +t.shear(sx,sy); +t.preshear(sx,sy); +\endcode
+ +Note that in both API, any many transformations can be concatenated in a single lines as shown in the two following equivalent examples: + + + +
\code +t.pretranslate(..).rotate(..).translate(..).scale(..); +\endcode
\code +t = Translation(..) * t * RotationType(..) * Translation(..) * Scaling(..); +\endcode
*/ diff --git a/test/geometry.cpp b/test/geometry.cpp index af9accb63..7b9784134 100644 --- a/test/geometry.cpp +++ b/test/geometry.cpp @@ -219,12 +219,24 @@ template void geometry(void) t0.setIdentity(); t0.scale(v0); VERIFY_IS_APPROX(t0 * v1, Scaling3(v0) * v1); + + // test transform inversion + t0.setIdentity(); + t0.translate(v0); + t0.linear().setRandom(); + VERIFY_IS_APPROX(t0.inverse(GenericAffine), t0.matrix().inverse()); + t0.setIdentity(); + t0.translate(v0).rotate(q1).scale(v1); + VERIFY_IS_APPROX(t0.inverse(NoShear), t0.matrix().inverse()); + t0.setIdentity(); + t0.translate(v0).rotate(q1); + VERIFY_IS_APPROX(t0.inverse(NoScaling), t0.matrix().inverse()); } void test_geometry() { for(int i = 0; i < g_repeat; i++) { CALL_SUBTEST( geometry() ); -// CALL_SUBTEST( geometry() ); + CALL_SUBTEST( geometry() ); } }