Add sections to the documentations of Isometry and Point.
This commit is contained in:
parent
c0f4ee6db9
commit
cf769522f8
@ -14,14 +14,50 @@ use simba::scalar::{RealField, SubsetOf};
|
||||
use simba::simd::SimdRealField;
|
||||
|
||||
use crate::base::allocator::Allocator;
|
||||
use crate::base::dimension::{DimName, DimNameAdd, DimNameSum, U1, U2, U3};
|
||||
use crate::base::dimension::{DimName, DimNameAdd, DimNameSum, U1};
|
||||
use crate::base::storage::Owned;
|
||||
use crate::base::{DefaultAllocator, MatrixN, Scalar, Unit, VectorN};
|
||||
use crate::geometry::{
|
||||
AbstractRotation, Point, Rotation2, Rotation3, Translation, UnitComplex, UnitQuaternion,
|
||||
};
|
||||
use crate::geometry::{AbstractRotation, 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.
|
||||
/// A direct isometry, i.e., a rotation followed by a translation (aka. a rigid-body motion).
|
||||
///
|
||||
/// This is also known as an element of a Special Euclidean (SE) group.
|
||||
/// The `Isometry` type can either represent a 2D or 3D isometry.
|
||||
/// A 2D isometry is composed of:
|
||||
/// - A translation part of type [`Translation2`](crate::Translation2)
|
||||
/// - A rotation part which can either be a [`UnitComplex`](crate::UnitComplex) or a [`Rotation2`](crate::Rotation2).
|
||||
/// A 3D isometry is composed of:
|
||||
/// - A translation part of type [`Translation3`](crate::Translation3)
|
||||
/// - A rotation part which can either be a [`UnitQuaternion`](crate::UnitQuaternion) or a [`Rotation3`](crate::Rotation3).
|
||||
///
|
||||
/// The [`Isometry2`](crate::Isometry2), [`Isometry3`](crate::Isometry3), [`IsometryMatrix2`](crate::IsometryMatrix2),
|
||||
/// and [`IsometryMatrix3`](crate::IsometryMatrix3) type aliases are provided for convenience. All
|
||||
/// their available methods are listed in this page and cant be grouped as follows.
|
||||
///
|
||||
/// Note that instead of using the [`Isometry`](crate::Isometry) type in your code directly, you should use one
|
||||
/// of its aliases: [`Isometry2`](crate::Isometry2), [`Isometry3`](crate::Isometry3),
|
||||
/// [`IsometryMatrix2`](crate::IsometryMatrix2), [`IsometryMatrix3`](crate::IsometryMatrix3). Though
|
||||
/// keep in mind that all the documentation of all the methods of these aliases will also appears on
|
||||
/// this page.
|
||||
///
|
||||
/// # Construction
|
||||
/// * [From a 2D vector and/or an angle <span style="float:right;">`new`, `translation`, `rotation`…</span>](#construction-from-a-2d-vector-andor-a-rotation-angle)
|
||||
/// * [From a 3D vector and/or an axis-angle <span style="float:right;">`new`, `translation`, `rotation`…</span>](#construction-from-a-3d-vector-andor-an-axis-angle)
|
||||
/// * [From a 3D eye position and target point <span style="float:right;">`look_at`, `look_at_lh`, `face_towards`…</span>](#construction-from-a-3d-eye-position-and-target-point)
|
||||
/// * [From the translation and rotation parts <span style="float:right;">`from_parts`…</span>](#from-the-translation-and-rotation-parts)
|
||||
///
|
||||
/// # Transformation and composition
|
||||
/// Note that transforming vectors and points can be done bu multiplication, e.g., `isometry * point`.
|
||||
/// Composing an isometry with another transformation can also be done by multiplication or division.
|
||||
///
|
||||
/// * [Transformation of a vector or a point <span style="float:right;">`transform_vector`, `inverse_transform_point`…</span>](#transformation-of-a-vector-or-a-point)
|
||||
/// * [Inversion and in-place composition <span style="float:right;">`inverse`, `append_rotation_wrt_point_mut`…</span>](#inversion-and-in-place-composition)
|
||||
/// * [2D interpolation <span style="float:right;">`lerp_slerp`…</span>](#2d-interpolation)
|
||||
/// * [3D interpolation <span style="float:right;">`lerp_slerp`…</span>](#3d-interpolation)
|
||||
///
|
||||
/// # Conversion to a matrix
|
||||
/// * [Conversion to a matrix <span style="float:right;">`to_matrix`…</span>](#conversion-to-a-matrix)
|
||||
///
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
|
||||
@ -103,7 +139,7 @@ where
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// # From the translation and rotation parts
|
||||
impl<N: Scalar, D: DimName, R: AbstractRotation<N, D>> Isometry<N, D, R>
|
||||
where
|
||||
DefaultAllocator: Allocator<N, D>,
|
||||
@ -131,6 +167,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// # Inversion and in-place composition
|
||||
impl<N: SimdRealField, D: DimName, R: AbstractRotation<N, D>> Isometry<N, D, R>
|
||||
where
|
||||
N::Element: SimdRealField,
|
||||
@ -261,7 +298,14 @@ where
|
||||
pub fn append_rotation_wrt_center_mut(&mut self, r: &R) {
|
||||
self.rotation = r.clone() * self.rotation.clone();
|
||||
}
|
||||
}
|
||||
|
||||
/// # Transformation of a vector or a point
|
||||
impl<N: SimdRealField, D: DimName, R: AbstractRotation<N, D>> Isometry<N, D, R>
|
||||
where
|
||||
N::Element: SimdRealField,
|
||||
DefaultAllocator: Allocator<N, D>,
|
||||
{
|
||||
/// Transform the given point by this isometry.
|
||||
///
|
||||
/// This is the same as the multiplication `self * pt`.
|
||||
@ -377,224 +421,19 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<N: SimdRealField> Isometry<N, U3, UnitQuaternion<N>> {
|
||||
/// Interpolates between two isometries using a linear interpolation for the translation part,
|
||||
/// and a spherical interpolation for the rotation part.
|
||||
///
|
||||
/// Panics if the angle between both rotations is 180 degrees (in which case the interpolation
|
||||
/// is not well-defined). Use `.try_lerp_slerp` instead to avoid the panic.
|
||||
///
|
||||
/// # Examples:
|
||||
///
|
||||
/// ```
|
||||
/// # use nalgebra::{Vector3, Translation3, Isometry3, UnitQuaternion};
|
||||
///
|
||||
/// let t1 = Translation3::new(1.0, 2.0, 3.0);
|
||||
/// let t2 = Translation3::new(4.0, 8.0, 12.0);
|
||||
/// let q1 = UnitQuaternion::from_euler_angles(std::f32::consts::FRAC_PI_4, 0.0, 0.0);
|
||||
/// let q2 = UnitQuaternion::from_euler_angles(-std::f32::consts::PI, 0.0, 0.0);
|
||||
/// let iso1 = Isometry3::from_parts(t1, q1);
|
||||
/// let iso2 = Isometry3::from_parts(t2, q2);
|
||||
///
|
||||
/// let iso3 = iso1.lerp_slerp(&iso2, 1.0 / 3.0);
|
||||
///
|
||||
/// assert_eq!(iso3.translation.vector, Vector3::new(2.0, 4.0, 6.0));
|
||||
/// assert_eq!(iso3.rotation.euler_angles(), (std::f32::consts::FRAC_PI_2, 0.0, 0.0));
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn lerp_slerp(&self, other: &Self, t: N) -> Self
|
||||
where
|
||||
N: RealField,
|
||||
{
|
||||
let tr = self.translation.vector.lerp(&other.translation.vector, t);
|
||||
let rot = self.rotation.slerp(&other.rotation, t);
|
||||
Self::from_parts(tr.into(), rot)
|
||||
}
|
||||
|
||||
/// Attempts to interpolate between two isometries using a linear interpolation for the translation part,
|
||||
/// and a spherical interpolation for the rotation part.
|
||||
///
|
||||
/// Retuns `None` if the angle between both rotations is 180 degrees (in which case the interpolation
|
||||
/// is not well-defined).
|
||||
///
|
||||
/// # Examples:
|
||||
///
|
||||
/// ```
|
||||
/// # use nalgebra::{Vector3, Translation3, Isometry3, UnitQuaternion};
|
||||
///
|
||||
/// let t1 = Translation3::new(1.0, 2.0, 3.0);
|
||||
/// let t2 = Translation3::new(4.0, 8.0, 12.0);
|
||||
/// let q1 = UnitQuaternion::from_euler_angles(std::f32::consts::FRAC_PI_4, 0.0, 0.0);
|
||||
/// let q2 = UnitQuaternion::from_euler_angles(-std::f32::consts::PI, 0.0, 0.0);
|
||||
/// let iso1 = Isometry3::from_parts(t1, q1);
|
||||
/// let iso2 = Isometry3::from_parts(t2, q2);
|
||||
///
|
||||
/// let iso3 = iso1.lerp_slerp(&iso2, 1.0 / 3.0);
|
||||
///
|
||||
/// assert_eq!(iso3.translation.vector, Vector3::new(2.0, 4.0, 6.0));
|
||||
/// assert_eq!(iso3.rotation.euler_angles(), (std::f32::consts::FRAC_PI_2, 0.0, 0.0));
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn try_lerp_slerp(&self, other: &Self, t: N, epsilon: N) -> Option<Self>
|
||||
where
|
||||
N: RealField,
|
||||
{
|
||||
let tr = self.translation.vector.lerp(&other.translation.vector, t);
|
||||
let rot = self.rotation.try_slerp(&other.rotation, t, epsilon)?;
|
||||
Some(Self::from_parts(tr.into(), rot))
|
||||
}
|
||||
}
|
||||
|
||||
impl<N: SimdRealField> Isometry<N, U3, Rotation3<N>> {
|
||||
/// Interpolates between two isometries using a linear interpolation for the translation part,
|
||||
/// and a spherical interpolation for the rotation part.
|
||||
///
|
||||
/// Panics if the angle between both rotations is 180 degrees (in which case the interpolation
|
||||
/// is not well-defined). Use `.try_lerp_slerp` instead to avoid the panic.
|
||||
///
|
||||
/// # Examples:
|
||||
///
|
||||
/// ```
|
||||
/// # use nalgebra::{Vector3, Translation3, Rotation3, IsometryMatrix3};
|
||||
///
|
||||
/// let t1 = Translation3::new(1.0, 2.0, 3.0);
|
||||
/// let t2 = Translation3::new(4.0, 8.0, 12.0);
|
||||
/// let q1 = Rotation3::from_euler_angles(std::f32::consts::FRAC_PI_4, 0.0, 0.0);
|
||||
/// let q2 = Rotation3::from_euler_angles(-std::f32::consts::PI, 0.0, 0.0);
|
||||
/// let iso1 = IsometryMatrix3::from_parts(t1, q1);
|
||||
/// let iso2 = IsometryMatrix3::from_parts(t2, q2);
|
||||
///
|
||||
/// let iso3 = iso1.lerp_slerp(&iso2, 1.0 / 3.0);
|
||||
///
|
||||
/// assert_eq!(iso3.translation.vector, Vector3::new(2.0, 4.0, 6.0));
|
||||
/// assert_eq!(iso3.rotation.euler_angles(), (std::f32::consts::FRAC_PI_2, 0.0, 0.0));
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn lerp_slerp(&self, other: &Self, t: N) -> Self
|
||||
where
|
||||
N: RealField,
|
||||
{
|
||||
let tr = self.translation.vector.lerp(&other.translation.vector, t);
|
||||
let rot = self.rotation.slerp(&other.rotation, t);
|
||||
Self::from_parts(tr.into(), rot)
|
||||
}
|
||||
|
||||
/// Attempts to interpolate between two isometries using a linear interpolation for the translation part,
|
||||
/// and a spherical interpolation for the rotation part.
|
||||
///
|
||||
/// Retuns `None` if the angle between both rotations is 180 degrees (in which case the interpolation
|
||||
/// is not well-defined).
|
||||
///
|
||||
/// # Examples:
|
||||
///
|
||||
/// ```
|
||||
/// # use nalgebra::{Vector3, Translation3, Rotation3, IsometryMatrix3};
|
||||
///
|
||||
/// let t1 = Translation3::new(1.0, 2.0, 3.0);
|
||||
/// let t2 = Translation3::new(4.0, 8.0, 12.0);
|
||||
/// let q1 = Rotation3::from_euler_angles(std::f32::consts::FRAC_PI_4, 0.0, 0.0);
|
||||
/// let q2 = Rotation3::from_euler_angles(-std::f32::consts::PI, 0.0, 0.0);
|
||||
/// let iso1 = IsometryMatrix3::from_parts(t1, q1);
|
||||
/// let iso2 = IsometryMatrix3::from_parts(t2, q2);
|
||||
///
|
||||
/// let iso3 = iso1.lerp_slerp(&iso2, 1.0 / 3.0);
|
||||
///
|
||||
/// assert_eq!(iso3.translation.vector, Vector3::new(2.0, 4.0, 6.0));
|
||||
/// assert_eq!(iso3.rotation.euler_angles(), (std::f32::consts::FRAC_PI_2, 0.0, 0.0));
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn try_lerp_slerp(&self, other: &Self, t: N, epsilon: N) -> Option<Self>
|
||||
where
|
||||
N: RealField,
|
||||
{
|
||||
let tr = self.translation.vector.lerp(&other.translation.vector, t);
|
||||
let rot = self.rotation.try_slerp(&other.rotation, t, epsilon)?;
|
||||
Some(Self::from_parts(tr.into(), rot))
|
||||
}
|
||||
}
|
||||
|
||||
impl<N: SimdRealField> Isometry<N, U2, UnitComplex<N>> {
|
||||
/// Interpolates between two isometries using a linear interpolation for the translation part,
|
||||
/// and a spherical interpolation for the rotation part.
|
||||
///
|
||||
/// Panics if the angle between both rotations is 180 degrees (in which case the interpolation
|
||||
/// is not well-defined). Use `.try_lerp_slerp` instead to avoid the panic.
|
||||
///
|
||||
/// # Examples:
|
||||
///
|
||||
/// ```
|
||||
/// # #[macro_use] extern crate approx;
|
||||
/// # use nalgebra::{Vector2, Translation2, UnitComplex, Isometry2};
|
||||
///
|
||||
/// let t1 = Translation2::new(1.0, 2.0);
|
||||
/// let t2 = Translation2::new(4.0, 8.0);
|
||||
/// let q1 = UnitComplex::new(std::f32::consts::FRAC_PI_4);
|
||||
/// let q2 = UnitComplex::new(-std::f32::consts::PI);
|
||||
/// let iso1 = Isometry2::from_parts(t1, q1);
|
||||
/// let iso2 = Isometry2::from_parts(t2, q2);
|
||||
///
|
||||
/// let iso3 = iso1.lerp_slerp(&iso2, 1.0 / 3.0);
|
||||
///
|
||||
/// assert_eq!(iso3.translation.vector, Vector2::new(2.0, 4.0));
|
||||
/// assert_relative_eq!(iso3.rotation.angle(), std::f32::consts::FRAC_PI_2);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn lerp_slerp(&self, other: &Self, t: N) -> Self
|
||||
where
|
||||
N: RealField,
|
||||
{
|
||||
let tr = self.translation.vector.lerp(&other.translation.vector, t);
|
||||
let rot = self.rotation.slerp(&other.rotation, t);
|
||||
Self::from_parts(tr.into(), rot)
|
||||
}
|
||||
}
|
||||
|
||||
impl<N: SimdRealField> Isometry<N, U2, Rotation2<N>> {
|
||||
/// Interpolates between two isometries using a linear interpolation for the translation part,
|
||||
/// and a spherical interpolation for the rotation part.
|
||||
///
|
||||
/// Panics if the angle between both rotations is 180 degrees (in which case the interpolation
|
||||
/// is not well-defined). Use `.try_lerp_slerp` instead to avoid the panic.
|
||||
///
|
||||
/// # Examples:
|
||||
///
|
||||
/// ```
|
||||
/// # #[macro_use] extern crate approx;
|
||||
/// # use nalgebra::{Vector2, Translation2, Rotation2, IsometryMatrix2};
|
||||
///
|
||||
/// let t1 = Translation2::new(1.0, 2.0);
|
||||
/// let t2 = Translation2::new(4.0, 8.0);
|
||||
/// let q1 = Rotation2::new(std::f32::consts::FRAC_PI_4);
|
||||
/// let q2 = Rotation2::new(-std::f32::consts::PI);
|
||||
/// let iso1 = IsometryMatrix2::from_parts(t1, q1);
|
||||
/// let iso2 = IsometryMatrix2::from_parts(t2, q2);
|
||||
///
|
||||
/// let iso3 = iso1.lerp_slerp(&iso2, 1.0 / 3.0);
|
||||
///
|
||||
/// assert_eq!(iso3.translation.vector, Vector2::new(2.0, 4.0));
|
||||
/// assert_relative_eq!(iso3.rotation.angle(), std::f32::consts::FRAC_PI_2);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn lerp_slerp(&self, other: &Self, t: N) -> Self
|
||||
where
|
||||
N: RealField,
|
||||
{
|
||||
let tr = self.translation.vector.lerp(&other.translation.vector, t);
|
||||
let rot = self.rotation.slerp(&other.rotation, t);
|
||||
Self::from_parts(tr.into(), rot)
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: we don't require `R: Rotation<...>` here because this is not useful for the implementation
|
||||
// and makes it hard to use it, e.g., for Transform × Isometry implementation.
|
||||
// This is OK since all constructors of the isometry enforce the Rotation bound already (and
|
||||
// explicit struct construction is prevented by the dummy ZST field).
|
||||
/// # Conversion to a matrix
|
||||
impl<N: SimdRealField, D: DimName, R> Isometry<N, D, R>
|
||||
where
|
||||
DefaultAllocator: Allocator<N, D>,
|
||||
{
|
||||
/// Converts this isometry into its equivalent homogeneous transformation matrix.
|
||||
///
|
||||
/// This is the same as `self.to_matrix()`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
@ -621,6 +460,33 @@ where
|
||||
|
||||
res
|
||||
}
|
||||
|
||||
/// Converts this isometry into its equivalent homogeneous transformation matrix.
|
||||
///
|
||||
/// This is the same as `self.to_homogeneous()`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # #[macro_use] extern crate approx;
|
||||
/// # use std::f32;
|
||||
/// # use nalgebra::{Isometry2, Vector2, Matrix3};
|
||||
/// let iso = Isometry2::new(Vector2::new(10.0, 20.0), f32::consts::FRAC_PI_6);
|
||||
/// let expected = Matrix3::new(0.8660254, -0.5, 10.0,
|
||||
/// 0.5, 0.8660254, 20.0,
|
||||
/// 0.0, 0.0, 1.0);
|
||||
///
|
||||
/// assert_relative_eq!(iso.to_matrix(), expected, epsilon = 1.0e-6);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn to_matrix(&self) -> MatrixN<N, DimNameSum<D, U1>>
|
||||
where
|
||||
D: DimNameAdd<U1>,
|
||||
R: SubsetOf<MatrixN<N, DimNameSum<D, U1>>>,
|
||||
DefaultAllocator: Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>>,
|
||||
{
|
||||
self.to_homogeneous()
|
||||
}
|
||||
}
|
||||
|
||||
impl<N: SimdRealField, D: DimName, R> Eq for Isometry<N, D, R>
|
||||
|
@ -11,12 +11,13 @@ use simba::scalar::RealField;
|
||||
use simba::simd::SimdRealField;
|
||||
|
||||
use crate::base::allocator::Allocator;
|
||||
use crate::base::dimension::{DimName, U2, U3};
|
||||
use crate::base::dimension::{DimName, U2};
|
||||
use crate::base::{DefaultAllocator, Vector2, Vector3};
|
||||
|
||||
use crate::geometry::{
|
||||
AbstractRotation, Isometry, Point, Point3, Rotation, Rotation2, Rotation3, Translation,
|
||||
Translation2, Translation3, UnitComplex, UnitQuaternion,
|
||||
AbstractRotation, Isometry, Isometry2, Isometry3, IsometryMatrix2, IsometryMatrix3, Point,
|
||||
Point3, Rotation, Rotation3, Translation, Translation2, Translation3, UnitComplex,
|
||||
UnitQuaternion,
|
||||
};
|
||||
|
||||
impl<N: SimdRealField, D: DimName, R: AbstractRotation<N, D>> Isometry<N, D, R>
|
||||
@ -112,8 +113,8 @@ where
|
||||
*
|
||||
*/
|
||||
|
||||
// 2D rotation.
|
||||
impl<N: SimdRealField> Isometry<N, U2, Rotation2<N>>
|
||||
/// # Construction from a 2D vector and/or a rotation angle
|
||||
impl<N: SimdRealField> IsometryMatrix2<N>
|
||||
where
|
||||
N::Element: SimdRealField,
|
||||
{
|
||||
@ -151,7 +152,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<N: SimdRealField> Isometry<N, U2, UnitComplex<N>>
|
||||
impl<N: SimdRealField> Isometry2<N>
|
||||
where
|
||||
N::Element: SimdRealField,
|
||||
{
|
||||
@ -190,191 +191,219 @@ where
|
||||
}
|
||||
|
||||
// 3D rotation.
|
||||
macro_rules! isometry_construction_impl(
|
||||
($RotId: ident < $($RotParams: ident),*>, $RRDim: ty, $RCDim: ty) => {
|
||||
impl<N: SimdRealField> Isometry<N, U3, $RotId<$($RotParams),*>>
|
||||
where N::Element: SimdRealField {
|
||||
/// Creates a new isometry from a translation and a rotation axis-angle.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # #[macro_use] extern crate approx;
|
||||
/// # use std::f32;
|
||||
/// # use nalgebra::{Isometry3, IsometryMatrix3, Point3, Vector3};
|
||||
/// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2;
|
||||
/// let translation = Vector3::new(1.0, 2.0, 3.0);
|
||||
/// // Point and vector being transformed in the tests.
|
||||
/// let pt = Point3::new(4.0, 5.0, 6.0);
|
||||
/// let vec = Vector3::new(4.0, 5.0, 6.0);
|
||||
///
|
||||
/// // Isometry with its rotation part represented as a UnitQuaternion
|
||||
/// let iso = Isometry3::new(translation, axisangle);
|
||||
/// assert_relative_eq!(iso * pt, Point3::new(7.0, 7.0, -1.0), epsilon = 1.0e-6);
|
||||
/// assert_relative_eq!(iso * vec, Vector3::new(6.0, 5.0, -4.0), epsilon = 1.0e-6);
|
||||
///
|
||||
/// // Isometry with its rotation part represented as a Rotation3 (a 3x3 rotation matrix).
|
||||
/// let iso = IsometryMatrix3::new(translation, axisangle);
|
||||
/// assert_relative_eq!(iso * pt, Point3::new(7.0, 7.0, -1.0), epsilon = 1.0e-6);
|
||||
/// assert_relative_eq!(iso * vec, Vector3::new(6.0, 5.0, -4.0), epsilon = 1.0e-6);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn new(translation: Vector3<N>, axisangle: Vector3<N>) -> Self {
|
||||
Self::from_parts(
|
||||
Translation::from(translation),
|
||||
$RotId::<$($RotParams),*>::from_scaled_axis(axisangle))
|
||||
}
|
||||
macro_rules! basic_isometry_construction_impl(
|
||||
($RotId: ident < $($RotParams: ident),*>) => {
|
||||
/// Creates a new isometry from a translation and a rotation axis-angle.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # #[macro_use] extern crate approx;
|
||||
/// # use std::f32;
|
||||
/// # use nalgebra::{Isometry3, IsometryMatrix3, Point3, Vector3};
|
||||
/// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2;
|
||||
/// let translation = Vector3::new(1.0, 2.0, 3.0);
|
||||
/// // Point and vector being transformed in the tests.
|
||||
/// let pt = Point3::new(4.0, 5.0, 6.0);
|
||||
/// let vec = Vector3::new(4.0, 5.0, 6.0);
|
||||
///
|
||||
/// // Isometry with its rotation part represented as a UnitQuaternion
|
||||
/// let iso = Isometry3::new(translation, axisangle);
|
||||
/// assert_relative_eq!(iso * pt, Point3::new(7.0, 7.0, -1.0), epsilon = 1.0e-6);
|
||||
/// assert_relative_eq!(iso * vec, Vector3::new(6.0, 5.0, -4.0), epsilon = 1.0e-6);
|
||||
///
|
||||
/// // Isometry with its rotation part represented as a Rotation3 (a 3x3 rotation matrix).
|
||||
/// let iso = IsometryMatrix3::new(translation, axisangle);
|
||||
/// assert_relative_eq!(iso * pt, Point3::new(7.0, 7.0, -1.0), epsilon = 1.0e-6);
|
||||
/// assert_relative_eq!(iso * vec, Vector3::new(6.0, 5.0, -4.0), epsilon = 1.0e-6);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn new(translation: Vector3<N>, axisangle: Vector3<N>) -> Self {
|
||||
Self::from_parts(
|
||||
Translation::from(translation),
|
||||
$RotId::<$($RotParams),*>::from_scaled_axis(axisangle))
|
||||
}
|
||||
|
||||
/// Creates a new isometry from the given translation coordinates.
|
||||
#[inline]
|
||||
pub fn translation(x: N, y: N, z: N) -> Self {
|
||||
Self::from_parts(Translation3::new(x, y, z), $RotId::identity())
|
||||
}
|
||||
/// Creates a new isometry from the given translation coordinates.
|
||||
#[inline]
|
||||
pub fn translation(x: N, y: N, z: N) -> Self {
|
||||
Self::from_parts(Translation3::new(x, y, z), $RotId::identity())
|
||||
}
|
||||
|
||||
/// Creates a new isometry from the given rotation angle.
|
||||
#[inline]
|
||||
pub fn rotation(axisangle: Vector3<N>) -> Self {
|
||||
Self::new(Vector3::zeros(), axisangle)
|
||||
}
|
||||
|
||||
/// Creates an isometry that corresponds to the local frame of an observer standing at the
|
||||
/// point `eye` and looking toward `target`.
|
||||
///
|
||||
/// It maps the `z` axis to the view direction `target - eye`and the origin to the `eye`.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * eye - The observer position.
|
||||
/// * target - The target position.
|
||||
/// * up - Vertical direction. The only requirement of this parameter is to not be collinear
|
||||
/// to `eye - at`. Non-collinearity is not checked.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # #[macro_use] extern crate approx;
|
||||
/// # use std::f32;
|
||||
/// # use nalgebra::{Isometry3, IsometryMatrix3, Point3, Vector3};
|
||||
/// let eye = Point3::new(1.0, 2.0, 3.0);
|
||||
/// let target = Point3::new(2.0, 2.0, 3.0);
|
||||
/// let up = Vector3::y();
|
||||
///
|
||||
/// // Isometry with its rotation part represented as a UnitQuaternion
|
||||
/// let iso = Isometry3::face_towards(&eye, &target, &up);
|
||||
/// assert_eq!(iso * Point3::origin(), eye);
|
||||
/// assert_relative_eq!(iso * Vector3::z(), Vector3::x());
|
||||
///
|
||||
/// // Isometry with its rotation part represented as Rotation3 (a 3x3 rotation matrix).
|
||||
/// let iso = IsometryMatrix3::face_towards(&eye, &target, &up);
|
||||
/// assert_eq!(iso * Point3::origin(), eye);
|
||||
/// assert_relative_eq!(iso * Vector3::z(), Vector3::x());
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn face_towards(eye: &Point3<N>,
|
||||
target: &Point3<N>,
|
||||
up: &Vector3<N>)
|
||||
-> Self {
|
||||
Self::from_parts(
|
||||
Translation::from(eye.coords.clone()),
|
||||
$RotId::face_towards(&(target - eye), up))
|
||||
}
|
||||
|
||||
/// Deprecated: Use [Isometry::face_towards] instead.
|
||||
#[deprecated(note="renamed to `face_towards`")]
|
||||
pub fn new_observer_frame(eye: &Point3<N>,
|
||||
target: &Point3<N>,
|
||||
up: &Vector3<N>)
|
||||
-> Self {
|
||||
Self::face_towards(eye, target, up)
|
||||
}
|
||||
|
||||
/// Builds a right-handed look-at view matrix.
|
||||
///
|
||||
/// It maps the view direction `target - eye` to the **negative** `z` axis to and the `eye` to the origin.
|
||||
/// This conforms to the common notion of right handed camera look-at **view matrix** from
|
||||
/// the computer graphics community, i.e. the camera is assumed to look toward its local `-z` axis.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * eye - The eye position.
|
||||
/// * target - The target position.
|
||||
/// * up - A vector approximately aligned with required the vertical axis. The only
|
||||
/// requirement of this parameter is to not be collinear to `target - eye`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # #[macro_use] extern crate approx;
|
||||
/// # use std::f32;
|
||||
/// # use nalgebra::{Isometry3, IsometryMatrix3, Point3, Vector3};
|
||||
/// let eye = Point3::new(1.0, 2.0, 3.0);
|
||||
/// let target = Point3::new(2.0, 2.0, 3.0);
|
||||
/// let up = Vector3::y();
|
||||
///
|
||||
/// // Isometry with its rotation part represented as a UnitQuaternion
|
||||
/// let iso = Isometry3::look_at_rh(&eye, &target, &up);
|
||||
/// assert_eq!(iso * eye, Point3::origin());
|
||||
/// assert_relative_eq!(iso * Vector3::x(), -Vector3::z());
|
||||
///
|
||||
/// // Isometry with its rotation part represented as Rotation3 (a 3x3 rotation matrix).
|
||||
/// let iso = IsometryMatrix3::look_at_rh(&eye, &target, &up);
|
||||
/// assert_eq!(iso * eye, Point3::origin());
|
||||
/// assert_relative_eq!(iso * Vector3::x(), -Vector3::z());
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn look_at_rh(eye: &Point3<N>,
|
||||
target: &Point3<N>,
|
||||
up: &Vector3<N>)
|
||||
-> Self {
|
||||
let rotation = $RotId::look_at_rh(&(target - eye), up);
|
||||
let trans = &rotation * (-eye);
|
||||
|
||||
Self::from_parts(Translation::from(trans.coords), rotation)
|
||||
}
|
||||
|
||||
/// Builds a left-handed look-at view matrix.
|
||||
///
|
||||
/// It maps the view direction `target - eye` to the **positive** `z` axis and the `eye` to the origin.
|
||||
/// This conforms to the common notion of right handed camera look-at **view matrix** from
|
||||
/// the computer graphics community, i.e. the camera is assumed to look toward its local `z` axis.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * eye - The eye position.
|
||||
/// * target - The target position.
|
||||
/// * up - A vector approximately aligned with required the vertical axis. The only
|
||||
/// requirement of this parameter is to not be collinear to `target - eye`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # #[macro_use] extern crate approx;
|
||||
/// # use std::f32;
|
||||
/// # use nalgebra::{Isometry3, IsometryMatrix3, Point3, Vector3};
|
||||
/// let eye = Point3::new(1.0, 2.0, 3.0);
|
||||
/// let target = Point3::new(2.0, 2.0, 3.0);
|
||||
/// let up = Vector3::y();
|
||||
///
|
||||
/// // Isometry with its rotation part represented as a UnitQuaternion
|
||||
/// let iso = Isometry3::look_at_lh(&eye, &target, &up);
|
||||
/// assert_eq!(iso * eye, Point3::origin());
|
||||
/// assert_relative_eq!(iso * Vector3::x(), Vector3::z());
|
||||
///
|
||||
/// // Isometry with its rotation part represented as Rotation3 (a 3x3 rotation matrix).
|
||||
/// let iso = IsometryMatrix3::look_at_lh(&eye, &target, &up);
|
||||
/// assert_eq!(iso * eye, Point3::origin());
|
||||
/// assert_relative_eq!(iso * Vector3::x(), Vector3::z());
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn look_at_lh(eye: &Point3<N>,
|
||||
target: &Point3<N>,
|
||||
up: &Vector3<N>)
|
||||
-> Self {
|
||||
let rotation = $RotId::look_at_lh(&(target - eye), up);
|
||||
let trans = &rotation * (-eye);
|
||||
|
||||
Self::from_parts(Translation::from(trans.coords), rotation)
|
||||
}
|
||||
/// Creates a new isometry from the given rotation angle.
|
||||
#[inline]
|
||||
pub fn rotation(axisangle: Vector3<N>) -> Self {
|
||||
Self::new(Vector3::zeros(), axisangle)
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
isometry_construction_impl!(Rotation3<N>, U3, U3);
|
||||
isometry_construction_impl!(UnitQuaternion<N>, U4, U1);
|
||||
macro_rules! look_at_isometry_construction_impl(
|
||||
($RotId: ident < $($RotParams: ident),*>) => {
|
||||
/// Creates an isometry that corresponds to the local frame of an observer standing at the
|
||||
/// point `eye` and looking toward `target`.
|
||||
///
|
||||
/// It maps the `z` axis to the view direction `target - eye`and the origin to the `eye`.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * eye - The observer position.
|
||||
/// * target - The target position.
|
||||
/// * up - Vertical direction. The only requirement of this parameter is to not be collinear
|
||||
/// to `eye - at`. Non-collinearity is not checked.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # #[macro_use] extern crate approx;
|
||||
/// # use std::f32;
|
||||
/// # use nalgebra::{Isometry3, IsometryMatrix3, Point3, Vector3};
|
||||
/// let eye = Point3::new(1.0, 2.0, 3.0);
|
||||
/// let target = Point3::new(2.0, 2.0, 3.0);
|
||||
/// let up = Vector3::y();
|
||||
///
|
||||
/// // Isometry with its rotation part represented as a UnitQuaternion
|
||||
/// let iso = Isometry3::face_towards(&eye, &target, &up);
|
||||
/// assert_eq!(iso * Point3::origin(), eye);
|
||||
/// assert_relative_eq!(iso * Vector3::z(), Vector3::x());
|
||||
///
|
||||
/// // Isometry with its rotation part represented as Rotation3 (a 3x3 rotation matrix).
|
||||
/// let iso = IsometryMatrix3::face_towards(&eye, &target, &up);
|
||||
/// assert_eq!(iso * Point3::origin(), eye);
|
||||
/// assert_relative_eq!(iso * Vector3::z(), Vector3::x());
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn face_towards(eye: &Point3<N>,
|
||||
target: &Point3<N>,
|
||||
up: &Vector3<N>)
|
||||
-> Self {
|
||||
Self::from_parts(
|
||||
Translation::from(eye.coords.clone()),
|
||||
$RotId::face_towards(&(target - eye), up))
|
||||
}
|
||||
|
||||
/// Deprecated: Use [Isometry::face_towards] instead.
|
||||
#[deprecated(note="renamed to `face_towards`")]
|
||||
pub fn new_observer_frame(eye: &Point3<N>,
|
||||
target: &Point3<N>,
|
||||
up: &Vector3<N>)
|
||||
-> Self {
|
||||
Self::face_towards(eye, target, up)
|
||||
}
|
||||
|
||||
/// Builds a right-handed look-at view matrix.
|
||||
///
|
||||
/// It maps the view direction `target - eye` to the **negative** `z` axis to and the `eye` to the origin.
|
||||
/// This conforms to the common notion of right handed camera look-at **view matrix** from
|
||||
/// the computer graphics community, i.e. the camera is assumed to look toward its local `-z` axis.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * eye - The eye position.
|
||||
/// * target - The target position.
|
||||
/// * up - A vector approximately aligned with required the vertical axis. The only
|
||||
/// requirement of this parameter is to not be collinear to `target - eye`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # #[macro_use] extern crate approx;
|
||||
/// # use std::f32;
|
||||
/// # use nalgebra::{Isometry3, IsometryMatrix3, Point3, Vector3};
|
||||
/// let eye = Point3::new(1.0, 2.0, 3.0);
|
||||
/// let target = Point3::new(2.0, 2.0, 3.0);
|
||||
/// let up = Vector3::y();
|
||||
///
|
||||
/// // Isometry with its rotation part represented as a UnitQuaternion
|
||||
/// let iso = Isometry3::look_at_rh(&eye, &target, &up);
|
||||
/// assert_eq!(iso * eye, Point3::origin());
|
||||
/// assert_relative_eq!(iso * Vector3::x(), -Vector3::z());
|
||||
///
|
||||
/// // Isometry with its rotation part represented as Rotation3 (a 3x3 rotation matrix).
|
||||
/// let iso = IsometryMatrix3::look_at_rh(&eye, &target, &up);
|
||||
/// assert_eq!(iso * eye, Point3::origin());
|
||||
/// assert_relative_eq!(iso * Vector3::x(), -Vector3::z());
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn look_at_rh(eye: &Point3<N>,
|
||||
target: &Point3<N>,
|
||||
up: &Vector3<N>)
|
||||
-> Self {
|
||||
let rotation = $RotId::look_at_rh(&(target - eye), up);
|
||||
let trans = &rotation * (-eye);
|
||||
|
||||
Self::from_parts(Translation::from(trans.coords), rotation)
|
||||
}
|
||||
|
||||
/// Builds a left-handed look-at view matrix.
|
||||
///
|
||||
/// It maps the view direction `target - eye` to the **positive** `z` axis and the `eye` to the origin.
|
||||
/// This conforms to the common notion of right handed camera look-at **view matrix** from
|
||||
/// the computer graphics community, i.e. the camera is assumed to look toward its local `z` axis.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * eye - The eye position.
|
||||
/// * target - The target position.
|
||||
/// * up - A vector approximately aligned with required the vertical axis. The only
|
||||
/// requirement of this parameter is to not be collinear to `target - eye`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # #[macro_use] extern crate approx;
|
||||
/// # use std::f32;
|
||||
/// # use nalgebra::{Isometry3, IsometryMatrix3, Point3, Vector3};
|
||||
/// let eye = Point3::new(1.0, 2.0, 3.0);
|
||||
/// let target = Point3::new(2.0, 2.0, 3.0);
|
||||
/// let up = Vector3::y();
|
||||
///
|
||||
/// // Isometry with its rotation part represented as a UnitQuaternion
|
||||
/// let iso = Isometry3::look_at_lh(&eye, &target, &up);
|
||||
/// assert_eq!(iso * eye, Point3::origin());
|
||||
/// assert_relative_eq!(iso * Vector3::x(), Vector3::z());
|
||||
///
|
||||
/// // Isometry with its rotation part represented as Rotation3 (a 3x3 rotation matrix).
|
||||
/// let iso = IsometryMatrix3::look_at_lh(&eye, &target, &up);
|
||||
/// assert_eq!(iso * eye, Point3::origin());
|
||||
/// assert_relative_eq!(iso * Vector3::x(), Vector3::z());
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn look_at_lh(eye: &Point3<N>,
|
||||
target: &Point3<N>,
|
||||
up: &Vector3<N>)
|
||||
-> Self {
|
||||
let rotation = $RotId::look_at_lh(&(target - eye), up);
|
||||
let trans = &rotation * (-eye);
|
||||
|
||||
Self::from_parts(Translation::from(trans.coords), rotation)
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
/// # Construction from a 3D vector and/or an axis-angle
|
||||
impl<N: SimdRealField> Isometry3<N>
|
||||
where
|
||||
N::Element: SimdRealField,
|
||||
{
|
||||
basic_isometry_construction_impl!(UnitQuaternion<N>);
|
||||
}
|
||||
|
||||
impl<N: SimdRealField> IsometryMatrix3<N>
|
||||
where
|
||||
N::Element: SimdRealField,
|
||||
{
|
||||
basic_isometry_construction_impl!(Rotation3<N>);
|
||||
}
|
||||
|
||||
/// # Construction from a 3D eye position and target point
|
||||
impl<N: SimdRealField> Isometry3<N>
|
||||
where
|
||||
N::Element: SimdRealField,
|
||||
{
|
||||
look_at_isometry_construction_impl!(UnitQuaternion<N>);
|
||||
}
|
||||
|
||||
impl<N: SimdRealField> IsometryMatrix3<N>
|
||||
where
|
||||
N::Element: SimdRealField,
|
||||
{
|
||||
look_at_isometry_construction_impl!(Rotation3<N>);
|
||||
}
|
||||
|
211
src/geometry/isometry_interpolation.rs
Normal file
211
src/geometry/isometry_interpolation.rs
Normal file
@ -0,0 +1,211 @@
|
||||
use crate::{Isometry2, Isometry3, IsometryMatrix2, IsometryMatrix3, RealField, SimdRealField};
|
||||
|
||||
/// # 3D interpolation
|
||||
impl<N: SimdRealField> Isometry3<N> {
|
||||
/// Interpolates between two isometries using a linear interpolation for the translation part,
|
||||
/// and a spherical interpolation for the rotation part.
|
||||
///
|
||||
/// Panics if the angle between both rotations is 180 degrees (in which case the interpolation
|
||||
/// is not well-defined). Use `.try_lerp_slerp` instead to avoid the panic.
|
||||
///
|
||||
/// # Examples:
|
||||
///
|
||||
/// ```
|
||||
/// # use nalgebra::{Vector3, Translation3, Isometry3, UnitQuaternion};
|
||||
///
|
||||
/// let t1 = Translation3::new(1.0, 2.0, 3.0);
|
||||
/// let t2 = Translation3::new(4.0, 8.0, 12.0);
|
||||
/// let q1 = UnitQuaternion::from_euler_angles(std::f32::consts::FRAC_PI_4, 0.0, 0.0);
|
||||
/// let q2 = UnitQuaternion::from_euler_angles(-std::f32::consts::PI, 0.0, 0.0);
|
||||
/// let iso1 = Isometry3::from_parts(t1, q1);
|
||||
/// let iso2 = Isometry3::from_parts(t2, q2);
|
||||
///
|
||||
/// let iso3 = iso1.lerp_slerp(&iso2, 1.0 / 3.0);
|
||||
///
|
||||
/// assert_eq!(iso3.translation.vector, Vector3::new(2.0, 4.0, 6.0));
|
||||
/// assert_eq!(iso3.rotation.euler_angles(), (std::f32::consts::FRAC_PI_2, 0.0, 0.0));
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn lerp_slerp(&self, other: &Self, t: N) -> Self
|
||||
where
|
||||
N: RealField,
|
||||
{
|
||||
let tr = self.translation.vector.lerp(&other.translation.vector, t);
|
||||
let rot = self.rotation.slerp(&other.rotation, t);
|
||||
Self::from_parts(tr.into(), rot)
|
||||
}
|
||||
|
||||
/// Attempts to interpolate between two isometries using a linear interpolation for the translation part,
|
||||
/// and a spherical interpolation for the rotation part.
|
||||
///
|
||||
/// Retuns `None` if the angle between both rotations is 180 degrees (in which case the interpolation
|
||||
/// is not well-defined).
|
||||
///
|
||||
/// # Examples:
|
||||
///
|
||||
/// ```
|
||||
/// # use nalgebra::{Vector3, Translation3, Isometry3, UnitQuaternion};
|
||||
///
|
||||
/// let t1 = Translation3::new(1.0, 2.0, 3.0);
|
||||
/// let t2 = Translation3::new(4.0, 8.0, 12.0);
|
||||
/// let q1 = UnitQuaternion::from_euler_angles(std::f32::consts::FRAC_PI_4, 0.0, 0.0);
|
||||
/// let q2 = UnitQuaternion::from_euler_angles(-std::f32::consts::PI, 0.0, 0.0);
|
||||
/// let iso1 = Isometry3::from_parts(t1, q1);
|
||||
/// let iso2 = Isometry3::from_parts(t2, q2);
|
||||
///
|
||||
/// let iso3 = iso1.lerp_slerp(&iso2, 1.0 / 3.0);
|
||||
///
|
||||
/// assert_eq!(iso3.translation.vector, Vector3::new(2.0, 4.0, 6.0));
|
||||
/// assert_eq!(iso3.rotation.euler_angles(), (std::f32::consts::FRAC_PI_2, 0.0, 0.0));
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn try_lerp_slerp(&self, other: &Self, t: N, epsilon: N) -> Option<Self>
|
||||
where
|
||||
N: RealField,
|
||||
{
|
||||
let tr = self.translation.vector.lerp(&other.translation.vector, t);
|
||||
let rot = self.rotation.try_slerp(&other.rotation, t, epsilon)?;
|
||||
Some(Self::from_parts(tr.into(), rot))
|
||||
}
|
||||
}
|
||||
|
||||
impl<N: SimdRealField> IsometryMatrix3<N> {
|
||||
/// Interpolates between two isometries using a linear interpolation for the translation part,
|
||||
/// and a spherical interpolation for the rotation part.
|
||||
///
|
||||
/// Panics if the angle between both rotations is 180 degrees (in which case the interpolation
|
||||
/// is not well-defined). Use `.try_lerp_slerp` instead to avoid the panic.
|
||||
///
|
||||
/// # Examples:
|
||||
///
|
||||
/// ```
|
||||
/// # use nalgebra::{Vector3, Translation3, Rotation3, IsometryMatrix3};
|
||||
///
|
||||
/// let t1 = Translation3::new(1.0, 2.0, 3.0);
|
||||
/// let t2 = Translation3::new(4.0, 8.0, 12.0);
|
||||
/// let q1 = Rotation3::from_euler_angles(std::f32::consts::FRAC_PI_4, 0.0, 0.0);
|
||||
/// let q2 = Rotation3::from_euler_angles(-std::f32::consts::PI, 0.0, 0.0);
|
||||
/// let iso1 = IsometryMatrix3::from_parts(t1, q1);
|
||||
/// let iso2 = IsometryMatrix3::from_parts(t2, q2);
|
||||
///
|
||||
/// let iso3 = iso1.lerp_slerp(&iso2, 1.0 / 3.0);
|
||||
///
|
||||
/// assert_eq!(iso3.translation.vector, Vector3::new(2.0, 4.0, 6.0));
|
||||
/// assert_eq!(iso3.rotation.euler_angles(), (std::f32::consts::FRAC_PI_2, 0.0, 0.0));
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn lerp_slerp(&self, other: &Self, t: N) -> Self
|
||||
where
|
||||
N: RealField,
|
||||
{
|
||||
let tr = self.translation.vector.lerp(&other.translation.vector, t);
|
||||
let rot = self.rotation.slerp(&other.rotation, t);
|
||||
Self::from_parts(tr.into(), rot)
|
||||
}
|
||||
|
||||
/// Attempts to interpolate between two isometries using a linear interpolation for the translation part,
|
||||
/// and a spherical interpolation for the rotation part.
|
||||
///
|
||||
/// Retuns `None` if the angle between both rotations is 180 degrees (in which case the interpolation
|
||||
/// is not well-defined).
|
||||
///
|
||||
/// # Examples:
|
||||
///
|
||||
/// ```
|
||||
/// # use nalgebra::{Vector3, Translation3, Rotation3, IsometryMatrix3};
|
||||
///
|
||||
/// let t1 = Translation3::new(1.0, 2.0, 3.0);
|
||||
/// let t2 = Translation3::new(4.0, 8.0, 12.0);
|
||||
/// let q1 = Rotation3::from_euler_angles(std::f32::consts::FRAC_PI_4, 0.0, 0.0);
|
||||
/// let q2 = Rotation3::from_euler_angles(-std::f32::consts::PI, 0.0, 0.0);
|
||||
/// let iso1 = IsometryMatrix3::from_parts(t1, q1);
|
||||
/// let iso2 = IsometryMatrix3::from_parts(t2, q2);
|
||||
///
|
||||
/// let iso3 = iso1.lerp_slerp(&iso2, 1.0 / 3.0);
|
||||
///
|
||||
/// assert_eq!(iso3.translation.vector, Vector3::new(2.0, 4.0, 6.0));
|
||||
/// assert_eq!(iso3.rotation.euler_angles(), (std::f32::consts::FRAC_PI_2, 0.0, 0.0));
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn try_lerp_slerp(&self, other: &Self, t: N, epsilon: N) -> Option<Self>
|
||||
where
|
||||
N: RealField,
|
||||
{
|
||||
let tr = self.translation.vector.lerp(&other.translation.vector, t);
|
||||
let rot = self.rotation.try_slerp(&other.rotation, t, epsilon)?;
|
||||
Some(Self::from_parts(tr.into(), rot))
|
||||
}
|
||||
}
|
||||
|
||||
/// # 2D interpolation
|
||||
impl<N: SimdRealField> Isometry2<N> {
|
||||
/// Interpolates between two isometries using a linear interpolation for the translation part,
|
||||
/// and a spherical interpolation for the rotation part.
|
||||
///
|
||||
/// Panics if the angle between both rotations is 180 degrees (in which case the interpolation
|
||||
/// is not well-defined). Use `.try_lerp_slerp` instead to avoid the panic.
|
||||
///
|
||||
/// # Examples:
|
||||
///
|
||||
/// ```
|
||||
/// # #[macro_use] extern crate approx;
|
||||
/// # use nalgebra::{Vector2, Translation2, UnitComplex, Isometry2};
|
||||
///
|
||||
/// let t1 = Translation2::new(1.0, 2.0);
|
||||
/// let t2 = Translation2::new(4.0, 8.0);
|
||||
/// let q1 = UnitComplex::new(std::f32::consts::FRAC_PI_4);
|
||||
/// let q2 = UnitComplex::new(-std::f32::consts::PI);
|
||||
/// let iso1 = Isometry2::from_parts(t1, q1);
|
||||
/// let iso2 = Isometry2::from_parts(t2, q2);
|
||||
///
|
||||
/// let iso3 = iso1.lerp_slerp(&iso2, 1.0 / 3.0);
|
||||
///
|
||||
/// assert_eq!(iso3.translation.vector, Vector2::new(2.0, 4.0));
|
||||
/// assert_relative_eq!(iso3.rotation.angle(), std::f32::consts::FRAC_PI_2);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn lerp_slerp(&self, other: &Self, t: N) -> Self
|
||||
where
|
||||
N: RealField,
|
||||
{
|
||||
let tr = self.translation.vector.lerp(&other.translation.vector, t);
|
||||
let rot = self.rotation.slerp(&other.rotation, t);
|
||||
Self::from_parts(tr.into(), rot)
|
||||
}
|
||||
}
|
||||
|
||||
impl<N: SimdRealField> IsometryMatrix2<N> {
|
||||
/// Interpolates between two isometries using a linear interpolation for the translation part,
|
||||
/// and a spherical interpolation for the rotation part.
|
||||
///
|
||||
/// Panics if the angle between both rotations is 180 degrees (in which case the interpolation
|
||||
/// is not well-defined). Use `.try_lerp_slerp` instead to avoid the panic.
|
||||
///
|
||||
/// # Examples:
|
||||
///
|
||||
/// ```
|
||||
/// # #[macro_use] extern crate approx;
|
||||
/// # use nalgebra::{Vector2, Translation2, Rotation2, IsometryMatrix2};
|
||||
///
|
||||
/// let t1 = Translation2::new(1.0, 2.0);
|
||||
/// let t2 = Translation2::new(4.0, 8.0);
|
||||
/// let q1 = Rotation2::new(std::f32::consts::FRAC_PI_4);
|
||||
/// let q2 = Rotation2::new(-std::f32::consts::PI);
|
||||
/// let iso1 = IsometryMatrix2::from_parts(t1, q1);
|
||||
/// let iso2 = IsometryMatrix2::from_parts(t2, q2);
|
||||
///
|
||||
/// let iso3 = iso1.lerp_slerp(&iso2, 1.0 / 3.0);
|
||||
///
|
||||
/// assert_eq!(iso3.translation.vector, Vector2::new(2.0, 4.0));
|
||||
/// assert_relative_eq!(iso3.rotation.angle(), std::f32::consts::FRAC_PI_2);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn lerp_slerp(&self, other: &Self, t: N) -> Self
|
||||
where
|
||||
N: RealField,
|
||||
{
|
||||
let tr = self.translation.vector.lerp(&other.translation.vector, t);
|
||||
let rot = self.rotation.slerp(&other.rotation, t);
|
||||
Self::from_parts(tr.into(), rot)
|
||||
}
|
||||
}
|
@ -83,6 +83,7 @@ mod transform_simba;
|
||||
|
||||
mod reflection;
|
||||
|
||||
mod isometry_interpolation;
|
||||
mod orthographic;
|
||||
mod perspective;
|
||||
|
||||
|
@ -19,7 +19,25 @@ use crate::base::dimension::{DimName, DimNameAdd, DimNameSum, U1};
|
||||
use crate::base::iter::{MatrixIter, MatrixIterMut};
|
||||
use crate::base::{DefaultAllocator, Scalar, VectorN};
|
||||
|
||||
/// A point in a n-dimensional euclidean space.
|
||||
/// A point in an euclidean space.
|
||||
///
|
||||
/// The difference between a point and a vector is only semantic. See [the user guide](https://www.nalgebra.org/points_and_transformations/)
|
||||
/// for details on the distinction. The most notable difference that vectors ignore translations.
|
||||
/// In particular, an [`Isometry2`](crate::Isometry2) or [`Isometry3`](crate::Isometry3) will
|
||||
/// transform points by applying a rotation and a translation on them. However, these isometries
|
||||
/// will only apply rotations to vectors (when doing `isometry * vector`, the translation part of
|
||||
/// the isometry is ignored).
|
||||
///
|
||||
/// # Construction
|
||||
/// * [From individual components <span style="float:right;">`new`…</span>](#construction-from-individual-components)
|
||||
/// * [Swizzling <span style="float:right;">`xx`, `yxz`…</span>](#swizzling)
|
||||
/// * [Other construction methods <span style="float:right;">`origin`, `from_slice`, `from_homogeneous`…</span>](#other-construction-methods)
|
||||
///
|
||||
/// # Transformation
|
||||
/// Transforming a point by an [Isometry](crate::Isometry), [rotation](crate::Rotation), etc. can be
|
||||
/// achieved by multiplication, e.g., `isometry * point` or `rotation * point`. Some of these transformation
|
||||
/// may have some other methods, e.g., `isometry.inverse_transform_point(&point)`. See the documentation
|
||||
/// of said transformations for details.
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Point<N: Scalar, D: DimName>
|
||||
|
@ -6,12 +6,17 @@ use rand::distributions::{Distribution, Standard};
|
||||
use rand::Rng;
|
||||
|
||||
use crate::base::allocator::Allocator;
|
||||
use crate::base::dimension::{DimName, DimNameAdd, DimNameSum, U1, U2, U3, U4, U5, U6};
|
||||
use crate::base::dimension::{DimName, DimNameAdd, DimNameSum, U1};
|
||||
use crate::base::{DefaultAllocator, Scalar, VectorN};
|
||||
use crate::{
|
||||
Point1, Point2, Point3, Point4, Point5, Point6, Vector1, Vector2, Vector3, Vector4, Vector5,
|
||||
Vector6,
|
||||
};
|
||||
use simba::scalar::ClosedDiv;
|
||||
|
||||
use crate::geometry::Point;
|
||||
|
||||
/// # Other construction methods
|
||||
impl<N: Scalar, D: DimName> Point<N, D>
|
||||
where
|
||||
DefaultAllocator: Allocator<N, D>,
|
||||
@ -79,7 +84,7 @@ where
|
||||
/// assert_eq!(pt, Some(Point3::new(1.0, 2.0, 3.0)));
|
||||
///
|
||||
/// // All component of the result will be divided by the
|
||||
/// // last component of the vector, here 2.0.
|
||||
/// // last component of the vector, here 2.0.
|
||||
/// let coords = Vector4::new(1.0, 2.0, 3.0, 2.0);
|
||||
/// let pt = Point3::from_homogeneous(coords);
|
||||
/// assert_eq!(pt, Some(Point3::new(0.5, 1.0, 1.5)));
|
||||
@ -158,46 +163,56 @@ where
|
||||
* Small points construction from components.
|
||||
*
|
||||
*/
|
||||
// NOTE: the impl for Point1 is not with the others so that we
|
||||
// can add a section with the impl block comment.
|
||||
/// # Construction from individual components
|
||||
impl<N: Scalar> Point1<N> {
|
||||
/// Initializes this point from its components.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # use nalgebra::Point1;
|
||||
/// let p = Point1::new(1.0);
|
||||
/// assert_eq!(p.x, 1.0);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn new(x: N) -> Self {
|
||||
Vector1::new(x).into()
|
||||
}
|
||||
}
|
||||
macro_rules! componentwise_constructors_impl(
|
||||
($($doc: expr; $D: ty, $($args: ident:$irow: expr),*);* $(;)*) => {$(
|
||||
impl<N: Scalar> Point<N, $D>
|
||||
where DefaultAllocator: Allocator<N, $D> {
|
||||
($($doc: expr; $Point: ident, $Vector: ident, $($args: ident:$irow: expr),*);* $(;)*) => {$(
|
||||
impl<N: Scalar> $Point<N> {
|
||||
#[doc = "Initializes this point from its components."]
|
||||
#[doc = "# Example\n```"]
|
||||
#[doc = $doc]
|
||||
#[doc = "```"]
|
||||
#[inline]
|
||||
pub fn new($($args: N),*) -> Self {
|
||||
unsafe {
|
||||
let mut res = Self::new_uninitialized();
|
||||
$( *res.get_unchecked_mut($irow) = $args; )*
|
||||
|
||||
res
|
||||
}
|
||||
$Vector::new($($args),*).into()
|
||||
}
|
||||
}
|
||||
)*}
|
||||
);
|
||||
|
||||
componentwise_constructors_impl!(
|
||||
"# use nalgebra::Point1;\nlet p = Point1::new(1.0);\nassert!(p.x == 1.0);";
|
||||
U1, x:0;
|
||||
"# use nalgebra::Point2;\nlet p = Point2::new(1.0, 2.0);\nassert!(p.x == 1.0 && p.y == 2.0);";
|
||||
U2, x:0, y:1;
|
||||
Point2, Vector2, x:0, y:1;
|
||||
"# use nalgebra::Point3;\nlet p = Point3::new(1.0, 2.0, 3.0);\nassert!(p.x == 1.0 && p.y == 2.0 && p.z == 3.0);";
|
||||
U3, x:0, y:1, z:2;
|
||||
Point3, Vector3, x:0, y:1, z:2;
|
||||
"# use nalgebra::Point4;\nlet p = Point4::new(1.0, 2.0, 3.0, 4.0);\nassert!(p.x == 1.0 && p.y == 2.0 && p.z == 3.0 && p.w == 4.0);";
|
||||
U4, x:0, y:1, z:2, w:3;
|
||||
Point4, Vector4, x:0, y:1, z:2, w:3;
|
||||
"# use nalgebra::Point5;\nlet p = Point5::new(1.0, 2.0, 3.0, 4.0, 5.0);\nassert!(p.x == 1.0 && p.y == 2.0 && p.z == 3.0 && p.w == 4.0 && p.a == 5.0);";
|
||||
U5, x:0, y:1, z:2, w:3, a:4;
|
||||
Point5, Vector5, x:0, y:1, z:2, w:3, a:4;
|
||||
"# use nalgebra::Point6;\nlet p = Point6::new(1.0, 2.0, 3.0, 4.0, 5.0, 6.0);\nassert!(p.x == 1.0 && p.y == 2.0 && p.z == 3.0 && p.w == 4.0 && p.a == 5.0 && p.b == 6.0);";
|
||||
U6, x:0, y:1, z:2, w:3, a:4, b:5;
|
||||
Point6, Vector6, x:0, y:1, z:2, w:3, a:4, b:5;
|
||||
);
|
||||
|
||||
macro_rules! from_array_impl(
|
||||
($($D: ty, $len: expr);*) => {$(
|
||||
impl <N: Scalar> From<[N; $len]> for Point<N, $D> {
|
||||
fn from (coords: [N; $len]) -> Self {
|
||||
($($Point: ident, $len: expr);*) => {$(
|
||||
impl <N: Scalar> From<[N; $len]> for $Point<N> {
|
||||
fn from(coords: [N; $len]) -> Self {
|
||||
Self {
|
||||
coords: coords.into()
|
||||
}
|
||||
@ -206,4 +221,4 @@ macro_rules! from_array_impl(
|
||||
)*}
|
||||
);
|
||||
|
||||
from_array_impl!(U1, 1; U2, 2; U3, 3; U4, 4; U5, 5; U6, 6);
|
||||
from_array_impl!(Point1, 1; Point2, 2; Point3, 3; Point4, 4; Point5, 5; Point6, 6);
|
||||
|
@ -6,60 +6,61 @@ use typenum::{self, Cmp, Greater};
|
||||
macro_rules! impl_swizzle {
|
||||
($( where $BaseDim: ident: $( $name: ident() -> $Result: ident[$($i: expr),+] ),+ ;)* ) => {
|
||||
$(
|
||||
impl<N: Scalar, D: DimName> Point<N, D>
|
||||
where
|
||||
DefaultAllocator: Allocator<N, D>,
|
||||
D::Value: Cmp<typenum::$BaseDim, Output=Greater>
|
||||
{
|
||||
$(
|
||||
/// Builds a new point from components of `self`.
|
||||
#[inline]
|
||||
pub fn $name(&self) -> $Result<N> {
|
||||
$Result::new($(self[$i].inlined_clone()),*)
|
||||
}
|
||||
)*
|
||||
}
|
||||
$(
|
||||
/// Builds a new point from components of `self`.
|
||||
#[inline]
|
||||
pub fn $name(&self) -> $Result<N>
|
||||
where D::Value: Cmp<typenum::$BaseDim, Output=Greater> {
|
||||
$Result::new($(self[$i].inlined_clone()),*)
|
||||
}
|
||||
)*
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
impl_swizzle!(
|
||||
where U0: xx() -> Point2[0, 0],
|
||||
xxx() -> Point3[0, 0, 0];
|
||||
/// # Swizzling
|
||||
impl<N: Scalar, D: DimName> Point<N, D>
|
||||
where
|
||||
DefaultAllocator: Allocator<N, D>,
|
||||
{
|
||||
impl_swizzle!(
|
||||
where U0: xx() -> Point2[0, 0],
|
||||
xxx() -> Point3[0, 0, 0];
|
||||
|
||||
where U1: xy() -> Point2[0, 1],
|
||||
yx() -> Point2[1, 0],
|
||||
yy() -> Point2[1, 1],
|
||||
xxy() -> Point3[0, 0, 1],
|
||||
xyx() -> Point3[0, 1, 0],
|
||||
xyy() -> Point3[0, 1, 1],
|
||||
yxx() -> Point3[1, 0, 0],
|
||||
yxy() -> Point3[1, 0, 1],
|
||||
yyx() -> Point3[1, 1, 0],
|
||||
yyy() -> Point3[1, 1, 1];
|
||||
where U1: xy() -> Point2[0, 1],
|
||||
yx() -> Point2[1, 0],
|
||||
yy() -> Point2[1, 1],
|
||||
xxy() -> Point3[0, 0, 1],
|
||||
xyx() -> Point3[0, 1, 0],
|
||||
xyy() -> Point3[0, 1, 1],
|
||||
yxx() -> Point3[1, 0, 0],
|
||||
yxy() -> Point3[1, 0, 1],
|
||||
yyx() -> Point3[1, 1, 0],
|
||||
yyy() -> Point3[1, 1, 1];
|
||||
|
||||
where U2: xz() -> Point2[0, 2],
|
||||
yz() -> Point2[1, 2],
|
||||
zx() -> Point2[2, 0],
|
||||
zy() -> Point2[2, 1],
|
||||
zz() -> Point2[2, 2],
|
||||
xxz() -> Point3[0, 0, 2],
|
||||
xyz() -> Point3[0, 1, 2],
|
||||
xzx() -> Point3[0, 2, 0],
|
||||
xzy() -> Point3[0, 2, 1],
|
||||
xzz() -> Point3[0, 2, 2],
|
||||
yxz() -> Point3[1, 0, 2],
|
||||
yyz() -> Point3[1, 1, 2],
|
||||
yzx() -> Point3[1, 2, 0],
|
||||
yzy() -> Point3[1, 2, 1],
|
||||
yzz() -> Point3[1, 2, 2],
|
||||
zxx() -> Point3[2, 0, 0],
|
||||
zxy() -> Point3[2, 0, 1],
|
||||
zxz() -> Point3[2, 0, 2],
|
||||
zyx() -> Point3[2, 1, 0],
|
||||
zyy() -> Point3[2, 1, 1],
|
||||
zyz() -> Point3[2, 1, 2],
|
||||
zzx() -> Point3[2, 2, 0],
|
||||
zzy() -> Point3[2, 2, 1],
|
||||
zzz() -> Point3[2, 2, 2];
|
||||
);
|
||||
where U2: xz() -> Point2[0, 2],
|
||||
yz() -> Point2[1, 2],
|
||||
zx() -> Point2[2, 0],
|
||||
zy() -> Point2[2, 1],
|
||||
zz() -> Point2[2, 2],
|
||||
xxz() -> Point3[0, 0, 2],
|
||||
xyz() -> Point3[0, 1, 2],
|
||||
xzx() -> Point3[0, 2, 0],
|
||||
xzy() -> Point3[0, 2, 1],
|
||||
xzz() -> Point3[0, 2, 2],
|
||||
yxz() -> Point3[1, 0, 2],
|
||||
yyz() -> Point3[1, 1, 2],
|
||||
yzx() -> Point3[1, 2, 0],
|
||||
yzy() -> Point3[1, 2, 1],
|
||||
yzz() -> Point3[1, 2, 2],
|
||||
zxx() -> Point3[2, 0, 0],
|
||||
zxy() -> Point3[2, 0, 1],
|
||||
zxz() -> Point3[2, 0, 2],
|
||||
zyx() -> Point3[2, 1, 0],
|
||||
zyy() -> Point3[2, 1, 1],
|
||||
zyz() -> Point3[2, 1, 2],
|
||||
zzx() -> Point3[2, 2, 0],
|
||||
zzy() -> Point3[2, 2, 1],
|
||||
zzz() -> Point3[2, 2, 2];
|
||||
);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user