Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
7056 lines (5432 sloc) 276 KB
<
/*
Magnum::Math
— a graphics-focused vector math library
https://doc.magnum.graphics/magnum/namespaceMagnum_1_1Math.html
https://doc.magnum.graphics/magnum/namespaceMagnum_1_1EigenIntegration.html
https://doc.magnum.graphics/magnum/namespaceMagnum_1_1GlmIntegration.html
This is a single-header library generated from the Magnum project. With the
goal being easy integration, it's deliberately free of all comments to keep
the file size small. More info, changelogs and full docs here:
- Project homepage — https://magnum.graphics/magnum/
- Documentation — https://doc.magnum.graphics/
- GitHub project page — https://github.com/mosra/magnum
- GitHub Singles repository — https://github.com/mosra/magnum-singles
v2019.01-241-g93686746a (2019-04-03)
- Initial release
Generated from Corrade v2019.01-118-ge4d1f1c4 (2019-03-31),
Magnum v2019.01-241-g93686746a (2019-04-03) and
Magnum Integration v2019.01-39-gb70bbe2 (2019-03-25), 7055 / 9427 LoC
*/
/*
This file is part of Magnum.
Copyright © 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016,
2017, 2018, 2019 Vladimír Vondruš <mosra@centrum.cz>
Copyright © 2016 Ashwin Ravichandran <ashwinravichandran24@gmail.com>
Copyright © 2016, 2018 Jonathan Hale <squareys@googlemail.com>
Copyright © 2017 sigman78 <sigman78@gmail.com>
Copyright © 2018 Borislav Stanimirov <b.stanimirov@abv.bg>
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
#include <ciso646>
#ifdef _GLIBCXX_USE_STD_SPEC_FUNCS
#undef _GLIBCXX_USE_STD_SPEC_FUNCS
#define _GLIBCXX_USE_STD_SPEC_FUNCS 0
#endif
#include <cmath>
#include <cstddef>
#include <cstdint>
#include <cstdlib>
#include <type_traits>
#include <utility>
#if (!defined(CORRADE_ASSERT) || !defined(CORRADE_CONSTEXPR_ASSERT) || !defined(CORRADE_INTERNAL_ASSERT_OUTPUT) || !defined(CORRADE_ASSERT_UNREACHABLE)) && !defined(NDEBUG)
#include <cassert>
#endif
#if defined(_MSC_VER) && _MSC_VER <= 1920
#define CORRADE_MSVC2017_COMPATIBILITY
#endif
#if defined(_MSC_VER) && _MSC_VER <= 1910
#define CORRADE_MSVC2015_COMPATIBILITY
#endif
#ifdef _WIN32
#define CORRADE_TARGET_WINDOWS
#endif
#ifdef __EMSCRIPTEN__
#define CORRADE_TARGET_EMSCRIPTEN
#endif
#ifdef __ANDROID__
#define CORRADE_TARGET_ANDROID
#endif
#ifndef MAGNUM_EXPORT
#define MAGNUM_EXPORT
#endif
#ifndef Magnum_Types_h
#define Magnum_Types_h
namespace Magnum {
typedef std::uint8_t UnsignedByte;
typedef std::int8_t Byte;
typedef std::uint16_t UnsignedShort;
typedef std::int16_t Short;
typedef std::uint32_t UnsignedInt;
typedef std::int32_t Int;
#ifndef CORRADE_TARGET_EMSCRIPTEN
typedef std::uint64_t UnsignedLong;
typedef std::int64_t Long;
#endif
typedef float Float;
typedef double Double;
}
#endif
#ifndef Magnum_Math_Math_h
#define Magnum_Math_Math_h
namespace Magnum { namespace Math {
template<std::size_t> class BoolVector;
template<class> struct Constants;
template<class> class Complex;
template<class> class Dual;
template<class> class DualComplex;
template<class> class DualQuaternion;
template<class> class Frustum;
template<std::size_t, class> class Matrix;
template<class T> using Matrix2x2 = Matrix<2, T>;
template<class T> using Matrix3x3 = Matrix<3, T>;
template<class T> using Matrix4x4 = Matrix<4, T>;
template<class> class Matrix3;
template<class> class Matrix4;
template<class> class Quaternion;
template<std::size_t, std::size_t, class> class RectangularMatrix;
template<class T> using Matrix2x3 = RectangularMatrix<2, 3, T>;
template<class T> using Matrix3x2 = RectangularMatrix<3, 2, T>;
template<class T> using Matrix2x4 = RectangularMatrix<2, 4, T>;
template<class T> using Matrix4x2 = RectangularMatrix<4, 2, T>;
template<class T> using Matrix3x4 = RectangularMatrix<3, 4, T>;
template<class T> using Matrix4x3 = RectangularMatrix<4, 3, T>;
template<template<class> class, class> class Unit;
template<class> class Deg;
template<class> class Rad;
class Half;
template<std::size_t, class> class Vector;
template<class> class Vector2;
template<class> class Vector3;
template<class> class Vector4;
template<class> struct ColorHsv;
template<class> class Color3;
template<class> class Color4;
template<UnsignedInt, UnsignedInt, class> class Bezier;
template<UnsignedInt dimensions, class T> using QuadraticBezier = Bezier<2, dimensions, T>;
template<UnsignedInt dimensions, class T> using CubicBezier = Bezier<3, dimensions, T>;
template<class T> using QuadraticBezier2D = QuadraticBezier<2, T>;
template<class T> using QuadraticBezier3D = QuadraticBezier<3, T>;
template<class T> using CubicBezier2D = CubicBezier<2, T>;
template<class T> using CubicBezier3D = CubicBezier<3, T>;
template<class> class CubicHermite;
template<class T> using CubicHermite1D = CubicHermite<T>;
template<class T> using CubicHermite2D = CubicHermite<Vector2<T>>;
template<class T> using CubicHermite3D = CubicHermite<Vector3<T>>;
template<class T> using CubicHermiteComplex = CubicHermite<Complex<T>>;
template<class T> using CubicHermiteQuaternion = CubicHermite<Quaternion<T>>;
template<UnsignedInt, class> class Range;
template<class T> using Range1D = Range<1, T>;
template<class> class Range2D;
template<class> class Range3D;
namespace Implementation {
template<class> struct StrictWeakOrdering;
}
}}
#endif
#ifndef MagnumMath_hpp
#define MagnumMath_hpp
namespace Magnum {
typedef Math::Half Half;
typedef Math::Vector2<Float> Vector2;
typedef Math::Vector3<Float> Vector3;
typedef Math::Vector4<Float> Vector4;
typedef Math::Vector2<UnsignedInt> Vector2ui;
typedef Math::Vector3<UnsignedInt> Vector3ui;
typedef Math::Vector4<UnsignedInt> Vector4ui;
typedef Math::Vector2<Int> Vector2i;
typedef Math::Vector3<Int> Vector3i;
typedef Math::Vector4<Int> Vector4i;
typedef Math::Color3<Float> Color3;
typedef Math::Color4<Float> Color4;
typedef Math::Color3<UnsignedByte> Color3ub;
typedef Math::Color4<UnsignedByte> Color4ub;
typedef Math::Matrix3<Float> Matrix3;
typedef Math::Matrix4<Float> Matrix4;
typedef Math::Matrix2x2<Float> Matrix2x2;
typedef Math::Matrix3x3<Float> Matrix3x3;
typedef Math::Matrix4x4<Float> Matrix4x4;
typedef Math::Matrix2x3<Float> Matrix2x3;
typedef Math::Matrix3x2<Float> Matrix3x2;
typedef Math::Matrix2x4<Float> Matrix2x4;
typedef Math::Matrix4x2<Float> Matrix4x2;
typedef Math::Matrix3x4<Float> Matrix3x4;
typedef Math::Matrix4x3<Float> Matrix4x3;
typedef Math::QuadraticBezier2D<Float> QuadraticBezier2D;
typedef Math::QuadraticBezier3D<Float> QuadraticBezier3D;
typedef Math::CubicBezier2D<Float> CubicBezier2D;
typedef Math::CubicBezier3D<Float> CubicBezier3D;
typedef Math::CubicHermite1D<Float> CubicHermite1D;
typedef Math::CubicHermite2D<Float> CubicHermite2D;
typedef Math::CubicHermite3D<Float> CubicHermite3D;
typedef Math::CubicHermiteComplex<Float> CubicHermiteComplex;
typedef Math::CubicHermiteQuaternion<Float> CubicHermiteQuaternion;
typedef Math::Complex<Float> Complex;
typedef Math::DualComplex<Float> DualComplex;
typedef Math::Quaternion<Float> Quaternion;
typedef Math::DualQuaternion<Float> DualQuaternion;
typedef Math::Constants<Float> Constants;
typedef Math::Deg<Float> Deg;
typedef Math::Rad<Float> Rad;
typedef Math::Range1D<Float> Range1D;
typedef Math::Range2D<Float> Range2D;
typedef Math::Range3D<Float> Range3D;
typedef Math::Range1D<Int> Range1Di;
typedef Math::Range2D<Int> Range2Di;
typedef Math::Range3D<Int> Range3Di;
typedef Math::Frustum<Float> Frustum;
typedef Math::Vector2<Double> Vector2d;
typedef Math::Vector3<Double> Vector3d;
typedef Math::Vector4<Double> Vector4d;
typedef Math::Matrix3<Double> Matrix3d;
typedef Math::Matrix4<Double> Matrix4d;
typedef Math::Matrix2x2<Double> Matrix2x2d;
typedef Math::Matrix3x3<Double> Matrix3x3d;
typedef Math::Matrix4x4<Double> Matrix4x4d;
typedef Math::Matrix2x3<Double> Matrix2x3d;
typedef Math::Matrix3x2<Double> Matrix3x2d;
typedef Math::Matrix2x4<Double> Matrix2x4d;
typedef Math::Matrix4x2<Double> Matrix4x2d;
typedef Math::Matrix3x4<Double> Matrix3x4d;
typedef Math::Matrix4x3<Double> Matrix4x3d;
typedef Math::QuadraticBezier2D<Float> QuadraticBezier2Dd;
typedef Math::QuadraticBezier3D<Float> QuadraticBezier3Dd;
typedef Math::CubicBezier2D<Float> CubicBezier2Dd;
typedef Math::CubicBezier3D<Float> CubicBezier3Dd;
typedef Math::CubicHermite1D<Double> CubicHermite1Dd;
typedef Math::CubicHermite2D<Double> CubicHermite2Dd;
typedef Math::CubicHermite3D<Double> CubicHermite3Dd;
typedef Math::CubicHermiteComplex<Double> CubicHermiteComplexd;
typedef Math::CubicHermiteQuaternion<Double> CubicHermiteQuaterniond;
typedef Math::Complex<Double> Complexd;
typedef Math::DualComplex<Double> DualComplexd;
typedef Math::Quaternion<Double> Quaterniond;
typedef Math::DualQuaternion<Double> DualQuaterniond;
typedef Math::Constants<Double> Constantsd;
typedef Math::Deg<Double> Degd;
typedef Math::Rad<Double> Radd;
typedef Math::Range1D<Double> Range1Dd;
typedef Math::Range2D<Double> Range2Dd;
typedef Math::Range3D<Double> Range3Dd;
typedef Math::Frustum<Double> Frustumd;
}
#endif
#ifndef Magnum_Math_Constants_h
#define Magnum_Math_Constants_h
namespace Magnum { namespace Math {
template<class> struct Constants;
template<> struct Constants<Double> {
Constants() = delete;
static constexpr Double pi() { return 3.141592653589793; }
static constexpr Double piHalf() { return 1.570796326794897; }
static constexpr Double piQuarter() { return 0.785398163397448; }
static constexpr Double tau() { return 6.283185307179586; }
static constexpr Double e() { return 2.718281828459045; }
static constexpr Double sqrt2() { return 1.414213562373095; }
static constexpr Double sqrt3() { return 1.732050807568877; }
static constexpr Double sqrtHalf() { return 0.707106781186547; }
static constexpr Double nan() { return Double(NAN); }
static constexpr Double inf() { return HUGE_VAL; }
};
template<> struct Constants<Float> {
Constants() = delete;
static constexpr Float pi() { return 3.141592654f; }
static constexpr Float piHalf() { return 1.570796327f; }
static constexpr Float piQuarter() { return 0.785398163f; }
static constexpr Float tau() { return 6.283185307f; }
static constexpr Float e() { return 2.718281828f; }
static constexpr Float sqrt2() { return 1.414213562f; }
static constexpr Float sqrt3() { return 1.732050808f; }
static constexpr Float sqrtHalf() { return 0.707106781f; }
static constexpr Float nan() { return NAN; }
static constexpr Float inf() { return HUGE_VALF; }
};
}}
#endif
#ifndef Magnum_Math_TypeTraits_h
#define Magnum_Math_TypeTraits_h
#ifndef FLOAT_EQUALITY_PRECISION
#define FLOAT_EQUALITY_PRECISION 1.0e-5f
#endif
#ifndef DOUBLE_EQUALITY_PRECISION
#define DOUBLE_EQUALITY_PRECISION 1.0e-14
#endif
#ifndef LONG_DOUBLE_EQUALITY_PRECISION
#if !defined(_MSC_VER) && (!defined(CORRADE_TARGET_ANDROID) || __LP64__)
#define LONG_DOUBLE_EQUALITY_PRECISION 1.0e-17l
#else
#define LONG_DOUBLE_EQUALITY_PRECISION 1.0e-14
#endif
#endif
namespace Magnum { namespace Math {
namespace Implementation {
template<class T> struct TypeTraitsDefault {
TypeTraitsDefault() = delete;
constexpr static bool equals(T a, T b) {
return a == b;
}
constexpr static bool equalsZero(T a, T) {
return !a;
}
};
}
template<class T> struct TypeTraits: Implementation::TypeTraitsDefault<T> {
};
namespace Implementation {
template<class> struct TypeTraitsName;
#define _c(type) template<> struct TypeTraitsName<type> { \
constexpr static const char* name() { return #type; } \
};
_c(UnsignedByte)
_c(Byte)
_c(UnsignedShort)
_c(Short)
_c(UnsignedInt)
_c(Int)
#ifndef CORRADE_TARGET_EMSCRIPTEN
_c(UnsignedLong)
_c(Long)
#endif
_c(Float)
_c(Double)
_c(long double)
#undef _c
template<class T> struct TypeTraitsIntegral: TypeTraitsDefault<T>, TypeTraitsName<T> {
constexpr static T epsilon() { return T(1); }
};
}
template<> struct TypeTraits<UnsignedByte>: Implementation::TypeTraitsIntegral<UnsignedByte> {
typedef Float FloatingPointType;
};
template<> struct TypeTraits<Byte>: Implementation::TypeTraitsIntegral<Byte> {
typedef Float FloatingPointType;
};
template<> struct TypeTraits<UnsignedShort>: Implementation::TypeTraitsIntegral<UnsignedShort> {
typedef Float FloatingPointType;
};
template<> struct TypeTraits<Short>: Implementation::TypeTraitsIntegral<Short> {
typedef Float FloatingPointType;
};
template<> struct TypeTraits<UnsignedInt>: Implementation::TypeTraitsIntegral<UnsignedInt> {
typedef Double FloatingPointType;
};
template<> struct TypeTraits<Int>: Implementation::TypeTraitsIntegral<Int> {
typedef Double FloatingPointType;
};
#ifndef CORRADE_TARGET_EMSCRIPTEN
template<> struct TypeTraits<UnsignedLong>: Implementation::TypeTraitsIntegral<UnsignedLong> {
typedef long double FloatingPointType;
};
template<> struct TypeTraits<Long>: Implementation::TypeTraitsIntegral<Long> {
typedef long double FloatingPointType;
};
#endif
namespace Implementation {
template<class T> struct TypeTraitsFloatingPoint: TypeTraitsName<T> {
TypeTraitsFloatingPoint() = delete;
static bool equals(T a, T b);
static bool equalsZero(T a, T epsilon);
};
template<class T> bool TypeTraitsFloatingPoint<T>::equals(const T a, const T b) {
if(a == b) return true;
const T absA = std::abs(a);
const T absB = std::abs(b);
const T difference = std::abs(a - b);
if(a == T{} || b == T{} || difference < TypeTraits<T>::epsilon())
return difference < TypeTraits<T>::epsilon();
return difference/(absA + absB) < TypeTraits<T>::epsilon();
}
template<class T> bool TypeTraitsFloatingPoint<T>::equalsZero(const T a, const T magnitude) {
if(a == T(0.0)) return true;
const T absA = std::abs(a);
if(absA < TypeTraits<T>::epsilon())
return absA < TypeTraits<T>::epsilon();
return absA*T(0.5)/magnitude < TypeTraits<T>::epsilon();
}
}
template<> struct TypeTraits<Float>: Implementation::TypeTraitsFloatingPoint<Float> {
typedef Float FloatingPointType;
constexpr static Float epsilon() { return FLOAT_EQUALITY_PRECISION; }
};
template<> struct TypeTraits<Double>: Implementation::TypeTraitsFloatingPoint<Double> {
typedef Double FloatingPointType;
constexpr static Double epsilon() { return DOUBLE_EQUALITY_PRECISION; }
};
template<> struct TypeTraits<long double>: Implementation::TypeTraitsFloatingPoint<long double> {
typedef long double FloatingPointType;
constexpr static long double epsilon() { return LONG_DOUBLE_EQUALITY_PRECISION; }
};
namespace Implementation {
template<class T> inline bool isNormalizedSquared(T lengthSquared) {
return std::abs(lengthSquared - T(1)) < T(2)*TypeTraits<T>::epsilon();
}
}
}}
#endif
#ifndef Corrade_Containers_Tags_h
#define Corrade_Containers_Tags_h
namespace Corrade { namespace Containers {
struct DefaultInitT {
struct Init{};
constexpr explicit DefaultInitT(Init) {}
};
struct ValueInitT {
struct Init{};
constexpr explicit ValueInitT(Init) {}
};
struct NoInitT {
struct Init{};
constexpr explicit NoInitT(Init) {}
};
struct NoCreateT {
struct Init{};
constexpr explicit NoCreateT(Init) {}
};
struct DirectInitT {
struct Init{};
constexpr explicit DirectInitT(Init) {}
};
struct InPlaceInitT {
struct Init{};
constexpr explicit InPlaceInitT(Init) {}
};
constexpr DefaultInitT DefaultInit{DefaultInitT::Init{}};
constexpr ValueInitT ValueInit{ValueInitT::Init{}};
constexpr NoInitT NoInit{NoInitT::Init{}};
constexpr NoCreateT NoCreate{NoCreateT::Init{}};
constexpr DirectInitT DirectInit{DirectInitT::Init{}};
constexpr InPlaceInitT InPlaceInit{InPlaceInitT::Init{}};
}}
#endif
#ifndef Magnum_Math_Tags_h
#define Magnum_Math_Tags_h
namespace Magnum { namespace Math {
typedef Corrade::Containers::NoInitT NoInitT;
struct ZeroInitT {
struct Init{};
constexpr explicit ZeroInitT(Init) {}
};
struct IdentityInitT {
struct Init{};
constexpr explicit IdentityInitT(Init) {}
};
using Corrade::Containers::NoInit;
constexpr ZeroInitT ZeroInit{ZeroInitT::Init{}};
constexpr IdentityInitT IdentityInit{IdentityInitT::Init{}};
}}
#endif
#ifndef Magnum_Math_Unit_h
#define Magnum_Math_Unit_h
namespace Magnum { namespace Math {
template<template<class> class Derived, class T> class Unit {
template<template<class> class, class> friend class Unit;
public:
typedef T Type;
constexpr /*implicit*/ Unit(ZeroInitT = ZeroInit) noexcept: _value(T(0)) {}
explicit Unit(NoInitT) noexcept {}
constexpr explicit Unit(T value) noexcept: _value(value) {}
template<class U> constexpr explicit Unit(Unit<Derived, U> value) noexcept: _value(T(value._value)) {}
constexpr /*implicit*/ Unit(const Unit<Derived, T>& other) noexcept = default;
constexpr explicit operator T() const { return _value; }
constexpr bool operator==(Unit<Derived, T> other) const {
return TypeTraits<T>::equals(_value, other._value);
}
constexpr bool operator!=(Unit<Derived, T> other) const {
return !operator==(other);
}
constexpr bool operator<(Unit<Derived, T> other) const {
return _value < other._value;
}
constexpr bool operator>(Unit<Derived, T> other) const {
return _value > other._value;
}
constexpr bool operator<=(Unit<Derived, T> other) const {
return !operator>(other);
}
constexpr bool operator>=(Unit<Derived, T> other) const {
return !operator<(other);
}
constexpr Unit<Derived, T> operator-() const {
return Unit<Derived, T>(-_value);
}
Unit<Derived, T>& operator+=(Unit<Derived, T> other) {
_value += other._value;
return *this;
}
constexpr Unit<Derived, T> operator+(Unit<Derived, T> other) const {
return Unit<Derived, T>(_value + other._value);
}
Unit<Derived, T>& operator-=(Unit<Derived, T> other) {
_value -= other._value;
return *this;
}
constexpr Unit<Derived, T> operator-(Unit<Derived, T> other) const {
return Unit<Derived, T>(_value - other._value);
}
Unit<Derived, T>& operator*=(T number) {
_value *= number;
return *this;
}
constexpr Unit<Derived, T> operator*(T number) const {
return Unit<Derived, T>(_value*number);
}
Unit<Derived, T>& operator/=(T number) {
_value /= number;
return *this;
}
constexpr Unit<Derived, T> operator/(T number) const {
return Unit<Derived, T>(_value/number);
}
constexpr T operator/(Unit<Derived, T> other) const {
return _value/other._value;
}
private:
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;
}
}}
#endif
#ifndef Magnum_Math_Angle_h
#define Magnum_Math_Angle_h
namespace Magnum { namespace Math {
template<class T> class Deg: public Unit<Deg, T> {
public:
constexpr /*implicit*/ Deg(ZeroInitT = ZeroInit) noexcept
: Unit<Math::Deg, T>{ZeroInit}
{}
explicit Deg(NoInitT) noexcept
: Unit<Math::Deg, T>{NoInit}
{}
constexpr explicit Deg(T value) noexcept: Unit<Math::Deg, T>(value) {}
template<class U> constexpr explicit Deg(Unit<Math::Deg, U> value) noexcept: Unit<Math::Deg, T>(value) {}
constexpr /*implicit*/ Deg(Unit<Math::Deg, T> other) noexcept: Unit<Math::Deg, T>(other) {}
constexpr /*implicit*/ Deg(Unit<Rad, T> value);
};
namespace Literals {
constexpr Deg<Double> operator "" _deg(long double value) { return Deg<Double>(Double(value)); }
constexpr Deg<Float> operator "" _degf(long double value) { return Deg<Float>(Float(value)); }
}
template<class T> class Rad: public Unit<Rad, T> {
public:
constexpr /*implicit*/ Rad(ZeroInitT = ZeroInit) noexcept
: Unit<Math::Rad, T>{ZeroInit}
{}
explicit Rad(NoInitT) noexcept
: Unit<Math::Rad, T>{NoInit}
{}
constexpr explicit Rad(T value) noexcept: Unit<Math::Rad, T>(value) {}
template<class U> constexpr explicit Rad(Unit<Math::Rad, U> value) noexcept: Unit<Math::Rad, T>(value) {}
constexpr /*implicit*/ Rad(Unit<Math::Rad, T> value) noexcept: Unit<Math::Rad, T>(value) {}
constexpr /*implicit*/ Rad(Unit<Deg, T> value);
};
namespace Literals {
constexpr Rad<Double> operator "" _rad(long double value) { return Rad<Double>(Double(value)); }
constexpr Rad<Float> operator "" _radf(long double value) { return Rad<Float>(Float(value)); }
}
template<class T> constexpr Deg<T>::Deg(Unit<Rad, T> value): Unit<Math::Deg, T>(T(180)*T(value)/Math::Constants<T>::pi()) {}
template<class T> constexpr Rad<T>::Rad(Unit<Deg, T> value): Unit<Math::Rad, T>(T(value)*Math::Constants<T>::pi()/T(180)) {}
}}
namespace Corrade { namespace Utility {
}}
#endif
#ifndef CORRADE_ASSERT
#ifdef NDEBUG
#define CORRADE_ASSERT(condition, message, returnValue) do {} while(0)
#else
#define CORRADE_ASSERT(condition, message, returnValue) assert(condition)
#endif
#endif
#ifndef CORRADE_CONSTEXPR_ASSERT
#ifdef NDEBUG
#define CORRADE_CONSTEXPR_ASSERT(condition, message) static_cast<void>(0)
#else
#define CORRADE_CONSTEXPR_ASSERT(condition, message) \
static_cast<void>((condition) ? 0 : ([&]() { \
assert(!#condition); \
}(), 0))
#endif
#endif
#ifndef CORRADE_INTERNAL_ASSERT_OUTPUT
#ifdef NDEBUG
#define CORRADE_INTERNAL_ASSERT_OUTPUT(call) \
static_cast<void>(call)
#else
#define CORRADE_INTERNAL_ASSERT_OUTPUT(call) assert(call)
#endif
#endif
#ifndef CORRADE_ASSERT_UNREACHABLE
#ifdef NDEBUG
#ifdef __GNUC__
#define CORRADE_ASSERT_UNREACHABLE() __builtin_unreachable()
#else
#define CORRADE_ASSERT_UNREACHABLE() std::abort()
#endif
#else
#define CORRADE_ASSERT_UNREACHABLE() assert(false)
#endif
#endif
#ifndef Magnum_Math_BoolVector_h
#define Magnum_Math_BoolVector_h
namespace Magnum { namespace Math {
namespace Implementation {
template<std::size_t, class> struct BoolVectorConverter;
template<std::size_t ...> struct Sequence {};
template<std::size_t N, std::size_t ...sequence> struct GenerateSequence:
GenerateSequence<N-1, N-1, sequence...> {};
template<std::size_t ...sequence> struct GenerateSequence<0, sequence...> {
typedef Sequence<sequence...> Type;
};
template<class T> constexpr T repeat(T value, std::size_t) { return value; }
}
template<std::size_t size> class BoolVector {
static_assert(size != 0, "BoolVector cannot have zero elements");
public:
enum: std::size_t {
Size = size,
DataSize = (size-1)/8+1
};
constexpr /*implicit*/ BoolVector(ZeroInitT = ZeroInit) noexcept: _data{} {}
explicit BoolVector(NoInitT) noexcept {}
template<class ...T, class U = typename std::enable_if<sizeof...(T)+1 == DataSize, bool>::type> constexpr /*implicit*/ BoolVector(UnsignedByte first, T... next) noexcept: _data{first, UnsignedByte(next)...} {}
template<class T, class U = typename std::enable_if<std::is_same<bool, T>::value && size != 1, bool>::type> constexpr explicit BoolVector(T value) noexcept: BoolVector(typename Implementation::GenerateSequence<DataSize>::Type(), value ? FullSegmentMask : 0) {}
template<class U, class V = decltype(Implementation::BoolVectorConverter<size, U>::from(std::declval<U>()))> constexpr explicit BoolVector(const U& other) noexcept: BoolVector{Implementation::BoolVectorConverter<size, U>::from(other)} {}
constexpr /*implicit*/ BoolVector(const BoolVector<size>&) noexcept = default;
template<class U, class V = decltype(Implementation::BoolVectorConverter<size, U>::to(std::declval<BoolVector<size>>()))> constexpr explicit operator U() const {
return Implementation::BoolVectorConverter<size, U>::to(*this);
}
UnsignedByte* data() { return _data; }
constexpr const UnsignedByte* data() const { return _data; }
constexpr bool operator[](std::size_t i) const {
return (_data[i/8] >> i%8) & 0x01;
}
BoolVector<size>& set(std::size_t i, bool value) {
value ? _data[i/8] |= (1 << i%8) :
_data[i/8] &= ~(1 << i%8);
return *this;
}
bool operator==(const BoolVector<size>& other) const;
bool operator!=(const BoolVector<size>& other) const {
return !operator==(other);
}
explicit operator bool() const { return all(); }
bool all() const;
bool none() const;
bool any() const { return !none(); }
BoolVector<size> operator~() const;
BoolVector<size> operator!() const { return operator~(); }
BoolVector<size>& operator&=(const BoolVector<size>& other) {
for(std::size_t i = 0; i != DataSize; ++i)
_data[i] &= other._data[i];
return *this;
}
BoolVector<size> operator&(const BoolVector<size>& other) const {
return BoolVector<size>(*this) &= other;
}
BoolVector<size> operator&&(const BoolVector<size>& other) const {
return BoolVector<size>(*this) &= other;
}
BoolVector<size>& operator|=(const BoolVector<size>& other) {
for(std::size_t i = 0; i != DataSize; ++i)
_data[i] |= other._data[i];
return *this;
}
BoolVector<size> operator|(const BoolVector<size>& other) const {
return BoolVector<size>(*this) |= other;
}
BoolVector<size> operator||(const BoolVector<size>& other) const {
return BoolVector<size>(*this) |= other;
}
BoolVector<size>& operator^=(const BoolVector<size>& other) {
for(std::size_t i = 0; i != DataSize; ++i)
_data[i] ^= other._data[i];
return *this;
}
BoolVector<size> operator^(const BoolVector<size>& other) const {
return BoolVector<size>(*this) ^= other;
}
private:
enum: UnsignedByte {
FullSegmentMask = 0xFF,
LastSegmentMask = (1 << size%8) - 1
};
template<std::size_t ...sequence> constexpr explicit BoolVector(Implementation::Sequence<sequence...>, UnsignedByte value): _data{Implementation::repeat(value, sequence)...} {}
UnsignedByte _data[(size-1)/8+1];
};
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;
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 {
for(std::size_t i = 0; i != size/8; ++i)
if(_data[i] != FullSegmentMask) return false;
if(size%8 && (_data[DataSize-1] & LastSegmentMask) != LastSegmentMask)
return false;
return true;
}
template<std::size_t size> inline bool BoolVector<size>::none() const {
for(std::size_t i = 0; i != size/8; ++i)
if(_data[i]) return false;
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{NoInit};
for(std::size_t i = 0; i != DataSize; ++i)
out._data[i] = ~_data[i];
return out;
}
namespace Implementation {
template<std::size_t size> struct StrictWeakOrdering<BoolVector<size>> {
bool operator()(const BoolVector<size>& a, const BoolVector<size>& b) const {
auto ad = a.data();
auto bd = b.data();
for(std::size_t i = 0; i < BoolVector<size>::DataSize - 1; ++i) {
if(ad[i] < bd[i])
return true;
if(ad[i] > bd[i])
return false;
}
constexpr UnsignedByte mask = UnsignedByte(0xFF) >> (BoolVector<size>::DataSize * 8 - size);
constexpr std::size_t i = BoolVector<size>::DataSize - 1;
return (ad[i] & mask) < (bd[i] & mask);
}
};
}
}}
#endif
#ifndef Magnum_Math_Vector_h
#define Magnum_Math_Vector_h
namespace Magnum { namespace Math {
template<class T> constexpr typename std::enable_if<std::is_arithmetic<T>::value, T>::type min(T a, T b) {
return b < a ? b : a;
}
template<class T> constexpr typename std::enable_if<std::is_arithmetic<T>::value, T>::type max(T a, T b) {
return a < b ? b : a;
}
namespace Implementation {
template<std::size_t, class, class> struct VectorConverter;
template<class T, class U> T lerp(const T& a, const T& b, U t) {
return T((U(1) - t)*a + t*b);
}
template<bool integral> struct IsZero;
template<> struct IsZero<false> {
template<std::size_t size, class T> bool operator()(const Vector<size, T>& vec) const {
return std::abs(vec.dot()) < TypeTraits<T>::epsilon();
}
};
template<> struct IsZero<true> {
template<std::size_t size, class T> bool operator()(const Vector<size, T>& vec) const {
return vec == Vector<size, T>{};
}
};
template<std::size_t, class> struct MatrixDeterminant;
}
template<std::size_t size, class T> inline T dot(const Vector<size, T>& a, const Vector<size, T>& b) {
return (a*b).sum();
}
template<std::size_t size, class FloatingPoint> inline
typename std::enable_if<std::is_floating_point<FloatingPoint>::value, Rad<FloatingPoint>>::type
angle(const Vector<size, FloatingPoint>& normalizedA, const Vector<size, FloatingPoint>& normalizedB) {
CORRADE_ASSERT(normalizedA.isNormalized() && normalizedB.isNormalized(),
"Math::angle(): vectors" << normalizedA << "and" << normalizedB << "are not normalized", {});
return Rad<FloatingPoint>(std::acos(dot(normalizedA, normalizedB)));
}
template<std::size_t size, class T> class Vector {
static_assert(size != 0, "Vector cannot have zero elements");
public:
typedef T Type;
enum: std::size_t {
Size = size
};
static Vector<size, T>& from(T* data) {
return *reinterpret_cast<Vector<size, T>*>(data);
}
static const Vector<size, T>& from(const T* data) {
return *reinterpret_cast<const Vector<size, T>*>(data);
}
template<std::size_t otherSize> constexpr static Vector<size, T> pad(const Vector<otherSize, T>& a, T value = T(0)) {
return padInternal<otherSize>(typename Implementation::GenerateSequence<size>::Type(), a, value);
}
constexpr /*implicit*/ Vector(ZeroInitT = ZeroInit) noexcept: _data{} {}
explicit Vector(NoInitT) noexcept {}
template<class ...U, class V = typename std::enable_if<sizeof...(U)+1 == size, T>::type> constexpr /*implicit*/ Vector(T first, U... next) noexcept: _data{first, next...} {}
template<class U, class V = typename std::enable_if<std::is_same<T, U>::value && size != 1, T>::type> constexpr explicit Vector(U value) noexcept: Vector(typename Implementation::GenerateSequence<size>::Type(), value) {}
template<class U> constexpr explicit Vector(const Vector<size, U>& other) noexcept: Vector(typename Implementation::GenerateSequence<size>::Type(), other) {}
template<class U, class V = decltype(Implementation::VectorConverter<size, T, U>::from(std::declval<U>()))> constexpr explicit Vector(const U& other) noexcept: Vector(Implementation::VectorConverter<size, T, U>::from(other)) {}
constexpr /*implicit*/ Vector(const Vector<size, T>&) noexcept = default;
template<class U, class V = decltype(Implementation::VectorConverter<size, T, U>::to(std::declval<Vector<size, T>>()))> constexpr explicit operator U() const {
return Implementation::VectorConverter<size, T, U>::to(*this);
}
T* data() { return _data; }
constexpr const T* data() const { return _data; }
T& operator[](std::size_t pos) { return _data[pos]; }
constexpr T operator[](std::size_t pos) const { return _data[pos]; }
bool operator==(const Vector<size, T>& other) const {
for(std::size_t i = 0; i != size; ++i)
if(!TypeTraits<T>::equals(_data[i], other._data[i])) return false;
return true;
}
bool operator!=(const Vector<size, T>& other) const {
return !operator==(other);
}
BoolVector<size> operator<(const Vector<size, T>& other) const;
BoolVector<size> operator<=(const Vector<size, T>& other) const;
BoolVector<size> operator>=(const Vector<size, T>& other) const;
BoolVector<size> operator>(const Vector<size, T>& other) const;
bool isZero() const {
return Implementation::IsZero<std::is_integral<T>::value>{}(*this);
}
bool isNormalized() const {
return Implementation::isNormalizedSquared(dot());
}
Vector<size, T> operator-() const;
Vector<size, T>& operator+=(const Vector<size, T>& other) {
for(std::size_t i = 0; i != size; ++i)
_data[i] += other._data[i];
return *this;
}
Vector<size, T> operator+(const Vector<size, T>& other) const {
return Vector<size, T>(*this) += other;
}
Vector<size, T>& operator-=(const Vector<size, T>& other) {
for(std::size_t i = 0; i != size; ++i)
_data[i] -= other._data[i];
return *this;
}
Vector<size, T> operator-(const Vector<size, T>& other) const {
return Vector<size, T>(*this) -= other;
}
Vector<size, T>& operator*=(T number) {
for(std::size_t i = 0; i != size; ++i)
_data[i] *= number;
return *this;
}
Vector<size, T> operator*(T number) const {
return Vector<size, T>(*this) *= number;
}
Vector<size, T>& operator/=(T number) {
for(std::size_t i = 0; i != size; ++i)
_data[i] /= number;
return *this;
}
Vector<size, T> operator/(T number) const {
return Vector<size, T>(*this) /= number;
}
Vector<size, T>& operator*=(const Vector<size, T>& other) {
for(std::size_t i = 0; i != size; ++i)
_data[i] *= other._data[i];
return *this;
}
Vector<size, T> operator*(const Vector<size, T>& other) const {
return Vector<size, T>(*this) *= other;
}
Vector<size, T>& operator/=(const Vector<size, T>& other) {
for(std::size_t i = 0; i != size; ++i)
_data[i] /= other._data[i];
return *this;
}
Vector<size, T> operator/(const Vector<size, T>& other) const {
return Vector<size, T>(*this) /= other;
}
T dot() const { return Math::dot(*this, *this); }
T length() const { return std::sqrt(dot()); }
template<class U = T> typename std::enable_if<std::is_floating_point<U>::value, T>::type
lengthInverted() const { return T(1)/length(); }
template<class U = T> typename std::enable_if<std::is_floating_point<U>::value, Vector<size, T>>::type
normalized() const { return *this*lengthInverted(); }
template<class U = T> typename std::enable_if<std::is_floating_point<U>::value, Vector<size, T>>::type
resized(T length) const {
return *this*(lengthInverted()*length);
}
template<class U = T> typename std::enable_if<std::is_floating_point<U>::value, Vector<size, T>>::type
projected(const Vector<size, T>& line) const {
return line*Math::dot(*this, line)/line.dot();
}
template<class U = T> typename std::enable_if<std::is_floating_point<U>::value, Vector<size, T>>::type
projectedOntoNormalized(const Vector<size, T>& line) const;
constexpr Vector<size, T> flipped() const {
return flippedInternal(typename Implementation::GenerateSequence<size>::Type{});
}
T sum() const;
T product() const;
T min() const;
T max() const;
std::pair<T, T> minmax() const;
protected:
T _data[size];
private:
template<std::size_t, class> friend class Vector;
template<std::size_t, std::size_t, class> friend class RectangularMatrix;
template<std::size_t, class> friend class Matrix;
template<std::size_t, class> friend struct Implementation::MatrixDeterminant;
template<class U, std::size_t ...sequence> constexpr explicit Vector(Implementation::Sequence<sequence...>, const Vector<size, U>& vector) noexcept: _data{T(vector._data[sequence])...} {}
template<std::size_t ...sequence> constexpr explicit Vector(Implementation::Sequence<sequence...>, T value) noexcept: _data{Implementation::repeat(value, sequence)...} {}
template<std::size_t otherSize, std::size_t ...sequence> constexpr static Vector<size, T> padInternal(Implementation::Sequence<sequence...>, const Vector<otherSize, T>& a, T value) {
return {sequence < otherSize ? a[sequence] : value...};
}
template<std::size_t ...sequence> constexpr Vector<size, T> flippedInternal(Implementation::Sequence<sequence...>) const {
return {_data[size - 1 - sequence]...};
}
};
template<std::size_t size, class T> inline Vector<size, T> operator*(
typename std::common_type<T>::type
number, const Vector<size, T>& vector)
{
return vector*number;
}
template<std::size_t size, class T> inline Vector<size, T> operator/(
typename std::common_type<T>::type
number, const Vector<size, T>& vector)
{
Vector<size, T> out;
for(std::size_t i = 0; i != size; ++i)
out[i] = number/vector[i];
return out;
}
template<std::size_t size, class Integral> inline
typename std::enable_if<std::is_integral<Integral>::value, Vector<size, Integral>&>::type
operator%=(Vector<size, Integral>& a, Integral b) {
for(std::size_t i = 0; i != size; ++i)
a[i] %= b;
return a;
}
template<std::size_t size, class Integral> inline
typename std::enable_if<std::is_integral<Integral>::value, Vector<size, Integral>>::type
operator%(const Vector<size, Integral>& a, Integral b) {
Vector<size, Integral> copy(a);
return copy %= b;
}
template<std::size_t size, class Integral> inline
typename std::enable_if<std::is_integral<Integral>::value, Vector<size, Integral>&>::type
operator%=(Vector<size, Integral>& a, const Vector<size, Integral>& b) {
for(std::size_t i = 0; i != size; ++i)
a[i] %= b[i];
return a;
}
template<std::size_t size, class Integral> inline
typename std::enable_if<std::is_integral<Integral>::value, Vector<size, Integral>>::type
operator%(const Vector<size, Integral>& a, const Vector<size, Integral>& b) {
Vector<size, Integral> copy(a);
return copy %= b;
}
template<std::size_t size, class Integral> inline
typename std::enable_if<std::is_integral<Integral>::value, Vector<size, Integral>>::type
operator~(const Vector<size, Integral>& vector) {
Vector<size, Integral> out;
for(std::size_t i = 0; i != size; ++i)
out[i] = ~vector[i];
return out;
}
template<std::size_t size, class Integral> inline
typename std::enable_if<std::is_integral<Integral>::value, Vector<size, Integral>&>::type
operator&=(Vector<size, Integral>& a, const Vector<size, Integral>& b) {
for(std::size_t i = 0; i != size; ++i)
a[i] &= b[i];
return a;
}
template<std::size_t size, class Integral> inline
typename std::enable_if<std::is_integral<Integral>::value, Vector<size, Integral>>::type
operator&(const Vector<size, Integral>& a, const Vector<size, Integral>& b) {
Vector<size, Integral> copy(a);
return copy &= b;
}
template<std::size_t size, class Integral> inline
typename std::enable_if<std::is_integral<Integral>::value, Vector<size, Integral>&>::type
operator|=(Vector<size, Integral>& a, const Vector<size, Integral>& b) {
for(std::size_t i = 0; i != size; ++i)
a[i] |= b[i];
return a;
}
template<std::size_t size, class Integral> inline
typename std::enable_if<std::is_integral<Integral>::value, Vector<size, Integral>>::type
operator|(const Vector<size, Integral>& a, const Vector<size, Integral>& b) {
Vector<size, Integral> copy(a);
return copy |= b;
}
template<std::size_t size, class Integral> inline
typename std::enable_if<std::is_integral<Integral>::value, Vector<size, Integral>&>::type
operator^=(Vector<size, Integral>& a, const Vector<size, Integral>& b) {
for(std::size_t i = 0; i != size; ++i)
a[i] ^= b[i];
return a;
}
template<std::size_t size, class Integral> inline
typename std::enable_if<std::is_integral<Integral>::value, Vector<size, Integral>>::type
operator^(const Vector<size, Integral>& a, const Vector<size, Integral>& b) {
Vector<size, Integral> copy(a);
return copy ^= b;
}
template<std::size_t size, class Integral> inline
typename std::enable_if<std::is_integral<Integral>::value, Vector<size, Integral>&>::type
operator<<=(Vector<size, Integral>& vector,
typename std::common_type<Integral>::type
shift)
{
for(std::size_t i = 0; i != size; ++i)
vector[i] <<= shift;
return vector;
}
template<std::size_t size, class Integral> inline
typename std::enable_if<std::is_integral<Integral>::value, Vector<size, Integral>>::type
operator<<(const Vector<size, Integral>& vector,
typename std::common_type<Integral>::type
shift)
{
Vector<size, Integral> copy(vector);
return copy <<= shift;
}
template<std::size_t size, class Integral> inline
typename std::enable_if<std::is_integral<Integral>::value, Vector<size, Integral>&>::type
operator>>=(Vector<size, Integral>& vector,
typename std::common_type<Integral>::type
shift) {
for(std::size_t i = 0; i != size; ++i)
vector[i] >>= shift;
return vector;
}
template<std::size_t size, class Integral> inline
typename std::enable_if<std::is_integral<Integral>::value, Vector<size, Integral>>::type
operator>>(const Vector<size, Integral>& vector,
typename std::common_type<Integral>::type
shift) {
Vector<size, Integral> copy(vector);
return copy >>= shift;
}
template<std::size_t size, class Integral, class FloatingPoint> inline
typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Vector<size, Integral>&>::type
operator*=(Vector<size, Integral>& vector, FloatingPoint number) {
for(std::size_t i = 0; i != size; ++i)
vector[i] = Integral(vector[i]*number);
return vector;
}
template<std::size_t size, class Integral, class FloatingPoint> inline
typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Vector<size, Integral>>::type
operator*(const Vector<size, Integral>& vector, FloatingPoint number) {
Vector<size, Integral> copy(vector);
return copy *= number;
}
template<std::size_t size, class FloatingPoint, class Integral> inline
typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Vector<size, Integral>>::type
operator*(FloatingPoint number, const Vector<size, Integral>& vector) {
return vector*number;
}
template<std::size_t size, class Integral, class FloatingPoint> inline
typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Vector<size, Integral>&>::type
operator/=(Vector<size, Integral>& vector, FloatingPoint number) {
for(std::size_t i = 0; i != size; ++i)
vector[i] = Integral(vector[i]/number);
return vector;
}
template<std::size_t size, class Integral, class FloatingPoint> inline
typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Vector<size, Integral>>::type
operator/(const Vector<size, Integral>& vector, FloatingPoint number) {
Vector<size, Integral> copy(vector);
return copy /= number;
}
template<std::size_t size, class Integral, class FloatingPoint> inline
typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Vector<size, Integral>&>::type
operator*=(Vector<size, Integral>& a, const Vector<size, FloatingPoint>& b) {
for(std::size_t i = 0; i != size; ++i)
a[i] = Integral(a[i]*b[i]);
return a;
}
template<std::size_t size, class Integral, class FloatingPoint> inline
typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Vector<size, Integral>>::type
operator*(const Vector<size, Integral>& a, const Vector<size, FloatingPoint>& b) {
Vector<size, Integral> copy(a);
return copy *= b;
}
template<std::size_t size, class FloatingPoint, class Integral> inline
typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Vector<size, Integral>>::type
operator*(const Vector<size, FloatingPoint>& a, const Vector<size, Integral>& b) {
return b*a;
}
template<std::size_t size, class Integral, class FloatingPoint> inline
typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Vector<size, Integral>&>::type
operator/=(Vector<size, Integral>& a, const Vector<size, FloatingPoint>& b) {
for(std::size_t i = 0; i != size; ++i)
a[i] = Integral(a[i]/b[i]);
return a;
}
template<std::size_t size, class Integral, class FloatingPoint> inline
typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Vector<size, Integral>>::type
operator/(const Vector<size, Integral>& a, const Vector<size, FloatingPoint>& b) {
Vector<size, Integral> copy(a);
return copy /= b;
}
#define MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(size, Type) \
static Type<T>& from(T* data) { \
return *reinterpret_cast<Type<T>*>(data); \
} \
static const Type<T>& from(const T* data) { \
return *reinterpret_cast<const Type<T>*>(data); \
} \
template<std::size_t otherSize> constexpr static Type<T> pad(const Math::Vector<otherSize, T>& a, T value = T(0)) { \
return Math::Vector<size, T>::pad(a, value); \
} \
\
Type<T> operator-() const { \
return Math::Vector<size, T>::operator-(); \
} \
Type<T>& operator+=(const Math::Vector<size, T>& other) { \
Math::Vector<size, T>::operator+=(other); \
return *this; \
} \
Type<T> operator+(const Math::Vector<size, T>& other) const { \
return Math::Vector<size, T>::operator+(other); \
} \
Type<T>& operator-=(const Math::Vector<size, T>& other) { \
Math::Vector<size, T>::operator-=(other); \
return *this; \
} \
Type<T> operator-(const Math::Vector<size, T>& other) const { \
return Math::Vector<size, T>::operator-(other); \
} \
Type<T>& operator*=(T number) { \
Math::Vector<size, T>::operator*=(number); \
return *this; \
} \
Type<T> operator*(T number) const { \
return Math::Vector<size, T>::operator*(number); \
} \
Type<T>& operator/=(T number) { \
Math::Vector<size, T>::operator/=(number); \
return *this; \
} \
Type<T> operator/(T number) const { \
return Math::Vector<size, T>::operator/(number); \
} \
Type<T>& operator*=(const Math::Vector<size, T>& other) { \
Math::Vector<size, T>::operator*=(other); \
return *this; \
} \
Type<T> operator*(const Math::Vector<size, T>& other) const { \
return Math::Vector<size, T>::operator*(other); \
} \
Type<T>& operator/=(const Math::Vector<size, T>& other) { \
Math::Vector<size, T>::operator/=(other); \
return *this; \
} \
Type<T> operator/(const Math::Vector<size, T>& other) const { \
return Math::Vector<size, T>::operator/(other); \
} \
\
template<class U = T> typename std::enable_if<std::is_floating_point<U>::value, Type<T>>::type normalized() const { \
return Math::Vector<size, T>::normalized(); \
} \
template<class U = T> typename std::enable_if<std::is_floating_point<U>::value, Type<T>>::type resized(T length) const { \
return Math::Vector<size, T>::resized(length); \
} \
template<class U = T> typename std::enable_if<std::is_floating_point<U>::value, Type<T>>::type projected(const Math::Vector<size, T>& other) const { \
return Math::Vector<size, T>::projected(other); \
} \
template<class U = T> typename std::enable_if<std::is_floating_point<U>::value, Type<T>>::type projectedOntoNormalized(const Math::Vector<size, T>& other) const { \
return Math::Vector<size, T>::projectedOntoNormalized(other); \
} \
constexpr Type<T> flipped() const { \
return Math::Vector<size, T>::flipped(); \
}
#define MAGNUM_VECTORn_OPERATOR_IMPLEMENTATION(size, Type) \
template<class T> inline Type<T> operator*(typename std::common_type<T>::type number, const Type<T>& vector) { \
return number*static_cast<const Math::Vector<size, T>&>(vector); \
} \
template<class T> inline Type<T> operator/(typename std::common_type<T>::type number, const Type<T>& vector) { \
return number/static_cast<const Math::Vector<size, T>&>(vector); \
} \
\
template<class Integral> inline typename std::enable_if<std::is_integral<Integral>::value, Type<Integral>&>::type operator%=(Type<Integral>& a, Integral b) { \
static_cast<Math::Vector<size, Integral>&>(a) %= b; \
return a; \
} \
template<class Integral> inline typename std::enable_if<std::is_integral<Integral>::value, Type<Integral>>::type operator%(const Type<Integral>& a, Integral b) { \
return static_cast<const Math::Vector<size, Integral>&>(a) % b; \
} \
template<class Integral> inline typename std::enable_if<std::is_integral<Integral>::value, Type<Integral>&>::type operator%=(Type<Integral>& a, const Math::Vector<size, Integral>& b) { \
static_cast<Math::Vector<size, Integral>&>(a) %= b; \
return a; \
} \
template<class Integral> inline typename std::enable_if<std::is_integral<Integral>::value, Type<Integral>>::type operator%(const Type<Integral>& a, const Math::Vector<size, Integral>& b) { \
return static_cast<const Math::Vector<size, Integral>&>(a) % b; \
} \
\
template<class Integral> inline typename std::enable_if<std::is_integral<Integral>::value, Type<Integral>>::type operator~(const Type<Integral>& vector) { \
return ~static_cast<const Math::Vector<size, Integral>&>(vector); \
} \
template<class Integral> inline typename std::enable_if<std::is_integral<Integral>::value, Type<Integral>&>::type operator&=(Type<Integral>& a, const Math::Vector<size, Integral>& b) { \
static_cast<Math::Vector<size, Integral>&>(a) &= b; \
return a; \
} \
template<class Integral> inline typename std::enable_if<std::is_integral<Integral>::value, Type<Integral>>::type operator&(const Type<Integral>& a, const Math::Vector<size, Integral>& b) { \
return static_cast<const Math::Vector<size, Integral>&>(a) & b; \
} \
template<class Integral> inline typename std::enable_if<std::is_integral<Integral>::value, Type<Integral>&>::type operator|=(Type<Integral>& a, const Math::Vector<size, Integral>& b) { \
static_cast<Math::Vector<size, Integral>&>(a) |= b; \
return a; \
} \
template<class Integral> inline typename std::enable_if<std::is_integral<Integral>::value, Type<Integral>>::type operator|(const Type<Integral>& a, const Math::Vector<size, Integral>& b) { \
return static_cast<const Math::Vector<size, Integral>&>(a) | b; \
} \
template<class Integral> inline typename std::enable_if<std::is_integral<Integral>::value, Type<Integral>&>::type operator^=(Type<Integral>& a, const Math::Vector<size, Integral>& b) { \
static_cast<Math::Vector<size, Integral>&>(a) ^= b; \
return a; \
} \
template<class Integral> inline typename std::enable_if<std::is_integral<Integral>::value, Type<Integral>>::type operator^(const Type<Integral>& a, const Math::Vector<size, Integral>& b) { \
return static_cast<const Math::Vector<size, Integral>&>(a) ^ b; \
} \
template<class Integral> inline typename std::enable_if<std::is_integral<Integral>::value, Type<Integral>&>::type operator<<=(Type<Integral>& vector, typename std::common_type<Integral>::type shift) { \
static_cast<Math::Vector<size, Integral>&>(vector) <<= shift; \
return vector; \
} \
template<class Integral> inline typename std::enable_if<std::is_integral<Integral>::value, Type<Integral>>::type operator<<(const Type<Integral>& vector, typename std::common_type<Integral>::type shift) { \
return static_cast<const Math::Vector<size, Integral>&>(vector) << shift; \
} \
template<class Integral> inline typename std::enable_if<std::is_integral<Integral>::value, Type<Integral>&>::type operator>>=(Type<Integral>& vector, typename std::common_type<Integral>::type shift) { \
static_cast<Math::Vector<size, Integral>&>(vector) >>= shift; \
return vector; \
} \
template<class Integral> inline typename std::enable_if<std::is_integral<Integral>::value, Type<Integral>>::type operator>>(const Type<Integral>& vector, typename std::common_type<Integral>::type shift) { \
return static_cast<const Math::Vector<size, Integral>&>(vector) >> shift; \
} \
template<class Integral, class FloatingPoint> inline typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Type<Integral>&>::type operator*=(Type<Integral>& vector, FloatingPoint number) { \
static_cast<Math::Vector<size, Integral>&>(vector) *= number; \
return vector; \
} \
template<class Integral, class FloatingPoint> inline typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Type<Integral>>::type operator*(const Type<Integral>& vector, FloatingPoint number) { \
return static_cast<const Math::Vector<size, Integral>&>(vector)*number; \
} \
template<class FloatingPoint, class Integral> inline typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Type<Integral>>::type operator*(FloatingPoint number, const Type<Integral>& vector) { \
return number*static_cast<const Math::Vector<size, Integral>&>(vector); \
} \
template<class Integral, class FloatingPoint> inline typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Type<Integral>&>::type operator/=(Type<Integral>& vector, FloatingPoint number) { \
static_cast<Math::Vector<size, Integral>&>(vector) /= number; \
return vector; \
} \
template<class Integral, class FloatingPoint> inline typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Type<Integral>>::type operator/(const Type<Integral>& vector, FloatingPoint number) { \
return static_cast<const Math::Vector<size, Integral>&>(vector)/number; \
} \
\
template<class Integral, class FloatingPoint> inline typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Type<Integral>&>::type operator*=(Type<Integral>& a, const Math::Vector<size, FloatingPoint>& b) { \
static_cast<Math::Vector<size, Integral>&>(a) *= b; \
return a; \
} \
template<class Integral, class FloatingPoint> inline typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Type<Integral>>::type operator*(const Type<Integral>& a, const Math::Vector<size, FloatingPoint>& b) { \
return static_cast<const Math::Vector<size, Integral>&>(a)*b; \
} \
template<class FloatingPoint, class Integral> inline typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Type<Integral>>::type operator*(const Math::Vector<size, FloatingPoint>& a, const Type<Integral>& b) { \
return a*static_cast<const Math::Vector<size, Integral>&>(b); \
} \
template<class Integral, class FloatingPoint> inline typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Type<Integral>&>::type operator/=(Type<Integral>& a, const Math::Vector<size, FloatingPoint>& b) { \
static_cast<Math::Vector<size, Integral>&>(a) /= b; \
return a; \
} \
template<class Integral, class FloatingPoint> inline typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Type<Integral>>::type operator/(const Type<Integral>& a, const Math::Vector<size, FloatingPoint>& b) { \
return static_cast<const Math::Vector<size, Integral>&>(a)/b; \
}
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>
template<class U> inline typename std::enable_if<std::is_floating_point<U>::value, Vector<size, T>>::type
Vector<size, T>::projectedOntoNormalized(const Vector<size, T>& line) const {
CORRADE_ASSERT(line.isNormalized(),
"Math::Vector::projectedOntoNormalized(): line" << line << "is not normalized", {});
return line*Math::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 = Math::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 = Math::max(out, _data[i]);
return out;
}
template<std::size_t size, class T> inline std::pair<T, T> Vector<size, T>::minmax() const {
T min{_data[0]}, max{_data[0]};
for(std::size_t i = 1; i != size; ++i) {
if(_data[i] < min)
min = _data[i];
else if(_data[i] > max)
max = _data[i];
}
return {min, max};
}
namespace Implementation {
template<std::size_t size, class T> struct StrictWeakOrdering<Vector<size, T>> {
bool operator()(const Vector<size, T>& a, const Vector<size, T>& b) const {
for(std::size_t i = 0; i < size; ++i) {
if(a[i] < b[i])
return true;
if(a[i] > b[i])
return false;
}
return false;
}
};
}
}}
#endif
#ifndef Magnum_Math_Bezier_h
#define Magnum_Math_Bezier_h
namespace Magnum { namespace Math {
namespace Implementation {
template<UnsignedInt, UnsignedInt, class, class> struct BezierConverter;
}
template<UnsignedInt order, UnsignedInt dimensions, class T> class Bezier {
static_assert(order != 0, "Bezier cannot have zero order");
template<UnsignedInt, UnsignedInt, class> friend class Bezier;
public:
typedef T Type;
enum: UnsignedInt {
Order = order,
Dimensions = dimensions
};
template<class VectorType> static
typename std::enable_if<std::is_base_of<Vector<dimensions, T>, VectorType>::value && order == 3, Bezier<order, dimensions, T>>::type
fromCubicHermite(const CubicHermite<VectorType>& a, const CubicHermite<VectorType>& b) {
return {a.point(), a.outTangent()/T(3) - a.point(), b.point() - b.inTangent()/T(3), b.point()};
}
constexpr /*implicit*/ Bezier(ZeroInitT = ZeroInit) noexcept
: Bezier<order, dimensions, T>{typename Implementation::GenerateSequence<order + 1>::Type{}, ZeroInit}
{}
explicit Bezier(NoInitT) noexcept
: Bezier<order, dimensions, T>{typename Implementation::GenerateSequence<order + 1>::Type{}, NoInit}
{}
template<typename... U> constexpr /*implicit*/ Bezier(const Vector<dimensions, T>& first, U... next) noexcept: _data{first, next...} {
static_assert(sizeof...(U) + 1 == order + 1, "Wrong number of arguments");
}
template<class U> constexpr explicit Bezier(const Bezier<order, dimensions, U>& other) noexcept: Bezier{typename Implementation::GenerateSequence<order + 1>::Type(), other} {}
template<class U, class V = decltype(Implementation::BezierConverter<order, dimensions, T, U>::from(std::declval<U>()))> constexpr explicit Bezier(const U& other) noexcept: Bezier<order, dimensions, T>{Implementation::BezierConverter<order, dimensions, T, U>::from(other)} {}
template<class U, class V = decltype(Implementation::BezierConverter<order, dimensions, T, U>::to(std::declval<Bezier<order, dimensions, T>>()))> constexpr explicit operator U() const {
return Implementation::BezierConverter<order, dimensions, T, U>::to(*this);
}
Vector<dimensions, T>* data() { return _data; }
constexpr const Vector<dimensions, T>* data() const { return _data; }
bool operator==(const Bezier<order, dimensions, T>& other) const {
for(std::size_t i = 0; i != order + 1; ++i)
if(_data[i] != other._data[i]) return false;
return true;
}
bool operator!=(const Bezier<order, dimensions, T>& other) const {
return !operator==(other);
}
Vector<dimensions, T>& operator[](std::size_t i) { return _data[i]; }
constexpr const Vector<dimensions, T>& operator[](std::size_t i) const { return _data[i]; }
Vector<dimensions, T> value(Float t) const {
Bezier<order, dimensions, T> iPoints[order + 1];
calculateIntermediatePoints(iPoints, t);
return iPoints[0][order];
}
std::pair<Bezier<order, dimensions, T>, Bezier<order, dimensions, T>> subdivide(Float t) const {
Bezier<order, dimensions, T> iPoints[order + 1];
calculateIntermediatePoints(iPoints, t);
Bezier<order, dimensions, T> left, right;
for(std::size_t i = 0; i <= order; ++i)
left[i] = iPoints[0][i];
for(std::size_t i = 0, j = order; i <= order; --j, ++i)
right[i] = iPoints[i][j];
return {left, right};
}
private:
template<class U, std::size_t ...sequence> constexpr explicit Bezier(Implementation::Sequence<sequence...>, const Bezier<order, dimensions, U>& other) noexcept: _data{Vector<dimensions, T>(other._data[sequence])...} {}
template<class U, std::size_t ...sequence> constexpr explicit Bezier(Implementation::Sequence<sequence...>, U): _data{Vector<dimensions, T>((static_cast<void>(sequence), U{typename U::Init{}}))...} {}
void calculateIntermediatePoints(Bezier<order, dimensions, T>(&iPoints)[order + 1], Float t) const {
for(std::size_t i = 0; i <= order; ++i) {
iPoints[i][0] = _data[i];
}
for(std::size_t r = 1; r <= order; ++r) {
for(std::size_t i = 0; i <= order - r; ++i) {
iPoints[i][r] = (1 - t)*iPoints[i][r - 1] + t*iPoints[i + 1][r - 1];
}
}
}
Vector<dimensions, T> _data[order + 1];
};
#ifndef CORRADE_MSVC2015_COMPATIBILITY /* Multiple definitions still broken */
template<UnsignedInt dimensions, class T> using QuadraticBezier = Bezier<2, dimensions, T>;
#endif
#ifndef CORRADE_MSVC2015_COMPATIBILITY /* Multiple definitions still broken */
template<class T> using QuadraticBezier2D = QuadraticBezier<2, T>;
#endif
#ifndef CORRADE_MSVC2015_COMPATIBILITY /* Multiple definitions still broken */
template<class T> using QuadraticBezier3D = QuadraticBezier<3, T>;
#endif
#ifndef CORRADE_MSVC2015_COMPATIBILITY /* Multiple definitions still broken */
template<UnsignedInt dimensions, class T> using CubicBezier = Bezier<3, dimensions, T>;
#endif
#ifndef CORRADE_MSVC2015_COMPATIBILITY /* Multiple definitions still broken */
template<class T> using CubicBezier2D = CubicBezier<2, T>;
#endif
#ifndef CORRADE_MSVC2015_COMPATIBILITY /* Multiple definitions still broken */
template<class T> using CubicBezier3D = CubicBezier<3, T>;
#endif
namespace Implementation {
template<UnsignedInt order, UnsignedInt dimensions, class T> struct StrictWeakOrdering<Bezier<order, dimensions, T>> {
bool operator()(const Bezier<order, dimensions, T>& a, const Bezier<order, dimensions, T>& b) const {
StrictWeakOrdering<Vector<dimensions, T>> o;
for(std::size_t i = 0; i < order + 1; ++i) {
if(o(a[i], b[i]))
return true;
if(o(b[i], a[i]))
return false;
}
return false;
}
};
}
}}
#endif
#ifndef Magnum_Math_RectangularMatrix_h
#define Magnum_Math_RectangularMatrix_h
namespace Magnum { namespace Math {
namespace Implementation {
template<std::size_t, std::size_t, class, class> struct RectangularMatrixConverter;
}
template<std::size_t cols, std::size_t rows, class T> class RectangularMatrix {
static_assert(cols != 0 && rows != 0, "RectangularMatrix cannot have zero elements");
template<std::size_t, std::size_t, class> friend class RectangularMatrix;
public:
typedef T Type;
enum: std::size_t {
Cols = cols,
Rows = rows,
DiagonalSize = (cols < rows ? cols : rows)
};
static RectangularMatrix<cols, rows, T>& from(T* data) {
return *reinterpret_cast<RectangularMatrix<cols, rows, T>*>(data);
}
static const RectangularMatrix<cols, rows, T>& from(const T* data) {
return *reinterpret_cast<const RectangularMatrix<cols, rows, T>*>(data);
}
static RectangularMatrix<cols, rows, T> fromVector(const Vector<cols*rows, T>& vector) {
return *reinterpret_cast<const RectangularMatrix<cols, rows, T>*>(vector.data());
}
constexpr static RectangularMatrix<cols, rows, T> fromDiagonal(const Vector<DiagonalSize, T>& diagonal) noexcept {
return RectangularMatrix(typename Implementation::GenerateSequence<cols>::Type(), diagonal);
}
constexpr /*implicit*/ RectangularMatrix(ZeroInitT = ZeroInit) noexcept
: RectangularMatrix<cols, rows, T>{typename Implementation::GenerateSequence<cols>::Type{}, ZeroInit}
{}
explicit RectangularMatrix(NoInitT) noexcept
: RectangularMatrix<cols, rows, T>{typename Implementation::GenerateSequence<cols>::Type{}, NoInit}
{}
template<class ...U> constexpr /*implicit*/ RectangularMatrix(const Vector<rows, T>& first, const U&... next) noexcept: _data{first, next...} {
static_assert(sizeof...(next)+1 == cols, "Improper number of arguments passed to RectangularMatrix constructor");
}
constexpr explicit RectangularMatrix(T value) noexcept
: RectangularMatrix{typename Implementation::GenerateSequence<cols>::Type(), value}
{}
template<class U> constexpr explicit RectangularMatrix(const RectangularMatrix<cols, rows, U>& other) noexcept: RectangularMatrix(typename Implementation::GenerateSequence<cols>::Type(), 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)) {}
constexpr /*implicit*/ RectangularMatrix(const RectangularMatrix<cols, rows, T>&) noexcept = default;
template<class U, class V = decltype(Implementation::RectangularMatrixConverter<cols, rows, T, U>::to(std::declval<RectangularMatrix<cols, rows, T>>()))> constexpr explicit operator U() const {
return Implementation::RectangularMatrixConverter<cols, rows, T, U>::to(*this);
}
T* data() { return _data[0].data(); }
constexpr const T* data() const { return _data[0].data(); }
Vector<rows, T>& operator[](std::size_t col) { return _data[col]; }
constexpr const Vector<rows, T>& operator[](std::size_t col) const { return _data[col]; }
Vector<cols, T> row(std::size_t row) const;
void setRow(std::size_t row, const Vector<cols, T>& data);
bool operator==(const RectangularMatrix<cols, rows, T>& other) const {
for(std::size_t i = 0; i != cols; ++i)
if(_data[i] != other._data[i]) return false;
return true;
}
bool operator!=(const RectangularMatrix<cols, rows, T>& other) const {
return !operator==(other);
}
BoolVector<cols*rows> operator<(const RectangularMatrix<cols, rows, T>& other) const {
return toVector() < other.toVector();
}
BoolVector<cols*rows> operator<=(const RectangularMatrix<cols, rows, T>& other) const {
return toVector() <= other.toVector();
}
BoolVector<cols*rows> operator>=(const RectangularMatrix<cols, rows, T>& other) const {
return toVector() >= other.toVector();
}
BoolVector<cols*rows> operator>(const RectangularMatrix<cols, rows, T>& other) const {
return toVector() > other.toVector();
}
RectangularMatrix<cols, rows, T> operator-() const;
RectangularMatrix<cols, rows, T>& operator+=(const RectangularMatrix<cols, rows, T>& other) {
for(std::size_t i = 0; i != cols; ++i)
_data[i] += other._data[i];
return *this;
}
RectangularMatrix<cols, rows, T> operator+(const RectangularMatrix<cols, rows, T>& other) const {
return RectangularMatrix<cols, rows, T>(*this)+=other;
}
RectangularMatrix<cols, rows, T>& operator-=(const RectangularMatrix<cols, rows, T>& other) {
for(std::size_t i = 0; i != cols; ++i)
_data[i] -= other._data[i];
return *this;
}
RectangularMatrix<cols, rows, T> operator-(const RectangularMatrix<cols, rows, T>& other) const {
return RectangularMatrix<cols, rows, T>(*this)-=other;
}
RectangularMatrix<cols, rows, T>& operator*=(T number) {
for(std::size_t i = 0; i != cols; ++i)
_data[i] *= number;
return *this;
}
RectangularMatrix<cols, rows, T> operator*(T number) const {
return RectangularMatrix<cols, rows, T>(*this) *= number;
}
RectangularMatrix<cols, rows, T>& operator/=(T number) {
for(std::size_t i = 0; i != cols; ++i)
_data[i] /= number;
return *this;
}
RectangularMatrix<cols, rows, T> operator/(T number) const {
return RectangularMatrix<cols, rows, T>(*this) /= number;
}
template<std::size_t size> RectangularMatrix<size, rows, T> operator*(const RectangularMatrix<size, cols, T>& other) const;
Vector<rows, T> operator*(const Vector<cols, T>& other) const {
return operator*(RectangularMatrix<1, cols, T>(other))[0];
}
RectangularMatrix<rows, cols, T> transposed() const;
constexpr RectangularMatrix<cols, rows, T> flippedCols() const {
return flippedColsInternal(typename Implementation::GenerateSequence<cols>::Type{});
}
constexpr RectangularMatrix<cols, rows, T> flippedRows() const {
return flippedRowsInternal(typename Implementation::GenerateSequence<cols>::Type{});
}
constexpr Vector<DiagonalSize, T> diagonal() const;
Vector<rows*cols, T> toVector() const {
return *reinterpret_cast<const Vector<rows*cols, T>*>(data());
}
protected:
template<std::size_t ...sequence> constexpr explicit RectangularMatrix(Implementation::Sequence<sequence...>, const Vector<DiagonalSize, T>& diagonal);
template<std::size_t ...sequence> constexpr explicit RectangularMatrix(Implementation::Sequence<sequence...>, T value) noexcept: _data{Vector<rows, T>((static_cast<void>(sequence), value))...} {}
private:
template<std::size_t, class> friend class Matrix;
template<std::size_t, class> friend struct Implementation::MatrixDeterminant;
template<class U, std::size_t ...sequence> constexpr explicit RectangularMatrix(Implementation::Sequence<sequence...>, const RectangularMatrix<cols, rows, U>& matrix) noexcept: _data{Vector<rows, T>(matrix[sequence])...} {}
template<class U, std::size_t ...sequence> constexpr explicit RectangularMatrix(Implementation::Sequence<sequence...>, U) noexcept: _data{Vector<rows, T>((static_cast<void>(sequence), U{typename U::Init{}}))...} {}
template<std::size_t ...sequence> constexpr RectangularMatrix<cols, rows, T> flippedColsInternal(Implementation::Sequence<sequence...>) const {
return {_data[cols - 1 - sequence]...};
}
template<std::size_t ...sequence> constexpr RectangularMatrix<cols, rows, T> flippedRowsInternal(Implementation::Sequence<sequence...>) const {
return {_data[sequence].flipped()...};
}
template<std::size_t ...sequence> constexpr Vector<DiagonalSize, T> diagonalInternal(Implementation::Sequence<sequence...>) const;
Vector<rows, T> _data[cols];
};
#ifndef CORRADE_MSVC2015_COMPATIBILITY /* Multiple definitions still broken */
template<class T> using Matrix2x3 = RectangularMatrix<2, 3, T>;
#endif
#ifndef CORRADE_MSVC2015_COMPATIBILITY /* Multiple definitions still broken */
template<class T> using Matrix3x2 = RectangularMatrix<3, 2, T>;
#endif
#ifndef CORRADE_MSVC2015_COMPATIBILITY /* Multiple definitions still broken */
template<class T> using Matrix2x4 = RectangularMatrix<2, 4, T>;
#endif
#ifndef CORRADE_MSVC2015_COMPATIBILITY /* Multiple definitions still broken */
template<class T> using Matrix4x2 = RectangularMatrix<4, 2, T>;
#endif
#ifndef CORRADE_MSVC2015_COMPATIBILITY /* Multiple definitions still broken */
template<class T> using Matrix3x4 = RectangularMatrix<3, 4, T>;
#endif
#ifndef CORRADE_MSVC2015_COMPATIBILITY /* Multiple definitions still broken */
template<class T> using Matrix4x3 = RectangularMatrix<4, 3, T>;
#endif
template<std::size_t cols, std::size_t rows, class T> inline RectangularMatrix<cols, rows, T> operator*(
typename std::common_type<T>::type
number, const RectangularMatrix<cols, rows, T>& matrix)
{
return matrix*number;
}
template<std::size_t cols, std::size_t rows, class T> inline RectangularMatrix<cols, rows, T> operator/(
typename std::common_type<T>::type
number, const RectangularMatrix<cols, rows, T>& matrix)
{
RectangularMatrix<cols, rows, T> out{NoInit};
for(std::size_t i = 0; i != cols; ++i)
out[i] = number/matrix[i];
return out;
}
template<std::size_t size, std::size_t cols, class T> inline RectangularMatrix<cols, size, T> operator*(const Vector<size, T>& vector, const RectangularMatrix<cols, 1, T>& matrix) {
return RectangularMatrix<1, size, T>(vector)*matrix;
}
#define MAGNUM_RECTANGULARMATRIX_SUBCLASS_IMPLEMENTATION(cols, rows, ...) \
static __VA_ARGS__& from(T* data) { \
return *reinterpret_cast<__VA_ARGS__*>(data); \
} \
static const __VA_ARGS__& from(const T* data) { \
return *reinterpret_cast<const __VA_ARGS__*>(data); \
} \
constexpr static __VA_ARGS__ fromDiagonal(const Vector<Math::RectangularMatrix<cols, rows, T>::DiagonalSize, T>& diagonal) { \
return Math::RectangularMatrix<cols, rows, T>::fromDiagonal(diagonal); \
} \
\
__VA_ARGS__ operator-() const { \
return Math::RectangularMatrix<cols, rows, T>::operator-(); \
} \
__VA_ARGS__& operator+=(const Math::RectangularMatrix<cols, rows, T>& other) { \
Math::RectangularMatrix<cols, rows, T>::operator+=(other); \
return *this; \
} \
__VA_ARGS__ operator+(const Math::RectangularMatrix<cols, rows, T>& other) const { \
return Math::RectangularMatrix<cols, rows, T>::operator+(other); \
} \
__VA_ARGS__& operator-=(const Math::RectangularMatrix<cols, rows, T>& other) { \
Math::RectangularMatrix<cols, rows, T>::operator-=(other); \
return *this; \
} \
__VA_ARGS__ operator-(const Math::RectangularMatrix<cols, rows, T>& other) const { \
return Math::RectangularMatrix<cols, rows, T>::operator-(other); \
} \
__VA_ARGS__& operator*=(T number) { \
Math::RectangularMatrix<cols, rows, T>::operator*=(number); \
return *this; \
} \
__VA_ARGS__ operator*(T number) const { \
return Math::RectangularMatrix<cols, rows, T>::operator*(number); \
} \
__VA_ARGS__& operator/=(T number) { \
Math::RectangularMatrix<cols, rows, T>::operator/=(number); \
return *this; \
} \
__VA_ARGS__ operator/(T number) const { \
return Math::RectangularMatrix<cols, rows, T>::operator/(number); \
} \
constexpr __VA_ARGS__ flippedCols() const { \
return Math::RectangularMatrix<cols, rows, T>::flippedCols(); \
} \
constexpr __VA_ARGS__ flippedRows() const { \
return Math::RectangularMatrix<cols, rows, T>::flippedRows(); \
} \
#define MAGNUM_MATRIX_OPERATOR_IMPLEMENTATION(...) \
template<std::size_t size, class T> inline __VA_ARGS__ operator*(typename std::common_type<T>::type number, const __VA_ARGS__& matrix) { \
return number*static_cast<const Math::RectangularMatrix<size, size, T>&>(matrix); \
} \
template<std::size_t size, class T> inline __VA_ARGS__ operator/(typename std::common_type<T>::type number, const __VA_ARGS__& matrix) { \
return number/static_cast<const Math::RectangularMatrix<size, size, T>&>(matrix); \
} \
template<std::size_t size, class T> inline __VA_ARGS__ operator*(const Vector<size, T>& vector, const RectangularMatrix<size, 1, T>& matrix) { \
return Math::RectangularMatrix<1, size, T>(vector)*matrix; \
}
#define MAGNUM_MATRIXn_OPERATOR_IMPLEMENTATION(size, Type) \
template<class T> inline Type<T> operator*(typename std::common_type<T>::type number, const Type<T>& matrix) { \
return number*static_cast<const Math::RectangularMatrix<size, size, T>&>(matrix); \
} \
template<class T> inline Type<T> operator/(typename std::common_type<T>::type number, const Type<T>& matrix) { \
return number/static_cast<const Math::RectangularMatrix<size, size, T>&>(matrix); \
} \
template<class T> inline Type<T> operator*(const Vector<size, T>& vector, const RectangularMatrix<size, 1, T>& matrix) { \
return Math::RectangularMatrix<1, size, T>(vector)*matrix; \
}
namespace Implementation {
template<std::size_t rows, std::size_t i, class T, std::size_t ...sequence> constexpr Vector<rows, T> diagonalMatrixColumn2(Implementation::Sequence<sequence...>, const T& number) {
return {(sequence == i ? number : T(0))...};
}
template<std::size_t rows, std::size_t i, class T> constexpr Vector<rows, T> diagonalMatrixColumn(const T& number) {
return diagonalMatrixColumn2<rows, i, T>(typename Implementation::GenerateSequence<rows>::Type(), number);
}
}
template<std::size_t cols, std::size_t rows, class T> template<std::size_t ...sequence> constexpr RectangularMatrix<cols, rows, T>::RectangularMatrix(Implementation::Sequence<sequence...>, const Vector<DiagonalSize, T>& diagonal): _data{Implementation::diagonalMatrixColumn<rows, sequence>(sequence < DiagonalSize ? diagonal[sequence] : T{})...} {}
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]._data[row];
return out;
}
template<std::size_t cols, std::size_t rows, class T> inline void RectangularMatrix<cols, rows, T>::setRow(std::size_t row, const Vector<cols, T>& data) {
for(std::size_t i = 0; i != cols; ++i)
_data[i]._data[row] = data._data[i];
}
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{ZeroInit};
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._data[col]._data[row] += _data[pos]._data[row]*other._data[col]._data[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{NoInit};
for(std::size_t col = 0; col != cols; ++col)
for(std::size_t row = 0; row != rows; ++row)
out._data[row]._data[col] = _data[col]._data[row];
return out;
}
template<std::size_t cols, std::size_t rows, class T> constexpr auto RectangularMatrix<cols, rows, T>::diagonal() const -> Vector<DiagonalSize, T> { return diagonalInternal(typename Implementation::GenerateSequence<DiagonalSize>::Type()); }
template<std::size_t cols, std::size_t rows, class T> template<std::size_t ...sequence> constexpr auto RectangularMatrix<cols, rows, T>::diagonalInternal(Implementation::Sequence<sequence...>) const -> Vector<DiagonalSize, T> {
return {_data[sequence][sequence]...};
}
namespace Implementation {
template<std::size_t cols, std::size_t rows, class T> struct StrictWeakOrdering<RectangularMatrix<cols, rows, T>> {
bool operator()(const RectangularMatrix<cols, rows, T>& a, const RectangularMatrix<cols, rows, T>& b) const {
StrictWeakOrdering<Vector<rows, T>> o;
for(std::size_t i = 0; i < cols; ++i) {
if(o(a[i], b[i]))
return true;
if(o(b[i], a[i]))
return false;
}
return false;
}
};
}
}}
#endif
#ifndef Magnum_Math_Matrix_h
#define Magnum_Math_Matrix_h
namespace Magnum { namespace Math {
namespace Implementation {
template<std::size_t, class> struct MatrixDeterminant;
template<std::size_t size, std::size_t col, std::size_t otherSize, class T, std::size_t ...row> constexpr Vector<size, T> valueOrIdentityVector(Sequence<row...>, const RectangularMatrix<otherSize, otherSize, T>& other) {
return {(col < otherSize && row < otherSize ? other[col][row] :
col == row ? T{1} : T{0})...};
}
template<std::size_t size, std::size_t col, std::size_t otherSize, class T> constexpr Vector<size, T> valueOrIdentityVector(const RectangularMatrix<otherSize, otherSize, T>& other) {
return valueOrIdentityVector<size, col>(typename Implementation::GenerateSequence<size>::Type(), other);
}
}
template<std::size_t size, class T> class Matrix: public RectangularMatrix<size, size, T> {
public:
enum: std::size_t {
Size = size
};
constexpr /*implicit*/ Matrix(IdentityInitT = IdentityInit, T value = T(1)) noexcept
: RectangularMatrix<size, size, T>{typename Implementation::GenerateSequence<size>::Type(), Vector<size, T>(value)}
{}
constexpr explicit Matrix(ZeroInitT) noexcept
: RectangularMatrix<size, size, T>{ZeroInit}
{}
constexpr explicit Matrix(NoInitT) noexcept
: RectangularMatrix<size, size, T>{NoInit}
{}
template<class ...U> constexpr /*implicit*/ Matrix(const Vector<size, T>& first, const U&... next) noexcept: RectangularMatrix<size, size, T>(first, next...) {}
constexpr explicit Matrix(T value) noexcept
: RectangularMatrix<size, size, T>{typename Implementation::GenerateSequence<size>::Type(), value}
{}
template<class U> constexpr explicit Matrix(const RectangularMatrix<size, size, U>& other) noexcept: RectangularMatrix<size, size, T>(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)) {}
template<std::size_t otherSize> constexpr explicit Matrix(const RectangularMatrix<otherSize, otherSize, T>& other) noexcept
: Matrix<size, T>{typename Implementation::GenerateSequence<size>::Type(), other}
{}
constexpr /*implicit*/ Matrix(const RectangularMatrix<size, size, T>& other) noexcept: RectangularMatrix<size, size, T>(other) {}
bool isOrthogonal() const;
T trace() const { return RectangularMatrix<size, size, T>::diagonal().sum(); }
Matrix<size-1, T> ij(std::size_t skipCol, std::size_t skipRow) const;
T determinant() const { return Implementation::MatrixDeterminant<size, T>()(*this); }
Matrix<size, T> inverted() const;
Matrix<size, T> invertedOrthogonal() const {
CORRADE_ASSERT(isOrthogonal(),
"Math::Matrix::invertedOrthogonal(): the matrix is not orthogonal:" << Corrade::Utility::Debug::Debug::newline << *this, {});
return RectangularMatrix<size, size, T>::transposed();
}
Matrix<size, T> operator*(const Matrix<size, T>& other) const {
return RectangularMatrix<size, size, T>::operator*(other);
}
template<std::size_t otherCols> RectangularMatrix<otherCols, size, T> operator*(const RectangularMatrix<otherCols, size, T>& other) const {
return RectangularMatrix<size, size, T>::operator*(other);
}
Vector<size, T> operator*(const Vector<size, T>& other) const {
return RectangularMatrix<size, size, T>::operator*(other);
}
Matrix<size, T> transposed() const {
return RectangularMatrix<size, size, T>::transposed();
}
MAGNUM_RECTANGULARMATRIX_SUBCLASS_IMPLEMENTATION(size, size, Matrix<size, T>)
private:
friend struct Implementation::MatrixDeterminant<size, T>;
template<std::size_t otherSize, std::size_t ...col> constexpr explicit Matrix(Implementation::Sequence<col...>, const RectangularMatrix<otherSize, otherSize, T>& other) noexcept: RectangularMatrix<size, size, T>{Implementation::valueOrIdentityVector<size, col>(other)...} {}
};
#ifndef CORRADE_MSVC2015_COMPATIBILITY /* Multiple definitions still broken */
template<class T> using Matrix2x2 = Matrix<2, T>;
#endif
#ifndef CORRADE_MSVC2015_COMPATIBILITY /* Multiple definitions still broken */
template<class T> using Matrix3x3 = Matrix<3, T>;
#endif
#ifndef CORRADE_MSVC2015_COMPATIBILITY /* Multiple definitions still broken */
template<class T> using Matrix4x4 = Matrix<4, T>;
#endif
MAGNUM_MATRIX_OPERATOR_IMPLEMENTATION(Matrix<size, T>)
#define MAGNUM_MATRIX_SUBCLASS_IMPLEMENTATION(size, Type, VectorType) \
VectorType<T>& operator[](std::size_t col) { \
return static_cast<VectorType<T>&>(Matrix<size, T>::operator[](col)); \
} \
constexpr const VectorType<T> operator[](std::size_t col) const { \
return VectorType<T>(Matrix<size, T>::operator[](col)); \
} \
VectorType<T> row(std::size_t row) const { \
return VectorType<T>(Matrix<size, T>::row(row)); \
} \
\
Type<T> operator*(const Matrix<size, T>& other) const { \
return Matrix<size, T>::operator*(other); \
} \
template<std::size_t otherCols> RectangularMatrix<otherCols, size, T> operator*(const RectangularMatrix<otherCols, size, T>& other) const { \
return Matrix<size, T>::operator*(other); \
} \
VectorType<T> operator*(const Vector<size, T>& other) const { \
return Matrix<size, T>::operator*(other); \
} \
\
Type<T> transposed() const { return Matrix<size, T>::transposed(); } \
constexpr VectorType<T> diagonal() const { return Matrix<size, T>::diagonal(); } \
Type<T> inverted() const { return Matrix<size, T>::inverted(); } \
Type<T> invertedOrthogonal() const { \
return Matrix<size, T>::invertedOrthogonal(); \
}
namespace Implementation {
template<std::size_t size, class T> struct MatrixDeterminant {
T operator()(const Matrix<size, T>& m) {
T out(0);
for(std::size_t col = 0; col != size; ++col)
out += ((col & 1) ? -1 : 1)*m._data[col]._data[0]*m.ij(col, 0).determinant();
return out;
}
};
template<class T> struct MatrixDeterminant<3, T> {
constexpr T operator()(const Matrix<3, T>& m) const {
return m._data[0]._data[0]*((m._data[1]._data[1]*m._data[2]._data[2]) - (m._data[2]._data[1]*m._data[1]._data[2])) -
m._data[0]._data[1]*(m._data[1]._data[0]*m._data[2]._data[2] - m._data[2]._data[0]*m._data[1]._data[2]) +
m._data[0]._data[2]*(m._data[1]._data[0]*m._data[2]._data[1] - m._data[2]._data[0]*m._data[1]._data[1]);
}
};
template<class T> struct MatrixDeterminant<2, T> {
constexpr T operator()(const Matrix<2, T>& m) const {
return m._data[0]._data[0]*m._data[1]._data[1] - m._data[1]._data[0]*m._data[0]._data[1];
}
};
template<class T> struct MatrixDeterminant<1, T> {
constexpr T operator()(const Matrix<1, T>& m) const {
return m._data[0]._data[0];
}
};
template<std::size_t size, class T> struct StrictWeakOrdering<Matrix<size, T>>: StrictWeakOrdering<RectangularMatrix<size, size, T>> {};
}
template<std::size_t size, class T> bool Matrix<size, T>::isOrthogonal() const {
for(std::size_t i = 0; i != size; ++i)
if(!RectangularMatrix<size, size, T>::_data[i].isNormalized()) return false;
for(std::size_t i = 0; i != size-1; ++i)
for(std::size_t j = i+1; j != size; ++j)
if(dot(RectangularMatrix<size, size, T>::_data[i], RectangularMatrix<size, size, T>::_data[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{NoInit};
for(std::size_t col = 0; col != size-1; ++col)
for(std::size_t row = 0; row != size-1; ++row)
out._data[col]._data[row] = RectangularMatrix<size, size, T>::
_data[col + (col >= skipCol)]
._data[row + (row >= skipRow)];
return out;
}
template<std::size_t size, class T> Matrix<size, T> Matrix<size, T>::inverted() const {
Matrix<size, T> out{NoInit};
const T _determinant = determinant();
for(std::size_t col = 0; col != size; ++col)
for(std::size_t row = 0; row != size; ++row)
out._data[col]._data[row] = (((row+col) & 1) ? -1 : 1)*ij(row, col).determinant()/_determinant;
return out;
}
}}
#endif
#ifndef Magnum_Math_Functions_h
#define Magnum_Math_Functions_h
namespace Magnum { namespace Math {
namespace Implementation {
template<UnsignedInt exponent> struct Pow {
Pow() = delete;
template<class T> constexpr static T pow(T base) {
return base*Pow<exponent-1>::pow(base);
}
};
template<> struct Pow<0> {
Pow() = delete;
template<class T> constexpr static T pow(T) { return T(1); }
};
template<class> struct IsBoolVectorOrScalar: std::false_type {};
template<> struct IsBoolVectorOrScalar<bool>: std::true_type {};
template<std::size_t size> struct IsBoolVectorOrScalar<BoolVector<size>>: std::true_type {};
template<class T> struct IsVectorOrScalar: std::is_arithmetic<T>::type {};
template<template<class> class Derived, class T> struct IsVectorOrScalar<Unit<Derived, T>>: std::true_type {};
template<class T> struct IsVectorOrScalar<Deg<T>>: std::true_type {};
template<class T> struct IsVectorOrScalar<Rad<T>>: std::true_type {};
template<std::size_t size, class T> struct IsVectorOrScalar<Vector<size, T>>: std::true_type {};
template<class T> struct IsVectorOrScalar<Vector2<T>>: std::true_type {};
template<class T> struct IsVectorOrScalar<Vector3<T>>: std::true_type {};
template<class T> struct IsVectorOrScalar<Vector4<T>>: std::true_type {};
template<class T> struct IsVectorOrScalar<Color3<T>>: std::true_type {};
template<class T> struct IsVectorOrScalar<Color4<T>>: std::true_type {};
}
UnsignedInt MAGNUM_EXPORT log(UnsignedInt base, UnsignedInt number);
UnsignedInt MAGNUM_EXPORT log2(UnsignedInt number);
template<class T> inline T log(T number) { return std::log(number); }
template<class T> inline T exp(T exponent) { return std::exp(exponent); }
template<class Integral> inline std::pair<Integral, Integral> div(Integral x, Integral y) {
static_assert(std::is_integral<Integral>{}, "Math::div(): not an integral type");
const auto result = std::div(x, y);
return {result.quot, result.rem};
}
template<class T> inline typename std::enable_if<std::is_arithmetic<T>::value, bool>::type isInf(T value) {
return std::isinf(value);
}
template<std::size_t size, class T> inline BoolVector<size> isInf(const Vector<size, T>& value) {
BoolVector<size> out;
for(std::size_t i = 0; i != size; ++i)
out.set(i, std::isinf(value[i]));
return out;
}
template<class T> inline typename std::enable_if<std::is_arithmetic<T>::value, bool>::type isNan(T value) {
return std::isnan(value);
}
template<std::size_t size, class T> inline BoolVector<size> isNan(const Vector<size, T>& value) {
BoolVector<size> out;
for(std::size_t i = 0; i != size; ++i)
out.set(i, std::isnan(value[i]));
return out;
}
template<class T> inline T sin(Unit<Rad, T> angle) { return std::sin(T(angle)); }
template<class T> inline T sin(Unit<Deg, T> angle) { return sin(Rad<T>(angle)); }
template<class T> inline T cos(Unit<Rad, T> angle) { return std::cos(T(angle)); }
template<class T> inline T cos(Unit<Deg, T> angle) { return cos(Rad<T>(angle)); }
template<class T> inline std::pair<T, T> sincos(Unit<Rad, T> angle) {
return {std::sin(T(angle)) ,std::cos(T(angle))};
}
template<class T> inline std::pair<T, T> sincos(Unit<Deg, T> angle) { return sincos(Rad<T>(angle)); }
template<class T> inline T tan(Unit<Rad, T> angle) { return std::tan(T(angle)); }
template<class T> inline T tan(Unit<Deg, T> angle) { return tan(Rad<T>(angle)); }
template<class T> inline Rad<T> asin(T value) { return Rad<T>(std::asin(value)); }
template<class T> inline Rad<T> acos(T value) { return Rad<T>(std::acos(value)); }
template<class T> inline Rad<T> atan(T value) { return Rad<T>(std::atan(value)); }
template<UnsignedInt exponent, class T> constexpr typename std::enable_if<std::is_arithmetic<T>::value, T>::type pow(T base) {
return Implementation::Pow<exponent>::pow(base);
}
template<UnsignedInt exponent, std::size_t size, class T> inline Vector<size, T> pow(const Vector<size, T>& base) {
Vector<size, T> out{NoInit};
for(std::size_t i = 0; i != size; ++i)
out[i] = Implementation::Pow<exponent>::pow(base[i]);
return out;
}
template<class T> inline typename std::enable_if<std::is_arithmetic<T>::value, T>::type pow(T base, T exponent) {
return std::pow(base, exponent);
}
template<std::size_t size, class T> inline Vector<size, T> pow(const Vector<size, T>& base, T exponent) {
Vector<size, T> out{NoInit};
for(std::size_t i = 0; i != size; ++i)
out[i] = std::pow(base[i], exponent);
return out;
}
template<std::size_t size, class T> inline Vector<size, T> min(const Vector<size, T>& value, const Vector<size, T>& min) {
Vector<size, T> out{NoInit};
for(std::size_t i = 0; i != size; ++i)
out[i] = Math::min(value[i], min[i]);
return out;
}
template<std::size_t size, class T> inline Vector<size, T> min(const Vector<size, T>& value, T min) {
Vector<size, T> out{NoInit};
for(std::size_t i = 0; i != size; ++i)
out[i] = Math::min(value[i], min);
return out;
}
template<std::size_t size, class T> Vector<size, T> max(const Vector<size, T>& value, const Vector<size, T>& max) {
Vector<size, T> out{NoInit};
for(std::size_t i = 0; i != size; ++i)
out[i] = Math::max(value[i], max[i]);
return out;
}
template<std::size_t size, class T> inline Vector<size, T> max(const Vector<size, T>& value, T max) {
Vector<size, T> out{NoInit};
for(std::size_t i = 0; i != size; ++i)
out[i] = Math::max(value[i], max);
return out;
}
template<class T> inline typename std::enable_if<std::is_arithmetic<T>::value, std::pair<T, T>>::type minmax(T a, T b) {
return a < b ? std::make_pair(a, b) : std::make_pair(b, a);
}
template<std::size_t size, class T> inline std::pair<Vector<size, T>, Vector<size, T>> minmax(const Vector<size, T>& a, const Vector<size, T>& b) {
using std::swap;
std::pair<Vector<size, T>, Vector<size, T>> out{a, b};
for(std::size_t i = 0; i != size; ++i)
if(out.first[i] > out.second[i]) swap(out.first[i], out.second[i]);
return out;
}
template<class T> inline typename std::enable_if<std::is_arithmetic<T>::value, T>::type clamp(T value, T min, T max) {
return Math::min(Math::max(value, min), max);
}
template<std::size_t size, class T> inline Vector<size, T> clamp(const Vector<size, T>& value, const Vector<size, T>& min, const Vector<size, T>& max) {
Vector<size, T> out{NoInit};
for(std::size_t i = 0; i != size; ++i)
out[i] = clamp(value[i], min[i], max[i]);
return out;
}
template<std::size_t size, class T> inline Vector<size, T> clamp(const Vector<size, T>& value, T min, T max) {
Vector<size, T> out{NoInit};
for(std::size_t i = 0; i != size; ++i)
out[i] = clamp(value[i], min, max);
return out;
}
template<class T> inline typename std::enable_if<std::is_arithmetic<T>::value, T>::type sign(const T& scalar) {
if(scalar > T(0)) return T(1);
if(scalar < T(0)) return T(-1);
return T(0);
}
template<std::size_t size, class T> inline Vector<size, T> sign(const Vector<size, T>& a) {
Vector<size, T> out{NoInit};
for(std::size_t i = 0; i != size; ++i)
out[i] = sign(a[i]);
return out;
}
template<class T> inline typename std::enable_if<std::is_arithmetic<T>::value, T>::type abs(T a) {
return std::abs(a);
}
template<std::size_t size, class T> inline Vector<size, T> abs(const Vector<size, T>& a) {
Vector<size, T> out{NoInit};
for(std::size_t i = 0; i != size; ++i)
out[i] = std::abs(a[i]);
return out;
}
template<class T> inline typename std::enable_if<std::is_arithmetic<T>::value, T>::type floor(T a) {
return std::floor(a);
}
template<std::size_t size, class T> inline Vector<size, T> floor(const Vector<size, T>& a) {
Vector<size, T> out{NoInit};
for(std::size_t i = 0; i != size; ++i)
out[i] = std::floor(a[i]);
return out;
}
template<class T> inline typename std::enable_if<std::is_arithmetic<T>::value, T>::type round(T a) {
return std::round(a);
}
template<std::size_t size, class T> inline Vector<size, T> round(const Vector<size, T>& a) {
Vector<size, T> out{NoInit};
for(std::size_t i = 0; i != size; ++i)
out[i] = std::round(a[i]);
return out;
}
template<class T> inline typename std::enable_if<std::is_arithmetic<T>::value, T>::type ceil(T a) {
return std::ceil(a);
}
template<std::size_t size, class T> inline Vector<size, T> ceil(const Vector<size, T>& a) {
Vector<size, T> out{NoInit};
for(std::size_t i = 0; i != size; ++i)
out[i] = std::ceil(a[i]);
return out;
}
template<class T> inline typename std::enable_if<std::is_arithmetic<T>::value, T>::type sqrt(T a) {
return T(std::sqrt(a));
}
template<std::size_t size, class T> inline Vector<size, T> sqrt(const Vector<size, T>& a) {
Vector<size, T> out{NoInit};
for(std::size_t i = 0; i != size; ++i)
out[i] = T(std::sqrt(a[i]));
return out;
}
template<class T> inline typename std::enable_if<std::is_arithmetic<T>::value, T>::type sqrtInverted(T a) {
return T(1)/std::sqrt(a);
}
template<std::size_t size, class T> inline Vector<size, T> sqrtInverted(const Vector<size, T>& a) {
return Vector<size, T>(T(1))/sqrt(a);
}
template<class T, class U> inline
typename std::enable_if<Implementation::IsVectorOrScalar<T>::value && !Implementation::IsBoolVectorOrScalar<U>::value, T>::type
lerp(const T& a, const T& b, U t) {
return Implementation::lerp(a, b, t);
}
template<class T> inline T lerp(const T& a, const T& b, bool t) {
return t ? b : a;
}
template<std::size_t size, class T> inline Vector<size, T> lerp(const Vector<size, T>& a, const Vector<size, T>& b, const BoolVector<size>& t) {
Vector<size, T> out{NoInit};
for(std::size_t i = 0; i != size; ++i)
out[i] = t[i] ? b[i] : a[i];
return out;
}
template<std::size_t size> inline BoolVector<size> lerp(const BoolVector<size>& a, const BoolVector<size>& b, const BoolVector<size>& t) {
BoolVector<size> out;
for(std::size_t i = 0; i != size; ++i)
out.set(i, t[i] ? b[i] : a[i]);
return out;
}
template<class T> inline T lerpInverted(T a, T b, T lerp) {
return (lerp - a)/(b - a);
}
template<std::size_t size, class T, class U> inline Vector<size, T> lerpInverted(const Vector<size, T>& a, const Vector<size, T>& b, const Vector<size, T>& lerp) {
return (lerp - a)/(b - a);
}
template<class T, class U> constexpr T select(const T& a, const T& b, U t) {
return lerp(a, b, t >= U(1));
}
template<class T> inline typename std::enable_if<std::is_arithmetic<T>::value, T>::type fma(T a, T b, T c) {
#ifndef CORRADE_TARGET_EMSCRIPTEN
return std::fma(a, b, c);
#else
return a*b + c;
#endif
}
template<std::size_t size, class T> inline Vector<size, T> fma(const Vector<size, T>& a, const Vector<size, T>& b, const Vector<size, T>& c) {
return a*b + c;
}
}}
#endif
#ifndef Magnum_Math_Packing_h
#define Magnum_Math_Packing_h
namespace Magnum { namespace Math {
namespace Implementation {
template<class T, UnsignedInt bits = sizeof(T)*8> inline constexpr T bitMax() {
return T(typename std::make_unsigned<T>::type(~T{}) >> (sizeof(T)*8 - (std::is_signed<T>::value ? bits - 1 : bits)));
}
}
template<class FloatingPoint, class Integral, UnsignedInt bits = sizeof(Integral)*8> inline typename std::enable_if<std::is_arithmetic<Integral>::value && std::is_unsigned<Integral>::value, FloatingPoint>::type unpack(const Integral& value) {
static_assert(std::is_floating_point<FloatingPoint>::value && std::is_integral<Integral>::value,
"unpacking must be done from integral to floating-point type");
static_assert(bits <= sizeof(Integral)*8,
"bit count larger than size of the integral type");
return value/FloatingPoint(Implementation::bitMax<Integral, bits>());
}
template<class FloatingPoint, class Integral, UnsignedInt bits = sizeof(Integral)*8> inline typename std::enable_if<std::is_arithmetic<Integral>::value && std::is_signed<Integral>::value, FloatingPoint>::type unpack(const Integral& value) {
static_assert(std::is_floating_point<FloatingPoint>::value && std::is_integral<Integral>::value,
"unpacking must be done from integral to floating-point type");
static_assert(bits <= sizeof(Integral)*8,
"bit count larger than size of the integral type");
return Math::max(value/FloatingPoint(Implementation::bitMax<Integral, bits>()), FloatingPoint(-1.0));
}
template<class FloatingPoint, std::size_t size, class Integral, UnsignedInt bits = sizeof(Integral)*8> FloatingPoint unpack(const Vector<size, Integral>& value) {
static_assert(FloatingPoint::Size == size,
"return vector type should have the same size as input vector type");
FloatingPoint out{NoInit};
for(std::size_t i = 0; i != size; ++i)
out[i] = unpack<typename FloatingPoint::Type, Integral, bits>(value[i]);
return out;
}
template<class FloatingPoint, UnsignedInt bits, class Integral> inline typename std::enable_if<std::is_arithmetic<Integral>::value, FloatingPoint>::type unpack(const Integral& value) {
return unpack<FloatingPoint, Integral, bits>(value);
}
template<class FloatingPoint, UnsignedInt bits, std::size_t size, class Integral> inline FloatingPoint unpack(const Vector<size, Integral>& value) {
return unpack<FloatingPoint, size, Integral, bits>(value);
}
template<class Integral, class FloatingPoint, UnsignedInt bits = sizeof(Integral)*8> inline typename std::enable_if<std::is_arithmetic<FloatingPoint>::value, Integral>::type pack(FloatingPoint value) {
static_assert(std::is_floating_point<FloatingPoint>::value && std::is_integral<Integral>::value,
"packing must be done from floating-point to integral type");
static_assert(bits <= sizeof(Integral)*8,
"bit count larger than size of the integral type");
return Integral(round(value*Implementation::bitMax<Integral, bits>()));
}
template<class Integral, std::size_t size, class FloatingPoint, UnsignedInt bits = sizeof(typename Integral::Type)*8> Integral pack(const Vector<size, FloatingPoint>& value) {
static_assert(Integral::Size == size,
"return vector type should have the same size as input vector type");
Integral out{NoInit};
for(std::size_t i = 0; i != size; ++i)
out[i] = pack<typename Integral::Type, FloatingPoint, bits>(value[i]);
return out;
}
template<class Integral, UnsignedInt bits, class FloatingPoint> inline typename std::enable_if<std::is_arithmetic<FloatingPoint>::value, Integral>::type pack(FloatingPoint value) {
return pack<Integral, FloatingPoint, bits>(value);
}
template<class Integral, UnsignedInt bits, std::size_t size, class FloatingPoint> inline Integral pack(const Vector<size, FloatingPoint>& value) {
return pack<Integral, size, FloatingPoint, bits>(value);
}
MAGNUM_EXPORT UnsignedShort packHalf(Float value);
template<std::size_t size> Vector<size, UnsignedShort> packHalf(const Vector<size, Float>& value) {
Vector<size, UnsignedShort> out{NoInit};
for(std::size_t i = 0; i != size; ++i)
out[i] = packHalf(value[i]);
return out;
}
MAGNUM_EXPORT Float unpackHalf(UnsignedShort value);
template<std::size_t size> Vector<size, Float> unpackHalf(const Vector<size, UnsignedShort>& value) {
Vector<size, Float> out{NoInit};
for(std::size_t i = 0; i != size; ++i)
out[i] = unpackHalf(value[i]);
return out;
}
}}
#endif
#ifndef Magnum_Math_Vector2_h
#define Magnum_Math_Vector2_h
namespace Magnum { namespace Math {
template<class T> inline T cross(const Vector2<T>& a, const Vector2<T>& b) {
return dot(a.perpendicular(), b);
}
template<class T> class Vector2: public Vector<2, T> {
public:
constexpr static Vector2<T> xAxis(T length = T(1)) { return {length, T(0)}; }
constexpr static Vector2<T> yAxis(T length = T(1)) { return {T(0), length}; }
constexpr static Vector2<T> xScale(T scale) { return {scale, T(1)}; }
constexpr static Vector2<T> yScale(T scale) { return {T(1), scale}; }
constexpr /*implicit*/ Vector2(ZeroInitT = ZeroInit) noexcept
: Vector<2, T>{ZeroInit}
{}
explicit Vector2(NoInitT) noexcept
: Vector<2, T>{NoInit}
{}
constexpr explicit Vector2(T value) noexcept: Vector<2, T>(value) {}
constexpr /*implicit*/ Vector2(T x, T y) noexcept: Vector<2, T>(x, y) {}
template<class U> constexpr explicit Vector2(const Vector<2, U>& other) noexcept: Vector<2, T>(other) {}
template<class U, class V =
#ifndef CORRADE_MSVC2015_COMPATIBILITY /* Causes ICE */
decltype(Implementation::VectorConverter<2, T, U>::from(std::declval<U>()))
#else
decltype(Implementation::VectorConverter<2, T, U>())
#endif
>
constexpr explicit Vector2(const U& other): Vector<2, T>(Implementation::VectorConverter<2, T, U>::from(other)) {}
constexpr /*implicit*/ Vector2(const Vector<2, T>& other) noexcept: Vector<2, T>(other) {}
T& x() { return Vector<2, T>::_data[0]; }
constexpr T x() const { return Vector<2, T>::_data[0]; }
T& y() { return Vector<2, T>::_data[1]; }
constexpr T y() const { return Vector<2, T>::_data[1]; }
Vector2<T> perpendicular() const { return {-y(), x()}; }
template<class U = T> typename std::enable_if<std::is_floating_point<U>::value, T>::type
aspectRatio() const { return x()/y(); }
MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(2, Vector2)
};
MAGNUM_VECTORn_OPERATOR_IMPLEMENTATION(2, Vector2)
namespace Implementation {
template<std::size_t, class> struct TypeForSize;
template<class T> struct TypeForSize<2, T> { typedef Math::Vector2<typename T::Type> Type; };
template<class T> struct StrictWeakOrdering<Vector2<T>>: StrictWeakOrdering<Vector<2, T>> {};
}
}}
#endif
#ifndef Magnum_Math_Swizzle_h
#define Magnum_Math_Swizzle_h
namespace Magnum { namespace Math {
namespace Implementation {
template<std::size_t size, std::size_t position> struct ComponentAtPosition {
static_assert(size > position, "Swizzle parameter out of range of base vector");
template<class T> 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> struct Component<size, 'x'>: public ComponentAtPosition<size, 0> {};
template<std::size_t size> struct Component<size, 'y'>: public ComponentAtPosition<size, 1> {};
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, 'r'>: public ComponentAtPosition<size, 0> {};
template<std::size_t size> struct Component<size, 'g'>: public ComponentAtPosition<size, 1> {};
template<std::size_t size> struct Component<size, 'b'>: public ComponentAtPosition<size, 2> {};
template<std::size_t size> struct Component<size, 'a'>: public ComponentAtPosition<size, 3> {};
template<std::size_t size> struct Component<size, '0'> {
template<class T> constexpr static T value(const Math::Vector<size, T>&) { return T(0); }
};
template<std::size_t size> struct Component<size, '1'> {
template<class T> constexpr static T value(const Math::Vector<size, T>&) { return T(1); }
};
template<std::size_t size, class T> struct TypeForSize {
typedef Math::Vector<size, typename T::Type> Type;
};
}
template<char ...components, class T> constexpr typename Implementation::TypeForSize<sizeof...(components), T>::Type swizzle(const T& vector) {
return {Implementation::Component<T::Size, components>::value(vector)...};
}
}}
#endif
#ifndef Magnum_Math_Vector3_h
#define Magnum_Math_Vector3_h
namespace Magnum { namespace Math {
template<class T> inline Vector3<T> cross(const Vector3<T>& a, const Vector3<T>& b) {
return swizzle<'y', 'z', 'x'>(a*swizzle<'y', 'z', 'x'>(b) -
b*swizzle<'y', 'z', 'x'>(a));
}
template<class T> class Vector3: public Vector<3, T> {
public:
constexpr static Vector3<T> xAxis(T length = T(1)) { return {length, T(0), T(0)}; }
constexpr static Vector3<T> yAxis(T length = T(1)) { return {T(0), length, T(0)}; }
constexpr static Vector3<T> zAxis(T length = T(1)) { return {T(0), T(0), length}; }
constexpr static Vector3<T> xScale(T scale) { return {scale, T(1), T(1)}; }
constexpr static Vector3<T> yScale(T scale) { return {T(1), scale, T(1)}; }
constexpr static Vector3<T> zScale(T scale) { return {T(1), T(1), scale}; }
constexpr /*implicit*/ Vector3(ZeroInitT = ZeroInit) noexcept
: Vector<3, T>{ZeroInit}
{}
explicit Vector3(NoInitT) noexcept
: Vector<3, T>{NoInit}
{}
constexpr explicit Vector3(T value) noexcept: Vector<3, T>(value) {}
constexpr /*implicit*/ Vector3(T x, T y, T z) noexcept: Vector<3, T>(x, y, z) {}
constexpr /*implicit*/ Vector3(const Vector2<T>& xy, T z) noexcept: Vector<3, T>(xy[0], xy[1], z) {}
template<class U> constexpr explicit Vector3(const Vector<3, U>& other) noexcept: Vector<3, T>(other) {}
template<class U, class V =
#ifndef CORRADE_MSVC2015_COMPATIBILITY /* Causes ICE */
decltype(Implementation::VectorConverter<3, T, U>::from(std::declval<U>()))
#else
decltype(Implementation::VectorConverter<3, T, U>())
#endif
>
constexpr explicit Vector3(const U& other): Vector<3, T>(Implementation::VectorConverter<3, T, U>::from(other)) {}
constexpr /*implicit*/ Vector3(const Vector<3, T>& other) noexcept: Vector<3, T>(other) {}
T& x() { return Vector<3, T>::_data[0]; }
constexpr T x() const { return Vector<3, T>::_data[0]; }
T& y() { return Vector<3, T>::_data[1]; }
constexpr T y() const { return Vector<3, T>::_data[1]; }
T& z() { return Vector<3, T>::_data[2]; }
constexpr T z() const { return Vector<3, T>::_data[2]; }
T& r() { return Vector<3, T>::_data[0]; }
constexpr T r() const { return Vector<3, T>::_data[0]; }
T& g() { return Vector<3, T>::_data[1]; }
constexpr T g() const { return Vector<3, T>::_data[1]; }
T& b() { return Vector<3, T>::_data[2]; }
constexpr T b() const { return Vector<3, T>::_data[2]; }
Vector2<T>& xy() { return Vector2<T>::from(Vector<3, T>::data()); }
constexpr const Vector2<T> xy() const {
return {Vector<3, T>::_data[0], Vector<3, T>::_data[1]};
}
MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(3, Vector3)
};
MAGNUM_VECTORn_OPERATOR_IMPLEMENTATION(3, Vector3)
namespace Implementation {
template<class T> struct TypeForSize<3, T> { typedef Math::Vector3<typename T::Type> Type; };
template<class T> struct StrictWeakOrdering<Vector3<T>>: StrictWeakOrdering<Vector<3, T>> {};
}
}}
#endif
#ifndef Magnum_Math_Vector4_h
#define Magnum_Math_Vector4_h
namespace Magnum { namespace Math {
template<class T> class Vector4: public Vector<4, T> {
public:
template<std::size_t otherSize> constexpr static Vector4<T> pad(const Vector<otherSize, T>& a, T xyz, T w) {
return {0 < otherSize ? a[0] : xyz,
1 < otherSize ? a[1] : xyz,
2 < otherSize ? a[2] : xyz,
3 < otherSize ? a[3] : w};
}
constexpr /*implicit*/ Vector4(ZeroInitT = ZeroInit) noexcept
: Vector<4, T>{ZeroInit}
{}
explicit Vector4(NoInitT) noexcept
: Vector<4, T>{NoInit}
{}
constexpr explicit Vector4(T value) noexcept: Vector<4, T>(value) {}
constexpr /*implicit*/ Vector4(T x, T y, T z, T w) noexcept: Vector<4, T>(x, y, z, w) {}
constexpr /*implicit*/ Vector4(const Vector3<T>& xyz, T w) noexcept: Vector<4, T>(xyz[0], xyz[1], xyz[2], w) {}
template<class U> constexpr explicit Vector4(const Vector<4, U>& other) noexcept: Vector<4, T>(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)) {}
constexpr /*implicit*/ Vector4(const Vector<4, T>& other) noexcept: Vector<4, T>(other) {}
T& x() { return Vector<4, T>::_data[0]; }
constexpr T x() const { return Vector<4, T>::_data[0]; }
T& y() { return Vector<4, T>::_data[1]; }
constexpr T y() const { return Vector<4, T>::_data[1]; }
T& z() { return Vector<4, T>::_data[2]; }
constexpr T z() const { return Vector<4, T>::_data[2]; }
T& w() { return Vector<4, T>::_data[3]; }
constexpr T w() const { return Vector<4, T>::_data[3]; }
T& r() { return Vector<4, T>::_data[0]; }
constexpr T r() const { return Vector<4, T>::_data[0]; }
T& g() { return Vector<4, T>::_data[1]; }
constexpr T g() const { return Vector<4, T>::_data[1]; }
T& b() { return Vector<4, T>::_data[2]; }
constexpr T b() const { return Vector<4, T>::_data[2]; }
T& a() { return Vector<4, T>::_data[3]; }
constexpr T a() const { return Vector<4, T>::_data[3]; }
Vector3<T>& xyz() { return Vector3<T>::from(Vector<4, T>::data()); }
constexpr const Vector3<T> xyz() const {
return {Vector<4, T>::_data[0], Vector<4, T>::_data[1], Vector<4, T>::_data[2]};
}
Vector3<T>& rgb() { return Vector3<T>::from(Vector<4, T>::data()); }
constexpr const Vector3<T> rgb() const {
return {Vector<4, T>::_data[0], Vector<4, T>::_data[1], Vector<4, T>::_data[2]};
}
Vector2<T>& xy() { return Vector2<T>::from(Vector<4, T>::data()); }
constexpr const Vector2<T> xy() const {
return {Vector<4, T>::_data[0], Vector<4, T>::_data[1]};
}
MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(4, Vector4)
};
template<class T> Vector4<T> planeEquation(const Vector3<T>& p0, const Vector3<T>& p1, const Vector3<T>& p2) {
const Vector3<T> normal = Math::cross(p1 - p0, p2 - p0).normalized();
return {normal, -Math::dot(normal, p0)};
}
template<class T> Vector4<T> planeEquation(const Vector3<T>& normal, const Vector3<T>& point) {
return {normal, -Math::dot(normal, point)};
}
MAGNUM_VECTORn_OPERATOR_IMPLEMENTATION(4, Vector4)
namespace Implementation {
template<class T> struct TypeForSize<4, T> { typedef Math::Vector4<typename T::Type> Type; };
template<class T> struct StrictWeakOrdering<Vector4<T>>: StrictWeakOrdering<Vector<4, T>> {};
}
}}
#endif
#ifndef Magnum_Math_Color_h
#define Magnum_Math_Color_h
namespace Magnum { namespace Math {
namespace Implementation {
template<class T> typename std::enable_if<std::is_floating_point<T>::value, Color3<T>>::type fromHsv(ColorHsv<T> hsv) {
hsv.hue -= floor(T(hsv.hue)/T(360))*Deg<T>(360);
if(hsv.hue < Deg<T>(0)) hsv.hue += Deg<T>(360);
int h = int(T(hsv.hue)/T(60)) % 6;
T f = T(hsv.hue)/T(60) - h;
T p = hsv.value * (T(1) - hsv.saturation);
T q = hsv.value * (T(1) - f*hsv.saturation);
T t = hsv.value * (T(1) - (T(1) - f)*hsv.saturation);
switch(h) {
case 0: return {hsv.value, t, p};
case 1: return {q, hsv.value, p};
case 2: return {p, hsv.value, t};
case 3: return {p, q, hsv.value};
case 4: return {t, p, hsv.value};
case 5: return {hsv.value, p, q};
default: CORRADE_ASSERT_UNREACHABLE();
}
}
template<class T> inline typename std::enable_if<std::is_integral<T>::value, Color3<T>>::type fromHsv(const ColorHsv<typename TypeTraits<T>::FloatingPointType>& hsv) {
return pack<Color3<T>>(fromHsv<typename TypeTraits<T>::FloatingPointType>(hsv));
}
template<class T> Deg<T> hue(const Color3<T>& color, T max, T delta) {
T deltaInv60 = T(60)/delta;
T hue(0);
if(delta != T(0)) {
if(max == color.r())
hue = (color.g()-color.b())*deltaInv60 + (color.g() < color.b() ? T(360) : T(0));
else if(max == color.g())
hue = (color.b()-color.r())*deltaInv60 + T(120);
else
hue = (color.r()-color.g())*deltaInv60 + T(240);
}
return Deg<T>(hue);
}
template<class T> inline Deg<T> hue(typename std::enable_if<std::is_floating_point<T>::value, const Color3<T>&>::type color) {
T max = color.max();
T delta = max - color.min();
return hue(color, max, delta);
}
template<class T> inline T saturation(typename std::enable_if<std::is_floating_point<T>::value, const Color3<T>&>::type color) {
T max = color.max();
T delta = max - color.min();
return max != T(0) ? delta/max : T(0);
}
template<class T> inline T value(typename std::enable_if<std::is_floating_point<T>::value, const Color3<T>&>::type color) {
return color.max();
}
template<class T> inline Deg<typename Color3<T>::FloatingPointType> hue(typename std::enable_if<std::is_integral<T>::value, const Color3<T>&>::type color) {
return hue<typename Color3<T>::FloatingPointType>(unpack<Color3<typename Color3<T>::FloatingPointType>>(color));
}
template<class T> inline typename Color3<T>::FloatingPointType saturation(typename std::enable_if<std::is_integral<T>::value, const Color3<T>&>::type& color) {
return saturation<typename Color3<T>::FloatingPointType>(unpack<Color3<typename Color3<T>::FloatingPointType>>(color));
}
template<class T> inline typename Color3<T>::FloatingPointType value(typename std::enable_if<std::is_integral<T>::value, const Color3<T>&>::type color) {
return unpack<typename Color3<T>::FloatingPointType>(color.max());
}
template<class T> inline ColorHsv<T> toHsv(typename std::enable_if<std::is_floating_point<T>::value, const Color3<T>&>::type color) {
T max = color.max();
T delta = max - color.min();
return ColorHsv<T>{hue<typename Color3<T>::FloatingPointType>(color, max, delta), max != T(0) ? delta/max : T(0), max};
}
template<class T> inline ColorHsv<typename TypeTraits<T>::FloatingPointType> toHsv(typename std::enable_if<std::is_integral<T>::value, const Color3<T>&>::type color) {
return toHsv<typename TypeTraits<T>::FloatingPointType>(unpack<Color3<typename TypeTraits<T>::FloatingPointType>>(color));
}
template<class T> typename std::enable_if<std::is_floating_point<T>::value, Color3<T>>::type fromSrgb(const Vector3<T>& srgb) {
constexpr const T a(T(0.055));
return lerp(srgb/T(12.92), pow((srgb + Vector3<T>{a})/(T(1.0) + a), T(2.4)), srgb > Vector3<T>(T(0.04045)));
}
template<class T> typename std::enable_if<std::is_floating_point<T>::value, Color4<T>>::type fromSrgbAlpha(const Vector4<T>& srgbAlpha) {
return {fromSrgb<T>(srgbAlpha.rgb()), srgbAlpha.a()};
}
template<class T> inline typename std::enable_if<std::is_integral<T>::value, Color3<T>>::type fromSrgb(const Vector3<typename Color3<T>::FloatingPointType>& srgb) {
return pack<Color3<T>>(fromSrgb<typename Color3<T>::FloatingPointType>(srgb));
}
template<class T> inline typename std::enable_if<std::is_integral<T>::value, Color4<T>>::type fromSrgbAlpha(const Vector4<typename Color4<T>::FloatingPointType>& srgbAlpha) {
return {fromSrgb<T>(srgbAlpha.rgb()), pack<T>(srgbAlpha.a())};
}
template<class T, class Integral> inline Color3<T> fromSrgbIntegral(const Vector3<Integral>& srgb) {
static_assert(std::is_integral<Integral>::value, "only conversion from different integral type is supported");
return fromSrgb<T>(unpack<Vector3<typename Color3<T>::FloatingPointType>>(srgb));
}
template<class T, class Integral> inline Color4<T> fromSrgbAlphaIntegral(const Vector4<Integral>& srgbAlpha) {
static_assert(std::is_integral<Integral>::value, "only conversion from different integral type is supported");
return fromSrgbAlpha<T>(unpack<Vector4<typename Color4<T>::FloatingPointType>>(srgbAlpha));
}
template<class T> Vector3<typename Color3<T>::FloatingPointType> toSrgb(typename std::enable_if<std::is_floating_point<T>::value, const Color3<T>&>::type rgb) {
constexpr const T a = T(0.055);
return lerp(rgb*T(12.92), (T(1.0) + a)*pow(rgb, T(1.0)/T(2.4)) - Vector3<T>{a}, rgb > Vector3<T>(T(0.0031308)));
}
template<class T> Vector4<typename Color4<T>::FloatingPointType> toSrgbAlpha(typename std::enable_if<std::is_floating_point<T>::value, const Color4<T>&>::type rgba) {
return {toSrgb<T>(rgba.rgb()), rgba.a()};
}
template<class T> inline Vector3<typename Color3<T>::FloatingPointType> toSrgb(typename std::enable_if<std::is_integral<T>::value, const Color3<T>&>::type rgb) {
return toSrgb<typename Color3<T>::FloatingPointType>(unpack<Color3<typename Color3<T>::FloatingPointType>>(rgb));
}
template<class T> inline Vector4<typename Color4<T>::FloatingPointType> toSrgbAlpha(typename std::enable_if<std::is_integral<T>::value, const Color4<T>&>::type rgba) {
return {toSrgb<T>(rgba.rgb()), unpack<typename Color3<T>::FloatingPointType>(rgba.a())};
}
template<class T, class Integral> inline Vector3<Integral> toSrgbIntegral(const Color3<T>& rgb) {
static_assert(std::is_integral<Integral>::value, "only conversion from different integral type is supported");
return pack<Vector3<Integral>>(toSrgb<T>(rgb));
}
template<class T, class Integral> inline Vector4<Integral> toSrgbAlphaIntegral(const Color4<T>& rgba) {
static_assert(std::is_integral<Integral>::value, "only conversion from different integral type is supported");
return pack<Vector4<Integral>>(toSrgbAlpha<T>(rgba));
}
template<class T> typename std::enable_if<std::is_floating_point<T>::value, Color3<T>>::type fromXyz(const Vector3<T>& xyz) {
return Matrix3x3<T>{
Vector3<T>{T(12831)/T(3959), T(-851781)/T(878810), T(705)/T(12673)},
Vector3<T>{T(-329)/T(214), T(1648619)/T(878810), T(-2585)/T(12673)},
Vector3<T>{T(-1974)/T(3959), T(36519)/T(878810), T(705)/T(667)}}*xyz;
}
template<class T> inline typename std::enable_if<std::is_integral<T>::value, Color3<T>>::type fromXyz(const Vector3<typename Color3<T>::FloatingPointType>& xyz) {
return pack<Color3<T>>(fromXyz<typename Color3<T>::FloatingPointType>(xyz));
}
template<class T> Vector3<typename Color3<T>::FloatingPointType> toXyz(typename std::enable_if<std::is_floating_point<T>::value, const Color3<T>&>::type rgb) {
return (Matrix3x3<T>{
Vector3<T>{T(506752)/T(1228815), T(87098)/T(409605), T(7918)/T(409605)},
Vector3<T>{T(87881)/T(245763), T(175762)/T(245763), T(87881)/T(737289)},
Vector3<T>{T(12673)/T(70218), T(12673)/T(175545), T(1001167)/T(1053270)}})*rgb;
}
template<class T> inline Vector3<typename Color3<T>::FloatingPointType> toXyz(typename std::enable_if<std::is_integral<T>::value, const Color3<T>&>::type rgb) {
return toXyz<typename Color3<T>::FloatingPointType>(unpack<Color3<typename Color3<T>::FloatingPointType>>(rgb));
}
#if !defined(CORRADE_MSVC2017_COMPATIBILITY) || defined(CORRADE_MSVC2015_COMPATIBILITY)
template<class T> constexpr typename std::enable_if<std::is_floating_point<T>::value, T>::type fullChannel() {
return T(1);
}
template<class T> constexpr typename std::enable_if<std::is_integral<T>::value, T>::type fullChannel() {
return Implementation::bitMax<T>();
}
#else
template<class T> constexpr T fullChannel() { return bitMax<T>(); }
template<> constexpr float fullChannel<float>() { return 1.0f; }
template<> constexpr double fullChannel<double>() { return 1.0; }
template<> constexpr long double fullChannel<long double>() { return 1.0l; }
#endif
}
template<class T> class Color3: public Vector3<T> {
public:
typedef typename TypeTraits<T>::FloatingPointType FloatingPointType;
constexpr static Color3<T> red(T red = Implementation::fullChannel<T>()) {
return Vector3<T>::xAxis(red);
}
constexpr static Color3<T> green(T green = Implementation::fullChannel<T>()) {
return Vector3<T>::yAxis(green);
}
constexpr static Color3<T> blue(T blue = Implementation::fullChannel<T>()) {
return Vector3<T>::zAxis(blue);
}
constexpr static Color3<T> cyan(T red = T(0)) {
return {red, Implementation::fullChannel<T>(), Implementation::fullChannel<T>()};
}
constexpr static Color3<T> magenta(T green = T(0)) {
return {Implementation::fullChannel<T>(), green, Implementation::fullChannel<T>()};
}
constexpr static Color3<T> yellow(T blue = T(0)) {
return {Implementation::fullChannel<T>(), Implementation::fullChannel<T>(), blue};
}
static Color3<T> fromHsv(const ColorHsv<FloatingPointType>& hsv) {
return Implementation::fromHsv<T>(hsv);
}
static Color3<T> fromSrgb(const Vector3<FloatingPointType>& srgb) {
return Implementation::fromSrgb<T>(srgb);
}
template<class Integral> static Color3<T> fromSrgb(const Vector3<Integral>& srgb) {
return Implementation::fromSrgbIntegral<T, Integral>(srgb);
}
static Color3<T> fromSrgb(UnsignedInt srgb) {
return fromSrgb<UnsignedByte>({UnsignedByte(srgb >> 16),
UnsignedByte(srgb >> 8),
UnsignedByte(srgb)});
}
static Color3<T> fromXyz(const Vector3<FloatingPointType>& xyz) {
return Implementation::fromXyz<T>(xyz);
}
constexpr /*implicit*/ Color3(ZeroInitT = ZeroInit) noexcept
: Vector3<T>{ZeroInit}
{}
explicit Color3(NoInitT) noexcept
: Vector3<T>{NoInit}
{}
constexpr explicit Color3(T rgb) noexcept: Vector3<T>(rgb) {}
constexpr /*implicit*/ Color3(T r, T g, T b) noexcept: Vector3<T>(r, g, b) {}
template<class U> constexpr explicit Color3(const Vector<3, U>& other) noexcept: Vector3<T>(other) {}
template<class U, class V =
#ifndef CORRADE_MSVC2015_COMPATIBILITY /* Causes ICE */
decltype(Implementation::VectorConverter<3, T, U>::from(std::declval<U>()))
#else
decltype(Implementation::VectorConverter<3, T, U>())
#endif
>
constexpr explicit Color3(const U& other): Vector3<T>(Implementation::VectorConverter<3, T, U>::from(other)) {}
constexpr /*implicit*/ Color3(const Vector<3, T>& other) noexcept: Vector3<T>(other) {}
ColorHsv<FloatingPointType> toHsv() const {
return Implementation::toHsv<T>(*this);
}
Deg<FloatingPointType> hue() const {
return Deg<FloatingPointType>(Implementation::hue<T>(*this));
}
FloatingPointType saturation() const {
return Implementation::saturation<T>(*this);
}
FloatingPointType value() const {
return Implementation::value<T>(*this);
}
Vector3<FloatingPointType> toSrgb() const {
return Implementation::toSrgb<T>(*this);
}
template<class Integral> Vector3<Integral> toSrgb() const {
return Implementation::toSrgbIntegral<T, Integral>(*this);
}
UnsignedInt toSrgbInt() const {
const auto srgb = toSrgb<UnsignedByte>();
return (srgb[0] << 16) | (srgb[1] << 8) | srgb[2];
}
Vector3<FloatingPointType> toXyz() const {
return Implementation::toXyz<T>(*this);
}
MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(3, Color3)
};
MAGNUM_VECTORn_OPERATOR_IMPLEMENTATION(3, Color3)
template<class T>
class Color4: public Vector4<T> {
public:
typedef typename Color3<T>::FloatingPointType FloatingPointType;
constexpr static Color4<T> red(T red = Implementation::fullChannel<T>(), T alpha = Implementation::fullChannel<T>()) {
return {red, T(0), T(0), alpha};
}
constexpr static Color4<T> green(T green = Implementation::fullChannel<T>(), T alpha = Implementation::fullChannel<T>()) {
return {T(0), green, T(0), alpha};
}
constexpr static Color4<T> blue(T blue = Implementation::fullChannel<T>(), T alpha = Implementation::fullChannel<T>()) {
return {T(0), T(0), blue, alpha};
}
constexpr static Color4<T> cyan(T red = T(0), T alpha = Implementation::fullChannel<T>()) {
return {red, Implementation::fullChannel<T>(), Implementation::fullChannel<T>(), alpha};
}
constexpr static Color4<T> magenta(T green = T(0), T alpha = Implementation::fullChannel<T>()) {
return {Implementation::fullChannel<T>(), green, Implementation::fullChannel<T>(), alpha};
}
constexpr static Color4<T> yellow(T blue = T(0), T alpha = Implementation::fullChannel<T>()) {
return {Implementation::fullChannel<T>(), Implementation::fullChannel<T>(), blue, alpha};
}
static Color4<T> fromHsv(const ColorHsv<FloatingPointType>& hsv, T a = Implementation::fullChannel<T>()) {
return Color4<T>(Implementation::fromHsv<T>(hsv), a);
}
static Color4<T> fromSrgbAlpha(const Vector4<FloatingPointType>& srgbAlpha) {
return {Implementation::fromSrgbAlpha<T>(srgbAlpha)};
}
static Color4<T> fromSrgb(const Vector3<FloatingPointType>& srgb, T a = Implementation::fullChannel<T>()) {
return {Implementation::fromSrgb<T>(srgb), a};
}
template<class Integral> static Color4<T> fromSrgbAlpha(const Vector4<Integral>& srgbAlpha) {
return {Implementation::fromSrgbAlphaIntegral<T, Integral>(srgbAlpha)};
}
template<class Integral> static Color4<T> fromSrgb(const Vector3<Integral>& srgb, T a = Implementation::fullChannel<T>()) {
return {Implementation::fromSrgbIntegral<T, Integral>(srgb), a};
}
static Color4<T> fromSrgbAlpha(UnsignedInt srgbAlpha) {
return fromSrgbAlpha<UnsignedByte>({UnsignedByte(srgbAlpha >> 24),
UnsignedByte(srgbAlpha >> 16),
UnsignedByte(srgbAlpha >> 8),
UnsignedByte(srgbAlpha)});
}
static Color4<T> fromSrgb(UnsignedInt srgb, T a = Implementation::fullChannel<T>()) {
return fromSrgb<UnsignedByte>({UnsignedByte(srgb >> 16),
UnsignedByte(srgb >> 8),
UnsignedByte(srgb)}, a);
}
static Color4<T> fromXyz(const Vector3<FloatingPointType> xyz, T a = Implementation::fullChannel<T>()) {
return {Implementation::fromXyz<T>(xyz), a};
}
constexpr /*implicit*/ Color4() noexcept: Vector4<T>(T(0), T(0), T(0), T(0)) {}
constexpr explicit Color4(ZeroInitT) noexcept
: Vector4<T>{ZeroInit}
{}
explicit Color4(NoInitT) noexcept
: Vector4<T>{NoInit}
{}
constexpr explicit Color4(T rgb, T alpha = Implementation::fullChannel<T>()) noexcept: Vector4<T>(rgb, rgb, rgb, alpha) {}
constexpr /*implicit*/ Color4(T r, T g, T b, T a = Implementation::fullChannel<T>()) noexcept: Vector4<T>(r, g, b, a) {}
constexpr /*implicit*/ Color4(const Vector3<T>& rgb, T a = Implementation::fullChannel<T>()) noexcept: Vector4<T>(rgb[0], rgb[1], rgb[2], a) {}
template<class U> constexpr explicit Color4(const Vector<4, U>& other) noexcept: Vector4<T>(other) {}
template<class U, class V =
#ifndef CORRADE_MSVC2015_COMPATIBILITY /* Causes ICE */
decltype(Implementation::VectorConverter<4, T, U>::from(std::declval<U>()))
#else
decltype(Implementation::VectorConverter<4, T, U>())
#endif
>
constexpr explicit Color4(const U& other): Vector4<T>(Implementation::VectorConverter<4, T, U>::from(other)) {}
constexpr /*implicit*/ Color4(const Vector<4, T>& other) noexcept: Vector4<T>(other) {}
ColorHsv<FloatingPointType> toHsv() const {
return Implementation::toHsv<T>(Vector4<T>::rgb());
}
Deg<FloatingPointType> hue() const {
return Implementation::hue<T>(Vector4<T>::rgb());
}
FloatingPointType saturation() const {
return Implementation::saturation<T>(Vector4<T>::rgb());
}
FloatingPointType value() const {
return Implementation::value<T>(Vector4<T>::rgb());
}
Vector4<FloatingPointType> toSrgbAlpha() const {
return Implementation::toSrgbAlpha<T>(*this);
}
template<class Integral> Vector4<Integral> toSrgbAlpha() const {
return Implementation::toSrgbAlphaIntegral<T, Integral>(*this);
}
UnsignedInt toSrgbAlphaInt() const {