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<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 #ifndef MAGNUM_TARGET_GLES
template<> inline constexpr Double smallestDelta<Double>() { return 1.0e-64; } template<> constexpr Double smallestDelta<Double>() { return 1.0e-64; }
#endif #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> { template<class T> class Deg: public Unit<Deg, T> {
public: public:
/** @brief Default constructor */ /** @brief Default constructor */
inline constexpr /*implicit*/ Deg() {} constexpr /*implicit*/ Deg() {}
/** @brief Explicit constructor from unitless type */ /** @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 */ /** @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 */ /** @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 * @brief Construct degrees from radians
@ -143,7 +143,7 @@ template<class T> class Deg: public Unit<Deg, T> {
* deg = 180 \frac {rad} \pi * deg = 180 \frac {rad} \pi
* @f] * @f]
*/ */
inline constexpr /*implicit*/ Deg(Unit<Rad, T> value); constexpr /*implicit*/ Deg(Unit<Rad, T> value);
}; };
#ifndef CORRADE_GCC46_COMPATIBILITY #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. @note Not available on GCC < 4.7. Use Deg::Deg(T) instead.
@requires_gl Only single-precision types are available in OpenGL ES. @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 #endif
/** @relates Deg /** @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. @note Not available on GCC < 4.7. Use Deg::Deg(T) instead.
@requires_gl Only single-precision types are available in OpenGL ES. @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 #endif
/** /**
@ -187,16 +187,16 @@ See Deg for more information.
template<class T> class Rad: public Unit<Rad, T> { template<class T> class Rad: public Unit<Rad, T> {
public: public:
/** @brief Default constructor */ /** @brief Default constructor */
inline constexpr /*implicit*/ Rad() {} constexpr /*implicit*/ Rad() {}
/** @brief Construct from unitless type */ /** @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 */ /** @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 */ /** @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 * @brief Construct radians from degrees
@ -206,7 +206,7 @@ template<class T> class Rad: public Unit<Rad, T> {
* rad = deg \frac \pi 180 * rad = deg \frac \pi 180
* @f] * @f]
*/ */
inline constexpr /*implicit*/ Rad(Unit<Deg, T> value); constexpr /*implicit*/ Rad(Unit<Deg, T> value);
}; };
#ifndef CORRADE_GCC46_COMPATIBILITY #ifndef CORRADE_GCC46_COMPATIBILITY
@ -218,7 +218,7 @@ See operator""_rad() for more information.
@see Magnum::operator""_rad(), operator""_radf(), operator""_deg() @see Magnum::operator""_rad(), operator""_radf(), operator""_deg()
@note Not available on GCC < 4.7. Use Rad::Rad(T) instead. @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 #endif
/** @relates Rad /** @relates Rad
@ -228,11 +228,11 @@ See operator""_degf() for more information.
@see Magnum::operator""_radf(), operator""_rad(), operator""_degf() @see Magnum::operator""_radf(), operator""_rad(), operator""_degf()
@note Not available on GCC < 4.7. Use Rad::Rad(T) instead. @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 #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> 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 Rad<T>::Rad(Unit<Deg, T> value): Unit<Math::Rad, T>(T(value)*Math::Constants<T>::pi()/T(180)) {}
/** @debugoperator{Magnum::Math::Rad} */ /** @debugoperator{Magnum::Math::Rad} */
template<class T> Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Unit<Rad, T>& value) { 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 #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 */ static const std::size_t DataSize = (size-1)/8+1; /**< @brief %Vector storage size */
/** @brief Construct zero-filled boolean vector */ /** @brief Construct zero-filled boolean vector */
inline constexpr BoolVector(): _data() {} constexpr BoolVector(): _data() {}
/** /**
* @brief Construct boolean vector from segment values * @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 * @param next Values for next Bbit segments
*/ */
#ifdef DOXYGEN_GENERATING_OUTPUT #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 #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 #endif
/** @brief Construct boolean vector with one value for all fields */ /** @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); inline explicit BoolVector(T value);
#else #else
#ifndef CORRADE_GCC46_COMPATIBILITY #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 #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); *this = BoolVector(typename Implementation::GenerateSequence<DataSize>::Type(), value ? FullSegmentMask : 0);
} }
#endif #endif
#endif #endif
/** @brief Copy constructor */ /** @brief Copy constructor */
inline constexpr BoolVector(const BoolVector<size>&) = default; constexpr BoolVector(const BoolVector<size>&) = default;
/** @brief Copy assignment */ /** @brief Copy assignment */
inline BoolVector<size>& operator=(const BoolVector<size>&) = default; BoolVector<size>& operator=(const BoolVector<size>&) = default;
/** /**
* @brief Raw data * @brief Raw data
@ -107,84 +107,46 @@ template<std::size_t size> class BoolVector {
* *
* @see operator[](), set() * @see operator[](), set()
*/ */
inline UnsignedByte* data() { return _data; } UnsignedByte* data() { return _data; }
inline constexpr const UnsignedByte* data() const { return _data; } /**< @overload */ constexpr const UnsignedByte* data() const { return _data; } /**< @overload */
/** @brief Bit at given position */ /** @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; return (_data[i/8] >> i%8) & 0x01;
} }
/** @brief Set bit at given position */ /** @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); _data[i/8] |= ((value & 0x01) << i%8);
return *this; return *this;
} }
/** @brief Equality comparison */ /** @brief Equality comparison */
inline bool operator==(const BoolVector<size>& other) const { 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;
}
/** @brief Non-equality comparison */ /** @brief Non-equality comparison */
inline bool operator!=(const BoolVector<size>& other) const { bool operator!=(const BoolVector<size>& other) const {
return !operator==(other); return !operator==(other);
} }
/** @brief Whether all bits are set */ /** @brief Whether all bits are set */
bool all() const { 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;
}
/** @brief Whether no bits are set */ /** @brief Whether no bits are set */
bool none() const { 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;
}
/** @brief Whether any bit is set */ /** @brief Whether any bit is set */
inline bool any() const { bool any() const { return !none(); }
return !none();
}
/** @brief Bitwise inversion */ /** @brief Bitwise inversion */
inline BoolVector<size> operator~() const { BoolVector<size> operator~() const;
BoolVector<size> out;
for(std::size_t i = 0; i != DataSize; ++i)
out._data[i] = ~_data[i];
return out;
}
/** /**
* @brief Bitwise AND and assign * @brief Bitwise AND and assign
* *
* The computation is done in-place. * 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) for(std::size_t i = 0; i != DataSize; ++i)
_data[i] &= other._data[i]; _data[i] &= other._data[i];
@ -196,7 +158,7 @@ template<std::size_t size> class BoolVector {
* *
* @see operator&=() * @see operator&=()
*/ */
inline BoolVector<size> operator&(const BoolVector<size>& other) const { BoolVector<size> operator&(const BoolVector<size>& other) const {
return BoolVector<size>(*this) &= other; return BoolVector<size>(*this) &= other;
} }
@ -205,7 +167,7 @@ template<std::size_t size> class BoolVector {
* *
* The computation is done in-place. * 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) for(std::size_t i = 0; i != DataSize; ++i)
_data[i] |= other._data[i]; _data[i] |= other._data[i];
@ -217,7 +179,7 @@ template<std::size_t size> class BoolVector {
* *
* @see operator|=() * @see operator|=()
*/ */
inline BoolVector<size> operator|(const BoolVector<size>& other) const { BoolVector<size> operator|(const BoolVector<size>& other) const {
return BoolVector<size>(*this) |= other; return BoolVector<size>(*this) |= other;
} }
@ -226,7 +188,7 @@ template<std::size_t size> class BoolVector {
* *
* The computation is done in-place. * 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) for(std::size_t i = 0; i != DataSize; ++i)
_data[i] ^= other._data[i]; _data[i] ^= other._data[i];
@ -238,7 +200,7 @@ template<std::size_t size> class BoolVector {
* *
* @see operator^=() * @see operator^=()
*/ */
inline BoolVector<size> operator^(const BoolVector<size>& other) const { BoolVector<size> operator^(const BoolVector<size>& other) const {
return BoolVector<size>(*this) ^= other; return BoolVector<size>(*this) ^= other;
} }
@ -249,7 +211,7 @@ template<std::size_t size> class BoolVector {
}; };
/* Implementation for Vector<size, T>::Vector(U) */ /* 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]; UnsignedByte _data[(size-1)/8+1];
}; };
@ -267,6 +229,50 @@ template<std::size_t size> Corrade::Utility::Debug operator<<(Corrade::Utility::
return debug; 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 #endif

64
src/Math/Complex.h

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

18
src/Math/Constants.h

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

42
src/Math/Dual.h

@ -50,7 +50,7 @@ template<class T> class Dual {
* *
* Both parts are default-constructed. * 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 * @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 * \hat a = a_0 + \epsilon a_\epsilon
* @f] * @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 */ /** @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) && return TypeTraits<T>::equals(_real, other._real) &&
TypeTraits<T>::equals(_dual, other._dual); TypeTraits<T>::equals(_dual, other._dual);
} }
/** @brief Non-equality comparison */ /** @brief Non-equality comparison */
inline bool operator!=(const Dual<T>& other) const { bool operator!=(const Dual<T>& other) const {
return !operator==(other); return !operator==(other);
} }
/** @brief Real part */ /** @brief Real part */
inline constexpr T real() const { return _real; } constexpr T real() const { return _real; }
/** @brief %Dual part */ /** @brief %Dual part */
inline constexpr T dual() const { return _dual; } constexpr T dual() const { return _dual; }
/** /**
* @brief Add and assign dual number * @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) * \hat a + \hat b = a_0 + b_0 + \epsilon (a_\epsilon + b_\epsilon)
* @f] * @f]
*/ */
inline Dual<T>& operator+=(const Dual<T>& other) { Dual<T>& operator+=(const Dual<T>& other) {
_real += other._real; _real += other._real;
_dual += other._dual; _dual += other._dual;
return *this; return *this;
@ -96,7 +96,7 @@ template<class T> class Dual {
* *
* @see operator+=() * @see operator+=()
*/ */
inline Dual<T> operator+(const Dual<T>& other) const { Dual<T> operator+(const Dual<T>& other) const {
return Dual<T>(*this)+=other; return Dual<T>(*this)+=other;
} }
@ -107,7 +107,7 @@ template<class T> class Dual {
* -\hat a = -a_0 - \epsilon a_\epsilon * -\hat a = -a_0 - \epsilon a_\epsilon
* @f] * @f]
*/ */
inline Dual<T> operator-() const { Dual<T> operator-() const {
return {-_real, -_dual}; 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) * \hat a - \hat b = a_0 - b_0 + \epsilon (a_\epsilon - b_\epsilon)
* @f] * @f]
*/ */
inline Dual<T>& operator-=(const Dual<T>& other) { Dual<T>& operator-=(const Dual<T>& other) {
_real -= other._real; _real -= other._real;
_dual -= other._dual; _dual -= other._dual;
return *this; return *this;
@ -129,7 +129,7 @@ template<class T> class Dual {
* *
* @see operator-=() * @see operator-=()
*/ */
inline Dual<T> operator-(const Dual<T>& other) const { Dual<T> operator-(const Dual<T>& other) const {
return Dual<T>(*this)-=other; 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) * \hat a \hat b = a_0 b_0 + \epsilon (a_0 b_\epsilon + a_\epsilon b_0)
* @f] * @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}; 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} * \frac{\hat a}{\hat b} = \frac{a_0}{b_0} + \epsilon \frac{a_\epsilon b_0 - a_0 b_\epsilon}{b_0^2}
* @f] * @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)}; 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 * \overline{\hat a} = a_0 - \epsilon a_\epsilon
* @f] * @f]
*/ */
inline Dual<T> conjugated() const { Dual<T> conjugated() const {
return {_real, -_dual}; return {_real, -_dual};
} }
@ -172,27 +172,27 @@ template<class T> class Dual {
#ifndef DOXYGEN_GENERATING_OUTPUT #ifndef DOXYGEN_GENERATING_OUTPUT
#define MAGNUM_DUAL_SUBCLASS_IMPLEMENTATION(Type, Underlying) \ #define MAGNUM_DUAL_SUBCLASS_IMPLEMENTATION(Type, Underlying) \
inline Type<T> operator-() const { \ Type<T> operator-() const { \
return Dual<Underlying<T>>::operator-(); \ 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); \ Dual<Underlying<T>>::operator+=(other); \
return *this; \ 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); \ 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); \ Dual<Underlying<T>>::operator-=(other); \
return *this; \ 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); \ 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); \ 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); \ return Dual<Underlying<T>>::operator/(other); \
} }
#endif #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(), * @see angle(), Complex::rotation(), Matrix3::rotation(),
* DualQuaternion::rotation() * DualQuaternion::rotation()
*/ */
inline static DualComplex<T> rotation(Rad<T> angle) { static DualComplex<T> rotation(Rad<T> angle) {
return {Complex<T>::rotation(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&), * @see translation() const, Matrix3::translation(const Vector2&),
* DualQuaternion::translation(), Vector2::xAxis(), Vector2::yAxis() * 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()}}; return {{}, {vector.x(), vector.y()}};
} }
@ -83,7 +83,7 @@ template<class T> class DualComplex: public Dual<Complex<T>> {
* @see toMatrix(), Complex::fromMatrix(), * @see toMatrix(), Complex::fromMatrix(),
* Matrix3::isRigidTransformation() * Matrix3::isRigidTransformation()
*/ */
inline static DualComplex<T> fromMatrix(const Matrix3<T>& matrix) { static DualComplex<T> fromMatrix(const Matrix3<T>& matrix) {
CORRADE_ASSERT(matrix.isRigidTransformation(), CORRADE_ASSERT(matrix.isRigidTransformation(),
"Math::DualComplex::fromMatrix(): the matrix doesn't represent rigid transformation", {}); "Math::DualComplex::fromMatrix(): the matrix doesn't represent rigid transformation", {});
return {Implementation::complexFromMatrix(matrix.rotationScaling()), Complex<T>(matrix.translation())}; 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 * @todoc Remove workaround when Doxygen is predictable
*/ */
#ifdef DOXYGEN_GENERATING_OUTPUT #ifdef DOXYGEN_GENERATING_OUTPUT
inline constexpr /*implicit*/ DualComplex(); constexpr /*implicit*/ DualComplex();
#else #else
inline constexpr /*implicit*/ DualComplex(): Dual<Complex<T>>({}, {T(0), T(0)}) {} constexpr /*implicit*/ DualComplex(): Dual<Complex<T>>({}, {T(0), T(0)}) {}
#endif #endif
/** /**
@ -110,7 +110,7 @@ template<class T> class DualComplex: public Dual<Complex<T>> {
* \hat c = c_0 + \epsilon c_\epsilon * \hat c = c_0 + \epsilon c_\epsilon
* @f] * @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 * @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 * @todoc Remove workaround when Doxygen is predictable
*/ */
#ifdef DOXYGEN_GENERATING_OUTPUT #ifdef DOXYGEN_GENERATING_OUTPUT
inline constexpr explicit DualComplex(const Vector2<T>& vector); constexpr explicit DualComplex(const Vector2<T>& vector);
#else #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 #endif
/** /**
@ -134,7 +134,7 @@ template<class T> class DualComplex: public Dual<Complex<T>> {
* @f] * @f]
* @see Complex::dot(), normalized() * @see Complex::dot(), normalized()
*/ */
inline bool isNormalized() const { bool isNormalized() const {
return Implementation::isNormalizedSquared(lengthSquared()); return Implementation::isNormalizedSquared(lengthSquared());
} }
@ -143,7 +143,7 @@ template<class T> class DualComplex: public Dual<Complex<T>> {
* *
* @see Complex::angle() * @see Complex::angle()
*/ */
inline constexpr Complex<T> rotation() const { constexpr Complex<T> rotation() const {
return this->real(); return this->real();
} }
@ -155,7 +155,7 @@ template<class T> class DualComplex: public Dual<Complex<T>> {
* @f] * @f]
* @see translation(const Vector2&) * @see translation(const Vector2&)
*/ */
inline Vector2<T> translation() const { Vector2<T> translation() const {
return Vector2<T>(this->dual()); return Vector2<T>(this->dual());
} }
@ -164,7 +164,7 @@ template<class T> class DualComplex: public Dual<Complex<T>> {
* *
* @see fromMatrix(), Complex::toMatrix() * @see fromMatrix(), Complex::toMatrix()
*/ */
inline Matrix3<T> toMatrix() const { Matrix3<T> toMatrix() const {
return Matrix3<T>::from(this->real().toMatrix(), translation()); return Matrix3<T>::from(this->real().toMatrix(), translation());
} }
@ -176,7 +176,7 @@ template<class T> class DualComplex: public Dual<Complex<T>> {
* @f] * @f]
* @todo can this be done similarly to dual quaternions? * @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()}; 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] * @f]
* @see dualConjugated(), conjugated(), Complex::conjugated() * @see dualConjugated(), conjugated(), Complex::conjugated()
*/ */
inline DualComplex<T> complexConjugated() const { DualComplex<T> complexConjugated() const {
return {this->real().conjugated(), this->dual().conjugated()}; return {this->real().conjugated(), this->dual().conjugated()};
} }
@ -200,7 +200,7 @@ template<class T> class DualComplex: public Dual<Complex<T>> {
* @f] * @f]
* @see complexConjugated(), conjugated(), Dual::conjugated() * @see complexConjugated(), conjugated(), Dual::conjugated()
*/ */
inline DualComplex<T> dualConjugated() const { DualComplex<T> dualConjugated() const {
return Dual<Complex<T>>::conjugated(); return Dual<Complex<T>>::conjugated();
} }
@ -213,7 +213,7 @@ template<class T> class DualComplex: public Dual<Complex<T>> {
* @see complexConjugated(), dualConjugated(), Complex::conjugated(), * @see complexConjugated(), dualConjugated(), Complex::conjugated(),
* Dual::conjugated() * Dual::conjugated()
*/ */
inline DualComplex<T> conjugated() const { DualComplex<T> conjugated() const {
return {this->real().conjugated(), {-this->dual().real(), this->dual().imaginary()}}; return {this->real().conjugated(), {-this->dual().real(), this->dual().imaginary()}};
} }
@ -226,7 +226,7 @@ template<class T> class DualComplex: public Dual<Complex<T>> {
* @f] * @f]
* @todo Can this be done similarly to dual quaternins? * @todo Can this be done similarly to dual quaternins?
*/ */
inline T lengthSquared() const { T lengthSquared() const {
return this->real().dot(); return this->real().dot();
} }
@ -239,7 +239,7 @@ template<class T> class DualComplex: public Dual<Complex<T>> {
* @f] * @f]
* @todo can this be done similarly to dual quaternions? * @todo can this be done similarly to dual quaternions?
*/ */
inline T length() const { T length() const {
return this->real().length(); return this->real().length();
} }
@ -252,7 +252,7 @@ template<class T> class DualComplex: public Dual<Complex<T>> {
* @see isNormalized() * @see isNormalized()
* @todo can this be done similarly to dual quaternions? * @todo can this be done similarly to dual quaternions?
*/ */
inline DualComplex<T> normalized() const { DualComplex<T> normalized() const {
return {this->real()/length(), this->dual()}; return {this->real()/length(), this->dual()};
} }
@ -265,7 +265,7 @@ template<class T> class DualComplex: public Dual<Complex<T>> {
* @f] * @f]
* @todo can this be done similarly to dual quaternions? * @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()); 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() * @see isNormalized(), inverted()
* @todo can this be done similarly to dual quaternions? * @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()); 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(), * @see DualComplex(const Vector2&), dual(), Matrix3::transformPoint(),
* Complex::transformVector(), DualQuaternion::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()); return Vector2<T>(((*this)*DualComplex<T>(vector)).dual());
} }
/* Verbatim copy of DUAL_SUBCLASS_IMPLEMENTATION(), as we need to hide /* Verbatim copy of DUAL_SUBCLASS_IMPLEMENTATION(), as we need to hide
Dual's operator*() and operator/() */ Dual's operator*() and operator/() */
#ifndef DOXYGEN_GENERATING_OUTPUT #ifndef DOXYGEN_GENERATING_OUTPUT
inline DualComplex<T> operator-() const { DualComplex<T> operator-() const {
return Dual<Complex<T>>::operator-(); 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); Dual<Complex<T>>::operator+=(other);
return *this; 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); 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); Dual<Complex<T>>::operator-=(other);
return *this; 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); return Dual<Complex<T>>::operator-(other);
} }
#endif #endif
private: private:
/* Used by Dual operators and dualConjugated() */ /* 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 /* Just to be sure nobody uses this, as it wouldn't probably work with
our operator*() */ 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(), * DualComplex::rotation(), Vector3::xAxis(), Vector3::yAxis(),
* Vector3::zAxis(), Vector::isNormalized() * 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)}}; 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(), * DualComplex::translation(), Vector3::xAxis(), Vector3::yAxis(),
* Vector3::zAxis() * 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)}}; return {{}, {vector/T(2), T(0)}};
} }
@ -86,7 +86,7 @@ template<class T> class DualQuaternion: public Dual<Quaternion<T>> {
* @see toMatrix(), Quaternion::fromMatrix(), * @see toMatrix(), Quaternion::fromMatrix(),
* Matrix4::isRigidTransformation() * Matrix4::isRigidTransformation()
*/ */
inline static DualQuaternion<T> fromMatrix(const Matrix4<T>& matrix) { static DualQuaternion<T> fromMatrix(const Matrix4<T>& matrix) {
CORRADE_ASSERT(matrix.isRigidTransformation(), CORRADE_ASSERT(matrix.isRigidTransformation(),
"Math::DualQuaternion::fromMatrix(): the matrix doesn't represent rigid transformation", {}); "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 * @todoc Remove workaround when Doxygen is predictable
*/ */
#ifdef DOXYGEN_GENERATING_OUTPUT #ifdef DOXYGEN_GENERATING_OUTPUT
inline constexpr /*implicit*/ DualQuaternion(); constexpr /*implicit*/ DualQuaternion();
#else #else
inline constexpr /*implicit*/ DualQuaternion(): Dual<Quaternion<T>>({}, {{}, T(0)}) {} constexpr /*implicit*/ DualQuaternion(): Dual<Quaternion<T>>({}, {{}, T(0)}) {}
#endif #endif
/** /**
@ -115,7 +115,7 @@ template<class T> class DualQuaternion: public Dual<Quaternion<T>> {
* \hat q = q_0 + \epsilon q_\epsilon * \hat q = q_0 + \epsilon q_\epsilon
* @f] * @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 * @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 * @todoc Remove workaround when Doxygen is predictable
*/ */
#ifdef DOXYGEN_GENERATING_OUTPUT #ifdef DOXYGEN_GENERATING_OUTPUT
inline constexpr explicit DualQuaternion(const Vector3<T>& vector); constexpr explicit DualQuaternion(const Vector3<T>& vector);
#else #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 #endif
/** /**
@ -140,7 +140,7 @@ template<class T> class DualQuaternion: public Dual<Quaternion<T>> {
* @f] * @f]
* @see lengthSquared(), normalized() * @see lengthSquared(), normalized()
*/ */
inline bool isNormalized() const { bool isNormalized() const {
/* Comparing dual part classically, as comparing sqrt() of it would /* Comparing dual part classically, as comparing sqrt() of it would
lead to overly strict precision */ lead to overly strict precision */
Dual<T> a = lengthSquared(); Dual<T> a = lengthSquared();
@ -153,7 +153,7 @@ template<class T> class DualQuaternion: public Dual<Quaternion<T>> {
* *
* @see Quaternion::angle(), Quaternion::axis() * @see Quaternion::angle(), Quaternion::axis()
*/ */
inline constexpr Quaternion<T> rotation() const { constexpr Quaternion<T> rotation() const {
return this->real(); return this->real();
} }
@ -165,7 +165,7 @@ template<class T> class DualQuaternion: public Dual<Quaternion<T>> {
* @f] * @f]
* @see translation(const Vector3&) * @see translation(const Vector3&)
*/ */
inline Vector3<T> translation() const { Vector3<T> translation() const {
return (this->dual()*this->real().conjugated()).vector()*T(2); return (this->dual()*this->real().conjugated()).vector()*T(2);
} }
@ -186,7 +186,7 @@ template<class T> class DualQuaternion: public Dual<Quaternion<T>> {
* @f] * @f]
* @see dualConjugated(), conjugated(), Quaternion::conjugated() * @see dualConjugated(), conjugated(), Quaternion::conjugated()
*/ */
inline DualQuaternion<T> quaternionConjugated() const { DualQuaternion<T> quaternionConjugated() const {
return {this->real().conjugated(), this->dual().conjugated()}; return {this->real().conjugated(), this->dual().conjugated()};
} }
@ -198,7 +198,7 @@ template<class T> class DualQuaternion: public Dual<Quaternion<T>> {
* @f] * @f]
* @see quaternionConjugated(), conjugated(), Dual::conjugated() * @see quaternionConjugated(), conjugated(), Dual::conjugated()
*/ */
inline DualQuaternion<T> dualConjugated() const { DualQuaternion<T> dualConjugated() const {
return Dual<Quaternion<T>>::conjugated(); return Dual<Quaternion<T>>::conjugated();
} }
@ -211,7 +211,7 @@ template<class T> class DualQuaternion: public Dual<Quaternion<T>> {
* @see quaternionConjugated(), dualConjugated(), Quaternion::conjugated(), * @see quaternionConjugated(), dualConjugated(), Quaternion::conjugated(),
* Dual::conjugated() * Dual::conjugated()
*/ */
inline DualQuaternion<T> conjugated() const { DualQuaternion<T> conjugated() const {
return {this->real().conjugated(), {this->dual().vector(), -this->dual().scalar()}}; 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) * |\hat q|^2 = \sqrt{\hat q^* \hat q}^2 = q_0 \cdot q_0 + \epsilon 2 (q_0 \cdot q_\epsilon)
* @f] * @f]
*/ */
inline Dual<T> lengthSquared() const { Dual<T> lengthSquared() const {
return {this->real().dot(), T(2)*Quaternion<T>::dot(this->real(), this->dual())}; 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|} * |\hat q| = \sqrt{\hat q^* \hat q} = |q_0| + \epsilon \frac{q_0 \cdot q_\epsilon}{|q_0|}
* @f] * @f]
*/ */
inline Dual<T> length() const { Dual<T> length() const {
return Math::sqrt(lengthSquared()); return Math::sqrt(lengthSquared());
} }
@ -244,7 +244,7 @@ template<class T> class DualQuaternion: public Dual<Quaternion<T>> {
* *
* @see isNormalized() * @see isNormalized()
*/ */
inline DualQuaternion<T> normalized() const { DualQuaternion<T> normalized() const {
return (*this)/length(); 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} * \hat q^{-1} = \frac{\hat q^*}{|\hat q|^2}
* @f] * @f]
*/ */
inline DualQuaternion<T> inverted() const { DualQuaternion<T> inverted() const {
return quaternionConjugated()/lengthSquared(); return quaternionConjugated()/lengthSquared();
} }
@ -269,7 +269,7 @@ template<class T> class DualQuaternion: public Dual<Quaternion<T>> {
* @f] * @f]
* @see isNormalized(), inverted() * @see isNormalized(), inverted()
*/ */
inline DualQuaternion<T> invertedNormalized() const { DualQuaternion<T> invertedNormalized() const {
CORRADE_ASSERT(isNormalized(), CORRADE_ASSERT(isNormalized(),
"Math::DualQuaternion::invertedNormalized(): dual quaternion must be normalized", {}); "Math::DualQuaternion::invertedNormalized(): dual quaternion must be normalized", {});
return quaternionConjugated(); return quaternionConjugated();
@ -285,7 +285,7 @@ template<class T> class DualQuaternion: public Dual<Quaternion<T>> {
* @see DualQuaternion(const Vector3&), dual(), Matrix4::transformPoint(), * @see DualQuaternion(const Vector3&), dual(), Matrix4::transformPoint(),
* Quaternion::transformVector(), DualComplex::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(); 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(), * Matrix4::transformPoint(), Quaternion::transformVectorNormalized(),
* DualComplex::transformPointNormalized() * DualComplex::transformPointNormalized()
*/ */
inline Vector3<T> transformPointNormalized(const Vector3<T>& vector) const { Vector3<T> transformPointNormalized(const Vector3<T>& vector) const {
CORRADE_ASSERT(isNormalized(), CORRADE_ASSERT(isNormalized(),
"Math::DualQuaternion::transformPointNormalized(): dual quaternion must be normalized", "Math::DualQuaternion::transformPointNormalized(): dual quaternion must be normalized",
Vector3<T>(std::numeric_limits<T>::quiet_NaN())); Vector3<T>(std::numeric_limits<T>::quiet_NaN()));
@ -311,7 +311,7 @@ template<class T> class DualQuaternion: public Dual<Quaternion<T>> {
private: private:
/* Used by Dual operators and dualConjugated() */ /* 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} */ /** @debugoperator{Magnum::Math::DualQuaternion} */

6
src/Math/Functions.h

@ -42,14 +42,14 @@ namespace Implementation {
template<UnsignedInt exponent> struct Pow { template<UnsignedInt exponent> struct Pow {
Pow() = delete; 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); return base*Pow<exponent-1>::pow(base);
} }
}; };
template<> struct Pow<0> { template<> struct Pow<0> {
Pow() = delete; 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. * 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); 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 * Source: http://mathworld.wolfram.com/Point-LineDistance2-Dimensional.html
* @see linePointSquared(const Vector2&, const Vector2&, const Vector2&) * @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; const Vector2<T> bMinusA = b - a;
return std::abs(Vector2<T>::cross(bMinusA, a - point))/bMinusA.length(); 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 * for comparing distance with other values, because it doesn't
* compute the square root. * 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; const Vector2<T> bMinusA = b - a;
return Math::pow<2>(Vector2<T>::cross(bMinusA, a - point))/bMinusA.dot(); 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 * Source: http://mathworld.wolfram.com/Point-LineDistance3-Dimensional.html
* @see linePointSquared(const Vector3&, const Vector3&, const Vector3&) * @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)); return std::sqrt(linePointSquared(a, b, point));
} }
@ -126,25 +126,7 @@ class Distance {
* *
* @see lineSegmentPointSquared() * @see lineSegmentPointSquared()
*/ */
template<class T> inline static T lineSegmentPoint(const Vector2<T>& a, const Vector2<T>& b, const Vector2<T>& point) { template<class T> 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);
}
/** /**
* @brief %Distance of point from line segment in 2D, squared * @brief %Distance of point from line segment in 2D, squared
@ -152,25 +134,7 @@ class Distance {
* More efficient than lineSegmentPoint() for comparing distance with * More efficient than lineSegmentPoint() for comparing distance with
* other values, because it doesn't compute the square root. * 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) { 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;
}
/** /**
* @brief %Dístance of point from line segment in 3D * @brief %Dístance of point from line segment in 3D
@ -183,7 +147,7 @@ class Distance {
* *
* @see lineSegmentPointSquared(const Vector3&, const Vector3&, const Vector3&) * @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)); 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 * More efficient than lineSegmentPoint(const Vector3&, const Vector3&, const Vector3&) for comparing distance with
* other values, because it doesn't compute the square root. * 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) { 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> 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 #endif

52
src/Math/Geometry/Rectangle.h

@ -51,7 +51,7 @@ template<class T> class Rectangle {
* @param bottomLeft Bottom left rectangle corner * @param bottomLeft Bottom left rectangle corner
* @param size %Rectangle size * @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}; return {bottomLeft, bottomLeft+size};
} }
@ -60,10 +60,10 @@ template<class T> class Rectangle {
* *
* Construct zero-area rectangle positioned at origin. * Construct zero-area rectangle positioned at origin.
*/ */
inline constexpr Rectangle() {} constexpr Rectangle() {}
/** @brief Construct rectangle from two corners */ /** @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 * @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}} * Rectangle<Byte> integral(floatingPoint); // {{1, 2}, {-15, 7}}
* @endcode * @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 */ /** @brief Copy constructor */
inline constexpr Rectangle(const Rectangle<T>&) = default; constexpr Rectangle(const Rectangle<T>&) = default;
/** @brief Assignment operator */ /** @brief Assignment operator */
inline Rectangle<T>& operator=(const Rectangle<T>&) = default; Rectangle<T>& operator=(const Rectangle<T>&) = default;
/** @brief Equality operator */ /** @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; return _bottomLeft == other._bottomLeft && _topRight == other._topRight;
} }
/** @brief Non-equality operator */ /** @brief Non-equality operator */
inline constexpr bool operator!=(const Rectangle<T>& other) const { constexpr bool operator!=(const Rectangle<T>& other) const {
return !operator==(other); return !operator==(other);
} }
/** @brief Bottom left corner */ /** @brief Bottom left corner */
inline Vector2<T>& bottomLeft() { return _bottomLeft; } Vector2<T>& bottomLeft() { return _bottomLeft; }
inline constexpr Vector2<T> bottomLeft() const { return _bottomLeft; } /**< @overload */ constexpr Vector2<T> bottomLeft() const { return _bottomLeft; } /**< @overload */
/** @brief Bottom right corner */ /** @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 */ /** @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 */ /** @brief Top right corner */
inline Vector2<T>& topRight() { return _topRight; } Vector2<T>& topRight() { return _topRight; }
inline constexpr Vector2<T> topRight() const { return _topRight; } /**< @overload */ constexpr Vector2<T> topRight() const { return _topRight; } /**< @overload */
/** @brief Bottom edge */ /** @brief Bottom edge */
inline T& bottom() { return _bottomLeft.y(); } T& bottom() { return _bottomLeft.y(); }
inline constexpr T bottom() const { return _bottomLeft.y(); } /**< @overload */ constexpr T bottom() const { return _bottomLeft.y(); } /**< @overload */
/** @brief Top edge */ /** @brief Top edge */
inline T& top() { return _topRight.y(); } T& top() { return _topRight.y(); }
inline constexpr T top() const { return _topRight.y(); } /**< @overload */ constexpr T top() const { return _topRight.y(); } /**< @overload */
/** @brief Left edge */ /** @brief Left edge */
inline T& left() { return _bottomLeft.x(); } T& left() { return _bottomLeft.x(); }
inline constexpr T left() const { return _bottomLeft.x(); } /**< @overload */ constexpr T left() const { return _bottomLeft.x(); } /**< @overload */
/** @brief Right edge */ /** @brief Right edge */
inline T& right() { return _topRight.x(); } T& right() { return _topRight.x(); }
inline constexpr T right() const { return _topRight.x(); } /**< @overload */ constexpr T right() const { return _topRight.x(); } /**< @overload */
/** @brief %Rectangle size */ /** @brief %Rectangle size */
inline constexpr Vector2<T> size() const { constexpr Vector2<T> size() const { return _topRight-_bottomLeft; }
return _topRight-_bottomLeft;
}
/** @brief %Rectangle width */ /** @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 */ /** @brief %Rectangle height */
inline constexpr T height() const { return _topRight.y() - _bottomLeft.y(); } constexpr T height() const { return _topRight.y() - _bottomLeft.y(); }
private: private:
Vector2<T> _bottomLeft; 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);`. * 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 */ /** @brief Pass to constructor to create identity matrix */
enum IdentityType { Identity }; 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. * you to specify value on diagonal.
* @todo use constexpr fromDiagonal() for this when it's done * @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) for(std::size_t i = 0; i != size; ++i)
(*this)[i][i] = value; (*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 first First column vector
* @param next Next column vectors * @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 * @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}} * // integral == {{1, 2}, {-15, 7}}
* @endcode * @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 */ /** @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 */ /** @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 * @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(), * @see transposed(), inverted(), Matrix3::isRigidTransformation(),
* Matrix4::isRigidTransformation() * Matrix4::isRigidTransformation()
*/ */
bool isOrthogonal() const { 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;
}
/** /**
* @brief Trace of the matrix * @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} * tr(A) = \sum_{i=1}^n a_{i,i}
* @f] * @f]
*/ */
T trace() const { T trace() const { return this->diagonal().sum(); }
return this->diagonal().sum();
}
/** @brief %Matrix without given column and row */ /** @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> ij(std::size_t skipCol, std::size_t skipRow) const;
Matrix<size-1, T> out(Matrix<size-1, T>::Zero);
for(std::size_t col = 0; col != size-1; ++col)
for(std::size_t row = 0; row != size-1; ++row)
out[col][row] = (*this)[col + (col >= skipCol)]
[row + (row >= skipRow)];
return out;
}
/** /**
* @brief Determinant * @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} * \det(A) = a_{0, 0} a_{1, 1} - a_{1, 0} a_{0, 1}
* @f] * @f]
*/ */
inline T determinant() const { return Implementation::MatrixDeterminant<size, T>()(*this); } T determinant() const { return Implementation::MatrixDeterminant<size, T>()(*this); }
/** /**
* @brief Inverted matrix * @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() * See invertedOrthogonal(), Matrix3::invertedRigid() and Matrix4::invertedRigid()
* which are faster alternatives for particular matrix types. * which are faster alternatives for particular matrix types.
*/ */
Matrix<size, T> inverted() const { 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;
}
/** /**
* @brief Inverted orthogonal matrix * @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(), * @see inverted(), isOrthogonal(), Matrix3::invertedRigid(),
* Matrix4::invertedRigid() * Matrix4::invertedRigid()
*/ */
inline Matrix<size, T> invertedOrthogonal() const { Matrix<size, T> invertedOrthogonal() const {
CORRADE_ASSERT(isOrthogonal(), CORRADE_ASSERT(isOrthogonal(),
"Math::Matrix::invertedOrthogonal(): the matrix is not orthogonal", {}); "Math::Matrix::invertedOrthogonal(): the matrix is not orthogonal", {});
return this->transposed(); return this->transposed();
@ -200,13 +167,13 @@ template<std::size_t size, class T> class Matrix: public RectangularMatrix<size,
#ifndef DOXYGEN_GENERATING_OUTPUT #ifndef DOXYGEN_GENERATING_OUTPUT
/* Reimplementation of functions to return correct type */ /* 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); 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); 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); return RectangularMatrix<size, size, T>::operator*(other);
} }
MAGNUM_RECTANGULARMATRIX_SUBCLASS_IMPLEMENTATION(size, size, Matrix<size, T>) 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 #ifndef DOXYGEN_GENERATING_OUTPUT
#define MAGNUM_MATRIX_SUBCLASS_IMPLEMENTATION(Type, VectorType, size) \ #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)); \ 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)); \ 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)); \ 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); \ 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); \ 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); \ return Matrix<size, T>::operator*(other); \
} \ } \
\ \
inline Type<T> transposed() const { return Matrix<size, T>::transposed(); } \ Type<T> transposed() const { return Matrix<size, T>::transposed(); } \
inline Type<T> inverted() const { return Matrix<size, T>::inverted(); } \ Type<T> inverted() const { return Matrix<size, T>::inverted(); } \
inline Type<T> invertedOrthogonal() const { \ Type<T> invertedOrthogonal() const { \
return Matrix<size, T>::invertedOrthogonal(); \ return Matrix<size, T>::invertedOrthogonal(); \
} }
@ -273,26 +240,28 @@ namespace Implementation {
template<std::size_t size, class T> class MatrixDeterminant { template<std::size_t size, class T> class MatrixDeterminant {
public: public:
T operator()(const Matrix<size, T>& m) { T operator()(const Matrix<size, T>& m);
T out(0); };
for(std::size_t col = 0; col != size; ++col) template<std::size_t size, class T> T MatrixDeterminant<size, T>::operator()(const Matrix<size, T>& m) {
out += ((col & 1) ? -1 : 1)*m[col][0]*m.ij(col, 0).determinant(); 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> { template<class T> class MatrixDeterminant<2, T> {
public: 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]; return m[0][0]*m[1][1] - m[1][0]*m[0][1];
} }
}; };
template<class T> class MatrixDeterminant<1, T> { template<class T> class MatrixDeterminant<1, T> {
public: public:
inline constexpr T operator()(const Matrix<1, T>& m) { constexpr T operator()(const Matrix<1, T>& m) {
return m[0][0]; return m[0][0];
} }
}; };
@ -300,6 +269,43 @@ template<class T> class MatrixDeterminant<1, T> {
} }
#endif #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 { 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(), * Matrix4::translation(const Vector3&), Vector2::xAxis(),
* Vector2::yAxis() * Vector2::yAxis()
*/ */
inline constexpr static Matrix3<T> translation(const Vector2<T>& vector) { 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)}};
}
/** /**
* @brief 2D scaling matrix * @brief 2D scaling matrix
@ -66,11 +62,7 @@ template<class T> class Matrix3: public Matrix<3, T> {
* @see rotationScaling() const, Matrix4::scaling(const Vector3&), * @see rotationScaling() const, Matrix4::scaling(const Vector3&),
* Vector2::xScale(), Vector2::yScale() * Vector2::xScale(), Vector2::yScale()
*/ */
inline constexpr static Matrix3<T> scaling(const Vector2<T>& vector) { 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)}};
}
/** /**
* @brief 2D rotation matrix * @brief 2D rotation matrix
@ -79,14 +71,7 @@ template<class T> class Matrix3: public Matrix<3, T> {
* @see rotation() const, Complex::rotation(), DualComplex::rotation(), * @see rotation() const, Complex::rotation(), DualComplex::rotation(),
* Matrix4::rotation(Rad, const Vector3&) * Matrix4::rotation(Rad, const Vector3&)
*/ */
static Matrix3<T> rotation(Rad<T> angle) { 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)}};
}
/** /**
* @brief 2D reflection matrix * @brief 2D reflection matrix
@ -120,14 +105,14 @@ template<class T> class Matrix3: public Matrix<3, T> {
* *
* @see rotationScaling() const, translation() const * @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)}, return {{rotationScaling[0], T(0)},
{rotationScaling[1], T(0)}, {rotationScaling[1], T(0)},
{ translation, T(1)}}; { translation, T(1)}};
} }
/** @copydoc Matrix::Matrix(ZeroType) */ /** @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 * @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. * @p value allows you to specify value on diagonal.
* @todo Use constexpr implementation in Matrix, when done * @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>( constexpr /*implicit*/ Matrix3(typename Matrix<3, T>::IdentityType = (Matrix<3, T>::Identity), T value = T(1));
Vector<3, T>(value, T(0), T(0)),
Vector<3, T>( T(0), value, T(0)),
Vector<3, T>( T(0), T(0), value)
) {}
/** @brief %Matrix from column vectors */ /** @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>&) */ /** @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 */ /** @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 */ /** @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 * @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). * no scaling or projection).
* @see isOrthogonal() * @see isOrthogonal()
*/ */
inline bool isRigidTransformation() const { bool isRigidTransformation() const {
return rotationScaling().isOrthogonal() && row(2) == Vector3<T>(T(0), T(0), T(1)); 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 * rotation(T), Matrix4::rotationScaling() const
* @todo extract rotation with assert for no scaling * @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(), return {(*this)[0].xy(),
(*this)[1].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 * @see rotationScaling() const, rotation(T), Matrix4::rotation() const
* @todo assert uniform scaling (otherwise this would be garbage) * @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(), return {(*this)[0].xy().normalized(),
(*this)[1].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. * First two elements of first column.
* @see up(), Vector2::xAxis(), Matrix4::right() * @see up(), Vector2::xAxis(), Matrix4::right()
*/ */
inline Vector2<T>& right() { return (*this)[0].xy(); } Vector2<T>& right() { return (*this)[0].xy(); }
inline constexpr Vector2<T> right() const { return (*this)[0].xy(); } /**< @overload */ constexpr Vector2<T> right() const { return (*this)[0].xy(); } /**< @overload */
/** /**
* @brief Up-pointing 2D vector * @brief Up-pointing 2D vector
@ -208,8 +189,8 @@ template<class T> class Matrix3: public Matrix<3, T> {
* First two elements of second column. * First two elements of second column.
* @see right(), Vector2::yAxis(), Matrix4::up() * @see right(), Vector2::yAxis(), Matrix4::up()
*/ */
inline Vector2<T>& up() { return (*this)[1].xy(); } Vector2<T>& up() { return (*this)[1].xy(); }
inline constexpr Vector2<T> up() const { return (*this)[1].xy(); } /**< @overload */ constexpr Vector2<T> up() const { return (*this)[1].xy(); } /**< @overload */
/** /**
* @brief 2D translation part of the matrix * @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&), * @see from(const Matrix<2, T>&, const Vector2&),
* translation(const Vector2&), Matrix4::translation() * translation(const Vector2&), Matrix4::translation()
*/ */
inline Vector2<T>& translation() { return (*this)[2].xy(); } Vector2<T>& translation() { return (*this)[2].xy(); }
inline constexpr Vector2<T> translation() const { return (*this)[2].xy(); } /**< @overload */ constexpr Vector2<T> translation() const { return (*this)[2].xy(); } /**< @overload */
/** /**
* @brief Inverted rigid transformation matrix * @brief Inverted rigid transformation matrix
@ -229,13 +210,7 @@ template<class T> class Matrix3: public Matrix<3, T> {
* @see isRigidTransformation(), invertedOrthogonal(), * @see isRigidTransformation(), invertedOrthogonal(),
* rotationScaling() const, translation() const * rotationScaling() const, translation() const
*/ */
inline Matrix3<T> invertedRigid() const { 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());
}
/** /**
* @brief Transform 2D vector with the matrix * @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() * @see Complex::transformVector(), Matrix4::transformVector()
* @todo extract 2x2 matrix and multiply directly? (benchmark that) * @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(); return ((*this)*Vector3<T>(vector, T(0))).xy();
} }
@ -260,7 +235,7 @@ template<class T> class Matrix3: public Matrix<3, T> {
* @f] * @f]
* @see DualComplex::transformPoint(), Matrix4::transformPoint() * @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(); 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); 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 { 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(), * Matrix3::translation(const Vector2&), Vector3::xAxis(),
* Vector3::yAxis(), Vector3::zAxis() * Vector3::yAxis(), Vector3::zAxis()
*/ */
inline constexpr static Matrix4<T> translation(const Vector3<T>& vector) { 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)}};
}
/** /**
* @brief 3D scaling * @brief 3D scaling
@ -72,12 +67,7 @@ template<class T> class Matrix4: public Matrix<4, T> {
* @see rotationScaling() const, Matrix3::scaling(const Vector2&), * @see rotationScaling() const, Matrix3::scaling(const Vector2&),
* Vector3::xScale(), Vector3::yScale(), Vector3::zScale() * Vector3::xScale(), Vector3::yScale(), Vector3::zScale()
*/ */
inline constexpr static Matrix4<T> scaling(const Vector3<T>& vector) { 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)}};
}
/** /**
* @brief 3D rotation around arbitrary axis * @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(), * Matrix3::rotation(Rad), Vector3::xAxis(), Vector3::yAxis(),
* Vector3::zAxis(), Vector::isNormalized() * Vector3::zAxis(), Vector::isNormalized()
*/ */
static Matrix4<T> rotation(Rad<T> angle, const Vector3<T>& normalizedAxis) { 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)}
};
}
/** /**
* @brief 3D rotation around X axis * @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(), * @see rotation(Rad, const Vector3&), rotationY(), rotationZ(),
* rotation() const, Quaternion::rotation(), Matrix3::rotation(Rad) * rotation() const, Quaternion::rotation(), Matrix3::rotation(Rad)
*/ */
static Matrix4<T> rotationX(Rad<T> angle) { 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)}};
}
/** /**
* @brief 3D rotation around Y axis * @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(), * @see rotation(Rad, const Vector3&), rotationX(), rotationZ(),
* rotation() const, Quaternion::rotation(), Matrix3::rotation(Rad) * rotation() const, Quaternion::rotation(), Matrix3::rotation(Rad)
*/ */
static Matrix4<T> rotationY(Rad<T> angle) { 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)}};
}
/** /**
* @brief 3D rotation matrix around Z axis * @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(), * @see rotation(Rad, const Vector3&), rotationX(), rotationY(),
* rotation() const, Quaternion::rotation(), Matrix3::rotation(Rad) * rotation() const, Quaternion::rotation(), Matrix3::rotation(Rad)
*/ */
static Matrix4<T> rotationZ(Rad<T> angle) { 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)}};
}
/** /**
* @brief 3D reflection matrix * @brief 3D reflection matrix
@ -183,11 +119,7 @@ template<class T> class Matrix4: public Matrix<4, T> {
* Expects that the normal is normalized. * Expects that the normal is normalized.
* @see Matrix3::reflection(), Vector::isNormalized() * @see Matrix3::reflection(), Vector::isNormalized()
*/ */
static Matrix4<T> reflection(const Vector3<T>& normal) { 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(), {});
}
/** /**
* @brief 3D orthographic projection matrix * @brief 3D orthographic projection matrix
@ -197,15 +129,7 @@ template<class T> class Matrix4: public Matrix<4, T> {
* *
* @see perspectiveProjection(), Matrix3::projection() * @see perspectiveProjection(), Matrix3::projection()
*/ */
static Matrix4<T> orthographicProjection(const Vector2<T>& size, T near, T far) { 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)}};
}
/** /**
* @brief 3D perspective projection matrix * @brief 3D perspective projection matrix
@ -215,15 +139,7 @@ template<class T> class Matrix4: public Matrix<4, T> {
* *
* @see orthographicProjection(), Matrix3::projection() * @see orthographicProjection(), Matrix3::projection()
*/ */
static Matrix4<T> perspectiveProjection(const Vector2<T>& size, T near, T far) { 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)}};
}
/** /**
* @brief 3D perspective projection matrix * @brief 3D perspective projection matrix
@ -235,8 +151,7 @@ template<class T> class Matrix4: public Matrix<4, T> {
* @see orthographicProjection(), Matrix3::projection() * @see orthographicProjection(), Matrix3::projection()
*/ */
static Matrix4<T> perspectiveProjection(Rad<T> fov, T aspectRatio, T near, T far) { 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); 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 * @see rotationScaling() const, translation() const
*/ */
inline constexpr static Matrix4<T> from(const Matrix<3, T>& rotationScaling, const Vector3<T>& translation) { 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)}};
}
/** @copydoc Matrix::Matrix(ZeroType) */ /** @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 * @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. * @p value allows you to specify value on diagonal.
* @todo Use constexpr implementation in Matrix, when done * @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>( constexpr /*implicit*/ Matrix4(typename Matrix<4, T>::IdentityType = (Matrix<4, T>::Identity), T value = T(1));
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)
) {}
/** @brief %Matrix from column vectors */ /** @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>&) */ /** @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 */ /** @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 */ /** @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 * @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). * no scaling or projection).
* @see isOrthogonal() * @see isOrthogonal()
*/ */
inline bool isRigidTransformation() const { bool isRigidTransformation() const {
return rotationScaling().isOrthogonal() && row(3) == Vector4<T>(T(0), T(0), T(0), T(1)); 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 * rotation(T, const Vector3&), Matrix3::rotationScaling() const
* @todo extract rotation with assert for no scaling * @todo extract rotation with assert for no scaling
*/ */
inline constexpr Matrix<3, T> rotationScaling() const { /* Not Matrix3, because it is for affine 2D transformations */
/* Not Matrix3, because it is for affine 2D transformations */ constexpr Matrix<3, T> rotationScaling() const;
return {(*this)[0].xyz(),
(*this)[1].xyz(),
(*this)[2].xyz()};
}
/** /**
* @brief 3D rotation part of the matrix * @brief 3D rotation part of the matrix
@ -320,12 +221,8 @@ template<class T> class Matrix4: public Matrix<4, T> {
* Matrix3::rotation() const * Matrix3::rotation() const
* @todo assert uniform scaling (otherwise this would be garbage) * @todo assert uniform scaling (otherwise this would be garbage)
*/ */
inline Matrix<3, T> rotation() const { /* Not Matrix3, because it is for affine 2D transformations */
/* Not Matrix3, because it is for affine 2D transformations */ Matrix<3, T> rotation() const;
return {(*this)[0].xyz().normalized(),
(*this)[1].xyz().normalized(),
(*this)[2].xyz().normalized()};
}
/** @todo uniform scaling extraction */ /** @todo uniform scaling extraction */
@ -335,8 +232,8 @@ template<class T> class Matrix4: public Matrix<4, T> {
* First three elements of first column. * First three elements of first column.
* @see up(), backward(), Vector3::xAxis(), Matrix3::right() * @see up(), backward(), Vector3::xAxis(), Matrix3::right()
*/ */
inline Vector3<T>& right() { return (*this)[0].xyz(); } Vector3<T>& right() { return (*this)[0].xyz(); }
inline constexpr Vector3<T> right() const { return (*this)[0].xyz(); } /**< @overload */ constexpr Vector3<T> right() const { return (*this)[0].xyz(); } /**< @overload */
/** /**
* @brief Up-pointing 3D vector * @brief Up-pointing 3D vector
@ -344,8 +241,8 @@ template<class T> class Matrix4: public Matrix<4, T> {
* First three elements of second column. * First three elements of second column.
* @see right(), backward(), Vector3::yAxis(), Matrix3::up() * @see right(), backward(), Vector3::yAxis(), Matrix3::up()
*/ */
inline Vector3<T>& up() { return (*this)[1].xyz(); } Vector3<T>& up() { return (*this)[1].xyz(); }
inline constexpr Vector3<T> up() const { return (*this)[1].xyz(); } /**< @overload */ constexpr Vector3<T> up() const { return (*this)[1].xyz(); } /**< @overload */
/** /**
* @brief Backward-pointing 3D vector * @brief Backward-pointing 3D vector
@ -353,8 +250,8 @@ template<class T> class Matrix4: public Matrix<4, T> {
* First three elements of third column. * First three elements of third column.
* @see right(), up(), Vector3::yAxis() * @see right(), up(), Vector3::yAxis()
*/ */
inline Vector3<T>& backward() { return (*this)[2].xyz(); } Vector3<T>& backward() { return (*this)[2].xyz(); }
inline constexpr Vector3<T> backward() const { return (*this)[2].xyz(); } /**< @overload */ constexpr Vector3<T> backward() const { return (*this)[2].xyz(); } /**< @overload */
/** /**
* @brief 3D translation part of the matrix * @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&), * @see from(const Matrix<3, T>&, const Vector3&),
* translation(const Vector3&), Matrix3::translation() * translation(const Vector3&), Matrix3::translation()
*/ */
inline Vector3<T>& translation() { return (*this)[3].xyz(); } Vector3<T>& translation() { return (*this)[3].xyz(); }
inline constexpr Vector3<T> translation() const { return (*this)[3].xyz(); } /**< @overload */ constexpr Vector3<T> translation() const { return (*this)[3].xyz(); } /**< @overload */
/** /**
* @brief Inverted rigid transformation matrix * @brief Inverted rigid transformation matrix
@ -374,13 +271,7 @@ template<class T> class Matrix4: public Matrix<4, T> {
* @see isRigidTransformation(), invertedOrthogonal(), * @see isRigidTransformation(), invertedOrthogonal(),
* rotationScaling() const, translation() const * rotationScaling() const, translation() const
*/ */
inline Matrix4<T> invertedRigid() const { 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());
}
/** /**
* @brief Transform 3D vector with the matrix * @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() * @see Quaternion::transformVector(), Matrix3::transformVector()
* @todo extract 3x3 matrix and multiply directly? (benchmark that) * @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(); return ((*this)*Vector4<T>(vector, T(0))).xyz();
} }
@ -405,7 +296,7 @@ template<class T> class Matrix4: public Matrix<4, T> {
* @f] * @f]
* @see DualQuaternion::transformPoint(), Matrix3::transformPoint() * @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(); 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); 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 { namespace Corrade { namespace Utility {

293
src/Math/Quaternion.h

@ -38,44 +38,6 @@
namespace Magnum { namespace Math { 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 @brief %Quaternion
@tparam T Underlying data type @tparam T Underlying data type
@ -95,7 +57,7 @@ template<class T> class Quaternion {
* @f] * @f]
* @see dot() const * @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 */ /** @todo Use four-component SIMD implementation when available */
return Vector3<T>::dot(a.vector(), b.vector()) + a.scalar()*b.scalar(); return Vector3<T>::dot(a.vector(), b.vector()) + a.scalar()*b.scalar();
} }
@ -108,11 +70,7 @@ template<class T> class Quaternion {
* @f] * @f]
* @see isNormalized(), Complex::angle(), Vector::angle() * @see isNormalized(), Complex::angle(), Vector::angle()
*/ */
inline static Rad<T> angle(const Quaternion<T>& normalizedA, const Quaternion<T>& normalizedB) { 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));
}
/** /**
* @brief Linear interpolation of two quaternions * @brief Linear interpolation of two quaternions
@ -125,12 +83,7 @@ template<class T> class Quaternion {
* @f] * @f]
* @see isNormalized(), slerp(), Math::lerp() * @see isNormalized(), slerp(), Math::lerp()
*/ */
inline static Quaternion<T> lerp(const Quaternion<T>& normalizedA, const Quaternion<T>& normalizedB, T t) { 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();
}
/** /**
* @brief Spherical linear interpolation of two quaternions * @brief Spherical linear interpolation of two quaternions
@ -145,13 +98,7 @@ template<class T> class Quaternion {
* @f] * @f]
* @see isNormalized(), lerp() * @see isNormalized(), lerp()
*/ */
inline static Quaternion<T> slerp(const Quaternion<T>& normalizedA, const Quaternion<T>& normalizedB, T t) { 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);
}
/** /**
* @brief Rotation quaternion * @brief Rotation quaternion
@ -165,12 +112,7 @@ template<class T> class Quaternion {
* Matrix4::rotation(), Complex::rotation(), Vector3::xAxis(), * Matrix4::rotation(), Complex::rotation(), Vector3::xAxis(),
* Vector3::yAxis(), Vector3::zAxis(), Vector::isNormalized() * Vector3::yAxis(), Vector3::zAxis(), Vector::isNormalized()
*/ */
inline static Quaternion<T> rotation(Rad<T> angle, const Vector3<T>& normalizedAxis) { 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)};
}
/** /**
* @brief Create quaternion from rotation matrix * @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). * Expects that the matrix is orthogonal (i.e. pure rotation).
* @see toMatrix(), DualComplex::fromMatrix(), Matrix::isOrthogonal() * @see toMatrix(), DualComplex::fromMatrix(), Matrix::isOrthogonal()
*/ */
inline static Quaternion<T> fromMatrix(const Matrix<3, T>& matrix) { 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);
}
/** /**
* @brief Default constructor * @brief Default constructor
@ -191,7 +129,7 @@ template<class T> class Quaternion {
* q = [\boldsymbol 0, 1] * q = [\boldsymbol 0, 1]
* @f] * @f]
*/ */
inline constexpr /*implicit*/ Quaternion(): _scalar(T(1)) {} constexpr /*implicit*/ Quaternion(): _scalar(T(1)) {}
/** /**
* @brief Construct quaternion from vector and scalar * @brief Construct quaternion from vector and scalar
@ -200,7 +138,7 @@ template<class T> class Quaternion {
* q = [\boldsymbol v, s] * q = [\boldsymbol v, s]
* @f] * @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 * @brief Construct quaternion from vector
@ -210,15 +148,15 @@ template<class T> class Quaternion {
* @f] * @f]
* @see transformVector(), transformVectorNormalized() * @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 */ /** @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); return _vector == other._vector && TypeTraits<T>::equals(_scalar, other._scalar);
} }
/** @brief Non-equality comparison */ /** @brief Non-equality comparison */
inline bool operator!=(const Quaternion<T>& other) const { bool operator!=(const Quaternion<T>& other) const {
return !operator==(other); return !operator==(other);
} }
@ -230,15 +168,15 @@ template<class T> class Quaternion {
* @f] * @f]
* @see dot(), normalized() * @see dot(), normalized()
*/ */
inline bool isNormalized() const { bool isNormalized() const {
return Implementation::isNormalizedSquared(dot()); return Implementation::isNormalizedSquared(dot());
} }
/** @brief %Vector part */ /** @brief %Vector part */
inline constexpr Vector3<T> vector() const { return _vector; } constexpr Vector3<T> vector() const { return _vector; }
/** @brief %Scalar part */ /** @brief %Scalar part */
inline constexpr T scalar() const { return _scalar; } constexpr T scalar() const { return _scalar; }
/** /**
* @brief Rotation angle of unit quaternion * @brief Rotation angle of unit quaternion
@ -248,12 +186,7 @@ template<class T> class Quaternion {
* @f] * @f]
* @see isNormalized(), axis(), rotation() * @see isNormalized(), axis(), rotation()
*/ */
inline Rad<T> angle() const { 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));
}
/** /**
* @brief Rotation axis of unit quaternion * @brief Rotation axis of unit quaternion
@ -265,12 +198,7 @@ template<class T> class Quaternion {
* @f] * @f]
* @see isNormalized(), angle(), rotation() * @see isNormalized(), angle(), rotation()
*/ */
inline Vector3<T> axis() const { Vector3<T> axis() const;
CORRADE_ASSERT(isNormalized(),
"Math::Quaternion::axis(): quaternion must be normalized",
{});
return _vector/std::sqrt(1-pow2(_scalar));
}
/** /**
* @brief Convert quaternion to rotation matrix * @brief Convert quaternion to rotation matrix
@ -278,19 +206,7 @@ template<class T> class Quaternion {
* @see fromMatrix(), DualQuaternion::toMatrix(), * @see fromMatrix(), DualQuaternion::toMatrix(),
* Matrix4::from(const Matrix<3, T>&, const Vector3<T>&) * Matrix4::from(const Matrix<3, T>&, const Vector3<T>&)
*/ */
Matrix<3, T> toMatrix() const { 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()))
};
}
/** /**
* @brief Add and assign quaternion * @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] * p + q = [\boldsymbol p_V + \boldsymbol q_V, p_S + q_S]
* @f] * @f]
*/ */
inline Quaternion<T>& operator+=(const Quaternion<T>& other) { Quaternion<T>& operator+=(const Quaternion<T>& other) {
_vector += other._vector; _vector += other._vector;
_scalar += other._scalar; _scalar += other._scalar;
return *this; return *this;
@ -310,7 +226,7 @@ template<class T> class Quaternion {
* *
* @see operator+=() * @see operator+=()
*/ */
inline Quaternion<T> operator+(const Quaternion<T>& other) const { Quaternion<T> operator+(const Quaternion<T>& other) const {
return Quaternion<T>(*this) += other; return Quaternion<T>(*this) += other;
} }
@ -321,9 +237,7 @@ template<class T> class Quaternion {
* -q = [-\boldsymbol q_V, -q_S] * -q = [-\boldsymbol q_V, -q_S]
* @f] * @f]
*/ */
inline Quaternion<T> operator-() const { Quaternion<T> operator-() const { return {-_vector, -_scalar}; }
return {-_vector, -_scalar};
}
/** /**
* @brief Subtract and assign quaternion * @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] * p - q = [\boldsymbol p_V - \boldsymbol q_V, p_S - q_S]
* @f] * @f]
*/ */
inline Quaternion<T>& operator-=(const Quaternion<T>& other) { Quaternion<T>& operator-=(const Quaternion<T>& other) {
_vector -= other._vector; _vector -= other._vector;
_scalar -= other._scalar; _scalar -= other._scalar;
return *this; return *this;
@ -343,7 +257,7 @@ template<class T> class Quaternion {
* *
* @see operator-=() * @see operator-=()
*/ */
inline Quaternion<T> operator-(const Quaternion<T>& other) const { Quaternion<T> operator-(const Quaternion<T>& other) const {
return Quaternion<T>(*this) -= other; 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] * q \cdot a = [\boldsymbol q_V \cdot a, q_S \cdot a]
* @f] * @f]
*/ */
inline Quaternion<T>& operator*=(T scalar) { Quaternion<T>& operator*=(T scalar) {
_vector *= scalar; _vector *= scalar;
_scalar *= scalar; _scalar *= scalar;
return *this; return *this;
@ -365,7 +279,7 @@ template<class T> class Quaternion {
* *
* @see operator*=(T) * @see operator*=(T)
*/ */
inline Quaternion<T> operator*(T scalar) const { Quaternion<T> operator*(T scalar) const {
return Quaternion<T>(*this) *= scalar; 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] * \frac q a = [\frac {\boldsymbol q_V} a, \frac {q_S} a]
* @f] * @f]
*/ */
inline Quaternion<T>& operator/=(T scalar) { Quaternion<T>& operator/=(T scalar) {
_vector /= scalar; _vector /= scalar;
_scalar /= scalar; _scalar /= scalar;
return *this; return *this;
@ -387,7 +301,7 @@ template<class T> class Quaternion {
* *
* @see operator/=(T) * @see operator/=(T)
*/ */
inline Quaternion<T> operator/(T scalar) const { Quaternion<T> operator/(T scalar) const {
return Quaternion<T>(*this) /= scalar; 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] * p_S q_S - \boldsymbol p_V \cdot \boldsymbol q_V]
* @f] * @f]
*/ */
inline Quaternion<T> operator*(const Quaternion<T>& other) const { 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)};
}
/** /**
* @brief Dot product of the quaternion * @brief Dot product of the quaternion
@ -413,9 +324,7 @@ template<class T> class Quaternion {
* @f] * @f]
* @see isNormalized(), dot(const Quaternion&, const Quaternion&) * @see isNormalized(), dot(const Quaternion&, const Quaternion&)
*/ */
inline T dot() const { T dot() const { return dot(*this, *this); }
return dot(*this, *this);
}
/** /**
* @brief %Quaternion length * @brief %Quaternion length
@ -426,18 +335,14 @@ template<class T> class Quaternion {
* @f] * @f]
* @see isNormalized() * @see isNormalized()
*/ */
inline T length() const { T length() const { return std::sqrt(dot()); }
return std::sqrt(dot());
}
/** /**
* @brief Normalized quaternion (of unit length) * @brief Normalized quaternion (of unit length)
* *
* @see isNormalized() * @see isNormalized()
*/ */
inline Quaternion<T> normalized() const { Quaternion<T> normalized() const { return (*this)/length(); }
return (*this)/length();
}
/** /**
* @brief Conjugated quaternion * @brief Conjugated quaternion
@ -446,9 +351,7 @@ template<class T> class Quaternion {
* q^* = [-\boldsymbol q_V, q_S] * q^* = [-\boldsymbol q_V, q_S]
* @f] * @f]
*/ */
inline Quaternion<T> conjugated() const { Quaternion<T> conjugated() const { return {-_vector, _scalar}; }
return {-_vector, _scalar};
}
/** /**
* @brief Inverted quaternion * @brief Inverted quaternion
@ -458,9 +361,7 @@ template<class T> class Quaternion {
* q^{-1} = \frac{q^*}{|q|^2} = \frac{q^*}{q \cdot q} * q^{-1} = \frac{q^*}{|q|^2} = \frac{q^*}{q \cdot q}
* @f] * @f]
*/ */
inline Quaternion<T> inverted() const { Quaternion<T> inverted() const { return conjugated()/dot(); }
return conjugated()/dot();
}
/** /**
* @brief Inverted normalized quaternion * @brief Inverted normalized quaternion
@ -471,12 +372,7 @@ template<class T> class Quaternion {
* @f] * @f]
* @see isNormalized(), inverted() * @see isNormalized(), inverted()
*/ */
inline Quaternion<T> invertedNormalized() const { Quaternion<T> invertedNormalized() const;
CORRADE_ASSERT(isNormalized(),
"Math::Quaternion::invertedNormalized(): quaternion must be normalized",
Quaternion<T>({}, std::numeric_limits<T>::quiet_NaN()));
return conjugated();
}
/** /**
* @brief Rotate vector with quaternion * @brief Rotate vector with quaternion
@ -488,7 +384,7 @@ template<class T> class Quaternion {
* @see Quaternion(const Vector3&), vector(), Matrix4::transformVector(), * @see Quaternion(const Vector3&), vector(), Matrix4::transformVector(),
* DualQuaternion::transformPoint(), Complex::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(); return ((*this)*Quaternion<T>(vector)*inverted()).vector();
} }
@ -502,21 +398,16 @@ template<class T> class Quaternion {
* @see isNormalized(), Quaternion(const Vector3&), vector(), Matrix4::transformVector(), * @see isNormalized(), Quaternion(const Vector3&), vector(), Matrix4::transformVector(),
* DualQuaternion::transformPointNormalized(), Complex::transformVector() * DualQuaternion::transformPointNormalized(), Complex::transformVector()
*/ */
inline Vector3<T> transformVectorNormalized(const Vector3<T>& vector) const { 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();
}
private: private:
/* Used to avoid including Functions.h */ /* Used to avoid including Functions.h */
inline constexpr static T pow2(T value) { constexpr static T pow2(T value) {
return value*value; return value*value;
} }
/* Used in angle() and slerp() (no assertions) */ /* 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)); return std::acos(dot(normalizedA, normalizedB));
} }
@ -562,6 +453,116 @@ extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utilit
#endif #endif
#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 #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 * @attention Use with caution, the function doesn't check whether the
* array is long enough. * 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); return *reinterpret_cast<RectangularMatrix<cols, rows, T>*>(data);
} }
/** @overload */ /** @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); 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() * @see diagonal()
* @todo make this constexpr * @todo make this constexpr
*/ */
inline static RectangularMatrix<cols, rows, T> fromDiagonal(const Vector<DiagonalSize, T>& diagonal) { 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;
}
/** /**
* @brief Construct matrix from vector * @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. * vector will make first column of resulting matrix.
* @see toVector() * @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()); return *reinterpret_cast<const RectangularMatrix<cols, rows, T>*>(vector.data());
} }
/** @brief Construct zero-filled matrix */ /** @brief Construct zero-filled matrix */
inline constexpr /*implicit*/ RectangularMatrix() {} constexpr /*implicit*/ RectangularMatrix() {}
/** /**
* @brief Construct matrix from column vectors * @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 * @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"); 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 * @endcode
*/ */
#ifndef CORRADE_GCC46_COMPATIBILITY #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 #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); *this = RectangularMatrix(typename Implementation::GenerateSequence<cols>::Type(), other);
} }
#endif #endif
/** @brief Construct matrix from external representation */ /** @brief Construct matrix from external representation */
#ifndef CORRADE_GCC46_COMPATIBILITY #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 #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); *this = Implementation::RectangularMatrixConverter<cols, rows, T, U>::from(other);
} }
#endif #endif
/** @brief Copy constructor */ /** @brief Copy constructor */
inline constexpr RectangularMatrix(const RectangularMatrix<cols, rows, T>&) = default; constexpr RectangularMatrix(const RectangularMatrix<cols, rows, T>&) = default;
/** @brief Assignment operator */ /** @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 */ /** @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? */ /** @bug Why this is not constexpr under GCC 4.6? */
return Implementation::RectangularMatrixConverter<cols, rows, T, U>::to(*this); 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[] * @see operator[]
*/ */
inline T* data() { return _data[0].data(); } T* data() { return _data[0].data(); }
inline constexpr const T* data() const { return _data[0].data(); } /**< @overload */ constexpr const T* data() const { return _data[0].data(); } /**< @overload */
/** /**
* @brief %Matrix column * @brief %Matrix column
@ -186,13 +179,8 @@ template<std::size_t cols, std::size_t rows, class T> class RectangularMatrix {
* *
* @see row(), data() * @see row(), data()
*/ */
inline Vector<rows, T>& operator[](std::size_t col) { Vector<rows, T>& operator[](std::size_t col) { return _data[col]; }
return _data[col]; constexpr const Vector<rows, T>& operator[](std::size_t col) const { return _data[col]; } /** @overload */
}
/** @overload */
inline constexpr const Vector<rows, T>& operator[](std::size_t col) const {
return _data[col];
}
/** /**
* @brief %Matrix row * @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. * is slower than accessing columns due to the way the matrix is stored.
* @see operator[]() * @see operator[]()
*/ */
inline Vector<cols, T> row(std::size_t row) const { 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;
}
/** @brief Equality comparison */ /** @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) for(std::size_t i = 0; i != cols; ++i)
if(_data[i] != other._data[i]) return false; 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>=(), * @see Vector::operator<(), 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); 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 * @brief Add and assign matrix
* *
@ -247,26 +237,10 @@ template<std::size_t cols, std::size_t rows, class T> class RectangularMatrix {
* *
* @see operator+=() * @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; 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 * @brief Subtract and assign matrix
* *
@ -286,7 +260,7 @@ template<std::size_t cols, std::size_t rows, class T> class RectangularMatrix {
* *
* @see operator-=() * @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; 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 #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 { template<class U> inline typename std::enable_if<std::is_arithmetic<U>::value, RectangularMatrix<cols, rows, T>>::type operator*(U number) const {
#else #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 #endif
return RectangularMatrix<cols, rows, T>(*this)*=number; 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 #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 { template<class U> inline typename std::enable_if<std::is_arithmetic<U>::value, RectangularMatrix<cols, rows, T>>::type operator/(U number) const {
#else #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 #endif
return RectangularMatrix<cols, rows, T>(*this)/=number; 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} * (\boldsymbol {AB})_{ji} = \sum_{k=0}^{m-1} \boldsymbol A_{ki} \boldsymbol B_{jk}
* @f] * @f]
*/ */
template<std::size_t size> RectangularMatrix<size, rows, T> operator*(const RectangularMatrix<size, cols, T>& other) const { 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;
}
/** /**
* @brief Multiply vector * @brief Multiply vector
@ -387,29 +352,15 @@ template<std::size_t cols, std::size_t rows, class T> class RectangularMatrix {
* *
* @see row() * @see row()
*/ */
RectangularMatrix<rows, cols, T> transposed() const { 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;
}
/** /**
* @brief Values on diagonal * @brief Values on diagonal
* *
* @see fromDiagonal() * @see fromDiagonal()
* @todo constexpr
*/ */
Vector<DiagonalSize, T> diagonal() const { 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;
}
/** /**
* @brief Convert matrix to vector * @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.). * summing the elements etc.).
* @see fromVector() * @see fromVector()
*/ */
inline Vector<rows*cols, T> toVector() const { Vector<rows*cols, T> toVector() const {
return *reinterpret_cast<const Vector<rows*cols, T>*>(data()); return *reinterpret_cast<const Vector<rows*cols, T>*>(data());
} }
private: private:
/* Implementation for RectangularMatrix<cols, rows, T>::RectangularMatrix(const RectangularMatrix<cols, rows, U>&) */ /* 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]; Vector<rows, T> _data[cols];
}; };
@ -453,9 +404,9 @@ The computation is done column-wise. @f[
@see RectangularMatrix::operator/(U) const @see RectangularMatrix::operator/(U) const
*/ */
#ifdef DOXYGEN_GENERATING_OUTPUT #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 #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 #endif
RectangularMatrix<cols, rows, T> out; RectangularMatrix<cols, rows, T> out;
@ -522,51 +473,108 @@ extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utilit
#endif #endif
#define MAGNUM_RECTANGULARMATRIX_SUBCLASS_IMPLEMENTATION(cols, rows, ...) \ #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); \ 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); \ 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); \ Math::RectangularMatrix<cols, rows, T>::operator=(other); \
return *this; \ return *this; \
} \ } \
\ \
inline __VA_ARGS__ operator-() const { \ __VA_ARGS__ operator-() const { \
return Math::RectangularMatrix<cols, rows, T>::operator-(); \ 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); \ Math::RectangularMatrix<cols, rows, T>::operator+=(other); \
return *this; \ 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); \ 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); \ Math::RectangularMatrix<cols, rows, T>::operator-=(other); \
return *this; \ 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); \ 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); \ Math::RectangularMatrix<cols, rows, T>::operator*=(number); \
return *this; \ 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); \ 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); \ Math::RectangularMatrix<cols, rows, T>::operator/=(number); \
return *this; \ 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); \ return Math::RectangularMatrix<cols, rows, T>::operator/(number); \
} }
#endif #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 { 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 { template<std::size_t size, std::size_t position> struct ComponentAtPosition {
static_assert(size > position, "Swizzle parameter out of range of base vector"); 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 {}; 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, '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, 'w'>: public ComponentAtPosition<size, 3> {};
template<std::size_t size> struct Component<size, '0'> { 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<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(), @see @ref matrix-vector-component-access, Vector4::xyz(),
Vector4::xy(), Vector3::xy() 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)...}; return {Implementation::Component<size, components>::value(vector)...};
} }

4
src/Math/Test/Matrix3Test.cpp

@ -37,14 +37,14 @@ namespace Magnum { namespace Math {
namespace Implementation { namespace Implementation {
template<> struct RectangularMatrixConverter<3, 3, float, Mat3> { 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>( return RectangularMatrix<3, 3, Float>(
Vector<3, Float>(other.a[0], other.a[1], other.a[2]), 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[3], other.a[4], other.a[5]),
Vector<3, Float>(other.a[6], other.a[7], other.a[8])); 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], return Mat3{{other[0][0], other[0][1], other[0][2],
other[1][0], other[1][1], other[1][2], other[1][0], other[1][1], other[1][2],
other[2][0], other[2][1], other[2][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 { namespace Implementation {
template<> struct RectangularMatrixConverter<4, 4, float, Mat4> { 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>( 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[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]), 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])); 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], 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[1][0], other[1][1], other[1][2], other[1][3],
other[2][0], other[2][1], other[2][2], other[2][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 { namespace Implementation {
template<> struct RectangularMatrixConverter<3, 3, float, Mat3> { 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>( return RectangularMatrix<3, 3, Float>(
Vector<3, Float>(other.a[0], other.a[1], other.a[2]), 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[3], other.a[4], other.a[5]),
Vector<3, Float>(other.a[6], other.a[7], other.a[8])); 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], return Mat3{{other[0][0], other[0][1], other[0][2],
other[1][0], other[1][1], other[1][2], other[1][0], other[1][1], other[1][2],
other[2][0], other[2][1], other[2][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 { namespace Implementation {
template<> struct RectangularMatrixConverter<2, 3, float, Mat2x3> { 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>( return RectangularMatrix<2, 3, Float>(
Vector<3, Float>(other.a[0], other.a[1], other.a[2]), 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[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], return Mat2x3{{other[0][0], other[0][1], other[0][2],
other[1][0], other[1][1], other[1][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 { namespace Implementation {
template<> struct VectorConverter<2, float, Vec2> { 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}; 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]}; return {other[0], other[1]};
} }
}; };

4
src/Math/Test/Vector3Test.cpp

@ -37,11 +37,11 @@ namespace Magnum { namespace Math {
namespace Implementation { namespace Implementation {
template<> struct VectorConverter<3, float, Vec3> { 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}; 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]}; return {other[0], other[1], other[2]};
} }
}; };

4
src/Math/Test/Vector4Test.cpp

@ -37,11 +37,11 @@ namespace Magnum { namespace Math {
namespace Implementation { namespace Implementation {
template<> struct VectorConverter<4, float, Vec4> { 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}; 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]}; 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 { namespace Implementation {
template<> struct VectorConverter<3, float, Vec3> { 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}; 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]}; return {other[0], other[1], other[2]};
} }
}; };

14
src/Math/TypeTraits.h

@ -56,7 +56,7 @@ namespace Implementation {
template<class T> struct TypeTraitsDefault { template<class T> struct TypeTraitsDefault {
TypeTraitsDefault() = delete; TypeTraitsDefault() = delete;
inline constexpr static bool equals(T a, T b) { constexpr static bool equals(T a, T b) {
return a == 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 * inequal. Returns 1 for integer types and reasonably small value for
* floating-point types. Not implemented for arbitrary types. * floating-point types. Not implemented for arbitrary types.
*/ */
inline constexpr static T epsilon(); constexpr static T epsilon();
/** /**
* @brief Fuzzy compare * @brief Fuzzy compare
@ -116,7 +116,7 @@ template<class T> struct TypeTraits: Implementation::TypeTraitsDefault<T> {
/* Integral scalar types */ /* Integral scalar types */
namespace Implementation { namespace Implementation {
template<class T> struct TypeTraitsIntegral: TypeTraitsDefault<T> { 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 { template<class T> struct TypeTraitsFloatingPoint {
TypeTraitsFloatingPoint() = delete; 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(); return std::abs(a - b) < TypeTraits<T>::epsilon();
} }
}; };
@ -168,19 +168,19 @@ namespace Implementation {
template<> struct TypeTraits<Float>: Implementation::TypeTraitsFloatingPoint<Float> { template<> struct TypeTraits<Float>: Implementation::TypeTraitsFloatingPoint<Float> {
typedef Float FloatingPointType; typedef Float FloatingPointType;
inline constexpr static Float epsilon() { return FLOAT_EQUALITY_PRECISION; } constexpr static Float epsilon() { return FLOAT_EQUALITY_PRECISION; }
}; };
#ifndef MAGNUM_TARGET_GLES #ifndef MAGNUM_TARGET_GLES
template<> struct TypeTraits<Double>: Implementation::TypeTraitsFloatingPoint<Double> { template<> struct TypeTraits<Double>: Implementation::TypeTraitsFloatingPoint<Double> {
typedef Double FloatingPointType; typedef Double FloatingPointType;
inline constexpr static Double epsilon() { return DOUBLE_EQUALITY_PRECISION; } constexpr static Double epsilon() { return DOUBLE_EQUALITY_PRECISION; }
}; };
#endif #endif
template<> struct TypeTraits<long double>: Implementation::TypeTraitsFloatingPoint<long double> { template<> struct TypeTraits<long double>: Implementation::TypeTraitsFloatingPoint<long double> {
typedef long double FloatingPointType; 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 /* 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 */ typedef T Type; /**< @brief Underlying data type */
/** @brief Default constructor */ /** @brief Default constructor */
inline constexpr /*implicit*/ Unit(): value(T(0)) {} constexpr /*implicit*/ Unit(): value(T(0)) {}
/** @brief Explicit conversion from unitless type */ /** @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 */ /** @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 */ /** @brief Explicit conversion to underlying type */
inline constexpr explicit operator T() const { return value; } constexpr explicit operator T() const { return value; }
/** @brief Equality comparison */ /** @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); return TypeTraits<T>::equals(value, other.value);
} }
/** @brief Non-equality comparison */ /** @brief Non-equality comparison */
inline constexpr bool operator!=(Unit<Derived, T> other) const { constexpr bool operator!=(Unit<Derived, T> other) const {
return !operator==(other); return !operator==(other);
} }
/** @brief Less than comparison */ /** @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; return value < other.value;
} }
/** @brief Greater than comparison */ /** @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; return value > other.value;
} }
/** @brief Less than or equal comparison */ /** @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); return !operator>(other);
} }
/** @brief Greater than or equal comparison */ /** @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); return !operator<(other);
} }
/** @brief Negated value */ /** @brief Negated value */
inline constexpr Unit<Derived, T> operator-() const { constexpr Unit<Derived, T> operator-() const {
return Unit<Derived, T>(-value); return Unit<Derived, T>(-value);
} }
/** @brief Add and assign 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; value += other.value;
return *this; return *this;
} }
/** @brief Add value */ /** @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); return Unit<Derived, T>(value + other.value);
} }
/** @brief Subtract and assign 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; value -= other.value;
return *this; return *this;
} }
/** @brief Subtract value */ /** @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); return Unit<Derived, T>(value - other.value);
} }
/** @brief Multiply with number and assign */ /** @brief Multiply with number and assign */
inline Unit<Derived, T>& operator*=(T number) { Unit<Derived, T>& operator*=(T number) {
value *= number; value *= number;
return *this; return *this;
} }
/** @brief Multiply with number */ /** @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); return Unit<Derived, T>(value*number);
} }
/** @brief Divide with number and assign */ /** @brief Divide with number and assign */
inline Unit<Derived, T>& operator/=(T number) { Unit<Derived, T>& operator/=(T number) {
value /= number; value /= number;
return *this; return *this;
} }
/** @brief Divide with number */ /** @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); return Unit<Derived, T>(value/number);
} }
/** @brief Ratio of two values */ /** @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; return value/other.value;
} }
@ -147,7 +147,7 @@ template<template<class> class Derived, class T> class Unit {
/** @relates Unit /** @relates Unit
@brief Multiply number with value @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; 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 * @attention Use with caution, the function doesn't check whether the
* array is long enough. * 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); return *reinterpret_cast<Vector<size, T>*>(data);
} }
/** @overload */ /** @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); return *reinterpret_cast<const Vector<size, T>*>(data);
} }
@ -89,7 +89,7 @@ template<std::size_t size, class T> class Vector {
* @f] * @f]
* @see dot() const, operator-(), Vector2::perpendicular() * @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(); return (a*b).sum();
} }
@ -101,11 +101,7 @@ template<std::size_t size, class T> class Vector {
* @f] * @f]
* @see isNormalized(), Quaternion::angle(), Complex::angle() * @see isNormalized(), Quaternion::angle(), Complex::angle()
*/ */
inline static Rad<T> angle(const Vector<size, T>& normalizedA, const Vector<size, T>& normalizedB) { 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)));
}
/** /**
* @brief Default constructor * @brief Default constructor
@ -114,7 +110,7 @@ template<std::size_t size, class T> class Vector {
* \boldsymbol v = \boldsymbol 0 * \boldsymbol v = \boldsymbol 0
* @f] * @f]
*/ */
inline constexpr /*implicit*/ Vector(): _data() {} constexpr /*implicit*/ Vector(): _data() {}
/** @todo Creating Vector from combination of vector and scalar types */ /** @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 * @param next Next values
*/ */
#ifdef DOXYGEN_GENERATING_OUTPUT #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 #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 #endif
/** @brief Construct vector with one value for all fields */ /** @brief Construct vector with one value for all fields */
#ifdef DOXYGEN_GENERATING_OUTPUT #ifdef DOXYGEN_GENERATING_OUTPUT
inline explicit Vector(T value); constexpr explicit Vector(T value);
#else #else
#ifndef CORRADE_GCC46_COMPATIBILITY #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 #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); *this = Vector(typename Implementation::GenerateSequence<size>::Type(), value);
} }
#endif #endif
@ -154,30 +150,30 @@ template<std::size_t size, class T> class Vector {
* @endcode * @endcode
*/ */
#ifndef CORRADE_GCC46_COMPATIBILITY #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 #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); *this = Vector(typename Implementation::GenerateSequence<size>::Type(), other);
} }
#endif #endif
/** @brief Construct vector from external representation */ /** @brief Construct vector from external representation */
#ifndef CORRADE_GCC46_COMPATIBILITY #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 #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); *this = Implementation::VectorConverter<size, T, U>::from(other);
} }
#endif #endif
/** @brief Copy constructor */ /** @brief Copy constructor */
inline constexpr Vector(const Vector<size, T>&) = default; constexpr Vector(const Vector<size, T>&) = default;
/** @brief Assignment operator */ /** @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 */ /** @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? */ /** @bug Why this is not constexpr under GCC 4.6? */
return Implementation::VectorConverter<size, T, U>::to(*this); return Implementation::VectorConverter<size, T, U>::to(*this);
} }
@ -188,19 +184,19 @@ template<std::size_t size, class T> class Vector {
* *
* @see operator[]() * @see operator[]()
*/ */
inline T* data() { return _data; } T* data() { return _data; }
inline constexpr const T* data() const { return _data; } /**< @overload */ constexpr const T* data() const { return _data; } /**< @overload */
/** /**
* @brief Value at given position * @brief Value at given position
* *
* @see data() * @see data()
*/ */
inline T& operator[](std::size_t pos) { return _data[pos]; } T& operator[](std::size_t pos) { return _data[pos]; }
inline constexpr T operator[](std::size_t pos) const { return _data[pos]; } /**< @overload */ constexpr T operator[](std::size_t pos) const { return _data[pos]; } /**< @overload */
/** @brief Equality comparison */ /** @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) for(std::size_t i = 0; i != size; ++i)
if(!TypeTraits<T>::equals(_data[i], other._data[i])) return false; 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 */ /** @brief Non-equality comparison */
inline bool operator!=(const Vector<size, T>& other) const { bool operator!=(const Vector<size, T>& other) const {
return !operator==(other); return !operator==(other);
} }
/** @brief Component-wise less than */ /** @brief Component-wise less than */
inline BoolVector<size> operator<(const Vector<size, T>& other) const { 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;
}
/** @brief Component-wise less than or equal */ /** @brief Component-wise less than or equal */
inline BoolVector<size> operator<=(const Vector<size, T>& other) const { 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;
}
/** @brief Component-wise greater than or equal */ /** @brief Component-wise greater than or equal */
inline BoolVector<size> operator>=(const Vector<size, T>& other) const { 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;
}
/** @brief Component-wise greater than */ /** @brief Component-wise greater than */
inline BoolVector<size> operator>(const Vector<size, T>& other) const { 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;
}
/** /**
* @brief Whether the vector is normalized * @brief Whether the vector is normalized
@ -260,26 +228,19 @@ template<std::size_t size, class T> class Vector {
* @f] * @f]
* @see dot(), normalized() * @see dot(), normalized()
*/ */
inline bool isNormalized() const { bool isNormalized() const {
return Implementation::isNormalizedSquared(dot()); return Implementation::isNormalizedSquared(dot());
} }
/** /**
* @brief Negated vector * @brief Negated vector
* *
* The computation is done in-place. @f[ * @f[
* \boldsymbol a_i = -\boldsymbol a_i * \boldsymbol b_i = -\boldsymbol a_i
* @f] * @f]
* @see Vector2::perpendicular() * @see Vector2::perpendicular()
*/ */
Vector<size, T> operator-() const { Vector<size, T> operator-() const;
Vector<size, T> out;
for(std::size_t i = 0; i != size; ++i)
out._data[i] = -_data[i];
return out;
}
/** /**
* @brief Add and assign vector * @brief Add and assign vector
@ -300,7 +261,7 @@ template<std::size_t size, class T> class Vector {
* *
* @see operator+=(), sum() * @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; return Vector<size, T>(*this) += other;
} }
@ -323,7 +284,7 @@ template<std::size_t size, class T> class Vector {
* *
* @see operator-=() * @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; return Vector<size, T>(*this) -= other;
} }
@ -337,7 +298,7 @@ template<std::size_t size, class T> class Vector {
#ifdef DOXYGEN_GENERATING_OUTPUT #ifdef DOXYGEN_GENERATING_OUTPUT
template<class U> Vector<size, T>& operator*=(U number) { template<class U> Vector<size, T>& operator*=(U number) {
#else #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 #endif
for(std::size_t i = 0; i != size; ++i) for(std::size_t i = 0; i != size; ++i)
_data[i] *= number; _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>&) * @see operator*=(U), operator*(U, const Vector<size, T>&)
*/ */
#ifdef DOXYGEN_GENERATING_OUTPUT #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 #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 #endif
return Vector<size, T>(*this) *= number; return Vector<size, T>(*this) *= number;
} }
@ -368,7 +329,7 @@ template<std::size_t size, class T> class Vector {
#ifdef DOXYGEN_GENERATING_OUTPUT #ifdef DOXYGEN_GENERATING_OUTPUT
template<class U> Vector<size, T>& operator/=(U number) { template<class U> Vector<size, T>& operator/=(U number) {
#else #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 #endif
for(std::size_t i = 0; i != size; ++i) for(std::size_t i = 0; i != size; ++i)
_data[i] /= number; _data[i] /= number;
@ -382,9 +343,9 @@ template<std::size_t size, class T> class Vector {
* @see operator/=(), operator/(U, const Vector<size, T>&) * @see operator/=(), operator/(U, const Vector<size, T>&)
*/ */
#ifdef DOXYGEN_GENERATING_OUTPUT #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 #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 #endif
return Vector<size, T>(*this) /= number; 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() * @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; 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>&) * @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; return Vector<size, T>(*this) /= other;
} }
@ -444,9 +405,7 @@ template<std::size_t size, class T> class Vector {
* @f] * @f]
* @see dot(const Vector&, const Vector&), isNormalized() * @see dot(const Vector&, const Vector&), isNormalized()
*/ */
inline T dot() const { T dot() const { return dot(*this, *this); }
return dot(*this, *this);
}
/** /**
* @brief %Vector length * @brief %Vector length
@ -458,9 +417,7 @@ template<std::size_t size, class T> class Vector {
* @see lengthInverted(), Math::sqrt(), normalized(), resized() * @see lengthInverted(), Math::sqrt(), normalized(), resized()
* @todo something like std::hypot() for possibly better precision? * @todo something like std::hypot() for possibly better precision?
*/ */
inline T length() const { T length() const { return std::sqrt(dot()); }
return std::sqrt(dot());
}
/** /**
* @brief Inverse vector length * @brief Inverse vector length
@ -470,18 +427,14 @@ template<std::size_t size, class T> class Vector {
* @f] * @f]
* @see length(), Math::sqrtInverted(), normalized(), resized() * @see length(), Math::sqrtInverted(), normalized(), resized()
*/ */
inline T lengthInverted() const { T lengthInverted() const { return T(1)/length(); }
return T(1)/length();
}
/** /**
* @brief Normalized vector (of unit length) * @brief Normalized vector (of unit length)
* *
* @see isNormalized(), lengthInverted(), resized() * @see isNormalized(), lengthInverted(), resized()
*/ */
inline Vector<size, T> normalized() const { Vector<size, T> normalized() const { return *this*lengthInverted(); }
return *this*lengthInverted();
}
/** /**
* @brief Resized vector * @brief Resized vector
@ -494,7 +447,7 @@ template<std::size_t size, class T> class Vector {
* @endcode * @endcode
* @see normalized() * @see normalized()
*/ */
inline Vector<size, T> resized(T length) const { Vector<size, T> resized(T length) const {
return *this*(lengthInverted()*length); return *this*(lengthInverted()*length);
} }
@ -506,7 +459,7 @@ template<std::size_t size, class T> class Vector {
* @f] * @f]
* @see dot(), projectedOntoNormalized() * @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(); return line*dot(*this, line)/line.dot();
} }
@ -520,73 +473,42 @@ template<std::size_t size, class T> class Vector {
* @f] * @f]
* @see dot() * @see dot()
*/ */
inline Vector<size, T> projectedOntoNormalized(const Vector<size, T>& line) const { 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);
}
/** /**
* @brief Sum of values in the vector * @brief Sum of values in the vector
* *
* @see operator+() * @see operator+()
*/ */
T sum() const { T sum() const;
T out(_data[0]);
for(std::size_t i = 1; i != size; ++i)
out += _data[i];
return out;
}
/** /**
* @brief Product of values in the vector * @brief Product of values in the vector
* *
* @see operator*(const Vector&) * @see operator*(const Vector&)
*/ */
T product() const { T product() const;
T out(_data[0]);
for(std::size_t i = 1; i != size; ++i)
out *= _data[i];
return out;
}
/** /**
* @brief Minimal value in the vector * @brief Minimal value in the vector
* *
* @see Math::min() * @see Math::min()
*/ */
T min() const { T min() const;
T out(_data[0]);
for(std::size_t i = 1; i != size; ++i)
out = std::min(out, _data[i]);
return out;
}
/** /**
* @brief Maximal value in the vector * @brief Maximal value in the vector
* *
* @see Math::max() * @see Math::max()
*/ */
T max() const { T max() const;
T out(_data[0]);
for(std::size_t i = 1; i != size; ++i)
out = std::max(out, _data[i]);
return out;
}
private: private:
/* Implementation for Vector<size, T>::Vector(const Vector<size, U>&) */ /* 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) */ /* 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]; T _data[size];
}; };
@ -658,71 +580,71 @@ extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utilit
#ifndef DOXYGEN_GENERATING_OUTPUT #ifndef DOXYGEN_GENERATING_OUTPUT
#define MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(Type, size) \ #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); \ 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); \ 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); \ Math::Vector<size, T>::operator=(other); \
return *this; \ return *this; \
} \ } \
\ \
inline Type<T> operator-() const { \ Type<T> operator-() const { \
return Math::Vector<size, T>::operator-(); \ 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); \ Math::Vector<size, T>::operator+=(other); \
return *this; \ 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); \ 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); \ Math::Vector<size, T>::operator-=(other); \
return *this; \ 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); \ 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); \ Math::Vector<size, T>::operator*=(number); \
return *this; \ 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); \ 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); \ Math::Vector<size, T>::operator/=(number); \
return *this; \ 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); \ 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); \ Math::Vector<size, T>::operator*=(other); \
return *this; \ 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); \ 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); \ Math::Vector<size, T>::operator/=(other); \
return *this; \ 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); \ return Math::Vector<size, T>::operator/(other); \
} \ } \
\ \
inline Type<T> normalized() const { \ Type<T> normalized() const { \
return Math::Vector<size, T>::normalized(); \ 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); \ 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); \ return Math::Vector<size, T>::projected(other); \
} }
@ -735,6 +657,99 @@ extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utilit
} }
#endif #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 { namespace Corrade { namespace Utility {

32
src/Math/Vector2.h

@ -51,7 +51,7 @@ template<class T> class Vector2: public Vector<2, T> {
* @endcode * @endcode
* @see yAxis(), xScale(), Matrix3::right() * @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) * @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 xAxis() for more information.
* @see yScale(), Matrix3::up() * @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) * @brief Scaling vector in direction of X axis (width)
@ -70,7 +70,7 @@ template<class T> class Vector2: public Vector<2, T> {
* @endcode * @endcode
* @see yScale(), xAxis() * @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) * @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 xScale() for more information.
* @see yAxis() * @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 * @brief 2D cross product
@ -91,15 +91,15 @@ template<class T> class Vector2: public Vector<2, T> {
* @f] * @f]
* @see perpendicular(), dot(const Vector&, const Vector&) * @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); return Vector<2, T>::dot(a.perpendicular(), b);
} }
/** @copydoc Vector::Vector() */ /** @copydoc Vector::Vector() */
inline constexpr /*implicit*/ Vector2() {} constexpr /*implicit*/ Vector2() {}
/** @copydoc Vector::Vector(T) */ /** @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 * @brief Constructor
@ -108,21 +108,21 @@ template<class T> class Vector2: public Vector<2, T> {
* \boldsymbol v = \begin{pmatrix} x \\ y \end{pmatrix} * \boldsymbol v = \begin{pmatrix} x \\ y \end{pmatrix}
* @f] * @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>&) */ /** @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 */ /** @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 */ /** @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 */ T& x() { return (*this)[0]; } /**< @brief X component */
inline constexpr T x() const { return (*this)[0]; } /**< @overload */ constexpr T x() const { return (*this)[0]; } /**< @overload */
inline T& y() { return (*this)[1]; } /**< @brief Y component */ T& y() { return (*this)[1]; } /**< @brief Y component */
inline constexpr T y() const { return (*this)[1]; } /**< @overload */ constexpr T y() const { return (*this)[1]; } /**< @overload */
/** /**
* @brief Perpendicular vector * @brief Perpendicular vector
@ -132,7 +132,7 @@ template<class T> class Vector2: public Vector<2, T> {
* @f] * @f]
* @see cross(), dot(const Vector&, const Vector&), operator-() const * @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) 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 * @endcode
* @see yAxis(), zAxis(), xScale(), Matrix4::right() * @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) * @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 xAxis() for more information.
* @see yScale(), Matrix4::up() * @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) * @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 xAxis() for more information.
* @see zScale(), Matrix4::backward() * @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) * @brief Scaling vector in direction of X axis (width)
@ -80,7 +80,7 @@ template<class T> class Vector3: public Vector<3, T> {
* @endcode * @endcode
* @see yScale(), zScale(), xAxis() * @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) * @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 xScale() for more information.
* @see yAxis() * @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) * @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 xScale() for more information.
* @see zAxis() * @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 * @brief Cross product
@ -107,16 +107,16 @@ template<class T> class Vector3: public Vector<3, T> {
* @f] * @f]
* @see Vector2::cross() * @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) - return swizzle<'y', 'z', 'x'>(a)*swizzle<'z', 'x', 'y'>(b) -
swizzle<'z', 'x', 'y'>(a)*swizzle<'y', 'z', 'x'>(b); swizzle<'z', 'x', 'y'>(a)*swizzle<'y', 'z', 'x'>(b);
} }
/** @copydoc Vector::Vector() */ /** @copydoc Vector::Vector() */
inline constexpr /*implicit*/ Vector3() {} constexpr /*implicit*/ Vector3() {}
/** @copydoc Vector::Vector(T) */ /** @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 * @brief Constructor
@ -125,7 +125,7 @@ template<class T> class Vector3: public Vector<3, T> {
* \boldsymbol v = \begin{pmatrix} x \\ y \\ z \end{pmatrix} * \boldsymbol v = \begin{pmatrix} x \\ y \\ z \end{pmatrix}
* @f] * @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 * @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} * \boldsymbol v = \begin{pmatrix} v_x \\ v_y \\ z \end{pmatrix}
* @f] * @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>&) */ /** @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 */ /** @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 */ /** @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 */ T& x() { return (*this)[0]; } /**< @brief X component */
inline constexpr T x() const { return (*this)[0]; } /**< @overload */ constexpr T x() const { return (*this)[0]; } /**< @overload */
inline T& y() { return (*this)[1]; } /**< @brief Y component */ T& y() { return (*this)[1]; } /**< @brief Y component */
inline constexpr T y() const { return (*this)[1]; } /**< @overload */ constexpr T y() const { return (*this)[1]; } /**< @overload */
inline T& z() { return (*this)[2]; } /**< @brief Z component */ T& z() { return (*this)[2]; } /**< @brief Z component */
inline constexpr T z() const { return (*this)[2]; } /**< @overload */ constexpr T z() const { return (*this)[2]; } /**< @overload */
/** /**
* @brief XY part of the vector * @brief XY part of the vector
@ -158,8 +158,8 @@ template<class T> class Vector3: public Vector<3, T> {
* *
* @see swizzle() * @see swizzle()
*/ */
inline Vector2<T>& xy() { return Vector2<T>::from(Vector<3, T>::data()); } Vector2<T>& xy() { return Vector2<T>::from(Vector<3, T>::data()); }
inline constexpr const Vector2<T> xy() const { return {x(), y()}; } /**< @overload */ constexpr const Vector2<T> xy() const { return {x(), y()}; } /**< @overload */
MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(Vector3, 3) 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> { template<class T> class Vector4: public Vector<4, T> {
public: public:
/** @copydoc Vector::Vector() */ /** @copydoc Vector::Vector() */
inline constexpr /*implicit*/ Vector4() {} constexpr /*implicit*/ Vector4() {}
/** @copydoc Vector::Vector(T) */ /** @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 * @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} * \boldsymbol v = \begin{pmatrix} x \\ y \\ z \\ w \end{pmatrix}
* @f] * @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 * @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} * \boldsymbol v = \begin{pmatrix} v_x \\ v_y \\ v_z \\ w \end{pmatrix}
* @f] * @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>&) */ /** @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 */ /** @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 */ /** @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 */ T& x() { return (*this)[0]; } /**< @brief X component */
inline constexpr T x() const { return (*this)[0]; } /**< @overload */ constexpr T x() const { return (*this)[0]; } /**< @overload */
inline T& y() { return (*this)[1]; } /**< @brief Y component */ T& y() { return (*this)[1]; } /**< @brief Y component */
inline constexpr T y() const { return (*this)[1]; } /**< @overload */ constexpr T y() const { return (*this)[1]; } /**< @overload */
inline T& z() { return (*this)[2]; } /**< @brief Z component */ T& z() { return (*this)[2]; } /**< @brief Z component */
inline constexpr T z() const { return (*this)[2]; } /**< @overload */ constexpr T z() const { return (*this)[2]; } /**< @overload */
inline T& w() { return (*this)[3]; } /**< @brief W component */ T& w() { return (*this)[3]; } /**< @brief W component */
inline constexpr T w() const { return (*this)[3]; } /**< @overload */ constexpr T w() const { return (*this)[3]; } /**< @overload */
/** /**
* @brief XYZ part of the vector * @brief XYZ part of the vector
@ -90,8 +90,8 @@ template<class T> class Vector4: public Vector<4, T> {
* *
* @see swizzle() * @see swizzle()
*/ */
inline Vector3<T>& xyz() { return Vector3<T>::from(Vector<4, T>::data()); } Vector3<T>& xyz() { return Vector3<T>::from(Vector<4, T>::data()); }
inline constexpr const Vector3<T> xyz() const { return {x(), y(), z()}; } /**< @overload */ constexpr const Vector3<T> xyz() const { return {x(), y(), z()}; } /**< @overload */
/** /**
* @brief XY part of the vector * @brief XY part of the vector
@ -99,8 +99,8 @@ template<class T> class Vector4: public Vector<4, T> {
* *
* @see swizzle() * @see swizzle()
*/ */
inline Vector2<T>& xy() { return Vector2<T>::from(Vector<4, T>::data()); } Vector2<T>& xy() { return Vector2<T>::from(Vector<4, T>::data()); }
inline constexpr const Vector2<T> xy() const { return {x(), y()}; } /**< @overload */ constexpr const Vector2<T> xy() const { return {x(), y()}; } /**< @overload */
MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(Vector4, 4) MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(Vector4, 4)
}; };

Loading…
Cancel
Save