From 9e0b61f30d995a7c5f5640039aeb8fb502b0629f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Wed, 5 Sep 2018 15:14:31 +0200 Subject: [PATCH] Math/Angle: Add sine, cosine, tangent methods --- include/Nazara/Math/Angle.hpp | 6 +++ include/Nazara/Math/Angle.inl | 78 +++++++++++++++++++++++++++++++++-- tests/Engine/Math/Angle.cpp | 47 +++++++++++++++++++-- 3 files changed, 125 insertions(+), 6 deletions(-) diff --git a/include/Nazara/Math/Angle.hpp b/include/Nazara/Math/Angle.hpp index ccf770959..e1c904204 100644 --- a/include/Nazara/Math/Angle.hpp +++ b/include/Nazara/Math/Angle.hpp @@ -11,6 +11,7 @@ #include #include #include +#include namespace Nz { @@ -28,6 +29,11 @@ namespace Nz Angle(const Angle&) = default; ~Angle() = default; + T GetCos() const; + T GetSin() const; + std::pair GetSinCos() const; + T GetTan() const; + Angle& MakeZero(); void Normalize(); diff --git a/include/Nazara/Math/Angle.inl b/include/Nazara/Math/Angle.inl index 0e8f8dbfe..e04a751d9 100644 --- a/include/Nazara/Math/Angle.inl +++ b/include/Nazara/Math/Angle.inl @@ -16,6 +16,11 @@ namespace Nz template<> struct AngleUtils { + template static constexpr T GetEpsilon() + { + return T(1e-4); + } + template static constexpr T GetLimit() { return 180; @@ -55,9 +60,14 @@ namespace Nz template<> struct AngleUtils { + template static constexpr T GetEpsilon() + { + return T(1e-5); + } + template static constexpr T GetLimit() { - return M_PI; + return T(M_PI); } template static T FromDegrees(T degrees) @@ -90,6 +100,14 @@ namespace Nz return out << "Angle(" << value << "rad)"; } }; + + // Naive implementation, hopefully optimized by the compiler + template + void SinCos(T x, T* sin, T* cos) + { + *sin = std::sin(x); + *cos = std::cos(x); + } } /*! * \ingroup math @@ -108,6 +126,59 @@ namespace Nz { } + /*! + * \brief Computes the cosine of the angle + * \return Cosine of angle + * + * \see GetSinCos + */ + template + T Angle::GetCos() const + { + return std::cos(ToRadians().angle); + } + + /*! + * \brief Computes the sine of the angle + * \return Sine of angle + * + * \see GetSinCos + */ + template + T Angle::GetSin() const + { + return std::sin(ToRadians().angle); + } + + /*! + * \brief Computes both sines and cosines of the angle + * \return Sine and cosine of the angle + * + * \remark This is potentially faster than calling both GetSin and GetCos separately as it can computes both values at the same time. + * + * \see GetCos, GetSin + */ + template + std::pair Angle::GetSinCos() const + { + T sin, cos; + Detail::SinCos(ToRadians().angle, &sin, &cos); + + return std::make_pair(sin, cos); + } + + /*! + * \brief Computes the tangent of the angle + * \return Tangent value of the angle + * + * \see GetCos, GetSin + */ + template + T Angle::GetTan() const + { + return std::tan(ToRadians().angle); + } + /*! * \brief Changes the angle value to zero */ @@ -115,6 +186,7 @@ namespace Nz Angle& Angle::MakeZero() { angle = T(0); + return *this; } /*! @@ -303,7 +375,7 @@ namespace Nz template bool Angle::operator==(const Angle& Angle) const { - return NumberEquals(angle, Angle.angle); + return NumberEquals(angle, Angle.angle, Detail::AngleUtils::GetEpsilon()); } /*! @@ -315,7 +387,7 @@ namespace Nz template bool Angle::operator!=(const Angle& Angle) const { - return !NumberEquals(angle, Angle.angle); + return !NumberEquals(angle, Angle.angle, Detail::AngleUtils::GetEpsilon()); } /*! diff --git a/tests/Engine/Math/Angle.cpp b/tests/Engine/Math/Angle.cpp index 81e83c261..a4abc4a82 100644 --- a/tests/Engine/Math/Angle.cpp +++ b/tests/Engine/Math/Angle.cpp @@ -29,6 +29,26 @@ SCENARIO("Angle", "[MATH][ANGLE]") CHECK(angle.ToRadians() == expectedResult); } } + + WHEN("We compute its sinus/cosinus separatly") + { + THEN("It should be equal to 1 and 0") + { + 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") + { + CHECK(sincos.first == Approx(1.f).margin(0.0001f)); + CHECK(sincos.second == Approx(0.f).margin(0.0001f)); + } + } } GIVEN("A degree angle of 480deg") @@ -48,9 +68,9 @@ SCENARIO("Angle", "[MATH][ANGLE]") } } - GIVEN("A degree angle of -270deg") + GIVEN("A degree angle of -300deg") { - Nz::DegreeAnglef angle(-270.f); + Nz::DegreeAnglef angle(-300.f); WHEN("We normalize it") { @@ -58,7 +78,7 @@ SCENARIO("Angle", "[MATH][ANGLE]") THEN("It should be equal to a normalized version of itself") { - Nz::DegreeAnglef expectedResult(90.f); + Nz::DegreeAnglef expectedResult(60.f); CHECK(angle == expectedResult); } @@ -91,7 +111,28 @@ SCENARIO("Angle", "[MATH][ANGLE]") CHECK(angle.ToDegrees() == expectedResult); } } + + WHEN("We compute its sinus/cosinus separatly") + { + THEN("It should be equal to 0 and -1") + { + CHECK(angle.GetSin() == Approx(0.f).margin(0.0001f)); + CHECK(angle.GetCos() == Approx(-1.f).margin(0.0001f)); + } + + } + AND_WHEN("We compute it at the same time") + { + auto sincos = angle.GetSinCos(); + + THEN("It should also be equal to 0 and -1") + { + CHECK(sincos.first == Approx(0.f).margin(0.0001f)); + CHECK(sincos.second == Approx(-1.f).margin(0.0001f)); + } + } } + GIVEN("A radian angle of 7pi") { Nz::RadianAnglef angle(float(7 * M_PI));