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}