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}