use approx::{AbsDiffEq, RelativeEq, UlpsEq}; use num::{One, Zero}; use std::fmt; use std::hash; #[cfg(feature = "abomonation-serialize")] use std::io::{Result as IOResult, Write}; #[cfg(feature = "serde-serialize-no-std")] use serde::{Deserialize, Deserializer, Serialize, Serializer}; #[cfg(feature = "serde-serialize-no-std")] use crate::base::storage::Owned; use crate::storage::Owned; #[cfg(feature = "abomonation-serialize")] use abomonation::Abomonation; use simba::scalar::RealField; use simba::simd::SimdRealField; use crate::base::allocator::Allocator; use crate::base::dimension::{DimNameAdd, DimNameSum, U1}; use crate::base::{Const, DefaultAllocator, OMatrix, SMatrix, SVector, Scalar, Unit}; 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 /// * [Conversion to a matrix `matrix`, `to_homogeneous`…](#conversion-to-a-matrix) /// #[repr(transparent)] #[derive(Debug)] pub struct Rotation { matrix: SMatrix, } impl hash::Hash for Rotation where Owned, Const>: hash::Hash, { fn hash(&self, state: &mut H) { self.matrix.hash(state) } } impl Copy for Rotation where Owned, Const>: Copy {} impl Clone for Rotation where Owned, Const>: Clone, { #[inline] fn clone(&self) -> Self { Self::from_matrix_unchecked(self.matrix.clone()) } } #[cfg(feature = "abomonation-serialize")] impl Abomonation for Rotation where SMatrix: Abomonation, { unsafe fn entomb(&self, writer: &mut W) -> IOResult<()> { self.matrix.entomb(writer) } fn extent(&self) -> usize { self.matrix.extent() } unsafe fn exhume<'a, 'b>(&'a mut self, bytes: &'b mut [u8]) -> Option<&'b mut [u8]> { self.matrix.exhume(bytes) } } #[cfg(feature = "serde-serialize-no-std")] impl Serialize for Rotation where Owned, Const>: Serialize, { fn serialize(&self, serializer: S) -> Result where S: Serializer, { self.matrix.serialize(serializer) } } #[cfg(feature = "serde-serialize-no-std")] impl<'a, T, const D: usize> Deserialize<'a> for Rotation where Owned, Const>: Deserialize<'a>, { fn deserialize(deserializer: Des) -> Result where Des: Deserializer<'a>, { let matrix = SMatrix::::deserialize(deserializer)?; Ok(Self::from_matrix_unchecked(matrix)) } } impl Rotation { /// 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: SMatrix) -> Self { assert!( matrix.is_square(), "Unable to create a rotation from a non-square matrix." ); Self { matrix } } } /// # Conversion to a matrix impl Rotation { /// A reference to the underlying matrix representation of this rotation. /// /// # Example /// ``` /// # use nalgebra::{Rotation2, Rotation3, Vector3, Matrix2, Matrix3}; /// # use std::f32; /// let rot = Rotation3::from_axis_angle(&Vector3::z_axis(), f32::consts::FRAC_PI_6); /// let expected = Matrix3::new(0.8660254, -0.5, 0.0, /// 0.5, 0.8660254, 0.0, /// 0.0, 0.0, 1.0); /// assert_eq!(*rot.matrix(), expected); /// /// /// let rot = Rotation2::new(f32::consts::FRAC_PI_6); /// let expected = Matrix2::new(0.8660254, -0.5, /// 0.5, 0.8660254); /// assert_eq!(*rot.matrix(), expected); /// ``` #[inline] #[must_use] pub fn matrix(&self) -> &SMatrix { &self.matrix } /// A mutable reference to the underlying matrix representation of this rotation. #[inline] #[deprecated(note = "Use `.matrix_mut_unchecked()` instead.")] pub fn matrix_mut(&mut self) -> &mut SMatrix { &mut self.matrix } /// A mutable reference to the underlying matrix representation of this rotation. /// /// This is suffixed by "_unchecked" because this allows the user to replace the /// matrix by another one that is non-inversible or non-orthonormal. If one of /// those properties is broken, subsequent method calls may return bogus results. #[inline] pub fn matrix_mut_unchecked(&mut self) -> &mut SMatrix { &mut self.matrix } /// Unwraps the underlying matrix. /// /// # Example /// ``` /// # use nalgebra::{Rotation2, Rotation3, Vector3, Matrix2, Matrix3}; /// # use std::f32; /// let rot = Rotation3::from_axis_angle(&Vector3::z_axis(), f32::consts::FRAC_PI_6); /// let mat = rot.into_inner(); /// let expected = Matrix3::new(0.8660254, -0.5, 0.0, /// 0.5, 0.8660254, 0.0, /// 0.0, 0.0, 1.0); /// assert_eq!(mat, expected); /// /// /// let rot = Rotation2::new(f32::consts::FRAC_PI_6); /// let mat = rot.into_inner(); /// let expected = Matrix2::new(0.8660254, -0.5, /// 0.5, 0.8660254); /// assert_eq!(mat, expected); /// ``` #[inline] pub fn into_inner(self) -> SMatrix { self.matrix } /// Unwraps the underlying matrix. /// Deprecated: Use [Rotation::into_inner] instead. #[deprecated(note = "use `.into_inner()` instead")] #[inline] pub fn unwrap(self) -> SMatrix { self.matrix } /// Converts this rotation into its equivalent homogeneous transformation matrix. /// /// This is the same as `self.into()`. /// /// # Example /// ``` /// # use nalgebra::{Rotation2, Rotation3, Vector3, Matrix3, Matrix4}; /// # use std::f32; /// let rot = Rotation3::from_axis_angle(&Vector3::z_axis(), f32::consts::FRAC_PI_6); /// let expected = Matrix4::new(0.8660254, -0.5, 0.0, 0.0, /// 0.5, 0.8660254, 0.0, 0.0, /// 0.0, 0.0, 1.0, 0.0, /// 0.0, 0.0, 0.0, 1.0); /// assert_eq!(rot.to_homogeneous(), expected); /// /// /// let rot = Rotation2::new(f32::consts::FRAC_PI_6); /// let expected = Matrix3::new(0.8660254, -0.5, 0.0, /// 0.5, 0.8660254, 0.0, /// 0.0, 0.0, 1.0); /// assert_eq!(rot.to_homogeneous(), expected); /// ``` #[inline] #[must_use] pub fn to_homogeneous(&self) -> OMatrix, U1>, DimNameSum, U1>> where T: Zero + One + Scalar, Const: DimNameAdd, DefaultAllocator: Allocator, U1>, DimNameSum, U1>>, { // We could use `SMatrix::to_homogeneous()` here, but that would imply // adding the additional traits `DimAdd` and `IsNotStaticOne`. Maybe // these things will get nicer once specialization lands in Rust. let mut res = OMatrix::, U1>, DimNameSum, U1>>::identity(); res.fixed_slice_mut::(0, 0).copy_from(&self.matrix); res } } /// # Transposition and inversion impl Rotation { /// Transposes `self`. /// /// Same as `.inverse()` because the inverse of a rotation matrix is its transform. /// /// # Example /// ``` /// # #[macro_use] extern crate approx; /// # use nalgebra::{Rotation2, Rotation3, Vector3}; /// let rot = Rotation3::new(Vector3::new(1.0, 2.0, 3.0)); /// let tr_rot = rot.transpose(); /// assert_relative_eq!(rot * tr_rot, Rotation3::identity(), epsilon = 1.0e-6); /// assert_relative_eq!(tr_rot * rot, Rotation3::identity(), epsilon = 1.0e-6); /// /// let rot = Rotation2::new(1.2); /// let tr_rot = rot.transpose(); /// assert_relative_eq!(rot * tr_rot, Rotation2::identity(), epsilon = 1.0e-6); /// assert_relative_eq!(tr_rot * rot, Rotation2::identity(), epsilon = 1.0e-6); /// ``` #[inline] #[must_use = "Did you mean to use transpose_mut()?"] pub fn transpose(&self) -> Self { Self::from_matrix_unchecked(self.matrix.transpose()) } /// Inverts `self`. /// /// Same as `.transpose()` because the inverse of a rotation matrix is its transform. /// /// # Example /// ``` /// # #[macro_use] extern crate approx; /// # use nalgebra::{Rotation2, Rotation3, Vector3}; /// let rot = Rotation3::new(Vector3::new(1.0, 2.0, 3.0)); /// let inv = rot.inverse(); /// assert_relative_eq!(rot * inv, Rotation3::identity(), epsilon = 1.0e-6); /// assert_relative_eq!(inv * rot, Rotation3::identity(), epsilon = 1.0e-6); /// /// let rot = Rotation2::new(1.2); /// let inv = rot.inverse(); /// assert_relative_eq!(rot * inv, Rotation2::identity(), epsilon = 1.0e-6); /// assert_relative_eq!(inv * rot, Rotation2::identity(), epsilon = 1.0e-6); /// ``` #[inline] #[must_use = "Did you mean to use inverse_mut()?"] pub fn inverse(&self) -> Self { self.transpose() } /// Transposes `self` in-place. /// /// Same as `.inverse_mut()` because the inverse of a rotation matrix is its transform. /// /// # Example /// ``` /// # #[macro_use] extern crate approx; /// # use nalgebra::{Rotation2, Rotation3, Vector3}; /// let rot = Rotation3::new(Vector3::new(1.0, 2.0, 3.0)); /// let mut tr_rot = Rotation3::new(Vector3::new(1.0, 2.0, 3.0)); /// tr_rot.transpose_mut(); /// /// assert_relative_eq!(rot * tr_rot, Rotation3::identity(), epsilon = 1.0e-6); /// assert_relative_eq!(tr_rot * rot, Rotation3::identity(), epsilon = 1.0e-6); /// /// let rot = Rotation2::new(1.2); /// let mut tr_rot = Rotation2::new(1.2); /// tr_rot.transpose_mut(); /// /// assert_relative_eq!(rot * tr_rot, Rotation2::identity(), epsilon = 1.0e-6); /// assert_relative_eq!(tr_rot * rot, Rotation2::identity(), epsilon = 1.0e-6); /// ``` #[inline] pub fn transpose_mut(&mut self) { self.matrix.transpose_mut() } /// Inverts `self` in-place. /// /// Same as `.transpose_mut()` because the inverse of a rotation matrix is its transform. /// /// # Example /// ``` /// # #[macro_use] extern crate approx; /// # use nalgebra::{Rotation2, Rotation3, Vector3}; /// let rot = Rotation3::new(Vector3::new(1.0, 2.0, 3.0)); /// let mut inv = Rotation3::new(Vector3::new(1.0, 2.0, 3.0)); /// inv.inverse_mut(); /// /// assert_relative_eq!(rot * inv, Rotation3::identity(), epsilon = 1.0e-6); /// assert_relative_eq!(inv * rot, Rotation3::identity(), epsilon = 1.0e-6); /// /// let rot = Rotation2::new(1.2); /// let mut inv = Rotation2::new(1.2); /// inv.inverse_mut(); /// /// assert_relative_eq!(rot * inv, Rotation2::identity(), epsilon = 1.0e-6); /// assert_relative_eq!(inv * rot, Rotation2::identity(), epsilon = 1.0e-6); /// ``` #[inline] pub fn inverse_mut(&mut self) { self.transpose_mut() } } /// # Transformation of a vector or a point impl Rotation where T::Element: SimdRealField, { /// Rotate the given point. /// /// This is the same as the multiplication `self * pt`. /// /// # Example /// ``` /// # #[macro_use] extern crate approx; /// # use std::f32; /// # use nalgebra::{Point3, Rotation2, Rotation3, UnitQuaternion, Vector3}; /// let rot = Rotation3::new(Vector3::y() * f32::consts::FRAC_PI_2); /// let transformed_point = rot.transform_point(&Point3::new(1.0, 2.0, 3.0)); /// /// assert_relative_eq!(transformed_point, Point3::new(3.0, 2.0, -1.0), epsilon = 1.0e-6); /// ``` #[inline] #[must_use] pub fn transform_point(&self, pt: &Point) -> Point { self * pt } /// Rotate the given vector. /// /// This is the same as the multiplication `self * v`. /// /// # Example /// ``` /// # #[macro_use] extern crate approx; /// # use std::f32; /// # use nalgebra::{Rotation2, Rotation3, UnitQuaternion, Vector3}; /// let rot = Rotation3::new(Vector3::y() * f32::consts::FRAC_PI_2); /// let transformed_vector = rot.transform_vector(&Vector3::new(1.0, 2.0, 3.0)); /// /// assert_relative_eq!(transformed_vector, Vector3::new(3.0, 2.0, -1.0), epsilon = 1.0e-6); /// ``` #[inline] #[must_use] pub fn transform_vector(&self, v: &SVector) -> SVector { self * v } /// Rotate the given point by the inverse of this rotation. This may be /// cheaper than inverting the rotation and then transforming the given /// point. /// /// # Example /// ``` /// # #[macro_use] extern crate approx; /// # use std::f32; /// # use nalgebra::{Point3, Rotation2, Rotation3, UnitQuaternion, Vector3}; /// let rot = Rotation3::new(Vector3::y() * f32::consts::FRAC_PI_2); /// let transformed_point = rot.inverse_transform_point(&Point3::new(1.0, 2.0, 3.0)); /// /// assert_relative_eq!(transformed_point, Point3::new(-3.0, 2.0, 1.0), epsilon = 1.0e-6); /// ``` #[inline] #[must_use] pub fn inverse_transform_point(&self, pt: &Point) -> Point { Point::from(self.inverse_transform_vector(&pt.coords)) } /// Rotate the given vector by the inverse of this rotation. This may be /// cheaper than inverting the rotation and then transforming the given /// vector. /// /// # Example /// ``` /// # #[macro_use] extern crate approx; /// # use std::f32; /// # use nalgebra::{Rotation2, Rotation3, UnitQuaternion, Vector3}; /// let rot = Rotation3::new(Vector3::y() * f32::consts::FRAC_PI_2); /// let transformed_vector = rot.inverse_transform_vector(&Vector3::new(1.0, 2.0, 3.0)); /// /// assert_relative_eq!(transformed_vector, Vector3::new(-3.0, 2.0, 1.0), epsilon = 1.0e-6); /// ``` #[inline] #[must_use] pub fn inverse_transform_vector(&self, v: &SVector) -> SVector { self.matrix().tr_mul(v) } /// Rotate the given vector by the inverse of this rotation. This may be /// cheaper than inverting the rotation and then transforming the given /// vector. /// /// # Example /// ``` /// # #[macro_use] extern crate approx; /// # use std::f32; /// # use nalgebra::{Rotation2, Rotation3, UnitQuaternion, Vector3}; /// let rot = Rotation3::new(Vector3::z() * f32::consts::FRAC_PI_2); /// let transformed_vector = rot.inverse_transform_unit_vector(&Vector3::x_axis()); /// /// assert_relative_eq!(transformed_vector, -Vector3::y_axis(), epsilon = 1.0e-6); /// ``` #[inline] #[must_use] pub fn inverse_transform_unit_vector(&self, v: &Unit>) -> Unit> { Unit::new_unchecked(self.inverse_transform_vector(&**v)) } } impl Eq for Rotation {} impl PartialEq for Rotation { #[inline] fn eq(&self, right: &Self) -> bool { self.matrix == right.matrix } } impl AbsDiffEq for Rotation where T: Scalar + AbsDiffEq, T::Epsilon: Copy, { type Epsilon = T::Epsilon; #[inline] fn default_epsilon() -> Self::Epsilon { T::default_epsilon() } #[inline] fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool { self.matrix.abs_diff_eq(&other.matrix, epsilon) } } impl RelativeEq for Rotation where T: Scalar + RelativeEq, T::Epsilon: Copy, { #[inline] fn default_max_relative() -> Self::Epsilon { T::default_max_relative() } #[inline] fn relative_eq( &self, other: &Self, epsilon: Self::Epsilon, max_relative: Self::Epsilon, ) -> bool { self.matrix .relative_eq(&other.matrix, epsilon, max_relative) } } impl UlpsEq for Rotation where T: Scalar + UlpsEq, T::Epsilon: Copy, { #[inline] fn default_max_ulps() -> u32 { T::default_max_ulps() } #[inline] fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool { self.matrix.ulps_eq(&other.matrix, epsilon, max_ulps) } } /* * * Display * */ impl fmt::Display for Rotation where T: RealField + fmt::Display, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let precision = f.precision().unwrap_or(3); writeln!(f, "Rotation matrix {{")?; write!(f, "{:.*}", precision, self.matrix)?; writeln!(f, "}}") } } // // /* // // * // // * Absolute // // * // // */ // // impl Absolute for $t { // // type AbsoluteValue = $submatrix; // // // // #[inline] // // fn abs(m: &$t) -> $submatrix { // // Absolute::abs(&m.submatrix) // // } // // }