From c351089e9f779d91f5ce4c9292e18879bedccd5d Mon Sep 17 00:00:00 2001 From: Miro Knejp Date: Mon, 11 May 2015 18:02:55 +0200 Subject: [PATCH] Dedicated extension to represent angle values Defines a dedicated type and operations for angles taking care of the radians/degrees issue and enforcing semantically sane usage. Applying these types consistently can prevent many problems related to conversions between degrees and radians. Furthermore it only supports operations which preserve the angle's dimension (under the assumption it is not dimensionless) allowing the compiler to detect misuses in equations. By not manually converting between degrees and radians everywhere in your program you can even gain some extra speed efficiency. Where ever you deal with angles (regardless if class members or function arguments) always use fangle/dangle and let it deal with the calculations necessary for radians/degrees conversions. Never again use a plain `float` in interfaces to represent angles or worry about these nuisances. The angle types should be no bigger than the datatype used for representation (if they are complain to your compiler vendor), are as efficient in copy and assignment operations as a native float or double, and can be safely passed by-value without fear of performance problems. --- glm/gtx/angle.hpp | 377 ++++++++++++++++++++++++++ glm/gtx/angle.inl | 583 ++++++++++++++++++++++++++++++++++++++++ test/gtx/CMakeLists.txt | 1 + test/gtx/gtx_angle.cpp | 328 ++++++++++++++++++++++ 4 files changed, 1289 insertions(+) create mode 100644 glm/gtx/angle.hpp create mode 100644 glm/gtx/angle.inl create mode 100644 test/gtx/gtx_angle.cpp diff --git a/glm/gtx/angle.hpp b/glm/gtx/angle.hpp new file mode 100644 index 00000000..021bbaf5 --- /dev/null +++ b/glm/gtx/angle.hpp @@ -0,0 +1,377 @@ +/////////////////////////////////////////////////////////////////////////////////// +/// OpenGL Mathematics (glm.g-truc.net) +/// +/// Copyright (c) 2005 - 2015 G-Truc Creation (www.g-truc.net) +/// Permission is hereby granted, free of charge, to any person obtaining a copy +/// of this software and associated documentation files (the "Software"), to deal +/// in the Software without restriction, including without limitation the rights +/// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +/// copies of the Software, and to permit persons to whom the Software is +/// furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// Restrictions: +/// By making use of the Software for military purposes, you choose to make +/// a Bunny unhappy. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +/// THE SOFTWARE. +/// +/// @ref gtx_associated_min_max +/// @file glm/gtx/angle.hpp +/// @date 2015-05-10 +/// @author Miroslav Knejp +/// +/// @see core (dependence) +/// +/// @defgroup gtx_angle GLM_GTX_angle +/// @ingroup gtx +/// +/// @brief Defines a dedicated type and operations for angles taking care of the radians/degrees issue and enforcing semantically sane usage. +/// +/// Applying these types consistently can prevent many problems related to +/// conversions between degrees and radians. Furthermore it only supports +/// operations which preserve the angle's dimension (under the assumption it is +/// not dimensionless) allowing the compiler to detect misuses in equations. By +/// not manually converting between degrees and radians everywhere in your +/// program you can even gain some extra speed efficiency. +/// +/// Where ever you deal with angles (regardless if class members or function +/// arguments) always use fangle/dangle and let it deal with the calculations +/// necessary for radians/degrees conversions. Never again use a plain `float` +/// in interfaces to represent angles or worry about these nuisances. +/// +/// The angle types should be no bigger than the datatype used for +/// representation (if they are complain to your compiler vendor), are +/// as efficient in copy and assignment operations as a native float or double, +/// and can be safely passed by-value without fear of performance problems. +/// +/// needs to be included to use this functionality. +/// +/// This extension also adds convenience overloads accepting angles instead of +/// plain floats to the following extensions for improved semantic checking: +/// - @ref gtc_matrix_transform +/// - @ref gtc_quaternion +/// - @ref gtx_fast_trigonometry +/// - @ref gtx_matrix_interpolation +/// - @ref gtx_matrix_transform_2d +/// - @ref gtx_rotate_normalized_axis +/// - @ref gtx_rotate_vector +/// - @ref gtx_transform +/// - @ref gtx_vector_angle +/// In order to use these overloads the respective extension header must be +/// included before otherwise calling them fails to compile. +/// This avoids making this extension implicitly dependent on those listed above. +/////////////////////////////////////////////////////////////////////////////////// + +#pragma once + +// Dependency: +#include "../glm.hpp" + +#if(defined(GLM_MESSAGES) && !defined(GLM_EXT_INCLUDED)) +# pragma message("GLM: GLM_GTX_angle included") +#endif + +namespace glm +{ + /// @addtogroup gtx_angle + /// @{ + + template + class tangle; + + ////////////////////////////////////// + // Explicit converting factory functions + + /// Create an angle from radians + template + GLM_FUNC_DECL GLM_CONSTEXPR tangle rad(T radians); + /// Create an angle from degrees + template + GLM_FUNC_DECL GLM_CONSTEXPR tangle deg(T degrees); + + ////////////////////////////////////// + // Explicit converting value access + + /// Extract an angle's magnitude converted to radians + template + GLM_FUNC_DECL GLM_CONSTEXPR T rad(tangle angle); + /// Extract an angle's magnitude converted to degrees + template + GLM_FUNC_DECL GLM_CONSTEXPR T deg(tangle angle); + + ////////////////////////////////////// + // Generic angle class defintion + + template + class tangle + { + public: + GLM_STATIC_ASSERT(std::numeric_limits::is_iec559, "'angle' only accepts floating-point types"); + + typedef tangle type; + typedef T value_type; + + ////////////////////////////////////// + // Implicit basic constructors + + GLM_FUNC_DECL GLM_CONSTEXPR tangle(); + GLM_FUNC_DECL GLM_CONSTEXPR tangle(tangle const & other); + template + GLM_FUNC_DECL GLM_CONSTEXPR tangle(tangle const & other); + + ////////////////////////////////////// + // Explicit basic constructors + + GLM_FUNC_DECL GLM_CONSTEXPR explicit tangle(ctor); + + ////////////////////////////////////// + // Assignment (compound) operators + + GLM_FUNC_DECL tvec4 & operator=(tangle const & rhs); + + template + GLM_FUNC_DECL tangle & operator=(tangle const & rhs); + template + GLM_FUNC_DECL tangle & operator+=(tangle const & rhs); + template + GLM_FUNC_DECL tangle & operator-=(tangle const & rhs); + template + GLM_FUNC_DECL tangle & operator*=(U rhs); + template + GLM_FUNC_DECL tangle & operator/=(U rhs); + + private: + friend GLM_CONSTEXPR tangle rad(T radians); + friend GLM_CONSTEXPR tangle deg(T degrees); + + friend GLM_CONSTEXPR T rad(tangle radians); + friend GLM_CONSTEXPR T deg(tangle degrees); + + GLM_FUNC_DECL GLM_CONSTEXPR tangle(T radians); + + T _radians; + }; + + typedef tangle fangle; // angle is already taken :( + typedef tangle dangle; + + ////////////////////////////////////// + // Unary arithmetic operators + + template + GLM_FUNC_DECL GLM_CONSTEXPR tangle operator+(tangle angle); + template + GLM_FUNC_DECL GLM_CONSTEXPR tangle operator-(tangle angle); + + ////////////////////////////////////// + // Binary arithmetic operators + + template + GLM_FUNC_DECL GLM_CONSTEXPR tangle operator+(tangle lhs, tangle rhs); + template + GLM_FUNC_DECL GLM_CONSTEXPR tangle operator-(tangle lhs, tangle rhs); + template + GLM_FUNC_DECL GLM_CONSTEXPR tangle operator*(tangle lhs, T rhs); + template + GLM_FUNC_DECL GLM_CONSTEXPR tangle operator*(T lhs, tangle rhs); + template + GLM_FUNC_DECL GLM_CONSTEXPR tangle operator/(tangle lhs, T rhs); + template + GLM_FUNC_DECL GLM_CONSTEXPR T operator/(tangle lhs, tangle rhs); + + ////////////////////////////////////// + // Comparison operators + + template + GLM_FUNC_DECL GLM_CONSTEXPR bool operator==(tangle lhs, tangle rhs); + template + GLM_FUNC_DECL GLM_CONSTEXPR bool operator!=(tangle lhs, tangle rhs); + template + GLM_FUNC_DECL GLM_CONSTEXPR bool operator<=(tangle lhs, tangle rhs); + template + GLM_FUNC_DECL GLM_CONSTEXPR bool operator>=(tangle lhs, tangle rhs); + template + GLM_FUNC_DECL GLM_CONSTEXPR bool operator<(tangle lhs, tangle rhs); + template + GLM_FUNC_DECL GLM_CONSTEXPR bool operator>(tangle lhs, tangle rhs); + + ////////////////////////////////////// + // Common functions + + template + GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tangle abs(tangle arg); + template + GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tangle clamp(tangle x, tangle minVal, tangle maxVal); + template + GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tangle max(tangle lhs, tangle rhs); + template + GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tangle min(tangle lhs, tangle rhs); + template + GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tangle mix(tangle x, tangle y, U a); + template + GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tangle mix(tangle x, tangle y, bool a); + template + GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tangle mod(tangle lhs, tangle rhs); + template + GLM_FUNC_DECL /*GLM_CONSTEXPR*/ T sign(tangle arg); + + ////////////////////////////////////// + // Special angle functions + + /// Normalize an angle's representation so lies within the interval [0; 2pi). + template + GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tangle normalize(tangle arg); + /// Compute the shortest distance between two *normalized* angles, which is always in the range [-pi; +pi]. + template + GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tangle distance(tangle from, tangle to); + + ////////////////////////////////////// + // Trigonometric functions + + template + GLM_FUNC_DECL /*GLM_CONSTEXPR*/ T cos(tangle arg); + template + GLM_FUNC_DECL /*GLM_CONSTEXPR*/ T sin(tangle arg); + template + GLM_FUNC_DECL /*GLM_CONSTEXPR*/ T tan(tangle arg); + template + GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tangle atan2(T y, T x); + template + GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tangle atan2(tvec2 const & v); + // TODO: These conflict with existing GLM functions :( +// template +// GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tangle acos(T arg); +// template +// GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tangle asin(T arg); +// template +// GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tangle atan(T arg); + + ////////////////////////////////////// + // GLM_GTC_matrix_transform + + template + GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tmat4x4 infinitePerspective(tangle fovy, T aspect, T near); + template + GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tmat4x4 perspective(tangle fovy, T aspect, T near, T far); + template + GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tmat4x4 perspectiveFov(tangle fov, T width, T height, T near, T far); + template + GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tmat4x4 rotate(tmat4x4 const & m, tangle angle, tvec3 const & axis); + template + GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tmat4x4 tweakedInfinitePerspective(tangle fovy, T aspect, T near); + template + GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tmat4x4 tweakedInfinitePerspective(tangle fovy, T aspect, T near, T ep); + + ////////////////////////////////////// + // GLM_GTC_quaternion + + template + struct tquat; + + // TODO: Some conflict with existing GTC functions :( +// template +// GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tangle angle(tquat const & q); + template + GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tquat angleAxis(tangle angle, tvec3 const & axis); +// template +// GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tangle pitch(tquat const & q); + template + GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tquat rotate(tquat< T, P > const & q, tangle angle, tvec3 const & axis); +// template +// GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tangle roll(tquat const & q); +// template +// GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tangle yaw(tquat const & q); + + ////////////////////////////////////// + // GLM_GTX_fast_trigonometry + + // TODO: Some conflict with existing GTX functions :( +// template +// GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tangle fastAcos(T x); +// template +// GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tangle fastAsin(T x); +// template +// GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tangle fastAtan(T y, T x); +// template +// GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tangle fastAtan(T x); + template + GLM_FUNC_DECL /*GLM_CONSTEXPR*/ T fastCos(tangle angle); + template + GLM_FUNC_DECL /*GLM_CONSTEXPR*/ T fastSin(tangle angle); + template + GLM_FUNC_DECL /*GLM_CONSTEXPR*/ T fastTan(tangle angle); + + ////////////////////////////////////// + // GLM_GTX_matrix_interpolation + + template + GLM_FUNC_DECL void axisAngle(tmat4x4 const & mat, tvec3 & axis, tangle angle); + template + GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tmat4x4 axisAngleMatrix(tvec3 const & axis, tangle angle); + + ////////////////////////////////////// + // GLM_GTX_matrix_transform_2d + + template + GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tmat3x3 rotate(tmat3x3 const & m, tangle angle); + + ////////////////////////////////////// + // GLM_GTX_rotate_normalized_axis + + template + GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tmat4x4 rotateNormalizedAxis(tmat4x4 const & m, tangle angle, tvec3 const & axis); + template + GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tquat rotateNormalizedAxis(tquat const & q, tangle angle, tvec3 const & axis); + + ////////////////////////////////////// + // GLM_GTX_rotate_vector + + template + GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tvec2 rotate(tvec2 const & v, tangle angle); + template + GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tvec3 rotate(tvec3 const & v, tangle angle, tvec3 const & normal); + template + GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tvec4 rotate(tvec4 const & v, tangle angle, tvec3 const & normal); + template + GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tvec3 rotateX(tvec3 const & v, tangle angle); + template + GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tvec4 rotateX(tvec4 const & v, tangle angle); + template + GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tvec3 rotateY(tvec3 const & v, tangle angle); + template + GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tvec4 rotateY(tvec4 const & v, tangle angle); + template + GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tvec3 rotateZ(tvec3 const & v, tangle angle); + template + GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tvec4 rotateZ(tvec4 const & v, tangle angle); + + ////////////////////////////////////// + // GLM_GTX_transform + + template + GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tmat4x4< T, P > rotate(tangle angle, tvec3< T, P > const & v); + + ////////////////////////////////////// + // GLM_GTX_vector_angle + + // TODO: These conflict with existing GTX functions :( +// template +// GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tangle angle(vecType const & x, vecType const & y); +// template +// GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tangle orientedAngle(tvec2 const & x, tvec2 const & y); +// template +// GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tangle orientedAngle(tvec3 const & x, tvec3 const & y, tvec3 const &ref); + + /// @} +} // namespace glm + +#include "angle.inl" diff --git a/glm/gtx/angle.inl b/glm/gtx/angle.inl new file mode 100644 index 00000000..51bae601 --- /dev/null +++ b/glm/gtx/angle.inl @@ -0,0 +1,583 @@ +/////////////////////////////////////////////////////////////////////////////////// +/// OpenGL Mathematics (glm.g-truc.net) +/// +/// Copyright (c) 2005 - 2015 G-Truc Creation (www.g-truc.net) +/// Permission is hereby granted, free of charge, to any person obtaining a copy +/// of this software and associated documentation files (the "Software"), to deal +/// in the Software without restriction, including without limitation the rights +/// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +/// copies of the Software, and to permit persons to whom the Software is +/// furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// Restrictions: +/// By making use of the Software for military purposes, you choose to make +/// a Bunny unhappy. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +/// THE SOFTWARE. +/// +/// @ref gtx_angle +/// @file glm/gtx/angle.inl +/// @date 2015-05-10 +/// @author Miroslav Knejp +/////////////////////////////////////////////////////////////////////////////////// + +namespace glm +{ + ////////////////////////////////////// + // Implicit basic constructors + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR tangle::tangle() +# ifndef GLM_FORCE_NO_CTOR_INIT + : _radians(0) +# endif + {} + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR tangle::tangle(tangle const & other) + : _radians(other._radians) + {} + + template + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR tangle::tangle(tangle const & other) + : _radians(other._radians) + {} + + ////////////////////////////////////// + // Explicit basic constructors + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR tangle::tangle(ctor) + {} + + ////////////////////////////////////// + // Assignment (compound) operators + + template + GLM_FUNC_QUALIFIER tvec4 & tangle::operator=(tangle const & rhs) + { + this->_radians = rhs._radians; + return *this; + } + + template + template + GLM_FUNC_QUALIFIER tangle & tangle::operator=(tangle const & rhs) + { + this->_radians = static_cast(rhs._radians); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER tangle & tangle::operator+=(tangle const & rhs) + { + this->_radians += static_cast(rhs._radians); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER tangle & tangle::operator-=(tangle const & rhs) + { + this->_radians -= static_cast(rhs._radians); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER tangle & tangle::operator*=(U rhs) + { + this->_radians *= static_cast(rhs); + return *this; + } + + template + template + GLM_FUNC_QUALIFIER tangle & tangle::operator/=(U rhs) + { + this->_radians /= static_cast(rhs); + return *this; + } + + ////////////////////////////////////// + // Explicit converting factory functions + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR tangle::tangle(T radians) + : _radians(radians) + {} + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR tangle rad(T radians) + { + return tangle(radians); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR tangle deg(T degrees) + { + // glm::radians is not constexpr + return tangle(degrees * static_cast(0.01745329251994329576923690768489)); + } + + ////////////////////////////////////// + // Explicit converting value access + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR T rad(tangle angle) + { + return angle._radians; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR T deg(tangle angle) + { + // glm::degrees is not constexpr + return angle._radians * static_cast(57.295779513082320876798154814105); + } + + ////////////////////////////////////// + // Unary arithmetic operators + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR tangle operator+(tangle angle) + { + return angle; + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR tangle operator-(tangle angle) + { + return rad(-rad(angle)); + } + + ////////////////////////////////////// + // Binary arithmetic operators + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR tangle operator+(tangle lhs, tangle rhs) + { + return rad(rad(lhs) + rad(rhs)); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR tangle operator-(tangle lhs, tangle rhs) + { + return rad(rad(lhs) - rad(rhs)); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR tangle operator*(tangle lhs, T rhs) + { + return rad(rad(lhs) * rhs); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR tangle operator*(T lhs, tangle rhs) + { + return rad(lhs * rad(rhs)); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR tangle operator/(tangle lhs, T rhs) + { + return rad(rad(lhs) / rhs); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR T operator/(tangle lhs, tangle rhs) + { + return rad(lhs) / rad(rhs); + } + + ////////////////////////////////////// + // Comparison operators + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR bool operator==(tangle lhs, tangle rhs) + { + return rad(lhs) == rad(rhs); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR bool operator!=(tangle lhs, tangle rhs) + { + return rad(lhs) != rad(rhs); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR bool operator<=(tangle lhs, tangle rhs) + { + return rad(lhs) <= rad(rhs); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR bool operator>=(tangle lhs, tangle rhs) + { + return rad(lhs) >= rad(rhs); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR bool operator<(tangle lhs, tangle rhs) + { + return rad(lhs) < rad(rhs); + } + + template + GLM_FUNC_QUALIFIER GLM_CONSTEXPR bool operator>(tangle lhs, tangle rhs) + { + return rad(lhs) > rad(rhs); + } + + ////////////////////////////////////// + // Common functions + + template + GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tangle abs(tangle arg) + { + return rad(abs(rad(arg))); + } + + template + GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tangle clamp(tangle x, tangle minVal, tangle maxVal) + { + return rad(clamp(rad(x), rad(minVal), rad(maxVal))); + } + + template + GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tangle max(tangle lhs, tangle rhs) + { + return rad(max(rad(lhs), rad(rhs))); + } + + template + GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tangle min(tangle lhs, tangle rhs) + { + return rad(min(rad(lhs), rad(rhs))); + } + + template + GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tangle mix(tangle x, tangle y, U a) + { + return rad(mix(rad(x), rad(y), a)); + } + + template + GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tangle mix(tangle x, tangle y, bool a) + { + return a ? y : x; + } + + template + GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tangle mod(tangle lhs, tangle rhs) + { + return rad(mod(rad(lhs), rad(rhs))); + } + + template + GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ T sign(tangle arg) + { + return sign(rad(arg)); + } + + ////////////////////////////////////// + // Special angle functions + + template + GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tangle normalize(tangle arg) + { + tangle x = mod(arg, deg(static_cast(360))); + return x < deg(static_cast(0)) ? x + deg(static_cast(360)) : x; + } + + template + GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tangle distance(tangle from, tangle to) + { + if(abs(to - from) > deg(static_cast(180))) + { + return (from > to ? to + deg(static_cast(360)) : to - deg(static_cast(360))) - from; + } + else + { + return to - from; + } + } + + ////////////////////////////////////// + // Trigonometric functions + + template + GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ T cos(tangle arg) + { + return std::cos(rad(arg)); + } + + template + GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ T sin(tangle arg) + { + return std::sin(rad(arg)); + } + + template + GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ T tan(tangle arg) + { + return std::tan(rad(arg)); + } + + template + GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tangle atan2(T y, T x) + { + return rad(std::atan2(y, x)); + } + + template + GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tangle atan2(tvec2 const & v) + { + return rad(std::atan2(v.y, v.x)); + } + +// template +// GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tangle acos(T arg) +// { +// return rad(std::acos(arg)); +// } +// +// template +// GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tangle asin(T arg) +// { +// return rad(std::asin(arg)); +// } +// +// template +// GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tangle atan(T arg) +// { +// return rad(std::atan(arg)); +// } + + ////////////////////////////////////// + // GLM_GTC_matrix_transform + + template + GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tmat4x4 infinitePerspective(tangle fovy, T aspect, T near) + { + return infinitePerspective(rad(fovy), aspect, near); + } + + template + GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tmat4x4 perspective(tangle fovy, T aspect, T near, T far) + { + return perspective(rad(fovy), aspect, near, far); + } + + template + GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tmat4x4 perspectiveFov(tangle fov, T width, T height, T near, T far) + { + return prespectiveFov(rad(fov), width, height, near, far); + } + + template + GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tmat4x4 rotate(tmat4x4 const & m, tangle angle, tvec3 const & axis) + { + return rotate(m, rad(angle), axis); + } + + template + GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tmat4x4 tweakedInfinitePerspective(tangle fovy, T aspect, T near) + { + return tweakedInfinitePerspective(rad(fovy), aspect, near); + } + + template + GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tmat4x4 tweakedInfinitePerspective(tangle fovy, T aspect, T near, T ep) + { + return tweakedInfinitePerspective(rad(fovy), aspect, near, ep); + } + + ////////////////////////////////////// + // GLM_GTC_quaternion + +// template +// GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tangle angle(tquat const & q); + + template + GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tquat angleAxis(tangle angle, tvec3 const & axis) + { + return angleAxis(rad(angle), axis); + } + +// template +// GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tangle pitch(tquat const & q); + + template + GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tquat rotate(tquat< T, P > const & q, tangle angle, tvec3 const & axis) + { + return rotate(q, rad(angle), axis); + } + +// template +// GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tangle roll(tquat const & q); + +// template +// GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tangle yaw(tquat const & q); + + ////////////////////////////////////// + // GLM_GTX_fast_trigonometry + +// template +// GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tangle fastAcos(T x); + +// template +// GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tangle fastAsin(T x); + +// template +// GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tangle fastAtan(T y, T x); + +// template +// GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tangle fastAtan(T x); + + template + GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ T fastCos(tangle angle) + { + return fastCos(rad(angle)); + } + + template + GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ T fastSin(tangle angle) + { + return fastSin(rad(angle)); + } + + template + GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ T fastTan(tangle angle) + { + return fastTan(rad(angle)); + } + + ////////////////////////////////////// + // GLM_GTX_matrix_interpolation + + template + GLM_FUNC_QUALIFIER void axisAngle(tmat4x4 const & mat, tvec3 & axis, tangle angle) + { + return axisAngle(mat, axis, rad(angle)); + } + + template + GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tmat4x4 axisAngleMatrix(tvec3 const & axis, tangle angle) + { + return axisAngleMatrix(axis, rad(angle)); + } + + ////////////////////////////////////// + // GLM_GTX_matrix_transform_2d + + template + GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tmat3x3 rotate(tmat3x3 const & m, tangle angle) + { + return rotate(m, rad(angle)); + } + + ////////////////////////////////////// + // GLM_GTX_rotate_normalized_axis + + template + GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tmat4x4 rotateNormalizedAxis(tmat4x4 const & m, tangle angle, tvec3 const & axis) + { + return rotateNormalizedAxis(m, rad(angle), axis); + } + + template + GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tquat rotateNormalizedAxis(tquat const & q, tangle angle, tvec3 const & axis) + { + return rotateNormalizedAxis(q, rad(angle), axis); + } + + ////////////////////////////////////// + // GLM_GTX_rotate_vector + + template + GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tvec2 rotate(tvec2 const & v, tangle angle) + { + return rotate(v, rad(angle)); + } + + template + GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tvec3 rotate(tvec3 const & v, tangle angle, tvec3 const & normal) + { + return rotate(v, rad(angle), normal); + } + + template + GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tvec4 rotate(tvec4 const & v, tangle angle, tvec3 const & normal) + { + return rotate(v, rad(angle), normal); + } + + template + GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tvec3 rotateX(tvec3 const & v, tangle angle) + { + return rotateX(v, rad(angle)); + } + + template + GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tvec4 rotateX(tvec4 const & v, tangle angle) + { + return rotateX(v, rad(angle)); + } + + template + GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tvec3 rotateY(tvec3 const & v, tangle angle) + { + return rotateY(v, rad(angle)); + } + + template + GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tvec4 rotateY(tvec4 const & v, tangle angle) + { + return rotateY(v, rad(angle)); + } + + template + GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tvec3 rotateZ(tvec3 const & v, tangle angle) + { + return rotateZ(v, rad(angle)); + } + + template + GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tvec4 rotateZ(tvec4 const & v, tangle angle) + { + return rotateZ(v, rad(angle)); + } + + ////////////////////////////////////// + // GLM_GTX_transform + + template + GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tmat4x4< T, P > rotate(tangle angle, tvec3< T, P > const & v) + { + return rotate(rad(angle), v); + } + + ////////////////////////////////////// + // GLM_GTX_vector_angle + +// template +// GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tangle angle(vecType const & x, vecType const & y); + +// template +// GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tangle orientedAngle(tvec2 const & x, tvec2 const & y); + +// template +// GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tangle orientedAngle(tvec3 const & x, tvec3 const & y, tvec3 const &ref); +} diff --git a/test/gtx/CMakeLists.txt b/test/gtx/CMakeLists.txt index 4be4343f..1e53ccd7 100644 --- a/test/gtx/CMakeLists.txt +++ b/test/gtx/CMakeLists.txt @@ -1,3 +1,4 @@ +glmCreateTestGTC(gtx_angle) glmCreateTestGTC(gtx_associated_min_max) glmCreateTestGTC(gtx_closest_point) glmCreateTestGTC(gtx_color_space_YCoCg) diff --git a/test/gtx/gtx_angle.cpp b/test/gtx/gtx_angle.cpp new file mode 100644 index 00000000..602306f5 --- /dev/null +++ b/test/gtx/gtx_angle.cpp @@ -0,0 +1,328 @@ +/////////////////////////////////////////////////////////////////////////////////// +/// OpenGL Mathematics (glm.g-truc.net) +/// +/// Copyright (c) 2005 - 2015 G-Truc Creation (www.g-truc.net) +/// Permission is hereby granted, free of charge, to any person obtaining a copy +/// of this software and associated documentation files (the "Software"), to deal +/// in the Software without restriction, including without limitation the rights +/// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +/// copies of the Software, and to permit persons to whom the Software is +/// furnished to do so, subject to the following conditions: +/// +/// The above copyright notice and this permission notice shall be included in +/// all copies or substantial portions of the Software. +/// +/// Restrictions: +/// By making use of the Software for military purposes, you choose to make +/// a Bunny unhappy. +/// +/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +/// THE SOFTWARE. +/// +/// @file test/gtx/gtx_angle.cpp +/// @date 2015-05-10 +/// @author Miroslav Knejp +/////////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include + +namespace +{ + const float pi = glm::pi(); + + int test_factory() + { + int Error(0); + + { + glm::fangle a = glm::rad(0.f); + Error += glm::epsilonEqual(rad(a), 0.f, 0.01f) ? 0 : 1; + Error += glm::epsilonEqual(deg(a), 0.f, 0.01f) ? 0 : 1; + } + { + glm::fangle a = glm::deg(0.f); + Error += glm::epsilonEqual(rad(a), 0.f, 0.01f) ? 0 : 1; + Error += glm::epsilonEqual(deg(a), 0.f, 0.01f) ? 0 : 1; + } + { + glm::fangle a = glm::rad(pi); + Error += glm::epsilonEqual(rad(a), pi, 0.01f) ? 0 : 1; + Error += glm::epsilonEqual(deg(a), 180.f, 0.01f) ? 0 : 1; + } + { + glm::fangle a = glm::deg(180.f); + Error += glm::epsilonEqual(rad(a), pi, 0.01f) ? 0 : 1; + Error += glm::epsilonEqual(deg(a), 180.f, 0.01f) ? 0 : 1; + } + { + glm::fangle a = glm::rad(-pi / 2); + Error += glm::epsilonEqual(rad(a), -pi / 2, 0.01f) ? 0 : 1; + Error += glm::epsilonEqual(deg(a), -90.f, 0.01f) ? 0 : 1; + } + { + glm::fangle a = glm::deg(-90.f); + Error += glm::epsilonEqual(rad(a), -pi / 2, 0.01f) ? 0 : 1; + Error += glm::epsilonEqual(deg(a), -90.f, 0.01f) ? 0 : 1; + } + return Error; + } + + int test_arithmetic() + { + int Error(0); + float x = static_cast(std::max(std::rand(), 1)) / RAND_MAX; + float y = static_cast(std::max(std::rand(), 1)) / RAND_MAX; + + { + glm::fangle a = glm::rad(x); + glm::fangle b = glm::rad(y); + Error += glm::epsilonEqual(x + y, rad(a + b), 0.01f) ? 0 : 1; + Error += glm::epsilonEqual(x - y, rad(a - b), 0.01f) ? 0 : 1; + } + { + glm::fangle a = glm::rad(x); + Error += glm::epsilonEqual(y * x, rad(y * a), 0.01f) ? 0 : 1; + Error += glm::epsilonEqual(x * y, rad(a * y), 0.01f) ? 0 : 1; + } + { + glm::fangle a = glm::rad(x); + Error += glm::epsilonEqual(x / y, rad(a / y), 0.01f) ? 0 : 1; + } + { + glm::fangle a = glm::rad(x); + glm::fangle b = glm::rad(y); + Error += glm::epsilonEqual(x / y, a / b, 0.01f) ? 0 : 1; + } + { + glm::fangle a = glm::rad(x); + Error += glm::epsilonEqual(+x, rad(+a), 0.01f) ? 0 : 1; + } + { + glm::fangle a = glm::rad(x); + Error += glm::epsilonEqual(-x, rad(-a), 0.01f) ? 0 : 1; + } + + return Error; + } + + int test_comparison() + { + int Error(0); + float x = -static_cast(std::max(std::rand(), 1)) / RAND_MAX; + float y = static_cast(std::max(std::rand(), 1)) / RAND_MAX; + + Error += glm::rad(x) == glm::rad(x) ? 0 : 1; + Error += glm::rad(x) == glm::rad(y) ? 1 : 0; + Error += glm::rad(x) != glm::rad(x) ? 1 : 0; + Error += glm::rad(x) != glm::rad(y) ? 0 : 1; + + Error += glm::rad(x) < glm::rad(x) ? 1 : 0; + Error += glm::rad(x) < glm::rad(y) ? 0 : 1; + + Error += glm::rad(x) > glm::rad(x) ? 1 : 0; + Error += glm::rad(y) > glm::rad(x) ? 0 : 1; + + Error += glm::rad(x) <= glm::rad(x) ? 0 : 1; + Error += glm::rad(x) <= glm::rad(y) ? 0 : 1; + + Error += glm::rad(x) >= glm::rad(x) ? 0 : 1; + Error += glm::rad(y) >= glm::rad(x) ? 0 : 1; + return Error; + } + + int test_constexpr() + { + int Error(0); + +# if GLM_HAS_CONSTEXPR + static_assert(std::is_literal_type::value, ""); + static_assert(std::is_literal_type::value, ""); + + constexpr auto a = glm::deg(1.f); + constexpr auto b = glm::rad(2.f); + constexpr auto f = 3.f; + + // Force compile-time evaluation + static_assert((rad(a), true), ""); + static_assert((deg(a), true), ""); + + static_assert((+a, true), ""); + static_assert((-a, true), ""); + + static_assert((a + b, true), ""); + static_assert((a - b, true), ""); + static_assert((a * f, true), ""); + static_assert((f * b, true), ""); + static_assert((a / f, true), ""); + static_assert((a / b, true), ""); + + static_assert((a == b) || true, ""); + static_assert((a != b) || true, ""); + static_assert((a <= b) || true, ""); + static_assert((a >= b) || true, ""); + static_assert((a < b) || true, ""); + static_assert((a > b) || true, ""); +# endif + + return Error; + } + + int test_common() + { + int Error(0); + + float x = static_cast(std::max(std::rand(), 1)) / RAND_MAX; + float y = static_cast(std::max(std::rand(), 1)) / RAND_MAX; + float f = static_cast(std::max(std::rand(), 1)) / RAND_MAX; + { + glm::fangle a = glm::rad(x); + glm::fangle b = glm::rad(-x); + Error += glm::epsilonEqual(x, rad(abs(b)), 0.01f) ? 0 : 1; + Error += glm::epsilonEqual(rad(a), rad(abs(b)), 0.01f) ? 0 : 1; + } + { + glm::fangle a = glm::rad(100.f); + glm::fangle b = glm::rad(200.f); + glm::fangle c = a - glm::rad(x); + glm::fangle d = b + glm::rad(y); + glm::fangle e = glm::rad(150.f); + Error += clamp(c, a, b) <= b ? 0 : 1; + Error += clamp(c, a, b) >= a ? 0 : 1; + Error += clamp(d, a, b) <= b ? 0 : 1; + Error += clamp(d, a, b) >= a ? 0 : 1; + Error += glm::epsilonEqual(rad(clamp(e, a, b)), rad(e), 0.01f) ? 0 : 1; + } + { + glm::fangle a = glm::rad(x); + glm::fangle b = glm::rad(y); + Error += glm::epsilonEqual(std::max(x, y), rad(max(a, b)), 0.01f) ? 0 : 1; + Error += glm::epsilonEqual(std::min(x, y), rad(min(a, b)), 0.01f) ? 0 : 1; + } + { + glm::fangle a = glm::rad(x); + glm::fangle b = glm::rad(y); + Error += glm::epsilonEqual(glm::mix(x, y, f), rad(mix(a, b, f)), 0.01f) ? 0 : 1; + Error += glm::epsilonEqual(x, rad(mix(a, b, false)), 0.01f) ? 0 : 1; + Error += glm::epsilonEqual(y, rad(mix(a, b, true)), 0.01f) ? 0 : 1; + } + { + glm::fangle a = glm::rad(x); + glm::fangle b = glm::rad(y); + Error += glm::epsilonEqual(glm::mod(x, y), rad(mod(a, b)), 0.01f) ? 0 : 1; + Error += glm::epsilonEqual(glm::mod(y, x), rad(mod(b, a)), 0.01f) ? 0 : 1; + } + { + Error += glm::epsilonEqual(1.f, sign(glm::rad(10.f)), 0.01f) ? 0 : 1; + Error += glm::epsilonEqual(0.f, sign(glm::rad(0.f)), 0.01f) ? 0 : 1; + Error += glm::epsilonEqual(-1.f, sign(glm::rad(-10.f)), 0.01f) ? 0 : 1; + + Error += glm::epsilonEqual(1.f, sign(glm::deg(10.f)), 0.01f) ? 0 : 1; + Error += glm::epsilonEqual(0.f, sign(glm::deg(0.f)), 0.01f) ? 0 : 1; + Error += glm::epsilonEqual(-1.f, sign(glm::deg(-10.f)), 0.01f) ? 0 : 1; + } + return Error; + } + + int test_special() + { + int Error(0); + + { + glm::fangle a = glm::rad(5 * pi); + Error += glm::epsilonEqual(pi, rad(normalize(a)), 0.01f) ? 0 : 1; + } + { + glm::fangle a = glm::rad(2 * pi); + Error += glm::epsilonEqual(0.f, rad(normalize(a)), 0.01f) ? 0 : 1; + } + { + glm::fangle a = glm::rad(-pi / 2); + Error += glm::epsilonEqual(1.5f * pi, rad(normalize(a)), 0.01f) ? 0 : 1; + } + { + glm::fangle a = glm::rad(-pi * 2); + Error += glm::epsilonEqual(0.f, rad(normalize(a)), 0.01f) ? 0 : 1; + } + { + glm::fangle a = glm::rad(5 * -pi); + Error += glm::epsilonEqual(pi, rad(normalize(a)), 0.01f) ? 0 : 1; + } + + { + glm::fangle a = glm::deg(0.f); + glm::fangle b = glm::deg(90.f); + Error += glm::epsilonEqual(90.f, deg(distance(a, b)), 0.01f) ? 0 : 1; + Error += glm::epsilonEqual(-90.f, deg(distance(b, a)), 0.01f) ? 0 : 1; + } + { + glm::fangle a = glm::deg(0.f); + glm::fangle b = glm::deg(180.f); + Error += glm::epsilonEqual(180.f, deg(distance(a, b)), 0.01f) ? 0 : 1; + Error += glm::epsilonEqual(-180.f, deg(distance(b, a)), 0.01f) ? 0 : 1; + } + { + glm::fangle a = glm::deg(0.f); + glm::fangle b = glm::deg(270.f); + Error += glm::epsilonEqual(-90.f, deg(distance(a, b)), 0.01f) ? 0 : 1; + Error += glm::epsilonEqual(90.f, deg(distance(b, a)), 0.01f) ? 0 : 1; + } + { + glm::fangle a = glm::deg(0.f); + glm::fangle b = glm::deg(360.f); + Error += glm::epsilonEqual(0.f, deg(distance(a, b)), 0.01f) ? 0 : 1; + Error += glm::epsilonEqual(0.f, deg(distance(b, a)), 0.01f) ? 0 : 1; + } + { + glm::fangle a = glm::deg(10.f); + glm::fangle b = glm::deg(350.f); + Error += glm::epsilonEqual(-20.f, deg(distance(a, b)), 0.01f) ? 0 : 1; + Error += glm::epsilonEqual(20.f, deg(distance(b, a)), 0.01f) ? 0 : 1; + } + + return Error; + } + + int test_trigonometric() + { + int Error(0); + + float x = static_cast(std::rand()); + float y = static_cast(std::rand()); + + { + glm::fangle a = glm::rad(x); + Error += glm::epsilonEqual(std::cos(x), cos(a), 0.0001f) ? 0 : 1; + Error += glm::epsilonEqual(std::sin(x), sin(a), 0.0001f) ? 0 : 1; + Error += glm::epsilonEqual(std::tan(x), tan(a), 0.0001f) ? 0 : 1; + } + Error += glm::epsilonEqual(std::atan2(y, x), rad(glm::atan2(y, x)), 0.0001f) ? 0 : 1; + Error += glm::epsilonEqual(std::atan2(y, x), rad(glm::atan2(glm::vec2(x, y))), 0.0001f) ? 0 : 1; + + return Error; + } +} + +int main() +{ + int Error(0); + std::srand(std::time(NULL)); + + Error += test_factory(); + Error += test_comparison(); + Error += test_arithmetic(); + Error += test_constexpr(); + Error += test_common(); + Error += test_special(); + Error += test_trigonometric(); + + return Error; +}