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),