nalgebra/geometry/
isometry_interpolation.rs

1use crate::{Isometry2, Isometry3, IsometryMatrix2, IsometryMatrix3, RealField, SimdRealField};
2
3/// # Interpolation
4impl<T: SimdRealField> Isometry3<T> {
5    /// Interpolates between two isometries using a linear interpolation for the translation part,
6    /// and a spherical interpolation for the rotation part.
7    ///
8    /// Panics if the angle between both rotations is 180 degrees (in which case the interpolation
9    /// is not well-defined). Use `.try_lerp_slerp` instead to avoid the panic.
10    ///
11    /// # Examples:
12    ///
13    /// ```
14    /// # use nalgebra::{Vector3, Translation3, Isometry3, UnitQuaternion};
15    ///
16    /// let t1 = Translation3::new(1.0, 2.0, 3.0);
17    /// let t2 = Translation3::new(4.0, 8.0, 12.0);
18    /// let q1 = UnitQuaternion::from_euler_angles(std::f32::consts::FRAC_PI_4, 0.0, 0.0);
19    /// let q2 = UnitQuaternion::from_euler_angles(-std::f32::consts::PI, 0.0, 0.0);
20    /// let iso1 = Isometry3::from_parts(t1, q1);
21    /// let iso2 = Isometry3::from_parts(t2, q2);
22    ///
23    /// let iso3 = iso1.lerp_slerp(&iso2, 1.0 / 3.0);
24    ///
25    /// assert_eq!(iso3.translation.vector, Vector3::new(2.0, 4.0, 6.0));
26    /// assert_eq!(iso3.rotation.euler_angles(), (std::f32::consts::FRAC_PI_2, 0.0, 0.0));
27    /// ```
28    #[inline]
29    #[must_use]
30    pub fn lerp_slerp(&self, other: &Self, t: T) -> Self
31    where
32        T: RealField,
33    {
34        let tr = self
35            .translation
36            .vector
37            .lerp(&other.translation.vector, t.clone());
38        let rot = self.rotation.slerp(&other.rotation, t);
39        Self::from_parts(tr.into(), rot)
40    }
41
42    /// Attempts to interpolate between two isometries using a linear interpolation for the translation part,
43    /// and a spherical interpolation for the rotation part.
44    ///
45    /// Returns `None` if the angle between both rotations is 180 degrees (in which case the interpolation
46    /// is not well-defined).
47    ///
48    /// # Examples:
49    ///
50    /// ```
51    /// # use nalgebra::{Vector3, Translation3, Isometry3, UnitQuaternion};
52    ///
53    /// let t1 = Translation3::new(1.0, 2.0, 3.0);
54    /// let t2 = Translation3::new(4.0, 8.0, 12.0);
55    /// let q1 = UnitQuaternion::from_euler_angles(std::f32::consts::FRAC_PI_4, 0.0, 0.0);
56    /// let q2 = UnitQuaternion::from_euler_angles(-std::f32::consts::PI, 0.0, 0.0);
57    /// let iso1 = Isometry3::from_parts(t1, q1);
58    /// let iso2 = Isometry3::from_parts(t2, q2);
59    ///
60    /// let iso3 = iso1.lerp_slerp(&iso2, 1.0 / 3.0);
61    ///
62    /// assert_eq!(iso3.translation.vector, Vector3::new(2.0, 4.0, 6.0));
63    /// assert_eq!(iso3.rotation.euler_angles(), (std::f32::consts::FRAC_PI_2, 0.0, 0.0));
64    /// ```
65    #[inline]
66    #[must_use]
67    pub fn try_lerp_slerp(&self, other: &Self, t: T, epsilon: T) -> Option<Self>
68    where
69        T: RealField,
70    {
71        let tr = self
72            .translation
73            .vector
74            .lerp(&other.translation.vector, t.clone());
75        let rot = self.rotation.try_slerp(&other.rotation, t, epsilon)?;
76        Some(Self::from_parts(tr.into(), rot))
77    }
78}
79
80impl<T: SimdRealField> IsometryMatrix3<T> {
81    /// Interpolates between two isometries using a linear interpolation for the translation part,
82    /// and a spherical interpolation for the rotation part.
83    ///
84    /// Panics if the angle between both rotations is 180 degrees (in which case the interpolation
85    /// is not well-defined). Use `.try_lerp_slerp` instead to avoid the panic.
86    ///
87    /// # Examples:
88    ///
89    /// ```
90    /// # use nalgebra::{Vector3, Translation3, Rotation3, IsometryMatrix3};
91    ///
92    /// let t1 = Translation3::new(1.0, 2.0, 3.0);
93    /// let t2 = Translation3::new(4.0, 8.0, 12.0);
94    /// let q1 = Rotation3::from_euler_angles(std::f32::consts::FRAC_PI_4, 0.0, 0.0);
95    /// let q2 = Rotation3::from_euler_angles(-std::f32::consts::PI, 0.0, 0.0);
96    /// let iso1 = IsometryMatrix3::from_parts(t1, q1);
97    /// let iso2 = IsometryMatrix3::from_parts(t2, q2);
98    ///
99    /// let iso3 = iso1.lerp_slerp(&iso2, 1.0 / 3.0);
100    ///
101    /// assert_eq!(iso3.translation.vector, Vector3::new(2.0, 4.0, 6.0));
102    /// assert_eq!(iso3.rotation.euler_angles(), (std::f32::consts::FRAC_PI_2, 0.0, 0.0));
103    /// ```
104    #[inline]
105    #[must_use]
106    pub fn lerp_slerp(&self, other: &Self, t: T) -> Self
107    where
108        T: RealField,
109    {
110        let tr = self
111            .translation
112            .vector
113            .lerp(&other.translation.vector, t.clone());
114        let rot = self.rotation.slerp(&other.rotation, t);
115        Self::from_parts(tr.into(), rot)
116    }
117
118    /// Attempts to interpolate between two isometries using a linear interpolation for the translation part,
119    /// and a spherical interpolation for the rotation part.
120    ///
121    /// Returns `None` if the angle between both rotations is 180 degrees (in which case the interpolation
122    /// is not well-defined).
123    ///
124    /// # Examples:
125    ///
126    /// ```
127    /// # use nalgebra::{Vector3, Translation3, Rotation3, IsometryMatrix3};
128    ///
129    /// let t1 = Translation3::new(1.0, 2.0, 3.0);
130    /// let t2 = Translation3::new(4.0, 8.0, 12.0);
131    /// let q1 = Rotation3::from_euler_angles(std::f32::consts::FRAC_PI_4, 0.0, 0.0);
132    /// let q2 = Rotation3::from_euler_angles(-std::f32::consts::PI, 0.0, 0.0);
133    /// let iso1 = IsometryMatrix3::from_parts(t1, q1);
134    /// let iso2 = IsometryMatrix3::from_parts(t2, q2);
135    ///
136    /// let iso3 = iso1.lerp_slerp(&iso2, 1.0 / 3.0);
137    ///
138    /// assert_eq!(iso3.translation.vector, Vector3::new(2.0, 4.0, 6.0));
139    /// assert_eq!(iso3.rotation.euler_angles(), (std::f32::consts::FRAC_PI_2, 0.0, 0.0));
140    /// ```
141    #[inline]
142    #[must_use]
143    pub fn try_lerp_slerp(&self, other: &Self, t: T, epsilon: T) -> Option<Self>
144    where
145        T: RealField,
146    {
147        let tr = self
148            .translation
149            .vector
150            .lerp(&other.translation.vector, t.clone());
151        let rot = self.rotation.try_slerp(&other.rotation, t, epsilon)?;
152        Some(Self::from_parts(tr.into(), rot))
153    }
154}
155
156impl<T: SimdRealField> Isometry2<T> {
157    /// Interpolates between two isometries using a linear interpolation for the translation part,
158    /// and a spherical interpolation for the rotation part.
159    ///
160    /// Panics if the angle between both rotations is 180 degrees (in which case the interpolation
161    /// is not well-defined). Use `.try_lerp_slerp` instead to avoid the panic.
162    ///
163    /// # Examples:
164    ///
165    /// ```
166    /// # #[macro_use] extern crate approx;
167    /// # use nalgebra::{Vector2, Translation2, UnitComplex, Isometry2};
168    ///
169    /// let t1 = Translation2::new(1.0, 2.0);
170    /// let t2 = Translation2::new(4.0, 8.0);
171    /// let q1 = UnitComplex::new(std::f32::consts::FRAC_PI_4);
172    /// let q2 = UnitComplex::new(-std::f32::consts::PI);
173    /// let iso1 = Isometry2::from_parts(t1, q1);
174    /// let iso2 = Isometry2::from_parts(t2, q2);
175    ///
176    /// let iso3 = iso1.lerp_slerp(&iso2, 1.0 / 3.0);
177    ///
178    /// assert_eq!(iso3.translation.vector, Vector2::new(2.0, 4.0));
179    /// assert_relative_eq!(iso3.rotation.angle(), std::f32::consts::FRAC_PI_2);
180    /// ```
181    #[inline]
182    #[must_use]
183    pub fn lerp_slerp(&self, other: &Self, t: T) -> Self
184    where
185        T: RealField,
186    {
187        let tr = self
188            .translation
189            .vector
190            .lerp(&other.translation.vector, t.clone());
191        let rot = self.rotation.slerp(&other.rotation, t);
192        Self::from_parts(tr.into(), rot)
193    }
194}
195
196impl<T: SimdRealField> IsometryMatrix2<T> {
197    /// Interpolates between two isometries using a linear interpolation for the translation part,
198    /// and a spherical interpolation for the rotation part.
199    ///
200    /// Panics if the angle between both rotations is 180 degrees (in which case the interpolation
201    /// is not well-defined). Use `.try_lerp_slerp` instead to avoid the panic.
202    ///
203    /// # Examples:
204    ///
205    /// ```
206    /// # #[macro_use] extern crate approx;
207    /// # use nalgebra::{Vector2, Translation2, Rotation2, IsometryMatrix2};
208    ///
209    /// let t1 = Translation2::new(1.0, 2.0);
210    /// let t2 = Translation2::new(4.0, 8.0);
211    /// let q1 = Rotation2::new(std::f32::consts::FRAC_PI_4);
212    /// let q2 = Rotation2::new(-std::f32::consts::PI);
213    /// let iso1 = IsometryMatrix2::from_parts(t1, q1);
214    /// let iso2 = IsometryMatrix2::from_parts(t2, q2);
215    ///
216    /// let iso3 = iso1.lerp_slerp(&iso2, 1.0 / 3.0);
217    ///
218    /// assert_eq!(iso3.translation.vector, Vector2::new(2.0, 4.0));
219    /// assert_relative_eq!(iso3.rotation.angle(), std::f32::consts::FRAC_PI_2);
220    /// ```
221    #[inline]
222    #[must_use]
223    pub fn lerp_slerp(&self, other: &Self, t: T) -> Self
224    where
225        T: RealField,
226    {
227        let tr = self
228            .translation
229            .vector
230            .lerp(&other.translation.vector, t.clone());
231        let rot = self.rotation.slerp(&other.rotation, t);
232        Self::from_parts(tr.into(), rot)
233    }
234}