mirror of https://github.com/mosra/magnum.git
37 changed files with 1200 additions and 679 deletions
@ -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() |
||||||
@ -0,0 +1,113 @@ |
|||||||
|
#ifndef Magnum_Math_Algorithms_GaussJordan_h |
||||||
|
#define Magnum_Math_Algorithms_GaussJordan_h |
||||||
|
/*
|
||||||
|
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz> |
||||||
|
|
||||||
|
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<size_t size, size_t rows, class T> static bool inPlaceTransposed(RectangularMatrix<size, size, T>& a, RectangularMatrix<size, rows, T>& t); |
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Eliminate in place |
||||||
|
* |
||||||
|
* Transposes the matrices, calls inPlaceTransposed() on them and then |
||||||
|
* transposes them back. |
||||||
|
*/ |
||||||
|
template<size_t size, size_t cols, class T> static bool inPlace(RectangularMatrix<size, size, T>& a, RectangularMatrix<cols, size, T>& t) { |
||||||
|
a = a.transposed(); |
||||||
|
RectangularMatrix<size, cols, T> tTransposed = t.transposed(); |
||||||
|
|
||||||
|
bool ret = inPlaceTransposed(a, tTransposed); |
||||||
|
|
||||||
|
a = a.transposed(); |
||||||
|
t = tTransposed.transposed(); |
||||||
|
|
||||||
|
return ret; |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
template<size_t size, size_t cols, class T> bool GaussJordan::inPlaceTransposed(RectangularMatrix<size, size, T>& a, RectangularMatrix<size, cols, T>& 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<T>::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 |
||||||
@ -0,0 +1 @@ |
|||||||
|
corrade_add_test2(MathAlgorithmsGaussJordanTest GaussJordanTest.cpp) |
||||||
@ -0,0 +1,60 @@ |
|||||||
|
/*
|
||||||
|
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz> |
||||||
|
|
||||||
|
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()); |
||||||
|
} |
||||||
|
|
||||||
|
}}}} |
||||||
@ -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š <mosra@centrum.cz> |
||||||
|
|
||||||
|
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 <TestSuite/Tester.h> |
||||||
|
|
||||||
|
namespace Magnum { namespace Math { namespace Algorithms { namespace Test { |
||||||
|
|
||||||
|
class GaussJordanTest: public Corrade::TestSuite::Tester<GaussJordanTest> { |
||||||
|
public: |
||||||
|
GaussJordanTest(); |
||||||
|
|
||||||
|
void singular(); |
||||||
|
void invert(); |
||||||
|
}; |
||||||
|
|
||||||
|
}}}} |
||||||
|
|
||||||
|
#endif |
||||||
@ -0,0 +1,467 @@ |
|||||||
|
#ifndef Magnum_Math_RectangularMatrix_h |
||||||
|
#define Magnum_Math_RectangularMatrix_h |
||||||
|
/*
|
||||||
|
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz> |
||||||
|
|
||||||
|
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 <cmath> |
||||||
|
#include <limits> |
||||||
|
#include <Utility/Debug.h> |
||||||
|
#include <Utility/Configuration.h> |
||||||
|
|
||||||
|
#include "MathTypeTraits.h" |
||||||
|
|
||||||
|
namespace Magnum { namespace Math { |
||||||
|
|
||||||
|
#ifndef DOXYGEN_GENERATING_OUTPUT |
||||||
|
namespace Implementation { |
||||||
|
template<size_t ...> struct Sequence {}; |
||||||
|
|
||||||
|
/* E.g. GenerateSequence<3>::Type is Sequence<0, 1, 2> */ |
||||||
|
template<size_t N, size_t ...sequence> struct GenerateSequence: |
||||||
|
GenerateSequence<N-1, N-1, sequence...> {}; |
||||||
|
|
||||||
|
template<size_t ...sequence> struct GenerateSequence<0, sequence...> { |
||||||
|
typedef Sequence<sequence...> Type; |
||||||
|
}; |
||||||
|
} |
||||||
|
#endif |
||||||
|
|
||||||
|
template<size_t size, class T> class Vector; |
||||||
|
|
||||||
|
/**
|
||||||
|
@brief Rectangular matrix |
||||||
|
@tparam c Column count |
||||||
|
@tparam r Row count |
||||||
|
|
||||||
|
See also Matrix (square) and Vector. |
||||||
|
*/ |
||||||
|
template<size_t c, size_t r, class T> class RectangularMatrix { |
||||||
|
static_assert(c != 0 && r != 0, "Matrix cannot have zero elements"); |
||||||
|
|
||||||
|
friend class Vector<r, T>; |
||||||
|
|
||||||
|
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<cols, rows, T>& from(T* data) { |
||||||
|
return *reinterpret_cast<RectangularMatrix<cols, rows, T>*>(data); |
||||||
|
} |
||||||
|
/** @overload */ |
||||||
|
inline constexpr static const RectangularMatrix<cols, rows, T>& from(const T* data) { |
||||||
|
return *reinterpret_cast<const RectangularMatrix<cols, rows, T>*>(data); |
||||||
|
} |
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief %Matrix from column vectors |
||||||
|
* @param first First column vector |
||||||
|
* @param next Next column vectors |
||||||
|
*/ |
||||||
|
template<class ...U> inline constexpr static RectangularMatrix<cols, rows, T> from(const Vector<rows, T>& 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<rows>::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<class ...U> 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<class ...U> inline constexpr RectangularMatrix(T first, U... next); |
||||||
|
#endif |
||||||
|
|
||||||
|
/** @brief Copy constructor */ |
||||||
|
inline constexpr RectangularMatrix(const RectangularMatrix<c, r, T>&) = default; |
||||||
|
|
||||||
|
/** @brief Assignment operator */ |
||||||
|
inline RectangularMatrix<c, r, T>& operator=(const RectangularMatrix<c, r, T>&) = 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<rows, T>& operator[](size_t col) { |
||||||
|
return Vector<rows, T>::from(_data+col*rows); |
||||||
|
} |
||||||
|
/** @overload */ |
||||||
|
inline constexpr const Vector<rows, T>& operator[](size_t col) const { |
||||||
|
return Vector<rows, T>::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<cols, rows, T>& other) const { |
||||||
|
for(size_t i = 0; i != cols*rows; ++i) |
||||||
|
if(!MathTypeTraits<T>::equals(_data[i], other._data[i])) return false; |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
/** @brief Non-equality operator */ |
||||||
|
inline constexpr bool operator!=(const RectangularMatrix<cols, rows, T>& other) const { |
||||||
|
return !operator==(other); |
||||||
|
} |
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Add matrix |
||||||
|
* |
||||||
|
* @see operator+=() |
||||||
|
*/ |
||||||
|
inline RectangularMatrix<cols, rows, T> operator+(const RectangularMatrix<cols, rows, T>& other) const { |
||||||
|
return RectangularMatrix<cols, rows, T>(*this)+=other; |
||||||
|
} |
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Add and assign matrix |
||||||
|
* |
||||||
|
* More efficient than operator+(), because it does the computation |
||||||
|
* in-place. |
||||||
|
*/ |
||||||
|
RectangularMatrix<cols, rows, T>& operator+=(const RectangularMatrix<cols, rows, T>& other) { |
||||||
|
for(size_t i = 0; i != cols*rows; ++i) |
||||||
|
_data[i] += other._data[i]; |
||||||
|
|
||||||
|
return *this; |
||||||
|
} |
||||||
|
|
||||||
|
/** @brief Negative matrix */ |
||||||
|
RectangularMatrix<cols, rows, T> operator-() const { |
||||||
|
RectangularMatrix<cols, rows, T> out; |
||||||
|
|
||||||
|
for(size_t i = 0; i != cols*rows; ++i) |
||||||
|
out._data[i] = -_data[i]; |
||||||
|
|
||||||
|
return out; |
||||||
|
} |
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Subtract matrix |
||||||
|
* |
||||||
|
* @see operator-=() |
||||||
|
*/ |
||||||
|
inline RectangularMatrix<cols, rows, T> operator-(const RectangularMatrix<cols, rows, T>& other) const { |
||||||
|
return RectangularMatrix<cols, rows, T>(*this)-=other; |
||||||
|
} |
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Subtract and assign matrix |
||||||
|
* |
||||||
|
* More efficient than operator-(), because it does the computation |
||||||
|
* in-place. |
||||||
|
*/ |
||||||
|
RectangularMatrix<cols, rows, T>& operator-=(const RectangularMatrix<cols, rows, T>& other) { |
||||||
|
for(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<cols, rows, T>&) |
||||||
|
*/ |
||||||
|
#ifndef DOXYGEN_GENERATING_OUTPUT |
||||||
|
template<class U> inline typename std::enable_if<std::is_arithmetic<U>::value, RectangularMatrix<cols, rows, T>>::type operator*(U number) const { |
||||||
|
#else |
||||||
|
template<class U> inline RectangularMatrix<cols, rows, T> operator*(U number) const { |
||||||
|
#endif |
||||||
|
return RectangularMatrix<cols, rows, T>(*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<class U> inline typename std::enable_if<std::is_arithmetic<U>::value, RectangularMatrix<cols, rows, T>&>::type operator*=(U number) { |
||||||
|
#else |
||||||
|
template<class U> RectangularMatrix<cols, rows, T>& 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<cols, rows, T>&) |
||||||
|
*/ |
||||||
|
#ifndef DOXYGEN_GENERATING_OUTPUT |
||||||
|
template<class U> inline typename std::enable_if<std::is_arithmetic<U>::value, RectangularMatrix<cols, rows, T>>::type operator/(U number) const { |
||||||
|
#else |
||||||
|
template<class U> inline RectangularMatrix<cols, rows, T> operator/(U number) const { |
||||||
|
#endif |
||||||
|
return RectangularMatrix<cols, rows, T>(*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<class U> inline typename std::enable_if<std::is_arithmetic<U>::value, RectangularMatrix<cols, rows, T>&>::type operator/=(U number) { |
||||||
|
#else |
||||||
|
template<class U> RectangularMatrix<cols, rows, T>& operator/=(U number) { |
||||||
|
#endif |
||||||
|
for(size_t i = 0; i != cols*rows; ++i) |
||||||
|
_data[i] /= number; |
||||||
|
|
||||||
|
return *this; |
||||||
|
} |
||||||
|
|
||||||
|
/** @brief Multiply matrix */ |
||||||
|
template<size_t size> RectangularMatrix<size, rows, T> operator*(const RectangularMatrix<size, cols, T>& other) const { |
||||||
|
RectangularMatrix<size, rows, T> 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<rows, T> operator*(const Vector<rows, T>& other) const { |
||||||
|
return operator*(static_cast<RectangularMatrix<1, rows, T>>(other)); |
||||||
|
} |
||||||
|
|
||||||
|
/** @brief Transposed matrix */ |
||||||
|
RectangularMatrix<rows, cols, T> transposed() const { |
||||||
|
RectangularMatrix<rows, cols, T> 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<size_t ...sequence, class ...U> inline constexpr static RectangularMatrix<cols, rows, T> from(Implementation::Sequence<sequence...> s, const Vector<rows, T>& first, U... next) { |
||||||
|
return from(s, next..., first[sequence]...); |
||||||
|
} |
||||||
|
template<size_t ...sequence, class ...U> inline constexpr static RectangularMatrix<cols, rows, T> from(Implementation::Sequence<sequence...>, T first, U... next) { |
||||||
|
return RectangularMatrix<cols, rows, T>(first, next...); |
||||||
|
} |
||||||
|
|
||||||
|
T _data[rows*cols]; |
||||||
|
}; |
||||||
|
|
||||||
|
/** @relates RectangularMatrix
|
||||||
|
@brief Multiply number with matrix |
||||||
|
|
||||||
|
@see RectangularMatrix::operator*(U) const |
||||||
|
*/ |
||||||
|
#ifndef DOXYGEN_GENERATING_OUTPUT |
||||||
|
template<size_t cols, size_t rows, class T, class U> inline typename std::enable_if<std::is_arithmetic<U>::value, RectangularMatrix<cols, rows, T>>::type operator*(U number, const RectangularMatrix<cols, rows, T>& matrix) { |
||||||
|
#else |
||||||
|
template<size_t cols, size_t rows, class T, class U> inline RectangularMatrix<cols, rows, T> operator*(U number, const RectangularMatrix<cols, rows, T>& 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<size_t cols, size_t rows, class T, class U> typename std::enable_if<std::is_arithmetic<U>::value, RectangularMatrix<cols, rows, T>>::type operator/(U number, const RectangularMatrix<cols, rows, T>& matrix) { |
||||||
|
#else |
||||||
|
template<size_t cols, size_t rows, class T, class U> RectangularMatrix<cols, rows, T> operator/(U number, const RectangularMatrix<cols, rows, T>& matrix) { |
||||||
|
#endif |
||||||
|
RectangularMatrix<cols, rows, T> out; |
||||||
|
|
||||||
|
for(size_t i = 0; i != cols*rows; ++i) |
||||||
|
out.data()[i] = number/matrix.data()[i]; |
||||||
|
|
||||||
|
return out; |
||||||
|
} |
||||||
|
|
||||||
|
/** @debugoperator{Magnum::Math::RectangularMatrix} */ |
||||||
|
template<size_t cols, size_t rows, class T> Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Magnum::Math::RectangularMatrix<cols, rows, T>& 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<T>::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<const __VA_ARGS__*>(data); \
|
||||||
|
} \
|
||||||
|
template<class ...U> inline constexpr static __VA_ARGS__ from(const Math::Vector<rows, T>& first, const U&... next) { \
|
||||||
|
return Math::RectangularMatrix<cols, rows, T>::from(first, next...); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
inline __VA_ARGS__& operator=(const Math::RectangularMatrix<cols, rows, T>& other) { \
|
||||||
|
Math::RectangularMatrix<cols, rows, T>::operator=(other); \
|
||||||
|
return *this; \
|
||||||
|
} |
||||||
|
|
||||||
|
#define MAGNUM_RECTANGULARMATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(cols, rows, ...) \ |
||||||
|
inline __VA_ARGS__ operator-() const { \
|
||||||
|
return Math::RectangularMatrix<cols, rows, T>::operator-(); \
|
||||||
|
} \
|
||||||
|
inline __VA_ARGS__ operator+(const Math::RectangularMatrix<cols, rows, T>& other) const { \
|
||||||
|
return Math::RectangularMatrix<cols, rows, T>::operator+(other); \
|
||||||
|
} \
|
||||||
|
inline __VA_ARGS__& operator+=(const Math::RectangularMatrix<cols, rows, T>& other) { \
|
||||||
|
Math::RectangularMatrix<cols, rows, T>::operator+=(other); \
|
||||||
|
return *this; \
|
||||||
|
} \
|
||||||
|
inline __VA_ARGS__ operator-(const Math::RectangularMatrix<cols, rows, T>& other) const { \
|
||||||
|
return Math::RectangularMatrix<cols, rows, T>::operator-(other); \
|
||||||
|
} \
|
||||||
|
inline __VA_ARGS__& operator-=(const Math::RectangularMatrix<cols, rows, T>& other) { \
|
||||||
|
Math::RectangularMatrix<cols, rows, T>::operator-=(other); \
|
||||||
|
return *this; \
|
||||||
|
} \
|
||||||
|
template<class U> inline typename std::enable_if<std::is_arithmetic<U>::value, __VA_ARGS__>::type operator*(U number) const { \
|
||||||
|
return Math::RectangularMatrix<cols, rows, T>::operator*(number); \
|
||||||
|
} \
|
||||||
|
template<class U> inline typename std::enable_if<std::is_arithmetic<U>::value, __VA_ARGS__&>::type operator*=(U number) { \
|
||||||
|
Math::RectangularMatrix<cols, rows, T>::operator*=(number); \
|
||||||
|
return *this; \
|
||||||
|
} \
|
||||||
|
template<class U> inline typename std::enable_if<std::is_arithmetic<U>::value, __VA_ARGS__>::type operator/(U number) const { \
|
||||||
|
return Math::RectangularMatrix<cols, rows, T>::operator/(number); \
|
||||||
|
} \
|
||||||
|
template<class U> inline typename std::enable_if<std::is_arithmetic<U>::value, __VA_ARGS__&>::type operator/=(U number) { \
|
||||||
|
Math::RectangularMatrix<cols, rows, T>::operator/=(number); \
|
||||||
|
return *this; \
|
||||||
|
} |
||||||
|
#endif |
||||||
|
|
||||||
|
}} |
||||||
|
|
||||||
|
namespace Corrade { namespace Utility { |
||||||
|
|
||||||
|
/** @configurationvalue{Magnum::Math::RectangularMatrix} */ |
||||||
|
template<size_t cols, size_t rows, class T> struct ConfigurationValue<Magnum::Math::RectangularMatrix<cols, rows, T>> { |
||||||
|
/** @brief Writes elements separated with spaces */ |
||||||
|
static std::string toString(const Magnum::Math::RectangularMatrix<cols, rows, T>& 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<T>::toString(value(col, row), flags); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return output; |
||||||
|
} |
||||||
|
|
||||||
|
/** @brief Reads elements separated with whitespace */ |
||||||
|
static Magnum::Math::RectangularMatrix<cols, rows, T> fromString(const std::string& stringValue, int flags = 0) { |
||||||
|
Magnum::Math::RectangularMatrix<cols, rows, T> 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<T>::fromString(num, flags); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return result; |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
}} |
||||||
|
|
||||||
|
/* Include also Vector, so the definition is complete */ |
||||||
|
#include "Vector.h" |
||||||
|
|
||||||
|
#endif |
||||||
@ -0,0 +1,237 @@ |
|||||||
|
/*
|
||||||
|
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz> |
||||||
|
|
||||||
|
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 <sstream> |
||||||
|
|
||||||
|
#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 RectangularMatrix<2, 2, float> Matrix2; |
||||||
|
typedef Vector<4, float> Vector4; |
||||||
|
|
||||||
|
RectangularMatrixTest::RectangularMatrixTest() { |
||||||
|
addTests(&RectangularMatrixTest::construct, |
||||||
|
&RectangularMatrixTest::constructFromVectors, |
||||||
|
&RectangularMatrixTest::constructZero, |
||||||
|
&RectangularMatrixTest::data, |
||||||
|
|
||||||
|
&RectangularMatrixTest::negative, |
||||||
|
&RectangularMatrixTest::addSubtract, |
||||||
|
&RectangularMatrixTest::multiplyDivide, |
||||||
|
&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::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, |
||||||
|
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::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, |
||||||
|
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<Matrix3x4>::toString(m), value); |
||||||
|
CORRADE_COMPARE(ConfigurationValue<Matrix3x4>::fromString(value), m); |
||||||
|
} |
||||||
|
|
||||||
|
}}} |
||||||
@ -0,0 +1,44 @@ |
|||||||
|
#ifndef Magnum_Math_Test_RectangularMatrixTest_h |
||||||
|
#define Magnum_Math_Test_RectangularMatrixTest_h |
||||||
|
/*
|
||||||
|
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz> |
||||||
|
|
||||||
|
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 <TestSuite/Tester.h> |
||||||
|
|
||||||
|
namespace Magnum { namespace Math { namespace Test { |
||||||
|
|
||||||
|
class RectangularMatrixTest: public Corrade::TestSuite::Tester<RectangularMatrixTest> { |
||||||
|
public: |
||||||
|
RectangularMatrixTest(); |
||||||
|
|
||||||
|
void construct(); |
||||||
|
void constructFromVectors(); |
||||||
|
void constructZero(); |
||||||
|
void data(); |
||||||
|
|
||||||
|
void negative(); |
||||||
|
void addSubtract(); |
||||||
|
void multiplyDivide(); |
||||||
|
void multiply(); |
||||||
|
|
||||||
|
void transposed(); |
||||||
|
|
||||||
|
void debug(); |
||||||
|
void configuration(); |
||||||
|
}; |
||||||
|
|
||||||
|
}}} |
||||||
|
|
||||||
|
#endif |
||||||
Loading…
Reference in new issue