nalgebra/geometry/
translation.rs

1use approx::{AbsDiffEq, RelativeEq, UlpsEq};
2use num::{One, Zero};
3use std::fmt;
4use std::hash;
5
6#[cfg(feature = "serde-serialize-no-std")]
7use serde::{Deserialize, Deserializer, Serialize, Serializer};
8
9use simba::scalar::{ClosedAddAssign, ClosedNeg, ClosedSubAssign};
10
11use crate::base::allocator::Allocator;
12use crate::base::dimension::{DimNameAdd, DimNameSum, U1};
13use crate::base::storage::Owned;
14use crate::base::{Const, DefaultAllocator, OMatrix, SVector, Scalar};
15
16use crate::geometry::Point;
17
18#[cfg(feature = "rkyv-serialize")]
19use rkyv::bytecheck;
20
21/// A translation.
22#[repr(C)]
23#[cfg_attr(
24    feature = "rkyv-serialize-no-std",
25    derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize),
26    archive(
27        as = "Translation<T::Archived, D>",
28        bound(archive = "
29        T: rkyv::Archive,
30        SVector<T, D>: rkyv::Archive<Archived = SVector<T::Archived, D>>
31    ")
32    )
33)]
34#[cfg_attr(feature = "rkyv-serialize", derive(bytecheck::CheckBytes))]
35#[derive(Copy, Clone)]
36pub struct Translation<T, const D: usize> {
37    /// The translation coordinates, i.e., how much is added to a point's coordinates when it is
38    /// translated.
39    pub vector: SVector<T, D>,
40}
41
42impl<T: fmt::Debug, const D: usize> fmt::Debug for Translation<T, D> {
43    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
44        self.vector.as_slice().fmt(formatter)
45    }
46}
47
48impl<T: Scalar + hash::Hash, const D: usize> hash::Hash for Translation<T, D>
49where
50    Owned<T, Const<D>>: hash::Hash,
51{
52    fn hash<H: hash::Hasher>(&self, state: &mut H) {
53        self.vector.hash(state)
54    }
55}
56
57#[cfg(feature = "bytemuck")]
58unsafe impl<T, const D: usize> bytemuck::Zeroable for Translation<T, D>
59where
60    T: Scalar + bytemuck::Zeroable,
61    SVector<T, D>: bytemuck::Zeroable,
62{
63}
64
65#[cfg(feature = "bytemuck")]
66unsafe impl<T, const D: usize> bytemuck::Pod for Translation<T, D>
67where
68    T: Scalar + bytemuck::Pod,
69    SVector<T, D>: bytemuck::Pod,
70{
71}
72
73#[cfg(feature = "serde-serialize-no-std")]
74impl<T: Scalar, const D: usize> Serialize for Translation<T, D>
75where
76    Owned<T, Const<D>>: Serialize,
77{
78    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
79    where
80        S: Serializer,
81    {
82        self.vector.serialize(serializer)
83    }
84}
85
86#[cfg(feature = "serde-serialize-no-std")]
87impl<'a, T: Scalar, const D: usize> Deserialize<'a> for Translation<T, D>
88where
89    Owned<T, Const<D>>: Deserialize<'a>,
90{
91    fn deserialize<Des>(deserializer: Des) -> Result<Self, Des::Error>
92    where
93        Des: Deserializer<'a>,
94    {
95        let matrix = SVector::<T, D>::deserialize(deserializer)?;
96
97        Ok(Translation::from(matrix))
98    }
99}
100
101impl<T: Scalar, const D: usize> Translation<T, D> {
102    /// Creates a new translation from the given vector.
103    #[inline]
104    #[deprecated(note = "Use `::from` instead.")]
105    pub fn from_vector(vector: SVector<T, D>) -> Translation<T, D> {
106        Translation { vector }
107    }
108
109    /// Inverts `self`.
110    ///
111    /// # Example
112    /// ```
113    /// # use nalgebra::{Translation2, Translation3};
114    /// let t = Translation3::new(1.0, 2.0, 3.0);
115    /// assert_eq!(t * t.inverse(), Translation3::identity());
116    /// assert_eq!(t.inverse() * t, Translation3::identity());
117    ///
118    /// // Work in all dimensions.
119    /// let t = Translation2::new(1.0, 2.0);
120    /// assert_eq!(t * t.inverse(), Translation2::identity());
121    /// assert_eq!(t.inverse() * t, Translation2::identity());
122    /// ```
123    #[inline]
124    #[must_use = "Did you mean to use inverse_mut()?"]
125    pub fn inverse(&self) -> Translation<T, D>
126    where
127        T: ClosedNeg,
128    {
129        Translation::from(-&self.vector)
130    }
131
132    /// Converts this translation into its equivalent homogeneous transformation matrix.
133    ///
134    /// # Example
135    /// ```
136    /// # use nalgebra::{Translation2, Translation3, Matrix3, Matrix4};
137    /// let t = Translation3::new(10.0, 20.0, 30.0);
138    /// let expected = Matrix4::new(1.0, 0.0, 0.0, 10.0,
139    ///                             0.0, 1.0, 0.0, 20.0,
140    ///                             0.0, 0.0, 1.0, 30.0,
141    ///                             0.0, 0.0, 0.0, 1.0);
142    /// assert_eq!(t.to_homogeneous(), expected);
143    ///
144    /// let t = Translation2::new(10.0, 20.0);
145    /// let expected = Matrix3::new(1.0, 0.0, 10.0,
146    ///                             0.0, 1.0, 20.0,
147    ///                             0.0, 0.0, 1.0);
148    /// assert_eq!(t.to_homogeneous(), expected);
149    /// ```
150    #[inline]
151    #[must_use]
152    pub fn to_homogeneous(&self) -> OMatrix<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>
153    where
154        T: Zero + One,
155        Const<D>: DimNameAdd<U1>,
156        DefaultAllocator: Allocator<DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>,
157    {
158        let mut res = OMatrix::<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>::identity();
159        res.fixed_view_mut::<D, 1>(0, D).copy_from(&self.vector);
160
161        res
162    }
163
164    /// Inverts `self` in-place.
165    ///
166    /// # Example
167    /// ```
168    /// # use nalgebra::{Translation2, Translation3};
169    /// let t = Translation3::new(1.0, 2.0, 3.0);
170    /// let mut inv_t = Translation3::new(1.0, 2.0, 3.0);
171    /// inv_t.inverse_mut();
172    /// assert_eq!(t * inv_t, Translation3::identity());
173    /// assert_eq!(inv_t * t, Translation3::identity());
174    ///
175    /// // Work in all dimensions.
176    /// let t = Translation2::new(1.0, 2.0);
177    /// let mut inv_t = Translation2::new(1.0, 2.0);
178    /// inv_t.inverse_mut();
179    /// assert_eq!(t * inv_t, Translation2::identity());
180    /// assert_eq!(inv_t * t, Translation2::identity());
181    /// ```
182    #[inline]
183    pub fn inverse_mut(&mut self)
184    where
185        T: ClosedNeg,
186    {
187        self.vector.neg_mut()
188    }
189}
190
191impl<T: Scalar + ClosedAddAssign, const D: usize> Translation<T, D> {
192    /// Translate the given point.
193    ///
194    /// This is the same as the multiplication `self * pt`.
195    ///
196    /// # Example
197    /// ```
198    /// # use nalgebra::{Translation3, Point3};
199    /// let t = Translation3::new(1.0, 2.0, 3.0);
200    /// let transformed_point = t.transform_point(&Point3::new(4.0, 5.0, 6.0));
201    /// assert_eq!(transformed_point, Point3::new(5.0, 7.0, 9.0));
202    /// ```
203    #[inline]
204    #[must_use]
205    pub fn transform_point(&self, pt: &Point<T, D>) -> Point<T, D> {
206        pt + &self.vector
207    }
208}
209
210impl<T: Scalar + ClosedSubAssign, const D: usize> Translation<T, D> {
211    /// Translate the given point by the inverse of this translation.
212    ///
213    /// # Example
214    /// ```
215    /// # use nalgebra::{Translation3, Point3};
216    /// let t = Translation3::new(1.0, 2.0, 3.0);
217    /// let transformed_point = t.inverse_transform_point(&Point3::new(4.0, 5.0, 6.0));
218    /// assert_eq!(transformed_point, Point3::new(3.0, 3.0, 3.0));
219    /// ```
220    #[inline]
221    #[must_use]
222    pub fn inverse_transform_point(&self, pt: &Point<T, D>) -> Point<T, D> {
223        pt - &self.vector
224    }
225}
226
227impl<T: Scalar + Eq, const D: usize> Eq for Translation<T, D> {}
228
229impl<T: Scalar + PartialEq, const D: usize> PartialEq for Translation<T, D> {
230    #[inline]
231    fn eq(&self, right: &Translation<T, D>) -> bool {
232        self.vector == right.vector
233    }
234}
235
236impl<T: Scalar + AbsDiffEq, const D: usize> AbsDiffEq for Translation<T, D>
237where
238    T::Epsilon: Clone,
239{
240    type Epsilon = T::Epsilon;
241
242    #[inline]
243    fn default_epsilon() -> Self::Epsilon {
244        T::default_epsilon()
245    }
246
247    #[inline]
248    fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
249        self.vector.abs_diff_eq(&other.vector, epsilon)
250    }
251}
252
253impl<T: Scalar + RelativeEq, const D: usize> RelativeEq for Translation<T, D>
254where
255    T::Epsilon: Clone,
256{
257    #[inline]
258    fn default_max_relative() -> Self::Epsilon {
259        T::default_max_relative()
260    }
261
262    #[inline]
263    fn relative_eq(
264        &self,
265        other: &Self,
266        epsilon: Self::Epsilon,
267        max_relative: Self::Epsilon,
268    ) -> bool {
269        self.vector
270            .relative_eq(&other.vector, epsilon, max_relative)
271    }
272}
273
274impl<T: Scalar + UlpsEq, const D: usize> UlpsEq for Translation<T, D>
275where
276    T::Epsilon: Clone,
277{
278    #[inline]
279    fn default_max_ulps() -> u32 {
280        T::default_max_ulps()
281    }
282
283    #[inline]
284    fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool {
285        self.vector.ulps_eq(&other.vector, epsilon, max_ulps)
286    }
287}
288
289/*
290 *
291 * Display
292 *
293 */
294impl<T: Scalar + fmt::Display, const D: usize> fmt::Display for Translation<T, D> {
295    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
296        let precision = f.precision().unwrap_or(3);
297
298        writeln!(f, "Translation {{")?;
299        write!(f, "{:.*}", precision, self.vector)?;
300        writeln!(f, "}}")
301    }
302}