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::fmt::Debug;
|
||||
use std::marker::PhantomData;
|
||||
|
@ -14,7 +15,7 @@ use base::{DefaultAllocator, MatrixN};
|
|||
|
||||
/// 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 {
|
||||
/// Indicates whether a `Transform` with the category `Self` has a bottom-row different from
|
||||
/// `0 0 .. 1`.
|
||||
|
@ -174,7 +175,8 @@ impl<N: Real, D: DimNameAdd<U1> + Copy, C: TCategory> Copy for Transform<N, D, C
|
|||
where
|
||||
DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>>,
|
||||
Owned<N, DimNameSum<D, U1>, DimNameSum<D, U1>>: Copy,
|
||||
{}
|
||||
{
|
||||
}
|
||||
|
||||
impl<N: Real, D: DimNameAdd<U1>, C: TCategory> Clone for Transform<N, D, C>
|
||||
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]
|
||||
pub fn unwrap(self) -> MatrixN<N, DimNameSum<D, U1>> {
|
||||
self.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]
|
||||
pub fn matrix(&self) -> &MatrixN<N, DimNameSum<D, U1>> {
|
||||
&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
|
||||
/// 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]
|
||||
pub fn matrix_mut_unchecked(&mut self) -> &mut MatrixN<N, DimNameSum<D, U1>> {
|
||||
&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.
|
||||
#[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> {
|
||||
Transform::from_matrix_unchecked(self.matrix.clone_owned())
|
||||
}
|
||||
|
||||
/// 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]
|
||||
pub fn to_homogeneous(&self) -> MatrixN<N, DimNameSum<D, U1>> {
|
||||
self.matrix().clone_owned()
|
||||
}
|
||||
|
||||
/// 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]
|
||||
pub fn try_inverse(self) -> Option<Transform<N, D, C>> {
|
||||
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`
|
||||
/// 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]
|
||||
pub fn inverse(self) -> Transform<N, D, C>
|
||||
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
|
||||
/// 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]
|
||||
pub fn try_inverse_mut(&mut self) -> bool {
|
||||
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
|
||||
/// `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]
|
||||
pub fn inverse_mut(&mut self)
|
||||
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)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
|
|
@ -2,16 +2,16 @@ use base::dimension::{U2, U3};
|
|||
|
||||
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>;
|
||||
/// 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>;
|
||||
/// A 2D affine transformation. Stored as an homogeneous 3x3 matrix.
|
||||
pub type Affine2<N> = Transform<N, U2, TAffine>;
|
||||
|
||||
/// A 3D general transformation that may not be inversible. Stored as an homogeneous 4x4 matrix.
|
||||
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>;
|
||||
/// A 3D affine transformation. Stored as an homogeneous 4x4 matrix.
|
||||
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>>
|
||||
{
|
||||
/// 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]
|
||||
pub fn identity() -> Self {
|
||||
Self::from_matrix_unchecked(MatrixN::<_, DimNameSum<D, U1>>::identity())
|
||||
|
|
Loading…
Reference in New Issue