sandbox
Loading...
Searching...
No Matches
angle.hpp
1#ifndef LIBSBX_MATH_ANGLE_HPP_
2#define LIBSBX_MATH_ANGLE_HPP_
3
4#include <cmath>
5#include <concepts>
6#include <numbers>
7
8#include <libsbx/math/concepts.hpp>
9
10namespace sbx::math {
11
12template<floating_point Type>
14
15public:
16
17 using value_type = Type;
18
19 inline static constexpr basic_degree min{value_type{0}};
20 inline static constexpr basic_degree max{value_type{360}};
21
22 constexpr basic_degree() = default;
23
24 template<scalar Other>
25 requires (std::is_convertible_v<Other, Type>)
26 constexpr basic_degree(const Other value) noexcept
27 : _value{static_cast<Type>(value)} { }
28
29 template<floating_point Other>
30 requires (std::is_convertible_v<Other, Type>)
31 constexpr basic_degree(const basic_degree<Other>& other) noexcept
32 : _value{static_cast<Type>(other._value)} { }
33
34 constexpr ~basic_degree() noexcept = default;
35
36 template<floating_point Other>
37 requires (std::is_convertible_v<Other, Type>)
38 constexpr auto operator=(const basic_degree<Other>& other) noexcept -> basic_degree<Type>& {
39 _value = static_cast<Type>(other._value);
40
41 return *this;
42 }
43
44 template<floating_point Other>
45 requires (std::is_convertible_v<Other, Type>)
46 constexpr auto operator+=(const basic_degree<Other>& rhs) noexcept -> basic_degree<Type>& {
47 _value += static_cast<Type>(rhs._value);
48
49 return *this;
50 }
51
52 template<floating_point Other>
53 requires (std::is_convertible_v<Other, Type>)
54 constexpr auto operator-=(const basic_degree<Other>& rhs) noexcept -> basic_degree<Type>& {
55 _value -= static_cast<Type>(rhs._value);
56
57 return *this;
58 }
59
60 template<floating_point Other>
61 requires (std::is_convertible_v<Other, Type>)
62 constexpr auto operator*=(const Other rhs) noexcept -> basic_degree<Type>& {
63 _value *= static_cast<Type>(rhs);
64
65 return *this;
66 }
67
68 template<floating_point Other>
69 requires (std::is_convertible_v<Other, Type>)
70 constexpr auto operator/=(const Other rhs) noexcept -> basic_degree<Type>& {
71 _value /= static_cast<Type>(rhs);
72
73 return *this;
74 }
75
76 constexpr auto value() const noexcept -> value_type {
77 return _value;
78 }
79
80 constexpr operator value_type() const noexcept {
81 return _value;
82 }
83
84private:
85
86 value_type _value{};
87
88}; // class basic_degree
89
90template<floating_point Type>
91constexpr auto operator==(const basic_degree<Type>& lhs, const basic_degree<Type>& rhs) noexcept -> bool {
92 return static_cast<basic_degree<Type>::value_type>(lhs) == static_cast<basic_degree<Type>::value_type>(rhs);
93}
94
95template<floating_point Type, floating_point Other>
96constexpr auto operator<=>(const basic_degree<Type>& lhs, const basic_degree<Other>& rhs) noexcept -> std::partial_ordering {
97 return static_cast<basic_degree<Type>::value_type>(lhs) <=> static_cast<basic_degree<Type>::value_type>(rhs);
98}
99
100template<floating_point Type, floating_point Other>
101requires (std::is_convertible_v<Other, Type>)
102constexpr auto operator+(basic_degree<Type> lhs, const basic_degree<Other>& rhs) noexcept -> basic_degree<Type> {
103 return lhs += rhs;
104}
105
106template<floating_point Type, floating_point Other>
107requires (std::is_convertible_v<Other, Type>)
108constexpr auto operator-(basic_degree<Type> lhs, const basic_degree<Other>& rhs) noexcept -> basic_degree<Type> {
109 return lhs -= rhs;
110}
111
112template<floating_point Type, std::convertible_to<Type> Other>
113constexpr auto operator*(basic_degree<Type> lhs, const Other rhs) noexcept -> basic_degree<Type> {
114 return lhs *= static_cast<Type>(rhs);
115}
116
117template<floating_point Type, std::convertible_to<Type> Other>
118constexpr auto operator/(basic_degree<Type> lhs, const Other rhs) noexcept -> basic_degree<Type> {
119 return lhs /= static_cast<Type>(rhs);
120}
121
122template<floating_point Type>
123constexpr auto clamp(const basic_degree<Type>& value, const basic_degree<Type>& min, const basic_degree<Type>& max) -> const basic_degree<Type>& {
124 if (value < min) {
125 return min;
126 }
127
128 if (value > max) {
129 return max;
130 }
131
132 return value;
133}
134
135using degree = basic_degree<std::float_t>;
136
137template<floating_point Type>
139
140public:
141
142 using value_type = Type;
143
144 inline static constexpr basic_radian min{value_type{0}};
145 inline static constexpr basic_radian max{value_type{2 * std::numbers::pi_v<value_type>}};
146
147 constexpr basic_radian() = default;
148
149 template<scalar Other>
150 requires (std::is_convertible_v<Other, Type>)
151 constexpr basic_radian(const Other value) noexcept
152 : _value{static_cast<Type>(value)} { }
153
154 template<floating_point Other>
155 requires (std::is_convertible_v<Other, Type>)
156 constexpr basic_radian(const basic_radian<Other>& other) noexcept
157 : _value{static_cast<Type>(other._value)} { }
158
159 constexpr ~basic_radian() noexcept = default;
160
161 template<floating_point Other>
162 requires (std::is_convertible_v<Other, Type>)
163 constexpr auto operator=(const basic_radian<Other>& other) noexcept -> basic_radian<Type>& {
164 _value = static_cast<Type>(other._value);
165
166 return *this;
167 }
168
169 template<floating_point Other>
170 requires (std::is_convertible_v<Other, Type>)
171 constexpr auto operator+=(const basic_radian<Other>& rhs) noexcept -> basic_radian<Type>& {
172 _value += static_cast<Type>(rhs._value);
173
174 return *this;
175 }
176
177 template<floating_point Other>
178 requires (std::is_convertible_v<Other, Type>)
179 constexpr auto operator-=(const basic_radian<Other>& rhs) noexcept -> basic_radian<Type>& {
180 _value -= static_cast<Type>(rhs._value);
181
182 return *this;
183 }
184
185 template<floating_point Other>
186 requires (std::is_convertible_v<Other, Type>)
187 constexpr auto operator*=(const Other rhs) noexcept -> basic_radian<Type>& {
188 _value *= static_cast<Type>(rhs);
189
190 return *this;
191 }
192
193 constexpr auto value() const noexcept -> value_type {
194 return _value;
195 }
196
197 constexpr operator value_type() const noexcept {
198 return _value;
199 }
200
201private:
202
203 value_type _value{};
204
205}; // class basic_radian
206
207template<floating_point Type>
208constexpr auto operator==(const basic_radian<Type>& lhs, const basic_radian<Type>& rhs) noexcept -> bool {
209 return static_cast<basic_radian<Type>::value_type>(lhs) == static_cast<basic_radian<Type>::value_type>(rhs);
210}
211
212template<floating_point Type, floating_point Other>
213constexpr auto operator<=>(const basic_radian<Type>& lhs, const basic_radian<Other>& rhs) noexcept -> std::partial_ordering {
214 return static_cast<basic_radian<Type>::value_type>(lhs) <=> static_cast<basic_radian<Type>::value_type>(rhs);
215}
216
217template<floating_point Type, floating_point Other>
218requires (std::is_convertible_v<Other, Type>)
219constexpr auto operator+(basic_radian<Type> lhs, const basic_radian<Other>& rhs) noexcept -> basic_radian<Type> {
220 return lhs += rhs;
221}
222
223template<floating_point Type, floating_point Other>
224requires (std::is_convertible_v<Other, Type>)
225constexpr auto operator-(basic_radian<Type> lhs, const basic_radian<Other>& rhs) noexcept -> basic_radian<Type> {
226 return lhs -= rhs;
227}
228
229template<floating_point Type, std::convertible_to<Type> Other>
230requires (std::is_convertible_v<Other, Type>)
231constexpr auto operator*(basic_radian<Type> lhs, const Other rhs) noexcept -> basic_radian<Type> {
232 return lhs *= static_cast<Type>(rhs);
233}
234
235template<floating_point Type>
236constexpr auto clamp(const basic_radian<Type>& value, const basic_radian<Type>& min, const basic_radian<Type>& max) -> const basic_radian<Type>& {
237 if (value < min) {
238 return min;
239 }
240
241 if (value > max) {
242 return max;
243 }
244
245 return value;
246}
247
248using radian = basic_radian<std::float_t>;
249
250template<floating_point Type>
252
253public:
254
255 using value_type = Type;
256
257 constexpr basic_angle(const basic_degree<value_type>& degree) noexcept
258 : _radian{degree.value() * std::numbers::pi_v<value_type> / static_cast<value_type>(180)} {}
259
260 constexpr basic_angle(const basic_radian<value_type>& radian) noexcept
261 : _radian{radian} { }
262
263 template<floating_point Other>
264 requires (std::is_convertible_v<Other, Type>)
265 constexpr basic_angle(const basic_angle<Other>& other) noexcept
266 : _radian{other._radian} { }
267
268 template<floating_point Other>
269 requires (std::is_convertible_v<Other, Type>)
270 constexpr auto operator+=(const basic_angle<Other>& other) noexcept -> basic_angle<Type>& {
271 _radian += basic_radian<Type>{other._radian};
272
273 return *this;
274 }
275
276 template<floating_point Other>
277 requires (std::is_convertible_v<Other, Type>)
278 constexpr auto operator+=(const basic_degree<Other>& other) noexcept -> basic_angle<Type>& {
279 return (*this += basic_angle<Other>{other});
280 }
281
282 template<floating_point Other>
283 requires (std::is_convertible_v<Other, Type>)
284 constexpr auto operator+=(const basic_radian<Other>& other) noexcept -> basic_angle<Type>& {
285 return (*this += basic_angle<Other>{other});
286 }
287
288 template<floating_point Other>
289 requires (std::is_convertible_v<Other, Type>)
290 constexpr auto operator-=(const basic_angle<Other>& other) noexcept -> basic_angle<Type>& {
291 _radian -= basic_radian<Type>{other._radian};
292
293 return *this;
294 }
295
296 template<floating_point Other>
297 requires (std::is_convertible_v<Other, Type>)
298 constexpr auto operator-=(const basic_degree<Other>& other) noexcept -> basic_angle<Type>& {
299 return (*this -= basic_angle<Other>{other});
300 }
301
302 template<floating_point Other>
303 requires (std::is_convertible_v<Other, Type>)
304 constexpr auto operator-=(const basic_radian<Other>& other) noexcept -> basic_angle<Type>& {
305 return (*this -= basic_angle<Other>{other});
306 }
307
308 template<floating_point Other>
309 requires (std::is_convertible_v<Other, Type>)
310 constexpr auto operator*=(const Other other) noexcept -> basic_angle<Type>& {
311 _radian = basic_radian<Type>{_radian.value() * static_cast<Type>(other)};
312
313 return *this;
314 }
315
316 constexpr auto to_degrees() const noexcept -> basic_degree<value_type> {
317 return basic_degree<value_type>{_radian.value() * static_cast<value_type>(180) / std::numbers::pi_v<value_type>};
318 }
319
320 constexpr auto to_radians() const noexcept -> basic_radian<value_type> {
321 return _radian;
322 }
323
324private:
325
326 basic_radian<Type> _radian{};
327
328}; // class basic_angle
329
330template<floating_point Type>
331constexpr auto operator==(const basic_angle<Type>& lhs, const basic_angle<Type>& rhs) noexcept -> bool {
332 return lhs.to_radians() == rhs.to_radians();
333}
334
335template<floating_point Type, floating_point Other>
336constexpr auto operator<=>(const basic_angle<Type>& lhs, const basic_angle<Other>& rhs) noexcept -> std::partial_ordering {
337 return lhs.to_radians() <=> rhs.to_radians();
338}
339
340template<floating_point LhsType, floating_point RhsType>
341requires (std::is_convertible_v<RhsType, LhsType>)
342constexpr auto operator+(basic_angle<LhsType> lhs, const basic_angle<RhsType>& rhs) noexcept -> basic_angle<LhsType> {
343 return lhs += rhs;
344}
345
346template<floating_point LhsType, floating_point RhsType>
347requires (std::is_convertible_v<RhsType, LhsType>)
348constexpr auto operator+(basic_angle<LhsType> lhs, const basic_degree<RhsType>& rhs) noexcept -> basic_angle<LhsType> {
349 return lhs += basic_angle<LhsType>(rhs);
350}
351
352template<floating_point LhsType, floating_point RhsType>
353requires (std::is_convertible_v<RhsType, LhsType>)
354constexpr auto operator+(basic_angle<LhsType> lhs, const basic_radian<RhsType>& rhs) noexcept -> basic_angle<LhsType> {
355 return lhs += basic_angle<LhsType>(rhs);
356}
357
358template<floating_point LhsType, floating_point RhsType>
359requires (std::is_convertible_v<RhsType, LhsType>)
360constexpr auto operator-(basic_angle<LhsType> lhs, const basic_angle<RhsType>& rhs) noexcept -> basic_angle<LhsType> {
361 return lhs -= rhs;
362}
363
364template<floating_point LhsType, floating_point RhsType>
365requires (std::is_convertible_v<RhsType, LhsType>)
366constexpr auto operator*(basic_angle<LhsType> lhs, const RhsType rhs) noexcept -> basic_angle<LhsType> {
367 return lhs *= rhs;
368}
369
370template<floating_point Type>
371constexpr auto clamp(const basic_angle<Type>& value, const basic_angle<Type>& min, const basic_angle<Type>& max) -> const basic_angle<Type>& {
372 if (value < min) {
373 return min;
374 }
375
376 if (value > max) {
377 return max;
378 }
379
380 return value;
381}
382
383using angle = basic_angle<std::float_t>;
384
385template<floating_point Type>
386constexpr auto to_degrees(const basic_radian<Type>& radian) noexcept -> basic_degree<Type> {
387 return basic_angle<Type>{radian}.to_degrees();
388}
389
390template<floating_point Type>
391constexpr auto to_radians(const basic_degree<Type>& degree) noexcept -> basic_radian<Type> {
392 return basic_angle<Type>{degree}.to_radians();
393}
394
395namespace literals {
396
397constexpr auto operator""_deg(long double value) noexcept -> degree {
398 return degree{static_cast<std::float_t>(value)};
399}
400
401constexpr auto operator""_deg(unsigned long long value) noexcept -> degree {
402 return degree{static_cast<std::float_t>(value)};
403}
404
405constexpr auto operator""_rad(long double value) noexcept -> radian {
406 return radian{static_cast<std::float_t>(value)};
407}
408
409constexpr auto operator""_rad(unsigned long long value) noexcept -> radian {
410 return radian{static_cast<std::float_t>(value)};
411}
412
413} // namespace literals
414
415} // namespace sbx::math
416
417#endif // LIBSBX_MATH_ANGLE_HPP_
Definition: angle.hpp:251
Definition: angle.hpp:13
Definition: angle.hpp:138