1 | // Copyright 2013 The Servo Project Developers. See the COPYRIGHT |
2 | // file at the top-level directory of this distribution. |
3 | // |
4 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or |
5 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license |
6 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your |
7 | // option. This file may not be copied, modified, or distributed |
8 | // except according to those terms. |
9 | |
10 | use crate::approxeq::ApproxEq; |
11 | use crate::trig::Trig; |
12 | use core::cmp::{Eq, PartialEq}; |
13 | use core::hash::Hash; |
14 | use core::iter::Sum; |
15 | use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Rem, Sub, SubAssign}; |
16 | use num_traits::real::Real; |
17 | use num_traits::{Float, FloatConst, NumCast, One, Zero}; |
18 | #[cfg (feature = "serde" )] |
19 | use serde::{Deserialize, Serialize}; |
20 | #[cfg (feature = "bytemuck" )] |
21 | use bytemuck::{Zeroable, Pod}; |
22 | |
23 | /// An angle in radians |
24 | #[derive (Copy, Clone, Default, Debug, PartialEq, Eq, PartialOrd, Hash)] |
25 | #[cfg_attr (feature = "serde" , derive(Serialize, Deserialize))] |
26 | #[cfg_attr (feature = "arbitrary" , derive(arbitrary::Arbitrary))] |
27 | pub struct Angle<T> { |
28 | pub radians: T, |
29 | } |
30 | |
31 | #[cfg (feature = "bytemuck" )] |
32 | unsafe impl<T: Zeroable> Zeroable for Angle<T> {} |
33 | |
34 | #[cfg (feature = "bytemuck" )] |
35 | unsafe impl<T: Pod> Pod for Angle<T> {} |
36 | |
37 | impl<T> Angle<T> { |
38 | #[inline ] |
39 | pub fn radians(radians: T) -> Self { |
40 | Angle { radians } |
41 | } |
42 | |
43 | #[inline ] |
44 | pub fn get(self) -> T { |
45 | self.radians |
46 | } |
47 | } |
48 | |
49 | impl<T> Angle<T> |
50 | where |
51 | T: Trig, |
52 | { |
53 | #[inline ] |
54 | pub fn degrees(deg: T) -> Self { |
55 | Angle { |
56 | radians: T::degrees_to_radians(deg), |
57 | } |
58 | } |
59 | |
60 | #[inline ] |
61 | pub fn to_degrees(self) -> T { |
62 | T::radians_to_degrees(self.radians) |
63 | } |
64 | } |
65 | |
66 | impl<T> Angle<T> |
67 | where |
68 | T: Rem<Output = T> + Sub<Output = T> + Add<Output = T> + Zero + FloatConst + PartialOrd + Copy, |
69 | { |
70 | /// Returns this angle in the [0..2*PI[ range. |
71 | pub fn positive(&self) -> Self { |
72 | let two_pi: T = T::PI() + T::PI(); |
73 | let mut a: T = self.radians % two_pi; |
74 | if a < T::zero() { |
75 | a = a + two_pi; |
76 | } |
77 | Angle::radians(a) |
78 | } |
79 | |
80 | /// Returns this angle in the ]-PI..PI] range. |
81 | pub fn signed(&self) -> Self { |
82 | Angle::pi() - (Angle::pi() - *self).positive() |
83 | } |
84 | } |
85 | |
86 | impl<T> Angle<T> |
87 | where |
88 | T: Rem<Output = T> |
89 | + Mul<Output = T> |
90 | + Sub<Output = T> |
91 | + Add<Output = T> |
92 | + One |
93 | + FloatConst |
94 | + Copy, |
95 | { |
96 | /// Returns the shortest signed angle between two angles. |
97 | /// |
98 | /// Takes wrapping and signs into account. |
99 | pub fn angle_to(&self, to: Self) -> Self { |
100 | let two: T = T::one() + T::one(); |
101 | let max: T = T::PI() * two; |
102 | let d: T = (to.radians - self.radians) % max; |
103 | |
104 | Angle::radians(two * d % max - d) |
105 | } |
106 | |
107 | /// Linear interpolation between two angles, using the shortest path. |
108 | pub fn lerp(&self, other: Self, t: T) -> Self { |
109 | *self + self.angle_to(other) * t |
110 | } |
111 | } |
112 | |
113 | impl<T> Angle<T> |
114 | where |
115 | T: Float, |
116 | { |
117 | /// Returns true if the angle is a finite number. |
118 | #[inline ] |
119 | pub fn is_finite(self) -> bool { |
120 | self.radians.is_finite() |
121 | } |
122 | } |
123 | |
124 | impl<T> Angle<T> |
125 | where |
126 | T: Real, |
127 | { |
128 | /// Returns (sin(self), cos(self)). |
129 | pub fn sin_cos(self) -> (T, T) { |
130 | self.radians.sin_cos() |
131 | } |
132 | } |
133 | |
134 | impl<T> Angle<T> |
135 | where |
136 | T: Zero, |
137 | { |
138 | pub fn zero() -> Self { |
139 | Angle::radians(T::zero()) |
140 | } |
141 | } |
142 | |
143 | impl<T> Angle<T> |
144 | where |
145 | T: FloatConst + Add<Output = T>, |
146 | { |
147 | pub fn pi() -> Self { |
148 | Angle::radians(T::PI()) |
149 | } |
150 | |
151 | pub fn two_pi() -> Self { |
152 | Angle::radians(T::PI() + T::PI()) |
153 | } |
154 | |
155 | pub fn frac_pi_2() -> Self { |
156 | Angle::radians(T::FRAC_PI_2()) |
157 | } |
158 | |
159 | pub fn frac_pi_3() -> Self { |
160 | Angle::radians(T::FRAC_PI_3()) |
161 | } |
162 | |
163 | pub fn frac_pi_4() -> Self { |
164 | Angle::radians(T::FRAC_PI_4()) |
165 | } |
166 | } |
167 | |
168 | impl<T> Angle<T> |
169 | where |
170 | T: NumCast + Copy, |
171 | { |
172 | /// Cast from one numeric representation to another. |
173 | #[inline ] |
174 | pub fn cast<NewT: NumCast>(&self) -> Angle<NewT> { |
175 | self.try_cast().unwrap() |
176 | } |
177 | |
178 | /// Fallible cast from one numeric representation to another. |
179 | pub fn try_cast<NewT: NumCast>(&self) -> Option<Angle<NewT>> { |
180 | NumCast::from(self.radians).map(|radians| Angle { radians }) |
181 | } |
182 | |
183 | // Convenience functions for common casts. |
184 | |
185 | /// Cast angle to `f32`. |
186 | #[inline ] |
187 | pub fn to_f32(&self) -> Angle<f32> { |
188 | self.cast() |
189 | } |
190 | |
191 | /// Cast angle `f64`. |
192 | #[inline ] |
193 | pub fn to_f64(&self) -> Angle<f64> { |
194 | self.cast() |
195 | } |
196 | } |
197 | |
198 | impl<T: Add<T, Output = T>> Add for Angle<T> { |
199 | type Output = Self; |
200 | fn add(self, other: Self) -> Self { |
201 | Self::radians(self.radians + other.radians) |
202 | } |
203 | } |
204 | |
205 | impl<T: Copy + Add<T, Output = T>> Add<&Self> for Angle<T> { |
206 | type Output = Self; |
207 | fn add(self, other: &Self) -> Self { |
208 | Self::radians(self.radians + other.radians) |
209 | } |
210 | } |
211 | |
212 | impl<T: Add + Zero> Sum for Angle<T> { |
213 | fn sum<I: Iterator<Item=Self>>(iter: I) -> Self { |
214 | iter.fold(Self::zero(), f:Add::add) |
215 | } |
216 | } |
217 | |
218 | impl<'a, T: 'a + Add + Copy + Zero> Sum<&'a Self> for Angle<T> { |
219 | fn sum<I: Iterator<Item=&'a Self>>(iter: I) -> Self { |
220 | iter.fold(Self::zero(), f:Add::add) |
221 | } |
222 | } |
223 | |
224 | impl<T: AddAssign<T>> AddAssign for Angle<T> { |
225 | fn add_assign(&mut self, other: Angle<T>) { |
226 | self.radians += other.radians; |
227 | } |
228 | } |
229 | |
230 | impl<T: Sub<T, Output = T>> Sub<Angle<T>> for Angle<T> { |
231 | type Output = Angle<T>; |
232 | fn sub(self, other: Angle<T>) -> <Self as Sub>::Output { |
233 | Angle::radians(self.radians - other.radians) |
234 | } |
235 | } |
236 | |
237 | impl<T: SubAssign<T>> SubAssign for Angle<T> { |
238 | fn sub_assign(&mut self, other: Angle<T>) { |
239 | self.radians -= other.radians; |
240 | } |
241 | } |
242 | |
243 | impl<T: Div<T, Output = T>> Div<Angle<T>> for Angle<T> { |
244 | type Output = T; |
245 | #[inline ] |
246 | fn div(self, other: Angle<T>) -> T { |
247 | self.radians / other.radians |
248 | } |
249 | } |
250 | |
251 | impl<T: Div<T, Output = T>> Div<T> for Angle<T> { |
252 | type Output = Angle<T>; |
253 | #[inline ] |
254 | fn div(self, factor: T) -> Angle<T> { |
255 | Angle::radians(self.radians / factor) |
256 | } |
257 | } |
258 | |
259 | impl<T: DivAssign<T>> DivAssign<T> for Angle<T> { |
260 | fn div_assign(&mut self, factor: T) { |
261 | self.radians /= factor; |
262 | } |
263 | } |
264 | |
265 | impl<T: Mul<T, Output = T>> Mul<T> for Angle<T> { |
266 | type Output = Angle<T>; |
267 | #[inline ] |
268 | fn mul(self, factor: T) -> Angle<T> { |
269 | Angle::radians(self.radians * factor) |
270 | } |
271 | } |
272 | |
273 | impl<T: MulAssign<T>> MulAssign<T> for Angle<T> { |
274 | fn mul_assign(&mut self, factor: T) { |
275 | self.radians *= factor; |
276 | } |
277 | } |
278 | |
279 | impl<T: Neg<Output = T>> Neg for Angle<T> { |
280 | type Output = Self; |
281 | fn neg(self) -> Self { |
282 | Angle::radians(-self.radians) |
283 | } |
284 | } |
285 | |
286 | impl<T: ApproxEq<T>> ApproxEq<T> for Angle<T> { |
287 | #[inline ] |
288 | fn approx_epsilon() -> T { |
289 | T::approx_epsilon() |
290 | } |
291 | |
292 | #[inline ] |
293 | fn approx_eq_eps(&self, other: &Angle<T>, approx_epsilon: &T) -> bool { |
294 | self.radians.approx_eq_eps(&other.radians, approx_epsilon) |
295 | } |
296 | } |
297 | |
298 | #[test ] |
299 | fn wrap_angles() { |
300 | use core::f32::consts::{FRAC_PI_2, PI}; |
301 | |
302 | assert!(Angle::radians(0.0).positive().approx_eq(&Angle::zero())); |
303 | assert!(Angle::radians(FRAC_PI_2) |
304 | .positive() |
305 | .approx_eq(&Angle::frac_pi_2())); |
306 | assert!(Angle::radians(-FRAC_PI_2) |
307 | .positive() |
308 | .approx_eq(&Angle::radians(3.0 * FRAC_PI_2))); |
309 | assert!(Angle::radians(3.0 * FRAC_PI_2) |
310 | .positive() |
311 | .approx_eq(&Angle::radians(3.0 * FRAC_PI_2))); |
312 | assert!(Angle::radians(5.0 * FRAC_PI_2) |
313 | .positive() |
314 | .approx_eq(&Angle::frac_pi_2())); |
315 | assert!(Angle::radians(2.0 * PI) |
316 | .positive() |
317 | .approx_eq(&Angle::zero())); |
318 | assert!(Angle::radians(-2.0 * PI) |
319 | .positive() |
320 | .approx_eq(&Angle::zero())); |
321 | assert!(Angle::radians(PI).positive().approx_eq(&Angle::pi())); |
322 | assert!(Angle::radians(-PI).positive().approx_eq(&Angle::pi())); |
323 | |
324 | assert!(Angle::radians(FRAC_PI_2) |
325 | .signed() |
326 | .approx_eq(&Angle::frac_pi_2())); |
327 | assert!(Angle::radians(3.0 * FRAC_PI_2) |
328 | .signed() |
329 | .approx_eq(&-Angle::frac_pi_2())); |
330 | assert!(Angle::radians(5.0 * FRAC_PI_2) |
331 | .signed() |
332 | .approx_eq(&Angle::frac_pi_2())); |
333 | assert!(Angle::radians(2.0 * PI).signed().approx_eq(&Angle::zero())); |
334 | assert!(Angle::radians(-2.0 * PI).signed().approx_eq(&Angle::zero())); |
335 | assert!(Angle::radians(-PI).signed().approx_eq(&Angle::pi())); |
336 | assert!(Angle::radians(PI).signed().approx_eq(&Angle::pi())); |
337 | } |
338 | |
339 | #[test ] |
340 | fn lerp() { |
341 | type A = Angle<f32>; |
342 | |
343 | let a: Angle = A::radians(1.0); |
344 | let b: Angle = A::radians(2.0); |
345 | assert!(a.lerp(b, 0.25).approx_eq(&Angle::radians(1.25))); |
346 | assert!(a.lerp(b, 0.5).approx_eq(&Angle::radians(1.5))); |
347 | assert!(a.lerp(b, 0.75).approx_eq(&Angle::radians(1.75))); |
348 | assert!(a |
349 | .lerp(b + A::two_pi(), 0.75) |
350 | .approx_eq(&Angle::radians(1.75))); |
351 | assert!(a |
352 | .lerp(b - A::two_pi(), 0.75) |
353 | .approx_eq(&Angle::radians(1.75))); |
354 | assert!(a |
355 | .lerp(b + A::two_pi() * 5.0, 0.75) |
356 | .approx_eq(&Angle::radians(1.75))); |
357 | } |
358 | |
359 | #[test ] |
360 | fn sum() { |
361 | type A = Angle<f32>; |
362 | let angles: [Angle; 3] = [A::radians(1.0), A::radians(2.0), A::radians(3.0)]; |
363 | let sum: Angle = A::radians(6.0); |
364 | assert_eq!(angles.iter().sum::<A>(), sum); |
365 | } |
366 | |