use approx::{AbsDiffEq, RelativeEq, UlpsEq}; use num::{One, Zero}; use std::fmt; use std::hash; #[cfg(feature = "abomonation-serialize")] use std::io::{Result as IOResult, Write}; #[cfg(feature = "serde-serialize")] use serde::{Deserialize, Deserializer, Serialize, Serializer}; #[cfg(feature = "abomonation-serialize")] use abomonation::Abomonation; use alga::general::{ClosedAdd, ClosedNeg, ClosedSub, RealField}; use crate::base::allocator::Allocator; use crate::base::dimension::{DimName, DimNameAdd, DimNameSum, U1}; use crate::base::storage::Owned; use crate::base::{DefaultAllocator, MatrixN, Scalar, VectorN}; use crate::geometry::Point; /// A translation. #[repr(C)] #[derive(Debug)] pub struct Translation where DefaultAllocator: Allocator { /// The translation coordinates, i.e., how much is added to a point's coordinates when it is /// translated. pub vector: VectorN, } impl hash::Hash for Translation where DefaultAllocator: Allocator, Owned: hash::Hash, { fn hash(&self, state: &mut H) { self.vector.hash(state) } } impl Copy for Translation where DefaultAllocator: Allocator, Owned: Copy, {} impl Clone for Translation where DefaultAllocator: Allocator, Owned: Clone, { #[inline] fn clone(&self) -> Self { Translation::from(self.vector.clone()) } } #[cfg(feature = "abomonation-serialize")] impl Abomonation for Translation where N: Scalar + Clone, D: DimName, VectorN: Abomonation, DefaultAllocator: Allocator, { unsafe fn entomb(&self, writer: &mut W) -> IOResult<()> { self.vector.entomb(writer) } fn extent(&self) -> usize { self.vector.extent() } unsafe fn exhume<'a, 'b>(&'a mut self, bytes: &'b mut [u8]) -> Option<&'b mut [u8]> { self.vector.exhume(bytes) } } #[cfg(feature = "serde-serialize")] impl Serialize for Translation where DefaultAllocator: Allocator, Owned: Serialize, { fn serialize(&self, serializer: S) -> Result where S: Serializer { self.vector.serialize(serializer) } } #[cfg(feature = "serde-serialize")] impl<'a, N: Scalar + Clone, D: DimName> Deserialize<'a> for Translation where DefaultAllocator: Allocator, Owned: Deserialize<'a>, { fn deserialize(deserializer: Des) -> Result where Des: Deserializer<'a> { let matrix = VectorN::::deserialize(deserializer)?; Ok(Translation::from(matrix)) } } impl Translation where DefaultAllocator: Allocator { /// Creates a new translation from the given vector. #[inline] #[deprecated(note = "Use `::from` instead.")] pub fn from_vector(vector: VectorN) -> Translation { Translation { vector: vector } } /// Inverts `self`. /// /// # Example /// ``` /// # use nalgebra::{Translation2, Translation3}; /// let t = Translation3::new(1.0, 2.0, 3.0); /// assert_eq!(t * t.inverse(), Translation3::identity()); /// assert_eq!(t.inverse() * t, Translation3::identity()); /// /// // Work in all dimensions. /// let t = Translation2::new(1.0, 2.0); /// assert_eq!(t * t.inverse(), Translation2::identity()); /// assert_eq!(t.inverse() * t, Translation2::identity()); /// ``` #[inline] pub fn inverse(&self) -> Translation where N: ClosedNeg { Translation::from(-&self.vector) } /// Converts this translation into its equivalent homogeneous transformation matrix. /// /// # Example /// ``` /// # use nalgebra::{Translation2, Translation3, Matrix3, Matrix4}; /// let t = Translation3::new(10.0, 20.0, 30.0); /// let expected = Matrix4::new(1.0, 0.0, 0.0, 10.0, /// 0.0, 1.0, 0.0, 20.0, /// 0.0, 0.0, 1.0, 30.0, /// 0.0, 0.0, 0.0, 1.0); /// assert_eq!(t.to_homogeneous(), expected); /// /// let t = Translation2::new(10.0, 20.0); /// let expected = Matrix3::new(1.0, 0.0, 10.0, /// 0.0, 1.0, 20.0, /// 0.0, 0.0, 1.0); /// assert_eq!(t.to_homogeneous(), expected); /// ``` #[inline] pub fn to_homogeneous(&self) -> MatrixN> where N: Zero + One, D: DimNameAdd, DefaultAllocator: Allocator, DimNameSum>, { let mut res = MatrixN::>::identity(); res.fixed_slice_mut::(0, D::dim()) .copy_from(&self.vector); res } /// Inverts `self` in-place. /// /// # Example /// ``` /// # use nalgebra::{Translation2, Translation3}; /// let t = Translation3::new(1.0, 2.0, 3.0); /// let mut inv_t = Translation3::new(1.0, 2.0, 3.0); /// inv_t.inverse_mut(); /// assert_eq!(t * inv_t, Translation3::identity()); /// assert_eq!(inv_t * t, Translation3::identity()); /// /// // Work in all dimensions. /// let t = Translation2::new(1.0, 2.0); /// let mut inv_t = Translation2::new(1.0, 2.0); /// inv_t.inverse_mut(); /// assert_eq!(t * inv_t, Translation2::identity()); /// assert_eq!(inv_t * t, Translation2::identity()); /// ``` #[inline] pub fn inverse_mut(&mut self) where N: ClosedNeg { self.vector.neg_mut() } } impl Translation where DefaultAllocator: Allocator { /// Translate the given point. /// /// This is the same as the multiplication `self * pt`. /// /// # Example /// ``` /// # use nalgebra::{Translation3, Point3}; /// let t = Translation3::new(1.0, 2.0, 3.0); /// let transformed_point = t.transform_point(&Point3::new(4.0, 5.0, 6.0)); /// assert_eq!(transformed_point, Point3::new(5.0, 7.0, 9.0)); #[inline] pub fn transform_point(&self, pt: &Point) -> Point { pt + &self.vector } } impl Translation where DefaultAllocator: Allocator { /// Translate the given point by the inverse of this translation. /// /// # Example /// ``` /// # use nalgebra::{Translation3, Point3}; /// let t = Translation3::new(1.0, 2.0, 3.0); /// let transformed_point = t.inverse_transform_point(&Point3::new(4.0, 5.0, 6.0)); /// assert_eq!(transformed_point, Point3::new(3.0, 3.0, 3.0)); #[inline] pub fn inverse_transform_point(&self, pt: &Point) -> Point { pt - &self.vector } } impl Eq for Translation where DefaultAllocator: Allocator {} impl PartialEq for Translation where DefaultAllocator: Allocator { #[inline] fn eq(&self, right: &Translation) -> bool { self.vector == right.vector } } impl AbsDiffEq for Translation where DefaultAllocator: Allocator, N::Epsilon: Copy, { type Epsilon = N::Epsilon; #[inline] fn default_epsilon() -> Self::Epsilon { N::default_epsilon() } #[inline] fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool { self.vector.abs_diff_eq(&other.vector, epsilon) } } impl RelativeEq for Translation where DefaultAllocator: Allocator, N::Epsilon: Copy, { #[inline] fn default_max_relative() -> Self::Epsilon { N::default_max_relative() } #[inline] fn relative_eq( &self, other: &Self, epsilon: Self::Epsilon, max_relative: Self::Epsilon, ) -> bool { self.vector .relative_eq(&other.vector, epsilon, max_relative) } } impl UlpsEq for Translation where DefaultAllocator: Allocator, N::Epsilon: Copy, { #[inline] fn default_max_ulps() -> u32 { N::default_max_ulps() } #[inline] fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool { self.vector.ulps_eq(&other.vector, epsilon, max_ulps) } } /* * * Display * */ impl fmt::Display for Translation where DefaultAllocator: Allocator + Allocator { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let precision = f.precision().unwrap_or(3); writeln!(f, "Translation {{")?; write!(f, "{:.*}", precision, self.vector)?; writeln!(f, "}}") } }