]> git.tdb.fi Git - libs/math.git/blob - source/geometry/angle.h
Improvements to the Angle class
[libs/math.git] / source / geometry / angle.h
1 #ifndef MSP_GEOMETRY_ANGLE_H_
2 #define MSP_GEOMETRY_ANGLE_H_
3
4 #include <cmath>
5
6 namespace Msp {
7 namespace Geometry {
8
9 /**
10 A planar angle.  Creating an Angle from a raw value or extracting it requires
11 specifying the units used.  This eliminates a common source of errors.
12 */
13 template<typename T>
14 class Angle
15 {
16 private:
17         T value;
18
19         explicit Angle(T v): value(v) { }
20 public:
21         Angle(): value(0) { }
22         template<typename U>
23         Angle(const Angle<U> &other): value(other.value) { }
24
25         static Angle from_degrees(T);
26         static Angle from_radians(T);
27         static Angle from_turns(T);
28
29         static Angle zero() { return from_radians(0); }
30         static Angle right() { return from_radians(M_PI/2); }
31         static Angle quarter_turn() { return right(); }
32         static Angle straight() { return from_radians(M_PI); }
33         static Angle half_turn() { return straight(); }
34         static Angle full_turn() { return from_radians(2*M_PI); }
35
36         T degrees() const { return value*180/M_PI; }
37         T radians() const { return value; }
38         T turns() const { return value/(2*M_PI); }
39
40         Angle &operator+=(const Angle &);
41         Angle &operator-=(const Angle &);
42         Angle &operator*=(T);
43         Angle &operator/=(T);
44
45         bool operator==(const Angle &other) const { return value==other.value; }
46         bool operator!=(const Angle &other) const { return value!=other.value; }
47         bool operator<(const Angle &other) const { return value<other.value; }
48         bool operator<=(const Angle &other) const { return value<=other.value; }
49         bool operator>(const Angle &other) const { return value>other.value; }
50         bool operator>=(const Angle &other) const { return value>=other.value; }
51
52         Angle &wrap_with_base(const Angle &);
53         Angle &wrap_positive();
54         Angle &wrap_balanced();
55 };
56
57 template<typename T>
58 inline Angle<T> Angle<T>::from_degrees(T d)
59 {
60         return Angle<T>(d*M_PI/180);
61 }
62
63 template<typename T>
64 inline Angle<T> Angle<T>::from_radians(T r)
65 {
66         return Angle<T>(r);
67 }
68
69 template<typename T>
70 inline Angle<T> Angle<T>::from_turns(T t)
71 {
72         return Angle<T>(t*2*M_PI);
73 }
74
75 template<typename T>
76 inline Angle<T> &Angle<T>::operator+=(const Angle &a)
77 {
78         value += a.value;
79         return *this;
80 }
81
82 template<typename T>
83 inline Angle<T> operator+(const Angle<T> &a1, const Angle<T> &a2)
84 {
85         Angle<T> r(a1);
86         return r += a2;
87 }
88
89 template<typename T>
90 inline Angle<T> &Angle<T>::operator-=(const Angle &a)
91 {
92         value -= a.value;
93         return *this;
94 }
95
96 template<typename T>
97 inline Angle<T> operator-(const Angle<T> &a1, const Angle<T> &a2)
98 {
99         Angle<T> r(a1);
100         return r -= a2;
101 }
102
103 template<typename T>
104 inline Angle<T> operator-(const Angle<T> &a)
105 {
106         return Angle<T>::zero()-a;
107 }
108
109 template<typename T>
110 inline Angle<T> &Angle<T>::operator*=(T s)
111 {
112         value *= s;
113         return *this;
114 }
115
116 template<typename T>
117 inline Angle<T> operator*(const Angle<T> &a, T s)
118 {
119         Angle<T> r(a);
120         return r *= s;
121 }
122
123 template<typename T>
124 inline Angle<T> operator*(T s, const Angle<T> &a)
125 {
126         return a*s;
127 }
128
129 template<typename T>
130 inline Angle<T> &Angle<T>::operator/=(T s)
131 {
132         value /= s;
133         return *this;
134 }
135
136 template<typename T>
137 inline Angle<T> operator/(const Angle<T> &a, T s)
138 {
139         Angle<T> r(a);
140         return r /= s;
141 }
142
143 template<typename T>
144 inline Angle<T> operator/(T s, const Angle<T> &a)
145 {
146         return a/s;
147 }
148
149 template<typename T>
150 inline T operator/(const Angle<T> &a1, const Angle<T> &a2)
151 {
152         return a1.radians()/a2.radians();
153 }
154
155 template<typename T>
156 inline Angle<T> &Angle<T>::wrap_with_base(const Angle<T> &b)
157 {
158         while(value<b.value)
159                 value += 2*M_PI;
160         while(value>=b.value+2*M_PI)
161                 value -= 2*M_PI;
162         return *this;
163 }
164
165 template<typename T>
166 inline Angle<T> &Angle<T>::wrap_positive()
167 {
168         return wrap_with_base(zero());
169 }
170
171 template<typename T>
172 inline Angle<T> &Angle<T>::wrap_balanced()
173 {
174         return wrap_with_base(-half_turn());
175 }
176
177 template<typename T>
178 inline Angle<T> wrap_with_base(const Angle<T> &a, const Angle<T> &b)
179 {
180         Angle<T> r = a;
181         return r.wrap_with_base(b);
182 }
183
184 template<typename T>
185 inline Angle<T> wrap_positive(const Angle<T> &a)
186 {
187         Angle<T> r = a;
188         return r.wrap_positive();
189 }
190
191 template<typename T>
192 inline Angle<T> wrap_balanced(const Angle<T> &a)
193 {
194         Angle<T> r = a;
195         return r.wrap_balanced();
196 }
197
198 template<typename T>
199 inline Angle<T> abs(const Angle<T> &angle)
200 {
201         return Angle<T>::from_radians(std::abs(angle.radians()));
202 }
203
204 template<typename T>
205 inline T sin(const Angle<T> &angle)
206 {
207         return std::sin(angle.radians());
208 }
209
210 template<typename T>
211 inline Angle<T> asin(T s)
212 {
213         return Angle<T>::from_radians(std::asin(s));
214 }
215
216 template<typename T>
217 inline T cos(const Angle<T> &angle)
218 {
219         return std::cos(angle.radians());
220 }
221
222 template<typename T>
223 inline Angle<T> acos(T s)
224 {
225         return Angle<T>::from_radians(std::acos(s));
226 }
227
228 template<typename T>
229 inline T tan(const Angle<T> &angle)
230 {
231         return std::tan(angle.radians());
232 }
233
234 template<typename T>
235 inline Angle<T> atan(T s)
236 {
237         return Angle<T>::from_radians(std::atan(s));
238 }
239
240 template<typename T>
241 inline Angle<T> atan2(T y, T x)
242 {
243         return Angle<T>::from_radians(std::atan2(y, x));
244 }
245
246 } // namespace Geometry
247 } // namespace Msp
248
249 #endif