From 2a2e9d7f8e57af6383f07e77a50a2a89b2407ee9 Mon Sep 17 00:00:00 2001 From: Terence Date: Sun, 24 Feb 2019 11:29:27 -0500 Subject: [PATCH 1/2] Add the `transform` methods as inherent methods on geometric types This adds `transform_point`, `transform_vector`, `inverse_transform_point` and `inverse_transform_vector` as inherent methods on the applicable geometric transformation structures, such that they can be used without the need to import the `Transformation` and `ProjectiveTransformation` traits from `alga`. --- src/geometry/isometry.rs | 89 ++++++++++++++++++++++++++++++- src/geometry/isometry_alga.rs | 9 ++-- src/geometry/quaternion.rs | 80 ++++++++++++++++++++++++++- src/geometry/quaternion_alga.rs | 10 ++-- src/geometry/rotation.rs | 80 ++++++++++++++++++++++++++- src/geometry/rotation_alga.rs | 8 +-- src/geometry/similarity.rs | 79 ++++++++++++++++++++++++++- src/geometry/similarity_alga.rs | 8 +-- src/geometry/transform.rs | 53 +++++++++++++++++- src/geometry/transform_alga.rs | 8 +-- src/geometry/translation.rs | 38 ++++++++++++- src/geometry/translation_alga.rs | 4 +- src/geometry/unit_complex.rs | 70 +++++++++++++++++++++++- src/geometry/unit_complex_alga.rs | 10 ++-- 14 files changed, 506 insertions(+), 40 deletions(-) mode change 100644 => 100755 src/geometry/isometry.rs mode change 100644 => 100755 src/geometry/isometry_alga.rs mode change 100644 => 100755 src/geometry/quaternion.rs mode change 100644 => 100755 src/geometry/quaternion_alga.rs mode change 100644 => 100755 src/geometry/rotation.rs mode change 100644 => 100755 src/geometry/rotation_alga.rs mode change 100644 => 100755 src/geometry/similarity.rs mode change 100644 => 100755 src/geometry/similarity_alga.rs mode change 100644 => 100755 src/geometry/transform.rs mode change 100644 => 100755 src/geometry/transform_alga.rs mode change 100644 => 100755 src/geometry/translation.rs mode change 100644 => 100755 src/geometry/translation_alga.rs mode change 100644 => 100755 src/geometry/unit_complex.rs mode change 100644 => 100755 src/geometry/unit_complex_alga.rs diff --git a/src/geometry/isometry.rs b/src/geometry/isometry.rs old mode 100644 new mode 100755 index 1097be47..04e77b7a --- a/src/geometry/isometry.rs +++ b/src/geometry/isometry.rs @@ -17,7 +17,7 @@ use alga::linear::Rotation; use base::allocator::Allocator; use base::dimension::{DimName, DimNameAdd, DimNameSum, U1}; use base::storage::Owned; -use base::{DefaultAllocator, MatrixN}; +use base::{DefaultAllocator, MatrixN, VectorN}; use geometry::{Point, Translation}; /// A direct isometry, i.e., a rotation followed by a translation, aka. a rigid-body motion, aka. an element of a Special Euclidean (SE) group. @@ -254,6 +254,93 @@ where DefaultAllocator: Allocator pub fn append_rotation_wrt_center_mut(&mut self, r: &R) { self.rotation = self.rotation.append_rotation(r); } + + /// Transform the given point by this isometry. + /// + /// # Example + /// + /// ``` + /// # #[macro_use] extern crate approx; + /// # use std::f32; + /// # use nalgebra::{Isometry3, Translation3, UnitQuaternion, Vector3, Point3}; + /// let tra = Translation3::new(0.0, 0.0, 3.0); + /// let rot = UnitQuaternion::from_scaled_axis(Vector3::y() * f32::consts::FRAC_PI_2); + /// let iso = Isometry3::from_parts(tra, rot); + /// + /// let transformed_point = iso.transform_point(&Point3::new(1.0, 2.0, 3.0)); + /// assert_relative_eq!(transformed_point, Point3::new(3.0, 2.0, 2.0), epsilon = 1.0e-6); + /// ``` + #[inline] + pub fn transform_point(&self, pt: &Point) -> Point { + self * pt + } + + /// Transform the given vector by this isometry, ignoring the translation + /// component of the isometry. + /// + /// # Example + /// + /// ``` + /// # #[macro_use] extern crate approx; + /// # use std::f32; + /// # use nalgebra::{Isometry3, Translation3, UnitQuaternion, Vector3}; + /// let tra = Translation3::new(0.0, 0.0, 3.0); + /// let rot = UnitQuaternion::from_scaled_axis(Vector3::y() * f32::consts::FRAC_PI_2); + /// let iso = Isometry3::from_parts(tra, rot); + /// + /// let transformed_point = iso.transform_vector(&Vector3::new(1.0, 2.0, 3.0)); + /// assert_relative_eq!(transformed_point, Vector3::new(3.0, 2.0, -1.0), epsilon = 1.0e-6); + /// ``` + #[inline] + pub fn transform_vector(&self, v: &VectorN) -> VectorN { + self * v + } + + /// Transform the given point by the inverse of this isometry. This may be + /// less expensive than computing the entire isometry inverse and then + /// transforming the point. + /// + /// # Example + /// + /// ``` + /// # #[macro_use] extern crate approx; + /// # use std::f32; + /// # use nalgebra::{Isometry3, Translation3, UnitQuaternion, Vector3, Point3}; + /// let tra = Translation3::new(0.0, 0.0, 3.0); + /// let rot = UnitQuaternion::from_scaled_axis(Vector3::y() * f32::consts::FRAC_PI_2); + /// let iso = Isometry3::from_parts(tra, rot); + /// + /// let transformed_point = iso.inverse_transform_point(&Point3::new(1.0, 2.0, 3.0)); + /// assert_relative_eq!(transformed_point, Point3::new(0.0, 2.0, 1.0), epsilon = 1.0e-6); + /// ``` + #[inline] + pub fn inverse_transform_point(&self, pt: &Point) -> Point { + self.rotation + .inverse_transform_point(&(pt - &self.translation.vector)) + } + + /// Transform the given vector by the inverse of this isometry, ignoring the + /// translation component of the isometry. This may be + /// less expensive than computing the entire isometry inverse and then + /// transforming the point. + /// + /// # Example + /// + /// ``` + /// # #[macro_use] extern crate approx; + /// # use std::f32; + /// # use nalgebra::{Isometry3, Translation3, UnitQuaternion, Vector3}; + /// let tra = Translation3::new(0.0, 0.0, 3.0); + /// let rot = UnitQuaternion::from_scaled_axis(Vector3::y() * f32::consts::FRAC_PI_2); + /// let iso = Isometry3::from_parts(tra, rot); + /// + /// let transformed_point = iso.inverse_transform_vector(&Vector3::new(1.0, 2.0, 3.0)); + /// assert_relative_eq!(transformed_point, Vector3::new(-3.0, 2.0, 1.0), epsilon = 1.0e-6); + /// ``` + #[inline] + pub fn inverse_transform_vector(&self, v: &VectorN) -> VectorN { + self.rotation.inverse_transform_vector(v) + } } // NOTE: we don't require `R: Rotation<...>` here because this is not useful for the implementation diff --git a/src/geometry/isometry_alga.rs b/src/geometry/isometry_alga.rs old mode 100644 new mode 100755 index fee8b63d..a327f3fb --- a/src/geometry/isometry_alga.rs +++ b/src/geometry/isometry_alga.rs @@ -85,12 +85,12 @@ where { #[inline] fn transform_point(&self, pt: &Point) -> Point { - self * pt + self.transform_point(pt) } #[inline] fn transform_vector(&self, v: &VectorN) -> VectorN { - self * v + self.transform_vector(v) } } @@ -101,13 +101,12 @@ where { #[inline] fn inverse_transform_point(&self, pt: &Point) -> Point { - self.rotation - .inverse_transform_point(&(pt - &self.translation.vector)) + self.inverse_transform_point(pt) } #[inline] fn inverse_transform_vector(&self, v: &VectorN) -> VectorN { - self.rotation.inverse_transform_vector(v) + self.inverse_transform_vector(v) } } diff --git a/src/geometry/quaternion.rs b/src/geometry/quaternion.rs old mode 100644 new mode 100755 index 96e4f19a..365e55e2 --- a/src/geometry/quaternion.rs +++ b/src/geometry/quaternion.rs @@ -19,7 +19,7 @@ use base::dimension::{U1, U3, U4}; use base::storage::{CStride, RStride}; use base::{Matrix3, MatrixN, MatrixSlice, MatrixSliceMut, Unit, Vector3, Vector4}; -use geometry::Rotation; +use geometry::{Point3, Rotation}; /// A quaternion. See the type alias `UnitQuaternion = Unit` for a quaternion /// that may be used as a rotation. @@ -1005,6 +1005,84 @@ impl UnitQuaternion { pub fn to_homogeneous(&self) -> MatrixN { self.to_rotation_matrix().to_homogeneous() } + + /// Rotate a point by this unit quaternion. + /// + /// # Example + /// + /// ``` + /// # #[macro_use] extern crate approx; + /// # use std::f32; + /// # use nalgebra::{UnitQuaternion, Vector3, Point3}; + /// let rot = UnitQuaternion::from_axis_angle(&Vector3::y_axis(), f32::consts::FRAC_PI_2); + /// let transformed_point = rot.transform_point(&Point3::new(1.0, 2.0, 3.0)); + /// + /// assert_relative_eq!(transformed_point, Point3::new(3.0, 2.0, -1.0), epsilon = 1.0e-6); + /// ``` + #[inline] + pub fn transform_point(&self, pt: &Point3) -> Point3 { + self * pt + } + + /// Rotate a vector by this unit quaternion. + /// + /// # Example + /// + /// ``` + /// # #[macro_use] extern crate approx; + /// # use std::f32; + /// # use nalgebra::{UnitQuaternion, Vector3}; + /// let rot = UnitQuaternion::from_axis_angle(&Vector3::y_axis(), f32::consts::FRAC_PI_2); + /// let transformed_vector = rot.transform_vector(&Vector3::new(1.0, 2.0, 3.0)); + /// + /// assert_relative_eq!(transformed_vector, Vector3::new(3.0, 2.0, -1.0), epsilon = 1.0e-6); + /// ``` + #[inline] + pub fn transform_vector(&self, v: &Vector3) -> Vector3 { + self * v + } + + /// Rotate a point by the inverse of this unit quaternion. This may be + /// cheaper than inverting the unit quaternion and transforming the + /// point. + /// + /// # Example + /// + /// ``` + /// # #[macro_use] extern crate approx; + /// # use std::f32; + /// # use nalgebra::{UnitQuaternion, Vector3, Point3}; + /// let rot = UnitQuaternion::from_axis_angle(&Vector3::y_axis(), f32::consts::FRAC_PI_2); + /// let transformed_point = rot.inverse_transform_point(&Point3::new(1.0, 2.0, 3.0)); + /// + /// assert_relative_eq!(transformed_point, Point3::new(-3.0, 2.0, 1.0), epsilon = 1.0e-6); + /// ``` + #[inline] + pub fn inverse_transform_point(&self, pt: &Point3) -> Point3 { + // FIXME: would it be useful performancewise not to call inverse explicitly (i-e. implement + // the inverse transformation explicitly here) ? + self.inverse() * pt + } + + /// Rotate a vector by the inverse of this unit quaternion. This may be + /// cheaper than inverting the unit quaternion and transforming the + /// vector. + /// + /// # Example + /// + /// ``` + /// # #[macro_use] extern crate approx; + /// # use std::f32; + /// # use nalgebra::{UnitQuaternion, Vector3}; + /// let rot = UnitQuaternion::from_axis_angle(&Vector3::y_axis(), f32::consts::FRAC_PI_2); + /// let transformed_vector = rot.inverse_transform_vector(&Vector3::new(1.0, 2.0, 3.0)); + /// + /// assert_relative_eq!(transformed_vector, Vector3::new(-3.0, 2.0, 1.0), epsilon = 1.0e-6); + /// ``` + #[inline] + pub fn inverse_transform_vector(&self, v: &Vector3) -> Vector3 { + self.inverse() * v + } } impl fmt::Display for UnitQuaternion { diff --git a/src/geometry/quaternion_alga.rs b/src/geometry/quaternion_alga.rs old mode 100644 new mode 100755 index 529d27f4..d931b206 --- a/src/geometry/quaternion_alga.rs +++ b/src/geometry/quaternion_alga.rs @@ -197,26 +197,24 @@ impl_structures!( impl Transformation> for UnitQuaternion { #[inline] fn transform_point(&self, pt: &Point3) -> Point3 { - self * pt + self.transform_point(pt) } #[inline] fn transform_vector(&self, v: &Vector3) -> Vector3 { - self * v + self.transform_vector(v) } } impl ProjectiveTransformation> for UnitQuaternion { #[inline] fn inverse_transform_point(&self, pt: &Point3) -> Point3 { - // FIXME: would it be useful performancewise not to call inverse explicitly (i-e. implement - // the inverse transformation explicitly here) ? - self.inverse() * pt + self.inverse_transform_point(pt) } #[inline] fn inverse_transform_vector(&self, v: &Vector3) -> Vector3 { - self.inverse() * v + self.inverse_transform_vector(v) } } diff --git a/src/geometry/rotation.rs b/src/geometry/rotation.rs old mode 100644 new mode 100755 index 6c50230e..961951f1 --- a/src/geometry/rotation.rs +++ b/src/geometry/rotation.rs @@ -18,7 +18,9 @@ use alga::general::Real; use base::allocator::Allocator; use base::dimension::{DimName, DimNameAdd, DimNameSum, U1}; -use base::{DefaultAllocator, MatrixN, Scalar}; +use base::{DefaultAllocator, MatrixN, Scalar, VectorN}; + +use geometry::Point; /// A rotation matrix. #[repr(C)] @@ -351,6 +353,82 @@ where DefaultAllocator: Allocator } } +impl Rotation +where DefaultAllocator: Allocator + Allocator +{ + /// Rotate the given point. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use std::f32; + /// # use nalgebra::{Point3, Rotation2, Rotation3, UnitQuaternion, Vector3}; + /// let rot = Rotation3::new(Vector3::y() * f32::consts::FRAC_PI_2); + /// let transformed_point = rot.transform_point(&Point3::new(1.0, 2.0, 3.0)); + /// + /// assert_relative_eq!(transformed_point, Point3::new(3.0, 2.0, -1.0), epsilon = 1.0e-6); + /// ``` + #[inline] + pub fn transform_point(&self, pt: &Point) -> Point { + self * pt + } + + /// Rotate the given vector. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use std::f32; + /// # use nalgebra::{Rotation2, Rotation3, UnitQuaternion, Vector3}; + /// let rot = Rotation3::new(Vector3::y() * f32::consts::FRAC_PI_2); + /// let transformed_vector = rot.transform_vector(&Vector3::new(1.0, 2.0, 3.0)); + /// + /// assert_relative_eq!(transformed_vector, Vector3::new(3.0, 2.0, -1.0), epsilon = 1.0e-6); + /// ``` + #[inline] + pub fn transform_vector(&self, v: &VectorN) -> VectorN { + self * v + } + + /// Rotate the given point by the inverse of this rotation. This may be + /// cheaper than inverting the rotation and then transforming the given + /// point. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use std::f32; + /// # use nalgebra::{Point3, Rotation2, Rotation3, UnitQuaternion, Vector3}; + /// let rot = Rotation3::new(Vector3::y() * f32::consts::FRAC_PI_2); + /// let transformed_point = rot.inverse_transform_point(&Point3::new(1.0, 2.0, 3.0)); + /// + /// assert_relative_eq!(transformed_point, Point3::new(-3.0, 2.0, 1.0), epsilon = 1.0e-6); + /// ``` + #[inline] + pub fn inverse_transform_point(&self, pt: &Point) -> Point { + Point::from(self.inverse_transform_vector(&pt.coords)) + } + + /// Rotate the given vector by the inverse of this rotation. This may be + /// cheaper than inverting the rotation and then transforming the given + /// vector. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use std::f32; + /// # use nalgebra::{Rotation2, Rotation3, UnitQuaternion, Vector3}; + /// let rot = Rotation3::new(Vector3::y() * f32::consts::FRAC_PI_2); + /// let transformed_vector = rot.inverse_transform_vector(&Vector3::new(1.0, 2.0, 3.0)); + /// + /// assert_relative_eq!(transformed_vector, Vector3::new(-3.0, 2.0, 1.0), epsilon = 1.0e-6); + /// ``` + #[inline] + pub fn inverse_transform_vector(&self, v: &VectorN) -> VectorN { + self.matrix().tr_mul(v) + } +} + impl Eq for Rotation where DefaultAllocator: Allocator {} impl PartialEq for Rotation diff --git a/src/geometry/rotation_alga.rs b/src/geometry/rotation_alga.rs old mode 100644 new mode 100755 index 18c47b41..cd411c8c --- a/src/geometry/rotation_alga.rs +++ b/src/geometry/rotation_alga.rs @@ -75,12 +75,12 @@ where DefaultAllocator: Allocator + Allocator { #[inline] fn transform_point(&self, pt: &Point) -> Point { - self * pt + self.transform_point(pt) } #[inline] fn transform_vector(&self, v: &VectorN) -> VectorN { - self * v + self.transform_vector(v) } } @@ -89,12 +89,12 @@ where DefaultAllocator: Allocator + Allocator { #[inline] fn inverse_transform_point(&self, pt: &Point) -> Point { - Point::from(self.inverse_transform_vector(&pt.coords)) + self.inverse_transform_point(pt) } #[inline] fn inverse_transform_vector(&self, v: &VectorN) -> VectorN { - self.matrix().tr_mul(v) + self.inverse_transform_vector(v) } } diff --git a/src/geometry/similarity.rs b/src/geometry/similarity.rs old mode 100644 new mode 100755 index f321d575..dcb0f20a --- a/src/geometry/similarity.rs +++ b/src/geometry/similarity.rs @@ -16,7 +16,7 @@ use alga::linear::Rotation; use base::allocator::Allocator; use base::dimension::{DimName, DimNameAdd, DimNameSum, U1}; use base::storage::Owned; -use base::{DefaultAllocator, MatrixN}; +use base::{DefaultAllocator, MatrixN, VectorN}; use geometry::{Isometry, Point, Translation}; /// A similarity, i.e., an uniform scaling, followed by a rotation, followed by a translation. @@ -238,6 +238,83 @@ where pub fn append_rotation_wrt_center_mut(&mut self, r: &R) { self.isometry.append_rotation_wrt_center_mut(r) } + + /// Transform the given point by this similarity. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use std::f32; + /// # use nalgebra::{Point3, Similarity3, Vector3}; + /// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2; + /// let translation = Vector3::new(1.0, 2.0, 3.0); + /// let sim = Similarity3::new(translation, axisangle, 3.0); + /// let transformed_point = sim.transform_point(&Point3::new(4.0, 5.0, 6.0)); + /// assert_relative_eq!(transformed_point, Point3::new(19.0, 17.0, -9.0), epsilon = 1.0e-5); + /// ``` + #[inline] + pub fn transform_point(&self, pt: &Point) -> Point { + self * pt + } + + /// Transform the given vector by this similarity, ignoring the translational + /// component. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use std::f32; + /// # use nalgebra::{Similarity3, Vector3}; + /// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2; + /// let translation = Vector3::new(1.0, 2.0, 3.0); + /// let sim = Similarity3::new(translation, axisangle, 3.0); + /// let transformed_vector = sim.transform_vector(&Vector3::new(4.0, 5.0, 6.0)); + /// assert_relative_eq!(transformed_vector, Vector3::new(18.0, 15.0, -12.0), epsilon = 1.0e-5); + /// ``` + #[inline] + pub fn transform_vector(&self, v: &VectorN) -> VectorN { + self * v + } + + /// Transform the given point by the inverse of this similarity. This may + /// be cheaper than inverting the similarity and then transforming the + /// given point. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use std::f32; + /// # use nalgebra::{Point3, Similarity3, Vector3}; + /// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2; + /// let translation = Vector3::new(1.0, 2.0, 3.0); + /// let sim = Similarity3::new(translation, axisangle, 2.0); + /// let transformed_point = sim.inverse_transform_point(&Point3::new(4.0, 5.0, 6.0)); + /// assert_relative_eq!(transformed_point, Point3::new(-1.5, 1.5, 1.5), epsilon = 1.0e-5); + /// ``` + #[inline] + pub fn inverse_transform_point(&self, pt: &Point) -> Point { + self.isometry.inverse_transform_point(pt) / self.scaling() + } + + /// Transform the given vector by the inverse of this similarity, + /// ignoring the translational component. This may be cheaper than + /// inverting the similarity and then transforming the given vector. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use std::f32; + /// # use nalgebra::{Similarity3, Vector3}; + /// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2; + /// let translation = Vector3::new(1.0, 2.0, 3.0); + /// let sim = Similarity3::new(translation, axisangle, 2.0); + /// let transformed_vector = sim.inverse_transform_vector(&Vector3::new(4.0, 5.0, 6.0)); + /// assert_relative_eq!(transformed_vector, Vector3::new(-3.0, 2.5, 2.0), epsilon = 1.0e-5); + /// ``` + #[inline] + pub fn inverse_transform_vector(&self, v: &VectorN) -> VectorN { + self.isometry.inverse_transform_vector(v) / self.scaling() + } } // NOTE: we don't require `R: Rotation<...>` here because this is not useful for the implementation diff --git a/src/geometry/similarity_alga.rs b/src/geometry/similarity_alga.rs old mode 100644 new mode 100755 index e8a6b154..9b723029 --- a/src/geometry/similarity_alga.rs +++ b/src/geometry/similarity_alga.rs @@ -82,12 +82,12 @@ where { #[inline] fn transform_point(&self, pt: &Point) -> Point { - self * pt + self.transform_point(pt) } #[inline] fn transform_vector(&self, v: &VectorN) -> VectorN { - self * v + self.transform_vector(v) } } @@ -98,12 +98,12 @@ where { #[inline] fn inverse_transform_point(&self, pt: &Point) -> Point { - self.isometry.inverse_transform_point(pt) / self.scaling() + self.inverse_transform_point(pt) } #[inline] fn inverse_transform_vector(&self, v: &VectorN) -> VectorN { - self.isometry.inverse_transform_vector(v) / self.scaling() + self.inverse_transform_vector(v) } } diff --git a/src/geometry/transform.rs b/src/geometry/transform.rs old mode 100644 new mode 100755 index 0d5d9c4a..56a65992 --- a/src/geometry/transform.rs +++ b/src/geometry/transform.rs @@ -6,12 +6,14 @@ use std::marker::PhantomData; #[cfg(feature = "serde-serialize")] use serde::{Deserialize, Deserializer, Serialize, Serializer}; -use alga::general::Real; +use alga::general::{Real, TwoSidedInverse}; use base::allocator::Allocator; use base::dimension::{DimName, DimNameAdd, DimNameSum, U1}; use base::storage::Owned; -use base::{DefaultAllocator, MatrixN}; +use base::{DefaultAllocator, MatrixN, VectorN}; + +use geometry::Point; /// Trait implemented by phantom types identifying the projective transformation type. /// @@ -452,6 +454,53 @@ where DefaultAllocator: Allocator, DimNameSum> } } +impl, C> Transform +where + N: Real, + C: TCategory, + DefaultAllocator: Allocator, DimNameSum> + + Allocator> + + Allocator + + Allocator, +{ + /// Transform the given point by this transformation. + #[inline] + pub fn transform_point(&self, pt: &Point) -> Point { + self * pt + } + + /// Transform the given vector by this transformation, ignoring the + /// translational component of the transformation. + #[inline] + pub fn transform_vector(&self, v: &VectorN) -> VectorN { + self * v + } +} + +impl, C: TCategory> Transform +where C: SubTCategoryOf, + DefaultAllocator: Allocator, DimNameSum> + + Allocator> + + Allocator + + Allocator, +{ + /// Transform the given point by the inverse of this transformation. + /// This may be cheaper than inverting the transformation and transforming + /// the point. + #[inline] + pub fn inverse_transform_point(&self, pt: &Point) -> Point { + self.two_sided_inverse() * pt + } + + /// Transform the given vector by the inverse of this transformation. + /// This may be cheaper than inverting the transformation and transforming + /// the vector. + #[inline] + pub fn inverse_transform_vector(&self, v: &VectorN) -> VectorN { + self.two_sided_inverse() * v + } +} + impl> Transform where DefaultAllocator: Allocator, DimNameSum> { diff --git a/src/geometry/transform_alga.rs b/src/geometry/transform_alga.rs old mode 100644 new mode 100755 index c5ba675b..d58b1d53 --- a/src/geometry/transform_alga.rs +++ b/src/geometry/transform_alga.rs @@ -96,12 +96,12 @@ where { #[inline] fn transform_point(&self, pt: &Point) -> Point { - self * pt + self.transform_point(pt) } #[inline] fn transform_vector(&self, v: &VectorN) -> VectorN { - self * v + self.transform_vector(v) } } @@ -116,12 +116,12 @@ where { #[inline] fn inverse_transform_point(&self, pt: &Point) -> Point { - self.two_sided_inverse() * pt + self.inverse_transform_point(pt) } #[inline] fn inverse_transform_vector(&self, v: &VectorN) -> VectorN { - self.two_sided_inverse() * v + self.inverse_transform_vector(v) } } diff --git a/src/geometry/translation.rs b/src/geometry/translation.rs old mode 100644 new mode 100755 index 7b1a8957..89960961 --- a/src/geometry/translation.rs +++ b/src/geometry/translation.rs @@ -11,13 +11,15 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer}; #[cfg(feature = "abomonation-serialize")] use abomonation::Abomonation; -use alga::general::{ClosedNeg, Real}; +use alga::general::{ClosedAdd, ClosedNeg, ClosedSub, Real}; use base::allocator::Allocator; use base::dimension::{DimName, DimNameAdd, DimNameSum, U1}; use base::storage::Owned; use base::{DefaultAllocator, MatrixN, Scalar, VectorN}; +use geometry::Point; + /// A translation. #[repr(C)] #[derive(Debug)] @@ -190,6 +192,40 @@ where DefaultAllocator: Allocator } } +impl Translation +where DefaultAllocator: Allocator +{ + /// Translate the given point. + /// + /// # 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] + pub fn transform_point(&self, pt: &Point) -> Point { + pt + &self.vector + } +} + +impl Translation +where DefaultAllocator: Allocator +{ + /// 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] + pub fn inverse_transform_point(&self, pt: &Point) -> Point { + pt - &self.vector + } +} + impl Eq for Translation where DefaultAllocator: Allocator {} impl PartialEq for Translation diff --git a/src/geometry/translation_alga.rs b/src/geometry/translation_alga.rs old mode 100644 new mode 100755 index fdd24014..c6157a17 --- a/src/geometry/translation_alga.rs +++ b/src/geometry/translation_alga.rs @@ -76,7 +76,7 @@ where DefaultAllocator: Allocator { #[inline] fn transform_point(&self, pt: &Point) -> Point { - pt + &self.vector + self.transform_point(pt) } #[inline] @@ -90,7 +90,7 @@ where DefaultAllocator: Allocator { #[inline] fn inverse_transform_point(&self, pt: &Point) -> Point { - pt - &self.vector + self.inverse_transform_point(pt) } #[inline] diff --git a/src/geometry/unit_complex.rs b/src/geometry/unit_complex.rs old mode 100644 new mode 100755 index f8d94dc8..bd064ef3 --- a/src/geometry/unit_complex.rs +++ b/src/geometry/unit_complex.rs @@ -3,8 +3,8 @@ use num_complex::Complex; use std::fmt; use alga::general::Real; -use base::{Matrix2, Matrix3, Unit, Vector1}; -use geometry::Rotation2; +use base::{Matrix2, Matrix3, Unit, Vector1, Vector2}; +use geometry::{Rotation2, Point2}; /// A complex number with a norm equal to 1. pub type UnitComplex = Unit>; @@ -251,6 +251,72 @@ impl UnitComplex { pub fn to_homogeneous(&self) -> Matrix3 { self.to_rotation_matrix().to_homogeneous() } + + /// Rotate the given point by this unit complex number. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{UnitComplex, Point2}; + /// # use std::f32; + /// let rot = UnitComplex::new(f32::consts::FRAC_PI_2); + /// let transformed_point = rot.transform_point(&Point2::new(1.0, 2.0)); + /// assert_relative_eq!(transformed_point, Point2::new(-2.0, 1.0), epsilon = 1.0e-6); + /// ``` + #[inline] + pub fn transform_point(&self, pt: &Point2) -> Point2 { + self * pt + } + + /// Rotate the given vector by this unit complex number. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{UnitComplex, Vector2}; + /// # use std::f32; + /// let rot = UnitComplex::new(f32::consts::FRAC_PI_2); + /// let transformed_vector = rot.transform_vector(&Vector2::new(1.0, 2.0)); + /// assert_relative_eq!(transformed_vector, Vector2::new(-2.0, 1.0), epsilon = 1.0e-6); + /// ``` + #[inline] + pub fn transform_vector(&self, v: &Vector2) -> Vector2 { + self * v + } + + /// Rotate the given point by the inverse of this unit complex number. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{UnitComplex, Point2}; + /// # use std::f32; + /// let rot = UnitComplex::new(f32::consts::FRAC_PI_2); + /// let transformed_point = rot.inverse_transform_point(&Point2::new(1.0, 2.0)); + /// assert_relative_eq!(transformed_point, Point2::new(2.0, -1.0), epsilon = 1.0e-6); + /// ``` + #[inline] + pub fn inverse_transform_point(&self, pt: &Point2) -> Point2 { + // FIXME: would it be useful performancewise not to call inverse explicitly (i-e. implement + // the inverse transformation explicitly here) ? + self.inverse() * pt + } + + /// Rotate the given vector by the inverse of this unit complex number. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{UnitComplex, Vector2}; + /// # use std::f32; + /// let rot = UnitComplex::new(f32::consts::FRAC_PI_2); + /// let transformed_vector = rot.inverse_transform_vector(&Vector2::new(1.0, 2.0)); + /// assert_relative_eq!(transformed_vector, Vector2::new(2.0, -1.0), epsilon = 1.0e-6); + /// ``` + #[inline] + pub fn inverse_transform_vector(&self, v: &Vector2) -> Vector2 { + self.inverse() * v + } } impl fmt::Display for UnitComplex { diff --git a/src/geometry/unit_complex_alga.rs b/src/geometry/unit_complex_alga.rs old mode 100644 new mode 100755 index 21b956d9..a52ea4e8 --- a/src/geometry/unit_complex_alga.rs +++ b/src/geometry/unit_complex_alga.rs @@ -63,12 +63,12 @@ where DefaultAllocator: Allocator { #[inline] fn transform_point(&self, pt: &Point2) -> Point2 { - self * pt + self.transform_point(pt) } #[inline] fn transform_vector(&self, v: &Vector2) -> Vector2 { - self * v + self.transform_vector(v) } } @@ -77,14 +77,12 @@ where DefaultAllocator: Allocator { #[inline] fn inverse_transform_point(&self, pt: &Point2) -> Point2 { - // FIXME: would it be useful performancewise not to call inverse explicitly (i-e. implement - // the inverse transformation explicitly here) ? - self.inverse() * pt + self.inverse_transform_point(pt) } #[inline] fn inverse_transform_vector(&self, v: &Vector2) -> Vector2 { - self.inverse() * v + self.inverse_transform_vector(v) } } From a2c0a453d35827cb40e62eaa9ff49b78b3f98598 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Crozet?= Date: Fri, 15 Mar 2019 10:50:47 -0400 Subject: [PATCH 2/2] Add operator explanation to docs Co-Authored-By: tpdickso --- src/geometry/isometry.rs | 4 ++++ src/geometry/quaternion.rs | 4 ++++ src/geometry/rotation.rs | 4 ++++ src/geometry/similarity.rs | 4 ++++ src/geometry/transform.rs | 4 ++++ src/geometry/translation.rs | 2 ++ src/geometry/unit_complex.rs | 4 ++++ 7 files changed, 26 insertions(+) diff --git a/src/geometry/isometry.rs b/src/geometry/isometry.rs index 04e77b7a..9519a347 100755 --- a/src/geometry/isometry.rs +++ b/src/geometry/isometry.rs @@ -257,6 +257,8 @@ where DefaultAllocator: Allocator /// Transform the given point by this isometry. /// + /// This is the same as the multiplication `self * pt`. + /// /// # Example /// /// ``` @@ -278,6 +280,8 @@ where DefaultAllocator: Allocator /// Transform the given vector by this isometry, ignoring the translation /// component of the isometry. /// + /// This is the same as the multiplication `self * v`. + /// /// # Example /// /// ``` diff --git a/src/geometry/quaternion.rs b/src/geometry/quaternion.rs index 365e55e2..c8617f1d 100755 --- a/src/geometry/quaternion.rs +++ b/src/geometry/quaternion.rs @@ -1008,6 +1008,8 @@ impl UnitQuaternion { /// Rotate a point by this unit quaternion. /// + /// This is the same as the multiplication `self * pt`. + /// /// # Example /// /// ``` @@ -1026,6 +1028,8 @@ impl UnitQuaternion { /// Rotate a vector by this unit quaternion. /// + /// This is the same as the multiplication `self * v`. + /// /// # Example /// /// ``` diff --git a/src/geometry/rotation.rs b/src/geometry/rotation.rs index 961951f1..10348eb4 100755 --- a/src/geometry/rotation.rs +++ b/src/geometry/rotation.rs @@ -358,6 +358,8 @@ where DefaultAllocator: Allocator + Allocator { /// Rotate the given point. /// + /// This is the same as the multiplication `self * pt`. + /// /// # Example /// ``` /// # #[macro_use] extern crate approx; @@ -375,6 +377,8 @@ where DefaultAllocator: Allocator + Allocator /// Rotate the given vector. /// + /// This is the same as the multiplication `self * v`. + /// /// # Example /// ``` /// # #[macro_use] extern crate approx; diff --git a/src/geometry/similarity.rs b/src/geometry/similarity.rs index dcb0f20a..b890dc67 100755 --- a/src/geometry/similarity.rs +++ b/src/geometry/similarity.rs @@ -241,6 +241,8 @@ where /// Transform the given point by this similarity. /// + /// This is the same as the multiplication `self * pt`. + /// /// # Example /// ``` /// # #[macro_use] extern crate approx; @@ -260,6 +262,8 @@ where /// Transform the given vector by this similarity, ignoring the translational /// component. /// + /// This is the same as the multiplication `self * t`. + /// /// # Example /// ``` /// # #[macro_use] extern crate approx; diff --git a/src/geometry/transform.rs b/src/geometry/transform.rs index 56a65992..e0eb1bb9 100755 --- a/src/geometry/transform.rs +++ b/src/geometry/transform.rs @@ -464,6 +464,8 @@ where + Allocator, { /// Transform the given point by this transformation. + /// + /// This is the same as the multiplication `self * pt`. #[inline] pub fn transform_point(&self, pt: &Point) -> Point { self * pt @@ -471,6 +473,8 @@ where /// Transform the given vector by this transformation, ignoring the /// translational component of the transformation. + /// + /// This is the same as the multiplication `self * v`. #[inline] pub fn transform_vector(&self, v: &VectorN) -> VectorN { self * v diff --git a/src/geometry/translation.rs b/src/geometry/translation.rs index 89960961..a49b2706 100755 --- a/src/geometry/translation.rs +++ b/src/geometry/translation.rs @@ -197,6 +197,8 @@ where DefaultAllocator: Allocator { /// Translate the given point. /// + /// This is the same as the multiplication `self * pt`. + /// /// # Example /// ``` /// # use nalgebra::{Translation3, Point3}; diff --git a/src/geometry/unit_complex.rs b/src/geometry/unit_complex.rs index bd064ef3..6e8cf81d 100755 --- a/src/geometry/unit_complex.rs +++ b/src/geometry/unit_complex.rs @@ -254,6 +254,8 @@ impl UnitComplex { /// Rotate the given point by this unit complex number. /// + /// This is the same as the multiplication `self * pt`. + /// /// # Example /// ``` /// # #[macro_use] extern crate approx; @@ -270,6 +272,8 @@ impl UnitComplex { /// Rotate the given vector by this unit complex number. /// + /// This is the same as the multiplication `self * v`. + /// /// # Example /// ``` /// # #[macro_use] extern crate approx;