diff --git a/src/geometry/scale.rs b/src/geometry/scale.rs new file mode 100755 index 00000000..48656f9c --- /dev/null +++ b/src/geometry/scale.rs @@ -0,0 +1,363 @@ +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 simba::scalar::{ClosedAdd, ClosedNeg, ClosedSub}; + +use crate::base::allocator::Allocator; +use crate::base::dimension::{DimNameAdd, DimNameSum, U1}; +use crate::base::storage::Owned; +use crate::base::{Const, DefaultAllocator, OMatrix, SVector, Scalar}; + +use crate::geometry::Point; + +/// A translation. +#[repr(C)] +pub struct Translation { + /// The translation coordinates, i.e., how much is added to a point's coordinates when it is + /// translated. + pub vector: SVector, +} + +impl fmt::Debug for Translation { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + self.vector.as_slice().fmt(formatter) + } +} + +impl hash::Hash for Translation +where + Owned>: hash::Hash, +{ + fn hash(&self, state: &mut H) { + self.vector.hash(state) + } +} + +impl Copy for Translation {} + +impl Clone for Translation +where + Owned>: Clone, +{ + #[inline] + fn clone(&self) -> Self { + Translation::from(self.vector.clone()) + } +} + +#[cfg(feature = "bytemuck")] +unsafe impl bytemuck::Zeroable for Translation +where + T: Scalar + bytemuck::Zeroable, + SVector: bytemuck::Zeroable, +{ +} + +#[cfg(feature = "bytemuck")] +unsafe impl bytemuck::Pod for Translation +where + T: Scalar + bytemuck::Pod, + SVector: bytemuck::Pod, +{ +} + +#[cfg(feature = "abomonation-serialize")] +impl Abomonation for Translation +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 Translation +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 Translation +where + Owned>: Deserialize<'a>, +{ + fn deserialize(deserializer: Des) -> Result + where + Des: Deserializer<'a>, + { + let matrix = SVector::::deserialize(deserializer)?; + + Ok(Translation::from(matrix)) + } +} + +#[cfg(feature = "rkyv-serialize-no-std")] +mod rkyv_impl { + use super::Translation; + use crate::base::SVector; + use rkyv::{offset_of, project_struct, Archive, Deserialize, Fallible, Serialize}; + + impl Archive for Translation { + type Archived = Translation; + 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 Translation { + fn serialize(&self, serializer: &mut S) -> Result { + self.vector.serialize(serializer) + } + } + + impl Deserialize, _D> + for Translation + where + T::Archived: Deserialize, + { + fn deserialize(&self, deserializer: &mut _D) -> Result, _D::Error> { + Ok(Translation { + vector: self.vector.deserialize(deserializer)?, + }) + } + } +} + +impl Translation { + /// Creates a new translation from the given vector. + #[inline] + #[deprecated(note = "Use `::from` instead.")] + pub fn from_vector(vector: SVector) -> Translation { + Translation { vector } + } + + /// Inverts `self`. + /// + /// # Example + /// ``` + /// # use nalgebra::{Translation2, Translation3}; + /// let t = Translation3::new(1.0, 2.0, 3.0); + /// assert_eq!(t * t.inverse(), Translation3::identity()); + /// assert_eq!(t.inverse() * t, Translation3::identity()); + /// + /// // Work in all dimensions. + /// let t = Translation2::new(1.0, 2.0); + /// assert_eq!(t * t.inverse(), Translation2::identity()); + /// assert_eq!(t.inverse() * t, Translation2::identity()); + /// ``` + #[inline] + #[must_use = "Did you mean to use inverse_mut()?"] + pub fn inverse(&self) -> Translation + where + T: ClosedNeg, + { + Translation::from(-&self.vector) + } + + /// Converts this translation into its equivalent homogeneous transformation matrix. + /// + /// # Example + /// ``` + /// # use nalgebra::{Translation2, Translation3, Matrix3, Matrix4}; + /// let t = Translation3::new(10.0, 20.0, 30.0); + /// let expected = Matrix4::new(1.0, 0.0, 0.0, 10.0, + /// 0.0, 1.0, 0.0, 20.0, + /// 0.0, 0.0, 1.0, 30.0, + /// 0.0, 0.0, 0.0, 1.0); + /// assert_eq!(t.to_homogeneous(), expected); + /// + /// let t = Translation2::new(10.0, 20.0); + /// let expected = Matrix3::new(1.0, 0.0, 10.0, + /// 0.0, 1.0, 20.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, + Const: DimNameAdd, + DefaultAllocator: Allocator, U1>, DimNameSum, U1>>, + { + let mut res = OMatrix::, U1>, DimNameSum, U1>>::identity(); + res.fixed_slice_mut::(0, D).copy_from(&self.vector); + + res + } + + /// Inverts `self` in-place. + /// + /// # Example + /// ``` + /// # use nalgebra::{Translation2, Translation3}; + /// let t = Translation3::new(1.0, 2.0, 3.0); + /// let mut inv_t = Translation3::new(1.0, 2.0, 3.0); + /// inv_t.inverse_mut(); + /// assert_eq!(t * inv_t, Translation3::identity()); + /// assert_eq!(inv_t * t, Translation3::identity()); + /// + /// // Work in all dimensions. + /// let t = Translation2::new(1.0, 2.0); + /// let mut inv_t = Translation2::new(1.0, 2.0); + /// inv_t.inverse_mut(); + /// assert_eq!(t * inv_t, Translation2::identity()); + /// assert_eq!(inv_t * t, Translation2::identity()); + /// ``` + #[inline] + pub fn inverse_mut(&mut self) + where + T: ClosedNeg, + { + self.vector.neg_mut() + } +} + +impl Translation { + /// Translate the given point. + /// + /// This is the same as the multiplication `self * pt`. + /// + /// # Example + /// ``` + /// # use nalgebra::{Translation3, Point3}; + /// let t = Translation3::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(5.0, 7.0, 9.0)); + #[inline] + #[must_use] + pub fn transform_point(&self, pt: &Point) -> Point { + pt + &self.vector + } +} + +impl Translation { + /// Translate the given point by the inverse of this translation. + /// + /// # Example + /// ``` + /// # use nalgebra::{Translation3, Point3}; + /// let t = Translation3::new(1.0, 2.0, 3.0); + /// let transformed_point = t.inverse_transform_point(&Point3::new(4.0, 5.0, 6.0)); + /// assert_eq!(transformed_point, Point3::new(3.0, 3.0, 3.0)); + #[inline] + #[must_use] + pub fn inverse_transform_point(&self, pt: &Point) -> Point { + pt - &self.vector + } +} + +impl Eq for Translation {} + +impl PartialEq for Translation { + #[inline] + fn eq(&self, right: &Translation) -> bool { + self.vector == right.vector + } +} + +impl AbsDiffEq for Translation +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 Translation +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 Translation +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 Translation { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let precision = f.precision().unwrap_or(3); + + writeln!(f, "Translation {{")?; + write!(f, "{:.*}", precision, self.vector)?; + writeln!(f, "}}") + } +}