1use crate::approxeq::ApproxEq;
11use crate::trig::Trig;
12
13use core::cmp::{Eq, PartialEq};
14use core::hash::Hash;
15use core::iter::Sum;
16use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Rem, Sub, SubAssign};
17
18#[cfg(feature = "bytemuck")]
19use bytemuck::{Pod, Zeroable};
20#[cfg(feature = "malloc_size_of")]
21use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
22use num_traits::real::Real;
23use num_traits::{Float, FloatConst, NumCast, One, Zero};
24#[cfg(feature = "serde")]
25use serde::{Deserialize, Serialize};
26
27#[derive(Copy, Clone, Default, Debug, PartialEq, Eq, PartialOrd, Hash)]
29#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
30pub struct Angle<T> {
31 pub radians: T,
32}
33
34#[cfg(feature = "bytemuck")]
35unsafe impl<T: Zeroable> Zeroable for Angle<T> {}
36
37#[cfg(feature = "bytemuck")]
38unsafe impl<T: Pod> Pod for Angle<T> {}
39
40#[cfg(feature = "arbitrary")]
41impl<'a, T> arbitrary::Arbitrary<'a> for Angle<T>
42where
43 T: arbitrary::Arbitrary<'a>,
44{
45 fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
47 Ok(Angle {
48 radians: arbitrary::Arbitrary::arbitrary(u)?,
49 })
50 }
51
52 fn size_hint(depth: usize) -> (usize, Option<usize>) {
53 <T as arbitrary::Arbitrary>::size_hint(depth)
54 }
55}
56
57#[cfg(feature = "malloc_size_of")]
58impl<T: MallocSizeOf> MallocSizeOf for Angle<T> {
59 fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
60 self.radians.size_of(ops)
61 }
62}
63
64impl<T> Angle<T> {
65 #[inline]
66 pub fn radians(radians: T) -> Self {
67 Angle { radians }
68 }
69
70 #[inline]
71 pub fn get(self) -> T {
72 self.radians
73 }
74}
75
76impl<T> Angle<T>
77where
78 T: Trig,
79{
80 #[inline]
81 pub fn degrees(deg: T) -> Self {
82 Angle {
83 radians: T::degrees_to_radians(deg),
84 }
85 }
86
87 #[inline]
88 pub fn to_degrees(self) -> T {
89 T::radians_to_degrees(self.radians)
90 }
91}
92
93impl<T> Angle<T>
94where
95 T: Rem<Output = T> + Sub<Output = T> + Add<Output = T> + Zero + FloatConst + PartialOrd + Copy,
96{
97 pub fn positive(&self) -> Self {
99 let two_pi = T::PI() + T::PI();
100 let mut a = self.radians % two_pi;
101 if a < T::zero() {
102 a = a + two_pi;
103 }
104 Angle::radians(a)
105 }
106
107 pub fn signed(&self) -> Self {
109 Angle::pi() - (Angle::pi() - *self).positive()
110 }
111}
112
113impl<T> Angle<T>
114where
115 T: Rem<Output = T>
116 + Mul<Output = T>
117 + Sub<Output = T>
118 + Add<Output = T>
119 + One
120 + FloatConst
121 + Copy,
122{
123 pub fn angle_to(&self, to: Self) -> Self {
127 let two = T::one() + T::one();
128 let max = T::PI() * two;
129 let d = (to.radians - self.radians) % max;
130
131 Angle::radians(two * d % max - d)
132 }
133
134 pub fn lerp(&self, other: Self, t: T) -> Self {
136 *self + self.angle_to(other) * t
137 }
138}
139
140impl<T> Angle<T>
141where
142 T: Float,
143{
144 #[inline]
146 pub fn is_finite(self) -> bool {
147 self.radians.is_finite()
148 }
149}
150
151impl<T> Angle<T>
152where
153 T: Real,
154{
155 pub fn sin_cos(self) -> (T, T) {
157 self.radians.sin_cos()
158 }
159}
160
161impl<T> Angle<T>
162where
163 T: Zero,
164{
165 pub fn zero() -> Self {
166 Angle::radians(T::zero())
167 }
168}
169
170impl<T> Angle<T>
171where
172 T: FloatConst + Add<Output = T>,
173{
174 pub fn pi() -> Self {
175 Angle::radians(T::PI())
176 }
177
178 pub fn two_pi() -> Self {
179 Angle::radians(T::PI() + T::PI())
180 }
181
182 pub fn frac_pi_2() -> Self {
183 Angle::radians(T::FRAC_PI_2())
184 }
185
186 pub fn frac_pi_3() -> Self {
187 Angle::radians(T::FRAC_PI_3())
188 }
189
190 pub fn frac_pi_4() -> Self {
191 Angle::radians(T::FRAC_PI_4())
192 }
193}
194
195impl<T> Angle<T>
196where
197 T: NumCast + Copy,
198{
199 #[inline]
201 pub fn cast<NewT: NumCast>(&self) -> Angle<NewT> {
202 self.try_cast().unwrap()
203 }
204
205 pub fn try_cast<NewT: NumCast>(&self) -> Option<Angle<NewT>> {
207 NumCast::from(self.radians).map(|radians| Angle { radians })
208 }
209
210 #[inline]
214 pub fn to_f32(&self) -> Angle<f32> {
215 self.cast()
216 }
217
218 #[inline]
220 pub fn to_f64(&self) -> Angle<f64> {
221 self.cast()
222 }
223}
224
225impl<T: Add<T, Output = T>> Add for Angle<T> {
226 type Output = Self;
227 fn add(self, other: Self) -> Self {
228 Self::radians(self.radians + other.radians)
229 }
230}
231
232impl<T: Copy + Add<T, Output = T>> Add<&Self> for Angle<T> {
233 type Output = Self;
234 fn add(self, other: &Self) -> Self {
235 Self::radians(self.radians + other.radians)
236 }
237}
238
239impl<T: Add + Zero> Sum for Angle<T> {
240 fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
241 iter.fold(Self::zero(), Add::add)
242 }
243}
244
245impl<'a, T: 'a + Add + Copy + Zero> Sum<&'a Self> for Angle<T> {
246 fn sum<I: Iterator<Item = &'a Self>>(iter: I) -> Self {
247 iter.fold(Self::zero(), Add::add)
248 }
249}
250
251impl<T: AddAssign<T>> AddAssign for Angle<T> {
252 fn add_assign(&mut self, other: Angle<T>) {
253 self.radians += other.radians;
254 }
255}
256
257impl<T: Sub<T, Output = T>> Sub<Angle<T>> for Angle<T> {
258 type Output = Angle<T>;
259 fn sub(self, other: Angle<T>) -> <Self as Sub>::Output {
260 Angle::radians(self.radians - other.radians)
261 }
262}
263
264impl<T: SubAssign<T>> SubAssign for Angle<T> {
265 fn sub_assign(&mut self, other: Angle<T>) {
266 self.radians -= other.radians;
267 }
268}
269
270impl<T: Div<T, Output = T>> Div<Angle<T>> for Angle<T> {
271 type Output = T;
272 #[inline]
273 fn div(self, other: Angle<T>) -> T {
274 self.radians / other.radians
275 }
276}
277
278impl<T: Div<T, Output = T>> Div<T> for Angle<T> {
279 type Output = Angle<T>;
280 #[inline]
281 fn div(self, factor: T) -> Angle<T> {
282 Angle::radians(self.radians / factor)
283 }
284}
285
286impl<T: DivAssign<T>> DivAssign<T> for Angle<T> {
287 fn div_assign(&mut self, factor: T) {
288 self.radians /= factor;
289 }
290}
291
292impl<T: Mul<T, Output = T>> Mul<T> for Angle<T> {
293 type Output = Angle<T>;
294 #[inline]
295 fn mul(self, factor: T) -> Angle<T> {
296 Angle::radians(self.radians * factor)
297 }
298}
299
300impl<T: MulAssign<T>> MulAssign<T> for Angle<T> {
301 fn mul_assign(&mut self, factor: T) {
302 self.radians *= factor;
303 }
304}
305
306impl<T: Neg<Output = T>> Neg for Angle<T> {
307 type Output = Self;
308 fn neg(self) -> Self {
309 Angle::radians(-self.radians)
310 }
311}
312
313impl<T: ApproxEq<T>> ApproxEq<T> for Angle<T> {
314 #[inline]
315 fn approx_epsilon() -> T {
316 T::approx_epsilon()
317 }
318
319 #[inline]
320 fn approx_eq_eps(&self, other: &Angle<T>, approx_epsilon: &T) -> bool {
321 self.radians.approx_eq_eps(&other.radians, approx_epsilon)
322 }
323}
324
325#[test]
326fn wrap_angles() {
327 use core::f32::consts::{FRAC_PI_2, PI};
328
329 assert!(Angle::radians(0.0).positive().approx_eq(&Angle::zero()));
330 assert!(Angle::radians(FRAC_PI_2)
331 .positive()
332 .approx_eq(&Angle::frac_pi_2()));
333 assert!(Angle::radians(-FRAC_PI_2)
334 .positive()
335 .approx_eq(&Angle::radians(3.0 * FRAC_PI_2)));
336 assert!(Angle::radians(3.0 * FRAC_PI_2)
337 .positive()
338 .approx_eq(&Angle::radians(3.0 * FRAC_PI_2)));
339 assert!(Angle::radians(5.0 * FRAC_PI_2)
340 .positive()
341 .approx_eq(&Angle::frac_pi_2()));
342 assert!(Angle::radians(2.0 * PI)
343 .positive()
344 .approx_eq(&Angle::zero()));
345 assert!(Angle::radians(-2.0 * PI)
346 .positive()
347 .approx_eq(&Angle::zero()));
348 assert!(Angle::radians(PI).positive().approx_eq(&Angle::pi()));
349 assert!(Angle::radians(-PI).positive().approx_eq(&Angle::pi()));
350
351 assert!(Angle::radians(FRAC_PI_2)
352 .signed()
353 .approx_eq(&Angle::frac_pi_2()));
354 assert!(Angle::radians(3.0 * FRAC_PI_2)
355 .signed()
356 .approx_eq(&-Angle::frac_pi_2()));
357 assert!(Angle::radians(5.0 * FRAC_PI_2)
358 .signed()
359 .approx_eq(&Angle::frac_pi_2()));
360 assert!(Angle::radians(2.0 * PI).signed().approx_eq(&Angle::zero()));
361 assert!(Angle::radians(-2.0 * PI).signed().approx_eq(&Angle::zero()));
362 assert!(Angle::radians(-PI).signed().approx_eq(&Angle::pi()));
363 assert!(Angle::radians(PI).signed().approx_eq(&Angle::pi()));
364}
365
366#[test]
367fn lerp() {
368 type A = Angle<f32>;
369
370 let a = A::radians(1.0);
371 let b = A::radians(2.0);
372 assert!(a.lerp(b, 0.25).approx_eq(&Angle::radians(1.25)));
373 assert!(a.lerp(b, 0.5).approx_eq(&Angle::radians(1.5)));
374 assert!(a.lerp(b, 0.75).approx_eq(&Angle::radians(1.75)));
375 assert!(a
376 .lerp(b + A::two_pi(), 0.75)
377 .approx_eq(&Angle::radians(1.75)));
378 assert!(a
379 .lerp(b - A::two_pi(), 0.75)
380 .approx_eq(&Angle::radians(1.75)));
381 assert!(a
382 .lerp(b + A::two_pi() * 5.0, 0.75)
383 .approx_eq(&Angle::radians(1.75)));
384}
385
386#[test]
387fn sum() {
388 type A = Angle<f32>;
389 let angles = [A::radians(1.0), A::radians(2.0), A::radians(3.0)];
390 let sum = A::radians(6.0);
391 assert_eq!(angles.iter().sum::<A>(), sum);
392}