Browse Source

Math: matrix/vector rework, part 2: matrix as array of column vectors.

Overall architecture is simplififed with this change and also it's not
needed to use reinterpret_cast in matrix internals anymore, thus there
is no need for operator() and [][] works now always as expected without
any risk of GCC misoptimizations.

On the other side, constructing matrix from list of elements is not
possible anymore. You have to specify the elements as list of
column vectors, which might be less convenient to write, but it helps to
distinguish what is column and what is row:

    Matrix<2, int> a(1, 2,                   // before
                     3, 4);

    Matrix<2, int> a(Vector<2, int>(1, 2),   // now
                     Vector<2, int>(3, 4));

For some matrix specializations (i.e. Matrix3 and Matrix4) it is
possible to use list-initialization instead of explicit type
specification:

    Matrix<3, int>({1, 2, 3},
                   {4, 5, 6},
                   {7, 8, 9});

I didn't yet figure out how to properly implement the general
(constexpr) constructor to also take lists, so it's a bit ugly for now.

Matrix operations are now done column-wise, which should help with
future SIMD implementations, documentation is also updated accordingly.
I also removed forgotten remains of matrix/matrix operator*=(), which
can be confusing, as the multiplication is not commutative. Why it is
not present is explained in d9c900f076.
pull/7/head
Vladimír Vondruš 13 years ago
parent
commit
baeadc9663
  1. 49
      doc/matrix-vector.dox
  2. 7
      src/Color.h
  3. 10
      src/Math/Algorithms/GaussJordan.h
  4. 27
      src/Math/Algorithms/Test/GaussJordanTest.cpp
  5. 14
      src/Math/Algorithms/Test/GramSchmidtTest.cpp
  6. 8
      src/Math/Geometry/Distance.h
  7. 58
      src/Math/Matrix.h
  8. 60
      src/Math/Matrix3.h
  9. 132
      src/Math/Matrix4.h
  10. 3
      src/Math/Point2D.h
  11. 3
      src/Math/Point3D.h
  12. 14
      src/Math/Quaternion.h
  13. 30
      src/Math/RectangularMatrix.cpp
  14. 254
      src/Math/RectangularMatrix.h
  15. 120
      src/Math/Test/Matrix3Test.cpp
  16. 198
      src/Math/Test/Matrix4Test.cpp
  17. 125
      src/Math/Test/MatrixTest.cpp
  18. 178
      src/Math/Test/RectangularMatrixTest.cpp
  19. 22
      src/Math/Vector.cpp
  20. 407
      src/Math/Vector.h
  21. 3
      src/Math/Vector2.h
  22. 3
      src/Math/Vector3.h
  23. 3
      src/Math/Vector4.h
  24. 2
      src/Mesh.h
  25. 32
      src/SceneGraph/Test/CameraTest.cpp

49
doc/matrix-vector.dox

@ -14,9 +14,9 @@ easier.
%Magnum has three main matrix and vector classes: RectangularMatrix, (square)
Matrix and Vector. To achieve greatest code reuse, %Matrix is internally
square %RectangularMatrix and %Vector is internally one-column
%RectangularMatrix. Both vectors and matrices can have arbitrary size (known
at compile time) and can store any meaningful type.
square %RectangularMatrix and %RectangularMatrix is internally array of one or
more %Vector instances. Both vectors and matrices can have arbitrary size
(known at compile time) and can store any arithmetic type.
Each subclass brings some specialization to its superclass and for most common
vector and matrix sizes there are specialized classes Matrix3 and Matrix4,
@ -50,14 +50,15 @@ Color4<float> black1; // {0.0f, 0.0f, 0.0f, 1.0f}
Color4<unsigned char> black2; // {0, 0, 0, 255}
@endcode
Most common and most efficient way to create matrix or vector is to pass
values of all components to the constructor.
Most common and most efficient way to create vector is to pass all values to
constructor, matrix is created by passing all column vectors to the
constructor.
@code
Matrix3<int> mat(0, 1, 2,
3, 4, 5,
6, 7, 8); // column-major (see explanation why below)
Vector3<int> vec(0, 1, 2);
Matrix3<int> mat({0, 1, 2},
{3, 4, 5},
{6, 7, 8});
@endcode
All constructors check number of passed arguments and the errors are catched
at compile time.
@ -83,8 +84,8 @@ same row count; vectors from vector and scalar:
@code
RectangularMatrix<2, 3, int> a;
Vector3<int> b, c;
Matrix3<int> mat = Matrix3<int>::from(b, a, c);
Vector<8, int> vec = Vector<8, int>::from(1, b, 2, c);
Matrix3<int> mat(a, b);
Vector<8, int> vec(1, b, 2, c);
@endcode
It is also possible to create them from an C-style array. The function does
@ -113,14 +114,10 @@ directly:
RectangularMatrix<3, 2, int> a;
a[2] /= 2; // third column (column major indexing, see explanation below)
a[0][1] = 5; // first column, second element
a(0, 1) += 3; // first column, second element (preferred)
Vector<3, int> b;
b[1] = 1; // second element
@endcode
For accessing matrix element prefer round bracket operator, as it is possibly
faster than the double square brackets (but never slower) and isn't prone to
compiler mis-optimizations.
Fixed-size vector subclasses have functions for accessing named components
and subparts:
@ -152,23 +149,19 @@ implications and it may differ from what is common in mathematics:
@code
RectangularMatrix<2, 3, int> mat; // two columns, three rows
@endcode
- Order of components in matrix constructors is also column-major, so the
elements passed in constructor doesn't need to be reordered internally
before putting them into data array:
- Order of components in matrix constructors is also column-major, further
emphasized by requirement that you have to pass directly column vectors:
@code
Matrix3<int> mat(0, 1, 2,
3, 4, 5,
6, 7, 8); // first column is {0, 1, 2}
Matrix3<int> mat({0, 1, 2},
{3, 4, 5},
{6, 7, 8}); // first column is {0, 1, 2}
@endcode
- Element accessing order is also column-major. It costs virtually no time to
return reference to portion of data array as column vector, thus the bracket
operator is accessing columns. Returned vector has also its own bracket
operator, which is indexing rows. To avoid confusion, first parameter of
round bracket operator is thus also column index.
- Element accessing order is also column-major, thus the bracket operator is
accessing columns. Returned vector has also its own bracket operator, which
is then indexing rows.
@code
mat[0] *= 2; // first column
mat[2][0] = 5; // first element of first column vector
mat(2, 0) += 3; // first element of first column
mat[2][0] = 5; // first element of first column
@endcode
- Various algorithms which commonly operate on matrix rows (such as
@ref Algorithms::GaussJordan "Gauss-Jordan elimination") have faster

7
src/Color.h

@ -22,7 +22,6 @@
#include <tuple>
#include "Math/Functions.h"
#include "Math/MathTypeTraits.h"
#include "Math/Vector4.h"
#include "Magnum.h"
@ -197,7 +196,7 @@ class Color3: public Math::Vector3<T> {
inline constexpr /*implicit*/ Color3(T r, T g, T b): Math::Vector3<T>(r, g, b) {}
/** @brief Copy constructor */
inline constexpr Color3(const Math::RectangularMatrix<1, 3, T>& other): Math::Vector3<T>(other) {}
inline constexpr Color3(const Math::Vector<3, T>& other): Math::Vector3<T>(other) {}
inline T& r() { return Math::Vector3<T>::x(); } /**< @brief R component */
inline constexpr T r() const { return Math::Vector3<T>::x(); } /**< @overload */
@ -252,7 +251,6 @@ class Color3: public Math::Vector3<T> {
}
MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(Color3, 3)
MAGNUM_RECTANGULARMATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(1, 3, Color3<T>)
};
MAGNUM_VECTOR_SUBCLASS_OPERATOR_IMPLEMENTATION(Color3, 3)
@ -325,7 +323,7 @@ class Color4: public Math::Vector4<T> {
inline constexpr /*implicit*/ Color4(const Math::Vector3<T>& rgb, T a = Implementation::defaultAlpha<T>()): Math::Vector4<T>(rgb[0], rgb[1], rgb[2], a) {}
/** @brief Copy constructor */
inline constexpr Color4(const Math::RectangularMatrix<1, 4, T>& other): Math::Vector4<T>(other) {}
inline constexpr Color4(const Math::Vector<4, T>& other): Math::Vector4<T>(other) {}
inline T& r() { return Math::Vector4<T>::x(); } /**< @brief R component */
inline constexpr T r() const { return Math::Vector4<T>::x(); } /**< @overload */
@ -366,7 +364,6 @@ class Color4: public Math::Vector4<T> {
}
MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(Color4, 4)
MAGNUM_RECTANGULARMATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(1, 4, Color4<T>)
};
MAGNUM_VECTOR_SUBCLASS_OPERATOR_IMPLEMENTATION(Color4, 4)

10
src/Math/Algorithms/GaussJordan.h

