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.
This commit is contained in:
Miro Knejp 2015-05-11 18:02:55 +02:00
parent 83409a0720
commit c351089e9f
4 changed files with 1289 additions and 0 deletions

377
glm/gtx/angle.hpp Normal file
View File

@ -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.
///
/// <glm/gtx/angle.hpp> 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 <glm/gtx/angle.hpp> 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<typename T, precision P = defaultp>
class tangle;
//////////////////////////////////////
// Explicit converting factory functions
/// Create an angle from radians
template <typename T>
GLM_FUNC_DECL GLM_CONSTEXPR tangle<T> rad(T radians);
/// Create an angle from degrees
template <typename T>
GLM_FUNC_DECL GLM_CONSTEXPR tangle<T> deg(T degrees);
//////////////////////////////////////
// Explicit converting value access
/// Extract an angle's magnitude converted to radians
template <typename T, precision P>
GLM_FUNC_DECL GLM_CONSTEXPR T rad(tangle<T, P> angle);
/// Extract an angle's magnitude converted to degrees
template <typename T, precision P>
GLM_FUNC_DECL GLM_CONSTEXPR T deg(tangle<T, P> angle);
//////////////////////////////////////
// Generic angle class defintion
template<typename T, precision P>
class tangle
{
public:
GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'angle' only accepts floating-point types");
typedef tangle<T, P> type;
typedef T value_type;
//////////////////////////////////////
// Implicit basic constructors
GLM_FUNC_DECL GLM_CONSTEXPR tangle();
GLM_FUNC_DECL GLM_CONSTEXPR tangle(tangle<T, P> const & other);
template <precision Q>
GLM_FUNC_DECL GLM_CONSTEXPR tangle(tangle<T, Q> const & other);
//////////////////////////////////////
// Explicit basic constructors
GLM_FUNC_DECL GLM_CONSTEXPR explicit tangle(ctor);
//////////////////////////////////////
// Assignment (compound) operators
GLM_FUNC_DECL tvec4<T, P> & operator=(tangle<T, P> const & rhs);
template <typename U>
GLM_FUNC_DECL tangle<T, P> & operator=(tangle<U, P> const & rhs);
template <typename U>
GLM_FUNC_DECL tangle<T, P> & operator+=(tangle<U, P> const & rhs);
template <typename U>
GLM_FUNC_DECL tangle<T, P> & operator-=(tangle<U, P> const & rhs);
template <typename U>
GLM_FUNC_DECL tangle<T, P> & operator*=(U rhs);
template <typename U>
GLM_FUNC_DECL tangle<T, P> & operator/=(U rhs);
private:
friend GLM_CONSTEXPR tangle rad<T>(T radians);
friend GLM_CONSTEXPR tangle deg<T>(T degrees);
friend GLM_CONSTEXPR T rad<T, P>(tangle radians);
friend GLM_CONSTEXPR T deg<T, P>(tangle degrees);
GLM_FUNC_DECL GLM_CONSTEXPR tangle(T radians);
T _radians;
};
typedef tangle<float> fangle; // angle is already taken :(
typedef tangle<double> dangle;
//////////////////////////////////////
// Unary arithmetic operators
template <typename T, precision P>
GLM_FUNC_DECL GLM_CONSTEXPR tangle<T, P> operator+(tangle<T, P> angle);
template <typename T, precision P>
GLM_FUNC_DECL GLM_CONSTEXPR tangle<T, P> operator-(tangle<T, P> angle);
//////////////////////////////////////
// Binary arithmetic operators
template <typename T, precision P>
GLM_FUNC_DECL GLM_CONSTEXPR tangle<T, P> operator+(tangle<T, P> lhs, tangle<T, P> rhs);
template <typename T, precision P>
GLM_FUNC_DECL GLM_CONSTEXPR tangle<T, P> operator-(tangle<T, P> lhs, tangle<T, P> rhs);
template <typename T, precision P>
GLM_FUNC_DECL GLM_CONSTEXPR tangle<T, P> operator*(tangle<T, P> lhs, T rhs);
template <typename T, precision P>
GLM_FUNC_DECL GLM_CONSTEXPR tangle<T, P> operator*(T lhs, tangle<T, P> rhs);
template <typename T, precision P>
GLM_FUNC_DECL GLM_CONSTEXPR tangle<T, P> operator/(tangle<T, P> lhs, T rhs);
template <typename T, precision P>
GLM_FUNC_DECL GLM_CONSTEXPR T operator/(tangle<T, P> lhs, tangle<T, P> rhs);
//////////////////////////////////////
// Comparison operators
template <typename T, precision P>
GLM_FUNC_DECL GLM_CONSTEXPR bool operator==(tangle<T, P> lhs, tangle<T, P> rhs);
template <typename T, precision P>
GLM_FUNC_DECL GLM_CONSTEXPR bool operator!=(tangle<T, P> lhs, tangle<T, P> rhs);
template <typename T, precision P>
GLM_FUNC_DECL GLM_CONSTEXPR bool operator<=(tangle<T, P> lhs, tangle<T, P> rhs);
template <typename T, precision P>
GLM_FUNC_DECL GLM_CONSTEXPR bool operator>=(tangle<T, P> lhs, tangle<T, P> rhs);
template <typename T, precision P>
GLM_FUNC_DECL GLM_CONSTEXPR bool operator<(tangle<T, P> lhs, tangle<T, P> rhs);
template <typename T, precision P>
GLM_FUNC_DECL GLM_CONSTEXPR bool operator>(tangle<T, P> lhs, tangle<T, P> rhs);
//////////////////////////////////////
// Common functions
template <typename T, precision P>
GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tangle<T, P> abs(tangle<T, P> arg);
template <typename T, precision P>
GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tangle<T, P> clamp(tangle<T, P> x, tangle<T, P> minVal, tangle<T, P> maxVal);
template <typename T, precision P>
GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tangle<T, P> max(tangle<T, P> lhs, tangle<T, P> rhs);
template <typename T, precision P>
GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tangle<T, P> min(tangle<T, P> lhs, tangle<T, P> rhs);
template <typename T, precision P, typename U>
GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tangle<T, P> mix(tangle<T, P> x, tangle<T, P> y, U a);
template <typename T, precision P>
GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tangle<T, P> mix(tangle<T, P> x, tangle<T, P> y, bool a);
template <typename T, precision P>
GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tangle<T, P> mod(tangle<T, P> lhs, tangle<T, P> rhs);
template <typename T, precision P>
GLM_FUNC_DECL /*GLM_CONSTEXPR*/ T sign(tangle<T, P> arg);
//////////////////////////////////////
// Special angle functions
/// Normalize an angle's representation so lies within the interval [0; 2pi).
template <typename T, precision P>
GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tangle<T, P> normalize(tangle<T, P> arg);
/// Compute the shortest distance between two *normalized* angles, which is always in the range [-pi; +pi].
template <typename T, precision P>
GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tangle<T, P> distance(tangle<T, P> from, tangle<T, P> to);
//////////////////////////////////////
// Trigonometric functions
template <typename T, precision P>
GLM_FUNC_DECL /*GLM_CONSTEXPR*/ T cos(tangle<T, P> arg);
template <typename T, precision P>
GLM_FUNC_DECL /*GLM_CONSTEXPR*/ T sin(tangle<T, P> arg);
template <typename T, precision P>
GLM_FUNC_DECL /*GLM_CONSTEXPR*/ T tan(tangle<T, P> arg);
template <typename T>
GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tangle<T> atan2(T y, T x);
template <typename T, precision P>
GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tangle<T, P> atan2(tvec2<T, P> const & v);
// TODO: These conflict with existing GLM functions :(
// template <typename T>
// GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tangle<T> acos(T arg);
// template <typename T>
// GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tangle<T> asin(T arg);
// template <typename T>
// GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tangle<T> atan(T arg);
//////////////////////////////////////
// GLM_GTC_matrix_transform
template<typename T, precision P>
GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tmat4x4<T, P> infinitePerspective(tangle<T, P> fovy, T aspect, T near);
template<typename T, precision P>
GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tmat4x4<T, P> perspective(tangle<T, P> fovy, T aspect, T near, T far);
template<typename T, precision P>
GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tmat4x4<T, P> perspectiveFov(tangle<T, P> fov, T width, T height, T near, T far);
template<typename T , precision P>
GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tmat4x4<T, P> rotate(tmat4x4<T, P> const & m, tangle<T, P> angle, tvec3<T, P> const & axis);
template<typename T, precision P>
GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tmat4x4<T, P> tweakedInfinitePerspective(tangle<T, P> fovy, T aspect, T near);
template<typename T, precision P>
GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tmat4x4<T, P> tweakedInfinitePerspective(tangle<T, P> fovy, T aspect, T near, T ep);
//////////////////////////////////////
// GLM_GTC_quaternion
template<typename T, precision P>
struct tquat;
// TODO: Some conflict with existing GTC functions :(
// template<typename T, precision P>
// GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tangle<T, P> angle(tquat<T, P> const & q);
template<typename T , precision P>
GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tquat<T, P> angleAxis(tangle<T, P> angle, tvec3<T, P> const & axis);
// template<typename T, precision P>
// GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tangle<T, P> pitch(tquat<T, P> const & q);
template<typename T , precision P>
GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tquat<T, P> rotate(tquat< T, P > const & q, tangle<T, P> angle, tvec3<T, P> const & axis);
// template<typename T, precision P>
// GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tangle<T, P> roll(tquat<T, P> const & q);
// template<typename T, precision P>
// GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tangle<T, P> yaw(tquat<T, P> const & q);
//////////////////////////////////////
// GLM_GTX_fast_trigonometry
// TODO: Some conflict with existing GTX functions :(
// template<typename T>
// GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tangle<T> fastAcos(T x);
// template<typename T>
// GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tangle<T> fastAsin(T x);
// template<typename T>
// GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tangle<T> fastAtan(T y, T x);
// template<typename T>
// GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tangle<T> fastAtan(T x);
template<typename T, precision P>
GLM_FUNC_DECL /*GLM_CONSTEXPR*/ T fastCos(tangle<T, P> angle);
template<typename T, precision P>
GLM_FUNC_DECL /*GLM_CONSTEXPR*/ T fastSin(tangle<T, P> angle);
template<typename T, precision P>
GLM_FUNC_DECL /*GLM_CONSTEXPR*/ T fastTan(tangle<T, P> angle);
//////////////////////////////////////
// GLM_GTX_matrix_interpolation
template<typename T, precision P>
GLM_FUNC_DECL void axisAngle(tmat4x4<T, P> const & mat, tvec3<T, P> & axis, tangle<T, P> angle);
template<typename T, precision P>
GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tmat4x4<T, P> axisAngleMatrix(tvec3<T, P> const & axis, tangle<T, P> angle);
//////////////////////////////////////
// GLM_GTX_matrix_transform_2d
template<typename T, precision P>
GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tmat3x3<T, P> rotate(tmat3x3<T, P> const & m, tangle<T, P> angle);
//////////////////////////////////////
// GLM_GTX_rotate_normalized_axis
template<typename T, precision P>
GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tmat4x4<T, P> rotateNormalizedAxis(tmat4x4<T, P> const & m, tangle<T, P> angle, tvec3<T, P> const & axis);
template<typename T, precision P>
GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tquat<T, P> rotateNormalizedAxis(tquat<T, P> const & q, tangle<T, P> angle, tvec3<T, P> const & axis);
//////////////////////////////////////
// GLM_GTX_rotate_vector
template<typename T, precision P>
GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tvec2<T, P> rotate(tvec2<T, P> const & v, tangle<T, P> angle);
template<typename T, precision P>
GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tvec3<T, P> rotate(tvec3<T, P> const & v, tangle<T, P> angle, tvec3<T, P> const & normal);
template<typename T, precision P>
GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tvec4<T, P> rotate(tvec4<T, P> const & v, tangle<T, P> angle, tvec3<T, P> const & normal);
template<typename T, precision P>
GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tvec3<T, P> rotateX(tvec3<T, P> const & v, tangle<T, P> angle);
template<typename T, precision P>
GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tvec4<T, P> rotateX(tvec4<T, P> const & v, tangle<T, P> angle);
template<typename T, precision P>
GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tvec3<T, P> rotateY(tvec3<T, P> const & v, tangle<T, P> angle);
template<typename T, precision P>
GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tvec4<T, P> rotateY(tvec4<T, P> const & v, tangle<T, P> angle);
template<typename T, precision P>
GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tvec3<T, P> rotateZ(tvec3<T, P> const & v, tangle<T, P> angle);
template<typename T, precision P>
GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tvec4<T, P> rotateZ(tvec4<T, P> const & v, tangle<T, P> angle);
//////////////////////////////////////
// GLM_GTX_transform
template<typename T, precision P>
GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tmat4x4< T, P > rotate(tangle<T, P> angle, tvec3< T, P > const & v);
//////////////////////////////////////
// GLM_GTX_vector_angle
// TODO: These conflict with existing GTX functions :(
// template<typename vecType>
// GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tangle<vecType::value_type> angle(vecType const & x, vecType const & y);
// template<typename T, precision P>
// GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tangle<T> orientedAngle(tvec2<T, P> const & x, tvec2<T, P> const & y);
// template<typename T, precision P>
// GLM_FUNC_DECL /*GLM_CONSTEXPR*/ tangle<T> orientedAngle(tvec3<T, P> const & x, tvec3<T, P> const & y, tvec3<T, P> const &ref);
/// @}
} // namespace glm
#include "angle.inl"

