fey_math/
rotations.rs

1use crate::{Cardinal, Degrees, Float, Octal, Radians, impl_angle};
2use serde::{Deserialize, Serialize};
3
4pub type RotationsF = Rotations<f32>;
5
6/// An angle represented in rotations.
7#[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/// Create a [`Rotations`].
15#[inline]
16pub const fn rots<T>(value: T) -> Rotations<T> {
17    Rotations(value)
18}
19
20impl<T: Float> Rotations<T> {
21    /// A 360° turn.
22    pub const ONE: Self = Self(T::ONE);
23
24    /// A 180° turn.
25    pub const HALF: Self = Self(T::HALF);
26
27    /// A 90° turn.
28    pub const QUARTER: Self = Self(T::QUARTER);
29
30    /// Convert from radians.
31    #[inline]
32    pub fn from_radians(value: Radians<T>) -> Self {
33        Self(value.0 / T::TAU)
34    }
35
36    /// Convert from degrees.
37    #[inline]
38    pub fn from_degrees(value: Degrees<T>) -> Self {
39        Self(value.0 / T::NUM_360)
40    }
41
42    /// Convert from rotations.
43    #[inline]
44    pub fn from_rotations(value: Rotations<T>) -> Self {
45        value
46    }
47
48    /// Convert from a cardinal direction.
49    #[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    /// Convert from an octal direction.
60    #[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    /// Wraps the angle into the range `(-0.5,0.5]`.
75    #[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}