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 {
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
79trig!(f32);
80trig!(f64);