From 8d5454b8ff9ea30dc3b084527c13b128351e451b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Sun, 7 Oct 2018 18:27:34 +0200 Subject: [PATCH] Math: ability to slice or expand square matrices. --- doc/changelog.dox | 2 ++ src/Magnum/Math/Matrix.h | 27 ++++++++++++++++++++++++++ src/Magnum/Math/Matrix3.h | 9 +++++++++ src/Magnum/Math/Matrix4.h | 9 +++++++++ src/Magnum/Math/Test/Matrix3Test.cpp | 25 ++++++++++++++++++++++-- src/Magnum/Math/Test/Matrix4Test.cpp | 27 +++++++++++++++++++++++++- src/Magnum/Math/Test/MatrixTest.cpp | 29 ++++++++++++++++++++++++++-- 7 files changed, 123 insertions(+), 5 deletions(-) diff --git a/doc/changelog.dox b/doc/changelog.dox index 8243c862d..1036b8bea 100644 --- a/doc/changelog.dox +++ b/doc/changelog.dox @@ -114,6 +114,8 @@ See also: @ref Math::Distance::pointPlane() and others - Ability to convert @ref Math::BoolVector from and to external representation +- Ability to construct @ref Math::Matrix from a smaller or larger square + matrix by slicing or expanding it - Mutable overloads for @ref Math::Complex::real(), @ref Math::Complex::imaginary(), @ref Math::Dual::real(), @ref Math::Dual::dual(), @ref Math::Quaternion::vector() and diff --git a/src/Magnum/Math/Matrix.h b/src/Magnum/Math/Matrix.h index 0b53c9b53..2efcd2970 100644 --- a/src/Magnum/Math/Matrix.h +++ b/src/Magnum/Math/Matrix.h @@ -35,6 +35,15 @@ namespace Magnum { namespace Math { namespace Implementation { template struct MatrixDeterminant; + + template constexpr Vector valueOrIdentityVector(Sequence, const RectangularMatrix& other) { + return {(col < otherSize && row < otherSize ? other[col][row] : + col == row ? T{1} : T{0})...}; + } + + template constexpr Vector valueOrIdentityVector(const RectangularMatrix& other) { + return valueOrIdentityVector(typename Implementation::GenerateSequence::Type(), other); + } } /** @@ -111,6 +120,20 @@ template class Matrix: public RectangularMatrix::from(std::declval()))> constexpr explicit Matrix(const U& other): RectangularMatrix(Implementation::RectangularMatrixConverter::from(other)) {} + /** + * @brief Construct matrix by slicing or expanding another of a different size + * + * If the other matrix is larger, takes only the first @cpp size @ce + * columns and rows from it; if the other matrix is smaller, it's + * expanded to an identity (ones on diagonal, zeros elsewhere). + */ + template constexpr explicit Matrix(const RectangularMatrix& other) noexcept + /** @todoc remove workaround when doxygen is sane */ + #ifndef DOXYGEN_GENERATING_OUTPUT + : Matrix{typename Implementation::GenerateSequence::Type(), other} + #endif + {} + /** @brief Copy constructor */ constexpr /*implicit*/ Matrix(const RectangularMatrix& other) noexcept: RectangularMatrix(other) {} @@ -199,6 +222,10 @@ template class Matrix: public RectangularMatrix) #endif + + private: + /* Implementation for RectangularMatrix::RectangularMatrix(const RectangularMatrix&) */ + template constexpr explicit Matrix(Implementation::Sequence, const RectangularMatrix& other) noexcept: RectangularMatrix{Implementation::valueOrIdentityVector(other)...} {} }; /** diff --git a/src/Magnum/Math/Matrix3.h b/src/Magnum/Math/Matrix3.h index c540b59d1..a6d1c545b 100644 --- a/src/Magnum/Math/Matrix3.h +++ b/src/Magnum/Math/Matrix3.h @@ -241,6 +241,15 @@ template class Matrix3: public Matrix3x3 { /** @brief Construct matrix from external representation */ template::from(std::declval()))> constexpr explicit Matrix3(const U& other) noexcept: Matrix3x3(Implementation::RectangularMatrixConverter<3, 3, T, U>::from(other)) {} + /** + * @brief Construct matrix by slicing or expanding another of a different size + * + * If the other matrix is larger, takes only the first @cpp size @ce + * columns and rows from it; if the other matrix is smaller, it's + * expanded to an identity (ones on diagonal, zeros elsewhere). + */ + template constexpr explicit Matrix3(const RectangularMatrix& other) noexcept: Matrix3x3{other} {} + /** @brief Copy constructor */ constexpr /*implicit*/ Matrix3(const RectangularMatrix<3, 3, T>& other) noexcept: Matrix3x3(other) {} diff --git a/src/Magnum/Math/Matrix4.h b/src/Magnum/Math/Matrix4.h index 454f9da4f..76d29d368 100644 --- a/src/Magnum/Math/Matrix4.h +++ b/src/Magnum/Math/Matrix4.h @@ -426,6 +426,15 @@ template class Matrix4: public Matrix4x4 { /** @brief Construct matrix from external representation */ template::from(std::declval()))> constexpr explicit Matrix4(const U& other): Matrix4x4(Implementation::RectangularMatrixConverter<4, 4, T, U>::from(other)) {} + /** + * @brief Construct matrix by slicing or expanding another of a different size + * + * If the other matrix is larger, takes only the first @cpp size @ce + * columns and rows from it; if the other matrix is smaller, it's + * expanded to an identity (ones on diagonal, zeros elsewhere). + */ + template constexpr explicit Matrix4(const RectangularMatrix& other) noexcept: Matrix4x4{other} {} + /** @brief Copy constructor */ constexpr /*implicit*/ Matrix4(const RectangularMatrix<4, 4, T>& other) noexcept: Matrix4x4(other) {} diff --git a/src/Magnum/Math/Test/Matrix3Test.cpp b/src/Magnum/Math/Test/Matrix3Test.cpp index bad040124..c9937ef57 100644 --- a/src/Magnum/Math/Test/Matrix3Test.cpp +++ b/src/Magnum/Math/Test/Matrix3Test.cpp @@ -65,6 +65,7 @@ struct Matrix3Test: Corrade::TestSuite::Tester { void constructNoInit(); void constructOneValue(); void constructConversion(); + void constructFromDifferentSize(); void constructCopy(); void convert(); @@ -98,11 +99,11 @@ struct Matrix3Test: Corrade::TestSuite::Tester { }; typedef Math::Deg Deg; +typedef Math::Matrix2x2 Matrix2x2; typedef Math::Matrix3 Matrix3; typedef Math::Matrix3 Matrix3i; -typedef Math::Matrix2x2 Matrix2x2; -typedef Math::Vector3 Vector3; typedef Math::Vector2 Vector2; +typedef Math::Vector3 Vector3; Matrix3Test::Matrix3Test() { addTests({&Matrix3Test::construct, @@ -111,6 +112,7 @@ Matrix3Test::Matrix3Test() { &Matrix3Test::constructNoInit, &Matrix3Test::constructOneValue, &Matrix3Test::constructConversion, + &Matrix3Test::constructFromDifferentSize, &Matrix3Test::constructCopy, &Matrix3Test::convert, @@ -233,6 +235,25 @@ void Matrix3Test::constructConversion() { CORRADE_VERIFY((std::is_nothrow_constructible::value)); } +void Matrix3Test::constructFromDifferentSize() { + constexpr Matrix3 a{{3.0f, 5.0f, 8.0f}, + {4.5f, 4.0f, 7.0f}, + {1.0f, 2.0f, 3.0f}}; + constexpr Matrix2x2 b{Vector2{3.0f, 5.0f}, + Vector2{4.5f, 4.0f}}; + constexpr Matrix3 c{{3.0f, 5.0f, 0.0f}, + {4.5f, 4.0f, 0.0f}, + {0.0f, 0.0f, 1.0f}}; + + constexpr Matrix3 larger{b}; + CORRADE_COMPARE(larger, c); + CORRADE_COMPARE(Matrix3{b}, c); + + constexpr Matrix2x2 smaller{a}; + CORRADE_COMPARE(smaller, b); + CORRADE_COMPARE(Matrix2x2{a}, b); +} + void Matrix3Test::constructCopy() { constexpr RectangularMatrix<3, 3, Float> a(Vector<3, Float>(3.0f, 5.0f, 8.0f), Vector<3, Float>(4.5f, 4.0f, 7.0f), diff --git a/src/Magnum/Math/Test/Matrix4Test.cpp b/src/Magnum/Math/Test/Matrix4Test.cpp index c792316c7..785544913 100644 --- a/src/Magnum/Math/Test/Matrix4Test.cpp +++ b/src/Magnum/Math/Test/Matrix4Test.cpp @@ -68,6 +68,7 @@ struct Matrix4Test: Corrade::TestSuite::Tester { void constructNoInit(); void constructOneValue(); void constructConversion(); + void constructFromDifferentSize(); void constructCopy(); void convert(); @@ -112,9 +113,11 @@ struct Matrix4Test: Corrade::TestSuite::Tester { typedef Math::Deg Deg; typedef Math::Rad Rad; +typedef Math::Matrix<2, Float> Matrix2x2; +typedef Math::Matrix<3, Float> Matrix3x3; typedef Math::Matrix4 Matrix4; typedef Math::Matrix4 Matrix4i; -typedef Math::Matrix<3, Float> Matrix3x3; +typedef Math::Vector2 Vector2; typedef Math::Vector3 Vector3; typedef Math::Vector4 Vector4; typedef Math::Constants Constants; @@ -126,6 +129,7 @@ Matrix4Test::Matrix4Test() { &Matrix4Test::constructNoInit, &Matrix4Test::constructOneValue, &Matrix4Test::constructConversion, + &Matrix4Test::constructFromDifferentSize, &Matrix4Test::constructCopy, &Matrix4Test::convert, @@ -268,6 +272,27 @@ void Matrix4Test::constructConversion() { CORRADE_VERIFY((std::is_nothrow_constructible::value)); } +void Matrix4Test::constructFromDifferentSize() { + constexpr Matrix4 a{{3.0f, 5.0f, 8.0f, -3.0f}, + {4.5f, 4.0f, 7.0f, 2.0f}, + {1.0f, 2.0f, 3.0f, -1.0f}, + {7.9f, -1.0f, 8.0f, -1.5f}}; + constexpr Matrix2x2 b{Vector2{3.0f, 5.0f}, + Vector2{4.5f, 4.0f}}; + constexpr Matrix4 c{{3.0f, 5.0f, 0.0f, 0.0f}, + {4.5f, 4.0f, 0.0f, 0.0f}, + {0.0f, 0.0f, 1.0f, 0.0f}, + {0.0f, 0.0f, 0.0f, 1.0f}}; + + constexpr Matrix4 larger{b}; + CORRADE_COMPARE(larger, c); + CORRADE_COMPARE(Matrix4{b}, c); + + constexpr Matrix2x2 smaller{a}; + CORRADE_COMPARE(smaller, b); + CORRADE_COMPARE(Matrix2x2{a}, b); +} + void Matrix4Test::constructCopy() { constexpr Matrix<4, Float> a(Vector<4, Float>(3.0f, 5.0f, 8.0f, -3.0f), Vector<4, Float>(4.5f, 4.0f, 7.0f, 2.0f), diff --git a/src/Magnum/Math/Test/MatrixTest.cpp b/src/Magnum/Math/Test/MatrixTest.cpp index d8f5dc4ff..4db8e4028 100644 --- a/src/Magnum/Math/Test/MatrixTest.cpp +++ b/src/Magnum/Math/Test/MatrixTest.cpp @@ -66,6 +66,7 @@ struct MatrixTest: Corrade::TestSuite::Tester { void constructOneValue(); void constructOneComponent(); void constructConversion(); + void constructFromDifferentSize(); void constructCopy(); void convert(); @@ -84,12 +85,14 @@ struct MatrixTest: Corrade::TestSuite::Tester { void configuration(); }; +typedef Matrix<2, Float> Matrix2x2; +typedef Matrix<3, Float> Matrix3x3; typedef Matrix<4, Float> Matrix4x4; typedef Matrix<4, Int> Matrix4x4i; -typedef Matrix<3, Float> Matrix3x3; +typedef Vector<2, Float> Vector2; +typedef Vector<3, Float> Vector3; typedef Vector<4, Float> Vector4; typedef Vector<4, Int> Vector4i; -typedef Vector<3, Float> Vector3; typedef Math::Constants Constants; MatrixTest::MatrixTest() { @@ -100,6 +103,7 @@ MatrixTest::MatrixTest() { &MatrixTest::constructOneValue, &MatrixTest::constructOneComponent, &MatrixTest::constructConversion, + &MatrixTest::constructFromDifferentSize, &MatrixTest::constructCopy, &MatrixTest::convert, @@ -230,6 +234,27 @@ void MatrixTest::constructConversion() { CORRADE_VERIFY((std::is_nothrow_constructible::value)); } +void MatrixTest::constructFromDifferentSize() { + constexpr Matrix4x4 a{Vector4{3.0f, 5.0f, 8.0f, -3.0f}, + Vector4{4.5f, 4.0f, 7.0f, 2.0f}, + Vector4{1.0f, 2.0f, 3.0f, -1.0f}, + Vector4{7.9f, -1.0f, 8.0f, -1.5f}}; + constexpr Matrix2x2 b{Vector2{3.0f, 5.0f}, + Vector2{4.5f, 4.0f}}; + constexpr Matrix4x4 c{Vector4{3.0f, 5.0f, 0.0f, 0.0f}, + Vector4{4.5f, 4.0f, 0.0f, 0.0f}, + Vector4{0.0f, 0.0f, 1.0f, 0.0f}, + Vector4{0.0f, 0.0f, 0.0f, 1.0f}}; + + constexpr Matrix4x4 larger{b}; + CORRADE_COMPARE(larger, c); + CORRADE_COMPARE(Matrix4x4{b}, c); + + constexpr Matrix2x2 smaller{a}; + CORRADE_COMPARE(smaller, b); + CORRADE_COMPARE(Matrix2x2{a}, b); +} + void MatrixTest::constructCopy() { constexpr RectangularMatrix<4, 4, Float> a(Vector4(3.0f, 5.0f, 8.0f, -3.0f), Vector4(4.5f, 4.0f, 7.0f, 2.0f),