nalgebra/geometry/
translation.rs

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