use std::fmt; use std::marker::PhantomData; use approx::ApproxEq; use alga::general::{Real, SubsetOf}; use alga::linear::Rotation; use core::{Scalar, OwnedSquareMatrix}; use core::dimension::{DimName, DimNameSum, DimNameAdd, U1}; use core::storage::{Storage, OwnedStorage}; use core::allocator::{Allocator, OwnedAllocator}; use geometry::{TranslationBase, PointBase}; /// An isometry that uses a data storage deduced from the allocator `A`. pub type OwnedIsometryBase = IsometryBase>::Buffer, R>; /// A direct isometry, i.e., a rotation followed by a translation. #[repr(C)] #[derive(Hash, Debug, Clone, Copy, Serialize, Deserialize)] pub struct IsometryBase { /// The pure rotational part of this isometry. pub rotation: R, /// The pure translational part of this isometry. pub translation: TranslationBase, // One dummy private field just to prevent explicit construction. #[serde(skip_serializing, skip_deserializing)] _noconstruct: PhantomData } impl IsometryBase where N: Real, S: OwnedStorage, R: Rotation>, S::Alloc: OwnedAllocator { /// Creates a new isometry from its rotational and translational parts. #[inline] pub fn from_parts(translation: TranslationBase, rotation: R) -> IsometryBase { IsometryBase { rotation: rotation, translation: translation, _noconstruct: PhantomData } } /// Inverts `self`. #[inline] pub fn inverse(&self) -> IsometryBase { let mut res = self.clone(); res.inverse_mut(); res } /// Inverts `self`. #[inline] pub fn inverse_mut(&mut self) { self.rotation.inverse_mut(); self.translation.inverse_mut(); self.translation.vector = self.rotation.transform_vector(&self.translation.vector); } /// Appends to `self` the given translation in-place. #[inline] pub fn append_translation_mut(&mut self, t: &TranslationBase) { self.translation.vector += &t.vector } /// Appends to `self` the given rotation in-place. #[inline] pub fn append_rotation_mut(&mut self, r: &R) { self.rotation = self.rotation.append_rotation(&r); self.translation.vector = r.transform_vector(&self.translation.vector); } /// Appends in-place to `self` a rotation centered at the point `p`, i.e., the rotation that /// lets `p` invariant. #[inline] pub fn append_rotation_wrt_point_mut(&mut self, r: &R, p: &PointBase) { self.translation.vector -= &p.coords; self.append_rotation_mut(r); self.translation.vector += &p.coords; } /// Appends in-place to `self` a rotation centered at the point with coordinates /// `self.translation`. #[inline] pub fn append_rotation_wrt_center_mut(&mut self, r: &R) { let center = PointBase::from_coordinates(self.translation.vector.clone()); self.append_rotation_wrt_point_mut(r, ¢er) } } // NOTE: we don't require `R: Rotation<...>` here because this is not useful for the implementation // and makes it hard to use it, e.g., for Transform × Isometry implementation. // This is OK since all constructors of the isometry enforce the Rotation bound already (and // explicit struct construction is prevented by the dummy ZST field). impl IsometryBase where N: Scalar, S: Storage { /// Converts this isometry into its equivalent homogeneous transformation matrix. #[inline] pub fn to_homogeneous(&self) -> OwnedSquareMatrix, S::Alloc> where D: DimNameAdd, R: SubsetOf, S::Alloc>>, S::Alloc: Allocator, DimNameSum> { let mut res: OwnedSquareMatrix = ::convert_ref(&self.rotation); res.fixed_slice_mut::(0, D::dim()).copy_from(&self.translation.vector); res } } impl Eq for IsometryBase where N: Real, S: OwnedStorage, R: Rotation> + Eq, S::Alloc: OwnedAllocator { } impl PartialEq for IsometryBase where N: Real, S: OwnedStorage, R: Rotation> + PartialEq, S::Alloc: OwnedAllocator { #[inline] fn eq(&self, right: &IsometryBase) -> bool { self.translation == right.translation && self.rotation == right.rotation } } impl ApproxEq for IsometryBase where N: Real, S: OwnedStorage, R: Rotation> + ApproxEq, S::Alloc: OwnedAllocator, N::Epsilon: Copy { type Epsilon = N::Epsilon; #[inline] fn default_epsilon() -> Self::Epsilon { N::default_epsilon() } #[inline] fn default_max_relative() -> Self::Epsilon { N::default_max_relative() } #[inline] fn default_max_ulps() -> u32 { N::default_max_ulps() } #[inline] fn relative_eq(&self, other: &Self, epsilon: Self::Epsilon, max_relative: Self::Epsilon) -> bool { self.translation.relative_eq(&other.translation, epsilon, max_relative) && self.rotation.relative_eq(&other.rotation, epsilon, max_relative) } #[inline] fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool { self.translation.ulps_eq(&other.translation, epsilon, max_ulps) && self.rotation.ulps_eq(&other.rotation, epsilon, max_ulps) } } /* * * Display * */ impl fmt::Display for IsometryBase where N: Real + fmt::Display, S: OwnedStorage, R: fmt::Display, S::Alloc: OwnedAllocator + Allocator { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let precision = f.precision().unwrap_or(3); try!(writeln!(f, "IsometryBase {{")); try!(write!(f, "{:.*}", precision, self.translation)); try!(write!(f, "{:.*}", precision, self.rotation)); writeln!(f, "}}") } } // /* // * // * Absolute // * // */ // impl Absolute for $t { // type AbsoluteValue = $submatrix; // // #[inline] // fn abs(m: &$t) -> $submatrix { // Absolute::abs(&m.submatrix) // } // }