update Transform::inverse() to take an optional argument stating whether the transformation is:

NonAffine, Affine (default), contains NoShear, contains NoScaling
that allows significant speed improvements. If you like it, this concept could be applied to
Transform::extractRotation (or to a more advanced decomposition function) and to Hyperplane::transformed()
and maybe to some other places... e.g., I think a Transform::normalMatrix() function would not harm and
warn user that the transformation of normals is not that trivial (I saw this mistake much too often)
This commit is contained in:
Gael Guennebaud 2008-08-30 12:42:06 +00:00
parent 9e7a9cde14
commit 236b7a545d
6 changed files with 188 additions and 37 deletions

View File

@ -25,6 +25,7 @@ namespace Eigen {
// the Geometry module use cwiseCos and cwiseSin which are defined in the Array module // the Geometry module use cwiseCos and cwiseSin which are defined in the Array module
#include "src/Array/CwiseOperators.h" #include "src/Array/CwiseOperators.h"
#include "src/Array/Functors.h" #include "src/Array/Functors.h"
#include "src/Array/PartialRedux.h"
#include "src/Geometry/OrthoMethods.h" #include "src/Geometry/OrthoMethods.h"
#include "src/Geometry/Quaternion.h" #include "src/Geometry/Quaternion.h"

View File

@ -35,18 +35,23 @@
* \param _Dim the dimension of the space, can be a compile time value or Dynamic * \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<typename _Scalar, int _Dim> template<typename _Scalar, int _Dim>
class Scaling class Scaling
{ {
public: public:
/** dimension of the space */
enum { Dim = _Dim }; enum { Dim = _Dim };
/** the scalar type of the coefficients */ /** the scalar type of the coefficients */
typedef _Scalar Scalar; typedef _Scalar Scalar;
typedef Matrix<Scalar,Dim,Dim> LinearMatrixType; /** corresponding vector type */
typedef Matrix<Scalar,Dim,1> VectorType; typedef Matrix<Scalar,Dim,1> VectorType;
/** corresponding linear transformation matrix type */
typedef Matrix<Scalar,Dim,Dim> LinearMatrixType;
/** corresponding translation type */
typedef Translation<Scalar,Dim> TranslationType; typedef Translation<Scalar,Dim> TranslationType;
/** corresponding affine transformation type */
typedef Transform<Scalar,Dim> TransformType; typedef Transform<Scalar,Dim> TransformType;
protected: protected:

View File

@ -25,6 +25,14 @@
#ifndef EIGEN_TRANSFORM_H #ifndef EIGEN_TRANSFORM_H
#define 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 // 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 // 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. // specializations, it is not allowed to use Dim+1 instead of HDim.
@ -73,7 +81,9 @@ public:
typedef Matrix<Scalar,Dim,1> VectorType; typedef Matrix<Scalar,Dim,1> VectorType;
/** type of a read/write reference to the translation part of the rotation */ /** type of a read/write reference to the translation part of the rotation */
typedef Block<MatrixType,Dim,1> TranslationPart; typedef Block<MatrixType,Dim,1> TranslationPart;
/** corresponding translation type */
typedef Translation<Scalar,Dim> TranslationType; typedef Translation<Scalar,Dim> TranslationType;
/** corresponding scaling transformation type */
typedef Scaling<Scalar,Dim> ScalingType; typedef Scaling<Scalar,Dim> ScalingType;
protected: protected:
@ -193,8 +203,11 @@ public:
Transform& shear(Scalar sx, Scalar sy); Transform& shear(Scalar sx, Scalar sy);
Transform& preshear(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) { return translate(t.vector()); }
inline Transform operator*(const TranslationType& t) const; 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) { return scale(s.coeffs()); }
inline Transform operator*(const ScalingType& s) const; inline Transform operator*(const ScalingType& s) const;
friend inline Transform operator*(const LinearMatrixType& mat, const Transform& t) friend inline Transform operator*(const LinearMatrixType& mat, const Transform& t)
@ -212,9 +225,7 @@ public:
Transform& fromPositionOrientationScale(const MatrixBase<PositionDerived> &position, Transform& fromPositionOrientationScale(const MatrixBase<PositionDerived> &position,
const OrientationType& orientation, const MatrixBase<ScaleDerived> &scale); const OrientationType& orientation, const MatrixBase<ScaleDerived> &scale);
/** \sa MatrixBase::inverse() */ inline const MatrixType inverse(TransformationKnowledge knowledge = GenericAffine) const;
const MatrixType inverse() const
{ return m_matrix.inverse(); }
const Scalar* data() const { return m_matrix.data(); } const Scalar* data() const { return m_matrix.data(); }
Scalar* data() { return m_matrix.data(); } Scalar* data() { return m_matrix.data(); }
@ -232,6 +243,10 @@ typedef Transform<double,2> Transform2d;
/** \ingroup GeometryModule */ /** \ingroup GeometryModule */
typedef Transform<double,3> Transform3d; typedef Transform<double,3> Transform3d;
/**************************
*** Optional QT support ***
**************************/
#ifdef EIGEN_QT_SUPPORT #ifdef EIGEN_QT_SUPPORT
/** Initialises \c *this from a QMatrix assuming the dimension is 2. /** Initialises \c *this from a QMatrix assuming the dimension is 2.
* *
@ -271,6 +286,10 @@ QMatrix Transform<Scalar,Dim>::toQMatrix(void) const
} }
#endif #endif
/*********************
*** Procedural API ***
*********************/
/** Applies on the right the non uniform scale transformation represented /** 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. * by the vector \a other to \c *this and returns a reference to \c *this.
* \sa prescale() * \sa prescale()
@ -399,6 +418,18 @@ Transform<Scalar,Dim>::preshear(Scalar sx, Scalar sy)
return *this; return *this;
} }
/******************************************************
*** Scaling, Translation and Rotation compatibility ***
******************************************************/
template<typename Scalar, int Dim>
inline Transform<Scalar,Dim>& Transform<Scalar,Dim>::operator=(const TranslationType& t)
{
setIdentity();
translation() = t.vector();
return *this;
}
template<typename Scalar, int Dim> template<typename Scalar, int Dim>
inline Transform<Scalar,Dim> Transform<Scalar,Dim>::operator*(const TranslationType& t) const inline Transform<Scalar,Dim> Transform<Scalar,Dim>::operator*(const TranslationType& t) const
{ {
@ -407,6 +438,15 @@ inline Transform<Scalar,Dim> Transform<Scalar,Dim>::operator*(const TranslationT
return res; return res;
} }
template<typename Scalar, int Dim>
inline Transform<Scalar,Dim>& Transform<Scalar,Dim>::operator=(const ScalingType& s)
{
m_matrix.setZero();
linear().diagonal() = s.coeffs();
m_matrix(Dim,Dim) = Scalar(1);
return *this;
}
template<typename Scalar, int Dim> template<typename Scalar, int Dim>
inline Transform<Scalar,Dim> Transform<Scalar,Dim>::operator*(const ScalingType& s) const inline Transform<Scalar,Dim> Transform<Scalar,Dim>::operator*(const ScalingType& s) const
{ {
@ -415,6 +455,10 @@ inline Transform<Scalar,Dim> Transform<Scalar,Dim>::operator*(const ScalingType&
return res; return res;
} }
/***************************
*** Specialial functions ***
***************************/
/** \returns the rotation part of the transformation using a QR decomposition. /** \returns the rotation part of the transformation using a QR decomposition.
* \sa extractRotationNoShear(), class QR * \sa extractRotationNoShear(), class QR
*/ */
@ -454,6 +498,65 @@ Transform<Scalar,Dim>::fromPositionOrientationScale(const MatrixBase<PositionDer
return *this; return *this;
} }
/** \returns the inverse transformation matrix according to some given knowledge
* on \c *this.
*
* \param knowledge allozs to optimize the inversion process when the transformion
* is known to be not a general transformation. The possible values are:
* - NonAffine if the transformation is not necessarily affines, i.e., if the
* last row is not guaranteed to be [0 ... 0 1]
* - GenericAffine is the default, the last row is assumed to be [0 ... 0 1]
* - NoShear if the transformation is only a concatenations of translations,
* rotations, and scalings.
* - NoScaling if the transformation is only a concatenations of translations
* and rotations.
*
* \sa MatrixBase::inverse()
*/
template<typename Scalar, int Dim>
inline const typename Transform<Scalar,Dim>::MatrixType
Transform<Scalar,Dim>::inverse(TransformationKnowledge knowledge) const
{
if (knowledge == NonAffine)
{
return m_matrix.inverse();
}
else
{
MatrixType res;
if (knowledge == GenericAffine)
{
res.template corner<Dim,Dim>(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<Dim,Dim>(TopLeft) = (invScaling2.asDiagonal() * linear().transpose()).lazy();
}
else if (knowledge == NoScaling)
{
res.template corner<Dim,Dim>(TopLeft) = linear().transpose();
}
else
{
ei_assert("invalid knowledge value in Transform::inverse()");
}
// translation and remaining parts
res.template corner<Dim,1>(TopRight) = - res.template corner<Dim,Dim>(TopLeft) * translation();
res.template corner<1,Dim>(BottomLeft).setZero();
res.coeffRef(Dim,Dim) = Scalar(1);
return res;
}
}
/*********************************** /***********************************
*** Specializations of operator* *** *** Specializations of operator* ***
***********************************/ ***********************************/

View File

@ -41,12 +41,17 @@ template<typename _Scalar, int _Dim>
class Translation class Translation
{ {
public: public:
/** dimension of the space */
enum { Dim = _Dim }; enum { Dim = _Dim };
/** the scalar type of the coefficients */ /** the scalar type of the coefficients */
typedef _Scalar Scalar; typedef _Scalar Scalar;
typedef Matrix<Scalar,Dim,Dim> LinearMatrixType; /** corresponding vector type */
typedef Matrix<Scalar,Dim,1> VectorType; typedef Matrix<Scalar,Dim,1> VectorType;
/** corresponding linear transformation matrix type */
typedef Matrix<Scalar,Dim,Dim> LinearMatrixType;
/** corresponding scaling transformation type */
typedef Scaling<Scalar,Dim> ScalingType; typedef Scaling<Scalar,Dim> ScalingType;
/** corresponding affine transformation type */
typedef Transform<Scalar,Dim> TransformType; typedef Transform<Scalar,Dim> TransformType;
protected: protected:

View File

@ -569,8 +569,8 @@ m = AngleAxisf(angle1, Vector3f::UnitZ())
<a href="#" class="top">top</a>\section TutorialGeoTransformation Affine transformations <a href="#" class="top">top</a>\section TutorialGeoTransformation Affine transformations
In Eigen we have chosen to not distinghish between points and vectors such that all points are 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, actually represented by displacement vectors from the origine ( \f$ \mathbf{p} \equiv \mathbf{p}-0 \f$ ).
real points and vector distinguish when the rotation is applied. With that in mind, real points and vector distinguish when the rotation is applied.
<table class="tutorial_code"> <table class="tutorial_code">
<tr><td></td><td>\b 3D </td><td>\b 2D </td></tr> <tr><td></td><td>\b 3D </td><td>\b 2D </td></tr>
<tr><td>Creation \n <span class="note">rot2D can also be an angle in radian</span></td><td>\code <tr><td>Creation \n <span class="note">rot2D can also be an angle in radian</span></td><td>\code
@ -606,6 +606,17 @@ aux.linear().corner<2,2>(TopLeft) = t.linear();
aux.translation().start<2>() = t.translation(); aux.translation().start<2>() = t.translation();
glLoadMatrixf(aux.data());\endcode</td></tr> glLoadMatrixf(aux.data());\endcode</td></tr>
<tr><td colspan="3">\b Component \b accessors</td></tr> <tr><td colspan="3">\b Component \b accessors</td></tr>
<tr><td>full read-write access to the internal matrix</td><td>\code
t.matrix() = mat4x4;
mat4x4 = t.matrix();
\endcode</td><td>\code
t.matrix() = mat3x3;
mat3x3 = t.matrix();
\endcode</td></tr>
<tr><td>coefficient accessors</td><td colspan="2">\code
t(i,j) = scalar; <=> t.matrix()(i,j) = scalar;
scalar = t(i,j); <=> scalar = t.matrix()(i,j);
\endcode</td></tr>
<tr><td>translation part</td><td>\code <tr><td>translation part</td><td>\code
t.translation() = vec3; t.translation() = vec3;
vec3 = t.translation(); vec3 = t.translation();
@ -620,36 +631,50 @@ mat3x3 = t.linear();
t.linear() = mat2x2; t.linear() = mat2x2;
mat2x2 = t.linear(); mat2x2 = t.linear();
\endcode</td></tr> \endcode</td></tr>
<tr><td colspan="3">\b Editing \b shortcuts</td></tr>
<tr><td>Applies a translation</td><td>\code
t.translate(Vector3f(tx, ty, tz));
t.pretranslate(Vector3f(tx, ty, tz));
\endcode</td><td>\code
t.translate(Vector2f(tx, ty));
t.pretranslate(Vector2f(tx, ty));
\endcode</td></tr>
<tr><td>Applies a rotation \n <span class="note">rot2D can also be an angle in radian</span></td><td>\code
t.rotate(rot3D);
t.prerotate(rot3D);
\endcode</td><td>\code
t.rotate(rot2D);
t.prerotate(rot2D);
\endcode</td></tr>
<tr><td>Applies a scaling</td><td>\code
t.scale(Vector3f(sx, sy, sz));
t.scale(Vector3f::Constant(s));
t.prescale(Vector3f(sx, sy, sz));
\endcode</td><td>\code
t.scale(Vector2f(sx, sy));
t.scale(Vector2f::Constant(s));
t.prescale(Vector2f(sx, sy));
\endcode</td></tr>
<tr><td>Applies a shear transformation \n(2D only)</td><td></td><td>\code
t.shear(sx,sy);
t.preshear(sx,sy);
\endcode</td></tr>
</table> </table>
\b Transformation \b creation \n
Eigen's geometry module offer two different ways to build and update transformation objects.
<table class="tutorial_code">
<tr><td></td><td>\b procedurale \b API </td><td>\b natural \b API </td></tr>
<tr><td>Applies a translation</td><td>\code
t.translate(Vector3(tx, ty, ...));
t.pretranslate(Vector3(tx, ty, ...));
\endcode</td><td>\code
t *= Translation(tx, ty, ...);
t = Translation(tx, ty, ...) * t;
\endcode</td></tr>
<tr><td>Applies a rotation \n <span class="note">In 2D, any_rotation can also be \n an angle in radian</span></td><td>\code
t.rotate(any_rotation);
t.prerotate(any_rotation);
\endcode</td><td>\code
t *= any_rotation;
t = any_rotation * t;
\endcode</td></tr>
<tr><td>Applies a scaling</td><td>\code
t.scale(Vector(sx, sy, ...));
t.scale(Vector::Constant(s));
t.prescale(Vector3f(sx, sy, ...));
\endcode</td><td>\code
t *= Scaling(sx, sy, ...);
t *= Scaling(s);
t = Scaling(sx, sy, ...) * t;
\endcode</td></tr>
<tr><td>Applies a shear transformation \n ( \b 2D \b only ! )</td><td>\code
t.shear(sx,sy);
t.preshear(sx,sy);
\endcode</td><td></td></tr>
</table>
Note that in both API, any many transformations can be concatenated in a single lines as shown in the two following equivalent examples:
<table class="tutorial_code">
<tr><td>\code
t.pretranslate(..).rotate(..).translate(..).scale(..);
\endcode</td></tr>
<tr><td>\code
t = Translation(..) * t * RotationType(..) * Translation(..) * Scaling(..);
\endcode</td></tr>
</table>
*/ */

View File

@ -219,12 +219,24 @@ template<typename Scalar> void geometry(void)
t0.setIdentity(); t0.setIdentity();
t0.scale(v0); t0.scale(v0);
VERIFY_IS_APPROX(t0 * v1, Scaling3(v0) * v1); 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() void test_geometry()
{ {
for(int i = 0; i < g_repeat; i++) { for(int i = 0; i < g_repeat; i++) {
CALL_SUBTEST( geometry<float>() ); CALL_SUBTEST( geometry<float>() );
// CALL_SUBTEST( geometry<double>() ); CALL_SUBTEST( geometry<double>() );
} }
} }