mirror of https://github.com/mosra/magnum.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
267 lines
9.3 KiB
267 lines
9.3 KiB
#ifndef Magnum_Math_Angle_h |
|
#define Magnum_Math_Angle_h |
|
/* |
|
This file is part of Magnum. |
|
|
|
Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš <mosra@centrum.cz> |
|
|
|
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. |
|
|
|
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 |
|
* @brief Class Magnum::Math::Deg, Magnum::Math::Rad and related operators. |
|
*/ |
|
|
|
#include <Utility/Debug.h> |
|
#include <corradeCompatibility.h> |
|
|
|
#include "Math/Constants.h" |
|
#include "Math/Math.h" |
|
#include "Math/Unit.h" |
|
|
|
#include "magnumVisibility.h" |
|
|
|
namespace Magnum { namespace Math { |
|
|
|
/** |
|
@brief Angle in degrees |
|
|
|
Along with Rad provides convenience classes to make angle specification and |
|
conversion less error-prone. |
|
|
|
@section Rad-usage Usage |
|
|
|
You can enter the value either by using literal: |
|
@code |
|
auto degrees = 60.0_degf; // type is Deg<Float> |
|
auto radians = 1.047_rad; // type is Rad<Double> |
|
@endcode |
|
|
|
Or explicitly convert unitless value (such as output from some function) to |
|
either degrees or radians: |
|
@code |
|
Double foo(); |
|
|
|
Deg<Float> degrees(35.0f); |
|
Rad<Double> radians(foo()); |
|
//degrees = 60.0f; // error, no implicit conversion |
|
@endcode |
|
|
|
The classes support all arithmetic operations, such as addition, subtraction |
|
or multiplication/division by unitless number: |
|
@code |
|
auto a = 60.0_degf + 17.35_degf; |
|
auto b = -a + 23.0_degf*4; |
|
//auto c = 60.0_degf*45.0_degf; // error, undefined resulting unit |
|
@endcode |
|
|
|
It is also possible to compare angles with all comparison operators, but |
|
comparison of degrees and radians is not possible without explicit conversion |
|
to common type: |
|
@code |
|
Rad<Float> angle(); |
|
|
|
Deg<Float> x = angle(); // convert to degrees for easier comparison |
|
if(x < 30.0_degf) foo(); |
|
//if(x > 1.57_radf) bar(); // error, both need to be of the same type |
|
@endcode |
|
|
|
It is possible to seamlessly convert between degrees and radians and explicitly |
|
convert the value back to underlying type: |
|
@code |
|
Float sine(Rad<Float> angle); |
|
Float a = sine(60.0_degf); // the same as sine(1.047_radf) |
|
Deg<Double> b = 1.047_rad; // the same as 60.0_deg |
|
Float d = Double(b); // 60.0 |
|
//Float e = b; // error, no implicit conversion |
|
@endcode |
|
|
|
@section Rad-conversions Requirement of explicit conversion |
|
|
|
The requirement of explicit conversions from and to unitless types helps to |
|
reduce unit-based errors. Consider following example with implicit conversions |
|
allowed: |
|
@code |
|
Float std::sin(Float angle); |
|
Float sine(Rad<Float> angle); |
|
|
|
Float a = 60.0f; // degrees |
|
sine(a); // silent error, sine() expected radians |
|
|
|
auto b = 60.0_degf; // degrees |
|
std::sin(b); // silent error, std::sin() expected radians |
|
@endcode |
|
|
|
These silent errors are easily avoided by requiring explicit conversions: |
|
@code |
|
//sine(angleInDegrees); // compilation error |
|
sine(Deg<Float>(angleInDegrees)); // explicitly specifying unit |
|
|
|
//std::sin(angleInDegrees); // compilation error |
|
std::sin(Float(Rad<Float>(angleInDegrees)); // required explicit conversion hints |
|
// to user that this case needs special |
|
// attention (i.e., conversion to radians) |
|
@endcode |
|
|
|
@see Magnum::Deg, Magnum::Degd |
|
*/ |
|
template<class T> class Deg: public Unit<Deg, T> { |
|
public: |
|
/** @brief Default constructor */ |
|
constexpr /*implicit*/ Deg() {} |
|
|
|
/** @brief Explicit constructor from unitless type */ |
|
constexpr explicit Deg(T value): Unit<Math::Deg, T>(value) {} |
|
|
|
/** @brief Copy constructor */ |
|
constexpr /*implicit*/ Deg(Unit<Math::Deg, T> value): Unit<Math::Deg, T>(value) {} |
|
|
|
/** @brief Construct from another underlying type */ |
|
template<class U> constexpr explicit Deg(Unit<Math::Deg, U> value): Unit<Math::Deg, T>(value) {} |
|
|
|
/** |
|
* @brief Construct degrees from radians |
|
* |
|
* Performs conversion from radians to degrees, i.e.: |
|
* @f[ |
|
* deg = 180 \frac {rad} \pi |
|
* @f] |
|
*/ |
|
constexpr /*implicit*/ Deg(Unit<Rad, T> value); |
|
}; |
|
|
|
#ifndef CORRADE_GCC46_COMPATIBILITY |
|
#ifndef MAGNUM_TARGET_GLES |
|
/** @relates Deg |
|
@brief Double-precision degree value literal |
|
|
|
Example usage: |
|
@code |
|
Double cosine = Math::cos(60.0_deg); // cosine = 0.5 |
|
Double cosine = Math::cos(1.047_rad); // cosine = 0.5 |
|
@endcode |
|
@see Magnum::operator""_deg(), operator""_degf(), operator""_rad() |
|
@note Not available on GCC < 4.7. Use Deg::Deg(T) instead. |
|
@requires_gl Only single-precision types are available in OpenGL ES. |
|
*/ |
|
constexpr Deg<Double> operator "" _deg(long double value) { return Deg<Double>(value); } |
|
#endif |
|
|
|
/** @relates Deg |
|
@brief Single-precision degree value literal |
|
|
|
Example usage: |
|
@code |
|
Float tangent = Math::tan(60.0_degf); // tangent = 1.732f |
|
Float tangent = Math::tan(1.047_radf); // tangent = 1.732f |
|
@endcode |
|
@see Magnum::operator""_degf(), operator""_deg(), operator""_radf() |
|
@note Not available on GCC < 4.7. Use Deg::Deg(T) instead. |
|
@requires_gl Only single-precision types are available in OpenGL ES. |
|
*/ |
|
constexpr Deg<Float> operator "" _degf(long double value) { return Deg<Float>(value); } |
|
#endif |
|
|
|
/** |
|
@brief Angle in radians |
|
|
|
See Deg for more information. |
|
@see Magnum::Rad, Magnum::Radd |
|
*/ |
|
template<class T> class Rad: public Unit<Rad, T> { |
|
public: |
|
/** @brief Default constructor */ |
|
constexpr /*implicit*/ Rad() {} |
|
|
|
/** @brief Construct from unitless type */ |
|
constexpr explicit Rad(T value): Unit<Math::Rad, T>(value) {} |
|
|
|
/** @brief Copy constructor */ |
|
constexpr /*implicit*/ Rad(Unit<Math::Rad, T> value): Unit<Math::Rad, T>(value) {} |
|
|
|
/** @brief Construct from another underlying type */ |
|
template<class U> constexpr explicit Rad(Unit<Math::Rad, U> value): Unit<Math::Rad, T>(value) {} |
|
|
|
/** |
|
* @brief Construct radians from degrees |
|
* |
|
* Performs conversion from degrees to radians, i.e.: |
|
* @f[ |
|
* rad = deg \frac \pi 180 |
|
* @f] |
|
*/ |
|
constexpr /*implicit*/ Rad(Unit<Deg, T> value); |
|
}; |
|
|
|
#ifndef CORRADE_GCC46_COMPATIBILITY |
|
#ifndef MAGNUM_TARGET_GLES |
|
/** @relates Rad |
|
@brief Double-precision radian value literal |
|
|
|
See operator""_rad() for more information. |
|
@see Magnum::operator""_rad(), operator""_radf(), operator""_deg() |
|
@note Not available on GCC < 4.7. Use Rad::Rad(T) instead. |
|
*/ |
|
constexpr Rad<Double> operator "" _rad(long double value) { return Rad<Double>(value); } |
|
#endif |
|
|
|
/** @relates Rad |
|
@brief Single-precision radian value literal |
|
|
|
See operator""_degf() for more information. |
|
@see Magnum::operator""_radf(), operator""_rad(), operator""_degf() |
|
@note Not available on GCC < 4.7. Use Rad::Rad(T) instead. |
|
*/ |
|
constexpr Rad<Float> operator "" _radf(long double value) { return Rad<Float>(value); } |
|
#endif |
|
|
|
template<class T> constexpr Deg<T>::Deg(Unit<Rad, T> value): Unit<Math::Deg, T>(T(180)*T(value)/Math::Constants<T>::pi()) {} |
|
template<class T> constexpr Rad<T>::Rad(Unit<Deg, T> value): Unit<Math::Rad, T>(T(value)*Math::Constants<T>::pi()/T(180)) {} |
|
|
|
/** @debugoperator{Magnum::Math::Rad} */ |
|
template<class T> Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Unit<Rad, T>& value) { |
|
debug << "Rad("; |
|
debug.setFlag(Corrade::Utility::Debug::SpaceAfterEachValue, false); |
|
debug << T(value) << ")"; |
|
debug.setFlag(Corrade::Utility::Debug::SpaceAfterEachValue, true); |
|
return debug; |
|
} |
|
|
|
/** @debugoperator{Magnum::Math::Deg} */ |
|
template<class T> Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Unit<Deg, T>& value) { |
|
debug << "Deg("; |
|
debug.setFlag(Corrade::Utility::Debug::SpaceAfterEachValue, false); |
|
debug << T(value) << ")"; |
|
debug.setFlag(Corrade::Utility::Debug::SpaceAfterEachValue, true); |
|
return debug; |
|
} |
|
|
|
/* Explicit instantiation for commonly used types */ |
|
#ifndef DOXYGEN_GENERATING_OUTPUT |
|
extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const Unit<Rad, Float>&); |
|
extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const Unit<Deg, Float>&); |
|
#ifndef MAGNUM_TARGET_GLES |
|
extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const Unit<Rad, Double>&); |
|
extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const Unit<Deg, Double>&); |
|
#endif |
|
#endif |
|
|
|
}} |
|
|
|
#endif
|
|
|