1use approx::{AbsDiffEq, RelativeEq, UlpsEq};
2use num::{One, Zero};
3use std::fmt;
4use std::hash;
5#[cfg(feature = "abomonation-serialize")]
6use std::io::{Result as IOResult, Write};
7
8#[cfg(feature = "serde-serialize-no-std")]
9use serde::{Deserialize, Deserializer, Serialize, Serializer};
10
11#[cfg(feature = "abomonation-serialize")]
12use abomonation::Abomonation;
13
14use simba::scalar::{ClosedAdd, ClosedNeg, ClosedSub};
15
16use crate::base::allocator::Allocator;
17use crate::base::dimension::{DimNameAdd, DimNameSum, U1};
18use crate::base::storage::Owned;
19use crate::base::{Const, DefaultAllocator, OMatrix, SVector, Scalar};
20
21use crate::geometry::Point;
22
23#[repr(C)]
25#[cfg_attr(
26 all(not(target_os = "cuda"), feature = "cuda"),
27 derive(cust::DeviceCopy)
28)]
29#[derive(Copy, Clone)]
30pub struct Translation<T, const D: usize> {
31 pub vector: SVector<T, D>,
34}
35
36impl<T: fmt::Debug, const D: usize> fmt::Debug for Translation<T, D> {
37 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
38 self.vector.as_slice().fmt(formatter)
39 }
40}
41
42impl<T: Scalar + hash::Hash, const D: usize> hash::Hash for Translation<T, D>
43where
44 Owned<T, Const<D>>: hash::Hash,
45{
46 fn hash<H: hash::Hasher>(&self, state: &mut H) {
47 self.vector.hash(state)
48 }
49}
50
51#[cfg(feature = "bytemuck")]
52unsafe impl<T, const D: usize> bytemuck::Zeroable for Translation<T, D>
53where
54 T: Scalar + bytemuck::Zeroable,
55 SVector<T, D>: bytemuck::Zeroable,
56{
57}
58
59#[cfg(feature = "bytemuck")]
60unsafe impl<T, const D: usize> bytemuck::Pod for Translation<T, D>
61where
62 T: Scalar + bytemuck::Pod,
63 SVector<T, D>: bytemuck::Pod,
64{
65}
66
67#[cfg(feature = "abomonation-serialize")]
68impl<T, const D: usize> Abomonation for Translation<T, D>
69where
70 T: Scalar,
71 SVector<T, D>: Abomonation,
72{
73 unsafe fn entomb<W: Write>(&self, writer: &mut W) -> IOResult<()> {
74 self.vector.entomb(writer)
75 }
76
77 fn extent(&self) -> usize {
78 self.vector.extent()
79 }
80
81 unsafe fn exhume<'a, 'b>(&'a mut self, bytes: &'b mut [u8]) -> Option<&'b mut [u8]> {
82 self.vector.exhume(bytes)
83 }
84}
85
86#[cfg(feature = "serde-serialize-no-std")]
87impl<T: Scalar, const D: usize> Serialize for Translation<T, D>
88where
89 Owned<T, Const<D>>: Serialize,
90{
91 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
92 where
93 S: Serializer,
94 {
95 self.vector.serialize(serializer)
96 }
97}
98
99#[cfg(feature = "serde-serialize-no-std")]
100impl<'a, T: Scalar, const D: usize> Deserialize<'a> for Translation<T, D>
101where
102 Owned<T, Const<D>>: Deserialize<'a>,
103{
104 fn deserialize<Des>(deserializer: Des) -> Result<Self, Des::Error>
105 where
106 Des: Deserializer<'a>,
107 {
108 let matrix = SVector::<T, D>::deserialize(deserializer)?;
109
110 Ok(Translation::from(matrix))
111 }
112}
113
114#[cfg(feature = "rkyv-serialize-no-std")]
115mod rkyv_impl {
116 use super::Translation;
117 use crate::base::SVector;
118 use rkyv::{offset_of, project_struct, Archive, Deserialize, Fallible, Serialize};
119
120 impl<T: Archive, const D: usize> Archive for Translation<T, D> {
121 type Archived = Translation<T::Archived, D>;
122 type Resolver = <SVector<T, D> as Archive>::Resolver;
123
124 fn resolve(
125 &self,
126 pos: usize,
127 resolver: Self::Resolver,
128 out: &mut core::mem::MaybeUninit<Self::Archived>,
129 ) {
130 self.vector.resolve(
131 pos + offset_of!(Self::Archived, vector),
132 resolver,
133 project_struct!(out: Self::Archived => vector),
134 );
135 }
136 }
137
138 impl<T: Serialize<S>, S: Fallible + ?Sized, const D: usize> Serialize<S> for Translation<T, D> {
139 fn serialize(&self, serializer: &mut S) -> Result<Self::Resolver, S::Error> {
140 self.vector.serialize(serializer)
141 }
142 }
143
144 impl<T: Archive, _D: Fallible + ?Sized, const D: usize> Deserialize<Translation<T, D>, _D>
145 for Translation<T::Archived, D>
146 where
147 T::Archived: Deserialize<T, _D>,
148 {
149 fn deserialize(&self, deserializer: &mut _D) -> Result<Translation<T, D>, _D::Error> {
150 Ok(Translation {
151 vector: self.vector.deserialize(deserializer)?,
152 })
153 }
154 }
155}
156
157impl<T: Scalar, const D: usize> Translation<T, D> {
158 #[inline]
160 #[deprecated(note = "Use `::from` instead.")]
161 pub fn from_vector(vector: SVector<T, D>) -> Translation<T, D> {
162 Translation { vector }
163 }
164
165 #[inline]
180 #[must_use = "Did you mean to use inverse_mut()?"]
181 pub fn inverse(&self) -> Translation<T, D>
182 where
183 T: ClosedNeg,
184 {
185 Translation::from(-&self.vector)
186 }
187
188 #[inline]
207 #[must_use]
208 pub fn to_homogeneous(&self) -> OMatrix<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>
209 where
210 T: Zero + One,
211 Const<D>: DimNameAdd<U1>,
212 DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>,
213 {
214 let mut res = OMatrix::<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>::identity();
215 res.fixed_slice_mut::<D, 1>(0, D).copy_from(&self.vector);
216
217 res
218 }
219
220 #[inline]
239 pub fn inverse_mut(&mut self)
240 where
241 T: ClosedNeg,
242 {
243 self.vector.neg_mut()
244 }
245}
246
247impl<T: Scalar + ClosedAdd, const D: usize> Translation<T, D> {
248 #[inline]
259 #[must_use]
260 pub fn transform_point(&self, pt: &Point<T, D>) -> Point<T, D> {
261 pt + &self.vector
262 }
263}
264
265impl<T: Scalar + ClosedSub, const D: usize> Translation<T, D> {
266 #[inline]
275 #[must_use]
276 pub fn inverse_transform_point(&self, pt: &Point<T, D>) -> Point<T, D> {
277 pt - &self.vector
278 }
279}
280
281impl<T: Scalar + Eq, const D: usize> Eq for Translation<T, D> {}
282
283impl<T: Scalar + PartialEq, const D: usize> PartialEq for Translation<T, D> {
284 #[inline]
285 fn eq(&self, right: &Translation<T, D>) -> bool {
286 self.vector == right.vector
287 }
288}
289
290impl<T: Scalar + AbsDiffEq, const D: usize> AbsDiffEq for Translation<T, D>
291where
292 T::Epsilon: Clone,
293{
294 type Epsilon = T::Epsilon;
295
296 #[inline]
297 fn default_epsilon() -> Self::Epsilon {
298 T::default_epsilon()
299 }
300
301 #[inline]
302 fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
303 self.vector.abs_diff_eq(&other.vector, epsilon)
304 }
305}
306
307impl<T: Scalar + RelativeEq, const D: usize> RelativeEq for Translation<T, D>
308where
309 T::Epsilon: Clone,
310{
311 #[inline]
312 fn default_max_relative() -> Self::Epsilon {
313 T::default_max_relative()
314 }
315
316 #[inline]
317 fn relative_eq(
318 &self,
319 other: &Self,
320 epsilon: Self::Epsilon,
321 max_relative: Self::Epsilon,
322 ) -> bool {
323 self.vector
324 .relative_eq(&other.vector, epsilon, max_relative)
325 }
326}
327
328impl<T: Scalar + UlpsEq, const D: usize> UlpsEq for Translation<T, D>
329where
330 T::Epsilon: Clone,
331{
332 #[inline]
333 fn default_max_ulps() -> u32 {
334 T::default_max_ulps()
335 }
336
337 #[inline]
338 fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool {
339 self.vector.ulps_eq(&other.vector, epsilon, max_ulps)
340 }
341}
342
343impl<T: Scalar + fmt::Display, const D: usize> fmt::Display for Translation<T, D> {
349 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
350 let precision = f.precision().unwrap_or(3);
351
352 writeln!(f, "Translation {{")?;
353 write!(f, "{:.*}", precision, self.vector)?;
354 writeln!(f, "}}")
355 }
356}