1#[derive(Clone, Copy, Debug, Default, PartialEq, PartialOrd)]
6pub struct Angle(f32);
7
8impl Angle {
9 #[inline]
11 pub const fn from_radians(rad: f32) -> Self {
12 Angle(rad)
13 }
14
15 #[inline]
17 pub fn from_degrees(deg: f32) -> Self {
18 Angle(deg.to_radians())
19 }
20
21 #[inline]
23 pub fn as_radians(self) -> f32 {
24 self.0
25 }
26
27 #[inline]
29 pub fn as_degrees(self) -> f32 {
30 self.0.to_degrees()
31 }
32
33 pub const fn zero() -> Self {
35 Angle(0.0)
36 }
37
38 pub fn normalized(self) -> Self {
40 let mut a = self.0 % (2.0 * std::f32::consts::PI);
41 if a > std::f32::consts::PI {
42 a -= 2.0 * std::f32::consts::PI;
43 } else if a < -std::f32::consts::PI {
44 a += 2.0 * std::f32::consts::PI;
45 }
46 Angle(a)
47 }
48
49 #[inline]
51 pub fn sin(self) -> f32 {
52 self.0.sin()
53 }
54
55 #[inline]
57 pub fn cos(self) -> f32 {
58 self.0.cos()
59 }
60
61 #[inline]
63 pub fn sin_cos(self) -> (f32, f32) {
64 self.0.sin_cos()
65 }
66
67 #[inline]
69 pub fn tan(self) -> f32 {
70 self.0.tan()
71 }
72}
73
74impl std::ops::Add for Angle {
75 type Output = Self;
76 #[inline]
77 fn add(self, rhs: Self) -> Self {
78 Angle(self.0 + rhs.0)
79 }
80}
81
82impl std::ops::Sub for Angle {
83 type Output = Self;
84 #[inline]
85 fn sub(self, rhs: Self) -> Self {
86 Angle(self.0 - rhs.0)
87 }
88}
89
90impl std::ops::Mul<f32> for Angle {
91 type Output = Self;
92 #[inline]
93 fn mul(self, rhs: f32) -> Self {
94 Angle(self.0 * rhs)
95 }
96}
97
98impl std::ops::Div<f32> for Angle {
99 type Output = Self;
100 #[inline]
101 fn div(self, rhs: f32) -> Self {
102 Angle(self.0 / rhs)
103 }
104}
105
106impl std::ops::Neg for Angle {
107 type Output = Self;
108 #[inline]
109 fn neg(self) -> Self {
110 Angle(-self.0)
111 }
112}
113
114impl std::ops::AddAssign for Angle {
115 fn add_assign(&mut self, rhs: Self) {
116 self.0 += rhs.0;
117 }
118}
119
120impl std::ops::SubAssign for Angle {
121 fn sub_assign(&mut self, rhs: Self) {
122 self.0 -= rhs.0;
123 }
124}
125
126#[cfg(test)]
127mod tests {
128 use super::*;
129
130 #[test]
131 fn test_degrees_to_radians() {
132 let a = Angle::from_degrees(180.0);
133 assert!((a.as_radians() - std::f32::consts::PI).abs() < 1e-6);
134 }
135
136 #[test]
137 fn test_normalize() {
138 let a = Angle::from_degrees(450.0).normalized();
139 assert!((a.as_degrees() - 90.0).abs() < 1e-4);
142 }
143}