euclid/
trig.rs

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