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