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 | /// Trait for basic trigonometry functions, so they can be used on generic numeric types |
11 | pub trait Trig { |
12 | fn sin(self) -> Self; |
13 | fn cos(self) -> Self; |
14 | fn tan(self) -> Self; |
15 | fn fast_atan2(y: Self, x: Self) -> Self; |
16 | fn degrees_to_radians(deg: Self) -> Self; |
17 | fn radians_to_degrees(rad: Self) -> Self; |
18 | } |
19 | |
20 | macro_rules! trig { |
21 | ($ty:ident) => { |
22 | impl Trig for $ty { |
23 | #[inline] |
24 | fn sin(self) -> $ty { |
25 | num_traits::Float::sin(self) |
26 | } |
27 | #[inline] |
28 | fn cos(self) -> $ty { |
29 | num_traits::Float::cos(self) |
30 | } |
31 | #[inline] |
32 | fn tan(self) -> $ty { |
33 | num_traits::Float::tan(self) |
34 | } |
35 | |
36 | /// A slightly faster approximation of `atan2`. |
37 | /// |
38 | /// Note that it does not deal with the case where both x and y are 0. |
39 | #[inline] |
40 | fn fast_atan2(y: $ty, x: $ty) -> $ty { |
41 | // This macro is used with f32 and f64 and clippy warns about the extra |
42 | // precision with f32. |
43 | #![cfg_attr(feature = "cargo-clippy" , allow(excessive_precision))] |
44 | |
45 | // See https://math.stackexchange.com/questions/1098487/atan2-faster-approximation#1105038 |
46 | use core::$ty::consts; |
47 | let x_abs = num_traits::Float::abs(x); |
48 | let y_abs = num_traits::Float::abs(y); |
49 | let a = x_abs.min(y_abs) / x_abs.max(y_abs); |
50 | let s = a * a; |
51 | let mut result = |
52 | ((-0.046_496_474_9 * s + 0.159_314_22) * s - 0.327_622_764) * s * a + a; |
53 | if y_abs > x_abs { |
54 | result = consts::FRAC_PI_2 - result; |
55 | } |
56 | if x < 0.0 { |
57 | result = consts::PI - result |
58 | } |
59 | if y < 0.0 { |
60 | result = -result |
61 | } |
62 | |
63 | result |
64 | } |
65 | |
66 | #[inline] |
67 | fn degrees_to_radians(deg: Self) -> Self { |
68 | deg.to_radians() |
69 | } |
70 | |
71 | #[inline] |
72 | fn radians_to_degrees(rad: Self) -> Self { |
73 | rad.to_degrees() |
74 | } |
75 | } |
76 | }; |
77 | } |
78 | |
79 | trig!(f32); |
80 | trig!(f64); |
81 | |