Math: Add support for Turn angles
This commit is contained in:
parent
6372f9cad8
commit
364d1bafb4
|
|
@ -29,8 +29,7 @@ namespace Nz
|
|||
constexpr Angle() = default;
|
||||
constexpr Angle(T angle);
|
||||
template<typename U> constexpr explicit Angle(const Angle<Unit, U>& Angle);
|
||||
constexpr Angle(const Angle<AngleUnit::Degree, T>& angle);
|
||||
constexpr Angle(const Angle<AngleUnit::Radian, T>& angle);
|
||||
template<AngleUnit FromUnit> constexpr Angle(const Angle<FromUnit, T>& angle);
|
||||
~Angle() = default;
|
||||
|
||||
T GetCos() const;
|
||||
|
|
@ -45,6 +44,8 @@ namespace Nz
|
|||
constexpr Angle& Set(const Angle& ang);
|
||||
template<typename U> constexpr Angle& Set(const Angle<Unit, U>& ang);
|
||||
|
||||
template<AngleUnit ToUnit> T To() const;
|
||||
template<AngleUnit ToUnit> Angle<ToUnit, T> ToAngle() const;
|
||||
constexpr T ToDegrees() const;
|
||||
constexpr Angle<AngleUnit::Degree, T> ToDegreeAngle() const;
|
||||
EulerAngles<T> ToEulerAngles() const;
|
||||
|
|
@ -52,6 +53,8 @@ namespace Nz
|
|||
constexpr T ToRadians() const;
|
||||
constexpr Angle<AngleUnit::Radian, T> ToRadianAngle() const;
|
||||
std::string ToString() const;
|
||||
constexpr T ToTurns() const;
|
||||
constexpr Angle<AngleUnit::Turn, T> 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<AngleUnit FromUnit> 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<double>;
|
||||
using RadianAnglef = RadianAngle<float>;
|
||||
|
||||
template<typename T>
|
||||
using TurnAngle = Angle<AngleUnit::Turn, T>;
|
||||
|
||||
using TurnAngled = TurnAngle<double>;
|
||||
using TurnAnglef = TurnAngle<float>;
|
||||
|
||||
template<AngleUnit Unit, typename T> bool Serialize(SerializationContext& context, const Angle<Unit, T>& angle, TypeTag<Angle<Unit, T>>);
|
||||
template<AngleUnit Unit, typename T> bool Unserialize(SerializationContext& context, Angle<Unit, T>* angle, TypeTag<Angle<Unit, T>>);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
|
|||
|
|
@ -14,7 +14,8 @@ namespace Nz
|
|||
enum class AngleUnit
|
||||
{
|
||||
Degree,
|
||||
Radian
|
||||
Radian,
|
||||
Turn
|
||||
};
|
||||
|
||||
enum class BoxCorner
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue