diff --git a/Eigen/Geometry b/Eigen/Geometry index aefad1c48..b5037306d 100644 --- a/Eigen/Geometry +++ b/Eigen/Geometry @@ -31,6 +31,8 @@ namespace Eigen { #include "src/Geometry/AngleAxis.h" #include "src/Geometry/Rotation.h" #include "src/Geometry/Transform.h" +#include "src/Geometry/Translation.h" +#include "src/Geometry/Scaling.h" #include "src/Geometry/Hyperplane.h" } // namespace Eigen diff --git a/Eigen/src/Core/util/ForwardDeclarations.h b/Eigen/src/Core/util/ForwardDeclarations.h index 8e40bea0f..b85ef94f7 100644 --- a/Eigen/src/Core/util/ForwardDeclarations.h +++ b/Eigen/src/Core/util/ForwardDeclarations.h @@ -105,5 +105,7 @@ template class Quaternion; template class Rotation2D; template class AngleAxis; template class Transform; +template class Translation; +template class Scaling; #endif // EIGEN_FORWARDDECLARATIONS_H diff --git a/Eigen/src/Geometry/Scaling.h b/Eigen/src/Geometry/Scaling.h new file mode 100644 index 000000000..fcf1c0437 --- /dev/null +++ b/Eigen/src/Geometry/Scaling.h @@ -0,0 +1,148 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. Eigen itself is part of the KDE project. +// +// Copyright (C) 2008 Gael Guennebaud +// +// Eigen is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 3 of the License, or (at your option) any later version. +// +// Alternatively, you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of +// the License, or (at your option) any later version. +// +// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License and a copy of the GNU General Public License along with +// Eigen. If not, see . + +#ifndef EIGEN_SCALING_H +#define EIGEN_SCALING_H + +/** \geometry_module \ingroup GeometryModule + * + * \class Scaling + * + * \brief Represents a possibly non uniform scaling transformation + * + * \param _Scalar the scalar type, i.e., the type of the coefficients. + * \param _Dim the dimension of the space, can be a compile time value or Dynamic + * + * + * \sa class Translate, class Transform + */ +template +class Scaling +{ +public: + enum { Dim = _Dim }; + /** the scalar type of the coefficients */ + typedef _Scalar Scalar; + typedef Matrix LinearMatrixType; + typedef Matrix VectorType; + typedef Translation TranslationType; + typedef Transform TransformType; + +protected: + + VectorType m_coeffs; + +public: + + /** Default constructor without initialization. */ + Scaling() {} + /** Constructs and initialize a uniform scaling transformation */ + explicit inline Scaling(const Scalar& s) { m_coeffs.setConstant(s); } + /** 2D only */ + inline Scaling(const Scalar& sx, const Scalar& sy) + { + ei_assert(Dim==2); + m_coeffs.x() = sx; + m_coeffs.y() = sy; + } + /** 3D only */ + inline Scaling(const Scalar& sx, const Scalar& sy, const Scalar& sz) + { + ei_assert(Dim==3); + m_coeffs.x() = sx; + m_coeffs.y() = sy; + m_coeffs.z() = sz; + } + /** Constructs and initialize the scaling transformation from a vector of scaling coefficients */ + explicit inline Scaling(const VectorType& coeffs) : m_coeffs(coeffs) {} + + const VectorType& coeffs() const { return m_coeffs; } + VectorType& coeffs() { return m_coeffs; } + + /** Concatenates two scaling */ + inline Scaling operator* (const Scaling& other) const + { return Scaling(coeffs().cwise() * other.coeffs()); } + + /** Concatenates a scaling and a translation */ + inline TransformType operator* (const TranslationType& t) const; + + /** Concatenates a scaling and an affine transformation */ + inline TransformType operator* (const TransformType& t) const; + + /** Concatenates a scaling and a linear transformation matrix */ + // TODO returns an expression + inline LinearMatrixType operator* (const LinearMatrixType& other) const + { return coeffs().asDiagonal() * other; } + + /** Concatenates a linear transformation matrix and a scaling */ + // TODO returns an expression + friend inline LinearMatrixType operator* (const LinearMatrixType& other, const Scaling& s) + { return other * s.coeffs().asDiagonal(); } + + /** Applies scaling to vector */ + inline VectorType operator* (const VectorType& other) const + { return coeffs().asDiagonal() * other; } + + /** \returns the inverse scaling */ + inline Scaling inverse() const + { return Scaling(coeffs.cwise().inverse()); } + + inline Scaling& operator=(const Scaling& other) + { + m_coeffs = other.m_coeffs; + return *this; + } + +}; + +/** \addtogroup GeometryModule */ +//@{ +typedef Scaling Scaling2f; +typedef Scaling Scaling2d; +typedef Scaling Scaling3f; +typedef Scaling Scaling3d; +//@} + +template +inline typename Scaling::TransformType +Scaling::operator* (const TranslationType& t) const +{ + TransformType res; + res.matrix().setZero(); + res.linear().diagonal() = coeffs(); + res.translation() = m_coeffs.cwise() * t.vector(); + res(Dim,Dim) = Scalar(1); + return res; +} + +template +inline typename Scaling::TransformType +Scaling::operator* (const TransformType& t) const +{ + TransformType res = t; + res.prescale(m_coeffs); + return res; +} + +#endif // EIGEN_SCALING_H diff --git a/Eigen/src/Geometry/Transform.h b/Eigen/src/Geometry/Transform.h index 1d4efb7be..f32577e88 100644 --- a/Eigen/src/Geometry/Transform.h +++ b/Eigen/src/Geometry/Transform.h @@ -73,6 +73,8 @@ public: typedef Matrix VectorType; /** type of a read/write reference to the translation part of the rotation */ typedef Block TranslationPart; + typedef Translation TranslationType; + typedef Scaling ScalingType; protected: @@ -81,7 +83,7 @@ protected: public: /** Default constructor without initialization of the coefficients. */ - Transform() { } + inline Transform() { } inline Transform(const Transform& other) { m_matrix = other.m_matrix; } @@ -129,10 +131,10 @@ public: /** shortcut for m_matrix(row,col); * \sa MatrixBase::operaror(int,int) const */ - Scalar operator() (int row, int col) const { return m_matrix(row,col); } + inline Scalar operator() (int row, int col) const { return m_matrix(row,col); } /** shortcut for m_matrix(row,col); * \sa MatrixBase::operaror(int,int) */ - Scalar& operator() (int row, int col) { return m_matrix(row,col); } + inline Scalar& operator() (int row, int col) { return m_matrix(row,col); } /** \returns a read-only expression of the transformation matrix */ inline const MatrixType& matrix() const { return m_matrix; } @@ -158,12 +160,12 @@ public: */ // note: this function is defined here because some compilers cannot find the respective declaration template - const typename ei_transform_product_impl::ResultType + inline const typename ei_transform_product_impl::ResultType operator * (const MatrixBase &other) const { return ei_transform_product_impl::run(*this,other.derived()); } /** Contatenates two transformations */ - const typename ProductReturnType::Type + inline const typename ProductReturnType::Type operator * (const Transform& other) const { return m_matrix * other.matrix(); } @@ -171,26 +173,38 @@ public: void setIdentity() { m_matrix.setIdentity(); } template - Transform& scale(const MatrixBase &other); + inline Transform& scale(const MatrixBase &other); template - Transform& prescale(const MatrixBase &other); + inline Transform& prescale(const MatrixBase &other); template - Transform& translate(const MatrixBase &other); + inline Transform& translate(const MatrixBase &other); template - Transform& pretranslate(const MatrixBase &other); + inline Transform& pretranslate(const MatrixBase &other); template - Transform& rotate(const RotationType& rotation); + inline Transform& rotate(const RotationType& rotation); template - Transform& prerotate(const RotationType& rotation); + inline Transform& prerotate(const RotationType& rotation); Transform& shear(Scalar sx, Scalar sy); Transform& preshear(Scalar sx, Scalar sy); + inline Transform& operator*=(const TranslationType& t) { return translate(t.vector()); } + inline Transform operator*(const TranslationType& t) const; + 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) + { + Transform res = t; + res.matrix().row(Dim) = t.matrix().row(Dim); + res.matrix().template block(0,0) = (mat * t.matrix().template block(0,0)).lazy(); + return res; + } + LinearMatrixType extractRotation() const; LinearMatrixType extractRotationNoShear() const; @@ -385,6 +399,22 @@ Transform::preshear(Scalar sx, Scalar sy) return *this; } +template +inline Transform Transform::operator*(const TranslationType& t) const +{ + Transform res = *this; + res.translate(t.vector()); + return res; +} + +template +inline Transform Transform::operator*(const ScalingType& s) const +{ + Transform res = *this; + res.scale(s.coeffs()); + return res; +} + /** \returns the rotation part of the transformation using a QR decomposition. * \sa extractRotationNoShear(), class QR */ @@ -438,6 +468,22 @@ struct ei_transform_product_impl { return tr.matrix() * other; } }; +template +struct ei_transform_product_impl +{ + typedef Transform TransformType; + typedef typename TransformType::MatrixType MatrixType; + typedef TransformType ResultType; + static ResultType run(const TransformType& tr, const Other& other) + { + TransformType res; + res.translation() = tr.translation(); + res.matrix().row(Dim) = tr.matrix().row(Dim); + res.linear() = (tr.linear() * other).lazy(); + return res; + } +}; + template struct ei_transform_product_impl { diff --git a/Eigen/src/Geometry/Translation.h b/Eigen/src/Geometry/Translation.h new file mode 100644 index 000000000..ad63b835f --- /dev/null +++ b/Eigen/src/Geometry/Translation.h @@ -0,0 +1,165 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. Eigen itself is part of the KDE project. +// +// Copyright (C) 2008 Gael Guennebaud +// +// Eigen is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 3 of the License, or (at your option) any later version. +// +// Alternatively, you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of +// the License, or (at your option) any later version. +// +// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License and a copy of the GNU General Public License along with +// Eigen. If not, see . + +#ifndef EIGEN_TRANSLATION_H +#define EIGEN_TRANSLATION_H + +/** \geometry_module \ingroup GeometryModule + * + * \class Translation + * + * \brief Represents a translation transformation + * + * \param _Scalar the scalar type, i.e., the type of the coefficients. + * \param _Dim the dimension of the space, can be a compile time value or Dynamic + * + * + * \sa class Scaling, class Transform + */ +template +class Translation +{ +public: + enum { Dim = _Dim }; + /** the scalar type of the coefficients */ + typedef _Scalar Scalar; + typedef Matrix LinearMatrixType; + typedef Matrix VectorType; + typedef Scaling ScalingType; + typedef Transform TransformType; + +protected: + + VectorType m_coeffs; + +public: + + /** Default constructor without initialization. */ + Translation() {} + /** */ + inline Translation(const Scalar& sx, const Scalar& sy) + { + ei_assert(Dim==2); + m_coeffs.x() = sx; + m_coeffs.y() = sy; + } + /** */ + inline Translation(const Scalar& sx, const Scalar& sy, const Scalar& sz) + { + ei_assert(Dim==3); + m_coeffs.x() = sx; + m_coeffs.y() = sy; + m_coeffs.z() = sz; + } + /** Constructs and initialize the scaling transformation from a vector of scaling coefficients */ + explicit inline Translation(const VectorType& vector) : m_coeffs(vector) {} + + const VectorType& vector() const { return m_coeffs; } + VectorType& vector() { return m_coeffs; } + + /** Concatenates two translation */ + inline Translation operator* (const Translation& other) const + { return Translation(m_coeffs + other.m_coeffs); } + + /** Concatenates a translation and a scaling */ + inline TransformType operator* (const ScalingType& other) const; + + /** Concatenates a translation and a linear transformation */ + inline TransformType operator* (const LinearMatrixType& linear) const; + + /** Concatenates a linear transformation and a translation */ + // its a nightmare to define a templated friend function outside its declaration + friend inline TransformType operator* (const LinearMatrixType& linear, const Translation& t) + { + TransformType res; + res.matrix().setZero(); + res.linear() = linear; + res.translation() = linear * t.m_coeffs; + res.matrix().row(Dim).setZero(); + res(Dim,Dim) = Scalar(1); + return res; + } + + /** Concatenates a translation and an affine transformation */ + inline TransformType operator* (const TransformType& t) const; + + /** Applies translation to vector */ + inline VectorType operator* (const VectorType& other) const + { return m_coeffs + other; } + + /** \returns the inverse translation (opposite) */ + Translation inverse() const { return Translation(-m_coeffs); } + + Translation& operator=(const Translation& other) + { + m_coeffs = other.m_coeffs; + return *this; + } + +}; + +/** \addtogroup GeometryModule */ +//@{ +typedef Translation Translation2f; +typedef Translation Translation2d; +typedef Translation Translation3f; +typedef Translation Translation3d; +//@} + + +template +inline typename Translation::TransformType +Translation::operator* (const ScalingType& other) const +{ + TransformType res; + res.matrix().setZero(); + res.linear().diagonal() = other.coeffs(); + res.translation() = m_coeffs; + res(Dim,Dim) = Scalar(1); + return res; +} + +template +inline typename Translation::TransformType +Translation::operator* (const LinearMatrixType& linear) const +{ + TransformType res; + res.matrix().setZero(); + res.linear() = linear; + res.translation() = m_coeffs; + res.matrix().row(Dim).setZero(); + res(Dim,Dim) = Scalar(1); + return res; +} + +template +inline typename Translation::TransformType +Translation::operator* (const TransformType& t) const +{ + TransformType res = t; + res.pretranslate(m_coeffs); + return res; +} + +#endif // EIGEN_TRANSLATION_H diff --git a/test/geometry.cpp b/test/geometry.cpp index da99c86ac..af9accb63 100644 --- a/test/geometry.cpp +++ b/test/geometry.cpp @@ -40,6 +40,12 @@ template void geometry(void) typedef Matrix Vector4; typedef Quaternion Quaternion; typedef AngleAxis AngleAxis; + typedef Transform Transform2; + typedef Transform Transform3; + typedef Scaling Scaling2; + typedef Scaling Scaling3; + typedef Translation Translation2; + typedef Translation Translation3; Quaternion q1, q2; Vector3 v0 = test_random_matrix(), @@ -115,12 +121,8 @@ template void geometry(void) VERIFY_IS_APPROX(AngleAxis(m).toRotationMatrix(), Quaternion(m).toRotationMatrix()); - // Transform // TODO complete the tests ! - typedef Transform Transform2; - typedef Transform Transform3; - a = 0; while (ei_abs(a)<0.1) a = ei_random(-0.4*M_PI, 0.4*M_PI); @@ -169,12 +171,60 @@ template void geometry(void) t21.linear() = Rotation2D(-a).toRotationMatrix(); VERIFY( (t20.fromPositionOrientationScale(v20,a,v21) * (t21.prescale(v21.cwise().inverse()).translate(-v20))).isIdentity(test_precision()) ); + + // Transform - new API + // 3D + t0.setIdentity(); + t0.rotate(q1).scale(v0).translate(v0); + // mat * scaling and mat * translation + t1 = (Matrix3(q1) * Scaling3(v0)) * Translation3(v0); + VERIFY_IS_APPROX(t0.matrix(), t1.matrix()); + // mat * transformation and scaling * translation + t1 = Matrix3(q1) * (Scaling3(v0) * Translation3(v0)); + VERIFY_IS_APPROX(t0.matrix(), t1.matrix()); + + t0.setIdentity(); + t0.prerotate(q1).prescale(v0).pretranslate(v0); + // translation * scaling and transformation * mat + t1 = (Translation3(v0) * Scaling3(v0)) * Matrix3(q1); + VERIFY_IS_APPROX(t0.matrix(), t1.matrix()); + // scaling * mat and translation * mat + t1 = Translation3(v0) * (Scaling3(v0) * Matrix3(q1)); + VERIFY_IS_APPROX(t0.matrix(), t1.matrix()); + + t0.setIdentity(); + t0.scale(v0).translate(v0).rotate(q1); + // translation * mat and scaling * transformation + t1 = Scaling3(v0) * (Translation3(v0) * Matrix3(q1)); + VERIFY_IS_APPROX(t0.matrix(), t1.matrix()); + // transformation * scaling + t0.scale(v0); + t1 = t1 * Scaling3(v0); + VERIFY_IS_APPROX(t0.matrix(), t1.matrix()); + // transformation * translation + t0.translate(v0); + t1 = t1 * Translation3(v0); + VERIFY_IS_APPROX(t0.matrix(), t1.matrix()); + // translation * transformation + t0.pretranslate(v0); + t1 = Translation3(v0) * t1; + VERIFY_IS_APPROX(t0.matrix(), t1.matrix()); + + // translation * vector + t0.setIdentity(); + t0.translate(v0); + VERIFY_IS_APPROX(t0 * v1, Translation3(v0) * v1); + + // scaling * vector + t0.setIdentity(); + t0.scale(v0); + VERIFY_IS_APPROX(t0 * v1, Scaling3(v0) * v1); } void test_geometry() { for(int i = 0; i < g_repeat; i++) { CALL_SUBTEST( geometry() ); - CALL_SUBTEST( geometry() ); +// CALL_SUBTEST( geometry() ); } }