use std::num::{One, Zero}; use std::rand::{Rand, Rng, RngUtil}; use std::cmp::ApproxEq; use traits::dim::Dim; use traits::inv::Inv; use traits::rotation::{Rotation, Rotate, Rotatable}; use traits::translation::{Translation, Translate, Translatable}; use traits::transformation; use traits::transformation::{Transformation, Transformable}; use traits::rlmul::{RMul, LMul}; use traits::homogeneous::{ToHomogeneous, FromHomogeneous}; use traits::column::Column; #[deriving(Eq, ToStr)] pub struct Transform { priv submat : M, priv subtrans : V } impl Transform { #[inline] pub fn new(mat: M, trans: V) -> Transform { Transform { submat: mat, subtrans: trans } } } impl Transform { #[inline] pub fn submat(&self) -> M { copy self.submat } #[inline] pub fn subtrans(&self) -> V { copy self.subtrans } } impl Dim for Transform { #[inline] fn dim() -> uint { Dim::dim::() } } impl One for Transform { #[inline] fn one() -> Transform { Transform { submat: One::one(), subtrans: Zero::zero() } } } impl Zero for Transform { #[inline] fn zero() -> Transform { Transform { submat: Zero::zero(), subtrans: Zero::zero() } } #[inline] fn is_zero(&self) -> bool { self.submat.is_zero() && self.subtrans.is_zero() } } impl + Mul, V: Add> Mul, Transform> for Transform { #[inline] fn mul(&self, other: &Transform) -> Transform { Transform { submat: self.submat * other.submat, subtrans: self.subtrans + self.submat.rmul(&other.subtrans) } } } impl, V: Add> RMul for Transform { #[inline] fn rmul(&self, other: &V) -> V { self.submat.rmul(other) + self.subtrans } } impl, V: Add> LMul for Transform { #[inline] fn lmul(&self, other: &V) -> V { self.submat.lmul(other) + self.subtrans } } impl> Translation for Transform { #[inline] fn translation(&self) -> V { self.subtrans.translation() } #[inline] fn inv_translation(&self) -> V { self.subtrans.inv_translation() } #[inline] fn translate_by(&mut self, t: &V) { self.subtrans.translate_by(t) } } impl, V, _0> Translate for Transform { #[inline] fn translate(&self, v: &V) -> V { self.submat.translate(v) } #[inline] fn inv_translate(&self, v: &V) -> V { self.submat.inv_translate(v) } } impl + Translation> Translatable> for Transform { #[inline] fn translated(&self, t: &V) -> Transform { Transform::new(copy self.submat, self.subtrans.translated(t)) } } impl + RMul + One, V, AV> Rotation for Transform { #[inline] fn rotation(&self) -> AV { self.submat.rotation() } #[inline] fn inv_rotation(&self) -> AV { self.submat.inv_rotation() } #[inline] fn rotate_by(&mut self, rot: &AV) { // FIXME: this does not seem opitmal let mut delta = One::one::(); delta.rotate_by(rot); self.submat.rotate_by(rot); self.subtrans = delta.rmul(&self.subtrans); } } impl, V, _0> Rotate for Transform { #[inline] fn rotate(&self, v: &V) -> V { self.submat.rotate(v) } #[inline] fn inv_rotate(&self, v: &V) -> V { self.submat.inv_rotate(v) } } impl + One, Res: Rotation + RMul + One, V, AV> Rotatable> for Transform { #[inline] fn rotated(&self, rot: &AV) -> Transform { // FIXME: this does not seem opitmal let delta = One::one::().rotated(rot); Transform::new(self.submat.rotated(rot), delta.rmul(&self.subtrans)) } } impl + Mul + Copy, V: Add + Neg + Copy> Transformation> for Transform { fn transformation(&self) -> Transform { copy *self } fn inv_transformation(&self) -> Transform { self.inverse() } fn transform_by(&mut self, other: &Transform) { *self = other * *self; } } impl, V: Add + Sub> transformation::Transform for Transform { #[inline] fn transform_vec(&self, v: &V) -> V { self.submat.transform_vec(v) + self.subtrans } #[inline] fn inv_transform(&self, v: &V) -> V { self.submat.inv_transform(&(v - self.subtrans)) } } // FIXME: constraints are too restrictive. // Should be: Transformable ... impl + Mul + Inv, V: Add + Neg> Transformable, Transform> for Transform { fn transformed(&self, t: &Transform) -> Transform { t * *self } } impl, V: Copy + Neg> Inv for Transform { #[inline] fn invert(&mut self) { self.submat.invert(); self.subtrans = self.submat.rmul(&-self.subtrans); } #[inline] fn inverse(&self) -> Transform { let mut res = copy *self; res.invert(); res } } impl, M2: Dim + Column, V: Copy> ToHomogeneous for Transform { fn to_homogeneous(&self) -> M2 { let mut res = self.submat.to_homogeneous(); // copy the translation let dim = Dim::dim::(); res.set_column(dim - 1, copy self.subtrans); res } } impl + Dim, M2: FromHomogeneous, V: Copy> FromHomogeneous for Transform { fn from_homogeneous(m: &M) -> Transform { Transform::new(FromHomogeneous::from_homogeneous(m), m.column(Dim::dim::() - 1)) } } impl, M:ApproxEq, V:ApproxEq> ApproxEq for Transform { #[inline] fn approx_epsilon() -> N { ApproxEq::approx_epsilon::() } #[inline] fn approx_eq(&self, other: &Transform) -> bool { self.submat.approx_eq(&other.submat) && self.subtrans.approx_eq(&other.subtrans) } #[inline] fn approx_eq_eps(&self, other: &Transform, epsilon: &N) -> bool { self.submat.approx_eq_eps(&other.submat, epsilon) && self.subtrans.approx_eq_eps(&other.subtrans, epsilon) } } impl Rand for Transform { #[inline] fn rand(rng: &mut R) -> Transform { Transform::new(rng.gen(), rng.gen()) } }