1use core::{
2 f64::{
3 self,
4 consts::{FRAC_PI_2, PI, TAU},
5 },
6 ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign},
7};
8use vexide::{devices::position::Position, float::Float};
9
10#[derive(Default, Debug, Clone, Copy, PartialEq)]
12pub struct Angle(f64);
13
14impl Angle {
15 pub const ZERO: Self = Self(0.0);
19
20 pub const QUARTER_TURN: Self = Self(FRAC_PI_2);
22
23 pub const HALF_TURN: Self = Self(PI);
25
26 pub const FULL_TURN: Self = Self(TAU);
28
29 pub const MIN: Self = Self(f64::MIN);
33
34 pub const MAX: Self = Self(f64::MAX);
38
39 pub const EPSILON: Self = Self(f64::EPSILON);
43
44 #[inline]
48 #[must_use]
49 pub const fn from_radians(radians: f64) -> Self {
50 Self(radians)
51 }
52
53 #[must_use]
55 pub const fn from_gradians(gradians: f64) -> Self {
56 Self(gradians * (PI / 200.0))
57 }
58
59 #[inline]
61 #[must_use]
62 pub const fn from_degrees(degrees: f64) -> Self {
63 Self(degrees.to_radians())
64 }
65
66 #[inline]
68 #[must_use]
69 pub const fn from_turns(turns: f64) -> Self {
70 Self(turns * TAU)
71 }
72
73 #[inline]
78 #[must_use]
79 pub fn asin(y: f64) -> Self {
80 Self(y.asin())
81 }
82
83 #[inline]
86 #[must_use]
87 pub fn acos(x: f64) -> Self {
88 Self(x.acos())
89 }
90
91 #[inline]
94 #[must_use]
95 pub fn atan(tan: f64) -> Self {
96 Self(tan.atan())
97 }
98
99 #[inline]
101 #[must_use]
102 pub fn atan2(y: f64, x: f64) -> Self {
103 Self(y.atan2(x))
104 }
105
106 #[inline]
108 #[must_use]
109 pub const fn as_degrees(&self) -> f64 {
110 self.0.to_degrees()
111 }
112
113 #[inline]
115 #[must_use]
116 pub fn as_turns(&self) -> f64 {
117 self.0 / TAU
118 }
119
120 #[inline]
122 #[must_use]
123 pub const fn as_radians(&self) -> f64 {
124 self.0
125 }
126
127 #[inline]
129 #[must_use]
130 pub const fn as_gradians(&self) -> f64 {
131 self.0 * (200.0 / PI)
132 }
133
134 #[inline]
136 #[must_use]
137 pub fn wrapped(&self) -> Self {
138 Self((-self.0 + PI).rem_euclid(TAU) - PI)
139 }
140
141 #[inline]
143 #[must_use]
144 pub fn wrapped_positive(&self) -> Self {
145 Self(self.0.rem_euclid(TAU))
146 }
147
148 #[inline]
150 #[must_use = "this returns the result of the operation, without modifying the original"]
151 pub const fn abs(self) -> Self {
152 Self(self.0.abs())
153 }
154
155 #[inline]
161 #[must_use = "this returns the result of the operation, without modifying the original"]
162 pub const fn signum(self) -> f64 {
163 self.0.signum()
164 }
165
166 #[inline]
180 #[must_use = "this returns the result of the operation, without modifying the original"]
181 pub const fn copysign(self, sign: Self) -> Self {
182 Self(self.0.copysign(sign.0))
183 }
184
185 #[inline]
193 #[must_use = "this returns the result of the operation, without modifying the original"]
194 pub fn mul_add(self, a: Self, b: Self) -> Self {
195 Self(self.0.mul_add(a.0, b.0))
196 }
197
198 #[inline]
200 #[must_use = "this returns the result of the operation, without modifying the original"]
201 pub fn div_euclid(self, rhs: Self) -> Self {
202 Self(self.0.div_euclid(rhs.0))
203 }
204
205 #[inline]
210 #[must_use = "this returns the result of the operation, without modifying the original"]
211 pub fn abs_sub(self, other: Self) -> Self {
212 #[allow(deprecated)]
213 Self(self.0.abs_sub(other.0))
214 }
215
216 #[inline]
218 #[must_use = "this returns the result of the operation, without modifying the original"]
219 pub fn sin(self) -> f64 {
220 self.0.sin()
221 }
222
223 #[inline]
225 #[must_use = "this returns the result of the operation, without modifying the original"]
226 pub fn cos(self) -> f64 {
227 self.0.cos()
228 }
229
230 #[inline]
232 #[must_use = "this returns the result of the operation, without modifying the original"]
233 pub fn tan(self) -> f64 {
234 self.0.tan()
235 }
236
237 #[inline]
240 #[must_use = "this returns the result of the operation, without modifying the original"]
241 pub fn sin_cos(self) -> (f64, f64) {
242 self.0.sin_cos()
243 }
244}
245
246impl From<Position> for Angle {
249 fn from(value: Position) -> Self {
250 Self::from_degrees(value.as_degrees())
251 }
252}
253
254impl Add<Angle> for Angle {
257 type Output = Self;
258
259 #[inline]
260 fn add(self, rhs: Self) -> Self::Output {
261 Self(self.0 + rhs.0)
262 }
263}
264
265impl Sub<Angle> for Angle {
266 type Output = Self;
267
268 #[inline]
269 fn sub(self, rhs: Self) -> Self::Output {
270 Self(self.0 - rhs.0)
271 }
272}
273
274impl Mul<f64> for Angle {
275 type Output = Self;
276
277 #[inline]
278 fn mul(self, rhs: f64) -> Self::Output {
279 Self(self.0 * rhs)
280 }
281}
282
283impl Div<f64> for Angle {
284 type Output = Self;
285
286 #[inline]
287 fn div(self, rhs: f64) -> Self::Output {
288 Self(self.0 / rhs)
289 }
290}
291
292impl AddAssign<Angle> for Angle {
293 #[inline]
294 fn add_assign(&mut self, rhs: Self) {
295 self.0 += rhs.0;
296 }
297}
298
299impl SubAssign<Angle> for Angle {
300 #[inline]
301 fn sub_assign(&mut self, rhs: Self) {
302 self.0 -= rhs.0;
303 }
304}
305
306impl MulAssign<f64> for Angle {
307 #[inline]
308 fn mul_assign(&mut self, rhs: f64) {
309 self.0 *= rhs;
310 }
311}
312
313impl DivAssign<f64> for Angle {
314 #[inline]
315 fn div_assign(&mut self, rhs: f64) {
316 self.0 /= rhs;
317 }
318}
319
320impl Neg for Angle {
321 type Output = Self;
322
323 #[inline]
324 fn neg(self) -> Self::Output {
325 Self(-self.0)
326 }
327}
328
329pub trait IntoAngle {
334 fn deg(self) -> Angle;
336
337 fn grad(self) -> Angle;
339
340 fn rad(self) -> Angle;
342
343 fn turns(self) -> Angle;
345}
346
347impl IntoAngle for f64 {
348 fn deg(self) -> Angle {
349 Angle::from_degrees(self)
350 }
351
352 fn rad(self) -> Angle {
353 Angle::from_radians(self)
354 }
355
356 fn grad(self) -> Angle {
357 Angle::from_gradians(self)
358 }
359
360 fn turns(self) -> Angle {
361 Angle::from_turns(self)
362 }
363}