#pragma once #include #include #include #include #include namespace Scop { namespace Internal { template struct AngleConversion; template struct AngleConversion { template static constexpr T Convert(T angle) { return angle; } }; template<> struct AngleConversion { template static constexpr T Convert(T angle) { return DegreeToRadian(angle); } }; template<> struct AngleConversion { template static constexpr T Convert(T angle) { return angle / T(360); } }; template<> struct AngleConversion { template static constexpr T Convert(T angle) { return RadianToDegree(angle); } }; template<> struct AngleConversion { template static constexpr T Convert(T angle) { return angle / Tau(); } }; template<> struct AngleConversion { template static constexpr T Convert(T angle) { return angle * T(360); } }; template<> struct AngleConversion { template static constexpr T Convert(T angle) { return angle * Tau(); } }; template struct AngleUtils; template<> struct AngleUtils { template static constexpr T GetEpsilon() { return T(1e-4); } template static constexpr T GetLimit() { return 360; } template static std::ostream& ToString(std::ostream& out, T value) { return out << "Angle(" << value << "deg)"; } }; template<> struct AngleUtils { template static constexpr T GetEpsilon() { return T(1e-5); } template static constexpr T GetLimit() { return Tau(); } template static std::ostream& ToString(std::ostream& out, T value) { return out << "Angle(" << value << "rad)"; } }; template<> struct AngleUtils { template static constexpr T GetEpsilon() { return T(1e-5); } template static constexpr T GetLimit() { return 1; } template static std::ostream& ToString(std::ostream& out, T value) { return out << "Angle(" << value << "turn)"; } }; template void SinCos(T x, T* sin, T* cos) { double s, c; ::sincos(x, &s, &c); *sin = static_cast(s); *cos = static_cast(c); } template<> inline void SinCos(float x, float* s, float* c) { ::sincosf(x, s, c); } template<> inline void SinCos(long double x, long double* s, long double* c) { ::sincosl(x, s, c); } } template constexpr Angle::Angle(T angle) : value(angle) { } template template constexpr Angle::Angle(const Angle& angle) : value(static_cast(angle.value)) { } template template constexpr Angle::Angle(const Angle& angle) : value(Internal::AngleConversion::Convert(angle.value)) { } template constexpr bool Angle::ApproxEqual(const Angle& angle) const { return ApproxEqual(angle, Internal::AngleUtils::template GetEpsilon()); } template constexpr bool Angle::ApproxEqual(const Angle& angle, T maxDifference) const { return NumberEquals(value, angle.value, maxDifference); } template T Angle::GetCos() const { return std::cos(ToRadians()); } template T Angle::GetSin() const { return std::sin(ToRadians()); } template std::pair Angle::GetSinCos() const { T sin, cos; Internal::SinCos(ToRadians(), &sin, &cos); return std::make_pair(sin, cos); } template T Angle::GetTan() const { return std::tan(ToRadians()); } template constexpr Angle& Angle::Normalize() { constexpr T limit = Internal::AngleUtils::template GetLimit(); constexpr T halfLimit = limit / T(2); value = Mod(value + halfLimit, limit); if (value < T(0)) value += limit; value -= halfLimit; return *this; } template template T Angle::To() const { return Internal::AngleConversion::Convert(value); } template template Angle Angle::ToAngle() const { return Angle(To()); } template constexpr T Angle::ToDegrees() const { return To(); } template constexpr Angle Angle::ToDegreeAngle() const { return ToAngle(); } template EulerAngles Angle::ToEulerAngles() const { return EulerAngles(0, 0, ToDegrees()); } template Quat Angle::ToQuat() const { auto halfAngle = Angle(*this) / 2.f; auto sincos = halfAngle.GetSinCos(); return Quat(sincos.second, 0, 0, sincos.first); } template constexpr T Angle::ToRadians() const { return To(); } template constexpr Angle Angle::ToRadianAngle() const { return ToAngle(); } template std::string Angle::ToString() const { std::ostringstream oss; Internal::AngleUtils::ToString(oss, value); return oss.str(); } template constexpr T Angle::ToTurns() const { return To(value); } template constexpr Angle Angle::ToTurnAngle() const { return ToAngle(); } template constexpr Angle Angle::operator+() const { return *this; } template constexpr Angle Angle::operator-() const { return Angle(-value); } template constexpr Angle Angle::operator+(Angle other) const { return Angle(value + other.value); } template constexpr Angle Angle::operator-(Angle other) const { return Angle(value - other.value); } template constexpr Angle Angle::operator*(T scalar) const { return Angle(value * scalar); } template constexpr Angle Angle::operator/(T divider) const { return Angle(value / divider); } template constexpr Angle& Angle::operator+=(Angle other) { value += other.value; return *this; } template constexpr Angle& Angle::operator-=(Angle other) { value -= other.value; return *this; } template constexpr Angle& Angle::operator*=(T scalar) { value *= scalar; return *this; } template constexpr Angle& Angle::operator/=(T divider) { value /= divider; return *this; } template constexpr bool Angle::operator==(Angle other) const { return value == other.value; } template constexpr bool Angle::operator!=(Angle other) const { return value != other.value; } template constexpr bool Angle::operator<(Angle other) const { return value < other.value; } template constexpr bool Angle::operator<=(Angle other) const { return value <= other.value; } template constexpr bool Angle::operator>(Angle other) const { return value > other.value; } template constexpr bool Angle::operator>=(Angle other) const { return value >= other.value; } template constexpr bool Angle::ApproxEqual(const Angle& lhs, const Angle& rhs) { return lhs.ApproxEqual(rhs); } template constexpr bool Angle::ApproxEqual(const Angle& lhs, const Angle& rhs, T maxDifference) { return lhs.ApproxEqual(rhs, maxDifference); } template constexpr Angle Angle::Clamp(Angle angle, Angle min, Angle max) { return Angle(std::clamp(angle.value, min.value, max.value)); } template template constexpr Angle Angle::From(T value) { return Angle(Internal::AngleConversion::Convert(value)); } template constexpr Angle Angle::FromDegrees(T degrees) { return From(degrees); } template constexpr Angle Angle::FromRadians(T radians) { return From(radians); } template constexpr Angle Angle::FromTurns(T turns) { return From(turns); } template constexpr Angle Angle::Zero() { return Angle(0); } template Angle operator/(T scale, Angle angle) { return Angle(scale / angle.value); } template std::ostream& operator<<(std::ostream& out, Angle angle) { return Internal::AngleUtils::ToString(out, angle.value); } template constexpr Angle Clamp(Angle value, T min, T max) { return std::max(std::min(value.value, max), min); } }