From 9461f780c433f38564cb434ece8b455f9e6a6e92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Tue, 21 Aug 2012 18:15:40 +0200 Subject: [PATCH 01/14] Ability to set buffer (sub)data from fixed-size array. Currently you had to do this, even if sizeof(data) was known at compile time: GLfloat data[] = { 2.0f, -1.5f, 3.0f, 7.0f }; buffer.setData(sizeof(data), data, usage); Now it's enough to do this: buffer.setData(data, usage); --- src/Buffer.h | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/src/Buffer.h b/src/Buffer.h index c76260f3e..54af31cf4 100644 --- a/src/Buffer.h +++ b/src/Buffer.h @@ -237,6 +237,19 @@ class Buffer { setData(_defaultTarget, size, data, usage); } + /** + * @brief Set buffer data + * @param data Fixed-size array with data + * @param usage %Buffer usage + * + * Sets buffer data with default target. More convenient for setting + * data from fixed-size arrays than + * setData(GLsizeiptr, const GLvoid*, Usage). + */ + template inline void setData(const T(&data)[size], Usage usage) { + setData(_defaultTarget, data, usage); + } + /** * @brief Set buffer data * @param data Vector with data @@ -260,6 +273,19 @@ class Buffer { glBufferData(static_cast(target), size, data, static_cast(usage)); } + /** + * @brief Set buffer data + * @param target %Target + * @param data Fixed-size array with data + * @param usage %Buffer usage + * + * More convenient for setting data from fixed-size arrays than + * setData(Target, GLsizeiptr, const GLvoid*, Usage). + */ + template inline void setData(Target target, const T(&data)[size], Usage usage) { + setData(target, size*sizeof(T), data, usage); + } + /** * @brief Set buffer data * @param target %Target @@ -282,6 +308,19 @@ class Buffer { setSubData(_defaultTarget, offset, size, data); } + /** + * @brief Set buffer subdata + * @param offset Offset + * @param data Fixed-size array with data + * + * Sets buffer subdata with default target. More convenient for + * setting data from fixed-size arrays than + * setSubData(GLintptr, GLsizeiptr, const GLvoid*). + */ + template inline void setSubData(GLintptr offset, const T(&data)[size]) { + setSubData(_defaultTarget, offset, data); + } + /** * @brief Set buffer subdata * @param offset Offset @@ -305,6 +344,19 @@ class Buffer { glBufferSubData(static_cast(target), offset, size, data); } + /** + * @brief Set buffer subdata + * @param target %Target + * @param offset Offset + * @param data Fixed-size array with data + * + * More convenient for setting data from fixed-size arrays than + * setSubData(Target, GLintptr, GLsizeiptr, const GLvoid*). + */ + template inline void setSubData(Target target, GLintptr offset, const T(&data)[size]) { + setSubData(target, offset, size*sizeof(T), data); + } + /** * @brief Set buffer subdata * @param target %Target From 070c4c1901e5453b4bed0e066c7c99afef84c025 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Wed, 22 Aug 2012 11:08:37 +0200 Subject: [PATCH 02/14] Removed unneeded friend declaration. --- src/Math/Matrix.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Math/Matrix.h b/src/Math/Matrix.h index 263185396..1e7f0a4c6 100644 --- a/src/Math/Matrix.h +++ b/src/Math/Matrix.h @@ -39,8 +39,6 @@ namespace Implementation { template class Matrix { static_assert(size != 0, "Matrix cannot have zero elements"); - friend class Matrix; /* for ij() */ - public: const static size_t Size = size; /**< @brief %Matrix size */ typedef T Type; /**< @brief %Matrix data type */ From 90881e733746076c2d1b27f9760dbd1f98d66fb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Wed, 22 Aug 2012 11:56:11 +0200 Subject: [PATCH 03/14] New base for matrices and vectors: RectangularMatrix. Currently moved only non-square functionality from Matrix there. Also static constant members such as row/column count and size are now lowercase, as they are variables, not types. --- src/Color.h | 8 +- src/Math/CMakeLists.txt | 1 + src/Math/Matrix.h | 218 +++--------------- src/Math/Matrix3.h | 4 +- src/Math/Matrix4.h | 4 +- src/Math/RectangularMatrix.h | 284 ++++++++++++++++++++++++ src/Math/Test/CMakeLists.txt | 2 + src/Math/Test/MatrixTest.cpp | 137 ------------ src/Math/Test/MatrixTest.h | 7 - src/Math/Test/RectangularMatrixTest.cpp | 187 ++++++++++++++++ src/Math/Test/RectangularMatrixTest.h | 39 ++++ src/Math/Test/VectorTest.cpp | 32 --- src/Math/Test/VectorTest.h | 2 - src/Math/Vector.h | 87 ++------ src/Math/Vector2.h | 4 +- src/Math/Vector3.h | 4 +- src/Math/Vector4.h | 4 +- src/MeshTools/Clean.h | 8 +- src/MeshTools/Test/CleanTest.h | 2 +- src/MeshTools/Test/SubdivideTest.h | 2 +- src/SceneGraph/Camera.cpp | 2 +- src/Swizzle.h | 2 +- 22 files changed, 580 insertions(+), 460 deletions(-) create mode 100644 src/Math/RectangularMatrix.h create mode 100644 src/Math/Test/RectangularMatrixTest.cpp create mode 100644 src/Math/Test/RectangularMatrixTest.h 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()]...}; } /** From 4bcc805616cd27e98749d8b79bb0830c4fa653e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Wed, 22 Aug 2012 12:33:56 +0200 Subject: [PATCH 04/14] Moved add/subtract operators from Vector to RectangularMatrix. --- src/Math/Matrix.h | 1 + src/Math/Matrix3.h | 1 + src/Math/Matrix4.h | 1 + src/Math/RectangularMatrix.h | 60 +++++++++++++++++++++++++ src/Math/Test/RectangularMatrixTest.cpp | 22 +++++++++ src/Math/Test/RectangularMatrixTest.h | 3 ++ src/Math/Test/VectorTest.cpp | 10 ----- src/Math/Test/VectorTest.h | 1 - src/Math/Vector.h | 52 +-------------------- src/Math/Vector2.h | 1 + src/Math/Vector3.h | 1 + src/Math/Vector4.h | 1 + 12 files changed, 92 insertions(+), 62 deletions(-) diff --git a/src/Math/Matrix.h b/src/Math/Matrix.h index d16e88823..e551f868c 100644 --- a/src/Math/Matrix.h +++ b/src/Math/Matrix.h @@ -142,6 +142,7 @@ template class Matrix: public RectangularMatrix { } #endif MAGNUM_RECTANGULARMATRIX_SUBCLASS_IMPLEMENTATION(size, size, Matrix) + MAGNUM_RECTANGULARMATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(size, size, Matrix) }; /** @debugoperator{Magnum::Math::Matrix} */ diff --git a/src/Math/Matrix3.h b/src/Math/Matrix3.h index bb6ad65c6..e537de58a 100644 --- a/src/Math/Matrix3.h +++ b/src/Math/Matrix3.h @@ -96,6 +96,7 @@ template class Matrix3: public Matrix<3, T> { inline constexpr Matrix3(const RectangularMatrix<3, 3, T>& other): Matrix<3, T>(other) {} MAGNUM_MATRIX_SUBCLASS_IMPLEMENTATION(Matrix3, Vector3, 3) + MAGNUM_RECTANGULARMATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(3, 3, Matrix3) }; /** @debugoperator{Magnum::Math::Matrix3} */ diff --git a/src/Math/Matrix4.h b/src/Math/Matrix4.h index 633376250..e0cfceb07 100644 --- a/src/Math/Matrix4.h +++ b/src/Math/Matrix4.h @@ -145,6 +145,7 @@ template class Matrix4: public Matrix<4, T> { } MAGNUM_MATRIX_SUBCLASS_IMPLEMENTATION(Matrix4, Vector4, 4) + MAGNUM_RECTANGULARMATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(4, 4, Matrix4) }; /** @debugoperator{Magnum::Math::Matrix4} */ diff --git a/src/Math/RectangularMatrix.h b/src/Math/RectangularMatrix.h index a5537d131..2ae79fea2 100644 --- a/src/Math/RectangularMatrix.h +++ b/src/Math/RectangularMatrix.h @@ -161,6 +161,50 @@ template class RectangularMatrix { return !operator==(other); } + /** + * @brief Add matrix + * + * @see operator+=() + */ + inline RectangularMatrix operator+(const RectangularMatrix& other) const { + return RectangularMatrix(*this)+=other; + } + + /** + * @brief Add and assign matrix + * + * More efficient than operator+(), because it does the computation + * in-place. + */ + RectangularMatrix& operator+=(const RectangularMatrix& other) { + for(size_t i = 0; i != cols*rows; ++i) + _data[i] += other._data[i]; + + return *this; + } + + /** + * @brief Subtract matrix + * + * @see operator-=() + */ + inline RectangularMatrix operator-(const RectangularMatrix& other) const { + return RectangularMatrix(*this)-=other; + } + + /** + * @brief Subtract and assign matrix + * + * More efficient than operator-(), because it does the computation + * in-place. + */ + RectangularMatrix& operator-=(const RectangularMatrix& other) { + for(size_t i = 0; i != cols*rows; ++i) + _data[i] -= other._data[i]; + + return *this; + } + /** @brief Multiply matrix */ template RectangularMatrix operator*(const RectangularMatrix& other) const { RectangularMatrix out; @@ -237,6 +281,22 @@ template Corrade::Utility::Debug operator<<(C RectangularMatrix::operator=(other); \ return *this; \ } + +#define MAGNUM_RECTANGULARMATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(cols, rows, ...) \ + inline __VA_ARGS__ operator+(const RectangularMatrix& other) const { \ + return RectangularMatrix::operator+(other); \ + } \ + inline __VA_ARGS__& operator+=(const RectangularMatrix& other) { \ + RectangularMatrix::operator+=(other); \ + return *this; \ + } \ + inline __VA_ARGS__ operator-(const RectangularMatrix& other) const { \ + return RectangularMatrix::operator-(other); \ + } \ + inline __VA_ARGS__& operator-=(const RectangularMatrix& other) { \ + RectangularMatrix::operator-=(other); \ + return *this; \ + } #endif }} diff --git a/src/Math/Test/RectangularMatrixTest.cpp b/src/Math/Test/RectangularMatrixTest.cpp index 0bf10e591..925ed8bd2 100644 --- a/src/Math/Test/RectangularMatrixTest.cpp +++ b/src/Math/Test/RectangularMatrixTest.cpp @@ -35,8 +35,12 @@ RectangularMatrixTest::RectangularMatrixTest() { &RectangularMatrixTest::constructFromVectors, &RectangularMatrixTest::constructZero, &RectangularMatrixTest::data, + + &RectangularMatrixTest::addSubtract, &RectangularMatrixTest::multiply, + &RectangularMatrixTest::transposed, + &RectangularMatrixTest::debug, &RectangularMatrixTest::configuration); } @@ -105,6 +109,24 @@ void RectangularMatrixTest::data() { CORRADE_COMPARE(m, expected); } +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 e(-4.0f, 1.5f, 12.0f, + -5.0f, 16.0f, 7.25f, + 8.0f, 1.0f, 30.0f, + 9.0f, 8.0f, 17.0f); + + CORRADE_COMPARE(a + b, e); + CORRADE_COMPARE(e - b, a); +} + void RectangularMatrixTest::multiply() { RectangularMatrix<4, 6, int> left( -5, 27, 10, 33, 0, -15, diff --git a/src/Math/Test/RectangularMatrixTest.h b/src/Math/Test/RectangularMatrixTest.h index 058912598..f2fcfed0f 100644 --- a/src/Math/Test/RectangularMatrixTest.h +++ b/src/Math/Test/RectangularMatrixTest.h @@ -27,7 +27,10 @@ class RectangularMatrixTest: public Corrade::TestSuite::Tester { void dot(); void multiplyDivide(); void multiplyDivideComponentWise(); - void addSubtract(); void dotSelf(); void length(); void normalized(); diff --git a/src/Math/Vector.h b/src/Math/Vector.h index 7fa0dde1d..4b4bbfd2a 100644 --- a/src/Math/Vector.h +++ b/src/Math/Vector.h @@ -229,42 +229,6 @@ template class Vector: public RectangularMatrix<1, s, T> { return *this; } - /** @brief Add two vectors */ - inline Vector operator+(const Vector& other) const { - return Vector(*this)+=other; - } - - /** - * @brief Add and assign vector - * - * More efficient than operator+(), because it does the computation - * in-place. - */ - Vector& operator+=(const Vector& other) { - for(size_t i = 0; i != size; ++i) - (*this)[i] += other[i]; - - return *this; - } - - /** @brief Subtract two vectors */ - inline Vector operator-(const Vector& other) const { - return Vector(*this)-=other; - } - - /** - * @brief Subtract and assign vector - * - * More efficient than operator-(), because it does the computation - * in-place. - */ - Vector& operator-=(const Vector& other) { - for(size_t i = 0; i != size; ++i) - (*this)[i] -= other[i]; - - return *this; - } - /** @brief Negative vector */ Vector operator-() const { Vector out; @@ -344,6 +308,7 @@ template class Vector: public RectangularMatrix<1, s, T> { } MAGNUM_RECTANGULARMATRIX_SUBCLASS_IMPLEMENTATION(1, size, Vector) + MAGNUM_RECTANGULARMATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(1, size, Vector) private: /* Hiding unused things from RectangularMatrix */ @@ -448,21 +413,6 @@ template Corrade::Utility::Debug operator<<(Corrade::Utili return *this; \ } \ \ - inline Type operator+(const Vector& other) const { \ - return Vector::operator+(other); \ - } \ - inline Type& operator+=(const Vector& other) { \ - Vector::operator+=(other); \ - return *this; \ - } \ - inline Type operator-(const Vector& other) const { \ - return Vector::operator-(other); \ - } \ - inline Type& operator-=(const Vector& other) { \ - Vector::operator-=(other); \ - return *this; \ - } \ - \ inline Type operator-() const { return Vector::operator-(); } \ inline Type normalized() const { return Vector::normalized(); } diff --git a/src/Math/Vector2.h b/src/Math/Vector2.h index 569439c88..d67e8b0c7 100644 --- a/src/Math/Vector2.h +++ b/src/Math/Vector2.h @@ -88,6 +88,7 @@ template class Vector2: public Vector<2, T> { inline void setY(T value) { (*this)[1] = value; } /**< @brief Set Y component */ 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 826f28377..623bb2c33 100644 --- a/src/Math/Vector3.h +++ b/src/Math/Vector3.h @@ -140,6 +140,7 @@ template class Vector3: public Vector<3, T> { inline constexpr Vector2 xy() const { return Vector2::from(Vector<3, T>::data()); } 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 eaebeac96..5adfe60ee 100644 --- a/src/Math/Vector4.h +++ b/src/Math/Vector4.h @@ -88,6 +88,7 @@ template class Vector4: public Vector<4, T> { inline constexpr Vector2 xy() const { return Vector2::from(Vector<4, T>::data()); } MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(Vector4, 4) + MAGNUM_RECTANGULARMATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(1, 3, Vector4) }; MAGNUM_VECTOR_SUBCLASS_OPERATOR_IMPLEMENTATION(Vector4, 4) From 8911dbdffe205de25387fce655e1d430cf1deb2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Wed, 22 Aug 2012 13:49:55 +0200 Subject: [PATCH 05/14] Moved multiplication and division from Vector to RectangularMatrix. --- src/Math/Matrix.h | 17 ++++ src/Math/RectangularMatrix.h | 110 ++++++++++++++++++++++++ src/Math/Test/RectangularMatrixTest.cpp | 23 +++++ src/Math/Test/RectangularMatrixTest.h | 1 + src/Math/Test/VectorTest.cpp | 22 ----- src/Math/Test/VectorTest.h | 1 - src/Math/Vector.h | 109 +---------------------- 7 files changed, 155 insertions(+), 128 deletions(-) diff --git a/src/Math/Matrix.h b/src/Math/Matrix.h index e551f868c..16beaf05c 100644 --- a/src/Math/Matrix.h +++ b/src/Math/Matrix.h @@ -145,6 +145,15 @@ template class Matrix: public RectangularMatrix { MAGNUM_RECTANGULARMATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(size, size, Matrix) }; +#ifndef DOXYGEN_GENERATING_OUTPUT +template inline Matrix operator*(U number, const Matrix& matrix) { + return number*RectangularMatrix(matrix); +} +template inline Matrix operator/(U number, const Matrix& matrix) { + return number/RectangularMatrix(matrix); +} +#endif + /** @debugoperator{Magnum::Math::Matrix} */ template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Magnum::Math::Matrix& value) { return debug << static_cast&>(value); @@ -191,6 +200,14 @@ template Corrade::Utility::Debug operator<<(Corrade::Utili inline Type transposed() const { return Matrix::transposed(); } \ inline Type inverted() const { return Matrix::inverted(); } +#define MAGNUM_MATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(Type, size) \ + template inline Type operator*(U number, const Type& matrix) { \ + return number*Matrix(matrix); \ + } \ + template inline Type operator/(U number, const Type& matrix) { \ + return number/Matrix(matrix); \ + } + namespace Implementation { template class MatrixDeterminant { diff --git a/src/Math/RectangularMatrix.h b/src/Math/RectangularMatrix.h index 2ae79fea2..7d4d2c508 100644 --- a/src/Math/RectangularMatrix.h +++ b/src/Math/RectangularMatrix.h @@ -205,6 +205,66 @@ template class RectangularMatrix { return *this; } + /** + * @brief Multiply matrix with number + * + * @see operator*=(U), operator*(U, const RectangularMatrix&) + */ + #ifndef DOXYGEN_GENERATING_OUTPUT + template inline typename std::enable_if::value, RectangularMatrix>::type operator*(U number) const { + #else + template inline RectangularMatrix operator*(U number) const { + #endif + return RectangularMatrix(*this)*=number; + } + + /** + * @brief Multiply matrix with number and assign + * + * More efficient than operator*(U), because it does the computation + * in-place. + */ + #ifndef DOXYGEN_GENERATING_OUTPUT + template inline typename std::enable_if::value, RectangularMatrix&>::type operator*=(U number) { + #else + template RectangularMatrix& operator*=(U number) { + #endif + for(size_t i = 0; i != cols*rows; ++i) + _data[i] *= number; + + return *this; + } + + /** + * @brief Divide matrix with number + * + * @see operator/=(), operator/(U, const RectangularMatrix&) + */ + #ifndef DOXYGEN_GENERATING_OUTPUT + template inline typename std::enable_if::value, RectangularMatrix>::type operator/(U number) const { + #else + template inline RectangularMatrix operator/(U number) const { + #endif + return RectangularMatrix(*this)/=number; + } + + /** + * @brief Divide matrix with number and assign + * + * More efficient than operator/(), because it does the computation + * in-place. + */ + #ifndef DOXYGEN_GENERATING_OUTPUT + template inline typename std::enable_if::value, RectangularMatrix&>::type operator/=(U number) { + #else + template RectangularMatrix& operator/=(U number) { + #endif + for(size_t i = 0; i != cols*rows; ++i) + _data[i] /= number; + + return *this; + } + /** @brief Multiply matrix */ template RectangularMatrix operator*(const RectangularMatrix& other) const { RectangularMatrix out; @@ -249,6 +309,42 @@ template class RectangularMatrix { T _data[rows*cols]; }; +/** @relates RectangularMatrix +@brief Multiply number with matrix + +@see RectangularMatrix::operator*(U) const +*/ +#ifndef DOXYGEN_GENERATING_OUTPUT +template inline typename std::enable_if::value, RectangularMatrix>::type operator*(U number, const RectangularMatrix& matrix) { +#else +template inline RectangularMatrix operator*(U number, const RectangularMatrix& matrix) { +#endif + return matrix*number; +} + +/** @relates RectangularMatrix +@brief Divide matrix with number and invert + +Example: +@code +RectangularMatrix<2, 3, float> mat(1.0f, 2.0f, -4.0f, 8.0f, -1.0f, 0.5f); +RectangularMatrix<2, 3, float> another = 1.0f/mat; // {1.0f, 0.5f, -0.25f, 0.128f, -1.0f, 2.0f} +@endcode +@see RectangularMatrix::operator/() +*/ +#ifndef DOXYGEN_GENERATING_OUTPUT +template typename std::enable_if::value, RectangularMatrix>::type operator/(U number, const RectangularMatrix& matrix) { +#else +template RectangularMatrix operator/(U number, const RectangularMatrix& matrix) { +#endif + RectangularMatrix out; + + for(size_t i = 0; i != cols*rows; ++i) + out.data()[i] = number/matrix.data()[i]; + + return out; +} + /** @debugoperator{Magnum::Math::RectangularMatrix} */ template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Magnum::Math::RectangularMatrix& value) { debug << "Matrix("; @@ -296,6 +392,20 @@ template Corrade::Utility::Debug operator<<(C inline __VA_ARGS__& operator-=(const RectangularMatrix& other) { \ RectangularMatrix::operator-=(other); \ return *this; \ + } \ + template inline typename std::enable_if::value, __VA_ARGS__>::type operator*(U number) const { \ + return RectangularMatrix::operator*(number); \ + } \ + template inline typename std::enable_if::value, __VA_ARGS__&>::type operator*=(U number) { \ + RectangularMatrix::operator*=(number); \ + return *this; \ + } \ + template inline typename std::enable_if::value, __VA_ARGS__>::type operator/(U number) const { \ + return RectangularMatrix::operator/(number); \ + } \ + template inline typename std::enable_if::value, __VA_ARGS__&>::type operator/=(U number) { \ + RectangularMatrix::operator/=(number); \ + return *this; \ } #endif diff --git a/src/Math/Test/RectangularMatrixTest.cpp b/src/Math/Test/RectangularMatrixTest.cpp index 925ed8bd2..51cfed605 100644 --- a/src/Math/Test/RectangularMatrixTest.cpp +++ b/src/Math/Test/RectangularMatrixTest.cpp @@ -28,6 +28,7 @@ namespace Magnum { namespace Math { namespace Test { typedef RectangularMatrix<4, 3, float> Matrix4x3; typedef RectangularMatrix<3, 4, float> Matrix3x4; +typedef RectangularMatrix<2, 2, float> Matrix2; typedef Vector<4, float> Vector4; RectangularMatrixTest::RectangularMatrixTest() { @@ -37,6 +38,7 @@ RectangularMatrixTest::RectangularMatrixTest() { &RectangularMatrixTest::data, &RectangularMatrixTest::addSubtract, + &RectangularMatrixTest::multiplyDivide, &RectangularMatrixTest::multiply, &RectangularMatrixTest::transposed, @@ -127,6 +129,27 @@ void RectangularMatrixTest::addSubtract() { CORRADE_COMPARE(e - b, a); } +void RectangularMatrixTest::multiplyDivide() { + Matrix2 vec(1.0f, 2.0f, 3.0f, 4.0f); + Matrix2 multiplied(-1.5f, -3.0f, -4.5f, -6.0f); + + CORRADE_COMPARE(vec*-1.5f, multiplied); + CORRADE_COMPARE(-1.5f*vec, multiplied); + CORRADE_COMPARE(multiplied/-1.5f, vec); + + Math::RectangularMatrix<1, 1, char> vecChar(32); + Math::RectangularMatrix<1, 1, char> multipliedChar(-48); + CORRADE_COMPARE(vecChar*-1.5f, multipliedChar); + CORRADE_COMPARE(multipliedChar/-1.5f, vecChar); + CORRADE_COMPARE(-1.5f*vecChar, 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); + CORRADE_COMPARE(1.0f/divisor, result); + CORRADE_COMPARE(-1550.0f/multipliedChar, vecChar); +} + void RectangularMatrixTest::multiply() { RectangularMatrix<4, 6, int> left( -5, 27, 10, 33, 0, -15, diff --git a/src/Math/Test/RectangularMatrixTest.h b/src/Math/Test/RectangularMatrixTest.h index f2fcfed0f..211d767bd 100644 --- a/src/Math/Test/RectangularMatrixTest.h +++ b/src/Math/Test/RectangularMatrixTest.h @@ -29,6 +29,7 @@ class RectangularMatrixTest: public Corrade::TestSuite::Tester vecChar(32); - Math::Vector<1, char> multipliedChar(-48); - CORRADE_COMPARE(vecChar*-1.5f, multipliedChar); - CORRADE_COMPARE(multipliedChar/-1.5f, vecChar); - CORRADE_COMPARE(-1.5f*vecChar, multipliedChar); - - /* Divide vector with number and inverse */ - Vector4 divisor(1.0f, 2.0f, -4.0f, 8.0f); - Vector4 result(1.0f, 0.5f, -0.25f, 0.125f); - CORRADE_COMPARE(1.0f/divisor, result); - CORRADE_COMPARE(-1550.0f/multipliedChar, vecChar); -} - void VectorTest::multiplyDivideComponentWise() { Vector4 vec(1.0f, 2.0f, 3.0f, 4.0f); Vector4 multiplier(7.0f, -4.0f, -1.5f, 1.0f); diff --git a/src/Math/Test/VectorTest.h b/src/Math/Test/VectorTest.h index 4504db2da..70fe2f878 100644 --- a/src/Math/Test/VectorTest.h +++ b/src/Math/Test/VectorTest.h @@ -26,7 +26,6 @@ class VectorTest: public Corrade::TestSuite::Tester { void construct(); void constructFrom(); void dot(); - void multiplyDivide(); void multiplyDivideComponentWise(); void dotSelf(); void length(); diff --git a/src/Math/Vector.h b/src/Math/Vector.h index 4b4bbfd2a..8ed2949c1 100644 --- a/src/Math/Vector.h +++ b/src/Math/Vector.h @@ -125,36 +125,6 @@ template class Vector: public RectangularMatrix<1, s, T> { 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 - * - * @see operator*=(U), operator*(U, const Vector&) - */ - #ifndef DOXYGEN_GENERATING_OUTPUT - template inline typename std::enable_if::value, Vector>::type operator*(U number) const { - #else - template inline Vector operator*(U number) const { - #endif - return Vector(*this)*=number; - } - - /** - * @brief Multiply vector and assign - * - * More efficient than operator*(U) const, because it does the - * computation in-place. - */ - #ifndef DOXYGEN_GENERATING_OUTPUT - template typename std::enable_if::value, Vector&>::type operator*=(U number) { - #else - template Vector& operator*=(U number) { - #endif - for(size_t i = 0; i != size; ++i) - (*this)[i] *= number; - - return *this; - } - /** * @brief Multiply vector component-wise * @@ -177,36 +147,6 @@ template class Vector: public RectangularMatrix<1, s, T> { return *this; } - /** - * @brief Divide vector - * - * @see operator/=(U), operator/(U, const Vector&) - */ - #ifndef DOXYGEN_GENERATING_OUTPUT - template inline typename std::enable_if::value, Vector>::type operator/(U number) const { - #else - template inline Vector operator/(U number) const { - #endif - return Vector(*this)/=number; - } - - /** - * @brief Divide vector and assign - * - * More efficient than operator/(U) const, because it does the - * computation in-place. - */ - #ifndef DOXYGEN_GENERATING_OUTPUT - template typename std::enable_if::value, Vector&>::type operator/=(U number) { - #else - template Vector& operator/=(U number) { - #endif - for(size_t i = 0; i != size; ++i) - (*this)[i] /= number; - - return *this; - } - /** * @brief Divide vector component-wise * @@ -318,41 +258,14 @@ template class Vector: public RectangularMatrix<1, s, T> { using RectangularMatrix<1, size, T>::operator(); }; -/** @relates Vector -@brief Multiply number with vector - -@see Vector::operator*(U) const -*/ #ifndef DOXYGEN_GENERATING_OUTPUT -template inline typename std::enable_if::value, Vector>::type operator*(U number, const Vector& vector) { -#else template inline Vector operator*(U number, const Vector& vector) { -#endif - return vector*number; + return number*RectangularMatrix<1, size, T>(vector); } - -/** @relates Vector -@brief Divide vector with number and invert - -Example: -@code -Vector<4, float> vec(1.0f, 2.0f, -4.0f, 8.0f); -Vector<4, float> another = 1.0f/vec; // {1.0f, 0.5f, -0.25f, 0.128f} -@endcode -@see Vector::operator/(U) const -*/ -#ifndef DOXYGEN_GENERATING_OUTPUT -template typename std::enable_if::value, Vector>::type operator/(U number, const Vector& vector) { -#else -template Vector operator/(U number, const Vector& vector) { -#endif - Vector out; - - for(size_t i = 0; i != size; ++i) - out[i] = number/vector[i]; - - return out; +template inline Vector operator/(U number, const Vector& vector) { + return number/RectangularMatrix<1, size, T>(vector); } +#endif /** @debugoperator{Magnum::Math::Vector} */ template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Magnum::Math::Vector& value) { @@ -384,13 +297,6 @@ template Corrade::Utility::Debug operator<<(Corrade::Utili return *this; \ } \ \ - template inline Type operator*(U number) const { \ - return Vector::operator*(number); \ - } \ - template inline Type& operator*=(U number) { \ - Vector::operator*=(number); \ - return *this; \ - } \ inline Type operator*(const Vector& other) const { \ return Vector::operator*(other); \ } \ @@ -398,13 +304,6 @@ template Corrade::Utility::Debug operator<<(Corrade::Utili Vector::operator*=(other); \ return *this; \ } \ - template inline Type operator/(U number) const { \ - return Vector::operator/(number); \ - } \ - template inline Type& operator/=(U number) { \ - Vector::operator/=(number); \ - return *this; \ - } \ inline Type operator/(const Vector& other) const { \ return Vector::operator/(other); \ } \ From 357b744d598e173548557bf3e528eea4bc53b1e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Wed, 22 Aug 2012 13:56:48 +0200 Subject: [PATCH 06/14] Vector function and operator reimplementation also for Color. --- src/Color.h | 10 ++++++++++ src/Math/RectangularMatrix.h | 32 ++++++++++++++++---------------- src/Math/Vector.h | 30 +++++++++++++++--------------- 3 files changed, 41 insertions(+), 31 deletions(-) diff --git a/src/Color.h b/src/Color.h index 125c820d2..304c5408e 100644 --- a/src/Color.h +++ b/src/Color.h @@ -276,8 +276,13 @@ template class Color3: public Math::Vector3 { inline constexpr FloatingPointType value() const { return Implementation::value(*this); } + + MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(Color3, 3) + MAGNUM_RECTANGULARMATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(1, 3, Color3) }; +MAGNUM_VECTOR_SUBCLASS_OPERATOR_IMPLEMENTATION(Color3, 3) + /** @brief Four-component (RGBA) color @@ -394,8 +399,13 @@ template class Color4: public Math::Vector4 { inline constexpr FloatingPointType value() const { return Implementation::value(rgb()); } + + MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(Color4, 4) + MAGNUM_RECTANGULARMATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(1, 4, Color4) }; +MAGNUM_VECTOR_SUBCLASS_OPERATOR_IMPLEMENTATION(Color4, 4) + /** @debugoperator{Magnum::Color3} */ template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Magnum::Color3& value) { return debug << static_cast&>(value); diff --git a/src/Math/RectangularMatrix.h b/src/Math/RectangularMatrix.h index 7d4d2c508..86293fc86 100644 --- a/src/Math/RectangularMatrix.h +++ b/src/Math/RectangularMatrix.h @@ -369,42 +369,42 @@ template Corrade::Utility::Debug operator<<(C 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...); \ + template inline constexpr static __VA_ARGS__ from(const Math::Vector& first, const U&... next) { \ + return Math::RectangularMatrix::from(first, next...); \ } \ \ - inline __VA_ARGS__& operator=(const RectangularMatrix& other) { \ - RectangularMatrix::operator=(other); \ + 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 RectangularMatrix& other) const { \ - return RectangularMatrix::operator+(other); \ + inline __VA_ARGS__ operator+(const Math::RectangularMatrix& other) const { \ + return Math::RectangularMatrix::operator+(other); \ } \ - inline __VA_ARGS__& operator+=(const RectangularMatrix& other) { \ - RectangularMatrix::operator+=(other); \ + inline __VA_ARGS__& operator+=(const Math::RectangularMatrix& other) { \ + Math::RectangularMatrix::operator+=(other); \ return *this; \ } \ - inline __VA_ARGS__ operator-(const RectangularMatrix& other) const { \ - return RectangularMatrix::operator-(other); \ + inline __VA_ARGS__ operator-(const Math::RectangularMatrix& other) const { \ + return Math::RectangularMatrix::operator-(other); \ } \ - inline __VA_ARGS__& operator-=(const RectangularMatrix& other) { \ - 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 RectangularMatrix::operator*(number); \ + return Math::RectangularMatrix::operator*(number); \ } \ template inline typename std::enable_if::value, __VA_ARGS__&>::type operator*=(U number) { \ - RectangularMatrix::operator*=(number); \ + Math::RectangularMatrix::operator*=(number); \ return *this; \ } \ template inline typename std::enable_if::value, __VA_ARGS__>::type operator/(U number) const { \ - return RectangularMatrix::operator/(number); \ + return Math::RectangularMatrix::operator/(number); \ } \ template inline typename std::enable_if::value, __VA_ARGS__&>::type operator/=(U number) { \ - RectangularMatrix::operator/=(number); \ + Math::RectangularMatrix::operator/=(number); \ return *this; \ } #endif diff --git a/src/Math/Vector.h b/src/Math/Vector.h index 8ed2949c1..728ce8029 100644 --- a/src/Math/Vector.h +++ b/src/Math/Vector.h @@ -288,39 +288,39 @@ template Corrade::Utility::Debug operator<<(Corrade::Utili inline constexpr static const Type& from(const T* data) { \ return *reinterpret_cast*>(data); \ } \ - template inline constexpr static Type from(const Vector& other) { \ - return Vector::from(other); \ + template inline constexpr static Type from(const Math::Vector& other) { \ + return Math::Vector::from(other); \ } \ \ inline Type& operator=(const Type& other) { \ - Vector::operator=(other); \ + Math::Vector::operator=(other); \ return *this; \ } \ \ - inline Type operator*(const Vector& other) const { \ - return Vector::operator*(other); \ + inline Type operator*(const Math::Vector& other) const { \ + return Math::Vector::operator*(other); \ } \ - inline Type& operator*=(const Vector& other) { \ - Vector::operator*=(other); \ + inline Type& operator*=(const Math::Vector& other) { \ + Math::Vector::operator*=(other); \ return *this; \ } \ - inline Type operator/(const Vector& other) const { \ - return Vector::operator/(other); \ + inline Type operator/(const Math::Vector& other) const { \ + return Math::Vector::operator/(other); \ } \ - inline Type& operator/=(const Vector& other) { \ - Vector::operator/=(other); \ + inline Type& operator/=(const Math::Vector& other) { \ + Math::Vector::operator/=(other); \ return *this; \ } \ \ - inline Type operator-() const { return Vector::operator-(); } \ - inline Type normalized() const { return Vector::normalized(); } + inline Type operator-() const { return Math::Vector::operator-(); } \ + inline Type normalized() const { return Math::Vector::normalized(); } #define MAGNUM_VECTOR_SUBCLASS_OPERATOR_IMPLEMENTATION(Type, size) \ template inline Type operator*(U number, const Type& vector) { \ - return number*Vector(vector); \ + return number*Math::Vector(vector); \ } \ template inline Type operator/(U number, const Type& vector) { \ - return number/Vector(vector); \ + return number/Math::Vector(vector); \ } #endif From 630a4153243ffd95fb327ec752a72243e27f8052 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Sat, 25 Aug 2012 01:01:22 +0200 Subject: [PATCH 07/14] Non-constant access to image data. Sometimes something needs to modify the data (in similar way it modifies e.g. MeshData) and there is no reason to forbid that, as the data must be non-const for delete[] operator anyway. There might be slight problem with ImageWrapper, which should be able to wrap const data, but currently nothing needs it. --- src/Image.h | 3 ++- src/ImageWrapper.h | 3 ++- src/Trade/ImageData.h | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/Image.h b/src/Image.h index 64557ea23..fd83832a7 100644 --- a/src/Image.h +++ b/src/Image.h @@ -76,7 +76,8 @@ template class Image: public AbstractImage { inline constexpr const Math::Vector& dimensions() const { return _dimensions; } /** @brief Pointer to raw data */ - inline constexpr const void* data() const { return _data; } + inline void* data() { return _data; } + inline constexpr const void* data() const { return _data; } /**< @overload */ /** * @brief Set image data diff --git a/src/ImageWrapper.h b/src/ImageWrapper.h index b4dc0e4e6..3a4ca8ce3 100644 --- a/src/ImageWrapper.h +++ b/src/ImageWrapper.h @@ -81,7 +81,8 @@ template class ImageWrapper: public AbstractImage { inline constexpr const Math::Vector& dimensions() const { return _dimensions; } /** @brief Pointer to raw data */ - inline constexpr const void* data() const { return _data; } + inline void* data() { return _data; } + inline constexpr const void* data() const { return _data; } /**< @overload */ /** * @brief Set image data diff --git a/src/Trade/ImageData.h b/src/Trade/ImageData.h index 587fb0bc9..f054f6464 100644 --- a/src/Trade/ImageData.h +++ b/src/Trade/ImageData.h @@ -70,7 +70,8 @@ template class ImageData: public AbstractImage { inline constexpr const Math::Vector& dimensions() const { return _dimensions; } /** @brief Pointer to raw data */ - inline constexpr const void* data() const { return _data; } + inline void* data() { return _data; } + inline constexpr const void* data() const { return _data; } /**< @overload */ private: std::string _name; From 70402d687fd7bfb47178a28b2d7b8d3ac4947dd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Sat, 25 Aug 2012 01:05:03 +0200 Subject: [PATCH 08/14] Added missing #include. --- src/Math/MathTypeTraits.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Math/MathTypeTraits.h b/src/Math/MathTypeTraits.h index fb97bb8b6..efe47f3a6 100644 --- a/src/Math/MathTypeTraits.h +++ b/src/Math/MathTypeTraits.h @@ -19,6 +19,7 @@ * @brief Class Magnum::Math::MathTypeTraits */ +#include #include /** @brief Precision when testing floats for equality */ From fb61c22e073a16f8e90761087b1dff32051becdc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Sat, 25 Aug 2012 15:27:33 +0200 Subject: [PATCH 09/14] Fixed matrix multiplication in RectangularMatrix subclasses. Now all possible cases are properly handled (row vector * column vector, column vector * row vector, ...). All operators taking arbitrary type as argument (element-wise multiplication) now have std::enable_if only for numerical types. --- src/Math/Matrix.h | 12 ++++++------ src/Math/Vector.h | 17 +++++++++++++---- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/src/Math/Matrix.h b/src/Math/Matrix.h index 16beaf05c..c524c877b 100644 --- a/src/Math/Matrix.h +++ b/src/Math/Matrix.h @@ -140,16 +140,16 @@ template class Matrix: public RectangularMatrix { inline Vector operator*(const Vector& other) const { return RectangularMatrix::operator*(other); } - #endif MAGNUM_RECTANGULARMATRIX_SUBCLASS_IMPLEMENTATION(size, size, Matrix) MAGNUM_RECTANGULARMATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(size, size, Matrix) + #endif }; #ifndef DOXYGEN_GENERATING_OUTPUT -template inline Matrix operator*(U number, const Matrix& matrix) { +template inline typename std::enable_if::value, Matrix>::type operator*(U number, const Matrix& matrix) { return number*RectangularMatrix(matrix); } -template inline Matrix operator/(U number, const Matrix& matrix) { +template inline typename std::enable_if::value, Matrix>::type operator/(U number, const Matrix& matrix) { return number/RectangularMatrix(matrix); } #endif @@ -190,7 +190,7 @@ template Corrade::Utility::Debug operator<<(Corrade::Utili Matrix::operator*=(other); \ return *this; \ } \ - template inline RectangularMatrix operator*(const RectangularMatrix& other) const { \ + template inline RectangularMatrix operator*(const RectangularMatrix& other) const { \ return Matrix::operator*(other); \ } \ inline VectorType operator*(const Vector& other) const { \ @@ -201,10 +201,10 @@ template Corrade::Utility::Debug operator<<(Corrade::Utili inline Type inverted() const { return Matrix::inverted(); } #define MAGNUM_MATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(Type, size) \ - template inline Type operator*(U number, const Type& matrix) { \ + template inline typename std::enable_if::value, Type>::type operator*(U number, const Type& matrix) { \ return number*Matrix(matrix); \ } \ - template inline Type operator/(U number, const Type& matrix) { \ + template inline typename std::enable_if::value, Type>::type operator/(U number, const Type& matrix) { \ return number/Matrix(matrix); \ } diff --git a/src/Math/Vector.h b/src/Math/Vector.h index 728ce8029..6776fcbd0 100644 --- a/src/Math/Vector.h +++ b/src/Math/Vector.h @@ -247,8 +247,14 @@ template class Vector: public RectangularMatrix<1, s, T> { 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); + } MAGNUM_RECTANGULARMATRIX_SUBCLASS_IMPLEMENTATION(1, size, Vector) MAGNUM_RECTANGULARMATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(1, size, Vector) + #endif private: /* Hiding unused things from RectangularMatrix */ @@ -259,10 +265,10 @@ template class Vector: public RectangularMatrix<1, s, T> { }; #ifndef DOXYGEN_GENERATING_OUTPUT -template inline Vector operator*(U number, const Vector& vector) { +template inline typename std::enable_if::value, Vector>::type operator*(U number, const Vector& vector) { return number*RectangularMatrix<1, size, T>(vector); } -template inline Vector operator/(U number, const Vector& vector) { +template inline typename std::enable_if::value, Vector>::type operator/(U number, const Vector& vector) { return number/RectangularMatrix<1, size, T>(vector); } #endif @@ -297,6 +303,9 @@ template Corrade::Utility::Debug operator<<(Corrade::Utili return *this; \ } \ \ + template inline Math::RectangularMatrix operator*(const Math::RectangularMatrix& other) const { \ + return Math::Vector::operator*(other); \ + } \ inline Type operator*(const Math::Vector& other) const { \ return Math::Vector::operator*(other); \ } \ @@ -316,10 +325,10 @@ template Corrade::Utility::Debug operator<<(Corrade::Utili inline Type normalized() const { return Math::Vector::normalized(); } #define MAGNUM_VECTOR_SUBCLASS_OPERATOR_IMPLEMENTATION(Type, size) \ - template inline Type operator*(U number, const Type& vector) { \ + template inline typename std::enable_if::value, Type>::type operator*(U number, const Type& vector) { \ return number*Math::Vector(vector); \ } \ - template inline Type operator/(U number, const Type& vector) { \ + template inline typename std::enable_if::value, Type>::type operator/(U number, const Type& vector) { \ return number/Math::Vector(vector); \ } #endif From 3558859cc691e627c177ae8fba9b1708bfdf31b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Sun, 26 Aug 2012 03:19:08 +0200 Subject: [PATCH 10/14] Utility function for clamping value in given limits. --- src/Math/Math.h | 6 ++++++ src/Math/Test/MathTest.cpp | 7 +++++++ src/Math/Test/MathTest.h | 1 + 3 files changed, 14 insertions(+) diff --git a/src/Math/Math.h b/src/Math/Math.h index aa9d77723..8c37df308 100644 --- a/src/Math/Math.h +++ b/src/Math/Math.h @@ -19,6 +19,7 @@ #include #include #include +#include #include "magnumVisibility.h" @@ -129,6 +130,11 @@ template inline constexpr typename std::ena FloatingPoint(value*std::numeric_limits::min())); } +/** @brief Clamp value */ +template inline T clamp(T value, T min, T max) { + return std::min(std::max(value, min), max); +} + /** @brief Angle in degrees diff --git a/src/Math/Test/MathTest.cpp b/src/Math/Test/MathTest.cpp index 9d76e9535..cfdc49243 100644 --- a/src/Math/Test/MathTest.cpp +++ b/src/Math/Test/MathTest.cpp @@ -28,6 +28,7 @@ MathTest::MathTest() { &MathTest::degrad, &MathTest::normalize, &MathTest::denormalize, + &MathTest::clamp, &MathTest::pow, &MathTest::log); } @@ -96,6 +97,12 @@ void MathTest::denormalize() { } } +void MathTest::clamp() { + CORRADE_COMPARE(Math::clamp(0.5f, -1.0f, 5.0f), 0.5f); + CORRADE_COMPARE(Math::clamp(-1.6f, -1.0f, 5.0f), -1.0f); + CORRADE_COMPARE(Math::clamp(9.5f, -1.0f, 5.0f), 5.0f); +} + void MathTest::pow() { CORRADE_COMPARE(Math::pow<10>(2ul), 1024ul); CORRADE_COMPARE(Math::pow<0>(3ul), 1ul); diff --git a/src/Math/Test/MathTest.h b/src/Math/Test/MathTest.h index 3bb32c5ea..568c0b148 100644 --- a/src/Math/Test/MathTest.h +++ b/src/Math/Test/MathTest.h @@ -27,6 +27,7 @@ class MathTest: public Corrade::TestSuite::Tester { void degrad(); void normalize(); void denormalize(); + void clamp(); void pow(); void log(); }; From e21c9ca3a5f31edc5d9de766907ad6455c8080ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Sun, 26 Aug 2012 03:19:39 +0200 Subject: [PATCH 11/14] Function for computing trace of square matrix. --- src/Math/Matrix.h | 16 ++++++++++++++++ src/Math/Test/MatrixTest.cpp | 13 +++++++++++++ src/Math/Test/MatrixTest.h | 1 + 3 files changed, 30 insertions(+) diff --git a/src/Math/Matrix.h b/src/Math/Matrix.h index c524c877b..2273ce3b1 100644 --- a/src/Math/Matrix.h +++ b/src/Math/Matrix.h @@ -81,6 +81,22 @@ template class Matrix: public RectangularMatrix { return (*this = *this*other); } + /** + * @brief Trace of the matrix + * + * @f[ + * tr(A) = \sum_{i=1}^n a_{i,i} + * @f] + */ + T trace() const { + T out(0); + + for(size_t i = 0; i != size; ++i) + out += (*this)(i, i); + + return out; + } + /** @brief %Matrix without given column and row */ Matrix ij(size_t skipCol, size_t skipRow) const { Matrix out(Matrix::Zero); diff --git a/src/Math/Test/MatrixTest.cpp b/src/Math/Test/MatrixTest.cpp index 1cdd211f6..2d803ec16 100644 --- a/src/Math/Test/MatrixTest.cpp +++ b/src/Math/Test/MatrixTest.cpp @@ -34,6 +34,7 @@ MatrixTest::MatrixTest() { addTests(&MatrixTest::construct, &MatrixTest::constructIdentity, &MatrixTest::constructZero, + &MatrixTest::trace, &MatrixTest::ij, &MatrixTest::determinant, &MatrixTest::inverted, @@ -96,6 +97,18 @@ void MatrixTest::constructZero() { CORRADE_COMPARE(zero, zeroExpected); } +void MatrixTest::trace() { + Matrix<5, int> 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 + ); + + CORRADE_COMPARE(m.trace(), -8); +} + 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 57f9377a5..ba1cb02ee 100644 --- a/src/Math/Test/MatrixTest.h +++ b/src/Math/Test/MatrixTest.h @@ -26,6 +26,7 @@ class MatrixTest: public Corrade::TestSuite::Tester { void construct(); void constructIdentity(); void constructZero(); + void trace(); void ij(); void determinant(); void inverted(); From 166afd5248d3f2515387c18595799b6af16e4976 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Sun, 26 Aug 2012 03:20:06 +0200 Subject: [PATCH 12/14] Documented missing features in Mesh in OpenGL ES. --- src/Mesh.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Mesh.h b/src/Mesh.h index e75567d8b..e02b026c1 100644 --- a/src/Mesh.h +++ b/src/Mesh.h @@ -162,7 +162,8 @@ class MAGNUM_EXPORT Mesh { * @brief Set point size * * @see setProgramPointSize() - * @requires_gl + * @requires_gl Set directly in vertex shader using @c gl_PointSize + * builtin variable. */ inline static void setPointSize(GLfloat size) { glPointSize(size); @@ -174,7 +175,7 @@ class MAGNUM_EXPORT Mesh { * If enabled, the point size is taken from vertex/geometry shader * builtin `gl_PointSize`. * @see setPointSize() - * @requires_gl + * @requires_gl Always enabled. */ inline static void setProgramPointSize(bool enabled) { enabled ? glEnable(GL_PROGRAM_POINT_SIZE) : glDisable(GL_PROGRAM_POINT_SIZE); From 742a75277d9d98382b599ff711307435bae15158 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Sun, 26 Aug 2012 17:57:23 +0200 Subject: [PATCH 13/14] Moved unary operator- from Vector to RectangularMatrix. --- src/Math/RectangularMatrix.h | 13 +++++++++++++ src/Math/Test/RectangularMatrixTest.cpp | 5 +++++ src/Math/Test/RectangularMatrixTest.h | 1 + src/Math/Test/VectorTest.cpp | 5 ----- src/Math/Test/VectorTest.h | 1 - src/Math/Vector.h | 11 ----------- 6 files changed, 19 insertions(+), 17 deletions(-) diff --git a/src/Math/RectangularMatrix.h b/src/Math/RectangularMatrix.h index 86293fc86..6c52764a8 100644 --- a/src/Math/RectangularMatrix.h +++ b/src/Math/RectangularMatrix.h @@ -183,6 +183,16 @@ template class RectangularMatrix { return *this; } + /** @brief Negative matrix */ + RectangularMatrix operator-() const { + RectangularMatrix out; + + for(size_t i = 0; i != cols*rows; ++i) + out._data[i] = -_data[i]; + + return out; + } + /** * @brief Subtract matrix * @@ -379,6 +389,9 @@ template Corrade::Utility::Debug operator<<(C } #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); \ } \ diff --git a/src/Math/Test/RectangularMatrixTest.cpp b/src/Math/Test/RectangularMatrixTest.cpp index 51cfed605..da0762179 100644 --- a/src/Math/Test/RectangularMatrixTest.cpp +++ b/src/Math/Test/RectangularMatrixTest.cpp @@ -37,6 +37,7 @@ RectangularMatrixTest::RectangularMatrixTest() { &RectangularMatrixTest::constructZero, &RectangularMatrixTest::data, + &RectangularMatrixTest::negative, &RectangularMatrixTest::addSubtract, &RectangularMatrixTest::multiplyDivide, &RectangularMatrixTest::multiply, @@ -111,6 +112,10 @@ void RectangularMatrixTest::data() { CORRADE_COMPARE(m, expected); } +void RectangularMatrixTest::negative() { + CORRADE_COMPARE(-Matrix2(1.0f, -3.0f, 5.0f, -10.0f), Matrix2(-1.0f, 3.0f, -5.0f, 10.0f)); +} + void RectangularMatrixTest::addSubtract() { Matrix4x3 a(0.0f, 1.0f, 3.0f, 4.0f, 5.0f, 7.0f, diff --git a/src/Math/Test/RectangularMatrixTest.h b/src/Math/Test/RectangularMatrixTest.h index 211d767bd..0eae0204a 100644 --- a/src/Math/Test/RectangularMatrixTest.h +++ b/src/Math/Test/RectangularMatrixTest.h @@ -28,6 +28,7 @@ class RectangularMatrixTest: public Corrade::TestSuite::Tester { void min(); void max(); void angle(); - void negative(); void debug(); void configuration(); diff --git a/src/Math/Vector.h b/src/Math/Vector.h index 6776fcbd0..da1372ee2 100644 --- a/src/Math/Vector.h +++ b/src/Math/Vector.h @@ -169,16 +169,6 @@ template class Vector: public RectangularMatrix<1, s, T> { return *this; } - /** @brief Negative vector */ - Vector operator-() const { - Vector out; - - for(size_t i = 0; i != size; ++i) - out[i] = -(*this)[i]; - - return out; - } - /** * @brief Dot product of the vector * @@ -321,7 +311,6 @@ template Corrade::Utility::Debug operator<<(Corrade::Utili return *this; \ } \ \ - inline Type operator-() const { return Math::Vector::operator-(); } \ inline Type normalized() const { return Math::Vector::normalized(); } #define MAGNUM_VECTOR_SUBCLASS_OPERATOR_IMPLEMENTATION(Type, size) \ From 1727357cc5b6e3030ae46c916b657c94874e4f84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Sun, 26 Aug 2012 22:43:33 +0200 Subject: [PATCH 14/14] Gauss-Jordan elimination. --- doc/namespaces.dox | 9 ++ src/Math/Algorithms/CMakeLists.txt | 8 ++ src/Math/Algorithms/GaussJordan.h | 113 +++++++++++++++++++ src/Math/Algorithms/Test/CMakeLists.txt | 1 + src/Math/Algorithms/Test/GaussJordanTest.cpp | 60 ++++++++++ src/Math/Algorithms/Test/GaussJordanTest.h | 32 ++++++ src/Math/CMakeLists.txt | 1 + 7 files changed, 224 insertions(+) create mode 100644 src/Math/Algorithms/CMakeLists.txt create mode 100644 src/Math/Algorithms/GaussJordan.h create mode 100644 src/Math/Algorithms/Test/CMakeLists.txt create mode 100644 src/Math/Algorithms/Test/GaussJordanTest.cpp create mode 100644 src/Math/Algorithms/Test/GaussJordanTest.h diff --git a/doc/namespaces.dox b/doc/namespaces.dox index 63587bca1..faf2cb178 100644 --- a/doc/namespaces.dox +++ b/doc/namespaces.dox @@ -28,6 +28,15 @@ Base classes for creating OpenGL contexts with various toolkits. Template classes for matrix and vector calculations. */ +/** @dir Math/Algorithms + * @brief Namespace Magnum::Math::Algorithms + */ +/** @namespace Magnum::Math::Algorithms +@brief %Algorithms + +Various matrix and vector algorithms. +*/ + /** @dir Math/Geometry * @brief Namespace Magnum::Math::Geometry */ diff --git a/src/Math/Algorithms/CMakeLists.txt b/src/Math/Algorithms/CMakeLists.txt new file mode 100644 index 000000000..cb5121b20 --- /dev/null +++ b/src/Math/Algorithms/CMakeLists.txt @@ -0,0 +1,8 @@ +set(MagnumMathAlgorithms_HEADERS + GaussJordan.h) +install(FILES ${MagnumMathAlgorithms_HEADERS} DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Math/Algorithms) + +if(BUILD_TESTS) + enable_testing() + add_subdirectory(Test) +endif() diff --git a/src/Math/Algorithms/GaussJordan.h b/src/Math/Algorithms/GaussJordan.h new file mode 100644 index 000000000..d98bf89c8 --- /dev/null +++ b/src/Math/Algorithms/GaussJordan.h @@ -0,0 +1,113 @@ +#ifndef Magnum_Math_Algorithms_GaussJordan_h +#define Magnum_Math_Algorithms_GaussJordan_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 GaussJordan + */ + +#include "Math/RectangularMatrix.h" + +namespace Magnum { namespace Math { namespace Algorithms { + +/** +@brief Gauss-Jordan elimination + +Based on ultra-compact Python code by Jarno Elonen, +http://elonen.iki.fi/code/misc-notes/python-gaussj/index.html. +*/ +class GaussJordan { + public: + /** + * @brief Eliminate transposed matrices in place + * @param a Transposed left side of augmented matrix + * @param t Transposed right side of augmented matrix + * @return True if @p a is regular, false if @p a is singular (and + * thus the system cannot be solved). + * + * As Gauss-Jordan elimination works on rows and matrices in OpenGL + * are column-major, it is more efficient to operate on transposed + * matrices and treat columns as rows. See also inPlace() which works + * with non-transposed matrices. + * + * The function eliminates matrix @p a and solves @p t in place. For + * efficiency reasons, only pure Gaussian elimination is done on @p a + * and the final backsubstitution is done only on @p t, as @p a would + * always end with identity matrix anyway. + */ + template static bool inPlaceTransposed(RectangularMatrix& a, RectangularMatrix& t); + + /** + * @brief Eliminate in place + * + * Transposes the matrices, calls inPlaceTransposed() on them and then + * transposes them back. + */ + template static bool inPlace(RectangularMatrix& a, RectangularMatrix& t) { + a = a.transposed(); + RectangularMatrix tTransposed = t.transposed(); + + bool ret = inPlaceTransposed(a, tTransposed); + + a = a.transposed(); + t = tTransposed.transposed(); + + return ret; + } +}; + +template bool GaussJordan::inPlaceTransposed(RectangularMatrix& a, RectangularMatrix& t) { + for(size_t row = 0; row != size; ++row) { + /* Find max pivot */ + size_t rowMax = row; + for(size_t row2 = row+1; row2 != size; ++row2) + if(std::abs(a(row2, row)) > std::abs(a(rowMax, row))) + rowMax = row2; + + /* Swap the rows */ + std::swap(a[row], a[rowMax]); + std::swap(t[row], t[rowMax]); + + /* Singular */ + if(MathTypeTraits::equals(a(row, row), 0)) + return false; + + /* Eliminate column */ + for(size_t row2 = row+1; row2 != size; ++row2) { + T c = a(row2, row)/a(row, row); + + a[row2] -= a[row]*c; + t[row2] -= t[row]*c; + } + } + + /* Backsubstitute */ + for(size_t row = size; row != 0; --row) { + T c = T(1)/a(row-1, row-1); + + for(size_t row2 = 0; row2 != row-1; ++row2) + t[row2] -= t[row-1]*a(row2, row-1)*c; + + /* Normalize the row */ + t[row-1] *= c; + } + + return true; +} + +}}} + +#endif diff --git a/src/Math/Algorithms/Test/CMakeLists.txt b/src/Math/Algorithms/Test/CMakeLists.txt new file mode 100644 index 000000000..8ebf44bc1 --- /dev/null +++ b/src/Math/Algorithms/Test/CMakeLists.txt @@ -0,0 +1 @@ +corrade_add_test2(MathAlgorithmsGaussJordanTest GaussJordanTest.cpp) diff --git a/src/Math/Algorithms/Test/GaussJordanTest.cpp b/src/Math/Algorithms/Test/GaussJordanTest.cpp new file mode 100644 index 000000000..51e36d89d --- /dev/null +++ b/src/Math/Algorithms/Test/GaussJordanTest.cpp @@ -0,0 +1,60 @@ +/* + 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 "GaussJordanTest.h" + +#include "Math/Algorithms/GaussJordan.h" + +CORRADE_TEST_MAIN(Magnum::Math::Algorithms::Test::GaussJordanTest) + +namespace Magnum { namespace Math { namespace Algorithms { namespace Test { + +typedef RectangularMatrix<4, 4, float> Matrix4; + +GaussJordanTest::GaussJordanTest() { + addTests(&GaussJordanTest::singular, + &GaussJordanTest::invert); +} + +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); + 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 a2(a); + Matrix4 inverse; + CORRADE_VERIFY(GaussJordan::inPlace(a2, inverse)); + + CORRADE_COMPARE(inverse, expectedInverse); + CORRADE_COMPARE(a*inverse, Matrix4()); +} + +}}}} diff --git a/src/Math/Algorithms/Test/GaussJordanTest.h b/src/Math/Algorithms/Test/GaussJordanTest.h new file mode 100644 index 000000000..0c25d27e0 --- /dev/null +++ b/src/Math/Algorithms/Test/GaussJordanTest.h @@ -0,0 +1,32 @@ +#ifndef Magnum_Math_Algorithms_Test_GaussJordanTest_h +#define Magnum_Math_Algorithms_Test_GaussJordanTest_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 Algorithms { namespace Test { + +class GaussJordanTest: public Corrade::TestSuite::Tester { + public: + GaussJordanTest(); + + void singular(); + void invert(); +}; + +}}}} + +#endif diff --git a/src/Math/CMakeLists.txt b/src/Math/CMakeLists.txt index 7053745a8..cf24e5d0b 100644 --- a/src/Math/CMakeLists.txt +++ b/src/Math/CMakeLists.txt @@ -13,6 +13,7 @@ set(MagnumMath_HEADERS Vector4.h) install(FILES ${MagnumMath_HEADERS} DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Math) +add_subdirectory(Algorithms) add_subdirectory(Geometry) if(BUILD_TESTS)