]> git.tdb.fi Git - libs/math.git/blob - source/geometry/angle.h
Use numeric literals in place of M_PI
[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.radians()) { }
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_turns(0.25); }
31         static Angle quarter_turn() { return right(); }
32         static Angle straight() { return from_turns(0.5); }
33         static Angle half_turn() { return straight(); }
34         static Angle full_turn() { return from_turns(1); }
35
36         T degrees() const { return value*57.2957795130823208768; }
37         T radians() const { return value; }
38         T turns() const { return value/6.28318530717958647692; }
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/57.2957795130823208768);
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*6.28318530717958647692);
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         const float two_pi = 6.28318530717958647692;
159         while(value<b.value)
160                 value += two_pi;
161         while(value>=b.value+two_pi)
162                 value -= two_pi;
163         return *this;
164 }
165
166 template<typename T>
167 inline Angle<T> &Angle<T>::wrap_positive()
168 {
169         return wrap_with_base(zero());
170 }
171
172 template<typename T>
173 inline Angle<T> &Angle<T>::wrap_balanced()
174 {
175         return wrap_with_base(-half_turn());
176 }
177
178 template<typename T>
179 inline Angle<T> wrap_with_base(const Angle<T> &a, const Angle<T> &b)
180 {
181         Angle<T> r = a;
182         return r.wrap_with_base(b);
183 }
184
185 template<typename T>
186 inline Angle<T> wrap_positive(const Angle<T> &a)
187 {
188         Angle<T> r = a;
189         return r.wrap_positive();
190 }
191
192 template<typename T>
193 inline Angle<T> wrap_balanced(const Angle<T> &a)
194 {
195         Angle<T> r = a;
196         return r.wrap_balanced();
197 }
198
199 template<typename T>
200 inline Angle<T> abs(const Angle<T> &angle)
201 {
202         using std::abs;
203         return Angle<T>::from_radians(abs(angle.radians()));
204 }
205
206 template<typename T>
207 inline T sin(const Angle<T> &angle)
208 {
209         using std::sin;
210         return sin(angle.radians());
211 }
212
213 template<typename T>
214 inline Angle<T> asin(T s)
215 {
216         using std::asin;
217         return Angle<T>::from_radians(asin(s));
218 }
219
220 template<typename T>
221 inline T cos(const Angle<T> &angle)
222 {
223         using std::cos;
224         return cos(angle.radians());
225 }
226
227 template<typename T>
228 inline Angle<T> acos(T s)
229 {
230         using std::acos;
231         return Angle<T>::from_radians(acos(s));
232 }
233
234 template<typename T>
235 inline T tan(const Angle<T> &angle)
236 {
237         using std::tan;
238         return tan(angle.radians());
239 }
240
241 template<typename T>
242 inline Angle<T> atan(T s)
243 {
244         using std::atan;
245         return Angle<T>::from_radians(atan(s));
246 }
247
248 template<typename T>
249 inline Angle<T> atan2(T y, T x)
250 {
251         using std::atan2;
252         return Angle<T>::from_radians(atan2(y, x));
253 }
254
255 } // namespace Geometry
256 } // namespace Msp
257
258 #endif