From cf769522f8fdbc94977072b6b708c7b594ab8dad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Crozet=20S=C3=A9bastien?= Date: Fri, 20 Nov 2020 17:45:11 +0100 Subject: [PATCH 1/6] Add sections to the documentations of Isometry and Point. --- src/geometry/isometry.rs | 294 +++++------------- src/geometry/isometry_construction.rs | 405 +++++++++++++------------ src/geometry/isometry_interpolation.rs | 211 +++++++++++++ src/geometry/mod.rs | 1 + src/geometry/point.rs | 20 +- src/geometry/point_construction.rs | 59 ++-- src/geometry/swizzle.rs | 103 +++---- 7 files changed, 617 insertions(+), 476 deletions(-) create mode 100644 src/geometry/isometry_interpolation.rs diff --git a/src/geometry/isometry.rs b/src/geometry/isometry.rs index edb27b5a..b2228301 100755 --- a/src/geometry/isometry.rs +++ b/src/geometry/isometry.rs @@ -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 `new`, `translation`, `rotation`…](#construction-from-a-2d-vector-andor-a-rotation-angle) +/// * [From a 3D vector and/or an axis-angle `new`, `translation`, `rotation`…](#construction-from-a-3d-vector-andor-an-axis-angle) +/// * [From a 3D eye position and target point `look_at`, `look_at_lh`, `face_towards`…](#construction-from-a-3d-eye-position-and-target-point) +/// * [From the translation and rotation parts `from_parts`…](#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 `transform_vector`, `inverse_transform_point`…](#transformation-of-a-vector-or-a-point) +/// * [Inversion and in-place composition `inverse`, `append_rotation_wrt_point_mut`…](#inversion-and-in-place-composition) +/// * [2D interpolation `lerp_slerp`…](#2d-interpolation) +/// * [3D interpolation `lerp_slerp`…](#3d-interpolation) +/// +/// # Conversion to a matrix +/// * [Conversion to a matrix `to_matrix`…](#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> Isometry where DefaultAllocator: Allocator, @@ -131,6 +167,7 @@ where } } +/// # Inversion and in-place composition impl> Isometry 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> Isometry +where + N::Element: SimdRealField, + DefaultAllocator: Allocator, +{ /// Transform the given point by this isometry. /// /// This is the same as the multiplication `self * pt`. @@ -377,224 +421,19 @@ where } } -impl Isometry> { - /// 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 - 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 Isometry> { - /// 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 - 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 Isometry> { - /// 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 Isometry> { - /// 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 Isometry where DefaultAllocator: Allocator, { /// 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> + where + D: DimNameAdd, + R: SubsetOf>>, + DefaultAllocator: Allocator, DimNameSum>, + { + self.to_homogeneous() + } } impl Eq for Isometry diff --git a/src/geometry/isometry_construction.rs b/src/geometry/isometry_construction.rs index a9f9c978..0f487547 100644 --- a/src/geometry/isometry_construction.rs +++ b/src/geometry/isometry_construction.rs @@ -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> Isometry @@ -112,8 +113,8 @@ where * */ -// 2D rotation. -impl Isometry> +/// # Construction from a 2D vector and/or a rotation angle +impl IsometryMatrix2 where N::Element: SimdRealField, { @@ -151,7 +152,7 @@ where } } -impl Isometry> +impl Isometry2 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 Isometry> - 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, axisangle: Vector3) -> 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, axisangle: Vector3) -> 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) -> 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, - target: &Point3, - up: &Vector3) - -> 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, - target: &Point3, - up: &Vector3) - -> 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, - target: &Point3, - up: &Vector3) - -> 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, - target: &Point3, - up: &Vector3) - -> 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) -> Self { + Self::new(Vector3::zeros(), axisangle) } } ); -isometry_construction_impl!(Rotation3, U3, U3); -isometry_construction_impl!(UnitQuaternion, 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, + target: &Point3, + up: &Vector3) + -> 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, + target: &Point3, + up: &Vector3) + -> 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, + target: &Point3, + up: &Vector3) + -> 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, + target: &Point3, + up: &Vector3) + -> 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 Isometry3 +where + N::Element: SimdRealField, +{ + basic_isometry_construction_impl!(UnitQuaternion); +} + +impl IsometryMatrix3 +where + N::Element: SimdRealField, +{ + basic_isometry_construction_impl!(Rotation3); +} + +/// # Construction from a 3D eye position and target point +impl Isometry3 +where + N::Element: SimdRealField, +{ + look_at_isometry_construction_impl!(UnitQuaternion); +} + +impl IsometryMatrix3 +where + N::Element: SimdRealField, +{ + look_at_isometry_construction_impl!(Rotation3); +} diff --git a/src/geometry/isometry_interpolation.rs b/src/geometry/isometry_interpolation.rs new file mode 100644 index 00000000..50e3f305 --- /dev/null +++ b/src/geometry/isometry_interpolation.rs @@ -0,0 +1,211 @@ +use crate::{Isometry2, Isometry3, IsometryMatrix2, IsometryMatrix3, RealField, SimdRealField}; + +/// # 3D interpolation +impl Isometry3 { + /// 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 + 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 IsometryMatrix3 { + /// 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 + 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 Isometry2 { + /// 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 IsometryMatrix2 { + /// 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) + } +} diff --git a/src/geometry/mod.rs b/src/geometry/mod.rs index 5701aa8f..25ef89f1 100644 --- a/src/geometry/mod.rs +++ b/src/geometry/mod.rs @@ -83,6 +83,7 @@ mod transform_simba; mod reflection; +mod isometry_interpolation; mod orthographic; mod perspective; diff --git a/src/geometry/point.rs b/src/geometry/point.rs index 0684b3b0..75410ccd 100644 --- a/src/geometry/point.rs +++ b/src/geometry/point.rs @@ -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 `new`…](#construction-from-individual-components) +/// * [Swizzling `xx`, `yxz`…](#swizzling) +/// * [Other construction methods `origin`, `from_slice`, `from_homogeneous`…](#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 diff --git a/src/geometry/point_construction.rs b/src/geometry/point_construction.rs index c54cb779..f567cfac 100644 --- a/src/geometry/point_construction.rs +++ b/src/geometry/point_construction.rs @@ -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 Point where DefaultAllocator: Allocator, @@ -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 Point1 { + /// 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 Point - where DefaultAllocator: Allocator { + ($($doc: expr; $Point: ident, $Vector: ident, $($args: ident:$irow: expr),*);* $(;)*) => {$( + impl $Point { #[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 From<[N; $len]> for Point { - fn from (coords: [N; $len]) -> Self { + ($($Point: ident, $len: expr);*) => {$( + impl From<[N; $len]> for $Point { + 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); diff --git a/src/geometry/swizzle.rs b/src/geometry/swizzle.rs index 9ec6b2e5..26971b74 100644 --- a/src/geometry/swizzle.rs +++ b/src/geometry/swizzle.rs @@ -6,60 +6,61 @@ use typenum::{self, Cmp, Greater}; macro_rules! impl_swizzle { ($( where $BaseDim: ident: $( $name: ident() -> $Result: ident[$($i: expr),+] ),+ ;)* ) => { $( - impl Point - where - DefaultAllocator: Allocator, - D::Value: Cmp - { - $( - /// Builds a new point from components of `self`. - #[inline] - pub fn $name(&self) -> $Result { - $Result::new($(self[$i].inlined_clone()),*) - } - )* - } + $( + /// Builds a new point from components of `self`. + #[inline] + pub fn $name(&self) -> $Result + where D::Value: Cmp { + $Result::new($(self[$i].inlined_clone()),*) + } + )* )* } } -impl_swizzle!( - where U0: xx() -> Point2[0, 0], - xxx() -> Point3[0, 0, 0]; +/// # Swizzling +impl Point +where + DefaultAllocator: Allocator, +{ + 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]; + ); +} From 2a3d98bff8ae5875928a6d44864c69f07838e0ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Crozet=20S=C3=A9bastien?= Date: Fri, 20 Nov 2020 17:46:03 +0100 Subject: [PATCH 2/6] Matrix, vector, isometry, and point aliases documentation: warn that the reader should take a look at the documentation of the aliased type too. --- src/base/alias.rs | 104 +++++++++++++++++++ src/base/alias_slice.rs | 180 +++++++++++++++++++++++++++++++++ src/geometry/isometry_alias.rs | 25 ++++- src/geometry/point_alias.rs | 12 +++ 4 files changed, 317 insertions(+), 4 deletions(-) diff --git a/src/base/alias.rs b/src/base/alias.rs index 7e64de0d..0f62a6e5 100644 --- a/src/base/alias.rs +++ b/src/base/alias.rs @@ -14,138 +14,242 @@ use crate::base::Matrix; * */ /// A statically sized column-major matrix with `R` rows and `C` columns. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** #[deprecated(note = "This matrix name contains a typo. Use MatrixMN instead.")] pub type MatrixNM = Matrix>; /// A statically sized column-major matrix with `R` rows and `C` columns. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type MatrixMN = Matrix>; /// A statically sized column-major square matrix with `D` rows and columns. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type MatrixN = Matrix>; /// A dynamically sized column-major matrix. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** #[cfg(any(feature = "std", feature = "alloc"))] pub type DMatrix = Matrix>; /// A heap-allocated, column-major, matrix with a dynamic number of rows and 1 columns. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** #[cfg(any(feature = "std", feature = "alloc"))] pub type MatrixXx1 = Matrix>; /// A heap-allocated, column-major, matrix with a dynamic number of rows and 2 columns. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** #[cfg(any(feature = "std", feature = "alloc"))] pub type MatrixXx2 = Matrix>; /// A heap-allocated, column-major, matrix with a dynamic number of rows and 3 columns. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** #[cfg(any(feature = "std", feature = "alloc"))] pub type MatrixXx3 = Matrix>; /// A heap-allocated, column-major, matrix with a dynamic number of rows and 4 columns. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** #[cfg(any(feature = "std", feature = "alloc"))] pub type MatrixXx4 = Matrix>; /// A heap-allocated, column-major, matrix with a dynamic number of rows and 5 columns. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** #[cfg(any(feature = "std", feature = "alloc"))] pub type MatrixXx5 = Matrix>; /// A heap-allocated, column-major, matrix with a dynamic number of rows and 6 columns. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** #[cfg(any(feature = "std", feature = "alloc"))] pub type MatrixXx6 = Matrix>; /// A heap-allocated, row-major, matrix with 1 rows and a dynamic number of columns. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** #[cfg(any(feature = "std", feature = "alloc"))] pub type Matrix1xX = Matrix>; /// A heap-allocated, row-major, matrix with 2 rows and a dynamic number of columns. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** #[cfg(any(feature = "std", feature = "alloc"))] pub type Matrix2xX = Matrix>; /// A heap-allocated, row-major, matrix with 3 rows and a dynamic number of columns. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** #[cfg(any(feature = "std", feature = "alloc"))] pub type Matrix3xX = Matrix>; /// A heap-allocated, row-major, matrix with 4 rows and a dynamic number of columns. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** #[cfg(any(feature = "std", feature = "alloc"))] pub type Matrix4xX = Matrix>; /// A heap-allocated, row-major, matrix with 5 rows and a dynamic number of columns. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** #[cfg(any(feature = "std", feature = "alloc"))] pub type Matrix5xX = Matrix>; /// A heap-allocated, row-major, matrix with 6 rows and a dynamic number of columns. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** #[cfg(any(feature = "std", feature = "alloc"))] pub type Matrix6xX = Matrix>; /// A stack-allocated, column-major, 1x1 square matrix. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type Matrix1 = Matrix>; /// A stack-allocated, column-major, 2x2 square matrix. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type Matrix2 = Matrix>; /// A stack-allocated, column-major, 3x3 square matrix. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type Matrix3 = Matrix>; /// A stack-allocated, column-major, 4x4 square matrix. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type Matrix4 = Matrix>; /// A stack-allocated, column-major, 5x5 square matrix. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type Matrix5 = Matrix>; /// A stack-allocated, column-major, 6x6 square matrix. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type Matrix6 = Matrix>; /// A stack-allocated, column-major, 1x2 matrix. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type Matrix1x2 = Matrix>; /// A stack-allocated, column-major, 1x3 matrix. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type Matrix1x3 = Matrix>; /// A stack-allocated, column-major, 1x4 matrix. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type Matrix1x4 = Matrix>; /// A stack-allocated, column-major, 1x5 matrix. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type Matrix1x5 = Matrix>; /// A stack-allocated, column-major, 1x6 matrix. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type Matrix1x6 = Matrix>; /// A stack-allocated, column-major, 2x3 matrix. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type Matrix2x3 = Matrix>; /// A stack-allocated, column-major, 2x4 matrix. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type Matrix2x4 = Matrix>; /// A stack-allocated, column-major, 2x5 matrix. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type Matrix2x5 = Matrix>; /// A stack-allocated, column-major, 2x6 matrix. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type Matrix2x6 = Matrix>; /// A stack-allocated, column-major, 3x4 matrix. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type Matrix3x4 = Matrix>; /// A stack-allocated, column-major, 3x5 matrix. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type Matrix3x5 = Matrix>; /// A stack-allocated, column-major, 3x6 matrix. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type Matrix3x6 = Matrix>; /// A stack-allocated, column-major, 4x5 matrix. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type Matrix4x5 = Matrix>; /// A stack-allocated, column-major, 4x6 matrix. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type Matrix4x6 = Matrix>; /// A stack-allocated, column-major, 5x6 matrix. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type Matrix5x6 = Matrix>; /// A stack-allocated, column-major, 2x1 matrix. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type Matrix2x1 = Matrix>; /// A stack-allocated, column-major, 3x1 matrix. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type Matrix3x1 = Matrix>; /// A stack-allocated, column-major, 4x1 matrix. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type Matrix4x1 = Matrix>; /// A stack-allocated, column-major, 5x1 matrix. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type Matrix5x1 = Matrix>; /// A stack-allocated, column-major, 6x1 matrix. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type Matrix6x1 = Matrix>; /// A stack-allocated, column-major, 3x2 matrix. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type Matrix3x2 = Matrix>; /// A stack-allocated, column-major, 4x2 matrix. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type Matrix4x2 = Matrix>; /// A stack-allocated, column-major, 5x2 matrix. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type Matrix5x2 = Matrix>; /// A stack-allocated, column-major, 6x2 matrix. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type Matrix6x2 = Matrix>; /// A stack-allocated, column-major, 4x3 matrix. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type Matrix4x3 = Matrix>; /// A stack-allocated, column-major, 5x3 matrix. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type Matrix5x3 = Matrix>; /// A stack-allocated, column-major, 6x3 matrix. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type Matrix6x3 = Matrix>; /// A stack-allocated, column-major, 5x4 matrix. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type Matrix5x4 = Matrix>; /// A stack-allocated, column-major, 6x4 matrix. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type Matrix6x4 = Matrix>; /// A stack-allocated, column-major, 6x5 matrix. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type Matrix6x5 = Matrix>; /* diff --git a/src/base/alias_slice.rs b/src/base/alias_slice.rs index 9efbf857..d919fef9 100644 --- a/src/base/alias_slice.rs +++ b/src/base/alias_slice.rs @@ -10,129 +10,207 @@ use crate::base::Matrix; * */ /// A column-major matrix slice with `R` rows and `C` columns. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type MatrixSliceMN<'a, N, R, C, RStride = U1, CStride = R> = Matrix>; /// A column-major matrix slice with `D` rows and columns. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type MatrixSliceN<'a, N, D, RStride = U1, CStride = D> = Matrix>; /// A column-major matrix slice dynamic numbers of rows and columns. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type DMatrixSlice<'a, N, RStride = U1, CStride = Dynamic> = Matrix>; /// A column-major 1x1 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type MatrixSlice1<'a, N, RStride = U1, CStride = U1> = Matrix>; /// A column-major 2x2 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type MatrixSlice2<'a, N, RStride = U1, CStride = U2> = Matrix>; /// A column-major 3x3 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type MatrixSlice3<'a, N, RStride = U1, CStride = U3> = Matrix>; /// A column-major 4x4 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type MatrixSlice4<'a, N, RStride = U1, CStride = U4> = Matrix>; /// A column-major 5x5 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type MatrixSlice5<'a, N, RStride = U1, CStride = U5> = Matrix>; /// A column-major 6x6 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type MatrixSlice6<'a, N, RStride = U1, CStride = U6> = Matrix>; /// A column-major 1x2 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type MatrixSlice1x2<'a, N, RStride = U1, CStride = U1> = Matrix>; /// A column-major 1x3 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type MatrixSlice1x3<'a, N, RStride = U1, CStride = U1> = Matrix>; /// A column-major 1x4 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type MatrixSlice1x4<'a, N, RStride = U1, CStride = U1> = Matrix>; /// A column-major 1x5 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type MatrixSlice1x5<'a, N, RStride = U1, CStride = U1> = Matrix>; /// A column-major 1x6 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type MatrixSlice1x6<'a, N, RStride = U1, CStride = U1> = Matrix>; /// A column-major 2x1 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type MatrixSlice2x1<'a, N, RStride = U1, CStride = U2> = Matrix>; /// A column-major 2x3 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type MatrixSlice2x3<'a, N, RStride = U1, CStride = U2> = Matrix>; /// A column-major 2x4 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type MatrixSlice2x4<'a, N, RStride = U1, CStride = U2> = Matrix>; /// A column-major 2x5 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type MatrixSlice2x5<'a, N, RStride = U1, CStride = U2> = Matrix>; /// A column-major 2x6 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type MatrixSlice2x6<'a, N, RStride = U1, CStride = U2> = Matrix>; /// A column-major 3x1 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type MatrixSlice3x1<'a, N, RStride = U1, CStride = U3> = Matrix>; /// A column-major 3x2 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type MatrixSlice3x2<'a, N, RStride = U1, CStride = U3> = Matrix>; /// A column-major 3x4 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type MatrixSlice3x4<'a, N, RStride = U1, CStride = U3> = Matrix>; /// A column-major 3x5 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type MatrixSlice3x5<'a, N, RStride = U1, CStride = U3> = Matrix>; /// A column-major 3x6 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type MatrixSlice3x6<'a, N, RStride = U1, CStride = U3> = Matrix>; /// A column-major 4x1 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type MatrixSlice4x1<'a, N, RStride = U1, CStride = U4> = Matrix>; /// A column-major 4x2 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type MatrixSlice4x2<'a, N, RStride = U1, CStride = U4> = Matrix>; /// A column-major 4x3 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type MatrixSlice4x3<'a, N, RStride = U1, CStride = U4> = Matrix>; /// A column-major 4x5 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type MatrixSlice4x5<'a, N, RStride = U1, CStride = U4> = Matrix>; /// A column-major 4x6 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type MatrixSlice4x6<'a, N, RStride = U1, CStride = U4> = Matrix>; /// A column-major 5x1 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type MatrixSlice5x1<'a, N, RStride = U1, CStride = U5> = Matrix>; /// A column-major 5x2 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type MatrixSlice5x2<'a, N, RStride = U1, CStride = U5> = Matrix>; /// A column-major 5x3 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type MatrixSlice5x3<'a, N, RStride = U1, CStride = U5> = Matrix>; /// A column-major 5x4 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type MatrixSlice5x4<'a, N, RStride = U1, CStride = U5> = Matrix>; /// A column-major 5x6 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type MatrixSlice5x6<'a, N, RStride = U1, CStride = U5> = Matrix>; /// A column-major 6x1 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type MatrixSlice6x1<'a, N, RStride = U1, CStride = U6> = Matrix>; /// A column-major 6x2 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type MatrixSlice6x2<'a, N, RStride = U1, CStride = U6> = Matrix>; /// A column-major 6x3 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type MatrixSlice6x3<'a, N, RStride = U1, CStride = U6> = Matrix>; /// A column-major 6x4 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type MatrixSlice6x4<'a, N, RStride = U1, CStride = U6> = Matrix>; /// A column-major 6x5 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type MatrixSlice6x5<'a, N, RStride = U1, CStride = U6> = Matrix>; @@ -183,21 +261,33 @@ pub type DVectorSlice<'a, N, RStride = U1, CStride = Dynamic> = Matrix>; /// A 1D column vector slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type VectorSlice1<'a, N, RStride = U1, CStride = U1> = Matrix>; /// A 2D column vector slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type VectorSlice2<'a, N, RStride = U1, CStride = U2> = Matrix>; /// A 3D column vector slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type VectorSlice3<'a, N, RStride = U1, CStride = U3> = Matrix>; /// A 4D column vector slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type VectorSlice4<'a, N, RStride = U1, CStride = U4> = Matrix>; /// A 5D column vector slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type VectorSlice5<'a, N, RStride = U1, CStride = U5> = Matrix>; /// A 6D column vector slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type VectorSlice6<'a, N, RStride = U1, CStride = U6> = Matrix>; @@ -209,129 +299,207 @@ pub type VectorSlice6<'a, N, RStride = U1, CStride = U6> = * */ /// A column-major matrix slice with `R` rows and `C` columns. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type MatrixSliceMutMN<'a, N, R, C, RStride = U1, CStride = R> = Matrix>; /// A column-major matrix slice with `D` rows and columns. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type MatrixSliceMutN<'a, N, D, RStride = U1, CStride = D> = Matrix>; /// A column-major matrix slice dynamic numbers of rows and columns. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type DMatrixSliceMut<'a, N, RStride = U1, CStride = Dynamic> = Matrix>; /// A column-major 1x1 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type MatrixSliceMut1<'a, N, RStride = U1, CStride = U1> = Matrix>; /// A column-major 2x2 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type MatrixSliceMut2<'a, N, RStride = U1, CStride = U2> = Matrix>; /// A column-major 3x3 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type MatrixSliceMut3<'a, N, RStride = U1, CStride = U3> = Matrix>; /// A column-major 4x4 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type MatrixSliceMut4<'a, N, RStride = U1, CStride = U4> = Matrix>; /// A column-major 5x5 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type MatrixSliceMut5<'a, N, RStride = U1, CStride = U5> = Matrix>; /// A column-major 6x6 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type MatrixSliceMut6<'a, N, RStride = U1, CStride = U6> = Matrix>; /// A column-major 1x2 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type MatrixSliceMut1x2<'a, N, RStride = U1, CStride = U1> = Matrix>; /// A column-major 1x3 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type MatrixSliceMut1x3<'a, N, RStride = U1, CStride = U1> = Matrix>; /// A column-major 1x4 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type MatrixSliceMut1x4<'a, N, RStride = U1, CStride = U1> = Matrix>; /// A column-major 1x5 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type MatrixSliceMut1x5<'a, N, RStride = U1, CStride = U1> = Matrix>; /// A column-major 1x6 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type MatrixSliceMut1x6<'a, N, RStride = U1, CStride = U1> = Matrix>; /// A column-major 2x1 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type MatrixSliceMut2x1<'a, N, RStride = U1, CStride = U2> = Matrix>; /// A column-major 2x3 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type MatrixSliceMut2x3<'a, N, RStride = U1, CStride = U2> = Matrix>; /// A column-major 2x4 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type MatrixSliceMut2x4<'a, N, RStride = U1, CStride = U2> = Matrix>; /// A column-major 2x5 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type MatrixSliceMut2x5<'a, N, RStride = U1, CStride = U2> = Matrix>; /// A column-major 2x6 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type MatrixSliceMut2x6<'a, N, RStride = U1, CStride = U2> = Matrix>; /// A column-major 3x1 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type MatrixSliceMut3x1<'a, N, RStride = U1, CStride = U3> = Matrix>; /// A column-major 3x2 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type MatrixSliceMut3x2<'a, N, RStride = U1, CStride = U3> = Matrix>; /// A column-major 3x4 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type MatrixSliceMut3x4<'a, N, RStride = U1, CStride = U3> = Matrix>; /// A column-major 3x5 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type MatrixSliceMut3x5<'a, N, RStride = U1, CStride = U3> = Matrix>; /// A column-major 3x6 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type MatrixSliceMut3x6<'a, N, RStride = U1, CStride = U3> = Matrix>; /// A column-major 4x1 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type MatrixSliceMut4x1<'a, N, RStride = U1, CStride = U4> = Matrix>; /// A column-major 4x2 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type MatrixSliceMut4x2<'a, N, RStride = U1, CStride = U4> = Matrix>; /// A column-major 4x3 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type MatrixSliceMut4x3<'a, N, RStride = U1, CStride = U4> = Matrix>; /// A column-major 4x5 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type MatrixSliceMut4x5<'a, N, RStride = U1, CStride = U4> = Matrix>; /// A column-major 4x6 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type MatrixSliceMut4x6<'a, N, RStride = U1, CStride = U4> = Matrix>; /// A column-major 5x1 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type MatrixSliceMut5x1<'a, N, RStride = U1, CStride = U5> = Matrix>; /// A column-major 5x2 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type MatrixSliceMut5x2<'a, N, RStride = U1, CStride = U5> = Matrix>; /// A column-major 5x3 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type MatrixSliceMut5x3<'a, N, RStride = U1, CStride = U5> = Matrix>; /// A column-major 5x4 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type MatrixSliceMut5x4<'a, N, RStride = U1, CStride = U5> = Matrix>; /// A column-major 5x6 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type MatrixSliceMut5x6<'a, N, RStride = U1, CStride = U5> = Matrix>; /// A column-major 6x1 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type MatrixSliceMut6x1<'a, N, RStride = U1, CStride = U6> = Matrix>; /// A column-major 6x2 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type MatrixSliceMut6x2<'a, N, RStride = U1, CStride = U6> = Matrix>; /// A column-major 6x3 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type MatrixSliceMut6x3<'a, N, RStride = U1, CStride = U6> = Matrix>; /// A column-major 6x4 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type MatrixSliceMut6x4<'a, N, RStride = U1, CStride = U6> = Matrix>; /// A column-major 6x5 matrix slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type MatrixSliceMut6x5<'a, N, RStride = U1, CStride = U6> = Matrix>; @@ -382,20 +550,32 @@ pub type DVectorSliceMut<'a, N, RStride = U1, CStride = Dynamic> = Matrix>; /// A 1D column vector slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type VectorSliceMut1<'a, N, RStride = U1, CStride = U1> = Matrix>; /// A 2D column vector slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type VectorSliceMut2<'a, N, RStride = U1, CStride = U2> = Matrix>; /// A 3D column vector slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type VectorSliceMut3<'a, N, RStride = U1, CStride = U3> = Matrix>; /// A 4D column vector slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type VectorSliceMut4<'a, N, RStride = U1, CStride = U4> = Matrix>; /// A 5D column vector slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type VectorSliceMut5<'a, N, RStride = U1, CStride = U5> = Matrix>; /// A 6D column vector slice. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Matrix`](crate::base::Matrix) type too.** pub type VectorSliceMut6<'a, N, RStride = U1, CStride = U6> = Matrix>; diff --git a/src/geometry/isometry_alias.rs b/src/geometry/isometry_alias.rs index 69d33cb4..8eecd3ee 100644 --- a/src/geometry/isometry_alias.rs +++ b/src/geometry/isometry_alias.rs @@ -2,16 +2,33 @@ use crate::base::dimension::{U2, U3}; use crate::geometry::{Isometry, Rotation2, Rotation3, UnitComplex, UnitQuaternion}; -/// A 2-dimensional direct isometry using a unit complex number for its rotational part. Also known as a rigid-body motion, or as an element of SE(2). +/// A 2-dimensional direct isometry using a unit complex number for its rotational part. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Isometry`](crate::Isometry) type too.** +/// +/// Also known as a 2D rigid-body motion, or as an element of SE(2). + pub type Isometry2 = Isometry>; -/// A 3-dimensional direct isometry using a unit quaternion for its rotational part. Also known as a rigid-body motion, or as an element of SE(3). +/// A 3-dimensional direct isometry using a unit quaternion for its rotational part. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Isometry`](crate::Isometry) type too.** +/// +/// Also known as a rigid-body motion, or as an element of SE(3). pub type Isometry3 = Isometry>; -/// A 2-dimensional direct isometry using a rotation matrix for its rotational part. Also known as a rigid-body motion, or as an element of SE(2). +/// A 2-dimensional direct isometry using a rotation matrix for its rotational part. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Isometry`](crate::Isometry) type too.** +/// +/// Also known as a rigid-body motion, or as an element of SE(2). pub type IsometryMatrix2 = Isometry>; -/// A 3-dimensional direct isometry using a rotation matrix for its rotational part. Also known as a rigid-body motion, or as an element of SE(3). +/// A 3-dimensional direct isometry using a rotation matrix for its rotational part. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Isometry`](crate::Isometry) type too.** +/// +/// Also known as a rigid-body motion, or as an element of SE(3). pub type IsometryMatrix3 = Isometry>; // This tests that the types correctly implement `Copy`, without having to run tests diff --git a/src/geometry/point_alias.rs b/src/geometry/point_alias.rs index 83f57301..05874ae4 100644 --- a/src/geometry/point_alias.rs +++ b/src/geometry/point_alias.rs @@ -3,14 +3,26 @@ use crate::base::dimension::{U1, U2, U3, U4, U5, U6}; use crate::geometry::Point; /// A statically sized 1-dimensional column point. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Point`](crate::Point) type too.** pub type Point1 = Point; /// A statically sized 2-dimensional column point. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Point`](crate::Point) type too.** pub type Point2 = Point; /// A statically sized 3-dimensional column point. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Point`](crate::Point) type too.** pub type Point3 = Point; /// A statically sized 4-dimensional column point. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Point`](crate::Point) type too.** pub type Point4 = Point; /// A statically sized 5-dimensional column point. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Point`](crate::Point) type too.** pub type Point5 = Point; /// A statically sized 6-dimensional column point. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Point`](crate::Point) type too.** pub type Point6 = Point; From 57723ef8fba2901a59388351aec306c1418225c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Crozet=20S=C3=A9bastien?= Date: Fri, 20 Nov 2020 17:52:32 +0100 Subject: [PATCH 3/6] Run cargo fmt. --- tests/linalg/qr.rs | 1 - tests/linalg/solve.rs | 1 - tests/linalg/tridiagonal.rs | 1 - 3 files changed, 3 deletions(-) diff --git a/tests/linalg/qr.rs b/tests/linalg/qr.rs index 93cb4973..a6e54af4 100644 --- a/tests/linalg/qr.rs +++ b/tests/linalg/qr.rs @@ -1,6 +1,5 @@ #![cfg(feature = "arbitrary")] - macro_rules! gen_tests( ($module: ident, $scalar: ty) => { mod $module { diff --git a/tests/linalg/solve.rs b/tests/linalg/solve.rs index e917cfc5..3bd6075e 100644 --- a/tests/linalg/solve.rs +++ b/tests/linalg/solve.rs @@ -1,6 +1,5 @@ #![cfg(feature = "arbitrary")] - macro_rules! gen_tests( ($module: ident, $scalar: ty) => { mod $module { diff --git a/tests/linalg/tridiagonal.rs b/tests/linalg/tridiagonal.rs index 7f7300a1..b787fd12 100644 --- a/tests/linalg/tridiagonal.rs +++ b/tests/linalg/tridiagonal.rs @@ -1,6 +1,5 @@ #![cfg(feature = "arbitrary")] - macro_rules! gen_tests( ($module: ident, $scalar: ty) => { mod $module { From 99ac7a8e082e67aac49f9342092fd8c8362c32a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Crozet=20S=C3=A9bastien?= Date: Sat, 21 Nov 2020 11:21:47 +0100 Subject: [PATCH 4/6] Add sections to the Rotation documentation --- src/geometry/isometry.rs | 9 +- src/geometry/isometry_interpolation.rs | 3 +- src/geometry/mod.rs | 3 +- src/geometry/rotation.rs | 107 ++++-- src/geometry/rotation_alias.rs | 4 + src/geometry/rotation_construction.rs | 1 + src/geometry/rotation_interpolation.rs | 78 ++++ src/geometry/rotation_specialization.rs | 464 +++++++++++------------- 8 files changed, 372 insertions(+), 297 deletions(-) create mode 100644 src/geometry/rotation_interpolation.rs diff --git a/src/geometry/isometry.rs b/src/geometry/isometry.rs index b2228301..7a630bed 100755 --- a/src/geometry/isometry.rs +++ b/src/geometry/isometry.rs @@ -30,10 +30,6 @@ use crate::geometry::{AbstractRotation, Point, Translation}; /// - 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 @@ -47,13 +43,12 @@ use crate::geometry::{AbstractRotation, Point, Translation}; /// * [From the translation and rotation parts `from_parts`…](#from-the-translation-and-rotation-parts) /// /// # Transformation and composition -/// Note that transforming vectors and points can be done bu multiplication, e.g., `isometry * point`. +/// Note that transforming vectors and points can be done by 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 `transform_vector`, `inverse_transform_point`…](#transformation-of-a-vector-or-a-point) /// * [Inversion and in-place composition `inverse`, `append_rotation_wrt_point_mut`…](#inversion-and-in-place-composition) -/// * [2D interpolation `lerp_slerp`…](#2d-interpolation) -/// * [3D interpolation `lerp_slerp`…](#3d-interpolation) +/// * [Interpolation `lerp_slerp`…](#interpolation) /// /// # Conversion to a matrix /// * [Conversion to a matrix `to_matrix`…](#conversion-to-a-matrix) diff --git a/src/geometry/isometry_interpolation.rs b/src/geometry/isometry_interpolation.rs index 50e3f305..f58b4115 100644 --- a/src/geometry/isometry_interpolation.rs +++ b/src/geometry/isometry_interpolation.rs @@ -1,6 +1,6 @@ use crate::{Isometry2, Isometry3, IsometryMatrix2, IsometryMatrix3, RealField, SimdRealField}; -/// # 3D interpolation +/// # Interpolation impl Isometry3 { /// Interpolates between two isometries using a linear interpolation for the translation part, /// and a spherical interpolation for the rotation part. @@ -137,7 +137,6 @@ impl IsometryMatrix3 { } } -/// # 2D interpolation impl Isometry2 { /// Interpolates between two isometries using a linear interpolation for the translation part, /// and a spherical interpolation for the rotation part. diff --git a/src/geometry/mod.rs b/src/geometry/mod.rs index 25ef89f1..d3e2236a 100644 --- a/src/geometry/mod.rs +++ b/src/geometry/mod.rs @@ -21,6 +21,7 @@ mod rotation_alga; mod rotation_alias; mod rotation_construction; mod rotation_conversion; +mod rotation_interpolation; mod rotation_ops; mod rotation_simba; // TODO: implement Rotation methods. mod rotation_specialization; @@ -58,6 +59,7 @@ mod isometry_alga; mod isometry_alias; mod isometry_construction; mod isometry_conversion; +mod isometry_interpolation; mod isometry_ops; mod isometry_simba; @@ -83,7 +85,6 @@ mod transform_simba; mod reflection; -mod isometry_interpolation; mod orthographic; mod perspective; diff --git a/src/geometry/rotation.rs b/src/geometry/rotation.rs index c30a3a97..20985093 100755 --- a/src/geometry/rotation.rs +++ b/src/geometry/rotation.rs @@ -23,6 +23,36 @@ use crate::base::{DefaultAllocator, MatrixN, Scalar, Unit, VectorN}; use crate::geometry::Point; /// A rotation matrix. +/// +/// This is also known as an element of a Special Orthogonal (SO) group. +/// The `Rotation` type can either represent a 2D or 3D rotation, represented as a matrix. +/// For a rotation based on quaternions, see [`UnitQuaternion`](crate::UnitQuaternion) instead. +/// +/// Note that instead of using the [`Rotation`](crate::Rotation) type in your code directly, you should use one +/// of its aliases: [`Rotation2`](crate::Rotation2), or [`Rotation3`](crate::Rotation3). Though +/// keep in mind that all the documentation of all the methods of these aliases will also appears on +/// this page. +/// +/// # Construction +/// * [Identity `identity`](#identity) +/// * [From a 2D rotation angle `new`…](#construction-from-a-2d-rotation-angle) +/// * [From an existing 2D matrix or rotations `from_matrix`, `rotation_between`, `powf`…](#construction-from-an-existing-2d-matrix-or-rotations) +/// * [From a 3D axis and/or angles `new`, `from_euler_angles`, `from_axis_angle`…](#construction-from-a-3d-axis-andor-angles) +/// * [From a 3D eye position and target point `look_at`, `look_at_lh`, `rotation_between`…](#construction-from-a-3d-eye-position-and-target-point) +/// * [From an existing 3D matrix or rotations `from_matrix`, `rotation_between`, `powf`…](#construction-from-an-existing-3d-matrix-or-rotations) +/// +/// # Transformation and composition +/// Note that transforming vectors and points can be done by multiplication, e.g., `rotation * point`. +/// Composing an rotation with another transformation can also be done by multiplication or division. +/// * [3D axis and angle extraction `angle`, `euler_angles`, `scaled_axis`, `angle_to`…](#3d-axis-and-angle-extraction) +/// * [2D angle extraction `angle`, `angle_to`…](#2d-angle-extraction) +/// * [Transformation of a vector or a point `transform_vector`, `inverse_transform_point`…](#transformation-of-a-vector-or-a-point) +/// * [Transposition and inversion `transpose`, `inverse`…](#transposition-and-inversion) +/// * [Interpolation `slerp`…](#interpolation) +/// +/// # Conversion to a matrix +/// * [Conversion to a matrix `matrix`, `to_homogeneous`…](#conversion-to-a-matrix) +/// #[repr(C)] #[derive(Debug)] pub struct Rotation @@ -111,6 +141,44 @@ where } } +impl Rotation +where + DefaultAllocator: Allocator, +{ + /// Creates a new rotation from the given square matrix. + /// + /// The matrix squareness is checked but not its orthonormality. + /// + /// # Example + /// ``` + /// # use nalgebra::{Rotation2, Rotation3, Matrix2, Matrix3}; + /// # use std::f32; + /// let mat = Matrix3::new(0.8660254, -0.5, 0.0, + /// 0.5, 0.8660254, 0.0, + /// 0.0, 0.0, 1.0); + /// let rot = Rotation3::from_matrix_unchecked(mat); + /// + /// assert_eq!(*rot.matrix(), mat); + /// + /// + /// let mat = Matrix2::new(0.8660254, -0.5, + /// 0.5, 0.8660254); + /// let rot = Rotation2::from_matrix_unchecked(mat); + /// + /// assert_eq!(*rot.matrix(), mat); + /// ``` + #[inline] + pub fn from_matrix_unchecked(matrix: MatrixN) -> Self { + assert!( + matrix.is_square(), + "Unable to create a rotation from a non-square matrix." + ); + + Self { matrix } + } +} + +/// # Conversion to a matrix impl Rotation where DefaultAllocator: Allocator, @@ -225,39 +293,13 @@ where res } +} - /// Creates a new rotation from the given square matrix. - /// - /// The matrix squareness is checked but not its orthonormality. - /// - /// # Example - /// ``` - /// # use nalgebra::{Rotation2, Rotation3, Matrix2, Matrix3}; - /// # use std::f32; - /// let mat = Matrix3::new(0.8660254, -0.5, 0.0, - /// 0.5, 0.8660254, 0.0, - /// 0.0, 0.0, 1.0); - /// let rot = Rotation3::from_matrix_unchecked(mat); - /// - /// assert_eq!(*rot.matrix(), mat); - /// - /// - /// let mat = Matrix2::new(0.8660254, -0.5, - /// 0.5, 0.8660254); - /// let rot = Rotation2::from_matrix_unchecked(mat); - /// - /// assert_eq!(*rot.matrix(), mat); - /// ``` - #[inline] - pub fn from_matrix_unchecked(matrix: MatrixN) -> Self { - assert!( - matrix.is_square(), - "Unable to create a rotation from a non-square matrix." - ); - - Self { matrix } - } - +/// # Transposition and inversion +impl Rotation +where + DefaultAllocator: Allocator, +{ /// Transposes `self`. /// /// Same as `.inverse()` because the inverse of a rotation matrix is its transform. @@ -361,6 +403,7 @@ where } } +/// # Transformation of a vector or a point impl Rotation where N::Element: SimdRealField, diff --git a/src/geometry/rotation_alias.rs b/src/geometry/rotation_alias.rs index 9fa5c2d0..f9e0230b 100644 --- a/src/geometry/rotation_alias.rs +++ b/src/geometry/rotation_alias.rs @@ -3,7 +3,11 @@ use crate::base::dimension::{U2, U3}; use crate::geometry::Rotation; /// A 2-dimensional rotation matrix. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Rotation`](crate::Rotation) type too.** pub type Rotation2 = Rotation; /// A 3-dimensional rotation matrix. +/// +/// **Because this is an alias, not all its methods are listed here. See the [`Rotation`](crate::Rotation) type too.** pub type Rotation3 = Rotation; diff --git a/src/geometry/rotation_construction.rs b/src/geometry/rotation_construction.rs index 12d93402..c351f373 100644 --- a/src/geometry/rotation_construction.rs +++ b/src/geometry/rotation_construction.rs @@ -8,6 +8,7 @@ use crate::base::{DefaultAllocator, MatrixN, Scalar}; use crate::geometry::Rotation; +/// # Identity impl Rotation where N: Scalar + Zero + One, diff --git a/src/geometry/rotation_interpolation.rs b/src/geometry/rotation_interpolation.rs new file mode 100644 index 00000000..5f861428 --- /dev/null +++ b/src/geometry/rotation_interpolation.rs @@ -0,0 +1,78 @@ +use crate::{RealField, Rotation2, Rotation3, SimdRealField, UnitComplex, UnitQuaternion}; + +/// # Interpolation +impl Rotation2 { + /// Spherical linear interpolation between two rotation matrices. + /// + /// # Examples: + /// + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::geometry::Rotation2; + /// + /// let rot1 = Rotation2::new(std::f32::consts::FRAC_PI_4); + /// let rot2 = Rotation2::new(-std::f32::consts::PI); + /// + /// let rot = rot1.slerp(&rot2, 1.0 / 3.0); + /// + /// assert_relative_eq!(rot.angle(), std::f32::consts::FRAC_PI_2); + /// ``` + #[inline] + pub fn slerp(&self, other: &Self, t: N) -> Self + where + N::Element: SimdRealField, + { + let c1 = UnitComplex::from(*self); + let c2 = UnitComplex::from(*other); + c1.slerp(&c2, t).into() + } +} + +impl Rotation3 { + /// Spherical linear interpolation between two rotation matrices. + /// + /// Panics if the angle between both rotations is 180 degrees (in which case the interpolation + /// is not well-defined). Use `.try_slerp` instead to avoid the panic. + /// + /// # Examples: + /// + /// ``` + /// # use nalgebra::geometry::Rotation3; + /// + /// 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 q = q1.slerp(&q2, 1.0 / 3.0); + /// + /// assert_eq!(q.euler_angles(), (std::f32::consts::FRAC_PI_2, 0.0, 0.0)); + /// ``` + #[inline] + pub fn slerp(&self, other: &Self, t: N) -> Self + where + N: RealField, + { + let q1 = UnitQuaternion::from(*self); + let q2 = UnitQuaternion::from(*other); + q1.slerp(&q2, t).into() + } + + /// Computes the spherical linear interpolation between two rotation matrices or returns `None` + /// if both rotations are approximately 180 degrees apart (in which case the interpolation is + /// not well-defined). + /// + /// # Arguments + /// * `self`: the first rotation to interpolate from. + /// * `other`: the second rotation to interpolate toward. + /// * `t`: the interpolation parameter. Should be between 0 and 1. + /// * `epsilon`: the value below which the sinus of the angle separating both rotations + /// must be to return `None`. + #[inline] + pub fn try_slerp(&self, other: &Self, t: N, epsilon: N) -> Option + where + N: RealField, + { + let q1 = Rotation3::from(*self); + let q2 = Rotation3::from(*other); + q1.try_slerp(&q2, t, epsilon).map(|q| q.into()) + } +} diff --git a/src/geometry/rotation_specialization.rs b/src/geometry/rotation_specialization.rs index 5cb7cb33..afc180d8 100644 --- a/src/geometry/rotation_specialization.rs +++ b/src/geometry/rotation_specialization.rs @@ -21,6 +21,7 @@ use crate::geometry::{Rotation2, Rotation3, UnitComplex, UnitQuaternion}; * 2D Rotation matrix. * */ +/// # Construction from a 2D rotation angle impl Rotation2 { /// Builds a 2 dimensional rotation matrix from an angle in radian. /// @@ -48,7 +49,10 @@ impl Rotation2 { pub fn from_scaled_axis>(axisangle: Vector) -> Self { Self::new(axisangle[0]) } +} +/// # Construction from an existing 2D matrix or rotations +impl Rotation2 { /// Builds a rotation matrix by extracting the rotation part of the given transformation `m`. /// /// This is an iterative method. See `.from_matrix_eps` to provide mover @@ -150,35 +154,6 @@ impl Rotation2 { crate::convert(UnitComplex::scaled_rotation_between(a, b, s).to_rotation_matrix()) } - /// The rotation angle. - /// - /// # Example - /// ``` - /// # #[macro_use] extern crate approx; - /// # use nalgebra::Rotation2; - /// let rot = Rotation2::new(1.78); - /// assert_relative_eq!(rot.angle(), 1.78); - /// ``` - #[inline] - pub fn angle(&self) -> N { - self.matrix()[(1, 0)].simd_atan2(self.matrix()[(0, 0)]) - } - - /// The rotation angle needed to make `self` and `other` coincide. - /// - /// # Example - /// ``` - /// # #[macro_use] extern crate approx; - /// # use nalgebra::Rotation2; - /// let rot1 = Rotation2::new(0.1); - /// let rot2 = Rotation2::new(1.7); - /// assert_relative_eq!(rot1.angle_to(&rot2), 1.6); - /// ``` - #[inline] - pub fn angle_to(&self, other: &Self) -> N { - self.rotation_to(other).angle() - } - /// The rotation matrix needed to make `self` and `other` coincide. /// /// The result is such that: `self.rotation_to(other) * self == other`. @@ -227,6 +202,38 @@ impl Rotation2 { pub fn powf(&self, n: N) -> Self { Self::new(self.angle() * n) } +} + +/// # 2D angle extraction +impl Rotation2 { + /// The rotation angle. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::Rotation2; + /// let rot = Rotation2::new(1.78); + /// assert_relative_eq!(rot.angle(), 1.78); + /// ``` + #[inline] + pub fn angle(&self) -> N { + self.matrix()[(1, 0)].simd_atan2(self.matrix()[(0, 0)]) + } + + /// The rotation angle needed to make `self` and `other` coincide. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::Rotation2; + /// let rot1 = Rotation2::new(0.1); + /// let rot2 = Rotation2::new(1.7); + /// assert_relative_eq!(rot1.angle_to(&rot2), 1.6); + /// ``` + #[inline] + pub fn angle_to(&self, other: &Self) -> N { + self.rotation_to(other).angle() + } /// The rotation angle returned as a 1-dimensional vector. /// @@ -236,31 +243,6 @@ impl Rotation2 { pub fn scaled_axis(&self) -> VectorN { Vector1::new(self.angle()) } - - /// Spherical linear interpolation between two rotation matrices. - /// - /// # Examples: - /// - /// ``` - /// # #[macro_use] extern crate approx; - /// # use nalgebra::geometry::Rotation2; - /// - /// let rot1 = Rotation2::new(std::f32::consts::FRAC_PI_4); - /// let rot2 = Rotation2::new(-std::f32::consts::PI); - /// - /// let rot = rot1.slerp(&rot2, 1.0 / 3.0); - /// - /// assert_relative_eq!(rot.angle(), std::f32::consts::FRAC_PI_2); - /// ``` - #[inline] - pub fn slerp(&self, other: &Self, t: N) -> Self - where - N::Element: SimdRealField, - { - let c1 = UnitComplex::from(*self); - let c2 = UnitComplex::from(*other); - c1.slerp(&c2, t).into() - } } impl Distribution> for Standard @@ -292,6 +274,7 @@ where * 3D Rotation matrix. * */ +/// # Construction from a 3D axis and/or angles impl Rotation3 where N::Element: SimdRealField, @@ -325,60 +308,6 @@ where Self::from_axis_angle(&axis, angle) } - /// Builds a rotation matrix by extracting the rotation part of the given transformation `m`. - /// - /// This is an iterative method. See `.from_matrix_eps` to provide mover - /// convergence parameters and starting solution. - /// This implements "A Robust Method to Extract the Rotational Part of Deformations" by Müller et al. - pub fn from_matrix(m: &Matrix3) -> Self - where - N: RealField, - { - Self::from_matrix_eps(m, N::default_epsilon(), 0, Self::identity()) - } - - /// Builds a rotation matrix by extracting the rotation part of the given transformation `m`. - /// - /// This implements "A Robust Method to Extract the Rotational Part of Deformations" by Müller et al. - /// - /// # Parameters - /// - /// * `m`: the matrix from which the rotational part is to be extracted. - /// * `eps`: the angular errors tolerated between the current rotation and the optimal one. - /// * `max_iter`: the maximum number of iterations. Loops indefinitely until convergence if set to `0`. - /// * `guess`: a guess of the solution. Convergence will be significantly faster if an initial solution close - /// to the actual solution is provided. Can be set to `Rotation3::identity()` if no other - /// guesses come to mind. - pub fn from_matrix_eps(m: &Matrix3, eps: N, mut max_iter: usize, guess: Self) -> Self - where - N: RealField, - { - if max_iter == 0 { - max_iter = usize::max_value(); - } - - let mut rot = guess.into_inner(); - - for _ in 0..max_iter { - let axis = rot.column(0).cross(&m.column(0)) - + rot.column(1).cross(&m.column(1)) - + rot.column(2).cross(&m.column(2)); - let denom = rot.column(0).dot(&m.column(0)) - + rot.column(1).dot(&m.column(1)) - + rot.column(2).dot(&m.column(2)); - - let axisangle = axis / (denom.abs() + N::default_epsilon()); - - if let Some((axis, angle)) = Unit::try_new_and_get(axisangle, eps) { - rot = Rotation3::from_axis_angle(&axis, angle) * rot; - } else { - break; - } - } - - Self::from_matrix_unchecked(rot) - } - /// Builds a 3D rotation matrix from an axis scaled by the rotation angle. /// /// This is the same as `Self::new(axisangle)`. @@ -488,67 +417,13 @@ where cp * cr, )) } +} - /// Creates Euler angles from a rotation. - /// - /// The angles are produced in the form (roll, pitch, yaw). - #[deprecated(note = "This is renamed to use `.euler_angles()`.")] - pub fn to_euler_angles(&self) -> (N, N, N) - where - N: RealField, - { - self.euler_angles() - } - - /// Euler angles corresponding to this rotation from a rotation. - /// - /// The angles are produced in the form (roll, pitch, yaw). - /// - /// # Example - /// ``` - /// # #[macro_use] extern crate approx; - /// # use nalgebra::Rotation3; - /// let rot = Rotation3::from_euler_angles(0.1, 0.2, 0.3); - /// let euler = rot.euler_angles(); - /// assert_relative_eq!(euler.0, 0.1, epsilon = 1.0e-6); - /// assert_relative_eq!(euler.1, 0.2, epsilon = 1.0e-6); - /// assert_relative_eq!(euler.2, 0.3, epsilon = 1.0e-6); - /// ``` - pub fn euler_angles(&self) -> (N, N, N) - where - N: RealField, - { - // Implementation informed by "Computing Euler angles from a rotation matrix", by Gregory G. Slabaugh - // https://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.371.6578 - if self[(2, 0)].abs() < N::one() { - let yaw = -self[(2, 0)].asin(); - let roll = (self[(2, 1)] / yaw.cos()).atan2(self[(2, 2)] / yaw.cos()); - let pitch = (self[(1, 0)] / yaw.cos()).atan2(self[(0, 0)] / yaw.cos()); - (roll, yaw, pitch) - } else if self[(2, 0)] <= -N::one() { - (self[(0, 1)].atan2(self[(0, 2)]), N::frac_pi_2(), N::zero()) - } else { - ( - -self[(0, 1)].atan2(-self[(0, 2)]), - -N::frac_pi_2(), - N::zero(), - ) - } - } - - /// Ensure this rotation is an orthonormal rotation matrix. This is useful when repeated - /// computations might cause the matrix from progressively not being orthonormal anymore. - #[inline] - pub fn renormalize(&mut self) - where - N: RealField, - { - let mut c = UnitQuaternion::from(*self); - let _ = c.renormalize(); - - *self = Self::from_matrix_eps(self.matrix(), N::default_epsilon(), 0, c.into()) - } - +/// # Construction from a 3D eye position and target point +impl Rotation3 +where + N::Element: SimdRealField, +{ /// Creates a rotation that corresponds to the local frame of an observer standing at the /// origin and looking toward `dir`. /// @@ -656,7 +531,13 @@ where { Self::face_towards(dir, up).inverse() } +} +/// # Construction from an existing 3D matrix or rotations +impl Rotation3 +where + N::Element: SimdRealField, +{ /// The rotation matrix required to align `a` and `b` but with its angle. /// /// This is the rotation `R` such that `(R * a).angle(b) == 0 && (R * a).dot(b).is_positive()`. @@ -727,6 +608,123 @@ where Some(Self::identity()) } + /// The rotation matrix needed to make `self` and `other` coincide. + /// + /// The result is such that: `self.rotation_to(other) * self == other`. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{Rotation3, Vector3}; + /// let rot1 = Rotation3::from_axis_angle(&Vector3::y_axis(), 1.0); + /// let rot2 = Rotation3::from_axis_angle(&Vector3::x_axis(), 0.1); + /// let rot_to = rot1.rotation_to(&rot2); + /// assert_relative_eq!(rot_to * rot1, rot2, epsilon = 1.0e-6); + /// ``` + #[inline] + pub fn rotation_to(&self, other: &Self) -> Self { + other * self.inverse() + } + + /// Raise the quaternion to a given floating power, i.e., returns the rotation with the same + /// axis as `self` and an angle equal to `self.angle()` multiplied by `n`. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::{Rotation3, Vector3, Unit}; + /// let axis = Unit::new_normalize(Vector3::new(1.0, 2.0, 3.0)); + /// let angle = 1.2; + /// let rot = Rotation3::from_axis_angle(&axis, angle); + /// let pow = rot.powf(2.0); + /// assert_relative_eq!(pow.axis().unwrap(), axis, epsilon = 1.0e-6); + /// assert_eq!(pow.angle(), 2.4); + /// ``` + #[inline] + pub fn powf(&self, n: N) -> Self + where + N: RealField, + { + if let Some(axis) = self.axis() { + Self::from_axis_angle(&axis, self.angle() * n) + } else if self.matrix()[(0, 0)] < N::zero() { + let minus_id = MatrixN::::from_diagonal_element(-N::one()); + Self::from_matrix_unchecked(minus_id) + } else { + Self::identity() + } + } + + /// Builds a rotation matrix by extracting the rotation part of the given transformation `m`. + /// + /// This is an iterative method. See `.from_matrix_eps` to provide mover + /// convergence parameters and starting solution. + /// This implements "A Robust Method to Extract the Rotational Part of Deformations" by Müller et al. + pub fn from_matrix(m: &Matrix3) -> Self + where + N: RealField, + { + Self::from_matrix_eps(m, N::default_epsilon(), 0, Self::identity()) + } + + /// Builds a rotation matrix by extracting the rotation part of the given transformation `m`. + /// + /// This implements "A Robust Method to Extract the Rotational Part of Deformations" by Müller et al. + /// + /// # Parameters + /// + /// * `m`: the matrix from which the rotational part is to be extracted. + /// * `eps`: the angular errors tolerated between the current rotation and the optimal one. + /// * `max_iter`: the maximum number of iterations. Loops indefinitely until convergence if set to `0`. + /// * `guess`: a guess of the solution. Convergence will be significantly faster if an initial solution close + /// to the actual solution is provided. Can be set to `Rotation3::identity()` if no other + /// guesses come to mind. + pub fn from_matrix_eps(m: &Matrix3, eps: N, mut max_iter: usize, guess: Self) -> Self + where + N: RealField, + { + if max_iter == 0 { + max_iter = usize::max_value(); + } + + let mut rot = guess.into_inner(); + + for _ in 0..max_iter { + let axis = rot.column(0).cross(&m.column(0)) + + rot.column(1).cross(&m.column(1)) + + rot.column(2).cross(&m.column(2)); + let denom = rot.column(0).dot(&m.column(0)) + + rot.column(1).dot(&m.column(1)) + + rot.column(2).dot(&m.column(2)); + + let axisangle = axis / (denom.abs() + N::default_epsilon()); + + if let Some((axis, angle)) = Unit::try_new_and_get(axisangle, eps) { + rot = Rotation3::from_axis_angle(&axis, angle) * rot; + } else { + break; + } + } + + Self::from_matrix_unchecked(rot) + } + + /// Ensure this rotation is an orthonormal rotation matrix. This is useful when repeated + /// computations might cause the matrix from progressively not being orthonormal anymore. + #[inline] + pub fn renormalize(&mut self) + where + N: RealField, + { + let mut c = UnitQuaternion::from(*self); + let _ = c.renormalize(); + + *self = Self::from_matrix_eps(self.matrix(), N::default_epsilon(), 0, c.into()) + } +} + +/// # 3D axis and angle extraction +impl Rotation3 { /// The rotation angle in [0; pi]. /// /// # Example @@ -837,103 +835,59 @@ where /// assert_relative_eq!(rot1.angle_to(&rot2), 1.0045657, epsilon = 1.0e-6); /// ``` #[inline] - pub fn angle_to(&self, other: &Self) -> N { + pub fn angle_to(&self, other: &Self) -> N + where + N::Element: SimdRealField, + { self.rotation_to(other).angle() } - /// The rotation matrix needed to make `self` and `other` coincide. + /// Creates Euler angles from a rotation. /// - /// The result is such that: `self.rotation_to(other) * self == other`. - /// - /// # Example - /// ``` - /// # #[macro_use] extern crate approx; - /// # use nalgebra::{Rotation3, Vector3}; - /// let rot1 = Rotation3::from_axis_angle(&Vector3::y_axis(), 1.0); - /// let rot2 = Rotation3::from_axis_angle(&Vector3::x_axis(), 0.1); - /// let rot_to = rot1.rotation_to(&rot2); - /// assert_relative_eq!(rot_to * rot1, rot2, epsilon = 1.0e-6); - /// ``` - #[inline] - pub fn rotation_to(&self, other: &Self) -> Self { - other * self.inverse() - } - - /// Raise the quaternion to a given floating power, i.e., returns the rotation with the same - /// axis as `self` and an angle equal to `self.angle()` multiplied by `n`. - /// - /// # Example - /// ``` - /// # #[macro_use] extern crate approx; - /// # use nalgebra::{Rotation3, Vector3, Unit}; - /// let axis = Unit::new_normalize(Vector3::new(1.0, 2.0, 3.0)); - /// let angle = 1.2; - /// let rot = Rotation3::from_axis_angle(&axis, angle); - /// let pow = rot.powf(2.0); - /// assert_relative_eq!(pow.axis().unwrap(), axis, epsilon = 1.0e-6); - /// assert_eq!(pow.angle(), 2.4); - /// ``` - #[inline] - pub fn powf(&self, n: N) -> Self + /// The angles are produced in the form (roll, pitch, yaw). + #[deprecated(note = "This is renamed to use `.euler_angles()`.")] + pub fn to_euler_angles(&self) -> (N, N, N) where N: RealField, { - if let Some(axis) = self.axis() { - Self::from_axis_angle(&axis, self.angle() * n) - } else if self.matrix()[(0, 0)] < N::zero() { - let minus_id = MatrixN::::from_diagonal_element(-N::one()); - Self::from_matrix_unchecked(minus_id) + self.euler_angles() + } + + /// Euler angles corresponding to this rotation from a rotation. + /// + /// The angles are produced in the form (roll, pitch, yaw). + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::Rotation3; + /// let rot = Rotation3::from_euler_angles(0.1, 0.2, 0.3); + /// let euler = rot.euler_angles(); + /// assert_relative_eq!(euler.0, 0.1, epsilon = 1.0e-6); + /// assert_relative_eq!(euler.1, 0.2, epsilon = 1.0e-6); + /// assert_relative_eq!(euler.2, 0.3, epsilon = 1.0e-6); + /// ``` + pub fn euler_angles(&self) -> (N, N, N) + where + N: RealField, + { + // Implementation informed by "Computing Euler angles from a rotation matrix", by Gregory G. Slabaugh + // https://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.371.6578 + if self[(2, 0)].abs() < N::one() { + let yaw = -self[(2, 0)].asin(); + let roll = (self[(2, 1)] / yaw.cos()).atan2(self[(2, 2)] / yaw.cos()); + let pitch = (self[(1, 0)] / yaw.cos()).atan2(self[(0, 0)] / yaw.cos()); + (roll, yaw, pitch) + } else if self[(2, 0)] <= -N::one() { + (self[(0, 1)].atan2(self[(0, 2)]), N::frac_pi_2(), N::zero()) } else { - Self::identity() + ( + -self[(0, 1)].atan2(-self[(0, 2)]), + -N::frac_pi_2(), + N::zero(), + ) } } - - /// Spherical linear interpolation between two rotation matrices. - /// - /// Panics if the angle between both rotations is 180 degrees (in which case the interpolation - /// is not well-defined). Use `.try_slerp` instead to avoid the panic. - /// - /// # Examples: - /// - /// ``` - /// # use nalgebra::geometry::Rotation3; - /// - /// 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 q = q1.slerp(&q2, 1.0 / 3.0); - /// - /// assert_eq!(q.euler_angles(), (std::f32::consts::FRAC_PI_2, 0.0, 0.0)); - /// ``` - #[inline] - pub fn slerp(&self, other: &Self, t: N) -> Self - where - N: RealField, - { - let q1 = UnitQuaternion::from(*self); - let q2 = UnitQuaternion::from(*other); - q1.slerp(&q2, t).into() - } - - /// Computes the spherical linear interpolation between two rotation matrices or returns `None` - /// if both rotations are approximately 180 degrees apart (in which case the interpolation is - /// not well-defined). - /// - /// # Arguments - /// * `self`: the first rotation to interpolate from. - /// * `other`: the second rotation to interpolate toward. - /// * `t`: the interpolation parameter. Should be between 0 and 1. - /// * `epsilon`: the value below which the sinus of the angle separating both rotations - /// must be to return `None`. - #[inline] - pub fn try_slerp(&self, other: &Self, t: N, epsilon: N) -> Option - where - N: RealField, - { - let q1 = Rotation3::from(*self); - let q2 = Rotation3::from(*other); - q1.try_slerp(&q2, t, epsilon).map(|q| q.into()) - } } impl Distribution> for Standard From c1372c3041eb5131b2a6538b83f4823ab437462e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Crozet=20S=C3=A9bastien?= Date: Sat, 21 Nov 2020 11:56:24 +0100 Subject: [PATCH 5/6] Add sections to the UnitComplex documentation --- src/geometry/rotation.rs | 2 +- src/geometry/unit_complex.rs | 119 ++++++++++------------ src/geometry/unit_complex_construction.rs | 75 ++++++++++++++ 3 files changed, 129 insertions(+), 67 deletions(-) diff --git a/src/geometry/rotation.rs b/src/geometry/rotation.rs index 20985093..e4f69fe6 100755 --- a/src/geometry/rotation.rs +++ b/src/geometry/rotation.rs @@ -50,7 +50,7 @@ use crate::geometry::Point; /// * [Transposition and inversion `transpose`, `inverse`…](#transposition-and-inversion) /// * [Interpolation `slerp`…](#interpolation) /// -/// # Conversion to a matrix +/// # Conversion /// * [Conversion to a matrix `matrix`, `to_homogeneous`…](#conversion-to-a-matrix) /// #[repr(C)] diff --git a/src/geometry/unit_complex.rs b/src/geometry/unit_complex.rs index 76d7f392..40148454 100755 --- a/src/geometry/unit_complex.rs +++ b/src/geometry/unit_complex.rs @@ -7,7 +7,26 @@ use crate::geometry::{Point2, Rotation2}; use simba::scalar::RealField; use simba::simd::SimdRealField; -/// A complex number with a norm equal to 1. +/// A 2D rotation represented as a complex number with magnitude 1. +/// +/// All the methods specific [`UnitComplex`](crate::UnitComplex) are listed here. You may also +/// read the documentation of the [`Complex`](crate::Complex) type which +/// is used internally and accessible with `unit_complex.complex()`. +/// +/// # Construction +/// * [Identity `identity`](#identity) +/// * [From a 2D rotation angle `new`, `from_cos_sin_unchecked`…](#construction-from-a-2d-rotation-angle) +/// * [From an existing 2D matrix or complex number `from_matrix`, `rotation_to`, `powf`…](#construction-from-an-existing-2d-matrix-or-complex-number) +/// * [From two vectors `rotation_between`, `scaled_rotation_between_axis`…](#construction-from-two-vectors) +/// +/// # Transformation and composition +/// * [Angle extraction `angle`, `angle_to`…](#angle-extraction) +/// * [Transformation of a vector or a point `transform_vector`, `inverse_transform_point`…](#transformation-of-a-vector-or-a-point) +/// * [Conjugation and inversion `conjugate`, `inverse_mut`…](#conjugation-and-inversion) +/// * [Interpolation `slerp`…](#interpolation) +/// +/// # Conversion +/// * [Conversion to a matrix `to_rotation_matrix`, `to_homogeneous`…](#conversion-to-a-matrix) pub type UnitComplex = Unit>; impl Normed for Complex { @@ -40,6 +59,7 @@ impl Normed for Complex { } } +/// # Angle extraction impl UnitComplex where N::Element: SimdRealField, @@ -115,24 +135,28 @@ where } } - /// The underlying complex number. - /// - /// Same as `self.as_ref()`. + /// The rotation angle needed to make `self` and `other` coincide. /// /// # Example /// ``` - /// # extern crate num_complex; - /// # use num_complex::Complex; + /// # #[macro_use] extern crate approx; /// # use nalgebra::UnitComplex; - /// let angle = 1.78f32; - /// let rot = UnitComplex::new(angle); - /// assert_eq!(*rot.complex(), Complex::new(angle.cos(), angle.sin())); + /// let rot1 = UnitComplex::new(0.1); + /// let rot2 = UnitComplex::new(1.7); + /// assert_relative_eq!(rot1.angle_to(&rot2), 1.6); /// ``` #[inline] - pub fn complex(&self) -> &Complex { - self.as_ref() + pub fn angle_to(&self, other: &Self) -> N { + let delta = self.rotation_to(other); + delta.angle() } +} +/// # Conjugation and inversion +impl UnitComplex +where + N::Element: SimdRealField, +{ /// Compute the conjugate of this unit complex number. /// /// # Example @@ -166,42 +190,6 @@ where self.conjugate() } - /// The rotation angle needed to make `self` and `other` coincide. - /// - /// # Example - /// ``` - /// # #[macro_use] extern crate approx; - /// # use nalgebra::UnitComplex; - /// let rot1 = UnitComplex::new(0.1); - /// let rot2 = UnitComplex::new(1.7); - /// assert_relative_eq!(rot1.angle_to(&rot2), 1.6); - /// ``` - #[inline] - pub fn angle_to(&self, other: &Self) -> N { - let delta = self.rotation_to(other); - delta.angle() - } - - /// The unit complex number needed to make `self` and `other` coincide. - /// - /// The result is such that: `self.rotation_to(other) * self == other`. - /// - /// # Example - /// ``` - /// # #[macro_use] extern crate approx; - /// # use nalgebra::UnitComplex; - /// let rot1 = UnitComplex::new(0.1); - /// let rot2 = UnitComplex::new(1.7); - /// let rot_to = rot1.rotation_to(&rot2); - /// - /// assert_relative_eq!(rot_to * rot1, rot2); - /// assert_relative_eq!(rot_to.inverse() * rot2, rot1); - /// ``` - #[inline] - pub fn rotation_to(&self, other: &Self) -> Self { - other / self - } - /// Compute in-place the conjugate of this unit complex number. /// /// # Example @@ -237,25 +225,13 @@ where pub fn inverse_mut(&mut self) { self.conjugate_mut() } +} - /// Raise this unit complex number to a given floating power. - /// - /// This returns the unit complex number that identifies a rotation angle equal to - /// `self.angle() × n`. - /// - /// # Example - /// ``` - /// # #[macro_use] extern crate approx; - /// # use nalgebra::UnitComplex; - /// let rot = UnitComplex::new(0.78); - /// let pow = rot.powf(2.0); - /// assert_relative_eq!(pow.angle(), 2.0 * 0.78); - /// ``` - #[inline] - pub fn powf(&self, n: N) -> Self { - Self::from_angle(self.angle() * n) - } - +/// # Conversion to a matrix +impl UnitComplex +where + N::Element: SimdRealField, +{ /// Builds the rotation matrix corresponding to this unit complex number. /// /// # Example @@ -290,7 +266,13 @@ where pub fn to_homogeneous(&self) -> Matrix3 { self.to_rotation_matrix().to_homogeneous() } +} +/// # Transformation of a vector or a point +impl UnitComplex +where + N::Element: SimdRealField, +{ /// Rotate the given point by this unit complex number. /// /// This is the same as the multiplication `self * pt`. @@ -376,7 +358,13 @@ where pub fn inverse_transform_unit_vector(&self, v: &Unit>) -> Unit> { self.inverse() * v } +} +/// # Interpolation +impl UnitComplex +where + N::Element: SimdRealField, +{ /// Spherical linear interpolation between two rotations represented as unit complex numbers. /// /// # Examples: @@ -392,7 +380,6 @@ where /// /// assert_relative_eq!(rot.angle(), std::f32::consts::FRAC_PI_2); /// ``` - #[inline] pub fn slerp(&self, other: &Self, t: N) -> Self { Self::new(self.angle() * (N::one() - t) + other.angle() * t) diff --git a/src/geometry/unit_complex_construction.rs b/src/geometry/unit_complex_construction.rs index 826b5671..65d36888 100644 --- a/src/geometry/unit_complex_construction.rs +++ b/src/geometry/unit_complex_construction.rs @@ -13,6 +13,7 @@ use crate::geometry::{Rotation2, UnitComplex}; use simba::scalar::RealField; use simba::simd::SimdRealField; +/// # Identity impl UnitComplex where N::Element: SimdRealField, @@ -32,7 +33,13 @@ where pub fn identity() -> Self { Self::new_unchecked(Complex::new(N::one(), N::zero())) } +} +/// # Construction from a 2D rotation angle +impl UnitComplex +where + N::Element: SimdRealField, +{ /// Builds the unit complex number corresponding to the rotation with the given angle. /// /// # Example @@ -100,6 +107,30 @@ where pub fn from_scaled_axis>(axisangle: Vector) -> Self { Self::from_angle(axisangle[0]) } +} + +/// # Construction from an existing 2D matrix or complex number +impl UnitComplex +where + N::Element: SimdRealField, +{ + /// The underlying complex number. + /// + /// Same as `self.as_ref()`. + /// + /// # Example + /// ``` + /// # extern crate num_complex; + /// # use num_complex::Complex; + /// # use nalgebra::UnitComplex; + /// let angle = 1.78f32; + /// let rot = UnitComplex::new(angle); + /// assert_eq!(*rot.complex(), Complex::new(angle.cos(), angle.sin())); + /// ``` + #[inline] + pub fn complex(&self) -> &Complex { + self.as_ref() + } /// Creates a new unit complex number from a complex number. /// @@ -165,6 +196,50 @@ where Rotation2::from_matrix_eps(m, eps, max_iter, guess).into() } + /// The unit complex number needed to make `self` and `other` coincide. + /// + /// The result is such that: `self.rotation_to(other) * self == other`. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::UnitComplex; + /// let rot1 = UnitComplex::new(0.1); + /// let rot2 = UnitComplex::new(1.7); + /// let rot_to = rot1.rotation_to(&rot2); + /// + /// assert_relative_eq!(rot_to * rot1, rot2); + /// assert_relative_eq!(rot_to.inverse() * rot2, rot1); + /// ``` + #[inline] + pub fn rotation_to(&self, other: &Self) -> Self { + other / self + } + + /// Raise this unit complex number to a given floating power. + /// + /// This returns the unit complex number that identifies a rotation angle equal to + /// `self.angle() × n`. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # use nalgebra::UnitComplex; + /// let rot = UnitComplex::new(0.78); + /// let pow = rot.powf(2.0); + /// assert_relative_eq!(pow.angle(), 2.0 * 0.78); + /// ``` + #[inline] + pub fn powf(&self, n: N) -> Self { + Self::from_angle(self.angle() * n) + } +} + +/// # Construction from two vectors +impl UnitComplex +where + N::Element: SimdRealField, +{ /// The unit complex needed to make `a` and `b` be collinear and point toward the same /// direction. /// From 651d318c26566ceac9062cd0b3f9be2d27eb92c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Crozet=20S=C3=A9bastien?= Date: Sat, 21 Nov 2020 12:19:04 +0100 Subject: [PATCH 6/6] Add sections to the Unit wrapper documentation --- src/base/interpolation.rs | 1 + src/base/unit.rs | 11 ++++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/base/interpolation.rs b/src/base/interpolation.rs index afd3ccc7..1d74d203 100644 --- a/src/base/interpolation.rs +++ b/src/base/interpolation.rs @@ -56,6 +56,7 @@ impl> Unit> { /// Computes the spherical linear interpolation between two unit vectors. /// diff --git a/src/base/unit.rs b/src/base/unit.rs index 5afa006b..20ca4603 100644 --- a/src/base/unit.rs +++ b/src/base/unit.rs @@ -15,7 +15,14 @@ use crate::{Dim, MatrixMN, RealField, Scalar, SimdComplexField, SimdRealField}; /// A wrapper that ensures the underlying algebraic entity has a unit norm. /// -/// Use `.as_ref()` or `.into_inner()` to obtain the underlying value by-reference or by-move. +/// **It is likely that the only piece of documentation that you need in this page are:** +/// - **[The construction with normalization](#construction-with-normalization)** +/// - **[Data extraction and construction without normalization](#data-extraction-and-construction-without-normalization)** +/// - **[Interpolation between two unit vectors](#interpolation-between-two-unit-vectors)** +/// +/// All the other impl blocks you will see in this page are about [`UnitComplex`](crate::UnitComplex) +/// and [`UnitQuaternion`](crate::UnitQuaternion); both built on top of `Unit`. If you are interested +/// in their documentation, read their dedicated pages directly. #[repr(transparent)] #[derive(Eq, PartialEq, Clone, Hash, Debug, Copy)] pub struct Unit { @@ -71,6 +78,7 @@ pub trait Normed { fn unscale_mut(&mut self, n: Self::Norm); } +/// # Construction with normalization impl Unit { /// Normalize the given vector and return it wrapped on a `Unit` structure. #[inline] @@ -140,6 +148,7 @@ impl Unit { } } +/// # Data extraction and construction without normalization impl Unit { /// Wraps the given value, assuming it is already normalized. #[inline]