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.

258 lines
10 KiB

#ifndef Magnum_Math_Matrix_h
#define Magnum_Math_Matrix_h
16 years ago
/*
15 years ago
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz>
16 years ago
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::Matrix
16 years ago
*/
#include "RectangularMatrix.h"
namespace Magnum { namespace Math {
16 years ago
#ifndef DOXYGEN_GENERATING_OUTPUT
namespace Implementation {
template<std::size_t size, class T> class MatrixDeterminant;
}
#endif
16 years ago
/**
@brief Square matrix
@tparam size %Matrix size
@tparam T Data type
See @ref matrix-vector for brief introduction.
@configurationvalueref{Magnum::Math::Matrix}
@see Magnum::Matrix2, Magnum::Matrix2d
16 years ago
*/
template<std::size_t size, class T> class Matrix: public RectangularMatrix<size, size, T> {
16 years ago
public:
const static std::size_t Size = size; /**< @brief %Matrix size */
/** @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);`.
*/
inline constexpr explicit Matrix(ZeroType) {}
/** @brief Pass to constructor to create identity matrix */
enum IdentityType { Identity };
16 years ago
/**
* @brief Default constructor
*
* You can also explicitly call this constructor with
* `Matrix m(Matrix::Identity);`. Optional parameter @p value allows
* you to specify value on diagonal.
13 years ago
* @todo use constexpr fromDiagonal() for this when it's done
16 years ago
*/
inline /*implicit*/ Matrix(IdentityType = Identity, T value = T(1)) {
for(std::size_t i = 0; i != size; ++i)
(*this)[i][i] = value;
16 years ago
}
/**
* @brief %Matrix from column vectors
* @param first First column vector
* @param next Next column vectors
*/
template<class ...U> inline constexpr /*implicit*/ Matrix(const Vector<size, T>& first, const U&... next): RectangularMatrix<size, size, T>(first, next...) {}
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
* Matrix<2, Float> floatingPoint({1.3f, 2.7f},
13 years ago
* {-15.0f, 7.0f});
* Matrix<2, Byte> integral(floatingPoint);
13 years ago
* // integral == {{1, 2}, {-15, 7}}
* @endcode
*/
template<class U> inline constexpr explicit Matrix(const RectangularMatrix<size, size, U>& other): RectangularMatrix<size, size, T>(other) {}
16 years ago
/** @brief Copy constructor */
inline constexpr Matrix(const RectangularMatrix<size, size, T>& other): RectangularMatrix<size, size, T>(other) {}
16 years ago
/**
* @brief Trace of the matrix
*
* @f[
* tr(A) = \sum_{i=1}^n a_{i,i}
* @f]
*/
T trace() const {
return this->diagonal().sum();
}
/** @brief %Matrix without given column and row */
Matrix<size-1, T> ij(std::size_t skipCol, 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;
}
/**
* @brief Determinant
*
* 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
* ij(). The formula is expanded down to 2x2 matrix, where the
* determinant is computed directly: @f[
* \det(A) = a_{0, 0} a_{1, 1} - a_{1, 0} a_{0, 1}
* @f]
*/
inline T determinant() const { return Implementation::MatrixDeterminant<size, T>()(*this); }
/**
* @brief Inverted matrix
*
* Computed using Cramer's rule: @f[
* A^{-1} = \frac{1}{\det(A)} Adj(A)
* @f]
*
14 years ago
* See Matrix3::invertedEuclidean() and Matrix4::invertedEuclidean()
* which are faster alternatives for particular matrix types.
*/
Matrix<size, T> inverted() const {
Matrix<size, T> out(Zero);
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;
}
#ifndef DOXYGEN_GENERATING_OUTPUT
/* Reimplementation of functions to return correct type */
inline Matrix<size, T> operator*(const Matrix<size, T>& other) const {
return RectangularMatrix<size, size, T>::operator*(other);
}
template<std::size_t otherCols> inline RectangularMatrix<otherCols, size, T> operator*(const RectangularMatrix<otherCols, size, T>& other) const {
return RectangularMatrix<size, size, T>::operator*(other);
}
inline Vector<size, T> operator*(const Vector<size, T>& other) const {
return RectangularMatrix<size, size, T>::operator*(other);
}
MAGNUM_RECTANGULARMATRIX_SUBCLASS_IMPLEMENTATION(size, size, Matrix<size, T>)
#endif
16 years ago
};
#ifndef DOXYGEN_GENERATING_OUTPUT
template<std::size_t size, class T, class U> inline typename std::enable_if<std::is_arithmetic<U>::value, Matrix<size, T>>::type operator*(U number, const Matrix<size, T>& matrix) {
return number*RectangularMatrix<size, size, T>(matrix);
}
template<std::size_t size, class T, class U> inline typename std::enable_if<std::is_arithmetic<U>::value, Matrix<size, T>>::type operator/(U number, const Matrix<size, T>& matrix) {
return number/RectangularMatrix<size, size, T>(matrix);
}
template<std::size_t size, class T> inline Matrix<size, T> operator*(const Vector<size, T>& vector, const RectangularMatrix<size, 1, T>& matrix) {
return RectangularMatrix<1, size, T>(vector)*matrix;
}
#endif
/** @debugoperator{Magnum::Math::Matrix} */
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);
}
#ifndef DOXYGEN_GENERATING_OUTPUT
#define MAGNUM_MATRIX_SUBCLASS_IMPLEMENTATION(Type, VectorType, size) \
inline VectorType<T>& operator[](std::size_t col) { \
return static_cast<VectorType<T>&>(Matrix<size, T>::operator[](col)); \
} \
inline constexpr const VectorType<T> operator[](std::size_t col) const { \
return VectorType<T>(Matrix<size, T>::operator[](col)); \
} \
\
inline Type<T> operator*(const Matrix<size, T>& other) const { \
return Matrix<size, T>::operator*(other); \
} \
template<std::size_t otherCols> inline RectangularMatrix<otherCols, size, T> operator*(const RectangularMatrix<otherCols, size, T>& other) const { \
return Matrix<size, T>::operator*(other); \
} \
inline VectorType<T> operator*(const Vector<size, T>& other) const { \
return Matrix<size, T>::operator*(other); \
} \
\
inline Type<T> transposed() const { return Matrix<size, T>::transposed(); } \
inline Type<T> inverted() const { return Matrix<size, T>::inverted(); }
#define MAGNUM_MATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(Type, size) \
template<class T, class U> inline typename std::enable_if<std::is_arithmetic<U>::value, Type<T>>::type operator*(U number, const Type<T>& matrix) { \
return number*Matrix<size, T>(matrix); \
} \
template<class T, class U> inline typename std::enable_if<std::is_arithmetic<U>::value, Type<T>>::type operator/(U number, const Type<T>& matrix) { \
return number/Matrix<size, T>(matrix); \
} \
template<class T> inline Type<T> operator*(const Vector<size, T>& vector, const RectangularMatrix<size, 1, T>& matrix) { \
return RectangularMatrix<1, size, T>(vector)*matrix; \
}
namespace Implementation {
template<std::size_t size, class T> class MatrixDeterminant {
public:
T operator()(const Matrix<size, T>& m) {
T out(0);
for(std::size_t col = 0; col != size; ++col)
out += ((col & 1) ? -1 : 1)*m[col][0]*m.ij(col, 0).determinant();
return out;
}
};
template<class T> class MatrixDeterminant<2, T> {
public:
inline constexpr T operator()(const Matrix<2, T>& m) {
return m[0][0]*m[1][1] - m[1][0]*m[0][1];
}
};
template<class T> class MatrixDeterminant<1, T> {
public:
inline constexpr T operator()(const Matrix<1, T>& m) {
return m[0][0];
}
};
}
#endif
}}
16 years ago
namespace Corrade { namespace Utility {
/** @configurationvalue{Magnum::Math::Matrix} */
template<std::size_t size, class T> struct ConfigurationValue<Magnum::Math::Matrix<size, T>>: public ConfigurationValue<Magnum::Math::RectangularMatrix<size, size, T>> {};
}}
16 years ago
#endif