diff --git a/doc/matrix-vector.dox b/doc/matrix-vector.dox index 9faab0993..6c50d5b33 100644 --- a/doc/matrix-vector.dox +++ b/doc/matrix-vector.dox @@ -14,9 +14,9 @@ easier. %Magnum has three main matrix and vector classes: RectangularMatrix, (square) Matrix and Vector. To achieve greatest code reuse, %Matrix is internally -square %RectangularMatrix and %Vector is internally one-column -%RectangularMatrix. Both vectors and matrices can have arbitrary size (known -at compile time) and can store any meaningful type. +square %RectangularMatrix and %RectangularMatrix is internally array of one or +more %Vector instances. Both vectors and matrices can have arbitrary size +(known at compile time) and can store any arithmetic type. Each subclass brings some specialization to its superclass and for most common vector and matrix sizes there are specialized classes Matrix3 and Matrix4, @@ -50,14 +50,15 @@ Color4 black1; // {0.0f, 0.0f, 0.0f, 1.0f} Color4 black2; // {0, 0, 0, 255} @endcode -Most common and most efficient way to create matrix or vector is to pass -values of all components to the constructor. +Most common and most efficient way to create vector is to pass all values to +constructor, matrix is created by passing all column vectors to the +constructor. @code -Matrix3 mat(0, 1, 2, - 3, 4, 5, - 6, 7, 8); // column-major (see explanation why below) - Vector3 vec(0, 1, 2); + +Matrix3 mat({0, 1, 2}, + {3, 4, 5}, + {6, 7, 8}); @endcode All constructors check number of passed arguments and the errors are catched at compile time. @@ -83,8 +84,8 @@ same row count; vectors from vector and scalar: @code RectangularMatrix<2, 3, int> a; Vector3 b, c; -Matrix3 mat = Matrix3::from(b, a, c); -Vector<8, int> vec = Vector<8, int>::from(1, b, 2, c); +Matrix3 mat(a, b); +Vector<8, int> vec(1, b, 2, c); @endcode It is also possible to create them from an C-style array. The function does @@ -113,14 +114,10 @@ directly: RectangularMatrix<3, 2, int> a; a[2] /= 2; // third column (column major indexing, see explanation below) a[0][1] = 5; // first column, second element -a(0, 1) += 3; // first column, second element (preferred) Vector<3, int> b; b[1] = 1; // second element @endcode -For accessing matrix element prefer round bracket operator, as it is possibly -faster than the double square brackets (but never slower) and isn't prone to -compiler mis-optimizations. Fixed-size vector subclasses have functions for accessing named components and subparts: @@ -152,23 +149,19 @@ implications and it may differ from what is common in mathematics: @code RectangularMatrix<2, 3, int> mat; // two columns, three rows @endcode -- Order of components in matrix constructors is also column-major, so the - elements passed in constructor doesn't need to be reordered internally - before putting them into data array: +- Order of components in matrix constructors is also column-major, further + emphasized by requirement that you have to pass directly column vectors: @code -Matrix3 mat(0, 1, 2, - 3, 4, 5, - 6, 7, 8); // first column is {0, 1, 2} +Matrix3 mat({0, 1, 2}, + {3, 4, 5}, + {6, 7, 8}); // first column is {0, 1, 2} @endcode -- Element accessing order is also column-major. It costs virtually no time to - return reference to portion of data array as column vector, thus the bracket - operator is accessing columns. Returned vector has also its own bracket - operator, which is indexing rows. To avoid confusion, first parameter of - round bracket operator is thus also column index. +- Element accessing order is also column-major, thus the bracket operator is + accessing columns. Returned vector has also its own bracket operator, which + is then indexing rows. @code mat[0] *= 2; // first column -mat[2][0] = 5; // first element of first column vector -mat(2, 0) += 3; // first element of first column +mat[2][0] = 5; // first element of first column @endcode - Various algorithms which commonly operate on matrix rows (such as @ref Algorithms::GaussJordan "Gauss-Jordan elimination") have faster diff --git a/src/Color.h b/src/Color.h index 27e651984..483137267 100644 --- a/src/Color.h +++ b/src/Color.h @@ -22,7 +22,6 @@ #include #include "Math/Functions.h" -#include "Math/MathTypeTraits.h" #include "Math/Vector4.h" #include "Magnum.h" @@ -197,7 +196,7 @@ class Color3: public Math::Vector3 { inline constexpr /*implicit*/ Color3(T r, T g, T b): Math::Vector3(r, g, b) {} /** @brief Copy constructor */ - inline constexpr Color3(const Math::RectangularMatrix<1, 3, T>& other): Math::Vector3(other) {} + inline constexpr Color3(const Math::Vector<3, T>& other): Math::Vector3(other) {} inline T& r() { return Math::Vector3::x(); } /**< @brief R component */ inline constexpr T r() const { return Math::Vector3::x(); } /**< @overload */ @@ -252,7 +251,6 @@ class Color3: public Math::Vector3 { } MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(Color3, 3) - MAGNUM_RECTANGULARMATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(1, 3, Color3) }; MAGNUM_VECTOR_SUBCLASS_OPERATOR_IMPLEMENTATION(Color3, 3) @@ -325,7 +323,7 @@ class Color4: public Math::Vector4 { inline constexpr /*implicit*/ Color4(const Math::Vector3& rgb, T a = Implementation::defaultAlpha()): Math::Vector4(rgb[0], rgb[1], rgb[2], a) {} /** @brief Copy constructor */ - inline constexpr Color4(const Math::RectangularMatrix<1, 4, T>& other): Math::Vector4(other) {} + inline constexpr Color4(const Math::Vector<4, T>& other): Math::Vector4(other) {} inline T& r() { return Math::Vector4::x(); } /**< @brief R component */ inline constexpr T r() const { return Math::Vector4::x(); } /**< @overload */ @@ -366,7 +364,6 @@ class Color4: public Math::Vector4 { } MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(Color4, 4) - MAGNUM_RECTANGULARMATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(1, 4, Color4) }; MAGNUM_VECTOR_SUBCLASS_OPERATOR_IMPLEMENTATION(Color4, 4) diff --git a/src/Math/Algorithms/GaussJordan.h b/src/Math/Algorithms/GaussJordan.h index 30154fbab..dc1734346 100644 --- a/src/Math/Algorithms/GaussJordan.h +++ b/src/Math/Algorithms/GaussJordan.h @@ -76,7 +76,7 @@ template bool GaussJordan::inPlaceT /* Find max pivot */ std::size_t rowMax = row; for(std::size_t row2 = row+1; row2 != size; ++row2) - if(std::abs(a(row2, row)) > std::abs(a(rowMax, row))) + if(std::abs(a[row2][row]) > std::abs(a[rowMax][row])) rowMax = row2; /* Swap the rows */ @@ -84,12 +84,12 @@ template bool GaussJordan::inPlaceT std::swap(t[row], t[rowMax]); /* Singular */ - if(MathTypeTraits::equals(a(row, row), 0)) + if(MathTypeTraits::equals(a[row][row], T(0))) return false; /* Eliminate column */ for(std::size_t row2 = row+1; row2 != size; ++row2) { - T c = a(row2, row)/a(row, row); + T c = a[row2][row]/a[row][row]; a[row2] -= a[row]*c; t[row2] -= t[row]*c; @@ -98,10 +98,10 @@ template bool GaussJordan::inPlaceT /* Backsubstitute */ for(std::size_t row = size; row != 0; --row) { - T c = T(1)/a(row-1, row-1); + T c = T(1)/a[row-1][row-1]; for(std::size_t row2 = 0; row2 != row-1; ++row2) - t[row2] -= t[row-1]*a(row2, row-1)*c; + t[row2] -= t[row-1]*a[row2][row-1]*c; /* Normalize the row */ t[row-1] *= c; diff --git a/src/Math/Algorithms/Test/GaussJordanTest.cpp b/src/Math/Algorithms/Test/GaussJordanTest.cpp index aad48debd..7bf870708 100644 --- a/src/Math/Algorithms/Test/GaussJordanTest.cpp +++ b/src/Math/Algorithms/Test/GaussJordanTest.cpp @@ -29,6 +29,7 @@ class GaussJordanTest: public Corrade::TestSuite::Tester { }; typedef Matrix<4, float> Matrix4; +typedef Vector<4, float> Vector4; GaussJordanTest::GaussJordanTest() { addTests(&GaussJordanTest::singular, @@ -36,25 +37,25 @@ GaussJordanTest::GaussJordanTest() { } void GaussJordanTest::singular() { - Matrix4 a(1.0f, 2.0f, 3.0f, 4.0f, - 2.0f, 3.0f, -7.0f, 11.0f, - 2.0f, 4.0f, 6.0f, 8.0f, - 1.0f, 2.0f, 7.0f, 40.0f); + Matrix4 a(Vector4(1.0f, 2.0f, 3.0f, 4.0f), + Vector4(2.0f, 3.0f, -7.0f, 11.0f), + Vector4(2.0f, 4.0f, 6.0f, 8.0f), + Vector4(1.0f, 2.0f, 7.0f, 40.0f)); RectangularMatrix<4, 1, float> t; CORRADE_VERIFY(!GaussJordan::inPlaceTransposed(a, t)); } void GaussJordanTest::invert() { - Matrix4 a(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); - - Matrix4 expectedInverse(-60/103.0f, 71/103.0f, -4/103.0f, 3/103.0f, - -66/103.0f, 109/103.0f, -25/103.0f, -7/103.0f, - 177/412.0f, -97/206.0f, 53/412.0f, -7/206.0f, - 259/412.0f, -185/206.0f, 31/412.0f, 27/206.0f); + Matrix4 a(Vector4(3.0f, 5.0f, 8.0f, 4.0f), + Vector4(4.0f, 4.0f, 7.0f, 3.0f), + Vector4(7.0f, -1.0f, 8.0f, 0.0f), + Vector4(9.0f, 4.0f, 5.0f, 9.0f)); + + Matrix4 expectedInverse(Vector4(-60/103.0f, 71/103.0f, -4/103.0f, 3/103.0f), + Vector4(-66/103.0f, 109/103.0f, -25/103.0f, -7/103.0f), + Vector4(177/412.0f, -97/206.0f, 53/412.0f, -7/206.0f), + Vector4(259/412.0f, -185/206.0f, 31/412.0f, 27/206.0f)); Matrix4 a2(a); Matrix4 inverse(Matrix4::Identity); diff --git a/src/Math/Algorithms/Test/GramSchmidtTest.cpp b/src/Math/Algorithms/Test/GramSchmidtTest.cpp index 764616324..528c6b82f 100644 --- a/src/Math/Algorithms/Test/GramSchmidtTest.cpp +++ b/src/Math/Algorithms/Test/GramSchmidtTest.cpp @@ -34,11 +34,9 @@ GramSchmidtTest::GramSchmidtTest() { } void GramSchmidtTest::test() { - Matrix3 m( - 3.0f, 5.0f, 8.0f, - 4.0f, 4.0f, 7.0f, - 7.0f, -1.0f, 8.0f - ); + Matrix3 m(Vector3(3.0f, 5.0f, 8.0f), + Vector3(4.0f, 4.0f, 7.0f), + Vector3(7.0f, -1.0f, 8.0f)); Matrix3 normalized = Algorithms::gramSchmidt(m); @@ -56,9 +54,9 @@ void GramSchmidtTest::test() { CORRADE_COMPARE(Vector3::dot(normalized[1], normalized[2]), 0.0f); /* Just to be sure */ - Matrix3 expected( 0.303046f, 0.505076f, 0.808122f, - 0.928316f, -0.348119f, -0.130544f, - -0.215388f, -0.789754f, 0.574367f); + Matrix3 expected(Vector3( 0.303046f, 0.505076f, 0.808122f), + Vector3( 0.928316f, -0.348119f, -0.130544f), + Vector3(-0.215388f, -0.789754f, 0.574367f)); CORRADE_COMPARE(normalized, expected); } diff --git a/src/Math/Geometry/Distance.h b/src/Math/Geometry/Distance.h index 2268f1f95..0433887d4 100644 --- a/src/Math/Geometry/Distance.h +++ b/src/Math/Geometry/Distance.h @@ -44,7 +44,7 @@ class Distance { * @see linePointSquared(const Vector2&, const Vector2&, const Vector2&) */ template inline static T linePoint(const Vector2& a, const Vector2& b, const Vector2& point) { - return std::abs(Matrix<2, T>::from(b - a, a - point).determinant())/(b - a).length(); + return std::abs(Matrix<2, T>(b - a, a - point).determinant())/(b - a).length(); } /** @@ -59,7 +59,7 @@ class Distance { */ template inline static T linePointSquared(const Vector2& a, const Vector2& b, const Vector2& point) { Vector2 bMinusA = b - a; - return Math::pow<2>(Matrix<2, T>::from(bMinusA, a - point).determinant())/bMinusA.dot(); + return Math::pow<2>(Matrix<2, T>(bMinusA, a - point).determinant())/bMinusA.dot(); } /** @@ -134,7 +134,7 @@ class Distance { return std::sqrt(pointDistanceB); /* Between A and B */ - return std::abs(Matrix<2, T>::from(bMinusA, -pointMinusA).determinant())/std::sqrt(bDistanceA); + return std::abs(Matrix<2, T>(bMinusA, -pointMinusA).determinant())/std::sqrt(bDistanceA); } /** @@ -160,7 +160,7 @@ class Distance { return pointDistanceB; /* Between A and B */ - return Math::pow<2>(Matrix<2, T>::from(bMinusA, -pointMinusA).determinant())/bDistanceA; + return Math::pow<2>(Matrix<2, T>(bMinusA, -pointMinusA).determinant())/bDistanceA; } /** diff --git a/src/Math/Matrix.h b/src/Math/Matrix.h index 1e17d95f4..e73930c58 100644 --- a/src/Math/Matrix.h +++ b/src/Math/Matrix.h @@ -64,27 +64,19 @@ template class Matrix: public RectangularMatrix inline constexpr /*implicit*/ Matrix(T first, U... next): RectangularMatrix(first, next...) {} + template inline constexpr /*implicit*/ Matrix(const Vector& first, const U&... next): RectangularMatrix(first, next...) {} /** @brief Copy constructor */ inline constexpr Matrix(const RectangularMatrix& other): RectangularMatrix(other) {} - /** @brief Multiply and assign matrix operator */ - inline Matrix& operator*=(const RectangularMatrix& other) { - return (*this = *this*other); - } - /** * @brief Trace of the matrix * @@ -96,7 +88,7 @@ template class Matrix: public RectangularMatrix class Matrix: public RectangularMatrix= skipCol), - row + (row >= skipRow)); + out[col][row] = (*this)[col + (col >= skipCol)] + [row + (row >= skipRow)]; return out; } @@ -143,7 +135,7 @@ template class Matrix: public RectangularMatrix class Matrix: public RectangularMatrix::operator*(other); } MAGNUM_RECTANGULARMATRIX_SUBCLASS_IMPLEMENTATION(size, size, Matrix) - MAGNUM_RECTANGULARMATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(size, size, Matrix) #endif }; @@ -171,6 +162,9 @@ template inline typename std::enable_if 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 /** @debugoperator{Magnum::Math::Matrix} */ @@ -180,21 +174,6 @@ template inline Corrade::Utility::Debug operator<<(Co #ifndef DOXYGEN_GENERATING_OUTPUT #define MAGNUM_MATRIX_SUBCLASS_IMPLEMENTATION(Type, VectorType, size) \ - inline constexpr static Type& from(T* data) { \ - return *reinterpret_cast*>(data); \ - } \ - inline constexpr static const Type& from(const T* data) { \ - return *reinterpret_cast*>(data); \ - } \ - template inline constexpr static Type from(const Vector& first, const U&... next) { \ - return Matrix::from(first, next...); \ - } \ - \ - inline Type& operator=(const Type& other) { \ - Matrix::operator=(other); \ - return *this; \ - } \ - \ inline VectorType& operator[](std::size_t col) { \ return VectorType::from(Matrix::data()+col*size); \ } \ @@ -205,10 +184,6 @@ template inline Corrade::Utility::Debug operator<<(Co inline Type operator*(const Matrix& other) const { \ return Matrix::operator*(other); \ } \ - inline Type& operator*=(const Matrix& other) { \ - Matrix::operator*=(other); \ - return *this; \ - } \ template inline RectangularMatrix operator*(const RectangularMatrix& other) const { \ return Matrix::operator*(other); \ } \ @@ -225,6 +200,9 @@ template inline Corrade::Utility::Debug operator<<(Co } \ 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 { @@ -235,7 +213,7 @@ template class MatrixDeterminant { T out(0); for(std::size_t col = 0; col != size; ++col) - out += ((col & 1) ? -1 : 1)*m(col, 0)*m.ij(col, 0).determinant(); + out += ((col & 1) ? -1 : 1)*m[col][0]*m.ij(col, 0).determinant(); return out; } @@ -244,14 +222,14 @@ template class MatrixDeterminant { template class MatrixDeterminant<2, T> { public: inline constexpr T operator()(const Matrix<2, T>& m) { - return m(0, 0)*m(1, 1) - m(1, 0)*m(0, 1); + return m[0][0]*m[1][1] - m[1][0]*m[0][1]; } }; template class MatrixDeterminant<1, T> { public: inline constexpr T operator()(const Matrix<1, T>& m) { - return m(0, 0); + return m[0][0]; } }; diff --git a/src/Math/Matrix3.h b/src/Math/Matrix3.h index 65014d7e7..832e02347 100644 --- a/src/Math/Matrix3.h +++ b/src/Math/Matrix3.h @@ -43,11 +43,9 @@ template class Matrix3: public Matrix<3, T> { * Vector2::xAxis(), Vector2::yAxis() */ inline constexpr static Matrix3 translation(const Vector2& vector) { - return Matrix3( /* Column-major! */ - T(1), T(0), T(0), - T(0), T(1), T(0), - vector.x(), vector.y(), T(1) - ); + return {{ T(1), T(0), T(0)}, + { T(0), T(1), T(0)}, + {vector.x(), vector.y(), T(1)}}; } /** @@ -58,11 +56,9 @@ template class Matrix3: public Matrix<3, T> { * Vector2::xScale(), Vector2::yScale() */ inline constexpr static Matrix3 scaling(const Vector2& vector) { - return Matrix3( /* Column-major! */ - vector.x(), T(0), T(0), - T(0), vector.y(), T(0), - T(0), T(0), T(1) - ); + return {{vector.x(), T(0), T(0)}, + { T(0), vector.y(), T(0)}, + { T(0), T(0), T(1)}}; } /** @@ -76,11 +72,9 @@ template class Matrix3: public Matrix<3, T> { T sine = std::sin(angle); T cosine = std::cos(angle); - return Matrix3( /* Column-major! */ - cosine, sine, T(0), - -sine, cosine, T(0), - T(0), T(0), T(1) - ); + return {{ cosine, sine, T(0)}, + { -sine, cosine, T(0)}, + { T(0), T(0), T(1)}}; } /** @@ -93,7 +87,7 @@ template class Matrix3: public Matrix<3, T> { static Matrix3 reflection(const Vector2& normal) { CORRADE_ASSERT(MathTypeTraits::equals(normal.dot(), T(1)), "Math::Matrix3::reflection(): normal must be normalized", {}); - return from(Matrix<2, T>() - T(2)*normal*normal.transposed(), {}); + return from(Matrix<2, T>() - T(2)*normal*RectangularMatrix<1, 2, T>(normal).transposed(), {}); } /** @@ -116,11 +110,9 @@ template class Matrix3: public Matrix<3, T> { * @see rotationScaling() const, translation() const */ static Matrix3 from(const Matrix<2, T>& rotationScaling, const Vector2& translation) { - return from( - Vector3(rotationScaling[0], T(0)), - Vector3(rotationScaling[1], T(0)), - Vector3(translation, T(1)) - ); + return {{rotationScaling[0], T(0)}, + {rotationScaling[1], T(0)}, + { translation, T(1)}}; } /** @copydoc Matrix::Matrix(ZeroType) */ @@ -128,13 +120,13 @@ template class Matrix3: public Matrix<3, T> { /** @copydoc Matrix::Matrix(IdentityType, T) */ inline constexpr /*implicit*/ Matrix3(typename Matrix<3, T>::IdentityType = (Matrix<3, T>::Identity), T value = T(1)): Matrix<3, T>( - value, T(0), T(0), - T(0), value, T(0), - T(0), T(0), value + Vector<3, T>(value, T(0), T(0)), + Vector<3, T>( T(0), value, T(0)), + Vector<3, T>( T(0), T(0), value) ) {} - /** @copydoc Matrix::Matrix */ - template inline constexpr /*implicit*/ Matrix3(T first, U... next): Matrix<3, T>(first, next...) {} + /** @brief %Matrix from column vectors */ + inline constexpr /*implicit*/ Matrix3(const Vector3& first, const Vector3& second, const Vector3& third): Matrix<3, T>(first, second, third) {} /** @brief Copy constructor */ inline constexpr Matrix3(const RectangularMatrix<3, 3, T>& other): Matrix<3, T>(other) {} @@ -147,9 +139,8 @@ template class Matrix3: public Matrix<3, T> { * rotation(T), Matrix4::rotationScaling() const */ inline Matrix<2, T> rotationScaling() const { - return Matrix<2, T>::from( - (*this)[0].xy(), - (*this)[1].xy()); + return {(*this)[0].xy(), + (*this)[1].xy()}; } /** @@ -159,9 +150,8 @@ template class Matrix3: public Matrix<3, T> { * @see rotationScaling() const, rotation(T), Matrix4::rotation() const */ inline Matrix<2, T> rotation() const { - return Matrix<2, T>::from( - (*this)[0].xy().normalized(), - (*this)[1].xy().normalized()); + return {(*this)[0].xy().normalized(), + (*this)[1].xy().normalized()}; } /** @@ -202,7 +192,7 @@ template class Matrix3: public Matrix<3, T> { * @see 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), + 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", {}); Matrix<2, T> inverseRotation = rotationScaling().transposed(); CORRADE_ASSERT((inverseRotation*rotationScaling() == Matrix<2, T>()), @@ -216,10 +206,12 @@ template class Matrix3: public Matrix<3, T> { } #endif + MAGNUM_RECTANGULARMATRIX_SUBCLASS_IMPLEMENTATION(3, 3, Matrix3) MAGNUM_MATRIX_SUBCLASS_IMPLEMENTATION(Matrix3, Vector3, 3) - MAGNUM_RECTANGULARMATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(3, 3, Matrix3) }; +MAGNUM_MATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(Matrix3, 3) + /** @debugoperator{Magnum::Math::Matrix3} */ template inline Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Matrix3& value) { return debug << static_cast&>(value); diff --git a/src/Math/Matrix4.h b/src/Math/Matrix4.h index dbbcaaf04..cbfa7ca4e 100644 --- a/src/Math/Matrix4.h +++ b/src/Math/Matrix4.h @@ -43,12 +43,10 @@ template class Matrix4: public Matrix<4, T> { * Vector3::xAxis(), Vector3::yAxis(), Vector3::zAxis() */ inline constexpr static Matrix4 translation(const Vector3& vector) { - return Matrix4( /* Column-major! */ - T(1), T(0), T(0), T(0), - T(0), T(1), T(0), T(0), - T(0), T(0), T(1), T(0), - vector.x(), vector.y(), vector.z(), T(1) - ); + return {{ T(1), T(0), T(0), T(0)}, + { T(0), T(1), T(0), T(0)}, + { T(0), T(0), T(1), T(0)}, + {vector.x(), vector.y(), vector.z(), T(1)}}; } /** @@ -59,12 +57,10 @@ template class Matrix4: public Matrix<4, T> { * Vector3::xScale(), Vector3::yScale(), Vector3::zScale() */ inline constexpr static Matrix4 scaling(const Vector3& vector) { - return Matrix4( /* Column-major! */ - vector.x(), T(0), T(0), T(0), - T(0), vector.y(), T(0), T(0), - T(0), T(0), vector.z(), T(0), - T(0), T(0), T(0), T(1) - ); + return {{vector.x(), T(0), T(0), T(0)}, + { T(0), vector.y(), T(0), T(0)}, + { T(0), T(0), vector.z(), T(0)}, + { T(0), T(0), T(0), T(1)}}; } /** @@ -92,21 +88,21 @@ template class Matrix4: public Matrix<4, T> { T yz = normalizedAxis.y()*normalizedAxis.z(); T zz = normalizedAxis.z()*normalizedAxis.z(); - return Matrix4( /* Column-major! */ - cosine + xx*oneMinusCosine, + return { + {cosine + xx*oneMinusCosine, xy*oneMinusCosine + normalizedAxis.z()*sine, xz*oneMinusCosine - normalizedAxis.y()*sine, - T(0), - xy*oneMinusCosine - normalizedAxis.z()*sine, + T(0)}, + {xy*oneMinusCosine - normalizedAxis.z()*sine, cosine + yy*oneMinusCosine, yz*oneMinusCosine + normalizedAxis.x()*sine, - T(0), - xz*oneMinusCosine + normalizedAxis.y()*sine, + T(0)}, + {xz*oneMinusCosine + normalizedAxis.y()*sine, yz*oneMinusCosine - normalizedAxis.x()*sine, cosine + zz*oneMinusCosine, - T(0), - T(0), T(0), T(0), T(1) - ); + T(0)}, + {T(0), T(0), T(0), T(1)} + }; } /** @@ -121,12 +117,10 @@ template class Matrix4: public Matrix<4, T> { T sine = std::sin(angle); T cosine = std::cos(angle); - return Matrix4( /* Column-major! */ - T(1), T(0), T(0), T(0), - T(0), cosine, sine, T(0), - T(0), -sine, cosine, T(0), - T(0), T(0), T(0), T(1) - ); + return {{T(1), T(0), T(0), T(0)}, + {T(0), cosine, sine, T(0)}, + {T(0), -sine, cosine, T(0)}, + {T(0), T(0), T(0), T(1)}}; } /** @@ -141,12 +135,10 @@ template class Matrix4: public Matrix<4, T> { T sine = std::sin(angle); T cosine = std::cos(angle); - return Matrix4( /* Column-major! */ - cosine, T(0), -sine, T(0), - T(0), T(1), T(0), T(0), - sine, T(0), cosine, T(0), - T(0), T(0), T(0), T(1) - ); + return {{cosine, T(0), -sine, T(0)}, + { T(0), T(1), T(0), T(0)}, + { sine, T(0), cosine, T(0)}, + { T(0), T(0), T(0), T(1)}}; } /** @@ -161,12 +153,10 @@ template class Matrix4: public Matrix<4, T> { T sine = std::sin(angle); T cosine = std::cos(angle); - return Matrix4( /* Column-major! */ - cosine, sine, T(0), T(0), - -sine, cosine, T(0), T(0), - T(0), T(0), T(1), T(0), - T(0), T(0), T(0), T(1) - ); + return {{cosine, sine, T(0), T(0)}, + { -sine, cosine, T(0), T(0)}, + { T(0), T(0), T(1), T(0)}, + { T(0), T(0), T(0), T(1)}}; } /** @@ -179,7 +169,7 @@ template class Matrix4: public Matrix<4, T> { static Matrix4 reflection(const Vector3& normal) { CORRADE_ASSERT(MathTypeTraits::equals(normal.dot(), T(1)), "Math::Matrix4::reflection(): normal must be normalized", {}); - return from(Matrix<3, T>() - T(2)*normal*normal.transposed(), {}); + return from(Matrix<3, T>() - T(2)*normal*RectangularMatrix<1, 3, T>(normal).transposed(), {}); } /** @@ -194,12 +184,10 @@ template class Matrix4: public Matrix<4, T> { Vector2 xyScale = T(2.0)/size; T zScale = T(2.0)/(near-far); - return Matrix4( /* Column-major! */ - xyScale.x(), T(0.0), T(0.0), T(0.0), - T(0.0), xyScale.y(), T(0.0), T(0.0), - T(0.0), T(0.0), zScale, T(0.0), - T(0.0), T(0.0), near*zScale-1, T(1.0) - ); + return {{xyScale.x(), T(0), T(0), T(0)}, + { T(0), xyScale.y(), T(0), T(0)}, + { T(0), T(0), zScale, T(0)}, + { T(0), T(0), near*zScale-T(1), T(1)}}; } /** @@ -214,12 +202,10 @@ template class Matrix4: public Matrix<4, T> { Vector2 xyScale = 2*near/size; T zScale = T(1.0)/(near-far); - return Matrix4( /* Column-major! */ - xyScale.x(), T(0.0), T(0.0), T(0.0), - T(0.0), xyScale.y(), T(0.0), T(0.0), - T(0.0), T(0.0), (far+near)*zScale, T(-1.0), - T(0.0), T(0.0), (2*far*near)*zScale, T(0.0) - ); + return {{xyScale.x(), T(0), T(0), T(0)}, + { T(0), xyScale.y(), T(0), T(0)}, + { T(0), T(0), (far+near)*zScale, T(-1)}, + { T(0), T(0), T(2)*far*near*zScale, T(0)}}; } /** @@ -247,12 +233,10 @@ template class Matrix4: public Matrix<4, T> { * @see rotationScaling() const, translation() const */ static Matrix4 from(const Matrix<3, T>& rotationScaling, const Vector3& translation) { - return from( - Vector4(rotationScaling[0], T(0)), - Vector4(rotationScaling[1], T(0)), - Vector4(rotationScaling[2], T(0)), - Vector4(translation, T(1)) - ); + return {{rotationScaling[0], T(0)}, + {rotationScaling[1], T(0)}, + {rotationScaling[2], T(0)}, + { translation, T(1)}}; } /** @copydoc Matrix::Matrix(ZeroType) */ @@ -260,14 +244,14 @@ template class Matrix4: public Matrix<4, T> { /** @copydoc Matrix::Matrix(IdentityType, T) */ inline constexpr /*implicit*/ Matrix4(typename Matrix<4, T>::IdentityType = (Matrix<4, T>::Identity), T value = T(1)): Matrix<4, T>( - value, T(0), T(0), T(0), - T(0), value, T(0), T(0), - T(0), T(0), value, T(0), - T(0), T(0), T(0), value + Vector<4, T>(value, T(0), T(0), T(0)), + Vector<4, T>( T(0), value, T(0), T(0)), + Vector<4, T>( T(0), T(0), value, T(0)), + Vector<4, T>( T(0), T(0), T(0), value) ) {} - /** @copydoc Matrix::Matrix */ - template inline constexpr /*implicit*/ Matrix4(T first, U... next): Matrix<4, T>(first, next...) {} + /** @brief %Matrix from column vectors */ + inline constexpr /*implicit*/ Matrix4(const Vector4& first, const Vector4& second, const Vector4& third, const Vector4& fourth): Matrix<4, T>(first, second, third, fourth) {} /** @brief Copy constructor */ inline constexpr Matrix4(const RectangularMatrix<4, 4, T>& other): Matrix<4, T>(other) {} @@ -281,10 +265,9 @@ template class Matrix4: public Matrix<4, T> { */ inline Matrix<3, T> rotationScaling() const { /* Not Matrix3, because it is for affine 2D transformations */ - return Matrix<3, T>::from( - (*this)[0].xyz(), - (*this)[1].xyz(), - (*this)[2].xyz()); + return {(*this)[0].xyz(), + (*this)[1].xyz(), + (*this)[2].xyz()}; } /** @@ -296,10 +279,9 @@ template class Matrix4: public Matrix<4, T> { */ inline Matrix<3, T> rotation() const { /* Not Matrix3, because it is for affine 2D transformations */ - return Matrix<3, T>::from( - (*this)[0].xyz().normalized(), - (*this)[1].xyz().normalized(), - (*this)[2].xyz().normalized()); + return {(*this)[0].xyz().normalized(), + (*this)[1].xyz().normalized(), + (*this)[2].xyz().normalized()}; } /** @@ -349,7 +331,7 @@ template class Matrix4: public Matrix<4, T> { * @see 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), + 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", {}); Matrix<3, T> inverseRotation = rotationScaling().transposed(); CORRADE_ASSERT((inverseRotation*rotationScaling() == Matrix<3, T>()), @@ -363,10 +345,12 @@ template class Matrix4: public Matrix<4, T> { } #endif + MAGNUM_RECTANGULARMATRIX_SUBCLASS_IMPLEMENTATION(4, 4, Matrix4) MAGNUM_MATRIX_SUBCLASS_IMPLEMENTATION(Matrix4, Vector4, 4) - MAGNUM_RECTANGULARMATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(4, 4, Matrix4) }; +MAGNUM_MATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(Matrix4, 4) + /** @debugoperator{Magnum::Math::Matrix4} */ template inline Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Matrix4& value) { return debug << static_cast&>(value); diff --git a/src/Math/Point2D.h b/src/Math/Point2D.h index 93adf7d9f..53fbc9b21 100644 --- a/src/Math/Point2D.h +++ b/src/Math/Point2D.h @@ -57,7 +57,7 @@ template class Point2D: public Vector3 { inline constexpr /*implicit*/ Point2D(const Vector2& xy, T z = T(1)): Vector3(xy, z) {} /** @brief Copy constructor */ - inline constexpr Point2D(const RectangularMatrix<1, 3, T>& other): Vector3(other) {} + inline constexpr Point2D(const Vector<3, T>& other): Vector3(other) {} /** * @brief Vector part of the point @@ -69,7 +69,6 @@ template class Point2D: public Vector3 { inline constexpr Vector2 vector() const { return Vector3::xy(); } /**< @overload */ MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(Point2D, 3) - MAGNUM_RECTANGULARMATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(1, 3, Point2D) }; MAGNUM_VECTOR_SUBCLASS_OPERATOR_IMPLEMENTATION(Point2D, 3) diff --git a/src/Math/Point3D.h b/src/Math/Point3D.h index 959b7e745..ca4588a8b 100644 --- a/src/Math/Point3D.h +++ b/src/Math/Point3D.h @@ -58,7 +58,7 @@ template class Point3D: public Vector4 { inline constexpr /*implicit*/ Point3D(const Vector3& xyz, T w = T(1)): Vector4(xyz, w) {} /** @brief Copy constructor */ - inline constexpr Point3D(const RectangularMatrix<1, 4, T>& other): Vector4(other) {} + inline constexpr Point3D(const Vector<4, T>& other): Vector4(other) {} /** * @brief Vector part of the point @@ -70,7 +70,6 @@ template class Point3D: public Vector4 { inline constexpr Vector3 vector() const { return Vector4::xyz(); } /**< @overload */ MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(Point3D, 4) - MAGNUM_RECTANGULARMATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(1, 4, Point3D) }; MAGNUM_VECTOR_SUBCLASS_OPERATOR_IMPLEMENTATION(Point3D, 4) diff --git a/src/Math/Quaternion.h b/src/Math/Quaternion.h index d962a03ef..1615c4e41 100644 --- a/src/Math/Quaternion.h +++ b/src/Math/Quaternion.h @@ -174,16 +174,16 @@ template class Quaternion { * @see Matrix4::from(const Matrix<3, T>&, const Vector3&) */ Matrix<3, T> matrix() const { - return { /* Column-major! */ - T(1) - 2*pow<2>(_vector.y()) - 2*pow<2>(_vector.z()), + return { + Vector<3, T>(T(1) - 2*pow<2>(_vector.y()) - 2*pow<2>(_vector.z()), 2*_vector.x()*_vector.y() + 2*_vector.z()*_scalar, - 2*_vector.x()*_vector.z() - 2*_vector.y()*_scalar, - 2*_vector.x()*_vector.y() - 2*_vector.z()*_scalar, + 2*_vector.x()*_vector.z() - 2*_vector.y()*_scalar), + Vector<3, T>(2*_vector.x()*_vector.y() - 2*_vector.z()*_scalar, T(1) - 2*pow<2>(_vector.x()) - 2*pow<2>(_vector.z()), - 2*_vector.y()*_vector.z() + 2*_vector.x()*_scalar, - 2*_vector.x()*_vector.z() + 2*_vector.y()*_scalar, + 2*_vector.y()*_vector.z() + 2*_vector.x()*_scalar), + Vector<3, T>(2*_vector.x()*_vector.z() + 2*_vector.y()*_scalar, 2*_vector.y()*_vector.z() - 2*_vector.x()*_scalar, - T(1) - 2*pow<2>(_vector.x()) - 2*pow<2>(_vector.y()) + T(1) - 2*pow<2>(_vector.x()) - 2*pow<2>(_vector.y())) }; } diff --git a/src/Math/RectangularMatrix.cpp b/src/Math/RectangularMatrix.cpp index 73b56677d..1716c3a14 100644 --- a/src/Math/RectangularMatrix.cpp +++ b/src/Math/RectangularMatrix.cpp @@ -18,21 +18,6 @@ namespace Magnum { namespace Math { #ifndef DOXYGEN_GENERATING_OUTPUT -template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Magnum::Math::RectangularMatrix<1, 2, float>&); -template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Magnum::Math::RectangularMatrix<1, 3, float>&); -template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Magnum::Math::RectangularMatrix<1, 4, float>&); -template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Magnum::Math::RectangularMatrix<1, 2, int>&); -template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Magnum::Math::RectangularMatrix<1, 3, int>&); -template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Magnum::Math::RectangularMatrix<1, 4, int>&); -template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Magnum::Math::RectangularMatrix<1, 2, unsigned int>&); -template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Magnum::Math::RectangularMatrix<1, 3, unsigned int>&); -template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Magnum::Math::RectangularMatrix<1, 4, unsigned int>&); -#ifndef MAGNUM_TARGET_GLES -template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Magnum::Math::RectangularMatrix<1, 2, double>&); -template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Magnum::Math::RectangularMatrix<1, 3, double>&); -template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Magnum::Math::RectangularMatrix<1, 4, double>&); -#endif - template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Magnum::Math::RectangularMatrix<2, 2, float>&); template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Magnum::Math::RectangularMatrix<3, 3, float>&); template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Magnum::Math::RectangularMatrix<4, 4, float>&); @@ -63,21 +48,6 @@ template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Magnu namespace Corrade { namespace Utility { #ifndef DOXYGEN_GENERATING_OUTPUT -template struct ConfigurationValue>; -template struct ConfigurationValue>; -template struct ConfigurationValue>; -template struct ConfigurationValue>; -template struct ConfigurationValue>; -template struct ConfigurationValue>; -template struct ConfigurationValue>; -template struct ConfigurationValue>; -template struct ConfigurationValue>; -#ifndef MAGNUM_TARGET_GLES -template struct ConfigurationValue>; -template struct ConfigurationValue>; -template struct ConfigurationValue>; -#endif - template struct ConfigurationValue>; template struct ConfigurationValue>; template struct ConfigurationValue>; diff --git a/src/Math/RectangularMatrix.h b/src/Math/RectangularMatrix.h index 0c5d91bb0..4667af89f 100644 --- a/src/Math/RectangularMatrix.h +++ b/src/Math/RectangularMatrix.h @@ -19,48 +19,12 @@ * @brief Class Magnum::Math::RectangularMatrix */ -#include -#include -#include -#include - -#include "MathTypeTraits.h" - -#include "magnumVisibility.h" +#include "Math/Vector.h" namespace Magnum { namespace Math { /** @todo Properly test all constexpr */ -/** @todoc Remove `ifndef` when Doxygen is sane again */ -#ifndef DOXYGEN_GENERATING_OUTPUT -template class RectangularMatrix; -#endif - -#ifndef DOXYGEN_GENERATING_OUTPUT -namespace Implementation { - template struct Sequence {}; - - /* E.g. GenerateSequence<3>::Type is Sequence<0, 1, 2> */ - template struct GenerateSequence: - GenerateSequence {}; - - template struct GenerateSequence<0, sequence...> { - typedef Sequence Type; - }; - - /* Implementation for RectangularMatrix::from(const RectangularMatrix&) */ - template inline constexpr Math::RectangularMatrix rectangularMatrixFrom(Sequence, const Math::RectangularMatrix& matrix) { - return {T(matrix.data()[sequence])...}; - } -} -#endif - -/** @todoc Remove `ifndef` when Doxygen is sane again */ -#ifndef DOXYGEN_GENERATING_OUTPUT -template class Vector; -#endif - /** @brief Rectangular matrix @tparam cols Column count @@ -75,7 +39,7 @@ math formulas are in reverse order (i.e. @f$ \boldsymbol A_{ji} @f$ instead of @f$ \boldsymbol A_{ij} @f$). */ template class RectangularMatrix { - static_assert(cols != 0 && rows != 0, "Matrix cannot have zero elements"); + static_assert(cols != 0 && rows != 0, "RectangularMatrix cannot have zero elements"); public: typedef T Type; /**< @brief Data type */ @@ -98,18 +62,6 @@ template class RectangularMatrix { return *reinterpret_cast*>(data); } - /** - * @brief %Matrix from column vectors - * @param first First column vector - * @param next Next column vectors - * - * @todo Creating matrix from arbitrary combination of matrices with n rows - */ - template inline constexpr static RectangularMatrix from(const Vector& first, const U&... next) { - static_assert(sizeof...(next)+1 == cols, "Improper number of arguments passed to Matrix from Vector constructor"); - return from(typename Implementation::GenerateSequence::Type(), first, next...); - } - /** * @brief %Matrix from another of different type * @@ -122,21 +74,21 @@ template class RectangularMatrix { * @endcode */ template inline constexpr static RectangularMatrix from(const RectangularMatrix& other) { - return Implementation::rectangularMatrixFrom(typename Implementation::GenerateSequence::Type(), other); + return from(typename Implementation::GenerateSequence::Type(), other); } - /** @brief Zero-filled matrix constructor */ - inline constexpr /*implicit*/ RectangularMatrix(): _data() {} + /** @brief Construct zero-filled matrix */ + inline constexpr /*implicit*/ RectangularMatrix() {} /** - * @brief Initializer-list constructor - * @param first First value - * @param next Next values + * @brief Construct matrix from column vectors + * @param first First column vector + * @param next Next column vectors * - * Note that the values are in column-major order. + * @todo Creating matrix from arbitrary combination of matrices with n rows */ - template inline constexpr /*implicit*/ RectangularMatrix(T first, U... next): _data{first, next...} { - static_assert(sizeof...(next)+1 == cols*rows, "Improper number of arguments passed to RectangularMatrix constructor"); + template inline constexpr /*implicit*/ RectangularMatrix(const Vector& first, const U&... next): _data{first, next...} { + static_assert(sizeof...(next)+1 == cols, "Improper number of arguments passed to RectangularMatrix constructor"); } /** @brief Copy constructor */ @@ -149,47 +101,35 @@ template class RectangularMatrix { * @brief Raw data * @return One-dimensional array of `size*size` length in column-major * order. + * + * @see operator[] */ - inline T* data() { return _data; } - inline constexpr const T* data() const { return _data; } /**< @overload */ + inline T* data() { return reinterpret_cast(_data); } + inline constexpr const T* data() const { return reinterpret_cast(_data); } /**< @overload */ /** * @brief %Matrix column * - * For accessing individual elements prefer to use operator(), as it - * is guaranteed to not involve unnecessary conversions. + * Particular elements can be accessed using Vector::operator[], e.g.: + * @code + * RectangularMatrix<4, 3, float> m; + * float a = m[2][1]; + * @endcode + * + * @see data() */ inline Vector& operator[](std::size_t col) { - return Vector::from(_data+col*rows); + return _data[col]; } /** @overload */ inline constexpr const Vector& operator[](std::size_t col) const { - return Vector::from(_data+col*rows); - } - - /** - * @brief Element on given position - * - * Prefer this instead of using `[][]`. - * @see operator[] - */ - inline T& operator()(std::size_t col, std::size_t row) { - return _data[col*rows+row]; - } - /** @overload */ - inline constexpr const T& operator()(std::size_t col, std::size_t row) const { - return _data[col*rows+row]; + return _data[col]; } - /** - * @brief Equality operator - * - * @see Vector::operator<(), Vector::operator<=(), Vector::operator>=(), - * Vector::operator>() - */ + /** @brief Equality comparison */ inline bool operator==(const RectangularMatrix& other) const { - for(std::size_t i = 0; i != cols*rows; ++i) - if(!MathTypeTraits::equals(_data[i], other._data[i])) return false; + for(std::size_t i = 0; i != cols; ++i) + if(_data[i] != other._data[i]) return false; return true; } @@ -207,12 +147,12 @@ template class RectangularMatrix { /** * @brief Add and assign matrix * - * The computation is done in-place. @f[ - * \boldsymbol A_{ji} = \boldsymbol A_{ji} + \boldsymbol B_{ji} + * The computation is done column-wise in-place. @f[ + * \boldsymbol A_j = \boldsymbol A_j + \boldsymbol B_j * @f] */ RectangularMatrix& operator+=(const RectangularMatrix& other) { - for(std::size_t i = 0; i != cols*rows; ++i) + for(std::size_t i = 0; i != cols; ++i) _data[i] += other._data[i]; return *this; @@ -230,14 +170,14 @@ template class RectangularMatrix { /** * @brief Negated matrix * - * The computation is done in-place. @f[ - * \boldsymbol A_{ji} = -\boldsymbol A_{ji} + * The computation is done column-wise in-place. @f[ + * \boldsymbol A_j = -\boldsymbol A_j * @f] */ RectangularMatrix operator-() const { RectangularMatrix out; - for(std::size_t i = 0; i != cols*rows; ++i) + for(std::size_t i = 0; i != cols; ++i) out._data[i] = -_data[i]; return out; @@ -246,12 +186,12 @@ template class RectangularMatrix { /** * @brief Subtract and assign matrix * - * The computation is done in-place. @f[ - * \boldsymbol A_{ji} = \boldsymbol A_{ji} - \boldsymbol B_{ji} + * The computation is done column-wise in-place. @f[ + * \boldsymbol A_j = \boldsymbol A_j - \boldsymbol B_j * @f] */ RectangularMatrix& operator-=(const RectangularMatrix& other) { - for(std::size_t i = 0; i != cols*rows; ++i) + for(std::size_t i = 0; i != cols; ++i) _data[i] -= other._data[i]; return *this; @@ -282,8 +222,8 @@ template class RectangularMatrix { /** * @brief Multiply matrix with number and assign * - * The computation is done in-place. @f[ - * \boldsymbol A_{ji} = a \boldsymbol A_{ji} + * The computation is done column-wise in-place. @f[ + * \boldsymbol A_j = a \boldsymbol A_j * @f] */ #ifndef DOXYGEN_GENERATING_OUTPUT @@ -291,7 +231,7 @@ template class RectangularMatrix { #else template RectangularMatrix& operator*=(U number) { #endif - for(std::size_t i = 0; i != cols*rows; ++i) + for(std::size_t i = 0; i != cols; ++i) _data[i] *= number; return *this; @@ -313,8 +253,8 @@ template class RectangularMatrix { /** * @brief Divide matrix with number and assign * - * The computation is done in-place. @f[ - * \boldsymbol A_{ji} = \frac{\boldsymbol A_{ji}} a + * The computation is done column-wise in-place. @f[ + * \boldsymbol A_j = \frac{\boldsymbol A_j} a * @f] */ #ifndef DOXYGEN_GENERATING_OUTPUT @@ -322,7 +262,7 @@ template class RectangularMatrix { #else template RectangularMatrix& operator/=(U number) { #endif - for(std::size_t i = 0; i != cols*rows; ++i) + for(std::size_t i = 0; i != cols; ++i) _data[i] /= number; return *this; @@ -341,7 +281,7 @@ template class RectangularMatrix { for(std::size_t col = 0; col != size; ++col) for(std::size_t row = 0; row != rows; ++row) for(std::size_t pos = 0; pos != cols; ++pos) - out(col, row) += (*this)(pos, row)*other(col, pos); + out[col][row] += (*this)[pos][row]*other[col][pos]; return out; } @@ -355,7 +295,7 @@ template class RectangularMatrix { * @f] */ Vector operator*(const Vector& other) const { - return operator*(static_cast>(other)); + return operator*(RectangularMatrix<1, rows, T>(other))[0]; } /** @brief Transposed matrix */ @@ -364,23 +304,18 @@ template class RectangularMatrix { for(std::size_t col = 0; col != cols; ++col) for(std::size_t row = 0; row != rows; ++row) - out(row, col) = (*this)(col, row); + out[row][col] = (*this)[col][row]; return out; } - #ifndef DOXYGEN_GENERATING_OUTPUT - protected: - T _data[rows*cols]; - #endif - private: - template inline constexpr static RectangularMatrix from(Implementation::Sequence s, const Vector& first, U... next) { - return from(s, next..., first[sequence]...); - } - template inline constexpr static RectangularMatrix from(Implementation::Sequence, T first, U... next) { - return RectangularMatrix(first, next...); + /* Implementation for RectangularMatrix::from(const RectangularMatrix&) */ + template inline constexpr static Math::RectangularMatrix from(Implementation::Sequence, const Math::RectangularMatrix& matrix) { + return {Vector::from(matrix[sequence])...}; } + + Vector _data[cols]; }; /** @relates RectangularMatrix @@ -399,8 +334,8 @@ template inline typename s /** @relates RectangularMatrix @brief Divide matrix with number and invert -@f[ - \boldsymbol B_{ji} = \frac a {\boldsymbol A_{ji}} +The computation is done column-wise. @f[ + \boldsymbol B_j = \frac a {\boldsymbol A_j} @f] @see RectangularMatrix::operator/(U) const */ @@ -411,12 +346,24 @@ template typename std::ena #endif RectangularMatrix out; - for(std::size_t i = 0; i != cols*rows; ++i) - out.data()[i] = number/matrix.data()[i]; + for(std::size_t i = 0; i != cols; ++i) + out[i] = number/matrix[i]; return out; } +/** @relates RectangularMatrix +@brief Multiply vector with rectangular matrix + +Internally the same as multiplying one-column matrix with one-row matrix. @f[ + (\boldsymbol {aA})_{ji} = \boldsymbol a_i \boldsymbol A_j +@f] +@see RectangularMatrix::operator*(const RectangularMatrix&) const +*/ +template inline RectangularMatrix operator*(const Vector& vector, const RectangularMatrix& matrix) { + return RectangularMatrix<1, size, T>(vector)*matrix; +} + /** @debugoperator{Magnum::Math::RectangularMatrix} */ template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Magnum::Math::RectangularMatrix& value) { debug << "Matrix("; @@ -433,24 +380,8 @@ template Corrade::Utility::Debug op return debug; } -/* Explicit instantiation for types used in OpenGL */ #ifndef DOXYGEN_GENERATING_OUTPUT -/* Vectors */ -extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<1, 2, float>&); -extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<1, 3, float>&); -extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<1, 4, float>&); -extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<1, 2, int>&); -extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<1, 3, int>&); -extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<1, 4, int>&); -extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<1, 2, unsigned int>&); -extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<1, 3, unsigned int>&); -extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<1, 4, unsigned int>&); -#ifndef MAGNUM_TARGET_GLES -extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<1, 2, double>&); -extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<1, 3, double>&); -extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<1, 4, double>&); -#endif - +/* Explicit instantiation for types used in OpenGL */ /* Square matrices */ extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<2, 2, float>&); extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<3, 3, float>&); @@ -476,9 +407,7 @@ extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utilit extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<3, 4, double>&); extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<4, 3, double>&); #endif -#endif -#ifndef DOXYGEN_GENERATING_OUTPUT #define MAGNUM_RECTANGULARMATRIX_SUBCLASS_IMPLEMENTATION(cols, rows, ...) \ inline constexpr static __VA_ARGS__& from(T* data) { \ return *reinterpret_cast<__VA_ARGS__*>(data); \ @@ -486,9 +415,6 @@ extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utilit inline constexpr static const __VA_ARGS__& from(const T* data) { \ return *reinterpret_cast(data); \ } \ - template inline constexpr static __VA_ARGS__ from(const Math::Vector& first, const U&... next) { \ - return Math::RectangularMatrix::from(first, next...); \ - } \ template inline constexpr static RectangularMatrix from(const Math::RectangularMatrix& other) { \ return Math::RectangularMatrix::from(other); \ } \ @@ -496,39 +422,38 @@ extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utilit inline __VA_ARGS__& operator=(const Math::RectangularMatrix& other) { \ Math::RectangularMatrix::operator=(other); \ return *this; \ - } - -#define MAGNUM_RECTANGULARMATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(cols, rows, ...) \ + } \ + \ inline __VA_ARGS__ operator-() const { \ return Math::RectangularMatrix::operator-(); \ } \ - inline __VA_ARGS__ operator+(const Math::RectangularMatrix& other) const { \ - return Math::RectangularMatrix::operator+(other); \ - } \ inline __VA_ARGS__& operator+=(const Math::RectangularMatrix& other) { \ Math::RectangularMatrix::operator+=(other); \ return *this; \ } \ - inline __VA_ARGS__ operator-(const Math::RectangularMatrix& other) const { \ - return Math::RectangularMatrix::operator-(other); \ + inline __VA_ARGS__ operator+(const Math::RectangularMatrix& other) const { \ + return Math::RectangularMatrix::operator+(other); \ } \ inline __VA_ARGS__& operator-=(const Math::RectangularMatrix& other) { \ Math::RectangularMatrix::operator-=(other); \ return *this; \ } \ - template inline typename std::enable_if::value, __VA_ARGS__>::type operator*(U number) const { \ - return Math::RectangularMatrix::operator*(number); \ + inline __VA_ARGS__ operator-(const Math::RectangularMatrix& other) const { \ + return Math::RectangularMatrix::operator-(other); \ } \ template inline typename std::enable_if::value, __VA_ARGS__&>::type operator*=(U number) { \ Math::RectangularMatrix::operator*=(number); \ return *this; \ } \ - template inline typename std::enable_if::value, __VA_ARGS__>::type operator/(U number) const { \ - return Math::RectangularMatrix::operator/(number); \ + template inline typename std::enable_if::value, __VA_ARGS__>::type operator*(U number) const { \ + return Math::RectangularMatrix::operator*(number); \ } \ template inline typename std::enable_if::value, __VA_ARGS__&>::type operator/=(U number) { \ Math::RectangularMatrix::operator/=(number); \ return *this; \ + } \ + template inline typename std::enable_if::value, __VA_ARGS__>::type operator/(U number) const { \ + return Math::RectangularMatrix::operator/(number); \ } #endif @@ -547,7 +472,7 @@ template struct ConfigurationValue< for(std::size_t row = 0; row != rows; ++row) { for(std::size_t col = 0; col != cols; ++col) { if(!output.empty()) output += ' '; - output += ConfigurationValue::toString(value(col, row), flags); + output += ConfigurationValue::toString(value[col][row], flags); } } @@ -564,7 +489,7 @@ template struct ConfigurationValue< std::string part = stringValue.substr(oldpos, pos-oldpos); if(!part.empty()) { - result(i%cols, i/cols) = ConfigurationValue::fromString(part, flags); + result[i%cols][i/cols] = ConfigurationValue::fromString(part, flags); ++i; } @@ -576,22 +501,6 @@ template struct ConfigurationValue< }; #ifndef DOXYGEN_GENERATING_OUTPUT -/* Vectors */ -extern template struct MAGNUM_EXPORT ConfigurationValue>; -extern template struct MAGNUM_EXPORT ConfigurationValue>; -extern template struct MAGNUM_EXPORT ConfigurationValue>; -extern template struct MAGNUM_EXPORT ConfigurationValue>; -extern template struct MAGNUM_EXPORT ConfigurationValue>; -extern template struct MAGNUM_EXPORT ConfigurationValue>; -extern template struct MAGNUM_EXPORT ConfigurationValue>; -extern template struct MAGNUM_EXPORT ConfigurationValue>; -extern template struct MAGNUM_EXPORT ConfigurationValue>; -#ifndef MAGNUM_TARGET_GLES -extern template struct MAGNUM_EXPORT ConfigurationValue>; -extern template struct MAGNUM_EXPORT ConfigurationValue>; -extern template struct MAGNUM_EXPORT ConfigurationValue>; -#endif - /* Square matrices */ extern template struct MAGNUM_EXPORT ConfigurationValue>; extern template struct MAGNUM_EXPORT ConfigurationValue>; @@ -621,7 +530,4 @@ extern template struct MAGNUM_EXPORT ConfigurationValue::pi()/7), Vector3::xAxis()), matrix); CORRADE_COMPARE(Matrix4::rotationX(rad(Math::Constants::pi()/7)), matrix); } void Matrix4Test::rotationY() { - Matrix4 matrix(0.90096887f, 0.0f, -0.43388374f, 0.0f, - 0.0f, 1.0f, 0.0f, 0.0f, - 0.43388374f, 0.0f, 0.90096887f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f); + Matrix4 matrix({0.90096887f, 0.0f, -0.43388374f, 0.0f}, + { 0.0f, 1.0f, 0.0f, 0.0f}, + {0.43388374f, 0.0f, 0.90096887f, 0.0f}, + { 0.0f, 0.0f, 0.0f, 1.0f}); CORRADE_COMPARE(Matrix4::rotation(rad(Math::Constants::pi()/7), Vector3::yAxis()), matrix); CORRADE_COMPARE(Matrix4::rotationY(rad(Math::Constants::pi()/7)), matrix); } void Matrix4Test::rotationZ() { - Matrix4 matrix( 0.90096887f, 0.43388374f, 0.0f, 0.0f, - -0.43388374f, 0.90096887f, 0.0f, 0.0f, - 0.0f, 0.0f, 1.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f); + Matrix4 matrix({ 0.90096887f, 0.43388374f, 0.0f, 0.0f}, + {-0.43388374f, 0.90096887f, 0.0f, 0.0f}, + { 0.0f, 0.0f, 1.0f, 0.0f}, + { 0.0f, 0.0f, 0.0f, 1.0f}); CORRADE_COMPARE(Matrix4::rotation(rad(Math::Constants::pi()/7), Vector3::zAxis()), matrix); CORRADE_COMPARE(Matrix4::rotationZ(rad(Math::Constants::pi()/7)), matrix); } @@ -174,12 +164,10 @@ void Matrix4Test::reflection() { CORRADE_COMPARE(o.str(), "Math::Matrix4::reflection(): normal must be normalized\n"); Matrix4 actual = Matrix4::reflection(normal.normalized()); - Matrix4 expected( - 0.777778f, 0.444444f, 0.444444f, 0.0f, - 0.444444f, 0.111111f, -0.888889f, 0.0f, - 0.444444f, -0.888889f, 0.111111f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f - ); + Matrix4 expected({0.777778f, 0.444444f, 0.444444f, 0.0f}, + {0.444444f, 0.111111f, -0.888889f, 0.0f}, + {0.444444f, -0.888889f, 0.111111f, 0.0f}, + { 0.0f, 0.0f, 0.0f, 1.0f}); CORRADE_COMPARE(actual*actual, Matrix4()); CORRADE_COMPARE(actual*normal, -normal); @@ -187,73 +175,59 @@ void Matrix4Test::reflection() { } void Matrix4Test::orthographicProjection() { - Matrix4 expected(0.4f, 0.0f, 0.0f, 0.0f, - 0.0f, 0.5f, 0.0f, 0.0f, - 0.0f, 0.0f, -0.25f, 0.0f, - 0.0f, 0.0f, -1.25f, 1.0f); + Matrix4 expected({0.4f, 0.0f, 0.0f, 0.0f}, + {0.0f, 0.5f, 0.0f, 0.0f}, + {0.0f, 0.0f, -0.25f, 0.0f}, + {0.0f, 0.0f, -1.25f, 1.0f}); CORRADE_COMPARE(Matrix4::orthographicProjection({5.0f, 4.0f}, 1, 9), expected); } void Matrix4Test::perspectiveProjection() { - Matrix4 expected(4.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 7.111111f, 0.0f, 0.0f, - 0.0f, 0.0f, -1.9411764f, -1.0f, - 0.0f, 0.0f, -94.1176452f, 0.0f); - + Matrix4 expected({4.0f, 0.0f, 0.0f, 0.0f}, + {0.0f, 7.111111f, 0.0f, 0.0f}, + {0.0f, 0.0f, -1.9411764f, -1.0f}, + {0.0f, 0.0f, -94.1176452f, 0.0f}); CORRADE_COMPARE(Matrix4::perspectiveProjection({16.0f, 9.0f}, 32.0f, 100), expected); } void Matrix4Test::perspectiveProjectionFov() { - Matrix4 expected(4.1652994f, 0.0f, 0.0f, 0.0f, - 0.0f, 9.788454f, 0.0f, 0.0f, - 0.0f, 0.0f, -1.9411764f, -1.0f, - 0.0f, 0.0f, -94.1176452f, 0.0f); - + Matrix4 expected({4.1652994f, 0.0f, 0.0f, 0.0f}, + { 0.0f, 9.788454f, 0.0f, 0.0f}, + { 0.0f, 0.0f, -1.9411764f, -1.0f}, + { 0.0f, 0.0f, -94.1176452f, 0.0f}); CORRADE_COMPARE(Matrix4::perspectiveProjection(deg(27.0f), 2.35f, 32.0f, 100), expected); } void Matrix4Test::fromParts() { - Matrix3 rotationScaling( - 3.0f, 5.0f, 8.0f, - 4.0f, 4.0f, 7.0f, - 7.0f, -1.0f, 8.0f - ); + Matrix3 rotationScaling(Vector3(3.0f, 5.0f, 8.0f), + Vector3(4.0f, 4.0f, 7.0f), + Vector3(7.0f, -1.0f, 8.0f)); Vector3 translation(9.0f, 4.0f, 5.0f); - Matrix4 expected( - 3.0f, 5.0f, 8.0f, 0.0f, - 4.0f, 4.0f, 7.0f, 0.0f, - 7.0f, -1.0f, 8.0f, 0.0f, - 9.0f, 4.0f, 5.0f, 1.0f - ); - + Matrix4 expected({3.0f, 5.0f, 8.0f, 0.0f}, + {4.0f, 4.0f, 7.0f, 0.0f}, + {7.0f, -1.0f, 8.0f, 0.0f}, + {9.0f, 4.0f, 5.0f, 1.0f}); CORRADE_COMPARE(Matrix4::from(rotationScaling, translation), expected); } void Matrix4Test::rotationScalingPart() { - 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 - ); - - Matrix3 expected( - 3.0f, 5.0f, 8.0f, - 4.0f, 4.0f, 7.0f, - 7.0f, -1.0f, 8.0f - ); - + 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}); + + Matrix3 expected(Vector3(3.0f, 5.0f, 8.0f), + Vector3(4.0f, 4.0f, 7.0f), + Vector3(7.0f, -1.0f, 8.0f)); CORRADE_COMPARE(m.rotationScaling(), expected); } void Matrix4Test::rotationPart() { - Matrix3 expectedRotationPart( - 0.35612214f, -0.80181062f, 0.47987163f, - 0.47987163f, 0.59757638f, 0.6423595f, - -0.80181062f, 0.0015183985f, 0.59757638f - ); + Matrix3 expectedRotationPart(Vector3( 0.35612214f, -0.80181062f, 0.47987163f), + Vector3( 0.47987163f, 0.59757638f, 0.6423595f), + Vector3(-0.80181062f, 0.0015183985f, 0.59757638f)); Matrix4 rotation = Matrix4::rotation(deg(-74.0f), Vector3(-1.0f, 2.0f, 2.0f).normalized()); CORRADE_COMPARE(rotation.rotation().determinant(), 1.0f); @@ -267,10 +241,10 @@ void Matrix4Test::rotationPart() { } void Matrix4Test::vectorParts() { - Matrix4 m(-1.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 12.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 35.0f, 0.0f, - -5.0f, 12.0f, 0.5f, 1.0f); + Matrix4 m({-1.0f, 0.0f, 0.0f, 0.0f}, + { 0.0f, 12.0f, 0.0f, 0.0f}, + { 0.0f, 0.0f, 35.0f, 0.0f}, + {-5.0f, 12.0f, 0.5f, 1.0f}); CORRADE_COMPARE(m.right(), Vector3::xAxis(-1.0f)); CORRADE_COMPARE(m.up(), Vector3::yAxis(12.0f)); @@ -282,12 +256,10 @@ 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 - ); + 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"); @@ -307,12 +279,10 @@ void Matrix4Test::invertedEuclidean() { } void Matrix4Test::debug() { - 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 - ); + 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}); std::ostringstream o; Debug(&o) << m; @@ -325,12 +295,10 @@ void Matrix4Test::debug() { void Matrix4Test::configuration() { Configuration c; - Matrix4 m( - 3.0f, 5.0f, 8.0f, 4.0f, - 4.0f, 4.0f, 7.0f, 3.125f, - 7.0f, -1.0f, 8.0f, 0.0f, - 9.0f, 4.0f, 5.0f, 9.55f - ); + Matrix4 m({3.0f, 5.0f, 8.0f, 4.0f}, + {4.0f, 4.0f, 7.0f, 3.125f}, + {7.0f, -1.0f, 8.0f, 0.0f}, + {9.0f, 4.0f, 5.0f, 9.55f}); std::string value("3 4 7 9 5 4 -1 4 8 7 8 5 4 3.125 0 9.55"); c.setValue("matrix", m); diff --git a/src/Math/Test/MatrixTest.cpp b/src/Math/Test/MatrixTest.cpp index b004d6a3e..8b377e915 100644 --- a/src/Math/Test/MatrixTest.cpp +++ b/src/Math/Test/MatrixTest.cpp @@ -42,6 +42,7 @@ class MatrixTest: public Corrade::TestSuite::Tester { typedef Matrix<4, float> Matrix4; typedef Matrix<3, float> Matrix3; typedef Vector<4, float> Vector4; +typedef Vector<3, float> Vector3; MatrixTest::MatrixTest() { addTests(&MatrixTest::construct, @@ -57,18 +58,16 @@ MatrixTest::MatrixTest() { void MatrixTest::construct() { float m[] = { - 3.0f, 5.0f, 8.0f, 4.0f, - 4.0f, 4.0f, 7.0f, 3.0f, + 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 + 9.0f, 4.0f, 5.0f, 9.0f }; - Matrix4 expected( - 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 - ); + Matrix4 expected(Vector4(3.0f, 5.0f, 8.0f, 4.0f), + Vector4(4.0f, 4.0f, 7.0f, 3.0f), + Vector4(7.0f, -1.0f, 8.0f, 0.0f), + Vector4(9.0f, 4.0f, 5.0f, 9.0f)); CORRADE_COMPARE(Matrix4::from(m), expected); } @@ -78,19 +77,15 @@ void MatrixTest::constructIdentity() { Matrix4 identity2(Matrix4::Identity); Matrix4 identity3(Matrix4::Identity, 4.0f); - Matrix4 identityExpected( - 1.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 1.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 1.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f - ); + Matrix4 identityExpected(Vector4(1.0f, 0.0f, 0.0f, 0.0f), + Vector4(0.0f, 1.0f, 0.0f, 0.0f), + Vector4(0.0f, 0.0f, 1.0f, 0.0f), + Vector4(0.0f, 0.0f, 0.0f, 1.0f)); - Matrix4 identity3Expected( - 4.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 4.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 4.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 4.0f - ); + Matrix4 identity3Expected(Vector4(4.0f, 0.0f, 0.0f, 0.0f), + Vector4(0.0f, 4.0f, 0.0f, 0.0f), + Vector4(0.0f, 0.0f, 4.0f, 0.0f), + Vector4(0.0f, 0.0f, 0.0f, 4.0f)); CORRADE_COMPARE(identity, identityExpected); CORRADE_COMPARE(identity2, identityExpected); @@ -100,71 +95,61 @@ void MatrixTest::constructIdentity() { void MatrixTest::constructZero() { Matrix4 zero(Matrix4::Zero); - Matrix4 zeroExpected( - 0.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 0.0f - ); + Matrix4 zeroExpected(Vector4(0.0f, 0.0f, 0.0f, 0.0f), + Vector4(0.0f, 0.0f, 0.0f, 0.0f), + Vector4(0.0f, 0.0f, 0.0f, 0.0f), + Vector4(0.0f, 0.0f, 0.0f, 0.0f)); CORRADE_COMPARE(zero, zeroExpected); } void MatrixTest::trace() { Matrix<5, std::int32_t> m( - 1, 2, 3, 0, 0, - 2, 3, 2, 1, -2, - 1, 1, -20, 1, 0, - 2, 0, 0, 10, 2, - 3, 1, 0, 1, -2 + Vector<5, std::int32_t>(1, 2, 3, 0, 0), + Vector<5, std::int32_t>(2, 3, 2, 1, -2), + Vector<5, std::int32_t>(1, 1, -20, 1, 0), + Vector<5, std::int32_t>(2, 0, 0, 10, 2), + Vector<5, std::int32_t>(3, 1, 0, 1, -2) ); CORRADE_COMPARE(m.trace(), -8); } void MatrixTest::ij() { - Matrix4 original( - 0.0f, 1.0f, 2.0f, 3.0f, - 4.0f, 5.0f, 6.0f, 7.0f, - 8.0f, 9.0f, 10.0f, 11.0f, - 12.0f, 13.0f, 14.0f, 15.0f - ); + Matrix4 original(Vector4( 0.0f, 1.0f, 2.0f, 3.0f), + Vector4( 4.0f, 5.0f, 6.0f, 7.0f), + Vector4( 8.0f, 9.0f, 10.0f, 11.0f), + Vector4(12.0f, 13.0f, 14.0f, 15.0f)); - Matrix3 skipped( - 0.0f, 1.0f, 3.0f, - 8.0f, 9.0f, 11.0f, - 12.0f, 13.0f, 15.0f - ); + Matrix3 skipped(Vector3( 0.0f, 1.0f, 3.0f), + Vector3( 8.0f, 9.0f, 11.0f), + Vector3(12.0f, 13.0f, 15.0f)); CORRADE_COMPARE(original.ij(1, 2), skipped); } void MatrixTest::determinant() { Matrix<5, std::int32_t> m( - 1, 2, 2, 1, 0, - 2, 3, 2, 1, -2, - 1, 1, 1, 1, 0, - 2, 0, 0, 1, 2, - 3, 1, 0, 1, -2 + Vector<5, std::int32_t>(1, 2, 2, 1, 0), + Vector<5, std::int32_t>(2, 3, 2, 1, -2), + Vector<5, std::int32_t>(1, 1, 1, 1, 0), + Vector<5, std::int32_t>(2, 0, 0, 1, 2), + Vector<5, std::int32_t>(3, 1, 0, 1, -2) ); CORRADE_COMPARE(m.determinant(), -2); } void MatrixTest::inverted() { - 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 - ); + Matrix4 m(Vector4(3.0f, 5.0f, 8.0f, 4.0f), + Vector4(4.0f, 4.0f, 7.0f, 3.0f), + Vector4(7.0f, -1.0f, 8.0f, 0.0f), + Vector4(9.0f, 4.0f, 5.0f, 9.0f)); - Matrix4 inverse( - -60/103.0f, 71/103.0f, -4/103.0f, 3/103.0f, - -66/103.0f, 109/103.0f, -25/103.0f, -7/103.0f, - 177/412.0f, -97/206.0f, 53/412.0f, -7/206.0f, - 259/412.0f, -185/206.0f, 31/412.0f, 27/206.0f - ); + Matrix4 inverse(Vector4(-60/103.0f, 71/103.0f, -4/103.0f, 3/103.0f), + Vector4(-66/103.0f, 109/103.0f, -25/103.0f, -7/103.0f), + Vector4(177/412.0f, -97/206.0f, 53/412.0f, -7/206.0f), + Vector4(259/412.0f, -185/206.0f, 31/412.0f, 27/206.0f)); Matrix4 _inverse = m.inverted(); @@ -173,12 +158,10 @@ void MatrixTest::inverted() { } void MatrixTest::debug() { - 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 - ); + Matrix4 m(Vector4(3.0f, 5.0f, 8.0f, 4.0f), + Vector4(4.0f, 4.0f, 7.0f, 3.0f), + Vector4(7.0f, -1.0f, 8.0f, 0.0f), + Vector4(9.0f, 4.0f, 5.0f, 9.0f)); std::ostringstream o; Debug(&o) << m; @@ -201,12 +184,10 @@ void MatrixTest::debug() { void MatrixTest::configuration() { Configuration c; - Matrix4 m( - 3.0f, 5.0f, 8.0f, 4.0f, - 4.0f, 4.0f, 7.0f, 3.125f, - 7.0f, -1.0f, 8.0f, 0.0f, - 9.0f, 4.0f, 5.0f, 9.55f - ); + Matrix4 m(Vector4(3.0f, 5.0f, 8.0f, 4.0f), + Vector4(4.0f, 4.0f, 7.0f, 3.125f), + Vector4(7.0f, -1.0f, 8.0f, 0.0f), + Vector4(9.0f, 4.0f, 5.0f, 9.55f)); std::string value("3 4 7 9 5 4 -1 4 8 7 8 5 4 3.125 0 9.55"); c.setValue("matrix", m); diff --git a/src/Math/Test/RectangularMatrixTest.cpp b/src/Math/Test/RectangularMatrixTest.cpp index 86bc8e61a..60f00e421 100644 --- a/src/Math/Test/RectangularMatrixTest.cpp +++ b/src/Math/Test/RectangularMatrixTest.cpp @@ -51,6 +51,9 @@ typedef RectangularMatrix<3, 4, float> Matrix3x4; typedef RectangularMatrix<2, 2, float> Matrix2; typedef RectangularMatrix<2, 2, std::int32_t> Matrix2i; typedef Vector<4, float> Vector4; +typedef Vector<3, float> Vector3; +typedef Vector<2, float> Vector2; +typedef Vector<2, std::int32_t> Vector2i; RectangularMatrixTest::RectangularMatrixTest() { addTests(&RectangularMatrixTest::constructFromData, @@ -79,11 +82,9 @@ void RectangularMatrixTest::constructFromData() { 7.0f, -1.0f, 8.0f, 0.0f }; - Matrix3x4 expected( - 3.0f, 5.0f, 8.0f, 4.0f, - 4.0f, 4.0f, 7.0f, 3.0f, - 7.0f, -1.0f, 8.0f, 0.0f - ); + Matrix3x4 expected(Vector4(3.0f, 5.0f, 8.0f, 4.0f), + Vector4(4.0f, 4.0f, 7.0f, 3.0f), + Vector4(7.0f, -1.0f, 8.0f, 0.0f)); CORRADE_COMPARE(Matrix3x4::from(m), expected); } @@ -91,33 +92,34 @@ void RectangularMatrixTest::constructFromData() { void RectangularMatrixTest::constructDefault() { Matrix4x3 zero; - Matrix4x3 zeroExpected( - 0.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.0f - ); + Matrix4x3 zeroExpected(Vector3(0.0f, 0.0f, 0.0f), + Vector3(0.0f, 0.0f, 0.0f), + Vector3(0.0f, 0.0f, 0.0f), + Vector3(0.0f, 0.0f, 0.0f)); CORRADE_COMPARE(zero, zeroExpected); } void RectangularMatrixTest::constructConversion() { - Matrix2 floatingPoint(1.3f, 2.7f, -15.0f, 7.0f); - Matrix2 floatingPointRounded(1.0f, 2.0f, -15.0f, 7.0f); - Matrix2i integral(1, 2, -15, 7); + Matrix2 floatingPoint(Vector2( 1.3f, 2.7f), + Vector2(-15.0f, 7.0f)); + Matrix2 floatingPointRounded(Vector2(1.0f, 2.0f), + Vector2(-15.0f, 7.0f)); + Matrix2i integral(Vector2i( 1, 2), + Vector2i(-15, 7)); CORRADE_COMPARE(Matrix2i::from(floatingPoint), integral); CORRADE_COMPARE(Matrix2::from(integral), floatingPointRounded); } void RectangularMatrixTest::constructFromVectors() { - Matrix3x4 actual = Matrix3x4::from(Vector4(1.0f, 2.0f, 3.0f, 4.0f), - Vector4(5.0f, 6.0f, 7.0f, 8.0f), - Vector4(9.0f, 10.0f, 11.0f, 12.0f)); + Matrix3x4 actual(Vector4(1.0f, 2.0f, 3.0f, 4.0f), + Vector4(5.0f, 6.0f, 7.0f, 8.0f), + Vector4(9.0f, 10.0f, 11.0f, 12.0f)); - Matrix3x4 expected(1.0f, 2.0f, 3.0f, 4.0f, - 5.0f, 6.0f, 7.0f, 8.0f, - 9.0f, 10.0f, 11.0f, 12.0f); + Matrix3x4 expected(Vector4(1.0f, 2.0f, 3.0f, 4.0f), + Vector4(5.0f, 6.0f, 7.0f, 8.0f), + Vector4(9.0f, 10.0f, 11.0f, 12.0f)); CORRADE_COMPARE(actual, expected); } @@ -128,54 +130,68 @@ void RectangularMatrixTest::data() { m[2] = vector; m[1][1] = 1.0f; - m(0, 2) = 1.5f; + m[0][2] = 1.5f; - CORRADE_COMPARE(m(1, 1), 1.0f); + CORRADE_COMPARE(m[1][1], 1.0f); CORRADE_COMPARE(m[0][2], 1.5f); CORRADE_COMPARE(m[2], vector); - Matrix3x4 expected( - 0.0f, 0.0f, 1.5f, 0.0f, - 0.0f, 1.0f, 0.0f, 0.0f, - 4.0f, 5.0f, 6.0f, 7.0f - ); + Matrix3x4 expected(Vector4(0.0f, 0.0f, 1.5f, 0.0f), + Vector4(0.0f, 1.0f, 0.0f, 0.0f), + Vector4(4.0f, 5.0f, 6.0f, 7.0f)); CORRADE_COMPARE(m, expected); } void RectangularMatrixTest::compare() { - CORRADE_VERIFY(Matrix2(1.0f, -3.0f, 5.0f, -10.0f) == Matrix2(1.0f + MathTypeTraits::epsilon()/2, -3.0f, 5.0f, -10.0f)); - CORRADE_VERIFY(Matrix2(1.0f, -1.0f, 5.0f, -10.0f) != Matrix2(1.0f, -1.0f + MathTypeTraits::epsilon()*2, 5.0f, -10.0f)); - - CORRADE_VERIFY(Matrix2i(1, -3, 5, -10) == Matrix2i(1, -3, 5, -10)); - CORRADE_VERIFY(Matrix2i(1, -3, 5, -10) != Matrix2i(1, -2, 5, -10)); + Matrix2 a(Vector2(1.0f, -3.0f), + Vector2(5.0f, -10.0f)); + Matrix2 b(Vector2(1.0f + MathTypeTraits::epsilon()/2, -3.0f), + Vector2(5.0f, -10.0f)); + Matrix2 c(Vector2(1.0f, -1.0f + MathTypeTraits::epsilon()*2), + Vector2(5.0f, -10.0f)); + CORRADE_VERIFY(a == b); + CORRADE_VERIFY(a != c); + + Matrix2i ai(Vector2i(1, -3), + Vector2i(5, -10)); + Matrix2i bi(Vector2i(1, -2), + Vector2i(5, -10)); + CORRADE_VERIFY(ai == ai); + CORRADE_VERIFY(ai != bi); } void RectangularMatrixTest::negative() { - CORRADE_COMPARE(-Matrix2(1.0f, -3.0f, 5.0f, -10.0f), Matrix2(-1.0f, 3.0f, -5.0f, 10.0f)); + Matrix2 matrix(Vector2(1.0f, -3.0f), + Vector2(5.0f, -10.0f)); + Matrix2 negated(Vector2(-1.0f, 3.0f), + Vector2(-5.0f, 10.0f)); + CORRADE_COMPARE(-matrix, negated); } void RectangularMatrixTest::addSubtract() { - Matrix4x3 a(0.0f, 1.0f, 3.0f, - 4.0f, 5.0f, 7.0f, - 8.0f, 9.0f, 11.0f, - 12.0f, 13.0f, 15.0f); - Matrix4x3 b(-4.0f, 0.5f, 9.0f, - -9.0f, 11.0f, 0.25f, - 0.0f, -8.0f, 19.0f, - -3.0f, -5.0f, 2.0f); - Matrix4x3 c(-4.0f, 1.5f, 12.0f, - -5.0f, 16.0f, 7.25f, - 8.0f, 1.0f, 30.0f, - 9.0f, 8.0f, 17.0f); + Matrix4x3 a(Vector3(0.0f, 1.0f, 3.0f), + Vector3(4.0f, 5.0f, 7.0f), + Vector3(8.0f, 9.0f, 11.0f), + Vector3(12.0f, 13.0f, 15.0f)); + Matrix4x3 b(Vector3(-4.0f, 0.5f, 9.0f), + Vector3(-9.0f, 11.0f, 0.25f), + Vector3( 0.0f, -8.0f, 19.0f), + Vector3(-3.0f, -5.0f, 2.0f)); + Matrix4x3 c(Vector3(-4.0f, 1.5f, 12.0f), + Vector3(-5.0f, 16.0f, 7.25f), + Vector3( 8.0f, 1.0f, 30.0f), + Vector3( 9.0f, 8.0f, 17.0f)); CORRADE_COMPARE(a + b, c); CORRADE_COMPARE(c - b, a); } void RectangularMatrixTest::multiplyDivide() { - Matrix2 matrix(1.0f, 2.0f, 3.0f, 4.0f); - Matrix2 multiplied(-1.5f, -3.0f, -4.5f, -6.0f); + Matrix2 matrix(Vector2(1.0f, 2.0f), + Vector2(3.0f, 4.0f)); + Matrix2 multiplied(Vector2(-1.5f, -3.0f), + Vector2(-4.5f, -6.0f)); CORRADE_COMPARE(matrix*-1.5f, multiplied); CORRADE_COMPARE(-1.5f*matrix, multiplied); @@ -188,62 +204,58 @@ void RectangularMatrixTest::multiplyDivide() { CORRADE_COMPARE(-1.5f*matrixChar, multipliedChar); /* Divide vector with number and inverse */ - Matrix2 divisor(1.0f, 2.0f, -4.0f, 8.0f); - Matrix2 result(1.0f, 0.5f, -0.25f, 0.125f); + 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() { RectangularMatrix<4, 6, std::int32_t> left( - -5, 27, 10, 33, 0, -15, - 7, 56, 66, 1, 0, -24, - 4, 41, 4, 0, 1, -4, - 9, -100, 19, -49, 1, 9 + Vector<6, std::int32_t>(-5, 27, 10, 33, 0, -15), + Vector<6, std::int32_t>( 7, 56, 66, 1, 0, -24), + Vector<6, std::int32_t>( 4, 41, 4, 0, 1, -4), + Vector<6, std::int32_t>( 9, -100, 19, -49, 1, 9) ); RectangularMatrix<5, 4, std::int32_t> right( - 1, -7, 0, 158, - 2, 24, -3, 40, - 3, -15, -2, -50, - 4, 17, -1, -284, - 5, 30, 4, 18 + Vector<4, std::int32_t>(1, -7, 0, 158), + Vector<4, std::int32_t>(2, 24, -3, 40), + Vector<4, std::int32_t>(3, -15, -2, -50), + Vector<4, std::int32_t>(4, 17, -1, -284), + Vector<4, std::int32_t>(5, 30, 4, 18) ); RectangularMatrix<5, 6, std::int32_t> expected( - 1368, -16165, 2550, -7716, 158, 1575, - 506, -2725, 2352, -1870, 37, -234, - -578, 4159, -1918, 2534, -52, -127, - -2461, 29419, -4238, 14065, -285, -3020, - 363, 179, 2388, -687, 22, -649 + Vector<6, std::int32_t>( 1368, -16165, 2550, -7716, 158, 1575), + Vector<6, std::int32_t>( 506, -2725, 2352, -1870, 37, -234), + Vector<6, std::int32_t>( -578, 4159, -1918, 2534, -52, -127), + Vector<6, std::int32_t>(-2461, 29419, -4238, 14065, -285, -3020), + Vector<6, std::int32_t>( 363, 179, 2388, -687, 22, -649) ); CORRADE_COMPARE(left*right, expected); } void RectangularMatrixTest::transposed() { - Matrix4x3 original( - 0.0f, 1.0f, 3.0f, - 4.0f, 5.0f, 7.0f, - 8.0f, 9.0f, 11.0f, - 12.0f, 13.0f, 15.0f - ); + Matrix4x3 original(Vector3( 0.0f, 1.0f, 3.0f), + Vector3( 4.0f, 5.0f, 7.0f), + Vector3( 8.0f, 9.0f, 11.0f), + Vector3(12.0f, 13.0f, 15.0f)); - Matrix3x4 transposed( - 0.0f, 4.0f, 8.0f, 12.0f, - 1.0f, 5.0f, 9.0f, 13.0f, - 3.0f, 7.0f, 11.0f, 15.0f - ); + Matrix3x4 transposed(Vector4(0.0f, 4.0f, 8.0f, 12.0f), + Vector4(1.0f, 5.0f, 9.0f, 13.0f), + Vector4(3.0f, 7.0f, 11.0f, 15.0f)); CORRADE_COMPARE(original.transposed(), transposed); } void RectangularMatrixTest::debug() { - Matrix3x4 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 - ); + Matrix3x4 m(Vector4(3.0f, 5.0f, 8.0f, 4.0f), + Vector4(4.0f, 4.0f, 7.0f, 3.0f), + Vector4(7.0f, -1.0f, 8.0f, 0.0f)); std::ostringstream o; Debug(&o) << m; @@ -263,11 +275,9 @@ void RectangularMatrixTest::debug() { } void RectangularMatrixTest::configuration() { - Matrix3x4 m( - 3.0f, 5.0f, 8.0f, 4.0f, - 4.0f, 4.0f, 7.0f, 3.125f, - 7.0f, -1.0f, 8.0f, 9.55f - ); + Matrix3x4 m(Vector4(3.0f, 5.0f, 8.0f, 4.0f), + Vector4(4.0f, 4.0f, 7.0f, 3.125f), + Vector4(7.0f, -1.0f, 8.0f, 9.55f)); std::string value("3 4 7 5 4 -1 8 7 8 4 3.125 9.55"); Configuration c; diff --git a/src/Math/Vector.cpp b/src/Math/Vector.cpp index 0004c854e..3e54dedd8 100644 --- a/src/Math/Vector.cpp +++ b/src/Math/Vector.cpp @@ -35,3 +35,25 @@ template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Magnu #endif }} + +namespace Corrade { namespace Utility { + +#ifndef DOXYGEN_GENERATING_OUTPUT +template struct ConfigurationValue>; +template struct ConfigurationValue>; +template struct ConfigurationValue>; +template struct ConfigurationValue>; +template struct ConfigurationValue>; +template struct ConfigurationValue>; +template struct ConfigurationValue>; +template struct ConfigurationValue>; +template struct ConfigurationValue>; +#ifndef MAGNUM_TARGET_GLES +template struct ConfigurationValue>; +template struct ConfigurationValue>; +template struct ConfigurationValue>; +#endif +#endif + +}} + diff --git a/src/Math/Vector.h b/src/Math/Vector.h index b2581d3f3..b85b65739 100644 --- a/src/Math/Vector.h +++ b/src/Math/Vector.h @@ -19,12 +19,32 @@ * @brief Class Magnum::Math::Vector */ +#include +#include #include +#include +#include -#include "RectangularMatrix.h" +#include "Math/MathTypeTraits.h" + +#include "magnumVisibility.h" namespace Magnum { namespace Math { +#ifndef DOXYGEN_GENERATING_OUTPUT +namespace Implementation { + template struct Sequence {}; + + /* E.g. GenerateSequence<3>::Type is Sequence<0, 1, 2> */ + template struct GenerateSequence: + GenerateSequence {}; + + template struct GenerateSequence<0, sequence...> { + typedef Sequence Type; + }; +} +#endif + /** @brief %Vector @tparam size %Vector size @@ -33,9 +53,45 @@ namespace Magnum { namespace Math { See @ref matrix-vector for brief introduction. @configurationvalueref{Magnum::Math::Vector} */ -template class Vector: public RectangularMatrix<1, size, T> { +template class Vector { + static_assert(size != 0, "Vector cannot have zero elements"); + + template friend class Vector; + public: - const static std::size_t Size = size; /**< @brief %Vector size */ + typedef T Type; /**< @brief Data type */ + const static std::size_t Size = size; /**< @brief %Vector size */ + + /** + * @brief %Vector from array + * @return Reference to the data as if it was Vector, thus doesn't + * perform any copying. + * + * @attention Use with caution, the function doesn't check whether the + * array is long enough. + */ + inline constexpr static Vector& from(T* data) { + return *reinterpret_cast*>(data); + } + /** @overload */ + inline constexpr static const Vector& from(const T* data) { + return *reinterpret_cast*>(data); + } + + /** + * @brief %Vector from another of different type + * + * Performs only default casting on the values, no rounding or + * anything else. Example usage: + * @code + * Vector<4, float> floatingPoint(1.3f, 2.7f, -15.0f, 7.0f); + * Vector<4, std::int8_t> integral(Vector<4, std::int8_t>::from(floatingPoint)); + * // integral == {1, 2, -15, 7} + * @endcode + */ + template inline constexpr static Vector from(const Vector& other) { + return from(typename Implementation::GenerateSequence::Type(), other); + } /** * @brief Dot product @@ -84,7 +140,7 @@ template class Vector: public RectangularMatrix<1, si } /** @brief Construct zero-filled vector */ - inline constexpr /*implicit*/ Vector() {} + inline constexpr /*implicit*/ Vector(): _data() {} /** @todo Creating Vector from combination of vector and scalar types */ @@ -93,7 +149,9 @@ template class Vector: public RectangularMatrix<1, si * @param first First value * @param next Next values */ - template inline constexpr /*implicit*/ Vector(T first, U... next): RectangularMatrix<1, size, T>(first, next...) {} + template inline constexpr /*implicit*/ Vector(T first, U... next): _data{first, next...} { + static_assert(sizeof...(next)+1 == size, "Improper number of arguments passed to Vector constructor"); + } /** @brief Construct vector with one value for all fields */ #ifdef DOXYGEN_GENERATING_OUTPUT @@ -102,15 +160,45 @@ template class Vector: public RectangularMatrix<1, si template inline explicit Vector(typename std::enable_if::value && size != 1, U>::type value) { #endif for(std::size_t i = 0; i != size; ++i) - (*this)[i] = value; + _data[i] = value; } /** @brief Copy constructor */ - inline constexpr Vector(const RectangularMatrix<1, size, T>& other): RectangularMatrix<1, size, T>(other) {} + inline constexpr Vector(const Vector&) = default; - /** @brief Value at given position */ - inline T& operator[](std::size_t pos) { return RectangularMatrix<1, size, T>::_data[pos]; } - inline constexpr T operator[](std::size_t pos) const { return RectangularMatrix<1, size, T>::_data[pos]; } /**< @overload */ + /** @brief Assignment operator */ + inline Vector& operator=(const Vector&) = default; + + /** + * @brief Raw data + * @return One-dimensional array of `size*size` length in column-major + * order. + * + * @see operator[] + */ + inline T* data() { return _data; } + inline constexpr const T* data() const { return _data; } /**< @overload */ + + /** + * @brief Value at given position + * + * @see data() + */ + inline T& operator[](std::size_t pos) { return _data[pos]; } + inline constexpr T operator[](std::size_t pos) const { return _data[pos]; } /**< @overload */ + + /** @brief Equality comparison */ + inline bool operator==(const Vector& other) const { + for(std::size_t i = 0; i != size; ++i) + if(!MathTypeTraits::equals(_data[i], other._data[i])) return false; + + return true; + } + + /** @brief Non-equality comparison */ + inline constexpr bool operator!=(const Vector& other) const { + return !operator==(other); + } /** * @brief Component-wise less than @@ -119,7 +207,7 @@ template class Vector: public RectangularMatrix<1, si */ inline bool operator<(const Vector& other) const { for(std::size_t i = 0; i != size; ++i) - if((*this)[i] >= other[i]) return false; + if(_data[i] >= other._data[i]) return false; return true; } @@ -131,7 +219,7 @@ template class Vector: public RectangularMatrix<1, si */ inline bool operator<=(const Vector& other) const { for(std::size_t i = 0; i != size; ++i) - if((*this)[i] > other[i]) return false; + if(_data[i] > other._data[i]) return false; return true; } @@ -143,7 +231,7 @@ template class Vector: public RectangularMatrix<1, si */ inline bool operator>=(const Vector& other) const { for(std::size_t i = 0; i != size; ++i) - if((*this)[i] < other[i]) return false; + if(_data[i] < other._data[i]) return false; return true; } @@ -155,11 +243,135 @@ template class Vector: public RectangularMatrix<1, si */ inline bool operator>(const Vector& other) const { for(std::size_t i = 0; i != size; ++i) - if((*this)[i] <= other[i]) return false; + if(_data[i] <= other._data[i]) return false; return true; } + /** + * @brief Negated vector + * + * The computation is done in-place. @f[ + * \boldsymbol a_i = -\boldsymbol a_i + * @f] + */ + Vector operator-() const { + Vector out; + + for(std::size_t i = 0; i != size; ++i) + out._data[i] = -_data[i]; + + return out; + } + + /** + * @brief Add and assign vector + * + * The computation is done in-place. @f[ + * \boldsymbol a_i = \boldsymbol a_i + \boldsymbol b_i + * @f] + */ + Vector& operator+=(const Vector& other) { + for(std::size_t i = 0; i != size; ++i) + _data[i] += other._data[i]; + + return *this; + } + + /** + * @brief Add vector + * + * @see operator+=() + */ + inline Vector operator+(const Vector& other) const { + return Vector(*this) += other; + } + + /** + * @brief Subtract and assign vector + * + * The computation is done in-place. @f[ + * \boldsymbol a_i = \boldsymbol a_i - \boldsymbol b_i + * @f] + */ + Vector& operator-=(const Vector& other) { + for(std::size_t i = 0; i != size; ++i) + _data[i] -= other._data[i]; + + return *this; + } + + /** + * @brief Subtract vector + * + * @see operator-=() + */ + inline Vector operator-(const Vector& other) const { + return Vector(*this) -= other; + } + + /** + * @brief Multiply vector with number and assign + * + * The computation is done in-place. @f[ + * \boldsymbol a_i = b \boldsymbol a_i + * @f] + */ + #ifdef DOXYGEN_GENERATING_OUTPUT + template Vector& operator*=(U number) { + #else + template inline typename std::enable_if::value, Vector&>::type operator*=(U number) { + #endif + for(std::size_t i = 0; i != size; ++i) + _data[i] *= number; + + return *this; + } + + /** + * @brief Multiply vector with number + * + * @see operator*=(U), operator*(U, const Vector&) + */ + #ifdef DOXYGEN_GENERATING_OUTPUT + template inline Vector operator*(U number) const { + #else + template inline typename std::enable_if::value, Vector>::type operator*(U number) const { + #endif + return Vector(*this) *= number; + } + + /** + * @brief Divide vector with number and assign + * + * The computation is done in-place. @f[ + * \boldsymbol a_i = \frac{\boldsymbol a_i} b + * @f] + */ + #ifdef DOXYGEN_GENERATING_OUTPUT + template Vector& operator/=(U number) { + #else + template inline typename std::enable_if::value, Vector&>::type operator/=(U number) { + #endif + for(std::size_t i = 0; i != size; ++i) + _data[i] /= number; + + return *this; + } + + /** + * @brief Divide vector with number + * + * @see operator/=(), operator/(U, const Vector&) + */ + #ifdef DOXYGEN_GENERATING_OUTPUT + template inline Vector operator/(U number) const { + #else + template inline typename std::enable_if::value, Vector>::type operator/(U number) const { + #endif + return Vector(*this) /= number; + } + /** * @brief Multiply vector component-wise and assign * @@ -169,7 +381,7 @@ template class Vector: public RectangularMatrix<1, si */ template Vector& operator*=(const Vector& other) { for(std::size_t i = 0; i != size; ++i) - (*this)[i] *= other[i]; + _data[i] *= other._data[i]; return *this; } @@ -192,7 +404,7 @@ template class Vector: public RectangularMatrix<1, si */ template Vector& operator/=(const Vector& other) { for(std::size_t i = 0; i != size; ++i) - (*this)[i] /= other[i]; + _data[i] /= other._data[i]; return *this; } @@ -252,66 +464,83 @@ template class Vector: public RectangularMatrix<1, si T out(0); for(std::size_t i = 0; i != size; ++i) - out += (*this)[i]; + out += _data[i]; return out; } /** @brief Product of values in the vector */ T product() const { - T out(1); + T out(_data[0]); - for(std::size_t i = 0; i != size; ++i) - out *= (*this)[i]; + for(std::size_t i = 1; i != size; ++i) + out *= _data[i]; return out; } /** @brief Minimal value in the vector */ T min() const { - T out((*this)[0]); + T out(_data[0]); for(std::size_t i = 1; i != size; ++i) - out = std::min(out, (*this)[i]); + out = std::min(out, _data[i]); return out; } /** @brief Maximal value in the vector */ T max() const { - T out((*this)[0]); + T out(_data[0]); for(std::size_t i = 1; i != size; ++i) - out = std::max(out, (*this)[i]); + out = std::max(out, _data[i]); return out; } - #ifndef DOXYGEN_GENERATING_OUTPUT - /* Reimplementation of functions to return correct type */ - template inline RectangularMatrix operator*(const RectangularMatrix& other) const { - return RectangularMatrix<1, size, T>::operator*(other); + private: + /* Implementation for from(const Vector&) */ + template inline constexpr static Vector from(Implementation::Sequence, const Vector& vector) { + return {T(vector.data()[sequence])...}; } - MAGNUM_RECTANGULARMATRIX_SUBCLASS_IMPLEMENTATION(1, size, Vector) - MAGNUM_RECTANGULARMATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(1, size, Vector) - #endif - private: - /* Hiding unused things from RectangularMatrix */ - using RectangularMatrix<1, size, T>::Cols; - using RectangularMatrix<1, size, T>::Rows; - using RectangularMatrix<1, size, T>::operator[]; - using RectangularMatrix<1, size, T>::operator(); + T _data[size]; }; -#ifndef DOXYGEN_GENERATING_OUTPUT +/** @relates Vector +@brief Multiply number with vector + +Same as Vector::operator*(U) const. +*/ +#ifdef DOXYGEN_GENERATING_OUTPUT +template inline Vector operator*(U number, const Vector& vector) { +#else template inline typename std::enable_if::value, Vector>::type operator*(U number, const Vector& vector) { - return number*RectangularMatrix<1, size, T>(vector); +#endif + return vector*number; } + +/** @relates Vector +@brief Divide vector with number and invert + +@f[ + \boldsymbol c_i = \frac b {\boldsymbol a_i} +@f] +@see Vector::operator/() +*/ +#ifdef DOXYGEN_GENERATING_OUTPUT +template inline Vector operator/(U number, const Vector& vector) { +#else template inline typename std::enable_if::value, Vector>::type operator/(U number, const Vector& vector) { - return number/RectangularMatrix<1, size, T>(vector); -} #endif + Vector out; + + for(std::size_t i = 0; i != size; ++i) + out[i] = number/vector[i]; + + return out; +} /** @debugoperator{Magnum::Math::Vector} */ template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Vector& value) { @@ -364,22 +593,50 @@ extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utilit return *this; \ } \ \ - template inline Math::RectangularMatrix operator*(const Math::RectangularMatrix& other) const { \ - return Math::Vector::operator*(other); \ + inline Type operator-() const { \ + return Math::Vector::operator-(); \ } \ - template inline Type operator*(const Math::Vector& other) const { \ - return Math::Vector::operator*(other); \ + inline Type& operator+=(const Math::Vector& other) { \ + Math::Vector::operator+=(other); \ + return *this; \ + } \ + inline Type operator+(const Math::Vector& other) const { \ + return Math::Vector::operator+(other); \ + } \ + inline Type& operator-=(const Math::Vector& other) { \ + Math::Vector::operator-=(other); \ + return *this; \ + } \ + inline Type operator-(const Math::Vector& other) const { \ + return Math::Vector::operator-(other); \ + } \ + template inline typename std::enable_if::value, Type&>::type operator*=(U number) { \ + Math::Vector::operator*=(number); \ + return *this; \ + } \ + template inline typename std::enable_if::value, Type>::type operator*(U number) const { \ + return Math::Vector::operator*(number); \ + } \ + template inline typename std::enable_if::value, Type&>::type operator/=(U number) { \ + Math::Vector::operator/=(number); \ + return *this; \ + } \ + template inline typename std::enable_if::value, Type>::type operator/(U number) const { \ + return Math::Vector::operator/(number); \ } \ template inline Type& operator*=(const Math::Vector& other) { \ Math::Vector::operator*=(other); \ return *this; \ } \ - template inline Type operator/(const Math::Vector& other) const { \ - return Math::Vector::operator/(other); \ + template inline Type operator*(const Math::Vector& other) const { \ + return Math::Vector::operator*(other); \ } \ template inline Type& operator/=(const Math::Vector& other) { \ Math::Vector::operator/=(other); \ return *this; \ + } \ + template inline Type operator/(const Math::Vector& other) const { \ + return Math::Vector::operator/(other); \ } \ \ inline Type normalized() const { return Math::Vector::normalized(); } \ @@ -400,8 +657,60 @@ extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utilit namespace Corrade { namespace Utility { -/** @configurationvalue{Magnum::Math::Vector} */ -template struct ConfigurationValue>: public ConfigurationValue> {}; +/** @configurationvalue{Magnum::Math::RectangularMatrix} */ +template struct ConfigurationValue> { + ConfigurationValue() = delete; + + /** @brief Writes elements separated with spaces */ + static std::string toString(const Magnum::Math::Vector& value, ConfigurationValueFlags flags) { + std::string output; + + for(std::size_t i = 0; i != size; ++i) { + if(!output.empty()) output += ' '; + output += ConfigurationValue::toString(value[i], flags); + } + + return output; + } + + /** @brief Reads elements separated with whitespace */ + static Magnum::Math::Vector fromString(const std::string& stringValue, ConfigurationValueFlags flags) { + Magnum::Math::Vector result; + + std::size_t oldpos = 0, pos = std::string::npos, i = 0; + do { + pos = stringValue.find(' ', oldpos); + std::string part = stringValue.substr(oldpos, pos-oldpos); + + if(!part.empty()) { + result[i] = ConfigurationValue::fromString(part, flags); + ++i; + } + + oldpos = pos+1; + } while(pos != std::string::npos); + + return result; + } +}; + +#ifndef DOXYGEN_GENERATING_OUTPUT +/* Vectors */ +extern template struct MAGNUM_EXPORT ConfigurationValue>; +extern template struct MAGNUM_EXPORT ConfigurationValue>; +extern template struct MAGNUM_EXPORT ConfigurationValue>; +extern template struct MAGNUM_EXPORT ConfigurationValue>; +extern template struct MAGNUM_EXPORT ConfigurationValue>; +extern template struct MAGNUM_EXPORT ConfigurationValue>; +extern template struct MAGNUM_EXPORT ConfigurationValue>; +extern template struct MAGNUM_EXPORT ConfigurationValue>; +extern template struct MAGNUM_EXPORT ConfigurationValue>; +#ifndef MAGNUM_TARGET_GLES +extern template struct MAGNUM_EXPORT ConfigurationValue>; +extern template struct MAGNUM_EXPORT ConfigurationValue>; +extern template struct MAGNUM_EXPORT ConfigurationValue>; +#endif +#endif }} diff --git a/src/Math/Vector2.h b/src/Math/Vector2.h index f27be7c48..ffd13751e 100644 --- a/src/Math/Vector2.h +++ b/src/Math/Vector2.h @@ -85,7 +85,7 @@ template class Vector2: public Vector<2, T> { inline constexpr /*implicit*/ Vector2(T x, T y): Vector<2, T>(x, y) {} /** @brief Copy constructor */ - inline constexpr Vector2(const RectangularMatrix<1, 2, T>& other): Vector<2, T>(other) {} + inline constexpr Vector2(const Vector<2, T>& other): Vector<2, T>(other) {} inline T& x() { return (*this)[0]; } /**< @brief X component */ inline constexpr T x() const { return (*this)[0]; } /**< @overload */ @@ -93,7 +93,6 @@ template class Vector2: public Vector<2, T> { inline constexpr T y() const { return (*this)[1]; } /**< @overload */ MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(Vector2, 2) - MAGNUM_RECTANGULARMATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(1, 2, Vector2) }; MAGNUM_VECTOR_SUBCLASS_OPERATOR_IMPLEMENTATION(Vector2, 2) diff --git a/src/Math/Vector3.h b/src/Math/Vector3.h index ddec15a4a..3897a726e 100644 --- a/src/Math/Vector3.h +++ b/src/Math/Vector3.h @@ -126,7 +126,7 @@ template class Vector3: public Vector<3, T> { inline constexpr /*implicit*/ Vector3(const Vector2& xy, T z): Vector<3, T>(xy[0], xy[1], z) {} /** @brief Copy constructor */ - inline constexpr Vector3(const RectangularMatrix<1, 3, T>& other): Vector<3, T>(other) {} + inline constexpr Vector3(const Vector<3, T>& other): Vector<3, T>(other) {} inline T& x() { return (*this)[0]; } /**< @brief X component */ inline constexpr T x() const { return (*this)[0]; } /**< @overload */ @@ -145,7 +145,6 @@ template class Vector3: public Vector<3, T> { inline constexpr Vector2 xy() const { return Vector2::from(Vector<3, T>::data()); } /**< @overload */ MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(Vector3, 3) - MAGNUM_RECTANGULARMATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(1, 3, Vector3) }; MAGNUM_VECTOR_SUBCLASS_OPERATOR_IMPLEMENTATION(Vector3, 3) diff --git a/src/Math/Vector4.h b/src/Math/Vector4.h index 9bc2265b2..8d93a6609 100644 --- a/src/Math/Vector4.h +++ b/src/Math/Vector4.h @@ -57,7 +57,7 @@ template class Vector4: public Vector<4, T> { inline constexpr /*implicit*/ Vector4(const Vector3& xyz, T w): Vector<4, T>(xyz[0], xyz[1], xyz[2], w) {} /** @brief Copy constructor */ - inline constexpr Vector4(const RectangularMatrix<1, 4, T>& other): Vector<4, T>(other) {} + inline constexpr Vector4(const Vector<4, T>& other): Vector<4, T>(other) {} inline T& x() { return (*this)[0]; } /**< @brief X component */ inline constexpr T x() const { return (*this)[0]; } /**< @overload */ @@ -87,7 +87,6 @@ template class Vector4: public Vector<4, T> { inline constexpr Vector2 xy() const { return Vector2::from(Vector<4, T>::data()); } /**< @overload */ MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(Vector4, 4) - MAGNUM_RECTANGULARMATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(1, 4, Vector4) }; MAGNUM_VECTOR_SUBCLASS_OPERATOR_IMPLEMENTATION(Vector4, 4) diff --git a/src/Mesh.h b/src/Mesh.h index 40a6658a3..959a0f334 100644 --- a/src/Mesh.h +++ b/src/Mesh.h @@ -210,6 +210,8 @@ for more information. @todo Support for indirect draw buffer (OpenGL 4.0, @extension{ARB,draw_indirect}) @todo Redo in a way that allows glMultiDrawArrays, glDrawArraysInstanced etc. +@todo test vertex specification & drawing +@todo How to glDrawElementsBaseVertex()/vertex offset -- in draw()? */ class MAGNUM_EXPORT Mesh { friend class Context; diff --git a/src/SceneGraph/Test/CameraTest.cpp b/src/SceneGraph/Test/CameraTest.cpp index 2a3ba52f9..07d42dfc3 100644 --- a/src/SceneGraph/Test/CameraTest.cpp +++ b/src/SceneGraph/Test/CameraTest.cpp @@ -75,27 +75,27 @@ void CameraTest::fixAspectRatio() { CORRADE_COMPARE((Implementation::aspectRatioFix<3, GLfloat>(AspectRatioPolicy::NotPreserved, projectionScale, size)), Matrix4()); /* Clip */ - Matrix4 expectedClip(1.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 4.0f/3.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 1.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f); + Matrix4 expectedClip({1.0f, 0.0f, 0.0f, 0.0f}, + {0.0f, 4.0f/3.0f, 0.0f, 0.0f}, + {0.0f, 0.0f, 1.0f, 0.0f}, + {0.0f, 0.0f, 0.0f, 1.0f}); CORRADE_COMPARE((Implementation::aspectRatioFix<3, GLfloat>(AspectRatioPolicy::Clip, Vector2(0.5f), size)), expectedClip); - Matrix4 expectedClipRectangle(1.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 2.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 1.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f); + Matrix4 expectedClipRectangle({1.0f, 0.0f, 0.0f, 0.0f}, + {0.0f, 2.0f, 0.0f, 0.0f}, + {0.0f, 0.0f, 1.0f, 0.0f}, + {0.0f, 0.0f, 0.0f, 1.0f}); CORRADE_COMPARE((Implementation::aspectRatioFix<3, GLfloat>(AspectRatioPolicy::Clip, projectionScale, size)), expectedClipRectangle); /* Extend */ - Matrix4 expectedExtend(3.0f/4.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 1.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 1.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f); + Matrix4 expectedExtend({3.0f/4.0f, 0.0f, 0.0f, 0.0f}, + { 0.0f, 1.0f, 0.0f, 0.0f}, + { 0.0f, 0.0f, 1.0f, 0.0f}, + { 0.0f, 0.0f, 0.0f, 1.0f}); CORRADE_COMPARE((Implementation::aspectRatioFix<3, GLfloat>(AspectRatioPolicy::Extend, Vector2(0.5f), size)), expectedExtend); - Matrix4 expectedExtendRectangle(0.5f, 0.0f, 0.0f, 0.0f, - 0.0f, 1.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 1.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f); + Matrix4 expectedExtendRectangle({0.5f, 0.0f, 0.0f, 0.0f}, + {0.0f, 1.0f, 0.0f, 0.0f}, + {0.0f, 0.0f, 1.0f, 0.0f}, + {0.0f, 0.0f, 0.0f, 1.0f}); CORRADE_COMPARE((Implementation::aspectRatioFix<3, GLfloat>(AspectRatioPolicy::Extend, projectionScale, size)), expectedExtendRectangle); }