1use crate::{about_eq_hash, about_eq_ord};
2
3use super::{EQ_GRANULARITY, EQ_GRANULARITY_100, Factor, about_eq};
4
5use std::{
6 f32::consts::{PI, TAU},
7 fmt, ops,
8};
9
10#[derive(Copy, Clone, serde::Serialize, serde::Deserialize)]
18#[serde(transparent)]
19pub struct AngleRadian(pub f32);
20impl ops::Add for AngleRadian {
21 type Output = Self;
22
23 fn add(self, rhs: Self) -> Self::Output {
24 Self(self.0 + rhs.0)
25 }
26}
27impl ops::AddAssign for AngleRadian {
28 fn add_assign(&mut self, rhs: Self) {
29 self.0 += rhs.0;
30 }
31}
32impl ops::Sub for AngleRadian {
33 type Output = Self;
34
35 fn sub(self, rhs: Self) -> Self::Output {
36 Self(self.0 - rhs.0)
37 }
38}
39impl ops::SubAssign for AngleRadian {
40 fn sub_assign(&mut self, rhs: Self) {
41 self.0 -= rhs.0;
42 }
43}
44impl ops::Neg for AngleRadian {
45 type Output = Self;
46
47 fn neg(self) -> Self::Output {
48 Self(-self.0)
49 }
50}
51impl AngleRadian {
52 pub fn modulo(self) -> Self {
54 AngleRadian(self.0.rem_euclid(TAU))
55 }
56
57 pub fn lerp(self, to: Self, factor: Factor) -> Self {
59 Self(lerp(self.0, to.0, factor))
60 }
61
62 pub fn slerp(self, to: Self, factor: Factor) -> Self {
72 Self(slerp(self.0, to.0, TAU, factor))
73 }
74}
75
76impl PartialEq for AngleRadian {
77 fn eq(&self, other: &Self) -> bool {
78 about_eq(self.0, other.0, EQ_GRANULARITY)
79 }
80}
81impl Eq for AngleRadian {}
82impl std::hash::Hash for AngleRadian {
83 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
84 about_eq_hash(self.0, EQ_GRANULARITY, state);
85 }
86}
87impl Ord for AngleRadian {
88 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
89 about_eq_ord(self.0, other.0, EQ_GRANULARITY)
90 }
91}
92impl PartialOrd for AngleRadian {
93 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
94 Some(self.cmp(other))
95 }
96}
97
98impl From<AngleGradian> for AngleRadian {
99 fn from(grad: AngleGradian) -> Self {
100 AngleRadian(grad.0 * PI / 200.0)
101 }
102}
103impl From<AngleDegree> for AngleRadian {
104 fn from(deg: AngleDegree) -> Self {
105 AngleRadian(deg.0.to_radians())
106 }
107}
108impl From<AngleTurn> for AngleRadian {
109 fn from(turn: AngleTurn) -> Self {
110 AngleRadian(turn.0 * TAU)
111 }
112}
113impl From<AngleRadian> for euclid::Angle<f32> {
114 fn from(rad: AngleRadian) -> Self {
115 euclid::Angle::radians(rad.0)
116 }
117}
118
119impl fmt::Debug for AngleRadian {
120 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
121 if f.alternate() {
122 f.debug_tuple("AngleRadian").field(&self.0).finish()
123 } else {
124 write!(f, "{}.rad()", self.0)
125 }
126 }
127}
128impl fmt::Display for AngleRadian {
129 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
130 write!(f, "{} rad", self.0)
131 }
132}
133
134#[derive(Copy, Clone, serde::Serialize, serde::Deserialize)]
142#[serde(transparent)]
143pub struct AngleGradian(pub f32);
144impl AngleGradian {
145 pub fn modulo(self) -> Self {
147 AngleGradian(self.0.rem_euclid(400.0))
148 }
149
150 pub fn lerp(self, to: Self, factor: Factor) -> Self {
152 Self(lerp(self.0, to.0, factor))
153 }
154
155 pub fn slerp(self, to: Self, factor: Factor) -> Self {
165 Self(slerp(self.0, to.0, 400.0, factor))
166 }
167}
168impl ops::Add for AngleGradian {
169 type Output = Self;
170
171 fn add(self, rhs: Self) -> Self::Output {
172 Self(self.0 + rhs.0)
173 }
174}
175impl ops::AddAssign for AngleGradian {
176 fn add_assign(&mut self, rhs: Self) {
177 self.0 += rhs.0;
178 }
179}
180impl ops::Sub for AngleGradian {
181 type Output = Self;
182
183 fn sub(self, rhs: Self) -> Self::Output {
184 Self(self.0 - rhs.0)
185 }
186}
187impl ops::SubAssign for AngleGradian {
188 fn sub_assign(&mut self, rhs: Self) {
189 self.0 -= rhs.0;
190 }
191}
192impl ops::Neg for AngleGradian {
193 type Output = Self;
194
195 fn neg(self) -> Self::Output {
196 Self(-self.0)
197 }
198}
199impl Ord for AngleGradian {
200 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
201 about_eq_ord(self.0, other.0, EQ_GRANULARITY)
202 }
203}
204impl PartialOrd for AngleGradian {
205 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
206 Some(self.cmp(other))
207 }
208}
209
210impl PartialEq for AngleGradian {
211 fn eq(&self, other: &Self) -> bool {
212 about_eq(self.0, other.0, EQ_GRANULARITY_100)
213 }
214}
215impl Eq for AngleGradian {}
216impl std::hash::Hash for AngleGradian {
217 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
218 about_eq_hash(self.0, EQ_GRANULARITY_100, state);
219 }
220}
221impl From<AngleRadian> for AngleGradian {
222 fn from(rad: AngleRadian) -> Self {
223 AngleGradian(rad.0 * 200.0 / PI)
224 }
225}
226impl From<AngleDegree> for AngleGradian {
227 fn from(deg: AngleDegree) -> Self {
228 AngleGradian(deg.0 * 10.0 / 9.0)
229 }
230}
231impl From<AngleTurn> for AngleGradian {
232 fn from(turn: AngleTurn) -> Self {
233 AngleGradian(turn.0 * 400.0)
234 }
235}
236impl fmt::Debug for AngleGradian {
237 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
238 if f.alternate() {
239 f.debug_tuple("AngleGradian").field(&self.0).finish()
240 } else {
241 write!(f, "{}.grad()", self.0)
242 }
243 }
244}
245impl fmt::Display for AngleGradian {
246 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
247 write!(f, "{} gon", self.0)
248 }
249}
250
251#[derive(Copy, Clone, serde::Serialize, serde::Deserialize)]
259#[serde(transparent)]
260pub struct AngleDegree(pub f32);
261impl AngleDegree {
262 pub fn modulo(self) -> Self {
264 AngleDegree(self.0.rem_euclid(360.0))
265 }
266
267 pub fn lerp(self, to: Self, factor: Factor) -> Self {
269 Self(lerp(self.0, to.0, factor))
270 }
271
272 pub fn slerp(self, to: Self, factor: Factor) -> Self {
282 Self(slerp(self.0, to.0, 360.0, factor))
283 }
284}
285impl ops::Add for AngleDegree {
286 type Output = Self;
287
288 fn add(self, rhs: Self) -> Self::Output {
289 Self(self.0 + rhs.0)
290 }
291}
292impl ops::AddAssign for AngleDegree {
293 fn add_assign(&mut self, rhs: Self) {
294 self.0 += rhs.0;
295 }
296}
297impl ops::Sub for AngleDegree {
298 type Output = Self;
299
300 fn sub(self, rhs: Self) -> Self::Output {
301 Self(self.0 - rhs.0)
302 }
303}
304impl ops::SubAssign for AngleDegree {
305 fn sub_assign(&mut self, rhs: Self) {
306 self.0 -= rhs.0;
307 }
308}
309impl ops::Neg for AngleDegree {
310 type Output = Self;
311
312 fn neg(self) -> Self::Output {
313 Self(-self.0)
314 }
315}
316
317impl PartialEq for AngleDegree {
318 fn eq(&self, other: &Self) -> bool {
319 about_eq(self.0, other.0, EQ_GRANULARITY_100)
320 }
321}
322impl Eq for AngleDegree {}
323impl Ord for AngleDegree {
324 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
325 about_eq_ord(self.0, other.0, EQ_GRANULARITY)
326 }
327}
328impl PartialOrd for AngleDegree {
329 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
330 Some(self.cmp(other))
331 }
332}
333impl std::hash::Hash for AngleDegree {
334 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
335 about_eq_hash(self.0, EQ_GRANULARITY_100, state);
336 }
337}
338impl From<AngleRadian> for AngleDegree {
339 fn from(rad: AngleRadian) -> Self {
340 AngleDegree(rad.0.to_degrees())
341 }
342}
343impl From<AngleGradian> for AngleDegree {
344 fn from(grad: AngleGradian) -> Self {
345 AngleDegree(grad.0 * 9.0 / 10.0)
346 }
347}
348impl From<AngleTurn> for AngleDegree {
349 fn from(turn: AngleTurn) -> Self {
350 AngleDegree(turn.0 * 360.0)
351 }
352}
353impl fmt::Debug for AngleDegree {
354 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
355 if f.alternate() {
356 f.debug_tuple("AngleDegree").field(&self.0).finish()
357 } else {
358 write!(f, "{}.deg()", self.0)
359 }
360 }
361}
362impl fmt::Display for AngleDegree {
363 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
364 write!(f, "{}º", self.0)
365 }
366}
367
368#[derive(Copy, Clone, serde::Serialize, serde::Deserialize)]
376#[serde(transparent)]
377pub struct AngleTurn(pub f32);
378impl AngleTurn {
379 pub fn modulo(self) -> Self {
381 AngleTurn(self.0.rem_euclid(1.0))
382 }
383
384 pub fn lerp(self, to: Self, factor: Factor) -> Self {
386 Self(lerp(self.0, to.0, factor))
387 }
388
389 pub fn slerp(self, to: Self, factor: Factor) -> Self {
399 Self(slerp(self.0, to.0, 1.0, factor))
400 }
401}
402impl ops::Add for AngleTurn {
403 type Output = Self;
404
405 fn add(self, rhs: Self) -> Self::Output {
406 Self(self.0 + rhs.0)
407 }
408}
409impl ops::AddAssign for AngleTurn {
410 fn add_assign(&mut self, rhs: Self) {
411 self.0 += rhs.0;
412 }
413}
414impl ops::Sub for AngleTurn {
415 type Output = Self;
416
417 fn sub(self, rhs: Self) -> Self::Output {
418 Self(self.0 - rhs.0)
419 }
420}
421impl ops::SubAssign for AngleTurn {
422 fn sub_assign(&mut self, rhs: Self) {
423 self.0 -= rhs.0;
424 }
425}
426impl ops::Neg for AngleTurn {
427 type Output = Self;
428
429 fn neg(self) -> Self::Output {
430 Self(-self.0)
431 }
432}
433
434impl fmt::Debug for AngleTurn {
435 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
436 if f.alternate() {
437 f.debug_tuple("AngleTurn").field(&self.0).finish()
438 } else {
439 write!(f, "{}.turn()", self.0)
440 }
441 }
442}
443impl fmt::Display for AngleTurn {
444 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
445 if (self.0 - 1.0).abs() < 0.0001 {
446 write!(f, "1 turn")
447 } else {
448 write!(f, "{} turns", self.0)
449 }
450 }
451}
452impl PartialEq for AngleTurn {
453 fn eq(&self, other: &Self) -> bool {
454 about_eq(self.0, other.0, EQ_GRANULARITY)
455 }
456}
457impl Eq for AngleTurn {}
458impl Ord for AngleTurn {
459 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
460 about_eq_ord(self.0, other.0, EQ_GRANULARITY)
461 }
462}
463impl PartialOrd for AngleTurn {
464 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
465 Some(self.cmp(other))
466 }
467}
468impl std::hash::Hash for AngleTurn {
469 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
470 about_eq_hash(self.0, EQ_GRANULARITY, state);
471 }
472}
473
474impl From<AngleRadian> for AngleTurn {
475 fn from(rad: AngleRadian) -> Self {
476 AngleTurn(rad.0 / TAU)
477 }
478}
479impl From<AngleGradian> for AngleTurn {
480 fn from(grad: AngleGradian) -> Self {
481 AngleTurn(grad.0 / 400.0)
482 }
483}
484impl From<AngleDegree> for AngleTurn {
485 fn from(deg: AngleDegree) -> Self {
486 AngleTurn(deg.0 / 360.0)
487 }
488}
489
490pub trait AngleUnits {
504 fn rad(self) -> AngleRadian;
506 fn grad(self) -> AngleGradian;
508 fn deg(self) -> AngleDegree;
510 fn turn(self) -> AngleTurn;
512}
513impl AngleUnits for f32 {
514 fn rad(self) -> AngleRadian {
515 AngleRadian(self)
516 }
517
518 fn grad(self) -> AngleGradian {
519 AngleGradian(self)
520 }
521
522 fn deg(self) -> AngleDegree {
523 AngleDegree(self)
524 }
525
526 fn turn(self) -> AngleTurn {
527 AngleTurn(self)
528 }
529}
530impl AngleUnits for i32 {
531 fn rad(self) -> AngleRadian {
532 AngleRadian(self as f32)
533 }
534
535 fn grad(self) -> AngleGradian {
536 AngleGradian(self as f32)
537 }
538
539 fn deg(self) -> AngleDegree {
540 AngleDegree(self as f32)
541 }
542
543 fn turn(self) -> AngleTurn {
544 AngleTurn(self as f32)
545 }
546}
547
548fn lerp(from: f32, to: f32, factor: Factor) -> f32 {
549 from + (to - from) * factor.0
550}
551
552fn slerp(from: f32, to: f32, turn: f32, factor: Factor) -> f32 {
553 let angle_to = {
554 let d = (to - from) % turn;
555 2.0 * d % turn - d
556 };
557 from + angle_to * factor.0
558}