forked from M-Labs/nalgebra
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`.
This commit is contained in:
parent
fac709b0c0
commit
2a2e9d7f8e
89
src/geometry/isometry.rs
Normal file → Executable file
89
src/geometry/isometry.rs
Normal file → Executable file
@ -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<N, D>
|
||||
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<N, D>) -> Point<N, D> {
|
||||
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<N, D>) -> VectorN<N, D> {
|
||||
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<N, D>) -> Point<N, D> {
|
||||
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<N, D>) -> VectorN<N, D> {
|
||||
self.rotation.inverse_transform_vector(v)
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: we don't require `R: Rotation<...>` here because this is not useful for the implementation
|
||||
|
9
src/geometry/isometry_alga.rs
Normal file → Executable file
9
src/geometry/isometry_alga.rs
Normal file → Executable file
@ -85,12 +85,12 @@ where
|
||||
{
|
||||
#[inline]
|
||||
fn transform_point(&self, pt: &Point<N, D>) -> Point<N, D> {
|
||||
self * pt
|
||||
self.transform_point(pt)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn transform_vector(&self, v: &VectorN<N, D>) -> VectorN<N, D> {
|
||||
self * v
|
||||
self.transform_vector(v)
|
||||
}
|
||||
}
|
||||
|
||||
@ -101,13 +101,12 @@ where
|
||||
{
|
||||
#[inline]
|
||||
fn inverse_transform_point(&self, pt: &Point<N, D>) -> Point<N, D> {
|
||||
self.rotation
|
||||
.inverse_transform_point(&(pt - &self.translation.vector))
|
||||
self.inverse_transform_point(pt)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn inverse_transform_vector(&self, v: &VectorN<N, D>) -> VectorN<N, D> {
|
||||
self.rotation.inverse_transform_vector(v)
|
||||
self.inverse_transform_vector(v)
|
||||
}
|
||||
}
|
||||
|
||||
|
80
src/geometry/quaternion.rs
Normal file → Executable file
80
src/geometry/quaternion.rs
Normal file → Executable file
@ -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<Quaternion>` for a quaternion
|
||||
/// that may be used as a rotation.
|
||||
@ -1005,6 +1005,84 @@ impl<N: Real> UnitQuaternion<N> {
|
||||
pub fn to_homogeneous(&self) -> MatrixN<N, U4> {
|
||||
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<N>) -> Point3<N> {
|
||||
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<N>) -> Vector3<N> {
|
||||
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<N>) -> Point3<N> {
|
||||
// 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<N>) -> Vector3<N> {
|
||||
self.inverse() * v
|
||||
}
|
||||
}
|
||||
|
||||
impl<N: Real + fmt::Display> fmt::Display for UnitQuaternion<N> {
|
||||
|
10
src/geometry/quaternion_alga.rs
Normal file → Executable file
10
src/geometry/quaternion_alga.rs
Normal file → Executable file
@ -197,26 +197,24 @@ impl_structures!(
|
||||
impl<N: Real> Transformation<Point3<N>> for UnitQuaternion<N> {
|
||||
#[inline]
|
||||
fn transform_point(&self, pt: &Point3<N>) -> Point3<N> {
|
||||
self * pt
|
||||
self.transform_point(pt)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn transform_vector(&self, v: &Vector3<N>) -> Vector3<N> {
|
||||
self * v
|
||||
self.transform_vector(v)
|
||||
}
|
||||
}
|
||||
|
||||
impl<N: Real> ProjectiveTransformation<Point3<N>> for UnitQuaternion<N> {
|
||||
#[inline]
|
||||
fn inverse_transform_point(&self, pt: &Point3<N>) -> Point3<N> {
|
||||
// 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<N>) -> Vector3<N> {
|
||||
self.inverse() * v
|
||||
self.inverse_transform_vector(v)
|
||||
}
|
||||
}
|
||||
|
||||
|
80
src/geometry/rotation.rs
Normal file → Executable file
80
src/geometry/rotation.rs
Normal file → Executable file
@ -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<N, D, D>
|
||||
}
|
||||
}
|
||||
|
||||
impl<N: Real, D: DimName> Rotation<N, D>
|
||||
where DefaultAllocator: Allocator<N, D, D> + Allocator<N, D>
|
||||
{
|
||||
/// 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<N, D>) -> Point<N, D> {
|
||||
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<N, D>) -> VectorN<N, D> {
|
||||
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<N, D>) -> Point<N, D> {
|
||||
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<N, D>) -> VectorN<N, D> {
|
||||
self.matrix().tr_mul(v)
|
||||
}
|
||||
}
|
||||
|
||||
impl<N: Scalar + Eq, D: DimName> Eq for Rotation<N, D> where DefaultAllocator: Allocator<N, D, D> {}
|
||||
|
||||
impl<N: Scalar + PartialEq, D: DimName> PartialEq for Rotation<N, D>
|
||||
|
8
src/geometry/rotation_alga.rs
Normal file → Executable file
8
src/geometry/rotation_alga.rs
Normal file → Executable file
@ -75,12 +75,12 @@ where DefaultAllocator: Allocator<N, D, D> + Allocator<N, D>
|
||||
{
|
||||
#[inline]
|
||||
fn transform_point(&self, pt: &Point<N, D>) -> Point<N, D> {
|
||||
self * pt
|
||||
self.transform_point(pt)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn transform_vector(&self, v: &VectorN<N, D>) -> VectorN<N, D> {
|
||||
self * v
|
||||
self.transform_vector(v)
|
||||
}
|
||||
}
|
||||
|
||||
@ -89,12 +89,12 @@ where DefaultAllocator: Allocator<N, D, D> + Allocator<N, D>
|
||||
{
|
||||
#[inline]
|
||||
fn inverse_transform_point(&self, pt: &Point<N, D>) -> Point<N, D> {
|
||||
Point::from(self.inverse_transform_vector(&pt.coords))
|
||||
self.inverse_transform_point(pt)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn inverse_transform_vector(&self, v: &VectorN<N, D>) -> VectorN<N, D> {
|
||||
self.matrix().tr_mul(v)
|
||||
self.inverse_transform_vector(v)
|
||||
}
|
||||
}
|
||||
|
||||
|
79
src/geometry/similarity.rs
Normal file → Executable file
79
src/geometry/similarity.rs
Normal file → Executable file
@ -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<N, D>) -> Point<N, D> {
|
||||
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<N, D>) -> VectorN<N, D> {
|
||||
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<N, D>) -> Point<N, D> {
|
||||
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<N, D>) -> VectorN<N, D> {
|
||||
self.isometry.inverse_transform_vector(v) / self.scaling()
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: we don't require `R: Rotation<...>` here because this is not useful for the implementation
|
||||
|
8
src/geometry/similarity_alga.rs
Normal file → Executable file
8
src/geometry/similarity_alga.rs
Normal file → Executable file
@ -82,12 +82,12 @@ where
|
||||
{
|
||||
#[inline]
|
||||
fn transform_point(&self, pt: &Point<N, D>) -> Point<N, D> {
|
||||
self * pt
|
||||
self.transform_point(pt)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn transform_vector(&self, v: &VectorN<N, D>) -> VectorN<N, D> {
|
||||
self * v
|
||||
self.transform_vector(v)
|
||||
}
|
||||
}
|
||||
|
||||
@ -98,12 +98,12 @@ where
|
||||
{
|
||||
#[inline]
|
||||
fn inverse_transform_point(&self, pt: &Point<N, D>) -> Point<N, D> {
|
||||
self.isometry.inverse_transform_point(pt) / self.scaling()
|
||||
self.inverse_transform_point(pt)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn inverse_transform_vector(&self, v: &VectorN<N, D>) -> VectorN<N, D> {
|
||||
self.isometry.inverse_transform_vector(v) / self.scaling()
|
||||
self.inverse_transform_vector(v)
|
||||
}
|
||||
}
|
||||
|
||||
|
53
src/geometry/transform.rs
Normal file → Executable file
53
src/geometry/transform.rs
Normal file → Executable file
@ -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<N, DimNameSum<D, U1>, DimNameSum<D, U1>>
|
||||
}
|
||||
}
|
||||
|
||||
impl<N, D: DimNameAdd<U1>, C> Transform<N, D, C>
|
||||
where
|
||||
N: Real,
|
||||
C: TCategory,
|
||||
DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>>
|
||||
+ Allocator<N, DimNameSum<D, U1>>
|
||||
+ Allocator<N, D, D>
|
||||
+ Allocator<N, D>,
|
||||
{
|
||||
/// Transform the given point by this transformation.
|
||||
#[inline]
|
||||
pub fn transform_point(&self, pt: &Point<N, D>) -> Point<N, D> {
|
||||
self * pt
|
||||
}
|
||||
|
||||
/// Transform the given vector by this transformation, ignoring the
|
||||
/// translational component of the transformation.
|
||||
#[inline]
|
||||
pub fn transform_vector(&self, v: &VectorN<N, D>) -> VectorN<N, D> {
|
||||
self * v
|
||||
}
|
||||
}
|
||||
|
||||
impl<N: Real, D: DimNameAdd<U1>, C: TCategory> Transform<N, D, C>
|
||||
where C: SubTCategoryOf<TProjective>,
|
||||
DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>>
|
||||
+ Allocator<N, DimNameSum<D, U1>>
|
||||
+ Allocator<N, D, D>
|
||||
+ Allocator<N, D>,
|
||||
{
|
||||
/// 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<N, D>) -> Point<N, D> {
|
||||
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<N, D>) -> VectorN<N, D> {
|
||||
self.two_sided_inverse() * v
|
||||
}
|
||||
}
|
||||
|
||||
impl<N: Real, D: DimNameAdd<U1>> Transform<N, D, TGeneral>
|
||||
where DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>>
|
||||
{
|
||||
|
8
src/geometry/transform_alga.rs
Normal file → Executable file
8
src/geometry/transform_alga.rs
Normal file → Executable file
@ -96,12 +96,12 @@ where
|
||||
{
|
||||
#[inline]
|
||||
fn transform_point(&self, pt: &Point<N, D>) -> Point<N, D> {
|
||||
self * pt
|
||||
self.transform_point(pt)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn transform_vector(&self, v: &VectorN<N, D>) -> VectorN<N, D> {
|
||||
self * v
|
||||
self.transform_vector(v)
|
||||
}
|
||||
}
|
||||
|
||||
@ -116,12 +116,12 @@ where
|
||||
{
|
||||
#[inline]
|
||||
fn inverse_transform_point(&self, pt: &Point<N, D>) -> Point<N, D> {
|
||||
self.two_sided_inverse() * pt
|
||||
self.inverse_transform_point(pt)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn inverse_transform_vector(&self, v: &VectorN<N, D>) -> VectorN<N, D> {
|
||||
self.two_sided_inverse() * v
|
||||
self.inverse_transform_vector(v)
|
||||
}
|
||||
}
|
||||
|
||||
|
38
src/geometry/translation.rs
Normal file → Executable file
38
src/geometry/translation.rs
Normal file → Executable file
@ -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<N, D>
|
||||
}
|
||||
}
|
||||
|
||||
impl<N: Scalar + ClosedAdd, D: DimName> Translation<N, D>
|
||||
where DefaultAllocator: Allocator<N, D>
|
||||
{
|
||||
/// 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<N, D>) -> Point<N, D> {
|
||||
pt + &self.vector
|
||||
}
|
||||
}
|
||||
|
||||
impl<N: Scalar + ClosedSub, D: DimName> Translation<N, D>
|
||||
where DefaultAllocator: Allocator<N, D>
|
||||
{
|
||||
/// 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<N, D>) -> Point<N, D> {
|
||||
pt - &self.vector
|
||||
}
|
||||
}
|
||||
|
||||
impl<N: Scalar + Eq, D: DimName> Eq for Translation<N, D> where DefaultAllocator: Allocator<N, D> {}
|
||||
|
||||
impl<N: Scalar + PartialEq, D: DimName> PartialEq for Translation<N, D>
|
||||
|
4
src/geometry/translation_alga.rs
Normal file → Executable file
4
src/geometry/translation_alga.rs
Normal file → Executable file
@ -76,7 +76,7 @@ where DefaultAllocator: Allocator<N, D>
|
||||
{
|
||||
#[inline]
|
||||
fn transform_point(&self, pt: &Point<N, D>) -> Point<N, D> {
|
||||
pt + &self.vector
|
||||
self.transform_point(pt)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@ -90,7 +90,7 @@ where DefaultAllocator: Allocator<N, D>
|
||||
{
|
||||
#[inline]
|
||||
fn inverse_transform_point(&self, pt: &Point<N, D>) -> Point<N, D> {
|
||||
pt - &self.vector
|
||||
self.inverse_transform_point(pt)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
70
src/geometry/unit_complex.rs
Normal file → Executable file
70
src/geometry/unit_complex.rs
Normal file → Executable file
@ -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<N> = Unit<Complex<N>>;
|
||||
@ -251,6 +251,72 @@ impl<N: Real> UnitComplex<N> {
|
||||
pub fn to_homogeneous(&self) -> Matrix3<N> {
|
||||
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<N>) -> Point2<N> {
|
||||
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<N>) -> Vector2<N> {
|
||||
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<N>) -> Point2<N> {
|
||||
// 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<N>) -> Vector2<N> {
|
||||
self.inverse() * v
|
||||
}
|
||||
}
|
||||
|
||||
impl<N: Real + fmt::Display> fmt::Display for UnitComplex<N> {
|
||||
|
10
src/geometry/unit_complex_alga.rs
Normal file → Executable file
10
src/geometry/unit_complex_alga.rs
Normal file → Executable file
@ -63,12 +63,12 @@ where DefaultAllocator: Allocator<N, U2>
|
||||
{
|
||||
#[inline]
|
||||
fn transform_point(&self, pt: &Point2<N>) -> Point2<N> {
|
||||
self * pt
|
||||
self.transform_point(pt)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn transform_vector(&self, v: &Vector2<N>) -> Vector2<N> {
|
||||
self * v
|
||||
self.transform_vector(v)
|
||||
}
|
||||
}
|
||||
|
||||
@ -77,14 +77,12 @@ where DefaultAllocator: Allocator<N, U2>
|
||||
{
|
||||
#[inline]
|
||||
fn inverse_transform_point(&self, pt: &Point2<N>) -> Point2<N> {
|
||||
// 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<N>) -> Vector2<N> {
|
||||
self.inverse() * v
|
||||
self.inverse_transform_vector(v)
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user