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);
81