Math: Add support for Turn angles

This commit is contained in:
SirLynix
2022-09-26 19:09:30 +02:00
parent 6372f9cad8
commit 364d1bafb4
4 changed files with 215 additions and 72 deletions

View File

@@ -17,6 +17,71 @@ namespace Nz
{
namespace Detail
{
template<AngleUnit From, AngleUnit To> struct AngleConversion;
template<AngleUnit Unit>
struct AngleConversion<Unit, Unit>
{
template<typename T> static constexpr T Convert(T angle)
{
return angle;
}
};
template<>
struct AngleConversion<AngleUnit::Degree, AngleUnit::Radian>
{
template<typename T> static constexpr T Convert(T angle)
{
return DegreeToRadian(angle);
}
};
template<>
struct AngleConversion<AngleUnit::Degree, AngleUnit::Turn>
{
template<typename T> static constexpr T Convert(T angle)
{
return angle / T(360);
}
};
template<>
struct AngleConversion<AngleUnit::Radian, AngleUnit::Degree>
{
template<typename T> static constexpr T Convert(T angle)
{
return RadianToDegree(angle);
}
};
template<>
struct AngleConversion<AngleUnit::Radian, AngleUnit::Turn>
{
template<typename T> static constexpr T Convert(T angle)
{
return angle / (T(2) * Pi<T>);
}
};
template<>
struct AngleConversion<AngleUnit::Turn, AngleUnit::Degree>
{
template<typename T> static constexpr T Convert(T angle)
{
return angle * T(360);
}
};
template<>
struct AngleConversion<AngleUnit::Turn, AngleUnit::Radian>
{
template<typename T> static constexpr T Convert(T angle)
{
return angle * T(2) * Pi<T>;
}
};
template<AngleUnit Unit> struct AngleUtils;
template<>
@@ -29,27 +94,7 @@ namespace Nz
template<typename T> static constexpr T GetLimit()
{
return 180;
}
template<typename T> static constexpr T FromDegrees(T degrees)
{
return degrees;
}
template<typename T> static constexpr T FromRadians(T radians)
{
return RadianToDegree(radians);
}
template<typename T> static constexpr T ToDegrees(T degrees)
{
return degrees;
}
template<typename T> static constexpr T ToRadians(T degrees)
{
return DegreeToRadian(degrees);
return 360;
}
template<typename T> static std::ostream& ToString(std::ostream& out, T value)
@@ -68,27 +113,7 @@ namespace Nz
template<typename T> static constexpr T GetLimit()
{
return Pi<T>;
}
template<typename T> static constexpr T FromDegrees(T degrees)
{
return DegreeToRadian(degrees);
}
template<typename T> static constexpr T FromRadians(T radians)
{
return radians;
}
template<typename T> static constexpr T ToDegrees(T radians)
{
return RadianToDegree(radians);
}
template<typename T> static constexpr T ToRadians(T radians)
{
return radians;
return T(2) * Pi<T>;
}
template<typename T> static std::ostream& ToString(std::ostream& out, T value)
@@ -97,6 +122,25 @@ namespace Nz
}
};
template<>
struct AngleUtils<AngleUnit::Turn>
{
template<typename T> static constexpr T GetEpsilon()
{
return T(1e-5);
}
template<typename T> static constexpr T GetLimit()
{
return 1;
}
template<typename T> static std::ostream& ToString(std::ostream& out, T value)
{
return out << "Angle(" << value << "turn)";
}
};
#ifdef NAZARA_PLATFORM_LINUX
template<typename T>
void SinCos(std::enable_if_t<!std::is_same<T, float>::value && !std::is_same<T, long double>::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<AngleUnit Unit, typename T>
constexpr Angle<Unit, T>::Angle(const Angle<AngleUnit::Degree, T>& angle) :
value(Detail::AngleUtils<Unit>::FromDegrees(angle.value))
{
}
/*!
* \brief Constructs an Angle object from a angle in radians, converting if required
*
* \param value Angle object to copy
*/
template<AngleUnit Unit, typename T>
constexpr Angle<Unit, T>::Angle(const Angle<AngleUnit::Radian, T>& angle) :
value(Detail::AngleUtils<Unit>::FromRadians(angle.value))
template<AngleUnit FromUnit>
constexpr Angle<Unit, T>::Angle(const Angle<FromUnit, T>& angle) :
value(Detail::AngleConversion<FromUnit, Unit>::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<AngleUnit Unit, typename T>
constexpr Angle<Unit, T>& Angle<Unit, T>::Normalize()
{
constexpr T limit = Detail::AngleUtils<Unit>::template GetLimit<T>();
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<AngleUnit Unit, typename T>
template<AngleUnit ToUnit>
T Angle<Unit, T>::To() const
{
return Detail::AngleConversion<Unit, ToUnit>::Convert(value);
}
/*!
* \brief Returns the ToUnit angle that is equivalent to this one
* \return Equivalent ToUnit angle
*/
template<AngleUnit Unit, typename T>
template<AngleUnit ToUnit>
Angle<ToUnit, T> Angle<Unit, T>::ToAngle() const
{
return Angle<ToUnit, T>(To<ToUnit>());
}
/*!
* \brief Returns the degree angle that is equivalent to this one
* \return Equivalent degree angle value
@@ -285,7 +341,7 @@ namespace Nz
template<AngleUnit Unit, typename T>
constexpr T Angle<Unit, T>::ToDegrees() const
{
return Detail::AngleUtils<Unit>::ToDegrees(value);
return To<AngleUnit::Degree>();
}
/*!
@@ -295,7 +351,7 @@ namespace Nz
template<AngleUnit Unit, typename T>
constexpr Angle<AngleUnit::Degree, T> Angle<Unit, T>::ToDegreeAngle() const
{
return DegreeAngle<T>(ToDegrees());
return ToAngle<AngleUnit::Degree>();
}
/*!
@@ -333,7 +389,7 @@ namespace Nz
template<AngleUnit Unit, typename T>
constexpr T Angle<Unit, T>::ToRadians() const
{
return Detail::AngleUtils<Unit>::ToRadians(value);
return To<AngleUnit::Radian>();
}
/*!
@@ -343,7 +399,7 @@ namespace Nz
template<AngleUnit Unit, typename T>
constexpr Angle<AngleUnit::Radian, T> Angle<Unit, T>::ToRadianAngle() const
{
return RadianAngle<T>(ToRadians());
return ToAngle<AngleUnit::Radian>();
}
/*!
@@ -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<AngleUnit Unit, typename T>
constexpr T Angle<Unit, T>::ToTurns() const
{
return To<AngleUnit::Turn>(value);
}
/*!
* \brief Returns the turn angle that is equivalent to this angle
* \return Equivalent turn angle
*/
template<AngleUnit Unit, typename T>
constexpr Angle<AngleUnit::Turn, T> Angle<Unit, T>::ToTurnAngle() const
{
return ToAngle<AngleUnit::Turn>();
}
/*!
* \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<Unit>::template GetEpsilon<T>());
}
/*!
* \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<AngleUnit Unit, typename T>
template<AngleUnit FromUnit>
constexpr Angle<Unit, T> Angle<Unit, T>::From(T value)
{
return Angle(Detail::AngleConversion<FromUnit, Unit>::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<AngleUnit Unit, typename T>
constexpr Angle<Unit, T> Angle<Unit, T>::FromDegrees(T ang)
constexpr Angle<Unit, T> Angle<Unit, T>::FromDegrees(T degrees)
{
return Angle(Detail::AngleUtils<Unit>::FromDegrees(ang));
return From<AngleUnit::Degree>(degrees);
}
/*!
@@ -545,9 +634,21 @@ namespace Nz
* \param ang Radian angle
*/
template<AngleUnit Unit, typename T>
constexpr Angle<Unit, T> Angle<Unit, T>::FromRadians(T ang)
constexpr Angle<Unit, T> Angle<Unit, T>::FromRadians(T radians)
{
return Angle(Detail::AngleUtils<Unit>::FromRadians(ang));
return From<AngleUnit::Radian>(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<AngleUnit Unit, typename T>
constexpr Angle<Unit, T> Angle<Unit, T>::FromTurns(T turns)
{
return From<AngleUnit::Turn>(turns);
}
/*!