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-no-std")] use serde::{Deserialize, Deserializer, Serialize, Serializer}; #[cfg(feature = "abomonation-serialize")] use abomonation::Abomonation; use simba::scalar::{ClosedAdd, ClosedNeg, ClosedSub}; use crate::base::allocator::Allocator; use crate::base::dimension::{DimNameAdd, DimNameSum, U1}; use crate::base::storage::Owned; use crate::base::{Const, DefaultAllocator, OMatrix, SVector, Scalar}; use crate::geometry::Point; /// A translation. #[repr(C)] pub struct Translation { /// The translation coordinates, i.e., how much is added to a point's coordinates when it is /// translated. pub vector: SVector, } impl fmt::Debug for Translation { fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { self.vector.as_slice().fmt(formatter) } } impl hash::Hash for Translation where Owned>: hash::Hash, { fn hash(&self, state: &mut H) { self.vector.hash(state) } } impl Copy for Translation {} impl Clone for Translation where Owned>: Clone, { #[inline] fn clone(&self) -> Self { Translation::from(self.vector.clone()) } } #[cfg(feature = "bytemuck")] unsafe impl bytemuck::Zeroable for Translation where T: Scalar + bytemuck::Zeroable, SVector: bytemuck::Zeroable, { } #[cfg(feature = "bytemuck")] unsafe impl bytemuck::Pod for Translation where T: Scalar + bytemuck::Pod, SVector: bytemuck::Pod, { } #[cfg(feature = "abomonation-serialize")] impl Abomonation for Translation where T: Scalar, SVector: Abomonation, { 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-no-std")] impl Serialize for Translation where Owned>: Serialize, { fn serialize(&self, serializer: S) -> Result where S: Serializer, { self.vector.serialize(serializer) } } #[cfg(feature = "serde-serialize-no-std")] impl<'a, T: Scalar, const D: usize> Deserialize<'a> for Translation where Owned>: Deserialize<'a>, { fn deserialize(deserializer: Des) -> Result where Des: Deserializer<'a>, { let matrix = SVector::::deserialize(deserializer)?; Ok(Translation::from(matrix)) } } #[cfg(feature = "rkyv-serialize-no-std")] mod rkyv_impl { use super::Translation; use crate::base::SVector; use rkyv::{offset_of, project_struct, Archive, Deserialize, Fallible, Serialize}; impl Archive for Translation { type Archived = Translation; type Resolver = as Archive>::Resolver; fn resolve( &self, pos: usize, resolver: Self::Resolver, out: &mut core::mem::MaybeUninit, ) { self.vector.resolve( pos + offset_of!(Self::Archived, vector), resolver, project_struct!(out: Self::Archived => vector), ); } } impl, S: Fallible + ?Sized, const D: usize> Serialize for Translation { fn serialize(&self, serializer: &mut S) -> Result { self.vector.serialize(serializer) } } impl Deserialize, _D> for Translation where T::Archived: Deserialize, { fn deserialize(&self, deserializer: &mut _D) -> Result, _D::Error> { Ok(Translation { vector: self.vector.deserialize(deserializer)?, }) } } } impl Translation { /// Creates a new translation from the given vector. #[inline] #[deprecated(note = "Use `::from` instead.")] pub fn from_vector(vector: SVector) -> Translation { Translation { 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] #[must_use = "Did you mean to use inverse_mut()?"] pub fn inverse(&self) -> Translation where T: 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] #[must_use] pub fn to_homogeneous(&self) -> OMatrix, U1>, DimNameSum, U1>> where T: Zero + One, Const: DimNameAdd, DefaultAllocator: Allocator, U1>, DimNameSum, U1>>, { let mut res = OMatrix::, U1>, DimNameSum, U1>>::identity(); res.fixed_slice_mut::(0, D).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 T: ClosedNeg, { self.vector.neg_mut() } } impl Translation { /// 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] #[must_use] pub fn transform_point(&self, pt: &Point) -> Point { pt + &self.vector } } impl Translation { /// 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] #[must_use] pub fn inverse_transform_point(&self, pt: &Point) -> Point { pt - &self.vector } } impl Eq for Translation {} impl PartialEq for Translation { #[inline] fn eq(&self, right: &Translation) -> bool { self.vector == right.vector } } impl AbsDiffEq for Translation where T::Epsilon: Clone, { type Epsilon = T::Epsilon; #[inline] fn default_epsilon() -> Self::Epsilon { T::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 T::Epsilon: Clone, { #[inline] fn default_max_relative() -> Self::Epsilon { T::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 T::Epsilon: Clone, { #[inline] fn default_max_ulps() -> u32 { T::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 { 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, "}}") } }