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#[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 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 #[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 #[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 #[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 #[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 #[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 #[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
289impl<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}