From 8c6ad490bc90155f8e6e397b374a161986b6233b Mon Sep 17 00:00:00 2001 From: Yuri Edward Date: Tue, 19 Oct 2021 14:02:07 +0200 Subject: [PATCH] Initial commit copy all translation_x files into scale_x files --- src/geometry/scale_alias.rs | 19 ++ src/geometry/scale_construction.rs | 123 ++++++++++++ src/geometry/scale_conversion.rs | 306 +++++++++++++++++++++++++++++ src/geometry/scale_coordinates.rs | 39 ++++ src/geometry/scale_ops.rs | 119 +++++++++++ src/geometry/scale_simba.rs | 49 +++++ 6 files changed, 655 insertions(+) create mode 100644 src/geometry/scale_alias.rs create mode 100644 src/geometry/scale_construction.rs create mode 100644 src/geometry/scale_conversion.rs create mode 100644 src/geometry/scale_coordinates.rs create mode 100644 src/geometry/scale_ops.rs create mode 100755 src/geometry/scale_simba.rs diff --git a/src/geometry/scale_alias.rs b/src/geometry/scale_alias.rs new file mode 100644 index 00000000..06dc0794 --- /dev/null +++ b/src/geometry/scale_alias.rs @@ -0,0 +1,19 @@ +use crate::geometry::Translation; + +/// A 1-dimensional translation. +pub type Translation1 = Translation; + +/// A 2-dimensional translation. +pub type Translation2 = Translation; + +/// A 3-dimensional translation. +pub type Translation3 = Translation; + +/// A 4-dimensional translation. +pub type Translation4 = Translation; + +/// A 5-dimensional translation. +pub type Translation5 = Translation; + +/// A 6-dimensional translation. +pub type Translation6 = Translation; diff --git a/src/geometry/scale_construction.rs b/src/geometry/scale_construction.rs new file mode 100644 index 00000000..5371b648 --- /dev/null +++ b/src/geometry/scale_construction.rs @@ -0,0 +1,123 @@ +#[cfg(feature = "arbitrary")] +use crate::base::storage::Owned; +#[cfg(feature = "arbitrary")] +use quickcheck::{Arbitrary, Gen}; + +use num::{One, Zero}; +#[cfg(feature = "rand-no-std")] +use rand::{ + distributions::{Distribution, Standard}, + Rng, +}; + +use simba::scalar::{ClosedAdd, SupersetOf}; + +use crate::base::{SVector, Scalar}; +use crate::geometry::Translation; + +impl Translation { + /// Creates a new identity translation. + /// + /// # Example + /// ``` + /// # use nalgebra::{Point2, Point3, Translation2, Translation3}; + /// let t = Translation2::identity(); + /// let p = Point2::new(1.0, 2.0); + /// assert_eq!(t * p, p); + /// + /// // Works in all dimensions. + /// let t = Translation3::identity(); + /// let p = Point3::new(1.0, 2.0, 3.0); + /// assert_eq!(t * p, p); + /// ``` + #[inline] + pub fn identity() -> Translation + where + T: Zero, + { + Self::from(SVector::::from_element(T::zero())) + } + + /// Cast the components of `self` to another type. + /// + /// # Example + /// ``` + /// # use nalgebra::Translation2; + /// let tra = Translation2::new(1.0f64, 2.0); + /// let tra2 = tra.cast::(); + /// assert_eq!(tra2, Translation2::new(1.0f32, 2.0)); + /// ``` + pub fn cast(self) -> Translation + where + Translation: SupersetOf, + { + crate::convert(self) + } +} + +impl One for Translation { + #[inline] + fn one() -> Self { + Self::identity() + } +} + +#[cfg(feature = "rand-no-std")] +impl Distribution> for Standard +where + Standard: Distribution, +{ + /// Generate an arbitrary random variate for testing purposes. + #[inline] + fn sample(&self, rng: &mut G) -> Translation { + Translation::from(rng.gen::>()) + } +} + +#[cfg(feature = "arbitrary")] +impl Arbitrary for Translation +where + Owned>: Send, +{ + #[inline] + fn arbitrary(rng: &mut Gen) -> Self { + let v: SVector = Arbitrary::arbitrary(rng); + Self::from(v) + } +} + +/* + * + * Small translation construction from components. + * + */ +macro_rules! componentwise_constructors_impl( + ($($doc: expr; $D: expr, $($args: ident:$irow: expr),*);* $(;)*) => {$( + impl Translation + { + #[doc = "Initializes this translation from its components."] + #[doc = "# Example\n```"] + #[doc = $doc] + #[doc = "```"] + #[inline] + pub const fn new($($args: T),*) -> Self { + Self { vector: SVector::::new($($args),*) } + } + } + )*} +); + +componentwise_constructors_impl!( + "# use nalgebra::Translation1;\nlet t = Translation1::new(1.0);\nassert!(t.vector.x == 1.0);"; + 1, x:0; + "# use nalgebra::Translation2;\nlet t = Translation2::new(1.0, 2.0);\nassert!(t.vector.x == 1.0 && t.vector.y == 2.0);"; + 2, x:0, y:1; + "# use nalgebra::Translation3;\nlet t = Translation3::new(1.0, 2.0, 3.0);\nassert!(t.vector.x == 1.0 && t.vector.y == 2.0 && t.vector.z == 3.0);"; + 3, x:0, y:1, z:2; + "# use nalgebra::Translation4;\nlet t = Translation4::new(1.0, 2.0, 3.0, 4.0);\nassert!(t.vector.x == 1.0 && t.vector.y == 2.0 && t.vector.z == 3.0 && t.vector.w == 4.0);"; + 4, x:0, y:1, z:2, w:3; + "# use nalgebra::Translation5;\nlet t = Translation5::new(1.0, 2.0, 3.0, 4.0, 5.0);\nassert!(t.vector.x == 1.0 && t.vector.y == 2.0 && t.vector.z == 3.0 && t.vector.w == 4.0 && t.vector.a == 5.0);"; + 5, x:0, y:1, z:2, w:3, a:4; + "# use nalgebra::Translation6;\nlet t = Translation6::new(1.0, 2.0, 3.0, 4.0, 5.0, 6.0);\nassert!(t.vector.x == 1.0 && t.vector.y == 2.0 && t.vector.z == 3.0 && t.vector.w == 4.0 && t.vector.a == 5.0 && t.vector.b == 6.0);"; + 6, x:0, y:1, z:2, w:3, a:4, b:5; +); diff --git a/src/geometry/scale_conversion.rs b/src/geometry/scale_conversion.rs new file mode 100644 index 00000000..70000efb --- /dev/null +++ b/src/geometry/scale_conversion.rs @@ -0,0 +1,306 @@ +use num::{One, Zero}; + +use simba::scalar::{RealField, SubsetOf, SupersetOf}; +use simba::simd::PrimitiveSimdValue; + +use crate::base::allocator::Allocator; +use crate::base::dimension::{DimNameAdd, DimNameSum, U1}; +use crate::base::{Const, DefaultAllocator, DimName, OMatrix, OVector, SVector, Scalar}; + +use crate::geometry::{ + AbstractRotation, Isometry, Similarity, SuperTCategoryOf, TAffine, Transform, Translation, + Translation3, UnitDualQuaternion, UnitQuaternion, +}; +use crate::Point; + +/* + * This file provides the following conversions: + * ============================================= + * + * Translation -> Translation + * Translation -> Isometry + * Translation3 -> UnitDualQuaternion + * Translation -> Similarity + * Translation -> Transform + * Translation -> Matrix (homogeneous) + */ + +impl SubsetOf> for Translation +where + T1: Scalar, + T2: Scalar + SupersetOf, +{ + #[inline] + fn to_superset(&self) -> Translation { + Translation::from(self.vector.to_superset()) + } + + #[inline] + fn is_in_subset(rot: &Translation) -> bool { + crate::is_convertible::<_, SVector>(&rot.vector) + } + + #[inline] + fn from_superset_unchecked(rot: &Translation) -> Self { + Translation { + vector: rot.vector.to_subset_unchecked(), + } + } +} + +impl SubsetOf> for Translation +where + T1: RealField, + T2: RealField + SupersetOf, + R: AbstractRotation, +{ + #[inline] + fn to_superset(&self) -> Isometry { + Isometry::from_parts(self.to_superset(), R::identity()) + } + + #[inline] + fn is_in_subset(iso: &Isometry) -> bool { + iso.rotation == R::identity() + } + + #[inline] + fn from_superset_unchecked(iso: &Isometry) -> Self { + Self::from_superset_unchecked(&iso.translation) + } +} + +impl SubsetOf> for Translation3 +where + T1: RealField, + T2: RealField + SupersetOf, +{ + #[inline] + fn to_superset(&self) -> UnitDualQuaternion { + let dq = UnitDualQuaternion::::from_parts(self.clone(), UnitQuaternion::identity()); + dq.to_superset() + } + + #[inline] + fn is_in_subset(dq: &UnitDualQuaternion) -> bool { + crate::is_convertible::<_, Translation>(&dq.translation()) + && dq.rotation() == UnitQuaternion::identity() + } + + #[inline] + fn from_superset_unchecked(dq: &UnitDualQuaternion) -> Self { + let dq: UnitDualQuaternion = crate::convert_ref_unchecked(dq); + dq.translation() + } +} + +impl SubsetOf> for Translation +where + T1: RealField, + T2: RealField + SupersetOf, + R: AbstractRotation, +{ + #[inline] + fn to_superset(&self) -> Similarity { + Similarity::from_parts(self.to_superset(), R::identity(), T2::one()) + } + + #[inline] + fn is_in_subset(sim: &Similarity) -> bool { + sim.isometry.rotation == R::identity() && sim.scaling() == T2::one() + } + + #[inline] + fn from_superset_unchecked(sim: &Similarity) -> Self { + Self::from_superset_unchecked(&sim.isometry.translation) + } +} + +impl SubsetOf> for Translation +where + T1: RealField, + T2: RealField + SupersetOf, + C: SuperTCategoryOf, + Const: DimNameAdd, + DefaultAllocator: Allocator, U1>, DimNameSum, U1>> + + Allocator, U1>, DimNameSum, U1>>, +{ + #[inline] + fn to_superset(&self) -> Transform { + Transform::from_matrix_unchecked(self.to_homogeneous().to_superset()) + } + + #[inline] + fn is_in_subset(t: &Transform) -> bool { + >::is_in_subset(t.matrix()) + } + + #[inline] + fn from_superset_unchecked(t: &Transform) -> Self { + Self::from_superset_unchecked(t.matrix()) + } +} + +impl + SubsetOf, U1>, DimNameSum, U1>>> for Translation +where + T1: RealField, + T2: RealField + SupersetOf, + Const: DimNameAdd, + DefaultAllocator: Allocator, U1>, DimNameSum, U1>> + + Allocator, U1>, DimNameSum, U1>>, + // + Allocator + // + Allocator +{ + #[inline] + fn to_superset(&self) -> OMatrix, U1>, DimNameSum, U1>> { + self.to_homogeneous().to_superset() + } + + #[inline] + fn is_in_subset(m: &OMatrix, U1>, DimNameSum, U1>>) -> bool { + let id = m.generic_slice((0, 0), (DimNameSum::, U1>::name(), Const::)); + + // Scalar types agree. + m.iter().all(|e| SupersetOf::::is_in_subset(e)) && + // The block part does nothing. + id.is_identity(T2::zero()) && + // The normalization factor is one. + m[(D, D)] == T2::one() + } + + #[inline] + fn from_superset_unchecked( + m: &OMatrix, U1>, DimNameSum, U1>>, + ) -> Self { + let t = m.fixed_slice::(0, D); + Self { + vector: crate::convert_unchecked(t.into_owned()), + } + } +} + +impl From> + for OMatrix, U1>, DimNameSum, U1>> +where + Const: DimNameAdd, + DefaultAllocator: + Allocator, U1>, DimNameSum, U1>> + Allocator>, +{ + #[inline] + fn from(t: Translation) -> Self { + t.to_homogeneous() + } +} + +impl From>> for Translation { + #[inline] + fn from(vector: OVector>) -> Self { + Translation { vector } + } +} + +impl From<[T; D]> for Translation { + #[inline] + fn from(coords: [T; D]) -> Self { + Translation { + vector: coords.into(), + } + } +} + +impl From> for Translation { + #[inline] + fn from(pt: Point) -> Self { + Translation { vector: pt.coords } + } +} + +impl From> for [T; D] { + #[inline] + fn from(t: Translation) -> Self { + t.vector.into() + } +} + +impl From<[Translation; 2]> + for Translation +where + T: From<[::Element; 2]>, + T::Element: Scalar, +{ + #[inline] + fn from(arr: [Translation; 2]) -> Self { + Self::from(OVector::from([ + arr[0].vector.clone(), + arr[1].vector.clone(), + ])) + } +} + +impl From<[Translation; 4]> + for Translation +where + T: From<[::Element; 4]>, + T::Element: Scalar, +{ + #[inline] + fn from(arr: [Translation; 4]) -> Self { + Self::from(OVector::from([ + arr[0].vector.clone(), + arr[1].vector.clone(), + arr[2].vector.clone(), + arr[3].vector.clone(), + ])) + } +} + +impl From<[Translation; 8]> + for Translation +where + T: From<[::Element; 8]>, + T::Element: Scalar, +{ + #[inline] + fn from(arr: [Translation; 8]) -> Self { + Self::from(OVector::from([ + arr[0].vector.clone(), + arr[1].vector.clone(), + arr[2].vector.clone(), + arr[3].vector.clone(), + arr[4].vector.clone(), + arr[5].vector.clone(), + arr[6].vector.clone(), + arr[7].vector.clone(), + ])) + } +} + +impl From<[Translation; 16]> + for Translation +where + T: From<[::Element; 16]>, + T::Element: Scalar, +{ + #[inline] + fn from(arr: [Translation; 16]) -> Self { + Self::from(OVector::from([ + arr[0].vector.clone(), + arr[1].vector.clone(), + arr[2].vector.clone(), + arr[3].vector.clone(), + arr[4].vector.clone(), + arr[5].vector.clone(), + arr[6].vector.clone(), + arr[7].vector.clone(), + arr[8].vector.clone(), + arr[9].vector.clone(), + arr[10].vector.clone(), + arr[11].vector.clone(), + arr[12].vector.clone(), + arr[13].vector.clone(), + arr[14].vector.clone(), + arr[15].vector.clone(), + ])) + } +} diff --git a/src/geometry/scale_coordinates.rs b/src/geometry/scale_coordinates.rs new file mode 100644 index 00000000..80267e06 --- /dev/null +++ b/src/geometry/scale_coordinates.rs @@ -0,0 +1,39 @@ +use std::ops::{Deref, DerefMut}; + +use crate::base::coordinates::{X, XY, XYZ, XYZW, XYZWA, XYZWAB}; +use crate::base::Scalar; + +use crate::geometry::Translation; + +/* + * + * Give coordinates to Translation{1 .. 6} + * + */ + +macro_rules! deref_impl( + ($D: expr, $Target: ident $(, $comps: ident)*) => { + impl Deref for Translation { + type Target = $Target; + + #[inline] + fn deref(&self) -> &Self::Target { + unsafe { &*(self as *const Translation as *const Self::Target) } + } + } + + impl DerefMut for Translation { + #[inline] + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { &mut *(self as *mut Translation as *mut Self::Target) } + } + } + } +); + +deref_impl!(1, X, x); +deref_impl!(2, XY, x, y); +deref_impl!(3, XYZ, x, y, z); +deref_impl!(4, XYZW, x, y, z, w); +deref_impl!(5, XYZWA, x, y, z, w, a); +deref_impl!(6, XYZWAB, x, y, z, w, a, b); diff --git a/src/geometry/scale_ops.rs b/src/geometry/scale_ops.rs new file mode 100644 index 00000000..8851183a --- /dev/null +++ b/src/geometry/scale_ops.rs @@ -0,0 +1,119 @@ +use std::ops::{Div, DivAssign, Mul, MulAssign}; + +use simba::scalar::{ClosedAdd, ClosedSub}; + +use crate::base::constraint::{SameNumberOfColumns, SameNumberOfRows, ShapeConstraint}; +use crate::base::dimension::U1; +use crate::base::{Const, Scalar}; + +use crate::geometry::{Point, Translation}; + +// Translation × Translation +add_sub_impl!(Mul, mul, ClosedAdd; + (Const, U1), (Const, U1) -> (Const, U1) + const D; for; where; + self: &'a Translation, right: &'b Translation, Output = Translation; + #[allow(clippy::suspicious_arithmetic_impl)] { Translation::from(&self.vector + &right.vector) }; + 'a, 'b); + +add_sub_impl!(Mul, mul, ClosedAdd; + (Const, U1), (Const, U1) -> (Const, U1) + const D; for; where; + self: &'a Translation, right: Translation, Output = Translation; + #[allow(clippy::suspicious_arithmetic_impl)] { Translation::from(&self.vector + right.vector) }; + 'a); + +add_sub_impl!(Mul, mul, ClosedAdd; + (Const, U1), (Const, U1) -> (Const, U1) + const D; for; where; + self: Translation, right: &'b Translation, Output = Translation; + #[allow(clippy::suspicious_arithmetic_impl)] { Translation::from(self.vector + &right.vector) }; + 'b); + +add_sub_impl!(Mul, mul, ClosedAdd; + (Const, U1), (Const, U1) -> (Const, U1) + const D; for; where; + self: Translation, right: Translation, Output = Translation; + #[allow(clippy::suspicious_arithmetic_impl)] { Translation::from(self.vector + right.vector) }; ); + +// Translation ÷ Translation +// TODO: instead of calling inverse explicitly, could we just add a `mul_tr` or `mul_inv` method? +add_sub_impl!(Div, div, ClosedSub; + (Const, U1), (Const, U1) -> (Const, U1) + const D; for; where; + self: &'a Translation, right: &'b Translation, Output = Translation; + #[allow(clippy::suspicious_arithmetic_impl)] { Translation::from(&self.vector - &right.vector) }; + 'a, 'b); + +add_sub_impl!(Div, div, ClosedSub; + (Const, U1), (Const, U1) -> (Const, U1) + const D; for; where; + self: &'a Translation, right: Translation, Output = Translation; + #[allow(clippy::suspicious_arithmetic_impl)] { Translation::from(&self.vector - right.vector) }; + 'a); + +add_sub_impl!(Div, div, ClosedSub; + (Const, U1), (Const, U1) -> (Const, U1) + const D; for; where; + self: Translation, right: &'b Translation, Output = Translation; + #[allow(clippy::suspicious_arithmetic_impl)] { Translation::from(self.vector - &right.vector) }; + 'b); + +add_sub_impl!(Div, div, ClosedSub; + (Const, U1), (Const, U1) -> (Const, U1) + const D; for; where; + self: Translation, right: Translation, Output = Translation; + #[allow(clippy::suspicious_arithmetic_impl)] { Translation::from(self.vector - right.vector) }; ); + +// Translation × Point +// TODO: we don't handle properly non-zero origins here. Do we want this to be the intended +// behavior? +add_sub_impl!(Mul, mul, ClosedAdd; + (Const, U1), (Const, U1) -> (Const, U1) + const D; for; where; + self: &'a Translation, right: &'b Point, Output = Point; + #[allow(clippy::suspicious_arithmetic_impl)] { right + &self.vector }; + 'a, 'b); + +add_sub_impl!(Mul, mul, ClosedAdd; + (Const, U1), (Const, U1) -> (Const, U1) + const D; for; where; + self: &'a Translation, right: Point, Output = Point; + #[allow(clippy::suspicious_arithmetic_impl)] { right + &self.vector }; + 'a); + +add_sub_impl!(Mul, mul, ClosedAdd; + (Const, U1), (Const, U1) -> (Const, U1) + const D; for; where; + self: Translation, right: &'b Point, Output = Point; + #[allow(clippy::suspicious_arithmetic_impl)] { right + self.vector }; + 'b); + +add_sub_impl!(Mul, mul, ClosedAdd; + (Const, U1), (Const, U1) -> (Const, U1) + const D; for; where; + self: Translation, right: Point, Output = Point; + #[allow(clippy::suspicious_arithmetic_impl)] { right + self.vector }; ); + +// Translation *= Translation +add_sub_assign_impl!(MulAssign, mul_assign, ClosedAdd; + const D; + self: Translation, right: &'b Translation; + #[allow(clippy::suspicious_op_assign_impl)] { self.vector += &right.vector }; + 'b); + +add_sub_assign_impl!(MulAssign, mul_assign, ClosedAdd; + const D; + self: Translation, right: Translation; + #[allow(clippy::suspicious_op_assign_impl)] { self.vector += right.vector }; ); + +add_sub_assign_impl!(DivAssign, div_assign, ClosedSub; + const D; + self: Translation, right: &'b Translation; + #[allow(clippy::suspicious_op_assign_impl)] { self.vector -= &right.vector }; + 'b); + +add_sub_assign_impl!(DivAssign, div_assign, ClosedSub; + const D; + self: Translation, right: Translation; + #[allow(clippy::suspicious_op_assign_impl)] { self.vector -= right.vector }; ); diff --git a/src/geometry/scale_simba.rs b/src/geometry/scale_simba.rs new file mode 100755 index 00000000..7f7f7ebf --- /dev/null +++ b/src/geometry/scale_simba.rs @@ -0,0 +1,49 @@ +use simba::simd::SimdValue; + +use crate::base::OVector; +use crate::Scalar; + +use crate::geometry::Translation; + +impl SimdValue for Translation +where + T::Element: Scalar, +{ + type Element = Translation; + type SimdBool = T::SimdBool; + + #[inline] + fn lanes() -> usize { + T::lanes() + } + + #[inline] + fn splat(val: Self::Element) -> Self { + OVector::splat(val.vector).into() + } + + #[inline] + fn extract(&self, i: usize) -> Self::Element { + self.vector.extract(i).into() + } + + #[inline] + unsafe fn extract_unchecked(&self, i: usize) -> Self::Element { + self.vector.extract_unchecked(i).into() + } + + #[inline] + fn replace(&mut self, i: usize, val: Self::Element) { + self.vector.replace(i, val.vector) + } + + #[inline] + unsafe fn replace_unchecked(&mut self, i: usize, val: Self::Element) { + self.vector.replace_unchecked(i, val.vector) + } + + #[inline] + fn select(self, cond: Self::SimdBool, other: Self) -> Self { + self.vector.select(cond, other.vector).into() + } +}