// Copyright (C) 2017 Jérôme Leclercq // This file is part of the "Nazara Engine - Mathematics module" // For conditions of distribution and use, see copyright notice in Config.hpp #include #include #include #include namespace Nz { namespace Detail { template struct AngleUtils; template<> struct AngleUtils { template static constexpr T GetLimit() { return 180; } template static T FromDegrees(T degrees) { return degrees; } template static T FromRadians(T radians) { return RadianToDegree(radians); } template static T ToDegrees(T degrees) { return degrees; } template static T ToRadians(T degrees) { return DegreeToRadian(degrees); } template static String ToString(T value) { return "Angle(" + String::Number(value) + "deg)"; } template static std::ostream& ToString(std::ostream& out, T value) { return out << "Angle(" << value << "deg)"; } }; template<> struct AngleUtils { template static constexpr T GetLimit() { return M_PI; } template static T FromDegrees(T degrees) { return DegreeToRadian(degrees); } template static T FromRadians(T radians) { return radians; } template static T ToDegrees(T radians) { return RadianToDegree(radians); } template static T ToRadians(T radians) { return radians; } template static String ToString(T value) { return "Angle(" + String::Number(value) + "rad)"; } template static std::ostream& ToString(std::ostream& out, T value) { return out << "Angle(" << value << "rad)"; } }; } /*! * \ingroup math * \class Nz::Angle * \brief Math class that represents an angle */ /*! * \brief Constructs an Angle object with an angle value * * \param Angle value of the angle */ template Angle::Angle(T Angle) : angle(Angle) { } /*! * \brief Changes the angle value to zero */ template Angle& Angle::MakeZero() { angle = T(0); } /*! * \brief Normalizes the angle value * * 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 [-M_PI, M_PI] */ template void Angle::Normalize() { constexpr T limit = Detail::AngleUtils::GetLimit(); constexpr T twoLimit = limit * T(2); angle = std::fmod(angle, twoLimit); if (angle < T(0)) angle += twoLimit; } /*! * \brief Changes the angle value by converting a radian angle * * \param Angle Radian angle which will be converted */ template template Angle& Angle::Set(const Angle& Angle) { angle = RadianToDegree(Angle.angle); return *this; } /*! * \brief Changes the angle value by converting a degree angle * * \param Angle Degree angle which will be converted */ template template Angle& Angle::Set(const Angle& Angle) { angle = DegreeToRadian(Angle.angle); return *this; } /*! * \brief Copies the angle value of an angle * * \param Angle Angle which will be copied */ template Angle& Angle::Set(const Angle& Angle) { angle = Angle.angle; return *this; } /*! * \brief Changes the angle value to the same as an Angle of a different type * * \param Angle Angle which will be casted * * \remark Conversion from U to T occurs using static_cast */ template template Angle& Angle::Set(const Angle& Angle) { angle = static_cast(Angle.angle); return *this; } /*! * \brief Returns the degree angle that is equivalent to this one * \return Equivalent degree angle */ template Angle Angle::ToDegrees() const { return DegreeAngle(Detail::AngleUtils::ToDegrees(angle)); } /*! * \brief Returns the radian angle that is equivalent to this angle * \return Equivalent radian angle */ template Angle Angle::ToRadians() const { return RadianAngle(Detail::AngleUtils::ToRadians(angle)); } /*! * \brief Converts the angle to a string representation * \return String representation of the angle */ template String Angle::ToString() const { return Detail::AngleUtils::ToString(angle); } /*! * \brief Addition operator * \return Adds two angles together * * \param angle Angle to add */ template Angle Angle::operator+(const Angle& Angle) const { return Angle(angle + Angle.angle); } /*! * \brief Subtraction operator * \return Subtracts two angles together * * \param angle Angle to subtract */ template Angle Angle::operator-(const Angle& Angle) const { return Angle(angle - Angle.angle); } /*! * \brief Adds an angle by another * \return A reference to the angle * * \param angle Angle to add */ template Angle& Angle::operator+=(const Angle& Angle) { angle += Angle.angle; return *this; } /*! * \brief Subtract an angle by another * \return A reference to the angle * * \param angle Angle to subtract */ template Angle& Angle::operator-=(const Angle& Angle) { angle -= Angle.angle; return *this; } /*! * \brief Scales the angle by a scalar * \return A reference to the angle * * \param scalar Multiplier */ template Angle& Angle::operator*=(T scalar) { angle *= scalar; return *this; } /*! * \brief Divides the angle by a scalar * \return A reference to the angle * * \param divider Divider */ template Angle& Angle::operator/=(T divider) { angle /= divider; return *this; } /*! * \brief Compares the angle to another for equality * \return True if both angles are equal * * \param Angle The other angle to compare to */ template bool Angle::operator==(const Angle& Angle) const { return NumberEquals(angle, Angle.angle); } /*! * \brief Compares the angle to another for inequality * \return True if both angles are equal * * \param Angle The other angle to compare to */ template bool Angle::operator!=(const Angle& Angle) const { return !NumberEquals(angle, Angle.angle); } /*! * \brief Returns an angle with an angle of zero * \return Zero angle */ template Angle Angle::Zero() { Angle angle; angle.MakeZero(); return angle; } /*! * \brief Serializes an Angle * \return true if successfully serialized * * \param context Serialization context * \param angle Input Angle */ template bool Serialize(SerializationContext& context, const Angle& angle, TypeTag>) { if (!Serialize(context, angle.angle)) return false; return true; } /*! * \brief Unserializes an Angle * \return true if successfully unserialized * * \param context Serialization context * \param angle Output Angle */ template bool Unserialize(SerializationContext& context, Angle* angle, TypeTag>) { if (!Unserialize(context, &angle->angle)) return false; return true; } } /*! * \brief Multiplication operator * \return An angle corresponding to scale * angle * * \param scale Multiplier * \param angle Angle */ template Nz::Angle operator*(T scale, const Nz::Angle& angle) { return Nz::Angle(scale * angle.angle); } /*! * \brief Division operator * \return An angle corresponding to scale / angle * * \param scale Divisor * \param angle Angle */ template Nz::Angle operator/(T scale, const Nz::Angle& angle) { return Nz::Angle(scale / angle.angle); } /*! * \brief Output operator * \return The stream * * \param out The stream * \param box The box to output */ template std::ostream& operator<<(std::ostream& out, const Nz::Angle& angle) { return Nz::Detail::AngleUtils::ToString(out, angle.angle); } #include