From 78417dfefad57ef331969f28ab6e3623fa6c4b1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Mon, 2 Sep 2013 17:19:42 +0200 Subject: [PATCH] Math: removed integer/float RectangularMatrix multiplication and division. We would need to duplicate all the functionality found in Vector, which I don't think is needed at all. If anyone needs to do this, it is possible to "linearize" the matrix into long vector and do the operations on it. Also updated subclass operator implementation, added tests for it, both for proper returned value and proper result type. --- src/Math/Matrix.h | 25 +---- src/Math/Matrix3.h | 4 +- src/Math/Matrix4.h | 4 +- src/Math/RectangularMatrix.h | 93 +++++++++++-------- src/Math/Test/RectangularMatrixTest.cpp | 117 ++++++++++++++++++++++-- 5 files changed, 169 insertions(+), 74 deletions(-) diff --git a/src/Math/Matrix.h b/src/Math/Matrix.h index e50272c9f..edcbaaf5c 100644 --- a/src/Math/Matrix.h +++ b/src/Math/Matrix.h @@ -180,17 +180,7 @@ template class Matrix: public RectangularMatrix inline typename std::enable_if::value, Matrix>::type operator*(U number, const Matrix& matrix) { - return number*RectangularMatrix(matrix); -} -template inline typename std::enable_if::value, Matrix>::type operator/(U number, const Matrix& matrix) { - return number/RectangularMatrix(matrix); -} -template inline Matrix operator*(const Vector& vector, const RectangularMatrix& matrix) { - return RectangularMatrix<1, size, T>(vector)*matrix; -} -#endif +MAGNUM_MATRIX_OPERATOR_IMPLEMENTATION(Matrix) /** @debugoperator{Magnum::Math::Matrix} */ template inline Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Matrix& value) { @@ -198,7 +188,7 @@ template inline Corrade::Utility::Debug operator<<(Co } #ifndef DOXYGEN_GENERATING_OUTPUT -#define MAGNUM_MATRIX_SUBCLASS_IMPLEMENTATION(Type, VectorType, size) \ +#define MAGNUM_MATRIX_SUBCLASS_IMPLEMENTATION(size, Type, VectorType) \ VectorType& operator[](std::size_t col) { \ return static_cast&>(Matrix::operator[](col)); \ } \ @@ -225,17 +215,6 @@ template inline Corrade::Utility::Debug operator<<(Co 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) { \ - return number*Matrix(matrix); \ - } \ - template inline typename std::enable_if::value, Type>::type operator/(U number, const Type& matrix) { \ - return number/Matrix(matrix); \ - } \ - template inline Type operator*(const Vector& vector, const RectangularMatrix& matrix) { \ - return RectangularMatrix<1, size, T>(vector)*matrix; \ - } - namespace Implementation { template class MatrixDeterminant { diff --git a/src/Math/Matrix3.h b/src/Math/Matrix3.h index d9d9b94b0..cbcc8e972 100644 --- a/src/Math/Matrix3.h +++ b/src/Math/Matrix3.h @@ -299,10 +299,10 @@ template class Matrix3: public Matrix<3, T> { } MAGNUM_RECTANGULARMATRIX_SUBCLASS_IMPLEMENTATION(3, 3, Matrix3) - MAGNUM_MATRIX_SUBCLASS_IMPLEMENTATION(Matrix3, Vector3, 3) + MAGNUM_MATRIX_SUBCLASS_IMPLEMENTATION(3, Matrix3, Vector3) }; -MAGNUM_MATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(Matrix3, 3) +MAGNUM_MATRIXn_OPERATOR_IMPLEMENTATION(3, Matrix3) /** @debugoperator{Magnum::Math::Matrix3} */ template inline Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Matrix3& value) { diff --git a/src/Math/Matrix4.h b/src/Math/Matrix4.h index 3653f480f..12464fc9d 100644 --- a/src/Math/Matrix4.h +++ b/src/Math/Matrix4.h @@ -367,10 +367,10 @@ template class Matrix4: public Matrix<4, T> { } MAGNUM_RECTANGULARMATRIX_SUBCLASS_IMPLEMENTATION(4, 4, Matrix4) - MAGNUM_MATRIX_SUBCLASS_IMPLEMENTATION(Matrix4, Vector4, 4) + MAGNUM_MATRIX_SUBCLASS_IMPLEMENTATION(4, Matrix4, Vector4) }; -MAGNUM_MATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(Matrix4, 4) +MAGNUM_MATRIXn_OPERATOR_IMPLEMENTATION(4, Matrix4) /** @debugoperator{Magnum::Math::Matrix4} */ template inline Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Matrix4& value) { diff --git a/src/Math/RectangularMatrix.h b/src/Math/RectangularMatrix.h index 1079ef9a9..0b445cd60 100644 --- a/src/Math/RectangularMatrix.h +++ b/src/Math/RectangularMatrix.h @@ -271,11 +271,7 @@ template class RectangularMatrix { * \boldsymbol A_j = a \boldsymbol A_j * @f] */ - #ifndef DOXYGEN_GENERATING_OUTPUT - template inline typename std::enable_if::value, RectangularMatrix&>::type operator*=(U number) { - #else - template RectangularMatrix& operator*=(U number) { - #endif + RectangularMatrix& operator*=(T number) { for(std::size_t i = 0; i != cols; ++i) _data[i] *= number; @@ -285,14 +281,10 @@ template class RectangularMatrix { /** * @brief Multiply matrix with number * - * @see operator*=(U), operator*(U, const RectangularMatrix&) + * @see operator*=(T), operator*(T, const RectangularMatrix&) */ - #ifndef DOXYGEN_GENERATING_OUTPUT - template inline typename std::enable_if::value, RectangularMatrix>::type operator*(U number) const { - #else - template RectangularMatrix operator*(U number) const { - #endif - return RectangularMatrix(*this)*=number; + RectangularMatrix operator*(T number) const { + return RectangularMatrix(*this) *= number; } /** @@ -302,11 +294,7 @@ template class RectangularMatrix { * \boldsymbol A_j = \frac{\boldsymbol A_j} a * @f] */ - #ifndef DOXYGEN_GENERATING_OUTPUT - template inline typename std::enable_if::value, RectangularMatrix&>::type operator/=(U number) { - #else - template RectangularMatrix& operator/=(U number) { - #endif + RectangularMatrix& operator/=(T number) { for(std::size_t i = 0; i != cols; ++i) _data[i] /= number; @@ -316,14 +304,11 @@ template class RectangularMatrix { /** * @brief Divide matrix with number * - * @see operator/=(), operator/(U, const RectangularMatrix&) + * @see operator/=(T), + * operator/(T, const RectangularMatrix&) */ - #ifndef DOXYGEN_GENERATING_OUTPUT - template inline typename std::enable_if::value, RectangularMatrix>::type operator/(U number) const { - #else - template RectangularMatrix operator/(U number) const { - #endif - return RectangularMatrix(*this)/=number; + RectangularMatrix operator/(T number) const { + return RectangularMatrix(*this) /= number; } /** @@ -385,13 +370,16 @@ template class RectangularMatrix { /** @relates RectangularMatrix @brief Multiply number with matrix -Same as RectangularMatrix::operator*(U) const. +Same as RectangularMatrix::operator*(T) const. */ -#ifdef DOXYGEN_GENERATING_OUTPUT -template inline RectangularMatrix operator*(U number, const RectangularMatrix& matrix) { -#else -template inline typename std::enable_if::value, RectangularMatrix>::type operator*(U number, const RectangularMatrix& matrix) { -#endif +template inline RectangularMatrix operator*( + #ifdef DOXYGEN_GENERATING_OUTPUT + T + #else + typename std::common_type::type + #endif + number, const RectangularMatrix& matrix) +{ return matrix*number; } @@ -401,13 +389,16 @@ template inline typename s The computation is done column-wise. @f[ \boldsymbol B_j = \frac a {\boldsymbol A_j} @f] -@see RectangularMatrix::operator/(U) const +@see RectangularMatrix::operator/(T) const */ -#ifdef DOXYGEN_GENERATING_OUTPUT -template inline RectangularMatrix operator/(U number, const RectangularMatrix& matrix) { -#else -template inline typename std::enable_if::value, RectangularMatrix>::type operator/(U number, const RectangularMatrix& matrix) { -#endif +template inline RectangularMatrix operator/( + #ifdef DOXYGEN_GENERATING_OUTPUT + T + #else + typename std::common_type::type + #endif + number, const RectangularMatrix& matrix) +{ RectangularMatrix out; for(std::size_t i = 0; i != cols; ++i) @@ -502,20 +493,42 @@ extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utilit __VA_ARGS__ operator-(const Math::RectangularMatrix& other) const { \ return Math::RectangularMatrix::operator-(other); \ } \ - template typename std::enable_if::value, __VA_ARGS__&>::type operator*=(U number) { \ + __VA_ARGS__& operator*=(T number) { \ Math::RectangularMatrix::operator*=(number); \ return *this; \ } \ - template typename std::enable_if::value, __VA_ARGS__>::type operator*(U number) const { \ + __VA_ARGS__ operator*(T number) const { \ return Math::RectangularMatrix::operator*(number); \ } \ - template typename std::enable_if::value, __VA_ARGS__&>::type operator/=(U number) { \ + __VA_ARGS__& operator/=(T number) { \ Math::RectangularMatrix::operator/=(number); \ return *this; \ } \ - template typename std::enable_if::value, __VA_ARGS__>::type operator/(U number) const { \ + __VA_ARGS__ operator/(T number) const { \ return Math::RectangularMatrix::operator/(number); \ } + +#define MAGNUM_MATRIX_OPERATOR_IMPLEMENTATION(...) \ + template inline __VA_ARGS__ operator*(typename std::common_type::type number, const __VA_ARGS__& matrix) { \ + return number*static_cast&>(matrix); \ + } \ + template inline __VA_ARGS__ operator/(typename std::common_type::type number, const __VA_ARGS__& matrix) { \ + return number/static_cast&>(matrix); \ + } \ + template inline __VA_ARGS__ operator*(const Vector& vector, const RectangularMatrix& matrix) { \ + return Math::RectangularMatrix<1, size, T>(vector)*matrix; \ + } + +#define MAGNUM_MATRIXn_OPERATOR_IMPLEMENTATION(size, Type) \ + template inline Type operator*(typename std::common_type::type number, const Type& matrix) { \ + return number*static_cast&>(matrix); \ + } \ + template inline Type operator/(typename std::common_type::type number, const Type& matrix) { \ + return number/static_cast&>(matrix); \ + } \ + template inline Type operator*(const Vector& vector, const RectangularMatrix& matrix) { \ + return Math::RectangularMatrix<1, size, T>(vector)*matrix; \ + } #endif template inline RectangularMatrix RectangularMatrix::fromDiagonal(const Vector& diagonal) { diff --git a/src/Math/Test/RectangularMatrixTest.cpp b/src/Math/Test/RectangularMatrixTest.cpp index 598dfde17..4aa2a541e 100644 --- a/src/Math/Test/RectangularMatrixTest.cpp +++ b/src/Math/Test/RectangularMatrixTest.cpp @@ -80,6 +80,9 @@ class RectangularMatrixTest: public Corrade::TestSuite::Tester { void vector(); + void subclassTypes(); + void subclass(); + void debug(); void configuration(); }; @@ -117,6 +120,9 @@ RectangularMatrixTest::RectangularMatrixTest() { &RectangularMatrixTest::vector, + &RectangularMatrixTest::subclassTypes, + &RectangularMatrixTest::subclass, + &RectangularMatrixTest::debug, &RectangularMatrixTest::configuration}); } @@ -308,19 +314,12 @@ void RectangularMatrixTest::multiplyDivide() { CORRADE_COMPARE(-1.5f*matrix, multiplied); CORRADE_COMPARE(multiplied/-1.5f, matrix); - Math::RectangularMatrix<1, 1, Byte> matrixChar(32); - Math::RectangularMatrix<1, 1, Byte> multipliedChar(-48); - CORRADE_COMPARE(matrixChar*-1.5f, multipliedChar); - CORRADE_COMPARE(multipliedChar/-1.5f, matrixChar); - CORRADE_COMPARE(-1.5f*matrixChar, multipliedChar); - /* Divide vector with number and inverse */ Matrix2 divisor(Vector2( 1.0f, 2.0f), Vector2(-4.0f, 8.0f)); Matrix2 result(Vector2( 1.0f, 0.5f), Vector2(-0.25f, 0.125f)); CORRADE_COMPARE(1.0f/divisor, result); - CORRADE_COMPARE(-1550.0f/multipliedChar, matrixChar); } void RectangularMatrixTest::multiply() { @@ -394,6 +393,110 @@ void RectangularMatrixTest::vector() { CORRADE_COMPARE(Matrix4x3i::fromVector(b), a); } +template class BasicMat: public Math::RectangularMatrix { + public: + template BasicMat(U&&... args): Math::RectangularMatrix{std::forward(args)...} {} + + MAGNUM_RECTANGULARMATRIX_SUBCLASS_IMPLEMENTATION(size, size, BasicMat) +}; + +MAGNUM_MATRIX_OPERATOR_IMPLEMENTATION(BasicMat) + +template class BasicMat2x2: public BasicMat<2, T> { + public: + template BasicMat2x2(U&&... args): BasicMat<2, T>{std::forward(args)...} {} + + MAGNUM_RECTANGULARMATRIX_SUBCLASS_IMPLEMENTATION(2, 2, BasicMat2x2) +}; + +MAGNUM_MATRIXn_OPERATOR_IMPLEMENTATION(2, BasicMat2x2) + +typedef BasicMat2x2 Mat2x2; + +void RectangularMatrixTest::subclassTypes() { + Float* const data = nullptr; + const Float* const cdata = nullptr; + CORRADE_VERIFY((std::is_same::value)); + CORRADE_VERIFY((std::is_same::value)); + + /* Const operators */ + const Mat2x2 c; + CORRADE_VERIFY((std::is_same::value)); + CORRADE_VERIFY((std::is_same::value)); + CORRADE_VERIFY((std::is_same::value)); + CORRADE_VERIFY((std::is_same::value)); + CORRADE_VERIFY((std::is_same::value)); + CORRADE_VERIFY((std::is_same::value)); + CORRADE_VERIFY((std::is_same()), Mat2x2>::value)); + + /* Assignment operators */ + Mat2x2 a; + CORRADE_VERIFY((std::is_same::value)); + CORRADE_VERIFY((std::is_same::value)); + CORRADE_VERIFY((std::is_same::value)); + CORRADE_VERIFY((std::is_same::value)); + CORRADE_VERIFY((std::is_same::value)); + + /* Operators on variable-sized matrix */ + const BasicMat<3, Float> c2; + CORRADE_VERIFY((std::is_same>::value)); + CORRADE_VERIFY((std::is_same>::value)); + CORRADE_VERIFY((std::is_same()), BasicMat<3, Float>>::value)); +} + +void RectangularMatrixTest::subclass() { + Float data[] = {1.0f, -2.0f, 3.0f, -4.5f}; + CORRADE_COMPARE(Mat2x2::from(data), Mat2x2(Vector2(1.0f, -2.0f), + Vector2(3.0f, -4.5f))); + + const Float cdata[] = {1.0f, -2.0f, 3.0f, -4.5f}; + CORRADE_COMPARE(Mat2x2::from(cdata), Mat2x2(Vector2(1.0f, -2.0f), + Vector2(3.0f, -4.5f))); + + const Mat2x2 a(Vector2(1.0f, -3.0f), + Vector2(-3.0f, 1.0f)); + CORRADE_COMPARE(-a, Mat2x2(Vector2(-1.0f, 3.0f), + Vector2(3.0f, -1.0f))); + + Mat2x2 b(Vector2(-2.0f, 5.0f), + Vector2(5.0f, -2.0f)); + const Mat2x2 bExpected(Vector2(-1.0f, 2.0f), + Vector2(2.0f, -1.0f)); + CORRADE_COMPARE(b + a, bExpected); + + Mat2x2 c(Vector2(-2.0f, 5.0f), + Vector2(5.0f, -2.0f)); + const Mat2x2 cExpected(Vector2(-3.0f, 8.0f), + Vector2(8.0f, -3.0f)); + CORRADE_COMPARE(c - a, cExpected); + + Mat2x2 d(Vector2(-2.0f, 5.0f), + Vector2(5.0f, -2.0f)); + const Mat2x2 dExpected(Vector2(-4.0f, 10.0f), + Vector2(10.0f, -4.0f)); + CORRADE_COMPARE(d*2.0f, dExpected); + CORRADE_COMPARE(2.0f*d, dExpected); + + Mat2x2 e(Vector2(-2.0f, 5.0f), + Vector2(5.0f, -2.0f)); + CORRADE_COMPARE(e/0.5f, dExpected); + CORRADE_COMPARE(2.0f/e, Mat2x2(Vector2(-1.0f, 0.4f), + Vector2(0.4f, -1.0f))); + const Vector2 f(2.0f, 5.0f); + const Math::RectangularMatrix<2, 1, Float> g(3.0f, -1.0f); + CORRADE_COMPARE(f*g, Mat2x2(Vector2(6.0f, 15.0f), + Vector2(-2.0f, -5.0f))); + + /* Operators on variable-sized matrix */ + const BasicMat<1, Float> h(-2.0f); + CORRADE_COMPARE(2.0f*h, (BasicMat<1, Float>(-4.0f))); + CORRADE_COMPARE(2.0f/h, (BasicMat<1, Float>(-1.0f))); + + const Math::Vector<1, Float> i(2.0f); + const Math::RectangularMatrix<1, 1, Float> j(3.0f); + CORRADE_COMPARE(i*j, (BasicMat<1, Float>(6.0f))); +} + void RectangularMatrixTest::debug() { Matrix3x4 m(Vector4(3.0f, 5.0f, 8.0f, 4.0f), Vector4(4.0f, 4.0f, 7.0f, 3.0f),