--- /dev/null
+#ifndef MSP_GEOMETRY_ANGLE_H_
+#define MSP_GEOMETRY_ANGLE_H_
+
+#include <cmath>
+
+namespace Msp {
+namespace Geometry {
+
+/**
+A planar angle. Creating an Angle from a raw value or extracting it requires
+specifying whether degrees or radians are used. This eliminates a common
+source of errors.
+*/
+template<typename T>
+class Angle
+{
+private:
+ T value;
+
+ explicit Angle(T);
+public:
+ template<typename U>
+ Angle(const Angle<U> &);
+
+ static Angle from_degrees(T);
+ static Angle from_radians(T);
+
+ static Angle right();
+ static Angle quarter_circle();
+ static Angle straight();
+ static Angle half_circle();
+ static Angle full_circle();
+
+ T degrees() const;
+ T radians() const;
+
+ Angle &operator+=(const Angle &);
+ Angle &operator-=(const Angle &);
+ Angle &operator*=(T);
+ Angle &operator/=(T);
+};
+
+template<typename T>
+inline Angle<T>::Angle(T v):
+ value(v)
+{ }
+
+template<typename T>
+template<typename U>
+inline Angle<T>::Angle(const Angle<U> &other):
+ value(other.value)
+{ }
+
+template<typename T>
+inline Angle<T> Angle<T>::from_degrees(T d)
+{
+ return Angle<T>(d*M_PI/180);
+}
+
+template<typename T>
+inline Angle<T> Angle<T>::from_radians(T r)
+{
+ return Angle<T>(r);
+}
+
+template<typename T>
+inline Angle<T> Angle<T>::right()
+{
+ return from_radians(M_PI/2);
+}
+
+template<typename T>
+inline Angle<T> Angle<T>::quarter_circle()
+{
+ return right();
+}
+
+template<typename T>
+inline Angle<T> Angle<T>::straight()
+{
+ return from_radians(M_PI);
+}
+
+template<typename T>
+inline Angle<T> Angle<T>::half_circle()
+{
+ return straight();
+}
+
+template<typename T>
+inline Angle<T> Angle<T>::full_circle()
+{
+ return from_radians(M_PI*2);
+}
+
+template<typename T>
+inline T Angle<T>::degrees() const
+{
+ return value*180/M_PI;
+}
+
+template<typename T>
+inline T Angle<T>::radians() const
+{
+ return value;
+}
+
+template<typename T>
+inline Angle<T> &Angle<T>::operator+=(const Angle &a)
+{
+ value += a.value;
+ return *this;
+}
+
+template<typename T>
+inline Angle<T> operator+(const Angle<T> &a1, const Angle<T> &a2)
+{
+ Angle<T> r(a1);
+ return r += a2;
+}
+
+template<typename T>
+inline Angle<T> &Angle<T>::operator-=(const Angle &a)
+{
+ value -= a.value;
+ return *this;
+}
+
+template<typename T>
+inline Angle<T> operator-(const Angle<T> &a1, const Angle<T> &a2)
+{
+ Angle<T> r(a1);
+ return r -= a2;
+}
+
+template<typename T>
+inline Angle<T> &Angle<T>::operator*=(T s)
+{
+ value *= s;
+ return *this;
+}
+
+template<typename T>
+inline Angle<T> operator*(const Angle<T> &a, T s)
+{
+ Angle<T> r(a);
+ return r *= s;
+}
+
+template<typename T>
+inline Angle<T> operator*(T s, const Angle<T> &a)
+{
+ return a*s;
+}
+
+template<typename T>
+inline Angle<T> &Angle<T>::operator/=(T s)
+{
+ value /= s;
+ return *this;
+}
+
+template<typename T>
+inline Angle<T> operator/(const Angle<T> &a, T s)
+{
+ Angle<T> r(a);
+ return r /= s;
+}
+
+template<typename T>
+inline Angle<T> operator/(T s, const Angle<T> &a)
+{
+ return a/s;
+}
+
+template<typename T>
+inline T sin(const Angle<T> &angle)
+{
+ return std::sin(angle.radians());
+}
+
+template<typename T>
+inline Angle<T> asin(T s)
+{
+ return Angle<T>::from_radians(std::asin(s));
+}
+
+template<typename T>
+inline T cos(const Angle<T> &angle)
+{
+ return std::cos(angle.radians());
+}
+
+template<typename T>
+inline Angle<T> acos(T s)
+{
+ return Angle<T>::from_radians(std::acos(s));
+}
+
+template<typename T>
+inline T tan(const Angle<T> &angle)
+{
+ return std::tan(angle.radians());
+}
+
+template<typename T>
+inline Angle<T> atan(T s)
+{
+ return Angle<T>::from_radians(std::atan(s));
+}
+
+template<typename T>
+inline Angle<T> atan2(T y, T x)
+{
+ return Angle<T>::from_radians(std::atan2(y, x));
+}
+
+} // namespace Geometry
+} // namespace Msp
+
+#endif