Browse Source

Merge branch 'master' into compatibility

Vladimír Vondruš 14 years ago
parent
commit
2268ded69c
  1. 9
      doc/namespaces.dox
  2. 52
      src/Buffer.h
  3. 18
      src/Color.h
  4. 3
      src/Image.h
  5. 3
      src/ImageWrapper.h
  6. 8
      src/Math/Algorithms/CMakeLists.txt
  7. 113
      src/Math/Algorithms/GaussJordan.h
  8. 1
      src/Math/Algorithms/Test/CMakeLists.txt
  9. 60
      src/Math/Algorithms/Test/GaussJordanTest.cpp
  10. 32
      src/Math/Algorithms/Test/GaussJordanTest.h
  11. 2
      src/Math/CMakeLists.txt
  12. 6
      src/Math/Math.h
  13. 1
      src/Math/MathTypeTraits.h
  14. 242
      src/Math/Matrix.h
  15. 5
      src/Math/Matrix3.h
  16. 5
      src/Math/Matrix4.h
  17. 467
      src/Math/RectangularMatrix.h
  18. 2
      src/Math/Test/CMakeLists.txt
  19. 7
      src/Math/Test/MathTest.cpp
  20. 1
      src/Math/Test/MathTest.h
  21. 142
      src/Math/Test/MatrixTest.cpp
  22. 8
      src/Math/Test/MatrixTest.h
  23. 237
      src/Math/Test/RectangularMatrixTest.cpp
  24. 44
      src/Math/Test/RectangularMatrixTest.h
  25. 69
      src/Math/Test/VectorTest.cpp
  26. 5
      src/Math/Test/VectorTest.h
  27. 298
      src/Math/Vector.h
  28. 5
      src/Math/Vector2.h
  29. 5
      src/Math/Vector3.h
  30. 5
      src/Math/Vector4.h
  31. 5
      src/Mesh.h
  32. 8
      src/MeshTools/Clean.h
  33. 2
      src/MeshTools/Test/CleanTest.h
  34. 2
      src/MeshTools/Test/SubdivideTest.h
  35. 2
      src/SceneGraph/Camera.cpp
  36. 2
      src/Swizzle.h
  37. 3
      src/Trade/ImageData.h

9
doc/namespaces.dox

@ -28,6 +28,15 @@ Base classes for creating OpenGL contexts with various toolkits.
Template classes for matrix and vector calculations.
*/
/** @dir Math/Algorithms
* @brief Namespace Magnum::Math::Algorithms
*/
/** @namespace Magnum::Math::Algorithms
@brief %Algorithms
Various matrix and vector algorithms.
*/
/** @dir Math/Geometry
* @brief Namespace Magnum::Math::Geometry
*/

52
src/Buffer.h

@ -237,6 +237,19 @@ class Buffer {
setData(_defaultTarget, size, data, usage);
}
/**
* @brief Set buffer data
* @param data Fixed-size array with data
* @param usage %Buffer usage
*
* Sets buffer data with default target. More convenient for setting
* data from fixed-size arrays than
* setData(GLsizeiptr, const GLvoid*, Usage).
*/
template<size_t size, class T> inline void setData(const T(&data)[size], Usage usage) {
setData(_defaultTarget, data, usage);
}
/**
* @brief Set buffer data
* @param data Vector with data
@ -260,6 +273,19 @@ class Buffer {
glBufferData(static_cast<GLenum>(target), size, data, static_cast<GLenum>(usage));
}
/**
* @brief Set buffer data
* @param target %Target
* @param data Fixed-size array with data
* @param usage %Buffer usage
*
* More convenient for setting data from fixed-size arrays than
* setData(Target, GLsizeiptr, const GLvoid*, Usage).
*/
template<size_t size, class T> inline void setData(Target target, const T(&data)[size], Usage usage) {
setData(target, size*sizeof(T), data, usage);
}
/**
* @brief Set buffer data
* @param target %Target
@ -282,6 +308,19 @@ class Buffer {
setSubData(_defaultTarget, offset, size, data);
}
/**
* @brief Set buffer subdata
* @param offset Offset
* @param data Fixed-size array with data
*
* Sets buffer subdata with default target. More convenient for
* setting data from fixed-size arrays than
* setSubData(GLintptr, GLsizeiptr, const GLvoid*).
*/
template<size_t size, class T> inline void setSubData(GLintptr offset, const T(&data)[size]) {
setSubData(_defaultTarget, offset, data);
}
/**
* @brief Set buffer subdata
* @param offset Offset
@ -305,6 +344,19 @@ class Buffer {
glBufferSubData(static_cast<GLenum>(target), offset, size, data);
}
/**
* @brief Set buffer subdata
* @param target %Target
* @param offset Offset
* @param data Fixed-size array with data
*
* More convenient for setting data from fixed-size arrays than
* setSubData(Target, GLintptr, GLsizeiptr, const GLvoid*).
*/
template<size_t size, class T> inline void setSubData(Target target, GLintptr offset, const T(&data)[size]) {
setSubData(target, offset, size*sizeof(T), data);
}
/**
* @brief Set buffer subdata
* @param target %Target

18
src/Color.h

@ -213,8 +213,8 @@ template<class T> class Color3: public Math::Vector3<T> {
*/
inline constexpr explicit Color3(T rgb): Math::Vector3<T>(rgb) {}
/** @copydoc Math::Vector::Vector(const Vector&) */
inline constexpr Color3(const Math::Vector<3, T>& other): Math::Vector3<T>(other) {}
/** @brief Copy constructor */
inline constexpr Color3(const Math::RectangularMatrix<1, 3, T>& other): Math::Vector3<T>(other) {}
/**
* @brief Constructor
@ -276,8 +276,13 @@ template<class T> class Color3: public Math::Vector3<T> {
inline constexpr FloatingPointType value() const {
return Implementation::value<T>(*this);
}
MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(Color3, 3)
MAGNUM_RECTANGULARMATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(1, 3, Color3<T>)
};
MAGNUM_VECTOR_SUBCLASS_OPERATOR_IMPLEMENTATION(Color3, 3)
/**
@brief Four-component (RGBA) color
@ -335,8 +340,8 @@ template<class T> class Color4: public Math::Vector4<T> {
*/
inline constexpr explicit Color4(T rgb, T alpha = Implementation::defaultAlpha<T>()): Math::Vector4<T>(rgb, rgb, rgb, alpha) {}
/** @copydoc Math::Vector::Vector(const Vector&) */
inline constexpr Color4(const Math::Vector<4, T>& other): Math::Vector4<T>(other) {}
/** @brief Copy constructor */
inline constexpr Color4(const Math::RectangularMatrix<1, 4, T>& other): Math::Vector4<T>(other) {}
/**
* @brief Constructor
@ -394,8 +399,13 @@ template<class T> class Color4: public Math::Vector4<T> {
inline constexpr FloatingPointType value() const {
return Implementation::value<T>(rgb());
}
MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(Color4, 4)
MAGNUM_RECTANGULARMATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(1, 4, Color4<T>)
};
MAGNUM_VECTOR_SUBCLASS_OPERATOR_IMPLEMENTATION(Color4, 4)
/** @debugoperator{Magnum::Color3} */
template<class T> Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Magnum::Color3<T>& value) {
return debug << static_cast<const Magnum::Math::Vector3<T>&>(value);

3
src/Image.h

@ -76,7 +76,8 @@ template<size_t imageDimensions> class Image: public AbstractImage {
inline constexpr const Math::Vector<Dimensions, GLsizei>& dimensions() const { return _dimensions; }
/** @brief Pointer to raw data */
inline constexpr const void* data() const { return _data; }
inline void* data() { return _data; }
inline constexpr const void* data() const { return _data; } /**< @overload */
/**
* @brief Set image data

3
src/ImageWrapper.h

@ -81,7 +81,8 @@ template<size_t imageDimensions> class ImageWrapper: public AbstractImage {
inline constexpr const Math::Vector<Dimensions, GLsizei>& dimensions() const { return _dimensions; }
/** @brief Pointer to raw data */
inline constexpr const void* data() const { return _data; }
inline void* data() { return _data; }
inline constexpr const void* data() const { return _data; } /**< @overload */
/**
* @brief Set image data

8
src/Math/Algorithms/CMakeLists.txt

@ -0,0 +1,8 @@
set(MagnumMathAlgorithms_HEADERS
GaussJordan.h)
install(FILES ${MagnumMathAlgorithms_HEADERS} DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Math/Algorithms)
if(BUILD_TESTS)
enable_testing()
add_subdirectory(Test)
endif()

113
src/Math/Algorithms/GaussJordan.h

@ -0,0 +1,113 @@
#ifndef Magnum_Math_Algorithms_GaussJordan_h
#define Magnum_Math_Algorithms_GaussJordan_h
/*
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz>
This file is part of Magnum.
Magnum is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 3
only, as published by the Free Software Foundation.
Magnum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License version 3 for more details.
*/
/** @file
* @brief Class GaussJordan
*/
#include "Math/RectangularMatrix.h"
namespace Magnum { namespace Math { namespace Algorithms {
/**
@brief Gauss-Jordan elimination
Based on ultra-compact Python code by Jarno Elonen,
http://elonen.iki.fi/code/misc-notes/python-gaussj/index.html.
*/
class GaussJordan {
public:
/**
* @brief Eliminate transposed matrices in place
* @param a Transposed left side of augmented matrix
* @param t Transposed right side of augmented matrix
* @return True if @p a is regular, false if @p a is singular (and
* thus the system cannot be solved).
*
* As Gauss-Jordan elimination works on rows and matrices in OpenGL
* are column-major, it is more efficient to operate on transposed
* matrices and treat columns as rows. See also inPlace() which works
* with non-transposed matrices.
*
* The function eliminates matrix @p a and solves @p t in place. For
* efficiency reasons, only pure Gaussian elimination is done on @p a
* and the final backsubstitution is done only on @p t, as @p a would
* always end with identity matrix anyway.
*/
template<size_t size, size_t rows, class T> static bool inPlaceTransposed(RectangularMatrix<size, size, T>& a, RectangularMatrix<size, rows, T>& t);
/**
* @brief Eliminate in place
*
* Transposes the matrices, calls inPlaceTransposed() on them and then
* transposes them back.
*/
template<size_t size, size_t cols, class T> static bool inPlace(RectangularMatrix<size, size, T>& a, RectangularMatrix<cols, size, T>& t) {
a = a.transposed();
RectangularMatrix<size, cols, T> tTransposed = t.transposed();
bool ret = inPlaceTransposed(a, tTransposed);
a = a.transposed();
t = tTransposed.transposed();
return ret;
}
};
template<size_t size, size_t cols, class T> bool GaussJordan::inPlaceTransposed(RectangularMatrix<size, size, T>& a, RectangularMatrix<size, cols, T>& t) {
for(size_t row = 0; row != size; ++row) {
/* Find max pivot */
size_t rowMax = row;
for(size_t row2 = row+1; row2 != size; ++row2)
if(std::abs(a(row2, row)) > std::abs(a(rowMax, row)))
rowMax = row2;
/* Swap the rows */
std::swap(a[row], a[rowMax]);
std::swap(t[row], t[rowMax]);
/* Singular */
if(MathTypeTraits<T>::equals(a(row, row), 0))
return false;
/* Eliminate column */
for(size_t row2 = row+1; row2 != size; ++row2) {
T c = a(row2, row)/a(row, row);
a[row2] -= a[row]*c;
t[row2] -= t[row]*c;
}
}
/* Backsubstitute */
for(size_t row = size; row != 0; --row) {
T c = T(1)/a(row-1, row-1);
for(size_t row2 = 0; row2 != row-1; ++row2)
t[row2] -= t[row-1]*a(row2, row-1)*c;
/* Normalize the row */
t[row-1] *= c;
}
return true;
}
}}}
#endif

1
src/Math/Algorithms/Test/CMakeLists.txt

@ -0,0 +1 @@
corrade_add_test2(MathAlgorithmsGaussJordanTest GaussJordanTest.cpp)

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

@ -0,0 +1,60 @@
/*
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz>
This file is part of Magnum.
Magnum is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 3
only, as published by the Free Software Foundation.
Magnum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License version 3 for more details.
*/
#include "GaussJordanTest.h"
#include "Math/Algorithms/GaussJordan.h"
CORRADE_TEST_MAIN(Magnum::Math::Algorithms::Test::GaussJordanTest)
namespace Magnum { namespace Math { namespace Algorithms { namespace Test {
typedef RectangularMatrix<4, 4, float> Matrix4;
GaussJordanTest::GaussJordanTest() {
addTests(&GaussJordanTest::singular,
&GaussJordanTest::invert);
}
void GaussJordanTest::singular() {
Matrix4 a(1.0f, 2.0f, 3.0f, 4.0f,
2.0f, 3.0f, -7.0f, 11.0f,
2.0f, 4.0f, 6.0f, 8.0f,
1.0f, 2.0f, 7.0f, 40.0f);
RectangularMatrix<4, 1, float> t;
CORRADE_VERIFY(!GaussJordan::inPlaceTransposed(a, t));
}
void GaussJordanTest::invert() {
Matrix4 a(3.0f, 5.0f, 8.0f, 4.0f,
4.0f, 4.0f, 7.0f, 3.0f,
7.0f, -1.0f, 8.0f, 0.0f,
9.0f, 4.0f, 5.0f, 9.0f);
Matrix4 expectedInverse(-60/103.0f, 71/103.0f, -4/103.0f, 3/103.0f,
-66/103.0f, 109/103.0f, -25/103.0f, -7/103.0f,
177/412.0f, -97/206.0f, 53/412.0f, -7/206.0f,
259/412.0f, -185/206.0f, 31/412.0f, 27/206.0f);
Matrix4 a2(a);
Matrix4 inverse;
CORRADE_VERIFY(GaussJordan::inPlace(a2, inverse));
CORRADE_COMPARE(inverse, expectedInverse);
CORRADE_COMPARE(a*inverse, Matrix4());
}
}}}}

32
src/Math/Algorithms/Test/GaussJordanTest.h

@ -0,0 +1,32 @@
#ifndef Magnum_Math_Algorithms_Test_GaussJordanTest_h
#define Magnum_Math_Algorithms_Test_GaussJordanTest_h
/*
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz>
This file is part of Magnum.
Magnum is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 3
only, as published by the Free Software Foundation.
Magnum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License version 3 for more details.
*/
#include <TestSuite/Tester.h>
namespace Magnum { namespace Math { namespace Algorithms { namespace Test {
class GaussJordanTest: public Corrade::TestSuite::Tester<GaussJordanTest> {
public:
GaussJordanTest();
void singular();
void invert();
};
}}}}
#endif

2
src/Math/CMakeLists.txt

@ -6,12 +6,14 @@ set(MagnumMath_HEADERS
Matrix.h
Matrix3.h
Matrix4.h
RectangularMatrix.h
Vector.h
Vector2.h
Vector3.h
Vector4.h)
install(FILES ${MagnumMath_HEADERS} DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Math)
add_subdirectory(Algorithms)
add_subdirectory(Geometry)
if(BUILD_TESTS)

6
src/Math/Math.h

@ -19,6 +19,7 @@
#include <cmath>
#include <type_traits>
#include <limits>
#include <algorithm>
#include "magnumCompatibility.h"
#include "magnumVisibility.h"
@ -130,6 +131,11 @@ template<class Integral, class FloatingPoint> inline constexpr typename std::ena
FloatingPoint(value*std::numeric_limits<Integral>::min()));
}
/** @brief Clamp value */
template<class T> inline T clamp(T value, T min, T max) {
return std::min(std::max(value, min), max);
}
/**
@brief Angle in degrees

1
src/Math/MathTypeTraits.h

@ -19,6 +19,7 @@
* @brief Class Magnum::Math::MathTypeTraits
*/
#include <cstddef>
#include <cmath>
#include "magnumCompatibility.h"

