Merge pull request #358 from bjz/rotation-one

Make Rotation trait depend on One
This commit is contained in:
Brendan Zabarauskas 2016-05-12 12:13:15 +10:00
commit a7f4aa1756
4 changed files with 33 additions and 67 deletions

View file

@ -58,12 +58,6 @@ impl<S: BaseFloat> Quaternion<S> {
Quaternion { s: s, v: v } Quaternion { s: s, v: v }
} }
/// The multiplicative identity.
#[inline]
pub fn one() -> Quaternion<S> {
Quaternion::from_sv(S::one(), Vector3::zero())
}
/// The conjugate of the quaternion. /// The conjugate of the quaternion.
#[inline] #[inline]
pub fn conjugate(self) -> Quaternion<S> { pub fn conjugate(self) -> Quaternion<S> {
@ -131,6 +125,13 @@ impl<S: BaseFloat> Zero for Quaternion<S> {
} }
} }
impl<S: BaseFloat> One for Quaternion<S> {
#[inline]
fn one() -> Quaternion<S> {
Quaternion::from_sv(S::one(), Vector3::zero())
}
}
impl<S: BaseFloat> VectorSpace for Quaternion<S> { impl<S: BaseFloat> VectorSpace for Quaternion<S> {
type Scalar = S; type Scalar = S;
} }
@ -332,9 +333,6 @@ impl<S: BaseFloat> From<Quaternion<S>> for Basis3<S> {
} }
impl<S: BaseFloat> Rotation<Point3<S>> for Quaternion<S> { impl<S: BaseFloat> Rotation<Point3<S>> for Quaternion<S> {
#[inline]
fn one() -> Quaternion<S> { Quaternion::one() }
#[inline] #[inline]
fn look_at(dir: Vector3<S>, up: Vector3<S>) -> Quaternion<S> { fn look_at(dir: Vector3<S>, up: Vector3<S>) -> Quaternion<S> {
Matrix3::look_at(dir, up).into() Matrix3::look_at(dir, up).into()
@ -350,17 +348,8 @@ impl<S: BaseFloat> Rotation<Point3<S>> for Quaternion<S> {
#[inline] #[inline]
fn rotate_vector(&self, vec: Vector3<S>) -> Vector3<S> { self * vec } fn rotate_vector(&self, vec: Vector3<S>) -> Vector3<S> { self * vec }
#[inline]
fn concat(&self, other: &Quaternion<S>) -> Quaternion<S> { self * other }
#[inline]
fn concat_self(&mut self, other: &Quaternion<S>) { *self = &*self * other; }
#[inline] #[inline]
fn invert(&self) -> Quaternion<S> { self.conjugate() / self.magnitude2() } fn invert(&self) -> Quaternion<S> { self.conjugate() / self.magnitude2() }
#[inline]
fn invert_self(&mut self) { *self = self.invert() }
} }
impl<S: BaseFloat> Rotation3<S> for Quaternion<S> { impl<S: BaseFloat> Rotation3<S> for Quaternion<S> {

View file

@ -14,6 +14,7 @@
// limitations under the License. // limitations under the License.
use std::fmt; use std::fmt;
use std::ops::*;
use structure::*; use structure::*;
@ -28,14 +29,11 @@ use vector::{Vector2, Vector3};
/// A trait for a generic rotation. A rotation is a transformation that /// A trait for a generic rotation. A rotation is a transformation that
/// creates a circular motion, and preserves at least one point in the space. /// creates a circular motion, and preserves at least one point in the space.
pub trait Rotation<P: EuclideanSpace>: PartialEq + Sized where pub trait Rotation<P: EuclideanSpace>: Sized + Copy + One where
// FIXME: Ugly type signatures - blocked by rust-lang/rust#24092 // FIXME: Ugly type signatures - blocked by rust-lang/rust#24092
Self: ApproxEq<Epsilon = <P as EuclideanSpace>::Scalar>, Self: ApproxEq<Epsilon = <P as EuclideanSpace>::Scalar>,
<P as EuclideanSpace>::Scalar: BaseFloat, <P as EuclideanSpace>::Scalar: BaseFloat,
{ {
/// Create the identity transform (causes no transformation).
fn one() -> Self;
/// Create a rotation to a given direction with an 'up' vector /// Create a rotation to a given direction with an 'up' vector
fn look_at(dir: P::Diff, up: P::Diff) -> Self; fn look_at(dir: P::Diff, up: P::Diff) -> Self;
@ -53,24 +51,9 @@ pub trait Rotation<P: EuclideanSpace>: PartialEq + Sized where
P::from_vec(self.rotate_vector(point.to_vec())) P::from_vec(self.rotate_vector(point.to_vec()))
} }
/// Create a new rotation which combines both this rotation, and another.
fn concat(&self, other: &Self) -> Self;
/// Create a new rotation which "un-does" this rotation. That is, /// Create a new rotation which "un-does" this rotation. That is,
/// `r.concat(r.invert())` is the identity. /// `r * r.invert()` is the identity.
fn invert(&self) -> Self; fn invert(&self) -> Self;
/// Modify this rotation in-place by combining it with another.
#[inline]
fn concat_self(&mut self, other: &Self) {
*self = Self::concat(self, other);
}
/// Invert this rotation in-place.
#[inline]
fn invert_self(&mut self) {
*self = self.invert();
}
} }
/// A two-dimensional rotation. /// A two-dimensional rotation.
@ -151,7 +134,7 @@ pub trait Rotation3<S: BaseFloat>: Rotation<Point3<S>>
/// ///
/// // Note that we can also concatenate rotations: /// // Note that we can also concatenate rotations:
/// let rot_half: Basis2<f64> = Rotation2::from_angle(rad(0.25f64 * f64::consts::PI)); /// let rot_half: Basis2<f64> = Rotation2::from_angle(rad(0.25f64 * f64::consts::PI));
/// let unit_y3 = rot_half.concat(&rot_half).rotate_vector(unit_x); /// let unit_y3 = (rot_half * rot_half).rotate_vector(unit_x);
/// assert!(unit_y3.approx_eq(&unit_y2)); /// assert!(unit_y3.approx_eq(&unit_y2));
/// ``` /// ```
#[derive(PartialEq, Copy, Clone, RustcEncodable, RustcDecodable)] #[derive(PartialEq, Copy, Clone, RustcEncodable, RustcDecodable)]
@ -172,9 +155,6 @@ impl<S: BaseFloat> From<Basis2<S>> for Matrix2<S> {
} }
impl<S: BaseFloat> Rotation<Point2<S>> for Basis2<S> { impl<S: BaseFloat> Rotation<Point2<S>> for Basis2<S> {
#[inline]
fn one() -> Basis2<S> { Basis2 { mat: Matrix2::identity() } }
#[inline] #[inline]
fn look_at(dir: Vector2<S>, up: Vector2<S>) -> Basis2<S> { fn look_at(dir: Vector2<S>, up: Vector2<S>) -> Basis2<S> {
Basis2 { mat: Matrix2::look_at(dir, up) } Basis2 { mat: Matrix2::look_at(dir, up) }
@ -188,18 +168,21 @@ impl<S: BaseFloat> Rotation<Point2<S>> for Basis2<S> {
#[inline] #[inline]
fn rotate_vector(&self, vec: Vector2<S>) -> Vector2<S> { self.mat * vec } fn rotate_vector(&self, vec: Vector2<S>) -> Vector2<S> { self.mat * vec }
#[inline]
fn concat(&self, other: &Basis2<S>) -> Basis2<S> { Basis2 { mat: self.mat * other.mat } }
#[inline]
fn concat_self(&mut self, other: &Basis2<S>) { self.mat = self.mat * other.mat; }
// TODO: we know the matrix is orthogonal, so this could be re-written // TODO: we know the matrix is orthogonal, so this could be re-written
// to be faster // to be faster
#[inline] #[inline]
fn invert(&self) -> Basis2<S> { Basis2 { mat: self.mat.invert().unwrap() } } fn invert(&self) -> Basis2<S> { Basis2 { mat: self.mat.invert().unwrap() } }
} }
impl<S: BaseFloat> One for Basis2<S> {
#[inline]
fn one() -> Basis2<S> { Basis2 { mat: Matrix2::one() } }
}
impl_operator!(<S: BaseFloat> Mul<Basis2<S> > for Basis2<S> {
fn mul(lhs, rhs) -> Basis2<S> { Basis2 { mat: lhs.mat * rhs.mat } }
});
impl<S: BaseFloat> ApproxEq for Basis2<S> { impl<S: BaseFloat> ApproxEq for Basis2<S> {
type Epsilon = S; type Epsilon = S;
@ -257,9 +240,6 @@ impl<S: BaseFloat> From<Basis3<S>> for Quaternion<S> {
} }
impl<S: BaseFloat> Rotation<Point3<S>> for Basis3<S> { impl<S: BaseFloat> Rotation<Point3<S>> for Basis3<S> {
#[inline]
fn one() -> Basis3<S> { Basis3 { mat: Matrix3::identity() } }
#[inline] #[inline]
fn look_at(dir: Vector3<S>, up: Vector3<S>) -> Basis3<S> { fn look_at(dir: Vector3<S>, up: Vector3<S>) -> Basis3<S> {
Basis3 { mat: Matrix3::look_at(dir, up) } Basis3 { mat: Matrix3::look_at(dir, up) }
@ -274,18 +254,21 @@ impl<S: BaseFloat> Rotation<Point3<S>> for Basis3<S> {
#[inline] #[inline]
fn rotate_vector(&self, vec: Vector3<S>) -> Vector3<S> { self.mat * vec } fn rotate_vector(&self, vec: Vector3<S>) -> Vector3<S> { self.mat * vec }
#[inline]
fn concat(&self, other: &Basis3<S>) -> Basis3<S> { Basis3 { mat: self.mat * other.mat } }
#[inline]
fn concat_self(&mut self, other: &Basis3<S>) { self.mat = self.mat * other.mat; }
// TODO: we know the matrix is orthogonal, so this could be re-written // TODO: we know the matrix is orthogonal, so this could be re-written
// to be faster // to be faster
#[inline] #[inline]
fn invert(&self) -> Basis3<S> { Basis3 { mat: self.mat.invert().unwrap() } } fn invert(&self) -> Basis3<S> { Basis3 { mat: self.mat.invert().unwrap() } }
} }
impl<S: BaseFloat> One for Basis3<S> {
#[inline]
fn one() -> Basis3<S> { Basis3 { mat: Matrix3::one() } }
}
impl_operator!(<S: BaseFloat> Mul<Basis3<S> > for Basis3<S> {
fn mul(lhs, rhs) -> Basis3<S> { Basis3 { mat: lhs.mat * rhs.mat } }
});
impl<S: BaseFloat> ApproxEq for Basis3<S> { impl<S: BaseFloat> ApproxEq for Basis3<S> {
type Epsilon = S; type Epsilon = S;

View file

@ -40,12 +40,6 @@ pub trait Transform<P: EuclideanSpace>: Sized {
/// Transform a point using this transform. /// Transform a point using this transform.
fn transform_point(&self, point: P) -> P; fn transform_point(&self, point: P) -> P;
/// Transform a vector as a point using this transform.
#[inline]
fn transform_as_point(&self, vec: P::Diff) -> P::Diff {
self.transform_point(P::from_vec(vec)).to_vec()
}
/// Combine this transform with another, yielding a new transformation /// Combine this transform with another, yielding a new transformation
/// which has the effects of both. /// which has the effects of both.
fn concat(&self, other: &Self) -> Self; fn concat(&self, other: &Self) -> Self;
@ -108,8 +102,8 @@ impl<P: EuclideanSpace, R: Rotation<P>> Transform<P> for Decomposed<P::Diff, R>
fn concat(&self, other: &Decomposed<P::Diff, R>) -> Decomposed<P::Diff, R> { fn concat(&self, other: &Decomposed<P::Diff, R>) -> Decomposed<P::Diff, R> {
Decomposed { Decomposed {
scale: self.scale * other.scale, scale: self.scale * other.scale,
rot: self.rot.concat(&other.rot), rot: self.rot * other.rot,
disp: self.transform_as_point(other.disp.clone()), disp: self.disp + other.disp,
} }
} }

View file

@ -33,7 +33,7 @@ mod rotation {
#[test] #[test]
fn test_invert_basis2() { fn test_invert_basis2() {
let a: Basis2<_> = rotation::a2(); let a: Basis2<_> = rotation::a2();
let a = a.concat(&a.invert()); let a = a * a.invert();
let a: &Matrix2<_> = a.as_ref(); let a: &Matrix2<_> = a.as_ref();
assert!(a.is_identity()); assert!(a.is_identity());
} }
@ -41,7 +41,7 @@ fn test_invert_basis2() {
#[test] #[test]
fn test_invert_basis3() { fn test_invert_basis3() {
let a: Basis3<_> = rotation::a3(); let a: Basis3<_> = rotation::a3();
let a = a.concat(&a.invert()); let a = a * a.invert();
let a: &Matrix3<_> = a.as_ref(); let a: &Matrix3<_> = a.as_ref();
assert!(a.is_identity()); assert!(a.is_identity());
} }