nalgebra/base/
interpolation.rs

1use crate::storage::Storage;
2use crate::{
3    Allocator, DefaultAllocator, Dim, OVector, One, RealField, Scalar, Unit, Vector, Zero,
4};
5use simba::scalar::{ClosedAdd, ClosedMul, ClosedSub};
6
7/// # Interpolation
8impl<T: Scalar + Zero + One + ClosedAdd + ClosedSub + ClosedMul, D: Dim, S: Storage<T, D>>
9    Vector<T, D, S>
10{
11    /// Returns `self * (1.0 - t) + rhs * t`, i.e., the linear blend of the vectors x and y using the scalar value a.
12    ///
13    /// The value for a is not restricted to the range `[0, 1]`.
14    ///
15    /// # Examples:
16    ///
17    /// ```
18    /// # use nalgebra::Vector3;
19    /// let x = Vector3::new(1.0, 2.0, 3.0);
20    /// let y = Vector3::new(10.0, 20.0, 30.0);
21    /// assert_eq!(x.lerp(&y, 0.1), Vector3::new(1.9, 3.8, 5.7));
22    /// ```
23    #[must_use]
24    pub fn lerp<S2: Storage<T, D>>(&self, rhs: &Vector<T, D, S2>, t: T) -> OVector<T, D>
25    where
26        DefaultAllocator: Allocator<T, D>,
27    {
28        let mut res = self.clone_owned();
29        res.axpy(t.clone(), rhs, T::one() - t);
30        res
31    }
32
33    /// Computes the spherical linear interpolation between two non-zero vectors.
34    ///
35    /// The result is a unit vector.
36    ///
37    /// # Examples:
38    ///
39    /// ```
40    /// # use nalgebra::{Unit, Vector2};
41    ///
42    /// let v1 =Vector2::new(1.0, 2.0);
43    /// let v2 = Vector2::new(2.0, -3.0);
44    ///
45    /// let v = v1.slerp(&v2, 1.0);
46    ///
47    /// assert_eq!(v, v2.normalize());
48    /// ```
49    #[must_use]
50    pub fn slerp<S2: Storage<T, D>>(&self, rhs: &Vector<T, D, S2>, t: T) -> OVector<T, D>
51    where
52        T: RealField,
53        DefaultAllocator: Allocator<T, D>,
54    {
55        let me = Unit::new_normalize(self.clone_owned());
56        let rhs = Unit::new_normalize(rhs.clone_owned());
57        me.slerp(&rhs, t).into_inner()
58    }
59}
60
61/// # Interpolation between two unit vectors
62impl<T: RealField, D: Dim, S: Storage<T, D>> Unit<Vector<T, D, S>> {
63    /// Computes the spherical linear interpolation between two unit vectors.
64    ///
65    /// # Examples:
66    ///
67    /// ```
68    /// # use nalgebra::{Unit, Vector2};
69    ///
70    /// let v1 = Unit::new_normalize(Vector2::new(1.0, 2.0));
71    /// let v2 = Unit::new_normalize(Vector2::new(2.0, -3.0));
72    ///
73    /// let v = v1.slerp(&v2, 1.0);
74    ///
75    /// assert_eq!(v, v2);
76    /// ```
77    #[must_use]
78    pub fn slerp<S2: Storage<T, D>>(
79        &self,
80        rhs: &Unit<Vector<T, D, S2>>,
81        t: T,
82    ) -> Unit<OVector<T, D>>
83    where
84        DefaultAllocator: Allocator<T, D>,
85    {
86        // TODO: the result is wrong when self and rhs are collinear with opposite direction.
87        self.try_slerp(rhs, t, T::default_epsilon())
88            .unwrap_or_else(|| Unit::new_unchecked(self.clone_owned()))
89    }
90
91    /// Computes the spherical linear interpolation between two unit vectors.
92    ///
93    /// Returns `None` if the two vectors are almost collinear and with opposite direction
94    /// (in this case, there is an infinity of possible results).
95    #[must_use]
96    pub fn try_slerp<S2: Storage<T, D>>(
97        &self,
98        rhs: &Unit<Vector<T, D, S2>>,
99        t: T,
100        epsilon: T,
101    ) -> Option<Unit<OVector<T, D>>>
102    where
103        DefaultAllocator: Allocator<T, D>,
104    {
105        let c_hang = self.dot(rhs);
106
107        // self == other
108        if c_hang >= T::one() {
109            return Some(Unit::new_unchecked(self.clone_owned()));
110        }
111
112        let hang = c_hang.clone().acos();
113        let s_hang = (T::one() - c_hang.clone() * c_hang).sqrt();
114
115        // TODO: what if s_hang is 0.0 ? The result is not well-defined.
116        if relative_eq!(s_hang, T::zero(), epsilon = epsilon) {
117            None
118        } else {
119            let ta = ((T::one() - t.clone()) * hang.clone()).sin() / s_hang.clone();
120            let tb = (t * hang).sin() / s_hang;
121            let mut res = self.scale(ta);
122            res.axpy(tb, &**rhs, T::one());
123
124            Some(Unit::new_unchecked(res))
125        }
126    }
127}