242
src/Math/Matrix.h

@ -19,7 +19,7 @@
* @brief Class Magnum::Math::Matrix
*/
#include "Vector.h"
#include "RectangularMatrix.h"
namespace Magnum { namespace Math {
@ -30,46 +30,16 @@ namespace Implementation {
#endif
/**
@brief %Matrix
@brief Square matrix
@tparam s %Matrix size
@configurationvalueref{Magnum::Math::Matrix}
@todo @c PERFORMANCE - loop unrolling for Matrix<3, T> and Matrix<4, T>
@todo first col, then row (cache adjacency)
*/
template<size_t size, class T> class Matrix {
static_assert(size != 0, "Matrix cannot have zero elements");
friend class Matrix<size+1, T>; /* for ij() */
template<size_t s, class T> class Matrix: public RectangularMatrix<s, s, T> {
public:
const static size_t Size = size; /**< @brief %Matrix size */
typedef T Type; /**< @brief %Matrix data type */
/**
* @brief %Matrix from array
* @return Reference to the data as if it was Matrix, thus doesn't
* perform any copying.
*
* @attention Use with caution, the function doesn't check whether the
* array is long enough.
*/
inline constexpr static Matrix<size, T>& from(T* data) {
return *reinterpret_cast<Matrix<size, T>*>(data);
}
/** @overload */
inline constexpr static const Matrix<size, T>& from(const T* data) {
return *reinterpret_cast<const Matrix<size, T>*>(data);
}
/**
* @brief %Matrix from column vectors
* @param first First column vector
* @param next Next column vectors
*/
template<class ...U> inline constexpr static Matrix<size, T> from(const Vector<size, T>& first, const U&... next) {
static_assert(sizeof...(next)+1 == size, "Improper number of arguments passed to Matrix from Vector constructor");
return from(typename Implementation::GenerateSequence<size>::Type(), first, next...);
}
const static size_t size = s; /**< @brief %Matrix size */
/** @brief Pass to constructor to create zero-filled matrix */
enum ZeroType { Zero };
@ -79,7 +49,7 @@ template<size_t size, class T> class Matrix {
*
* Use this constructor by calling `Matrix m(Matrix::Zero);`.
*/
inline constexpr explicit Matrix(ZeroType): _data() {}
inline constexpr explicit Matrix(ZeroType) {}
/** @brief Pass to constructor to create identity matrix */
enum IdentityType { Identity };
@ -91,117 +61,38 @@ template<size_t size, class T> class Matrix {
* `Matrix m(Matrix::Identity);`. Optional parameter @p value allows
* you to specify value on diagonal.
*/
inline explicit Matrix(IdentityType = Identity, T value = T(1)): _data() {
inline explicit Matrix(IdentityType = Identity, T value = T(1)) {
for(size_t i = 0; i != size; ++i)
_data[size*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 Remove workaround when Doxygen supports uniform initialization
*/
/** @copydoc RectangularMatrix::RectangularMatrix(T, U...) */
#ifndef DOXYGEN_GENERATING_OUTPUT
template<class ...U> inline constexpr Matrix(T first, U... next): _data{first, next...} {
static_assert(sizeof...(next)+1 == size*size, "Improper number of arguments passed to Matrix constructor");
}
template<class ...U> inline constexpr Matrix(T first, U... next): RectangularMatrix<size, size, T>(first, next...) {}
#else
template<class ...U> inline constexpr Matrix(T first, U... next);
#endif
/** @brief Copy constructor */
inline constexpr Matrix(const Matrix<size, T>&) = default;
/** @brief Assignment operator */
inline Matrix<size, T>& operator=(const Matrix<size, T>&) = default;
inline constexpr Matrix(const RectangularMatrix<size, size, T>& other): RectangularMatrix<size, size, T>(other) {}
/**
* @brief Raw data
* @return One-dimensional array of `size*size` length in column-major
* order.
*/
inline T* data() { return _data; }
inline constexpr const T* data() const { return _data; } /**< @overload */
/**
* @brief %Matrix column
*
* For accessing individual elements prefer to use operator(), as it
* is guaranteed to not involve unnecessary conversions.
*/
inline Vector<size, T>& operator[](size_t col) {
return Vector<size, T>::from(_data+col*size);
}
/** @overload */
inline constexpr const Vector<size, T>& operator[](size_t col) const {
return Vector<size, T>::from(_data+col*size);
/** @brief Multiply and assign matrix operator */
inline Matrix<size, T>& operator*=(const RectangularMatrix<size, size, T>& other) {
return (*this = *this*other);
}
/**
* @brief Element on given position
* @brief Trace of the matrix
*
* Prefer this instead of using `[][]`.
* @see operator[]
* @f[
* tr(A) = \sum_{i=1}^n a_{i,i}
* @f]
*/
inline T& operator()(size_t col, size_t row) {
return _data[col*size+row];
}
/** @overload */
inline constexpr const T& operator()(size_t col, size_t row) const {
return _data[col*size+row];
}
/** @brief Equality operator */
inline bool operator==(const Matrix<size, T>& other) const {
for(size_t i = 0; i != size*size; ++i)
if(!MathTypeTraits<T>::equals(_data[i], other._data[i])) return false;
return true;
}
/** @brief Non-equality operator */
inline constexpr bool operator!=(const Matrix<size, T>& other) const {
return !operator==(other);
}
/** @brief Multiply matrix operator */
Matrix<size, T> operator*(const Matrix<size, T>& other) const {
Matrix<size, T> out(Zero);
for(size_t row = 0; row != size; ++row)
for(size_t col = 0; col != size; ++col)
for(size_t pos = 0; pos != size; ++pos)
out(col, row) += (*this)(pos, row)*other(col, pos);
return out;
}
/** @brief Multiply and assign matrix operator */
inline Matrix<size, T>& operator*=(const Matrix<size, T>& other) {
return (*this = *this*other);
}
/** @brief Multiply vector operator */
Vector<size, T> operator*(const Vector<size, T>& other) const {
Vector<size, T> out;
for(size_t row = 0; row != size; ++row)
for(size_t pos = 0; pos != size; ++pos)
out[row] += (*this)(pos, row)*other[pos];
return out;
}
/** @brief Transposed matrix */
Matrix<size, T> transposed() const {
Matrix<size, T> out(Zero);
T trace() const {
T out(0);
for(size_t row = 0; row != size; ++row)
for(size_t col = 0; col != size; ++col)
out(row, col) = (*this)(col, row);
for(size_t i = 0; i != size; ++i)
out += (*this)(i, i);
return out;
}
@ -254,32 +145,34 @@ template<size_t size, class T> class Matrix {
return out;
}
private:
template<size_t ...sequence, class ...U> inline constexpr static Matrix<size, T> from(Implementation::Sequence<sequence...> s, const Vector<size, T>& first, U... next) {
return from(s, next..., first[sequence]...);
#ifndef DOXYGEN_GENERATING_OUTPUT
/* Reimplementation of functions to return correct type */
inline Matrix<size, T> operator*(const Matrix<size, T>& other) const {
return RectangularMatrix<size, size, T>::operator*(other);
}
template<size_t ...sequence, class ...U> inline constexpr static Matrix<size, T> from(Implementation::Sequence<sequence...>, T first, U... next) {
return Matrix<size, T>(first, next...);
template<size_t otherCols> inline RectangularMatrix<otherCols, size, T> operator*(const RectangularMatrix<otherCols, size, T>& other) const {
return RectangularMatrix<size, size, T>::operator*(other);
}
T _data[size*size];
inline Vector<size, T> operator*(const Vector<size, T>& other) const {
return RectangularMatrix<size, size, T>::operator*(other);
}
MAGNUM_RECTANGULARMATRIX_SUBCLASS_IMPLEMENTATION(size, size, Matrix<size, T>)
MAGNUM_RECTANGULARMATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(size, size, Matrix<size, T>)
#endif
};
#ifndef DOXYGEN_GENERATING_OUTPUT
template<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<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);
}
#endif
/** @debugoperator{Magnum::Math::Matrix} */
template<size_t size, class T> Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Magnum::Math::Matrix<size, T>& value) {
debug << "Matrix(";
debug.setFlag(Corrade::Utility::Debug::SpaceAfterEachValue, false);
for(size_t row = 0; row != size; ++row) {
if(row != 0) debug << ",\n ";
for(size_t col = 0; col != size; ++col) {
if(col != 0) debug << ", ";
debug << typename MathTypeTraits<T>::NumericType(value[col][row]);
}
}
debug << ')';
debug.setFlag(Corrade::Utility::Debug::SpaceAfterEachValue, true);
return debug;
return debug << static_cast<const Magnum::Math::RectangularMatrix<size, size, T>&>(value);
}
#ifndef DOXYGEN_GENERATING_OUTPUT
@ -313,6 +206,9 @@ template<size_t size, class T> Corrade::Utility::Debug operator<<(Corrade::Utili
Matrix<size, T>::operator*=(other); \
return *this; \
} \
template<size_t otherCols> inline RectangularMatrix<otherCols, size, T> operator*(const RectangularMatrix<otherCols, size, T>& other) const { \
return Matrix<size, T>::operator*(other); \
} \
inline VectorType<T> operator*(const Vector<size, T>& other) const { \
return Matrix<size, T>::operator*(other); \
} \
@ -320,6 +216,14 @@ template<size_t size, class T> Corrade::Utility::Debug operator<<(Corrade::Utili
inline Type<T> transposed() const { return Matrix<size, T>::transposed(); } \
inline Type<T> inverted() const { return Matrix<size, T>::inverted(); }
#define MAGNUM_MATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(Type, size) \
template<class T, class U> inline typename std::enable_if<std::is_arithmetic<U>::value, Type<T>>::type operator*(U number, const Type<T>& matrix) { \
return number*Matrix<size, T>(matrix); \
} \
template<class T, class U> inline typename std::enable_if<std::is_arithmetic<U>::value, Type<T>>::type operator/(U number, const Type<T>& matrix) { \
return number/Matrix<size, T>(matrix); \
}
namespace Implementation {
template<size_t size, class T> class MatrixDeterminant {
@ -357,40 +261,8 @@ template<class T> class MatrixDeterminant<1, T> {
}}
namespace Corrade { namespace Utility {
/** @configurationvalue{Magnum::Math::Matrix} */
template<size_t size, class T> struct ConfigurationValue<Magnum::Math::Matrix<size, T>> {
/** @brief Writes elements separated with spaces */
static std::string toString(const Magnum::Math::Matrix<size, T>& value, int flags = 0) {
std::string output;
for(size_t row = 0; row != size; ++row) {
for(size_t col = 0; col != size; ++col) {
if(!output.empty()) output += ' ';
output += ConfigurationValue<T>::toString(value(col, row), flags);
}
}
return output;
}
/** @brief Reads elements separated with whitespace */
static Magnum::Math::Matrix<size, T> fromString(const std::string& stringValue, int flags = 0) {
Magnum::Math::Matrix<size, T> result(Magnum::Math::Matrix<size, T>::Zero);
std::istringstream in(stringValue);
for(size_t row = 0; row != size; ++row) {
for(size_t col = 0; col != size; ++col) {
std::string num;
in >> num;
result(col, row) = ConfigurationValue<T>::fromString(num, flags);
}
}
return result;
}
};
/** @configurationvalue{Magnum::Math::Matrix} */
template<size_t size, class T> struct ConfigurationValue<Magnum::Math::Matrix<size, T>>: public ConfigurationValue<Magnum::Math::RectangularMatrix<size, size, T>> {};
}}
#endif

5
src/Math/Matrix3.h

@ -92,10 +92,11 @@ template<class T> class Matrix3: public Matrix<3, T> {
template<class ...U> inline constexpr Matrix3(T first, U... next) {}
#endif
/** @copydoc Matrix::Matrix(const Matrix<size, T>&) */
inline constexpr Matrix3(const Matrix<3, T>& other): Matrix<3, T>(other) {}
/** @brief Copy constructor */
inline constexpr Matrix3(const RectangularMatrix<3, 3, T>& other): Matrix<3, T>(other) {}
MAGNUM_MATRIX_SUBCLASS_IMPLEMENTATION(Matrix3, Vector3, 3)
MAGNUM_RECTANGULARMATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(3, 3, Matrix3<T>)
};
/** @debugoperator{Magnum::Math::Matrix3} */

5
src/Math/Matrix4.h

@ -122,8 +122,8 @@ template<class T> class Matrix4: public Matrix<4, T> {
template<class ...U> inline constexpr Matrix4(T first, U... next) {}
#endif
/** @copydoc Matrix::Matrix(const Matrix<size, T>&) */
inline constexpr Matrix4(const Matrix<4, T>& other): Matrix<4, T>(other) {}
/** @brief Copy constructor */
inline constexpr Matrix4(const RectangularMatrix<4, 4, T>& other): Matrix<4, T>(other) {}
/** @copydoc Matrix::ij() */
inline Matrix3<T> ij(size_t skipRow, size_t skipCol) const { return Matrix<4, T>::ij(skipRow, skipCol); }
@ -158,6 +158,7 @@ template<class T> class Matrix4: public Matrix<4, T> {
}
MAGNUM_MATRIX_SUBCLASS_IMPLEMENTATION(Matrix4, Vector4, 4)
MAGNUM_RECTANGULARMATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(4, 4, Matrix4<T>)
};
/** @debugoperator{Magnum::Math::Matrix4} */

467
src/Math/RectangularMatrix.h

@ -0,0 +1,467 @@
#ifndef Magnum_Math_RectangularMatrix_h
#define Magnum_Math_RectangularMatrix_h
/*
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz>
This file is part of Magnum.
Magnum is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 3
only, as published by the Free Software Foundation.
Magnum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License version 3 for more details.
*/
/** @file
* @brief Class Magnum::Math::RectangularMatrix
*/
#include <cmath>
#include <limits>
#include <Utility/Debug.h>
#include <Utility/Configuration.h>
#include "MathTypeTraits.h"
namespace Magnum { namespace Math {
#ifndef DOXYGEN_GENERATING_OUTPUT
namespace Implementation {
template<size_t ...> struct Sequence {};
/* E.g. GenerateSequence<3>::Type is Sequence<0, 1, 2> */
template<size_t N, size_t ...sequence> struct GenerateSequence:
GenerateSequence<N-1, N-1, sequence...> {};
template<size_t ...sequence> struct GenerateSequence<0, sequence...> {
typedef Sequence<sequence...> Type;
};
}
#endif
template<size_t size, class T> class Vector;
/**
@brief Rectangular matrix
@tparam c Column count
@tparam r Row count
See also Matrix (square) and Vector.
*/
template<size_t c, size_t r, class T> class RectangularMatrix {
static_assert(c != 0 && r != 0, "Matrix cannot have zero elements");
friend class Vector<r, T>;
public:
typedef T Type; /**< @brief Data type */
const static size_t cols = c; /**< @brief %Matrix column count */
const static size_t rows = r; /**< @brief %Matrix row count */
/**
* @brief %Matrix from array
* @return Reference to the data as if it was Matrix, thus doesn't
* perform any copying.
*
* @attention Use with caution, the function doesn't check whether the
* array is long enough.
*/
inline constexpr static RectangularMatrix<cols, rows, T>& from(T* data) {
return *reinterpret_cast<RectangularMatrix<cols, rows, T>*>(data);
}
/** @overload */
inline constexpr static const RectangularMatrix<cols, rows, T>& from(const T* data) {
return *reinterpret_cast<const RectangularMatrix<cols, rows, T>*>(data);
}
/**
* @brief %Matrix from column vectors
* @param first First column vector
* @param next Next column vectors
*/
template<class ...U> inline constexpr static RectangularMatrix<cols, rows, T> from(const Vector<rows, T>& first, const U&... next) {
static_assert(sizeof...(next)+1 == cols, "Improper number of arguments passed to Matrix from Vector constructor");
return from(typename Implementation::GenerateSequence<rows>::Type(), first, next...);
}
/** @brief Zero-filled matrix constructor */
inline constexpr RectangularMatrix(): _data() {}
/**
* @brief Initializer-list constructor
* @param first First value
* @param next Next values
*
* Note that the values are in column-major order.
* @todoc Remove workaround when Doxygen supports uniform initialization
*/
#ifndef DOXYGEN_GENERATING_OUTPUT
template<class ...U> inline constexpr RectangularMatrix(T first, U... next): _data{first, next...} {
static_assert(sizeof...(next)+1 == cols*rows, "Improper number of arguments passed to Matrix constructor");
}
#else
template<class ...U> inline constexpr RectangularMatrix(T first, U... next);
#endif
/** @brief Copy constructor */
inline constexpr RectangularMatrix(const RectangularMatrix<c, r, T>&) = default;
/** @brief Assignment operator */
inline RectangularMatrix<c, r, T>& operator=(const RectangularMatrix<c, r, T>&) = default;
/**
* @brief Raw data
* @return One-dimensional array of `size*size` length in column-major
* order.
*/
inline T* data() { return _data; }
inline constexpr const T* data() const { return _data; } /**< @overload */
/**
* @brief %Matrix column
*
* For accessing individual elements prefer to use operator(), as it
* is guaranteed to not involve unnecessary conversions.
*/
inline Vector<rows, T>& operator[](size_t col) {
return Vector<rows, T>::from(_data+col*rows);
}
/** @overload */
inline constexpr const Vector<rows, T>& operator[](size_t col) const {
return Vector<rows, T>::from(_data+col*rows);
}
/**
* @brief Element on given position
*
* Prefer this instead of using `[][]`.
* @see operator[]
*/
inline T& operator()(size_t col, size_t row) {
return _data[col*rows+row];
}
/** @overload */
inline constexpr const T& operator()(size_t col, size_t row) const {
return _data[col*rows+row];
}
/** @brief Equality operator */
inline bool operator==(const RectangularMatrix<cols, rows, T>& other) const {
for(size_t i = 0; i != cols*rows; ++i)
if(!MathTypeTraits<T>::equals(_data[i], other._data[i])) return false;
return true;
}
/** @brief Non-equality operator */
inline constexpr bool operator!=(const RectangularMatrix<cols, rows, T>& other) const {
return !operator==(other);
}
/**
* @brief Add matrix
*
* @see operator+=()
*/
inline RectangularMatrix<cols, rows, T> operator+(const RectangularMatrix<cols, rows, T>& other) const {
return RectangularMatrix<cols, rows, T>(*this)+=other;
}
/**
* @brief Add and assign matrix
*
* More efficient than operator+(), because it does the computation
* in-place.
*/
RectangularMatrix<cols, rows, T>& operator+=(const RectangularMatrix<cols, rows, T>& other) {
for(size_t i = 0; i != cols*rows; ++i)
_data[i] += other._data[i];
return *this;
}
/** @brief Negative matrix */
RectangularMatrix<cols, rows, T> operator-() const {
RectangularMatrix<cols, rows, T> out;
for(size_t i = 0; i != cols*rows; ++i)
out._data[i] = -_data[i];
return out;
}
/**
* @brief Subtract matrix
*
* @see operator-=()
*/
inline RectangularMatrix<cols, rows, T> operator-(const RectangularMatrix<cols, rows, T>& other) const {
return RectangularMatrix<cols, rows, T>(*this)-=other;
}
/**
* @brief Subtract and assign matrix
*
* More efficient than operator-(), because it does the computation
* in-place.
*/
RectangularMatrix<cols, rows, T>& operator-=(const RectangularMatrix<cols, rows, T>& other) {
for(size_t i = 0; i != cols*rows; ++i)
_data[i] -= other._data[i];
return *this;
}
/**
* @brief Multiply matrix with number
*
* @see operator*=(U), operator*(U, const RectangularMatrix<cols, rows, T>&)
*/
#ifndef DOXYGEN_GENERATING_OUTPUT
template<class U> inline typename std::enable_if<std::is_arithmetic<U>::value, RectangularMatrix<cols, rows, T>>::type operator*(U number) const {
#else
template<class U> inline RectangularMatrix<cols, rows, T> operator*(U number) const {
#endif
return RectangularMatrix<cols, rows, T>(*this)*=number;
}
/**
* @brief Multiply matrix with number and assign
*
* More efficient than operator*(U), because it does the computation
* in-place.
*/
#ifndef DOXYGEN_GENERATING_OUTPUT
template<class U> inline typename std::enable_if<std::is_arithmetic<U>::value, RectangularMatrix<cols, rows, T>&>::type operator*=(U number) {
#else
template<class U> RectangularMatrix<cols, rows, T>& operator*=(U number) {
#endif
for(size_t i = 0; i != cols*rows; ++i)
_data[i] *= number;
return *this;
}
/**
* @brief Divide matrix with number
*
* @see operator/=(), operator/(U, const RectangularMatrix<cols, rows, T>&)
*/
#ifndef DOXYGEN_GENERATING_OUTPUT
template<class U> inline typename std::enable_if<std::is_arithmetic<U>::value, RectangularMatrix<cols, rows, T>>::type operator/(U number) const {
#else
template<class U> inline RectangularMatrix<cols, rows, T> operator/(U number) const {
#endif
return RectangularMatrix<cols, rows, T>(*this)/=number;
}
/**
* @brief Divide matrix with number and assign
*
* More efficient than operator/(), because it does the computation
* in-place.
*/
#ifndef DOXYGEN_GENERATING_OUTPUT
template<class U> inline typename std::enable_if<std::is_arithmetic<U>::value, RectangularMatrix<cols, rows, T>&>::type operator/=(U number) {
#else
template<class U> RectangularMatrix<cols, rows, T>& operator/=(U number) {
#endif
for(size_t i = 0; i != cols*rows; ++i)
_data[i] /= number;
return *this;
}
/** @brief Multiply matrix */
template<size_t size> RectangularMatrix<size, rows, T> operator*(const RectangularMatrix<size, cols, T>& other) const {
RectangularMatrix<size, rows, T> out;
for(size_t row = 0; row != rows; ++row)
for(size_t col = 0; col != size; ++col) /** @todo swap */
for(size_t pos = 0; pos != cols; ++pos)
out(col, row) += (*this)(pos, row)*other(col, pos);
return out;
}
/**
* @brief Multiply vector
*
* Internally the same as multiplying with one-column matrix, but
* returns vector.
*/
Vector<rows, T> operator*(const Vector<rows, T>& other) const {
return operator*(static_cast<RectangularMatrix<1, rows, T>>(other));
}
/** @brief Transposed matrix */
RectangularMatrix<rows, cols, T> transposed() const {
RectangularMatrix<rows, cols, T> out;
for(size_t col = 0; col != cols; ++col)
for(size_t row = 0; row != rows; ++row)
out(row, col) = (*this)(col, row);
return out;
}
private:
template<size_t ...sequence, class ...U> inline constexpr static RectangularMatrix<cols, rows, T> from(Implementation::Sequence<sequence...> s, const Vector<rows, T>& first, U... next) {
return from(s, next..., first[sequence]...);
}
template<size_t ...sequence, class ...U> inline constexpr static RectangularMatrix<cols, rows, T> from(Implementation::Sequence<sequence...>, T first, U... next) {
return RectangularMatrix<cols, rows, T>(first, next...);
}
T _data[rows*cols];
};
/** @relates RectangularMatrix
@brief Multiply number with matrix
@see RectangularMatrix::operator*(U) const
*/
#ifndef DOXYGEN_GENERATING_OUTPUT
template<size_t cols, size_t rows, class T, class U> inline typename std::enable_if<std::is_arithmetic<U>::value, RectangularMatrix<cols, rows, T>>::type operator*(U number, const RectangularMatrix<cols, rows, T>& matrix) {
#else
template<size_t cols, size_t rows, class T, class U> inline RectangularMatrix<cols, rows, T> operator*(U number, const RectangularMatrix<cols, rows, T>& matrix) {
#endif
return matrix*number;
}
/** @relates RectangularMatrix
@brief Divide matrix with number and invert
Example:
@code
RectangularMatrix<2, 3, float> mat(1.0f, 2.0f, -4.0f, 8.0f, -1.0f, 0.5f);
RectangularMatrix<2, 3, float> another = 1.0f/mat; // {1.0f, 0.5f, -0.25f, 0.128f, -1.0f, 2.0f}
@endcode
@see RectangularMatrix::operator/()
*/
#ifndef DOXYGEN_GENERATING_OUTPUT
template<size_t cols, size_t rows, class T, class U> typename std::enable_if<std::is_arithmetic<U>::value, RectangularMatrix<cols, rows, T>>::type operator/(U number, const RectangularMatrix<cols, rows, T>& matrix) {
#else
template<size_t cols, size_t rows, class T, class U> RectangularMatrix<cols, rows, T> operator/(U number, const RectangularMatrix<cols, rows, T>& matrix) {
#endif
RectangularMatrix<cols, rows, T> out;
for(size_t i = 0; i != cols*rows; ++i)
out.data()[i] = number/matrix.data()[i];
return out;
}
/** @debugoperator{Magnum::Math::RectangularMatrix} */
template<size_t cols, size_t rows, class T> Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Magnum::Math::RectangularMatrix<cols, rows, T>& value) {
debug << "Matrix(";
debug.setFlag(Corrade::Utility::Debug::SpaceAfterEachValue, false);
for(size_t row = 0; row != rows; ++row) {
if(row != 0) debug << ",\n ";
for(size_t col = 0; col != cols; ++col) {
if(col != 0) debug << ", ";
debug << typename MathTypeTraits<T>::NumericType(value[col][row]);
}
}
debug << ')';
debug.setFlag(Corrade::Utility::Debug::SpaceAfterEachValue, true);
return debug;
}
#ifndef DOXYGEN_GENERATING_OUTPUT
#define MAGNUM_RECTANGULARMATRIX_SUBCLASS_IMPLEMENTATION(cols, rows, ...) \
inline constexpr static __VA_ARGS__& from(T* data) { \
return *reinterpret_cast<__VA_ARGS__*>(data); \
} \
inline constexpr static const __VA_ARGS__& from(const T* data) { \
return *reinterpret_cast<const __VA_ARGS__*>(data); \
} \
template<class ...U> inline constexpr static __VA_ARGS__ from(const Math::Vector<rows, T>& first, const U&... next) { \
return Math::RectangularMatrix<cols, rows, T>::from(first, next...); \
} \
\
inline __VA_ARGS__& operator=(const Math::RectangularMatrix<cols, rows, T>& other) { \
Math::RectangularMatrix<cols, rows, T>::operator=(other); \
return *this; \
}
#define MAGNUM_RECTANGULARMATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(cols, rows, ...) \
inline __VA_ARGS__ operator-() const { \
return Math::RectangularMatrix<cols, rows, T>::operator-(); \
} \
inline __VA_ARGS__ operator+(const Math::RectangularMatrix<cols, rows, T>& other) const { \
return Math::RectangularMatrix<cols, rows, T>::operator+(other); \
} \
inline __VA_ARGS__& operator+=(const Math::RectangularMatrix<cols, rows, T>& other) { \
Math::RectangularMatrix<cols, rows, T>::operator+=(other); \
return *this; \
} \
inline __VA_ARGS__ operator-(const Math::RectangularMatrix<cols, rows, T>& other) const { \
return Math::RectangularMatrix<cols, rows, T>::operator-(other); \
} \
inline __VA_ARGS__& operator-=(const Math::RectangularMatrix<cols, rows, T>& other) { \
Math::RectangularMatrix<cols, rows, T>::operator-=(other); \
return *this; \
} \
template<class U> inline typename std::enable_if<std::is_arithmetic<U>::value, __VA_ARGS__>::type operator*(U number) const { \
return Math::RectangularMatrix<cols, rows, T>::operator*(number); \
} \
template<class U> inline typename std::enable_if<std::is_arithmetic<U>::value, __VA_ARGS__&>::type operator*=(U number) { \
Math::RectangularMatrix<cols, rows, T>::operator*=(number); \
return *this; \
} \
template<class U> inline typename std::enable_if<std::is_arithmetic<U>::value, __VA_ARGS__>::type operator/(U number) const { \
return Math::RectangularMatrix<cols, rows, T>::operator/(number); \
} \
template<class U> inline typename std::enable_if<std::is_arithmetic<U>::value, __VA_ARGS__&>::type operator/=(U number) { \
Math::RectangularMatrix<cols, rows, T>::operator/=(number); \
return *this; \
}
#endif
}}
namespace Corrade { namespace Utility {
/** @configurationvalue{Magnum::Math::RectangularMatrix} */
template<size_t cols, size_t rows, class T> struct ConfigurationValue<Magnum::Math::RectangularMatrix<cols, rows, T>> {
/** @brief Writes elements separated with spaces */
static std::string toString(const Magnum::Math::RectangularMatrix<cols, rows, T>& value, int flags = 0) {
std::string output;
for(size_t row = 0; row != rows; ++row) {
for(size_t col = 0; col != cols; ++col) {
if(!output.empty()) output += ' ';
output += ConfigurationValue<T>::toString(value(col, row), flags);
}
}
return output;
}
/** @brief Reads elements separated with whitespace */
static Magnum::Math::RectangularMatrix<cols, rows, T> fromString(const std::string& stringValue, int flags = 0) {
Magnum::Math::RectangularMatrix<cols, rows, T> result;
std::istringstream in(stringValue);
for(size_t row = 0; row != rows; ++row) {
for(size_t col = 0; col != cols; ++col) {
std::string num;
in >> num;
result(col, row) = ConfigurationValue<T>::fromString(num, flags);
}
}
return result;
}
};
}}
/* Include also Vector, so the definition is complete */
#include "Vector.h"
#endif

2
src/Math/Test/CMakeLists.txt

@ -1,5 +1,7 @@
corrade_add_test2(MathMathTypeTraitsTest MathTypeTraitsTest.cpp)
corrade_add_test2(MathRectangularMatrixTest RectangularMatrixTest.cpp)
corrade_add_test2(MathVectorTest VectorTest.cpp)
set_target_properties(MathVectorTest PROPERTIES COMPILE_FLAGS -DCORRADE_GRACEFUL_ASSERT)
corrade_add_test2(MathVector2Test Vector2Test.cpp)

7
src/Math/Test/MathTest.cpp

@ -28,6 +28,7 @@ MathTest::MathTest() {
&MathTest::degrad,
&MathTest::normalize,
&MathTest::denormalize,
&MathTest::clamp,
&MathTest::pow,
&MathTest::log);
}
@ -96,6 +97,12 @@ void MathTest::denormalize() {
}
}
void MathTest::clamp() {
CORRADE_COMPARE(Math::clamp(0.5f, -1.0f, 5.0f), 0.5f);
CORRADE_COMPARE(Math::clamp(-1.6f, -1.0f, 5.0f), -1.0f);
CORRADE_COMPARE(Math::clamp(9.5f, -1.0f, 5.0f), 5.0f);
}
void MathTest::pow() {
CORRADE_COMPARE(Math::pow<10>(2ul), 1024ul);
CORRADE_COMPARE(Math::pow<0>(3ul), 1ul);

1
src/Math/Test/MathTest.h

@ -27,6 +27,7 @@ class MathTest: public Corrade::TestSuite::Tester<MathTest> {
void degrad();
void normalize();
void denormalize();
void clamp();
void pow();
void log();
};

142
src/Math/Test/MatrixTest.cpp

@ -32,15 +32,9 @@ typedef Vector<4, float> Vector4;
MatrixTest::MatrixTest() {
addTests(&MatrixTest::construct,
&MatrixTest::constructFromVectors,
&MatrixTest::constructIdentity,
&MatrixTest::constructZero,
&MatrixTest::data,
&MatrixTest::copy,
&MatrixTest::multiplyIdentity,
&MatrixTest::multiply,
&MatrixTest::multiplyVector,
&MatrixTest::transposed,
&MatrixTest::trace,
&MatrixTest::ij,
&MatrixTest::determinant,
&MatrixTest::inverted,
@ -66,20 +60,6 @@ void MatrixTest::construct() {
CORRADE_COMPARE(Matrix4::from(m), expected);
}
void MatrixTest::constructFromVectors() {
Matrix4 actual = Matrix4::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),
Vector4(13.0f, 14.0f, 15.0f, 16.0f));
Matrix4 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,
13.0f, 14.0f, 15.0f, 16.0f);
CORRADE_COMPARE(actual, expected);
}
void MatrixTest::constructIdentity() {
Matrix4 identity;
Matrix4 identity2(Matrix4::Identity);
@ -117,120 +97,16 @@ void MatrixTest::constructZero() {
CORRADE_COMPARE(zero, zeroExpected);
}
void MatrixTest::data() {
Matrix4 m(Matrix4::Zero);
Vector4 vector(4.0f, 5.0f, 6.0f, 7.0f);
m[3] = vector;
m[2][1] = 1.0f;
m(1, 2) = 1.5f;
CORRADE_COMPARE(m(2, 1), 1.0f);
CORRADE_COMPARE(m[1][2], 1.5f);
CORRADE_COMPARE(m[3], vector);
Matrix4 expected(
0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.5f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
4.0f, 5.0f, 6.0f, 7.0f
);
CORRADE_COMPARE(m, expected);
}
void MatrixTest::copy() {
Matrix4 m1(Matrix4::Zero);
m1(2, 3) = 1.0f;
/* Copy */
Matrix4 m2(m1);
Matrix4 m3;
m3(0, 0) = 1.0f; /* this line is here so it's not optimized to Matrix4 m3(m1) */
m3 = m1;
/* Change original */
m1(3, 2) = 1.0f;
/* Verify the copy is the same as original */
Matrix4 original(Matrix4::Zero);
original(2, 3) = 1.0f;
CORRADE_COMPARE(m2, original);
CORRADE_COMPARE(m3, original);
}
void MatrixTest::multiplyIdentity() {
Matrix4 values(
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
);
CORRADE_COMPARE(Matrix4()*values, values);
CORRADE_COMPARE(values*Matrix4(), values);
}
void MatrixTest::multiply() {
Matrix<5, int> left(
-3, -3, -1, 3, -5,
-1, -3, -5, 2, 3,
-1, -4, 3, -1, -2,
-5, -5, -1, -4, -1,
1, 3, -3, -4, -1
);
Matrix<5, int> right(
0, 5, 3, 4, 4,
5, 5, 0, 0, -2,
3, 2, -4, -3, 0,
-3, 0, -1, 2, -1,
0, -1, -4, 4, 3
);
Matrix<5, int> expected(
-24, -35, -32, -25, 1,
-22, -36, -24, 33, -8,
8, 16, -22, 29, 2,
-1, 0, 1, -12, 16,
-12, 8, -20, -26, -2
);
CORRADE_COMPARE((left *= right), expected);
}
void MatrixTest::multiplyVector() {
Matrix<5, int> matrix(
-3, -3, -1, 3, -5,
-1, -3, -5, 2, 3,
-1, -4, 3, -1, -2,
-5, -5, -1, -4, -1,
1, 3, -3, -4, -1
);
CORRADE_COMPARE((matrix*Vector<5, int>(0, 5, 3, 4, 4)), (Vector<5, int>(-24, -35, -32, -25, 1)));
}
void MatrixTest::transposed() {
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 transposed(
0.0f, 4.0f, 8.0f, 12.0f,
1.0f, 5.0f, 9.0f, 13.0f,
2.0f, 6.0f, 10.0f, 14.0f,
3.0f, 7.0f, 11.0f, 15.0f
void MatrixTest::trace() {
Matrix<5, int> 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
);
CORRADE_COMPARE(original.transposed(), transposed);
CORRADE_COMPARE(m.trace(), -8);
}
void MatrixTest::ij() {

8
src/Math/Test/MatrixTest.h

@ -24,15 +24,9 @@ class MatrixTest: public Corrade::TestSuite::Tester<MatrixTest> {
MatrixTest();
void construct();
void constructFromVectors();
void constructIdentity();
void constructZero();
void data();
void copy();
void multiplyIdentity();
void multiply();
void multiplyVector();
void transposed();
void trace();
void ij();
void determinant();
void inverted();

237
src/Math/Test/RectangularMatrixTest.cpp

@ -0,0 +1,237 @@
/*
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz>
This file is part of Magnum.
Magnum is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 3
only, as published by the Free Software Foundation.
Magnum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License version 3 for more details.
*/
#include "RectangularMatrixTest.h"
#include <sstream>
#include "RectangularMatrix.h"
CORRADE_TEST_MAIN(Magnum::Math::Test::RectangularMatrixTest)
using namespace std;
using namespace Corrade::Utility;
namespace Magnum { namespace Math { namespace Test {
typedef RectangularMatrix<4, 3, float> Matrix4x3;
typedef RectangularMatrix<3, 4, float> Matrix3x4;
typedef RectangularMatrix<2, 2, float> Matrix2;
typedef Vector<4, float> Vector4;
RectangularMatrixTest::RectangularMatrixTest() {
addTests(&RectangularMatrixTest::construct,
&RectangularMatrixTest::constructFromVectors,
&RectangularMatrixTest::constructZero,
&RectangularMatrixTest::data,
&RectangularMatrixTest::negative,
&RectangularMatrixTest::addSubtract,
&RectangularMatrixTest::multiplyDivide,
&RectangularMatrixTest::multiply,
&RectangularMatrixTest::transposed,
&RectangularMatrixTest::debug,
&RectangularMatrixTest::configuration);
}
void RectangularMatrixTest::construct() {
float m[] = {
3.0f, 5.0f, 8.0f, 4.0f,
4.0f, 4.0f, 7.0f, 3.0f,
7.0f, -1.0f, 8.0f, 0.0f
};
Matrix3x4 expected(
3.0f, 5.0f, 8.0f, 4.0f,
4.0f, 4.0f, 7.0f, 3.0f,
7.0f, -1.0f, 8.0f, 0.0f
);
CORRADE_COMPARE(Matrix3x4::from(m), expected);
}
void RectangularMatrixTest::constructFromVectors() {
Matrix3x4 actual = Matrix3x4::from(Vector4(1.0f, 2.0f, 3.0f, 4.0f),
Vector4(5.0f, 6.0f, 7.0f, 8.0f),
Vector4(9.0f, 10.0f, 11.0f, 12.0f));
Matrix3x4 expected(1.0f, 2.0f, 3.0f, 4.0f,
5.0f, 6.0f, 7.0f, 8.0f,
9.0f, 10.0f, 11.0f, 12.0f);
CORRADE_COMPARE(actual, expected);
}
void RectangularMatrixTest::constructZero() {
Matrix4x3 zero;
Matrix4x3 zeroExpected(
0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f
);
CORRADE_COMPARE(zero, zeroExpected);
}
void RectangularMatrixTest::data() {
Matrix3x4 m;
Vector4 vector(4.0f, 5.0f, 6.0f, 7.0f);
m[2] = vector;
m[1][1] = 1.0f;
m(0, 2) = 1.5f;
CORRADE_COMPARE(m(1, 1), 1.0f);
CORRADE_COMPARE(m[0][2], 1.5f);
CORRADE_COMPARE(m[2], vector);
Matrix3x4 expected(
0.0f, 0.0f, 1.5f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
4.0f, 5.0f, 6.0f, 7.0f
);
CORRADE_COMPARE(m, expected);
}
void RectangularMatrixTest::negative() {
CORRADE_COMPARE(-Matrix2(1.0f, -3.0f, 5.0f, -10.0f), Matrix2(-1.0f, 3.0f, -5.0f, 10.0f));
}
void RectangularMatrixTest::addSubtract() {
Matrix4x3 a(0.0f, 1.0f, 3.0f,
4.0f, 5.0f, 7.0f,
8.0f, 9.0f, 11.0f,
12.0f, 13.0f, 15.0f);
Matrix4x3 b(-4.0f, 0.5f, 9.0f,
-9.0f, 11.0f, 0.25f,
0.0f, -8.0f, 19.0f,
-3.0f, -5.0f, 2.0f);
Matrix4x3 e(-4.0f, 1.5f, 12.0f,
-5.0f, 16.0f, 7.25f,
8.0f, 1.0f, 30.0f,
9.0f, 8.0f, 17.0f);
CORRADE_COMPARE(a + b, e);
CORRADE_COMPARE(e - b, a);
}
void RectangularMatrixTest::multiplyDivide() {
Matrix2 vec(1.0f, 2.0f, 3.0f, 4.0f);
Matrix2 multiplied(-1.5f, -3.0f, -4.5f, -6.0f);
CORRADE_COMPARE(vec*-1.5f, multiplied);
CORRADE_COMPARE(-1.5f*vec, multiplied);
CORRADE_COMPARE(multiplied/-1.5f, vec);
Math::RectangularMatrix<1, 1, char> vecChar(32);
Math::RectangularMatrix<1, 1, char> multipliedChar(-48);
CORRADE_COMPARE(vecChar*-1.5f, multipliedChar);
CORRADE_COMPARE(multipliedChar/-1.5f, vecChar);
CORRADE_COMPARE(-1.5f*vecChar, multipliedChar);
/* Divide vector with number and inverse */
Matrix2 divisor(1.0f, 2.0f, -4.0f, 8.0f);
Matrix2 result(1.0f, 0.5f, -0.25f, 0.125f);
CORRADE_COMPARE(1.0f/divisor, result);
CORRADE_COMPARE(-1550.0f/multipliedChar, vecChar);
}
void RectangularMatrixTest::multiply() {
RectangularMatrix<4, 6, int> left(
-5, 27, 10, 33, 0, -15,
7, 56, 66, 1, 0, -24,
4, 41, 4, 0, 1, -4,
9, -100, 19, -49, 1, 9
);
RectangularMatrix<5, 4, int> right(
1, -7, 0, 158,
2, 24, -3, 40,
3, -15, -2, -50,
4, 17, -1, -284,
5, 30, 4, 18
);
RectangularMatrix<5, 6, int> expected(
1368, -16165, 2550, -7716, 158, 1575,
506, -2725, 2352, -1870, 37, -234,
-578, 4159, -1918, 2534, -52, -127,
-2461, 29419, -4238, 14065, -285, -3020,
363, 179, 2388, -687, 22, -649
);
CORRADE_COMPARE(left*right, expected);
}
void RectangularMatrixTest::transposed() {
Matrix4x3 original(
0.0f, 1.0f, 3.0f,
4.0f, 5.0f, 7.0f,
8.0f, 9.0f, 11.0f,
12.0f, 13.0f, 15.0f
);
Matrix3x4 transposed(
0.0f, 4.0f, 8.0f, 12.0f,
1.0f, 5.0f, 9.0f, 13.0f,
3.0f, 7.0f, 11.0f, 15.0f
);
CORRADE_COMPARE(original.transposed(), transposed);
}
void RectangularMatrixTest::debug() {
Matrix3x4 m(
3.0f, 5.0f, 8.0f, 4.0f,
4.0f, 4.0f, 7.0f, 3.0f,
7.0f, -1.0f, 8.0f, 0.0f
);
ostringstream o;
Debug(&o) << m;
CORRADE_COMPARE(o.str(), "Matrix(3, 4, 7,\n"
" 5, 4, -1,\n"
" 8, 7, 8,\n"
" 4, 3, 0)\n");
o.str("");
Debug(&o) << "a" << Matrix3x4() << "b" << RectangularMatrix<4, 3, char>();
CORRADE_COMPARE(o.str(), "a Matrix(0, 0, 0,\n"
" 0, 0, 0,\n"
" 0, 0, 0,\n"
" 0, 0, 0) b Matrix(0, 0, 0, 0,\n"
" 0, 0, 0, 0,\n"
" 0, 0, 0, 0)\n");
}
void RectangularMatrixTest::configuration() {
Matrix3x4 m(
3.0f, 5.0f, 8.0f, 4.0f,
4.0f, 4.0f, 7.0f, 3.125f,
7.0f, -1.0f, 8.0f, 9.55f
);
string value("3 4 7 5 4 -1 8 7 8 4 3.125 9.55");
CORRADE_COMPARE(ConfigurationValue<Matrix3x4>::toString(m), value);
CORRADE_COMPARE(ConfigurationValue<Matrix3x4>::fromString(value), m);
}
}}}

44
src/Math/Test/RectangularMatrixTest.h

@ -0,0 +1,44 @@
#ifndef Magnum_Math_Test_RectangularMatrixTest_h
#define Magnum_Math_Test_RectangularMatrixTest_h
/*
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz>
This file is part of Magnum.
Magnum is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 3
only, as published by the Free Software Foundation.
Magnum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License version 3 for more details.
*/
#include <TestSuite/Tester.h>
namespace Magnum { namespace Math { namespace Test {
class RectangularMatrixTest: public Corrade::TestSuite::Tester<RectangularMatrixTest> {
public:
RectangularMatrixTest();
void construct();
void constructFromVectors();
void constructZero();
void data();
void negative();
void addSubtract();
void multiplyDivide();
void multiply();
void transposed();
void debug();
void configuration();
};
}}}
#endif

69
src/Math/Test/VectorTest.cpp

@ -34,12 +34,8 @@ typedef Vector<3, float> Vector3;
VectorTest::VectorTest() {
addTests(&VectorTest::construct,
&VectorTest::constructFrom,
&VectorTest::data,
&VectorTest::copy,
&VectorTest::dot,
&VectorTest::multiplyDivide,
&VectorTest::multiplyDivideComponentWise,
&VectorTest::addSubtract,
&VectorTest::dotSelf,
&VectorTest::length,
&VectorTest::normalized,
@ -48,7 +44,6 @@ VectorTest::VectorTest() {
&VectorTest::min,
&VectorTest::max,
&VectorTest::angle,
&VectorTest::negative,
&VectorTest::debug,
&VectorTest::configuration);
}
@ -69,61 +64,10 @@ void VectorTest::constructFrom() {
CORRADE_COMPARE(Vector4::from(integral), floatingPointRounded);
}
void VectorTest::data() {
Vector4 v;
v[2] = 1.5f;
v[0] = 1.0f;
CORRADE_COMPARE(v, Vector4(1.0f, 0.0f, 1.5f, 0.0f));
}
void VectorTest::copy() {
Vector4 v1;
v1[3] = 1.0f;
Vector4 v2(v1);
Vector4 v3;
v3[0] = 0.0f; /* this line is here so it's not optimized to Vector4 v3(v1) */
v3 = v1;
/* Change original */
v1[2] = 1.0f;
/* Verify the copy is the same as original original */
Vector4 original;
original[3] = 1.0f;
CORRADE_COMPARE(v2, original);
CORRADE_COMPARE(v3, original);
}
void VectorTest::dot() {
CORRADE_COMPARE(Vector4::dot({1.0f, 0.5f, 0.75f, 1.5f}, {2.0f, 4.0f, 1.0f, 7.0f}), 15.25f);
}
void VectorTest::multiplyDivide() {
Vector4 vec(1.0f, 2.0f, 3.0f, 4.0f);
Vector4 multiplied(-1.5f, -3.0f, -4.5f, -6.0f);
CORRADE_COMPARE(vec*-1.5f, multiplied);
CORRADE_COMPARE(-1.5f*vec, multiplied);
CORRADE_COMPARE(multiplied/-1.5f, vec);
Math::Vector<1, char> vecChar(32);
Math::Vector<1, char> multipliedChar(-48);
CORRADE_COMPARE(vecChar*-1.5f, multipliedChar);
CORRADE_COMPARE(multipliedChar/-1.5f, vecChar);
CORRADE_COMPARE(-1.5f*vecChar, multipliedChar);
/* Divide vector with number and inverse */
Vector4 divisor(1.0f, 2.0f, -4.0f, 8.0f);
Vector4 result(1.0f, 0.5f, -0.25f, 0.125f);
CORRADE_COMPARE(1.0f/divisor, result);
CORRADE_COMPARE(-1550.0f/multipliedChar, vecChar);
}
void VectorTest::multiplyDivideComponentWise() {
Vector4 vec(1.0f, 2.0f, 3.0f, 4.0f);
Vector4 multiplier(7.0f, -4.0f, -1.5f, 1.0f);
@ -133,15 +77,6 @@ void VectorTest::multiplyDivideComponentWise() {
CORRADE_COMPARE(multiplied/multiplier, vec);
}
void VectorTest::addSubtract() {
Vector4 a(0.5f, -7.5f, 9.0f, -11.0f);
Vector4 b(-0.5, 1.0f, 0.0f, 7.5f);
Vector4 expected(0.0f, -6.5f, 9.0f, -3.5f);
CORRADE_COMPARE(a + b, expected);
CORRADE_COMPARE(expected - b, a);
}
void VectorTest::dotSelf() {
CORRADE_COMPARE(Vector4(1.0f, 2.0f, 3.0f, 4.0f).dot(), 30.0f);
}
@ -181,10 +116,6 @@ void VectorTest::angle() {
CORRADE_COMPARE(Vector3::angle(Vector3(2.0f, 3.0f, 4.0f).normalized(), Vector3(1.0f, -2.0f, 3.0f).normalized()), rad(1.162514f));
}
void VectorTest::negative() {
CORRADE_COMPARE(-Vector4(1.0f, -3.0f, 5.0f, -10.0f), Vector4(-1.0f, 3.0f, -5.0f, 10.0f));
}
void VectorTest::debug() {
ostringstream o;
Debug(&o) << Vector4(0.5f, 15.0f, 1.0f, 1.0f);

5
src/Math/Test/VectorTest.h

@ -25,12 +25,8 @@ class VectorTest: public Corrade::TestSuite::Tester<VectorTest> {
void construct();
void constructFrom();
void data();
void copy();
void dot();
void multiplyDivide();
void multiplyDivideComponentWise();
void addSubtract();
void dotSelf();
void length();
void normalized();
@ -39,7 +35,6 @@ class VectorTest: public Corrade::TestSuite::Tester<VectorTest> {
void min();
void max();
void angle();
void negative();
void debug();
void configuration();

298
src/Math/Vector.h

@ -19,12 +19,7 @@
* @brief Class Magnum::Math::Vector
*/
#include <cmath>
#include <limits>
#include <Utility/Debug.h>
#include <Utility/Configuration.h>
#include "MathTypeTraits.h"
#include "RectangularMatrix.h"
namespace Magnum { namespace Math {
@ -32,16 +27,6 @@ template<size_t size, class T> class Vector;
#ifndef DOXYGEN_GENERATING_OUTPUT
namespace Implementation {
template<size_t ...> struct Sequence {};
/* E.g. GenerateSequence<3>::Type is Sequence<0, 1, 2> */
template<size_t N, size_t ...sequence> struct GenerateSequence:
GenerateSequence<N-1, N-1, sequence...> {};
template<size_t ...sequence> struct GenerateSequence<0, sequence...> {
typedef Sequence<sequence...> Type;
};
/* Implementation for Vector<size, T>::from(const Vector<size, U>&) */
template<class T, class U, size_t ...sequence> inline constexpr Math::Vector<sizeof...(sequence), T> vectorFrom(Sequence<sequence...>, const Math::Vector<sizeof...(sequence), U>& vector) {
return {T(vector[sequence])...};
@ -55,28 +40,9 @@ namespace Implementation {
@configurationvalueref{Magnum::Math::Vector}
@todo Constexprize all for loops
*/
template<size_t size, class T> class Vector {
static_assert(size != 0, "Vector cannot have zero elements");
template<size_t s, class T> class Vector: public RectangularMatrix<1, s, T> {
public:
const static size_t Size = size; /**< @brief %Vector size */
typedef T Type; /**< @brief %Vector data type */
/**
* @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);
}
const static size_t size = s; /**< @brief %Vector size */
/**
* @brief %Vector from another of different type
@ -126,19 +92,15 @@ template<size_t size, class T> class Vector {
}
/** @brief Default constructor */
inline constexpr Vector(): _data() {}
inline constexpr Vector() {}
/**
* @brief Initializer-list constructor
* @param first First value
* @param next Next values
*
* @todoc Remove workaround when Doxygen supports uniform initialization
*/
#ifndef DOXYGEN_GENERATING_OUTPUT
template<class ...U> inline constexpr Vector(T first, U... next): _data{first, next...} {
static_assert(sizeof...(next)+1 == size, "Improper number of arguments passed to Vector constructor");
}
template<class ...U> inline constexpr Vector(T first, U... next): RectangularMatrix<1, size, T>(first, next...) {}
#else
template<class ...U> inline constexpr Vector(T first, U... next);
#endif
@ -153,68 +115,15 @@ template<size_t size, class T> class Vector {
inline explicit Vector(T value) {
#endif
for(size_t i = 0; i != size; ++i)
_data[i] = value;
(*this)[i] = value;
}
/** @brief Copy constructor */
inline constexpr Vector(const Vector<size, T>&) = default;
/** @brief Assignment operator */
inline Vector<size, T>& operator=(const Vector<size, T>&) = default;
/**
* @brief Raw data
* @return Array with the same size as the vector
*/
inline T* data() { return _data; }
inline constexpr const T* data() const { return _data; } /**< @overload */
inline constexpr Vector(const RectangularMatrix<1, size, T>& other): RectangularMatrix<1, size, T>(other) {}
/** @brief Value at given position */
inline T& operator[](size_t pos) { return _data[pos]; }
inline constexpr T operator[](size_t pos) const { return _data[pos]; } /**< @overload */
/** @brief Equality operator */
inline bool operator==(const Vector<size, T>& other) const {
for(size_t pos = 0; pos != size; ++pos)
if(!MathTypeTraits<T>::equals((*this)[pos], other[pos])) return false;
return true;
}
/** @brief Non-equality operator */
inline bool operator!=(const Vector<size, T>& other) const {
return !operator==(other);
}
/**
* @brief Multiply vector
*
* @see operator*=(U), operator*(U, const Vector<size, T>&)
*/
#ifndef DOXYGEN_GENERATING_OUTPUT
template<class U> inline typename std::enable_if<std::is_arithmetic<U>::value, Vector<size, T>>::type operator*(U number) const {
#else
template<class U> inline Vector<size, T> operator*(U number) const {
#endif
return Vector<size, T>(*this)*=number;
}
/**
* @brief Multiply vector and assign
*
* More efficient than operator*(U) const, because it does the
* computation in-place.
*/
#ifndef DOXYGEN_GENERATING_OUTPUT
template<class U> typename std::enable_if<std::is_arithmetic<U>::value, Vector<size, T>&>::type operator*=(U number) {
#else
template<class U> Vector<size, T>& operator*=(U number) {
#endif
for(size_t i = 0; i != size; ++i)
(*this)[i] *= number;
return *this;
}
inline T& operator[](size_t pos) { return RectangularMatrix<1, size, T>::_data[pos]; }
inline constexpr T operator[](size_t pos) const { return RectangularMatrix<1, size, T>::_data[pos]; } /**< @overload */
/**
* @brief Multiply vector component-wise
@ -238,36 +147,6 @@ template<size_t size, class T> class Vector {
return *this;
}
/**
* @brief Divide vector
*
* @see operator/=(U), operator/(U, const Vector<size, T>&)
*/
#ifndef DOXYGEN_GENERATING_OUTPUT
template<class U> inline typename std::enable_if<std::is_arithmetic<U>::value, Vector<size, T>>::type operator/(U number) const {
#else
template<class U> inline Vector<size, T> operator/(U number) const {
#endif
return Vector<size, T>(*this)/=number;
}
/**
* @brief Divide vector and assign
*
* More efficient than operator/(U) const, because it does the
* computation in-place.
*/
#ifndef DOXYGEN_GENERATING_OUTPUT
template<class U> typename std::enable_if<std::is_arithmetic<U>::value, Vector<size, T>&>::type operator/=(U number) {
#else
template<class U> Vector<size, T>& operator/=(U number) {
#endif
for(size_t i = 0; i != size; ++i)
(*this)[i] /= number;
return *this;
}
/**
* @brief Divide vector component-wise
*
@ -290,52 +169,6 @@ template<size_t size, class T> class Vector {
return *this;
}
/** @brief Add two vectors */
inline Vector<size, T> operator+(const Vector<size, T>& other) const {
return Vector<size, T>(*this)+=other;
}
/**
* @brief Add and assign vector
*
* More efficient than operator+(), because it does the computation
* in-place.
*/
Vector<size, T>& operator+=(const Vector<size, T>& other) {
for(size_t i = 0; i != size; ++i)
(*this)[i] += other[i];
return *this;
}
/** @brief Subtract two vectors */
inline Vector<size, T> operator-(const Vector<size, T>& other) const {
return Vector<size, T>(*this)-=other;
}
/**
* @brief Subtract and assign vector
*
* More efficient than operator-(), because it does the computation
* in-place.
*/
Vector<size, T>& operator-=(const Vector<size, T>& other) {
for(size_t i = 0; i != size; ++i)
(*this)[i] -= other[i];
return *this;
}
/** @brief Negative vector */
Vector<size, T> operator-() const {
Vector<size, T> out;
for(size_t i = 0; i != size; ++i)
out[i] = -(*this)[i];
return out;
}
/**
* @brief Dot product of the vector
*
@ -404,45 +237,31 @@ template<size_t size, class T> class Vector {
return out;
}
#ifndef DOXYGEN_GENERATING_OUTPUT
/* Reimplementation of functions to return correct type */
template<size_t otherCols> inline RectangularMatrix<otherCols, size, T> operator*(const RectangularMatrix<otherCols, 1, T>& other) const {
return RectangularMatrix<1, size, T>::operator*(other);
}
MAGNUM_RECTANGULARMATRIX_SUBCLASS_IMPLEMENTATION(1, size, Vector<size, T>)
MAGNUM_RECTANGULARMATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(1, size, Vector<size, T>)
#endif
private:
T _data[size];
/* 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();
};
/** @relates Vector
@brief Multiply number with vector
@see Vector::operator*(U) const
*/
#ifndef DOXYGEN_GENERATING_OUTPUT
template<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) {
#else
template<size_t size, class T, class U> inline Vector<size, T> operator*(U number, const Vector<size, T>& vector) {
#endif
return vector*number;
return number*RectangularMatrix<1, size, T>(vector);
}
/** @relates Vector
@brief Divide vector with number and invert
Example:
@code
Vector<4, float> vec(1.0f, 2.0f, -4.0f, 8.0f);
Vector<4, float> another = 1.0f/vec; // {1.0f, 0.5f, -0.25f, 0.128f}
@endcode
@see Vector::operator/(U) const
*/
#ifndef DOXYGEN_GENERATING_OUTPUT
template<size_t size, class T, class U> typename std::enable_if<std::is_arithmetic<U>::value, Vector<size, T>>::type operator/(U number, const Vector<size, T>& vector) {
#else
template<size_t size, class T, class U> Vector<size, T> operator/(U number, const Vector<size, T>& vector) {
#endif
Vector<size, T> out;
for(size_t i = 0; i != size; ++i)
out[i] = number/vector[i];
return out;
template<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
/** @debugoperator{Magnum::Math::Vector} */
template<size_t size, class T> Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Magnum::Math::Vector<size, T>& value) {
@ -465,68 +284,41 @@ template<size_t size, class T> Corrade::Utility::Debug operator<<(Corrade::Utili
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, U>& other) { \
return Vector<size, T>::from(other); \
template<class U> inline constexpr static Type<T> from(const Math::Vector<size, U>& other) { \
return Math::Vector<size, T>::from(other); \
} \
\
inline Type<T>& operator=(const Type<T>& other) { \
Vector<size, T>::operator=(other); \
Math::Vector<size, T>::operator=(other); \
return *this; \
} \
\
template<class U> inline Type<T> operator*(U number) const { \
return Vector<size, T>::operator*(number); \
} \
template<class U> inline Type<T>& operator*=(U number) { \
Vector<size, T>::operator*=(number); \
return *this; \
} \
inline Type<T> operator*(const Vector<size, T>& other) const { \
return Vector<size, T>::operator*(other); \
} \
inline Type<T>& operator*=(const Vector<size, T>& other) { \
Vector<size, T>::operator*=(other); \
return *this; \
template<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); \
} \
template<class U> inline Type<T> operator/(U number) const { \
return Vector<size, T>::operator/(number); \
} \
template<class U> inline Type<T>& operator/=(U number) { \
Vector<size, T>::operator/=(number); \
return *this; \
} \
inline Type<T> operator/(const Vector<size, T>& other) const { \
return Vector<size, T>::operator/(other); \
} \
inline Type<T>& operator/=(const Vector<size, T>& other) { \
Vector<size, T>::operator/=(other); \
return *this; \
} \
\
inline Type<T> operator+(const Vector<size, T>& other) const { \
return Vector<size, T>::operator+(other); \
inline Type<T> operator*(const Math::Vector<size, T>& other) const { \
return Math::Vector<size, T>::operator*(other); \
} \
inline Type<T>& operator+=(const Vector<size, T>& other) { \
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 Vector<size, T>& other) const { \
return Vector<size, T>::operator-(other); \
inline Type<T> operator/(const Math::Vector<size, T>& other) const { \
return Math::Vector<size, T>::operator/(other); \
} \
inline Type<T>& operator-=(const Vector<size, T>& other) { \
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 { return Vector<size, T>::operator-(); } \
inline Type<T> normalized() const { return Vector<size, T>::normalized(); }
inline Type<T> normalized() const { return Math::Vector<size, T>::normalized(); }
#define MAGNUM_VECTOR_SUBCLASS_OPERATOR_IMPLEMENTATION(Type, size) \
template<class T, class U> inline Type<T> operator*(U number, const Type<T>& vector) { \
return number*Vector<size, T>(vector); \
template<class T, class U> inline typename std::enable_if<std::is_arithmetic<U>::value, Type<T>>::type operator*(U number, const Type<T>& vector) { \
return number*Math::Vector<size, T>(vector); \
} \
template<class T, class U> inline Type<T> operator/(U number, const Type<T>& vector) { \
return number/Vector<size, T>(vector); \
template<class T, class U> inline typename std::enable_if<std::is_arithmetic<U>::value, Type<T>>::type operator/(U number, const Type<T>& vector) { \
return number/Math::Vector<size, T>(vector); \
}
#endif

5
src/Math/Vector2.h

@ -71,8 +71,8 @@ template<class T> class Vector2: public Vector<2, T> {
/** @copydoc Vector::Vector(T) */
inline constexpr explicit Vector2(T value = T()): Vector<2, T>(value, value) {}
/** @copydoc Vector::Vector(const Vector&) */
inline constexpr Vector2(const Vector<2, T>& other): Vector<2, T>(other) {}
/** @brief Copy constructor */
inline constexpr Vector2(const RectangularMatrix<1, 2, T>& other): Vector<2, T>(other) {}
/**
* @brief Constructor
@ -88,6 +88,7 @@ template<class T> class Vector2: public Vector<2, T> {
inline void setY(T value) { (*this)[1] = value; } /**< @brief Set Y component */
MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(Vector2, 2)
MAGNUM_RECTANGULARMATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(1, 2, Vector2<T>)
};
MAGNUM_VECTOR_SUBCLASS_OPERATOR_IMPLEMENTATION(Vector2, 2)

5
src/Math/Vector3.h

@ -105,8 +105,8 @@ template<class T> class Vector3: public Vector<3, T> {
/** @copydoc Vector::Vector(T) */
inline constexpr explicit Vector3(T value): Vector<3, T>(value, value, value) {}
/** @copydoc Vector::Vector(const Vector&) */
inline constexpr Vector3(const Vector<3, T>& other): Vector<3, T>(other) {}
/** @brief Copy constructor */
inline constexpr Vector3(const RectangularMatrix<1, 3, T>& other): Vector<3, T>(other) {}
/**
* @brief Constructor
@ -140,6 +140,7 @@ template<class T> class Vector3: public Vector<3, T> {
inline constexpr Vector2<T> xy() const { return Vector2<T>::from(Vector<3, T>::data()); }
MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(Vector3, 3)
MAGNUM_RECTANGULARMATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(1, 3, Vector3<T>)
};
MAGNUM_VECTOR_SUBCLASS_OPERATOR_IMPLEMENTATION(Vector3, 3)

5
src/Math/Vector4.h

@ -40,8 +40,8 @@ template<class T> class Vector4: public Vector<4, T> {
/** @copydoc Vector::Vector(T) */
inline constexpr explicit Vector4(T value): Vector<4, T>(value, value, value, value) {}
/** @copydoc Vector::Vector(const Vector&) */
inline constexpr Vector4(const Vector<4, T>& other): Vector<4, T>(other) {}
/** @brief Copy constructor */
inline constexpr Vector4(const RectangularMatrix<1, 4, T>& other): Vector<4, T>(other) {}
/**
* @brief Constructor
@ -88,6 +88,7 @@ template<class T> class Vector4: public Vector<4, T> {
inline constexpr Vector2<T> xy() const { return Vector2<T>::from(Vector<4, T>::data()); }
MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(Vector4, 4)
MAGNUM_RECTANGULARMATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(1, 3, Vector4<T>)
};
MAGNUM_VECTOR_SUBCLASS_OPERATOR_IMPLEMENTATION(Vector4, 4)

5
src/Mesh.h

@ -162,7 +162,8 @@ class MAGNUM_EXPORT Mesh {
* @brief Set point size
*
* @see setProgramPointSize()
* @requires_gl
* @requires_gl Set directly in vertex shader using @c gl_PointSize
* builtin variable.
*/
inline static void setPointSize(GLfloat size) {
glPointSize(size);
@ -174,7 +175,7 @@ class MAGNUM_EXPORT Mesh {
* If enabled, the point size is taken from vertex/geometry shader
* builtin `gl_PointSize`.
* @see setPointSize()
* @requires_gl
* @requires_gl Always enabled.
*/
inline static void setProgramPointSize(bool enabled) {
enabled ? glEnable(GL_PROGRAM_POINT_SIZE) : glDisable(GL_PROGRAM_POINT_SIZE);

8
src/MeshTools/Clean.h

@ -39,7 +39,7 @@ template<class Vertex, size_t vertexSize = Vertex::Size> class Clean {
/* Get mesh bounds */
Vertex min, max;
for(size_t i = 0; i != Vertex::Size; ++i) {
for(size_t i = 0; i != Vertex::size; ++i) {
min[i] = std::numeric_limits<typename Vertex::Type>::max();
max[i] = std::numeric_limits<typename Vertex::Type>::min();
}
@ -53,7 +53,7 @@ template<class Vertex, size_t vertexSize = Vertex::Size> class Clean {
/* Make epsilon so large that size_t can index all vertices inside
mesh bounds. */
Vertex size = max-min;
for(size_t i = 0; i != Vertex::Size; ++i)
for(size_t i = 0; i != Vertex::size; ++i)
if(static_cast<typename Vertex::Type>(size[i]/std::numeric_limits<size_t>::max()) > epsilon)
epsilon = static_cast<typename Vertex::Type>(size[i]/std::numeric_limits<size_t>::max());
@ -93,7 +93,7 @@ template<class Vertex, size_t vertexSize = Vertex::Size> class Clean {
std::swap(newVertices, vertices);
/* Move vertex coordinates by epsilon/2 in next direction */
if(moving != Vertex::Size) {
if(moving != Vertex::size) {
moved = Vertex();
moved[moving] = epsilon/2;
}
@ -138,7 +138,7 @@ Removes duplicate vertices from the mesh.
@todo Interpolate vertices, not collapse them to first in the cell
@todo Ability to specify other attributes for interpolation
*/
template<class Vertex, size_t vertexSize = Vertex::Size> inline void clean(std::vector<unsigned int>& indices, std::vector<Vertex>& vertices, typename Vertex::Type epsilon = TypeTraits<typename Vertex::Type>::epsilon()) {
template<class Vertex, size_t vertexSize = Vertex::size> inline void clean(std::vector<unsigned int>& indices, std::vector<Vertex>& vertices, typename Vertex::Type epsilon = TypeTraits<typename Vertex::Type>::epsilon()) {
Implementation::Clean<Vertex, vertexSize>(indices, vertices)(epsilon);
}

2
src/MeshTools/Test/CleanTest.h

@ -28,7 +28,7 @@ class CleanTest: public Corrade::TestSuite::Tester<CleanTest> {
private:
class Vector1 {
public:
static const size_t Size = 1;
static const size_t size = 1;
typedef int Type;
Vector1(): data(0) {}

2
src/MeshTools/Test/SubdivideTest.h

@ -29,7 +29,7 @@ class SubdivideTest: public Corrade::TestSuite::Tester<SubdivideTest> {
private:
class Vector1 {
public:
static const size_t Size = 1;
static const size_t size = 1;
typedef int Type;
Vector1(): data(0) {}

2
src/SceneGraph/Camera.cpp

@ -33,7 +33,7 @@ template<class MatrixType> MatrixType aspectRatioFix(AspectRatioPolicy aspectRat
/* Extend on larger side = scale larger side down
Clip on smaller side = scale smaller side up */
return Camera<MatrixType::Size-1>::aspectRatioScale(
return Camera<MatrixType::size-1>::aspectRatioScale(
(relativeAspectRatio.x() > relativeAspectRatio.y()) == (aspectRatioPolicy == AspectRatioPolicy::Extend) ?
Vector2(relativeAspectRatio.y()/relativeAspectRatio.x(), 1.0f) :
Vector2(1.0f, relativeAspectRatio.x()/relativeAspectRatio.y()));

2
src/Swizzle.h

@ -100,7 +100,7 @@ instead of at runtime.
@see Vector4::xyz(), Vector4::rgb(), Vector4::xy(), Vector3::xy()
*/
template<char ...components, class T> inline constexpr typename Implementation::TypeForSize<sizeof...(components), T>::Type swizzle(const T& vector) {
return {vector[Implementation::GetComponent<T::Size, components>::value()]...};
return {vector[Implementation::GetComponent<T::size, components>::value()]...};
}
/**

3
src/Trade/ImageData.h

@ -70,7 +70,8 @@ template<size_t imageDimensions> class ImageData: public AbstractImage {
inline constexpr const Math::Vector<Dimensions, GLsizei>& dimensions() const { return _dimensions; }
/** @brief Pointer to raw data */
inline constexpr const void* data() const { return _data; }
inline void* data() { return _data; }
inline constexpr const void* data() const { return _data; } /**< @overload */
private:
std::string _name;

Loading…
Cancel
Save