use approx::{AbsDiffEq, RelativeEq, UlpsEq}; use num::{One, Zero}; use std::fmt; use std::hash; #[cfg(feature = "abomonation-serialize")] use std::io::{Result as IOResult, Write}; #[cfg(feature = "serde-serialize-no-std")] use serde::{Deserialize, Deserializer, Serialize, Serializer}; #[cfg(feature = "abomonation-serialize")] use abomonation::Abomonation; 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)] 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) } } impl Copy for Scale {} impl Clone for Scale where Owned>: Clone, { #[inline] fn clone(&self) -> Self { Scale::from(self.vector.clone()) } } #[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 = "abomonation-serialize")] impl Abomonation for Scale where T: Scalar, SVector: Abomonation, { unsafe fn entomb(&self, writer: &mut W) -> IOResult<()> { self.vector.entomb(writer) } fn extent(&self) -> usize { self.vector.extent() } unsafe fn exhume<'a, 'b>(&'a mut self, bytes: &'b mut [u8]) -> Option<&'b mut [u8]> { self.vector.exhume(bytes) } } #[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)) } } #[cfg(feature = "rkyv-serialize-no-std")] mod rkyv_impl { use super::Scale; use crate::base::SVector; use rkyv::{offset_of, project_struct, Archive, Deserialize, Fallible, Serialize}; impl Archive for Scale { type Archived = Scale; type Resolver = as Archive>::Resolver; fn resolve( &self, pos: usize, resolver: Self::Resolver, out: &mut core::mem::MaybeUninit, ) { self.vector.resolve( pos + offset_of!(Self::Archived, vector), resolver, project_struct!(out: Self::Archived => vector), ); } } impl, S: Fallible + ?Sized, const D: usize> Serialize for Scale { fn serialize(&self, serializer: &mut S) -> Result { self.vector.serialize(serializer) } } impl Deserialize, _D> for Scale where T::Archived: Deserialize, { fn deserialize(&self, deserializer: &mut _D) -> Result, _D::Error> { Ok(Scale { vector: self.vector.deserialize(deserializer)?, }) } } } impl Scale { /// Inverts `self`. /// /// # Example /// ``` /// # use nalgebra::{Scale2, Scale3}; /// let t = Scale3::new(1.0, 2.0, 3.0); /// assert_eq!(t * t.inverse(), Scale3::identity()); /// assert_eq!(t.inverse() * t, Scale3::identity()); /// /// // Work in all dimensions. /// let t = Scale2::new(1.0, 2.0); /// assert_eq!(t * t.inverse(), Scale2::identity()); /// assert_eq!(t.inverse() * t, Scale2::identity()); /// ``` #[inline] #[must_use = "Did you mean to use inverse_mut()?"] pub fn inverse(&self) -> Scale where T: ClosedDiv + One, { let useless: SVector = SVector::from_element(T::one()); return useless.component_div(&self.vector).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>, { // Unfortunately rust refuses at all costs to allow calling .to_homogeneous on a SVector // (self.vector) so I had to do a manual copy in a new OVector // The exact error is that to_homogeneous when called on a SVector requires DimAdd on Const // not DimNameAdd which will strangely bring rust into thinking that DimNameAdd is a // trait object and no longer a generic parameter. let mut v = OVector::, U1>>::from_element(T::one()); for i in 0..D { v[(i, 0)] = self.vector[(i, 0)].clone(); } return OMatrix::, U1>, DimNameSum, U1>>::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); /// inv_t.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); /// inv_t.inverse_mut(); /// assert_eq!(t * inv_t, Scale2::identity()); /// assert_eq!(inv_t * t, Scale2::identity()); /// ``` #[inline] pub fn inverse_mut(&mut self) where T: ClosedDiv + One, { self.vector = self.inverse().vector; } } 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 { return 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.inverse_transform_point(&Point3::new(4.0, 6.0, 6.0)); /// assert_eq!(transformed_point, Point3::new(4.0, 3.0, 2.0)); #[inline] #[must_use] pub fn inverse_transform_point(&self, pt: &Point) -> Point { return self.inverse() * 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, "}}") } }