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#include <libsbx/math/smooth_value.hpp>
10
11namespace sbx::math {
12
13template<floating_point Type>
15
16public:
17
18 using value_type = Type;
19
20 inline static constexpr basic_degree min{value_type{0}};
21 inline static constexpr basic_degree max{value_type{360}};
22
23 constexpr basic_degree() = default;
24
25 template<scalar Other>
26 requires (std::is_convertible_v<Other, Type>)
27 constexpr basic_degree(const Other value) noexcept
28 : _value{static_cast<Type>(value)} { }
29
30 template<floating_point Other>
31 requires (std::is_convertible_v<Other, Type>)
32 constexpr basic_degree(const basic_degree<Other>& other) noexcept
33 : _value{static_cast<Type>(other._value)} { }
34
35 constexpr ~basic_degree() noexcept = default;
36
37 template<floating_point Other>
38 requires (std::is_convertible_v<Other, Type>)
39 constexpr auto operator=(const basic_degree<Other>& other) noexcept -> basic_degree<Type>& {
40 _value = static_cast<Type>(other._value);
41
42 return *this;
43 }
44
45 template<floating_point Other>
46 requires (std::is_convertible_v<Other, Type>)
47 constexpr auto operator+=(const basic_degree<Other>& rhs) noexcept -> basic_degree<Type>& {
48 _value += static_cast<Type>(rhs._value);
49
50 return *this;
51 }
52
53 template<floating_point Other>
54 requires (std::is_convertible_v<Other, Type>)
55 constexpr auto operator-=(const basic_degree<Other>& rhs) noexcept -> basic_degree<Type>& {
56 _value -= static_cast<Type>(rhs._value);
57
58 return *this;
59 }
60
61 template<floating_point Other>
62 requires (std::is_convertible_v<Other, Type>)
63 constexpr auto operator*=(const Other rhs) noexcept -> basic_degree<Type>& {
64 _value *= static_cast<Type>(rhs);
65
66 return *this;
67 }
68
69 template<floating_point Other>
70 requires (std::is_convertible_v<Other, Type>)
71 constexpr auto operator/=(const Other rhs) noexcept -> basic_degree<Type>& {
72 _value /= static_cast<Type>(rhs);
73
74 return *this;
75 }
76
77 constexpr auto value() const noexcept -> value_type {
78 return _value;
79 }
80
81 constexpr operator value_type() const noexcept {
82 return _value;
83 }
84
85 constexpr auto data() noexcept -> value_type* {
86 return &_value;
87 }
88
89private:
90
91 value_type _value{};
92
93}; // class basic_degree
94
95template<floating_point Type>
96constexpr auto operator==(const basic_degree<Type>& lhs, const basic_degree<Type>& rhs) noexcept -> bool {
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>
101constexpr auto operator<=>(const basic_degree<Type>& lhs, const basic_degree<Other>& rhs) noexcept -> std::partial_ordering {
102 return static_cast<basic_degree<Type>::value_type>(lhs) <=> static_cast<basic_degree<Type>::value_type>(rhs);
103}
104
105template<floating_point Type, floating_point Other>
106requires (std::is_convertible_v<Other, Type>)
107constexpr auto operator+(basic_degree<Type> lhs, const basic_degree<Other>& rhs) noexcept -> basic_degree<Type> {
108 return lhs += rhs;
109}
110
111template<floating_point Type, floating_point Other>
112requires (std::is_convertible_v<Other, Type>)
113constexpr auto operator-(basic_degree<Type> lhs, const basic_degree<Other>& rhs) noexcept -> basic_degree<Type> {
114 return lhs -= 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, std::convertible_to<Type> Other>
123constexpr auto operator/(basic_degree<Type> lhs, const Other rhs) noexcept -> basic_degree<Type> {
124 return lhs /= static_cast<Type>(rhs);
125}
126
127template<floating_point Type>
128constexpr auto clamp(const basic_degree<Type>& value, const basic_degree<Type>& min, const basic_degree<Type>& max) -> const basic_degree<Type>& {
129 if (value < min) {
130 return min;
131 }
132
133 if (value > max) {
134 return max;
135 }
136
137 return value;
138}
139
140using degree = basic_degree<std::float_t>;
141
142template<floating_point Type>
143struct is_smoothable<basic_degree<Type>> : std::true_type { };
144
145template<floating_point Type>
147
149
150 inline static constexpr auto equal(const basic_degree<Type>& lhs, const basic_degree<Type>& rhs) noexcept -> bool {
151 return base_trait::equal(lhs.value(), rhs.value());
152 }
153
154}; // template<floating_point Type>
155
156template<floating_point Type>
157inline constexpr auto mix(const basic_degree<Type> x, const basic_degree<Type> y, const Type a) -> basic_degree<Type> {
158 return basic_degree<Type>{x.value() * (static_cast<Type>(1) - a) + y.value() * a};
159}
160
161template<floating_point Type>
163
164public:
165
166 using value_type = Type;
167
168 inline static constexpr basic_radian min{value_type{0}};
169 inline static constexpr basic_radian max{value_type{2 * std::numbers::pi_v<value_type>}};
170
171 constexpr basic_radian() = default;
172
173 template<scalar Other>
174 requires (std::is_convertible_v<Other, Type>)
175 constexpr basic_radian(const Other value) noexcept
176 : _value{static_cast<Type>(value)} { }
177
178 template<floating_point Other>
179 requires (std::is_convertible_v<Other, Type>)
180 constexpr basic_radian(const basic_radian<Other>& other) noexcept
181 : _value{static_cast<Type>(other._value)} { }
182
183 constexpr ~basic_radian() noexcept = default;
184
185 template<floating_point Other>
186 requires (std::is_convertible_v<Other, Type>)
187 constexpr auto operator=(const basic_radian<Other>& other) noexcept -> basic_radian<Type>& {
188 _value = static_cast<Type>(other._value);
189
190 return *this;
191 }
192
193 template<floating_point Other>
194 requires (std::is_convertible_v<Other, Type>)
195 constexpr auto operator+=(const basic_radian<Other>& rhs) noexcept -> basic_radian<Type>& {
196 _value += static_cast<Type>(rhs._value);
197
198 return *this;
199 }
200
201 template<floating_point Other>
202 requires (std::is_convertible_v<Other, Type>)
203 constexpr auto operator-=(const basic_radian<Other>& rhs) noexcept -> basic_radian<Type>& {
204 _value -= static_cast<Type>(rhs._value);
205
206 return *this;
207 }
208
209 template<floating_point Other>
210 requires (std::is_convertible_v<Other, Type>)
211 constexpr auto operator*=(const Other rhs) noexcept -> basic_radian<Type>& {
212 _value *= static_cast<Type>(rhs);
213
214 return *this;
215 }
216
217 constexpr auto value() const noexcept -> value_type {
218 return _value;
219 }
220
221 constexpr operator value_type() const noexcept {
222 return _value;
223 }
224
225 constexpr auto data() noexcept -> value_type* {
226 return &_value;
227 }
228
229private:
230
231 value_type _value{};
232
233}; // class basic_radian
234
235template<floating_point Type>
236constexpr auto operator==(const basic_radian<Type>& lhs, const basic_radian<Type>& rhs) noexcept -> bool {
237 return static_cast<basic_radian<Type>::value_type>(lhs) == static_cast<basic_radian<Type>::value_type>(rhs);
238}
239
240template<floating_point Type, floating_point Other>
241constexpr auto operator<=>(const basic_radian<Type>& lhs, const basic_radian<Other>& rhs) noexcept -> std::partial_ordering {
242 return static_cast<basic_radian<Type>::value_type>(lhs) <=> static_cast<basic_radian<Type>::value_type>(rhs);
243}
244
245template<floating_point Type, floating_point Other>
246requires (std::is_convertible_v<Other, Type>)
247constexpr auto operator+(basic_radian<Type> lhs, const basic_radian<Other>& rhs) noexcept -> basic_radian<Type> {
248 return lhs += rhs;
249}
250
251template<floating_point Type, floating_point Other>
252requires (std::is_convertible_v<Other, Type>)
253constexpr auto operator-(basic_radian<Type> lhs, const basic_radian<Other>& rhs) noexcept -> basic_radian<Type> {
254 return lhs -= rhs;
255}
256
257template<floating_point Type, std::convertible_to<Type> Other>
258requires (std::is_convertible_v<Other, Type>)
259constexpr auto operator*(basic_radian<Type> lhs, const Other rhs) noexcept -> basic_radian<Type> {
260 return lhs *= static_cast<Type>(rhs);
261}
262
263template<floating_point Type>
264constexpr auto clamp(const basic_radian<Type>& value, const basic_radian<Type>& min, const basic_radian<Type>& max) -> const basic_radian<Type>& {
265 if (value < min) {
266 return min;
267 }
268
269 if (value > max) {
270 return max;
271 }
272
273 return value;
274}
275
276using radian = basic_radian<std::float_t>;
277
278template<floating_point Type>
280
281public:
282
283 using value_type = Type;
284
285 constexpr basic_angle(const basic_degree<value_type>& degree) noexcept
286 : _radian{degree.value() * std::numbers::pi_v<value_type> / static_cast<value_type>(180)} {}
287
288 constexpr basic_angle(const basic_radian<value_type>& radian) noexcept
289 : _radian{radian} { }
290
291 template<floating_point Other>
292 requires (std::is_convertible_v<Other, Type>)
293 constexpr basic_angle(const basic_angle<Other>& other) noexcept
294 : _radian{other._radian} { }
295
296 template<floating_point Other>
297 requires (std::is_convertible_v<Other, Type>)
298 constexpr auto operator+=(const basic_angle<Other>& other) noexcept -> basic_angle<Type>& {
299 _radian += basic_radian<Type>{other._radian};
300
301 return *this;
302 }
303
304 template<floating_point Other>
305 requires (std::is_convertible_v<Other, Type>)
306 constexpr auto operator+=(const basic_degree<Other>& other) noexcept -> basic_angle<Type>& {
307 return (*this += basic_angle<Other>{other});
308 }
309
310 template<floating_point Other>
311 requires (std::is_convertible_v<Other, Type>)
312 constexpr auto operator+=(const basic_radian<Other>& other) noexcept -> basic_angle<Type>& {
313 return (*this += basic_angle<Other>{other});
314 }
315
316 template<floating_point Other>
317 requires (std::is_convertible_v<Other, Type>)
318 constexpr auto operator-=(const basic_angle<Other>& other) noexcept -> basic_angle<Type>& {
319 _radian -= basic_radian<Type>{other._radian};
320
321 return *this;
322 }
323
324 template<floating_point Other>
325 requires (std::is_convertible_v<Other, Type>)
326 constexpr auto operator-=(const basic_degree<Other>& other) noexcept -> basic_angle<Type>& {
327 return (*this -= basic_angle<Other>{other});
328 }
329
330 template<floating_point Other>
331 requires (std::is_convertible_v<Other, Type>)
332 constexpr auto operator-=(const basic_radian<Other>& other) noexcept -> basic_angle<Type>& {
333 return (*this -= basic_angle<Other>{other});
334 }
335
336 template<floating_point Other>
337 requires (std::is_convertible_v<Other, Type>)
338 constexpr auto operator*=(const Other other) noexcept -> basic_angle<Type>& {
339 _radian = basic_radian<Type>{_radian.value() * static_cast<Type>(other)};
340
341 return *this;
342 }
343
344 constexpr auto to_degrees() const noexcept -> basic_degree<value_type> {
345 return basic_degree<value_type>{_radian.value() * static_cast<value_type>(180) / std::numbers::pi_v<value_type>};
346 }
347
348 constexpr auto to_radians() const noexcept -> basic_radian<value_type> {
349 return _radian;
350 }
351
352private:
353
354 basic_radian<Type> _radian{};
355
356}; // class basic_angle
357
358template<floating_point Type>
359constexpr auto operator==(const basic_angle<Type>& lhs, const basic_angle<Type>& rhs) noexcept -> bool {
360 return lhs.to_radians() == rhs.to_radians();
361}
362
363template<floating_point Type, floating_point Other>
364constexpr auto operator<=>(const basic_angle<Type>& lhs, const basic_angle<Other>& rhs) noexcept -> std::partial_ordering {
365 return lhs.to_radians() <=> rhs.to_radians();
366}
367
368template<floating_point LhsType, floating_point RhsType>
369requires (std::is_convertible_v<RhsType, LhsType>)
370constexpr auto operator+(basic_angle<LhsType> lhs, const basic_angle<RhsType>& rhs) noexcept -> basic_angle<LhsType> {
371 return lhs += rhs;
372}
373
374template<floating_point LhsType, floating_point RhsType>
375requires (std::is_convertible_v<RhsType, LhsType>)
376constexpr auto operator+(basic_angle<LhsType> lhs, const basic_degree<RhsType>& rhs) noexcept -> basic_angle<LhsType> {
377 return lhs += basic_angle<LhsType>(rhs);
378}
379
380template<floating_point LhsType, floating_point RhsType>
381requires (std::is_convertible_v<RhsType, LhsType>)
382constexpr auto operator+(basic_angle<LhsType> lhs, const basic_radian<RhsType>& rhs) noexcept -> basic_angle<LhsType> {
383 return lhs += basic_angle<LhsType>(rhs);
384}
385
386template<floating_point LhsType, floating_point RhsType>
387requires (std::is_convertible_v<RhsType, LhsType>)
388constexpr auto operator-(basic_angle<LhsType> lhs, const basic_angle<RhsType>& rhs) noexcept -> basic_angle<LhsType> {
389 return lhs -= rhs;
390}
391
392template<floating_point LhsType, floating_point RhsType>
393requires (std::is_convertible_v<RhsType, LhsType>)
394constexpr auto operator-(basic_angle<LhsType> lhs, const basic_degree<RhsType>& rhs) noexcept -> basic_angle<LhsType> {
395 return lhs -= basic_angle<LhsType>(rhs);
396}
397
398template<floating_point LhsType, floating_point RhsType>
399requires (std::is_convertible_v<RhsType, LhsType>)
400constexpr auto operator-(basic_angle<LhsType> lhs, const basic_radian<RhsType>& rhs) noexcept -> basic_angle<LhsType> {
401 return lhs -= basic_angle<LhsType>(rhs);
402}
403
404template<floating_point LhsType, floating_point RhsType>
405requires (std::is_convertible_v<RhsType, LhsType>)
406constexpr auto operator*(basic_angle<LhsType> lhs, const RhsType rhs) noexcept -> basic_angle<LhsType> {
407 return lhs *= rhs;
408}
409
410template<floating_point Type>
411constexpr auto clamp(const basic_angle<Type>& value, const basic_angle<Type>& min, const basic_angle<Type>& max) -> const basic_angle<Type>& {
412 if (value < min) {
413 return min;
414 }
415
416 if (value > max) {
417 return max;
418 }
419
420 return value;
421}
422
423using angle = basic_angle<std::float_t>;
424
425template<floating_point Type>
426constexpr auto to_degrees(const basic_radian<Type>& radian) noexcept -> basic_degree<Type> {
427 return basic_angle<Type>{radian}.to_degrees();
428}
429
430template<floating_point Type>
431constexpr auto to_radians(const basic_degree<Type>& degree) noexcept -> basic_radian<Type> {
432 return basic_angle<Type>{degree}.to_radians();
433}
434
435template<floating_point Type>
436constexpr auto sin(const basic_angle<Type>& angle) noexcept -> Type {
437 return std::sin(angle.to_radians().value());
438}
439
440template<floating_point Type>
441constexpr auto sin(const basic_degree<Type>& degree) noexcept -> Type {
442 return sin(basic_angle<Type>{degree});
443}
444
445template<floating_point Type>
446constexpr auto sin(const basic_radian<Type>& radian) noexcept -> Type {
447 return sin(basic_angle<Type>{radian});
448}
449
450template<floating_point Type>
451constexpr auto cos(const basic_angle<Type>& angle) noexcept -> Type {
452 return std::cos(angle.to_radians().value());
453}
454
455template<floating_point Type>
456constexpr auto cos(const basic_degree<Type>& degree) noexcept -> Type {
457 return cos(basic_angle<Type>{degree});
458}
459
460template<floating_point Type>
461constexpr auto cos(const basic_radian<Type>& radian) noexcept -> Type {
462 return cos(basic_angle<Type>{radian});
463}
464
465template<floating_point Type>
466constexpr auto tan(const basic_angle<Type>& angle) noexcept -> Type {
467 return std::tan(angle.to_radians().value());
468}
469
470namespace literals {
471
472constexpr auto operator""_deg(long double value) noexcept -> degree {
473 return degree{static_cast<std::float_t>(value)};
474}
475
476constexpr auto operator""_deg(unsigned long long value) noexcept -> degree {
477 return degree{static_cast<std::float_t>(value)};
478}
479
480constexpr auto operator""_rad(long double value) noexcept -> radian {
481 return radian{static_cast<std::float_t>(value)};
482}
483
484constexpr auto operator""_rad(unsigned long long value) noexcept -> radian {
485 return radian{static_cast<std::float_t>(value)};
486}
487
488} // namespace literals
489
490} // namespace sbx::math
491
492#endif // LIBSBX_MATH_ANGLE_HPP_
Definition: angle.hpp:279
Definition: angle.hpp:14
Definition: angle.hpp:162
Definition: traits.hpp:13
Definition: traits.hpp:10
Definition: smooth_value.hpp:25