remove the conceptualy broken "NoShear" transformation traits,

and rename NonAfine => Projective, GenericAffine => Affine, NoScaling => Isometry
This commit is contained in:
Gael Guennebaud 2008-09-01 17:14:34 +00:00
parent 6825c8dd6b
commit 49ff9b204c
4 changed files with 26 additions and 62 deletions

View File

@ -229,14 +229,11 @@ class Hyperplane
} }
template<typename XprType> template<typename XprType>
inline Hyperplane& transform(const MatrixBase<XprType>& mat, TransformTraits traits = GenericAffine) inline Hyperplane& transform(const MatrixBase<XprType>& mat, TransformTraits traits = Affine)
{ {
if (traits==GenericAffine) if (traits==Affine)
normal() = mat.inverse().transpose() * normal(); normal() = mat.inverse().transpose() * normal();
else if (traits==NoShear) else if (traits==Isometry)
normal() = (mat.colwise().norm2().cwise().inverse().eval().asDiagonal()
* mat.transpose()).transpose() * normal();
else if (traits==NoScaling)
normal() = mat * normal(); normal() = mat * normal();
else else
{ {
@ -246,7 +243,7 @@ class Hyperplane
} }
inline Hyperplane& transform(const Transform<Scalar,AmbientDimAtCompileTime>& t, inline Hyperplane& transform(const Transform<Scalar,AmbientDimAtCompileTime>& t,
TransformTraits traits = GenericAffine) TransformTraits traits = Affine)
{ {
transform(t.linear(), traits); transform(t.linear(), traits);
offset() -= t.translation().dot(normal()); offset() -= t.translation().dot(normal());

View File

@ -27,10 +27,9 @@
/** Represents some traits of a transformation */ /** Represents some traits of a transformation */
enum TransformTraits { enum TransformTraits {
NoScaling, ///< the transformation is a concatenation of translations, rotations Isometry, ///< the transformation is a concatenation of translations and rotations
NoShear, ///< the transformation is a concatenation of translations, rotations and scalings Affine, ///< the transformation is affine (linear transformation + translation)
GenericAffine, ///< the transformation is affine (linear transformation + translation) Projective ///< the transformation might not be affine
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
@ -231,13 +230,13 @@ public:
template<typename Derived> template<typename Derived>
inline Transform operator*(const RotationBase<Derived,Dim>& r) const; inline Transform operator*(const RotationBase<Derived,Dim>& r) const;
LinearMatrixType extractRotation(TransformTraits traits = GenericAffine) const; LinearMatrixType extractRotation(TransformTraits traits = Affine) const;
template<typename PositionDerived, typename OrientationType, typename ScaleDerived> template<typename PositionDerived, typename OrientationType, typename ScaleDerived>
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);
inline const MatrixType inverse(TransformTraits traits = GenericAffine) const; inline const MatrixType inverse(TransformTraits traits = Affine) const;
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(); }
@ -545,9 +544,8 @@ inline Transform<Scalar,Dim> Transform<Scalar,Dim>::operator*(const RotationBase
* *
* \param traits allows to optimize the extraction process when the transformion * \param traits allows to optimize the extraction process when the transformion
* is known to be not a general aafine transformation. The possible values are: * is known to be not a general aafine transformation. The possible values are:
* - GenericAffine which use a QR decomposition (default), * - Affine which use a QR decomposition (default),
* - NoShear which is the most probable case and very fast, * - Isometry which simply returns the linear part !
* - NoScaling which simply returns the linear part !
* *
* \warning this function consider the scaling is positive * \warning this function consider the scaling is positive
* *
@ -560,8 +558,8 @@ template<typename Scalar, int Dim>
typename Transform<Scalar,Dim>::LinearMatrixType typename Transform<Scalar,Dim>::LinearMatrixType
Transform<Scalar,Dim>::extractRotation(TransformTraits traits) const Transform<Scalar,Dim>::extractRotation(TransformTraits traits) const
{ {
ei_assert(traits!=NonAffine && "you cannot extract a rotation from a non affine transformation"); ei_assert(traits!=Projective && "you cannot extract a rotation from a non affine transformation");
if (traits == GenericAffine) if (traits == Affine)
{ {
// FIXME maybe QR should be fixed to return a R matrix with a positive diagonal ?? // FIXME maybe QR should be fixed to return a R matrix with a positive diagonal ??
QR<LinearMatrixType> qr(linear()); QR<LinearMatrixType> qr(linear());
@ -572,18 +570,11 @@ Transform<Scalar,Dim>::extractRotation(TransformTraits traits) const
matQ.col(i) = -matQ.col(i); matQ.col(i) = -matQ.col(i);
return matQ; return matQ;
} }
else if (traits == NoShear) else if (traits == Isometry) // though that's stupid let's handle it !
{
// extract linear = rotation * scaling
// => rotation = linear * inv(Scaling)
VectorType invScaling = linear().colwise().norm().cwise().inverse();
return linear() * invScaling.asDiagonal();
}
else if (traits == NoScaling) // though that's stupid let's handle it !
return linear(); return linear();
else else
{ {
ei_assert("invalid traits value in Transform::inverse()"); ei_assert("invalid traits value in Transform::extractRotation()");
return LinearMatrixType(); return LinearMatrixType();
} }
} }
@ -610,12 +601,10 @@ Transform<Scalar,Dim>::fromPositionOrientationScale(const MatrixBase<PositionDer
* *
* \param traits allows to optimize the inversion process when the transformion * \param traits allows to optimize the inversion process when the transformion
* is known to be not a general transformation. The possible values are: * is known to be not a general transformation. The possible values are:
* - NonAffine if the transformation is not necessarily affines, i.e., if the * - Projective if the transformation is not necessarily affine, i.e., if the
* last row is not guaranteed to be [0 ... 0 1] * last row is not guaranteed to be [0 ... 0 1]
* - GenericAffine is the default, the last row is assumed to be [0 ... 0 1] * - Affine is the default, the last row is assumed to be [0 ... 0 1]
* - NoShear if the transformation is only a concatenations of translations, * - Isometry if the transformation is only a concatenations of translations
* rotations, and scalings.
* - NoScaling if the transformation is only a concatenations of translations
* and rotations. * and rotations.
* *
* \warning unless \a traits is always set to NoShear or NoScaling, this function * \warning unless \a traits is always set to NoShear or NoScaling, this function
@ -628,31 +617,18 @@ template<typename Scalar, int Dim>
inline const typename Transform<Scalar,Dim>::MatrixType inline const typename Transform<Scalar,Dim>::MatrixType
Transform<Scalar,Dim>::inverse(TransformTraits traits) const Transform<Scalar,Dim>::inverse(TransformTraits traits) const
{ {
if (traits == NonAffine) if (traits == Projective)
{ {
return m_matrix.inverse(); return m_matrix.inverse();
} }
else else
{ {
MatrixType res; MatrixType res;
if (traits == GenericAffine) if (traits == Affine)
{ {
res.template corner<Dim,Dim>(TopLeft) = linear().inverse(); res.template corner<Dim,Dim>(TopLeft) = linear().inverse();
} }
else if (traits == NoShear) else if (traits == Isometry)
{
// 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 (traits == NoScaling)
{ {
res.template corner<Dim,Dim>(TopLeft) = linear().transpose(); res.template corner<Dim,Dim>(TopLeft) = linear().transpose();
} }

View File

@ -265,19 +265,15 @@ template<typename Scalar> void geometry(void)
t0.setIdentity(); t0.setIdentity();
t0.translate(v0); t0.translate(v0);
t0.linear().setRandom(); t0.linear().setRandom();
VERIFY_IS_APPROX(t0.inverse(GenericAffine), t0.matrix().inverse()); VERIFY_IS_APPROX(t0.inverse(Affine), t0.matrix().inverse());
t0.setIdentity();
t0.translate(v0).rotate(q1).scale(v1);
VERIFY_IS_APPROX(t0.inverse(NoShear), t0.matrix().inverse());
t0.setIdentity(); t0.setIdentity();
t0.translate(v0).rotate(q1); t0.translate(v0).rotate(q1);
VERIFY_IS_APPROX(t0.inverse(NoScaling), t0.matrix().inverse()); VERIFY_IS_APPROX(t0.inverse(Isometry), t0.matrix().inverse());
// test extract rotation // test extract rotation
t0.setIdentity(); t0.setIdentity();
t0.translate(v0).rotate(q1).scale(v1); t0.translate(v0).rotate(q1).scale(v1);
VERIFY_IS_APPROX(t0.extractRotation(GenericAffine) * v1, Matrix3(q1) * v1); VERIFY_IS_APPROX(t0.extractRotation(Affine) * v1, Matrix3(q1) * v1);
VERIFY_IS_APPROX(t0.extractRotation(NoShear) * v1, Matrix3(q1) * v1);
} }
void test_geometry() void test_geometry()

View File

@ -71,19 +71,14 @@ template<typename HyperplaneType> void hyperplane(const HyperplaneType& _plane)
pl2 = pl1; pl2 = pl1;
VERIFY_IS_MUCH_SMALLER_THAN( pl2.transform(rot).absDistance(rot * p1), Scalar(1) ); VERIFY_IS_MUCH_SMALLER_THAN( pl2.transform(rot).absDistance(rot * p1), Scalar(1) );
pl2 = pl1; pl2 = pl1;
VERIFY_IS_MUCH_SMALLER_THAN( pl2.transform(rot,NoScaling).absDistance(rot * p1), Scalar(1) ); VERIFY_IS_MUCH_SMALLER_THAN( pl2.transform(rot,Isometry).absDistance(rot * p1), Scalar(1) );
pl2 = pl1; pl2 = pl1;
VERIFY_IS_MUCH_SMALLER_THAN( pl2.transform(rot*scaling).absDistance((rot*scaling) * p1), Scalar(1) ); VERIFY_IS_MUCH_SMALLER_THAN( pl2.transform(rot*scaling).absDistance((rot*scaling) * p1), Scalar(1) );
pl2 = pl1; pl2 = pl1;
VERIFY_IS_MUCH_SMALLER_THAN( pl2.transform(rot*scaling, NoShear).absDistance((rot*scaling) * p1), Scalar(1) );
pl2 = pl1;
VERIFY_IS_MUCH_SMALLER_THAN( pl2.transform(rot*scaling*translation) VERIFY_IS_MUCH_SMALLER_THAN( pl2.transform(rot*scaling*translation)
.absDistance((rot*scaling*translation) * p1), Scalar(1) ); .absDistance((rot*scaling*translation) * p1), Scalar(1) );
pl2 = pl1; pl2 = pl1;
VERIFY_IS_MUCH_SMALLER_THAN( pl2.transform(rot*scaling*translation,NoShear) VERIFY_IS_MUCH_SMALLER_THAN( pl2.transform(rot*translation,Isometry)
.absDistance((rot*scaling*translation) * p1), Scalar(1) );
pl2 = pl1;
VERIFY_IS_MUCH_SMALLER_THAN( pl2.transform(rot*translation,NoScaling)
.absDistance((rot*translation) * p1), Scalar(1) ); .absDistance((rot*translation) * p1), Scalar(1) );
} }
} }