#ifndef Magnum_Math_Angle_h #define Magnum_Math_Angle_h /* Copyright © 2010, 2011, 2012 Vladimír Vondruš This file is part of Magnum. Magnum is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License version 3 only, as published by the Free Software Foundation. Magnum is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License version 3 for more details. */ /** @file * @brief Class Magnum::Math::Deg, Magnum::Math::Rad and related operators. */ #include #include #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 auto radians = 1.047_rad; // type is Rad @endcode Or explicitly convert unitless value (such as output from some function) to either degrees or radians: @code Double foo(); Deg degrees(35.0f); Rad 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 angle(); Deg 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 angle); Float a = sine(60.0_degf); // the same as sine(1.047_radf) Deg 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 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(angleInDegrees)); // explicitly specifying unit //std::sin(angleInDegrees); // compilation error std::sin(Float(Rad(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 Deg: public Unit { public: /** @brief Default constructor */ inline constexpr /*implicit*/ Deg() {} /** @brief Explicit constructor from unitless type */ inline constexpr explicit Deg(T value): Unit(value) {} /** @brief Copy constructor */ inline constexpr /*implicit*/ Deg(Unit value): Unit(value) {} /** @brief Construct from another underlying type */ template inline constexpr explicit Deg(Unit value): Unit(value) {} /** * @brief Construct degrees from radians * * Performs conversion from radians to degrees, i.e.: * @f[ * deg = 180 \frac {rad} \pi * @f] */ inline constexpr /*implicit*/ Deg(Unit value); }; #ifndef CORRADE_GCC46_COMPATIBILITY /** @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. */ inline constexpr Deg operator "" _deg(long double value) { return Deg(value); } /** @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. */ inline constexpr Deg operator "" _degf(long double value) { return Deg(value); } #endif /** @brief Angle in radians See Deg for more information. @see Magnum::Rad, Magnum::Radd */ template class Rad: public Unit { public: /** @brief Default constructor */ inline constexpr /*implicit*/ Rad() {} /** @brief Construct from unitless type */ inline constexpr explicit Rad(T value): Unit(value) {} /** @brief Copy constructor */ inline constexpr /*implicit*/ Rad(Unit value): Unit(value) {} /** @brief Construct from another underlying type */ template inline constexpr explicit Rad(Unit value): Unit(value) {} /** * @brief Construct radians from degrees * * Performs conversion from degrees to radians, i.e.: * @f[ * rad = deg \frac \pi 180 * @f] */ inline constexpr /*implicit*/ Rad(Unit value); }; #ifndef CORRADE_GCC46_COMPATIBILITY /** @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. */ inline constexpr Rad operator "" _rad(long double value) { return Rad(value); } /** @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. */ inline constexpr Rad operator "" _radf(long double value) { return Rad(value); } #endif template inline constexpr Deg::Deg(Unit value): Unit(T(180)*T(value)/Math::Constants::pi()) {} template inline constexpr Rad::Rad(Unit value): Unit(T(value)*Math::Constants::pi()/T(180)) {} /** @debugoperator{Magnum::Math::Rad} */ template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Unit& 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 Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Unit& 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&); extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const Unit&); #ifndef MAGNUM_TARGET_GLES extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const Unit&); extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const Unit&); #endif #endif }} #endif