583
glm/gtx/angle.inl Normal file
View File

@ -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 <typename T, precision P>
GLM_FUNC_QUALIFIER GLM_CONSTEXPR tangle<T, P>::tangle()
# ifndef GLM_FORCE_NO_CTOR_INIT
: _radians(0)
# endif
{}
template <typename T, precision P>
GLM_FUNC_QUALIFIER GLM_CONSTEXPR tangle<T, P>::tangle(tangle<T, P> const & other)
: _radians(other._radians)
{}
template <typename T, precision P>
template <precision Q>
GLM_FUNC_QUALIFIER GLM_CONSTEXPR tangle<T, P>::tangle(tangle<T, Q> const & other)
: _radians(other._radians)
{}
//////////////////////////////////////
// Explicit basic constructors
template <typename T, precision P>
GLM_FUNC_QUALIFIER GLM_CONSTEXPR tangle<T, P>::tangle(ctor)
{}
//////////////////////////////////////
// Assignment (compound) operators
template <typename T, precision P>
GLM_FUNC_QUALIFIER tvec4<T, P> & tangle<T, P>::operator=(tangle<T, P> const & rhs)
{
this->_radians = rhs._radians;
return *this;
}
template <typename T, precision P>
template <typename U>
GLM_FUNC_QUALIFIER tangle<T, P> & tangle<T, P>::operator=(tangle<U, P> const & rhs)
{
this->_radians = static_cast<T>(rhs._radians);
return *this;
}
template <typename T, precision P>
template <typename U>
GLM_FUNC_QUALIFIER tangle<T, P> & tangle<T, P>::operator+=(tangle<U, P> const & rhs)
{
this->_radians += static_cast<T>(rhs._radians);
return *this;
}
template <typename T, precision P>
template <typename U>
GLM_FUNC_QUALIFIER tangle<T, P> & tangle<T, P>::operator-=(tangle<U, P> const & rhs)
{
this->_radians -= static_cast<T>(rhs._radians);
return *this;
}
template <typename T, precision P>
template <typename U>
GLM_FUNC_QUALIFIER tangle<T, P> & tangle<T, P>::operator*=(U rhs)
{
this->_radians *= static_cast<T>(rhs);
return *this;
}
template <typename T, precision P>
template <typename U>
GLM_FUNC_QUALIFIER tangle<T, P> & tangle<T, P>::operator/=(U rhs)
{
this->_radians /= static_cast<T>(rhs);
return *this;
}
//////////////////////////////////////
// Explicit converting factory functions
template <typename T, precision P>
GLM_FUNC_QUALIFIER GLM_CONSTEXPR tangle<T, P>::tangle(T radians)
: _radians(radians)
{}
template <typename T>
GLM_FUNC_QUALIFIER GLM_CONSTEXPR tangle<T> rad(T radians)
{
return tangle<T>(radians);
}
template <typename T>
GLM_FUNC_QUALIFIER GLM_CONSTEXPR tangle<T> deg(T degrees)
{
// glm::radians is not constexpr
return tangle<T>(degrees * static_cast<T>(0.01745329251994329576923690768489));
}
//////////////////////////////////////
// Explicit converting value access
template <typename T, precision P>
GLM_FUNC_QUALIFIER GLM_CONSTEXPR T rad(tangle<T, P> angle)
{
return angle._radians;
}
template <typename T, precision P>
GLM_FUNC_QUALIFIER GLM_CONSTEXPR T deg(tangle<T, P> angle)
{
// glm::degrees is not constexpr
return angle._radians * static_cast<T>(57.295779513082320876798154814105);
}
//////////////////////////////////////
// Unary arithmetic operators
template <typename T, precision P>
GLM_FUNC_QUALIFIER GLM_CONSTEXPR tangle<T, P> operator+(tangle<T, P> angle)
{
return angle;
}
template <typename T, precision P>
GLM_FUNC_QUALIFIER GLM_CONSTEXPR tangle<T, P> operator-(tangle<T, P> angle)
{
return rad(-rad(angle));
}
//////////////////////////////////////
// Binary arithmetic operators
template <typename T, precision P>
GLM_FUNC_QUALIFIER GLM_CONSTEXPR tangle<T, P> operator+(tangle<T, P> lhs, tangle<T, P> rhs)
{
return rad(rad(lhs) + rad(rhs));
}
template <typename T, precision P>
GLM_FUNC_QUALIFIER GLM_CONSTEXPR tangle<T, P> operator-(tangle<T, P> lhs, tangle<T, P> rhs)
{
return rad(rad(lhs) - rad(rhs));
}
template <typename T, precision P>
GLM_FUNC_QUALIFIER GLM_CONSTEXPR tangle<T, P> operator*(tangle<T, P> lhs, T rhs)
{
return rad(rad(lhs) * rhs);
}
template <typename T, precision P>
GLM_FUNC_QUALIFIER GLM_CONSTEXPR tangle<T, P> operator*(T lhs, tangle<T, P> rhs)
{
return rad(lhs * rad(rhs));
}
template <typename T, precision P>
GLM_FUNC_QUALIFIER GLM_CONSTEXPR tangle<T, P> operator/(tangle<T, P> lhs, T rhs)
{
return rad(rad(lhs) / rhs);
}
template <typename T, precision P>
GLM_FUNC_QUALIFIER GLM_CONSTEXPR T operator/(tangle<T, P> lhs, tangle<T, P> rhs)
{
return rad(lhs) / rad(rhs);
}
//////////////////////////////////////
// Comparison operators
template <typename T, precision P>
GLM_FUNC_QUALIFIER GLM_CONSTEXPR bool operator==(tangle<T, P> lhs, tangle<T, P> rhs)
{
return rad(lhs) == rad(rhs);
}
template <typename T, precision P>
GLM_FUNC_QUALIFIER GLM_CONSTEXPR bool operator!=(tangle<T, P> lhs, tangle<T, P> rhs)
{
return rad(lhs) != rad(rhs);
}
template <typename T, precision P>
GLM_FUNC_QUALIFIER GLM_CONSTEXPR bool operator<=(tangle<T, P> lhs, tangle<T, P> rhs)
{
return rad(lhs) <= rad(rhs);
}
template <typename T, precision P>
GLM_FUNC_QUALIFIER GLM_CONSTEXPR bool operator>=(tangle<T, P> lhs, tangle<T, P> rhs)
{
return rad(lhs) >= rad(rhs);
}
template <typename T, precision P>
GLM_FUNC_QUALIFIER GLM_CONSTEXPR bool operator<(tangle<T, P> lhs, tangle<T, P> rhs)
{
return rad(lhs) < rad(rhs);
}
template <typename T, precision P>
GLM_FUNC_QUALIFIER GLM_CONSTEXPR bool operator>(tangle<T, P> lhs, tangle<T, P> rhs)
{
return rad(lhs) > rad(rhs);
}
//////////////////////////////////////
// Common functions
template <typename T, precision P>
GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tangle<T, P> abs(tangle<T, P> arg)
{
return rad(abs(rad(arg)));
}
template <typename T, precision P>
GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tangle<T, P> clamp(tangle<T, P> x, tangle<T, P> minVal, tangle<T, P> maxVal)
{
return rad(clamp(rad(x), rad(minVal), rad(maxVal)));
}
template <typename T, precision P>
GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tangle<T, P> max(tangle<T, P> lhs, tangle<T, P> rhs)
{
return rad(max(rad(lhs), rad(rhs)));
}
template <typename T, precision P>
GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tangle<T, P> min(tangle<T, P> lhs, tangle<T, P> rhs)
{
return rad(min(rad(lhs), rad(rhs)));
}
template <typename T, precision P, typename U>
GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tangle<T, P> mix(tangle<T, P> x, tangle<T, P> y, U a)
{
return rad(mix(rad(x), rad(y), a));
}
template <typename T, precision P>
GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tangle<T, P> mix(tangle<T, P> x, tangle<T, P> y, bool a)
{
return a ? y : x;
}
template <typename T, precision P>
GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tangle<T, P> mod(tangle<T, P> lhs, tangle<T, P> rhs)
{
return rad(mod(rad(lhs), rad(rhs)));
}
template <typename T, precision P>
GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ T sign(tangle<T, P> arg)
{
return sign(rad(arg));
}
//////////////////////////////////////
// Special angle functions
template <typename T, precision P>
GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tangle<T, P> normalize(tangle<T, P> arg)
{
tangle<T, P> x = mod(arg, deg(static_cast<T>(360)));
return x < deg(static_cast<T>(0)) ? x + deg(static_cast<T>(360)) : x;
}
template <typename T, precision P>
GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tangle<T, P> distance(tangle<T, P> from, tangle<T, P> to)
{
if(abs(to - from) > deg(static_cast<T>(180)))
{
return (from > to ? to + deg(static_cast<T>(360)) : to - deg(static_cast<T>(360))) - from;
}
else
{
return to - from;
}
}
//////////////////////////////////////
// Trigonometric functions
template <typename T, precision P>
GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ T cos(tangle<T, P> arg)
{
return std::cos(rad(arg));
}
template <typename T, precision P>
GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ T sin(tangle<T, P> arg)
{
return std::sin(rad(arg));
}
template <typename T, precision P>
GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ T tan(tangle<T, P> arg)
{
return std::tan(rad(arg));
}
template <typename T>
GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tangle<T> atan2(T y, T x)
{
return rad(std::atan2(y, x));
}
template <typename T, precision P>
GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tangle<T, P> atan2(tvec2<T, P> const & v)
{
return rad(std::atan2(v.y, v.x));
}
// template <typename T>
// GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tangle<T> acos(T arg)
// {
// return rad(std::acos(arg));
// }
//
// template <typename T>
// GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tangle<T> asin(T arg)
// {
// return rad(std::asin(arg));
// }
//
// template <typename T>
// GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tangle<T> atan(T arg)
// {
// return rad(std::atan(arg));
// }
//////////////////////////////////////
// GLM_GTC_matrix_transform
template<typename T, precision P>
GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tmat4x4<T, P> infinitePerspective(tangle<T, P> fovy, T aspect, T near)
{
return infinitePerspective(rad(fovy), aspect, near);
}
template<typename T, precision P>
GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tmat4x4<T, P> perspective(tangle<T, P> fovy, T aspect, T near, T far)
{
return perspective(rad(fovy), aspect, near, far);
}
template<typename T, precision P>
GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tmat4x4<T, P> perspectiveFov(tangle<T, P> fov, T width, T height, T near, T far)
{
return prespectiveFov(rad(fov), width, height, near, far);
}
template<typename T , precision P>
GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tmat4x4<T, P> rotate(tmat4x4<T, P> const & m, tangle<T, P> angle, tvec3<T, P> const & axis)
{
return rotate(m, rad(angle), axis);
}
template<typename T, precision P>
GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tmat4x4<T, P> tweakedInfinitePerspective(tangle<T, P> fovy, T aspect, T near)
{
return tweakedInfinitePerspective(rad(fovy), aspect, near);
}
template<typename T, precision P>
GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tmat4x4<T, P> tweakedInfinitePerspective(tangle<T, P> fovy, T aspect, T near, T ep)
{
return tweakedInfinitePerspective(rad(fovy), aspect, near, ep);
}
//////////////////////////////////////
// GLM_GTC_quaternion
// template<typename T, precision P>
// GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tangle<T, P> angle(tquat<T, P> const & q);
template<typename T , precision P>
GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tquat<T, P> angleAxis(tangle<T, P> angle, tvec3<T, P> const & axis)
{
return angleAxis(rad(angle), axis);
}
// template<typename T, precision P>
// GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tangle<T, P> pitch(tquat<T, P> const & q);
template<typename T , precision P>
GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tquat<T, P> rotate(tquat< T, P > const & q, tangle<T, P> angle, tvec3<T, P> const & axis)
{
return rotate(q, rad(angle), axis);
}
// template<typename T, precision P>
// GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tangle<T, P> roll(tquat<T, P> const & q);
// template<typename T, precision P>
// GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tangle<T, P> yaw(tquat<T, P> const & q);
//////////////////////////////////////
// GLM_GTX_fast_trigonometry
// template<typename T>
// GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tangle<T> fastAcos(T x);
// template<typename T>
// GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tangle<T> fastAsin(T x);
// template<typename T>
// GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tangle<T> fastAtan(T y, T x);
// template<typename T>
// GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tangle<T> fastAtan(T x);
template<typename T, precision P>
GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ T fastCos(tangle<T, P> angle)
{
return fastCos(rad(angle));
}
template<typename T, precision P>
GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ T fastSin(tangle<T, P> angle)
{
return fastSin(rad(angle));
}
template<typename T, precision P>
GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ T fastTan(tangle<T, P> angle)
{
return fastTan(rad(angle));
}
//////////////////////////////////////
// GLM_GTX_matrix_interpolation
template<typename T, precision P>
GLM_FUNC_QUALIFIER void axisAngle(tmat4x4<T, P> const & mat, tvec3<T, P> & axis, tangle<T, P> angle)
{
return axisAngle(mat, axis, rad(angle));
}
template<typename T, precision P>
GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tmat4x4<T, P> axisAngleMatrix(tvec3<T, P> const & axis, tangle<T, P> angle)
{
return axisAngleMatrix(axis, rad(angle));
}
//////////////////////////////////////
// GLM_GTX_matrix_transform_2d
template<typename T, precision P>
GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tmat3x3<T, P> rotate(tmat3x3<T, P> const & m, tangle<T, P> angle)
{
return rotate(m, rad(angle));
}
//////////////////////////////////////
// GLM_GTX_rotate_normalized_axis
template<typename T, precision P>
GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tmat4x4<T, P> rotateNormalizedAxis(tmat4x4<T, P> const & m, tangle<T, P> angle, tvec3<T, P> const & axis)
{
return rotateNormalizedAxis(m, rad(angle), axis);
}
template<typename T, precision P>
GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tquat<T, P> rotateNormalizedAxis(tquat<T, P> const & q, tangle<T, P> angle, tvec3<T, P> const & axis)
{
return rotateNormalizedAxis(q, rad(angle), axis);
}
//////////////////////////////////////
// GLM_GTX_rotate_vector
template<typename T, precision P>
GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tvec2<T, P> rotate(tvec2<T, P> const & v, tangle<T, P> angle)
{
return rotate(v, rad(angle));
}
template<typename T, precision P>
GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tvec3<T, P> rotate(tvec3<T, P> const & v, tangle<T, P> angle, tvec3<T, P> const & normal)
{
return rotate(v, rad(angle), normal);
}
template<typename T, precision P>
GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tvec4<T, P> rotate(tvec4<T, P> const & v, tangle<T, P> angle, tvec3<T, P> const & normal)
{
return rotate(v, rad(angle), normal);
}
template<typename T, precision P>
GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tvec3<T, P> rotateX(tvec3<T, P> const & v, tangle<T, P> angle)
{
return rotateX(v, rad(angle));
}
template<typename T, precision P>
GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tvec4<T, P> rotateX(tvec4<T, P> const & v, tangle<T, P> angle)
{
return rotateX(v, rad(angle));
}
template<typename T, precision P>
GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tvec3<T, P> rotateY(tvec3<T, P> const & v, tangle<T, P> angle)
{
return rotateY(v, rad(angle));
}
template<typename T, precision P>
GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tvec4<T, P> rotateY(tvec4<T, P> const & v, tangle<T, P> angle)
{
return rotateY(v, rad(angle));
}
template<typename T, precision P>
GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tvec3<T, P> rotateZ(tvec3<T, P> const & v, tangle<T, P> angle)
{
return rotateZ(v, rad(angle));
}
template<typename T, precision P>
GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tvec4<T, P> rotateZ(tvec4<T, P> const & v, tangle<T, P> angle)
{
return rotateZ(v, rad(angle));
}
//////////////////////////////////////
// GLM_GTX_transform
template<typename T, precision P>
GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tmat4x4< T, P > rotate(tangle<T, P> angle, tvec3< T, P > const & v)
{
return rotate(rad(angle), v);
}
//////////////////////////////////////
// GLM_GTX_vector_angle
// template<typename vecType>
// GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tangle<vecType::value_type> angle(vecType const & x, vecType const & y);
// template<typename T, precision P>
// GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tangle<T> orientedAngle(tvec2<T, P> const & x, tvec2<T, P> const & y);
// template<typename T, precision P>
// GLM_FUNC_QUALIFIER /*GLM_CONSTEXPR*/ tangle<T> orientedAngle(tvec3<T, P> const & x, tvec3<T, P> const & y, tvec3<T, P> const &ref);
}

View File

@ -1,3 +1,4 @@
glmCreateTestGTC(gtx_angle)
glmCreateTestGTC(gtx_associated_min_max) glmCreateTestGTC(gtx_associated_min_max)
glmCreateTestGTC(gtx_closest_point) glmCreateTestGTC(gtx_closest_point)
glmCreateTestGTC(gtx_color_space_YCoCg) glmCreateTestGTC(gtx_color_space_YCoCg)

328
test/gtx/gtx_angle.cpp Normal file
View File

@ -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 <glm/gtx/angle.hpp>
#include <glm/gtc/epsilon.hpp>
#include <algorithm>
#include <cstdlib>
#include <ctime>
namespace
{
const float pi = glm::pi<float>();
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<float>(std::max(std::rand(), 1)) / RAND_MAX;
float y = static_cast<float>(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<float>(std::max(std::rand(), 1)) / RAND_MAX;
float y = static_cast<float>(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<glm::fangle>::value, "");
static_assert(std::is_literal_type<glm::angled>::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<float>(std::max(std::rand(), 1)) / RAND_MAX;
float y = static_cast<float>(std::max(std::rand(), 1)) / RAND_MAX;
float f = static_cast<float>(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<float>(std::rand());
float y = static_cast<float>(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;
}