1use crate::{Point, Rectangle, Vector};
2
3use std::f32::consts::{FRAC_PI_2, PI};
4use std::fmt::Display;
5use std::ops::{Add, AddAssign, Div, Mul, RangeInclusive, Rem, Sub, SubAssign};
6
7#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
9pub struct Degrees(pub f32);
10
11impl Degrees {
12 pub const RANGE: RangeInclusive<Self> = Self(0.0)..=Self(360.0);
14}
15
16impl PartialEq<f32> for Degrees {
17 fn eq(&self, other: &f32) -> bool {
18 self.0.eq(other)
19 }
20}
21
22impl PartialOrd<f32> for Degrees {
23 fn partial_cmp(&self, other: &f32) -> Option<std::cmp::Ordering> {
24 self.0.partial_cmp(other)
25 }
26}
27
28impl From<f32> for Degrees {
29 fn from(degrees: f32) -> Self {
30 Self(degrees)
31 }
32}
33
34impl From<u8> for Degrees {
35 fn from(degrees: u8) -> Self {
36 Self(f32::from(degrees))
37 }
38}
39
40impl From<Degrees> for f32 {
41 fn from(degrees: Degrees) -> Self {
42 degrees.0
43 }
44}
45
46impl From<Degrees> for f64 {
47 fn from(degrees: Degrees) -> Self {
48 Self::from(degrees.0)
49 }
50}
51
52impl Mul<f32> for Degrees {
53 type Output = Degrees;
54
55 fn mul(self, rhs: f32) -> Self::Output {
56 Self(self.0 * rhs)
57 }
58}
59
60impl num_traits::FromPrimitive for Degrees {
61 fn from_i64(n: i64) -> Option<Self> {
62 Some(Self(n as f32))
63 }
64
65 fn from_u64(n: u64) -> Option<Self> {
66 Some(Self(n as f32))
67 }
68
69 fn from_f64(n: f64) -> Option<Self> {
70 Some(Self(n as f32))
71 }
72}
73
74impl num_traits::AsPrimitive<f32> for Degrees {
75 fn as_(self) -> f32 {
76 self.0
77 }
78}
79
80impl num_traits::AsPrimitive<f64> for Degrees {
81 fn as_(self) -> f64 {
82 f64::from(self.0)
83 }
84}
85
86#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
88pub struct Radians(pub f32);
89
90impl Radians {
91 pub const RANGE: RangeInclusive<Self> = Self(0.0)..=Self(2.0 * PI);
93
94 pub const PI: Self = Self(PI);
96
97 pub fn to_distance(&self, bounds: &Rectangle) -> (Point, Point) {
99 let angle = self.0 - FRAC_PI_2;
100 let r = Vector::new(f32::cos(angle), f32::sin(angle));
101
102 let distance_to_rect = f32::max(
103 f32::abs(r.x * bounds.width / 2.0),
104 f32::abs(r.y * bounds.height / 2.0),
105 );
106
107 let start = bounds.center() - r * distance_to_rect;
108 let end = bounds.center() + r * distance_to_rect;
109
110 (start, end)
111 }
112}
113
114impl From<Degrees> for Radians {
115 fn from(degrees: Degrees) -> Self {
116 Self(degrees.0 * PI / 180.0)
117 }
118}
119
120impl From<f32> for Radians {
121 fn from(radians: f32) -> Self {
122 Self(radians)
123 }
124}
125
126impl From<u8> for Radians {
127 fn from(radians: u8) -> Self {
128 Self(f32::from(radians))
129 }
130}
131
132impl From<Radians> for f32 {
133 fn from(radians: Radians) -> Self {
134 radians.0
135 }
136}
137
138impl From<Radians> for f64 {
139 fn from(radians: Radians) -> Self {
140 Self::from(radians.0)
141 }
142}
143
144impl num_traits::FromPrimitive for Radians {
145 fn from_i64(n: i64) -> Option<Self> {
146 Some(Self(n as f32))
147 }
148
149 fn from_u64(n: u64) -> Option<Self> {
150 Some(Self(n as f32))
151 }
152
153 fn from_f64(n: f64) -> Option<Self> {
154 Some(Self(n as f32))
155 }
156}
157
158impl num_traits::AsPrimitive<f32> for Radians {
159 fn as_(self) -> f32 {
160 self.0
161 }
162}
163
164impl num_traits::AsPrimitive<f64> for Radians {
165 fn as_(self) -> f64 {
166 f64::from(self.0)
167 }
168}
169
170impl Sub for Radians {
171 type Output = Self;
172
173 fn sub(self, rhs: Self) -> Self::Output {
174 Self(self.0 - rhs.0)
175 }
176}
177
178impl SubAssign for Radians {
179 fn sub_assign(&mut self, rhs: Self) {
180 self.0 = self.0 - rhs.0;
181 }
182}
183
184impl Add for Radians {
185 type Output = Self;
186
187 fn add(self, rhs: Self) -> Self::Output {
188 Self(self.0 + rhs.0)
189 }
190}
191
192impl Add<Degrees> for Radians {
193 type Output = Self;
194
195 fn add(self, rhs: Degrees) -> Self::Output {
196 Self(self.0 + rhs.0.to_radians())
197 }
198}
199
200impl AddAssign for Radians {
201 fn add_assign(&mut self, rhs: Radians) {
202 self.0 = self.0 + rhs.0;
203 }
204}
205
206impl Mul for Radians {
207 type Output = Self;
208
209 fn mul(self, rhs: Radians) -> Self::Output {
210 Radians(self.0 * rhs.0)
211 }
212}
213
214impl Mul<f32> for Radians {
215 type Output = Self;
216
217 fn mul(self, rhs: f32) -> Self::Output {
218 Self(self.0 * rhs)
219 }
220}
221
222impl Mul<Radians> for f32 {
223 type Output = Radians;
224
225 fn mul(self, rhs: Radians) -> Self::Output {
226 Radians(self * rhs.0)
227 }
228}
229
230impl Div<f32> for Radians {
231 type Output = Self;
232
233 fn div(self, rhs: f32) -> Self::Output {
234 Radians(self.0 / rhs)
235 }
236}
237
238impl Div for Radians {
239 type Output = Self;
240
241 fn div(self, rhs: Self) -> Self::Output {
242 Self(self.0 / rhs.0)
243 }
244}
245
246impl Rem for Radians {
247 type Output = Self;
248
249 fn rem(self, rhs: Self) -> Self::Output {
250 Self(self.0 % rhs.0)
251 }
252}
253
254impl PartialEq<f32> for Radians {
255 fn eq(&self, other: &f32) -> bool {
256 self.0.eq(other)
257 }
258}
259
260impl PartialOrd<f32> for Radians {
261 fn partial_cmp(&self, other: &f32) -> Option<std::cmp::Ordering> {
262 self.0.partial_cmp(other)
263 }
264}
265
266impl Display for Radians {
267 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
268 write!(f, "{} rad", self.0)
269 }
270}