Add doc-tests to Transform.
This commit is contained in:
parent
b6d741c593
commit
69490c2cea
|
@ -1,3 +1,4 @@
|
||||||
|
use approx::{AbsDiffEq, RelativeEq, UlpsEq};
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
@ -14,7 +15,7 @@ use base::{DefaultAllocator, MatrixN};
|
||||||
|
|
||||||
/// Trait implemented by phantom types identifying the projective transformation type.
|
/// Trait implemented by phantom types identifying the projective transformation type.
|
||||||
///
|
///
|
||||||
/// NOTE: this trait is not intended to be implementable outside of the `nalgebra` crate.
|
/// NOTE: this trait is not intended to be implemented outside of the `nalgebra` crate.
|
||||||
pub trait TCategory: Any + Debug + Copy + PartialEq + Send {
|
pub trait TCategory: Any + Debug + Copy + PartialEq + Send {
|
||||||
/// Indicates whether a `Transform` with the category `Self` has a bottom-row different from
|
/// Indicates whether a `Transform` with the category `Self` has a bottom-row different from
|
||||||
/// `0 0 .. 1`.
|
/// `0 0 .. 1`.
|
||||||
|
@ -174,7 +175,8 @@ impl<N: Real, D: DimNameAdd<U1> + Copy, C: TCategory> Copy for Transform<N, D, C
|
||||||
where
|
where
|
||||||
DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>>,
|
DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>>,
|
||||||
Owned<N, DimNameSum<D, U1>, DimNameSum<D, U1>>: Copy,
|
Owned<N, DimNameSum<D, U1>, DimNameSum<D, U1>>: Copy,
|
||||||
{}
|
{
|
||||||
|
}
|
||||||
|
|
||||||
impl<N: Real, D: DimNameAdd<U1>, C: TCategory> Clone for Transform<N, D, C>
|
impl<N: Real, D: DimNameAdd<U1>, C: TCategory> Clone for Transform<N, D, C>
|
||||||
where DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>>
|
where DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>>
|
||||||
|
@ -236,13 +238,35 @@ where DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The underlying matrix.
|
/// 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.unwrap(), m);
|
||||||
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn unwrap(self) -> MatrixN<N, DimNameSum<D, U1>> {
|
pub fn unwrap(self) -> MatrixN<N, DimNameSum<D, U1>> {
|
||||||
self.matrix
|
self.matrix
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A reference to the underlying matrix.
|
/// A reference to 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.matrix(), m);
|
||||||
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn matrix(&self) -> &MatrixN<N, DimNameSum<D, U1>> {
|
pub fn matrix(&self) -> &MatrixN<N, DimNameSum<D, U1>> {
|
||||||
&self.matrix
|
&self.matrix
|
||||||
|
@ -252,6 +276,24 @@ where DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>>
|
||||||
///
|
///
|
||||||
/// It is `_unchecked` because direct modifications of this matrix may break invariants
|
/// It is `_unchecked` because direct modifications of this matrix may break invariants
|
||||||
/// identified by this transformation category.
|
/// identified by this transformation category.
|
||||||
|
///
|
||||||
|
/// # 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]
|
#[inline]
|
||||||
pub fn matrix_mut_unchecked(&mut self) -> &mut MatrixN<N, DimNameSum<D, U1>> {
|
pub fn matrix_mut_unchecked(&mut self) -> &mut MatrixN<N, DimNameSum<D, U1>> {
|
||||||
&mut self.matrix
|
&mut self.matrix
|
||||||
|
@ -270,19 +312,54 @@ where DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>>
|
||||||
|
|
||||||
/// Clones this transform into one that owns its data.
|
/// Clones this transform into one that owns its data.
|
||||||
#[inline]
|
#[inline]
|
||||||
#[deprecated(note = "This method is a no-op and will be removed in a future release.")]
|
#[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<N, D, C> {
|
pub fn clone_owned(&self) -> Transform<N, D, C> {
|
||||||
Transform::from_matrix_unchecked(self.matrix.clone_owned())
|
Transform::from_matrix_unchecked(self.matrix.clone_owned())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Converts this transform into its equivalent homogeneous transformation matrix.
|
/// Converts this transform into its equivalent homogeneous transformation 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.unwrap(), m);
|
||||||
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn to_homogeneous(&self) -> MatrixN<N, DimNameSum<D, U1>> {
|
pub fn to_homogeneous(&self) -> MatrixN<N, DimNameSum<D, U1>> {
|
||||||
self.matrix().clone_owned()
|
self.matrix().clone_owned()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Attempts to invert this transformation. You may use `.inverse` instead of this
|
/// Attempts to invert this transformation. You may use `.inverse` instead of this
|
||||||
/// transformation has a subcategory of `TProjective`.
|
/// 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;
|
||||||
|
/// # extern crate nalgebra;
|
||||||
|
/// # 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]
|
#[inline]
|
||||||
pub fn try_inverse(self) -> Option<Transform<N, D, C>> {
|
pub fn try_inverse(self) -> Option<Transform<N, D, C>> {
|
||||||
if let Some(m) = self.matrix.try_inverse() {
|
if let Some(m) = self.matrix.try_inverse() {
|
||||||
|
@ -293,7 +370,22 @@ where DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>>
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Inverts this transformation. Use `.try_inverse` if this transform has the `TGeneral`
|
/// Inverts this transformation. Use `.try_inverse` if this transform has the `TGeneral`
|
||||||
/// category (it may not be invertible).
|
/// category (i.e., a `Transform{2,3}` may not be invertible).
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
/// ```
|
||||||
|
/// # #[macro_use] extern crate approx;
|
||||||
|
/// # extern crate nalgebra;
|
||||||
|
/// # 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]
|
#[inline]
|
||||||
pub fn inverse(self) -> Transform<N, D, C>
|
pub fn inverse(self) -> Transform<N, D, C>
|
||||||
where C: SubTCategoryOf<TProjective> {
|
where C: SubTCategoryOf<TProjective> {
|
||||||
|
@ -303,6 +395,29 @@ where DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>>
|
||||||
|
|
||||||
/// Attempts to invert this transformation in-place. You may use `.inverse_mut` instead of this
|
/// Attempts to invert this transformation in-place. You may use `.inverse_mut` instead of this
|
||||||
/// transformation has a subcategory of `TProjective`.
|
/// transformation has a subcategory of `TProjective`.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
/// ```
|
||||||
|
/// # #[macro_use] extern crate approx;
|
||||||
|
/// # extern crate nalgebra;
|
||||||
|
/// # 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]
|
#[inline]
|
||||||
pub fn try_inverse_mut(&mut self) -> bool {
|
pub fn try_inverse_mut(&mut self) -> bool {
|
||||||
self.matrix.try_inverse_mut()
|
self.matrix.try_inverse_mut()
|
||||||
|
@ -310,6 +425,22 @@ where DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>>
|
||||||
|
|
||||||
/// Inverts this transformation in-place. Use `.try_inverse_mut` if this transform has the
|
/// Inverts this transformation in-place. Use `.try_inverse_mut` if this transform has the
|
||||||
/// `TGeneral` category (it may not be invertible).
|
/// `TGeneral` category (it may not be invertible).
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
/// ```
|
||||||
|
/// # #[macro_use] extern crate approx;
|
||||||
|
/// # extern crate nalgebra;
|
||||||
|
/// # 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]
|
#[inline]
|
||||||
pub fn inverse_mut(&mut self)
|
pub fn inverse_mut(&mut self)
|
||||||
where C: SubTCategoryOf<TProjective> {
|
where C: SubTCategoryOf<TProjective> {
|
||||||
|
@ -328,6 +459,63 @@ where DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<N: Real, D: DimNameAdd<U1>, C: TCategory> AbsDiffEq for Transform<N, D, C>
|
||||||
|
where
|
||||||
|
N::Epsilon: Copy,
|
||||||
|
DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>>,
|
||||||
|
{
|
||||||
|
type Epsilon = N::Epsilon;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn default_epsilon() -> Self::Epsilon {
|
||||||
|
N::default_epsilon()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
|
||||||
|
self.matrix.abs_diff_eq(&other.matrix, epsilon)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<N: Real, D: DimNameAdd<U1>, C: TCategory> RelativeEq for Transform<N, D, C>
|
||||||
|
where
|
||||||
|
N::Epsilon: Copy,
|
||||||
|
DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>>,
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
fn default_max_relative() -> Self::Epsilon {
|
||||||
|
N::default_max_relative()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn relative_eq(
|
||||||
|
&self,
|
||||||
|
other: &Self,
|
||||||
|
epsilon: Self::Epsilon,
|
||||||
|
max_relative: Self::Epsilon,
|
||||||
|
) -> bool
|
||||||
|
{
|
||||||
|
self.matrix
|
||||||
|
.relative_eq(&other.matrix, epsilon, max_relative)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<N: Real, D: DimNameAdd<U1>, C: TCategory> UlpsEq for Transform<N, D, C>
|
||||||
|
where
|
||||||
|
N::Epsilon: Copy,
|
||||||
|
DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>>,
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
fn default_max_ulps() -> u32 {
|
||||||
|
N::default_max_ulps()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
|
@ -2,16 +2,16 @@ use base::dimension::{U2, U3};
|
||||||
|
|
||||||
use geometry::{TAffine, TGeneral, TProjective, Transform};
|
use geometry::{TAffine, TGeneral, TProjective, Transform};
|
||||||
|
|
||||||
/// A 2D general transformation that may not be inversible. Stored as an homogeneous 3x3 matrix.
|
/// A 2D general transformation that may not be invertible. Stored as an homogeneous 3x3 matrix.
|
||||||
pub type Transform2<N> = Transform<N, U2, TGeneral>;
|
pub type Transform2<N> = Transform<N, U2, TGeneral>;
|
||||||
/// An inversible 2D general transformation. Stored as an homogeneous 3x3 matrix.
|
/// An invertible 2D general transformation. Stored as an homogeneous 3x3 matrix.
|
||||||
pub type Projective2<N> = Transform<N, U2, TProjective>;
|
pub type Projective2<N> = Transform<N, U2, TProjective>;
|
||||||
/// A 2D affine transformation. Stored as an homogeneous 3x3 matrix.
|
/// A 2D affine transformation. Stored as an homogeneous 3x3 matrix.
|
||||||
pub type Affine2<N> = Transform<N, U2, TAffine>;
|
pub type Affine2<N> = Transform<N, U2, TAffine>;
|
||||||
|
|
||||||
/// A 3D general transformation that may not be inversible. Stored as an homogeneous 4x4 matrix.
|
/// A 3D general transformation that may not be inversible. Stored as an homogeneous 4x4 matrix.
|
||||||
pub type Transform3<N> = Transform<N, U3, TGeneral>;
|
pub type Transform3<N> = Transform<N, U3, TGeneral>;
|
||||||
/// An inversible 3D general transformation. Stored as an homogeneous 4x4 matrix.
|
/// An invertible 3D general transformation. Stored as an homogeneous 4x4 matrix.
|
||||||
pub type Projective3<N> = Transform<N, U3, TProjective>;
|
pub type Projective3<N> = Transform<N, U3, TProjective>;
|
||||||
/// A 3D affine transformation. Stored as an homogeneous 4x4 matrix.
|
/// A 3D affine transformation. Stored as an homogeneous 4x4 matrix.
|
||||||
pub type Affine3<N> = Transform<N, U3, TAffine>;
|
pub type Affine3<N> = Transform<N, U3, TAffine>;
|
||||||
|
|
|
@ -12,6 +12,33 @@ impl<N: Real, D: DimNameAdd<U1>, C: TCategory> Transform<N, D, C>
|
||||||
where DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>>
|
where DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>>
|
||||||
{
|
{
|
||||||
/// Creates a new identity transform.
|
/// Creates a new identity transform.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use nalgebra::{Transform2, Projective2, Affine2, Transform3, Projective3, Affine3, Point2, Point3};
|
||||||
|
///
|
||||||
|
/// let pt = Point2::new(1.0, 2.0);
|
||||||
|
/// let t = Projective2::identity();
|
||||||
|
/// assert_eq!(t * pt, pt);
|
||||||
|
///
|
||||||
|
/// let aff = Affine2::identity();
|
||||||
|
/// assert_eq!(aff * pt, pt);
|
||||||
|
///
|
||||||
|
/// let aff = Transform2::identity();
|
||||||
|
/// assert_eq!(aff * pt, pt);
|
||||||
|
///
|
||||||
|
/// // Also works in 3D.
|
||||||
|
/// let pt = Point3::new(1.0, 2.0, 3.0);
|
||||||
|
/// let t = Projective3::identity();
|
||||||
|
/// assert_eq!(t * pt, pt);
|
||||||
|
///
|
||||||
|
/// let aff = Affine3::identity();
|
||||||
|
/// assert_eq!(aff * pt, pt);
|
||||||
|
///
|
||||||
|
/// let aff = Transform3::identity();
|
||||||
|
/// assert_eq!(aff * pt, pt);
|
||||||
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn identity() -> Self {
|
pub fn identity() -> Self {
|
||||||
Self::from_matrix_unchecked(MatrixN::<_, DimNameSum<D, U1>>::identity())
|
Self::from_matrix_unchecked(MatrixN::<_, DimNameSum<D, U1>>::identity())
|
||||||
|
|
Loading…
Reference in New Issue