nalgebra/geometry/
rotation_interpolation.rs

1use crate::{RealField, Rotation2, Rotation3, SimdRealField, UnitComplex, UnitQuaternion};
2
3/// # Interpolation
4impl<T: SimdRealField> Rotation2<T> {
5    /// Spherical linear interpolation between two rotation matrices.
6    ///
7    /// # Examples:
8    ///
9    /// ```
10    /// # #[macro_use] extern crate approx;
11    /// # use nalgebra::geometry::Rotation2;
12    ///
13    /// let rot1 = Rotation2::new(std::f32::consts::FRAC_PI_4);
14    /// let rot2 = Rotation2::new(-std::f32::consts::PI);
15    ///
16    /// let rot = rot1.slerp(&rot2, 1.0 / 3.0);
17    ///
18    /// assert_relative_eq!(rot.angle(), std::f32::consts::FRAC_PI_2);
19    /// ```
20    #[inline]
21    #[must_use]
22    pub fn slerp(&self, other: &Self, t: T) -> Self
23    where
24        T::Element: SimdRealField,
25    {
26        let c1 = UnitComplex::from(self.clone());
27        let c2 = UnitComplex::from(other.clone());
28        c1.slerp(&c2, t).into()
29    }
30}
31
32impl<T: SimdRealField> Rotation3<T> {
33    /// Spherical linear interpolation between two rotation matrices.
34    ///
35    /// Panics if the angle between both rotations is 180 degrees (in which case the interpolation
36    /// is not well-defined). Use `.try_slerp` instead to avoid the panic.
37    ///
38    /// # Examples:
39    ///
40    /// ```
41    /// # use nalgebra::geometry::Rotation3;
42    ///
43    /// let q1 = Rotation3::from_euler_angles(std::f32::consts::FRAC_PI_4, 0.0, 0.0);
44    /// let q2 = Rotation3::from_euler_angles(-std::f32::consts::PI, 0.0, 0.0);
45    ///
46    /// let q = q1.slerp(&q2, 1.0 / 3.0);
47    ///
48    /// assert_eq!(q.euler_angles(), (std::f32::consts::FRAC_PI_2, 0.0, 0.0));
49    /// ```
50    #[inline]
51    #[must_use]
52    pub fn slerp(&self, other: &Self, t: T) -> Self
53    where
54        T: RealField,
55    {
56        let q1 = UnitQuaternion::from(self.clone());
57        let q2 = UnitQuaternion::from(other.clone());
58        q1.slerp(&q2, t).into()
59    }
60
61    /// Computes the spherical linear interpolation between two rotation matrices or returns `None`
62    /// if both rotations are approximately 180 degrees apart (in which case the interpolation is
63    /// not well-defined).
64    ///
65    /// # Arguments
66    /// * `self`: the first rotation to interpolate from.
67    /// * `other`: the second rotation to interpolate toward.
68    /// * `t`: the interpolation parameter. Should be between 0 and 1.
69    /// * `epsilon`: the value below which the sinus of the angle separating both rotations
70    ///   must be to return `None`.
71    #[inline]
72    #[must_use]
73    pub fn try_slerp(&self, other: &Self, t: T, epsilon: T) -> Option<Self>
74    where
75        T: RealField,
76    {
77        let q1 = UnitQuaternion::from(self.clone());
78        let q2 = UnitQuaternion::from(other.clone());
79        q1.try_slerp(&q2, t, epsilon).map(|q| q.into())
80    }
81}