diff --git a/include/Nazara/Math/Angle.hpp b/include/Nazara/Math/Angle.hpp index 10525c56e..28537473e 100644 --- a/include/Nazara/Math/Angle.hpp +++ b/include/Nazara/Math/Angle.hpp @@ -18,6 +18,9 @@ namespace Nz { struct SerializationContext; + template class EulerAngles; + template class Quaternion; + template class Angle { @@ -45,13 +48,20 @@ namespace Nz template Angle& Set(const Angle& Angle); Angle ToDegrees() const; + EulerAngles ToEulerAngles() const; + Quaternion ToQuaternion() const; Angle ToRadians() const; String ToString() const; + operator EulerAngles() const; + operator Quaternion() const; + Angle& operator=(const Angle&) = default; Angle operator+(const Angle& other) const; Angle operator-(const Angle& other) const; + Angle operator*(T scalar) const; + Angle operator/(T divider) const; Angle& operator+=(const Angle& other); Angle& operator-=(const Angle& other); diff --git a/include/Nazara/Math/Angle.inl b/include/Nazara/Math/Angle.inl index 4cec7bb1a..71d5631cc 100644 --- a/include/Nazara/Math/Angle.inl +++ b/include/Nazara/Math/Angle.inl @@ -319,6 +319,58 @@ namespace Nz return Detail::AngleUtils::ToString(angle); } + /*! + * \brief Shortcut allowing implicit conversion to Euler angles + * \return Euler Angles representing a 2D rotation by this angle + * + * \see ToEulerAngles + */ + template + Angle::operator EulerAngles() const + { + return ToEulerAngles(); + } + + /*! + * \brief Shortcut allowing implicit conversion to Quaternion + * \return Quaternion representing a 2D rotation by this angle + * + * \see ToQuaternion + */ + template + Angle::operator Quaternion() const + { + return ToQuaternion(); + } + + /*! + * \brief Converts the angle to an Euler Angles representation + * \return A 2D rotation expressed in Euler angles + * + * This will assume two-dimensional usage, and will set the angle value (as degrees) as the roll value of the Euler Angles, leaving pitch and yaw to zero + */ + template + EulerAngles Angle::ToEulerAngles() const + { + return EulerAngles(0, 0, ToDegrees().angle); + } + + /*! + * \brief Converts the angle to a Quaternion representation + * \return A 2D rotation expressed with Quaternion + * + * This will assume two-dimensional usage, as if the angle was first converted to Euler Angles and then to a Quaternion + * + * \see ToEulerAngles + */ + template + Quaternion Angle::ToQuaternion() const + { + auto halfAngle = Angle(*this) / 2.f; + auto sincos = halfAngle.GetSinCos(); + return Quaternion(sincos.second, 0, 0, sincos.first); + } + /*! * \brief Addition operator * \return Adds two angles together @@ -343,6 +395,30 @@ namespace Nz return Angle(angle - other.angle); } + /*! + * \brief Multiplication operator + * \return A copy of the angle, scaled by the multiplier + * + * \param scalar Multiplier + */ + template + Angle Angle::operator*(T scalar) const + { + return Angle(angle * scalar); + } + + /*! + * \brief Divides the angle by a scalar + * \return A copy of the angle, divided by the divider + * + * \param divider Divider + */ + template + Angle Angle::operator/(T divider) const + { + return Angle(angle / divider); + } + /*! * \brief Adds an angle by another * \return A reference to the angle diff --git a/tests/Engine/Math/Angle.cpp b/tests/Engine/Math/Angle.cpp index a4abc4a82..3b5346c06 100644 --- a/tests/Engine/Math/Angle.cpp +++ b/tests/Engine/Math/Angle.cpp @@ -1,4 +1,6 @@ #include +#include +#include #include SCENARIO("Angle", "[MATH][ANGLE]") @@ -37,16 +39,33 @@ SCENARIO("Angle", "[MATH][ANGLE]") CHECK(angle.GetSin() == Approx(1.f).margin(0.0001f)); CHECK(angle.GetCos() == Approx(0.f).margin(0.0001f)); } - - } - AND_WHEN("We compute it at the same time") - { - auto sincos = angle.GetSinCos(); - - THEN("It should also be equal to 1 and 0") + AND_WHEN("We compute sin/cos at the same time") { - CHECK(sincos.first == Approx(1.f).margin(0.0001f)); - CHECK(sincos.second == Approx(0.f).margin(0.0001f)); + auto sincos = angle.GetSinCos(); + + THEN("It should also be equal to 1 and 0") + { + CHECK(sincos.first == Approx(1.f).margin(0.0001f)); + CHECK(sincos.second == Approx(0.f).margin(0.0001f)); + } + } + } + + WHEN("We get the Euler Angles representation of this angle") + { + Nz::EulerAnglesf eulerAngles = angle; + THEN("It should be equivalent to a 2D rotation by this angle") + { + CHECK(eulerAngles == Nz::EulerAnglesf(0.f, 0.f, 90.f)); + } + AND_WHEN("We get the Quaternion representation of this angle") + { + Nz::Quaternionf quat = angle; + + THEN("It should be equivalent to a 2D rotation by this angle") + { + CHECK(quat == eulerAngles.ToQuaternion()); + } } } } @@ -131,6 +150,24 @@ SCENARIO("Angle", "[MATH][ANGLE]") CHECK(sincos.second == Approx(-1.f).margin(0.0001f)); } } + + WHEN("We get the Euler Angles representation of this angle") + { + Nz::EulerAnglesf eulerAngles = angle; + THEN("It should be equivalent to a 2D rotation by this angle") + { + CHECK(eulerAngles == Nz::EulerAnglesf(0.f, 0.f, -180.f)); + } + AND_WHEN("We get the Quaternion representation of this angle") + { + Nz::Quaternionf quat = angle; + + THEN("It should be equivalent to a 2D rotation by this angle") + { + CHECK(quat == eulerAngles.ToQuaternion()); + } + } + } } GIVEN("A radian angle of 7pi")