use approx::{AbsDiffEq, RelativeEq, UlpsEq}; use num::{One, Zero}; use std::fmt; use std::hash; #[cfg(feature = "serde-serialize-no-std")] use serde::{Deserialize, Deserializer, Serialize, Serializer}; use crate::base::allocator::Allocator; use crate::base::dimension::{DimNameAdd, DimNameSum, U1}; use crate::base::storage::Owned; use crate::base::{Const, DefaultAllocator, OMatrix, OVector, SVector, Scalar}; use crate::ClosedDiv; use crate::ClosedMul; use crate::geometry::Point; /// A scale which supports non-uniform scaling. #[repr(C)] #[cfg_attr( feature = "rkyv-serialize-no-std", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) )] #[cfg_attr( feature = "rkyv-serialize", archive_attr(derive(bytecheck::CheckBytes)) )] #[cfg_attr(feature = "cuda", derive(cust_core::DeviceCopy))] #[derive(Copy, Clone)] pub struct Scale { /// The scale coordinates, i.e., how much is multiplied to a point's coordinates when it is /// scaled. pub vector: SVector, } impl fmt::Debug for Scale { fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { self.vector.as_slice().fmt(formatter) } } impl hash::Hash for Scale where Owned>: hash::Hash, { fn hash(&self, state: &mut H) { self.vector.hash(state) } } #[cfg(feature = "bytemuck")] unsafe impl bytemuck::Zeroable for Scale where T: Scalar + bytemuck::Zeroable, SVector: bytemuck::Zeroable, { } #[cfg(feature = "bytemuck")] unsafe impl bytemuck::Pod for Scale where T: Scalar + bytemuck::Pod, SVector: bytemuck::Pod, { } #[cfg(feature = "serde-serialize-no-std")] impl Serialize for Scale where Owned>: Serialize, { fn serialize(&self, serializer: S) -> Result where S: Serializer, { self.vector.serialize(serializer) } } #[cfg(feature = "serde-serialize-no-std")] impl<'a, T: Scalar, const D: usize> Deserialize<'a> for Scale where Owned>: Deserialize<'a>, { fn deserialize(deserializer: Des) -> Result where Des: Deserializer<'a>, { let matrix = SVector::::deserialize(deserializer)?; Ok(Scale::from(matrix)) } } impl Scale { /// Inverts `self`. /// /// # Example /// ``` /// # use nalgebra::{Scale2, Scale3}; /// let t = Scale3::new(1.0, 2.0, 3.0); /// assert_eq!(t * t.try_inverse().unwrap(), Scale3::identity()); /// assert_eq!(t.try_inverse().unwrap() * t, Scale3::identity()); /// /// // Work in all dimensions. /// let t = Scale2::new(1.0, 2.0); /// assert_eq!(t * t.try_inverse().unwrap(), Scale2::identity()); /// assert_eq!(t.try_inverse().unwrap() * t, Scale2::identity()); /// /// // Returns None if any coordinate is 0. /// let t = Scale2::new(0.0, 2.0); /// assert_eq!(t.try_inverse(), None); /// ``` #[inline] #[must_use = "Did you mean to use try_inverse_mut()?"] pub fn try_inverse(&self) -> Option> where T: ClosedDiv + One + Zero, { for i in 0..D { if self.vector[i] == T::zero() { return None; } } return Some(self.vector.map(|e| T::one() / e).into()); } /// Inverts `self`. /// /// # Example /// ``` /// # use nalgebra::{Scale2, Scale3}; /// /// unsafe { /// let t = Scale3::new(1.0, 2.0, 3.0); /// assert_eq!(t * t.inverse_unchecked(), Scale3::identity()); /// assert_eq!(t.inverse_unchecked() * t, Scale3::identity()); /// /// // Work in all dimensions. /// let t = Scale2::new(1.0, 2.0); /// assert_eq!(t * t.inverse_unchecked(), Scale2::identity()); /// assert_eq!(t.inverse_unchecked() * t, Scale2::identity()); /// } /// ``` #[inline] #[must_use] pub unsafe fn inverse_unchecked(&self) -> Scale where T: ClosedDiv + One, { return self.vector.map(|e| T::one() / e).into(); } /// Inverts `self`. /// /// # Example /// ``` /// # use nalgebra::{Scale2, Scale3}; /// let t = Scale3::new(1.0, 2.0, 3.0); /// assert_eq!(t * t.pseudo_inverse(), Scale3::identity()); /// assert_eq!(t.pseudo_inverse() * t, Scale3::identity()); /// /// // Work in all dimensions. /// let t = Scale2::new(1.0, 2.0); /// assert_eq!(t * t.pseudo_inverse(), Scale2::identity()); /// assert_eq!(t.pseudo_inverse() * t, Scale2::identity()); /// /// // Inverts only non-zero coordinates. /// let t = Scale2::new(0.0, 2.0); /// assert_eq!(t * t.pseudo_inverse(), Scale2::new(0.0, 1.0)); /// assert_eq!(t.pseudo_inverse() * t, Scale2::new(0.0, 1.0)); /// ``` #[inline] #[must_use] pub fn pseudo_inverse(&self) -> Scale where T: ClosedDiv + One + Zero, { return self .vector .map(|e| { if e != T::zero() { T::one() / e } else { T::zero() } }) .into(); } /// Converts this Scale into its equivalent homogeneous transformation matrix. /// /// # Example /// ``` /// # use nalgebra::{Scale2, Scale3, Matrix3, Matrix4}; /// let t = Scale3::new(10.0, 20.0, 30.0); /// let expected = Matrix4::new(10.0, 0.0, 0.0, 0.0, /// 0.0, 20.0, 0.0, 0.0, /// 0.0, 0.0, 30.0, 0.0, /// 0.0, 0.0, 0.0, 1.0); /// assert_eq!(t.to_homogeneous(), expected); /// /// let t = Scale2::new(10.0, 20.0); /// let expected = Matrix3::new(10.0, 0.0, 0.0, /// 0.0, 20.0, 0.0, /// 0.0, 0.0, 1.0); /// assert_eq!(t.to_homogeneous(), expected); /// ``` #[inline] #[must_use] pub fn to_homogeneous(&self) -> OMatrix, U1>, DimNameSum, U1>> where T: Zero + One + Clone, Const: DimNameAdd, DefaultAllocator: Allocator, U1>, DimNameSum, U1>> + Allocator, U1>, U1>, { // TODO: use self.vector.push() instead. We can’t right now because // that would require the DimAdd bound (but here we use DimNameAdd). // This should be fixable once Rust gets a more complete support of // const-generics. let mut v = OVector::from_element(T::one()); for i in 0..D { v[i] = self.vector[i].clone(); } return OMatrix::from_diagonal(&v); } /// Inverts `self` in-place. /// /// # Example /// ``` /// # use nalgebra::{Scale2, Scale3}; /// let t = Scale3::new(1.0, 2.0, 3.0); /// let mut inv_t = Scale3::new(1.0, 2.0, 3.0); /// assert!(inv_t.try_inverse_mut()); /// assert_eq!(t * inv_t, Scale3::identity()); /// assert_eq!(inv_t * t, Scale3::identity()); /// /// // Work in all dimensions. /// let t = Scale2::new(1.0, 2.0); /// let mut inv_t = Scale2::new(1.0, 2.0); /// assert!(inv_t.try_inverse_mut()); /// assert_eq!(t * inv_t, Scale2::identity()); /// assert_eq!(inv_t * t, Scale2::identity()); /// /// // Does not perform any operation if a coordinate is 0. /// let mut t = Scale2::new(0.0, 2.0); /// assert!(!t.try_inverse_mut()); /// ``` #[inline] pub fn try_inverse_mut(&mut self) -> bool where T: ClosedDiv + One + Zero, { if let Some(v) = self.try_inverse() { self.vector = v.vector; true } else { false } } } impl Scale { /// Translate the given point. /// /// This is the same as the multiplication `self * pt`. /// /// # Example /// ``` /// # use nalgebra::{Scale3, Point3}; /// let t = Scale3::new(1.0, 2.0, 3.0); /// let transformed_point = t.transform_point(&Point3::new(4.0, 5.0, 6.0)); /// assert_eq!(transformed_point, Point3::new(4.0, 10.0, 18.0)); /// ``` #[inline] #[must_use] pub fn transform_point(&self, pt: &Point) -> Point { self * pt } } impl Scale { /// Translate the given point by the inverse of this Scale. /// /// # Example /// ``` /// # use nalgebra::{Scale3, Point3}; /// let t = Scale3::new(1.0, 2.0, 3.0); /// let transformed_point = t.try_inverse_transform_point(&Point3::new(4.0, 6.0, 6.0)).unwrap(); /// assert_eq!(transformed_point, Point3::new(4.0, 3.0, 2.0)); /// /// // Returns None if the inverse doesn't exist. /// let t = Scale3::new(1.0, 0.0, 3.0); /// let transformed_point = t.try_inverse_transform_point(&Point3::new(4.0, 6.0, 6.0)); /// assert_eq!(transformed_point, None); /// ``` #[inline] #[must_use] pub fn try_inverse_transform_point(&self, pt: &Point) -> Option> { self.try_inverse().map(|s| s * pt) } } impl Eq for Scale {} impl PartialEq for Scale { #[inline] fn eq(&self, right: &Scale) -> bool { self.vector == right.vector } } impl AbsDiffEq for Scale where T::Epsilon: Clone, { type Epsilon = T::Epsilon; #[inline] fn default_epsilon() -> Self::Epsilon { T::default_epsilon() } #[inline] fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool { self.vector.abs_diff_eq(&other.vector, epsilon) } } impl RelativeEq for Scale where T::Epsilon: Clone, { #[inline] fn default_max_relative() -> Self::Epsilon { T::default_max_relative() } #[inline] fn relative_eq( &self, other: &Self, epsilon: Self::Epsilon, max_relative: Self::Epsilon, ) -> bool { self.vector .relative_eq(&other.vector, epsilon, max_relative) } } impl UlpsEq for Scale where T::Epsilon: Clone, { #[inline] fn default_max_ulps() -> u32 { T::default_max_ulps() } #[inline] fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool { self.vector.ulps_eq(&other.vector, epsilon, max_ulps) } } /* * * Display * */ impl fmt::Display for Scale { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let precision = f.precision().unwrap_or(3); writeln!(f, "Scale {{")?; write!(f, "{:.*}", precision, self.vector)?; writeln!(f, "}}") } }