| 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 | #![allow(clippy::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 | |