From a21fd0df078c3c6245370de69b6016acd2d222da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Sat, 4 May 2013 13:35:52 +0200 Subject: [PATCH] Math: ability to convert matrices from/to external representation. --- src/Math/Matrix.h | 3 ++ src/Math/Matrix3.h | 3 ++ src/Math/Matrix4.h | 3 ++ src/Math/RectangularMatrix.h | 19 ++++++++ src/Math/Test/Matrix3Test.cpp | 55 ++++++++++++++++++++++- src/Math/Test/Matrix4Test.cpp | 58 ++++++++++++++++++++++++- src/Math/Test/MatrixTest.cpp | 54 ++++++++++++++++++++++- src/Math/Test/RectangularMatrixTest.cpp | 52 +++++++++++++++++++++- 8 files changed, 243 insertions(+), 4 deletions(-) diff --git a/src/Math/Matrix.h b/src/Math/Matrix.h index 4ebb07b6a..adcbba862 100644 --- a/src/Math/Matrix.h +++ b/src/Math/Matrix.h @@ -97,6 +97,9 @@ template class Matrix: public RectangularMatrix inline constexpr explicit Matrix(const RectangularMatrix& other): RectangularMatrix(other) {} + /** @brief Construct matrix from external representation */ + template::from(std::declval()))> inline constexpr explicit Matrix(const U& other): RectangularMatrix(Implementation::RectangularMatrixConverter::from(other)) {} + /** @brief Copy constructor */ inline constexpr Matrix(const RectangularMatrix& other): RectangularMatrix(other) {} diff --git a/src/Math/Matrix3.h b/src/Math/Matrix3.h index 344f55d86..a8fd81577 100644 --- a/src/Math/Matrix3.h +++ b/src/Math/Matrix3.h @@ -149,6 +149,9 @@ template class Matrix3: public Matrix<3, T> { /** @copydoc Matrix::Matrix(const RectangularMatrix&) */ template inline constexpr explicit Matrix3(const RectangularMatrix<3, 3, U>& other): Matrix<3, T>(other) {} + /** @brief Construct matrix from external representation */ + template::from(std::declval()))> inline constexpr explicit Matrix3(const U& other): Matrix<3, T>(Implementation::RectangularMatrixConverter<3, 3, T, U>::from(other)) {} + /** @brief Copy constructor */ inline constexpr Matrix3(const RectangularMatrix<3, 3, T>& other): Matrix<3, T>(other) {} diff --git a/src/Math/Matrix4.h b/src/Math/Matrix4.h index 9202d3437..b1c3c39d3 100644 --- a/src/Math/Matrix4.h +++ b/src/Math/Matrix4.h @@ -280,6 +280,9 @@ template class Matrix4: public Matrix<4, T> { /** @copydoc Matrix::Matrix(const RectangularMatrix&) */ template inline constexpr explicit Matrix4(const RectangularMatrix<4, 4, U>& other): Matrix<4, T>(other) {} + /** @brief Construct matrix from external representation */ + template::from(std::declval()))> inline constexpr explicit Matrix4(const U& other): Matrix<4, T>(Implementation::RectangularMatrixConverter<4, 4, T, U>::from(other)) {} + /** @brief Copy constructor */ inline constexpr Matrix4(const RectangularMatrix<4, 4, T>& other): Matrix<4, T>(other) {} diff --git a/src/Math/RectangularMatrix.h b/src/Math/RectangularMatrix.h index 48b86a3f8..3702a4aaf 100644 --- a/src/Math/RectangularMatrix.h +++ b/src/Math/RectangularMatrix.h @@ -32,6 +32,10 @@ namespace Magnum { namespace Math { +namespace Implementation { + template struct RectangularMatrixConverter; +} + /** @brief Rectangular matrix @tparam cols Column count @@ -140,12 +144,27 @@ template class RectangularMatrix { } #endif + /** @brief Construct matrix from external representation */ + #ifndef CORRADE_GCC46_COMPATIBILITY + template::from(std::declval()))> inline constexpr explicit RectangularMatrix(const U& other): RectangularMatrix(Implementation::RectangularMatrixConverter::from(other)) {} + #else + template::from(std::declval()))> inline explicit RectangularMatrix(const U& other) { + *this = Implementation::RectangularMatrixConverter::from(other); + } + #endif + /** @brief Copy constructor */ inline constexpr RectangularMatrix(const RectangularMatrix&) = default; /** @brief Assignment operator */ inline RectangularMatrix& operator=(const RectangularMatrix&) = default; + /** @brief Convert matrix to external representation */ + template::to(std::declval>()))> inline constexpr explicit operator U() const { + /** @bug Why this is not constexpr under GCC 4.6? */ + return Implementation::RectangularMatrixConverter::to(*this); + } + /** * @brief Raw data * @return One-dimensional array of `size*size` length in column-major diff --git a/src/Math/Test/Matrix3Test.cpp b/src/Math/Test/Matrix3Test.cpp index 5ff187c9a..cffdc11d0 100644 --- a/src/Math/Test/Matrix3Test.cpp +++ b/src/Math/Test/Matrix3Test.cpp @@ -28,7 +28,32 @@ #include "Math/Matrix3.h" -namespace Magnum { namespace Math { namespace Test { +struct Mat3 { + float a[9]; +}; + +namespace Magnum { namespace Math { + +namespace Implementation { + +template<> struct RectangularMatrixConverter<3, 3, float, Mat3> { + inline constexpr static RectangularMatrix<3, 3, Float> from(const Mat3& other) { + return RectangularMatrix<3, 3, Float>( + Vector<3, Float>(other.a[0], other.a[1], other.a[2]), + Vector<3, Float>(other.a[3], other.a[4], other.a[5]), + Vector<3, Float>(other.a[6], other.a[7], other.a[8])); + } + + inline constexpr static Mat3 to(const RectangularMatrix<3, 3, Float>& other) { + return Mat3{other[0][0], other[0][1], other[0][2], + other[1][0], other[1][1], other[1][2], + other[2][0], other[2][1], other[2][2]}; + } +}; + +} + +namespace Test { class Matrix3Test: public Corrade::TestSuite::Tester { public: @@ -40,6 +65,8 @@ class Matrix3Test: public Corrade::TestSuite::Tester { void constructConversion(); void constructCopy(); + void convert(); + void isRigidTransformation(); void translation(); @@ -62,6 +89,7 @@ typedef Math::Deg Deg; typedef Math::Matrix3 Matrix3; typedef Math::Matrix3 Matrix3i; typedef Math::Matrix<2, Float> Matrix2; +typedef Math::Vector3 Vector3; typedef Math::Vector2 Vector2; Matrix3Test::Matrix3Test() { @@ -71,6 +99,8 @@ Matrix3Test::Matrix3Test() { &Matrix3Test::constructConversion, &Matrix3Test::constructCopy, + &Matrix3Test::convert, + &Matrix3Test::isRigidTransformation, &Matrix3Test::translation, @@ -150,6 +180,29 @@ void Matrix3Test::constructCopy() { {7.9f, -1.0f, 8.0f})); } +void Matrix3Test::convert() { + constexpr Mat3 a{1.5f, 2.0f, -3.5f, + 2.0f, -3.1f, 0.4f, + 9.5f, -1.5f, 0.1f}; + constexpr Matrix3 b(Vector3(1.5f, 2.0f, -3.5f), + Vector3(2.0f, -3.1f, 0.4f), + Vector3(9.5f, -1.5f, 0.1f)); + + constexpr Matrix3 c(b); + CORRADE_COMPARE(c, b); + + #ifndef CORRADE_GCC46_COMPATIBILITY + constexpr /* Not constexpr under GCC < 4.7 */ + #endif + Mat3 d(b); + for(std::size_t i = 0; i != 9; ++i) + CORRADE_COMPARE(d.a[0], a.a[0]); + + /* Implicit conversion is not allowed */ + CORRADE_VERIFY(!(std::is_convertible::value)); + CORRADE_VERIFY(!(std::is_convertible::value)); +} + void Matrix3Test::isRigidTransformation() { CORRADE_VERIFY(!Matrix3({1.0f, 0.0f, 0.0f}, {0.1f, 1.0f, 0.0f}, diff --git a/src/Math/Test/Matrix4Test.cpp b/src/Math/Test/Matrix4Test.cpp index a00d5c781..bc79ef964 100644 --- a/src/Math/Test/Matrix4Test.cpp +++ b/src/Math/Test/Matrix4Test.cpp @@ -28,7 +28,34 @@ #include "Math/Matrix4.h" -namespace Magnum { namespace Math { namespace Test { +struct Mat4 { + float a[16]; +}; + +namespace Magnum { namespace Math { + +namespace Implementation { + +template<> struct RectangularMatrixConverter<4, 4, float, Mat4> { + inline constexpr static RectangularMatrix<4, 4, Float> from(const Mat4& other) { + return RectangularMatrix<4, 4, Float>( + Vector<4, Float>(other.a[0], other.a[1], other.a[2], other.a[3]), + Vector<4, Float>(other.a[4], other.a[5], other.a[6], other.a[7]), + Vector<4, Float>(other.a[8], other.a[9], other.a[10], other.a[11]), + Vector<4, Float>(other.a[12], other.a[13], other.a[14], other.a[15])); + } + + inline constexpr static Mat4 to(const RectangularMatrix<4, 4, Float>& other) { + return Mat4{other[0][0], other[0][1], other[0][2], other[0][3], + other[1][0], other[1][1], other[1][2], other[1][3], + other[2][0], other[2][1], other[2][2], other[2][3], + other[3][0], other[3][1], other[3][2], other[3][3]}; + } +}; + +} + +namespace Test { class Matrix4Test: public Corrade::TestSuite::Tester { public: @@ -40,6 +67,8 @@ class Matrix4Test: public Corrade::TestSuite::Tester { void constructConversion(); void constructCopy(); + void convert(); + void isRigidTransformation(); void translation(); @@ -77,6 +106,8 @@ Matrix4Test::Matrix4Test() { &Matrix4Test::constructConversion, &Matrix4Test::constructCopy, + &Matrix4Test::convert, + &Matrix4Test::isRigidTransformation, &Matrix4Test::translation, @@ -171,6 +202,31 @@ void Matrix4Test::constructCopy() { {7.9f, -1.0f, 8.0f, -1.5f})); } +void Matrix4Test::convert() { + constexpr Mat4 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 Matrix4 b({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 Matrix4 c(b); + CORRADE_COMPARE(c, b); + + #ifndef CORRADE_GCC46_COMPATIBILITY + constexpr /* Not constexpr under GCC < 4.7 */ + #endif + Mat4 d(b); + for(std::size_t i = 0; i != 16; ++i) + CORRADE_COMPARE(d.a[i], a.a[i]); + + /* Implicit conversion is not allowed */ + CORRADE_VERIFY(!(std::is_convertible::value)); + CORRADE_VERIFY(!(std::is_convertible::value)); +} + void Matrix4Test::isRigidTransformation() { CORRADE_VERIFY(!Matrix4({1.0f, 0.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f, 0.0f}, diff --git a/src/Math/Test/MatrixTest.cpp b/src/Math/Test/MatrixTest.cpp index 92061d41d..f22f2934b 100644 --- a/src/Math/Test/MatrixTest.cpp +++ b/src/Math/Test/MatrixTest.cpp @@ -28,7 +28,32 @@ #include "Math/Matrix.h" -namespace Magnum { namespace Math { namespace Test { +struct Mat3 { + float a[9]; +}; + +namespace Magnum { namespace Math { + +namespace Implementation { + +template<> struct RectangularMatrixConverter<3, 3, float, Mat3> { + inline constexpr static RectangularMatrix<3, 3, Float> from(const Mat3& other) { + return RectangularMatrix<3, 3, Float>( + Vector<3, Float>(other.a[0], other.a[1], other.a[2]), + Vector<3, Float>(other.a[3], other.a[4], other.a[5]), + Vector<3, Float>(other.a[6], other.a[7], other.a[8])); + } + + inline constexpr static Mat3 to(const RectangularMatrix<3, 3, Float>& other) { + return Mat3{other[0][0], other[0][1], other[0][2], + other[1][0], other[1][1], other[1][2], + other[2][0], other[2][1], other[2][2]}; + } +}; + +} + +namespace Test { class MatrixTest: public Corrade::TestSuite::Tester { public: @@ -40,6 +65,8 @@ class MatrixTest: public Corrade::TestSuite::Tester { void constructConversion(); void constructCopy(); + void convert(); + void isOrthogonal(); void trace(); @@ -67,6 +94,8 @@ MatrixTest::MatrixTest() { &MatrixTest::constructConversion, &MatrixTest::constructCopy, + &MatrixTest::convert, + &MatrixTest::isOrthogonal, &MatrixTest::trace, @@ -149,6 +178,29 @@ void MatrixTest::constructCopy() { Vector4(7.9f, -1.0f, 8.0f, -1.5f))); } +void MatrixTest::convert() { + constexpr Mat3 a{1.5f, 2.0f, -3.5f, + 2.0f, -3.1f, 0.4f, + 9.5f, -1.5f, 0.1f}; + constexpr Matrix3 b(Vector3(1.5f, 2.0f, -3.5f), + Vector3(2.0f, -3.1f, 0.4f), + Vector3(9.5f, -1.5f, 0.1f)); + + constexpr Matrix3 c(b); + CORRADE_COMPARE(c, b); + + #ifndef CORRADE_GCC46_COMPATIBILITY + constexpr /* Not constexpr under GCC < 4.7 */ + #endif + Mat3 d(b); + for(std::size_t i = 0; i != 9; ++i) + CORRADE_COMPARE(d.a[i], a.a[i]); + + /* Implicit conversion is not allowed */ + CORRADE_VERIFY(!(std::is_convertible::value)); + CORRADE_VERIFY(!(std::is_convertible::value)); +} + void MatrixTest::isOrthogonal() { CORRADE_VERIFY(!Matrix3(Vector3(1.0f, 0.0f, 0.0f), Vector3(0.0f, 1.0f, 0.0f), diff --git a/src/Math/Test/RectangularMatrixTest.cpp b/src/Math/Test/RectangularMatrixTest.cpp index ab25a608c..48b2ecee3 100644 --- a/src/Math/Test/RectangularMatrixTest.cpp +++ b/src/Math/Test/RectangularMatrixTest.cpp @@ -28,7 +28,30 @@ #include "Math/RectangularMatrix.h" -namespace Magnum { namespace Math { namespace Test { +struct Mat2x3 { + float a[6]; +}; + +namespace Magnum { namespace Math { + +namespace Implementation { + +template<> struct RectangularMatrixConverter<2, 3, float, Mat2x3> { + inline constexpr static RectangularMatrix<2, 3, Float> from(const Mat2x3& other) { + return RectangularMatrix<2, 3, Float>( + Vector<3, Float>(other.a[0], other.a[1], other.a[2]), + Vector<3, Float>(other.a[3], other.a[4], other.a[5])); + } + + inline constexpr static Mat2x3 to(const RectangularMatrix<2, 3, Float>& other) { + return Mat2x3{other[0][0], other[0][1], other[0][2], + other[1][0], other[1][1], other[1][2]}; + } +}; + +} + +namespace Test { class RectangularMatrixTest: public Corrade::TestSuite::Tester { public: @@ -41,6 +64,7 @@ class RectangularMatrixTest: public Corrade::TestSuite::Tester { void constructFromDiagonal(); void constructCopy(); + void convert(); void data(); void row(); @@ -77,6 +101,7 @@ RectangularMatrixTest::RectangularMatrixTest() { &RectangularMatrixTest::constructFromDiagonal, &RectangularMatrixTest::constructCopy, + &RectangularMatrixTest::convert, &RectangularMatrixTest::data, &RectangularMatrixTest::row, @@ -168,6 +193,31 @@ void RectangularMatrixTest::constructCopy() { Vector4(9.0f, 10.0f, 11.0f, 12.0f))); } +void RectangularMatrixTest::convert() { + typedef RectangularMatrix<2, 3, Float> Matrix2x3; + constexpr Mat2x3 a{1.5f, 2.0f, -3.5f, + 2.0f, -3.1f, 0.4f}; + constexpr Matrix2x3 b(Vector3(1.5f, 2.0f, -3.5f), + Vector3(2.0f, -3.1f, 0.4f)); + + #ifndef CORRADE_GCC46_COMPATIBILITY + constexpr /* Not constexpr under GCC < 4.7 */ + #endif + Matrix2x3 c(b); + CORRADE_COMPARE(c, b); + + #ifndef CORRADE_GCC46_COMPATIBILITY + constexpr /* Not constexpr under GCC < 4.7 */ + #endif + Mat2x3 d(b); + for(std::size_t i = 0; i != 5; ++i) + CORRADE_COMPARE(d.a[i], a.a[i]); + + /* Implicit conversion is not allowed */ + CORRADE_VERIFY(!(std::is_convertible::value)); + CORRADE_VERIFY(!(std::is_convertible::value)); +} + void RectangularMatrixTest::data() { Matrix3x4 m; Vector4 vector(4.0f, 5.0f, 6.0f, 7.0f);