From 0b39e8f3005190f49796cdc131ba47975a702e16 Mon Sep 17 00:00:00 2001 From: Brendan Zabarauskas Date: Sat, 12 Dec 2015 18:39:31 +1100 Subject: [PATCH] Add missing by-ref and by-val permutations of quaternion operators --- CHANGELOG.md | 3 + src/quaternion.rs | 164 +++++++++++++++++++++++++++------------------- 2 files changed, 98 insertions(+), 69 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0a8bac5..d9c9b7e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,9 @@ This project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +### Added +- Add missing by-ref and by-val permutations of `Quaternion` operators. + ## [v0.6.0] - 2015-12-12 ### Added diff --git a/src/quaternion.rs b/src/quaternion.rs index 42f0dc9..96bfbb6 100644 --- a/src/quaternion.rs +++ b/src/quaternion.rs @@ -67,8 +67,8 @@ impl Quaternion { /// The dot product of the quaternion and `q`. #[inline] - pub fn dot(self, q: Quaternion) -> S { - self.s * q.s + self.v.dot(q.v) + pub fn dot(self, other: Quaternion) -> S { + self.s * other.s + self.v.dot(other.v) } /// The conjugate of the quaternion. @@ -105,86 +105,121 @@ impl Quaternion { /// Do a normalized linear interpolation with `other`, by `amount`. pub fn nlerp(self, other: Quaternion, amount: S) -> Quaternion { - (&(self * (S::one() - amount)) + &(other * amount)).normalize() + (self * (S::one() - amount) + other * amount).normalize() } } -impl Mul for Quaternion { +impl Neg for Quaternion { type Output = Quaternion; #[inline] - fn mul(self, value: S) -> Quaternion { - Quaternion::from_sv(self.s * value, self.v * value) - } + fn neg(self) -> Quaternion { Quaternion::from_sv(-self.s, -self.v) } } -impl<'a, S: BaseFloat> Mul for &'a Quaternion { +impl<'a, S: BaseFloat> Neg for &'a Quaternion { type Output = Quaternion; #[inline] - fn mul(self, value: S) -> Quaternion { - Quaternion::from_sv(self.s * value, self.v * value) - } + fn neg(self) -> Quaternion { Quaternion::from_sv(-self.s, -self.v) } } -impl Div for Quaternion { - type Output = Quaternion; +/// Generates a binary operator implementation for the permutations of by-ref and by-val +macro_rules! impl_binary_operator { + // When the right operand is a scalar + (<$S:ident> $Binop:ident<$Rhs:ident> for $Lhs:ty { fn $binop:ident($lhs:ident, $rhs:ident) -> $Output:ty { $body:expr } }) => { + impl<$S: BaseFloat> $Binop<$Rhs> for $Lhs { + type Output = $Output; + #[inline] + fn $binop(self, other: $Rhs) -> $Output { + let ($lhs, $rhs) = (self, other); $body + } + } - #[inline] - fn div(self, value: S) -> Quaternion { - Quaternion::from_sv(self.s / value, self.v / value) - } + impl<'a, $S: BaseFloat> $Binop<$Rhs> for &'a $Lhs { + type Output = $Output; + #[inline] + fn $binop(self, other: $Rhs) -> $Output { + let ($lhs, $rhs) = (self, other); $body + } + } + }; + // When the right operand is a compound type + (<$S:ident> $Binop:ident<$Rhs:ty> for $Lhs:ty { fn $binop:ident($lhs:ident, $rhs:ident) -> $Output:ty { $body:expr } }) => { + impl<$S: BaseFloat> $Binop<$Rhs> for $Lhs { + type Output = $Output; + #[inline] + fn $binop(self, other: $Rhs) -> $Output { + let ($lhs, $rhs) = (self, other); $body + } + } + + impl<'a, $S: BaseFloat> $Binop<&'a $Rhs> for $Lhs { + type Output = $Output; + #[inline] + fn $binop(self, other: &'a $Rhs) -> $Output { + let ($lhs, $rhs) = (self, other); $body + } + } + + impl<'a, $S: BaseFloat> $Binop<$Rhs> for &'a $Lhs { + type Output = $Output; + #[inline] + fn $binop(self, other: $Rhs) -> $Output { + let ($lhs, $rhs) = (self, other); $body + } + } + + impl<'a, 'b, $S: BaseFloat> $Binop<&'a $Rhs> for &'b $Lhs { + type Output = $Output; + #[inline] + fn $binop(self, other: &'a $Rhs) -> $Output { + let ($lhs, $rhs) = (self, other); $body + } + } + }; } -impl<'a, S: BaseFloat> Div for &'a Quaternion { - type Output = Quaternion; - - #[inline] - fn div(self, value: S) -> Quaternion { - Quaternion::from_sv(self.s / value, self.v / value) +impl_binary_operator!( Mul for Quaternion { + fn mul(lhs, rhs) -> Quaternion { + Quaternion::from_sv(lhs.s * rhs, lhs.v * rhs) } -} +}); -impl<'a, 'b, S: BaseFloat> Mul<&'b Vector3> for &'a Quaternion { - type Output = Vector3; +impl_binary_operator!( Div for Quaternion { + fn div(lhs, rhs) -> Quaternion { + Quaternion::from_sv(lhs.s / rhs, lhs.v / rhs) + } +}); - #[inline] - fn mul(self, vec: &'b Vector3) -> Vector3 { +impl_binary_operator!( Mul > for Quaternion { + fn mul(lhs, rhs) -> Vector3 {{ + let rhs = rhs.clone(); let two: S = cast(2i8).unwrap(); - let tmp = self.v.cross(*vec) + (vec * self.s); - (self.v.cross(tmp) * two) + vec + let tmp = lhs.v.cross(rhs) + (rhs * lhs.s); + (lhs.v.cross(tmp) * two) + rhs + }} +}); + +impl_binary_operator!( Add > for Quaternion { + fn add(lhs, rhs) -> Quaternion { + Quaternion::from_sv(lhs.s + rhs.s, lhs.v + rhs.v) } -} +}); -impl<'a, 'b, S: BaseFloat> Add<&'b Quaternion> for &'a Quaternion { - type Output = Quaternion; - - #[inline] - fn add(self, other: &'b Quaternion) -> Quaternion { - Quaternion::from_sv(self.s + other.s, self.v + &other.v) +impl_binary_operator!( Sub > for Quaternion { + fn sub(lhs, rhs) -> Quaternion { + Quaternion::from_sv(lhs.s - rhs.s, lhs.v - rhs.v) } -} +}); -impl<'a, 'b, S: BaseFloat> Sub<&'b Quaternion> for &'a Quaternion { - type Output = Quaternion; - - #[inline] - fn sub(self, other: &'b Quaternion) -> Quaternion { - Quaternion::from_sv(self.s - other.s, self.v - &other.v) +impl_binary_operator!( Mul > for Quaternion { + fn mul(lhs, rhs) -> Quaternion { + Quaternion::new(lhs.s * rhs.s - lhs.v.x * rhs.v.x - lhs.v.y * rhs.v.y - lhs.v.z * rhs.v.z, + lhs.s * rhs.v.x + lhs.v.x * rhs.s + lhs.v.y * rhs.v.z - lhs.v.z * rhs.v.y, + lhs.s * rhs.v.y + lhs.v.y * rhs.s + lhs.v.z * rhs.v.x - lhs.v.x * rhs.v.z, + lhs.s * rhs.v.z + lhs.v.z * rhs.s + lhs.v.x * rhs.v.y - lhs.v.y * rhs.v.x) } -} - -impl<'a, 'b, S: BaseFloat> Mul<&'b Quaternion> for &'a Quaternion { - type Output = Quaternion; - - #[inline] - fn mul(self, other: &'b Quaternion) -> Quaternion { - Quaternion::new(self.s * other.s - self.v.x * other.v.x - self.v.y * other.v.y - self.v.z * other.v.z, - self.s * other.v.x + self.v.x * other.s + self.v.y * other.v.z - self.v.z * other.v.y, - self.s * other.v.y + self.v.y * other.s + self.v.z * other.v.x - self.v.x * other.v.z, - self.s * other.v.z + self.v.z * other.s + self.v.x * other.v.y - self.v.y * other.v.x) - } -} +}); impl ApproxEq for Quaternion { type Epsilon = S; @@ -236,7 +271,7 @@ impl Quaternion { let scale1 = sin(theta.mul_s(S::one() - amount)); let scale2 = sin(theta.mul_s(amount)); - &(&(self * scale1) + &(other * scale2)) * sin(theta).recip() + (self * scale1 + other * scale2) * sin(theta).recip() } } @@ -331,15 +366,6 @@ impl From> for Matrix4 { } } -impl Neg for Quaternion { - type Output = Quaternion; - - #[inline] - fn neg(self) -> Quaternion { - Quaternion::from_sv(-self.s, -self.v) - } -} - impl fmt::Debug for Quaternion { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{:?} + {:?}i + {:?}j + {:?}k", @@ -374,7 +400,7 @@ impl Rotation> for Quaternion { } #[inline] - fn rotate_vector(&self, vec: Vector3) -> Vector3 { self * &vec } + fn rotate_vector(&self, vec: Vector3) -> Vector3 { self * vec } #[inline] fn concat(&self, other: &Quaternion) -> Quaternion { self * other } @@ -383,7 +409,7 @@ impl Rotation> for Quaternion { fn concat_self(&mut self, other: &Quaternion) { *self = &*self * other; } #[inline] - fn invert(&self) -> Quaternion { &self.conjugate() / self.magnitude2() } + fn invert(&self) -> Quaternion { self.conjugate() / self.magnitude2() } #[inline] fn invert_self(&mut self) { *self = self.invert() }