You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

183 lines
5.3 KiB

  1. use std::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd};
  2. use std::f64::consts::PI;
  3. use auto_ops::impl_op_ex;
  4. #[cfg(feature = "serde")]
  5. use serde::{Deserialize, Serialize};
  6. pub use super::numeric::{Float, Numeric};
  7. /* Angle */
  8. #[derive(Debug, Clone, Copy)]
  9. #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
  10. pub enum Angle<T> {
  11. Deg(T),
  12. Rad(T),
  13. }
  14. impl<T> Angle<T>
  15. where
  16. T: Numeric,
  17. {
  18. pub fn into_inner(self) -> T {
  19. match self {
  20. Self::Deg(v) => v,
  21. Self::Rad(v) => v,
  22. }
  23. }
  24. pub fn into_deg(self) -> Self {
  25. match self {
  26. Self::Deg(v) => Self::Deg(v),
  27. Self::Rad(v) => Self::Rad(T::to_degrees(v)),
  28. }
  29. }
  30. pub fn into_rad(self) -> Self {
  31. match self {
  32. Self::Deg(v) => Self::Deg(T::to_radians(v)),
  33. Self::Rad(v) => Self::Rad(v),
  34. }
  35. }
  36. pub fn abs(self) -> Self {
  37. match self {
  38. Self::Deg(value) => Self::Deg(value.abs()),
  39. Self::Rad(value) => Self::Rad(value.abs()),
  40. }
  41. }
  42. fn _neg(self) -> Self {
  43. match self {
  44. Self::Deg(value) => Self::Deg(-value),
  45. Self::Rad(value) => Self::Rad(-value),
  46. }
  47. }
  48. fn _add(self, other: &Self) -> Self {
  49. match self {
  50. Self::Deg(value) => Self::Deg(value + other.into_deg().into_inner()),
  51. Self::Rad(value) => Self::Rad(value + other.into_rad().into_inner()),
  52. }
  53. }
  54. fn _mul(self, other: T) -> Self {
  55. match self {
  56. Self::Deg(value) => Self::Deg(value * other),
  57. Self::Rad(value) => Self::Rad(value * other),
  58. }
  59. }
  60. }
  61. impl<T> Angle<T>
  62. where
  63. T: Float,
  64. {
  65. pub fn sin(self) -> T {
  66. T::sin(self.into_rad().into_inner())
  67. }
  68. pub fn cos(self) -> T {
  69. T::cos(self.into_rad().into_inner())
  70. }
  71. /// Normalizes the angle to (-pi, pi] / (-180.0, 180.0]
  72. pub fn normalize(self) -> Self {
  73. match self {
  74. Self::Deg(value) => Self::Deg(normalize(value, T::new(-180.0), T::new(180.0))),
  75. Self::Rad(value) => Self::Rad(normalize(value, T::new(-PI), T::new(PI))),
  76. }
  77. }
  78. }
  79. impl_op_ex!(*|a: &f32, b: &Angle<f32>| -> Angle<f32> { b._mul(*a) });
  80. impl_op_ex!(- <T: Numeric> |a: &Angle<T>| -> Angle<T> { a._neg() });
  81. impl_op_ex!(+ <T: Numeric> |a: &Angle<T>, b: &Angle<T>| -> Angle<T> { a._add(b) });
  82. impl_op_ex!(- <T: Numeric> |a: &Angle<T>, b: &Angle<T>| -> Angle<T> { a._add(&b._neg()) });
  83. impl_op_ex!(* <T: Numeric> |a: &Angle<T>, b: &T| -> Angle<T> { a._mul(*b) });
  84. impl_op_ex!(/ <T: Numeric> |a: &Angle<T>, b: &T| -> Angle<T> { a._mul(T::one() / *b) });
  85. impl_op_ex!(+= <T: Numeric> |a: &mut Angle<T>, b: &Angle<T>| { *a = a._add(b); });
  86. impl_op_ex!(-= <T: Numeric> |a: &mut Angle<T>, b: &Angle<T>| { *a = a._add(&b._neg()); });
  87. impl<T, S> PartialEq<Angle<S>> for Angle<T>
  88. where
  89. T: Numeric + PartialEq<S>,
  90. S: Numeric,
  91. {
  92. fn eq(&self, other: &Angle<S>) -> bool {
  93. match self {
  94. Self::Deg(v) => v.eq(&other.into_deg().into_inner()),
  95. Self::Rad(v) => v.eq(&other.into_rad().into_inner()),
  96. }
  97. }
  98. }
  99. impl<T> Eq for Angle<T> where T: Numeric + Eq {}
  100. impl<T, S> PartialOrd<Angle<S>> for Angle<T>
  101. where
  102. T: Numeric + PartialOrd<S>,
  103. S: Numeric,
  104. {
  105. fn partial_cmp(&self, other: &Angle<S>) -> Option<Ordering> {
  106. match self {
  107. Self::Deg(v) => v.partial_cmp(&other.into_deg().into_inner()),
  108. Self::Rad(v) => v.partial_cmp(&other.into_rad().into_inner()),
  109. }
  110. }
  111. }
  112. impl<T> Ord for Angle<T>
  113. where
  114. T: Ord + Numeric,
  115. {
  116. fn cmp(&self, other: &Self) -> Ordering {
  117. match self {
  118. Self::Deg(v) => v.cmp(&other.into_deg().into_inner()),
  119. Self::Rad(v) => v.cmp(&other.into_rad().into_inner()),
  120. }
  121. }
  122. }
  123. fn normalize<T>(value: T, min: T, max: T) -> T
  124. where
  125. T: Float,
  126. {
  127. let range = max - min;
  128. let value = value - min;
  129. let f = (value / range).floor();
  130. value + min - f * range
  131. }
  132. #[cfg(test)]
  133. mod tests {
  134. use super::*;
  135. #[test]
  136. fn normalize() {
  137. assert_eq!(Angle::Deg(-180.0), Angle::Deg(540.0).normalize());
  138. assert_eq!(Angle::Deg(-180.0), Angle::Deg(180.0).normalize());
  139. assert_eq!(Angle::Deg(-180.0), Angle::Deg(-180.0).normalize());
  140. assert_eq!(Angle::Deg(-180.0), Angle::Deg(-540.0).normalize());
  141. assert_eq!(Angle::Deg(0.0), Angle::Deg(720.0).normalize());
  142. assert_eq!(Angle::Deg(0.0), Angle::Deg(360.0).normalize());
  143. assert_eq!(Angle::Deg(0.0), Angle::Deg(-360.0).normalize());
  144. assert_eq!(Angle::Deg(0.0), Angle::Deg(-720.0).normalize());
  145. assert_eq!(Angle::Deg(90.0), Angle::Deg(-630.0).normalize());
  146. assert_eq!(Angle::Deg(90.0), Angle::Deg(-270.0).normalize());
  147. assert_eq!(Angle::Deg(90.0), Angle::Deg(90.0).normalize());
  148. assert_eq!(Angle::Deg(90.0), Angle::Deg(450.0).normalize());
  149. assert_eq!(Angle::Deg(90.0), Angle::Deg(810.0).normalize());
  150. assert_eq!(Angle::Deg(-90.0), Angle::Deg(-810.0).normalize());
  151. assert_eq!(Angle::Deg(-90.0), Angle::Deg(-450.0).normalize());
  152. assert_eq!(Angle::Deg(-90.0), Angle::Deg(-90.0).normalize());
  153. assert_eq!(Angle::Deg(-90.0), Angle::Deg(270.0).normalize());
  154. assert_eq!(Angle::Deg(-90.0), Angle::Deg(630.0).normalize());
  155. }
  156. }