diff --git a/src/angle.rs b/src/angle.rs index fdcda6f..530455d 100644 --- a/src/angle.rs +++ b/src/angle.rs @@ -22,7 +22,7 @@ use std::ops::*; use rand::{Rand, Rng}; use rand::distributions::range::SampleRange; -use rust_num::{Float, One, Zero}; +use rust_num::{Float, Zero}; use rust_num::traits::cast; use approx::ApproxEq; @@ -75,7 +75,7 @@ impl ScalarConv for Deg { /// Operations on angles. pub trait Angle where - Self: Clone + Zero, + Self: Copy + Clone, Self: PartialEq + PartialOrd, // FIXME: Ugly type signatures - blocked by rust-lang/rust#24092 Self: ApproxEq::Unitless>, @@ -91,7 +91,7 @@ pub trait Angle where fn from>(theta: A) -> Self; /// Negate this angle, in-place. - #[inline] fn neg_self(&mut self) { *self = -(*self).clone() } + #[inline] fn neg_self(&mut self) { *self = -*self } /// Add this angle with another, returning the new angle. #[inline] fn add_a(&self, other: Self) -> Self { ScalarConv::from(*self.s() + *other.s()) } @@ -149,6 +149,7 @@ pub trait Angle where self.add_a(self.sub_a(other).mul_s(cast(0.5f64).unwrap())).normalize() } + fn zero() -> Self; fn full_turn() -> Self; #[inline] fn turn_div_2() -> Self { Self::full_turn().div_s(cast(2i8).unwrap()) } @@ -161,97 +162,6 @@ pub trait Angle where #[inline] pub fn bisect(a: A, b: A) -> A { a.bisect(b) } -impl>, S: BaseFloat> Add for Rad { - type Output = Rad; - - #[inline] - fn add(self, other: R) -> Rad { rad(self.s + other.into().s) } -} - -impl>, S: BaseFloat> Add for Deg { - type Output = Deg; - - #[inline] - fn add(self, other: R) -> Deg { deg(self.s + other.into().s) } -} - -impl>, S: BaseFloat> Sub for Rad { - type Output = Rad; - - #[inline] - fn sub(self, other: R) -> Rad { rad(self.s - other.into().s) } -} - -impl>, S: BaseFloat> Sub for Deg { - type Output = Deg; - - #[inline] - fn sub(self, other: R) -> Deg { deg(self.s - other.into().s) } -} - -impl Neg for Rad { - type Output = Rad; - - #[inline] - fn neg(self) -> Rad { rad(-self.s) } -} -impl Neg for Deg { - type Output = Deg; - - #[inline] - fn neg(self) -> Deg { deg(-self.s) } -} - -impl Zero for Rad { - #[inline] - fn zero() -> Rad { rad(S::zero()) } - #[inline] - fn is_zero(&self) -> bool { *self == Self::zero() } -} -impl Zero for Deg { - #[inline] - fn zero() -> Deg { deg(S::zero()) } - #[inline] - fn is_zero(&self) -> bool { *self == Self::zero() } -} - -impl>, S: BaseFloat> Mul for Rad { - type Output = Rad; - - #[inline] - fn mul(self, other: R) -> Rad { rad(self.s * other.into().s) } -} - -impl>, S: BaseFloat> Mul for Deg { - type Output = Deg; - - #[inline] - fn mul(self, other: R) -> Deg { deg(self.s * other.into().s) } -} - -impl One for Rad { - #[inline] - fn one() -> Rad { rad(S::one()) } -} -impl One for Deg { - #[inline] - fn one() -> Deg { deg(S::one()) } -} - -const PI_2: f64 = f64::consts::PI * 2f64; - -impl Angle for Rad { - type Unitless = S; - #[inline] fn from>(theta: A) -> Rad { theta.into() } - #[inline] fn full_turn() -> Rad { rad(cast(PI_2).unwrap()) } -} - -impl Angle for Deg { - type Unitless = S; - #[inline] fn from>(theta: A) -> Deg { theta.into() } - #[inline] fn full_turn() -> Deg { deg(cast(360i32).unwrap()) } -} - #[inline] pub fn sin>>(theta: R) -> S { theta.into().s.sin() } #[inline] pub fn cos>>(theta: R) -> S { theta.into().s.cos() } #[inline] pub fn tan>>(theta: R) -> S { theta.into().s.tan() } @@ -266,49 +176,82 @@ impl Angle for Deg { #[inline] pub fn atan>>(s: S) -> R { rad(s.atan()).into() } #[inline] pub fn atan2>>(a: S, b: S) -> R { rad(a.atan2(b)).into() } -impl fmt::Debug for Rad { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{:?} rad", self.s) +macro_rules! impl_angle { + ($Angle:ident, $fmt:expr, $full_turn:expr, $hi:expr) => { + impl Angle for $Angle { + type Unitless = S; + + #[inline] + fn zero() -> $Angle { ScalarConv::from(S::zero()) } + + #[inline] + fn from>(theta: A) -> $Angle { theta.into() } + + #[inline] + fn full_turn() -> $Angle { ScalarConv::from(cast($full_turn).unwrap()) } + } + + impl Neg for $Angle { + type Output = $Angle; + + #[inline] + fn neg(self) -> $Angle { ScalarConv::from(-self.s) } + } + + impl<'a, S: BaseFloat> Neg for &'a $Angle { + type Output = $Angle; + + #[inline] + fn neg(self) -> $Angle { ScalarConv::from(-self.s) } + } + + impl_binary_operator!( Add<$Angle > for $Angle { + fn add(lhs, rhs) -> $Angle { ScalarConv::from(lhs.s + rhs.s) } + }); + impl_binary_operator!( Sub<$Angle > for $Angle { + fn sub(lhs, rhs) -> $Angle { ScalarConv::from(lhs.s - rhs.s) } + }); + impl_binary_operator!( Div<$Angle > for $Angle { + fn div(lhs, rhs) -> S { lhs.s / rhs.s } + }); + impl_binary_operator!( Rem<$Angle > for $Angle { + fn rem(lhs, rhs) -> S { lhs.s % rhs.s } + }); + + impl_binary_operator!( Mul for $Angle { + fn mul(lhs, scalar) -> $Angle { ScalarConv::from(lhs.s * scalar) } + }); + impl_binary_operator!( Div for $Angle { + fn div(lhs, scalar) -> $Angle { ScalarConv::from(lhs.s / scalar) } + }); + impl_binary_operator!( Rem for $Angle { + fn rem(lhs, scalar) -> $Angle { ScalarConv::from(lhs.s % scalar) } + }); + + impl ApproxEq for $Angle { + type Epsilon = S; + + #[inline] + fn approx_eq_eps(&self, other: &$Angle, epsilon: &S) -> bool { + self.s.approx_eq_eps(&other.s, epsilon) + } + } + + impl Rand for $Angle { + #[inline] + fn rand(rng: &mut R) -> $Angle { + let angle: S = rng.gen_range(cast(-$hi).unwrap(), cast($hi).unwrap()); + ScalarConv::from(angle) + } + } + + impl fmt::Debug for $Angle { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, $fmt, self.s) + } + } } } -impl -fmt::Debug for Deg { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{:?}°", self.s) - } -} - -impl ApproxEq for Rad { - type Epsilon = S; - - #[inline] - fn approx_eq_eps(&self, other: &Rad, epsilon: &S) -> bool { - self.s.approx_eq_eps(&other.s, epsilon) - } -} - -impl ApproxEq for Deg { - type Epsilon = S; - - #[inline] - fn approx_eq_eps(&self, other: &Deg, epsilon: &S) -> bool { - self.s.approx_eq_eps(&other.s, epsilon) - } -} - -impl Rand for Rad { - #[inline] - fn rand(rng: &mut R) -> Rad { - let angle: S = rng.gen_range(cast(-f64::consts::PI).unwrap(), cast(f64::consts::PI).unwrap()); - rad(angle) - } -} - -impl Rand for Deg { - #[inline] - fn rand(rng: &mut R) -> Deg { - let angle: S = rng.gen_range(cast(-180f64).unwrap(), cast(180f64).unwrap()); - deg(angle) - } -} +impl_angle!(Rad, "{:?} rad", f64::consts::PI * 2.0, f64::consts::PI); +impl_angle!(Deg, "{:?}°", 360, 180);