1#![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#[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 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 #[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 #[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 #[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 #[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 #[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 #[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
293impl<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}