1use crate::{Cardinal, Degrees, Float, Octal, Radians, impl_angle};
2use serde::{Deserialize, Serialize};
3
4pub type RotationsF = Rotations<f32>;
5
6#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
8#[serde(transparent)]
9#[repr(transparent)]
10pub struct Rotations<T>(pub T);
11
12impl_angle!(Rotations, from_rotations, to_rotations);
13
14#[inline]
16pub const fn rots<T>(value: T) -> Rotations<T> {
17 Rotations(value)
18}
19
20impl<T: Float> Rotations<T> {
21 pub const ONE: Self = Self(T::ONE);
23
24 pub const HALF: Self = Self(T::HALF);
26
27 pub const QUARTER: Self = Self(T::QUARTER);
29
30 #[inline]
32 pub fn from_radians(value: Radians<T>) -> Self {
33 Self(value.0 / T::TAU)
34 }
35
36 #[inline]
38 pub fn from_degrees(value: Degrees<T>) -> Self {
39 Self(value.0 / T::NUM_360)
40 }
41
42 #[inline]
44 pub fn from_rotations(value: Rotations<T>) -> Self {
45 value
46 }
47
48 #[inline]
50 pub fn from_cardinal(value: Cardinal) -> Self {
51 Self(match value {
52 Cardinal::East => T::ZERO,
53 Cardinal::South => T::QUARTER,
54 Cardinal::West => T::HALF,
55 Cardinal::North => -T::QUARTER,
56 })
57 }
58
59 #[inline]
61 pub fn from_octal(value: Octal) -> Self {
62 Self(match value {
63 Octal::East => T::ZERO,
64 Octal::SouthEast => T::EIGHTH,
65 Octal::South => T::QUARTER,
66 Octal::SouthWest => T::QUARTER + T::EIGHTH,
67 Octal::West => T::HALF,
68 Octal::NorthWest => -T::EIGHTH,
69 Octal::North => -T::QUARTER,
70 Octal::NorthEast => -(T::QUARTER + T::EIGHTH),
71 })
72 }
73
74 #[inline]
76 pub fn wrap(self) -> Self {
77 let angle = self.0;
78 Self(if angle > -T::HALF && angle <= T::HALF {
79 angle
80 } else {
81 let angle = angle % T::ONE;
82 if angle <= -T::HALF {
83 angle + T::ONE
84 } else if angle > T::HALF {
85 angle - T::ONE
86 } else {
87 angle
88 }
89 })
90 }
91}