1
2use num_traits::NumCast;
3use std::ops::{Mul, Div, Add, Sub, Neg};
4use float_cmp::{Ulps, ApproxEq};
5use FullFloat;
6use vector::Vec2;
7
8#[repr(C)]
11#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
12#[derive(Serialize, Deserialize)]
13pub struct Angle<F>(F);
14
15impl<F: FullFloat> Angle<F>
16{
17    #[inline]
19    pub fn new_radians(radians: F) -> Angle<F>
20    {
21        Angle::<F>::from_radians(radians)
22    }
23
24    pub fn from_radians(radians: F) -> Angle<F>
26    {
27        Angle(radians)
28    }
29
30    pub fn as_radians(&self) -> F {
32        self.0
33    }
34
35    #[inline]
37    pub fn new_degrees(degrees: F) -> Angle<F>
38    {
39        Angle::<F>::from_degrees(degrees)
40    }
41
42    pub fn from_degrees(degrees: F) -> Angle<F>
44    {
45        let one_eighty: F = NumCast::from(180.0_f32).unwrap();
46        Angle(F::PI() * degrees / one_eighty)
47    }
48
49    pub fn as_degrees(&self) -> F {
51        let one_eighty: F = NumCast::from(180.0_f32).unwrap();
52        self.0 * one_eighty / F::PI()
53    }
54
55    #[inline]
57    pub fn new_cycles(cycles: F) -> Angle<F>
58    {
59        Angle::<F>::from_cycles(cycles)
60    }
61
62    pub fn from_cycles(cycles: F) -> Angle<F>
64    {
65        let two: F = NumCast::from(2.0_f32).unwrap();
66        Angle(two * F::PI() * cycles)
67    }
68
69    pub fn as_cycles(&self) -> F {
71        let two: F = NumCast::from(2.0_f32).unwrap();
72        self.0 / (two * F::PI())
73    }
74
75    pub fn of_vector(vec: &Vec2<F>) -> Angle<F>
79    {
80        Angle(vec.y.atan2(vec.x))
81    }
82}
83
84impl<F: FullFloat> Mul<F> for Angle<F>
85{
86    type Output = Angle<F>;
87
88    fn mul(self, rhs: F) -> Angle<F> {
89        Angle(self.0 * rhs)
90    }
91}
92
93impl<F: FullFloat> Div<F> for Angle<F>
94{
95    type Output = Angle<F>;
96
97    fn div(self, rhs: F) -> Angle<F> {
98        Angle(self.0 / rhs)
99    }
100}
101
102impl<F: FullFloat> Add<Angle<F>> for Angle<F>
103{
104    type Output = Angle<F>;
105
106    fn add(self, rhs: Angle<F>) -> Angle<F> {
107        Angle(self.0 + rhs.0)
108    }
109}
110
111impl<F: FullFloat> Sub<Angle<F>> for Angle<F>
112{
113    type Output = Angle<F>;
114
115    fn sub(self, rhs: Angle<F>) -> Angle<F> {
116        Angle(self.0 - rhs.0)
117    }
118}
119
120impl<F: FullFloat> Neg for Angle<F> {
121    type Output = Angle<F>;
122
123    fn neg(self) -> Angle<F> {
124        Angle(-self.0)
125    }
126}
127
128impl<F: FullFloat> ApproxEq for Angle<F> {
129    type Flt = F;
130
131    fn approx_eq(&self, other: &Self,
132                 epsilon: <F as ApproxEq>::Flt,
133                 ulps: <<F as ApproxEq>::Flt as Ulps>::U) -> bool
134    {
135        self.0.approx_eq(&other.0, epsilon, ulps)
136    }
137}
138
139#[cfg(test)]
140mod tests {
141    use super::*;
142    use std::f32::consts::PI;
143    use std::f32::EPSILON;
144    use vector::Vec2;
145
146    #[test]
147    fn test_radians() {
148        let f: f32 = 1.234;
149        let a = Angle::from_radians(f);
150        assert_eq!(a.as_radians(), f);
151    }
152
153    #[test]
154    fn test_degrees() {
155        let f: f32 = 1.234;
156        let a = Angle::from_degrees(f);
157        assert_eq!(a.as_degrees(), f);
158    }
159
160    #[test]
161    fn test_cycles() {
162        let f: f32 = 1.234;
163        let a = Angle::from_cycles(f);
164        assert_eq!(a.as_cycles(), f);
165    }
166
167    #[test]
168    fn test_relations() {
169        let h1 = Angle::from_radians(PI);
170        let h2 = Angle::from_degrees(180.0);
171        let h3 = Angle::from_cycles(0.5);
172        assert!(h1.approx_eq(&h2, 2.0 * EPSILON, 2));
173        assert!(h1.approx_eq(&h3, 2.0 * EPSILON, 2));
174        assert!(h2.approx_eq(&h3, 2.0 * EPSILON, 2));
175    }
176
177    #[test]
178    fn test_vector_angle() {
179        let q1 = Vec2::new(1.0, 1.0);
180        let q2 = Vec2::new(-1.0, 1.0);
181        let q3 = Vec2::new(-1.0, -1.0);
182        let q4 = Vec2::new(1.0, -1.0);
183
184        assert!(Angle::of_vector(&q1).approx_eq(
185            &Angle::from_cycles(1.0/8.0), 2.0 * EPSILON, 2));
186        assert!(Angle::of_vector(&q2).approx_eq(
187            &Angle::from_cycles(3.0/8.0), 2.0 * EPSILON, 2));
188        assert!(Angle::of_vector(&q3).approx_eq(
189            &Angle::from_cycles(-3.0/8.0), 2.0 * EPSILON, 2));
190        assert!(Angle::of_vector(&q4).approx_eq(
191            &Angle::from_cycles(-1.0/8.0), 2.0 * EPSILON, 2));
192    }
193}