Browse Source

Math: deinlined heavy functions, removed redundant `inline`.

Also fixed unary RectangularMatrix::operator-() and Vector::operator-()
documentation (was stating that the operation is done in-place, which is
impossible.
pull/278/head
Vladimír Vondruš 13 years ago
parent
commit
06a4e297bc
  1. 4
      src/Math/Algorithms/Svd.h
  2. 32
      src/Math/Angle.h
  3. 132
      src/Math/BoolVector.h
  4. 64
      src/Math/Complex.h
  5. 18
      src/Math/Constants.h
  6. 42
      src/Math/Dual.h
  7. 56
      src/Math/DualComplex.h
  8. 44
      src/Math/DualQuaternion.h
  9. 6
      src/Math/Functions.h
  10. 126
      src/Math/Geometry/Distance.h
  11. 52
      src/Math/Geometry/Rectangle.h
  12. 138
      src/Math/Matrix.h
  13. 104
      src/Math/Matrix3.h
  14. 311
      src/Math/Matrix4.h
  15. 293
      src/Math/Quaternion.h
  16. 212
      src/Math/RectangularMatrix.h
  17. 8
      src/Math/Swizzle.h
  18. 4
      src/Math/Test/Matrix3Test.cpp
  19. 4
      src/Math/Test/Matrix4Test.cpp
  20. 4
      src/Math/Test/MatrixTest.cpp
  21. 4
      src/Math/Test/RectangularMatrixTest.cpp
  22. 4
      src/Math/Test/Vector2Test.cpp
  23. 4
      src/Math/Test/Vector3Test.cpp
  24. 4
      src/Math/Test/Vector4Test.cpp
  25. 4
      src/Math/Test/VectorTest.cpp
  26. 14
      src/Math/TypeTraits.h
  27. 42
      src/Math/Unit.h
  28. 317
      src/Math/Vector.h
  29. 32
      src/Math/Vector2.h
  30. 44
      src/Math/Vector3.h
  31. 38
      src/Math/Vector4.h

4
src/Math/Algorithms/Svd.h

@ -49,9 +49,9 @@ template<class T> T pythagoras(T a, T b) {
}
template<class T> constexpr T smallestDelta();
template<> inline constexpr Float smallestDelta<Float>() { return 1.0e-32; }
template<> constexpr Float smallestDelta<Float>() { return 1.0e-32; }
#ifndef MAGNUM_TARGET_GLES
template<> inline constexpr Double smallestDelta<Double>() { return 1.0e-64; }
template<> constexpr Double smallestDelta<Double>() { return 1.0e-64; }
#endif
}

32
src/Math/Angle.h

