2018-05-19 21:41:58 +08:00
use approx ::{ AbsDiffEq , RelativeEq , UlpsEq } ;
2016-12-05 05:44:42 +08:00
use std ::fmt ;
2017-08-03 01:37:44 +08:00
use std ::hash ;
2018-07-20 21:25:55 +08:00
#[ cfg(feature = " abomonation-serialize " ) ]
use std ::io ::{ Result as IOResult , Write } ;
2016-12-05 05:44:42 +08:00
2021-04-12 18:14:16 +08:00
#[ cfg(feature = " serde-serialize-no-std " ) ]
2018-10-22 13:00:10 +08:00
use serde ::{ Deserialize , Serialize } ;
2016-12-05 05:44:42 +08:00
2021-05-05 23:14:18 +08:00
#[ cfg(feature = " rkyv-serialize-no-std " ) ]
use rkyv ::{ Archive , Deserialize , Serialize } ;
2017-08-14 20:32:02 +08:00
#[ cfg(feature = " abomonation-serialize " ) ]
use abomonation ::Abomonation ;
2020-03-21 19:16:46 +08:00
use simba ::scalar ::{ RealField , SubsetOf } ;
2020-03-22 06:22:55 +08:00
use simba ::simd ::SimdRealField ;
2017-02-13 01:17:09 +08:00
2019-03-23 21:29:07 +08:00
use crate ::base ::allocator ::Allocator ;
2021-04-07 20:29:20 +08:00
use crate ::base ::dimension ::{ DimNameAdd , DimNameSum , U1 } ;
2019-03-23 21:29:07 +08:00
use crate ::base ::storage ::Owned ;
2021-04-11 17:00:38 +08:00
use crate ::base ::{ Const , DefaultAllocator , OMatrix , SVector , Scalar , Unit } ;
2020-11-21 00:45:11 +08:00
use crate ::geometry ::{ AbstractRotation , Point , Translation } ;
/// 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).
///
/// Note that instead of using the [`Isometry`](crate::Isometry) type in your code directly, you should use one
/// of its aliases: [`Isometry2`](crate::Isometry2), [`Isometry3`](crate::Isometry3),
/// [`IsometryMatrix2`](crate::IsometryMatrix2), [`IsometryMatrix3`](crate::IsometryMatrix3). Though
/// keep in mind that all the documentation of all the methods of these aliases will also appears on
/// this page.
///
/// # Construction
/// * [From a 2D vector and/or an angle <span style="float:right;">`new`, `translation`, `rotation`…</span>](#construction-from-a-2d-vector-andor-a-rotation-angle)
/// * [From a 3D vector and/or an axis-angle <span style="float:right;">`new`, `translation`, `rotation`…</span>](#construction-from-a-3d-vector-andor-an-axis-angle)
/// * [From a 3D eye position and target point <span style="float:right;">`look_at`, `look_at_lh`, `face_towards`…</span>](#construction-from-a-3d-eye-position-and-target-point)
/// * [From the translation and rotation parts <span style="float:right;">`from_parts`…</span>](#from-the-translation-and-rotation-parts)
///
/// # Transformation and composition
2020-11-21 18:21:47 +08:00
/// Note that transforming vectors and points can be done by multiplication, e.g., `isometry * point`.
2020-11-21 00:45:11 +08:00
/// Composing an isometry with another transformation can also be done by multiplication or division.
///
/// * [Transformation of a vector or a point <span style="float:right;">`transform_vector`, `inverse_transform_point`…</span>](#transformation-of-a-vector-or-a-point)
/// * [Inversion and in-place composition <span style="float:right;">`inverse`, `append_rotation_wrt_point_mut`…</span>](#inversion-and-in-place-composition)
2020-11-21 18:21:47 +08:00
/// * [Interpolation <span style="float:right;">`lerp_slerp`…</span>](#interpolation)
2020-11-21 00:45:11 +08:00
///
/// # Conversion to a matrix
/// * [Conversion to a matrix <span style="float:right;">`to_matrix`…</span>](#conversion-to-a-matrix)
///
2016-12-05 05:44:42 +08:00
#[ repr(C) ]
2017-08-03 01:37:44 +08:00
#[ derive(Debug) ]
2021-04-12 18:14:16 +08:00
#[ cfg_attr(feature = " serde-serialize-no-std " , derive(Serialize, Deserialize)) ]
2018-05-19 21:41:58 +08:00
#[ cfg_attr(
2021-04-12 18:14:16 +08:00
feature = " serde-serialize-no-std " ,
2018-11-03 20:35:56 +08:00
serde ( bound ( serialize = " R: Serialize,
2021-04-11 17:00:38 +08:00
DefaultAllocator : Allocator < T , Const < D > > ,
Owned < T , Const < D > > : Serialize " ))
2018-05-19 21:41:58 +08:00
) ]
#[ cfg_attr(
2021-04-12 18:14:16 +08:00
feature = " serde-serialize-no-std " ,
2018-11-03 20:35:56 +08:00
serde ( bound ( deserialize = " R: Deserialize<'de>,
2021-04-11 17:00:38 +08:00
DefaultAllocator : Allocator < T , Const < D > > ,
Owned < T , Const < D > > : Deserialize < ' de > " ))
2018-05-19 21:41:58 +08:00
) ]
2021-04-11 17:00:38 +08:00
pub struct Isometry < T : Scalar , R , const D : usize > {
2017-02-13 01:17:09 +08:00
/// The pure rotational part of this isometry.
2018-02-02 19:26:35 +08:00
pub rotation : R ,
2017-02-13 01:17:09 +08:00
/// The pure translational part of this isometry.
2021-04-11 17:00:38 +08:00
pub translation : Translation < T , D > ,
2016-12-05 05:44:42 +08:00
}
2017-08-14 20:32:02 +08:00
#[ cfg(feature = " abomonation-serialize " ) ]
2021-04-11 17:00:38 +08:00
impl < T , R , const D : usize > Abomonation for Isometry < T , R , D >
2018-02-02 19:26:35 +08:00
where
2021-04-11 17:00:38 +08:00
T : SimdRealField ,
2018-02-02 19:26:35 +08:00
R : Abomonation ,
2021-04-11 17:00:38 +08:00
Translation < T , D > : Abomonation ,
2017-08-14 20:32:02 +08:00
{
2018-07-20 21:25:55 +08:00
unsafe fn entomb < W : Write > ( & self , writer : & mut W ) -> IOResult < ( ) > {
self . rotation . entomb ( writer ) ? ;
self . translation . entomb ( writer )
2017-08-14 20:32:02 +08:00
}
2018-07-20 21:25:55 +08:00
fn extent ( & self ) -> usize {
self . rotation . extent ( ) + self . translation . extent ( )
2017-08-14 20:32:02 +08:00
}
unsafe fn exhume < ' a , ' b > ( & ' a mut self , bytes : & ' b mut [ u8 ] ) -> Option < & ' b mut [ u8 ] > {
2018-02-02 19:26:35 +08:00
self . rotation
. exhume ( bytes )
2017-08-14 20:32:02 +08:00
. and_then ( | bytes | self . translation . exhume ( bytes ) )
}
}
2021-05-07 08:59:02 +08:00
#[ cfg(feature = " rkyv-serialize-no-std " ) ]
impl < T : Scalar + Archive , R : Archive , const D : usize > Archive for Isometry < T , R , D >
where
T ::Archived : Scalar ,
{
type Archived = Isometry < T ::Archived , R ::Archived , D > ;
type Resolver = ( R ::Resolver , < Translation < T , D > as Archive > ::Resolver ) ;
fn resolve ( & self , pos : usize , resolver : Self ::Resolver , out : & mut core ::mem ::MaybeUninit < Self ::Archived > ) {
self . rotation . resolve (
pos + rkyv ::offset_of! ( Self ::Archived , rotation ) ,
resolver . 0 ,
rkyv ::project_struct! ( out : Self ::Archived = > rotation )
) ;
self . translation . resolve (
pos + rkyv ::offset_of! ( Self ::Archived , translation ) ,
resolver . 1 ,
rkyv ::project_struct! ( out : Self ::Archived = > translation )
) ;
}
}
#[ cfg(feature = " rkyv-serialize-no-std " ) ]
impl < T : Scalar + Serialize < S > , R : Serialize < S > , S : rkyv ::Fallible + ? Sized , const D : usize > Serialize < S > for Isometry < T , R , D >
where
T ::Archived : Scalar ,
{
fn serialize ( & self , serializer : & mut S ) -> Result < Self ::Resolver , S ::Error > {
Ok ( (
self . rotation . serialize ( serializer ) ? ,
self . translation . serialize ( serializer ) ? ,
) )
}
}
#[ cfg(feature = " rkyv-serialize-no-std " ) ]
impl < T : Scalar + Archive , R : Archive , _D : rkyv ::Fallible + ? Sized , const D : usize > Deserialize < Isometry < T , R , D > , _D > for Isometry < T ::Archived , R ::Archived , D >
where
T ::Archived : Scalar + Deserialize < T , _D > ,
R ::Archived : Scalar + Deserialize < R , _D > ,
{
fn deserialize ( & self , deserializer : & mut _D ) -> Result < Isometry < T , R , D > , _D ::Error > {
Ok ( Isometry {
rotation : self . rotation . deserialize ( deserializer ) ? ,
translation : self . translation . deserialize ( deserializer ) ? ,
} )
}
}
2021-04-11 17:00:38 +08:00
impl < T : Scalar + hash ::Hash , R : hash ::Hash , const D : usize > hash ::Hash for Isometry < T , R , D >
2018-02-02 19:26:35 +08:00
where
2021-04-11 17:00:38 +08:00
Owned < T , Const < D > > : hash ::Hash ,
2018-02-02 19:26:35 +08:00
{
2017-08-03 01:37:44 +08:00
fn hash < H : hash ::Hasher > ( & self , state : & mut H ) {
self . translation . hash ( state ) ;
self . rotation . hash ( state ) ;
}
}
2021-04-11 17:00:38 +08:00
impl < T : Scalar + Copy , R : Copy , const D : usize > Copy for Isometry < T , R , D > where
Owned < T , Const < D > > : Copy
2018-11-03 20:35:56 +08:00
{
}
2017-08-03 01:37:44 +08:00
2021-04-11 17:00:38 +08:00
impl < T : Scalar , R : Clone , const D : usize > Clone for Isometry < T , R , D > {
2017-08-03 01:37:44 +08:00
#[ inline ]
fn clone ( & self ) -> Self {
2020-10-13 16:12:14 +08:00
Self {
rotation : self . rotation . clone ( ) ,
translation : self . translation . clone ( ) ,
}
2017-08-03 01:37:44 +08:00
}
}
2020-11-21 00:45:11 +08:00
/// # From the translation and rotation parts
2021-04-11 17:00:38 +08:00
impl < T : Scalar , R : AbstractRotation < T , D > , const D : usize > Isometry < T , R , D > {
2016-12-05 05:44:42 +08:00
/// Creates a new isometry from its rotational and translational parts.
2018-10-22 14:04:35 +08:00
///
/// # Example
///
/// ```
/// # #[macro_use] extern crate approx;
/// # use std::f32;
/// # use nalgebra::{Isometry3, Translation3, UnitQuaternion, Vector3, Point3};
/// let tra = Translation3::new(0.0, 0.0, 3.0);
/// let rot = UnitQuaternion::from_scaled_axis(Vector3::y() * f32::consts::PI);
/// let iso = Isometry3::from_parts(tra, rot);
///
/// assert_relative_eq!(iso * Point3::new(1.0, 2.0, 3.0), Point3::new(-1.0, 2.0, 0.0), epsilon = 1.0e-6);
/// ```
2016-12-05 05:44:42 +08:00
#[ inline ]
2021-04-11 17:00:38 +08:00
pub fn from_parts ( translation : Translation < T , D > , rotation : R ) -> Self {
2019-02-17 05:29:41 +08:00
Self {
2020-03-22 06:22:55 +08:00
rotation ,
translation ,
2016-12-05 05:44:42 +08:00
}
}
2020-03-24 17:16:31 +08:00
}
2016-12-05 05:44:42 +08:00
2020-11-21 00:45:11 +08:00
/// # Inversion and in-place composition
2021-04-11 17:00:38 +08:00
impl < T : SimdRealField , R : AbstractRotation < T , D > , const D : usize > Isometry < T , R , D >
2020-03-24 17:16:31 +08:00
where
2021-04-11 17:00:38 +08:00
T ::Element : SimdRealField ,
2020-03-24 17:16:31 +08:00
{
2016-12-05 05:44:42 +08:00
/// Inverts `self`.
2018-10-22 14:04:35 +08:00
///
/// # Example
///
/// ```
/// # use std::f32;
/// # use nalgebra::{Isometry2, Point2, Vector2};
/// let iso = Isometry2::new(Vector2::new(1.0, 2.0), f32::consts::FRAC_PI_2);
/// let inv = iso.inverse();
/// let pt = Point2::new(1.0, 2.0);
///
/// assert_eq!(inv * (iso * pt), pt);
/// ```
2016-12-05 05:44:42 +08:00
#[ inline ]
2019-06-06 05:04:04 +08:00
#[ must_use = " Did you mean to use inverse_mut()? " ]
2019-02-17 05:29:41 +08:00
pub fn inverse ( & self ) -> Self {
2016-12-05 05:44:42 +08:00
let mut res = self . clone ( ) ;
res . inverse_mut ( ) ;
res
}
2018-10-22 14:04:35 +08:00
/// Inverts `self` in-place.
///
/// # Example
///
/// ```
/// # use std::f32;
/// # use nalgebra::{Isometry2, Point2, Vector2};
/// let mut iso = Isometry2::new(Vector2::new(1.0, 2.0), f32::consts::FRAC_PI_2);
/// let pt = Point2::new(1.0, 2.0);
/// let transformed_pt = iso * pt;
/// iso.inverse_mut();
///
/// assert_eq!(iso * transformed_pt, pt);
/// ```
2016-12-05 05:44:42 +08:00
#[ inline ]
pub fn inverse_mut ( & mut self ) {
2020-03-21 19:16:46 +08:00
self . rotation . inverse_mut ( ) ;
2016-12-05 05:44:42 +08:00
self . translation . inverse_mut ( ) ;
self . translation . vector = self . rotation . transform_vector ( & self . translation . vector ) ;
}
2020-12-18 18:55:46 +08:00
/// Computes `self.inverse() * rhs` in a more efficient way.
///
/// # Example
///
/// ```
/// # use std::f32;
/// # use nalgebra::{Isometry2, Point2, Vector2};
/// let mut iso1 = Isometry2::new(Vector2::new(1.0, 2.0), f32::consts::FRAC_PI_2);
/// let mut iso2 = Isometry2::new(Vector2::new(10.0, 20.0), f32::consts::FRAC_PI_4);
///
/// assert_eq!(iso1.inverse() * iso2, iso1.inv_mul(&iso2));
/// ```
#[ inline ]
2021-04-11 17:00:38 +08:00
pub fn inv_mul ( & self , rhs : & Isometry < T , R , D > ) -> Self {
2020-12-18 18:55:46 +08:00
let inv_rot1 = self . rotation . inverse ( ) ;
let tr_12 = rhs . translation . vector . clone ( ) - self . translation . vector . clone ( ) ;
Isometry ::from_parts (
inv_rot1 . transform_vector ( & tr_12 ) . into ( ) ,
inv_rot1 * rhs . rotation . clone ( ) ,
)
}
2016-12-05 05:44:42 +08:00
/// Appends to `self` the given translation in-place.
2018-10-22 14:04:35 +08:00
///
/// # Example
///
/// ```
/// # use std::f32;
/// # use nalgebra::{Isometry2, Translation2, Vector2};
/// let mut iso = Isometry2::new(Vector2::new(1.0, 2.0), f32::consts::FRAC_PI_2);
/// let tra = Translation2::new(3.0, 4.0);
/// // Same as `iso = tra * iso`.
/// iso.append_translation_mut(&tra);
///
/// assert_eq!(iso.translation, Translation2::new(4.0, 6.0));
/// ```
2016-12-05 05:44:42 +08:00
#[ inline ]
2021-04-11 17:00:38 +08:00
pub fn append_translation_mut ( & mut self , t : & Translation < T , D > ) {
2016-12-05 05:44:42 +08:00
self . translation . vector + = & t . vector
}
/// Appends to `self` the given rotation in-place.
2018-10-22 14:04:35 +08:00
///
/// # Example
///
/// ```
/// # #[macro_use] extern crate approx;
/// # use std::f32;
/// # use nalgebra::{Isometry2, Translation2, UnitComplex, Vector2};
/// let mut iso = Isometry2::new(Vector2::new(1.0, 2.0), f32::consts::PI / 6.0);
/// let rot = UnitComplex::new(f32::consts::PI / 2.0);
/// // Same as `iso = rot * iso`.
/// iso.append_rotation_mut(&rot);
///
/// assert_relative_eq!(iso, Isometry2::new(Vector2::new(-2.0, 1.0), f32::consts::PI * 2.0 / 3.0), epsilon = 1.0e-6);
/// ```
2016-12-05 05:44:42 +08:00
#[ inline ]
pub fn append_rotation_mut ( & mut self , r : & R ) {
2020-03-21 19:16:46 +08:00
self . rotation = r . clone ( ) * self . rotation . clone ( ) ;
2016-12-05 05:44:42 +08:00
self . translation . vector = r . transform_vector ( & self . translation . vector ) ;
}
/// Appends in-place to `self` a rotation centered at the point `p`, i.e., the rotation that
/// lets `p` invariant.
2018-10-22 14:04:35 +08:00
///
/// # Example
///
/// ```
/// # #[macro_use] extern crate approx;
/// # use std::f32;
/// # use nalgebra::{Isometry2, Translation2, UnitComplex, Vector2, Point2};
/// let mut iso = Isometry2::new(Vector2::new(1.0, 2.0), f32::consts::FRAC_PI_2);
/// let rot = UnitComplex::new(f32::consts::FRAC_PI_2);
/// let pt = Point2::new(1.0, 0.0);
/// iso.append_rotation_wrt_point_mut(&rot, &pt);
///
/// assert_relative_eq!(iso * pt, Point2::new(-2.0, 0.0), epsilon = 1.0e-6);
/// ```
2016-12-05 05:44:42 +08:00
#[ inline ]
2021-04-11 17:00:38 +08:00
pub fn append_rotation_wrt_point_mut ( & mut self , r : & R , p : & Point < T , D > ) {
2016-12-05 05:44:42 +08:00
self . translation . vector - = & p . coords ;
self . append_rotation_mut ( r ) ;
self . translation . vector + = & p . coords ;
}
/// Appends in-place to `self` a rotation centered at the point with coordinates
/// `self.translation`.
2018-10-22 14:04:35 +08:00
///
/// # Example
///
/// ```
/// # use std::f32;
/// # use nalgebra::{Isometry2, Translation2, UnitComplex, Vector2, Point2};
/// let mut iso = Isometry2::new(Vector2::new(1.0, 2.0), f32::consts::FRAC_PI_2);
/// let rot = UnitComplex::new(f32::consts::FRAC_PI_2);
/// iso.append_rotation_wrt_center_mut(&rot);
///
/// // The translation part should not have changed.
/// assert_eq!(iso.translation.vector, Vector2::new(1.0, 2.0));
/// assert_eq!(iso.rotation, UnitComplex::new(f32::consts::PI));
/// ```
2016-12-05 05:44:42 +08:00
#[ inline ]
pub fn append_rotation_wrt_center_mut ( & mut self , r : & R ) {
2020-03-21 19:16:46 +08:00
self . rotation = r . clone ( ) * self . rotation . clone ( ) ;
2016-12-05 05:44:42 +08:00
}
2020-11-21 00:45:11 +08:00
}
2019-02-25 00:29:27 +08:00
2020-11-21 00:45:11 +08:00
/// # Transformation of a vector or a point
2021-04-11 17:00:38 +08:00
impl < T : SimdRealField , R : AbstractRotation < T , D > , const D : usize > Isometry < T , R , D >
2020-11-21 00:45:11 +08:00
where
2021-04-11 17:00:38 +08:00
T ::Element : SimdRealField ,
2020-11-21 00:45:11 +08:00
{
2019-02-25 00:29:27 +08:00
/// Transform the given point by this isometry.
///
2019-03-15 22:50:47 +08:00
/// This is the same as the multiplication `self * pt`.
///
2019-02-25 00:29:27 +08:00
/// # Example
///
/// ```
/// # #[macro_use] extern crate approx;
/// # use std::f32;
/// # use nalgebra::{Isometry3, Translation3, UnitQuaternion, Vector3, Point3};
/// let tra = Translation3::new(0.0, 0.0, 3.0);
/// let rot = UnitQuaternion::from_scaled_axis(Vector3::y() * f32::consts::FRAC_PI_2);
/// let iso = Isometry3::from_parts(tra, rot);
///
/// let transformed_point = iso.transform_point(&Point3::new(1.0, 2.0, 3.0));
/// assert_relative_eq!(transformed_point, Point3::new(3.0, 2.0, 2.0), epsilon = 1.0e-6);
/// ```
#[ inline ]
2021-04-11 17:00:38 +08:00
pub fn transform_point ( & self , pt : & Point < T , D > ) -> Point < T , D > {
2019-02-25 00:29:27 +08:00
self * pt
}
/// Transform the given vector by this isometry, ignoring the translation
/// component of the isometry.
///
2019-03-15 22:50:47 +08:00
/// This is the same as the multiplication `self * v`.
///
2019-02-25 00:29:27 +08:00
/// # Example
///
/// ```
/// # #[macro_use] extern crate approx;
/// # use std::f32;
/// # use nalgebra::{Isometry3, Translation3, UnitQuaternion, Vector3};
/// let tra = Translation3::new(0.0, 0.0, 3.0);
/// let rot = UnitQuaternion::from_scaled_axis(Vector3::y() * f32::consts::FRAC_PI_2);
/// let iso = Isometry3::from_parts(tra, rot);
///
/// let transformed_point = iso.transform_vector(&Vector3::new(1.0, 2.0, 3.0));
/// assert_relative_eq!(transformed_point, Vector3::new(3.0, 2.0, -1.0), epsilon = 1.0e-6);
/// ```
#[ inline ]
2021-04-11 17:00:38 +08:00
pub fn transform_vector ( & self , v : & SVector < T , D > ) -> SVector < T , D > {
2019-02-25 00:29:27 +08:00
self * v
}
/// Transform the given point by the inverse of this isometry. This may be
/// less expensive than computing the entire isometry inverse and then
/// transforming the point.
///
/// # Example
///
/// ```
/// # #[macro_use] extern crate approx;
/// # use std::f32;
/// # use nalgebra::{Isometry3, Translation3, UnitQuaternion, Vector3, Point3};
/// let tra = Translation3::new(0.0, 0.0, 3.0);
/// let rot = UnitQuaternion::from_scaled_axis(Vector3::y() * f32::consts::FRAC_PI_2);
/// let iso = Isometry3::from_parts(tra, rot);
///
/// let transformed_point = iso.inverse_transform_point(&Point3::new(1.0, 2.0, 3.0));
/// assert_relative_eq!(transformed_point, Point3::new(0.0, 2.0, 1.0), epsilon = 1.0e-6);
/// ```
#[ inline ]
2021-04-11 17:00:38 +08:00
pub fn inverse_transform_point ( & self , pt : & Point < T , D > ) -> Point < T , D > {
2019-02-25 00:29:27 +08:00
self . rotation
. inverse_transform_point ( & ( pt - & self . translation . vector ) )
}
/// Transform the given vector by the inverse of this isometry, ignoring the
/// translation component of the isometry. This may be
/// less expensive than computing the entire isometry inverse and then
/// transforming the point.
///
/// # Example
///
/// ```
/// # #[macro_use] extern crate approx;
/// # use std::f32;
/// # use nalgebra::{Isometry3, Translation3, UnitQuaternion, Vector3};
/// let tra = Translation3::new(0.0, 0.0, 3.0);
/// let rot = UnitQuaternion::from_scaled_axis(Vector3::y() * f32::consts::FRAC_PI_2);
/// let iso = Isometry3::from_parts(tra, rot);
///
/// let transformed_point = iso.inverse_transform_vector(&Vector3::new(1.0, 2.0, 3.0));
/// assert_relative_eq!(transformed_point, Vector3::new(-3.0, 2.0, 1.0), epsilon = 1.0e-6);
/// ```
#[ inline ]
2021-04-11 17:00:38 +08:00
pub fn inverse_transform_vector ( & self , v : & SVector < T , D > ) -> SVector < T , D > {
2019-02-25 00:29:27 +08:00
self . rotation . inverse_transform_vector ( v )
}
2020-10-25 18:23:34 +08:00
/// Transform the given unit vector by the inverse of this isometry, ignoring the
/// translation component of the isometry. This may be
/// less expensive than computing the entire isometry inverse and then
/// transforming the point.
///
/// # Example
///
/// ```
/// # #[macro_use] extern crate approx;
/// # use std::f32;
/// # use nalgebra::{Isometry3, Translation3, UnitQuaternion, Vector3};
/// let tra = Translation3::new(0.0, 0.0, 3.0);
/// let rot = UnitQuaternion::from_scaled_axis(Vector3::z() * f32::consts::FRAC_PI_2);
/// let iso = Isometry3::from_parts(tra, rot);
///
/// let transformed_point = iso.inverse_transform_unit_vector(&Vector3::x_axis());
/// assert_relative_eq!(transformed_point, -Vector3::y_axis(), epsilon = 1.0e-6);
/// ```
#[ inline ]
2021-04-11 17:00:38 +08:00
pub fn inverse_transform_unit_vector ( & self , v : & Unit < SVector < T , D > > ) -> Unit < SVector < T , D > > {
2020-10-25 18:23:34 +08:00
self . rotation . inverse_transform_unit_vector ( v )
}
2020-10-25 21:00:47 +08:00
}
2020-10-25 18:39:27 +08:00
2016-12-05 05:44:42 +08:00
// 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).
2020-11-21 00:45:11 +08:00
/// # Conversion to a matrix
2021-04-11 17:00:38 +08:00
impl < T : SimdRealField , R , const D : usize > Isometry < T , R , D > {
2016-12-05 05:44:42 +08:00
/// Converts this isometry into its equivalent homogeneous transformation matrix.
2018-10-22 14:04:35 +08:00
///
2020-11-21 00:45:11 +08:00
/// This is the same as `self.to_matrix()`.
///
2018-10-22 14:04:35 +08:00
/// # 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_homogeneous(), expected, epsilon = 1.0e-6);
/// ```
2016-12-05 05:44:42 +08:00
#[ inline ]
2021-04-11 17:00:38 +08:00
pub fn to_homogeneous ( & self ) -> OMatrix < T , DimNameSum < Const < D > , U1 > , DimNameSum < Const < D > , U1 > >
2018-02-02 19:26:35 +08:00
where
2021-04-07 20:29:20 +08:00
Const < D > : DimNameAdd < U1 > ,
2021-04-11 17:00:38 +08:00
R : SubsetOf < OMatrix < T , DimNameSum < Const < D > , U1 > , DimNameSum < Const < D > , U1 > > > ,
DefaultAllocator : Allocator < T , DimNameSum < Const < D > , U1 > , DimNameSum < Const < D > , U1 > > ,
2018-02-02 19:26:35 +08:00
{
2021-04-11 17:00:38 +08:00
let mut res : OMatrix < T , _ , _ > = crate ::convert_ref ( & self . rotation ) ;
res . fixed_slice_mut ::< D , 1 > ( 0 , D )
2018-02-02 19:26:35 +08:00
. copy_from ( & self . translation . vector ) ;
2016-12-05 05:44:42 +08:00
res
}
2020-11-21 00:45:11 +08:00
/// 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 ]
2021-04-11 17:00:38 +08:00
pub fn to_matrix ( & self ) -> OMatrix < T , DimNameSum < Const < D > , U1 > , DimNameSum < Const < D > , U1 > >
2020-11-21 00:45:11 +08:00
where
2021-04-07 20:29:20 +08:00
Const < D > : DimNameAdd < U1 > ,
2021-04-11 17:00:38 +08:00
R : SubsetOf < OMatrix < T , DimNameSum < Const < D > , U1 > , DimNameSum < Const < D > , U1 > > > ,
DefaultAllocator : Allocator < T , DimNameSum < Const < D > , U1 > , DimNameSum < Const < D > , U1 > > ,
2020-11-21 00:45:11 +08:00
{
self . to_homogeneous ( )
}
2016-12-05 05:44:42 +08:00
}
2021-04-11 17:00:38 +08:00
impl < T : SimdRealField , R , const D : usize > Eq for Isometry < T , R , D > where
R : AbstractRotation < T , D > + Eq
2018-11-03 20:35:56 +08:00
{
}
2016-12-05 05:44:42 +08:00
2021-04-11 17:00:38 +08:00
impl < T : SimdRealField , R , const D : usize > PartialEq for Isometry < T , R , D >
2018-02-02 19:26:35 +08:00
where
2021-04-11 17:00:38 +08:00
R : AbstractRotation < T , D > + PartialEq ,
2018-02-02 19:26:35 +08:00
{
2016-12-05 05:44:42 +08:00
#[ inline ]
2019-02-17 05:29:41 +08:00
fn eq ( & self , right : & Self ) -> bool {
2018-02-02 19:26:35 +08:00
self . translation = = right . translation & & self . rotation = = right . rotation
2016-12-05 05:44:42 +08:00
}
}
2021-04-11 17:00:38 +08:00
impl < T : RealField , R , const D : usize > AbsDiffEq for Isometry < T , R , D >
2018-02-02 19:26:35 +08:00
where
2021-04-11 17:00:38 +08:00
R : AbstractRotation < T , D > + AbsDiffEq < Epsilon = T ::Epsilon > ,
T ::Epsilon : Copy ,
2018-02-02 19:26:35 +08:00
{
2021-04-11 17:00:38 +08:00
type Epsilon = T ::Epsilon ;
2016-12-05 05:44:42 +08:00
#[ inline ]
fn default_epsilon ( ) -> Self ::Epsilon {
2021-04-11 17:00:38 +08:00
T ::default_epsilon ( )
2016-12-05 05:44:42 +08:00
}
#[ inline ]
2018-05-19 21:41:58 +08:00
fn abs_diff_eq ( & self , other : & Self , epsilon : Self ::Epsilon ) -> bool {
self . translation . abs_diff_eq ( & other . translation , epsilon )
& & self . rotation . abs_diff_eq ( & other . rotation , epsilon )
2016-12-05 05:44:42 +08:00
}
2018-05-19 21:41:58 +08:00
}
2016-12-05 05:44:42 +08:00
2021-04-11 17:00:38 +08:00
impl < T : RealField , R , const D : usize > RelativeEq for Isometry < T , R , D >
2018-05-19 21:41:58 +08:00
where
2021-04-11 17:00:38 +08:00
R : AbstractRotation < T , D > + RelativeEq < Epsilon = T ::Epsilon > ,
T ::Epsilon : Copy ,
2018-05-19 21:41:58 +08:00
{
2016-12-05 05:44:42 +08:00
#[ inline ]
2018-05-19 21:41:58 +08:00
fn default_max_relative ( ) -> Self ::Epsilon {
2021-04-11 17:00:38 +08:00
T ::default_max_relative ( )
2016-12-05 05:44:42 +08:00
}
#[ inline ]
2018-02-02 19:26:35 +08:00
fn relative_eq (
& self ,
other : & Self ,
epsilon : Self ::Epsilon ,
max_relative : Self ::Epsilon ,
2020-04-05 23:15:43 +08:00
) -> bool {
2018-02-02 19:26:35 +08:00
self . translation
. relative_eq ( & other . translation , epsilon , max_relative )
2018-07-20 21:25:55 +08:00
& & self
. rotation
2018-02-02 19:26:35 +08:00
. relative_eq ( & other . rotation , epsilon , max_relative )
2016-12-05 05:44:42 +08:00
}
2018-05-19 21:41:58 +08:00
}
2021-04-11 17:00:38 +08:00
impl < T : RealField , R , const D : usize > UlpsEq for Isometry < T , R , D >
2018-05-19 21:41:58 +08:00
where
2021-04-11 17:00:38 +08:00
R : AbstractRotation < T , D > + UlpsEq < Epsilon = T ::Epsilon > ,
T ::Epsilon : Copy ,
2018-05-19 21:41:58 +08:00
{
#[ inline ]
fn default_max_ulps ( ) -> u32 {
2021-04-11 17:00:38 +08:00
T ::default_max_ulps ( )
2018-05-19 21:41:58 +08:00
}
2016-12-05 05:44:42 +08:00
#[ inline ]
fn ulps_eq ( & self , other : & Self , epsilon : Self ::Epsilon , max_ulps : u32 ) -> bool {
2018-02-02 19:26:35 +08:00
self . translation
. ulps_eq ( & other . translation , epsilon , max_ulps )
& & self . rotation . ulps_eq ( & other . rotation , epsilon , max_ulps )
2016-12-05 05:44:42 +08:00
}
}
/*
*
* Display
*
* /
2021-04-11 17:00:38 +08:00
impl < T : RealField + fmt ::Display , R , const D : usize > fmt ::Display for Isometry < T , R , D >
2018-02-02 19:26:35 +08:00
where
R : fmt ::Display ,
{
2016-12-05 05:44:42 +08:00
fn fmt ( & self , f : & mut fmt ::Formatter ) -> fmt ::Result {
let precision = f . precision ( ) . unwrap_or ( 3 ) ;
2019-03-23 21:29:07 +08:00
writeln! ( f , " Isometry {{ " ) ? ;
write! ( f , " {:.*} " , precision , self . translation ) ? ;
write! ( f , " {:.*} " , precision , self . rotation ) ? ;
2016-12-05 05:44:42 +08:00
writeln! ( f , " }} " )
}
}