1use super::Float;
2use std::ops::{Add, Sub, Mul, Div, AddAssign, SubAssign, MulAssign, DivAssign};
3use std::cmp::Ordering;
4
5#[derive(Debug, Copy, Clone)]
6pub enum Angle<F: Float = f32> {
7 Radians(F),
8 Degrees(F),
9}
10
11impl<F: Float> Angle<F> {
12 pub fn radians(value: F) -> Self {
13 Angle::Radians(value)
14 }
15
16 pub fn degrees(value: F) -> Self {
17 Angle::Degrees(value)
18 }
19
20 pub fn n_pi(n: F) -> Self {
21 Self::radians(n * F::pi())
22 }
23
24 pub fn zero() -> Self {
25 Self::radians(F::zero())
26 }
27
28 pub fn value(&self) -> F {
29 match self {
30 Self::Radians(value) => *value,
31 Self::Degrees(value) => *value,
32 }
33 }
34
35 pub fn set_value(&mut self, new_value: F) {
36 match self {
37 Self::Radians(value) => *value = new_value,
38 Self::Degrees(value) => *value = new_value,
39 }
40 }
41
42 pub fn radians_value(&self) -> F {
43 match self {
44 Self::Radians(value) => *value,
45 Self::Degrees(value) => value.to_radians(),
46 }
47 }
48
49 pub fn degrees_value(&self) -> F {
50 match self {
51 Self::Radians(value) => value.to_degrees(),
52 Self::Degrees(value) => *value,
53 }
54 }
55
56 pub fn to_degrees(&self) -> Self {
57 Angle::Degrees(self.degrees_value())
58 }
59
60 pub fn to_radians(&self) -> Self {
61 Angle::Radians(self.radians_value())
62 }
63}
64
65impl<F: Float> Add for Angle<F> {
66 type Output = Self;
67
68 fn add(self, other: Self) -> Self::Output {
69 match self {
70 Self::Radians(value) => Self::Radians(value + other.radians_value()),
71 Self::Degrees(value) => Self::Degrees(value + other.degrees_value()),
72 }
73 }
74}
75
76impl<F: Float> Sub for Angle<F> {
77 type Output = Self;
78
79 fn sub(self, other: Self) -> Self::Output {
80 match self {
81 Self::Radians(value) => Self::Radians(value - other.radians_value()),
82 Self::Degrees(value) => Self::Degrees(value - other.degrees_value()),
83 }
84 }
85}
86
87impl<F: Float> AddAssign for Angle<F> {
88 fn add_assign(&mut self, other: Self) {
89 match self {
90 Self::Radians(value) => *value += other.radians_value(),
91 Self::Degrees(value) => *value += other.degrees_value(),
92 }
93 }
94}
95
96impl<F: Float> SubAssign for Angle<F> {
97 fn sub_assign(&mut self, other: Self) {
98 match self {
99 Self::Radians(value) => *value -= other.radians_value(),
100 Self::Degrees(value) => *value -= other.degrees_value(),
101 }
102 }
103}
104
105impl<F: Float> Mul<F> for Angle<F> {
106 type Output = Self;
107
108 fn mul(self, rhs: F) -> Self::Output {
109 match self {
110 Self::Radians(value) => Self::Radians(value * rhs),
111 Self::Degrees(value) => Self::Degrees(value * rhs),
112 }
113 }
114}
115
116impl<F: Float> Div<F> for Angle<F> {
117 type Output = Self;
118
119 fn div(self, rhs: F) -> Self::Output {
120 match self {
121 Self::Radians(value) => Self::Radians(value / rhs),
122 Self::Degrees(value) => Self::Degrees(value / rhs),
123 }
124 }
125}
126
127impl<F: Float> MulAssign<F> for Angle<F> {
128 fn mul_assign(&mut self, rhs: F) {
129 match self {
130 Self::Radians(value) => *value *= rhs,
131 Self::Degrees(value) => *value *= rhs,
132 }
133 }
134}
135
136impl<F: Float> DivAssign<F> for Angle<F> {
137 fn div_assign(&mut self, rhs: F) {
138 match self {
139 Self::Radians(value) => *value /= rhs,
140 Self::Degrees(value) => *value /= rhs,
141 }
142 }
143}
144
145impl<F: Float> PartialEq for Angle<F> {
146 fn eq(&self, other: &Self) -> bool {
147 self.radians_value() == other.radians_value()
148 }
149}
150
151impl<F: Float> PartialOrd for Angle<F> {
152 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
153 self.radians_value().partial_cmp(&other.radians_value())
154 }
155}
156
157#[cfg(test)]
158mod tests {
159 use super::Angle;
160
161 #[test]
162 fn test_create() {
163 assert_eq!(Angle::<f32>::radians(std::f32::consts::PI * 2.0), Angle::<f32>::n_pi(2.0));
164 assert_eq!(Angle::<f32>::n_pi(1.0), Angle::<f32>::degrees(180.0));
165 assert_eq!(Angle::<f32>::n_pi(2.0).value(), std::f32::consts::PI * 2.0);
166 assert_eq!(Angle::<f32>::degrees(90.0).value(), 90.0f32);
167 assert_eq!(Angle::<f32>::zero(), Angle::<f32>::radians(0.0));
168 assert_eq!(Angle::<f32>::zero(), Angle::<f32>::degrees(0.0));
169 assert_eq!(Angle::<f32>::zero().value(), 0.0f32);
170 }
171
172 #[test]
173 fn test_convert() {
174 assert_eq!(Angle::<f32>::n_pi(1.0).to_degrees().value(), 180.0f32);
175 assert_eq!(Angle::<f32>::degrees(90.0).to_radians().value(), std::f32::consts::PI * 0.5);
176 assert_eq!(Angle::<f32>::n_pi(2.0).to_degrees().value(), Angle::<f32>::n_pi(2.0).degrees_value());
177 assert_eq!(Angle::<f32>::degrees(180.0).to_radians().value(), Angle::<f32>::degrees(180.0).radians_value());
178 }
179
180 #[test]
181 fn test_operator() {
182 assert_eq!(Angle::<f32>::n_pi(1.0) + Angle::<f32>::n_pi(1.0), Angle::<f32>::n_pi(2.0));
183 assert_eq!(Angle::<f32>::degrees(90.0) + Angle::<f32>::degrees(90.0), Angle::<f32>::degrees(180.0));
184 assert_eq!(Angle::<f32>::n_pi(1.0) + Angle::<f32>::degrees(180.0), Angle::<f32>::n_pi(2.0));
185 assert_eq!(Angle::<f32>::degrees(90.0) + Angle::<f32>::n_pi(0.5), Angle::<f32>::degrees(180.0));
186 assert_eq!(Angle::<f32>::n_pi(2.0) - Angle::<f32>::n_pi(1.0), Angle::<f32>::n_pi(1.0));
187 assert_eq!(Angle::<f32>::degrees(180.0) - Angle::<f32>::degrees(90.0), Angle::<f32>::degrees(90.0));
188 assert_eq!(Angle::<f32>::n_pi(2.0) - Angle::<f32>::degrees(180.0), Angle::<f32>::n_pi(1.0));
189 assert_eq!(Angle::<f32>::degrees(180.0) - Angle::<f32>::n_pi(0.5), Angle::<f32>::degrees(90.0));
190 assert_eq!(Angle::<f32>::n_pi(1.0) * 2.0, Angle::<f32>::n_pi(2.0));
191 assert_eq!(Angle::<f32>::degrees(90.0) * 2.0, Angle::<f32>::degrees(180.0));
192 assert_eq!(Angle::<f32>::n_pi(2.0) / 2.0, Angle::<f32>::n_pi(1.0));
193 assert_eq!(Angle::<f32>::degrees(90.0) / 2.0, Angle::<f32>::degrees(45.0));
194
195 let mut angle = Angle::<f32>::n_pi(2.0);
196 angle += Angle::<f32>::n_pi(2.0);
197 assert_eq!(angle, Angle::<f32>::n_pi(4.0));
198 angle += Angle::<f32>::degrees(180.0);
199 assert_eq!(angle, Angle::<f32>::n_pi(5.0));
200 angle -= Angle::<f32>::n_pi(1.0);
201 assert_eq!(angle, Angle::<f32>::n_pi(4.0));
202 angle -= Angle::<f32>::degrees(180.0);
203 assert_eq!(angle, Angle::<f32>::n_pi(3.0));
204
205 let mut angle = Angle::<f32>::degrees(180.0);
206 angle += Angle::<f32>::degrees(180.0);
207 assert_eq!(angle, Angle::<f32>::degrees(360.0));
208 angle += Angle::<f32>::n_pi(2.0);
209 assert_eq!(angle, Angle::<f32>::degrees(720.0));
210 angle -= Angle::<f32>::degrees(360.0);
211 assert_eq!(angle, Angle::<f32>::degrees(360.0));
212 angle -= Angle::<f32>::n_pi(1.0);
213 assert_eq!(angle, Angle::<f32>::degrees(180.0));
214
215 let mut angle = Angle::<f32>::n_pi(1.0);
216 angle *= 4.0;
217 assert_eq!(angle, Angle::<f32>::n_pi(4.0));
218 angle /= 2.0;
219 assert_eq!(angle, Angle::<f32>::n_pi(2.0));
220
221 let mut angle = Angle::<f32>::degrees(180.0);
222 angle *= 4.0;
223 assert_eq!(angle, Angle::<f32>::degrees(720.0));
224 angle /= 2.0;
225 assert_eq!(angle, Angle::<f32>::degrees(360.0));
226 }
227
228 #[test]
229 fn test_compare() {
230 assert!(Angle::<f32>::n_pi(1.5) > Angle::<f32>::n_pi(0.5));
231 assert!(Angle::<f32>::n_pi(1.0) < Angle::<f32>::n_pi(2.0));
232 assert!(Angle::<f32>::degrees(90.0) > Angle::<f32>::degrees(45.0));
233 assert!(Angle::<f32>::degrees(30.0) < Angle::<f32>::degrees(60.0));
234 assert!(Angle::<f32>::n_pi(2.0) > Angle::<f32>::degrees(300.0));
235 assert!(Angle::<f32>::n_pi(0.5) < Angle::<f32>::degrees(135.0));
236 }
237}