radiant_utils/math/
angle.rs

1use prelude::*;
2use super::Vec2;
3
4/// An Angle between -PI and PI.
5#[cfg_attr(feature = "serialize-serde", derive(Deserialize, Serialize))]
6#[derive(Copy, Clone, PartialEq, PartialOrd)]
7pub struct Angle<T = f32>(pub T);
8
9impl<T> Angle<T> where T: Float {
10    /// Returns the angle's value in radians.
11    pub fn to_radians(self: &Self) -> T {
12        self.0
13    }
14    /// Returns the angle's value in degrees.
15    pub fn to_degrees(self: &Self) -> T {
16        self.0.to_degrees()
17    }
18    /// Returns a vector pointing in the direction of the angle.
19    #[deprecated(since = "0.2.2", note = "use Vec2::from() instead")]
20    pub fn to_vec2(self: &Self) -> Vec2<T> {
21        Vec2::from(*self)
22    }
23    /// Creates an angle from a radians value.
24    pub fn from_radians(radians: T) -> Self {
25        Angle::<T>(radians)
26    }
27    /// Creates an angle from a degrees value.
28    pub fn from_degrees(degrees: T) -> Self {
29        Self::from_radians(degrees.to_radians())
30    }
31    /// Returns a normalized version of the angle.
32    #[allow(non_snake_case)]
33    pub fn normalize(self: &Self) -> Self {
34        let PI = NumCast::from(f64::consts::PI).unwrap();
35        if self.0.abs() > PI {
36            let two_PI = NumCast::from(f64::consts::PI * 2.0).unwrap();
37            Angle(self.0 - two_PI * ((self.0 + PI) / two_PI).floor())
38        } else {
39            *self
40        }
41    }
42    /// Returns smallest directional angle between self and target.
43    pub fn diff(self: &Self, other: Self) -> Self {
44        let mut this = *self;
45        this.align_with(other);
46        this - other
47    }
48    /// Mutates self so that subtracting the target will yield the smallest directional angle between self and target.
49    #[allow(non_snake_case)]
50    pub fn align_with(self: &mut Self, target: Self) -> &mut Self {
51
52        let PI = NumCast::from(f64::consts::PI).unwrap();
53        let two_PI = NumCast::from(f64::consts::PI * 2.0).unwrap();
54
55        // normalize
56
57        if self.0.abs() > PI {
58            self.0 = self.0 - two_PI * ((self.0 + PI) / two_PI).floor();
59        }
60
61        let target_radians = if target.0.abs() > PI {
62            target.0 - two_PI * ((target.0 + PI) / two_PI).floor()
63        } else {
64            target.0
65        };
66
67        // adjust self if self-other would exceend +/-PI
68
69        let diff = self.0 - target_radians;
70
71        if diff.abs() > PI {
72            self.0 = self.0 - diff.signum() * two_PI;
73        }
74
75        self
76    }
77}
78
79// from vector
80
81impl<T> From<Vec2<T>> for Angle<T> where T: Float {
82    fn from(vec: Vec2<T>) -> Angle<T> {
83        Angle(vec.1.atan2(vec.0))
84    }
85}
86
87// from/to float
88
89impl<T> From<T> for Angle<T> where T: Float {
90    fn from(other: T) -> Angle<T> {
91        Angle(other)
92    }
93}
94
95impl From<Angle<f64>> for f64 {
96    fn from(other: Angle<f64>) -> f64 {
97        other.to_radians() as f64
98    }
99}
100
101impl From<Angle<f32>> for f32 {
102    fn from(other: Angle<f32>) -> f32 {
103        other.to_radians() as f32
104    }
105}
106
107impl<'a> From<&'a Angle<f64>> for f64 {
108    fn from(other: &'a Angle<f64>) -> f64 {
109        other.to_radians() as f64
110    }
111}
112
113impl<'a> From<&'a Angle<f32>> for f32 {
114    fn from(other: &'a Angle<f32>) -> f32 {
115        other.to_radians() as f32
116    }
117}
118
119// Default
120
121impl<T> Default for Angle<T> where T: Float {
122    fn default() -> Self {
123        Angle(T::zero())
124    }
125}
126
127// TODO: why?
128
129impl<T> ToPrimitive for Angle<T> where T: Float {
130    fn to_f64(self: &Self) -> Option<f64> {
131        NumCast::from(self.to_radians())
132    }
133    fn to_f32(self: &Self) -> Option<f32> {
134        NumCast::from(self.to_radians())
135    }
136    fn to_i64(self: &Self) -> Option<i64> {
137        NumCast::from(self.to_radians())
138    }
139    fn to_u64(self: &Self) -> Option<u64> {
140        let value = self.to_radians();
141        if value >= T::zero() { NumCast::from(self.to_radians()) } else { None }
142    }
143}
144
145impl<T> FromPrimitive for Angle<T> where T: Float {
146    fn from_f64(n: f64) -> Option<Angle<T>> {
147        Some(Angle(NumCast::from(n).unwrap()))
148    }
149    fn from_f32(n: f32) -> Option<Angle<T>> {
150        Some(Angle(NumCast::from(n).unwrap()))
151    }
152    fn from_i64(n: i64) -> Option<Angle<T>> {
153        Some(Angle(NumCast::from(n).unwrap()))
154    }
155    fn from_u64(n: u64) -> Option<Angle<T>> {
156        Some(Angle(NumCast::from(n).unwrap()))
157    }
158}
159
160// operators
161
162impl<T> Neg for Angle<T> where T: Float {
163    type Output = Angle<T>;
164
165    fn neg(self) -> Angle<T> {
166        Angle::<T>(-self.0)
167    }
168}
169
170impl<T> Add for Angle<T> where T: Float {
171    type Output = Angle<T>;
172    fn add(self, other: Angle<T>) -> Angle<T> {
173        Angle::<T>(self.0 + other.0)
174    }
175}
176
177impl<T> AddAssign for Angle<T> where T: Float {
178    fn add_assign(self: &mut Self, other: Angle<T>) {
179        *self = Angle::<T>(self.0 + other.0)
180    }
181}
182
183impl<T> Sub for Angle<T> where T: Float {
184    type Output = Angle<T>;
185    fn sub(self, other: Angle<T>) -> Angle<T> {
186        Angle::<T>(self.0 - other.0)
187    }
188}
189
190impl<T> SubAssign for Angle<T> where T: Float {
191    fn sub_assign(self: &mut Self, other: Angle<T>) {
192        *self = Angle::<T>(self.0 - other.0)
193    }
194}
195
196impl<T> Mul<Angle<T>> for Angle<T> where T: Float {
197    type Output = Angle<T>;
198    fn mul(self, other: Angle<T>) -> Angle<T> {
199        Angle::<T>(self.0 * other.0)
200    }
201}
202
203impl<T> MulAssign for Angle<T> where T: Float {
204    fn mul_assign(&mut self, other: Angle<T>) {
205        *self = Angle::<T>(self.0 * other.0)
206    }
207}
208
209impl<T> Mul<T> for Angle<T> where T: Float {
210    type Output = Angle<T>;
211    fn mul(self, other: T) -> Angle<T> {
212        Angle::<T>(self.0 * other)
213    }
214}
215
216impl<T> Div<Angle<T>> for Angle<T> where T: Float {
217    type Output = Angle<T>;
218    fn div(self, other: Angle<T>) -> Angle<T> {
219        Angle::<T>(self.0 / other.0)
220    }
221}
222
223impl<T> DivAssign for Angle<T> where T: Float {
224    fn div_assign(&mut self, other: Angle<T>) {
225        *self = Angle::<T>(self.0 / other.0)
226    }
227}
228
229impl<T> Div<T> for Angle<T> where T: Float {
230    type Output = Angle<T>;
231    fn div(self, other: T) -> Angle<T> {
232        Angle::<T>(self.0 / other)
233    }
234}
235
236// as radiant uniform
237
238#[cfg(feature = "uniforms")]
239use radiant_rs::{Uniform, AsUniform};
240
241#[cfg(feature = "uniforms")]
242impl AsUniform for Angle<f32> {
243    fn as_uniform(&self) -> Uniform {
244        Uniform::Float(self.0)
245    }
246}
247
248#[cfg(feature = "uniforms")]
249impl AsUniform for Angle<f64> {
250    fn as_uniform(&self) -> Uniform {
251        Uniform::Double(self.0)
252    }
253}
254
255// debug print
256
257impl<T> Debug for Angle<T> where T: Debug + Float {
258    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
259        write!(f, "Angle({:?})", self.0)
260    }
261}