From 364d1bafb4eca7007f1ef2f70ba0c510a0f725d1 Mon Sep 17 00:00:00 2001 From: SirLynix Date: Mon, 26 Sep 2022 19:09:30 +0200 Subject: [PATCH] Math: Add support for Turn angles --- include/Nazara/Math/Angle.hpp | 19 ++- include/Nazara/Math/Angle.inl | 235 +++++++++++++++++++++++--------- include/Nazara/Math/Enums.hpp | 3 +- tests/Engine/Math/AngleTest.cpp | 30 ++++ 4 files changed, 215 insertions(+), 72 deletions(-) diff --git a/include/Nazara/Math/Angle.hpp b/include/Nazara/Math/Angle.hpp index 3f92bcf9d..3c1064bbb 100644 --- a/include/Nazara/Math/Angle.hpp +++ b/include/Nazara/Math/Angle.hpp @@ -29,8 +29,7 @@ namespace Nz constexpr Angle() = default; constexpr Angle(T angle); template constexpr explicit Angle(const Angle& Angle); - constexpr Angle(const Angle& angle); - constexpr Angle(const Angle& angle); + template constexpr Angle(const Angle& angle); ~Angle() = default; T GetCos() const; @@ -45,6 +44,8 @@ namespace Nz constexpr Angle& Set(const Angle& ang); template constexpr Angle& Set(const Angle& ang); + template T To() const; + template Angle ToAngle() const; constexpr T ToDegrees() const; constexpr Angle ToDegreeAngle() const; EulerAngles ToEulerAngles() const; @@ -52,6 +53,8 @@ namespace Nz constexpr T ToRadians() const; constexpr Angle ToRadianAngle() const; std::string ToString() const; + constexpr T ToTurns() const; + constexpr Angle ToTurnAngle() const; constexpr Angle& operator=(const Angle&) = default; @@ -71,8 +74,10 @@ namespace Nz constexpr bool operator==(const Angle& other) const; constexpr bool operator!=(const Angle& other) const; - static constexpr Angle FromDegrees(T ang); - static constexpr Angle FromRadians(T ang); + template static constexpr Angle From(T value); + static constexpr Angle FromDegrees(T degrees); + static constexpr Angle FromRadians(T radians); + static constexpr Angle FromTurns(T turn); static constexpr Angle Zero(); T value; @@ -90,6 +95,12 @@ namespace Nz using RadianAngled = RadianAngle; using RadianAnglef = RadianAngle; + template + using TurnAngle = Angle; + + using TurnAngled = TurnAngle; + using TurnAnglef = TurnAngle; + template bool Serialize(SerializationContext& context, const Angle& angle, TypeTag>); template bool Unserialize(SerializationContext& context, Angle* angle, TypeTag>); } diff --git a/include/Nazara/Math/Angle.inl b/include/Nazara/Math/Angle.inl index 5d9726118..2bd29c217 100644 --- a/include/Nazara/Math/Angle.inl +++ b/include/Nazara/Math/Angle.inl @@ -17,6 +17,71 @@ namespace Nz { namespace Detail { + 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 / (T(2) * Pi); + } + }; + + 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 * T(2) * Pi; + } + }; + template struct AngleUtils; template<> @@ -29,27 +94,7 @@ namespace Nz template static constexpr T GetLimit() { - return 180; - } - - template static constexpr T FromDegrees(T degrees) - { - return degrees; - } - - template static constexpr T FromRadians(T radians) - { - return RadianToDegree(radians); - } - - template static constexpr T ToDegrees(T degrees) - { - return degrees; - } - - template static constexpr T ToRadians(T degrees) - { - return DegreeToRadian(degrees); + return 360; } template static std::ostream& ToString(std::ostream& out, T value) @@ -68,27 +113,7 @@ namespace Nz template static constexpr T GetLimit() { - return Pi; - } - - template static constexpr T FromDegrees(T degrees) - { - return DegreeToRadian(degrees); - } - - template static constexpr T FromRadians(T radians) - { - return radians; - } - - template static constexpr T ToDegrees(T radians) - { - return RadianToDegree(radians); - } - - template static constexpr T ToRadians(T radians) - { - return radians; + return T(2) * Pi; } template static std::ostream& ToString(std::ostream& out, T value) @@ -97,6 +122,25 @@ namespace Nz } }; + 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)"; + } + }; + #ifdef NAZARA_PLATFORM_LINUX template void SinCos(std::enable_if_t::value && !std::is_same::value, double> x, T* sin, T* cos) @@ -147,24 +191,14 @@ namespace Nz } /*! - * \brief Constructs an Angle object from a angle in degrees, converting if required + * \brief Constructs an Angle object from a angle in a specific unit, converting if required * * \param value Angle object to copy */ template - constexpr Angle::Angle(const Angle& angle) : - value(Detail::AngleUtils::FromDegrees(angle.value)) - { - } - - /*! - * \brief Constructs an Angle object from a angle in radians, converting if required - * - * \param value Angle object to copy - */ - template - constexpr Angle::Angle(const Angle& angle) : - value(Detail::AngleUtils::FromRadians(angle.value)) + template + constexpr Angle::Angle(const Angle& angle) : + value(Detail::AngleConversion::Convert(angle.value)) { } @@ -237,16 +271,16 @@ namespace Nz * If angle exceeds local limits positively or negatively, bring it back between them. * For degree angles, local limits are [-180, 180] * For radian angles, local limits are [-Pi, Pi] + * For turn angles, local limits are [-1, 1] */ template constexpr Angle& Angle::Normalize() { constexpr T limit = Detail::AngleUtils::template GetLimit(); - constexpr T twoLimit = limit * T(2); - value = std::fmod(value, twoLimit); + value = std::fmod(value, limit); if (value < T(0)) - value += twoLimit; + value += limit; return *this; } @@ -278,6 +312,28 @@ namespace Nz return *this; } + /*! + * \brief Returns the ToUnit angle that is equivalent to this one + * \return Equivalent ToUnit angle value + */ + template + template + T Angle::To() const + { + return Detail::AngleConversion::Convert(value); + } + + /*! + * \brief Returns the ToUnit angle that is equivalent to this one + * \return Equivalent ToUnit angle + */ + template + template + Angle Angle::ToAngle() const + { + return Angle(To()); + } + /*! * \brief Returns the degree angle that is equivalent to this one * \return Equivalent degree angle value @@ -285,7 +341,7 @@ namespace Nz template constexpr T Angle::ToDegrees() const { - return Detail::AngleUtils::ToDegrees(value); + return To(); } /*! @@ -295,7 +351,7 @@ namespace Nz template constexpr Angle Angle::ToDegreeAngle() const { - return DegreeAngle(ToDegrees()); + return ToAngle(); } /*! @@ -333,7 +389,7 @@ namespace Nz template constexpr T Angle::ToRadians() const { - return Detail::AngleUtils::ToRadians(value); + return To(); } /*! @@ -343,7 +399,7 @@ namespace Nz template constexpr Angle Angle::ToRadianAngle() const { - return RadianAngle(ToRadians()); + return ToAngle(); } /*! @@ -359,6 +415,26 @@ namespace Nz return oss.str(); } + /*! + * \brief Returns the turn angle that is equivalent to this angle + * \return Equivalent turn angle value + */ + template + constexpr T Angle::ToTurns() const + { + return To(value); + } + + /*! + * \brief Returns the turn angle that is equivalent to this angle + * \return Equivalent turn angle + */ + template + constexpr Angle Angle::ToTurnAngle() const + { + return ToAngle(); + } + /*! * \brief Returns the degree angle that is equivalent to this one * \return Equivalent degree angle @@ -526,6 +602,19 @@ namespace Nz return !NumberEquals(value, other.value, Detail::AngleUtils::template GetEpsilon()); } + /*! + * \brief Builds an Angle instance using a FromUnit angle, converting if needed + * \return An angle describing the FromUnit angle as Unit + * + * \param ang Degree angle + */ + template + template + constexpr Angle Angle::From(T value) + { + return Angle(Detail::AngleConversion::Convert(value)); + } + /*! * \brief Builds an Angle instance using a degree angle, converting if needed * \return An angle describing the degree angle as Unit @@ -533,9 +622,9 @@ namespace Nz * \param ang Degree angle */ template - constexpr Angle Angle::FromDegrees(T ang) + constexpr Angle Angle::FromDegrees(T degrees) { - return Angle(Detail::AngleUtils::FromDegrees(ang)); + return From(degrees); } /*! @@ -545,9 +634,21 @@ namespace Nz * \param ang Radian angle */ template - constexpr Angle Angle::FromRadians(T ang) + constexpr Angle Angle::FromRadians(T radians) { - return Angle(Detail::AngleUtils::FromRadians(ang)); + return From(radians); + } + + /*! + * \brief Builds an Angle instance using a radian angle, converting if needed + * \return An angle describing the radian angle as Unit + * + * \param ang Radian angle + */ + template + constexpr Angle Angle::FromTurns(T turns) + { + return From(turns); } /*! diff --git a/include/Nazara/Math/Enums.hpp b/include/Nazara/Math/Enums.hpp index fea2a90da..70db19004 100644 --- a/include/Nazara/Math/Enums.hpp +++ b/include/Nazara/Math/Enums.hpp @@ -14,7 +14,8 @@ namespace Nz enum class AngleUnit { Degree, - Radian + Radian, + Turn }; enum class BoxCorner diff --git a/tests/Engine/Math/AngleTest.cpp b/tests/Engine/Math/AngleTest.cpp index 5b764c597..b9d3a0738 100644 --- a/tests/Engine/Math/AngleTest.cpp +++ b/tests/Engine/Math/AngleTest.cpp @@ -33,6 +33,19 @@ SCENARIO("Angle", "[MATH][ANGLE]") } } + WHEN("We convert it to turns") + { + Nz::TurnAnglef turnAngle(angle); + + THEN("It should be equal to pi/2") + { + Nz::TurnAnglef expectedResult(1.f / 4.f); + + CHECK(turnAngle == expectedResult); + CHECK(angle.ToTurnAngle() == expectedResult); + } + } + WHEN("We compute its sinus/cosinus separatly") { THEN("It should be equal to 1 and 0") @@ -204,4 +217,21 @@ SCENARIO("Angle", "[MATH][ANGLE]") } } } + + GIVEN("A turn angle of 1.5f") + { + Nz::TurnAnglef angle(1.5f); + + WHEN("We normalize it") + { + angle.Normalize(); + + THEN("It should be equal to a normalized version of itself") + { + Nz::TurnAnglef expectedResult(0.5f); + + CHECK(angle == expectedResult); + } + } + } }