diff --git a/src/Color.h b/src/Color.h index c95e010a3..125c820d2 100644 --- a/src/Color.h +++ b/src/Color.h @@ -213,8 +213,8 @@ template class Color3: public Math::Vector3 { */ inline constexpr explicit Color3(T rgb): Math::Vector3(rgb) {} - /** @copydoc Math::Vector::Vector(const Vector&) */ - inline constexpr Color3(const Math::Vector<3, T>& other): Math::Vector3(other) {} + /** @brief Copy constructor */ + inline constexpr Color3(const Math::RectangularMatrix<1, 3, T>& other): Math::Vector3(other) {} /** * @brief Constructor @@ -335,8 +335,8 @@ template class Color4: public Math::Vector4 { */ inline constexpr explicit Color4(T rgb, T alpha = Implementation::defaultAlpha()): Math::Vector4(rgb, rgb, rgb, alpha) {} - /** @copydoc Math::Vector::Vector(const Vector&) */ - inline constexpr Color4(const Math::Vector<4, T>& other): Math::Vector4(other) {} + /** @brief Copy constructor */ + inline constexpr Color4(const Math::RectangularMatrix<1, 4, T>& other): Math::Vector4(other) {} /** * @brief Constructor diff --git a/src/Math/CMakeLists.txt b/src/Math/CMakeLists.txt index a0cc17b69..7053745a8 100644 --- a/src/Math/CMakeLists.txt +++ b/src/Math/CMakeLists.txt @@ -6,6 +6,7 @@ set(MagnumMath_HEADERS Matrix.h Matrix3.h Matrix4.h + RectangularMatrix.h Vector.h Vector2.h Vector3.h diff --git a/src/Math/Matrix.h b/src/Math/Matrix.h index 1e7f0a4c6..d16e88823 100644 --- a/src/Math/Matrix.h +++ b/src/Math/Matrix.h @@ -19,7 +19,7 @@ * @brief Class Magnum::Math::Matrix */ -#include "Vector.h" +#include "RectangularMatrix.h" namespace Magnum { namespace Math { @@ -30,44 +30,16 @@ namespace Implementation { #endif /** -@brief %Matrix +@brief Square matrix +@tparam s %Matrix size @configurationvalueref{Magnum::Math::Matrix} @todo @c PERFORMANCE - loop unrolling for Matrix<3, T> and Matrix<4, T> @todo first col, then row (cache adjacency) */ -template class Matrix { - static_assert(size != 0, "Matrix cannot have zero elements"); - +template class Matrix: public RectangularMatrix { public: - const static size_t Size = size; /**< @brief %Matrix size */ - typedef T Type; /**< @brief %Matrix data type */ - - /** - * @brief %Matrix from array - * @return Reference to the data as if it was Matrix, thus doesn't - * perform any copying. - * - * @attention Use with caution, the function doesn't check whether the - * array is long enough. - */ - inline constexpr static Matrix& from(T* data) { - return *reinterpret_cast*>(data); - } - /** @overload */ - inline constexpr static const Matrix& from(const T* data) { - return *reinterpret_cast*>(data); - } - - /** - * @brief %Matrix from column vectors - * @param first First column vector - * @param next Next column vectors - */ - template inline constexpr static Matrix from(const Vector& first, const U&... next) { - static_assert(sizeof...(next)+1 == size, "Improper number of arguments passed to Matrix from Vector constructor"); - return from(typename Implementation::GenerateSequence::Type(), first, next...); - } + const static size_t size = s; /**< @brief %Matrix size */ /** @brief Pass to constructor to create zero-filled matrix */ enum ZeroType { Zero }; @@ -77,7 +49,7 @@ template class Matrix { * * Use this constructor by calling `Matrix m(Matrix::Zero);`. */ - inline constexpr explicit Matrix(ZeroType): _data() {} + inline constexpr explicit Matrix(ZeroType) {} /** @brief Pass to constructor to create identity matrix */ enum IdentityType { Identity }; @@ -89,121 +61,26 @@ template class Matrix { * `Matrix m(Matrix::Identity);`. Optional parameter @p value allows * you to specify value on diagonal. */ - inline explicit Matrix(IdentityType = Identity, T value = T(1)): _data() { + inline explicit Matrix(IdentityType = Identity, T value = T(1)) { for(size_t i = 0; i != size; ++i) - _data[size*i+i] = value; + (*this)(i, i) = value; } - /** - * @brief Initializer-list constructor - * @param first First value - * @param next Next values - * - * Note that the values are in column-major order. - * @todoc Remove workaround when Doxygen supports uniform initialization - */ + /** @copydoc RectangularMatrix::RectangularMatrix(T, U...) */ #ifndef DOXYGEN_GENERATING_OUTPUT - template inline constexpr Matrix(T first, U... next): _data{first, next...} { - static_assert(sizeof...(next)+1 == size*size, "Improper number of arguments passed to Matrix constructor"); - } + template inline constexpr Matrix(T first, U... next): RectangularMatrix(first, next...) {} #else template inline constexpr Matrix(T first, U... next); #endif /** @brief Copy constructor */ - inline constexpr Matrix(const Matrix&) = default; - - /** @brief Assignment operator */ - inline Matrix& operator=(const Matrix&) = default; - - /** - * @brief Raw data - * @return One-dimensional array of `size*size` length in column-major - * order. - */ - inline T* data() { return _data; } - inline constexpr const T* data() const { return _data; } /**< @overload */ - - /** - * @brief %Matrix column - * - * For accessing individual elements prefer to use operator(), as it - * is guaranteed to not involve unnecessary conversions. - */ - inline Vector& operator[](size_t col) { - return Vector::from(_data+col*size); - } - /** @overload */ - inline constexpr const Vector& operator[](size_t col) const { - return Vector::from(_data+col*size); - } - - /** - * @brief Element on given position - * - * Prefer this instead of using `[][]`. - * @see operator[] - */ - inline T& operator()(size_t col, size_t row) { - return _data[col*size+row]; - } - /** @overload */ - inline constexpr const T& operator()(size_t col, size_t row) const { - return _data[col*size+row]; - } - - /** @brief Equality operator */ - inline bool operator==(const Matrix& other) const { - for(size_t i = 0; i != size*size; ++i) - if(!MathTypeTraits::equals(_data[i], other._data[i])) return false; - - return true; - } - - /** @brief Non-equality operator */ - inline constexpr bool operator!=(const Matrix& other) const { - return !operator==(other); - } - - /** @brief Multiply matrix operator */ - Matrix operator*(const Matrix& other) const { - Matrix out(Zero); - - for(size_t row = 0; row != size; ++row) - for(size_t col = 0; col != size; ++col) - for(size_t pos = 0; pos != size; ++pos) - out(col, row) += (*this)(pos, row)*other(col, pos); - - return out; - } + inline constexpr Matrix(const RectangularMatrix& other): RectangularMatrix(other) {} /** @brief Multiply and assign matrix operator */ - inline Matrix& operator*=(const Matrix& other) { + inline Matrix& operator*=(const RectangularMatrix& other) { return (*this = *this*other); } - /** @brief Multiply vector operator */ - Vector operator*(const Vector& other) const { - Vector out; - - for(size_t row = 0; row != size; ++row) - for(size_t pos = 0; pos != size; ++pos) - out[row] += (*this)(pos, row)*other[pos]; - - return out; - } - - /** @brief Transposed matrix */ - Matrix transposed() const { - Matrix out(Zero); - - for(size_t row = 0; row != size; ++row) - for(size_t col = 0; col != size; ++col) - out(row, col) = (*this)(col, row); - - return out; - } - /** @brief %Matrix without given column and row */ Matrix ij(size_t skipCol, size_t skipRow) const { Matrix out(Matrix::Zero); @@ -252,32 +129,24 @@ template class Matrix { return out; } - private: - template inline constexpr static Matrix from(Implementation::Sequence s, const Vector& first, U... next) { - return from(s, next..., first[sequence]...); + #ifndef DOXYGEN_GENERATING_OUTPUT + /* Reimplementation of functions to return correct type */ + inline Matrix operator*(const Matrix& other) const { + return RectangularMatrix::operator*(other); } - - template inline constexpr static Matrix from(Implementation::Sequence, T first, U... next) { - return Matrix(first, next...); + template inline RectangularMatrix operator*(const RectangularMatrix& other) const { + return RectangularMatrix::operator*(other); } - - T _data[size*size]; + inline Vector operator*(const Vector& other) const { + return RectangularMatrix::operator*(other); + } + #endif + MAGNUM_RECTANGULARMATRIX_SUBCLASS_IMPLEMENTATION(size, size, Matrix) }; /** @debugoperator{Magnum::Math::Matrix} */ template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Magnum::Math::Matrix& value) { - debug << "Matrix("; - debug.setFlag(Corrade::Utility::Debug::SpaceAfterEachValue, false); - for(size_t row = 0; row != size; ++row) { - if(row != 0) debug << ",\n "; - for(size_t col = 0; col != size; ++col) { - if(col != 0) debug << ", "; - debug << typename MathTypeTraits::NumericType(value[col][row]); - } - } - debug << ')'; - debug.setFlag(Corrade::Utility::Debug::SpaceAfterEachValue, true); - return debug; + return debug << static_cast&>(value); } #ifndef DOXYGEN_GENERATING_OUTPUT @@ -311,6 +180,9 @@ template Corrade::Utility::Debug operator<<(Corrade::Utili Matrix::operator*=(other); \ return *this; \ } \ + template inline RectangularMatrix operator*(const RectangularMatrix& other) const { \ + return Matrix::operator*(other); \ + } \ inline VectorType operator*(const Vector& other) const { \ return Matrix::operator*(other); \ } \ @@ -355,40 +227,8 @@ template class MatrixDeterminant<1, T> { }} namespace Corrade { namespace Utility { - -/** @configurationvalue{Magnum::Math::Matrix} */ -template struct ConfigurationValue> { - /** @brief Writes elements separated with spaces */ - static std::string toString(const Magnum::Math::Matrix& value, int flags = 0) { - std::string output; - - for(size_t row = 0; row != size; ++row) { - for(size_t col = 0; col != size; ++col) { - if(!output.empty()) output += ' '; - output += ConfigurationValue::toString(value(col, row), flags); - } - } - - return output; - } - - /** @brief Reads elements separated with whitespace */ - static Magnum::Math::Matrix fromString(const std::string& stringValue, int flags = 0) { - Magnum::Math::Matrix result(Magnum::Math::Matrix::Zero); - std::istringstream in(stringValue); - - for(size_t row = 0; row != size; ++row) { - for(size_t col = 0; col != size; ++col) { - std::string num; - in >> num; - result(col, row) = ConfigurationValue::fromString(num, flags); - } - } - - return result; - } -}; - + /** @configurationvalue{Magnum::Math::Matrix} */ + template struct ConfigurationValue>: public ConfigurationValue> {}; }} #endif diff --git a/src/Math/Matrix3.h b/src/Math/Matrix3.h index 1cf5640b8..bb6ad65c6 100644 --- a/src/Math/Matrix3.h +++ b/src/Math/Matrix3.h @@ -92,8 +92,8 @@ template class Matrix3: public Matrix<3, T> { template inline constexpr Matrix3(T first, U... next) {} #endif - /** @copydoc Matrix::Matrix(const Matrix&) */ - inline constexpr Matrix3(const Matrix<3, T>& other): Matrix<3, T>(other) {} + /** @brief Copy constructor */ + inline constexpr Matrix3(const RectangularMatrix<3, 3, T>& other): Matrix<3, T>(other) {} MAGNUM_MATRIX_SUBCLASS_IMPLEMENTATION(Matrix3, Vector3, 3) }; diff --git a/src/Math/Matrix4.h b/src/Math/Matrix4.h index c4b0f3935..633376250 100644 --- a/src/Math/Matrix4.h +++ b/src/Math/Matrix4.h @@ -122,8 +122,8 @@ template class Matrix4: public Matrix<4, T> { template inline constexpr Matrix4(T first, U... next) {} #endif - /** @copydoc Matrix::Matrix(const Matrix&) */ - inline constexpr Matrix4(const Matrix<4, T>& other): Matrix<4, T>(other) {} + /** @brief Copy constructor */ + inline constexpr Matrix4(const RectangularMatrix<4, 4, T>& other): Matrix<4, T>(other) {} /** @copydoc Matrix::ij() */ inline Matrix3 ij(size_t skipRow, size_t skipCol) const { return Matrix<4, T>::ij(skipRow, skipCol); } diff --git a/src/Math/RectangularMatrix.h b/src/Math/RectangularMatrix.h new file mode 100644 index 000000000..a5537d131 --- /dev/null +++ b/src/Math/RectangularMatrix.h @@ -0,0 +1,284 @@ +#ifndef Magnum_Math_RectangularMatrix_h +#define Magnum_Math_RectangularMatrix_h +/* + Copyright © 2010, 2011, 2012 Vladimír Vondruš + + This file is part of Magnum. + + Magnum is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 3 + only, as published by the Free Software Foundation. + + Magnum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License version 3 for more details. +*/ + +/** @file + * @brief Class Magnum::Math::RectangularMatrix + */ + +#include +#include +#include +#include + +#include "MathTypeTraits.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 + +template class Vector; + +/** +@brief Rectangular matrix +@tparam c Column count +@tparam r Row count + +See also Matrix (square) and Vector. +*/ +template class RectangularMatrix { + static_assert(c != 0 && r != 0, "Matrix cannot have zero elements"); + + friend class Vector; + + public: + typedef T Type; /**< @brief Data type */ + const static size_t cols = c; /**< @brief %Matrix column count */ + const static size_t rows = r; /**< @brief %Matrix row count */ + + /** + * @brief %Matrix from array + * @return Reference to the data as if it was Matrix, thus doesn't + * perform any copying. + * + * @attention Use with caution, the function doesn't check whether the + * array is long enough. + */ + inline constexpr static RectangularMatrix& from(T* data) { + return *reinterpret_cast*>(data); + } + /** @overload */ + inline constexpr static const RectangularMatrix& from(const T* data) { + return *reinterpret_cast*>(data); + } + + /** + * @brief %Matrix from column vectors + * @param first First column vector + * @param next Next column vectors + */ + 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 Zero-filled matrix constructor */ + inline constexpr RectangularMatrix(): _data() {} + + /** + * @brief Initializer-list constructor + * @param first First value + * @param next Next values + * + * Note that the values are in column-major order. + * @todoc Remove workaround when Doxygen supports uniform initialization + */ + #ifndef DOXYGEN_GENERATING_OUTPUT + template inline constexpr RectangularMatrix(T first, U... next): _data{first, next...} { + static_assert(sizeof...(next)+1 == cols*rows, "Improper number of arguments passed to Matrix constructor"); + } + #else + template inline constexpr RectangularMatrix(T first, U... next); + #endif + + /** @brief Copy constructor */ + inline constexpr RectangularMatrix(const RectangularMatrix&) = default; + + /** @brief Assignment operator */ + inline RectangularMatrix& operator=(const RectangularMatrix&) = default; + + /** + * @brief Raw data + * @return One-dimensional array of `size*size` length in column-major + * order. + */ + inline T* data() { return _data; } + inline constexpr const T* data() const { return _data; } /**< @overload */ + + /** + * @brief %Matrix column + * + * For accessing individual elements prefer to use operator(), as it + * is guaranteed to not involve unnecessary conversions. + */ + inline Vector& operator[](size_t col) { + return Vector::from(_data+col*rows); + } + /** @overload */ + inline constexpr const Vector& operator[](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()(size_t col, size_t row) { + return _data[col*rows+row]; + } + /** @overload */ + inline constexpr const T& operator()(size_t col, size_t row) const { + return _data[col*rows+row]; + } + + /** @brief Equality operator */ + inline bool operator==(const RectangularMatrix& other) const { + for(size_t i = 0; i != cols*rows; ++i) + if(!MathTypeTraits::equals(_data[i], other._data[i])) return false; + + return true; + } + + /** @brief Non-equality operator */ + inline constexpr bool operator!=(const RectangularMatrix& other) const { + return !operator==(other); + } + + /** @brief Multiply matrix */ + template RectangularMatrix operator*(const RectangularMatrix& other) const { + RectangularMatrix out; + + for(size_t row = 0; row != rows; ++row) + for(size_t col = 0; col != size; ++col) /** @todo swap */ + for(size_t pos = 0; pos != cols; ++pos) + out(col, row) += (*this)(pos, row)*other(col, pos); + + return out; + } + + /** + * @brief Multiply vector + * + * Internally the same as multiplying with one-column matrix, but + * returns vector. + */ + Vector operator*(const Vector& other) const { + return operator*(static_cast>(other)); + } + + /** @brief Transposed matrix */ + RectangularMatrix transposed() const { + RectangularMatrix out; + + for(size_t col = 0; col != cols; ++col) + for(size_t row = 0; row != rows; ++row) + out(row, col) = (*this)(col, row); + + return out; + } + + 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...); + } + + T _data[rows*cols]; +}; + +/** @debugoperator{Magnum::Math::RectangularMatrix} */ +template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Magnum::Math::RectangularMatrix& value) { + debug << "Matrix("; + debug.setFlag(Corrade::Utility::Debug::SpaceAfterEachValue, false); + for(size_t row = 0; row != rows; ++row) { + if(row != 0) debug << ",\n "; + for(size_t col = 0; col != cols; ++col) { + if(col != 0) debug << ", "; + debug << typename MathTypeTraits::NumericType(value[col][row]); + } + } + debug << ')'; + debug.setFlag(Corrade::Utility::Debug::SpaceAfterEachValue, true); + return debug; +} + +#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); \ + } \ + inline constexpr static const __VA_ARGS__& from(const T* data) { \ + return *reinterpret_cast(data); \ + } \ + template inline constexpr static __VA_ARGS__ from(const Vector& first, const U&... next) { \ + return RectangularMatrix::from(first, next...); \ + } \ + \ + inline __VA_ARGS__& operator=(const RectangularMatrix& other) { \ + RectangularMatrix::operator=(other); \ + return *this; \ + } +#endif + +}} + +namespace Corrade { namespace Utility { + +/** @configurationvalue{Magnum::Math::RectangularMatrix} */ +template struct ConfigurationValue> { + /** @brief Writes elements separated with spaces */ + static std::string toString(const Magnum::Math::RectangularMatrix& value, int flags = 0) { + std::string output; + + for(size_t row = 0; row != rows; ++row) { + for(size_t col = 0; col != cols; ++col) { + if(!output.empty()) output += ' '; + output += ConfigurationValue::toString(value(col, row), flags); + } + } + + return output; + } + + /** @brief Reads elements separated with whitespace */ + static Magnum::Math::RectangularMatrix fromString(const std::string& stringValue, int flags = 0) { + Magnum::Math::RectangularMatrix result; + std::istringstream in(stringValue); + + for(size_t row = 0; row != rows; ++row) { + for(size_t col = 0; col != cols; ++col) { + std::string num; + in >> num; + result(col, row) = ConfigurationValue::fromString(num, flags); + } + } + + return result; + } +}; + +}} + +/* Include also Vector, so the definition is complete */ +#include "Vector.h" + +#endif diff --git a/src/Math/Test/CMakeLists.txt b/src/Math/Test/CMakeLists.txt index b77ac8e4c..784a73776 100644 --- a/src/Math/Test/CMakeLists.txt +++ b/src/Math/Test/CMakeLists.txt @@ -1,5 +1,7 @@ corrade_add_test2(MathMathTypeTraitsTest MathTypeTraitsTest.cpp) +corrade_add_test2(MathRectangularMatrixTest RectangularMatrixTest.cpp) + corrade_add_test2(MathVectorTest VectorTest.cpp) set_target_properties(MathVectorTest PROPERTIES COMPILE_FLAGS -DCORRADE_GRACEFUL_ASSERT) corrade_add_test2(MathVector2Test Vector2Test.cpp) diff --git a/src/Math/Test/MatrixTest.cpp b/src/Math/Test/MatrixTest.cpp index d9e986c85..1cdd211f6 100644 --- a/src/Math/Test/MatrixTest.cpp +++ b/src/Math/Test/MatrixTest.cpp @@ -32,15 +32,8 @@ typedef Vector<4, float> Vector4; MatrixTest::MatrixTest() { addTests(&MatrixTest::construct, - &MatrixTest::constructFromVectors, &MatrixTest::constructIdentity, &MatrixTest::constructZero, - &MatrixTest::data, - &MatrixTest::copy, - &MatrixTest::multiplyIdentity, - &MatrixTest::multiply, - &MatrixTest::multiplyVector, - &MatrixTest::transposed, &MatrixTest::ij, &MatrixTest::determinant, &MatrixTest::inverted, @@ -66,20 +59,6 @@ void MatrixTest::construct() { CORRADE_COMPARE(Matrix4::from(m), expected); } -void MatrixTest::constructFromVectors() { - Matrix4 actual = Matrix4::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), - Vector4(13.0f, 14.0f, 15.0f, 16.0f)); - - Matrix4 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, - 13.0f, 14.0f, 15.0f, 16.0f); - - CORRADE_COMPARE(actual, expected); -} - void MatrixTest::constructIdentity() { Matrix4 identity; Matrix4 identity2(Matrix4::Identity); @@ -117,122 +96,6 @@ void MatrixTest::constructZero() { CORRADE_COMPARE(zero, zeroExpected); } -void MatrixTest::data() { - Matrix4 m(Matrix4::Zero); - - Vector4 vector(4.0f, 5.0f, 6.0f, 7.0f); - - m[3] = vector; - m[2][1] = 1.0f; - - m(1, 2) = 1.5f; - - CORRADE_COMPARE(m(2, 1), 1.0f); - CORRADE_COMPARE(m[1][2], 1.5f); - CORRADE_COMPARE(m[3], vector); - - Matrix4 expected( - 0.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 1.5f, 0.0f, - 0.0f, 1.0f, 0.0f, 0.0f, - 4.0f, 5.0f, 6.0f, 7.0f - ); - - CORRADE_COMPARE(m, expected); -} - -void MatrixTest::copy() { - Matrix4 m1(Matrix4::Zero); - - m1(2, 3) = 1.0f; - - /* Copy */ - Matrix4 m2(m1); - Matrix4 m3; - m3(0, 0) = 1.0f; /* this line is here so it's not optimized to Matrix4 m3(m1) */ - m3 = m1; - - /* Change original */ - m1(3, 2) = 1.0f; - - /* Verify the copy is the same as original */ - Matrix4 original(Matrix4::Zero); - original(2, 3) = 1.0f; - - CORRADE_COMPARE(m2, original); - CORRADE_COMPARE(m3, original); -} - -void MatrixTest::multiplyIdentity() { - Matrix4 values( - 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 - ); - - CORRADE_COMPARE(Matrix4()*values, values); - CORRADE_COMPARE(values*Matrix4(), values); -} - -void MatrixTest::multiply() { - Matrix<5, int> left( - -3, -3, -1, 3, -5, - -1, -3, -5, 2, 3, - -1, -4, 3, -1, -2, - -5, -5, -1, -4, -1, - 1, 3, -3, -4, -1 - ); - - Matrix<5, int> right( - 0, 5, 3, 4, 4, - 5, 5, 0, 0, -2, - 3, 2, -4, -3, 0, - -3, 0, -1, 2, -1, - 0, -1, -4, 4, 3 - ); - - Matrix<5, int> expected( - -24, -35, -32, -25, 1, - -22, -36, -24, 33, -8, - 8, 16, -22, 29, 2, - -1, 0, 1, -12, 16, - -12, 8, -20, -26, -2 - ); - - CORRADE_COMPARE((left *= right), expected); -} - -void MatrixTest::multiplyVector() { - Matrix<5, int> matrix( - -3, -3, -1, 3, -5, - -1, -3, -5, 2, 3, - -1, -4, 3, -1, -2, - -5, -5, -1, -4, -1, - 1, 3, -3, -4, -1 - ); - - CORRADE_COMPARE((matrix*Vector<5, int>(0, 5, 3, 4, 4)), (Vector<5, int>(-24, -35, -32, -25, 1))); -} - -void MatrixTest::transposed() { - 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 transposed( - 0.0f, 4.0f, 8.0f, 12.0f, - 1.0f, 5.0f, 9.0f, 13.0f, - 2.0f, 6.0f, 10.0f, 14.0f, - 3.0f, 7.0f, 11.0f, 15.0f - ); - - CORRADE_COMPARE(original.transposed(), transposed); -} - void MatrixTest::ij() { Matrix4 original( 0.0f, 1.0f, 2.0f, 3.0f, diff --git a/src/Math/Test/MatrixTest.h b/src/Math/Test/MatrixTest.h index bb4eab650..57f9377a5 100644 --- a/src/Math/Test/MatrixTest.h +++ b/src/Math/Test/MatrixTest.h @@ -24,15 +24,8 @@ class MatrixTest: public Corrade::TestSuite::Tester { MatrixTest(); void construct(); - void constructFromVectors(); void constructIdentity(); void constructZero(); - void data(); - void copy(); - void multiplyIdentity(); - void multiply(); - void multiplyVector(); - void transposed(); void ij(); void determinant(); void inverted(); diff --git a/src/Math/Test/RectangularMatrixTest.cpp b/src/Math/Test/RectangularMatrixTest.cpp new file mode 100644 index 000000000..0bf10e591 --- /dev/null +++ b/src/Math/Test/RectangularMatrixTest.cpp @@ -0,0 +1,187 @@ +/* + Copyright © 2010, 2011, 2012 Vladimír Vondruš + + This file is part of Magnum. + + Magnum is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 3 + only, as published by the Free Software Foundation. + + Magnum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License version 3 for more details. +*/ + +#include "RectangularMatrixTest.h" + +#include + +#include "RectangularMatrix.h" + +CORRADE_TEST_MAIN(Magnum::Math::Test::RectangularMatrixTest) + +using namespace std; +using namespace Corrade::Utility; + +namespace Magnum { namespace Math { namespace Test { + +typedef RectangularMatrix<4, 3, float> Matrix4x3; +typedef RectangularMatrix<3, 4, float> Matrix3x4; +typedef Vector<4, float> Vector4; + +RectangularMatrixTest::RectangularMatrixTest() { + addTests(&RectangularMatrixTest::construct, + &RectangularMatrixTest::constructFromVectors, + &RectangularMatrixTest::constructZero, + &RectangularMatrixTest::data, + &RectangularMatrixTest::multiply, + &RectangularMatrixTest::transposed, + &RectangularMatrixTest::debug, + &RectangularMatrixTest::configuration); +} + +void RectangularMatrixTest::construct() { + float 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 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 + ); + + CORRADE_COMPARE(Matrix3x4::from(m), expected); +} + +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 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); + + CORRADE_COMPARE(actual, expected); +} + +void RectangularMatrixTest::constructZero() { + 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 + ); + + CORRADE_COMPARE(zero, zeroExpected); +} + +void RectangularMatrixTest::data() { + Matrix3x4 m; + + Vector4 vector(4.0f, 5.0f, 6.0f, 7.0f); + + m[2] = vector; + m[1][1] = 1.0f; + + m(0, 2) = 1.5f; + + 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 + ); + + CORRADE_COMPARE(m, expected); +} + +void RectangularMatrixTest::multiply() { + RectangularMatrix<4, 6, int> 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 + ); + + RectangularMatrix<5, 4, int> right( + 1, -7, 0, 158, + 2, 24, -3, 40, + 3, -15, -2, -50, + 4, 17, -1, -284, + 5, 30, 4, 18 + ); + + RectangularMatrix<5, 6, int> 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 + ); + + 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 + ); + + 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 + ); + + 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 + ); + + ostringstream o; + Debug(&o) << m; + CORRADE_COMPARE(o.str(), "Matrix(3, 4, 7,\n" + " 5, 4, -1,\n" + " 8, 7, 8,\n" + " 4, 3, 0)\n"); + + o.str(""); + Debug(&o) << "a" << Matrix3x4() << "b" << RectangularMatrix<4, 3, char>(); + CORRADE_COMPARE(o.str(), "a Matrix(0, 0, 0,\n" + " 0, 0, 0,\n" + " 0, 0, 0,\n" + " 0, 0, 0) b Matrix(0, 0, 0, 0,\n" + " 0, 0, 0, 0,\n" + " 0, 0, 0, 0)\n"); +} + +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 + ); + string value("3 4 7 5 4 -1 8 7 8 4 3.125 9.55"); + CORRADE_COMPARE(ConfigurationValue::toString(m), value); + CORRADE_COMPARE(ConfigurationValue::fromString(value), m); +} + +}}} diff --git a/src/Math/Test/RectangularMatrixTest.h b/src/Math/Test/RectangularMatrixTest.h new file mode 100644 index 000000000..058912598 --- /dev/null +++ b/src/Math/Test/RectangularMatrixTest.h @@ -0,0 +1,39 @@ +#ifndef Magnum_Math_Test_RectangularMatrixTest_h +#define Magnum_Math_Test_RectangularMatrixTest_h +/* + Copyright © 2010, 2011, 2012 Vladimír Vondruš + + This file is part of Magnum. + + Magnum is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 3 + only, as published by the Free Software Foundation. + + Magnum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License version 3 for more details. +*/ + +#include + +namespace Magnum { namespace Math { namespace Test { + +class RectangularMatrixTest: public Corrade::TestSuite::Tester { + public: + RectangularMatrixTest(); + + void construct(); + void constructFromVectors(); + void constructZero(); + void data(); + void multiply(); + void transposed(); + + void debug(); + void configuration(); +}; + +}}} + +#endif diff --git a/src/Math/Test/VectorTest.cpp b/src/Math/Test/VectorTest.cpp index cbafca1c9..a344d64b5 100644 --- a/src/Math/Test/VectorTest.cpp +++ b/src/Math/Test/VectorTest.cpp @@ -34,8 +34,6 @@ typedef Vector<3, float> Vector3; VectorTest::VectorTest() { addTests(&VectorTest::construct, &VectorTest::constructFrom, - &VectorTest::data, - &VectorTest::copy, &VectorTest::dot, &VectorTest::multiplyDivide, &VectorTest::multiplyDivideComponentWise, @@ -69,36 +67,6 @@ void VectorTest::constructFrom() { CORRADE_COMPARE(Vector4::from(integral), floatingPointRounded); } -void VectorTest::data() { - Vector4 v; - v[2] = 1.5f; - - v[0] = 1.0f; - - CORRADE_COMPARE(v, Vector4(1.0f, 0.0f, 1.5f, 0.0f)); -} - -void VectorTest::copy() { - Vector4 v1; - - v1[3] = 1.0f; - - Vector4 v2(v1); - Vector4 v3; - v3[0] = 0.0f; /* this line is here so it's not optimized to Vector4 v3(v1) */ - v3 = v1; - - /* Change original */ - v1[2] = 1.0f; - - /* Verify the copy is the same as original original */ - Vector4 original; - original[3] = 1.0f; - - CORRADE_COMPARE(v2, original); - CORRADE_COMPARE(v3, original); -} - void VectorTest::dot() { CORRADE_COMPARE(Vector4::dot({1.0f, 0.5f, 0.75f, 1.5f}, {2.0f, 4.0f, 1.0f, 7.0f}), 15.25f); } diff --git a/src/Math/Test/VectorTest.h b/src/Math/Test/VectorTest.h index cde0cafa9..17eaddc10 100644 --- a/src/Math/Test/VectorTest.h +++ b/src/Math/Test/VectorTest.h @@ -25,8 +25,6 @@ class VectorTest: public Corrade::TestSuite::Tester { void construct(); void constructFrom(); - void data(); - void copy(); void dot(); void multiplyDivide(); void multiplyDivideComponentWise(); diff --git a/src/Math/Vector.h b/src/Math/Vector.h index c6344ac0b..7fa0dde1d 100644 --- a/src/Math/Vector.h +++ b/src/Math/Vector.h @@ -19,12 +19,7 @@ * @brief Class Magnum::Math::Vector */ -#include -#include -#include -#include - -#include "MathTypeTraits.h" +#include "RectangularMatrix.h" namespace Magnum { namespace Math { @@ -32,16 +27,6 @@ template class Vector; #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 Vector::from(const Vector&) */ template inline constexpr Math::Vector vectorFrom(Sequence, const Math::Vector& vector) { return {T(vector[sequence])...}; @@ -55,28 +40,9 @@ namespace Implementation { @configurationvalueref{Magnum::Math::Vector} @todo Constexprize all for loops */ -template class Vector { - static_assert(size != 0, "Vector cannot have zero elements"); - +template class Vector: public RectangularMatrix<1, s, T> { public: - const static size_t Size = size; /**< @brief %Vector size */ - typedef T Type; /**< @brief %Vector data type */ - - /** - * @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); - } + const static size_t size = s; /**< @brief %Vector size */ /** * @brief %Vector from another of different type @@ -126,19 +92,15 @@ template class Vector { } /** @brief Default constructor */ - inline constexpr Vector(): _data() {} + inline constexpr Vector() {} /** * @brief Initializer-list constructor * @param first First value * @param next Next values - * - * @todoc Remove workaround when Doxygen supports uniform initialization */ #ifndef DOXYGEN_GENERATING_OUTPUT - template inline constexpr Vector(T first, U... next): _data{first, next...} { - static_assert(sizeof...(next)+1 == size, "Improper number of arguments passed to Vector constructor"); - } + template inline constexpr Vector(T first, U... next): RectangularMatrix<1, size, T>(first, next...) {} #else template inline constexpr Vector(T first, U... next); #endif @@ -153,38 +115,15 @@ template class Vector { inline explicit Vector(T value) { #endif for(size_t i = 0; i != size; ++i) - _data[i] = value; + (*this)[i] = value; } /** @brief Copy constructor */ - inline constexpr Vector(const Vector&) = default; - - /** @brief Assignment operator */ - inline Vector& operator=(const Vector&) = default; - - /** - * @brief Raw data - * @return Array with the same size as the vector - */ - inline T* data() { return _data; } - inline constexpr const T* data() const { return _data; } /**< @overload */ + inline constexpr Vector(const RectangularMatrix<1, size, T>& other): RectangularMatrix<1, size, T>(other) {} /** @brief Value at given position */ - inline T& operator[](size_t pos) { return _data[pos]; } - inline constexpr T operator[](size_t pos) const { return _data[pos]; } /**< @overload */ - - /** @brief Equality operator */ - inline bool operator==(const Vector& other) const { - for(size_t pos = 0; pos != size; ++pos) - if(!MathTypeTraits::equals((*this)[pos], other[pos])) return false; - - return true; - } - - /** @brief Non-equality operator */ - inline bool operator!=(const Vector& other) const { - return !operator==(other); - } + inline T& operator[](size_t pos) { return RectangularMatrix<1, size, T>::_data[pos]; } + inline constexpr T operator[](size_t pos) const { return RectangularMatrix<1, size, T>::_data[pos]; } /**< @overload */ /** * @brief Multiply vector @@ -404,8 +343,14 @@ template class Vector { return out; } + MAGNUM_RECTANGULARMATRIX_SUBCLASS_IMPLEMENTATION(1, size, Vector) + private: - T _data[size]; + /* 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(); }; /** @relates Vector diff --git a/src/Math/Vector2.h b/src/Math/Vector2.h index 68d19cb33..569439c88 100644 --- a/src/Math/Vector2.h +++ b/src/Math/Vector2.h @@ -71,8 +71,8 @@ template class Vector2: public Vector<2, T> { /** @copydoc Vector::Vector(T) */ inline constexpr explicit Vector2(T value = T()): Vector<2, T>(value, value) {} - /** @copydoc Vector::Vector(const Vector&) */ - inline constexpr Vector2(const Vector<2, T>& other): Vector<2, T>(other) {} + /** @brief Copy constructor */ + inline constexpr Vector2(const RectangularMatrix<1, 2, T>& other): Vector<2, T>(other) {} /** * @brief Constructor diff --git a/src/Math/Vector3.h b/src/Math/Vector3.h index 212e79ac4..826f28377 100644 --- a/src/Math/Vector3.h +++ b/src/Math/Vector3.h @@ -105,8 +105,8 @@ template class Vector3: public Vector<3, T> { /** @copydoc Vector::Vector(T) */ inline constexpr explicit Vector3(T value): Vector<3, T>(value, value, value) {} - /** @copydoc Vector::Vector(const Vector&) */ - inline constexpr Vector3(const Vector<3, T>& other): Vector<3, T>(other) {} + /** @brief Copy constructor */ + inline constexpr Vector3(const RectangularMatrix<1, 3, T>& other): Vector<3, T>(other) {} /** * @brief Constructor diff --git a/src/Math/Vector4.h b/src/Math/Vector4.h index 303361921..eaebeac96 100644 --- a/src/Math/Vector4.h +++ b/src/Math/Vector4.h @@ -40,8 +40,8 @@ template class Vector4: public Vector<4, T> { /** @copydoc Vector::Vector(T) */ inline constexpr explicit Vector4(T value): Vector<4, T>(value, value, value, value) {} - /** @copydoc Vector::Vector(const Vector&) */ - inline constexpr Vector4(const Vector<4, T>& other): Vector<4, T>(other) {} + /** @brief Copy constructor */ + inline constexpr Vector4(const RectangularMatrix<1, 4, T>& other): Vector<4, T>(other) {} /** * @brief Constructor diff --git a/src/MeshTools/Clean.h b/src/MeshTools/Clean.h index 7f5247d07..bca23aeb9 100644 --- a/src/MeshTools/Clean.h +++ b/src/MeshTools/Clean.h @@ -39,7 +39,7 @@ template class Clean { /* Get mesh bounds */ Vertex min, max; - for(size_t i = 0; i != Vertex::Size; ++i) { + for(size_t i = 0; i != Vertex::size; ++i) { min[i] = std::numeric_limits::max(); max[i] = std::numeric_limits::min(); } @@ -53,7 +53,7 @@ template class Clean { /* Make epsilon so large that size_t can index all vertices inside mesh bounds. */ Vertex size = max-min; - for(size_t i = 0; i != Vertex::Size; ++i) + for(size_t i = 0; i != Vertex::size; ++i) if(static_cast(size[i]/std::numeric_limits::max()) > epsilon) epsilon = static_cast(size[i]/std::numeric_limits::max()); @@ -91,7 +91,7 @@ template class Clean { std::swap(newVertices, vertices); /* Move vertex coordinates by epsilon/2 in next direction */ - if(moving != Vertex::Size) { + if(moving != Vertex::size) { moved = Vertex(); moved[moving] = epsilon/2; } @@ -136,7 +136,7 @@ Removes duplicate vertices from the mesh. @todo Interpolate vertices, not collapse them to first in the cell @todo Ability to specify other attributes for interpolation */ -template inline void clean(std::vector& indices, std::vector& vertices, typename Vertex::Type epsilon = TypeTraits::epsilon()) { +template inline void clean(std::vector& indices, std::vector& vertices, typename Vertex::Type epsilon = TypeTraits::epsilon()) { Implementation::Clean(indices, vertices)(epsilon); } diff --git a/src/MeshTools/Test/CleanTest.h b/src/MeshTools/Test/CleanTest.h index f24e4730e..5663733d6 100644 --- a/src/MeshTools/Test/CleanTest.h +++ b/src/MeshTools/Test/CleanTest.h @@ -28,7 +28,7 @@ class CleanTest: public Corrade::TestSuite::Tester { private: class Vector1 { public: - static const size_t Size = 1; + static const size_t size = 1; typedef int Type; Vector1(): data(0) {} diff --git a/src/MeshTools/Test/SubdivideTest.h b/src/MeshTools/Test/SubdivideTest.h index bc7569cb5..af7c43484 100644 --- a/src/MeshTools/Test/SubdivideTest.h +++ b/src/MeshTools/Test/SubdivideTest.h @@ -29,7 +29,7 @@ class SubdivideTest: public Corrade::TestSuite::Tester { private: class Vector1 { public: - static const size_t Size = 1; + static const size_t size = 1; typedef int Type; Vector1(): data(0) {} diff --git a/src/SceneGraph/Camera.cpp b/src/SceneGraph/Camera.cpp index f6896667b..aba491f2a 100644 --- a/src/SceneGraph/Camera.cpp +++ b/src/SceneGraph/Camera.cpp @@ -33,7 +33,7 @@ template MatrixType aspectRatioFix(AspectRatioPolicy aspectRat /* Extend on larger side = scale larger side down Clip on smaller side = scale smaller side up */ - return Camera::aspectRatioScale( + return Camera::aspectRatioScale( (relativeAspectRatio.x() > relativeAspectRatio.y()) == (aspectRatioPolicy == AspectRatioPolicy::Extend) ? Vector2(relativeAspectRatio.y()/relativeAspectRatio.x(), 1.0f) : Vector2(1.0f, relativeAspectRatio.x()/relativeAspectRatio.y())); diff --git a/src/Swizzle.h b/src/Swizzle.h index 22239225b..8f30f96a5 100644 --- a/src/Swizzle.h +++ b/src/Swizzle.h @@ -100,7 +100,7 @@ instead of at runtime. @see Vector4::xyz(), Vector4::rgb(), Vector4::xy(), Vector3::xy() */ template inline constexpr typename Implementation::TypeForSize::Type swizzle(const T& vector) { - return {vector[Implementation::GetComponent::value()]...}; + return {vector[Implementation::GetComponent::value()]...}; } /**