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}