@ -76,7 +76,7 @@ template<std::size_t size, std::size_t cols, class T> bool GaussJordan::inPlaceT
/* Find max pivot */
std::size_t rowMax = row;
for(std::size_t row2 = row+1; row2 != size; ++row2)
if(std::abs(a(row2, row)) > std::abs(a(rowMax, row)))
if(std::abs(a[row2][row]) > std::abs(a[rowMax][row]))
rowMax = row2;
/* Swap the rows */
@ -84,12 +84,12 @@ template<std::size_t size, std::size_t cols, class T> bool GaussJordan::inPlaceT
std::swap(t[row], t[rowMax]);
/* Singular */
if(MathTypeTraits<T>::equals(a(row, row), 0))
if(MathTypeTraits<T>::equals(a[row][row], T(0)))
return false;
/* Eliminate column */
for(std::size_t row2 = row+1; row2 != size; ++row2) {
T c = a(row2, row)/a(row, row);
T c = a[row2][row]/a[row][row];
a[row2] -= a[row]*c;
t[row2] -= t[row]*c;
@ -98,10 +98,10 @@ template<std::size_t size, std::size_t cols, class T> bool GaussJordan::inPlaceT
/* Backsubstitute */
for(std::size_t row = size; row != 0; --row) {
T c = T(1)/a(row-1, row-1);
T c = T(1)/a[row-1][row-1];
for(std::size_t row2 = 0; row2 != row-1; ++row2)
t[row2] -= t[row-1]*a(row2, row-1)*c;
t[row2] -= t[row-1]*a[row2][row-1]*c;
/* Normalize the row */
t[row-1] *= c;

27
src/Math/Algorithms/Test/GaussJordanTest.cpp

@ -29,6 +29,7 @@ class GaussJordanTest: public Corrade::TestSuite::Tester {
};
typedef Matrix<4, float> Matrix4;
typedef Vector<4, float> Vector4;
GaussJordanTest::GaussJordanTest() {
addTests(&GaussJordanTest::singular,
@ -36,25 +37,25 @@ GaussJordanTest::GaussJordanTest() {
}
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);
Matrix4 a(Vector4(1.0f, 2.0f, 3.0f, 4.0f),
Vector4(2.0f, 3.0f, -7.0f, 11.0f),
Vector4(2.0f, 4.0f, 6.0f, 8.0f),
Vector4(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 a(Vector4(3.0f, 5.0f, 8.0f, 4.0f),
Vector4(4.0f, 4.0f, 7.0f, 3.0f),
Vector4(7.0f, -1.0f, 8.0f, 0.0f),
Vector4(9.0f, 4.0f, 5.0f, 9.0f));
Matrix4 expectedInverse(Vector4(-60/103.0f, 71/103.0f, -4/103.0f, 3/103.0f),
Vector4(-66/103.0f, 109/103.0f, -25/103.0f, -7/103.0f),
Vector4(177/412.0f, -97/206.0f, 53/412.0f, -7/206.0f),
Vector4(259/412.0f, -185/206.0f, 31/412.0f, 27/206.0f));
Matrix4 a2(a);
Matrix4 inverse(Matrix4::Identity);

14
src/Math/Algorithms/Test/GramSchmidtTest.cpp

@ -34,11 +34,9 @@ GramSchmidtTest::GramSchmidtTest() {
}
void GramSchmidtTest::test() {
Matrix3 m(
3.0f, 5.0f, 8.0f,
4.0f, 4.0f, 7.0f,
7.0f, -1.0f, 8.0f
);
Matrix3 m(Vector3(3.0f, 5.0f, 8.0f),
Vector3(4.0f, 4.0f, 7.0f),
Vector3(7.0f, -1.0f, 8.0f));
Matrix3 normalized = Algorithms::gramSchmidt(m);
@ -56,9 +54,9 @@ void GramSchmidtTest::test() {
CORRADE_COMPARE(Vector3::dot(normalized[1], normalized[2]), 0.0f);
/* Just to be sure */
Matrix3 expected( 0.303046f, 0.505076f, 0.808122f,
0.928316f, -0.348119f, -0.130544f,
-0.215388f, -0.789754f, 0.574367f);
Matrix3 expected(Vector3( 0.303046f, 0.505076f, 0.808122f),
Vector3( 0.928316f, -0.348119f, -0.130544f),
Vector3(-0.215388f, -0.789754f, 0.574367f));
CORRADE_COMPARE(normalized, expected);
}

8
src/Math/Geometry/Distance.h

@ -44,7 +44,7 @@ class Distance {
* @see linePointSquared(const Vector2&, const Vector2&, const Vector2&)
*/
template<class T> inline static T linePoint(const Vector2<T>& a, const Vector2<T>& b, const Vector2<T>& point) {
return std::abs(Matrix<2, T>::from(b - a, a - point).determinant())/(b - a).length();
return std::abs(Matrix<2, T>(b - a, a - point).determinant())/(b - a).length();
}
/**
@ -59,7 +59,7 @@ class Distance {
*/
template<class T> inline static T linePointSquared(const Vector2<T>& a, const Vector2<T>& b, const Vector2<T>& point) {
Vector2<T> bMinusA = b - a;
return Math::pow<2>(Matrix<2, T>::from(bMinusA, a - point).determinant())/bMinusA.dot();
return Math::pow<2>(Matrix<2, T>(bMinusA, a - point).determinant())/bMinusA.dot();
}
/**
@ -134,7 +134,7 @@ class Distance {
return std::sqrt(pointDistanceB);
/* Between A and B */
return std::abs(Matrix<2, T>::from(bMinusA, -pointMinusA).determinant())/std::sqrt(bDistanceA);
return std::abs(Matrix<2, T>(bMinusA, -pointMinusA).determinant())/std::sqrt(bDistanceA);
}
/**
@ -160,7 +160,7 @@ class Distance {
return pointDistanceB;
/* Between A and B */
return Math::pow<2>(Matrix<2, T>::from(bMinusA, -pointMinusA).determinant())/bDistanceA;
return Math::pow<2>(Matrix<2, T>(bMinusA, -pointMinusA).determinant())/bDistanceA;
}
/**

58
src/Math/Matrix.h

@ -64,27 +64,19 @@ template<std::size_t size, class T> class Matrix: public RectangularMatrix<size,
*/
inline /*implicit*/ Matrix(IdentityType = Identity, T value = T(1)) {
for(std::size_t i = 0; i != size; ++i)
(*this)(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 Make this copydoc when Doxygen is fixed
* @brief %Matrix from column vectors
* @param first First column vector
* @param next Next column vectors
*/
template<class ...U> inline constexpr /*implicit*/ Matrix(T first, U... next): RectangularMatrix<size, size, T>(first, next...) {}
template<class ...U> inline constexpr /*implicit*/ Matrix(const Vector<size, T>& first, const U&... next): RectangularMatrix<size, size, T>(first, next...) {}
/** @brief Copy constructor */
inline constexpr Matrix(const RectangularMatrix<size, size, T>& other): RectangularMatrix<size, size, T>(other) {}
/** @brief Multiply and assign matrix operator */
inline Matrix<size, T>& operator*=(const RectangularMatrix<size, size, T>& other) {
return (*this = *this*other);
}
/**
* @brief Trace of the matrix
*
@ -96,7 +88,7 @@ template<std::size_t size, class T> class Matrix: public RectangularMatrix<size,
T out(0);
for(std::size_t i = 0; i != size; ++i)
out += (*this)(i, i);
out += (*this)[i][i];
return out;
}
@ -107,8 +99,8 @@ template<std::size_t size, class T> class Matrix: public RectangularMatrix<size,
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));
out[col][row] = (*this)[col + (col >= skipCol)]
[row + (row >= skipRow)];
return out;
}
@ -143,7 +135,7 @@ template<std::size_t size, class T> class Matrix: public RectangularMatrix<size,
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;
out[col][row] = (((row+col) & 1) ? -1 : 1)*ij(row, col).determinant()/_determinant;
return out;
}
@ -160,7 +152,6 @@ template<std::size_t size, class T> class Matrix: public RectangularMatrix<size,
return RectangularMatrix<size, size, T>::operator*(other);
}
MAGNUM_RECTANGULARMATRIX_SUBCLASS_IMPLEMENTATION(size, size, Matrix<size, T>)
MAGNUM_RECTANGULARMATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(size, size, Matrix<size, T>)
#endif
};
@ -171,6 +162,9 @@ template<std::size_t size, class T, class U> inline typename std::enable_if<std:
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} */
@ -180,21 +174,6 @@ template<std::size_t size, class T> inline Corrade::Utility::Debug operator<<(Co
#ifndef DOXYGEN_GENERATING_OUTPUT
#define MAGNUM_MATRIX_SUBCLASS_IMPLEMENTATION(Type, VectorType, size) \
inline constexpr static Type<T>& from(T* data) { \
return *reinterpret_cast<Type<T>*>(data); \
} \
inline constexpr static const Type<T>& from(const T* data) { \
return *reinterpret_cast<const Type<T>*>(data); \
} \
template<class ...U> inline constexpr static Type<T> from(const Vector<size, T>& first, const U&... next) { \
return Matrix<size, T>::from(first, next...); \
} \
\
inline Type<T>& operator=(const Type<T>& other) { \
Matrix<size, T>::operator=(other); \
return *this; \
} \
\
inline VectorType<T>& operator[](std::size_t col) { \
return VectorType<T>::from(Matrix<size, T>::data()+col*size); \
} \
@ -205,10 +184,6 @@ template<std::size_t size, class T> inline Corrade::Utility::Debug operator<<(Co
inline Type<T> operator*(const Matrix<size, T>& other) const { \
return Matrix<size, T>::operator*(other); \
} \
inline Type<T>& operator*=(const Matrix<size, T>& other) { \
Matrix<size, T>::operator*=(other); \
return *this; \
} \
template<std::size_t otherCols> inline RectangularMatrix<otherCols, size, T> operator*(const RectangularMatrix<otherCols, size, T>& other) const { \
return Matrix<size, T>::operator*(other); \
} \
@ -225,6 +200,9 @@ template<std::size_t size, class T> inline Corrade::Utility::Debug operator<<(Co
} \
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 {
@ -235,7 +213,7 @@ template<std::size_t size, class T> class MatrixDeterminant {
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();
out += ((col & 1) ? -1 : 1)*m[col][0]*m.ij(col, 0).determinant();
return out;
}
@ -244,14 +222,14 @@ template<std::size_t size, class T> class MatrixDeterminant {
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);
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);
return m[0][0];
}
};

60
src/Math/Matrix3.h

@ -43,11 +43,9 @@ template<class T> class Matrix3: public Matrix<3, T> {
* Vector2::xAxis(), Vector2::yAxis()
*/
inline constexpr static Matrix3<T> translation(const Vector2<T>& vector) {
return Matrix3<T>( /* Column-major! */
T(1), T(0), T(0),
T(0), T(1), T(0),
vector.x(), vector.y(), T(1)
);
return {{ T(1), T(0), T(0)},
{ T(0), T(1), T(0)},
{vector.x(), vector.y(), T(1)}};
}
/**
@ -58,11 +56,9 @@ template<class T> class Matrix3: public Matrix<3, T> {
* Vector2::xScale(), Vector2::yScale()
*/
inline constexpr static Matrix3<T> scaling(const Vector2<T>& vector) {
return Matrix3<T>( /* Column-major! */
vector.x(), T(0), T(0),
T(0), vector.y(), T(0),
T(0), T(0), T(1)
);
return {{vector.x(), T(0), T(0)},
{ T(0), vector.y(), T(0)},
{ T(0), T(0), T(1)}};
}
/**
@ -76,11 +72,9 @@ template<class T> class Matrix3: public Matrix<3, T> {
T sine = std::sin(angle);
T cosine = std::cos(angle);
return Matrix3<T>( /* Column-major! */
cosine, sine, T(0),
-sine, cosine, T(0),
T(0), T(0), T(1)
);
return {{ cosine, sine, T(0)},
{ -sine, cosine, T(0)},
{ T(0), T(0), T(1)}};
}
/**
@ -93,7 +87,7 @@ template<class T> class Matrix3: public Matrix<3, T> {
static Matrix3<T> reflection(const Vector2<T>& normal) {
CORRADE_ASSERT(MathTypeTraits<T>::equals(normal.dot(), T(1)),
"Math::Matrix3::reflection(): normal must be normalized", {});
return from(Matrix<2, T>() - T(2)*normal*normal.transposed(), {});
return from(Matrix<2, T>() - T(2)*normal*RectangularMatrix<1, 2, T>(normal).transposed(), {});
}
/**
@ -116,11 +110,9 @@ template<class T> class Matrix3: public Matrix<3, T> {
* @see rotationScaling() const, translation() const
*/
static Matrix3<T> from(const Matrix<2, T>& rotationScaling, const Vector2<T>& translation) {
return from(
Vector3<T>(rotationScaling[0], T(0)),
Vector3<T>(rotationScaling[1], T(0)),
Vector3<T>(translation, T(1))
);
return {{rotationScaling[0], T(0)},
{rotationScaling[1], T(0)},
{ translation, T(1)}};
}
/** @copydoc Matrix::Matrix(ZeroType) */
@ -128,13 +120,13 @@ template<class T> class Matrix3: public Matrix<3, T> {
/** @copydoc Matrix::Matrix(IdentityType, T) */
inline constexpr /*implicit*/ Matrix3(typename Matrix<3, T>::IdentityType = (Matrix<3, T>::Identity), T value = T(1)): Matrix<3, T>(
value, T(0), T(0),
T(0), value, T(0),
T(0), T(0), value
Vector<3, T>(value, T(0), T(0)),
Vector<3, T>( T(0), value, T(0)),
Vector<3, T>( T(0), T(0), value)
) {}
/** @copydoc Matrix::Matrix */
template<class ...U> inline constexpr /*implicit*/ Matrix3(T first, U... next): Matrix<3, T>(first, next...) {}
/** @brief %Matrix from column vectors */
inline constexpr /*implicit*/ Matrix3(const Vector3<T>& first, const Vector3<T>& second, const Vector3<T>& third): Matrix<3, T>(first, second, third) {}
/** @brief Copy constructor */
inline constexpr Matrix3(const RectangularMatrix<3, 3, T>& other): Matrix<3, T>(other) {}
@ -147,9 +139,8 @@ template<class T> class Matrix3: public Matrix<3, T> {
* rotation(T), Matrix4::rotationScaling() const
*/
inline Matrix<2, T> rotationScaling() const {
return Matrix<2, T>::from(
(*this)[0].xy(),
(*this)[1].xy());
return {(*this)[0].xy(),
(*this)[1].xy()};
}
/**
@ -159,9 +150,8 @@ template<class T> class Matrix3: public Matrix<3, T> {
* @see rotationScaling() const, rotation(T), Matrix4::rotation() const
*/
inline Matrix<2, T> rotation() const {
return Matrix<2, T>::from(
(*this)[0].xy().normalized(),
(*this)[1].xy().normalized());
return {(*this)[0].xy().normalized(),
(*this)[1].xy().normalized()};
}
/**
@ -202,7 +192,7 @@ template<class T> class Matrix3: public Matrix<3, T> {
* @see rotationScaling() const, translation() const
*/
inline Matrix3<T> invertedEuclidean() const {
CORRADE_ASSERT((*this)(0, 2) == T(0) && (*this)(1, 2) == T(0) && (*this)(2, 2) == T(1),
CORRADE_ASSERT((*this)[0][2] == T(0) && (*this)[1][2] == T(0) && (*this)[2][2] == T(1),
"Math::Matrix3::invertedEuclidean(): unexpected values on last row", {});
Matrix<2, T> inverseRotation = rotationScaling().transposed();
CORRADE_ASSERT((inverseRotation*rotationScaling() == Matrix<2, T>()),
@ -216,10 +206,12 @@ template<class T> class Matrix3: public Matrix<3, T> {
}
#endif
MAGNUM_RECTANGULARMATRIX_SUBCLASS_IMPLEMENTATION(3, 3, Matrix3<T>)
MAGNUM_MATRIX_SUBCLASS_IMPLEMENTATION(Matrix3, Vector3, 3)
MAGNUM_RECTANGULARMATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(3, 3, Matrix3<T>)
};
MAGNUM_MATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(Matrix3, 3)
/** @debugoperator{Magnum::Math::Matrix3} */
template<class T> inline Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Matrix3<T>& value) {
return debug << static_cast<const Matrix<3, T>&>(value);

132
src/Math/Matrix4.h

@ -43,12 +43,10 @@ template<class T> class Matrix4: public Matrix<4, T> {
* Vector3::xAxis(), Vector3::yAxis(), Vector3::zAxis()
*/
inline constexpr static Matrix4<T> translation(const Vector3<T>& vector) {
return Matrix4<T>( /* Column-major! */
T(1), T(0), T(0), T(0),
T(0), T(1), T(0), T(0),
T(0), T(0), T(1), T(0),
vector.x(), vector.y(), vector.z(), T(1)
);
return {{ T(1), T(0), T(0), T(0)},
{ T(0), T(1), T(0), T(0)},
{ T(0), T(0), T(1), T(0)},
{vector.x(), vector.y(), vector.z(), T(1)}};
}
/**
@ -59,12 +57,10 @@ template<class T> class Matrix4: public Matrix<4, T> {
* Vector3::xScale(), Vector3::yScale(), Vector3::zScale()
*/
inline constexpr static Matrix4<T> scaling(const Vector3<T>& vector) {
return Matrix4<T>( /* Column-major! */
vector.x(), T(0), T(0), T(0),
T(0), vector.y(), T(0), T(0),
T(0), T(0), vector.z(), T(0),
T(0), T(0), T(0), T(1)
);
return {{vector.x(), T(0), T(0), T(0)},
{ T(0), vector.y(), T(0), T(0)},
{ T(0), T(0), vector.z(), T(0)},
{ T(0), T(0), T(0), T(1)}};
}
/**
@ -92,21 +88,21 @@ template<class T> class Matrix4: public Matrix<4, T> {
T yz = normalizedAxis.y()*normalizedAxis.z();
T zz = normalizedAxis.z()*normalizedAxis.z();
return Matrix4<T>( /* Column-major! */
cosine + xx*oneMinusCosine,
return {
{cosine + xx*oneMinusCosine,
xy*oneMinusCosine + normalizedAxis.z()*sine,
xz*oneMinusCosine - normalizedAxis.y()*sine,
T(0),
xy*oneMinusCosine - normalizedAxis.z()*sine,
T(0)},
{xy*oneMinusCosine - normalizedAxis.z()*sine,
cosine + yy*oneMinusCosine,
yz*oneMinusCosine + normalizedAxis.x()*sine,
T(0),
xz*oneMinusCosine + normalizedAxis.y()*sine,
T(0)},
{xz*oneMinusCosine + normalizedAxis.y()*sine,
yz*oneMinusCosine - normalizedAxis.x()*sine,
cosine + zz*oneMinusCosine,
T(0),
T(0), T(0), T(0), T(1)
);
T(0)},
{T(0), T(0), T(0), T(1)}
};
}
/**
@ -121,12 +117,10 @@ template<class T> class Matrix4: public Matrix<4, T> {
T sine = std::sin(angle);
T cosine = std::cos(angle);
return Matrix4<T>( /* Column-major! */
T(1), T(0), T(0), T(0),
T(0), cosine, sine, T(0),
T(0), -sine, cosine, T(0),
T(0), T(0), T(0), T(1)
);
return {{T(1), T(0), T(0), T(0)},
{T(0), cosine, sine, T(0)},
{T(0), -sine, cosine, T(0)},
{T(0), T(0), T(0), T(1)}};
}
/**
@ -141,12 +135,10 @@ template<class T> class Matrix4: public Matrix<4, T> {
T sine = std::sin(angle);
T cosine = std::cos(angle);
return Matrix4<T>( /* Column-major! */
cosine, T(0), -sine, T(0),
T(0), T(1), T(0), T(0),
sine, T(0), cosine, T(0),
T(0), T(0), T(0), T(1)
);
return {{cosine, T(0), -sine, T(0)},
{ T(0), T(1), T(0), T(0)},
{ sine, T(0), cosine, T(0)},
{ T(0), T(0), T(0), T(1)}};
}
/**
@ -161,12 +153,10 @@ template<class T> class Matrix4: public Matrix<4, T> {
T sine = std::sin(angle);
T cosine = std::cos(angle);
return Matrix4<T>( /* Column-major! */
cosine, sine, T(0), T(0),
-sine, cosine, T(0), T(0),
T(0), T(0), T(1), T(0),
T(0), T(0), T(0), T(1)
);
return {{cosine, sine, T(0), T(0)},
{ -sine, cosine, T(0), T(0)},
{ T(0), T(0), T(1), T(0)},
{ T(0), T(0), T(0), T(1)}};
}
/**
@ -179,7 +169,7 @@ template<class T> class Matrix4: public Matrix<4, T> {
static Matrix4<T> reflection(const Vector3<T>& normal) {
CORRADE_ASSERT(MathTypeTraits<T>::equals(normal.dot(), T(1)),
"Math::Matrix4::reflection(): normal must be normalized", {});
return from(Matrix<3, T>() - T(2)*normal*normal.transposed(), {});
return from(Matrix<3, T>() - T(2)*normal*RectangularMatrix<1, 3, T>(normal).transposed(), {});
}
/**
@ -194,12 +184,10 @@ template<class T> class Matrix4: public Matrix<4, T> {
Vector2<T> xyScale = T(2.0)/size;
T zScale = T(2.0)/(near-far);
return Matrix4<T>( /* Column-major! */
xyScale.x(), T(0.0), T(0.0), T(0.0),
T(0.0), xyScale.y(), T(0.0), T(0.0),
T(0.0), T(0.0), zScale, T(0.0),
T(0.0), T(0.0), near*zScale-1, T(1.0)
);
return {{xyScale.x(), T(0), T(0), T(0)},
{ T(0), xyScale.y(), T(0), T(0)},
{ T(0), T(0), zScale, T(0)},
{ T(0), T(0), near*zScale-T(1), T(1)}};
}
/**
@ -214,12 +202,10 @@ template<class T> class Matrix4: public Matrix<4, T> {
Vector2<T> xyScale = 2*near/size;
T zScale = T(1.0)/(near-far);
return Matrix4<T>( /* Column-major! */
xyScale.x(), T(0.0), T(0.0), T(0.0),
T(0.0), xyScale.y(), T(0.0), T(0.0),
T(0.0), T(0.0), (far+near)*zScale, T(-1.0),
T(0.0), T(0.0), (2*far*near)*zScale, T(0.0)
);
return {{xyScale.x(), T(0), T(0), T(0)},
{ T(0), xyScale.y(), T(0), T(0)},
{ T(0), T(0), (far+near)*zScale, T(-1)},
{ T(0), T(0), T(2)*far*near*zScale, T(0)}};
}
/**
@ -247,12 +233,10 @@ template<class T> class Matrix4: public Matrix<4, T> {
* @see rotationScaling() const, translation() const
*/
static Matrix4<T> from(const Matrix<3, T>& rotationScaling, const Vector3<T>& translation) {
return from(
Vector4<T>(rotationScaling[0], T(0)),
Vector4<T>(rotationScaling[1], T(0)),
Vector4<T>(rotationScaling[2], T(0)),
Vector4<T>(translation, T(1))
);
return {{rotationScaling[0], T(0)},
{rotationScaling[1], T(0)},
{rotationScaling[2], T(0)},
{ translation, T(1)}};
}
/** @copydoc Matrix::Matrix(ZeroType) */
@ -260,14 +244,14 @@ template<class T> class Matrix4: public Matrix<4, T> {
/** @copydoc Matrix::Matrix(IdentityType, T) */
inline constexpr /*implicit*/ Matrix4(typename Matrix<4, T>::IdentityType = (Matrix<4, T>::Identity), T value = T(1)): Matrix<4, T>(
value, T(0), T(0), T(0),
T(0), value, T(0), T(0),
T(0), T(0), value, T(0),
T(0), T(0), T(0), value
Vector<4, T>(value, T(0), T(0), T(0)),
Vector<4, T>( T(0), value, T(0), T(0)),
Vector<4, T>( T(0), T(0), value, T(0)),
Vector<4, T>( T(0), T(0), T(0), value)
) {}
/** @copydoc Matrix::Matrix */
template<class ...U> inline constexpr /*implicit*/ Matrix4(T first, U... next): Matrix<4, T>(first, next...) {}
/** @brief %Matrix from column vectors */
inline constexpr /*implicit*/ Matrix4(const Vector4<T>& first, const Vector4<T>& second, const Vector4<T>& third, const Vector4<T>& fourth): Matrix<4, T>(first, second, third, fourth) {}
/** @brief Copy constructor */
inline constexpr Matrix4(const RectangularMatrix<4, 4, T>& other): Matrix<4, T>(other) {}
@ -281,10 +265,9 @@ template<class T> class Matrix4: public Matrix<4, T> {
*/
inline Matrix<3, T> rotationScaling() const {
/* Not Matrix3, because it is for affine 2D transformations */
return Matrix<3, T>::from(
(*this)[0].xyz(),
(*this)[1].xyz(),
(*this)[2].xyz());
return {(*this)[0].xyz(),
(*this)[1].xyz(),
(*this)[2].xyz()};
}
/**
@ -296,10 +279,9 @@ template<class T> class Matrix4: public Matrix<4, T> {
*/
inline Matrix<3, T> rotation() const {
/* Not Matrix3, because it is for affine 2D transformations */
return Matrix<3, T>::from(
(*this)[0].xyz().normalized(),
(*this)[1].xyz().normalized(),
(*this)[2].xyz().normalized());
return {(*this)[0].xyz().normalized(),
(*this)[1].xyz().normalized(),
(*this)[2].xyz().normalized()};
}
/**
@ -349,7 +331,7 @@ template<class T> class Matrix4: public Matrix<4, T> {
* @see rotationScaling() const, translation() const
*/
inline Matrix4<T> invertedEuclidean() const {
CORRADE_ASSERT((*this)(0, 3) == T(0) && (*this)(1, 3) == T(0) && (*this)(2, 3) == T(0) && (*this)(3, 3) == T(1),
CORRADE_ASSERT((*this)[0][3] == T(0) && (*this)[1][3] == T(0) && (*this)[2][3] == T(0) && (*this)[3][3] == T(1),
"Math::Matrix4::invertedEuclidean(): unexpected values on last row", {});
Matrix<3, T> inverseRotation = rotationScaling().transposed();
CORRADE_ASSERT((inverseRotation*rotationScaling() == Matrix<3, T>()),
@ -363,10 +345,12 @@ template<class T> class Matrix4: public Matrix<4, T> {
}
#endif
MAGNUM_RECTANGULARMATRIX_SUBCLASS_IMPLEMENTATION(4, 4, Matrix4<T>)
MAGNUM_MATRIX_SUBCLASS_IMPLEMENTATION(Matrix4, Vector4, 4)
MAGNUM_RECTANGULARMATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(4, 4, Matrix4<T>)
};
MAGNUM_MATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(Matrix4, 4)
/** @debugoperator{Magnum::Math::Matrix4} */
template<class T> inline Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Matrix4<T>& value) {
return debug << static_cast<const Matrix<4, T>&>(value);

3
src/Math/Point2D.h

@ -57,7 +57,7 @@ template<class T> class Point2D: public Vector3<T> {
inline constexpr /*implicit*/ Point2D(const Vector2<T>& xy, T z = T(1)): Vector3<T>(xy, z) {}
/** @brief Copy constructor */
inline constexpr Point2D(const RectangularMatrix<1, 3, T>& other): Vector3<T>(other) {}
inline constexpr Point2D(const Vector<3, T>& other): Vector3<T>(other) {}
/**
* @brief Vector part of the point
@ -69,7 +69,6 @@ template<class T> class Point2D: public Vector3<T> {
inline constexpr Vector2<T> vector() const { return Vector3<T>::xy(); } /**< @overload */
MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(Point2D, 3)
MAGNUM_RECTANGULARMATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(1, 3, Point2D<T>)
};
MAGNUM_VECTOR_SUBCLASS_OPERATOR_IMPLEMENTATION(Point2D, 3)

3
src/Math/Point3D.h

@ -58,7 +58,7 @@ template<class T> class Point3D: public Vector4<T> {
inline constexpr /*implicit*/ Point3D(const Vector3<T>& xyz, T w = T(1)): Vector4<T>(xyz, w) {}
/** @brief Copy constructor */
inline constexpr Point3D(const RectangularMatrix<1, 4, T>& other): Vector4<T>(other) {}
inline constexpr Point3D(const Vector<4, T>& other): Vector4<T>(other) {}
/**
* @brief Vector part of the point
@ -70,7 +70,6 @@ template<class T> class Point3D: public Vector4<T> {
inline constexpr Vector3<T> vector() const { return Vector4<T>::xyz(); } /**< @overload */
MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(Point3D, 4)
MAGNUM_RECTANGULARMATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(1, 4, Point3D<T>)
};
MAGNUM_VECTOR_SUBCLASS_OPERATOR_IMPLEMENTATION(Point3D, 4)

14
src/Math/Quaternion.h

@ -174,16 +174,16 @@ template<class T> class Quaternion {
* @see Matrix4::from(const Matrix<3, T>&, const Vector3<T>&)
*/
Matrix<3, T> matrix() const {
return { /* Column-major! */
T(1) - 2*pow<2>(_vector.y()) - 2*pow<2>(_vector.z()),
return {
Vector<3, T>(T(1) - 2*pow<2>(_vector.y()) - 2*pow<2>(_vector.z()),
2*_vector.x()*_vector.y() + 2*_vector.z()*_scalar,
2*_vector.x()*_vector.z() - 2*_vector.y()*_scalar,
2*_vector.x()*_vector.y() - 2*_vector.z()*_scalar,
2*_vector.x()*_vector.z() - 2*_vector.y()*_scalar),
Vector<3, T>(2*_vector.x()*_vector.y() - 2*_vector.z()*_scalar,
T(1) - 2*pow<2>(_vector.x()) - 2*pow<2>(_vector.z()),
2*_vector.y()*_vector.z() + 2*_vector.x()*_scalar,
2*_vector.x()*_vector.z() + 2*_vector.y()*_scalar,
2*_vector.y()*_vector.z() + 2*_vector.x()*_scalar),
Vector<3, T>(2*_vector.x()*_vector.z() + 2*_vector.y()*_scalar,
2*_vector.y()*_vector.z() - 2*_vector.x()*_scalar,
T(1) - 2*pow<2>(_vector.x()) - 2*pow<2>(_vector.y())
T(1) - 2*pow<2>(_vector.x()) - 2*pow<2>(_vector.y()))
};
}

30
src/Math/RectangularMatrix.cpp

@ -18,21 +18,6 @@
namespace Magnum { namespace Math {
#ifndef DOXYGEN_GENERATING_OUTPUT
template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Magnum::Math::RectangularMatrix<1, 2, float>&);
template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Magnum::Math::RectangularMatrix<1, 3, float>&);
template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Magnum::Math::RectangularMatrix<1, 4, float>&);
template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Magnum::Math::RectangularMatrix<1, 2, int>&);
template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Magnum::Math::RectangularMatrix<1, 3, int>&);
template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Magnum::Math::RectangularMatrix<1, 4, int>&);
template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Magnum::Math::RectangularMatrix<1, 2, unsigned int>&);
template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Magnum::Math::RectangularMatrix<1, 3, unsigned int>&);
template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Magnum::Math::RectangularMatrix<1, 4, unsigned int>&);
#ifndef MAGNUM_TARGET_GLES
template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Magnum::Math::RectangularMatrix<1, 2, double>&);
template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Magnum::Math::RectangularMatrix<1, 3, double>&);
template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Magnum::Math::RectangularMatrix<1, 4, double>&);
#endif
template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Magnum::Math::RectangularMatrix<2, 2, float>&);
template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Magnum::Math::RectangularMatrix<3, 3, float>&);
template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Magnum::Math::RectangularMatrix<4, 4, float>&);
@ -63,21 +48,6 @@ template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Magnu
namespace Corrade { namespace Utility {
#ifndef DOXYGEN_GENERATING_OUTPUT
template struct ConfigurationValue<Magnum::Math::RectangularMatrix<1, 2, float>>;
template struct ConfigurationValue<Magnum::Math::RectangularMatrix<1, 3, float>>;
template struct ConfigurationValue<Magnum::Math::RectangularMatrix<1, 4, float>>;
template struct ConfigurationValue<Magnum::Math::RectangularMatrix<1, 2, int>>;
template struct ConfigurationValue<Magnum::Math::RectangularMatrix<1, 3, int>>;
template struct ConfigurationValue<Magnum::Math::RectangularMatrix<1, 4, int>>;
template struct ConfigurationValue<Magnum::Math::RectangularMatrix<1, 2, unsigned int>>;
template struct ConfigurationValue<Magnum::Math::RectangularMatrix<1, 3, unsigned int>>;
template struct ConfigurationValue<Magnum::Math::RectangularMatrix<1, 4, unsigned int>>;
#ifndef MAGNUM_TARGET_GLES
template struct ConfigurationValue<Magnum::Math::RectangularMatrix<1, 2, double>>;
template struct ConfigurationValue<Magnum::Math::RectangularMatrix<1, 3, double>>;
template struct ConfigurationValue<Magnum::Math::RectangularMatrix<1, 4, double>>;
#endif
template struct ConfigurationValue<Magnum::Math::RectangularMatrix<2, 2, float>>;
template struct ConfigurationValue<Magnum::Math::RectangularMatrix<3, 3, float>>;
template struct ConfigurationValue<Magnum::Math::RectangularMatrix<4, 4, float>>;

254
src/Math/RectangularMatrix.h

@ -19,48 +19,12 @@
* @brief Class Magnum::Math::RectangularMatrix
*/
#include <cmath>
#include <limits>
#include <Utility/Debug.h>
#include <Utility/ConfigurationValue.h>
#include "MathTypeTraits.h"
#include "magnumVisibility.h"
#include "Math/Vector.h"
namespace Magnum { namespace Math {
/** @todo Properly test all constexpr */
/** @todoc Remove `ifndef` when Doxygen is sane again */
#ifndef DOXYGEN_GENERATING_OUTPUT
template<std::size_t, std::size_t, class> class RectangularMatrix;
#endif
#ifndef DOXYGEN_GENERATING_OUTPUT
namespace Implementation {
template<std::size_t ...> struct Sequence {};
/* E.g. GenerateSequence<3>::Type is Sequence<0, 1, 2> */
template<std::size_t N, std::size_t ...sequence> struct GenerateSequence:
GenerateSequence<N-1, N-1, sequence...> {};
template<std::size_t ...sequence> struct GenerateSequence<0, sequence...> {
typedef Sequence<sequence...> Type;
};
/* Implementation for RectangularMatrix<cols, rows, T>::from(const RectangularMatrix<cols, rows, U>&) */
template<class T, class U, std::size_t c, std::size_t ...sequence> inline constexpr Math::RectangularMatrix<c, sizeof...(sequence)/c, T> rectangularMatrixFrom(Sequence<sequence...>, const Math::RectangularMatrix<c, sizeof...(sequence)/c, U>& matrix) {
return {T(matrix.data()[sequence])...};
}
}
#endif
/** @todoc Remove `ifndef` when Doxygen is sane again */
#ifndef DOXYGEN_GENERATING_OUTPUT
template<std::size_t size, class T> class Vector;
#endif
/**
@brief Rectangular matrix
@tparam cols Column count
@ -75,7 +39,7 @@ math formulas are in reverse order (i.e. @f$ \boldsymbol A_{ji} @f$ instead
of @f$ \boldsymbol A_{ij} @f$).
*/
template<std::size_t cols, std::size_t rows, class T> class RectangularMatrix {
static_assert(cols != 0 && rows != 0, "Matrix cannot have zero elements");
static_assert(cols != 0 && rows != 0, "RectangularMatrix cannot have zero elements");
public:
typedef T Type; /**< @brief Data type */
@ -98,18 +62,6 @@ template<std::size_t cols, std::size_t rows, class T> class RectangularMatrix {
return *reinterpret_cast<const RectangularMatrix<cols, rows, T>*>(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<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 %Matrix from another of different type
*
@ -122,21 +74,21 @@ template<std::size_t cols, std::size_t rows, class T> class RectangularMatrix {
* @endcode
*/
template<class U> inline constexpr static RectangularMatrix<cols, rows, T> from(const RectangularMatrix<cols, rows, U>& other) {
return Implementation::rectangularMatrixFrom<T, U>(typename Implementation::GenerateSequence<cols*rows>::Type(), other);
return from(typename Implementation::GenerateSequence<cols>::Type(), other);
}
/** @brief Zero-filled matrix constructor */
inline constexpr /*implicit*/ RectangularMatrix(): _data() {}
/** @brief Construct zero-filled matrix */
inline constexpr /*implicit*/ RectangularMatrix() {}
/**
* @brief Initializer-list constructor
* @param first First value
* @param next Next values
* @brief Construct matrix from column vectors
* @param first First column vector
* @param next Next column vectors
*
* Note that the values are in column-major order.
* @todo Creating matrix from arbitrary combination of matrices with n rows
*/
template<class ...U> inline constexpr /*implicit*/ RectangularMatrix(T first, U... next): _data{first, next...} {
static_assert(sizeof...(next)+1 == cols*rows, "Improper number of arguments passed to RectangularMatrix constructor");
template<class ...U> inline constexpr /*implicit*/ RectangularMatrix(const Vector<rows, T>& first, const U&... next): _data{first, next...} {
static_assert(sizeof...(next)+1 == cols, "Improper number of arguments passed to RectangularMatrix constructor");
}
/** @brief Copy constructor */
@ -149,47 +101,35 @@ template<std::size_t cols, std::size_t rows, class T> class RectangularMatrix {
* @brief Raw data
* @return One-dimensional array of `size*size` length in column-major
* order.
*
* @see operator[]
*/
inline T* data() { return _data; }
inline constexpr const T* data() const { return _data; } /**< @overload */
inline T* data() { return reinterpret_cast<T*>(_data); }
inline constexpr const T* data() const { return reinterpret_cast<const T*>(_data); } /**< @overload */
/**
* @brief %Matrix column
*
* For accessing individual elements prefer to use operator(), as it
* is guaranteed to not involve unnecessary conversions.
* Particular elements can be accessed using Vector::operator[], e.g.:
* @code
* RectangularMatrix<4, 3, float> m;
* float a = m[2][1];
* @endcode
*
* @see data()
*/
inline Vector<rows, T>& operator[](std::size_t col) {
return Vector<rows, T>::from(_data+col*rows);
return _data[col];
}
/** @overload */
inline constexpr const Vector<rows, T>& operator[](std::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()(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];
return _data[col];
}
/**
* @brief Equality operator
*
* @see Vector::operator<(), Vector::operator<=(), Vector::operator>=(),
* Vector::operator>()
*/
/** @brief Equality comparison */
inline bool operator==(const RectangularMatrix<cols, rows, T>& other) const {
for(std::size_t i = 0; i != cols*rows; ++i)
if(!MathTypeTraits<T>::equals(_data[i], other._data[i])) return false;
for(std::size_t i = 0; i != cols; ++i)
if(_data[i] != other._data[i]) return false;
return true;
}
@ -207,12 +147,12 @@ template<std::size_t cols, std::size_t rows, class T> class RectangularMatrix {
/**
* @brief Add and assign matrix
*
* The computation is done in-place. @f[
* \boldsymbol A_{ji} = \boldsymbol A_{ji} + \boldsymbol B_{ji}
* The computation is done column-wise in-place. @f[
* \boldsymbol A_j = \boldsymbol A_j + \boldsymbol B_j
* @f]
*/
RectangularMatrix<cols, rows, T>& operator+=(const RectangularMatrix<cols, rows, T>& other) {
for(std::size_t i = 0; i != cols*rows; ++i)
for(std::size_t i = 0; i != cols; ++i)
_data[i] += other._data[i];
return *this;
@ -230,14 +170,14 @@ template<std::size_t cols, std::size_t rows, class T> class RectangularMatrix {
/**
* @brief Negated matrix
*
* The computation is done in-place. @f[
* \boldsymbol A_{ji} = -\boldsymbol A_{ji}
* The computation is done column-wise in-place. @f[
* \boldsymbol A_j = -\boldsymbol A_j
* @f]
*/
RectangularMatrix<cols, rows, T> operator-() const {
RectangularMatrix<cols, rows, T> out;
for(std::size_t i = 0; i != cols*rows; ++i)
for(std::size_t i = 0; i != cols; ++i)
out._data[i] = -_data[i];
return out;
@ -246,12 +186,12 @@ template<std::size_t cols, std::size_t rows, class T> class RectangularMatrix {
/**
* @brief Subtract and assign matrix
*
* The computation is done in-place. @f[
* \boldsymbol A_{ji} = \boldsymbol A_{ji} - \boldsymbol B_{ji}
* The computation is done column-wise in-place. @f[
* \boldsymbol A_j = \boldsymbol A_j - \boldsymbol B_j
* @f]
*/
RectangularMatrix<cols, rows, T>& operator-=(const RectangularMatrix<cols, rows, T>& other) {
for(std::size_t i = 0; i != cols*rows; ++i)
for(std::size_t i = 0; i != cols; ++i)
_data[i] -= other._data[i];
return *this;
@ -282,8 +222,8 @@ template<std::size_t cols, std::size_t rows, class T> class RectangularMatrix {
/**
* @brief Multiply matrix with number and assign
*
* The computation is done in-place. @f[
* \boldsymbol A_{ji} = a \boldsymbol A_{ji}
* The computation is done column-wise in-place. @f[
* \boldsymbol A_j = a \boldsymbol A_j
* @f]
*/
#ifndef DOXYGEN_GENERATING_OUTPUT
@ -291,7 +231,7 @@ template<std::size_t cols, std::size_t rows, class T> class RectangularMatrix {
#else
template<class U> RectangularMatrix<cols, rows, T>& operator*=(U number) {
#endif
for(std::size_t i = 0; i != cols*rows; ++i)
for(std::size_t i = 0; i != cols; ++i)
_data[i] *= number;
return *this;
@ -313,8 +253,8 @@ template<std::size_t cols, std::size_t rows, class T> class RectangularMatrix {
/**
* @brief Divide matrix with number and assign
*
* The computation is done in-place. @f[
* \boldsymbol A_{ji} = \frac{\boldsymbol A_{ji}} a
* The computation is done column-wise in-place. @f[
* \boldsymbol A_j = \frac{\boldsymbol A_j} a
* @f]
*/
#ifndef DOXYGEN_GENERATING_OUTPUT
@ -322,7 +262,7 @@ template<std::size_t cols, std::size_t rows, class T> class RectangularMatrix {
#else
template<class U> RectangularMatrix<cols, rows, T>& operator/=(U number) {
#endif
for(std::size_t i = 0; i != cols*rows; ++i)
for(std::size_t i = 0; i != cols; ++i)
_data[i] /= number;
return *this;
@ -341,7 +281,7 @@ template<std::size_t cols, std::size_t rows, class T> class RectangularMatrix {
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);
out[col][row] += (*this)[pos][row]*other[col][pos];
return out;
}
@ -355,7 +295,7 @@ template<std::size_t cols, std::size_t rows, class T> class RectangularMatrix {
* @f]
*/
Vector<rows, T> operator*(const Vector<rows, T>& other) const {
return operator*(static_cast<RectangularMatrix<1, rows, T>>(other));
return operator*(RectangularMatrix<1, rows, T>(other))[0];
}
/** @brief Transposed matrix */
@ -364,23 +304,18 @@ template<std::size_t cols, std::size_t rows, class T> class RectangularMatrix {
for(std::size_t col = 0; col != cols; ++col)
for(std::size_t row = 0; row != rows; ++row)
out(row, col) = (*this)(col, row);
out[row][col] = (*this)[col][row];
return out;
}
#ifndef DOXYGEN_GENERATING_OUTPUT
protected:
T _data[rows*cols];
#endif
private:
template<std::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<std::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...);
/* Implementation for RectangularMatrix<cols, rows, T>::from(const RectangularMatrix<cols, rows, U>&) */
template<class U, std::size_t c, std::size_t ...sequence> inline constexpr static Math::RectangularMatrix<c, sizeof...(sequence), T> from(Implementation::Sequence<sequence...>, const Math::RectangularMatrix<c, sizeof...(sequence), U>& matrix) {
return {Vector<sizeof...(sequence), T>::from(matrix[sequence])...};
}
Vector<rows, T> _data[cols];
};
/** @relates RectangularMatrix
@ -399,8 +334,8 @@ template<std::size_t cols, std::size_t rows, class T, class U> inline typename s
/** @relates RectangularMatrix
@brief Divide matrix with number and invert
@f[
\boldsymbol B_{ji} = \frac a {\boldsymbol A_{ji}}
The computation is done column-wise. @f[
\boldsymbol B_j = \frac a {\boldsymbol A_j}
@f]
@see RectangularMatrix::operator/(U) const
*/
@ -411,12 +346,24 @@ template<std::size_t cols, std::size_t rows, class T, class U> typename std::ena
#endif
RectangularMatrix<cols, rows, T> out;
for(std::size_t i = 0; i != cols*rows; ++i)
out.data()[i] = number/matrix.data()[i];
for(std::size_t i = 0; i != cols; ++i)
out[i] = number/matrix[i];
return out;
}
/** @relates RectangularMatrix
@brief Multiply vector with rectangular matrix
Internally the same as multiplying one-column matrix with one-row matrix. @f[
(\boldsymbol {aA})_{ji} = \boldsymbol a_i \boldsymbol A_j
@f]
@see RectangularMatrix::operator*(const RectangularMatrix<size, cols, T>&) const
*/
template<std::size_t size, std::size_t cols, class T> inline RectangularMatrix<cols, size, T> operator*(const Vector<size, T>& vector, const RectangularMatrix<cols, 1, T>& matrix) {
return RectangularMatrix<1, size, T>(vector)*matrix;
}
/** @debugoperator{Magnum::Math::RectangularMatrix} */
template<std::size_t cols, std::size_t rows, class T> Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Magnum::Math::RectangularMatrix<cols, rows, T>& value) {
debug << "Matrix(";
@ -433,24 +380,8 @@ template<std::size_t cols, std::size_t rows, class T> Corrade::Utility::Debug op
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
/* Explicit instantiation for types used in OpenGL */
/* 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>&);
@ -476,9 +407,7 @@ extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utilit
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); \
@ -486,9 +415,6 @@ extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utilit
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...); \
} \
template<class U> inline constexpr static RectangularMatrix<cols, rows, T> from(const Math::RectangularMatrix<cols, rows, U>& other) { \
return Math::RectangularMatrix<cols, rows, T>::from(other); \
} \
@ -496,39 +422,38 @@ extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utilit
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) 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); \
inline __VA_ARGS__ operator-(const Math::RectangularMatrix<cols, rows, T>& other) const { \
return Math::RectangularMatrix<cols, rows, T>::operator-(other); \
} \
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) 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); \
}
#endif
@ -547,7 +472,7 @@ template<std::size_t cols, std::size_t rows, class T> struct ConfigurationValue<
for(std::size_t row = 0; row != rows; ++row) {
for(std::size_t col = 0; col != cols; ++col) {
if(!output.empty()) output += ' ';
output += ConfigurationValue<T>::toString(value(col, row), flags);
output += ConfigurationValue<T>::toString(value[col][row], flags);
}
}
@ -564,7 +489,7 @@ template<std::size_t cols, std::size_t rows, class T> struct ConfigurationValue<
std::string part = stringValue.substr(oldpos, pos-oldpos);
if(!part.empty()) {
result(i%cols, i/cols) = ConfigurationValue<T>::fromString(part, flags);
result[i%cols][i/cols] = ConfigurationValue<T>::fromString(part, flags);
++i;
}
@ -576,22 +501,6 @@ template<std::size_t cols, std::size_t rows, class T> struct ConfigurationValue<
};
#ifndef DOXYGEN_GENERATING_OUTPUT
/* Vectors */
extern template struct MAGNUM_EXPORT ConfigurationValue<Magnum::Math::RectangularMatrix<1, 2, float>>;
extern template struct MAGNUM_EXPORT ConfigurationValue<Magnum::Math::RectangularMatrix<1, 3, float>>;
extern template struct MAGNUM_EXPORT ConfigurationValue<Magnum::Math::RectangularMatrix<1, 4, float>>;
extern template struct MAGNUM_EXPORT ConfigurationValue<Magnum::Math::RectangularMatrix<1, 2, int>>;
extern template struct MAGNUM_EXPORT ConfigurationValue<Magnum::Math::RectangularMatrix<1, 3, int>>;
extern template struct MAGNUM_EXPORT ConfigurationValue<Magnum::Math::RectangularMatrix<1, 4, int>>;
extern template struct MAGNUM_EXPORT ConfigurationValue<Magnum::Math::RectangularMatrix<1, 2, unsigned int>>;
extern template struct MAGNUM_EXPORT ConfigurationValue<Magnum::Math::RectangularMatrix<1, 3, unsigned int>>;
extern template struct MAGNUM_EXPORT ConfigurationValue<Magnum::Math::RectangularMatrix<1, 4, unsigned int>>;
#ifndef MAGNUM_TARGET_GLES
extern template struct MAGNUM_EXPORT ConfigurationValue<Magnum::Math::RectangularMatrix<1, 2, double>>;
extern template struct MAGNUM_EXPORT ConfigurationValue<Magnum::Math::RectangularMatrix<1, 3, double>>;
extern template struct MAGNUM_EXPORT ConfigurationValue<Magnum::Math::RectangularMatrix<1, 4, double>>;
#endif
/* Square matrices */
extern template struct MAGNUM_EXPORT ConfigurationValue<Magnum::Math::RectangularMatrix<2, 2, float>>;
extern template struct MAGNUM_EXPORT ConfigurationValue<Magnum::Math::RectangularMatrix<3, 3, float>>;
@ -621,7 +530,4 @@ extern template struct MAGNUM_EXPORT ConfigurationValue<Magnum::Math::Rectangula
}}
/* Include also Vector, so the definition is complete */
#include "Vector.h"
#endif

120
src/Math/Test/Matrix3Test.cpp

@ -70,17 +70,13 @@ void Matrix3Test::constructIdentity() {
Matrix3 identity2(Matrix3::Identity);
Matrix3 identity3(Matrix3::Identity, 4.0f);
Matrix3 identityExpected(
1.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 1.0f
);
Matrix3 identity3Expected(
4.0f, 0.0f, 0.0f,
0.0f, 4.0f, 0.0f,
0.0f, 0.0f, 4.0f
);
Matrix3 identityExpected({1.0f, 0.0f, 0.0f},
{0.0f, 1.0f, 0.0f},
{0.0f, 0.0f, 1.0f});
Matrix3 identity3Expected({4.0f, 0.0f, 0.0f},
{0.0f, 4.0f, 0.0f},
{0.0f, 0.0f, 4.0f});
CORRADE_COMPARE(identity, identityExpected);
CORRADE_COMPARE(identity2, identityExpected);
@ -88,31 +84,25 @@ void Matrix3Test::constructIdentity() {
}
void Matrix3Test::translation() {
Matrix3 matrix(
1.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f,
3.0f, 1.0f, 1.0f
);
Matrix3 matrix({1.0f, 0.0f, 0.0f},
{0.0f, 1.0f, 0.0f},
{3.0f, 1.0f, 1.0f});
CORRADE_COMPARE(Matrix3::translation({3.0f, 1.0f}), matrix);
}
void Matrix3Test::scaling() {
Matrix3 matrix(
3.0f, 0.0f, 0.0f,
0.0f, 1.5f, 0.0f,
0.0f, 0.0f, 1.0f
);
Matrix3 matrix({3.0f, 0.0f, 0.0f},
{0.0f, 1.5f, 0.0f},
{0.0f, 0.0f, 1.0f});
CORRADE_COMPARE(Matrix3::scaling({3.0f, 1.5f}), matrix);
}
void Matrix3Test::rotation() {
Matrix3 matrix(
0.965926f, 0.258819f, 0.0f,
-0.258819f, 0.965926f, 0.0f,
0.0f, 0.0f, 1.0f
);
Matrix3 matrix({ 0.965926f, 0.258819f, 0.0f},
{-0.258819f, 0.965926f, 0.0f},
{ 0.0f, 0.0f, 1.0f});
CORRADE_COMPARE(Matrix3::rotation(deg(15.0f)), matrix);
}
@ -127,11 +117,9 @@ void Matrix3Test::reflection() {
CORRADE_COMPARE(o.str(), "Math::Matrix3::reflection(): normal must be normalized\n");
Matrix3 actual = Matrix3::reflection(normal.normalized());
Matrix3 expected(
0.6f, 0.8f, 0.0f,
0.8f, -0.6f, 0.0f,
0.0f, 0.0f, 1.0f
);
Matrix3 expected({0.6f, 0.8f, 0.0f},
{0.8f, -0.6f, 0.0f},
{0.0f, 0.0f, 1.0f});
CORRADE_COMPARE(actual*actual, Matrix3());
CORRADE_COMPARE(actual*normal, -normal);
@ -139,50 +127,40 @@ void Matrix3Test::reflection() {
}
void Matrix3Test::projection() {
Matrix3 expected(2.0f/4.0f, 0.0f, 0.0f,
0.0f, 2.0f/3.0f, 0.0f,
0.0f, 0.0f, 1.0f);
Matrix3 expected({2.0f/4.0f, 0.0f, 0.0f},
{ 0.0f, 2.0f/3.0f, 0.0f},
{ 0.0f, 0.0f, 1.0f});
CORRADE_COMPARE(Matrix3::projection({4.0f, 3.0f}), expected);
}
void Matrix3Test::fromParts() {
Matrix2 rotationScaling(
3.0f, 5.0f,
4.0f, 4.0f
);
Matrix2 rotationScaling(Vector2(3.0f, 5.0f),
Vector2(4.0f, 4.0f));
Vector2 translation(7.0f, -1.0f);
Matrix3 expected(
3.0f, 5.0f, 0.0f,
4.0f, 4.0f, 0.0f,
7.0f, -1.0f, 1.0f
);
Matrix3 expected({3.0f, 5.0f, 0.0f},
{4.0f, 4.0f, 0.0f},
{7.0f, -1.0f, 1.0f});
CORRADE_COMPARE(Matrix3::from(rotationScaling, translation), expected);
}
void Matrix3Test::rotationScalingPart() {
Matrix3 m(
3.0f, 5.0f, 8.0f,
4.0f, 4.0f, 7.0f,
7.0f, -1.0f, 8.0f
);
Matrix3 m({3.0f, 5.0f, 8.0f},
{4.0f, 4.0f, 7.0f},
{7.0f, -1.0f, 8.0f});
Matrix2 expected(
3.0f, 5.0f,
4.0f, 4.0f
);
Matrix2 expected(Vector2(3.0f, 5.0f),
Vector2(4.0f, 4.0f));
CORRADE_COMPARE(m.rotationScaling(), expected);
}
void Matrix3Test::rotationPart() {
Matrix2 expectedRotationPart(
0.965926f, 0.258819f,
-0.258819f, 0.965926f
);
Matrix2 expectedRotationPart(Vector2( 0.965926f, 0.258819f),
Vector2(-0.258819f, 0.965926f));
Matrix3 rotation = Matrix3::rotation(deg(15.0f));
CORRADE_COMPARE(rotation.rotation(), expectedRotationPart);
@ -192,9 +170,9 @@ void Matrix3Test::rotationPart() {
}
void Matrix3Test::vectorParts() {
Matrix3 m(15.0f, 0.0f, 0.0f,
0.0f, -3.0f, 0.0f,
-5.0f, 12.0f, 1.0f);
Matrix3 m({15.0f, 0.0f, 0.0f},
{ 0.0f, -3.0f, 0.0f},
{-5.0f, 12.0f, 1.0f});
CORRADE_COMPARE(m.right(), Vector2::xAxis(15.0f));
CORRADE_COMPARE(m.up(), Vector2::yAxis(-3.0f));
@ -205,11 +183,9 @@ void Matrix3Test::invertedEuclidean() {
std::ostringstream o;
Error::setOutput(&o);
Matrix3 m(
3.0f, 5.0f, 8.0f,
4.0f, 4.0f, 7.0f,
7.0f, -1.0f, 8.0f
);
Matrix3 m({3.0f, 5.0f, 8.0f},
{4.0f, 4.0f, 7.0f},
{7.0f, -1.0f, 8.0f});
CORRADE_COMPARE(m.invertedEuclidean(), Matrix3());
CORRADE_COMPARE(o.str(), "Math::Matrix3::invertedEuclidean(): unexpected values on last row\n");
@ -229,11 +205,9 @@ void Matrix3Test::invertedEuclidean() {
}
void Matrix3Test::debug() {
Matrix3 m(
3.0f, 5.0f, 8.0f,
4.0f, 4.0f, 7.0f,
7.0f, -1.0f, 8.0f
);
Matrix3 m({3.0f, 5.0f, 8.0f},
{4.0f, 4.0f, 7.0f},
{7.0f, -1.0f, 8.0f});
std::ostringstream o;
Debug(&o) << m;
@ -245,11 +219,9 @@ void Matrix3Test::debug() {
void Matrix3Test::configuration() {
Configuration c;
Matrix3 m(
5.0f, 8.0f, 4.0f,
4.0f, 7.0f, 3.125f,
4.0f, 5.0f, 9.55f
);
Matrix3 m({5.0f, 8.0f, 4.0f},
{4.0f, 7.0f, 3.125f},
{4.0f, 5.0f, 9.55f});
std::string value("5 4 4 8 7 5 4 3.125 9.55");
c.setValue("matrix", m);

198
src/Math/Test/Matrix4Test.cpp

@ -80,19 +80,15 @@ void Matrix4Test::constructIdentity() {
Matrix4 identity2(Matrix4::Identity);
Matrix4 identity3(Matrix4::Identity, 4.0f);
Matrix4 identityExpected(
1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f
);
Matrix4 identity3Expected(
4.0f, 0.0f, 0.0f, 0.0f,
0.0f, 4.0f, 0.0f, 0.0f,
0.0f, 0.0f, 4.0f, 0.0f,
0.0f, 0.0f, 0.0f, 4.0f
);
Matrix4 identityExpected({1.0f, 0.0f, 0.0f, 0.0f},
{0.0f, 1.0f, 0.0f, 0.0f},
{0.0f, 0.0f, 1.0f, 0.0f},
{0.0f, 0.0f, 0.0f, 1.0f});
Matrix4 identity3Expected({4.0f, 0.0f, 0.0f, 0.0f},
{0.0f, 4.0f, 0.0f, 0.0f},
{0.0f, 0.0f, 4.0f, 0.0f},
{0.0f, 0.0f, 0.0f, 4.0f});
CORRADE_COMPARE(identity, identityExpected);
CORRADE_COMPARE(identity2, identityExpected);
@ -100,23 +96,19 @@ void Matrix4Test::constructIdentity() {
}
void Matrix4Test::translation() {
Matrix4 matrix(
1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
3.0f, 1.0f, 2.0f, 1.0f
);
Matrix4 matrix({1.0f, 0.0f, 0.0f, 0.0f},
{0.0f, 1.0f, 0.0f, 0.0f},
{0.0f, 0.0f, 1.0f, 0.0f},
{3.0f, 1.0f, 2.0f, 1.0f});
CORRADE_COMPARE(Matrix4::translation({3.0f, 1.0f, 2.0f}), matrix);
}
void Matrix4Test::scaling() {
Matrix4 matrix(
3.0f, 0.0f, 0.0f, 0.0f,
0.0f, 1.5f, 0.0f, 0.0f,
0.0f, 0.0f, 2.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f
);
Matrix4 matrix({3.0f, 0.0f, 0.0f, 0.0f},
{0.0f, 1.5f, 0.0f, 0.0f},
{0.0f, 0.0f, 2.0f, 0.0f},
{0.0f, 0.0f, 0.0f, 1.0f});
CORRADE_COMPARE(Matrix4::scaling({3.0f, 1.5f, 2.0f}), matrix);
}
@ -128,38 +120,36 @@ void Matrix4Test::rotation() {
CORRADE_COMPARE(Matrix4::rotation(deg(-74.0f), {-1.0f, 2.0f, 2.0f}), Matrix4());
CORRADE_COMPARE(o.str(), "Math::Matrix4::rotation(): axis must be normalized\n");
Matrix4 matrix(
0.35612214f, -0.80181062f, 0.47987163f, 0.0f,
0.47987163f, 0.59757638f, 0.6423595f, 0.0f,
-0.80181062f, 0.0015183985f, 0.59757638f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f
);
Matrix4 matrix({ 0.35612214f, -0.80181062f, 0.47987163f, 0.0f},
{ 0.47987163f, 0.59757638f, 0.6423595f, 0.0f},
{-0.80181062f, 0.0015183985f, 0.59757638f, 0.0f},
{ 0.0f, 0.0f, 0.0f, 1.0f});
CORRADE_COMPARE(Matrix4::rotation(deg(-74.0f), Vector3(-1.0f, 2.0f, 2.0f).normalized()), matrix);
}
void Matrix4Test::rotationX() {
Matrix4 matrix(1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.90096887f, 0.43388374f, 0.0f,
0.0f, -0.43388374f, 0.90096887f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f);
Matrix4 matrix({1.0f, 0.0f, 0.0f, 0.0f},
{0.0f, 0.90096887f, 0.43388374f, 0.0f},
{0.0f, -0.43388374f, 0.90096887f, 0.0f},
{0.0f, 0.0f, 0.0f, 1.0f});
CORRADE_COMPARE(Matrix4::rotation(rad(Math::Constants<float>::pi()/7), Vector3::xAxis()), matrix);
CORRADE_COMPARE(Matrix4::rotationX(rad(Math::Constants<float>::pi()/7)), matrix);
}
void Matrix4Test::rotationY() {
Matrix4 matrix(0.90096887f, 0.0f, -0.43388374f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
0.43388374f, 0.0f, 0.90096887f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f);
Matrix4 matrix({0.90096887f, 0.0f, -0.43388374f, 0.0f},
{ 0.0f, 1.0f, 0.0f, 0.0f},
{0.43388374f, 0.0f, 0.90096887f, 0.0f},
{ 0.0f, 0.0f, 0.0f, 1.0f});
CORRADE_COMPARE(Matrix4::rotation(rad(Math::Constants<float>::pi()/7), Vector3::yAxis()), matrix);
CORRADE_COMPARE(Matrix4::rotationY(rad(Math::Constants<float>::pi()/7)), matrix);
}
void Matrix4Test::rotationZ() {
Matrix4 matrix( 0.90096887f, 0.43388374f, 0.0f, 0.0f,
-0.43388374f, 0.90096887f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f);
Matrix4 matrix({ 0.90096887f, 0.43388374f, 0.0f, 0.0f},
{-0.43388374f, 0.90096887f, 0.0f, 0.0f},
{ 0.0f, 0.0f, 1.0f, 0.0f},
{ 0.0f, 0.0f, 0.0f, 1.0f});
CORRADE_COMPARE(Matrix4::rotation(rad(Math::Constants<float>::pi()/7), Vector3::zAxis()), matrix);
CORRADE_COMPARE(Matrix4::rotationZ(rad(Math::Constants<float>::pi()/7)), matrix);
}
@ -174,12 +164,10 @@ void Matrix4Test::reflection() {
CORRADE_COMPARE(o.str(), "Math::Matrix4::reflection(): normal must be normalized\n");
Matrix4 actual = Matrix4::reflection(normal.normalized());
Matrix4 expected(
0.777778f, 0.444444f, 0.444444f, 0.0f,
0.444444f, 0.111111f, -0.888889f, 0.0f,
0.444444f, -0.888889f, 0.111111f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f
);
Matrix4 expected({0.777778f, 0.444444f, 0.444444f, 0.0f},
{0.444444f, 0.111111f, -0.888889f, 0.0f},
{0.444444f, -0.888889f, 0.111111f, 0.0f},
{ 0.0f, 0.0f, 0.0f, 1.0f});
CORRADE_COMPARE(actual*actual, Matrix4());
CORRADE_COMPARE(actual*normal, -normal);
@ -187,73 +175,59 @@ void Matrix4Test::reflection() {
}
void Matrix4Test::orthographicProjection() {
Matrix4 expected(0.4f, 0.0f, 0.0f, 0.0f,
0.0f, 0.5f, 0.0f, 0.0f,
0.0f, 0.0f, -0.25f, 0.0f,
0.0f, 0.0f, -1.25f, 1.0f);
Matrix4 expected({0.4f, 0.0f, 0.0f, 0.0f},
{0.0f, 0.5f, 0.0f, 0.0f},
{0.0f, 0.0f, -0.25f, 0.0f},
{0.0f, 0.0f, -1.25f, 1.0f});
CORRADE_COMPARE(Matrix4::orthographicProjection({5.0f, 4.0f}, 1, 9), expected);
}
void Matrix4Test::perspectiveProjection() {
Matrix4 expected(4.0f, 0.0f, 0.0f, 0.0f,
0.0f, 7.111111f, 0.0f, 0.0f,
0.0f, 0.0f, -1.9411764f, -1.0f,
0.0f, 0.0f, -94.1176452f, 0.0f);
Matrix4 expected({4.0f, 0.0f, 0.0f, 0.0f},
{0.0f, 7.111111f, 0.0f, 0.0f},
{0.0f, 0.0f, -1.9411764f, -1.0f},
{0.0f, 0.0f, -94.1176452f, 0.0f});
CORRADE_COMPARE(Matrix4::perspectiveProjection({16.0f, 9.0f}, 32.0f, 100), expected);
}
void Matrix4Test::perspectiveProjectionFov() {
Matrix4 expected(4.1652994f, 0.0f, 0.0f, 0.0f,
0.0f, 9.788454f, 0.0f, 0.0f,
0.0f, 0.0f, -1.9411764f, -1.0f,
0.0f, 0.0f, -94.1176452f, 0.0f);
Matrix4 expected({4.1652994f, 0.0f, 0.0f, 0.0f},
{ 0.0f, 9.788454f, 0.0f, 0.0f},
{ 0.0f, 0.0f, -1.9411764f, -1.0f},
{ 0.0f, 0.0f, -94.1176452f, 0.0f});
CORRADE_COMPARE(Matrix4::perspectiveProjection(deg(27.0f), 2.35f, 32.0f, 100), expected);
}
void Matrix4Test::fromParts() {
Matrix3 rotationScaling(
3.0f, 5.0f, 8.0f,
4.0f, 4.0f, 7.0f,
7.0f, -1.0f, 8.0f
);
Matrix3 rotationScaling(Vector3(3.0f, 5.0f, 8.0f),
Vector3(4.0f, 4.0f, 7.0f),
Vector3(7.0f, -1.0f, 8.0f));
Vector3 translation(9.0f, 4.0f, 5.0f);
Matrix4 expected(
3.0f, 5.0f, 8.0f, 0.0f,
4.0f, 4.0f, 7.0f, 0.0f,
7.0f, -1.0f, 8.0f, 0.0f,
9.0f, 4.0f, 5.0f, 1.0f
);
Matrix4 expected({3.0f, 5.0f, 8.0f, 0.0f},
{4.0f, 4.0f, 7.0f, 0.0f},
{7.0f, -1.0f, 8.0f, 0.0f},
{9.0f, 4.0f, 5.0f, 1.0f});
CORRADE_COMPARE(Matrix4::from(rotationScaling, translation), expected);
}
void Matrix4Test::rotationScalingPart() {
Matrix4 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,
9.0f, 4.0f, 5.0f, 9.0f
);
Matrix3 expected(
3.0f, 5.0f, 8.0f,
4.0f, 4.0f, 7.0f,
7.0f, -1.0f, 8.0f
);
Matrix4 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},
{9.0f, 4.0f, 5.0f, 9.0f});
Matrix3 expected(Vector3(3.0f, 5.0f, 8.0f),
Vector3(4.0f, 4.0f, 7.0f),
Vector3(7.0f, -1.0f, 8.0f));
CORRADE_COMPARE(m.rotationScaling(), expected);
}
void Matrix4Test::rotationPart() {
Matrix3 expectedRotationPart(
0.35612214f, -0.80181062f, 0.47987163f,
0.47987163f, 0.59757638f, 0.6423595f,
-0.80181062f, 0.0015183985f, 0.59757638f
);
Matrix3 expectedRotationPart(Vector3( 0.35612214f, -0.80181062f, 0.47987163f),
Vector3( 0.47987163f, 0.59757638f, 0.6423595f),
Vector3(-0.80181062f, 0.0015183985f, 0.59757638f));
Matrix4 rotation = Matrix4::rotation(deg(-74.0f), Vector3(-1.0f, 2.0f, 2.0f).normalized());
CORRADE_COMPARE(rotation.rotation().determinant(), 1.0f);
@ -267,10 +241,10 @@ void Matrix4Test::rotationPart() {
}
void Matrix4Test::vectorParts() {
Matrix4 m(-1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 12.0f, 0.0f, 0.0f,
0.0f, 0.0f, 35.0f, 0.0f,
-5.0f, 12.0f, 0.5f, 1.0f);
Matrix4 m({-1.0f, 0.0f, 0.0f, 0.0f},
{ 0.0f, 12.0f, 0.0f, 0.0f},
{ 0.0f, 0.0f, 35.0f, 0.0f},
{-5.0f, 12.0f, 0.5f, 1.0f});
CORRADE_COMPARE(m.right(), Vector3::xAxis(-1.0f));
CORRADE_COMPARE(m.up(), Vector3::yAxis(12.0f));
@ -282,12 +256,10 @@ void Matrix4Test::invertedEuclidean() {
std::ostringstream o;
Error::setOutput(&o);
Matrix4 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,
9.0f, 4.0f, 5.0f, 9.0f
);
Matrix4 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},
{9.0f, 4.0f, 5.0f, 9.0f});
CORRADE_COMPARE(m.invertedEuclidean(), Matrix4());
CORRADE_COMPARE(o.str(), "Math::Matrix4::invertedEuclidean(): unexpected values on last row\n");
@ -307,12 +279,10 @@ void Matrix4Test::invertedEuclidean() {
}
void Matrix4Test::debug() {
Matrix4 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,
9.0f, 4.0f, 5.0f, 9.0f
);
Matrix4 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},
{9.0f, 4.0f, 5.0f, 9.0f});
std::ostringstream o;
Debug(&o) << m;
@ -325,12 +295,10 @@ void Matrix4Test::debug() {
void Matrix4Test::configuration() {
Configuration c;
Matrix4 m(
3.0f, 5.0f, 8.0f, 4.0f,
4.0f, 4.0f, 7.0f, 3.125f,
7.0f, -1.0f, 8.0f, 0.0f,
9.0f, 4.0f, 5.0f, 9.55f
);
Matrix4 m({3.0f, 5.0f, 8.0f, 4.0f},
{4.0f, 4.0f, 7.0f, 3.125f},
{7.0f, -1.0f, 8.0f, 0.0f},
{9.0f, 4.0f, 5.0f, 9.55f});
std::string value("3 4 7 9 5 4 -1 4 8 7 8 5 4 3.125 0 9.55");
c.setValue("matrix", m);

125
src/Math/Test/MatrixTest.cpp

@ -42,6 +42,7 @@ class MatrixTest: public Corrade::TestSuite::Tester {
typedef Matrix<4, float> Matrix4;
typedef Matrix<3, float> Matrix3;
typedef Vector<4, float> Vector4;
typedef Vector<3, float> Vector3;
MatrixTest::MatrixTest() {
addTests(&MatrixTest::construct,
@ -57,18 +58,16 @@ MatrixTest::MatrixTest() {
void MatrixTest::construct() {
float m[] = {
3.0f, 5.0f, 8.0f, 4.0f,
4.0f, 4.0f, 7.0f, 3.0f,
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
9.0f, 4.0f, 5.0f, 9.0f
};
Matrix4 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,
9.0f, 4.0f, 5.0f, 9.0f
);
Matrix4 expected(Vector4(3.0f, 5.0f, 8.0f, 4.0f),
Vector4(4.0f, 4.0f, 7.0f, 3.0f),
Vector4(7.0f, -1.0f, 8.0f, 0.0f),
Vector4(9.0f, 4.0f, 5.0f, 9.0f));
CORRADE_COMPARE(Matrix4::from(m), expected);
}
@ -78,19 +77,15 @@ void MatrixTest::constructIdentity() {
Matrix4 identity2(Matrix4::Identity);
Matrix4 identity3(Matrix4::Identity, 4.0f);
Matrix4 identityExpected(
1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f
);
Matrix4 identityExpected(Vector4(1.0f, 0.0f, 0.0f, 0.0f),
Vector4(0.0f, 1.0f, 0.0f, 0.0f),
Vector4(0.0f, 0.0f, 1.0f, 0.0f),
Vector4(0.0f, 0.0f, 0.0f, 1.0f));
Matrix4 identity3Expected(
4.0f, 0.0f, 0.0f, 0.0f,
0.0f, 4.0f, 0.0f, 0.0f,
0.0f, 0.0f, 4.0f, 0.0f,
0.0f, 0.0f, 0.0f, 4.0f
);
Matrix4 identity3Expected(Vector4(4.0f, 0.0f, 0.0f, 0.0f),
Vector4(0.0f, 4.0f, 0.0f, 0.0f),
Vector4(0.0f, 0.0f, 4.0f, 0.0f),
Vector4(0.0f, 0.0f, 0.0f, 4.0f));
CORRADE_COMPARE(identity, identityExpected);
CORRADE_COMPARE(identity2, identityExpected);
@ -100,71 +95,61 @@ void MatrixTest::constructIdentity() {
void MatrixTest::constructZero() {
Matrix4 zero(Matrix4::Zero);
Matrix4 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,
0.0f, 0.0f, 0.0f, 0.0f
);
Matrix4 zeroExpected(Vector4(0.0f, 0.0f, 0.0f, 0.0f),
Vector4(0.0f, 0.0f, 0.0f, 0.0f),
Vector4(0.0f, 0.0f, 0.0f, 0.0f),
Vector4(0.0f, 0.0f, 0.0f, 0.0f));
CORRADE_COMPARE(zero, zeroExpected);
}
void MatrixTest::trace() {
Matrix<5, std::int32_t> 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
Vector<5, std::int32_t>(1, 2, 3, 0, 0),
Vector<5, std::int32_t>(2, 3, 2, 1, -2),
Vector<5, std::int32_t>(1, 1, -20, 1, 0),
Vector<5, std::int32_t>(2, 0, 0, 10, 2),
Vector<5, std::int32_t>(3, 1, 0, 1, -2)
);
CORRADE_COMPARE(m.trace(), -8);
}
void MatrixTest::ij() {
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 original(Vector4( 0.0f, 1.0f, 2.0f, 3.0f),
Vector4( 4.0f, 5.0f, 6.0f, 7.0f),
Vector4( 8.0f, 9.0f, 10.0f, 11.0f),
Vector4(12.0f, 13.0f, 14.0f, 15.0f));
Matrix3 skipped(
0.0f, 1.0f, 3.0f,
8.0f, 9.0f, 11.0f,
12.0f, 13.0f, 15.0f
);
Matrix3 skipped(Vector3( 0.0f, 1.0f, 3.0f),
Vector3( 8.0f, 9.0f, 11.0f),
Vector3(12.0f, 13.0f, 15.0f));
CORRADE_COMPARE(original.ij(1, 2), skipped);
}
void MatrixTest::determinant() {
Matrix<5, std::int32_t> m(
1, 2, 2, 1, 0,
2, 3, 2, 1, -2,
1, 1, 1, 1, 0,
2, 0, 0, 1, 2,
3, 1, 0, 1, -2
Vector<5, std::int32_t>(1, 2, 2, 1, 0),
Vector<5, std::int32_t>(2, 3, 2, 1, -2),
Vector<5, std::int32_t>(1, 1, 1, 1, 0),
Vector<5, std::int32_t>(2, 0, 0, 1, 2),
Vector<5, std::int32_t>(3, 1, 0, 1, -2)
);
CORRADE_COMPARE(m.determinant(), -2);
}
void MatrixTest::inverted() {
Matrix4 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,
9.0f, 4.0f, 5.0f, 9.0f
);
Matrix4 m(Vector4(3.0f, 5.0f, 8.0f, 4.0f),
Vector4(4.0f, 4.0f, 7.0f, 3.0f),
Vector4(7.0f, -1.0f, 8.0f, 0.0f),
Vector4(9.0f, 4.0f, 5.0f, 9.0f));
Matrix4 inverse(
-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 inverse(Vector4(-60/103.0f, 71/103.0f, -4/103.0f, 3/103.0f),
Vector4(-66/103.0f, 109/103.0f, -25/103.0f, -7/103.0f),
Vector4(177/412.0f, -97/206.0f, 53/412.0f, -7/206.0f),
Vector4(259/412.0f, -185/206.0f, 31/412.0f, 27/206.0f));
Matrix4 _inverse = m.inverted();
@ -173,12 +158,10 @@ void MatrixTest::inverted() {
}
void MatrixTest::debug() {
Matrix4 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,
9.0f, 4.0f, 5.0f, 9.0f
);
Matrix4 m(Vector4(3.0f, 5.0f, 8.0f, 4.0f),
Vector4(4.0f, 4.0f, 7.0f, 3.0f),
Vector4(7.0f, -1.0f, 8.0f, 0.0f),
Vector4(9.0f, 4.0f, 5.0f, 9.0f));
std::ostringstream o;
Debug(&o) << m;
@ -201,12 +184,10 @@ void MatrixTest::debug() {
void MatrixTest::configuration() {
Configuration c;
Matrix4 m(
3.0f, 5.0f, 8.0f, 4.0f,
4.0f, 4.0f, 7.0f, 3.125f,
7.0f, -1.0f, 8.0f, 0.0f,
9.0f, 4.0f, 5.0f, 9.55f
);
Matrix4 m(Vector4(3.0f, 5.0f, 8.0f, 4.0f),
Vector4(4.0f, 4.0f, 7.0f, 3.125f),
Vector4(7.0f, -1.0f, 8.0f, 0.0f),
Vector4(9.0f, 4.0f, 5.0f, 9.55f));
std::string value("3 4 7 9 5 4 -1 4 8 7 8 5 4 3.125 0 9.55");
c.setValue("matrix", m);

178
src/Math/Test/RectangularMatrixTest.cpp

@ -51,6 +51,9 @@ typedef RectangularMatrix<3, 4, float> Matrix3x4;
typedef RectangularMatrix<2, 2, float> Matrix2;
typedef RectangularMatrix<2, 2, std::int32_t> Matrix2i;
typedef Vector<4, float> Vector4;
typedef Vector<3, float> Vector3;
typedef Vector<2, float> Vector2;
typedef Vector<2, std::int32_t> Vector2i;
RectangularMatrixTest::RectangularMatrixTest() {
addTests(&RectangularMatrixTest::constructFromData,
@ -79,11 +82,9 @@ void RectangularMatrixTest::constructFromData() {
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
);
Matrix3x4 expected(Vector4(3.0f, 5.0f, 8.0f, 4.0f),
Vector4(4.0f, 4.0f, 7.0f, 3.0f),
Vector4(7.0f, -1.0f, 8.0f, 0.0f));
CORRADE_COMPARE(Matrix3x4::from(m), expected);
}
@ -91,33 +92,34 @@ void RectangularMatrixTest::constructFromData() {
void RectangularMatrixTest::constructDefault() {
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
);
Matrix4x3 zeroExpected(Vector3(0.0f, 0.0f, 0.0f),
Vector3(0.0f, 0.0f, 0.0f),
Vector3(0.0f, 0.0f, 0.0f),
Vector3(0.0f, 0.0f, 0.0f));
CORRADE_COMPARE(zero, zeroExpected);
}
void RectangularMatrixTest::constructConversion() {
Matrix2 floatingPoint(1.3f, 2.7f, -15.0f, 7.0f);
Matrix2 floatingPointRounded(1.0f, 2.0f, -15.0f, 7.0f);
Matrix2i integral(1, 2, -15, 7);
Matrix2 floatingPoint(Vector2( 1.3f, 2.7f),
Vector2(-15.0f, 7.0f));
Matrix2 floatingPointRounded(Vector2(1.0f, 2.0f),
Vector2(-15.0f, 7.0f));
Matrix2i integral(Vector2i( 1, 2),
Vector2i(-15, 7));
CORRADE_COMPARE(Matrix2i::from(floatingPoint), integral);
CORRADE_COMPARE(Matrix2::from(integral), floatingPointRounded);
}
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 actual(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);
Matrix3x4 expected(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));
CORRADE_COMPARE(actual, expected);
}
@ -128,54 +130,68 @@ void RectangularMatrixTest::data() {
m[2] = vector;
m[1][1] = 1.0f;
m(0, 2) = 1.5f;
m[0][2] = 1.5f;
CORRADE_COMPARE(m(1, 1), 1.0f);
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
);
Matrix3x4 expected(Vector4(0.0f, 0.0f, 1.5f, 0.0f),
Vector4(0.0f, 1.0f, 0.0f, 0.0f),
Vector4(4.0f, 5.0f, 6.0f, 7.0f));
CORRADE_COMPARE(m, expected);
}
void RectangularMatrixTest::compare() {
CORRADE_VERIFY(Matrix2(1.0f, -3.0f, 5.0f, -10.0f) == Matrix2(1.0f + MathTypeTraits<float>::epsilon()/2, -3.0f, 5.0f, -10.0f));
CORRADE_VERIFY(Matrix2(1.0f, -1.0f, 5.0f, -10.0f) != Matrix2(1.0f, -1.0f + MathTypeTraits<float>::epsilon()*2, 5.0f, -10.0f));
CORRADE_VERIFY(Matrix2i(1, -3, 5, -10) == Matrix2i(1, -3, 5, -10));
CORRADE_VERIFY(Matrix2i(1, -3, 5, -10) != Matrix2i(1, -2, 5, -10));
Matrix2 a(Vector2(1.0f, -3.0f),
Vector2(5.0f, -10.0f));
Matrix2 b(Vector2(1.0f + MathTypeTraits<float>::epsilon()/2, -3.0f),
Vector2(5.0f, -10.0f));
Matrix2 c(Vector2(1.0f, -1.0f + MathTypeTraits<float>::epsilon()*2),
Vector2(5.0f, -10.0f));
CORRADE_VERIFY(a == b);
CORRADE_VERIFY(a != c);
Matrix2i ai(Vector2i(1, -3),
Vector2i(5, -10));
Matrix2i bi(Vector2i(1, -2),
Vector2i(5, -10));
CORRADE_VERIFY(ai == ai);
CORRADE_VERIFY(ai != bi);
}
void RectangularMatrixTest::negative() {
CORRADE_COMPARE(-Matrix2(1.0f, -3.0f, 5.0f, -10.0f), Matrix2(-1.0f, 3.0f, -5.0f, 10.0f));
Matrix2 matrix(Vector2(1.0f, -3.0f),
Vector2(5.0f, -10.0f));
Matrix2 negated(Vector2(-1.0f, 3.0f),
Vector2(-5.0f, 10.0f));
CORRADE_COMPARE(-matrix, negated);
}
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 c(-4.0f, 1.5f, 12.0f,
-5.0f, 16.0f, 7.25f,
8.0f, 1.0f, 30.0f,
9.0f, 8.0f, 17.0f);
Matrix4x3 a(Vector3(0.0f, 1.0f, 3.0f),
Vector3(4.0f, 5.0f, 7.0f),
Vector3(8.0f, 9.0f, 11.0f),
Vector3(12.0f, 13.0f, 15.0f));
Matrix4x3 b(Vector3(-4.0f, 0.5f, 9.0f),
Vector3(-9.0f, 11.0f, 0.25f),
Vector3( 0.0f, -8.0f, 19.0f),
Vector3(-3.0f, -5.0f, 2.0f));
Matrix4x3 c(Vector3(-4.0f, 1.5f, 12.0f),
Vector3(-5.0f, 16.0f, 7.25f),
Vector3( 8.0f, 1.0f, 30.0f),
Vector3( 9.0f, 8.0f, 17.0f));
CORRADE_COMPARE(a + b, c);
CORRADE_COMPARE(c - b, a);
}
void RectangularMatrixTest::multiplyDivide() {
Matrix2 matrix(1.0f, 2.0f, 3.0f, 4.0f);
Matrix2 multiplied(-1.5f, -3.0f, -4.5f, -6.0f);
Matrix2 matrix(Vector2(1.0f, 2.0f),
Vector2(3.0f, 4.0f));
Matrix2 multiplied(Vector2(-1.5f, -3.0f),
Vector2(-4.5f, -6.0f));
CORRADE_COMPARE(matrix*-1.5f, multiplied);
CORRADE_COMPARE(-1.5f*matrix, multiplied);
@ -188,62 +204,58 @@ void RectangularMatrixTest::multiplyDivide() {
CORRADE_COMPARE(-1.5f*matrixChar, 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);
Matrix2 divisor(Vector2( 1.0f, 2.0f),
Vector2(-4.0f, 8.0f));
Matrix2 result(Vector2( 1.0f, 0.5f),
Vector2(-0.25f, 0.125f));
CORRADE_COMPARE(1.0f/divisor, result);
CORRADE_COMPARE(-1550.0f/multipliedChar, matrixChar);
}
void RectangularMatrixTest::multiply() {
RectangularMatrix<4, 6, std::int32_t> 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
Vector<6, std::int32_t>(-5, 27, 10, 33, 0, -15),
Vector<6, std::int32_t>( 7, 56, 66, 1, 0, -24),
Vector<6, std::int32_t>( 4, 41, 4, 0, 1, -4),
Vector<6, std::int32_t>( 9, -100, 19, -49, 1, 9)
);
RectangularMatrix<5, 4, std::int32_t> right(
1, -7, 0, 158,
2, 24, -3, 40,
3, -15, -2, -50,
4, 17, -1, -284,
5, 30, 4, 18
Vector<4, std::int32_t>(1, -7, 0, 158),
Vector<4, std::int32_t>(2, 24, -3, 40),
Vector<4, std::int32_t>(3, -15, -2, -50),
Vector<4, std::int32_t>(4, 17, -1, -284),
Vector<4, std::int32_t>(5, 30, 4, 18)
);
RectangularMatrix<5, 6, std::int32_t> 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
Vector<6, std::int32_t>( 1368, -16165, 2550, -7716, 158, 1575),
Vector<6, std::int32_t>( 506, -2725, 2352, -1870, 37, -234),
Vector<6, std::int32_t>( -578, 4159, -1918, 2534, -52, -127),
Vector<6, std::int32_t>(-2461, 29419, -4238, 14065, -285, -3020),
Vector<6, std::int32_t>( 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
);
Matrix4x3 original(Vector3( 0.0f, 1.0f, 3.0f),
Vector3( 4.0f, 5.0f, 7.0f),
Vector3( 8.0f, 9.0f, 11.0f),
Vector3(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
);
Matrix3x4 transposed(Vector4(0.0f, 4.0f, 8.0f, 12.0f),
Vector4(1.0f, 5.0f, 9.0f, 13.0f),
Vector4(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
);
Matrix3x4 m(Vector4(3.0f, 5.0f, 8.0f, 4.0f),
Vector4(4.0f, 4.0f, 7.0f, 3.0f),
Vector4(7.0f, -1.0f, 8.0f, 0.0f));
std::ostringstream o;
Debug(&o) << m;
@ -263,11 +275,9 @@ void RectangularMatrixTest::debug() {
}
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
);
Matrix3x4 m(Vector4(3.0f, 5.0f, 8.0f, 4.0f),
Vector4(4.0f, 4.0f, 7.0f, 3.125f),
Vector4(7.0f, -1.0f, 8.0f, 9.55f));
std::string value("3 4 7 5 4 -1 8 7 8 4 3.125 9.55");
Configuration c;

22
src/Math/Vector.cpp

@ -35,3 +35,25 @@ template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug, const Magnu
#endif
}}
namespace Corrade { namespace Utility {
#ifndef DOXYGEN_GENERATING_OUTPUT
template struct ConfigurationValue<Magnum::Math::Vector<2, float>>;
template struct ConfigurationValue<Magnum::Math::Vector<3, float>>;
template struct ConfigurationValue<Magnum::Math::Vector<4, float>>;
template struct ConfigurationValue<Magnum::Math::Vector<2, int>>;
template struct ConfigurationValue<Magnum::Math::Vector<3, int>>;
template struct ConfigurationValue<Magnum::Math::Vector<4, int>>;
template struct ConfigurationValue<Magnum::Math::Vector<2, unsigned int>>;
template struct ConfigurationValue<Magnum::Math::Vector<3, unsigned int>>;
template struct ConfigurationValue<Magnum::Math::Vector<4, unsigned int>>;
#ifndef MAGNUM_TARGET_GLES
template struct ConfigurationValue<Magnum::Math::Vector<2, double>>;
template struct ConfigurationValue<Magnum::Math::Vector<3, double>>;
template struct ConfigurationValue<Magnum::Math::Vector<4, double>>;
#endif
#endif
}}

407
src/Math/Vector.h

@ -19,12 +19,32 @@
* @brief Class Magnum::Math::Vector
*/
#include <cmath>
#include <limits>
#include <Utility/Assert.h>
#include <Utility/Debug.h>
#include <Utility/ConfigurationValue.h>
#include "RectangularMatrix.h"
#include "Math/MathTypeTraits.h"
#include "magnumVisibility.h"
namespace Magnum { namespace Math {
#ifndef DOXYGEN_GENERATING_OUTPUT
namespace Implementation {
template<std::size_t ...> struct Sequence {};
/* E.g. GenerateSequence<3>::Type is Sequence<0, 1, 2> */
template<std::size_t N, std::size_t ...sequence> struct GenerateSequence:
GenerateSequence<N-1, N-1, sequence...> {};
template<std::size_t ...sequence> struct GenerateSequence<0, sequence...> {
typedef Sequence<sequence...> Type;
};
}
#endif
/**
@brief %Vector
@tparam size %Vector size
@ -33,9 +53,45 @@ namespace Magnum { namespace Math {
See @ref matrix-vector for brief introduction.
@configurationvalueref{Magnum::Math::Vector}
*/
template<std::size_t size, class T> class Vector: public RectangularMatrix<1, size, T> {
template<std::size_t size, class T> class Vector {
static_assert(size != 0, "Vector cannot have zero elements");
template<std::size_t, class> friend class Vector;
public:
const static std::size_t Size = size; /**< @brief %Vector size */
typedef T Type; /**< @brief Data type */
const static std::size_t Size = size; /**< @brief %Vector size */
/**
* @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<size, T>& from(T* data) {
return *reinterpret_cast<Vector<size, T>*>(data);
}
/** @overload */
inline constexpr static const Vector<size, T>& from(const T* data) {
return *reinterpret_cast<const Vector<size, T>*>(data);
}
/**
* @brief %Vector from another of different type
*
* Performs only default casting on the values, no rounding or
* anything else. Example usage:
* @code
* Vector<4, float> floatingPoint(1.3f, 2.7f, -15.0f, 7.0f);
* Vector<4, std::int8_t> integral(Vector<4, std::int8_t>::from(floatingPoint));
* // integral == {1, 2, -15, 7}
* @endcode
*/
template<class U> inline constexpr static Vector<size, T> from(const Vector<size, U>& other) {
return from(typename Implementation::GenerateSequence<size>::Type(), other);
}
/**
* @brief Dot product
@ -84,7 +140,7 @@ template<std::size_t size, class T> class Vector: public RectangularMatrix<1, si
}
/** @brief Construct zero-filled vector */
inline constexpr /*implicit*/ Vector() {}
inline constexpr /*implicit*/ Vector(): _data() {}
/** @todo Creating Vector from combination of vector and scalar types */
@ -93,7 +149,9 @@ template<std::size_t size, class T> class Vector: public RectangularMatrix<1, si
* @param first First value
* @param next Next values
*/
template<class ...U> inline constexpr /*implicit*/ Vector(T first, U... next): RectangularMatrix<1, size, T>(first, next...) {}
template<class ...U> inline constexpr /*implicit*/ Vector(T first, U... next): _data{first, next...} {
static_assert(sizeof...(next)+1 == size, "Improper number of arguments passed to Vector constructor");
}
/** @brief Construct vector with one value for all fields */
#ifdef DOXYGEN_GENERATING_OUTPUT
@ -102,15 +160,45 @@ template<std::size_t size, class T> class Vector: public RectangularMatrix<1, si
template<class U> inline explicit Vector(typename std::enable_if<std::is_same<T, U>::value && size != 1, U>::type value) {
#endif
for(std::size_t i = 0; i != size; ++i)
(*this)[i] = value;
_data[i] = value;
}
/** @brief Copy constructor */
inline constexpr Vector(const RectangularMatrix<1, size, T>& other): RectangularMatrix<1, size, T>(other) {}
inline constexpr Vector(const Vector<size, T>&) = default;
/** @brief Value at given position */
inline T& operator[](std::size_t pos) { return RectangularMatrix<1, size, T>::_data[pos]; }
inline constexpr T operator[](std::size_t pos) const { return RectangularMatrix<1, size, T>::_data[pos]; } /**< @overload */
/** @brief Assignment operator */
inline Vector<size, T>& operator=(const Vector<size, T>&) = default;
/**
* @brief Raw data
* @return One-dimensional array of `size*size` length in column-major
* order.
*
* @see operator[]
*/
inline T* data() { return _data; }
inline constexpr const T* data() const { return _data; } /**< @overload */
/**
* @brief Value at given position
*
* @see data()
*/
inline T& operator[](std::size_t pos) { return _data[pos]; }
inline constexpr T operator[](std::size_t pos) const { return _data[pos]; } /**< @overload */
/** @brief Equality comparison */
inline bool operator==(const Vector<size, T>& other) const {
for(std::size_t i = 0; i != size; ++i)
if(!MathTypeTraits<T>::equals(_data[i], other._data[i])) return false;
return true;
}
/** @brief Non-equality comparison */
inline constexpr bool operator!=(const Vector<size, T>& other) const {
return !operator==(other);
}
/**
* @brief Component-wise less than
@ -119,7 +207,7 @@ template<std::size_t size, class T> class Vector: public RectangularMatrix<1, si
*/
inline bool operator<(const Vector<size, T>& other) const {
for(std::size_t i = 0; i != size; ++i)
if((*this)[i] >= other[i]) return false;
if(_data[i] >= other._data[i]) return false;
return true;
}
@ -131,7 +219,7 @@ template<std::size_t size, class T> class Vector: public RectangularMatrix<1, si
*/
inline bool operator<=(const Vector<size, T>& other) const {
for(std::size_t i = 0; i != size; ++i)
if((*this)[i] > other[i]) return false;
if(_data[i] > other._data[i]) return false;
return true;
}
@ -143,7 +231,7 @@ template<std::size_t size, class T> class Vector: public RectangularMatrix<1, si
*/
inline bool operator>=(const Vector<size, T>& other) const {
for(std::size_t i = 0; i != size; ++i)
if((*this)[i] < other[i]) return false;
if(_data[i] < other._data[i]) return false;
return true;
}
@ -155,11 +243,135 @@ template<std::size_t size, class T> class Vector: public RectangularMatrix<1, si
*/
inline bool operator>(const Vector<size, T>& other) const {
for(std::size_t i = 0; i != size; ++i)
if((*this)[i] <= other[i]) return false;
if(_data[i] <= other._data[i]) return false;
return true;
}
/**
* @brief Negated vector
*
* The computation is done in-place. @f[
* \boldsymbol a_i = -\boldsymbol a_i
* @f]
*/
Vector<size, T> operator-() const {
Vector<size, T> out;
for(std::size_t i = 0; i != size; ++i)
out._data[i] = -_data[i];
return out;
}
/**
* @brief Add and assign vector
*
* The computation is done in-place. @f[
* \boldsymbol a_i = \boldsymbol a_i + \boldsymbol b_i
* @f]
*/
Vector<size, T>& operator+=(const Vector<size, T>& other) {
for(std::size_t i = 0; i != size; ++i)
_data[i] += other._data[i];
return *this;
}
/**
* @brief Add vector
*
* @see operator+=()
*/
inline Vector<size, T> operator+(const Vector<size, T>& other) const {
return Vector<size, T>(*this) += other;
}
/**
* @brief Subtract and assign vector
*
* The computation is done in-place. @f[
* \boldsymbol a_i = \boldsymbol a_i - \boldsymbol b_i
* @f]
*/
Vector<size, T>& operator-=(const Vector<size, T>& other) {
for(std::size_t i = 0; i != size; ++i)
_data[i] -= other._data[i];
return *this;
}
/**
* @brief Subtract vector
*
* @see operator-=()
*/
inline Vector<size, T> operator-(const Vector<size, T>& other) const {
return Vector<size, T>(*this) -= other;
}
/**
* @brief Multiply vector with number and assign
*
* The computation is done in-place. @f[
* \boldsymbol a_i = b \boldsymbol a_i
* @f]
*/
#ifdef DOXYGEN_GENERATING_OUTPUT
template<class U> Vector<size, T>& operator*=(U number) {
#else
template<class U> inline typename std::enable_if<std::is_arithmetic<U>::value, Vector<size, T>&>::type operator*=(U number) {
#endif
for(std::size_t i = 0; i != size; ++i)
_data[i] *= number;
return *this;
}
/**
* @brief Multiply vector with number
*
* @see operator*=(U), operator*(U, const Vector<size, T>&)
*/
#ifdef DOXYGEN_GENERATING_OUTPUT
template<class U> inline Vector<size, T> operator*(U number) const {
#else
template<class U> inline typename std::enable_if<std::is_arithmetic<U>::value, Vector<size, T>>::type operator*(U number) const {
#endif
return Vector<size, T>(*this) *= number;
}
/**
* @brief Divide vector with number and assign
*
* The computation is done in-place. @f[
* \boldsymbol a_i = \frac{\boldsymbol a_i} b
* @f]
*/
#ifdef DOXYGEN_GENERATING_OUTPUT
template<class U> Vector<size, T>& operator/=(U number) {
#else
template<class U> inline typename std::enable_if<std::is_arithmetic<U>::value, Vector<size, T>&>::type operator/=(U number) {
#endif
for(std::size_t i = 0; i != size; ++i)
_data[i] /= number;
return *this;
}
/**
* @brief Divide vector with number
*
* @see operator/=(), operator/(U, const Vector<size, T>&)
*/
#ifdef DOXYGEN_GENERATING_OUTPUT
template<class U> inline Vector<size, T> operator/(U number) const {
#else
template<class U> inline typename std::enable_if<std::is_arithmetic<U>::value, Vector<size, T>>::type operator/(U number) const {
#endif
return Vector<size, T>(*this) /= number;
}
/**
* @brief Multiply vector component-wise and assign
*
@ -169,7 +381,7 @@ template<std::size_t size, class T> class Vector: public RectangularMatrix<1, si
*/
template<class U> Vector<size, T>& operator*=(const Vector<size, U>& other) {
for(std::size_t i = 0; i != size; ++i)
(*this)[i] *= other[i];
_data[i] *= other._data[i];
return *this;
}
@ -192,7 +404,7 @@ template<std::size_t size, class T> class Vector: public RectangularMatrix<1, si
*/
template<class U> Vector<size, T>& operator/=(const Vector<size, U>& other) {
for(std::size_t i = 0; i != size; ++i)
(*this)[i] /= other[i];
_data[i] /= other._data[i];
return *this;
}
@ -252,66 +464,83 @@ template<std::size_t size, class T> class Vector: public RectangularMatrix<1, si
T out(0);
for(std::size_t i = 0; i != size; ++i)
out += (*this)[i];
out += _data[i];
return out;
}
/** @brief Product of values in the vector */
T product() const {
T out(1);
T out(_data[0]);
for(std::size_t i = 0; i != size; ++i)
out *= (*this)[i];
for(std::size_t i = 1; i != size; ++i)
out *= _data[i];
return out;
}
/** @brief Minimal value in the vector */
T min() const {
T out((*this)[0]);
T out(_data[0]);
for(std::size_t i = 1; i != size; ++i)
out = std::min(out, (*this)[i]);
out = std::min(out, _data[i]);
return out;
}
/** @brief Maximal value in the vector */
T max() const {
T out((*this)[0]);
T out(_data[0]);
for(std::size_t i = 1; i != size; ++i)
out = std::max(out, (*this)[i]);
out = std::max(out, _data[i]);
return out;
}
#ifndef DOXYGEN_GENERATING_OUTPUT
/* Reimplementation of functions to return correct type */
template<std::size_t otherCols> inline RectangularMatrix<otherCols, size, T> operator*(const RectangularMatrix<otherCols, 1, T>& other) const {
return RectangularMatrix<1, size, T>::operator*(other);
private:
/* Implementation for from(const Vector<size, U>&) */
template<class U, std::size_t ...sequence> inline constexpr static Vector<sizeof...(sequence), T> from(Implementation::Sequence<sequence...>, const Vector<sizeof...(sequence), U>& vector) {
return {T(vector.data()[sequence])...};
}
MAGNUM_RECTANGULARMATRIX_SUBCLASS_IMPLEMENTATION(1, size, Vector<size, T>)
MAGNUM_RECTANGULARMATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(1, size, Vector<size, T>)
#endif
private:
/* 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();
T _data[size];
};
#ifndef DOXYGEN_GENERATING_OUTPUT
/** @relates Vector
@brief Multiply number with vector
Same as Vector::operator*(U) const.
*/
#ifdef DOXYGEN_GENERATING_OUTPUT
template<std::size_t size, class T, class U> inline Vector<size, T> operator*(U number, const Vector<size, T>& vector) {
#else
template<std::size_t size, class T, class U> inline typename std::enable_if<std::is_arithmetic<U>::value, Vector<size, T>>::type operator*(U number, const Vector<size, T>& vector) {
return number*RectangularMatrix<1, size, T>(vector);
#endif
return vector*number;
}
/** @relates Vector
@brief Divide vector with number and invert
@f[
\boldsymbol c_i = \frac b {\boldsymbol a_i}
@f]
@see Vector::operator/()
*/
#ifdef DOXYGEN_GENERATING_OUTPUT
template<std::size_t size, class T, class U> inline Vector<size, T> operator/(U number, const Vector<size, T>& vector) {
#else
template<std::size_t size, class T, class U> inline typename std::enable_if<std::is_arithmetic<U>::value, Vector<size, T>>::type operator/(U number, const Vector<size, T>& vector) {
return number/RectangularMatrix<1, size, T>(vector);
}
#endif
Vector<size, T> out;
for(std::size_t i = 0; i != size; ++i)
out[i] = number/vector[i];
return out;
}
/** @debugoperator{Magnum::Math::Vector} */
template<std::size_t size, class T> Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Vector<size, T>& value) {
@ -364,22 +593,50 @@ extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utilit
return *this; \
} \
\
template<std::size_t otherCols> inline Math::RectangularMatrix<otherCols, size, T> operator*(const Math::RectangularMatrix<otherCols, 1, T>& other) const { \
return Math::Vector<size, T>::operator*(other); \
inline Type<T> operator-() const { \
return Math::Vector<size, T>::operator-(); \
} \
template<class U> inline Type<T> operator*(const Math::Vector<size, U>& other) const { \
return Math::Vector<size, T>::operator*(other); \
inline Type<T>& operator+=(const Math::Vector<size, T>& other) { \
Math::Vector<size, T>::operator+=(other); \
return *this; \
} \
inline Type<T> operator+(const Math::Vector<size, T>& other) const { \
return Math::Vector<size, T>::operator+(other); \
} \
inline Type<T>& operator-=(const Math::Vector<size, T>& other) { \
Math::Vector<size, T>::operator-=(other); \
return *this; \
} \
inline Type<T> operator-(const Math::Vector<size, T>& other) const { \
return Math::Vector<size, T>::operator-(other); \
} \
template<class U> inline typename std::enable_if<std::is_arithmetic<U>::value, Type<T>&>::type operator*=(U number) { \
Math::Vector<size, T>::operator*=(number); \
return *this; \
} \
template<class U> inline typename std::enable_if<std::is_arithmetic<U>::value, Type<T>>::type operator*(U number) const { \
return Math::Vector<size, T>::operator*(number); \
} \
template<class U> inline typename std::enable_if<std::is_arithmetic<U>::value, Type<T>&>::type operator/=(U number) { \
Math::Vector<size, T>::operator/=(number); \
return *this; \
} \
template<class U> inline typename std::enable_if<std::is_arithmetic<U>::value, Type<T>>::type operator/(U number) const { \
return Math::Vector<size, T>::operator/(number); \
} \
template<class U> inline Type<T>& operator*=(const Math::Vector<size, U>& other) { \
Math::Vector<size, T>::operator*=(other); \
return *this; \
} \
template<class U> inline Type<T> operator/(const Math::Vector<size, U>& other) const { \
return Math::Vector<size, T>::operator/(other); \
template<class U> inline Type<T> operator*(const Math::Vector<size, U>& other) const { \
return Math::Vector<size, T>::operator*(other); \
} \
template<class U> inline Type<T>& operator/=(const Math::Vector<size, U>& other) { \
Math::Vector<size, T>::operator/=(other); \
return *this; \
} \
template<class U> inline Type<T> operator/(const Math::Vector<size, U>& other) const { \
return Math::Vector<size, T>::operator/(other); \
} \
\
inline Type<T> normalized() const { return Math::Vector<size, T>::normalized(); } \
@ -400,8 +657,60 @@ extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utilit
namespace Corrade { namespace Utility {
/** @configurationvalue{Magnum::Math::Vector} */
template<std::size_t size, class T> struct ConfigurationValue<Magnum::Math::Vector<size, T>>: public ConfigurationValue<Magnum::Math::RectangularMatrix<1, size, T>> {};
/** @configurationvalue{Magnum::Math::RectangularMatrix} */
template<std::size_t size, class T> struct ConfigurationValue<Magnum::Math::Vector<size, T>> {
ConfigurationValue() = delete;
/** @brief Writes elements separated with spaces */
static std::string toString(const Magnum::Math::Vector<size, T>& value, ConfigurationValueFlags flags) {
std::string output;
for(std::size_t i = 0; i != size; ++i) {
if(!output.empty()) output += ' ';
output += ConfigurationValue<T>::toString(value[i], flags);
}
return output;
}
/** @brief Reads elements separated with whitespace */
static Magnum::Math::Vector<size, T> fromString(const std::string& stringValue, ConfigurationValueFlags flags) {
Magnum::Math::Vector<size, T> result;
std::size_t oldpos = 0, pos = std::string::npos, i = 0;
do {
pos = stringValue.find(' ', oldpos);
std::string part = stringValue.substr(oldpos, pos-oldpos);
if(!part.empty()) {
result[i] = ConfigurationValue<T>::fromString(part, flags);
++i;
}
oldpos = pos+1;
} while(pos != std::string::npos);
return result;
}
};
#ifndef DOXYGEN_GENERATING_OUTPUT
/* Vectors */
extern template struct MAGNUM_EXPORT ConfigurationValue<Magnum::Math::Vector<2, float>>;
extern template struct MAGNUM_EXPORT ConfigurationValue<Magnum::Math::Vector<3, float>>;
extern template struct MAGNUM_EXPORT ConfigurationValue<Magnum::Math::Vector<4, float>>;
extern template struct MAGNUM_EXPORT ConfigurationValue<Magnum::Math::Vector<2, int>>;
extern template struct MAGNUM_EXPORT ConfigurationValue<Magnum::Math::Vector<3, int>>;
extern template struct MAGNUM_EXPORT ConfigurationValue<Magnum::Math::Vector<4, int>>;
extern template struct MAGNUM_EXPORT ConfigurationValue<Magnum::Math::Vector<2, unsigned int>>;
extern template struct MAGNUM_EXPORT ConfigurationValue<Magnum::Math::Vector<3, unsigned int>>;
extern template struct MAGNUM_EXPORT ConfigurationValue<Magnum::Math::Vector<4, unsigned int>>;
#ifndef MAGNUM_TARGET_GLES
extern template struct MAGNUM_EXPORT ConfigurationValue<Magnum::Math::Vector<2, double>>;
extern template struct MAGNUM_EXPORT ConfigurationValue<Magnum::Math::Vector<3, double>>;
extern template struct MAGNUM_EXPORT ConfigurationValue<Magnum::Math::Vector<4, double>>;
#endif
#endif
}}

3
src/Math/Vector2.h

@ -85,7 +85,7 @@ template<class T> class Vector2: public Vector<2, T> {
inline constexpr /*implicit*/ Vector2(T x, T y): Vector<2, T>(x, y) {}
/** @brief Copy constructor */
inline constexpr Vector2(const RectangularMatrix<1, 2, T>& other): Vector<2, T>(other) {}
inline constexpr Vector2(const Vector<2, T>& other): Vector<2, T>(other) {}
inline T& x() { return (*this)[0]; } /**< @brief X component */
inline constexpr T x() const { return (*this)[0]; } /**< @overload */
@ -93,7 +93,6 @@ template<class T> class Vector2: public Vector<2, T> {
inline constexpr T y() const { return (*this)[1]; } /**< @overload */
MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(Vector2, 2)
MAGNUM_RECTANGULARMATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(1, 2, Vector2<T>)
};
MAGNUM_VECTOR_SUBCLASS_OPERATOR_IMPLEMENTATION(Vector2, 2)

3
src/Math/Vector3.h

@ -126,7 +126,7 @@ template<class T> class Vector3: public Vector<3, T> {
inline constexpr /*implicit*/ Vector3(const Vector2<T>& xy, T z): Vector<3, T>(xy[0], xy[1], z) {}
/** @brief Copy constructor */
inline constexpr Vector3(const RectangularMatrix<1, 3, T>& other): Vector<3, T>(other) {}
inline constexpr Vector3(const Vector<3, T>& other): Vector<3, T>(other) {}
inline T& x() { return (*this)[0]; } /**< @brief X component */
inline constexpr T x() const { return (*this)[0]; } /**< @overload */
@ -145,7 +145,6 @@ template<class T> class Vector3: public Vector<3, T> {
inline constexpr Vector2<T> xy() const { return Vector2<T>::from(Vector<3, T>::data()); } /**< @overload */
MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(Vector3, 3)
MAGNUM_RECTANGULARMATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(1, 3, Vector3<T>)
};
MAGNUM_VECTOR_SUBCLASS_OPERATOR_IMPLEMENTATION(Vector3, 3)

3
src/Math/Vector4.h

@ -57,7 +57,7 @@ template<class T> class Vector4: public Vector<4, T> {
inline constexpr /*implicit*/ Vector4(const Vector3<T>& xyz, T w): Vector<4, T>(xyz[0], xyz[1], xyz[2], w) {}
/** @brief Copy constructor */
inline constexpr Vector4(const RectangularMatrix<1, 4, T>& other): Vector<4, T>(other) {}
inline constexpr Vector4(const Vector<4, T>& other): Vector<4, T>(other) {}
inline T& x() { return (*this)[0]; } /**< @brief X component */
inline constexpr T x() const { return (*this)[0]; } /**< @overload */
@ -87,7 +87,6 @@ template<class T> class Vector4: public Vector<4, T> {
inline constexpr Vector2<T> xy() const { return Vector2<T>::from(Vector<4, T>::data()); } /**< @overload */
MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(Vector4, 4)
MAGNUM_RECTANGULARMATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(1, 4, Vector4<T>)
};
MAGNUM_VECTOR_SUBCLASS_OPERATOR_IMPLEMENTATION(Vector4, 4)

2
src/Mesh.h

@ -210,6 +210,8 @@ for more information.
@todo Support for indirect draw buffer (OpenGL 4.0, @extension{ARB,draw_indirect})
@todo Redo in a way that allows glMultiDrawArrays, glDrawArraysInstanced etc.
@todo test vertex specification & drawing
@todo How to glDrawElementsBaseVertex()/vertex offset -- in draw()?
*/
class MAGNUM_EXPORT Mesh {
friend class Context;

32
src/SceneGraph/Test/CameraTest.cpp

@ -75,27 +75,27 @@ void CameraTest::fixAspectRatio() {
CORRADE_COMPARE((Implementation::aspectRatioFix<3, GLfloat>(AspectRatioPolicy::NotPreserved, projectionScale, size)), Matrix4());
/* Clip */
Matrix4 expectedClip(1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 4.0f/3.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f);
Matrix4 expectedClip({1.0f, 0.0f, 0.0f, 0.0f},
{0.0f, 4.0f/3.0f, 0.0f, 0.0f},
{0.0f, 0.0f, 1.0f, 0.0f},
{0.0f, 0.0f, 0.0f, 1.0f});
CORRADE_COMPARE((Implementation::aspectRatioFix<3, GLfloat>(AspectRatioPolicy::Clip, Vector2(0.5f), size)), expectedClip);
Matrix4 expectedClipRectangle(1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 2.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f);
Matrix4 expectedClipRectangle({1.0f, 0.0f, 0.0f, 0.0f},
{0.0f, 2.0f, 0.0f, 0.0f},
{0.0f, 0.0f, 1.0f, 0.0f},
{0.0f, 0.0f, 0.0f, 1.0f});
CORRADE_COMPARE((Implementation::aspectRatioFix<3, GLfloat>(AspectRatioPolicy::Clip, projectionScale, size)), expectedClipRectangle);
/* Extend */
Matrix4 expectedExtend(3.0f/4.0f, 0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f);
Matrix4 expectedExtend({3.0f/4.0f, 0.0f, 0.0f, 0.0f},
{ 0.0f, 1.0f, 0.0f, 0.0f},
{ 0.0f, 0.0f, 1.0f, 0.0f},
{ 0.0f, 0.0f, 0.0f, 1.0f});
CORRADE_COMPARE((Implementation::aspectRatioFix<3, GLfloat>(AspectRatioPolicy::Extend, Vector2(0.5f), size)), expectedExtend);
Matrix4 expectedExtendRectangle(0.5f, 0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f);
Matrix4 expectedExtendRectangle({0.5f, 0.0f, 0.0f, 0.0f},
{0.0f, 1.0f, 0.0f, 0.0f},
{0.0f, 0.0f, 1.0f, 0.0f},
{0.0f, 0.0f, 0.0f, 1.0f});
CORRADE_COMPARE((Implementation::aspectRatioFix<3, GLfloat>(AspectRatioPolicy::Extend, projectionScale, size)), expectedExtendRectangle);
}

Loading…
Cancel
Save