#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" #include "magnumVisibility.h" namespace Magnum { namespace Math { /** @todo Properly test all constexpr */ template class RectangularMatrix; #ifndef DOXYGEN_GENERATING_OUTPUT namespace Implementation { template struct Sequence {}; /* E.g. GenerateSequence<3>::Type is Sequence<0, 1, 2> */ template struct GenerateSequence: GenerateSequence {}; template struct GenerateSequence<0, sequence...> { typedef Sequence Type; }; /* Implementation for RectangularMatrix::from(const RectangularMatrix&) */ template inline constexpr Math::RectangularMatrix rectangularMatrixFrom(Sequence, const Math::RectangularMatrix& matrix) { return {T(matrix.data()[sequence])...}; } } #endif template class Vector; /** @brief Rectangular matrix @tparam cols Column count @tparam rows Row count @tparam T Data type See @ref matrix-vector for brief introduction. See also Matrix (square) and Vector. */ template class RectangularMatrix { static_assert(cols != 0 && rows != 0, "Matrix cannot have zero elements"); public: typedef T Type; /**< @brief Data type */ const static std::size_t Cols = cols; /**< @brief %Matrix column count */ const static std::size_t Rows = rows; /**< @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 * * @todo Creating matrix from arbitrary combination of matrices with n rows */ template inline constexpr static RectangularMatrix from(const Vector& first, const U&... next) { static_assert(sizeof...(next)+1 == cols, "Improper number of arguments passed to Matrix from Vector constructor"); return from(typename Implementation::GenerateSequence::Type(), first, next...); } /** * @brief %Matrix from another of different type * * Performs only default casting on the values, no rounding or * anything else. Example usage: * @code * RectangularMatrix<4, 1, float> floatingPoint(1.3f, 2.7f, -15.0f, 7.0f); * RectangularMatrix<4, 1, std::int8_t> integral(RectangularMatrix<4, 1, std::int8_t>::from(floatingPoint)); * // integral == {1, 2, -15, 7} * @endcode */ template inline constexpr static RectangularMatrix from(const RectangularMatrix& other) { return Implementation::rectangularMatrixFrom(typename Implementation::GenerateSequence::Type(), other); } /** @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[](std::size_t col) { return Vector::from(_data+col*rows); } /** @overload */ inline constexpr const Vector& operator[](std::size_t col) const { return Vector::from(_data+col*rows); } /** * @brief Element on given position * * Prefer this instead of using `[][]`. * @see operator[] */ inline T& operator()(std::size_t col, std::size_t row) { return _data[col*rows+row]; } /** @overload */ inline constexpr const T& operator()(std::size_t col, std::size_t row) const { return _data[col*rows+row]; } /** @brief Equality operator */ inline bool operator==(const RectangularMatrix& other) const { for(std::size_t i = 0; i != cols*rows; ++i) if(!MathTypeTraits::equals(_data[i], other._data[i])) return false; return true; } /** @brief Non-equality operator */ inline constexpr bool operator!=(const RectangularMatrix& other) const { 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(std::size_t i = 0; i != cols*rows; ++i) _data[i] += other._data[i]; return *this; } /** @brief Negative matrix */ RectangularMatrix operator-() const { RectangularMatrix out; for(std::size_t i = 0; i != cols*rows; ++i) out._data[i] = -_data[i]; return out; } /** * @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(std::size_t i = 0; i != cols*rows; ++i) _data[i] -= other._data[i]; 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(std::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(std::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; for(std::size_t col = 0; col != size; ++col) for(std::size_t row = 0; row != rows; ++row) for(std::size_t pos = 0; pos != cols; ++pos) out(col, row) += (*this)(pos, row)*other(col, pos); 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(std::size_t col = 0; col != cols; ++col) for(std::size_t row = 0; row != rows; ++row) out(row, col) = (*this)(col, row); return out; } #ifndef DOXYGEN_GENERATING_OUTPUT protected: T _data[rows*cols]; #endif private: template inline constexpr static RectangularMatrix from(Implementation::Sequence s, const Vector& first, U... next) { return from(s, next..., first[sequence]...); } template inline constexpr static RectangularMatrix from(Implementation::Sequence, T first, U... next) { return RectangularMatrix(first, next...); } }; /** @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(std::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("; debug.setFlag(Corrade::Utility::Debug::SpaceAfterEachValue, false); for(std::size_t row = 0; row != rows; ++row) { if(row != 0) debug << ",\n "; for(std::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; } /* Explicit instantiation for types used in OpenGL */ #ifndef DOXYGEN_GENERATING_OUTPUT /* Vectors */ extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<1, 2, float>&); extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<1, 3, float>&); extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<1, 4, float>&); extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<1, 2, int>&); extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<1, 3, int>&); extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<1, 4, int>&); extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<1, 2, unsigned int>&); extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<1, 3, unsigned int>&); extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<1, 4, unsigned int>&); #ifndef MAGNUM_TARGET_GLES extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<1, 2, double>&); extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<1, 3, double>&); extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<1, 4, double>&); #endif /* Square matrices */ extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<2, 2, float>&); extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<3, 3, float>&); extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<4, 4, float>&); #ifndef MAGNUM_TARGET_GLES extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<2, 2, double>&); extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<3, 3, double>&); extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<4, 4, double>&); #endif /* Rectangular matrices */ extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<2, 3, float>&); extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<3, 2, float>&); extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<2, 4, float>&); extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<4, 2, float>&); extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<3, 4, float>&); extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<4, 3, float>&); #ifndef MAGNUM_TARGET_GLES extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<2, 3, double>&); extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<3, 2, double>&); extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<2, 4, double>&); extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<4, 2, double>&); extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<3, 4, double>&); extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const RectangularMatrix<4, 3, double>&); #endif #endif #ifndef DOXYGEN_GENERATING_OUTPUT #define MAGNUM_RECTANGULARMATRIX_SUBCLASS_IMPLEMENTATION(cols, rows, ...) \ inline constexpr static __VA_ARGS__& from(T* data) { \ return *reinterpret_cast<__VA_ARGS__*>(data); \ } \ inline constexpr static const __VA_ARGS__& from(const T* data) { \ return *reinterpret_cast(data); \ } \ template inline constexpr static __VA_ARGS__ from(const Math::Vector& first, const U&... next) { \ return Math::RectangularMatrix::from(first, next...); \ } \ template inline constexpr static RectangularMatrix from(const Math::RectangularMatrix& other) { \ return Math::RectangularMatrix::from(other); \ } \ \ inline __VA_ARGS__& operator=(const Math::RectangularMatrix& other) { \ Math::RectangularMatrix::operator=(other); \ return *this; \ } #define MAGNUM_RECTANGULARMATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(cols, rows, ...) \ inline __VA_ARGS__ operator-() const { \ return Math::RectangularMatrix::operator-(); \ } \ inline __VA_ARGS__ operator+(const Math::RectangularMatrix& other) const { \ return Math::RectangularMatrix::operator+(other); \ } \ inline __VA_ARGS__& operator+=(const Math::RectangularMatrix& other) { \ Math::RectangularMatrix::operator+=(other); \ return *this; \ } \ inline __VA_ARGS__ operator-(const Math::RectangularMatrix& other) const { \ return Math::RectangularMatrix::operator-(other); \ } \ inline __VA_ARGS__& operator-=(const Math::RectangularMatrix& other) { \ Math::RectangularMatrix::operator-=(other); \ return *this; \ } \ template inline typename std::enable_if::value, __VA_ARGS__>::type operator*(U number) const { \ return Math::RectangularMatrix::operator*(number); \ } \ template inline typename std::enable_if::value, __VA_ARGS__&>::type operator*=(U number) { \ Math::RectangularMatrix::operator*=(number); \ return *this; \ } \ template inline typename std::enable_if::value, __VA_ARGS__>::type operator/(U number) const { \ return Math::RectangularMatrix::operator/(number); \ } \ template inline typename std::enable_if::value, __VA_ARGS__&>::type operator/=(U number) { \ Math::RectangularMatrix::operator/=(number); \ 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(std::size_t row = 0; row != rows; ++row) { for(std::size_t col = 0; col != cols; ++col) { if(!output.empty()) output += ' '; output += ConfigurationValue::toString(value(col, row), flags); } } 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(std::size_t row = 0; row != rows; ++row) { for(std::size_t col = 0; col != cols; ++col) { std::string num; in >> num; result(col, row) = ConfigurationValue::fromString(num, flags); } } return result; } }; #ifndef DOXYGEN_GENERATING_OUTPUT /* Vectors */ extern template struct MAGNUM_EXPORT ConfigurationValue>; extern template struct MAGNUM_EXPORT ConfigurationValue>; extern template struct MAGNUM_EXPORT ConfigurationValue>; extern template struct MAGNUM_EXPORT ConfigurationValue>; extern template struct MAGNUM_EXPORT ConfigurationValue>; extern template struct MAGNUM_EXPORT ConfigurationValue>; extern template struct MAGNUM_EXPORT ConfigurationValue>; extern template struct MAGNUM_EXPORT ConfigurationValue>; extern template struct MAGNUM_EXPORT ConfigurationValue>; #ifndef MAGNUM_TARGET_GLES extern template struct MAGNUM_EXPORT ConfigurationValue>; extern template struct MAGNUM_EXPORT ConfigurationValue>; extern template struct MAGNUM_EXPORT ConfigurationValue>; #endif /* Square matrices */ extern template struct MAGNUM_EXPORT ConfigurationValue>; extern template struct MAGNUM_EXPORT ConfigurationValue>; extern template struct MAGNUM_EXPORT ConfigurationValue>; #ifndef MAGNUM_TARGET_GLES extern template struct MAGNUM_EXPORT ConfigurationValue>; extern template struct MAGNUM_EXPORT ConfigurationValue>; extern template struct MAGNUM_EXPORT ConfigurationValue>; #endif /* Rectangular matrices */ extern template struct MAGNUM_EXPORT ConfigurationValue>; extern template struct MAGNUM_EXPORT ConfigurationValue>; extern template struct MAGNUM_EXPORT ConfigurationValue>; extern template struct MAGNUM_EXPORT ConfigurationValue>; extern template struct MAGNUM_EXPORT ConfigurationValue>; extern template struct MAGNUM_EXPORT ConfigurationValue>; #ifndef MAGNUM_TARGET_GLES extern template struct MAGNUM_EXPORT ConfigurationValue>; extern template struct MAGNUM_EXPORT ConfigurationValue>; extern template struct MAGNUM_EXPORT ConfigurationValue>; extern template struct MAGNUM_EXPORT ConfigurationValue>; extern template struct MAGNUM_EXPORT ConfigurationValue>; extern template struct MAGNUM_EXPORT ConfigurationValue>; #endif #endif }} /* Include also Vector, so the definition is complete */ #include "Vector.h" #endif