mirror of https://github.com/mosra/magnum.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
334 lines
13 KiB
334 lines
13 KiB
|
16 years ago
|
#ifndef Magnum_Math_Matrix_h
|
||
|
|
#define Magnum_Math_Matrix_h
|
||
|
16 years ago
|
/*
|
||
|
|
This file is part of Magnum.
|
||
|
|
|
||
|
13 years ago
|
Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš <mosra@centrum.cz>
|
||
|
|
|
||
|
|
Permission is hereby granted, free of charge, to any person obtaining a
|
||
|
|
copy of this software and associated documentation files (the "Software"),
|
||
|
|
to deal in the Software without restriction, including without limitation
|
||
|
|
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||
|
|
and/or sell copies of the Software, and to permit persons to whom the
|
||
|
|
Software is furnished to do so, subject to the following conditions:
|
||
|
|
|
||
|
|
The above copyright notice and this permission notice shall be included
|
||
|
|
in all copies or substantial portions of the Software.
|
||
|
|
|
||
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||
|
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||
|
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||
|
|
DEALINGS IN THE SOFTWARE.
|
||
|
16 years ago
|
*/
|
||
|
|
|
||
|
|
/** @file
|
||
|
16 years ago
|
* @brief Class Magnum::Math::Matrix
|
||
|
16 years ago
|
*/
|
||
|
|
|
||
|
14 years ago
|
#include "RectangularMatrix.h"
|
||
|
16 years ago
|
|
||
|
16 years ago
|
namespace Magnum { namespace Math {
|
||
|
16 years ago
|
|
||
|
14 years ago
|
namespace Implementation {
|
||
|
14 years ago
|
template<std::size_t size, class T> class MatrixDeterminant;
|
||
|
14 years ago
|
}
|
||
|
|
|
||
|
16 years ago
|
/**
|
||
|
14 years ago
|
@brief Square matrix
|
||
|
14 years ago
|
@tparam size %Matrix size
|
||
|
|
@tparam T Data type
|
||
|
14 years ago
|
|
||
|
|
See @ref matrix-vector for brief introduction.
|
||
|
14 years ago
|
|
||
|
|
@configurationvalueref{Magnum::Math::Matrix}
|
||
|
13 years ago
|
@see @ref Matrix2x2, @ref Matrix3x3, @ref Matrix4x4
|
||
|
16 years ago
|
*/
|
||
|
14 years ago
|
template<std::size_t size, class T> class Matrix: public RectangularMatrix<size, size, T> {
|
||
|
16 years ago
|
public:
|
||
|
14 years ago
|
const static std::size_t Size = size; /**< @brief %Matrix size */
|
||
|
14 years ago
|
|
||
|
14 years ago
|
/** @brief Pass to constructor to create zero-filled matrix */
|
||
|
|
enum ZeroType { Zero };
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @brief Zero-filled matrix constructor
|
||
|
|
*
|
||
|
|
* Use this constructor by calling `Matrix m(Matrix::Zero);`.
|
||
|
|
*/
|
||
|
13 years ago
|
constexpr explicit Matrix(ZeroType) {}
|
||
|
14 years ago
|
|
||
|
|
/** @brief Pass to constructor to create identity matrix */
|
||
|
|
enum IdentityType { Identity };
|
||
|
|
|
||
|
16 years ago
|
/**
|
||
|
|
* @brief Default constructor
|
||
|
14 years ago
|
*
|
||
|
|
* You can also explicitly call this constructor with
|
||
|
14 years ago
|
* `Matrix m(Matrix::Identity);`. Optional parameter @p value allows
|
||
|
|
* you to specify value on diagonal.
|
||
|
16 years ago
|
*/
|
||
|
13 years ago
|
constexpr /*implicit*/ Matrix(IdentityType = Identity, T value = T(1)): RectangularMatrix<size, size, T>(typename Implementation::GenerateSequence<size>::Type(),
|
||
|
|
/* The original one is not constexpr under GCC 4.6 */
|
||
|
|
#ifndef CORRADE_GCC46_COMPATIBILITY
|
||
|
|
Vector<size, T>(value)
|
||
|
|
#else
|
||
|
|
Vector<size, T>(typename Implementation::GenerateSequence<size>::Type(), value)
|
||
|
|
#endif
|
||
|
|
) {}
|
||
|
16 years ago
|
|
||
|
14 years ago
|
/**
|
||
|
13 years ago
|
* @brief %Matrix from column vectors
|
||
|
|
* @param first First column vector
|
||
|
|
* @param next Next column vectors
|
||
|
14 years ago
|
*/
|
||
|
13 years ago
|
template<class ...U> constexpr /*implicit*/ Matrix(const Vector<size, T>& first, const U&... next): RectangularMatrix<size, size, T>(first, next...) {}
|
||
|
14 years ago
|
|
||
|
13 years ago
|
/**
|
||
|
|
* @brief Construct matrix from another of different type
|
||
|
|
*
|
||
|
|
* Performs only default casting on the values, no rounding or
|
||
|
|
* anything else. Example usage:
|
||
|
|
* @code
|
||
|
13 years ago
|
* Matrix2x2<Float> floatingPoint({1.3f, 2.7f},
|
||
|
13 years ago
|
* {-15.0f, 7.0f});
|
||
|
13 years ago
|
* Matrix2x2<Byte> integral(floatingPoint);
|
||
|
13 years ago
|
* // integral == {{1, 2}, {-15, 7}}
|
||
|
|
* @endcode
|
||
|
|
*/
|
||
|
13 years ago
|
template<class U> constexpr explicit Matrix(const RectangularMatrix<size, size, U>& other): RectangularMatrix<size, size, T>(other) {}
|
||
|
13 years ago
|
|
||
|
13 years ago
|
/** @brief Construct matrix from external representation */
|
||
|
13 years ago
|
template<class U, class V = decltype(Implementation::RectangularMatrixConverter<size, size, T, U>::from(std::declval<U>()))> constexpr explicit Matrix(const U& other): RectangularMatrix<size, size, T>(Implementation::RectangularMatrixConverter<size, size, T, U>::from(other)) {}
|
||
|
13 years ago
|
|
||
|
16 years ago
|
/** @brief Copy constructor */
|
||
|
13 years ago
|
constexpr Matrix(const RectangularMatrix<size, size, T>& other): RectangularMatrix<size, size, T>(other) {}
|
||
|
16 years ago
|
|
||
|
13 years ago
|
/**
|
||
|
|
* @brief Whether the matrix is orthogonal
|
||
|
|
*
|
||
|
|
* The matrix is orthogonal if its transpose is equal to its inverse: @f[
|
||
|
|
* Q^T = Q^{-1}
|
||
|
|
* @f]
|
||
|
13 years ago
|
* @see transposed(), inverted(), Matrix3::isRigidTransformation(),
|
||
|
|
* Matrix4::isRigidTransformation()
|
||
|
13 years ago
|
*/
|
||
|
13 years ago
|
bool isOrthogonal() const;
|
||
|
13 years ago
|
|
||
|
14 years ago
|
/**
|
||
|
|
* @brief Trace of the matrix
|
||
|
|
*
|
||
|
|
* @f[
|
||
|
|
* tr(A) = \sum_{i=1}^n a_{i,i}
|
||
|
|
* @f]
|
||
|
|
*/
|
||
|
13 years ago
|
T trace() const { return RectangularMatrix<size, size, T>::diagonal().sum(); }
|
||
|
14 years ago
|
|
||
|
14 years ago
|
/** @brief %Matrix without given column and row */
|
||
|
13 years ago
|
Matrix<size-1, T> ij(std::size_t skipCol, std::size_t skipRow) const;
|
||
|
16 years ago
|
|
||
|
16 years ago
|
/**
|
||
|
|
* @brief Determinant
|
||
|
|
*
|
||
|
14 years ago
|
* Computed recursively using Laplace's formula: @f[
|
||
|
|
* \det(A) = \sum_{j=1}^n (-1)^{i+j} a_{i,j} \det(A^{i,j})
|
||
|
|
* @f] @f$ A^{i, j} @f$ is matrix without i-th row and j-th column, see
|
||
|
14 years ago
|
* ij(). The formula is expanded down to 2x2 matrix, where the
|
||
|
14 years ago
|
* determinant is computed directly: @f[
|
||
|
|
* \det(A) = a_{0, 0} a_{1, 1} - a_{1, 0} a_{0, 1}
|
||
|
14 years ago
|
* @f]
|
||
|
16 years ago
|
*/
|
||
|
13 years ago
|
T determinant() const { return Implementation::MatrixDeterminant<size, T>()(*this); }
|
||
|
16 years ago
|
|
||
|
|
/**
|
||
|
14 years ago
|
* @brief Inverted matrix
|
||
|
14 years ago
|
*
|
||
|
14 years ago
|
* Computed using Cramer's rule: @f[
|
||
|
|
* A^{-1} = \frac{1}{\det(A)} Adj(A)
|
||
|
14 years ago
|
* @f]
|
||
|
13 years ago
|
* See invertedOrthogonal(), Matrix3::invertedRigid() and Matrix4::invertedRigid()
|
||
|
14 years ago
|
* which are faster alternatives for particular matrix types.
|
||
|
16 years ago
|
*/
|
||
|
13 years ago
|
Matrix<size, T> inverted() const;
|
||
|
16 years ago
|
|
||
|
13 years ago
|
/**
|
||
|
|
* @brief Inverted orthogonal matrix
|
||
|
|
*
|
||
|
|
* Equivalent to transposed(), expects that the matrix is orthogonal. @f[
|
||
|
|
* A^{-1} = A^T
|
||
|
|
* @f]
|
||
|
|
* @see inverted(), isOrthogonal(), Matrix3::invertedRigid(),
|
||
|
|
* Matrix4::invertedRigid()
|
||
|
|
*/
|
||
|
13 years ago
|
Matrix<size, T> invertedOrthogonal() const {
|
||
|
13 years ago
|
CORRADE_ASSERT(isOrthogonal(),
|
||
|
|
"Math::Matrix::invertedOrthogonal(): the matrix is not orthogonal", {});
|
||
|
13 years ago
|
return RectangularMatrix<size, size, T>::transposed();
|
||
|
13 years ago
|
}
|
||
|
|
|
||
|
14 years ago
|
#ifndef DOXYGEN_GENERATING_OUTPUT
|
||
|
|
/* Reimplementation of functions to return correct type */
|
||
|
13 years ago
|
Matrix<size, T> operator*(const Matrix<size, T>& other) const {
|
||
|
14 years ago
|
return RectangularMatrix<size, size, T>::operator*(other);
|
||
|
14 years ago
|
}
|
||
|
13 years ago
|
template<std::size_t otherCols> RectangularMatrix<otherCols, size, T> operator*(const RectangularMatrix<otherCols, size, T>& other) const {
|
||
|
14 years ago
|
return RectangularMatrix<size, size, T>::operator*(other);
|
||
|
14 years ago
|
}
|
||
|
13 years ago
|
Vector<size, T> operator*(const Vector<size, T>& other) const {
|
||
|
14 years ago
|
return RectangularMatrix<size, size, T>::operator*(other);
|
||
|
|
}
|
||
|
|
MAGNUM_RECTANGULARMATRIX_SUBCLASS_IMPLEMENTATION(size, size, Matrix<size, T>)
|
||
|
14 years ago
|
#endif
|
||
|
16 years ago
|
};
|
||
|
|
|
||
|
13 years ago
|
#ifndef CORRADE_GCC46_COMPATIBILITY
|
||
|
|
/**
|
||
|
|
@brief 2x2 matrix
|
||
|
|
|
||
|
|
Convenience alternative to <tt>%Matrix<2, T></tt>. See @ref Matrix for more
|
||
|
|
information.
|
||
|
|
@note Not available on GCC < 4.7. Use <tt>%Matrix<2, T></tt> instead.
|
||
|
|
@see @ref Magnum::Matrix2x2, @ref Magnum::Matrix2x2d
|
||
|
|
*/
|
||
|
|
template<class T> using Matrix2x2 = Matrix<2, T>;
|
||
|
|
|
||
|
|
/**
|
||
|
|
@brief 3x3 matrix
|
||
|
|
|
||
|
|
Convenience alternative to <tt>%Matrix<3, T></tt>. See @ref Matrix for more
|
||
|
|
information. Note that this is different from @ref Matrix3, which contains
|
||
|
|
additional functions for transformations in 2D.
|
||
|
|
@note Not available on GCC < 4.7. Use <tt>%Matrix<3, T></tt> instead.
|
||
|
|
@see @ref Magnum::Matrix3x3, @ref Magnum::Matrix3x3d
|
||
|
|
*/
|
||
|
|
template<class T> using Matrix3x3 = Matrix<3, T>;
|
||
|
|
|
||
|
|
/**
|
||
|
|
@brief 4x4 matrix
|
||
|
|
|
||
|
|
Convenience alternative to <tt>%Matrix<4, T></tt>. See @ref Matrix for more
|
||
|
|
information. Note that this is different from @ref Matrix4, which contains
|
||
|
|
additional functions for transformations in 3D.
|
||
|
|
@note Not available on GCC < 4.7. Use <tt>%Matrix<3, T></tt> instead.
|
||
|
|
@see @ref Magnum::Matrix4x4, @ref Magnum::Matrix4x4d
|
||
|
|
*/
|
||
|
|
template<class T> using Matrix4x4 = Matrix<4, T>;
|
||
|
|
#endif
|
||
|
|
|
||
|
13 years ago
|
MAGNUM_MATRIX_OPERATOR_IMPLEMENTATION(Matrix<size, T>)
|
||
|
14 years ago
|
|
||
|
14 years ago
|
/** @debugoperator{Magnum::Math::Matrix} */
|
||
|
14 years ago
|
template<std::size_t size, class T> inline Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Matrix<size, T>& value) {
|
||
|
14 years ago
|
return debug << static_cast<const RectangularMatrix<size, size, T>&>(value);
|
||
|
14 years ago
|
}
|
||
|
|
|
||
|
14 years ago
|
#ifndef DOXYGEN_GENERATING_OUTPUT
|
||
|
13 years ago
|
#define MAGNUM_MATRIX_SUBCLASS_IMPLEMENTATION(size, Type, VectorType) \
|
||
|
13 years ago
|
VectorType<T>& operator[](std::size_t col) { \
|
||
|
13 years ago
|
return static_cast<VectorType<T>&>(Matrix<size, T>::operator[](col)); \
|
||
|
14 years ago
|
} \
|
||
|
13 years ago
|
constexpr const VectorType<T> operator[](std::size_t col) const { \
|
||
|
13 years ago
|
return VectorType<T>(Matrix<size, T>::operator[](col)); \
|
||
|
14 years ago
|
} \
|
||
|
13 years ago
|
VectorType<T> row(std::size_t row) const { \
|
||
|
13 years ago
|
return VectorType<T>(Matrix<size, T>::row(row)); \
|
||
|
|
} \
|
||
|
14 years ago
|
\
|
||
|
13 years ago
|
Type<T> operator*(const Matrix<size, T>& other) const { \
|
||
|
14 years ago
|
return Matrix<size, T>::operator*(other); \
|
||
|
|
} \
|
||
|
13 years ago
|
template<std::size_t otherCols> RectangularMatrix<otherCols, size, T> operator*(const RectangularMatrix<otherCols, size, T>& other) const { \
|
||
|
14 years ago
|
return Matrix<size, T>::operator*(other); \
|
||
|
|
} \
|
||
|
13 years ago
|
VectorType<T> operator*(const Vector<size, T>& other) const { \
|
||
|
14 years ago
|
return Matrix<size, T>::operator*(other); \
|
||
|
|
} \
|
||
|
|
\
|
||
|
13 years ago
|
Type<T> transposed() const { return Matrix<size, T>::transposed(); } \
|
||
|
13 years ago
|
constexpr VectorType<T> diagonal() const { return Matrix<size, T>::diagonal(); } \
|
||
|
13 years ago
|
Type<T> inverted() const { return Matrix<size, T>::inverted(); } \
|
||
|
|
Type<T> invertedOrthogonal() const { \
|
||
|
13 years ago
|
return Matrix<size, T>::invertedOrthogonal(); \
|
||
|
|
}
|
||
|
14 years ago
|
|
||
|
14 years ago
|
namespace Implementation {
|
||
|
|
|
||
|
14 years ago
|
template<std::size_t size, class T> class MatrixDeterminant {
|
||
|
16 years ago
|
public:
|
||
|
13 years ago
|
T operator()(const Matrix<size, T>& m);
|
||
|
|
};
|
||
|
14 years ago
|
|
||
|
13 years ago
|
template<std::size_t size, class T> T MatrixDeterminant<size, T>::operator()(const Matrix<size, T>& m) {
|
||
|
|
T out(0);
|
||
|
14 years ago
|
|
||
|
13 years ago
|
for(std::size_t col = 0; col != size; ++col)
|
||
|
|
out += ((col & 1) ? -1 : 1)*m[col][0]*m.ij(col, 0).determinant();
|
||
|
|
|
||
|
|
return out;
|
||
|
|
}
|
||
|
16 years ago
|
|
||
|
14 years ago
|
template<class T> class MatrixDeterminant<2, T> {
|
||
|
14 years ago
|
public:
|
||
|
13 years ago
|
constexpr T operator()(const Matrix<2, T>& m) const {
|
||
|
13 years ago
|
return m[0][0]*m[1][1] - m[1][0]*m[0][1];
|
||
|
16 years ago
|
}
|
||
|
14 years ago
|
};
|
||
|
16 years ago
|
|
||
|
14 years ago
|
template<class T> class MatrixDeterminant<1, T> {
|
||
|
14 years ago
|
public:
|
||
|
13 years ago
|
constexpr T operator()(const Matrix<1, T>& m) const {
|
||
|
13 years ago
|
return m[0][0];
|
||
|
14 years ago
|
}
|
||
|
16 years ago
|
};
|
||
|
14 years ago
|
|
||
|
|
}
|
||
|
15 years ago
|
#endif
|
||
|
|
|
||
|
13 years ago
|
template<std::size_t size, class T> bool Matrix<size, T>::isOrthogonal() const {
|
||
|
|
/* Normality */
|
||
|
|
for(std::size_t i = 0; i != size; ++i)
|
||
|
|
if(!(*this)[i].isNormalized()) return false;
|
||
|
|
|
||
|
|
/* Orthogonality */
|
||
|
|
for(std::size_t i = 0; i != size-1; ++i)
|
||
|
|
for(std::size_t j = i+1; j != size; ++j)
|
||
|
|
if(Vector<size, T>::dot((*this)[i], (*this)[j]) > TypeTraits<T>::epsilon())
|
||
|
|
return false;
|
||
|
|
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
template<std::size_t size, class T> Matrix<size-1, T> Matrix<size, T>::ij(const std::size_t skipCol, const std::size_t skipRow) const {
|
||
|
|
Matrix<size-1, T> out(Matrix<size-1, T>::Zero);
|
||
|
|
|
||
|
|
for(std::size_t col = 0; col != size-1; ++col)
|
||
|
|
for(std::size_t row = 0; row != size-1; ++row)
|
||
|
|
out[col][row] = (*this)[col + (col >= skipCol)]
|
||
|
|
[row + (row >= skipRow)];
|
||
|
|
|
||
|
|
return out;
|
||
|
|
}
|
||
|
|
|
||
|
|
template<std::size_t size, class T> Matrix<size, T> Matrix<size, T>::inverted() const {
|
||
|
|
Matrix<size, T> out(Zero);
|
||
|
|
|
||
|
|
const T _determinant = determinant();
|
||
|
|
|
||
|
|
for(std::size_t col = 0; col != size; ++col)
|
||
|
|
for(std::size_t row = 0; row != size; ++row)
|
||
|
|
out[col][row] = (((row+col) & 1) ? -1 : 1)*ij(row, col).determinant()/_determinant;
|
||
|
|
|
||
|
|
return out;
|
||
|
|
}
|
||
|
|
|
||
|
16 years ago
|
}}
|
||
|
16 years ago
|
|
||
|
14 years ago
|
namespace Corrade { namespace Utility {
|
||
|
14 years ago
|
/** @configurationvalue{Magnum::Math::Matrix} */
|
||
|
14 years ago
|
template<std::size_t size, class T> struct ConfigurationValue<Magnum::Math::Matrix<size, T>>: public ConfigurationValue<Magnum::Math::RectangularMatrix<size, size, T>> {};
|
||
|
14 years ago
|
}}
|
||
|
|
|
||
|
16 years ago
|
#endif
|