Math/Angle: Add sine, cosine, tangent methods

This commit is contained in:
Jérôme Leclercq 2018-09-05 15:14:31 +02:00
parent 3cc70daf3e
commit 9e0b61f30d
3 changed files with 125 additions and 6 deletions

View File

@ -11,6 +11,7 @@
#include <Nazara/Math/Algorithm.hpp>
#include <Nazara/Math/Enums.hpp>
#include <type_traits>
#include <utility>
namespace Nz
{
@ -28,6 +29,11 @@ namespace Nz
Angle(const Angle&) = default;
~Angle() = default;
T GetCos() const;
T GetSin() const;
std::pair<T, T> GetSinCos() const;
T GetTan() const;
Angle& MakeZero();
void Normalize();

View File

@ -16,6 +16,11 @@ namespace Nz
template<>
struct AngleUtils<AngleUnit::Degree>
{
template<typename T> static constexpr T GetEpsilon()
{
return T(1e-4);
}
template<typename T> static constexpr T GetLimit()
{
return 180;
@ -55,9 +60,14 @@ namespace Nz
template<>
struct AngleUtils<AngleUnit::Radian>
{
template<typename T> static constexpr T GetEpsilon()
{
return T(1e-5);
}
template<typename T> static constexpr T GetLimit()
{
return M_PI;
return T(M_PI);
}
template<typename T> static T FromDegrees(T degrees)
@ -90,6 +100,14 @@ namespace Nz
return out << "Angle(" << value << "rad)";
}
};
// Naive implementation, hopefully optimized by the compiler
template<typename T>
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<AngleUnit Unit, typename T>
T Angle<Unit, T>::GetCos() const
{
return std::cos(ToRadians().angle);
}
/*!
* \brief Computes the sine of the angle
* \return Sine of angle
*
* \see GetSinCos
*/
template<AngleUnit Unit, typename T>
T Angle<Unit, T>::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<AngleUnit Unit, typename T>
std::pair<T, T> Angle<Unit, T>::GetSinCos() const
{
T sin, cos;
Detail::SinCos<T>(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<AngleUnit Unit, typename T>
T Angle<Unit, T>::GetTan() const
{
return std::tan(ToRadians().angle);
}
/*!
* \brief Changes the angle value to zero
*/
@ -115,6 +186,7 @@ namespace Nz
Angle<Unit, T>& Angle<Unit, T>::MakeZero()
{
angle = T(0);
return *this;
}
/*!
@ -303,7 +375,7 @@ namespace Nz
template<AngleUnit Unit, typename T>
bool Angle<Unit, T>::operator==(const Angle& Angle) const
{
return NumberEquals(angle, Angle.angle);
return NumberEquals(angle, Angle.angle, Detail::AngleUtils<Unit>::GetEpsilon<T>());
}
/*!
@ -315,7 +387,7 @@ namespace Nz
template<AngleUnit Unit, typename T>
bool Angle<Unit, T>::operator!=(const Angle& Angle) const
{
return !NumberEquals(angle, Angle.angle);
return !NumberEquals(angle, Angle.angle, Detail::AngleUtils<Unit>::GetEpsilon<T>());
}
/*!

View File

@ -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));