nalgebra/geometry/scale.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 crate::base::allocator::Allocator;
10use crate::base::dimension::{DimNameAdd, DimNameSum, U1};
11use crate::base::storage::Owned;
12use crate::base::{Const, DefaultAllocator, OMatrix, OVector, SVector, Scalar};
13use crate::ClosedDivAssign;
14use crate::ClosedMulAssign;
15
16use crate::geometry::Point;
17
18#[cfg(feature = "rkyv-serialize")]
19use rkyv::bytecheck;
20
21/// A scale which supports non-uniform scaling.
22#[repr(C)]
23#[cfg_attr(
24 feature = "rkyv-serialize-no-std",
25 derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize),
26 archive(
27 as = "Scale<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 Scale<T, const D: usize> {
37 /// The scale coordinates, i.e., how much is multiplied to a point's coordinates when it is
38 /// scaled.
39 pub vector: SVector<T, D>,
40}
41
42impl<T: fmt::Debug, const D: usize> fmt::Debug for Scale<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 Scale<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 Scale<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 Scale<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 Scale<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 Scale<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(Scale::from(matrix))
98 }
99}
100
101impl<T: Scalar, const D: usize> Scale<T, D> {
102 /// Inverts `self`.
103 ///
104 /// # Example
105 /// ```
106 /// # use nalgebra::{Scale2, Scale3};
107 /// let t = Scale3::new(1.0, 2.0, 3.0);
108 /// assert_eq!(t * t.try_inverse().unwrap(), Scale3::identity());
109 /// assert_eq!(t.try_inverse().unwrap() * t, Scale3::identity());
110 ///
111 /// // Work in all dimensions.
112 /// let t = Scale2::new(1.0, 2.0);
113 /// assert_eq!(t * t.try_inverse().unwrap(), Scale2::identity());
114 /// assert_eq!(t.try_inverse().unwrap() * t, Scale2::identity());
115 ///
116 /// // Returns None if any coordinate is 0.
117 /// let t = Scale2::new(0.0, 2.0);
118 /// assert_eq!(t.try_inverse(), None);
119 /// ```
120 #[inline]
121 #[must_use = "Did you mean to use try_inverse_mut()?"]
122 pub fn try_inverse(&self) -> Option<Scale<T, D>>
123 where
124 T: ClosedDivAssign + One + Zero,
125 {
126 for i in 0..D {
127 if self.vector[i] == T::zero() {
128 return None;
129 }
130 }
131 Some(self.vector.map(|e| T::one() / e).into())
132 }
133
134 /// Inverts `self`.
135 ///
136 /// # Example
137 /// ```
138 /// # use nalgebra::{Scale2, Scale3};
139 ///
140 /// unsafe {
141 /// let t = Scale3::new(1.0, 2.0, 3.0);
142 /// assert_eq!(t * t.inverse_unchecked(), Scale3::identity());
143 /// assert_eq!(t.inverse_unchecked() * t, Scale3::identity());
144 ///
145 /// // Work in all dimensions.
146 /// let t = Scale2::new(1.0, 2.0);
147 /// assert_eq!(t * t.inverse_unchecked(), Scale2::identity());
148 /// assert_eq!(t.inverse_unchecked() * t, Scale2::identity());
149 /// }
150 /// ```
151 ///
152 /// # Safety
153 ///
154 /// Should only be used if all scaling is known to be non-zero.
155 #[inline]
156 #[must_use]
157 pub unsafe fn inverse_unchecked(&self) -> Scale<T, D>
158 where
159 T: ClosedDivAssign + One,
160 {
161 self.vector.map(|e| T::one() / e).into()
162 }
163
164 /// Inverts `self`.
165 ///
166 /// # Example
167 /// ```
168 /// # use nalgebra::{Scale2, Scale3};
169 /// let t = Scale3::new(1.0, 2.0, 3.0);
170 /// assert_eq!(t * t.pseudo_inverse(), Scale3::identity());
171 /// assert_eq!(t.pseudo_inverse() * t, Scale3::identity());
172 ///
173 /// // Work in all dimensions.
174 /// let t = Scale2::new(1.0, 2.0);
175 /// assert_eq!(t * t.pseudo_inverse(), Scale2::identity());
176 /// assert_eq!(t.pseudo_inverse() * t, Scale2::identity());
177 ///
178 /// // Inverts only non-zero coordinates.
179 /// let t = Scale2::new(0.0, 2.0);
180 /// assert_eq!(t * t.pseudo_inverse(), Scale2::new(0.0, 1.0));
181 /// assert_eq!(t.pseudo_inverse() * t, Scale2::new(0.0, 1.0));
182 /// ```
183 #[inline]
184 #[must_use]
185 pub fn pseudo_inverse(&self) -> Scale<T, D>
186 where
187 T: ClosedDivAssign + One + Zero,
188 {
189 self.vector
190 .map(|e| {
191 if e != T::zero() {
192 T::one() / e
193 } else {
194 T::zero()
195 }
196 })
197 .into()
198 }
199
200 /// Converts this Scale into its equivalent homogeneous transformation matrix.
201 ///
202 /// # Example
203 /// ```
204 /// # use nalgebra::{Scale2, Scale3, Matrix3, Matrix4};
205 /// let t = Scale3::new(10.0, 20.0, 30.0);
206 /// let expected = Matrix4::new(10.0, 0.0, 0.0, 0.0,
207 /// 0.0, 20.0, 0.0, 0.0,
208 /// 0.0, 0.0, 30.0, 0.0,
209 /// 0.0, 0.0, 0.0, 1.0);
210 /// assert_eq!(t.to_homogeneous(), expected);
211 ///
212 /// let t = Scale2::new(10.0, 20.0);
213 /// let expected = Matrix3::new(10.0, 0.0, 0.0,
214 /// 0.0, 20.0, 0.0,
215 /// 0.0, 0.0, 1.0);
216 /// assert_eq!(t.to_homogeneous(), expected);
217 /// ```
218 #[inline]
219 #[must_use]
220 pub fn to_homogeneous(&self) -> OMatrix<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>
221 where
222 T: Zero + One + Clone,
223 Const<D>: DimNameAdd<U1>,
224 DefaultAllocator: Allocator<DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>
225 + Allocator<DimNameSum<Const<D>, U1>, U1>,
226 {
227 // TODO: use self.vector.push() instead. We can’t right now because
228 // that would require the DimAdd bound (but here we use DimNameAdd).
229 // This should be fixable once Rust gets a more complete support of
230 // const-generics.
231 let mut v = OVector::from_element(T::one());
232 for i in 0..D {
233 v[i] = self.vector[i].clone();
234 }
235 OMatrix::from_diagonal(&v)
236 }
237
238 /// Inverts `self` in-place.
239 ///
240 /// # Example
241 /// ```
242 /// # use nalgebra::{Scale2, Scale3};
243 /// let t = Scale3::new(1.0, 2.0, 3.0);
244 /// let mut inv_t = Scale3::new(1.0, 2.0, 3.0);
245 /// assert!(inv_t.try_inverse_mut());
246 /// assert_eq!(t * inv_t, Scale3::identity());
247 /// assert_eq!(inv_t * t, Scale3::identity());
248 ///
249 /// // Work in all dimensions.
250 /// let t = Scale2::new(1.0, 2.0);
251 /// let mut inv_t = Scale2::new(1.0, 2.0);
252 /// assert!(inv_t.try_inverse_mut());
253 /// assert_eq!(t * inv_t, Scale2::identity());
254 /// assert_eq!(inv_t * t, Scale2::identity());
255 ///
256 /// // Does not perform any operation if a coordinate is 0.
257 /// let mut t = Scale2::new(0.0, 2.0);
258 /// assert!(!t.try_inverse_mut());
259 /// ```
260 #[inline]
261 pub fn try_inverse_mut(&mut self) -> bool
262 where
263 T: ClosedDivAssign + One + Zero,
264 {
265 if let Some(v) = self.try_inverse() {
266 self.vector = v.vector;
267 true
268 } else {
269 false
270 }
271 }
272}
273
274impl<T: Scalar + ClosedMulAssign, const D: usize> Scale<T, D> {
275 /// Translate the given point.
276 ///
277 /// This is the same as the multiplication `self * pt`.
278 ///
279 /// # Example
280 /// ```
281 /// # use nalgebra::{Scale3, Point3};
282 /// let t = Scale3::new(1.0, 2.0, 3.0);
283 /// let transformed_point = t.transform_point(&Point3::new(4.0, 5.0, 6.0));
284 /// assert_eq!(transformed_point, Point3::new(4.0, 10.0, 18.0));
285 /// ```
286 #[inline]
287 #[must_use]
288 pub fn transform_point(&self, pt: &Point<T, D>) -> Point<T, D> {
289 self * pt
290 }
291}
292
293impl<T: Scalar + ClosedDivAssign + ClosedMulAssign + One + Zero, const D: usize> Scale<T, D> {
294 /// Translate the given point by the inverse of this Scale.
295 ///
296 /// # Example
297 /// ```
298 /// # use nalgebra::{Scale3, Point3};
299 /// let t = Scale3::new(1.0, 2.0, 3.0);
300 /// let transformed_point = t.try_inverse_transform_point(&Point3::new(4.0, 6.0, 6.0)).unwrap();
301 /// assert_eq!(transformed_point, Point3::new(4.0, 3.0, 2.0));
302 ///
303 /// // Returns None if the inverse doesn't exist.
304 /// let t = Scale3::new(1.0, 0.0, 3.0);
305 /// let transformed_point = t.try_inverse_transform_point(&Point3::new(4.0, 6.0, 6.0));
306 /// assert_eq!(transformed_point, None);
307 /// ```
308 #[inline]
309 #[must_use]
310 pub fn try_inverse_transform_point(&self, pt: &Point<T, D>) -> Option<Point<T, D>> {
311 self.try_inverse().map(|s| s * pt)
312 }
313}
314
315impl<T: Scalar + Eq, const D: usize> Eq for Scale<T, D> {}
316
317impl<T: Scalar + PartialEq, const D: usize> PartialEq for Scale<T, D> {
318 #[inline]
319 fn eq(&self, right: &Scale<T, D>) -> bool {
320 self.vector == right.vector
321 }
322}
323
324impl<T: Scalar + AbsDiffEq, const D: usize> AbsDiffEq for Scale<T, D>
325where
326 T::Epsilon: Clone,
327{
328 type Epsilon = T::Epsilon;
329
330 #[inline]
331 fn default_epsilon() -> Self::Epsilon {
332 T::default_epsilon()
333 }
334
335 #[inline]
336 fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
337 self.vector.abs_diff_eq(&other.vector, epsilon)
338 }
339}
340
341impl<T: Scalar + RelativeEq, const D: usize> RelativeEq for Scale<T, D>
342where
343 T::Epsilon: Clone,
344{
345 #[inline]
346 fn default_max_relative() -> Self::Epsilon {
347 T::default_max_relative()
348 }
349
350 #[inline]
351 fn relative_eq(
352 &self,
353 other: &Self,
354 epsilon: Self::Epsilon,
355 max_relative: Self::Epsilon,
356 ) -> bool {
357 self.vector
358 .relative_eq(&other.vector, epsilon, max_relative)
359 }
360}
361
362impl<T: Scalar + UlpsEq, const D: usize> UlpsEq for Scale<T, D>
363where
364 T::Epsilon: Clone,
365{
366 #[inline]
367 fn default_max_ulps() -> u32 {
368 T::default_max_ulps()
369 }
370
371 #[inline]
372 fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool {
373 self.vector.ulps_eq(&other.vector, epsilon, max_ulps)
374 }
375}
376
377/*
378 *
379 * Display
380 *
381 */
382impl<T: Scalar + fmt::Display, const D: usize> fmt::Display for Scale<T, D> {
383 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
384 let precision = f.precision().unwrap_or(3);
385
386 writeln!(f, "Scale {{")?;
387 write!(f, "{:.*}", precision, self.vector)?;
388 writeln!(f, "}}")
389 }
390}