/**
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.
+specifying the units used. This eliminates a common source of errors.
*/
template<typename T>
class Angle
private:
T value;
- explicit Angle(T);
+ explicit Angle(T v): value(v) { }
public:
+ Angle(): value(0) { }
template<typename U>
- Angle(const Angle<U> &);
+ Angle(const Angle<U> &other): value(other.value) { }
static Angle from_degrees(T);
static Angle from_radians(T);
+ static Angle from_turns(T);
- static Angle right();
- static Angle quarter_circle();
- static Angle straight();
- static Angle half_circle();
- static Angle full_circle();
+ static Angle zero() { return from_radians(0); }
+ static Angle right() { return from_radians(M_PI/2); }
+ static Angle quarter_turn() { return right(); }
+ static Angle straight() { return from_radians(M_PI); }
+ static Angle half_turn() { return straight(); }
+ static Angle full_turn() { return from_radians(2*M_PI); }
- T degrees() const;
- T radians() const;
+ T degrees() const { return value*180/M_PI; }
+ T radians() const { return value; }
+ T turns() const { return value/(2*M_PI); }
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)
-{ }
+ bool operator==(const Angle &other) const { return value==other.value; }
+ bool operator!=(const Angle &other) const { return value!=other.value; }
+ bool operator<(const Angle &other) const { return value<other.value; }
+ bool operator<=(const Angle &other) const { return value<=other.value; }
+ bool operator>(const Angle &other) const { return value>other.value; }
+ bool operator>=(const Angle &other) const { return value>=other.value; }
-template<typename T>
-template<typename U>
-inline Angle<T>::Angle(const Angle<U> &other):
- value(other.value)
-{ }
+ Angle &wrap_with_base(const Angle &);
+ Angle &wrap_positive();
+ Angle &wrap_balanced();
+};
template<typename T>
inline Angle<T> Angle<T>::from_degrees(T d)
}
template<typename T>
-inline Angle<T> Angle<T>::right()
+inline Angle<T> Angle<T>::from_turns(T t)
{
- 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;
+ return Angle<T>(t*2*M_PI);
}
template<typename T>
return r -= a2;
}
+template<typename T>
+inline Angle<T> operator-(const Angle<T> &a)
+{
+ return Angle<T>::zero()-a;
+}
+
template<typename T>
inline Angle<T> &Angle<T>::operator*=(T s)
{
return a/s;
}
+template<typename T>
+inline T operator/(const Angle<T> &a1, const Angle<T> &a2)
+{
+ return a1.radians()/a2.radians();
+}
+
+template<typename T>
+inline Angle<T> &Angle<T>::wrap_with_base(const Angle<T> &b)
+{
+ while(value<b.value)
+ value += 2*M_PI;
+ while(value>=b.value+2*M_PI)
+ value -= 2*M_PI;
+ return *this;
+}
+
+template<typename T>
+inline Angle<T> &Angle<T>::wrap_positive()
+{
+ return wrap_with_base(zero());
+}
+
+template<typename T>
+inline Angle<T> &Angle<T>::wrap_balanced()
+{
+ return wrap_with_base(-half_turn());
+}
+
+template<typename T>
+inline Angle<T> wrap_with_base(const Angle<T> &a, const Angle<T> &b)
+{
+ Angle<T> r = a;
+ return r.wrap_with_base(b);
+}
+
+template<typename T>
+inline Angle<T> wrap_positive(const Angle<T> &a)
+{
+ Angle<T> r = a;
+ return r.wrap_positive();
+}
+
+template<typename T>
+inline Angle<T> wrap_balanced(const Angle<T> &a)
+{
+ Angle<T> r = a;
+ return r.wrap_balanced();
+}
+
+template<typename T>
+inline Angle<T> abs(const Angle<T> &angle)
+{
+ return Angle<T>::from_radians(std::abs(angle.radians()));
+}
+
template<typename T>
inline T sin(const Angle<T> &angle)
{