nalgebra/src/geometry/transform.rs

654 lines
21 KiB
Rust
Raw Normal View History

2018-11-08 14:51:43 +08:00
use approx::{AbsDiffEq, RelativeEq, UlpsEq};
use std::any::Any;
use std::fmt::Debug;
use std::hash;
use std::marker::PhantomData;
#[cfg(feature = "serde-serialize-no-std")]
2018-10-22 13:00:10 +08:00
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use simba::scalar::RealField;
2019-03-23 21:29:07 +08:00
use crate::base::allocator::Allocator;
use crate::base::dimension::{DimNameAdd, DimNameSum, U1};
use crate::base::storage::Owned;
2021-04-11 17:00:38 +08:00
use crate::base::{Const, DefaultAllocator, DimName, OMatrix, SVector};
use crate::geometry::Point;
/// Trait implemented by phantom types identifying the projective transformation type.
///
2018-11-08 14:51:43 +08:00
/// NOTE: this trait is not intended to be implemented outside of the `nalgebra` crate.
pub trait TCategory: Any + Debug + Copy + PartialEq + Send {
2017-02-13 01:17:09 +08:00
/// Indicates whether a `Transform` with the category `Self` has a bottom-row different from
/// `0 0 .. 1`.
#[inline]
fn has_normalizer() -> bool {
true
}
/// Checks that the given matrix is a valid homogeneous representation of an element of the
/// category `Self`.
2021-04-11 17:00:38 +08:00
fn check_homogeneous_invariants<T: RealField, D: DimName>(mat: &OMatrix<T, D, D>) -> bool
2018-02-02 19:26:35 +08:00
where
2021-04-11 17:00:38 +08:00
T::Epsilon: Copy,
DefaultAllocator: Allocator<T, D, D>;
}
2017-02-13 01:17:09 +08:00
/// Traits that gives the `Transform` category that is compatible with the result of the
/// multiplication of transformations with categories `Self` and `Other`.
pub trait TCategoryMul<Other: TCategory>: TCategory {
2017-02-13 01:17:09 +08:00
/// The transform category that results from the multiplication of a `Transform<Self>` to a
/// `Transform<Other>`. This is usually equal to `Self` or `Other`, whichever is the most
/// general category.
type Representative: TCategory;
}
2017-02-13 01:17:09 +08:00
/// Indicates that `Self` is a more general `Transform` category than `Other`.
2018-02-02 19:26:35 +08:00
pub trait SuperTCategoryOf<Other: TCategory>: TCategory {}
2017-02-13 01:17:09 +08:00
/// Indicates that `Self` is a more specific `Transform` category than `Other`.
///
/// Automatically implemented based on `SuperTCategoryOf`.
2018-02-02 19:26:35 +08:00
pub trait SubTCategoryOf<Other: TCategory>: TCategory {}
impl<T1, T2> SubTCategoryOf<T2> for T1
2018-02-02 19:26:35 +08:00
where
T1: TCategory,
T2: SuperTCategoryOf<T1>,
{
}
2017-02-13 01:17:09 +08:00
/// Tag representing the most general (not necessarily inversible) `Transform` type.
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
2018-10-22 13:00:10 +08:00
pub enum TGeneral {}
2017-02-13 01:17:09 +08:00
/// Tag representing the most general inversible `Transform` type.
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
2018-10-22 13:00:10 +08:00
pub enum TProjective {}
2017-02-13 01:17:09 +08:00
/// Tag representing an affine `Transform`. Its bottom-row is equal to `(0, 0 ... 0, 1)`.
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
2018-10-22 13:00:10 +08:00
pub enum TAffine {}
impl TCategory for TGeneral {
#[inline]
2021-04-11 17:00:38 +08:00
fn check_homogeneous_invariants<T: RealField, D: DimName>(_: &OMatrix<T, D, D>) -> bool
2018-02-02 19:26:35 +08:00
where
2021-04-11 17:00:38 +08:00
T::Epsilon: Copy,
DefaultAllocator: Allocator<T, D, D>,
2018-02-02 19:26:35 +08:00
{
true
}
}
impl TCategory for TProjective {
#[inline]
2021-04-11 17:00:38 +08:00
fn check_homogeneous_invariants<T: RealField, D: DimName>(mat: &OMatrix<T, D, D>) -> bool
2018-02-02 19:26:35 +08:00
where
2021-04-11 17:00:38 +08:00
T::Epsilon: Copy,
DefaultAllocator: Allocator<T, D, D>,
2018-02-02 19:26:35 +08:00
{
mat.is_invertible()
}
}
impl TCategory for TAffine {
#[inline]
fn has_normalizer() -> bool {
false
}
#[inline]
2021-04-11 17:00:38 +08:00
fn check_homogeneous_invariants<T: RealField, D: DimName>(mat: &OMatrix<T, D, D>) -> bool
2018-02-02 19:26:35 +08:00
where
2021-04-11 17:00:38 +08:00
T::Epsilon: Copy,
DefaultAllocator: Allocator<T, D, D>,
2018-02-02 19:26:35 +08:00
{
let last = D::dim() - 1;
2018-10-22 13:00:10 +08:00
mat.is_invertible()
2021-04-11 17:00:38 +08:00
&& mat[(last, last)] == T::one()
2018-02-02 19:26:35 +08:00
&& (0..last).all(|i| mat[(last, i)].is_zero())
}
}
macro_rules! category_mul_impl(
($($a: ident * $b: ident => $c: ty);* $(;)*) => {$(
impl TCategoryMul<$a> for $b {
type Representative = $c;
}
)*}
);
// We require stability uppon multiplication.
impl<T: TCategory> TCategoryMul<T> for T {
type Representative = T;
}
category_mul_impl!(
// TGeneral * TGeneral => TGeneral;
TGeneral * TProjective => TGeneral;
TGeneral * TAffine => TGeneral;
TProjective * TGeneral => TGeneral;
// TProjective * TProjective => TProjective;
TProjective * TAffine => TProjective;
TAffine * TGeneral => TGeneral;
TAffine * TProjective => TProjective;
// TAffine * TAffine => TAffine;
);
macro_rules! super_tcategory_impl(
($($a: ident >= $b: ident);* $(;)*) => {$(
impl SuperTCategoryOf<$b> for $a { }
)*}
);
2018-02-02 19:26:35 +08:00
impl<T: TCategory> SuperTCategoryOf<T> for T {}
super_tcategory_impl!(
TGeneral >= TProjective;
TGeneral >= TAffine;
TProjective >= TAffine;
);
/// A transformation matrix in homogeneous coordinates.
///
/// It is stored as a matrix with dimensions `(D + 1, D + 1)`, e.g., it stores a 4x4 matrix for a
/// 3D transformation.
#[repr(C)]
#[derive(Debug)]
pub struct Transform<T: RealField, C: TCategory, const D: usize>
2020-04-06 00:49:48 +08:00
where
Const<D>: DimNameAdd<U1>,
2021-04-11 17:00:38 +08:00
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>,
2018-02-02 19:26:35 +08:00
{
2021-04-11 17:00:38 +08:00
matrix: OMatrix<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>,
2018-02-02 19:26:35 +08:00
_phantom: PhantomData<C>,
}
impl<T: RealField + hash::Hash, C: TCategory, const D: usize> hash::Hash for Transform<T, C, D>
where
Const<D>: DimNameAdd<U1>,
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>,
Owned<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>: hash::Hash,
{
fn hash<H: hash::Hasher>(&self, state: &mut H) {
self.matrix.hash(state);
}
}
impl<T: RealField, C: TCategory, const D: usize> Copy for Transform<T, C, D>
2018-02-02 19:26:35 +08:00
where
Const<D>: DimNameAdd<U1>,
2021-04-11 17:00:38 +08:00
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>,
Owned<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>: Copy,
2018-11-08 14:51:43 +08:00
{
}
impl<T: RealField, C: TCategory, const D: usize> Clone for Transform<T, C, D>
2020-04-06 00:49:48 +08:00
where
Const<D>: DimNameAdd<U1>,
2021-04-11 17:00:38 +08:00
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>,
2018-02-02 19:26:35 +08:00
{
#[inline]
fn clone(&self) -> Self {
Transform::from_matrix_unchecked(self.matrix.clone())
}
}
#[cfg(feature = "bytemuck")]
unsafe impl<T, C: TCategory, const D: usize> bytemuck::Zeroable for Transform<T, C, D>
2021-07-17 12:17:56 +08:00
where
T: RealField + bytemuck::Zeroable,
2021-07-17 12:17:56 +08:00
Const<D>: DimNameAdd<U1>,
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>,
OMatrix<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>: bytemuck::Zeroable,
{
}
#[cfg(feature = "bytemuck")]
unsafe impl<T, C: TCategory, const D: usize> bytemuck::Pod for Transform<T, C, D>
where
T: RealField + bytemuck::Pod,
Const<D>: DimNameAdd<U1>,
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>,
OMatrix<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>: bytemuck::Pod,
Owned<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>: Copy,
2021-07-17 12:17:56 +08:00
{
}
#[cfg(feature = "serde-serialize-no-std")]
impl<T: RealField, C: TCategory, const D: usize> Serialize for Transform<T, C, D>
2018-02-02 19:26:35 +08:00
where
Const<D>: DimNameAdd<U1>,
2021-04-11 17:00:38 +08:00
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>,
Owned<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>: Serialize,
2018-02-02 19:26:35 +08:00
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
2020-04-06 00:49:48 +08:00
where
S: Serializer,
{
2018-02-02 19:26:35 +08:00
self.matrix.serialize(serializer)
}
}
#[cfg(feature = "serde-serialize-no-std")]
impl<'a, T: RealField, C: TCategory, const D: usize> Deserialize<'a> for Transform<T, C, D>
2018-02-02 19:26:35 +08:00
where
Const<D>: DimNameAdd<U1>,
2021-04-11 17:00:38 +08:00
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>,
Owned<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>: Deserialize<'a>,
2018-02-02 19:26:35 +08:00
{
fn deserialize<Des>(deserializer: Des) -> Result<Self, Des::Error>
2020-04-06 00:49:48 +08:00
where
Des: Deserializer<'a>,
{
2021-04-11 17:00:38 +08:00
let matrix = OMatrix::<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>::deserialize(
deserializer,
)?;
2018-02-02 19:26:35 +08:00
Ok(Transform::from_matrix_unchecked(matrix))
}
}
impl<T: RealField + Eq, C: TCategory, const D: usize> Eq for Transform<T, C, D>
where
Const<D>: DimNameAdd<U1>,
2021-04-11 17:00:38 +08:00
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>,
2020-04-06 00:49:48 +08:00
{
}
impl<T: RealField, C: TCategory, const D: usize> PartialEq for Transform<T, C, D>
2020-04-06 00:49:48 +08:00
where
Const<D>: DimNameAdd<U1>,
2021-04-11 17:00:38 +08:00
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>,
2018-02-02 19:26:35 +08:00
{
#[inline]
fn eq(&self, right: &Self) -> bool {
self.matrix == right.matrix
}
}
impl<T: RealField, C: TCategory, const D: usize> Transform<T, C, D>
2020-04-06 00:49:48 +08:00
where
Const<D>: DimNameAdd<U1>,
2021-04-11 17:00:38 +08:00
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>,
2018-02-02 19:26:35 +08:00
{
/// Creates a new transformation from the given homogeneous matrix. The transformation category
/// of `Self` is not checked to be verified by the given matrix.
#[inline]
2021-04-11 17:00:38 +08:00
pub fn from_matrix_unchecked(
matrix: OMatrix<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>,
) -> Self {
Transform {
2020-10-11 16:57:26 +08:00
matrix,
2018-02-02 19:26:35 +08:00
_phantom: PhantomData,
}
}
2018-11-08 14:51:43 +08:00
/// Retrieves the underlying matrix.
///
/// # Examples
/// ```
/// # use nalgebra::{Matrix3, Transform2};
///
/// let m = Matrix3::new(1.0, 2.0, 0.0,
/// 3.0, 4.0, 0.0,
/// 0.0, 0.0, 1.0);
/// let t = Transform2::from_matrix_unchecked(m);
/// assert_eq!(t.into_inner(), m);
2018-11-08 14:51:43 +08:00
/// ```
#[inline]
2021-04-11 17:00:38 +08:00
pub fn into_inner(self) -> OMatrix<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>> {
self.matrix
}
/// Retrieves the underlying matrix.
2021-07-28 07:18:29 +08:00
/// Deprecated: Use [`Transform::into_inner`] instead.
2020-03-21 19:16:46 +08:00
#[deprecated(note = "use `.into_inner()` instead")]
#[inline]
2021-04-11 17:00:38 +08:00
pub fn unwrap(self) -> OMatrix<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>> {
self.matrix
}
2018-09-24 12:48:42 +08:00
/// A reference to the underlying matrix.
2018-11-08 14:51:43 +08:00
///
/// # Examples
/// ```
/// # use nalgebra::{Matrix3, Transform2};
///
/// let m = Matrix3::new(1.0, 2.0, 0.0,
/// 3.0, 4.0, 0.0,
/// 0.0, 0.0, 1.0);
/// let t = Transform2::from_matrix_unchecked(m);
/// assert_eq!(*t.matrix(), m);
/// ```
#[inline]
#[must_use]
2021-04-11 17:00:38 +08:00
pub fn matrix(&self) -> &OMatrix<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>> {
&self.matrix
}
/// A mutable reference to the underlying matrix.
///
/// It is `_unchecked` because direct modifications of this matrix may break invariants
/// identified by this transformation category.
2018-11-08 14:51:43 +08:00
///
/// # Examples
/// ```
/// # use nalgebra::{Matrix3, Transform2};
///
/// let m = Matrix3::new(1.0, 2.0, 0.0,
/// 3.0, 4.0, 0.0,
/// 0.0, 0.0, 1.0);
/// let mut t = Transform2::from_matrix_unchecked(m);
/// t.matrix_mut_unchecked().m12 = 42.0;
/// t.matrix_mut_unchecked().m23 = 90.0;
///
///
/// let expected = Matrix3::new(1.0, 42.0, 0.0,
/// 3.0, 4.0, 90.0,
/// 0.0, 0.0, 1.0);
/// assert_eq!(*t.matrix(), expected);
/// ```
#[inline]
2021-04-11 17:00:38 +08:00
pub fn matrix_mut_unchecked(
&mut self,
) -> &mut OMatrix<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>> {
&mut self.matrix
}
/// Sets the category of this transform.
///
/// This can be done only if the new category is more general than the current one, e.g., a
/// transform with category `TProjective` cannot be converted to a transform with category
/// `TAffine` because not all projective transformations are affine (the other way-round is
/// valid though).
#[inline]
2021-04-11 17:00:38 +08:00
pub fn set_category<CNew: SuperTCategoryOf<C>>(self) -> Transform<T, CNew, D> {
Transform::from_matrix_unchecked(self.matrix)
}
/// Clones this transform into one that owns its data.
#[inline]
2018-11-08 14:51:43 +08:00
#[deprecated(
note = "This method is redundant with automatic `Copy` and the `.clone()` method and will be removed in a future release."
)]
pub fn clone_owned(&self) -> Transform<T, C, D> {
Transform::from_matrix_unchecked(self.matrix.clone_owned())
}
/// Converts this transform into its equivalent homogeneous transformation matrix.
2018-11-08 14:51:43 +08:00
///
/// # Examples
/// ```
/// # use nalgebra::{Matrix3, Transform2};
///
/// let m = Matrix3::new(1.0, 2.0, 0.0,
/// 3.0, 4.0, 0.0,
/// 0.0, 0.0, 1.0);
/// let t = Transform2::from_matrix_unchecked(m);
/// assert_eq!(t.into_inner(), m);
2018-11-08 14:51:43 +08:00
/// ```
#[inline]
#[must_use]
pub fn to_homogeneous(&self) -> OMatrix<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>> {
self.matrix().clone_owned()
}
/// Attempts to invert this transformation. You may use `.inverse` instead of this
2018-11-08 14:51:43 +08:00
/// transformation has a subcategory of `TProjective` (i.e. if it is a `Projective{2,3}` or `Affine{2,3}`).
///
/// # Examples
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::{Matrix3, Transform2};
///
/// let m = Matrix3::new(2.0, 2.0, -0.3,
/// 3.0, 4.0, 0.1,
/// 0.0, 0.0, 1.0);
/// let t = Transform2::from_matrix_unchecked(m);
/// let inv_t = t.try_inverse().unwrap();
/// assert_relative_eq!(t * inv_t, Transform2::identity());
/// assert_relative_eq!(inv_t * t, Transform2::identity());
///
/// // Non-invertible case.
/// let m = Matrix3::new(0.0, 2.0, 1.0,
/// 3.0, 0.0, 5.0,
/// 0.0, 0.0, 0.0);
/// let t = Transform2::from_matrix_unchecked(m);
/// assert!(t.try_inverse().is_none());
/// ```
#[inline]
#[must_use = "Did you mean to use try_inverse_mut()?"]
pub fn try_inverse(self) -> Option<Transform<T, C, D>> {
2021-06-18 15:45:37 +08:00
self.matrix
.try_inverse()
.map(Transform::from_matrix_unchecked)
}
/// Inverts this transformation. Use `.try_inverse` if this transform has the `TGeneral`
2018-11-08 14:51:43 +08:00
/// category (i.e., a `Transform{2,3}` may not be invertible).
///
/// # Examples
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::{Matrix3, Projective2};
///
/// let m = Matrix3::new(2.0, 2.0, -0.3,
/// 3.0, 4.0, 0.1,
/// 0.0, 0.0, 1.0);
/// let proj = Projective2::from_matrix_unchecked(m);
/// let inv_t = proj.inverse();
/// assert_relative_eq!(proj * inv_t, Projective2::identity());
/// assert_relative_eq!(inv_t * proj, Projective2::identity());
/// ```
#[inline]
#[must_use = "Did you mean to use inverse_mut()?"]
2021-04-11 17:00:38 +08:00
pub fn inverse(self) -> Transform<T, C, D>
2020-04-06 00:49:48 +08:00
where
C: SubTCategoryOf<TProjective>,
{
2020-11-15 23:57:49 +08:00
// TODO: specialize for TAffine?
Transform::from_matrix_unchecked(self.matrix.try_inverse().unwrap())
}
/// Attempts to invert this transformation in-place. You may use `.inverse_mut` instead of this
/// transformation has a subcategory of `TProjective`.
2018-11-08 14:51:43 +08:00
///
/// # Examples
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::{Matrix3, Transform2};
///
/// let m = Matrix3::new(2.0, 2.0, -0.3,
/// 3.0, 4.0, 0.1,
/// 0.0, 0.0, 1.0);
/// let t = Transform2::from_matrix_unchecked(m);
/// let mut inv_t = t;
/// assert!(inv_t.try_inverse_mut());
/// assert_relative_eq!(t * inv_t, Transform2::identity());
/// assert_relative_eq!(inv_t * t, Transform2::identity());
///
/// // Non-invertible case.
/// let m = Matrix3::new(0.0, 2.0, 1.0,
/// 3.0, 0.0, 5.0,
/// 0.0, 0.0, 0.0);
/// let mut t = Transform2::from_matrix_unchecked(m);
/// assert!(!t.try_inverse_mut());
/// ```
#[inline]
pub fn try_inverse_mut(&mut self) -> bool {
self.matrix.try_inverse_mut()
}
/// Inverts this transformation in-place. Use `.try_inverse_mut` if this transform has the
/// `TGeneral` category (it may not be invertible).
2018-11-08 14:51:43 +08:00
///
/// # Examples
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::{Matrix3, Projective2};
///
/// let m = Matrix3::new(2.0, 2.0, -0.3,
/// 3.0, 4.0, 0.1,
/// 0.0, 0.0, 1.0);
/// let proj = Projective2::from_matrix_unchecked(m);
/// let mut inv_t = proj;
/// inv_t.inverse_mut();
/// assert_relative_eq!(proj * inv_t, Projective2::identity());
/// assert_relative_eq!(inv_t * proj, Projective2::identity());
/// ```
#[inline]
pub fn inverse_mut(&mut self)
2020-04-06 00:49:48 +08:00
where
C: SubTCategoryOf<TProjective>,
{
let _ = self.matrix.try_inverse_mut();
}
}
2021-04-11 17:00:38 +08:00
impl<T, C, const D: usize> Transform<T, C, D>
where
2021-04-11 17:00:38 +08:00
T: RealField,
C: TCategory,
Const<D>: DimNameAdd<U1>,
2021-04-11 17:00:38 +08:00
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>
+ Allocator<T, DimNameSum<Const<D>, U1>>, // + Allocator<T, D, D>
// + Allocator<T, D>
{
/// Transform the given point by this transformation.
///
/// This is the same as the multiplication `self * pt`.
#[inline]
#[must_use]
2021-04-11 17:00:38 +08:00
pub fn transform_point(&self, pt: &Point<T, D>) -> Point<T, D> {
self * pt
}
/// Transform the given vector by this transformation, ignoring the
/// translational component of the transformation.
///
/// This is the same as the multiplication `self * v`.
#[inline]
#[must_use]
2021-04-11 17:00:38 +08:00
pub fn transform_vector(&self, v: &SVector<T, D>) -> SVector<T, D> {
self * v
}
}
2021-04-11 17:00:38 +08:00
impl<T: RealField, C: TCategory, const D: usize> Transform<T, C, D>
2020-03-21 19:16:46 +08:00
where
Const<D>: DimNameAdd<U1>,
2020-03-21 19:16:46 +08:00
C: SubTCategoryOf<TProjective>,
2021-04-11 17:00:38 +08:00
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>
+ Allocator<T, DimNameSum<Const<D>, U1>>, // + Allocator<T, D, D>
// + Allocator<T, D>
{
/// Transform the given point by the inverse of this transformation.
/// This may be cheaper than inverting the transformation and transforming
/// the point.
#[inline]
#[must_use]
2021-04-11 17:00:38 +08:00
pub fn inverse_transform_point(&self, pt: &Point<T, D>) -> Point<T, D> {
2020-03-21 19:16:46 +08:00
self.clone().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]
#[must_use]
2021-04-11 17:00:38 +08:00
pub fn inverse_transform_vector(&self, v: &SVector<T, D>) -> SVector<T, D> {
2020-03-21 19:16:46 +08:00
self.clone().inverse() * v
}
}
2021-04-11 17:00:38 +08:00
impl<T: RealField, const D: usize> Transform<T, TGeneral, D>
2020-04-06 00:49:48 +08:00
where
Const<D>: DimNameAdd<U1>,
2021-04-11 17:00:38 +08:00
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>,
2018-02-02 19:26:35 +08:00
{
/// A mutable reference to underlying matrix. Use `.matrix_mut_unchecked` instead if this
/// transformation category is not `TGeneral`.
#[inline]
2021-04-11 17:00:38 +08:00
pub fn matrix_mut(
&mut self,
) -> &mut OMatrix<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>> {
self.matrix_mut_unchecked()
}
}
2021-04-11 17:00:38 +08:00
impl<T: RealField, C: TCategory, const D: usize> AbsDiffEq for Transform<T, C, D>
2018-11-08 14:51:43 +08:00
where
Const<D>: DimNameAdd<U1>,
2021-04-11 17:00:38 +08:00
T::Epsilon: Copy,
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>,
2018-11-08 14:51:43 +08:00
{
2021-04-11 17:00:38 +08:00
type Epsilon = T::Epsilon;
2018-11-08 14:51:43 +08:00
#[inline]
fn default_epsilon() -> Self::Epsilon {
2021-04-11 17:00:38 +08:00
T::default_epsilon()
2018-11-08 14:51:43 +08:00
}
#[inline]
fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
self.matrix.abs_diff_eq(&other.matrix, epsilon)
}
}
2021-04-11 17:00:38 +08:00
impl<T: RealField, C: TCategory, const D: usize> RelativeEq for Transform<T, C, D>
2018-11-08 14:51:43 +08:00
where
Const<D>: DimNameAdd<U1>,
2021-04-11 17:00:38 +08:00
T::Epsilon: Copy,
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>,
2018-11-08 14:51:43 +08:00
{
#[inline]
fn default_max_relative() -> Self::Epsilon {
2021-04-11 17:00:38 +08:00
T::default_max_relative()
2018-11-08 14:51:43 +08:00
}
#[inline]
fn relative_eq(
&self,
other: &Self,
epsilon: Self::Epsilon,
max_relative: Self::Epsilon,
2020-04-06 00:49:48 +08:00
) -> bool {
2018-11-08 14:51:43 +08:00
self.matrix
.relative_eq(&other.matrix, epsilon, max_relative)
}
}
2021-04-11 17:00:38 +08:00
impl<T: RealField, C: TCategory, const D: usize> UlpsEq for Transform<T, C, D>
2018-11-08 14:51:43 +08:00
where
Const<D>: DimNameAdd<U1>,
2021-04-11 17:00:38 +08:00
T::Epsilon: Copy,
DefaultAllocator: Allocator<T, DimNameSum<Const<D>, U1>, DimNameSum<Const<D>, U1>>,
2018-11-08 14:51:43 +08:00
{
#[inline]
fn default_max_ulps() -> u32 {
2021-04-11 17:00:38 +08:00
T::default_max_ulps()
2018-11-08 14:51:43 +08:00
}
#[inline]
fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool {
self.matrix.ulps_eq(&other.matrix, epsilon, max_ulps)
}
}
#[cfg(test)]
mod tests {
use super::*;
2019-03-23 21:29:07 +08:00
use crate::base::Matrix4;
#[test]
fn checks_homogeneous_invariants_of_square_identity_matrix() {
2018-02-02 19:26:35 +08:00
assert!(TAffine::check_homogeneous_invariants(
&Matrix4::<f32>::identity()
));
}
}