@ -124,16 +124,16 @@ std::sin(Float(Rad<Float>(angleInDegrees)); // required explicit conversion hint
template<class T> class Deg: public Unit<Deg, T> {
public:
/** @brief Default constructor */
inline constexpr /*implicit*/ Deg() {}
constexpr /*implicit*/ Deg() {}
/** @brief Explicit constructor from unitless type */
inline constexpr explicit Deg(T value): Unit<Math::Deg, T>(value) {}
constexpr explicit Deg(T value): Unit<Math::Deg, T>(value) {}
/** @brief Copy constructor */
inline constexpr /*implicit*/ Deg(Unit<Math::Deg, T> value): Unit<Math::Deg, T>(value) {}
constexpr /*implicit*/ Deg(Unit<Math::Deg, T> value): Unit<Math::Deg, T>(value) {}
/** @brief Construct from another underlying type */
template<class U> inline constexpr explicit Deg(Unit<Math::Deg, U> value): Unit<Math::Deg, T>(value) {}
template<class U> constexpr explicit Deg(Unit<Math::Deg, U> value): Unit<Math::Deg, T>(value) {}
/**
* @brief Construct degrees from radians
@ -143,7 +143,7 @@ template<class T> class Deg: public Unit<Deg, T> {
* deg = 180 \frac {rad} \pi
* @f]
*/
inline constexpr /*implicit*/ Deg(Unit<Rad, T> value);
constexpr /*implicit*/ Deg(Unit<Rad, T> value);
};
#ifndef CORRADE_GCC46_COMPATIBILITY
@ -160,7 +160,7 @@ Double cosine = Math::cos(1.047_rad); // cosine = 0.5
@note Not available on GCC < 4.7. Use Deg::Deg(T) instead.
@requires_gl Only single-precision types are available in OpenGL ES.
*/
inline constexpr Deg<Double> operator "" _deg(long double value) { return Deg<Double>(value); }
constexpr Deg<Double> operator "" _deg(long double value) { return Deg<Double>(value); }
#endif
/** @relates Deg
@ -175,7 +175,7 @@ Float tangent = Math::tan(1.047_radf); // tangent = 1.732f
@note Not available on GCC < 4.7. Use Deg::Deg(T) instead.
@requires_gl Only single-precision types are available in OpenGL ES.
*/
inline constexpr Deg<Float> operator "" _degf(long double value) { return Deg<Float>(value); }
constexpr Deg<Float> operator "" _degf(long double value) { return Deg<Float>(value); }
#endif
/**
@ -187,16 +187,16 @@ See Deg for more information.
template<class T> class Rad: public Unit<Rad, T> {
public:
/** @brief Default constructor */
inline constexpr /*implicit*/ Rad() {}
constexpr /*implicit*/ Rad() {}
/** @brief Construct from unitless type */
inline constexpr explicit Rad(T value): Unit<Math::Rad, T>(value) {}
constexpr explicit Rad(T value): Unit<Math::Rad, T>(value) {}
/** @brief Copy constructor */
inline constexpr /*implicit*/ Rad(Unit<Math::Rad, T> value): Unit<Math::Rad, T>(value) {}
constexpr /*implicit*/ Rad(Unit<Math::Rad, T> value): Unit<Math::Rad, T>(value) {}
/** @brief Construct from another underlying type */
template<class U> inline constexpr explicit Rad(Unit<Math::Rad, U> value): Unit<Math::Rad, T>(value) {}
template<class U> constexpr explicit Rad(Unit<Math::Rad, U> value): Unit<Math::Rad, T>(value) {}
/**
* @brief Construct radians from degrees
@ -206,7 +206,7 @@ template<class T> class Rad: public Unit<Rad, T> {
* rad = deg \frac \pi 180
* @f]
*/
inline constexpr /*implicit*/ Rad(Unit<Deg, T> value);
constexpr /*implicit*/ Rad(Unit<Deg, T> value);
};
#ifndef CORRADE_GCC46_COMPATIBILITY
@ -218,7 +218,7 @@ See operator""_rad() for more information.
@see Magnum::operator""_rad(), operator""_radf(), operator""_deg()
@note Not available on GCC < 4.7. Use Rad::Rad(T) instead.
*/
inline constexpr Rad<Double> operator "" _rad(long double value) { return Rad<Double>(value); }
constexpr Rad<Double> operator "" _rad(long double value) { return Rad<Double>(value); }
#endif
/** @relates Rad
@ -228,11 +228,11 @@ See operator""_degf() for more information.
@see Magnum::operator""_radf(), operator""_rad(), operator""_degf()
@note Not available on GCC < 4.7. Use Rad::Rad(T) instead.
*/
inline constexpr Rad<Float> operator "" _radf(long double value) { return Rad<Float>(value); }
constexpr Rad<Float> operator "" _radf(long double value) { return Rad<Float>(value); }
#endif
template<class T> inline constexpr Deg<T>::Deg(Unit<Rad, T> value): Unit<Math::Deg, T>(T(180)*T(value)/Math::Constants<T>::pi()) {}
template<class T> inline constexpr Rad<T>::Rad(Unit<Deg, T> value): Unit<Math::Rad, T>(T(value)*Math::Constants<T>::pi()/T(180)) {}
template<class T> constexpr Deg<T>::Deg(Unit<Rad, T> value): Unit<Math::Deg, T>(T(180)*T(value)/Math::Constants<T>::pi()) {}
template<class T> constexpr Rad<T>::Rad(Unit<Deg, T> value): Unit<Math::Rad, T>(T(value)*Math::Constants<T>::pi()/T(180)) {}
/** @debugoperator{Magnum::Math::Rad} */
template<class T> Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Unit<Rad, T>& value) {

132
src/Math/BoolVector.h

@ -49,7 +49,7 @@ namespace Implementation {
};
#endif
template<class T> inline constexpr T repeat(T value, std::size_t) { return value; }
template<class T> constexpr T repeat(T value, std::size_t) { return value; }
}
/**
@ -69,7 +69,7 @@ template<std::size_t size> class BoolVector {
static const std::size_t DataSize = (size-1)/8+1; /**< @brief %Vector storage size */
/** @brief Construct zero-filled boolean vector */
inline constexpr BoolVector(): _data() {}
constexpr BoolVector(): _data() {}
/**
* @brief Construct boolean vector from segment values
@ -77,9 +77,9 @@ template<std::size_t size> class BoolVector {
* @param next Values for next Bbit segments
*/
#ifdef DOXYGEN_GENERATING_OUTPUT
template<class ...T> inline constexpr /*implicit*/ BoolVector(UnsignedByte first, T... next);
template<class ...T> constexpr /*implicit*/ BoolVector(UnsignedByte first, T... next);
#else
template<class ...T, class U = typename std::enable_if<sizeof...(T)+1 == DataSize, bool>::type> inline constexpr /*implicit*/ BoolVector(UnsignedByte first, T... next): _data{first, UnsignedByte(next)...} {}
template<class ...T, class U = typename std::enable_if<sizeof...(T)+1 == DataSize, bool>::type> constexpr /*implicit*/ BoolVector(UnsignedByte first, T... next): _data{first, UnsignedByte(next)...} {}
#endif
/** @brief Construct boolean vector with one value for all fields */
@ -87,19 +87,19 @@ template<std::size_t size> class BoolVector {
inline explicit BoolVector(T value);
#else
#ifndef CORRADE_GCC46_COMPATIBILITY
template<class T, class U = typename std::enable_if<std::is_same<bool, T>::value && size != 1, bool>::type> inline constexpr explicit BoolVector(T value): BoolVector(typename Implementation::GenerateSequence<DataSize>::Type(), value ? FullSegmentMask : 0) {}
template<class T, class U = typename std::enable_if<std::is_same<bool, T>::value && size != 1, bool>::type> constexpr explicit BoolVector(T value): BoolVector(typename Implementation::GenerateSequence<DataSize>::Type(), value ? FullSegmentMask : 0) {}
#else
template<class T, class U = typename std::enable_if<std::is_same<bool, T>::value && size != 1, bool>::type> inline explicit BoolVector(T value) {
template<class T, class U = typename std::enable_if<std::is_same<bool, T>::value && size != 1, bool>::type> explicit BoolVector(T value) {
*this = BoolVector(typename Implementation::GenerateSequence<DataSize>::Type(), value ? FullSegmentMask : 0);
}
#endif
#endif
/** @brief Copy constructor */
inline constexpr BoolVector(const BoolVector<size>&) = default;
constexpr BoolVector(const BoolVector<size>&) = default;
/** @brief Copy assignment */
inline BoolVector<size>& operator=(const BoolVector<size>&) = default;
BoolVector<size>& operator=(const BoolVector<size>&) = default;
/**
* @brief Raw data
@ -107,84 +107,46 @@ template<std::size_t size> class BoolVector {
*
* @see operator[](), set()
*/
inline UnsignedByte* data() { return _data; }
inline constexpr const UnsignedByte* data() const { return _data; } /**< @overload */
UnsignedByte* data() { return _data; }
constexpr const UnsignedByte* data() const { return _data; } /**< @overload */
/** @brief Bit at given position */
inline constexpr bool operator[](std::size_t i) const {
constexpr bool operator[](std::size_t i) const {
return (_data[i/8] >> i%8) & 0x01;
}
/** @brief Set bit at given position */
inline BoolVector<size>& set(std::size_t i, bool value) {
BoolVector<size>& set(std::size_t i, bool value) {
_data[i/8] |= ((value & 0x01) << i%8);
return *this;
}
/** @brief Equality comparison */
inline bool operator==(const BoolVector<size>& other) const {
for(std::size_t i = 0; i != size/8; ++i)
if(_data[i] != other._data[i]) return false;
/* Check last segment */
if(size%8 && (_data[DataSize-1] & LastSegmentMask) != (other._data[DataSize-1] & LastSegmentMask))
return false;
return true;
}
bool operator==(const BoolVector<size>& other) const;
/** @brief Non-equality comparison */
inline bool operator!=(const BoolVector<size>& other) const {
bool operator!=(const BoolVector<size>& other) const {
return !operator==(other);
}
/** @brief Whether all bits are set */
bool all() const {
/* Check all full segments */
for(std::size_t i = 0; i != size/8; ++i)
if(_data[i] != FullSegmentMask) return false;
/* Check last segment */
if(size%8 && (_data[DataSize-1] & LastSegmentMask) != LastSegmentMask)
return false;
return true;
}
bool all() const;
/** @brief Whether no bits are set */
bool none() const {
/* Check all full segments */
for(std::size_t i = 0; i != size/8; ++i)
if(_data[i]) return false;
/* Check last segment */
if(size%8 && (_data[DataSize-1] & LastSegmentMask))
return false;
return true;
}
bool none() const;
/** @brief Whether any bit is set */
inline bool any() const {
return !none();
}
bool any() const { return !none(); }
/** @brief Bitwise inversion */
inline BoolVector<size> operator~() const {
BoolVector<size> out;
for(std::size_t i = 0; i != DataSize; ++i)
out._data[i] = ~_data[i];
return out;
}
BoolVector<size> operator~() const;
/**
* @brief Bitwise AND and assign
*
* The computation is done in-place.
*/
inline BoolVector<size>& operator&=(const BoolVector<size>& other) {
BoolVector<size>& operator&=(const BoolVector<size>& other) {
for(std::size_t i = 0; i != DataSize; ++i)
_data[i] &= other._data[i];
@ -196,7 +158,7 @@ template<std::size_t size> class BoolVector {
*
* @see operator&=()
*/
inline BoolVector<size> operator&(const BoolVector<size>& other) const {
BoolVector<size> operator&(const BoolVector<size>& other) const {
return BoolVector<size>(*this) &= other;
}
@ -205,7 +167,7 @@ template<std::size_t size> class BoolVector {
*
* The computation is done in-place.
*/
inline BoolVector<size>& operator|=(const BoolVector<size>& other) {
BoolVector<size>& operator|=(const BoolVector<size>& other) {
for(std::size_t i = 0; i != DataSize; ++i)
_data[i] |= other._data[i];
@ -217,7 +179,7 @@ template<std::size_t size> class BoolVector {
*
* @see operator|=()
*/
inline BoolVector<size> operator|(const BoolVector<size>& other) const {
BoolVector<size> operator|(const BoolVector<size>& other) const {
return BoolVector<size>(*this) |= other;
}
@ -226,7 +188,7 @@ template<std::size_t size> class BoolVector {
*
* The computation is done in-place.
*/
inline BoolVector<size>& operator^=(const BoolVector<size>& other) {
BoolVector<size>& operator^=(const BoolVector<size>& other) {
for(std::size_t i = 0; i != DataSize; ++i)
_data[i] ^= other._data[i];
@ -238,7 +200,7 @@ template<std::size_t size> class BoolVector {
*
* @see operator^=()
*/
inline BoolVector<size> operator^(const BoolVector<size>& other) const {
BoolVector<size> operator^(const BoolVector<size>& other) const {
return BoolVector<size>(*this) ^= other;
}
@ -249,7 +211,7 @@ template<std::size_t size> class BoolVector {
};
/* Implementation for Vector<size, T>::Vector(U) */
template<std::size_t ...sequence> inline constexpr explicit BoolVector(Implementation::Sequence<sequence...>, UnsignedByte value): _data{Implementation::repeat(value, sequence)...} {}
template<std::size_t ...sequence> constexpr explicit BoolVector(Implementation::Sequence<sequence...>, UnsignedByte value): _data{Implementation::repeat(value, sequence)...} {}
UnsignedByte _data[(size-1)/8+1];
};
@ -267,6 +229,50 @@ template<std::size_t size> Corrade::Utility::Debug operator<<(Corrade::Utility::
return debug;
}
template<std::size_t size> inline bool BoolVector<size>::operator==(const BoolVector< size >& other) const {
for(std::size_t i = 0; i != size/8; ++i)
if(_data[i] != other._data[i]) return false;
/* Check last segment */
if(size%8 && (_data[DataSize-1] & LastSegmentMask) != (other._data[DataSize-1] & LastSegmentMask))
return false;
return true;
}
template<std::size_t size> inline bool BoolVector<size>::all() const {
/* Check all full segments */
for(std::size_t i = 0; i != size/8; ++i)
if(_data[i] != FullSegmentMask) return false;
/* Check last segment */
if(size%8 && (_data[DataSize-1] & LastSegmentMask) != LastSegmentMask)
return false;
return true;
}
template<std::size_t size> inline bool BoolVector<size>::none() const {
/* Check all full segments */
for(std::size_t i = 0; i != size/8; ++i)
if(_data[i]) return false;
/* Check last segment */
if(size%8 && (_data[DataSize-1] & LastSegmentMask))
return false;
return true;
}
template<std::size_t size> inline BoolVector<size> BoolVector<size>::operator~() const {
BoolVector<size> out;
for(std::size_t i = 0; i != DataSize; ++i)
out._data[i] = ~_data[i];
return out;
}
}}
#endif

64
src/Math/Complex.h

@ -40,7 +40,7 @@ namespace Magnum { namespace Math {
namespace Implementation {
/* No assertions fired, for internal use. Not private member because used
from outside the class. */
template<class T> inline static Complex<T> complexFromMatrix(const Matrix<2, T>& matrix) {
template<class T> constexpr static Complex<T> complexFromMatrix(const Matrix<2, T>& matrix) {
return {matrix[0][0], matrix[0][1]};
}
}
@ -64,7 +64,7 @@ template<class T> class Complex {
* @f]
* @see dot() const
*/
inline static T dot(const Complex<T>& a, const Complex<T>& b) {
static T dot(const Complex<T>& a, const Complex<T>& b) {
return a._real*b._real + a._imaginary*b._imaginary;
}
@ -76,7 +76,7 @@ template<class T> class Complex {
* @f]
* @see isNormalized(), Quaternion::angle(), Vector::angle()
*/
inline static Rad<T> angle(const Complex<T>& normalizedA, const Complex<T>& normalizedB) {
static Rad<T> angle(const Complex<T>& normalizedA, const Complex<T>& normalizedB) {
CORRADE_ASSERT(normalizedA.isNormalized() && normalizedB.isNormalized(),
"Math::Complex::angle(): complex numbers must be normalized", Rad<T>(std::numeric_limits<T>::quiet_NaN()));
return Rad<T>(std::acos(normalizedA._real*normalizedB._real + normalizedA._imaginary*normalizedB._imaginary));
@ -91,7 +91,7 @@ template<class T> class Complex {
* @f]
* @see angle(), Matrix3::rotation(), Quaternion::rotation()
*/
inline static Complex<T> rotation(Rad<T> angle) {
static Complex<T> rotation(Rad<T> angle) {
return {std::cos(T(angle)), std::sin(T(angle))};
}
@ -101,7 +101,7 @@ template<class T> class Complex {
* Expects that the matrix is orthogonal (i.e. pure rotation).
* @see toMatrix(), DualComplex::fromMatrix(), Matrix::isOrthogonal()
*/
inline static Complex<T> fromMatrix(const Matrix<2, T>& matrix) {
static Complex<T> fromMatrix(const Matrix<2, T>& matrix) {
CORRADE_ASSERT(matrix.isOrthogonal(),
"Math::Complex::fromMatrix(): the matrix is not orthogonal", {});
return Implementation::complexFromMatrix(matrix);
@ -114,7 +114,7 @@ template<class T> class Complex {
* c = 1 + i0
* @f]
*/
inline constexpr /*implicit*/ Complex(): _real(T(1)), _imaginary(T(0)) {}
constexpr /*implicit*/ Complex(): _real(T(1)), _imaginary(T(0)) {}
/**
* @brief Construct complex number from real and imaginary part
@ -123,7 +123,7 @@ template<class T> class Complex {
* c = a + ib
* @f]
*/
inline constexpr /*implicit*/ Complex(T real, T imaginary): _real(real), _imaginary(imaginary) {}
constexpr /*implicit*/ Complex(T real, T imaginary): _real(real), _imaginary(imaginary) {}
/**
* @brief Construct complex number from vector
@ -133,16 +133,16 @@ template<class T> class Complex {
* @f]
* @see operator Vector2(), transformVector()
*/
inline constexpr explicit Complex(const Vector2<T>& vector): _real(vector.x()), _imaginary(vector.y()) {}
constexpr explicit Complex(const Vector2<T>& vector): _real(vector.x()), _imaginary(vector.y()) {}
/** @brief Equality comparison */
inline bool operator==(const Complex<T>& other) const {
bool operator==(const Complex<T>& other) const {
return TypeTraits<T>::equals(_real, other._real) &&
TypeTraits<T>::equals(_imaginary, other._imaginary);
}
/** @brief Non-equality comparison */
inline bool operator!=(const Complex<T>& other) const {
bool operator!=(const Complex<T>& other) const {
return !operator==(other);
}
@ -154,15 +154,15 @@ template<class T> class Complex {
* @f]
* @see dot(), normalized()
*/
inline bool isNormalized() const {
bool isNormalized() const {
return Implementation::isNormalizedSquared(dot());
}
/** @brief Real part */
inline constexpr T real() const { return _real; }
constexpr T real() const { return _real; }
/** @brief Imaginary part */
inline constexpr T imaginary() const { return _imaginary; }
constexpr T imaginary() const { return _imaginary; }
/**
* @brief Convert complex number to vector
@ -171,7 +171,7 @@ template<class T> class Complex {
* \boldsymbol v = \begin{pmatrix} a \\ b \end{pmatrix}
* @f]
*/
inline constexpr explicit operator Vector2<T>() const {
constexpr explicit operator Vector2<T>() const {
return {_real, _imaginary};
}
@ -183,7 +183,7 @@ template<class T> class Complex {
* @f]
* @see rotation()
*/
inline Rad<T> angle() const {
Rad<T> angle() const {
return Rad<T>(std::atan2(_imaginary, _real));
}
@ -211,7 +211,7 @@ template<class T> class Complex {
* c_0 + c_1 = (a_0 + a_1) + i(b_0 + b_1)
* @f]
*/
inline Complex<T>& operator+=(const Complex<T>& other) {
Complex<T>& operator+=(const Complex<T>& other) {
_real += other._real;
_imaginary += other._imaginary;
return *this;
@ -222,7 +222,7 @@ template<class T> class Complex {
*
* @see operator+=()
*/
inline Complex<T> operator+(const Complex<T>& other) const {
Complex<T> operator+(const Complex<T>& other) const {
return Complex<T>(*this) += other;
}
@ -233,7 +233,7 @@ template<class T> class Complex {
* -c = -a -ib
* @f]
*/
inline Complex<T> operator-() const {
Complex<T> operator-() const {
return {-_real, -_imaginary};
}
@ -244,7 +244,7 @@ template<class T> class Complex {
* c_0 - c_1 = (a_0 - a_1) + i(b_0 - b_1)
* @f]
*/
inline Complex<T>& operator-=(const Complex<T>& other) {
Complex<T>& operator-=(const Complex<T>& other) {
_real -= other._real;
_imaginary -= other._imaginary;
return *this;
@ -255,7 +255,7 @@ template<class T> class Complex {
*
* @see operator-=()
*/
inline Complex<T> operator-(const Complex<T>& other) const {
Complex<T> operator-(const Complex<T>& other) const {
return Complex<T>(*this) -= other;
}
@ -266,7 +266,7 @@ template<class T> class Complex {
* c \cdot t = ta + itb
* @f]
*/
inline Complex<T>& operator*=(T scalar) {
Complex<T>& operator*=(T scalar) {
_real *= scalar;
_imaginary *= scalar;
return *this;
@ -277,7 +277,7 @@ template<class T> class Complex {
*
* @see operator*=(T)
*/
inline Complex<T> operator*(T scalar) const {
Complex<T> operator*(T scalar) const {
return Complex<T>(*this) *= scalar;
}
@ -288,7 +288,7 @@ template<class T> class Complex {
* \frac c t = \frac a t + i \frac b t
* @f]
*/
inline Complex<T>& operator/=(T scalar) {
Complex<T>& operator/=(T scalar) {
_real /= scalar;
_imaginary /= scalar;
return *this;
@ -299,7 +299,7 @@ template<class T> class Complex {
*
* @see operator/=(T)
*/
inline Complex<T> operator/(T scalar) const {
Complex<T> operator/(T scalar) const {
return Complex<T>(*this) /= scalar;
}
@ -310,7 +310,7 @@ template<class T> class Complex {
* c_0 c_1 = (a_0 + ib_0)(a_1 + ib_1) = (a_0 a_1 - b_0 b_1) + i(a_1 b_0 + a_0 b_1)
* @f]
*/
inline Complex<T> operator*(const Complex<T>& other) const {
Complex<T> operator*(const Complex<T>& other) const {
return {_real*other._real - _imaginary*other._imaginary,
_imaginary*other._real + _real*other._imaginary};
}
@ -324,7 +324,7 @@ template<class T> class Complex {
* @f]
* @see dot(const Complex&, const Complex&), isNormalized()
*/
inline T dot() const {
T dot() const {
return dot(*this, *this);
}
@ -337,7 +337,7 @@ template<class T> class Complex {
* @f]
* @see isNormalized()
*/
inline T length() const {
T length() const {
/** @todo Remove when NaCl's newlib has this fixed */
#ifndef CORRADE_TARGET_NACL_NEWLIB
return std::hypot(_real, _imaginary);
@ -351,7 +351,7 @@ template<class T> class Complex {
*
* @see isNormalized()
*/
inline Complex<T> normalized() const {
Complex<T> normalized() const {
return (*this)/length();
}
@ -362,7 +362,7 @@ template<class T> class Complex {
* c^* = a - ib
* @f]
*/
inline Complex<T> conjugated() const {
Complex<T> conjugated() const {
return {_real, -_imaginary};
}
@ -374,7 +374,7 @@ template<class T> class Complex {
* c^{-1} = \frac{c^*}{|c|^2} = \frac{c^*}{c \cdot c}
* @f]
*/
inline Complex<T> inverted() const {
Complex<T> inverted() const {
return conjugated()/dot();
}
@ -387,7 +387,7 @@ template<class T> class Complex {
* @f]
* @see isNormalized(), inverted()
*/
inline Complex<T> invertedNormalized() const {
Complex<T> invertedNormalized() const {
CORRADE_ASSERT(isNormalized(),
"Math::Complex::invertedNormalized(): complex number must be normalized",
Complex<T>(std::numeric_limits<T>::quiet_NaN(), {}));
@ -402,7 +402,7 @@ template<class T> class Complex {
* @f]
* @see Complex(const Vector2&), operator Vector2(), Matrix3::transformVector()
*/
inline Vector2<T> transformVector(const Vector2<T>& vector) const {
Vector2<T> transformVector(const Vector2<T>& vector) const {
return Vector2<T>((*this)*Complex<T>(vector));
}

18
src/Math/Constants.h

@ -47,10 +47,10 @@ template<class T> struct Constants {
*
* @see Deg, Rad
*/
static inline constexpr T pi();
static constexpr T pi();
static inline constexpr T sqrt2(); /**< @brief Square root of 2 */
static inline constexpr T sqrt3(); /**< @brief Square root of 3 */
static constexpr T sqrt2(); /**< @brief Square root of 2 */
static constexpr T sqrt3(); /**< @brief Square root of 3 */
#endif
};
@ -59,17 +59,17 @@ template<class T> struct Constants {
template<> struct Constants<Double> {
Constants() = delete;
static inline constexpr Double pi() { return 3.141592653589793; }
static inline constexpr Double sqrt2() { return 1.414213562373095; }
static inline constexpr Double sqrt3() { return 1.732050807568877; }
static constexpr Double pi() { return 3.141592653589793; }
static constexpr Double sqrt2() { return 1.414213562373095; }
static constexpr Double sqrt3() { return 1.732050807568877; }
};
#endif
template<> struct Constants<Float> {
Constants() = delete;
static inline constexpr Float pi() { return 3.141592654f; }
static inline constexpr Float sqrt2() { return 1.414213562f; }
static inline constexpr Float sqrt3() { return 1.732050808f; }
static constexpr Float pi() { return 3.141592654f; }
static constexpr Float sqrt2() { return 1.414213562f; }
static constexpr Float sqrt3() { return 1.732050808f; }
};
#endif

42
src/Math/Dual.h

@ -50,7 +50,7 @@ template<class T> class Dual {
*
* Both parts are default-constructed.
*/
inline constexpr /*implicit*/ Dual(): _real(), _dual() {}
constexpr /*implicit*/ Dual(): _real(), _dual() {}
/**
* @brief Construct dual number from real and dual part
@ -59,24 +59,24 @@ template<class T> class Dual {
* \hat a = a_0 + \epsilon a_\epsilon
* @f]
*/
inline constexpr /*implicit*/ Dual(const T& real, const T& dual = T()): _real(real), _dual(dual) {}
constexpr /*implicit*/ Dual(const T& real, const T& dual = T()): _real(real), _dual(dual) {}
/** @brief Equality comparison */
inline bool operator==(const Dual<T>& other) const {
bool operator==(const Dual<T>& other) const {
return TypeTraits<T>::equals(_real, other._real) &&
TypeTraits<T>::equals(_dual, other._dual);
}
/** @brief Non-equality comparison */
inline bool operator!=(const Dual<T>& other) const {
bool operator!=(const Dual<T>& other) const {
return !operator==(other);
}
/** @brief Real part */
inline constexpr T real() const { return _real; }
constexpr T real() const { return _real; }
/** @brief %Dual part */
inline constexpr T dual() const { return _dual; }
constexpr T dual() const { return _dual; }
/**
* @brief Add and assign dual number
@ -85,7 +85,7 @@ template<class T> class Dual {
* \hat a + \hat b = a_0 + b_0 + \epsilon (a_\epsilon + b_\epsilon)
* @f]
*/
inline Dual<T>& operator+=(const Dual<T>& other) {
Dual<T>& operator+=(const Dual<T>& other) {
_real += other._real;
_dual += other._dual;
return *this;
@ -96,7 +96,7 @@ template<class T> class Dual {
*
* @see operator+=()
*/
inline Dual<T> operator+(const Dual<T>& other) const {
Dual<T> operator+(const Dual<T>& other) const {
return Dual<T>(*this)+=other;
}
@ -107,7 +107,7 @@ template<class T> class Dual {
* -\hat a = -a_0 - \epsilon a_\epsilon
* @f]
*/
inline Dual<T> operator-() const {
Dual<T> operator-() const {
return {-_real, -_dual};
}
@ -118,7 +118,7 @@ template<class T> class Dual {
* \hat a - \hat b = a_0 - b_0 + \epsilon (a_\epsilon - b_\epsilon)
* @f]
*/
inline Dual<T>& operator-=(const Dual<T>& other) {
Dual<T>& operator-=(const Dual<T>& other) {
_real -= other._real;
_dual -= other._dual;
return *this;
@ -129,7 +129,7 @@ template<class T> class Dual {
*
* @see operator-=()
*/
inline Dual<T> operator-(const Dual<T>& other) const {
Dual<T> operator-(const Dual<T>& other) const {
return Dual<T>(*this)-=other;
}
@ -140,7 +140,7 @@ template<class T> class Dual {
* \hat a \hat b = a_0 b_0 + \epsilon (a_0 b_\epsilon + a_\epsilon b_0)
* @f]
*/
template<class U> inline Dual<T> operator*(const Dual<U>& other) const {
template<class U> Dual<T> operator*(const Dual<U>& other) const {
return {_real*other._real, _real*other._dual + _dual*other._real};
}
@ -151,7 +151,7 @@ template<class T> class Dual {
* \frac{\hat a}{\hat b} = \frac{a_0}{b_0} + \epsilon \frac{a_\epsilon b_0 - a_0 b_\epsilon}{b_0^2}
* @f]
*/
template<class U> inline Dual<T> operator/(const Dual<U>& other) const {
template<class U> Dual<T> operator/(const Dual<U>& other) const {
return {_real/other._real, (_dual*other._real - _real*other._dual)/(other._real*other._real)};
}
@ -162,7 +162,7 @@ template<class T> class Dual {
* \overline{\hat a} = a_0 - \epsilon a_\epsilon
* @f]
*/
inline Dual<T> conjugated() const {
Dual<T> conjugated() const {
return {_real, -_dual};
}
@ -172,27 +172,27 @@ template<class T> class Dual {
#ifndef DOXYGEN_GENERATING_OUTPUT
#define MAGNUM_DUAL_SUBCLASS_IMPLEMENTATION(Type, Underlying) \
inline Type<T> operator-() const { \
Type<T> operator-() const { \
return Dual<Underlying<T>>::operator-(); \
} \
inline Type<T>& operator+=(const Dual<Underlying<T>>& other) { \
Type<T>& operator+=(const Dual<Underlying<T>>& other) { \
Dual<Underlying<T>>::operator+=(other); \
return *this; \
} \
inline Type<T> operator+(const Dual<Underlying<T>>& other) const { \
Type<T> operator+(const Dual<Underlying<T>>& other) const { \
return Dual<Underlying<T>>::operator+(other); \
} \
inline Type<T>& operator-=(const Dual<Underlying<T>>& other) { \
Type<T>& operator-=(const Dual<Underlying<T>>& other) { \
Dual<Underlying<T>>::operator-=(other); \
return *this; \
} \
inline Type<T> operator-(const Dual<Underlying<T>>& other) const { \
Type<T> operator-(const Dual<Underlying<T>>& other) const { \
return Dual<Underlying<T>>::operator-(other); \
} \
template<class U> inline Type<T> operator*(const Dual<U>& other) const { \
template<class U> Type<T> operator*(const Dual<U>& other) const { \
return Dual<Underlying<T>>::operator*(other); \
} \
template<class U> inline Type<T> operator/(const Dual<U>& other) const { \
template<class U> Type<T> operator/(const Dual<U>& other) const { \
return Dual<Underlying<T>>::operator/(other); \
}
#endif

56
src/Math/DualComplex.h

@ -58,7 +58,7 @@ template<class T> class DualComplex: public Dual<Complex<T>> {
* @see angle(), Complex::rotation(), Matrix3::rotation(),
* DualQuaternion::rotation()
*/
inline static DualComplex<T> rotation(Rad<T> angle) {
static DualComplex<T> rotation(Rad<T> angle) {
return {Complex<T>::rotation(angle), {{}, {}}};
}
@ -72,7 +72,7 @@ template<class T> class DualComplex: public Dual<Complex<T>> {
* @see translation() const, Matrix3::translation(const Vector2&),
* DualQuaternion::translation(), Vector2::xAxis(), Vector2::yAxis()
*/
inline static DualComplex<T> translation(const Vector2<T>& vector) {
static DualComplex<T> translation(const Vector2<T>& vector) {
return {{}, {vector.x(), vector.y()}};
}
@ -83,7 +83,7 @@ template<class T> class DualComplex: public Dual<Complex<T>> {
* @see toMatrix(), Complex::fromMatrix(),
* Matrix3::isRigidTransformation()
*/
inline static DualComplex<T> fromMatrix(const Matrix3<T>& matrix) {
static DualComplex<T> fromMatrix(const Matrix3<T>& matrix) {
CORRADE_ASSERT(matrix.isRigidTransformation(),
"Math::DualComplex::fromMatrix(): the matrix doesn't represent rigid transformation", {});
return {Implementation::complexFromMatrix(matrix.rotationScaling()), Complex<T>(matrix.translation())};
@ -98,9 +98,9 @@ template<class T> class DualComplex: public Dual<Complex<T>> {
* @todoc Remove workaround when Doxygen is predictable
*/
#ifdef DOXYGEN_GENERATING_OUTPUT
inline constexpr /*implicit*/ DualComplex();
constexpr /*implicit*/ DualComplex();
#else
inline constexpr /*implicit*/ DualComplex(): Dual<Complex<T>>({}, {T(0), T(0)}) {}
constexpr /*implicit*/ DualComplex(): Dual<Complex<T>>({}, {T(0), T(0)}) {}
#endif
/**
@ -110,7 +110,7 @@ template<class T> class DualComplex: public Dual<Complex<T>> {
* \hat c = c_0 + \epsilon c_\epsilon
* @f]
*/
inline constexpr /*implicit*/ DualComplex(const Complex<T>& real, const Complex<T>& dual = Complex<T>(T(0), T(0))): Dual<Complex<T>>(real, dual) {}
constexpr /*implicit*/ DualComplex(const Complex<T>& real, const Complex<T>& dual = Complex<T>(T(0), T(0))): Dual<Complex<T>>(real, dual) {}
/**
* @brief Construct dual complex number from vector
@ -121,9 +121,9 @@ template<class T> class DualComplex: public Dual<Complex<T>> {
* @todoc Remove workaround when Doxygen is predictable
*/
#ifdef DOXYGEN_GENERATING_OUTPUT
inline constexpr explicit DualComplex(const Vector2<T>& vector);
constexpr explicit DualComplex(const Vector2<T>& vector);
#else
inline constexpr explicit DualComplex(const Vector2<T>& vector): Dual<Complex<T>>({}, Complex<T>(vector)) {}
constexpr explicit DualComplex(const Vector2<T>& vector): Dual<Complex<T>>({}, Complex<T>(vector)) {}
#endif
/**
@ -134,7 +134,7 @@ template<class T> class DualComplex: public Dual<Complex<T>> {
* @f]
* @see Complex::dot(), normalized()
*/
inline bool isNormalized() const {
bool isNormalized() const {
return Implementation::isNormalizedSquared(lengthSquared());
}
@ -143,7 +143,7 @@ template<class T> class DualComplex: public Dual<Complex<T>> {
*
* @see Complex::angle()
*/
inline constexpr Complex<T> rotation() const {
constexpr Complex<T> rotation() const {
return this->real();
}
@ -155,7 +155,7 @@ template<class T> class DualComplex: public Dual<Complex<T>> {
* @f]
* @see translation(const Vector2&)
*/
inline Vector2<T> translation() const {
Vector2<T> translation() const {
return Vector2<T>(this->dual());
}
@ -164,7 +164,7 @@ template<class T> class DualComplex: public Dual<Complex<T>> {
*
* @see fromMatrix(), Complex::toMatrix()
*/
inline Matrix3<T> toMatrix() const {
Matrix3<T> toMatrix() const {
return Matrix3<T>::from(this->real().toMatrix(), translation());
}
@ -176,7 +176,7 @@ template<class T> class DualComplex: public Dual<Complex<T>> {
* @f]
* @todo can this be done similarly to dual quaternions?
*/
inline DualComplex<T> operator*(const DualComplex<T>& other) const {
DualComplex<T> operator*(const DualComplex<T>& other) const {
return {this->real()*other.real(), this->real()*other.dual() + this->dual()};
}
@ -188,7 +188,7 @@ template<class T> class DualComplex: public Dual<Complex<T>> {
* @f]
* @see dualConjugated(), conjugated(), Complex::conjugated()
*/
inline DualComplex<T> complexConjugated() const {
DualComplex<T> complexConjugated() const {
return {this->real().conjugated(), this->dual().conjugated()};
}
@ -200,7 +200,7 @@ template<class T> class DualComplex: public Dual<Complex<T>> {
* @f]
* @see complexConjugated(), conjugated(), Dual::conjugated()
*/
inline DualComplex<T> dualConjugated() const {
DualComplex<T> dualConjugated() const {
return Dual<Complex<T>>::conjugated();
}
@ -213,7 +213,7 @@ template<class T> class DualComplex: public Dual<Complex<T>> {
* @see complexConjugated(), dualConjugated(), Complex::conjugated(),
* Dual::conjugated()
*/
inline DualComplex<T> conjugated() const {
DualComplex<T> conjugated() const {
return {this->real().conjugated(), {-this->dual().real(), this->dual().imaginary()}};
}
@ -226,7 +226,7 @@ template<class T> class DualComplex: public Dual<Complex<T>> {
* @f]
* @todo Can this be done similarly to dual quaternins?
*/
inline T lengthSquared() const {
T lengthSquared() const {
return this->real().dot();
}
@ -239,7 +239,7 @@ template<class T> class DualComplex: public Dual<Complex<T>> {
* @f]
* @todo can this be done similarly to dual quaternions?
*/
inline T length() const {
T length() const {
return this->real().length();
}
@ -252,7 +252,7 @@ template<class T> class DualComplex: public Dual<Complex<T>> {
* @see isNormalized()
* @todo can this be done similarly to dual quaternions?
*/
inline DualComplex<T> normalized() const {
DualComplex<T> normalized() const {
return {this->real()/length(), this->dual()};
}
@ -265,7 +265,7 @@ template<class T> class DualComplex: public Dual<Complex<T>> {
* @f]
* @todo can this be done similarly to dual quaternions?
*/
inline DualComplex<T> inverted() const {
DualComplex<T> inverted() const {
return DualComplex<T>(this->real().inverted(), {{}, {}})*DualComplex<T>({}, -this->dual());
}
@ -278,7 +278,7 @@ template<class T> class DualComplex: public Dual<Complex<T>> {
* @see isNormalized(), inverted()
* @todo can this be done similarly to dual quaternions?
*/
inline DualComplex<T> invertedNormalized() const {
DualComplex<T> invertedNormalized() const {
return DualComplex<T>(this->real().invertedNormalized(), {{}, {}})*DualComplex<T>({}, -this->dual());
}
@ -292,35 +292,35 @@ template<class T> class DualComplex: public Dual<Complex<T>> {
* @see DualComplex(const Vector2&), dual(), Matrix3::transformPoint(),
* Complex::transformVector(), DualQuaternion::transformPoint()
*/
inline Vector2<T> transformPoint(const Vector2<T>& vector) const {
Vector2<T> transformPoint(const Vector2<T>& vector) const {
return Vector2<T>(((*this)*DualComplex<T>(vector)).dual());
}
/* Verbatim copy of DUAL_SUBCLASS_IMPLEMENTATION(), as we need to hide
Dual's operator*() and operator/() */
#ifndef DOXYGEN_GENERATING_OUTPUT
inline DualComplex<T> operator-() const {
DualComplex<T> operator-() const {
return Dual<Complex<T>>::operator-();
}
inline DualComplex<T>& operator+=(const Dual<Complex<T>>& other) {
DualComplex<T>& operator+=(const Dual<Complex<T>>& other) {
Dual<Complex<T>>::operator+=(other);
return *this;
}
inline DualComplex<T> operator+(const Dual<Complex<T>>& other) const {
DualComplex<T> operator+(const Dual<Complex<T>>& other) const {
return Dual<Complex<T>>::operator+(other);
}
inline DualComplex<T>& operator-=(const Dual<Complex<T>>& other) {
DualComplex<T>& operator-=(const Dual<Complex<T>>& other) {
Dual<Complex<T>>::operator-=(other);
return *this;
}
inline DualComplex<T> operator-(const Dual<Complex<T>>& other) const {
DualComplex<T> operator-(const Dual<Complex<T>>& other) const {
return Dual<Complex<T>>::operator-(other);
}
#endif
private:
/* Used by Dual operators and dualConjugated() */
inline constexpr DualComplex(const Dual<Complex<T>>& other): Dual<Complex<T>>(other) {}
constexpr DualComplex(const Dual<Complex<T>>& other): Dual<Complex<T>>(other) {}
/* Just to be sure nobody uses this, as it wouldn't probably work with
our operator*() */

44
src/Math/DualQuaternion.h

@ -58,7 +58,7 @@ template<class T> class DualQuaternion: public Dual<Quaternion<T>> {
* DualComplex::rotation(), Vector3::xAxis(), Vector3::yAxis(),
* Vector3::zAxis(), Vector::isNormalized()
*/
inline static DualQuaternion<T> rotation(Rad<T> angle, const Vector3<T>& normalizedAxis) {
static DualQuaternion<T> rotation(Rad<T> angle, const Vector3<T>& normalizedAxis) {
return {Quaternion<T>::rotation(angle, normalizedAxis), {{}, T(0)}};
}
@ -75,7 +75,7 @@ template<class T> class DualQuaternion: public Dual<Quaternion<T>> {
* DualComplex::translation(), Vector3::xAxis(), Vector3::yAxis(),
* Vector3::zAxis()
*/
inline static DualQuaternion<T> translation(const Vector3<T>& vector) {
static DualQuaternion<T> translation(const Vector3<T>& vector) {
return {{}, {vector/T(2), T(0)}};
}
@ -86,7 +86,7 @@ template<class T> class DualQuaternion: public Dual<Quaternion<T>> {
* @see toMatrix(), Quaternion::fromMatrix(),
* Matrix4::isRigidTransformation()
*/
inline static DualQuaternion<T> fromMatrix(const Matrix4<T>& matrix) {
static DualQuaternion<T> fromMatrix(const Matrix4<T>& matrix) {
CORRADE_ASSERT(matrix.isRigidTransformation(),
"Math::DualQuaternion::fromMatrix(): the matrix doesn't represent rigid transformation", {});
@ -103,9 +103,9 @@ template<class T> class DualQuaternion: public Dual<Quaternion<T>> {
* @todoc Remove workaround when Doxygen is predictable
*/
#ifdef DOXYGEN_GENERATING_OUTPUT
inline constexpr /*implicit*/ DualQuaternion();
constexpr /*implicit*/ DualQuaternion();
#else
inline constexpr /*implicit*/ DualQuaternion(): Dual<Quaternion<T>>({}, {{}, T(0)}) {}
constexpr /*implicit*/ DualQuaternion(): Dual<Quaternion<T>>({}, {{}, T(0)}) {}
#endif
/**
@ -115,7 +115,7 @@ template<class T> class DualQuaternion: public Dual<Quaternion<T>> {
* \hat q = q_0 + \epsilon q_\epsilon
* @f]
*/
inline constexpr /*implicit*/ DualQuaternion(const Quaternion<T>& real, const Quaternion<T>& dual = Quaternion<T>({}, T(0))): Dual<Quaternion<T>>(real, dual) {}
constexpr /*implicit*/ DualQuaternion(const Quaternion<T>& real, const Quaternion<T>& dual = Quaternion<T>({}, T(0))): Dual<Quaternion<T>>(real, dual) {}
/**
* @brief Construct dual quaternion from vector
@ -127,9 +127,9 @@ template<class T> class DualQuaternion: public Dual<Quaternion<T>> {
* @todoc Remove workaround when Doxygen is predictable
*/
#ifdef DOXYGEN_GENERATING_OUTPUT
inline constexpr explicit DualQuaternion(const Vector3<T>& vector);
constexpr explicit DualQuaternion(const Vector3<T>& vector);
#else
inline constexpr explicit DualQuaternion(const Vector3<T>& vector): Dual<Quaternion<T>>({}, {vector, T(0)}) {}
constexpr explicit DualQuaternion(const Vector3<T>& vector): Dual<Quaternion<T>>({}, {vector, T(0)}) {}
#endif
/**
@ -140,7 +140,7 @@ template<class T> class DualQuaternion: public Dual<Quaternion<T>> {
* @f]
* @see lengthSquared(), normalized()
*/
inline bool isNormalized() const {
bool isNormalized() const {
/* Comparing dual part classically, as comparing sqrt() of it would
lead to overly strict precision */
Dual<T> a = lengthSquared();
@ -153,7 +153,7 @@ template<class T> class DualQuaternion: public Dual<Quaternion<T>> {
*
* @see Quaternion::angle(), Quaternion::axis()
*/
inline constexpr Quaternion<T> rotation() const {
constexpr Quaternion<T> rotation() const {
return this->real();
}
@ -165,7 +165,7 @@ template<class T> class DualQuaternion: public Dual<Quaternion<T>> {
* @f]
* @see translation(const Vector3&)
*/
inline Vector3<T> translation() const {
Vector3<T> translation() const {
return (this->dual()*this->real().conjugated()).vector()*T(2);
}
@ -186,7 +186,7 @@ template<class T> class DualQuaternion: public Dual<Quaternion<T>> {
* @f]
* @see dualConjugated(), conjugated(), Quaternion::conjugated()
*/
inline DualQuaternion<T> quaternionConjugated() const {
DualQuaternion<T> quaternionConjugated() const {
return {this->real().conjugated(), this->dual().conjugated()};
}
@ -198,7 +198,7 @@ template<class T> class DualQuaternion: public Dual<Quaternion<T>> {
* @f]
* @see quaternionConjugated(), conjugated(), Dual::conjugated()
*/
inline DualQuaternion<T> dualConjugated() const {
DualQuaternion<T> dualConjugated() const {
return Dual<Quaternion<T>>::conjugated();
}
@ -211,7 +211,7 @@ template<class T> class DualQuaternion: public Dual<Quaternion<T>> {
* @see quaternionConjugated(), dualConjugated(), Quaternion::conjugated(),
* Dual::conjugated()
*/
inline DualQuaternion<T> conjugated() const {
DualQuaternion<T> conjugated() const {
return {this->real().conjugated(), {this->dual().vector(), -this->dual().scalar()}};
}
@ -223,7 +223,7 @@ template<class T> class DualQuaternion: public Dual<Quaternion<T>> {
* |\hat q|^2 = \sqrt{\hat q^* \hat q}^2 = q_0 \cdot q_0 + \epsilon 2 (q_0 \cdot q_\epsilon)
* @f]
*/
inline Dual<T> lengthSquared() const {
Dual<T> lengthSquared() const {
return {this->real().dot(), T(2)*Quaternion<T>::dot(this->real(), this->dual())};
}
@ -235,7 +235,7 @@ template<class T> class DualQuaternion: public Dual<Quaternion<T>> {
* |\hat q| = \sqrt{\hat q^* \hat q} = |q_0| + \epsilon \frac{q_0 \cdot q_\epsilon}{|q_0|}
* @f]
*/
inline Dual<T> length() const {
Dual<T> length() const {
return Math::sqrt(lengthSquared());
}
@ -244,7 +244,7 @@ template<class T> class DualQuaternion: public Dual<Quaternion<T>> {
*
* @see isNormalized()
*/
inline DualQuaternion<T> normalized() const {
DualQuaternion<T> normalized() const {
return (*this)/length();
}
@ -256,7 +256,7 @@ template<class T> class DualQuaternion: public Dual<Quaternion<T>> {
* \hat q^{-1} = \frac{\hat q^*}{|\hat q|^2}
* @f]
*/
inline DualQuaternion<T> inverted() const {
DualQuaternion<T> inverted() const {
return quaternionConjugated()/lengthSquared();
}
@ -269,7 +269,7 @@ template<class T> class DualQuaternion: public Dual<Quaternion<T>> {
* @f]
* @see isNormalized(), inverted()
*/
inline DualQuaternion<T> invertedNormalized() const {
DualQuaternion<T> invertedNormalized() const {
CORRADE_ASSERT(isNormalized(),
"Math::DualQuaternion::invertedNormalized(): dual quaternion must be normalized", {});
return quaternionConjugated();
@ -285,7 +285,7 @@ template<class T> class DualQuaternion: public Dual<Quaternion<T>> {
* @see DualQuaternion(const Vector3&), dual(), Matrix4::transformPoint(),
* Quaternion::transformVector(), DualComplex::transformPoint()
*/
inline Vector3<T> transformPoint(const Vector3<T>& vector) const {
Vector3<T> transformPoint(const Vector3<T>& vector) const {
return ((*this)*DualQuaternion<T>(vector)*inverted().dualConjugated()).dual().vector();
}
@ -300,7 +300,7 @@ template<class T> class DualQuaternion: public Dual<Quaternion<T>> {
* Matrix4::transformPoint(), Quaternion::transformVectorNormalized(),
* DualComplex::transformPointNormalized()
*/
inline Vector3<T> transformPointNormalized(const Vector3<T>& vector) const {
Vector3<T> transformPointNormalized(const Vector3<T>& vector) const {
CORRADE_ASSERT(isNormalized(),
"Math::DualQuaternion::transformPointNormalized(): dual quaternion must be normalized",
Vector3<T>(std::numeric_limits<T>::quiet_NaN()));
@ -311,7 +311,7 @@ template<class T> class DualQuaternion: public Dual<Quaternion<T>> {
private:
/* Used by Dual operators and dualConjugated() */
inline constexpr DualQuaternion(const Dual<Quaternion<T>>& other): Dual<Quaternion<T>>(other) {}
constexpr DualQuaternion(const Dual<Quaternion<T>>& other): Dual<Quaternion<T>>(other) {}
};
/** @debugoperator{Magnum::Math::DualQuaternion} */

6
src/Math/Functions.h

@ -42,14 +42,14 @@ namespace Implementation {
template<UnsignedInt exponent> struct Pow {
Pow() = delete;
template<class T> inline constexpr static T pow(T base) {
template<class T> constexpr static T pow(T base) {
return base*Pow<exponent-1>::pow(base);
}
};
template<> struct Pow<0> {
Pow() = delete;
template<class T> inline constexpr static T pow(T) { return 1; }
template<class T> constexpr static T pow(T) { return 1; }
};
}
@ -58,7 +58,7 @@ namespace Implementation {
*
* Returns integral power of base to the exponent.
*/
template<UnsignedInt exponent, class T> inline constexpr T pow(T base) {
template<UnsignedInt exponent, class T> constexpr T pow(T base) {
return Implementation::Pow<exponent>::pow(base);
}

126
src/Math/Geometry/Distance.h

@ -51,7 +51,7 @@ class Distance {
* Source: http://mathworld.wolfram.com/Point-LineDistance2-Dimensional.html
* @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) {
template<class T> static T linePoint(const Vector2<T>& a, const Vector2<T>& b, const Vector2<T>& point) {
const Vector2<T> bMinusA = b - a;
return std::abs(Vector2<T>::cross(bMinusA, a - point))/bMinusA.length();
}
@ -66,7 +66,7 @@ class Distance {
* for comparing distance with other values, because it doesn't
* compute the square root.
*/
template<class T> inline static T linePointSquared(const Vector2<T>& a, const Vector2<T>& b, const Vector2<T>& point) {
template<class T> static T linePointSquared(const Vector2<T>& a, const Vector2<T>& b, const Vector2<T>& point) {
const Vector2<T> bMinusA = b - a;
return Math::pow<2>(Vector2<T>::cross(bMinusA, a - point))/bMinusA.dot();
}
@ -85,7 +85,7 @@ class Distance {
* Source: http://mathworld.wolfram.com/Point-LineDistance3-Dimensional.html
* @see linePointSquared(const Vector3&, const Vector3&, const Vector3&)
*/
template<class T> inline static T linePoint(const Vector3<T>& a, const Vector3<T>& b, const Vector3<T>& point) {
template<class T> static T linePoint(const Vector3<T>& a, const Vector3<T>& b, const Vector3<T>& point) {
return std::sqrt(linePointSquared(a, b, point));
}
@ -126,25 +126,7 @@ class Distance {
*
* @see lineSegmentPointSquared()
*/
template<class T> inline static T lineSegmentPoint(const Vector2<T>& a, const Vector2<T>& b, const Vector2<T>& point) {
const Vector2<T> pointMinusA = point - a;
const Vector2<T> pointMinusB = point - b;
const Vector2<T> bMinusA = b - a;
const T pointDistanceA = pointMinusA.dot();
const T pointDistanceB = pointMinusB.dot();
const T bDistanceA = bMinusA.dot();
/* Point is before A */
if(pointDistanceB > bDistanceA + pointDistanceA)
return std::sqrt(pointDistanceA);
/* Point is after B */
if(pointDistanceA > bDistanceA + pointDistanceB)
return std::sqrt(pointDistanceB);
/* Between A and B */
return std::abs(Vector2<T>::cross(bMinusA, -pointMinusA))/std::sqrt(bDistanceA);
}
template<class T> static T lineSegmentPoint(const Vector2<T>& a, const Vector2<T>& b, const Vector2<T>& point);
/**
* @brief %Distance of point from line segment in 2D, squared
@ -152,25 +134,7 @@ class Distance {
* More efficient than lineSegmentPoint() for comparing distance with
* other values, because it doesn't compute the square root.
*/
template<class T> static T lineSegmentPointSquared(const Vector2<T>& a, const Vector2<T>& b, const Vector2<T>& point) {
const Vector2<T> pointMinusA = point - a;
const Vector2<T> pointMinusB = point - b;
const Vector2<T> bMinusA = b - a;
const T pointDistanceA = pointMinusA.dot();
const T pointDistanceB = pointMinusB.dot();
const T bDistanceA = bMinusA.dot();
/* Point is before A */
if(pointDistanceB > bDistanceA + pointDistanceA)
return pointDistanceA;
/* Point is after B */
if(pointDistanceA > bDistanceA + pointDistanceB)
return pointDistanceB;
/* Between A and B */
return Math::pow<2>(Vector2<T>::cross(bMinusA, -pointMinusA))/bDistanceA;
}
template<class T> static T lineSegmentPointSquared(const Vector2<T>& a, const Vector2<T>& b, const Vector2<T>& point);
/**
* @brief %Dístance of point from line segment in 3D
@ -183,7 +147,7 @@ class Distance {
*
* @see lineSegmentPointSquared(const Vector3&, const Vector3&, const Vector3&)
*/
template<class T> inline static T lineSegmentPoint(const Vector3<T>& a, const Vector3<T>& b, const Vector3<T>& point) {
template<class T> static T lineSegmentPoint(const Vector3<T>& a, const Vector3<T>& b, const Vector3<T>& point) {
return std::sqrt(lineSegmentPointSquared(a, b, point));
}
@ -193,26 +157,68 @@ class Distance {
* More efficient than lineSegmentPoint(const Vector3&, const Vector3&, const Vector3&) for comparing distance with
* other values, because it doesn't compute the square root.
*/
template<class T> static T lineSegmentPointSquared(const Vector3<T>& a, const Vector3<T>& b, const Vector3<T>& point) {
const Vector3<T> pointMinusA = point - a;
const Vector3<T> pointMinusB = point - b;
const T pointDistanceA = pointMinusA.dot();
const T pointDistanceB = pointMinusB.dot();
const T bDistanceA = (b - a).dot();
/* Point is before A */
if(pointDistanceB > bDistanceA + pointDistanceA)
return pointDistanceA;
/* Point is after B */
if(pointDistanceA > bDistanceA + pointDistanceB)
return pointDistanceB;
/* Between A and B */
return Vector3<T>::cross(pointMinusA, pointMinusB).dot()/bDistanceA;
}
template<class T> static T lineSegmentPointSquared(const Vector3<T>& a, const Vector3<T>& b, const Vector3<T>& point);
};
template<class T> T Distance::lineSegmentPoint(const Vector2<T>& a, const Vector2<T>& b, const Vector2<T>& point) {
const Vector2<T> pointMinusA = point - a;
const Vector2<T> pointMinusB = point - b;
const Vector2<T> bMinusA = b - a;
const T pointDistanceA = pointMinusA.dot();
const T pointDistanceB = pointMinusB.dot();
const T bDistanceA = bMinusA.dot();
/* Point is before A */
if(pointDistanceB > bDistanceA + pointDistanceA)
return std::sqrt(pointDistanceA);
/* Point is after B */
if(pointDistanceA > bDistanceA + pointDistanceB)
return std::sqrt(pointDistanceB);
/* Between A and B */
return std::abs(Vector2<T>::cross(bMinusA, -pointMinusA))/std::sqrt(bDistanceA);
}
template<class T> T Distance::lineSegmentPointSquared(const Vector2<T>& a, const Vector2<T>& b, const Vector2<T>& point) {
const Vector2<T> pointMinusA = point - a;
const Vector2<T> pointMinusB = point - b;
const Vector2<T> bMinusA = b - a;
const T pointDistanceA = pointMinusA.dot();
const T pointDistanceB = pointMinusB.dot();
const T bDistanceA = bMinusA.dot();
/* Point is before A */
if(pointDistanceB > bDistanceA + pointDistanceA)
return pointDistanceA;
/* Point is after B */
if(pointDistanceA > bDistanceA + pointDistanceB)
return pointDistanceB;
/* Between A and B */
return Math::pow<2>(Vector2<T>::cross(bMinusA, -pointMinusA))/bDistanceA;
}
template<class T> T Distance::lineSegmentPointSquared(const Vector3<T>& a, const Vector3<T>& b, const Vector3<T>& point) {
const Vector3<T> pointMinusA = point - a;
const Vector3<T> pointMinusB = point - b;
const T pointDistanceA = pointMinusA.dot();
const T pointDistanceB = pointMinusB.dot();
const T bDistanceA = (b - a).dot();
/* Point is before A */
if(pointDistanceB > bDistanceA + pointDistanceA)
return pointDistanceA;
/* Point is after B */
if(pointDistanceA > bDistanceA + pointDistanceB)
return pointDistanceB;
/* Between A and B */
return Vector3<T>::cross(pointMinusA, pointMinusB).dot()/bDistanceA;
}
}}}
#endif

52
src/Math/Geometry/Rectangle.h

@ -51,7 +51,7 @@ template<class T> class Rectangle {
* @param bottomLeft Bottom left rectangle corner
* @param size %Rectangle size
*/
inline static Rectangle<T> fromSize(const Vector2<T>& bottomLeft, const Vector2<T>& size) {
static Rectangle<T> fromSize(const Vector2<T>& bottomLeft, const Vector2<T>& size) {
return {bottomLeft, bottomLeft+size};
}
@ -60,10 +60,10 @@ template<class T> class Rectangle {
*
* Construct zero-area rectangle positioned at origin.
*/
inline constexpr Rectangle() {}
constexpr Rectangle() {}
/** @brief Construct rectangle from two corners */
inline constexpr Rectangle(const Vector2<T>& bottomLeft, const Vector2<T>& topRight): _bottomLeft(bottomLeft), _topRight(topRight) {}
constexpr Rectangle(const Vector2<T>& bottomLeft, const Vector2<T>& topRight): _bottomLeft(bottomLeft), _topRight(topRight) {}
/**
* @brief Construct rectangle from another of different type
@ -75,64 +75,62 @@ template<class T> class Rectangle {
* Rectangle<Byte> integral(floatingPoint); // {{1, 2}, {-15, 7}}
* @endcode
*/
template<class U> inline constexpr explicit Rectangle(const Rectangle<U>& other): _bottomLeft(other._bottomLeft), _topRight(other._topRight) {}
template<class U> constexpr explicit Rectangle(const Rectangle<U>& other): _bottomLeft(other._bottomLeft), _topRight(other._topRight) {}
/** @brief Copy constructor */
inline constexpr Rectangle(const Rectangle<T>&) = default;
constexpr Rectangle(const Rectangle<T>&) = default;
/** @brief Assignment operator */
inline Rectangle<T>& operator=(const Rectangle<T>&) = default;
Rectangle<T>& operator=(const Rectangle<T>&) = default;
/** @brief Equality operator */
inline constexpr bool operator==(const Rectangle<T>& other) const {
constexpr bool operator==(const Rectangle<T>& other) const {
return _bottomLeft == other._bottomLeft && _topRight == other._topRight;
}
/** @brief Non-equality operator */
inline constexpr bool operator!=(const Rectangle<T>& other) const {
constexpr bool operator!=(const Rectangle<T>& other) const {
return !operator==(other);
}
/** @brief Bottom left corner */
inline Vector2<T>& bottomLeft() { return _bottomLeft; }
inline constexpr Vector2<T> bottomLeft() const { return _bottomLeft; } /**< @overload */
Vector2<T>& bottomLeft() { return _bottomLeft; }
constexpr Vector2<T> bottomLeft() const { return _bottomLeft; } /**< @overload */
/** @brief Bottom right corner */
inline constexpr Vector2<T> bottomRight() const { return {_topRight.x(), _bottomLeft.y()}; } /**< @overload */
constexpr Vector2<T> bottomRight() const { return {_topRight.x(), _bottomLeft.y()}; } /**< @overload */
/** @brief Top left corner */
inline constexpr Vector2<T> topLeft() const { return {_bottomLeft.x(), _topRight.y()}; } /**< @overload */
constexpr Vector2<T> topLeft() const { return {_bottomLeft.x(), _topRight.y()}; } /**< @overload */
/** @brief Top right corner */
inline Vector2<T>& topRight() { return _topRight; }
inline constexpr Vector2<T> topRight() const { return _topRight; } /**< @overload */
Vector2<T>& topRight() { return _topRight; }
constexpr Vector2<T> topRight() const { return _topRight; } /**< @overload */
/** @brief Bottom edge */
inline T& bottom() { return _bottomLeft.y(); }
inline constexpr T bottom() const { return _bottomLeft.y(); } /**< @overload */
T& bottom() { return _bottomLeft.y(); }
constexpr T bottom() const { return _bottomLeft.y(); } /**< @overload */
/** @brief Top edge */
inline T& top() { return _topRight.y(); }
inline constexpr T top() const { return _topRight.y(); } /**< @overload */
T& top() { return _topRight.y(); }
constexpr T top() const { return _topRight.y(); } /**< @overload */
/** @brief Left edge */
inline T& left() { return _bottomLeft.x(); }
inline constexpr T left() const { return _bottomLeft.x(); } /**< @overload */
T& left() { return _bottomLeft.x(); }
constexpr T left() const { return _bottomLeft.x(); } /**< @overload */
/** @brief Right edge */
inline T& right() { return _topRight.x(); }
inline constexpr T right() const { return _topRight.x(); } /**< @overload */
T& right() { return _topRight.x(); }
constexpr T right() const { return _topRight.x(); } /**< @overload */
/** @brief %Rectangle size */
inline constexpr Vector2<T> size() const {
return _topRight-_bottomLeft;
}
constexpr Vector2<T> size() const { return _topRight-_bottomLeft; }
/** @brief %Rectangle width */
inline constexpr T width() const { return _topRight.x() - _bottomLeft.x(); }
constexpr T width() const { return _topRight.x() - _bottomLeft.x(); }
/** @brief %Rectangle height */
inline constexpr T height() const { return _topRight.y() - _bottomLeft.y(); }
constexpr T height() const { return _topRight.y() - _bottomLeft.y(); }
private:
Vector2<T> _bottomLeft;

138
src/Math/Matrix.h

@ -58,7 +58,7 @@ template<std::size_t size, class T> class Matrix: public RectangularMatrix<size,
*
* Use this constructor by calling `Matrix m(Matrix::Zero);`.
*/
inline constexpr explicit Matrix(ZeroType) {}
constexpr explicit Matrix(ZeroType) {}
/** @brief Pass to constructor to create identity matrix */
enum IdentityType { Identity };
@ -71,7 +71,7 @@ template<std::size_t size, class T> class Matrix: public RectangularMatrix<size,
* you to specify value on diagonal.
* @todo use constexpr fromDiagonal() for this when it's done
*/
inline /*implicit*/ Matrix(IdentityType = Identity, T value = T(1)) {
/*implicit*/ Matrix(IdentityType = Identity, T value = T(1)) {
for(std::size_t i = 0; i != size; ++i)
(*this)[i][i] = value;
}
@ -81,7 +81,7 @@ template<std::size_t size, class T> class Matrix: public RectangularMatrix<size,
* @param first First column vector
* @param next Next column vectors
*/
template<class ...U> inline constexpr /*implicit*/ Matrix(const Vector<size, T>& first, const U&... next): RectangularMatrix<size, size, T>(first, next...) {}
template<class ...U> constexpr /*implicit*/ Matrix(const Vector<size, T>& first, const U&... next): RectangularMatrix<size, size, T>(first, next...) {}
/**
* @brief Construct matrix from another of different type
@ -95,13 +95,13 @@ template<std::size_t size, class T> class Matrix: public RectangularMatrix<size,
* // integral == {{1, 2}, {-15, 7}}
* @endcode
*/
template<class U> inline constexpr explicit Matrix(const RectangularMatrix<size, size, U>& other): RectangularMatrix<size, size, T>(other) {}
template<class U> constexpr explicit Matrix(const RectangularMatrix<size, size, U>& other): RectangularMatrix<size, size, T>(other) {}
/** @brief Construct matrix from external representation */
template<class U, class V = decltype(Implementation::RectangularMatrixConverter<size, size, T, U>::from(std::declval<U>()))> inline constexpr explicit Matrix(const U& other): RectangularMatrix<size, size, T>(Implementation::RectangularMatrixConverter<size, size, T, U>::from(other)) {}
template<class U, class V = decltype(Implementation::RectangularMatrixConverter<size, size, T, U>::from(std::declval<U>()))> constexpr explicit Matrix(const U& other): RectangularMatrix<size, size, T>(Implementation::RectangularMatrixConverter<size, size, T, U>::from(other)) {}
/** @brief Copy constructor */
inline constexpr Matrix(const RectangularMatrix<size, size, T>& other): RectangularMatrix<size, size, T>(other) {}
constexpr Matrix(const RectangularMatrix<size, size, T>& other): RectangularMatrix<size, size, T>(other) {}
/**
* @brief Whether the matrix is orthogonal
@ -112,19 +112,7 @@ template<std::size_t size, class T> class Matrix: public RectangularMatrix<size,
* @see transposed(), inverted(), Matrix3::isRigidTransformation(),
* Matrix4::isRigidTransformation()
*/
bool isOrthogonal() const {
/* Normality */
for(std::size_t i = 0; i != size; ++i)
if(!(*this)[i].isNormalized()) return false;
/* Orthogonality */
for(std::size_t i = 0; i != size-1; ++i)
for(std::size_t j = i+1; j != size; ++j)
if(Vector<size, T>::dot((*this)[i], (*this)[j]) > TypeTraits<T>::epsilon())
return false;
return true;
}
bool isOrthogonal() const;
/**
* @brief Trace of the matrix
@ -133,21 +121,10 @@ template<std::size_t size, class T> class Matrix: public RectangularMatrix<size,
* tr(A) = \sum_{i=1}^n a_{i,i}
* @f]
*/
T trace() const {
return this->diagonal().sum();
}
T trace() const { return this->diagonal().sum(); }
/** @brief %Matrix without given column and row */
Matrix<size-1, T> ij(std::size_t skipCol, std::size_t skipRow) const {
Matrix<size-1, T> out(Matrix<size-1, T>::Zero);
for(std::size_t col = 0; col != size-1; ++col)
for(std::size_t row = 0; row != size-1; ++row)
out[col][row] = (*this)[col + (col >= skipCol)]
[row + (row >= skipRow)];
return out;
}
Matrix<size-1, T> ij(std::size_t skipCol, std::size_t skipRow) const;
/**
* @brief Determinant
@ -160,7 +137,7 @@ template<std::size_t size, class T> class Matrix: public RectangularMatrix<size,
* \det(A) = a_{0, 0} a_{1, 1} - a_{1, 0} a_{0, 1}
* @f]
*/
inline T determinant() const { return Implementation::MatrixDeterminant<size, T>()(*this); }
T determinant() const { return Implementation::MatrixDeterminant<size, T>()(*this); }
/**
* @brief Inverted matrix
@ -171,17 +148,7 @@ template<std::size_t size, class T> class Matrix: public RectangularMatrix<size,
* See invertedOrthogonal(), Matrix3::invertedRigid() and Matrix4::invertedRigid()
* which are faster alternatives for particular matrix types.
*/
Matrix<size, T> inverted() const {
Matrix<size, T> out(Zero);
T _determinant = determinant();
for(std::size_t col = 0; col != size; ++col)
for(std::size_t row = 0; row != size; ++row)
out[col][row] = (((row+col) & 1) ? -1 : 1)*ij(row, col).determinant()/_determinant;
return out;
}
Matrix<size, T> inverted() const;
/**
* @brief Inverted orthogonal matrix
@ -192,7 +159,7 @@ template<std::size_t size, class T> class Matrix: public RectangularMatrix<size,
* @see inverted(), isOrthogonal(), Matrix3::invertedRigid(),
* Matrix4::invertedRigid()
*/
inline Matrix<size, T> invertedOrthogonal() const {
Matrix<size, T> invertedOrthogonal() const {
CORRADE_ASSERT(isOrthogonal(),
"Math::Matrix::invertedOrthogonal(): the matrix is not orthogonal", {});
return this->transposed();
@ -200,13 +167,13 @@ template<std::size_t size, class T> class Matrix: public RectangularMatrix<size,
#ifndef DOXYGEN_GENERATING_OUTPUT
/* Reimplementation of functions to return correct type */
inline Matrix<size, T> operator*(const Matrix<size, T>& other) const {
Matrix<size, T> operator*(const Matrix<size, T>& other) const {
return RectangularMatrix<size, size, T>::operator*(other);
}
template<std::size_t otherCols> inline RectangularMatrix<otherCols, size, T> operator*(const RectangularMatrix<otherCols, size, T>& other) const {
template<std::size_t otherCols> RectangularMatrix<otherCols, size, T> operator*(const RectangularMatrix<otherCols, size, T>& other) const {
return RectangularMatrix<size, size, T>::operator*(other);
}
inline Vector<size, T> operator*(const Vector<size, T>& other) const {
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>)
@ -232,29 +199,29 @@ 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 VectorType<T>& operator[](std::size_t col) { \
VectorType<T>& operator[](std::size_t col) { \
return static_cast<VectorType<T>&>(Matrix<size, T>::operator[](col)); \
} \
inline constexpr const VectorType<T> operator[](std::size_t col) const { \
constexpr const VectorType<T> operator[](std::size_t col) const { \
return VectorType<T>(Matrix<size, T>::operator[](col)); \
} \
inline VectorType<T> row(std::size_t row) const { \
VectorType<T> row(std::size_t row) const { \
return VectorType<T>(Matrix<size, T>::row(row)); \
} \
\
inline Type<T> operator*(const Matrix<size, T>& other) const { \
Type<T> operator*(const Matrix<size, T>& other) const { \
return Matrix<size, T>::operator*(other); \
} \
template<std::size_t otherCols> inline RectangularMatrix<otherCols, size, T> operator*(const RectangularMatrix<otherCols, size, T>& other) const { \
template<std::size_t otherCols> 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 { \
VectorType<T> operator*(const Vector<size, T>& other) const { \
return Matrix<size, T>::operator*(other); \
} \
\
inline Type<T> transposed() const { return Matrix<size, T>::transposed(); } \
inline Type<T> inverted() const { return Matrix<size, T>::inverted(); } \
inline Type<T> invertedOrthogonal() const { \
Type<T> transposed() const { return Matrix<size, T>::transposed(); } \
Type<T> inverted() const { return Matrix<size, T>::inverted(); } \
Type<T> invertedOrthogonal() const { \
return Matrix<size, T>::invertedOrthogonal(); \
}
@ -273,26 +240,28 @@ namespace Implementation {
template<std::size_t size, class T> class MatrixDeterminant {
public:
T operator()(const Matrix<size, T>& m) {
T out(0);
T operator()(const Matrix<size, T>& m);
};
for(std::size_t col = 0; col != size; ++col)
out += ((col & 1) ? -1 : 1)*m[col][0]*m.ij(col, 0).determinant();
template<std::size_t size, class T> T MatrixDeterminant<size, T>::operator()(const Matrix<size, T>& m) {
T out(0);
return out;
}
};
for(std::size_t col = 0; col != size; ++col)
out += ((col & 1) ? -1 : 1)*m[col][0]*m.ij(col, 0).determinant();
return out;
}
template<class T> class MatrixDeterminant<2, T> {
public:
inline constexpr T operator()(const Matrix<2, T>& m) {
constexpr T operator()(const Matrix<2, T>& m) {
return m[0][0]*m[1][1] - m[1][0]*m[0][1];
}
};
template<class T> class MatrixDeterminant<1, T> {
public:
inline constexpr T operator()(const Matrix<1, T>& m) {
constexpr T operator()(const Matrix<1, T>& m) {
return m[0][0];
}
};
@ -300,6 +269,43 @@ template<class T> class MatrixDeterminant<1, T> {
}
#endif
template<std::size_t size, class T> bool Matrix<size, T>::isOrthogonal() const {
/* Normality */
for(std::size_t i = 0; i != size; ++i)
if(!(*this)[i].isNormalized()) return false;
/* Orthogonality */
for(std::size_t i = 0; i != size-1; ++i)
for(std::size_t j = i+1; j != size; ++j)
if(Vector<size, T>::dot((*this)[i], (*this)[j]) > TypeTraits<T>::epsilon())
return false;
return true;
}
template<std::size_t size, class T> Matrix<size-1, T> Matrix<size, T>::ij(const std::size_t skipCol, const std::size_t skipRow) const {
Matrix<size-1, T> out(Matrix<size-1, T>::Zero);
for(std::size_t col = 0; col != size-1; ++col)
for(std::size_t row = 0; row != size-1; ++row)
out[col][row] = (*this)[col + (col >= skipCol)]
[row + (row >= skipRow)];
return out;
}
template<std::size_t size, class T> Matrix<size, T> Matrix<size, T>::inverted() const {
Matrix<size, T> out(Zero);
const T _determinant = determinant();
for(std::size_t col = 0; col != size; ++col)
for(std::size_t row = 0; row != size; ++row)
out[col][row] = (((row+col) & 1) ? -1 : 1)*ij(row, col).determinant()/_determinant;
return out;
}
}}
namespace Corrade { namespace Utility {

104
src/Math/Matrix3.h

@ -53,11 +53,7 @@ template<class T> class Matrix3: public Matrix<3, T> {
* Matrix4::translation(const Vector3&), Vector2::xAxis(),
* Vector2::yAxis()
*/
inline constexpr static Matrix3<T> translation(const Vector2<T>& vector) {
return {{ T(1), T(0), T(0)},
{ T(0), T(1), T(0)},
{vector.x(), vector.y(), T(1)}};
}
constexpr static Matrix3<T> translation(const Vector2<T>& vector);
/**
* @brief 2D scaling matrix
@ -66,11 +62,7 @@ template<class T> class Matrix3: public Matrix<3, T> {
* @see rotationScaling() const, Matrix4::scaling(const Vector3&),
* Vector2::xScale(), Vector2::yScale()
*/
inline constexpr static Matrix3<T> scaling(const Vector2<T>& vector) {
return {{vector.x(), T(0), T(0)},
{ T(0), vector.y(), T(0)},
{ T(0), T(0), T(1)}};
}
constexpr static Matrix3<T> scaling(const Vector2<T>& vector);
/**
* @brief 2D rotation matrix
@ -79,14 +71,7 @@ template<class T> class Matrix3: public Matrix<3, T> {
* @see rotation() const, Complex::rotation(), DualComplex::rotation(),
* Matrix4::rotation(Rad, const Vector3&)
*/
static Matrix3<T> rotation(Rad<T> angle) {
T sine = std::sin(T(angle));
T cosine = std::cos(T(angle));
return {{ cosine, sine, T(0)},
{ -sine, cosine, T(0)},
{ T(0), T(0), T(1)}};
}
static Matrix3<T> rotation(Rad<T> angle);
/**
* @brief 2D reflection matrix
@ -120,14 +105,14 @@ template<class T> class Matrix3: public Matrix<3, T> {
*
* @see rotationScaling() const, translation() const
*/
inline constexpr static Matrix3<T> from(const Matrix<2, T>& rotationScaling, const Vector2<T>& translation) {
constexpr static Matrix3<T> from(const Matrix<2, T>& rotationScaling, const Vector2<T>& translation) {
return {{rotationScaling[0], T(0)},
{rotationScaling[1], T(0)},
{ translation, T(1)}};
}
/** @copydoc Matrix::Matrix(ZeroType) */
inline constexpr explicit Matrix3(typename Matrix<3, T>::ZeroType): Matrix<3, T>(Matrix<3, T>::Zero) {}
constexpr explicit Matrix3(typename Matrix<3, T>::ZeroType): Matrix<3, T>(Matrix<3, T>::Zero) {}
/**
* @brief Default constructor
@ -137,23 +122,19 @@ template<class T> class Matrix3: public Matrix<3, T> {
* @p value allows you to specify value on diagonal.
* @todo Use constexpr implementation in Matrix, when done
*/
inline constexpr /*implicit*/ Matrix3(typename Matrix<3, T>::IdentityType = (Matrix<3, T>::Identity), T value = T(1)): Matrix<3, T>(
Vector<3, T>(value, T(0), T(0)),
Vector<3, T>( T(0), value, T(0)),
Vector<3, T>( T(0), T(0), value)
) {}
constexpr /*implicit*/ Matrix3(typename Matrix<3, T>::IdentityType = (Matrix<3, T>::Identity), T value = T(1));
/** @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) {}
constexpr /*implicit*/ Matrix3(const Vector3<T>& first, const Vector3<T>& second, const Vector3<T>& third): Matrix<3, T>(first, second, third) {}
/** @copydoc Matrix::Matrix(const RectangularMatrix<size, size, U>&) */
template<class U> inline constexpr explicit Matrix3(const RectangularMatrix<3, 3, U>& other): Matrix<3, T>(other) {}
template<class U> constexpr explicit Matrix3(const RectangularMatrix<3, 3, U>& other): Matrix<3, T>(other) {}
/** @brief Construct matrix from external representation */
template<class U, class V = decltype(Implementation::RectangularMatrixConverter<3, 3, T, U>::from(std::declval<U>()))> inline constexpr explicit Matrix3(const U& other): Matrix<3, T>(Implementation::RectangularMatrixConverter<3, 3, T, U>::from(other)) {}
template<class U, class V = decltype(Implementation::RectangularMatrixConverter<3, 3, T, U>::from(std::declval<U>()))> constexpr explicit Matrix3(const U& other): Matrix<3, T>(Implementation::RectangularMatrixConverter<3, 3, T, U>::from(other)) {}
/** @brief Copy constructor */
inline constexpr Matrix3(const RectangularMatrix<3, 3, T>& other): Matrix<3, T>(other) {}
constexpr Matrix3(const RectangularMatrix<3, 3, T>& other): Matrix<3, T>(other) {}
/**
* @brief Check whether the matrix represents rigid transformation
@ -162,7 +143,7 @@ template<class T> class Matrix3: public Matrix<3, T> {
* no scaling or projection).
* @see isOrthogonal()
*/
inline bool isRigidTransformation() const {
bool isRigidTransformation() const {
return rotationScaling().isOrthogonal() && row(2) == Vector3<T>(T(0), T(0), T(1));
}
@ -174,7 +155,7 @@ template<class T> class Matrix3: public Matrix<3, T> {
* rotation(T), Matrix4::rotationScaling() const
* @todo extract rotation with assert for no scaling
*/
inline constexpr Matrix<2, T> rotationScaling() const {
constexpr Matrix<2, T> rotationScaling() const {
return {(*this)[0].xy(),
(*this)[1].xy()};
}
@ -186,7 +167,7 @@ template<class T> class Matrix3: public Matrix<3, T> {
* @see rotationScaling() const, rotation(T), Matrix4::rotation() const
* @todo assert uniform scaling (otherwise this would be garbage)
*/
inline Matrix<2, T> rotation() const {
Matrix<2, T> rotation() const {
return {(*this)[0].xy().normalized(),
(*this)[1].xy().normalized()};
}
@ -199,8 +180,8 @@ template<class T> class Matrix3: public Matrix<3, T> {
* First two elements of first column.
* @see up(), Vector2::xAxis(), Matrix4::right()
*/
inline Vector2<T>& right() { return (*this)[0].xy(); }
inline constexpr Vector2<T> right() const { return (*this)[0].xy(); } /**< @overload */
Vector2<T>& right() { return (*this)[0].xy(); }
constexpr Vector2<T> right() const { return (*this)[0].xy(); } /**< @overload */
/**
* @brief Up-pointing 2D vector
@ -208,8 +189,8 @@ template<class T> class Matrix3: public Matrix<3, T> {
* First two elements of second column.
* @see right(), Vector2::yAxis(), Matrix4::up()
*/
inline Vector2<T>& up() { return (*this)[1].xy(); }
inline constexpr Vector2<T> up() const { return (*this)[1].xy(); } /**< @overload */
Vector2<T>& up() { return (*this)[1].xy(); }
constexpr Vector2<T> up() const { return (*this)[1].xy(); } /**< @overload */
/**
* @brief 2D translation part of the matrix
@ -218,8 +199,8 @@ template<class T> class Matrix3: public Matrix<3, T> {
* @see from(const Matrix<2, T>&, const Vector2&),
* translation(const Vector2&), Matrix4::translation()
*/
inline Vector2<T>& translation() { return (*this)[2].xy(); }
inline constexpr Vector2<T> translation() const { return (*this)[2].xy(); } /**< @overload */
Vector2<T>& translation() { return (*this)[2].xy(); }
constexpr Vector2<T> translation() const { return (*this)[2].xy(); } /**< @overload */
/**
* @brief Inverted rigid transformation matrix
@ -229,13 +210,7 @@ template<class T> class Matrix3: public Matrix<3, T> {
* @see isRigidTransformation(), invertedOrthogonal(),
* rotationScaling() const, translation() const
*/
inline Matrix3<T> invertedRigid() const {
CORRADE_ASSERT(isRigidTransformation(),
"Math::Matrix3::invertedRigid(): the matrix doesn't represent rigid transformation", {});
Matrix<2, T> inverseRotation = rotationScaling().transposed();
return from(inverseRotation, inverseRotation*-translation());
}
Matrix3<T> invertedRigid() const;
/**
* @brief Transform 2D vector with the matrix
@ -247,7 +222,7 @@ template<class T> class Matrix3: public Matrix<3, T> {
* @see Complex::transformVector(), Matrix4::transformVector()
* @todo extract 2x2 matrix and multiply directly? (benchmark that)
*/
inline Vector2<T> transformVector(const Vector2<T>& vector) const {
Vector2<T> transformVector(const Vector2<T>& vector) const {
return ((*this)*Vector3<T>(vector, T(0))).xy();
}
@ -260,7 +235,7 @@ template<class T> class Matrix3: public Matrix<3, T> {
* @f]
* @see DualComplex::transformPoint(), Matrix4::transformPoint()
*/
inline Vector2<T> transformPoint(const Vector2<T>& vector) const {
Vector2<T> transformPoint(const Vector2<T>& vector) const {
return ((*this)*Vector3<T>(vector, T(1))).xy();
}
@ -275,6 +250,41 @@ template<class T> inline Corrade::Utility::Debug operator<<(Corrade::Utility::De
return debug << static_cast<const Matrix<3, T>&>(value);
}
template<class T> constexpr Matrix3<T>::Matrix3(typename Matrix<3, T>::IdentityType, const T value): Matrix<3, T>(
Vector<3, T>(value, T(0), T(0)),
Vector<3, T>( T(0), value, T(0)),
Vector<3, T>( T(0), T(0), value)
) {}
template<class T> constexpr Matrix3<T> Matrix3<T>::translation(const Vector2<T>& vector) {
return {{ T(1), T(0), T(0)},
{ T(0), T(1), T(0)},
{vector.x(), vector.y(), T(1)}};
}
template<class T> constexpr Matrix3<T> Matrix3<T>::scaling(const Vector2< T >& vector) {
return {{vector.x(), T(0), T(0)},
{ T(0), vector.y(), T(0)},
{ T(0), T(0), T(1)}};
}
template<class T> Matrix3<T> Matrix3<T>::rotation(const Rad<T> angle) {
const T sine = std::sin(T(angle));
const T cosine = std::cos(T(angle));
return {{ cosine, sine, T(0)},
{ -sine, cosine, T(0)},
{ T(0), T(0), T(1)}};
}
template<class T> inline Matrix3<T> Matrix3<T>::invertedRigid() const {
CORRADE_ASSERT(isRigidTransformation(),
"Math::Matrix3::invertedRigid(): the matrix doesn't represent rigid transformation", {});
Matrix<2, T> inverseRotation = rotationScaling().transposed();
return from(inverseRotation, inverseRotation*-translation());
}
}}
namespace Corrade { namespace Utility {

311
src/Math/Matrix4.h

@ -58,12 +58,7 @@ template<class T> class Matrix4: public Matrix<4, T> {
* Matrix3::translation(const Vector2&), Vector3::xAxis(),
* Vector3::yAxis(), Vector3::zAxis()
*/
inline constexpr static Matrix4<T> translation(const Vector3<T>& vector) {
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)}};
}
constexpr static Matrix4<T> translation(const Vector3<T>& vector);
/**
* @brief 3D scaling
@ -72,12 +67,7 @@ template<class T> class Matrix4: public Matrix<4, T> {
* @see rotationScaling() const, Matrix3::scaling(const Vector2&),
* Vector3::xScale(), Vector3::yScale(), Vector3::zScale()
*/
inline constexpr static Matrix4<T> scaling(const Vector3<T>& vector) {
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)}};
}
constexpr static Matrix4<T> scaling(const Vector3<T>& vector);
/**
* @brief 3D rotation around arbitrary axis
@ -90,37 +80,7 @@ template<class T> class Matrix4: public Matrix<4, T> {
* Matrix3::rotation(Rad), Vector3::xAxis(), Vector3::yAxis(),
* Vector3::zAxis(), Vector::isNormalized()
*/
static Matrix4<T> rotation(Rad<T> angle, const Vector3<T>& normalizedAxis) {
CORRADE_ASSERT(normalizedAxis.isNormalized(),
"Math::Matrix4::rotation(): axis must be normalized", {});
T sine = std::sin(T(angle));
T cosine = std::cos(T(angle));
T oneMinusCosine = T(1) - cosine;
T xx = normalizedAxis.x()*normalizedAxis.x();
T xy = normalizedAxis.x()*normalizedAxis.y();
T xz = normalizedAxis.x()*normalizedAxis.z();
T yy = normalizedAxis.y()*normalizedAxis.y();
T yz = normalizedAxis.y()*normalizedAxis.z();
T zz = normalizedAxis.z()*normalizedAxis.z();
return {
{cosine + xx*oneMinusCosine,
xy*oneMinusCosine + normalizedAxis.z()*sine,
xz*oneMinusCosine - normalizedAxis.y()*sine,
T(0)},
{xy*oneMinusCosine - normalizedAxis.z()*sine,
cosine + yy*oneMinusCosine,
yz*oneMinusCosine + normalizedAxis.x()*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)}
};
}
static Matrix4<T> rotation(Rad<T> angle, const Vector3<T>& normalizedAxis);
/**
* @brief 3D rotation around X axis
@ -130,15 +90,7 @@ template<class T> class Matrix4: public Matrix<4, T> {
* @see rotation(Rad, const Vector3&), rotationY(), rotationZ(),
* rotation() const, Quaternion::rotation(), Matrix3::rotation(Rad)
*/
static Matrix4<T> rotationX(Rad<T> angle) {
T sine = std::sin(T(angle));
T cosine = std::cos(T(angle));
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)}};
}
static Matrix4<T> rotationX(Rad<T> angle);
/**
* @brief 3D rotation around Y axis
@ -148,15 +100,7 @@ template<class T> class Matrix4: public Matrix<4, T> {
* @see rotation(Rad, const Vector3&), rotationX(), rotationZ(),
* rotation() const, Quaternion::rotation(), Matrix3::rotation(Rad)
*/
static Matrix4<T> rotationY(Rad<T> angle) {
T sine = std::sin(T(angle));
T cosine = std::cos(T(angle));
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)}};
}
static Matrix4<T> rotationY(Rad<T> angle);
/**
* @brief 3D rotation matrix around Z axis
@ -166,15 +110,7 @@ template<class T> class Matrix4: public Matrix<4, T> {
* @see rotation(Rad, const Vector3&), rotationX(), rotationY(),
* rotation() const, Quaternion::rotation(), Matrix3::rotation(Rad)
*/
static Matrix4<T> rotationZ(Rad<T> angle) {
T sine = std::sin(T(angle));
T cosine = std::cos(T(angle));
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)}};
}
static Matrix4<T> rotationZ(Rad<T> angle);
/**
* @brief 3D reflection matrix
@ -183,11 +119,7 @@ template<class T> class Matrix4: public Matrix<4, T> {
* Expects that the normal is normalized.
* @see Matrix3::reflection(), Vector::isNormalized()
*/
static Matrix4<T> reflection(const Vector3<T>& normal) {
CORRADE_ASSERT(normal.isNormalized(),
"Math::Matrix4::reflection(): normal must be normalized", {});
return from(Matrix<3, T>() - T(2)*normal*RectangularMatrix<1, 3, T>(normal).transposed(), {});
}
static Matrix4<T> reflection(const Vector3<T>& normal);
/**
* @brief 3D orthographic projection matrix
@ -197,15 +129,7 @@ template<class T> class Matrix4: public Matrix<4, T> {
*
* @see perspectiveProjection(), Matrix3::projection()
*/
static Matrix4<T> orthographicProjection(const Vector2<T>& size, T near, T far) {
Vector2<T> xyScale = T(2.0)/size;
T zScale = T(2.0)/(near-far);
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)}};
}
static Matrix4<T> orthographicProjection(const Vector2<T>& size, T near, T far);
/**
* @brief 3D perspective projection matrix
@ -215,15 +139,7 @@ template<class T> class Matrix4: public Matrix<4, T> {
*
* @see orthographicProjection(), Matrix3::projection()
*/
static Matrix4<T> perspectiveProjection(const Vector2<T>& size, T near, T far) {
Vector2<T> xyScale = 2*near/size;
T zScale = T(1.0)/(near-far);
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)}};
}
static Matrix4<T> perspectiveProjection(const Vector2<T>& size, T near, T far);
/**
* @brief 3D perspective projection matrix
@ -235,8 +151,7 @@ template<class T> class Matrix4: public Matrix<4, T> {
* @see orthographicProjection(), Matrix3::projection()
*/
static Matrix4<T> perspectiveProjection(Rad<T> fov, T aspectRatio, T near, T far) {
T xyScale = 2*std::tan(T(fov)/2)*near;
const T xyScale = 2*std::tan(T(fov)/2)*near;
return perspectiveProjection(Vector2<T>(xyScale, xyScale/aspectRatio), near, far);
}
@ -249,15 +164,10 @@ template<class T> class Matrix4: public Matrix<4, T> {
*
* @see rotationScaling() const, translation() const
*/
inline constexpr static Matrix4<T> from(const Matrix<3, T>& rotationScaling, const Vector3<T>& translation) {
return {{rotationScaling[0], T(0)},
{rotationScaling[1], T(0)},
{rotationScaling[2], T(0)},
{ translation, T(1)}};
}
constexpr static Matrix4<T> from(const Matrix<3, T>& rotationScaling, const Vector3<T>& translation);
/** @copydoc Matrix::Matrix(ZeroType) */
inline constexpr explicit Matrix4(typename Matrix<4, T>::ZeroType): Matrix<4, T>(Matrix<4, T>::Zero) {}
constexpr explicit Matrix4(typename Matrix<4, T>::ZeroType): Matrix<4, T>(Matrix<4, T>::Zero) {}
/**
* @brief Default constructor
@ -267,24 +177,19 @@ template<class T> class Matrix4: public Matrix<4, T> {
* @p value allows you to specify value on diagonal.
* @todo Use constexpr implementation in Matrix, when done
*/
inline constexpr /*implicit*/ Matrix4(typename Matrix<4, T>::IdentityType = (Matrix<4, T>::Identity), T value = T(1)): Matrix<4, T>(
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)
) {}
constexpr /*implicit*/ Matrix4(typename Matrix<4, T>::IdentityType = (Matrix<4, T>::Identity), T value = T(1));
/** @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) {}
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) {}
/** @copydoc Matrix::Matrix(const RectangularMatrix<size, size, U>&) */
template<class U> inline constexpr explicit Matrix4(const RectangularMatrix<4, 4, U>& other): Matrix<4, T>(other) {}
template<class U> constexpr explicit Matrix4(const RectangularMatrix<4, 4, U>& other): Matrix<4, T>(other) {}
/** @brief Construct matrix from external representation */
template<class U, class V = decltype(Implementation::RectangularMatrixConverter<4, 4, T, U>::from(std::declval<U>()))> inline constexpr explicit Matrix4(const U& other): Matrix<4, T>(Implementation::RectangularMatrixConverter<4, 4, T, U>::from(other)) {}
template<class U, class V = decltype(Implementation::RectangularMatrixConverter<4, 4, T, U>::from(std::declval<U>()))> constexpr explicit Matrix4(const U& other): Matrix<4, T>(Implementation::RectangularMatrixConverter<4, 4, T, U>::from(other)) {}
/** @brief Copy constructor */
inline constexpr Matrix4(const RectangularMatrix<4, 4, T>& other): Matrix<4, T>(other) {}
constexpr Matrix4(const RectangularMatrix<4, 4, T>& other): Matrix<4, T>(other) {}
/**
* @brief Check whether the matrix represents rigid transformation
@ -293,7 +198,7 @@ template<class T> class Matrix4: public Matrix<4, T> {
* no scaling or projection).
* @see isOrthogonal()
*/
inline bool isRigidTransformation() const {
bool isRigidTransformation() const {
return rotationScaling().isOrthogonal() && row(3) == Vector4<T>(T(0), T(0), T(0), T(1));
}
@ -305,12 +210,8 @@ template<class T> class Matrix4: public Matrix<4, T> {
* rotation(T, const Vector3&), Matrix3::rotationScaling() const
* @todo extract rotation with assert for no scaling
*/
inline constexpr Matrix<3, T> rotationScaling() const {
/* Not Matrix3, because it is for affine 2D transformations */
return {(*this)[0].xyz(),
(*this)[1].xyz(),
(*this)[2].xyz()};
}
/* Not Matrix3, because it is for affine 2D transformations */
constexpr Matrix<3, T> rotationScaling() const;
/**
* @brief 3D rotation part of the matrix
@ -320,12 +221,8 @@ template<class T> class Matrix4: public Matrix<4, T> {
* Matrix3::rotation() const
* @todo assert uniform scaling (otherwise this would be garbage)
*/
inline Matrix<3, T> rotation() const {
/* Not Matrix3, because it is for affine 2D transformations */
return {(*this)[0].xyz().normalized(),
(*this)[1].xyz().normalized(),
(*this)[2].xyz().normalized()};
}
/* Not Matrix3, because it is for affine 2D transformations */
Matrix<3, T> rotation() const;
/** @todo uniform scaling extraction */
@ -335,8 +232,8 @@ template<class T> class Matrix4: public Matrix<4, T> {
* First three elements of first column.
* @see up(), backward(), Vector3::xAxis(), Matrix3::right()
*/
inline Vector3<T>& right() { return (*this)[0].xyz(); }
inline constexpr Vector3<T> right() const { return (*this)[0].xyz(); } /**< @overload */
Vector3<T>& right() { return (*this)[0].xyz(); }
constexpr Vector3<T> right() const { return (*this)[0].xyz(); } /**< @overload */
/**
* @brief Up-pointing 3D vector
@ -344,8 +241,8 @@ template<class T> class Matrix4: public Matrix<4, T> {
* First three elements of second column.
* @see right(), backward(), Vector3::yAxis(), Matrix3::up()
*/
inline Vector3<T>& up() { return (*this)[1].xyz(); }
inline constexpr Vector3<T> up() const { return (*this)[1].xyz(); } /**< @overload */
Vector3<T>& up() { return (*this)[1].xyz(); }
constexpr Vector3<T> up() const { return (*this)[1].xyz(); } /**< @overload */
/**
* @brief Backward-pointing 3D vector
@ -353,8 +250,8 @@ template<class T> class Matrix4: public Matrix<4, T> {
* First three elements of third column.
* @see right(), up(), Vector3::yAxis()
*/
inline Vector3<T>& backward() { return (*this)[2].xyz(); }
inline constexpr Vector3<T> backward() const { return (*this)[2].xyz(); } /**< @overload */
Vector3<T>& backward() { return (*this)[2].xyz(); }
constexpr Vector3<T> backward() const { return (*this)[2].xyz(); } /**< @overload */
/**
* @brief 3D translation part of the matrix
@ -363,8 +260,8 @@ template<class T> class Matrix4: public Matrix<4, T> {
* @see from(const Matrix<3, T>&, const Vector3&),
* translation(const Vector3&), Matrix3::translation()
*/
inline Vector3<T>& translation() { return (*this)[3].xyz(); }
inline constexpr Vector3<T> translation() const { return (*this)[3].xyz(); } /**< @overload */
Vector3<T>& translation() { return (*this)[3].xyz(); }
constexpr Vector3<T> translation() const { return (*this)[3].xyz(); } /**< @overload */
/**
* @brief Inverted rigid transformation matrix
@ -374,13 +271,7 @@ template<class T> class Matrix4: public Matrix<4, T> {
* @see isRigidTransformation(), invertedOrthogonal(),
* rotationScaling() const, translation() const
*/
inline Matrix4<T> invertedRigid() const {
CORRADE_ASSERT(isRigidTransformation(),
"Math::Matrix4::invertedRigid(): the matrix doesn't represent rigid transformation", {});
Matrix<3, T> inverseRotation = rotationScaling().transposed();
return from(inverseRotation, inverseRotation*-translation());
}
Matrix4<T> invertedRigid() const;
/**
* @brief Transform 3D vector with the matrix
@ -392,7 +283,7 @@ template<class T> class Matrix4: public Matrix<4, T> {
* @see Quaternion::transformVector(), Matrix3::transformVector()
* @todo extract 3x3 matrix and multiply directly? (benchmark that)
*/
inline Vector3<T> transformVector(const Vector3<T>& vector) const {
Vector3<T> transformVector(const Vector3<T>& vector) const {
return ((*this)*Vector4<T>(vector, T(0))).xyz();
}
@ -405,7 +296,7 @@ template<class T> class Matrix4: public Matrix<4, T> {
* @f]
* @see DualQuaternion::transformPoint(), Matrix3::transformPoint()
*/
inline Vector3<T> transformPoint(const Vector3<T>& vector) const {
Vector3<T> transformPoint(const Vector3<T>& vector) const {
return ((*this)*Vector4<T>(vector, T(1))).xyz();
}
@ -420,6 +311,142 @@ template<class T> inline Corrade::Utility::Debug operator<<(Corrade::Utility::De
return debug << static_cast<const Matrix<4, T>&>(value);
}
template<class T> constexpr Matrix4<T> Matrix4<T>::translation(const Vector3<T>& vector) {
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)}};
}
template<class T> constexpr Matrix4<T> Matrix4<T>::scaling(const Vector3<T>& vector) {
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)}};
}
template<class T> Matrix4<T> Matrix4<T>::rotation(const Rad<T> angle, const Vector3<T>& normalizedAxis) {
CORRADE_ASSERT(normalizedAxis.isNormalized(),
"Math::Matrix4::rotation(): axis must be normalized", {});
const T sine = std::sin(T(angle));
const T cosine = std::cos(T(angle));
const T oneMinusCosine = T(1) - cosine;
const T xx = normalizedAxis.x()*normalizedAxis.x();
const T xy = normalizedAxis.x()*normalizedAxis.y();
const T xz = normalizedAxis.x()*normalizedAxis.z();
const T yy = normalizedAxis.y()*normalizedAxis.y();
const T yz = normalizedAxis.y()*normalizedAxis.z();
const T zz = normalizedAxis.z()*normalizedAxis.z();
return {
{cosine + xx*oneMinusCosine,
xy*oneMinusCosine + normalizedAxis.z()*sine,
xz*oneMinusCosine - normalizedAxis.y()*sine,
T(0)},
{xy*oneMinusCosine - normalizedAxis.z()*sine,
cosine + yy*oneMinusCosine,
yz*oneMinusCosine + normalizedAxis.x()*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)}
};
}
template<class T> Matrix4<T> Matrix4<T>::rotationX(const Rad<T> angle) {
const T sine = std::sin(T(angle));
const T cosine = std::cos(T(angle));
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)}};
}
template<class T> Matrix4<T> Matrix4<T>::rotationY(const Rad<T> angle) {
const T sine = std::sin(T(angle));
const T cosine = std::cos(T(angle));
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)}};
}
template<class T> Matrix4<T> Matrix4<T>::rotationZ(const Rad<T> angle) {
const T sine = std::sin(T(angle));
const T cosine = std::cos(T(angle));
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)}};
}
template<class T> Matrix4<T> Matrix4<T>::reflection(const Vector3<T>& normal) {
CORRADE_ASSERT(normal.isNormalized(),
"Math::Matrix4::reflection(): normal must be normalized", {});
return from(Matrix<3, T>() - T(2)*normal*RectangularMatrix<1, 3, T>(normal).transposed(), {});
}
template<class T> Matrix4<T> Matrix4<T>::orthographicProjection(const Vector2<T>& size, const T near, const T far) {
const Vector2<T> xyScale = T(2.0)/size;
const T zScale = T(2.0)/(near-far);
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)}};
}
template<class T> Matrix4<T> Matrix4<T>::perspectiveProjection(const Vector2<T>& size, const T near, const T far) {
Vector2<T> xyScale = 2*near/size;
T zScale = T(1.0)/(near-far);
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)}};
}
template<class T> constexpr Matrix4<T> Matrix4<T>::from(const Matrix<3, T>& rotationScaling, const Vector3<T>& translation) {
return {{rotationScaling[0], T(0)},
{rotationScaling[1], T(0)},
{rotationScaling[2], T(0)},
{ translation, T(1)}};
}
template<class T> constexpr Matrix4<T>::Matrix4(typename Matrix<4, T>::IdentityType, const T value): Matrix<4, T>(
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)
) {}
template<class T> constexpr Matrix<3, T> Matrix4<T>::rotationScaling() const {
return {(*this)[0].xyz(),
(*this)[1].xyz(),
(*this)[2].xyz()};
}
template<class T> inline Matrix<3, T> Matrix4<T>::rotation() const {
return {(*this)[0].xyz().normalized(),
(*this)[1].xyz().normalized(),
(*this)[2].xyz().normalized()};
}
template<class T> Matrix4<T> Matrix4<T>::invertedRigid() const {
CORRADE_ASSERT(isRigidTransformation(),
"Math::Matrix4::invertedRigid(): the matrix doesn't represent rigid transformation", {});
Matrix<3, T> inverseRotation = rotationScaling().transposed();
return from(inverseRotation, inverseRotation*-translation());
}
}}
namespace Corrade { namespace Utility {

293
src/Math/Quaternion.h

@ -38,44 +38,6 @@
namespace Magnum { namespace Math {
namespace Implementation {
/* No assertions fired, for internal use. Not private member because used from
outside the class. */
template<class T> inline Quaternion<T> quaternionFromMatrix(const Matrix<3, T>& m) {
const Vector<3, T> diagonal = m.diagonal();
const T trace = diagonal.sum();
/* Diagonal is positive */
if(trace > T(0)) {
const T s = std::sqrt(trace + T(1));
const T t = T(0.5)/s;
return {Vector3<T>(m[1][2] - m[2][1],
m[2][0] - m[0][2],
m[0][1] - m[1][0])*t, s*T(0.5)};
}
/* Diagonal is negative */
std::size_t i = 0;
if(diagonal[1] > diagonal[0]) i = 1;
if(diagonal[2] > diagonal[i]) i = 2;
const std::size_t j = (i + 1) % 3;
const std::size_t k = (i + 2) % 3;
const T s = std::sqrt(diagonal[i] - diagonal[j] - diagonal[k] + T(1));
const T t = (s == T(0) ? T(0) : T(0.5)/s);
Vector3<T> vec;
vec[i] = s*T(0.5);
vec[j] = (m[i][j] + m[j][i])*t;
vec[k] = (m[i][k] + m[k][i])*t;
return {vec, (m[j][k] - m[k][j])*t};
}
}
/**
@brief %Quaternion
@tparam T Underlying data type
@ -95,7 +57,7 @@ template<class T> class Quaternion {
* @f]
* @see dot() const
*/
inline static T dot(const Quaternion<T>& a, const Quaternion<T>& b) {
static T dot(const Quaternion<T>& a, const Quaternion<T>& b) {
/** @todo Use four-component SIMD implementation when available */
return Vector3<T>::dot(a.vector(), b.vector()) + a.scalar()*b.scalar();
}
@ -108,11 +70,7 @@ template<class T> class Quaternion {
* @f]
* @see isNormalized(), Complex::angle(), Vector::angle()
*/
inline static Rad<T> angle(const Quaternion<T>& normalizedA, const Quaternion<T>& normalizedB) {
CORRADE_ASSERT(normalizedA.isNormalized() && normalizedB.isNormalized(),
"Math::Quaternion::angle(): quaternions must be normalized", Rad<T>(std::numeric_limits<T>::quiet_NaN()));
return Rad<T>(angleInternal(normalizedA, normalizedB));
}
static Rad<T> angle(const Quaternion<T>& normalizedA, const Quaternion<T>& normalizedB);
/**
* @brief Linear interpolation of two quaternions
@ -125,12 +83,7 @@ template<class T> class Quaternion {
* @f]
* @see isNormalized(), slerp(), Math::lerp()
*/
inline static Quaternion<T> lerp(const Quaternion<T>& normalizedA, const Quaternion<T>& normalizedB, T t) {
CORRADE_ASSERT(normalizedA.isNormalized() && normalizedB.isNormalized(),
"Math::Quaternion::lerp(): quaternions must be normalized",
Quaternion<T>({}, std::numeric_limits<T>::quiet_NaN()));
return ((T(1) - t)*normalizedA + t*normalizedB).normalized();
}
static Quaternion<T> lerp(const Quaternion<T>& normalizedA, const Quaternion<T>& normalizedB, T t);
/**
* @brief Spherical linear interpolation of two quaternions
@ -145,13 +98,7 @@ template<class T> class Quaternion {
* @f]
* @see isNormalized(), lerp()
*/
inline static Quaternion<T> slerp(const Quaternion<T>& normalizedA, const Quaternion<T>& normalizedB, T t) {
CORRADE_ASSERT(normalizedA.isNormalized() && normalizedB.isNormalized(),
"Math::Quaternion::slerp(): quaternions must be normalized",
Quaternion<T>({}, std::numeric_limits<T>::quiet_NaN()));
T a = angleInternal(normalizedA, normalizedB);
return (std::sin((T(1) - t)*a)*normalizedA + std::sin(t*a)*normalizedB)/std::sin(a);
}
static Quaternion<T> slerp(const Quaternion<T>& normalizedA, const Quaternion<T>& normalizedB, T t);
/**
* @brief Rotation quaternion
@ -165,12 +112,7 @@ template<class T> class Quaternion {
* Matrix4::rotation(), Complex::rotation(), Vector3::xAxis(),
* Vector3::yAxis(), Vector3::zAxis(), Vector::isNormalized()
*/
inline static Quaternion<T> rotation(Rad<T> angle, const Vector3<T>& normalizedAxis) {
CORRADE_ASSERT(normalizedAxis.isNormalized(),
"Math::Quaternion::rotation(): axis must be normalized", {});
return {normalizedAxis*std::sin(T(angle)/2), std::cos(T(angle)/2)};
}
static Quaternion<T> rotation(Rad<T> angle, const Vector3<T>& normalizedAxis);
/**
* @brief Create quaternion from rotation matrix
@ -178,11 +120,7 @@ template<class T> class Quaternion {
* Expects that the matrix is orthogonal (i.e. pure rotation).
* @see toMatrix(), DualComplex::fromMatrix(), Matrix::isOrthogonal()
*/
inline static Quaternion<T> fromMatrix(const Matrix<3, T>& matrix) {
CORRADE_ASSERT(matrix.isOrthogonal(),
"Math::Quaternion::fromMatrix(): the matrix is not orthogonal", {});
return Implementation::quaternionFromMatrix(matrix);
}
static Quaternion<T> fromMatrix(const Matrix<3, T>& matrix);
/**
* @brief Default constructor
@ -191,7 +129,7 @@ template<class T> class Quaternion {
* q = [\boldsymbol 0, 1]
* @f]
*/
inline constexpr /*implicit*/ Quaternion(): _scalar(T(1)) {}
constexpr /*implicit*/ Quaternion(): _scalar(T(1)) {}
/**
* @brief Construct quaternion from vector and scalar
@ -200,7 +138,7 @@ template<class T> class Quaternion {
* q = [\boldsymbol v, s]
* @f]
*/
inline constexpr /*implicit*/ Quaternion(const Vector3<T>& vector, T scalar): _vector(vector), _scalar(scalar) {}
constexpr /*implicit*/ Quaternion(const Vector3<T>& vector, T scalar): _vector(vector), _scalar(scalar) {}
/**
* @brief Construct quaternion from vector
@ -210,15 +148,15 @@ template<class T> class Quaternion {
* @f]
* @see transformVector(), transformVectorNormalized()
*/
inline constexpr explicit Quaternion(const Vector3<T>& vector): _vector(vector), _scalar(T(0)) {}
constexpr explicit Quaternion(const Vector3<T>& vector): _vector(vector), _scalar(T(0)) {}
/** @brief Equality comparison */
inline bool operator==(const Quaternion<T>& other) const {
bool operator==(const Quaternion<T>& other) const {
return _vector == other._vector && TypeTraits<T>::equals(_scalar, other._scalar);
}
/** @brief Non-equality comparison */
inline bool operator!=(const Quaternion<T>& other) const {
bool operator!=(const Quaternion<T>& other) const {
return !operator==(other);
}
@ -230,15 +168,15 @@ template<class T> class Quaternion {
* @f]
* @see dot(), normalized()
*/
inline bool isNormalized() const {
bool isNormalized() const {
return Implementation::isNormalizedSquared(dot());
}
/** @brief %Vector part */
inline constexpr Vector3<T> vector() const { return _vector; }
constexpr Vector3<T> vector() const { return _vector; }
/** @brief %Scalar part */
inline constexpr T scalar() const { return _scalar; }
constexpr T scalar() const { return _scalar; }
/**
* @brief Rotation angle of unit quaternion
@ -248,12 +186,7 @@ template<class T> class Quaternion {
* @f]
* @see isNormalized(), axis(), rotation()
*/
inline Rad<T> angle() const {
CORRADE_ASSERT(isNormalized(),
"Math::Quaternion::angle(): quaternion must be normalized",
Rad<T>(std::numeric_limits<T>::quiet_NaN()));
return Rad<T>(T(2)*std::acos(_scalar));
}
Rad<T> angle() const;
/**
* @brief Rotation axis of unit quaternion
@ -265,12 +198,7 @@ template<class T> class Quaternion {
* @f]
* @see isNormalized(), angle(), rotation()
*/
inline Vector3<T> axis() const {
CORRADE_ASSERT(isNormalized(),
"Math::Quaternion::axis(): quaternion must be normalized",
{});
return _vector/std::sqrt(1-pow2(_scalar));
}
Vector3<T> axis() const;
/**
* @brief Convert quaternion to rotation matrix
@ -278,19 +206,7 @@ template<class T> class Quaternion {
* @see fromMatrix(), DualQuaternion::toMatrix(),
* Matrix4::from(const Matrix<3, T>&, const Vector3<T>&)
*/
Matrix<3, T> toMatrix() const {
return {
Vector<3, T>(T(1) - 2*pow2(_vector.y()) - 2*pow2(_vector.z()),
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*pow2(_vector.x()) - 2*pow2(_vector.z()),
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*pow2(_vector.x()) - 2*pow2(_vector.y()))
};
}
Matrix<3, T> toMatrix() const;
/**
* @brief Add and assign quaternion
@ -299,7 +215,7 @@ template<class T> class Quaternion {
* p + q = [\boldsymbol p_V + \boldsymbol q_V, p_S + q_S]
* @f]
*/
inline Quaternion<T>& operator+=(const Quaternion<T>& other) {
Quaternion<T>& operator+=(const Quaternion<T>& other) {
_vector += other._vector;
_scalar += other._scalar;
return *this;
@ -310,7 +226,7 @@ template<class T> class Quaternion {
*
* @see operator+=()
*/
inline Quaternion<T> operator+(const Quaternion<T>& other) const {
Quaternion<T> operator+(const Quaternion<T>& other) const {
return Quaternion<T>(*this) += other;
}
@ -321,9 +237,7 @@ template<class T> class Quaternion {
* -q = [-\boldsymbol q_V, -q_S]
* @f]
*/
inline Quaternion<T> operator-() const {
return {-_vector, -_scalar};
}
Quaternion<T> operator-() const { return {-_vector, -_scalar}; }
/**
* @brief Subtract and assign quaternion
@ -332,7 +246,7 @@ template<class T> class Quaternion {
* p - q = [\boldsymbol p_V - \boldsymbol q_V, p_S - q_S]
* @f]
*/
inline Quaternion<T>& operator-=(const Quaternion<T>& other) {
Quaternion<T>& operator-=(const Quaternion<T>& other) {
_vector -= other._vector;
_scalar -= other._scalar;
return *this;
@ -343,7 +257,7 @@ template<class T> class Quaternion {
*
* @see operator-=()
*/
inline Quaternion<T> operator-(const Quaternion<T>& other) const {
Quaternion<T> operator-(const Quaternion<T>& other) const {
return Quaternion<T>(*this) -= other;
}
@ -354,7 +268,7 @@ template<class T> class Quaternion {
* q \cdot a = [\boldsymbol q_V \cdot a, q_S \cdot a]
* @f]
*/
inline Quaternion<T>& operator*=(T scalar) {
Quaternion<T>& operator*=(T scalar) {
_vector *= scalar;
_scalar *= scalar;
return *this;
@ -365,7 +279,7 @@ template<class T> class Quaternion {
*
* @see operator*=(T)
*/
inline Quaternion<T> operator*(T scalar) const {
Quaternion<T> operator*(T scalar) const {
return Quaternion<T>(*this) *= scalar;
}
@ -376,7 +290,7 @@ template<class T> class Quaternion {
* \frac q a = [\frac {\boldsymbol q_V} a, \frac {q_S} a]
* @f]
*/
inline Quaternion<T>& operator/=(T scalar) {
Quaternion<T>& operator/=(T scalar) {
_vector /= scalar;
_scalar /= scalar;
return *this;
@ -387,7 +301,7 @@ template<class T> class Quaternion {
*
* @see operator/=(T)
*/
inline Quaternion<T> operator/(T scalar) const {
Quaternion<T> operator/(T scalar) const {
return Quaternion<T>(*this) /= scalar;
}
@ -399,10 +313,7 @@ template<class T> class Quaternion {
* p_S q_S - \boldsymbol p_V \cdot \boldsymbol q_V]
* @f]
*/
inline Quaternion<T> operator*(const Quaternion<T>& other) const {
return {_scalar*other._vector + other._scalar*_vector + Vector3<T>::cross(_vector, other._vector),
_scalar*other._scalar - Vector3<T>::dot(_vector, other._vector)};
}
Quaternion<T> operator*(const Quaternion<T>& other) const;
/**
* @brief Dot product of the quaternion
@ -413,9 +324,7 @@ template<class T> class Quaternion {
* @f]
* @see isNormalized(), dot(const Quaternion&, const Quaternion&)
*/
inline T dot() const {
return dot(*this, *this);
}
T dot() const { return dot(*this, *this); }
/**
* @brief %Quaternion length
@ -426,18 +335,14 @@ template<class T> class Quaternion {
* @f]
* @see isNormalized()
*/
inline T length() const {
return std::sqrt(dot());
}
T length() const { return std::sqrt(dot()); }
/**
* @brief Normalized quaternion (of unit length)
*
* @see isNormalized()
*/
inline Quaternion<T> normalized() const {
return (*this)/length();
}
Quaternion<T> normalized() const { return (*this)/length(); }
/**
* @brief Conjugated quaternion
@ -446,9 +351,7 @@ template<class T> class Quaternion {
* q^* = [-\boldsymbol q_V, q_S]
* @f]
*/
inline Quaternion<T> conjugated() const {
return {-_vector, _scalar};
}
Quaternion<T> conjugated() const { return {-_vector, _scalar}; }
/**
* @brief Inverted quaternion
@ -458,9 +361,7 @@ template<class T> class Quaternion {
* q^{-1} = \frac{q^*}{|q|^2} = \frac{q^*}{q \cdot q}
* @f]
*/
inline Quaternion<T> inverted() const {
return conjugated()/dot();
}
Quaternion<T> inverted() const { return conjugated()/dot(); }
/**
* @brief Inverted normalized quaternion
@ -471,12 +372,7 @@ template<class T> class Quaternion {
* @f]
* @see isNormalized(), inverted()
*/
inline Quaternion<T> invertedNormalized() const {
CORRADE_ASSERT(isNormalized(),
"Math::Quaternion::invertedNormalized(): quaternion must be normalized",
Quaternion<T>({}, std::numeric_limits<T>::quiet_NaN()));
return conjugated();
}
Quaternion<T> invertedNormalized() const;
/**
* @brief Rotate vector with quaternion
@ -488,7 +384,7 @@ template<class T> class Quaternion {
* @see Quaternion(const Vector3&), vector(), Matrix4::transformVector(),
* DualQuaternion::transformPoint(), Complex::transformVector()
*/
inline Vector3<T> transformVector(const Vector3<T>& vector) const {
Vector3<T> transformVector(const Vector3<T>& vector) const {
return ((*this)*Quaternion<T>(vector)*inverted()).vector();
}
@ -502,21 +398,16 @@ template<class T> class Quaternion {
* @see isNormalized(), Quaternion(const Vector3&), vector(), Matrix4::transformVector(),
* DualQuaternion::transformPointNormalized(), Complex::transformVector()
*/
inline Vector3<T> transformVectorNormalized(const Vector3<T>& vector) const {
CORRADE_ASSERT(isNormalized(),
"Math::Quaternion::transformVectorNormalized(): quaternion must be normalized",
Vector3<T>(std::numeric_limits<T>::quiet_NaN()));
return ((*this)*Quaternion<T>(vector)*conjugated()).vector();
}
Vector3<T> transformVectorNormalized(const Vector3<T>& vector) const;
private:
/* Used to avoid including Functions.h */
inline constexpr static T pow2(T value) {
constexpr static T pow2(T value) {
return value*value;
}
/* Used in angle() and slerp() (no assertions) */
inline static T angleInternal(const Quaternion<T>& normalizedA, const Quaternion<T>& normalizedB) {
static T angleInternal(const Quaternion<T>& normalizedA, const Quaternion<T>& normalizedB) {
return std::acos(dot(normalizedA, normalizedB));
}
@ -562,6 +453,116 @@ extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utilit
#endif
#endif
namespace Implementation {
/* No assertions fired, for internal use. Not private member because used from
outside the class. */
template<class T> Quaternion<T> quaternionFromMatrix(const Matrix<3, T>& m) {
const Vector<3, T> diagonal = m.diagonal();
const T trace = diagonal.sum();
/* Diagonal is positive */
if(trace > T(0)) {
const T s = std::sqrt(trace + T(1));
const T t = T(0.5)/s;
return {Vector3<T>(m[1][2] - m[2][1],
m[2][0] - m[0][2],
m[0][1] - m[1][0])*t, s*T(0.5)};
}
/* Diagonal is negative */
std::size_t i = 0;
if(diagonal[1] > diagonal[0]) i = 1;
if(diagonal[2] > diagonal[i]) i = 2;
const std::size_t j = (i + 1) % 3;
const std::size_t k = (i + 2) % 3;
const T s = std::sqrt(diagonal[i] - diagonal[j] - diagonal[k] + T(1));
const T t = (s == T(0) ? T(0) : T(0.5)/s);
Vector3<T> vec;
vec[i] = s*T(0.5);
vec[j] = (m[i][j] + m[j][i])*t;
vec[k] = (m[i][k] + m[k][i])*t;
return {vec, (m[j][k] - m[k][j])*t};
}
}
template<class T> inline Rad<T> Quaternion<T>::angle(const Quaternion<T>& normalizedA, const Quaternion<T>& normalizedB) {
CORRADE_ASSERT(normalizedA.isNormalized() && normalizedB.isNormalized(),
"Math::Quaternion::angle(): quaternions must be normalized", Rad<T>(std::numeric_limits<T>::quiet_NaN()));
return Rad<T>(angleInternal(normalizedA, normalizedB));
}
template<class T> inline Quaternion<T> Quaternion<T>::lerp(const Quaternion<T>& normalizedA, const Quaternion<T>& normalizedB, const T t) {
CORRADE_ASSERT(normalizedA.isNormalized() && normalizedB.isNormalized(),
"Math::Quaternion::lerp(): quaternions must be normalized", Quaternion<T>({}, std::numeric_limits<T>::quiet_NaN()));
return ((T(1) - t)*normalizedA + t*normalizedB).normalized();
}
template<class T> inline Quaternion<T> Quaternion<T>::slerp(const Quaternion<T>& normalizedA, const Quaternion<T>& normalizedB, const T t) {
CORRADE_ASSERT(normalizedA.isNormalized() && normalizedB.isNormalized(),
"Math::Quaternion::slerp(): quaternions must be normalized", Quaternion<T>({}, std::numeric_limits<T>::quiet_NaN()));
const T a = angleInternal(normalizedA, normalizedB);
return (std::sin((T(1) - t)*a)*normalizedA + std::sin(t*a)*normalizedB)/std::sin(a);
}
template<class T> inline Quaternion<T> Quaternion<T>::rotation(const Rad<T> angle, const Vector3<T>& normalizedAxis) {
CORRADE_ASSERT(normalizedAxis.isNormalized(),
"Math::Quaternion::rotation(): axis must be normalized", {});
return {normalizedAxis*std::sin(T(angle)/2), std::cos(T(angle)/2)};
}
template<class T> inline Quaternion<T> Quaternion<T>::fromMatrix(const Matrix<3, T>& matrix) {
CORRADE_ASSERT(matrix.isOrthogonal(), "Math::Quaternion::fromMatrix(): the matrix is not orthogonal", {});
return Implementation::quaternionFromMatrix(matrix);
}
template<class T> inline Rad<T> Quaternion<T>::angle() const {
CORRADE_ASSERT(isNormalized(), "Math::Quaternion::angle(): quaternion must be normalized",
Rad<T>(std::numeric_limits<T>::quiet_NaN()));
return Rad<T>(T(2)*std::acos(_scalar));
}
template<class T> inline Vector3<T> Quaternion<T>::axis() const {
CORRADE_ASSERT(isNormalized(), "Math::Quaternion::axis(): quaternion must be normalized", {});
return _vector/std::sqrt(1-pow2(_scalar));
}
template<class T> Matrix<3, T> Quaternion<T>::toMatrix() const {
return {
Vector<3, T>(T(1) - 2*pow2(_vector.y()) - 2*pow2(_vector.z()),
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*pow2(_vector.x()) - 2*pow2(_vector.z()),
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*pow2(_vector.x()) - 2*pow2(_vector.y()))
};
}
template<class T> inline Quaternion<T> Quaternion<T>::operator*(const Quaternion<T>& other) const {
return {_scalar*other._vector + other._scalar*_vector + Vector3<T>::cross(_vector, other._vector),
_scalar*other._scalar - Vector3<T>::dot(_vector, other._vector)};
}
template<class T> inline Quaternion<T> Quaternion<T>::invertedNormalized() const {
CORRADE_ASSERT(isNormalized(), "Math::Quaternion::invertedNormalized(): quaternion must be normalized",
Quaternion<T>({}, std::numeric_limits<T>::quiet_NaN()));
return conjugated();
}
template<class T> inline Vector3<T> Quaternion<T>::transformVectorNormalized(const Vector3< T >& vector) const {
CORRADE_ASSERT(isNormalized(), "Math::Quaternion::transformVectorNormalized(): quaternion must be normalized",
Vector3<T>(std::numeric_limits<T>::quiet_NaN()));
return ((*this)*Quaternion<T>(vector)*conjugated()).vector();
}
}}
#endif

212
src/Math/RectangularMatrix.h

@ -77,11 +77,11 @@ template<std::size_t cols, std::size_t rows, class T> class RectangularMatrix {
* @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) {
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) {
constexpr static const RectangularMatrix<cols, rows, T>& from(const T* data) {
return *reinterpret_cast<const RectangularMatrix<cols, rows, T>*>(data);
}
@ -91,14 +91,7 @@ template<std::size_t cols, std::size_t rows, class T> class RectangularMatrix {
* @see diagonal()
* @todo make this constexpr
*/
inline static RectangularMatrix<cols, rows, T> fromDiagonal(const Vector<DiagonalSize, T>& diagonal) {
RectangularMatrix<cols, rows, T> out;
for(std::size_t i = 0; i != DiagonalSize; ++i)
out[i][i] = diagonal[i];
return out;
}
static RectangularMatrix<cols, rows, T> fromDiagonal(const Vector<DiagonalSize, T>& diagonal);
/**
* @brief Construct matrix from vector
@ -107,12 +100,12 @@ template<std::size_t cols, std::size_t rows, class T> class RectangularMatrix {
* vector will make first column of resulting matrix.
* @see toVector()
*/
inline static RectangularMatrix<cols, rows, T> fromVector(const Vector<cols*rows, T>& vector) {
static RectangularMatrix<cols, rows, T> fromVector(const Vector<cols*rows, T>& vector) {
return *reinterpret_cast<const RectangularMatrix<cols, rows, T>*>(vector.data());
}
/** @brief Construct zero-filled matrix */
inline constexpr /*implicit*/ RectangularMatrix() {}
constexpr /*implicit*/ RectangularMatrix() {}
/**
* @brief Construct matrix from column vectors
@ -121,7 +114,7 @@ template<std::size_t cols, std::size_t rows, class T> class RectangularMatrix {
*
* @todo Creating matrix from arbitrary combination of matrices with n rows
*/
template<class ...U> inline constexpr /*implicit*/ RectangularMatrix(const Vector<rows, T>& first, const U&... next): _data{first, next...} {
template<class ...U> 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");
}
@ -137,30 +130,30 @@ template<std::size_t cols, std::size_t rows, class T> class RectangularMatrix {
* @endcode
*/
#ifndef CORRADE_GCC46_COMPATIBILITY
template<class U> inline constexpr explicit RectangularMatrix(const RectangularMatrix<cols, rows, U>& other): RectangularMatrix(typename Implementation::GenerateSequence<cols>::Type(), other) {}
template<class U> constexpr explicit RectangularMatrix(const RectangularMatrix<cols, rows, U>& other): RectangularMatrix(typename Implementation::GenerateSequence<cols>::Type(), other) {}
#else
template<class U> inline explicit RectangularMatrix(const RectangularMatrix<cols, rows, U>& other) {
template<class U> explicit RectangularMatrix(const RectangularMatrix<cols, rows, U>& other) {
*this = RectangularMatrix(typename Implementation::GenerateSequence<cols>::Type(), other);
}
#endif
/** @brief Construct matrix from external representation */
#ifndef CORRADE_GCC46_COMPATIBILITY
template<class U, class V = decltype(Implementation::RectangularMatrixConverter<cols, rows, T, U>::from(std::declval<U>()))> inline constexpr explicit RectangularMatrix(const U& other): RectangularMatrix(Implementation::RectangularMatrixConverter<cols, rows, T, U>::from(other)) {}
template<class U, class V = decltype(Implementation::RectangularMatrixConverter<cols, rows, T, U>::from(std::declval<U>()))> constexpr explicit RectangularMatrix(const U& other): RectangularMatrix(Implementation::RectangularMatrixConverter<cols, rows, T, U>::from(other)) {}
#else
template<class U, class V = decltype(Implementation::RectangularMatrixConverter<cols, rows, T, U>::from(std::declval<U>()))> inline explicit RectangularMatrix(const U& other) {
template<class U, class V = decltype(Implementation::RectangularMatrixConverter<cols, rows, T, U>::from(std::declval<U>()))> explicit RectangularMatrix(const U& other) {
*this = Implementation::RectangularMatrixConverter<cols, rows, T, U>::from(other);
}
#endif
/** @brief Copy constructor */
inline constexpr RectangularMatrix(const RectangularMatrix<cols, rows, T>&) = default;
constexpr RectangularMatrix(const RectangularMatrix<cols, rows, T>&) = default;
/** @brief Assignment operator */
inline RectangularMatrix<cols, rows, T>& operator=(const RectangularMatrix<cols, rows, T>&) = default;
RectangularMatrix<cols, rows, T>& operator=(const RectangularMatrix<cols, rows, T>&) = default;
/** @brief Convert matrix to external representation */
template<class U, class V = decltype(Implementation::RectangularMatrixConverter<cols, rows, T, U>::to(std::declval<RectangularMatrix<cols, rows, T>>()))> inline constexpr explicit operator U() const {
template<class U, class V = decltype(Implementation::RectangularMatrixConverter<cols, rows, T, U>::to(std::declval<RectangularMatrix<cols, rows, T>>()))> constexpr explicit operator U() const {
/** @bug Why this is not constexpr under GCC 4.6? */
return Implementation::RectangularMatrixConverter<cols, rows, T, U>::to(*this);
}
@ -172,8 +165,8 @@ template<std::size_t cols, std::size_t rows, class T> class RectangularMatrix {
*
* @see operator[]
*/
inline T* data() { return _data[0].data(); }
inline constexpr const T* data() const { return _data[0].data(); } /**< @overload */
T* data() { return _data[0].data(); }
constexpr const T* data() const { return _data[0].data(); } /**< @overload */
/**
* @brief %Matrix column
@ -186,13 +179,8 @@ template<std::size_t cols, std::size_t rows, class T> class RectangularMatrix {
*
* @see row(), data()
*/
inline Vector<rows, T>& operator[](std::size_t col) {
return _data[col];
}
/** @overload */
inline constexpr const Vector<rows, T>& operator[](std::size_t col) const {
return _data[col];
}
Vector<rows, T>& operator[](std::size_t col) { return _data[col]; }
constexpr const Vector<rows, T>& operator[](std::size_t col) const { return _data[col]; } /** @overload */
/**
* @brief %Matrix row
@ -201,17 +189,10 @@ template<std::size_t cols, std::size_t rows, class T> class RectangularMatrix {
* is slower than accessing columns due to the way the matrix is stored.
* @see operator[]()
*/
inline Vector<cols, T> row(std::size_t row) const {
Vector<cols, T> out;
for(std::size_t i = 0; i != cols; ++i)
out[i] = _data[i][row];
return out;
}
Vector<cols, T> row(std::size_t row) const;
/** @brief Equality comparison */
inline bool operator==(const RectangularMatrix<cols, rows, T>& other) const {
bool operator==(const RectangularMatrix<cols, rows, T>& other) const {
for(std::size_t i = 0; i != cols; ++i)
if(_data[i] != other._data[i]) return false;
@ -224,10 +205,19 @@ template<std::size_t cols, std::size_t rows, class T> class RectangularMatrix {
* @see Vector::operator<(), Vector::operator<=(), Vector::operator>=(),
* Vector::operator>()
*/
inline bool operator!=(const RectangularMatrix<cols, rows, T>& other) const {
bool operator!=(const RectangularMatrix<cols, rows, T>& other) const {
return !operator==(other);
}
/**
* @brief Negated matrix
*
* The computation is done column-wise. @f[
* \boldsymbol B_j = -\boldsymbol A_j
* @f]
*/
RectangularMatrix<cols, rows, T> operator-() const;
/**
* @brief Add and assign matrix
*
@ -247,26 +237,10 @@ template<std::size_t cols, std::size_t rows, class T> class RectangularMatrix {
*
* @see operator+=()
*/
inline RectangularMatrix<cols, rows, T> operator+(const RectangularMatrix<cols, rows, T>& other) const {
RectangularMatrix<cols, rows, T> operator+(const RectangularMatrix<cols, rows, T>& other) const {
return RectangularMatrix<cols, rows, T>(*this)+=other;
}
/**
* @brief Negated matrix
*
* 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; ++i)
out._data[i] = -_data[i];
return out;
}
/**
* @brief Subtract and assign matrix
*
@ -286,7 +260,7 @@ template<std::size_t cols, std::size_t rows, class T> class RectangularMatrix {
*
* @see operator-=()
*/
inline RectangularMatrix<cols, rows, T> operator-(const RectangularMatrix<cols, rows, T>& other) const {
RectangularMatrix<cols, rows, T> operator-(const RectangularMatrix<cols, rows, T>& other) const {
return RectangularMatrix<cols, rows, T>(*this)-=other;
}
@ -316,7 +290,7 @@ template<std::size_t cols, std::size_t rows, class T> class RectangularMatrix {
#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 {
template<class U> RectangularMatrix<cols, rows, T> operator*(U number) const {
#endif
return RectangularMatrix<cols, rows, T>(*this)*=number;
}
@ -347,7 +321,7 @@ template<std::size_t cols, std::size_t rows, class T> class RectangularMatrix {
#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 {
template<class U> RectangularMatrix<cols, rows, T> operator/(U number) const {
#endif
return RectangularMatrix<cols, rows, T>(*this)/=number;
}
@ -359,16 +333,7 @@ template<std::size_t cols, std::size_t rows, class T> class RectangularMatrix {
* (\boldsymbol {AB})_{ji} = \sum_{k=0}^{m-1} \boldsymbol A_{ki} \boldsymbol B_{jk}
* @f]
*/
template<std::size_t size> RectangularMatrix<size, rows, T> operator*(const RectangularMatrix<size, cols, T>& other) const {
RectangularMatrix<size, rows, T> out;
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] += _data[pos][row]*other._data[col][pos];
return out;
}
template<std::size_t size> RectangularMatrix<size, rows, T> operator*(const RectangularMatrix<size, cols, T>& other) const;
/**
* @brief Multiply vector
@ -387,29 +352,15 @@ template<std::size_t cols, std::size_t rows, class T> class RectangularMatrix {
*
* @see row()
*/
RectangularMatrix<rows, cols, T> transposed() const {
RectangularMatrix<rows, cols, T> out;
for(std::size_t col = 0; col != cols; ++col)
for(std::size_t row = 0; row != rows; ++row)
out[row][col] = _data[col][row];
return out;
}
RectangularMatrix<rows, cols, T> transposed() const;
/**
* @brief Values on diagonal
*
* @see fromDiagonal()
* @todo constexpr
*/
Vector<DiagonalSize, T> diagonal() const {
Vector<DiagonalSize, T> out;
for(std::size_t i = 0; i != DiagonalSize; ++i)
out[i] = _data[i][i];
return out;
}
Vector<DiagonalSize, T> diagonal() const;
/**
* @brief Convert matrix to vector
@ -420,13 +371,13 @@ template<std::size_t cols, std::size_t rows, class T> class RectangularMatrix {
* summing the elements etc.).
* @see fromVector()
*/
inline Vector<rows*cols, T> toVector() const {
Vector<rows*cols, T> toVector() const {
return *reinterpret_cast<const Vector<rows*cols, T>*>(data());
}
private:
/* Implementation for RectangularMatrix<cols, rows, T>::RectangularMatrix(const RectangularMatrix<cols, rows, U>&) */
template<class U, std::size_t ...sequence> inline constexpr explicit RectangularMatrix(Implementation::Sequence<sequence...>, const RectangularMatrix<cols, rows, U>& matrix): _data{Vector<rows, T>(matrix[sequence])...} {}
template<class U, std::size_t ...sequence> constexpr explicit RectangularMatrix(Implementation::Sequence<sequence...>, const RectangularMatrix<cols, rows, U>& matrix): _data{Vector<rows, T>(matrix[sequence])...} {}
Vector<rows, T> _data[cols];
};
@ -453,9 +404,9 @@ The computation is done column-wise. @f[
@see RectangularMatrix::operator/(U) const
*/
#ifdef DOXYGEN_GENERATING_OUTPUT
template<std::size_t cols, std::size_t rows, class T, class U> RectangularMatrix<cols, rows, T> operator/(U number, const RectangularMatrix<cols, rows, T>& matrix) {
template<std::size_t cols, std::size_t rows, class T, class U> inline RectangularMatrix<cols, rows, T> operator/(U number, const RectangularMatrix<cols, rows, T>& matrix) {
#else
template<std::size_t cols, std::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) {
template<std::size_t cols, std::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) {
#endif
RectangularMatrix<cols, rows, T> out;
@ -522,51 +473,108 @@ extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utilit
#endif
#define MAGNUM_RECTANGULARMATRIX_SUBCLASS_IMPLEMENTATION(cols, rows, ...) \
inline constexpr static __VA_ARGS__& from(T* data) { \
constexpr static __VA_ARGS__& from(T* data) { \
return *reinterpret_cast<__VA_ARGS__*>(data); \
} \
inline constexpr static const __VA_ARGS__& from(const T* data) { \
constexpr static const __VA_ARGS__& from(const T* data) { \
return *reinterpret_cast<const __VA_ARGS__*>(data); \
} \
\
inline __VA_ARGS__& operator=(const Math::RectangularMatrix<cols, rows, T>& other) { \
__VA_ARGS__& operator=(const Math::RectangularMatrix<cols, rows, T>& other) { \
Math::RectangularMatrix<cols, rows, T>::operator=(other); \
return *this; \
} \
\
inline __VA_ARGS__ operator-() const { \
__VA_ARGS__ operator-() const { \
return Math::RectangularMatrix<cols, rows, T>::operator-(); \
} \
inline __VA_ARGS__& operator+=(const Math::RectangularMatrix<cols, rows, T>& other) { \
__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 { \
__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) { \
__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 { \
__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) { \
template<class U> 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 { \
template<class U> 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) { \
template<class U> 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 { \
template<class U> 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
template<std::size_t cols, std::size_t rows, class T> inline RectangularMatrix<cols, rows, T> RectangularMatrix<cols, rows, T>::fromDiagonal(const Vector<DiagonalSize, T>& diagonal) {
RectangularMatrix<cols, rows, T> out;
for(std::size_t i = 0; i != DiagonalSize; ++i)
out[i][i] = diagonal[i];
return out;
}
template<std::size_t cols, std::size_t rows, class T> inline Vector<cols, T> RectangularMatrix<cols, rows, T>::row(std::size_t row) const {
Vector<cols, T> out;
for(std::size_t i = 0; i != cols; ++i)
out[i] = _data[i][row];
return out;
}
template<std::size_t cols, std::size_t rows, class T> inline RectangularMatrix<cols, rows, T> RectangularMatrix<cols, rows, T>::operator-() const {
RectangularMatrix<cols, rows, T> out;
for(std::size_t i = 0; i != cols; ++i)
out._data[i] = -_data[i];
return out;
}
template<std::size_t cols, std::size_t rows, class T> template<std::size_t size> inline RectangularMatrix<size, rows, T> RectangularMatrix<cols, rows, T>::operator*(const RectangularMatrix<size, cols, T>& other) const {
RectangularMatrix<size, rows, T> out;
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] += _data[pos][row]*other._data[col][pos];
return out;
}
template<std::size_t cols, std::size_t rows, class T> inline RectangularMatrix<rows, cols, T> RectangularMatrix<cols, rows, T>::transposed() const {
RectangularMatrix<rows, cols, T> out;
for(std::size_t col = 0; col != cols; ++col)
for(std::size_t row = 0; row != rows; ++row)
out[row][col] = _data[col][row];
return out;
}
template<std::size_t cols, std::size_t rows, class T> auto RectangularMatrix<cols, rows, T>::diagonal() const -> Vector<DiagonalSize, T> {
Vector<DiagonalSize, T> out;
for(std::size_t i = 0; i != DiagonalSize; ++i)
out[i] = _data[i][i];
return out;
}
}}
namespace Corrade { namespace Utility {

8
src/Math/Swizzle.h

@ -36,7 +36,7 @@ namespace Implementation {
template<std::size_t size, std::size_t position> struct ComponentAtPosition {
static_assert(size > position, "Swizzle parameter out of range of base vector");
template<class T> inline constexpr static T value(const Math::Vector<size, T>& vector) { return vector[position]; }
template<class T> constexpr static T value(const Math::Vector<size, T>& vector) { return vector[position]; }
};
template<std::size_t size, char component> struct Component {};
@ -45,10 +45,10 @@ namespace Implementation {
template<std::size_t size> struct Component<size, 'z'>: public ComponentAtPosition<size, 2> {};
template<std::size_t size> struct Component<size, 'w'>: public ComponentAtPosition<size, 3> {};
template<std::size_t size> struct Component<size, '0'> {
template<class T> inline constexpr static T value(const Math::Vector<size, T>&) { return T(0); }
template<class T> constexpr static T value(const Math::Vector<size, T>&) { return T(0); }
};
template<std::size_t size> struct Component<size, '1'> {
template<class T> inline constexpr static T value(const Math::Vector<size, T>&) { return T(1); }
template<class T> constexpr static T value(const Math::Vector<size, T>&) { return T(1); }
};
}
@ -72,7 +72,7 @@ present in this lightweight implementation for Math namespace.
@see @ref matrix-vector-component-access, Vector4::xyz(),
Vector4::xy(), Vector3::xy()
*/
template<char ...components, std::size_t size, class T> inline constexpr Vector<sizeof...(components), T> swizzle(const Vector<size, T>& vector) {
template<char ...components, std::size_t size, class T> constexpr Vector<sizeof...(components), T> swizzle(const Vector<size, T>& vector) {
return {Implementation::Component<size, components>::value(vector)...};
}

4
src/Math/Test/Matrix3Test.cpp

@ -37,14 +37,14 @@ namespace Magnum { namespace Math {
namespace Implementation {
template<> struct RectangularMatrixConverter<3, 3, float, Mat3> {
inline constexpr static RectangularMatrix<3, 3, Float> from(const Mat3& other) {
constexpr static RectangularMatrix<3, 3, Float> from(const Mat3& other) {
return RectangularMatrix<3, 3, Float>(
Vector<3, Float>(other.a[0], other.a[1], other.a[2]),
Vector<3, Float>(other.a[3], other.a[4], other.a[5]),
Vector<3, Float>(other.a[6], other.a[7], other.a[8]));
}
inline constexpr static Mat3 to(const RectangularMatrix<3, 3, Float>& other) {
constexpr static Mat3 to(const RectangularMatrix<3, 3, Float>& other) {
return Mat3{{other[0][0], other[0][1], other[0][2],
other[1][0], other[1][1], other[1][2],
other[2][0], other[2][1], other[2][2]}};

4
src/Math/Test/Matrix4Test.cpp

@ -37,7 +37,7 @@ namespace Magnum { namespace Math {
namespace Implementation {
template<> struct RectangularMatrixConverter<4, 4, float, Mat4> {
inline constexpr static RectangularMatrix<4, 4, Float> from(const Mat4& other) {
constexpr static RectangularMatrix<4, 4, Float> from(const Mat4& other) {
return RectangularMatrix<4, 4, Float>(
Vector<4, Float>(other.a[0], other.a[1], other.a[2], other.a[3]),
Vector<4, Float>(other.a[4], other.a[5], other.a[6], other.a[7]),
@ -45,7 +45,7 @@ template<> struct RectangularMatrixConverter<4, 4, float, Mat4> {
Vector<4, Float>(other.a[12], other.a[13], other.a[14], other.a[15]));
}
inline constexpr static Mat4 to(const RectangularMatrix<4, 4, Float>& other) {
constexpr static Mat4 to(const RectangularMatrix<4, 4, Float>& other) {
return Mat4{{other[0][0], other[0][1], other[0][2], other[0][3],
other[1][0], other[1][1], other[1][2], other[1][3],
other[2][0], other[2][1], other[2][2], other[2][3],

4
src/Math/Test/MatrixTest.cpp

@ -37,14 +37,14 @@ namespace Magnum { namespace Math {
namespace Implementation {
template<> struct RectangularMatrixConverter<3, 3, float, Mat3> {
inline constexpr static RectangularMatrix<3, 3, Float> from(const Mat3& other) {
constexpr static RectangularMatrix<3, 3, Float> from(const Mat3& other) {
return RectangularMatrix<3, 3, Float>(
Vector<3, Float>(other.a[0], other.a[1], other.a[2]),
Vector<3, Float>(other.a[3], other.a[4], other.a[5]),
Vector<3, Float>(other.a[6], other.a[7], other.a[8]));
}
inline constexpr static Mat3 to(const RectangularMatrix<3, 3, Float>& other) {
constexpr static Mat3 to(const RectangularMatrix<3, 3, Float>& other) {
return Mat3{{other[0][0], other[0][1], other[0][2],
other[1][0], other[1][1], other[1][2],
other[2][0], other[2][1], other[2][2]}};

4
src/Math/Test/RectangularMatrixTest.cpp

@ -37,13 +37,13 @@ namespace Magnum { namespace Math {
namespace Implementation {
template<> struct RectangularMatrixConverter<2, 3, float, Mat2x3> {
inline constexpr static RectangularMatrix<2, 3, Float> from(const Mat2x3& other) {
constexpr static RectangularMatrix<2, 3, Float> from(const Mat2x3& other) {
return RectangularMatrix<2, 3, Float>(
Vector<3, Float>(other.a[0], other.a[1], other.a[2]),
Vector<3, Float>(other.a[3], other.a[4], other.a[5]));
}
inline constexpr static Mat2x3 to(const RectangularMatrix<2, 3, Float>& other) {
constexpr static Mat2x3 to(const RectangularMatrix<2, 3, Float>& other) {
return Mat2x3{{other[0][0], other[0][1], other[0][2],
other[1][0], other[1][1], other[1][2]}};
}

4
src/Math/Test/Vector2Test.cpp

@ -37,11 +37,11 @@ namespace Magnum { namespace Math {
namespace Implementation {
template<> struct VectorConverter<2, float, Vec2> {
inline constexpr static Vector<2, float> from(const Vec2& other) {
constexpr static Vector<2, float> from(const Vec2& other) {
return {other.x, other.y};
}
inline constexpr static Vec2 to(const Vector<2, float>& other) {
constexpr static Vec2 to(const Vector<2, float>& other) {
return {other[0], other[1]};
}
};

4
src/Math/Test/Vector3Test.cpp

@ -37,11 +37,11 @@ namespace Magnum { namespace Math {
namespace Implementation {
template<> struct VectorConverter<3, float, Vec3> {
inline constexpr static Vector<3, Float> from(const Vec3& other) {
constexpr static Vector<3, Float> from(const Vec3& other) {
return {other.x, other.y, other.z};
}
inline constexpr static Vec3 to(const Vector<3, Float>& other) {
constexpr static Vec3 to(const Vector<3, Float>& other) {
return {other[0], other[1], other[2]};
}
};

4
src/Math/Test/Vector4Test.cpp

@ -37,11 +37,11 @@ namespace Magnum { namespace Math {
namespace Implementation {
template<> struct VectorConverter<4, float, Vec4> {
inline constexpr static Vector<4, Float> from(const Vec4& other) {
constexpr static Vector<4, Float> from(const Vec4& other) {
return {other.x, other.y, other.z, other.w};
}
inline constexpr static Vec4 to(const Vector<4, Float>& other) {
constexpr static Vec4 to(const Vector<4, Float>& other) {
return {other[0], other[1], other[2], other[3]};
}
};

4
src/Math/Test/VectorTest.cpp

@ -37,11 +37,11 @@ namespace Magnum { namespace Math {
namespace Implementation {
template<> struct VectorConverter<3, float, Vec3> {
inline constexpr static Vector<3, Float> from(const Vec3& other) {
constexpr static Vector<3, Float> from(const Vec3& other) {
return {other.x, other.y, other.z};
}
inline constexpr static Vec3 to(const Vector<3, Float>& other) {
constexpr static Vec3 to(const Vector<3, Float>& other) {
return {other[0], other[1], other[2]};
}
};

14
src/Math/TypeTraits.h

@ -56,7 +56,7 @@ namespace Implementation {
template<class T> struct TypeTraitsDefault {
TypeTraitsDefault() = delete;
inline constexpr static bool equals(T a, T b) {
constexpr static bool equals(T a, T b) {
return a == b;
}
};
@ -93,7 +93,7 @@ template<class T> struct TypeTraits: Implementation::TypeTraitsDefault<T> {
* inequal. Returns 1 for integer types and reasonably small value for
* floating-point types. Not implemented for arbitrary types.
*/
inline constexpr static T epsilon();
constexpr static T epsilon();
/**
* @brief Fuzzy compare
@ -116,7 +116,7 @@ template<class T> struct TypeTraits: Implementation::TypeTraitsDefault<T> {
/* Integral scalar types */
namespace Implementation {
template<class T> struct TypeTraitsIntegral: TypeTraitsDefault<T> {
inline constexpr static T epsilon() { return T(1); }
constexpr static T epsilon() { return T(1); }
};
}
@ -159,7 +159,7 @@ namespace Implementation {
template<class T> struct TypeTraitsFloatingPoint {
TypeTraitsFloatingPoint() = delete;
inline static bool equals(T a, T b) {
static bool equals(T a, T b) {
return std::abs(a - b) < TypeTraits<T>::epsilon();
}
};
@ -168,19 +168,19 @@ namespace Implementation {
template<> struct TypeTraits<Float>: Implementation::TypeTraitsFloatingPoint<Float> {
typedef Float FloatingPointType;
inline constexpr static Float epsilon() { return FLOAT_EQUALITY_PRECISION; }
constexpr static Float epsilon() { return FLOAT_EQUALITY_PRECISION; }
};
#ifndef MAGNUM_TARGET_GLES
template<> struct TypeTraits<Double>: Implementation::TypeTraitsFloatingPoint<Double> {
typedef Double FloatingPointType;
inline constexpr static Double epsilon() { return DOUBLE_EQUALITY_PRECISION; }
constexpr static Double epsilon() { return DOUBLE_EQUALITY_PRECISION; }
};
#endif
template<> struct TypeTraits<long double>: Implementation::TypeTraitsFloatingPoint<long double> {
typedef long double FloatingPointType;
inline constexpr static long double epsilon() { return LONG_DOUBLE_EQUALITY_PRECISION; }
constexpr static long double epsilon() { return LONG_DOUBLE_EQUALITY_PRECISION; }
};
/* Comparing squared length to 1 is not sufficient to compare within range

42
src/Math/Unit.h

@ -45,98 +45,98 @@ template<template<class> class Derived, class T> class Unit {
typedef T Type; /**< @brief Underlying data type */
/** @brief Default constructor */
inline constexpr /*implicit*/ Unit(): value(T(0)) {}
constexpr /*implicit*/ Unit(): value(T(0)) {}
/** @brief Explicit conversion from unitless type */
inline constexpr explicit Unit(T value): value(value) {}
constexpr explicit Unit(T value): value(value) {}
/** @brief Construct from another underlying type */
template<class U> inline constexpr explicit Unit(Unit<Derived, U> value): value(value.value) {}
template<class U> constexpr explicit Unit(Unit<Derived, U> value): value(value.value) {}
/** @brief Explicit conversion to underlying type */
inline constexpr explicit operator T() const { return value; }
constexpr explicit operator T() const { return value; }
/** @brief Equality comparison */
inline constexpr bool operator==(Unit<Derived, T> other) const {
constexpr bool operator==(Unit<Derived, T> other) const {
return TypeTraits<T>::equals(value, other.value);
}
/** @brief Non-equality comparison */
inline constexpr bool operator!=(Unit<Derived, T> other) const {
constexpr bool operator!=(Unit<Derived, T> other) const {
return !operator==(other);
}
/** @brief Less than comparison */
inline constexpr bool operator<(Unit<Derived, T> other) const {
constexpr bool operator<(Unit<Derived, T> other) const {
return value < other.value;
}
/** @brief Greater than comparison */
inline constexpr bool operator>(Unit<Derived, T> other) const {
constexpr bool operator>(Unit<Derived, T> other) const {
return value > other.value;
}
/** @brief Less than or equal comparison */
inline constexpr bool operator<=(Unit<Derived, T> other) const {
constexpr bool operator<=(Unit<Derived, T> other) const {
return !operator>(other);
}
/** @brief Greater than or equal comparison */
inline constexpr bool operator>=(Unit<Derived, T> other) const {
constexpr bool operator>=(Unit<Derived, T> other) const {
return !operator<(other);
}
/** @brief Negated value */
inline constexpr Unit<Derived, T> operator-() const {
constexpr Unit<Derived, T> operator-() const {
return Unit<Derived, T>(-value);
}
/** @brief Add and assign value */
inline Unit<Derived, T>& operator+=(Unit<Derived, T> other) {
Unit<Derived, T>& operator+=(Unit<Derived, T> other) {
value += other.value;
return *this;
}
/** @brief Add value */
inline constexpr Unit<Derived, T> operator+(Unit<Derived, T> other) const {
constexpr Unit<Derived, T> operator+(Unit<Derived, T> other) const {
return Unit<Derived, T>(value + other.value);
}
/** @brief Subtract and assign value */
inline Unit<Derived, T>& operator-=(Unit<Derived, T> other) {
Unit<Derived, T>& operator-=(Unit<Derived, T> other) {
value -= other.value;
return *this;
}
/** @brief Subtract value */
inline constexpr Unit<Derived, T> operator-(Unit<Derived, T> other) const {
constexpr Unit<Derived, T> operator-(Unit<Derived, T> other) const {
return Unit<Derived, T>(value - other.value);
}
/** @brief Multiply with number and assign */
inline Unit<Derived, T>& operator*=(T number) {
Unit<Derived, T>& operator*=(T number) {
value *= number;
return *this;
}
/** @brief Multiply with number */
inline constexpr Unit<Derived, T> operator*(T number) const {
constexpr Unit<Derived, T> operator*(T number) const {
return Unit<Derived, T>(value*number);
}
/** @brief Divide with number and assign */
inline Unit<Derived, T>& operator/=(T number) {
Unit<Derived, T>& operator/=(T number) {
value /= number;
return *this;
}
/** @brief Divide with number */
inline constexpr Unit<Derived, T> operator/(T number) const {
constexpr Unit<Derived, T> operator/(T number) const {
return Unit<Derived, T>(value/number);
}
/** @brief Ratio of two values */
inline constexpr T operator/(Unit<Derived, T> other) const {
constexpr T operator/(Unit<Derived, T> other) const {
return value/other.value;
}
@ -147,7 +147,7 @@ template<template<class> class Derived, class T> class Unit {
/** @relates Unit
@brief Multiply number with value
*/
template<template<class> class Derived, class T> inline constexpr Unit<Derived, T> operator*(typename std::common_type<T>::type number, const Unit<Derived, T>& value) {
template<template<class> class Derived, class T> constexpr Unit<Derived, T> operator*(typename std::common_type<T>::type number, const Unit<Derived, T>& value) {
return value*number;
}

317
src/Math/Vector.h

@ -71,11 +71,11 @@ template<std::size_t size, class T> class Vector {
* @attention Use with caution, the function doesn't check whether the
* array is long enough.
*/
inline constexpr static Vector<size, T>& from(T* data) {
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) {
constexpr static const Vector<size, T>& from(const T* data) {
return *reinterpret_cast<const Vector<size, T>*>(data);
}
@ -89,7 +89,7 @@ template<std::size_t size, class T> class Vector {
* @f]
* @see dot() const, operator-(), Vector2::perpendicular()
*/
inline static T dot(const Vector<size, T>& a, const Vector<size, T>& b) {
static T dot(const Vector<size, T>& a, const Vector<size, T>& b) {
return (a*b).sum();
}
@ -101,11 +101,7 @@ template<std::size_t size, class T> class Vector {
* @f]
* @see isNormalized(), Quaternion::angle(), Complex::angle()
*/
inline static Rad<T> angle(const Vector<size, T>& normalizedA, const Vector<size, T>& normalizedB) {
CORRADE_ASSERT(normalizedA.isNormalized() && normalizedB.isNormalized(),
"Math::Vector::angle(): vectors must be normalized", Rad<T>(std::numeric_limits<T>::quiet_NaN()));
return Rad<T>(std::acos(dot(normalizedA, normalizedB)));
}
static Rad<T> angle(const Vector<size, T>& normalizedA, const Vector<size, T>& normalizedB);
/**
* @brief Default constructor
@ -114,7 +110,7 @@ template<std::size_t size, class T> class Vector {
* \boldsymbol v = \boldsymbol 0
* @f]
*/
inline constexpr /*implicit*/ Vector(): _data() {}
constexpr /*implicit*/ Vector(): _data() {}
/** @todo Creating Vector from combination of vector and scalar types */
@ -124,19 +120,19 @@ template<std::size_t size, class T> class Vector {
* @param next Next values
*/
#ifdef DOXYGEN_GENERATING_OUTPUT
template<class ...U> inline constexpr /*implicit*/ Vector(T first, U... next);
template<class ...U> constexpr /*implicit*/ Vector(T first, U... next);
#else
template<class ...U, class V = typename std::enable_if<sizeof...(U)+1 == size, T>::type> inline constexpr /*implicit*/ Vector(T first, U... next): _data{first, next...} {}
template<class ...U, class V = typename std::enable_if<sizeof...(U)+1 == size, T>::type> constexpr /*implicit*/ Vector(T first, U... next): _data{first, next...} {}
#endif
/** @brief Construct vector with one value for all fields */
#ifdef DOXYGEN_GENERATING_OUTPUT
inline explicit Vector(T value);
constexpr explicit Vector(T value);
#else
#ifndef CORRADE_GCC46_COMPATIBILITY
template<class U, class V = typename std::enable_if<std::is_same<T, U>::value && size != 1, T>::type> inline constexpr explicit Vector(U value): Vector(typename Implementation::GenerateSequence<size>::Type(), value) {}
template<class U, class V = typename std::enable_if<std::is_same<T, U>::value && size != 1, T>::type> constexpr explicit Vector(U value): Vector(typename Implementation::GenerateSequence<size>::Type(), value) {}
#else
template<class U, class V = typename std::enable_if<std::is_same<T, U>::value && size != 1, T>::type> inline explicit Vector(U value) {
template<class U, class V = typename std::enable_if<std::is_same<T, U>::value && size != 1, T>::type> explicit Vector(U value) {
*this = Vector(typename Implementation::GenerateSequence<size>::Type(), value);
}
#endif
@ -154,30 +150,30 @@ template<std::size_t size, class T> class Vector {
* @endcode
*/
#ifndef CORRADE_GCC46_COMPATIBILITY
template<class U> inline constexpr explicit Vector(const Vector<size, U>& other): Vector(typename Implementation::GenerateSequence<size>::Type(), other) {}
template<class U> constexpr explicit Vector(const Vector<size, U>& other): Vector(typename Implementation::GenerateSequence<size>::Type(), other) {}
#else
template<class U> inline explicit Vector(const Vector<size, U>& other) {
template<class U> explicit Vector(const Vector<size, U>& other) {
*this = Vector(typename Implementation::GenerateSequence<size>::Type(), other);
}
#endif
/** @brief Construct vector from external representation */
#ifndef CORRADE_GCC46_COMPATIBILITY
template<class U, class V = decltype(Implementation::VectorConverter<size, T, U>::from(std::declval<U>()))> inline constexpr explicit Vector(const U& other): Vector(Implementation::VectorConverter<size, T, U>::from(other)) {}
template<class U, class V = decltype(Implementation::VectorConverter<size, T, U>::from(std::declval<U>()))> constexpr explicit Vector(const U& other): Vector(Implementation::VectorConverter<size, T, U>::from(other)) {}
#else
template<class U, class V = decltype(Implementation::VectorConverter<size, T, U>::from(std::declval<U>()))> inline explicit Vector(const U& other) {
template<class U, class V = decltype(Implementation::VectorConverter<size, T, U>::from(std::declval<U>()))> explicit Vector(const U& other) {
*this = Implementation::VectorConverter<size, T, U>::from(other);
}
#endif
/** @brief Copy constructor */
inline constexpr Vector(const Vector<size, T>&) = default;
constexpr Vector(const Vector<size, T>&) = default;
/** @brief Assignment operator */
inline Vector<size, T>& operator=(const Vector<size, T>&) = default;
Vector<size, T>& operator=(const Vector<size, T>&) = default;
/** @brief Convert vector to external representation */
template<class U, class V = decltype(Implementation::VectorConverter<size, T, U>::to(std::declval<Vector<size, T>>()))> inline constexpr explicit operator U() const {
template<class U, class V = decltype(Implementation::VectorConverter<size, T, U>::to(std::declval<Vector<size, T>>()))> constexpr explicit operator U() const {
/** @bug Why this is not constexpr under GCC 4.6? */
return Implementation::VectorConverter<size, T, U>::to(*this);
}
@ -188,19 +184,19 @@ template<std::size_t size, class T> class Vector {
*
* @see operator[]()
*/
inline T* data() { return _data; }
inline constexpr const T* data() const { return _data; } /**< @overload */
T* data() { return _data; }
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 */
T& operator[](std::size_t pos) { return _data[pos]; }
constexpr T operator[](std::size_t pos) const { return _data[pos]; } /**< @overload */
/** @brief Equality comparison */
inline bool operator==(const Vector<size, T>& other) const {
bool operator==(const Vector<size, T>& other) const {
for(std::size_t i = 0; i != size; ++i)
if(!TypeTraits<T>::equals(_data[i], other._data[i])) return false;
@ -208,49 +204,21 @@ template<std::size_t size, class T> class Vector {
}
/** @brief Non-equality comparison */
inline bool operator!=(const Vector<size, T>& other) const {
bool operator!=(const Vector<size, T>& other) const {
return !operator==(other);
}
/** @brief Component-wise less than */
inline BoolVector<size> operator<(const Vector<size, T>& other) const {
BoolVector<size> out;
for(std::size_t i = 0; i != size; ++i)
out.set(i, _data[i] < other._data[i]);
return out;
}
BoolVector<size> operator<(const Vector<size, T>& other) const;
/** @brief Component-wise less than or equal */
inline BoolVector<size> operator<=(const Vector<size, T>& other) const {
BoolVector<size> out;
for(std::size_t i = 0; i != size; ++i)
out.set(i, _data[i] <= other._data[i]);
return out;
}
BoolVector<size> operator<=(const Vector<size, T>& other) const;
/** @brief Component-wise greater than or equal */
inline BoolVector<size> operator>=(const Vector<size, T>& other) const {
BoolVector<size> out;
for(std::size_t i = 0; i != size; ++i)
out.set(i, _data[i] >= other._data[i]);
return out;
}
BoolVector<size> operator>=(const Vector<size, T>& other) const;
/** @brief Component-wise greater than */
inline BoolVector<size> operator>(const Vector<size, T>& other) const {
BoolVector<size> out;
for(std::size_t i = 0; i != size; ++i)
out.set(i, _data[i] > other._data[i]);
return out;
}
BoolVector<size> operator>(const Vector<size, T>& other) const;
/**
* @brief Whether the vector is normalized
@ -260,26 +228,19 @@ template<std::size_t size, class T> class Vector {
* @f]
* @see dot(), normalized()
*/
inline bool isNormalized() const {
bool isNormalized() const {
return Implementation::isNormalizedSquared(dot());
}
/**
* @brief Negated vector
*
* The computation is done in-place. @f[
* \boldsymbol a_i = -\boldsymbol a_i
* @f[
* \boldsymbol b_i = -\boldsymbol a_i
* @f]
* @see Vector2::perpendicular()
*/
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;
}
Vector<size, T> operator-() const;
/**
* @brief Add and assign vector
@ -300,7 +261,7 @@ template<std::size_t size, class T> class Vector {
*
* @see operator+=(), sum()
*/
inline Vector<size, T> operator+(const Vector<size, T>& other) const {
Vector<size, T> operator+(const Vector<size, T>& other) const {
return Vector<size, T>(*this) += other;
}
@ -323,7 +284,7 @@ template<std::size_t size, class T> class Vector {
*
* @see operator-=()
*/
inline Vector<size, T> operator-(const Vector<size, T>& other) const {
Vector<size, T> operator-(const Vector<size, T>& other) const {
return Vector<size, T>(*this) -= other;
}
@ -337,7 +298,7 @@ template<std::size_t size, class T> class Vector {
#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) {
template<class U> 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;
@ -351,9 +312,9 @@ template<std::size_t size, class T> class Vector {
* @see operator*=(U), operator*(U, const Vector<size, T>&)
*/
#ifdef DOXYGEN_GENERATING_OUTPUT
template<class U> inline Vector<size, T> operator*(U number) const {
template<class U> 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 {
template<class U> typename std::enable_if<std::is_arithmetic<U>::value, Vector<size, T>>::type operator*(U number) const {
#endif
return Vector<size, T>(*this) *= number;
}
@ -368,7 +329,7 @@ template<std::size_t size, class T> class Vector {
#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) {
template<class U> 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;
@ -382,9 +343,9 @@ template<std::size_t size, class T> class Vector {
* @see operator/=(), operator/(U, const Vector<size, T>&)
*/
#ifdef DOXYGEN_GENERATING_OUTPUT
template<class U> inline Vector<size, T> operator/(U number) const {
template<class U> 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 {
template<class U> typename std::enable_if<std::is_arithmetic<U>::value, Vector<size, T>>::type operator/(U number) const {
#endif
return Vector<size, T>(*this) /= number;
}
@ -408,7 +369,7 @@ template<std::size_t size, class T> class Vector {
*
* @see operator*=(const Vector<size, U>&), product()
*/
template<class U> inline Vector<size, T> operator*(const Vector<size, U>& other) const {
template<class U> Vector<size, T> operator*(const Vector<size, U>& other) const {
return Vector<size, T>(*this) *= other;
}
@ -431,7 +392,7 @@ template<std::size_t size, class T> class Vector {
*
* @see operator/=(const Vector<size, U>&)
*/
template<class U> inline Vector<size, T> operator/(const Vector<size, U>& other) const {
template<class U> Vector<size, T> operator/(const Vector<size, U>& other) const {
return Vector<size, T>(*this) /= other;
}
@ -444,9 +405,7 @@ template<std::size_t size, class T> class Vector {
* @f]
* @see dot(const Vector&, const Vector&), isNormalized()
*/
inline T dot() const {
return dot(*this, *this);
}
T dot() const { return dot(*this, *this); }
/**
* @brief %Vector length
@ -458,9 +417,7 @@ template<std::size_t size, class T> class Vector {
* @see lengthInverted(), Math::sqrt(), normalized(), resized()
* @todo something like std::hypot() for possibly better precision?
*/
inline T length() const {
return std::sqrt(dot());
}
T length() const { return std::sqrt(dot()); }
/**
* @brief Inverse vector length
@ -470,18 +427,14 @@ template<std::size_t size, class T> class Vector {
* @f]
* @see length(), Math::sqrtInverted(), normalized(), resized()
*/
inline T lengthInverted() const {
return T(1)/length();
}
T lengthInverted() const { return T(1)/length(); }
/**
* @brief Normalized vector (of unit length)
*
* @see isNormalized(), lengthInverted(), resized()
*/
inline Vector<size, T> normalized() const {
return *this*lengthInverted();
}
Vector<size, T> normalized() const { return *this*lengthInverted(); }
/**
* @brief Resized vector
@ -494,7 +447,7 @@ template<std::size_t size, class T> class Vector {
* @endcode
* @see normalized()
*/
inline Vector<size, T> resized(T length) const {
Vector<size, T> resized(T length) const {
return *this*(lengthInverted()*length);
}
@ -506,7 +459,7 @@ template<std::size_t size, class T> class Vector {
* @f]
* @see dot(), projectedOntoNormalized()
*/
inline Vector<size, T> projected(const Vector<size, T>& line) const {
Vector<size, T> projected(const Vector<size, T>& line) const {
return line*dot(*this, line)/line.dot();
}
@ -520,73 +473,42 @@ template<std::size_t size, class T> class Vector {
* @f]
* @see dot()
*/
inline Vector<size, T> projectedOntoNormalized(const Vector<size, T>& line) const {
CORRADE_ASSERT(line.isNormalized(), "Math::Vector::projectedOntoNormalized(): line must be normalized", (Vector<size, T>(std::numeric_limits<T>::quiet_NaN())));
return line*dot(*this, line);
}
Vector<size, T> projectedOntoNormalized(const Vector<size, T>& line) const;
/**
* @brief Sum of values in the vector
*
* @see operator+()
*/
T sum() const {
T out(_data[0]);
for(std::size_t i = 1; i != size; ++i)
out += _data[i];
return out;
}
T sum() const;
/**
* @brief Product of values in the vector
*
* @see operator*(const Vector&)
*/
T product() const {
T out(_data[0]);
for(std::size_t i = 1; i != size; ++i)
out *= _data[i];
return out;
}
T product() const;
/**
* @brief Minimal value in the vector
*
* @see Math::min()
*/
T min() const {
T out(_data[0]);
for(std::size_t i = 1; i != size; ++i)
out = std::min(out, _data[i]);
return out;
}
T min() const;
/**
* @brief Maximal value in the vector
*
* @see Math::max()
*/
T max() const {
T out(_data[0]);
for(std::size_t i = 1; i != size; ++i)
out = std::max(out, _data[i]);
return out;
}
T max() const;
private:
/* Implementation for Vector<size, T>::Vector(const Vector<size, U>&) */
template<class U, std::size_t ...sequence> inline constexpr explicit Vector(Implementation::Sequence<sequence...>, const Vector<sizeof...(sequence), U>& vector): _data{T(vector._data[sequence])...} {}
template<class U, std::size_t ...sequence> constexpr explicit Vector(Implementation::Sequence<sequence...>, const Vector<sizeof...(sequence), U>& vector): _data{T(vector._data[sequence])...} {}
/* Implementation for Vector<size, T>::Vector(U) */
template<std::size_t ...sequence> inline constexpr explicit Vector(Implementation::Sequence<sequence...>, T value): _data{Implementation::repeat(value, sequence)...} {}
template<std::size_t ...sequence> constexpr explicit Vector(Implementation::Sequence<sequence...>, T value): _data{Implementation::repeat(value, sequence)...} {}
T _data[size];
};
@ -658,71 +580,71 @@ extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utilit
#ifndef DOXYGEN_GENERATING_OUTPUT
#define MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(Type, size) \
inline constexpr static Type<T>& from(T* data) { \
constexpr static Type<T>& from(T* data) { \
return *reinterpret_cast<Type<T>*>(data); \
} \
inline constexpr static const Type<T>& from(const T* data) { \
constexpr static const Type<T>& from(const T* data) { \
return *reinterpret_cast<const Type<T>*>(data); \
} \
\
inline Type<T>& operator=(const Type<T>& other) { \
Type<T>& operator=(const Type<T>& other) { \
Math::Vector<size, T>::operator=(other); \
return *this; \
} \
\
inline Type<T> operator-() const { \
Type<T> operator-() const { \
return Math::Vector<size, T>::operator-(); \
} \
inline Type<T>& operator+=(const Math::Vector<size, T>& other) { \
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 { \
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) { \
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 { \
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) { \
template<class U> 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 { \
template<class U> 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) { \
template<class U> 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 { \
template<class U> 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) { \
template<class U> 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 { \
template<class U> 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) { \
template<class U> 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 { \
template<class U> Type<T> operator/(const Math::Vector<size, U>& other) const { \
return Math::Vector<size, T>::operator/(other); \
} \
\
inline Type<T> normalized() const { \
Type<T> normalized() const { \
return Math::Vector<size, T>::normalized(); \
} \
inline Type<T> resized(T length) const { \
Type<T> resized(T length) const { \
return Math::Vector<size, T>::resized(length); \
} \
inline Type<T> projected(const Math::Vector<size, T>& other) const { \
Type<T> projected(const Math::Vector<size, T>& other) const { \
return Math::Vector<size, T>::projected(other); \
}
@ -735,6 +657,99 @@ extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utilit
}
#endif
template<std::size_t size, class T> inline Rad<T> Vector<size, T>::angle(const Vector<size, T>& normalizedA, const Vector<size, T>& normalizedB) {
CORRADE_ASSERT(normalizedA.isNormalized() && normalizedB.isNormalized(),
"Math::Vector::angle(): vectors must be normalized", Rad<T>(std::numeric_limits<T>::quiet_NaN()));
return Rad<T>(std::acos(dot(normalizedA, normalizedB)));
}
template<std::size_t size, class T> inline BoolVector<size> Vector<size, T>::operator<(const Vector<size, T>& other) const {
BoolVector<size> out;
for(std::size_t i = 0; i != size; ++i)
out.set(i, _data[i] < other._data[i]);
return out;
}
template<std::size_t size, class T> inline BoolVector<size> Vector<size, T>::operator<=(const Vector<size, T>& other) const {
BoolVector<size> out;
for(std::size_t i = 0; i != size; ++i)
out.set(i, _data[i] <= other._data[i]);
return out;
}
template<std::size_t size, class T> inline BoolVector<size> Vector<size, T>::operator>=(const Vector<size, T>& other) const {
BoolVector<size> out;
for(std::size_t i = 0; i != size; ++i)
out.set(i, _data[i] >= other._data[i]);
return out;
}
template<std::size_t size, class T> inline BoolVector<size> Vector<size, T>::operator>(const Vector<size, T>& other) const {
BoolVector<size> out;
for(std::size_t i = 0; i != size; ++i)
out.set(i, _data[i] > other._data[i]);
return out;
}
template<std::size_t size, class T> inline Vector<size, T> 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;
}
template<std::size_t size, class T> inline Vector<size, T> Vector<size, T>::projectedOntoNormalized(const Vector<size, T>& line) const {
CORRADE_ASSERT(line.isNormalized(), "Math::Vector::projectedOntoNormalized(): line must be normalized",
(Vector<size, T>(std::numeric_limits<T>::quiet_NaN())));
return line*dot(*this, line);
}
template<std::size_t size, class T> inline T Vector<size, T>::sum() const {
T out(_data[0]);
for(std::size_t i = 1; i != size; ++i)
out += _data[i];
return out;
}
template<std::size_t size, class T> inline T Vector<size, T>::product() const {
T out(_data[0]);
for(std::size_t i = 1; i != size; ++i)
out *= _data[i];
return out;
}
template<std::size_t size, class T> inline T Vector<size, T>::min() const {
T out(_data[0]);
for(std::size_t i = 1; i != size; ++i)
out = std::min(out, _data[i]);
return out;
}
template<std::size_t size, class T> inline T Vector<size, T>::max() const {
T out(_data[0]);
for(std::size_t i = 1; i != size; ++i)
out = std::max(out, _data[i]);
return out;
}
}}
namespace Corrade { namespace Utility {

32
src/Math/Vector2.h

@ -51,7 +51,7 @@ template<class T> class Vector2: public Vector<2, T> {
* @endcode
* @see yAxis(), xScale(), Matrix3::right()
*/
inline constexpr static Vector2<T> xAxis(T length = T(1)) { return Vector2<T>(length, T()); }
constexpr static Vector2<T> xAxis(T length = T(1)) { return Vector2<T>(length, T()); }
/**
* @brief %Vector in direction of Y axis (up)
@ -59,7 +59,7 @@ template<class T> class Vector2: public Vector<2, T> {
* See xAxis() for more information.
* @see yScale(), Matrix3::up()
*/
inline constexpr static Vector2<T> yAxis(T length = T(1)) { return Vector2<T>(T(), length); }
constexpr static Vector2<T> yAxis(T length = T(1)) { return Vector2<T>(T(), length); }
/**
* @brief Scaling vector in direction of X axis (width)
@ -70,7 +70,7 @@ template<class T> class Vector2: public Vector<2, T> {
* @endcode
* @see yScale(), xAxis()
*/
inline constexpr static Vector2<T> xScale(T scale) { return Vector2<T>(scale, T(1)); }
constexpr static Vector2<T> xScale(T scale) { return Vector2<T>(scale, T(1)); }
/**
* @brief Scaling vector in direction of Y axis (height)
@ -78,7 +78,7 @@ template<class T> class Vector2: public Vector<2, T> {
* See xScale() for more information.
* @see yAxis()
*/
inline constexpr static Vector2<T> yScale(T scale) { return Vector2<T>(T(1), scale); }
constexpr static Vector2<T> yScale(T scale) { return Vector2<T>(T(1), scale); }
/**
* @brief 2D cross product
@ -91,15 +91,15 @@ template<class T> class Vector2: public Vector<2, T> {
* @f]
* @see perpendicular(), dot(const Vector&, const Vector&)
*/
inline static T cross(const Vector2<T>& a, const Vector2<T>& b) {
static T cross(const Vector2<T>& a, const Vector2<T>& b) {
return Vector<2, T>::dot(a.perpendicular(), b);
}
/** @copydoc Vector::Vector() */
inline constexpr /*implicit*/ Vector2() {}
constexpr /*implicit*/ Vector2() {}
/** @copydoc Vector::Vector(T) */
inline constexpr explicit Vector2(T value): Vector<2, T>(value) {}
constexpr explicit Vector2(T value): Vector<2, T>(value) {}
/**
* @brief Constructor
@ -108,21 +108,21 @@ template<class T> class Vector2: public Vector<2, T> {
* \boldsymbol v = \begin{pmatrix} x \\ y \end{pmatrix}
* @f]
*/
inline constexpr /*implicit*/ Vector2(T x, T y): Vector<2, T>(x, y) {}
constexpr /*implicit*/ Vector2(T x, T y): Vector<2, T>(x, y) {}
/** @copydoc Vector::Vector(const Vector<size, U>&) */
template<class U> inline constexpr explicit Vector2(const Vector<2, U>& other): Vector<2, T>(other) {}
template<class U> constexpr explicit Vector2(const Vector<2, U>& other): Vector<2, T>(other) {}
/** @brief Construct vector from external representation */
template<class U, class V = decltype(Implementation::VectorConverter<2, T, U>::from(std::declval<U>()))> inline constexpr explicit Vector2(const U& other): Vector<2, T>(Implementation::VectorConverter<2, T, U>::from(other)) {}
template<class U, class V = decltype(Implementation::VectorConverter<2, T, U>::from(std::declval<U>()))> constexpr explicit Vector2(const U& other): Vector<2, T>(Implementation::VectorConverter<2, T, U>::from(other)) {}
/** @brief Copy constructor */
inline constexpr Vector2(const Vector<2, T>& other): Vector<2, T>(other) {}
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 */
inline T& y() { return (*this)[1]; } /**< @brief Y component */
inline constexpr T y() const { return (*this)[1]; } /**< @overload */
T& x() { return (*this)[0]; } /**< @brief X component */
constexpr T x() const { return (*this)[0]; } /**< @overload */
T& y() { return (*this)[1]; } /**< @brief Y component */
constexpr T y() const { return (*this)[1]; } /**< @overload */
/**
* @brief Perpendicular vector
@ -132,7 +132,7 @@ template<class T> class Vector2: public Vector<2, T> {
* @f]
* @see cross(), dot(const Vector&, const Vector&), operator-() const
*/
inline Vector2<T> perpendicular() const { return {-y(), x()}; }
Vector2<T> perpendicular() const { return {-y(), x()}; }
MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(Vector2, 2)
};

44
src/Math/Vector3.h

@ -53,7 +53,7 @@ template<class T> class Vector3: public Vector<3, T> {
* @endcode
* @see yAxis(), zAxis(), xScale(), Matrix4::right()
*/
inline constexpr static Vector3<T> xAxis(T length = T(1)) { return Vector3<T>(length, T(), T()); }
constexpr static Vector3<T> xAxis(T length = T(1)) { return Vector3<T>(length, T(), T()); }
/**
* @brief %Vector in direction of Y axis (up)
@ -61,7 +61,7 @@ template<class T> class Vector3: public Vector<3, T> {
* See xAxis() for more information.
* @see yScale(), Matrix4::up()
*/
inline constexpr static Vector3<T> yAxis(T length = T(1)) { return Vector3<T>(T(), length, T()); }
constexpr static Vector3<T> yAxis(T length = T(1)) { return Vector3<T>(T(), length, T()); }
/**
* @brief %Vector in direction of Z axis (backward)
@ -69,7 +69,7 @@ template<class T> class Vector3: public Vector<3, T> {
* See xAxis() for more information.
* @see zScale(), Matrix4::backward()
*/
inline constexpr static Vector3<T> zAxis(T length = T(1)) { return Vector3<T>(T(), T(), length); }
constexpr static Vector3<T> zAxis(T length = T(1)) { return Vector3<T>(T(), T(), length); }
/**
* @brief Scaling vector in direction of X axis (width)
@ -80,7 +80,7 @@ template<class T> class Vector3: public Vector<3, T> {
* @endcode
* @see yScale(), zScale(), xAxis()
*/
inline constexpr static Vector3<T> xScale(T scale) { return Vector3<T>(scale, T(1), T(1)); }
constexpr static Vector3<T> xScale(T scale) { return Vector3<T>(scale, T(1), T(1)); }
/**
* @brief Scaling vector in direction of Y axis (height)
@ -88,7 +88,7 @@ template<class T> class Vector3: public Vector<3, T> {
* See xScale() for more information.
* @see yAxis()
*/
inline constexpr static Vector3<T> yScale(T scale) { return Vector3<T>(T(1), scale, T(1)); }
constexpr static Vector3<T> yScale(T scale) { return Vector3<T>(T(1), scale, T(1)); }
/**
* @brief Scaling vector in direction of Z axis (depth)
@ -96,7 +96,7 @@ template<class T> class Vector3: public Vector<3, T> {
* See xScale() for more information.
* @see zAxis()
*/
inline constexpr static Vector3<T> zScale(T scale) { return Vector3<T>(T(1), T(1), scale); }
constexpr static Vector3<T> zScale(T scale) { return Vector3<T>(T(1), T(1), scale); }
/**
* @brief Cross product
@ -107,16 +107,16 @@ template<class T> class Vector3: public Vector<3, T> {
* @f]
* @see Vector2::cross()
*/
inline static Vector3<T> cross(const Vector3<T>& a, const Vector3<T>& b) {
static Vector3<T> cross(const Vector3<T>& a, const Vector3<T>& b) {
return swizzle<'y', 'z', 'x'>(a)*swizzle<'z', 'x', 'y'>(b) -
swizzle<'z', 'x', 'y'>(a)*swizzle<'y', 'z', 'x'>(b);
}
/** @copydoc Vector::Vector() */
inline constexpr /*implicit*/ Vector3() {}
constexpr /*implicit*/ Vector3() {}
/** @copydoc Vector::Vector(T) */
inline constexpr explicit Vector3(T value): Vector<3, T>(value) {}
constexpr explicit Vector3(T value): Vector<3, T>(value) {}
/**
* @brief Constructor
@ -125,7 +125,7 @@ template<class T> class Vector3: public Vector<3, T> {
* \boldsymbol v = \begin{pmatrix} x \\ y \\ z \end{pmatrix}
* @f]
*/
inline constexpr /*implicit*/ Vector3(T x, T y, T z): Vector<3, T>(x, y, z) {}
constexpr /*implicit*/ Vector3(T x, T y, T z): Vector<3, T>(x, y, z) {}
/**
* @brief Constructor
@ -134,23 +134,23 @@ template<class T> class Vector3: public Vector<3, T> {
* \boldsymbol v = \begin{pmatrix} v_x \\ v_y \\ z \end{pmatrix}
* @f]
*/
inline constexpr /*implicit*/ Vector3(const Vector2<T>& xy, T z): Vector<3, T>(xy[0], xy[1], z) {}
constexpr /*implicit*/ Vector3(const Vector2<T>& xy, T z): Vector<3, T>(xy[0], xy[1], z) {}
/** @copydoc Vector::Vector(const Vector<size, U>&) */
template<class U> inline constexpr explicit Vector3(const Vector<3, U>& other): Vector<3, T>(other) {}
template<class U> constexpr explicit Vector3(const Vector<3, U>& other): Vector<3, T>(other) {}
/** @brief Construct vector from external representation */
template<class U, class V = decltype(Implementation::VectorConverter<3, T, U>::from(std::declval<U>()))> inline constexpr explicit Vector3(const U& other): Vector<3, T>(Implementation::VectorConverter<3, T, U>::from(other)) {}
template<class U, class V = decltype(Implementation::VectorConverter<3, T, U>::from(std::declval<U>()))> constexpr explicit Vector3(const U& other): Vector<3, T>(Implementation::VectorConverter<3, T, U>::from(other)) {}
/** @brief Copy constructor */
inline constexpr Vector3(const Vector<3, T>& other): Vector<3, T>(other) {}
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 */
inline T& y() { return (*this)[1]; } /**< @brief Y component */
inline constexpr T y() const { return (*this)[1]; } /**< @overload */
inline T& z() { return (*this)[2]; } /**< @brief Z component */
inline constexpr T z() const { return (*this)[2]; } /**< @overload */
T& x() { return (*this)[0]; } /**< @brief X component */
constexpr T x() const { return (*this)[0]; } /**< @overload */
T& y() { return (*this)[1]; } /**< @brief Y component */
constexpr T y() const { return (*this)[1]; } /**< @overload */
T& z() { return (*this)[2]; } /**< @brief Z component */
constexpr T z() const { return (*this)[2]; } /**< @overload */
/**
* @brief XY part of the vector
@ -158,8 +158,8 @@ template<class T> class Vector3: public Vector<3, T> {
*
* @see swizzle()
*/
inline Vector2<T>& xy() { return Vector2<T>::from(Vector<3, T>::data()); }
inline constexpr const Vector2<T> xy() const { return {x(), y()}; } /**< @overload */
Vector2<T>& xy() { return Vector2<T>::from(Vector<3, T>::data()); }
constexpr const Vector2<T> xy() const { return {x(), y()}; } /**< @overload */
MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(Vector3, 3)
};

38
src/Math/Vector4.h

@ -43,10 +43,10 @@ See @ref matrix-vector for brief introduction.
template<class T> class Vector4: public Vector<4, T> {
public:
/** @copydoc Vector::Vector() */
inline constexpr /*implicit*/ Vector4() {}
constexpr /*implicit*/ Vector4() {}
/** @copydoc Vector::Vector(T) */
inline constexpr explicit Vector4(T value): Vector<4, T>(value) {}
constexpr explicit Vector4(T value): Vector<4, T>(value) {}
/**
* @brief Constructor
@ -55,7 +55,7 @@ template<class T> class Vector4: public Vector<4, T> {
* \boldsymbol v = \begin{pmatrix} x \\ y \\ z \\ w \end{pmatrix}
* @f]
*/
inline constexpr /*implicit*/ Vector4(T x, T y, T z, T w): Vector<4, T>(x, y, z, w) {}
constexpr /*implicit*/ Vector4(T x, T y, T z, T w): Vector<4, T>(x, y, z, w) {}
/**
* @brief Constructor
@ -64,25 +64,25 @@ template<class T> class Vector4: public Vector<4, T> {
* \boldsymbol v = \begin{pmatrix} v_x \\ v_y \\ v_z \\ w \end{pmatrix}
* @f]
*/
inline constexpr /*implicit*/ Vector4(const Vector3<T>& xyz, T w): Vector<4, T>(xyz[0], xyz[1], xyz[2], w) {}
constexpr /*implicit*/ Vector4(const Vector3<T>& xyz, T w): Vector<4, T>(xyz[0], xyz[1], xyz[2], w) {}
/** @copydoc Vector::Vector(const Vector<size, U>&) */
template<class U> inline constexpr explicit Vector4(const Vector<4, U>& other): Vector<4, T>(other) {}
template<class U> constexpr explicit Vector4(const Vector<4, U>& other): Vector<4, T>(other) {}
/** @brief Construct vector from external representation */
template<class U, class V = decltype(Implementation::VectorConverter<4, T, U>::from(std::declval<U>()))> inline constexpr explicit Vector4(const U& other): Vector<4, T>(Implementation::VectorConverter<4, T, U>::from(other)) {}
template<class U, class V = decltype(Implementation::VectorConverter<4, T, U>::from(std::declval<U>()))> constexpr explicit Vector4(const U& other): Vector<4, T>(Implementation::VectorConverter<4, T, U>::from(other)) {}
/** @brief Copy constructor */
inline constexpr Vector4(const Vector<4, T>& other): Vector<4, T>(other) {}
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 */
inline T& y() { return (*this)[1]; } /**< @brief Y component */
inline constexpr T y() const { return (*this)[1]; } /**< @overload */
inline T& z() { return (*this)[2]; } /**< @brief Z component */
inline constexpr T z() const { return (*this)[2]; } /**< @overload */
inline T& w() { return (*this)[3]; } /**< @brief W component */
inline constexpr T w() const { return (*this)[3]; } /**< @overload */
T& x() { return (*this)[0]; } /**< @brief X component */
constexpr T x() const { return (*this)[0]; } /**< @overload */
T& y() { return (*this)[1]; } /**< @brief Y component */
constexpr T y() const { return (*this)[1]; } /**< @overload */
T& z() { return (*this)[2]; } /**< @brief Z component */
constexpr T z() const { return (*this)[2]; } /**< @overload */
T& w() { return (*this)[3]; } /**< @brief W component */
constexpr T w() const { return (*this)[3]; } /**< @overload */
/**
* @brief XYZ part of the vector
@ -90,8 +90,8 @@ template<class T> class Vector4: public Vector<4, T> {
*
* @see swizzle()
*/
inline Vector3<T>& xyz() { return Vector3<T>::from(Vector<4, T>::data()); }
inline constexpr const Vector3<T> xyz() const { return {x(), y(), z()}; } /**< @overload */
Vector3<T>& xyz() { return Vector3<T>::from(Vector<4, T>::data()); }
constexpr const Vector3<T> xyz() const { return {x(), y(), z()}; } /**< @overload */
/**
* @brief XY part of the vector
@ -99,8 +99,8 @@ template<class T> class Vector4: public Vector<4, T> {
*
* @see swizzle()
*/
inline Vector2<T>& xy() { return Vector2<T>::from(Vector<4, T>::data()); }
inline constexpr const Vector2<T> xy() const { return {x(), y()}; } /**< @overload */
Vector2<T>& xy() { return Vector2<T>::from(Vector<4, T>::data()); }
constexpr const Vector2<T> xy() const { return {x(), y()}; } /**< @overload */
MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(Vector4, 4)
};

Loading…
Cancel
Save