1extern crate num_traits as num;
32#[macro_use]
33#[cfg(feature = "approx")]
34extern crate approx;
35#[cfg(feature = "serde")]
36#[macro_use]
37extern crate serde;
38
39use std::ops::*;
40use std::f64::consts;
41use std::fmt;
42use std::convert::From;
43use num::{Float, NumCast};
44
45#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Hash)]
49#[repr(transparent)]
50#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
51pub struct Deg<T>(pub T);
52#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Hash)]
56#[repr(transparent)]
57#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
58pub struct Gon<T>(pub T);
59#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Hash)]
63#[repr(transparent)]
64#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
65pub struct Rad<T>(pub T);
66#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Hash)]
70#[repr(transparent)]
71#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
72pub struct Turns<T>(pub T);
73#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Hash)]
76#[repr(transparent)]
77#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
78pub struct ArcMinutes<T>(pub T);
79#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Hash)]
82#[repr(transparent)]
83#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
84pub struct ArcSeconds<T>(pub T);
85
86pub trait FromAngle<T>
92 where T: Angle
93{
94 fn from_angle(from: T) -> Self;
96}
97
98pub trait IntoAngle<To>
102 where To: Angle<Scalar = Self::OutputScalar>
103{
104 type OutputScalar: Float;
105 fn into_angle(self) -> To;
107}
108
109pub trait Angle: Clone + FromAngle<Self> + PartialEq + PartialOrd + num::Zero {
111 type Scalar: Float;
113
114 fn new(value: Self::Scalar) -> Self;
119
120 fn period() -> Self::Scalar;
122 fn scalar(&self) -> Self::Scalar;
126 fn set_scalar(&mut self, value: Self::Scalar);
128 fn normalize(self) -> Self;
136 fn is_normalized(&self) -> bool;
138
139 fn sin(self) -> Self::Scalar;
141 fn cos(self) -> Self::Scalar;
143 fn tan(self) -> Self::Scalar;
145 fn sin_cos(self) -> (Self::Scalar, Self::Scalar);
147
148 fn asin(value: Self::Scalar) -> Self;
150 fn acos(value: Self::Scalar) -> Self;
152 fn atan(value: Self::Scalar) -> Self;
154 fn atan2(x: Self::Scalar, y: Self::Scalar) -> Self;
157
158 fn full_turn() -> Self;
162 fn half_turn() -> Self;
164 fn quarter_turn() -> Self;
166
167 fn invert(self) -> Self;
173 fn reflect_x(self) -> Self;
177}
178
179pub trait Interpolate: Angle {
181 fn interpolate<U>(&self, right: &U, pos: Self::Scalar) -> Self
192 where U: Clone + IntoAngle<Self, OutputScalar = Self::Scalar>;
193
194 fn interpolate_forward<U>(&self, right: &U, pos: Self::Scalar) -> Self
202 where U: Clone + IntoAngle<Self, OutputScalar = Self::Scalar>;
203}
204
205macro_rules! impl_angle {
206 ($Struct: ident, $period: expr) => {
207 impl<T: Float> Angle for $Struct<T>
208 {
209 type Scalar = T;
210
211 fn new(value: T) -> $Struct<T> {
212 $Struct(value)
213 }
214
215 fn period() -> T {
216 cast($period).unwrap()
217 }
218
219 fn scalar(&self) -> T {
220 self.0
221 }
222 fn set_scalar(&mut self, value: T) {
223 self.0 = value;
224 }
225 fn is_normalized(&self) -> bool {
226 self.0 >= T::zero() && self.0 < Self::period()
227 }
228
229 fn normalize(self) -> $Struct<T> {
230 if !self.is_normalized() {
231 let shifted = self.0 % Self::period();
232 if shifted < T::zero() {
233 $Struct(shifted + Self::period())
234 } else {
235 $Struct(shifted)
236 }
237 } else {
238 self
239 }
240 }
241
242 fn sin(self) -> T {
243 Rad::from_angle(self).0.sin()
244 }
245 fn cos(self) -> T {
246 Rad::from_angle(self).0.cos()
247 }
248 fn tan(self) -> T {
249 Rad::from_angle(self).0.tan()
250 }
251 fn sin_cos(self) -> (T, T) {
252 Rad::from_angle(self).0.sin_cos()
253 }
254 fn asin(value: T) -> $Struct<T> {
255 $Struct::from_angle(Rad(value.asin()))
256 }
257 fn acos(value: T) -> $Struct<T> {
258 $Struct::from_angle(Rad(value.acos()))
259 }
260 fn atan(value: T) -> $Struct<T> {
261 $Struct::from_angle(Rad(value.atan()))
262 }
263 fn atan2(y: T, x: T) -> $Struct<T> {
264 $Struct::from_angle(Rad(y.atan2(x)))
265 }
266
267 fn full_turn() -> Self {
268 $Struct(Self::period())
269 }
270 fn half_turn() -> Self {
271 $Struct(cast::<_, Self::Scalar>(0.5).unwrap() * Self::period())
272 }
273 fn quarter_turn() -> Self {
274 $Struct(cast::<_, Self::Scalar>(0.25).unwrap() * Self::period())
275 }
276 fn invert(self) -> Self {
277 self + Self::half_turn()
278 }
279 fn reflect_x(self) -> Self {
280 Self::full_turn() - self
281 }
282 }
283
284 impl<T: Float> Interpolate for $Struct<T> {
285 fn interpolate<U>(&self, right: &U, pos: Self::Scalar) -> Self
286 where U: Clone + IntoAngle<Self, OutputScalar=Self::Scalar>
287 {
288 let end = right.clone().into_angle();
289 let forward_distance = (end.0 - self.0).abs();
290 let inv_pos = cast::<_, Self::Scalar>(1.0).unwrap() - pos;
291
292 if forward_distance > Self::half_turn().0 {
293 if *self > end {
294 $Struct(self.0 * inv_pos + (end.0 + Self::period()) * pos)
295 } else {
296 $Struct((self.0 + Self::period()) * inv_pos + end.0 * pos)
297 }
298 } else {
299 $Struct(self.0 * inv_pos + end.0 * pos)
300 }
301 }
302
303 fn interpolate_forward<U>(&self, right: &U, pos: Self::Scalar) -> Self
304 where U: Clone + IntoAngle<Self, OutputScalar = Self::Scalar>
305 {
306 let inv_pos = cast::<_, Self::Scalar>(1.0).unwrap() - pos;
307 $Struct(self.0 * inv_pos + right.clone().into_angle().0 * pos)
308 }
309 }
310
311 #[cfg(feature = "approx")]
312 impl<T: Float + approx::AbsDiffEq> approx::AbsDiffEq for $Struct<T>
313 where T::Epsilon: Clone,
314 {
315 type Epsilon = T::Epsilon;
316
317 fn default_epsilon() -> Self::Epsilon {
318 T::default_epsilon()
319 }
320
321 fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool
322 {
323 let inv_self = self.clone().reflect_x();
324
325 self.0.abs_diff_eq(&other.0, epsilon.clone())
326 || self.0.abs_diff_eq(&other.clone().reflect_x().0,
327 epsilon.clone())
328 || inv_self.0.abs_diff_eq(&other.0, epsilon)
329 }
330 }
331
332 #[cfg(feature = "approx")]
333 impl<T: Float + approx::RelativeEq> approx::RelativeEq for $Struct<T>
334 where T::Epsilon: Clone,
335 {
336 fn default_max_relative() -> Self::Epsilon {
337 T::default_max_relative()
338 }
339
340 fn relative_eq(&self, other: &Self, epsilon: Self::Epsilon,
341 max_relative: Self::Epsilon) -> bool {
342 let inv_self = self.clone().reflect_x();
343
344 self.0.relative_eq(&other.0, epsilon.clone(), max_relative.clone())
345 || self.0.relative_eq(&other.clone().reflect_x().0,
346 epsilon.clone(), max_relative.clone())
347 || inv_self.0.relative_eq(&other.0, epsilon, max_relative)
348 }
349 }
350
351 #[cfg(feature = "approx")]
352 impl<T: Float + approx::UlpsEq> approx::UlpsEq for $Struct<T>
353 where T::Epsilon: Clone,
354 {
355 fn default_max_ulps() -> u32 {
356 T::default_max_ulps()
357 }
358 fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool {
359 let inv_self = self.clone().reflect_x();
360
361 self.0.ulps_eq(&other.0, epsilon.clone(), max_ulps)
362 || self.0.ulps_eq(&other.clone().reflect_x().0, epsilon.clone(), max_ulps)
363 || inv_self.0.ulps_eq(&other.0, epsilon, max_ulps)
364 }
365 }
366
367 impl<T: Rem<T, Output=T>> Rem for $Struct<T> {
368 type Output=$Struct<T>;
369 fn rem(self, rhs: $Struct<T>) -> $Struct<T> {
370 $Struct(self.0 % rhs.0)
371 }
372 }
373
374 impl<T: RemAssign> RemAssign for $Struct<T> {
375 fn rem_assign(&mut self, rhs: $Struct<T>) {
376 self.0 %= rhs.0;
377 }
378 }
379
380 impl<U, T> Add<U> for $Struct<T>
381 where T: Float + Add<T, Output=T>,
382 U: IntoAngle<$Struct<T>, OutputScalar=T>
383 {
384 type Output=$Struct<T>;
385 fn add(self, rhs: U) -> $Struct<T> {
386 $Struct(self.0 + rhs.into_angle().0)
387 }
388 }
389
390 impl<U, T> AddAssign<U> for $Struct<T>
391 where T: Float + AddAssign<T>,
392 U: IntoAngle<$Struct<T>, OutputScalar=T>
393 {
394 fn add_assign(&mut self, rhs: U) {
395 self.0 += rhs.into_angle().0;
396 }
397 }
398
399 impl<U, T> Sub<U> for $Struct<T>
400 where T: Float + Sub<T, Output=T>,
401 U: IntoAngle<$Struct<T>, OutputScalar=T>
402 {
403 type Output=$Struct<T>;
404 fn sub(self, rhs: U) -> $Struct<T> {
405 $Struct(self.0 - rhs.into_angle().0)
406 }
407 }
408
409 impl<U, T> SubAssign<U> for $Struct<T>
410 where T: Float + SubAssign<T>,
411 U: IntoAngle<$Struct<T>, OutputScalar=T>
412 {
413 fn sub_assign(&mut self, rhs: U) {
414 self.0 -= rhs.into_angle().0;
415 }
416 }
417
418 impl<T: Mul<T, Output=T>> Mul<T> for $Struct<T> {
419 type Output=$Struct<T>;
420 fn mul(self, rhs: T) -> $Struct<T> {
421 $Struct(self.0 * rhs)
422 }
423 }
424
425 impl<T: MulAssign<T>> MulAssign<T> for $Struct<T> {
426 fn mul_assign(&mut self, rhs: T) {
427 self.0 *= rhs;
428 }
429 }
430
431 impl<T: Div<T, Output=T>> Div<T> for $Struct<T> {
432 type Output=$Struct<T>;
433 fn div(self, rhs: T) -> $Struct<T> {
434 $Struct(self.0 / rhs)
435 }
436 }
437
438 impl<T: DivAssign<T>> DivAssign<T> for $Struct<T> {
439 fn div_assign(&mut self, rhs: T) {
440 self.0 /= rhs;
441 }
442 }
443
444 impl<T: Neg<Output=T>> Neg for $Struct<T> {
445 type Output=$Struct<T>;
446 fn neg(self) -> $Struct<T> {
447 $Struct(-self.0)
448 }
449 }
450
451 impl<T: Float> num::Zero for $Struct<T> {
452 fn zero() -> $Struct<T> {
453 $Struct(T::zero())
454 }
455 fn is_zero(&self) -> bool {
456 self.0 == T::zero()
457 }
458 }
459
460 impl<T: num::Zero> Default for $Struct<T> {
461 fn default() -> $Struct<T> {
462 $Struct(T::zero())
463 }
464 }
465
466 impl<T, U> FromAngle<U> for $Struct<T>
467 where U: Angle<Scalar=T>,
468 T: Float,
469 {
470 fn from_angle(from: U) -> $Struct<T> {
471 $Struct(from.scalar() * $Struct::period() / U::period())
472 }
473 }
474 }
475}
476
477macro_rules! impl_from_for_angle {
478 ($from: ty, $to: ty) => {
479 impl<T: Float> From<$from> for $to {
480 fn from(from: $from) -> $to {Self::from_angle(from)}
481 }
482 }
483}
484
485impl_angle!(Deg, 360.0);
486impl_angle!(Gon, 400.0);
487impl_angle!(Rad, consts::PI * 2.0);
488impl_angle!(Turns, 1.0);
489impl_angle!(ArcMinutes, 360.0 * 60.0);
490impl_angle!(ArcSeconds, 360.0 * 3600.0);
491
492impl_from_for_angle!(Deg<T>, Rad<T>);
493impl_from_for_angle!(Deg<T>, Turns<T>);
494impl_from_for_angle!(Deg<T>, Gon<T>);
495
496impl_from_for_angle!(Gon<T>, Deg<T>);
497impl_from_for_angle!(Gon<T>, Rad<T>);
498impl_from_for_angle!(Gon<T>, Turns<T>);
499
500impl_from_for_angle!(Rad<T>, Deg<T>);
501impl_from_for_angle!(Rad<T>, Gon<T>);
502impl_from_for_angle!(Rad<T>, Turns<T>);
503
504impl_from_for_angle!(Turns<T>, Deg<T>);
505impl_from_for_angle!(Turns<T>, Gon<T>);
506impl_from_for_angle!(Turns<T>, Rad<T>);
507
508impl_from_for_angle!(ArcMinutes<T>, Deg<T>);
509impl_from_for_angle!(ArcSeconds<T>, Deg<T>);
510impl_from_for_angle!(ArcSeconds<T>, ArcMinutes<T>);
511
512impl<T: Float> Deg<T> {
513 pub fn from_components(degs: Deg<T>, mins: ArcMinutes<T>, secs: ArcSeconds<T>) -> Self {
524 degs + mins + secs
525 }
526
527 pub fn decompose(self) -> (Deg<T>, ArcMinutes<T>, ArcSeconds<T>) {
532 let sixty: T = cast(60.0).unwrap();
533 let degs = self.0.floor();
534 let rem = self.0 - degs;
535 let mins = (rem * sixty).floor();
536 let rem_s = rem * sixty - mins;
537 let seconds = rem_s * sixty;
538
539 (Deg(degs), ArcMinutes(mins), ArcSeconds(seconds))
540 }
541}
542
543impl<T: Float> Rad<T> {
544 pub fn pi() -> Rad<T> {
545 Rad(cast(consts::PI).unwrap())
546 }
547 pub fn pi_over_2() -> Rad<T> {
548 Rad(cast(consts::PI / 2.0).unwrap())
549 }
550 pub fn pi_over_3() -> Rad<T> {
551 Rad(cast(consts::PI / 3.0).unwrap())
552 }
553 pub fn pi_over_4() -> Rad<T> {
554 Rad(cast(consts::PI / 4.0).unwrap())
555 }
556}
557
558impl<T, U> IntoAngle<U> for T
559 where U: Angle<Scalar = T::Scalar> + FromAngle<T>,
560 T: Angle
561{
562 type OutputScalar = T::Scalar;
563 fn into_angle(self) -> U {
564 U::from_angle(self)
565 }
566}
567impl<T: fmt::Display> fmt::Display for Deg<T> {
568 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
569 write!(f, "{}°", self.0)
570 }
571}
572impl<T: fmt::Display> fmt::Display for Gon<T> {
573 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
574 write!(f, "{}gon", self.0)
575 }
576}
577impl<T: fmt::Display> fmt::Display for Rad<T> {
578 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
579 write!(f, "{}r", self.0)
580 }
581}
582impl<T: fmt::Display> fmt::Display for Turns<T> {
583 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
584 write!(f, "{}", self.0)
585 }
586}
587impl<T: fmt::Display> fmt::Display for ArcMinutes<T> {
588 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
589 write!(f, "{}'", self.0)
590 }
591}
592impl<T: fmt::Display> fmt::Display for ArcSeconds<T> {
593 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
594 write!(f, "{}\"", self.0)
595 }
596}
597
598pub fn mean<T, Scalar, Out>(iter: T) -> Out
603 where T: IntoIterator,
604 T::Item: IntoAngle<Rad<Scalar>, OutputScalar=Scalar>,
605 Scalar: Float + AddAssign,
606 Out: Angle<Scalar=Scalar> + FromAngle<Rad<Scalar>>,
607{
608 let mut sum_of_sines: Scalar = cast(0.0).unwrap();
609 let mut sum_of_cosines: Scalar = cast(0.0).unwrap();
610
611 for angle in iter.into_iter() {
612 let intermediate_angle: Rad<Scalar> = angle.into_angle();
613 let (sin, cos) = intermediate_angle.sin_cos();
614 sum_of_sines += sin;
615 sum_of_cosines += cos;
616 }
617
618 Out::atan2(sum_of_sines, sum_of_cosines).normalize()
619}
620
621fn cast<T: NumCast, U: NumCast>(from: T) -> Option<U> {
622 U::from(from)
623}
624
625#[cfg(test)]
626mod test {
627 #[cfg(feature = "serde")]
628 extern crate serde_test;
629
630 use std::f64::consts;
631 use std::f64;
632 use super::*;
633
634 #[test]
635 fn test_construct() {
636 assert_relative_eq!(Deg(50.0), Deg::new(50.0));
637 let mut a1 = Deg(100.0);
638 let scalar = a1.scalar();
639 a1.set_scalar(scalar + 150.0);
640 assert_relative_eq!(a1, Deg(250.0));
641 }
642
643 #[test]
644 fn test_convert() {
645 assert_relative_eq!(ArcMinutes(120.0).into_angle(), Deg(2.0), epsilon=1e-6);
646 assert_relative_eq!(ArcMinutes(120.0).into_angle(), Gon(2.222222), epsilon=1e-6);
647 assert_relative_eq!(ArcSeconds(30.0).into_angle(), ArcMinutes(0.5), epsilon=1e-6);
648 assert_relative_eq!(Deg(30.0) + ArcMinutes(30.0) + ArcSeconds(30.0),
649 Deg(30.50833333333), epsilon=1e-6);
650 assert_relative_eq!(Rad(consts::PI).into_angle(), Deg(180.0), epsilon=1e-6);
651 assert_relative_eq!(Turns(0.25).into_angle(), Deg(90.0), epsilon=1e-6);
652 assert_relative_eq!(Turns(0.25).into_angle(), Rad(consts::PI / 2.0), epsilon=1e-6);
653 assert_relative_eq!(ArcMinutes(600.0).into_angle(), Deg(10.0), epsilon=1e-6);
654 assert_relative_eq!(ArcMinutes(5400.0).into_angle(), Rad(consts::PI / 2.0), epsilon=1e-6);
655 assert_relative_eq!(Gon(100.0).into_angle(), Deg(90.0), epsilon=1e-6);
656 assert_relative_eq!(Gon(50.0).into_angle(), Rad(consts::PI / 4.0), epsilon=1e-6);
657 }
658
659 #[test]
660 fn test_arithmetic() {
661 {
662 let a1 = Rad(2.0);
663 let a2 = Deg(100.0);
664
665 let a3 = a2 + a1;
666 assert_relative_eq!(a3.0, 214.59, epsilon=1e-2);
667
668 let a4 = Deg(50.0);
669 let a5 = a2 + a4;
670 assert_ulps_eq!(a5.0, 150.0);
671
672 let mut a6 = Deg(123.0);
673 a6 += Deg(10.0);
674 a6 += Rad::pi();
675 assert_ulps_eq!(a6.0, 313.0);
676
677 let a7 = Deg(50.0);
678 assert_ulps_eq!(a7 * 2.0, Deg(100.0));
679 }
680 {
681 let a1 = Rad(2.0);
682 let a2 = a1 % Rad(1.5);
683 assert_ulps_eq!(a2, Rad(0.5));
684 assert_ulps_eq!(Rad(1.0) * 2.0, Rad(2.0));
685 assert_ulps_eq!(Rad(consts::PI * 2.0) / 2.0, Rad(consts::PI));
686 }
687 {
688 let a10 = Gon(15.0);
689 let a11 = Deg(43.0);
690 let a12 = a11 + a10;
691 assert_relative_eq!(a12.0, 56.5, epsilon=1e-2);
692 let a13 = a10 + a11;
693 assert_relative_eq!(a13.0, 62.7778, epsilon=1e-2);
694 }
695 }
696
697 #[test]
698 fn test_trig() {
699 assert_ulps_eq!(Deg(0.0).sin(), 0.0);
700 assert_ulps_eq!(Gon(0.0).sin(), 0.0);
701 assert_ulps_eq!(Rad(consts::PI / 2.0).sin(), 1.0);
702 assert_ulps_eq!(Deg(90.0).sin(), 1.0);
703 assert_ulps_eq!(Deg(45.0).tan(), 1.0);
704 assert_relative_eq!(Deg(405.0).tan(), 1.0, epsilon=1e-6);
705 assert_relative_eq!(Gon(450.0).tan(), 1.0, epsilon=1e-6);
706 let a1 = Rad(consts::PI * 1.25);
707 assert_relative_eq!(a1.cos(), -f64::sqrt(2.0) / 2.0, epsilon=1e-6);
708 assert_relative_eq!(a1.cos(), Deg(135.0).cos(), epsilon=1e-6);
709 assert_relative_eq!(a1.cos(), Gon(150.0).cos(), epsilon=1e-6);
710
711 assert_relative_eq!(Deg::acos(1.0), Deg(0.0));
712 assert_relative_eq!(Deg::acos(0.0), Deg(90.0));
713 assert_relative_eq!(Deg::acos(0.0), Deg::from(Gon(100.0)));
714 assert_relative_eq!(Rad::acos(0.0), Rad::pi_over_2());
715 }
716
717 #[test]
718 fn test_equality() {
719 let a1 = Rad(2.0);
720 assert_ulps_eq!(a1, Rad(2.0));
721 assert_ulps_eq!(Deg(200.0), Deg(200.0));
722 assert!(!(Deg(200.0) == Deg(100.0)));
723
724 assert!(Deg(200.0) < Deg(300.0));
725 assert!(Deg(250.0) > Deg(100.0));
726
727 assert_relative_eq!(Deg(359.999999), Deg(0.0), epsilon=1e-4);
728 assert_ulps_eq!(Deg(359.999999), Deg(0.0), epsilon=1e-4);
729 assert_ulps_eq!(Deg(359.99999), Deg(0.0), epsilon=1e-4);
730 }
731
732 #[test]
733 fn test_normalize() {
734 let mut a1 = Deg(200.0);
735 a1 += Deg(300.0);
736 assert_ulps_eq!(a1, Deg(500.0));
737 a1 = a1.normalize();
738 assert_ulps_eq!(a1, Deg(140.0));
739 assert_ulps_eq!(a1.normalize(), a1);
740
741 let a2 = Deg(50.0);
742 assert_ulps_eq!(a2 - Deg(150.0), Deg(-100.0));
743 let a3 = a2 - Deg(100.0);
744 assert!(!a3.is_normalized());
745 assert_ulps_eq!(a3.normalize(), Deg(310.0));
746 assert_ulps_eq!(a3.normalize().normalize(), a3.normalize());
747 assert!(a3.normalize().is_normalized());
748
749 let a4 = Rad(consts::PI);
750 let a5 = a4 + Rad(consts::PI * 2.0);
751 assert_ulps_eq!(a5, Rad(consts::PI * 3.0));
752 assert!(!a3.is_normalized());
753 assert_ulps_eq!(a5.normalize(), Rad(consts::PI));
754 let a6 = a4 - Rad(consts::PI * 2.0);
755 assert_ulps_eq!(a6, Rad(consts::PI * -1.0));
756 assert!(!a6.is_normalized());
757 assert_ulps_eq!(a6.normalize(), a5.normalize());
758
759 assert_ulps_eq!(Deg(360.0).normalize(), Deg(0.0));
760 assert_ulps_eq!(Deg(-1.0).normalize(), Deg(359.0));
761 assert_ulps_eq!(Deg(-360.0).normalize(), Deg(0.0));
762 assert_relative_eq!(Deg(-359.9).normalize(), Deg(0.1), epsilon=1e-6);
763
764 assert_relative_eq!(Gon(725.0).normalize().into_angle(), Deg(292.5), epsilon=1e-6);
765 assert_relative_eq!(Gon(-275.0).normalize(), Gon(125.0), epsilon=1e-6);
766 }
767
768 #[test]
769 fn decompose() {
770 {
771 let (deg, min, sec) = Deg(50.25).decompose();
772
773 assert_ulps_eq!(deg, Deg(50.0));
774 assert_ulps_eq!(min, ArcMinutes(15.0));
775 assert_ulps_eq!(sec, ArcSeconds(0.0));
776 }
777 {
778 let (deg, min, sec) = Deg(90.3131).decompose();
779
780 assert_ulps_eq!(deg, Deg(90.0));
781 assert_ulps_eq!(min, ArcMinutes(18.0));
782 assert_relative_eq!(sec, ArcSeconds(47.16), epsilon=1e-6);
783 }
784 }
785
786 #[test]
787 fn test_interpolate() {
788 assert_relative_eq!(Deg(60.0).interpolate(&Deg(120.0), 0.5), Deg(90.0));
789 assert_relative_eq!(Deg(50.0).interpolate(&Rad(consts::PI), 0.75),
790 Deg(147.5), epsilon=1e-6);
791 assert_relative_eq!(Turns(0.50).interpolate(&Deg(30.0), 0.25),
792 Turns(0.39583333333), epsilon=1e-6);
793
794 assert_relative_eq!(Deg(100.0).interpolate(&Deg(310.0), 0.5).normalize(), Deg(25.0));
795 assert_relative_eq!(Deg(100.0).interpolate_forward(&Deg(310.0), 0.5).normalize(),
796 Deg(205.0));
797 assert_relative_eq!(Gon(66.6666667).interpolate(&Deg(120.0), 0.5), Gon(100.0), epsilon=1e-6);
798 assert_relative_eq!(Rad::pi_over_2().interpolate(&Rad(0.0), 0.5), Rad::pi_over_4());
799 }
800
801 #[test]
802 fn test_constants() {
803 assert_ulps_eq!(Deg::half_turn(), Deg(180.0));
804 assert_ulps_eq!(Deg::quarter_turn(), Deg(90.0));
805 assert_ulps_eq!(Rad::half_turn(), Rad(consts::PI));
806 assert_ulps_eq!(Rad::<f32>::full_turn(), Rad(Rad::period()));
807 assert_ulps_eq!(Gon::half_turn(), Gon(200.0));
808 assert_ulps_eq!(Gon::quarter_turn(), Gon(100.0));
809 }
810
811 #[test]
812 fn test_invert() {
813 assert_ulps_eq!(Deg(0.0).invert(), Deg(180.0));
814 assert_ulps_eq!(Deg(180.0).invert().normalize(), Deg(0.0));
815 assert_ulps_eq!(Gon(200.0).invert().normalize(), Gon(0.0));
816 assert_ulps_eq!(Deg(80.0).invert(), Deg(260.0));
817 assert_ulps_eq!(Gon(80.0).invert(), Gon(280.0));
818 }
819
820 #[test]
821 fn test_reflect_x() {
822 assert_relative_eq!(Deg(359.9999999999).reflect_x(),
823 Deg(0.0000000000001), epsilon=1e-5);
824 assert_relative_eq!(Deg(180.0).reflect_x(), Deg(180.0));
825 assert_relative_eq!(Deg(90.0).reflect_x(), Deg(90.0));
826 assert_relative_eq!(Deg(0.0).reflect_x(), Deg(0.0));
827 assert_relative_eq!(Deg(45.0).reflect_x(), Deg(315.0));
828 assert_relative_eq!(Deg(215.0).reflect_x(), Deg(145.0));
829 assert_relative_eq!(Gon(50.0).reflect_x(), Gon(350.0));
830 assert_relative_eq!(Gon(215.0).reflect_x(), Gon(185.0));
831 }
832
833 #[test]
834 fn test_mean() {
835 assert_relative_eq!(mean(vec![Deg(280.0), Deg(10.0)].into_iter()), Deg(325.0));
836 assert_relative_eq!(mean(vec![Turns(0.5), Turns(0.0)].into_iter()), Deg(90.0));
837 assert_relative_eq!(mean([Rad(0.0), Rad(0.0)].into_iter().cloned()), Rad(0.0));
838 }
839
840 #[cfg(feature = "serde")]
841 #[test]
842 fn test_serialize() {
843 use self::serde_test::{Token, assert_tokens};
844
845 assert_tokens(&Deg(90.0), &[Token::NewtypeStruct {name: "Deg"}, Token::F64(90.0)]);
846 assert_tokens(&Rad(0.5f32), &[Token::NewtypeStruct {name: "Rad"}, Token::F32(0.5f32)]);
847 assert_tokens(&Gon(300.0), &[Token::NewtypeStruct {name: "Gon"}, Token::F64(300.0)]);
848 assert_tokens(&Turns(0.666), &[Token::NewtypeStruct {name: "Turns"}, Token::F64(0.666)]);
849 }
850
851 #[cfg(feature = "serde")]
852 #[test]
853 fn test_deserialize() {
854 use self::serde_test::{Token, assert_de_tokens};
855
856 assert_de_tokens(&Deg(90.0), &[Token::NewtypeStruct {name: "Deg"}, Token::F64(90.0)]);
857 assert_de_tokens(&Rad(0.5f32), &[Token::NewtypeStruct {name: "Rad"}, Token::F32(0.5f32)]);
858 assert_de_tokens(&Gon(300.0), &[Token::NewtypeStruct {name: "Gon"}, Token::F64(300.0)]);
859 assert_de_tokens(&Turns(0.666), &[Token::NewtypeStruct {name: "Turns"}, Token::F64(0.666)]);
860 }
861}