From 33058aa5b06b029db15e73a732387ffde61f0282 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Thu, 14 Mar 2013 16:02:41 +0100 Subject: [PATCH] Math: Matrix::invertedOrthogonal(), Matrix{3,4}::invertedRigid(). Renamed original invertedEuclidean() functions to invertedRigid() and simplified them using isRigidTransformation(). --- doc/transformations.dox | 6 ++-- src/Math/Matrix.h | 23 +++++++++++++-- src/Math/Matrix3.h | 18 +++++------- src/Math/Matrix4.h | 18 +++++------- src/Math/Test/CMakeLists.txt | 1 + src/Math/Test/Matrix3Test.cpp | 28 +++++++----------- src/Math/Test/Matrix4Test.cpp | 29 +++++++------------ src/Math/Test/MatrixTest.cpp | 17 +++++++++++ .../EuclideanMatrixTransformation2D.h | 2 +- .../EuclideanMatrixTransformation3D.h | 2 +- 10 files changed, 79 insertions(+), 65 deletions(-) diff --git a/doc/transformations.dox b/doc/transformations.dox index 4ead3685b..a069e2fe8 100644 --- a/doc/transformations.dox +++ b/doc/transformations.dox @@ -188,9 +188,9 @@ Inverse transformation can be computed using Matrix3::inverted(), Matrix4::inver Complex::inverted(), Quaternion::inverted(), DualComplex::inverted() or DualQuaternion::inverted(). %Matrix inversion is quite costly, so if your transformation involves only translation and rotation, you can use faster -alternatives Matrix3::invertedEuclidean() and Matrix4::invertedEuclidean(). If -you are sure that the (dual) complex number or (dual) quaternion is of unit -length, you can use Complex::invertedNormalized(), Quaternion::invertedNormalized(), +alternatives Matrix3::invertedRigid() and Matrix4::invertedRigid(). If you are +sure that the (dual) complex number or (dual) quaternion is of unit length, you +can use Complex::invertedNormalized(), Quaternion::invertedNormalized(), DualComplex::invertedNormalized() or DualQuaternion::invertedNormalized() which is a little bit faster, because it doesn't need to renormalize the result. diff --git a/src/Math/Matrix.h b/src/Math/Matrix.h index 11f1c739e..432ded0d8 100644 --- a/src/Math/Matrix.h +++ b/src/Math/Matrix.h @@ -168,8 +168,7 @@ template class Matrix: public RectangularMatrix inverted() const { @@ -184,6 +183,21 @@ template class Matrix: public RectangularMatrix invertedOrthogonal() const { + CORRADE_ASSERT(isOrthogonal(), + "Math::Matrix::invertedOrthogonal(): the matrix is not orthogonal", {}); + return this->transposed(); + } + #ifndef DOXYGEN_GENERATING_OUTPUT /* Reimplementation of functions to return correct type */ inline Matrix operator*(const Matrix& other) const { @@ -239,7 +253,10 @@ template inline Corrade::Utility::Debug operator<<(Co } \ \ inline Type transposed() const { return Matrix::transposed(); } \ - inline Type inverted() const { return Matrix::inverted(); } + inline Type inverted() const { return Matrix::inverted(); } \ + inline Type invertedOrthogonal() const { \ + return Matrix::invertedOrthogonal(); \ + } #define MAGNUM_MATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(Type, size) \ template inline typename std::enable_if::value, Type>::type operator*(U number, const Type& matrix) { \ diff --git a/src/Math/Matrix3.h b/src/Math/Matrix3.h index 6e678eefc..a60e0133e 100644 --- a/src/Math/Matrix3.h +++ b/src/Math/Matrix3.h @@ -218,20 +218,18 @@ template class Matrix3: public Matrix<3, T> { inline constexpr Vector2 translation() const { return (*this)[2].xy(); } /**< @overload */ /** - * @brief Inverted Euclidean transformation matrix + * @brief Inverted rigid transformation matrix * - * Assumes that the matrix represents Euclidean transformation (i.e. - * only rotation and translation, no scaling) and creates inverted - * matrix from transposed rotation part and negated translation part. + * Expects that the matrix represents rigid transformation. * Significantly faster than the general algorithm in inverted(). - * @see rotationScaling() const, translation() const + * @see isRigidTransformation(), invertedOrthogonal(), + * rotationScaling() const, translation() const */ - inline Matrix3 invertedEuclidean() const { - CORRADE_ASSERT((*this)[0][2] == T(0) && (*this)[1][2] == T(0) && (*this)[2][2] == T(1), - "Math::Matrix3::invertedEuclidean(): unexpected values on last row", {}); + inline Matrix3 invertedRigid() const { + CORRADE_ASSERT(isRigidTransformation(), + "Math::Matrix3::invertedRigid(): the matrix doesn't represent rigid transformation", {}); + Matrix<2, T> inverseRotation = rotationScaling().transposed(); - CORRADE_ASSERT((inverseRotation*rotationScaling() == Matrix<2, T>()), - "Math::Matrix3::invertedEuclidean(): the matrix doesn't represent Euclidean transformation", {}); return from(inverseRotation, inverseRotation*-translation()); } diff --git a/src/Math/Matrix4.h b/src/Math/Matrix4.h index fdefc41b1..9837bdae7 100644 --- a/src/Math/Matrix4.h +++ b/src/Math/Matrix4.h @@ -363,20 +363,18 @@ template class Matrix4: public Matrix<4, T> { inline constexpr Vector3 translation() const { return (*this)[3].xyz(); } /**< @overload */ /** - * @brief Inverted Euclidean transformation matrix + * @brief Inverted rigid transformation matrix * - * Expects that the matrix represents Euclidean transformation (i.e. - * only rotation and translation, no scaling) and creates inverted - * matrix from transposed rotation part and negated translation part. + * Expects that the matrix represents rigid transformation. * Significantly faster than the general algorithm in inverted(). - * @see rotationScaling() const, translation() const + * @see isRigidTransformation(), invertedOrthogonal(), + * rotationScaling() const, translation() const */ - inline Matrix4 invertedEuclidean() const { - CORRADE_ASSERT((*this)[0][3] == T(0) && (*this)[1][3] == T(0) && (*this)[2][3] == T(0) && (*this)[3][3] == T(1), - "Math::Matrix4::invertedEuclidean(): unexpected values on last row", {}); + inline Matrix4 invertedRigid() const { + CORRADE_ASSERT(isRigidTransformation(), + "Math::Matrix4::invertedRigid(): the matrix doesn't represent rigid transformation", {}); + Matrix<3, T> inverseRotation = rotationScaling().transposed(); - CORRADE_ASSERT((inverseRotation*rotationScaling() == Matrix<3, T>()), - "Math::Matrix4::invertedEuclidean(): the matrix doesn't represent Euclidean transformation", {}); return from(inverseRotation, inverseRotation*-translation()); } diff --git a/src/Math/Test/CMakeLists.txt b/src/Math/Test/CMakeLists.txt index e071c9da9..65fe5141c 100644 --- a/src/Math/Test/CMakeLists.txt +++ b/src/Math/Test/CMakeLists.txt @@ -49,6 +49,7 @@ corrade_add_test(MathDualQuaternionTest DualQuaternionTest.cpp LIBRARIES MagnumM set_target_properties( MathVectorTest + MathMatrixTest MathMatrix3Test MathMatrix4Test MathComplexTest diff --git a/src/Math/Test/Matrix3Test.cpp b/src/Math/Test/Matrix3Test.cpp index 71a14458e..eeaa8dd8b 100644 --- a/src/Math/Test/Matrix3Test.cpp +++ b/src/Math/Test/Matrix3Test.cpp @@ -51,7 +51,7 @@ class Matrix3Test: public Corrade::TestSuite::Tester { void rotationScalingPart(); void rotationPart(); void vectorParts(); - void invertedEuclidean(); + void invertedRigid(); void transform(); void debug(); @@ -82,7 +82,7 @@ Matrix3Test::Matrix3Test() { &Matrix3Test::rotationScalingPart, &Matrix3Test::rotationPart, &Matrix3Test::vectorParts, - &Matrix3Test::invertedEuclidean, + &Matrix3Test::invertedRigid, &Matrix3Test::transform, &Matrix3Test::debug, @@ -271,20 +271,7 @@ void Matrix3Test::vectorParts() { CORRADE_COMPARE(translation, Vector2(-5.0f, 12.0f)); } -void Matrix3Test::invertedEuclidean() { - std::ostringstream o; - Error::setOutput(&o); - - Matrix3 m({3.0f, 5.0f, 8.0f}, - {4.0f, 4.0f, 7.0f}, - {7.0f, -1.0f, 8.0f}); - CORRADE_COMPARE(m.invertedEuclidean(), Matrix3()); - CORRADE_COMPARE(o.str(), "Math::Matrix3::invertedEuclidean(): unexpected values on last row\n"); - - o.str({}); - CORRADE_COMPARE(Matrix3::scaling(Vector2(2.0f)).invertedEuclidean(), Matrix3()); - CORRADE_COMPARE(o.str(), "Math::Matrix3::invertedEuclidean(): the matrix doesn't represent Euclidean transformation\n"); - +void Matrix3Test::invertedRigid() { Matrix3 actual = Matrix3::rotation(Deg(-74.0f))* Matrix3::reflection(Vector2(0.5f, -2.0f).normalized())* Matrix3::translation({2.0f, -3.0f}); @@ -292,8 +279,13 @@ void Matrix3Test::invertedEuclidean() { Matrix3::reflection(Vector2(0.5f, -2.0f).normalized())* Matrix3::rotation(Deg(74.0f)); - CORRADE_COMPARE(actual.invertedEuclidean(), expected); - CORRADE_COMPARE(actual.invertedEuclidean(), actual.inverted()); + std::ostringstream o; + Error::setOutput(&o); + (2*actual).invertedRigid(); + CORRADE_COMPARE(o.str(), "Math::Matrix3::invertedRigid(): the matrix doesn't represent rigid transformation\n"); + + CORRADE_COMPARE(actual.invertedRigid(), expected); + CORRADE_COMPARE(actual.invertedRigid(), actual.inverted()); } void Matrix3Test::transform() { diff --git a/src/Math/Test/Matrix4Test.cpp b/src/Math/Test/Matrix4Test.cpp index c7e2826c9..771b5dba7 100644 --- a/src/Math/Test/Matrix4Test.cpp +++ b/src/Math/Test/Matrix4Test.cpp @@ -56,7 +56,7 @@ class Matrix4Test: public Corrade::TestSuite::Tester { void rotationScalingPart(); void rotationPart(); void vectorParts(); - void invertedEuclidean(); + void invertedRigid(); void transform(); void debug(); @@ -93,7 +93,7 @@ Matrix4Test::Matrix4Test() { &Matrix4Test::rotationScalingPart, &Matrix4Test::rotationPart, &Matrix4Test::vectorParts, - &Matrix4Test::invertedEuclidean, + &Matrix4Test::invertedRigid, &Matrix4Test::transform, &Matrix4Test::debug, @@ -355,21 +355,7 @@ void Matrix4Test::vectorParts() { CORRADE_COMPARE(translation, Vector3(-5.0f, 12.0f, 0.5f)); } -void Matrix4Test::invertedEuclidean() { - std::ostringstream o; - Error::setOutput(&o); - - Matrix4 m({3.0f, 5.0f, 8.0f, 4.0f}, - {4.0f, 4.0f, 7.0f, 3.0f}, - {7.0f, -1.0f, 8.0f, 0.0f}, - {9.0f, 4.0f, 5.0f, 9.0f}); - CORRADE_COMPARE(m.invertedEuclidean(), Matrix4()); - CORRADE_COMPARE(o.str(), "Math::Matrix4::invertedEuclidean(): unexpected values on last row\n"); - - o.str({}); - CORRADE_COMPARE(Matrix4::scaling(Vector3(2.0f)).invertedEuclidean(), Matrix4()); - CORRADE_COMPARE(o.str(), "Math::Matrix4::invertedEuclidean(): the matrix doesn't represent Euclidean transformation\n"); - +void Matrix4Test::invertedRigid() { Matrix4 actual = Matrix4::rotation(Deg(-74.0f), Vector3(-1.0f, 0.5f, 2.0f).normalized())* Matrix4::reflection(Vector3(0.5f, -2.0f, 2.0f).normalized())* Matrix4::translation({1.0f, 2.0f, -3.0f}); @@ -377,8 +363,13 @@ void Matrix4Test::invertedEuclidean() { Matrix4::reflection(Vector3(0.5f, -2.0f, 2.0f).normalized())* Matrix4::rotation(Deg(74.0f), Vector3(-1.0f, 0.5f, 2.0f).normalized()); - CORRADE_COMPARE(actual.invertedEuclidean(), expected); - CORRADE_COMPARE(actual.invertedEuclidean(), actual.inverted()); + std::ostringstream o; + Error::setOutput(&o); + (2*actual).invertedRigid(); + CORRADE_COMPARE(o.str(), "Math::Matrix4::invertedRigid(): the matrix doesn't represent rigid transformation\n"); + + CORRADE_COMPARE(actual.invertedRigid(), expected); + CORRADE_COMPARE(actual.invertedRigid(), actual.inverted()); } void Matrix4Test::transform() { diff --git a/src/Math/Test/MatrixTest.cpp b/src/Math/Test/MatrixTest.cpp index bd7dca4c3..62973756f 100644 --- a/src/Math/Test/MatrixTest.cpp +++ b/src/Math/Test/MatrixTest.cpp @@ -46,6 +46,7 @@ class MatrixTest: public Corrade::TestSuite::Tester { void ij(); void determinant(); void inverted(); + void invertedOrthogonal(); void debug(); void configuration(); @@ -57,6 +58,7 @@ typedef Matrix<3, Float> Matrix3; typedef Vector<4, Float> Vector4; typedef Vector<4, Int> Vector4i; typedef Vector<3, Float> Vector3; +typedef Math::Constants Constants; MatrixTest::MatrixTest() { addTests({&MatrixTest::construct, @@ -71,6 +73,7 @@ MatrixTest::MatrixTest() { &MatrixTest::ij, &MatrixTest::determinant, &MatrixTest::inverted, + &MatrixTest::invertedOrthogonal, &MatrixTest::debug, &MatrixTest::configuration}); } @@ -209,6 +212,20 @@ void MatrixTest::inverted() { CORRADE_COMPARE(_inverse*m, Matrix4()); } +void MatrixTest::invertedOrthogonal() { + std::ostringstream o; + Error::setOutput(&o); + + Matrix3 a(Vector3(Constants::sqrt3()/2.0f, 0.5f, 0.0f), + Vector3(-0.5f, Constants::sqrt3()/2.0f, 0.0f), + Vector3(0.0f, 0.0f, 1.0f)); + (a*2).invertedOrthogonal(); + CORRADE_COMPARE(o.str(), "Math::Matrix::invertedOrthogonal(): the matrix is not orthogonal\n"); + + CORRADE_COMPARE(a.invertedOrthogonal()*a, Matrix3()); + CORRADE_COMPARE(a.invertedOrthogonal(), a.inverted()); +} + void MatrixTest::debug() { Matrix4 m(Vector4(3.0f, 5.0f, 8.0f, 4.0f), Vector4(4.0f, 4.0f, 7.0f, 3.0f), diff --git a/src/SceneGraph/EuclideanMatrixTransformation2D.h b/src/SceneGraph/EuclideanMatrixTransformation2D.h index f3e81f9d9..b5c920e27 100644 --- a/src/SceneGraph/EuclideanMatrixTransformation2D.h +++ b/src/SceneGraph/EuclideanMatrixTransformation2D.h @@ -68,7 +68,7 @@ class EuclideanMatrixTransformation2D: public AbstractTranslationRotation2D { } inline static Math::Matrix3 inverted(const Math::Matrix3& transformation) { - return transformation.invertedEuclidean(); + return transformation.invertedRigid(); } inline Math::Matrix3 transformation() const { diff --git a/src/SceneGraph/EuclideanMatrixTransformation3D.h b/src/SceneGraph/EuclideanMatrixTransformation3D.h index 751f5f0b3..90c32f435 100644 --- a/src/SceneGraph/EuclideanMatrixTransformation3D.h +++ b/src/SceneGraph/EuclideanMatrixTransformation3D.h @@ -68,7 +68,7 @@ class EuclideanMatrixTransformation3D: public AbstractTranslationRotation3D { } inline static Math::Matrix4 inverted(const Math::Matrix4& transformation) { - return transformation.invertedEuclidean(); + return transformation.invertedRigid(); } inline Math::Matrix4 transformation() const {