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
85private:
86
87 value_type _value{};
88
89}; // class basic_degree
90
91template<floating_point Type>
92constexpr auto operator==(const basic_degree<Type>& lhs, const basic_degree<Type>& rhs) noexcept -> bool {
93 return static_cast<basic_degree<Type>::value_type>(lhs) == static_cast<basic_degree<Type>::value_type>(rhs);
94}
95
96template<floating_point Type, floating_point Other>
97constexpr auto operator<=>(const basic_degree<Type>& lhs, const basic_degree<Other>& rhs) noexcept -> std::partial_ordering {
98 return static_cast<basic_degree<Type>::value_type>(lhs) <=> static_cast<basic_degree<Type>::value_type>(rhs);
99}
100
101template<floating_point Type, floating_point Other>
102requires (std::is_convertible_v<Other, Type>)
103constexpr auto operator+(basic_degree<Type> lhs, const basic_degree<Other>& rhs) noexcept -> basic_degree<Type> {
104 return lhs += rhs;
105}
106
107template<floating_point Type, floating_point Other>
108requires (std::is_convertible_v<Other, Type>)
109constexpr auto operator-(basic_degree<Type> lhs, const basic_degree<Other>& rhs) noexcept -> basic_degree<Type> {
110 return lhs -= rhs;
111}
112
113template<floating_point Type, std::convertible_to<Type> Other>
114constexpr auto operator*(basic_degree<Type> lhs, const Other rhs) noexcept -> basic_degree<Type> {
115 return lhs *= static_cast<Type>(rhs);
116}
117
118template<floating_point Type, std::convertible_to<Type> Other>
119constexpr auto operator/(basic_degree<Type> lhs, const Other rhs) noexcept -> basic_degree<Type> {
120 return lhs /= static_cast<Type>(rhs);
121}
122
123template<floating_point Type>
124constexpr auto clamp(const basic_degree<Type>& value, const basic_degree<Type>& min, const basic_degree<Type>& max) -> const basic_degree<Type>& {
125 if (value < min) {
126 return min;
127 }
128
129 if (value > max) {
130 return max;
131 }
132
133 return value;
134}
135
136using degree = basic_degree<std::float_t>;
137
138template<floating_point Type>
139struct is_smoothable<basic_degree<Type>> : std::true_type { };
140
141template<floating_point Type>
143
145
146 inline static constexpr auto equal(const basic_degree<Type>& lhs, const basic_degree<Type>& rhs) noexcept -> bool {
147 return base_trait::equal(lhs.value(), rhs.value());
148 }
149
150}; // template<floating_point Type>
151
152template<floating_point Type>
153inline constexpr auto mix(const basic_degree<Type> x, const basic_degree<Type> y, const Type a) -> basic_degree<Type> {
154 return basic_degree<Type>{x.value() * (static_cast<Type>(1) - a) + y.value() * a};
155}
156
157template<floating_point Type>
159
160public:
161
162 using value_type = Type;
163
164 inline static constexpr basic_radian min{value_type{0}};
165 inline static constexpr basic_radian max{value_type{2 * std::numbers::pi_v<value_type>}};
166
167 constexpr basic_radian() = default;
168
169 template<scalar Other>
170 requires (std::is_convertible_v<Other, Type>)
171 constexpr basic_radian(const Other value) noexcept
172 : _value{static_cast<Type>(value)} { }
173
174 template<floating_point Other>
175 requires (std::is_convertible_v<Other, Type>)
176 constexpr basic_radian(const basic_radian<Other>& other) noexcept
177 : _value{static_cast<Type>(other._value)} { }
178
179 constexpr ~basic_radian() noexcept = default;
180
181 template<floating_point Other>
182 requires (std::is_convertible_v<Other, Type>)
183 constexpr auto operator=(const basic_radian<Other>& other) noexcept -> basic_radian<Type>& {
184 _value = static_cast<Type>(other._value);
185
186 return *this;
187 }
188
189 template<floating_point Other>
190 requires (std::is_convertible_v<Other, Type>)
191 constexpr auto operator+=(const basic_radian<Other>& rhs) noexcept -> basic_radian<Type>& {
192 _value += static_cast<Type>(rhs._value);
193
194 return *this;
195 }
196
197 template<floating_point Other>
198 requires (std::is_convertible_v<Other, Type>)
199 constexpr auto operator-=(const basic_radian<Other>& rhs) noexcept -> basic_radian<Type>& {
200 _value -= static_cast<Type>(rhs._value);
201
202 return *this;
203 }
204
205 template<floating_point Other>
206 requires (std::is_convertible_v<Other, Type>)
207 constexpr auto operator*=(const Other rhs) noexcept -> basic_radian<Type>& {
208 _value *= static_cast<Type>(rhs);
209
210 return *this;
211 }
212
213 constexpr auto value() const noexcept -> value_type {
214 return _value;
215 }
216
217 constexpr operator value_type() const noexcept {
218 return _value;
219 }
220
221private:
222
223 value_type _value{};
224
225}; // class basic_radian
226
227template<floating_point Type>
228constexpr auto operator==(const basic_radian<Type>& lhs, const basic_radian<Type>& rhs) noexcept -> bool {
229 return static_cast<basic_radian<Type>::value_type>(lhs) == static_cast<basic_radian<Type>::value_type>(rhs);
230}
231
232template<floating_point Type, floating_point Other>
233constexpr auto operator<=>(const basic_radian<Type>& lhs, const basic_radian<Other>& rhs) noexcept -> std::partial_ordering {
234 return static_cast<basic_radian<Type>::value_type>(lhs) <=> static_cast<basic_radian<Type>::value_type>(rhs);
235}
236
237template<floating_point Type, floating_point Other>
238requires (std::is_convertible_v<Other, Type>)
239constexpr auto operator+(basic_radian<Type> lhs, const basic_radian<Other>& rhs) noexcept -> basic_radian<Type> {
240 return lhs += rhs;
241}
242
243template<floating_point Type, floating_point Other>
244requires (std::is_convertible_v<Other, Type>)
245constexpr auto operator-(basic_radian<Type> lhs, const basic_radian<Other>& rhs) noexcept -> basic_radian<Type> {
246 return lhs -= rhs;
247}
248
249template<floating_point Type, std::convertible_to<Type> Other>
250requires (std::is_convertible_v<Other, Type>)
251constexpr auto operator*(basic_radian<Type> lhs, const Other rhs) noexcept -> basic_radian<Type> {
252 return lhs *= static_cast<Type>(rhs);
253}
254
255template<floating_point Type>
256constexpr auto clamp(const basic_radian<Type>& value, const basic_radian<Type>& min, const basic_radian<Type>& max) -> const basic_radian<Type>& {
257 if (value < min) {
258 return min;
259 }
260
261 if (value > max) {
262 return max;
263 }
264
265 return value;
266}
267
268using radian = basic_radian<std::float_t>;
269
270template<floating_point Type>
272
273public:
274
275 using value_type = Type;
276
277 constexpr basic_angle(const basic_degree<value_type>& degree) noexcept
278 : _radian{degree.value() * std::numbers::pi_v<value_type> / static_cast<value_type>(180)} {}
279
280 constexpr basic_angle(const basic_radian<value_type>& radian) noexcept
281 : _radian{radian} { }
282
283 template<floating_point Other>
284 requires (std::is_convertible_v<Other, Type>)
285 constexpr basic_angle(const basic_angle<Other>& other) noexcept
286 : _radian{other._radian} { }
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 basic_angle<Other>& other) noexcept -> basic_angle<Type>& {
311 _radian -= basic_radian<Type>{other._radian};
312
313 return *this;
314 }
315
316 template<floating_point Other>
317 requires (std::is_convertible_v<Other, Type>)
318 constexpr auto operator-=(const basic_degree<Other>& other) noexcept -> basic_angle<Type>& {
319 return (*this -= basic_angle<Other>{other});
320 }
321
322 template<floating_point Other>
323 requires (std::is_convertible_v<Other, Type>)
324 constexpr auto operator-=(const basic_radian<Other>& other) noexcept -> basic_angle<Type>& {
325 return (*this -= basic_angle<Other>{other});
326 }
327
328 template<floating_point Other>
329 requires (std::is_convertible_v<Other, Type>)
330 constexpr auto operator*=(const Other other) noexcept -> basic_angle<Type>& {
331 _radian = basic_radian<Type>{_radian.value() * static_cast<Type>(other)};
332
333 return *this;
334 }
335
336 constexpr auto to_degrees() const noexcept -> basic_degree<value_type> {
337 return basic_degree<value_type>{_radian.value() * static_cast<value_type>(180) / std::numbers::pi_v<value_type>};
338 }
339
340 constexpr auto to_radians() const noexcept -> basic_radian<value_type> {
341 return _radian;
342 }
343
344private:
345
346 basic_radian<Type> _radian{};
347
348}; // class basic_angle
349
350template<floating_point Type>
351constexpr auto operator==(const basic_angle<Type>& lhs, const basic_angle<Type>& rhs) noexcept -> bool {
352 return lhs.to_radians() == rhs.to_radians();
353}
354
355template<floating_point Type, floating_point Other>
356constexpr auto operator<=>(const basic_angle<Type>& lhs, const basic_angle<Other>& rhs) noexcept -> std::partial_ordering {
357 return lhs.to_radians() <=> rhs.to_radians();
358}
359
360template<floating_point LhsType, floating_point RhsType>
361requires (std::is_convertible_v<RhsType, LhsType>)
362constexpr auto operator+(basic_angle<LhsType> lhs, const basic_angle<RhsType>& rhs) noexcept -> basic_angle<LhsType> {
363 return lhs += rhs;
364}
365
366template<floating_point LhsType, floating_point RhsType>
367requires (std::is_convertible_v<RhsType, LhsType>)
368constexpr auto operator+(basic_angle<LhsType> lhs, const basic_degree<RhsType>& rhs) noexcept -> basic_angle<LhsType> {
369 return lhs += basic_angle<LhsType>(rhs);
370}
371
372template<floating_point LhsType, floating_point RhsType>
373requires (std::is_convertible_v<RhsType, LhsType>)
374constexpr auto operator+(basic_angle<LhsType> lhs, const basic_radian<RhsType>& rhs) noexcept -> basic_angle<LhsType> {
375 return lhs += basic_angle<LhsType>(rhs);
376}
377
378template<floating_point LhsType, floating_point RhsType>
379requires (std::is_convertible_v<RhsType, LhsType>)
380constexpr auto operator-(basic_angle<LhsType> lhs, const basic_angle<RhsType>& rhs) noexcept -> basic_angle<LhsType> {
381 return lhs -= rhs;
382}
383
384template<floating_point LhsType, floating_point RhsType>
385requires (std::is_convertible_v<RhsType, LhsType>)
386constexpr auto operator-(basic_angle<LhsType> lhs, const basic_degree<RhsType>& rhs) noexcept -> basic_angle<LhsType> {
387 return lhs -= basic_angle<LhsType>(rhs);
388}
389
390template<floating_point LhsType, floating_point RhsType>
391requires (std::is_convertible_v<RhsType, LhsType>)
392constexpr auto operator-(basic_angle<LhsType> lhs, const basic_radian<RhsType>& rhs) noexcept -> basic_angle<LhsType> {
393 return lhs -= basic_angle<LhsType>(rhs);
394}
395
396template<floating_point LhsType, floating_point RhsType>
397requires (std::is_convertible_v<RhsType, LhsType>)
398constexpr auto operator*(basic_angle<LhsType> lhs, const RhsType rhs) noexcept -> basic_angle<LhsType> {
399 return lhs *= rhs;
400}
401
402template<floating_point Type>
403constexpr auto clamp(const basic_angle<Type>& value, const basic_angle<Type>& min, const basic_angle<Type>& max) -> const basic_angle<Type>& {
404 if (value < min) {
405 return min;
406 }
407
408 if (value > max) {
409 return max;
410 }
411
412 return value;
413}
414
415using angle = basic_angle<std::float_t>;
416
417template<floating_point Type>
418constexpr auto to_degrees(const basic_radian<Type>& radian) noexcept -> basic_degree<Type> {
419 return basic_angle<Type>{radian}.to_degrees();
420}
421
422template<floating_point Type>
423constexpr auto to_radians(const basic_degree<Type>& degree) noexcept -> basic_radian<Type> {
424 return basic_angle<Type>{degree}.to_radians();
425}
426
427namespace literals {
428
429constexpr auto operator""_deg(long double value) noexcept -> degree {
430 return degree{static_cast<std::float_t>(value)};
431}
432
433constexpr auto operator""_deg(unsigned long long value) noexcept -> degree {
434 return degree{static_cast<std::float_t>(value)};
435}
436
437constexpr auto operator""_rad(long double value) noexcept -> radian {
438 return radian{static_cast<std::float_t>(value)};
439}
440
441constexpr auto operator""_rad(unsigned long long value) noexcept -> radian {
442 return radian{static_cast<std::float_t>(value)};
443}
444
445} // namespace literals
446
447} // namespace sbx::math
448
449#endif // LIBSBX_MATH_ANGLE_HPP_
Definition: angle.hpp:271
Definition: angle.hpp:14
Definition: angle.hpp:158
Definition: traits.hpp:13
Definition: traits.hpp:10
Definition: smooth_value.hpp:25