1#[cfg(feature = "serialization")] use serde_derive::{Deserialize, Serialize};
4#[cfg(not(feature = "std"))] use alloc::vec::Vec;
5#[cfg(feature = "std")] use std::cmp::Ordering;
6#[cfg(feature = "std")] use std::ops::{Div, Mul};
7#[cfg(not(feature = "std"))] use core::ops::{Div, Mul};
8#[cfg(not(feature = "std"))] use core::cmp::Ordering;
9
10use crate::interpolate::{Interpolate, Additive, One, Trigo};
11use crate::interpolation::Interpolation;
12use crate::key::Key;
13
14#[derive(Debug, Clone)]
27#[cfg_attr(feature = "serialization", derive(Deserialize, Serialize))]
28pub struct Spline<T, V>(pub(crate) Vec<Key<T, V>>);
29
30impl<T, V> Spline<T, V> {
31 fn internal_sort(&mut self) where T: PartialOrd {
33 self.0.sort_by(|k0, k1| k0.t.partial_cmp(&k1.t).unwrap_or(Ordering::Less));
34 }
35
36 pub fn from_vec(keys: Vec<Key<T, V>>) -> Self where T: PartialOrd {
39 let mut spline = Spline(keys);
40 spline.internal_sort();
41 spline
42 }
43
44 pub fn from_iter<I>(iter: I) -> Self where I: Iterator<Item = Key<T, V>>, T: PartialOrd {
52 Self::from_vec(iter.collect())
53 }
54
55 pub fn keys(&self) -> &[Key<T, V>] {
57 &self.0
58 }
59
60 #[inline(always)]
62 pub fn len(&self) -> usize {
63 self.0.len()
64 }
65
66 #[inline(always)]
68 pub fn is_empty(&self) -> bool {
69 self.0.is_empty()
70 }
71
72 pub fn sample_with_key(&self, t: T) -> Option<(V, &Key<T, V>, Option<&Key<T, V>>)>
88 where T: Additive + One + Trigo + Mul<T, Output = T> + Div<T, Output = T> + PartialOrd,
89 V: Interpolate<T> {
90 let keys = &self.0;
91 let i = search_lower_cp(keys, t)?;
92 let cp0 = &keys[i];
93
94 match cp0.interpolation {
95 Interpolation::Step(threshold) => {
96 let cp1 = &keys[i + 1];
97 let nt = normalize_time(t, cp0, cp1);
98 let value = if nt < threshold { cp0.value } else { cp1.value };
99
100 Some((value, cp0, Some(cp1)))
101 }
102
103 Interpolation::Linear => {
104 let cp1 = &keys[i + 1];
105 let nt = normalize_time(t, cp0, cp1);
106 let value = Interpolate::lerp(cp0.value, cp1.value, nt);
107
108 Some((value, cp0, Some(cp1)))
109 }
110
111 Interpolation::Cosine => {
112 let two_t = T::one() + T::one();
113 let cp1 = &keys[i + 1];
114 let nt = normalize_time(t, cp0, cp1);
115 let cos_nt = (T::one() - (nt * T::pi()).cos()) / two_t;
116 let value = Interpolate::lerp(cp0.value, cp1.value, cos_nt);
117
118 Some((value, cp0, Some(cp1)))
119 }
120
121 Interpolation::CatmullRom => {
122 if i == 0 || i >= keys.len() - 2 {
125 None
126 } else {
127 let cp1 = &keys[i + 1];
128 let cpm0 = &keys[i - 1];
129 let cpm1 = &keys[i + 2];
130 let nt = normalize_time(t, cp0, cp1);
131 let value = Interpolate::cubic_hermite((cpm0.value, cpm0.t), (cp0.value, cp0.t), (cp1.value, cp1.t), (cpm1.value, cpm1.t), nt);
132
133 Some((value, cp0, Some(cp1)))
134 }
135 }
136
137 Interpolation::Bezier(u) => {
138 let cp1 = &keys[i + 1];
140 let nt = normalize_time(t, cp0, cp1);
141
142 let value =
143 if let Interpolation::Bezier(v) = cp1.interpolation {
144 Interpolate::cubic_bezier(cp0.value, u, v, cp1.value, nt)
145 } else {
146 Interpolate::quadratic_bezier(cp0.value, u, cp1.value, nt)
147 };
148
149 Some((value, cp0, Some(cp1)))
150 }
151
152 Interpolation::StrokeBezier(input, output) => {
153 let cp1 = &keys[i + 1];
154 let nt = normalize_time(t, cp0, cp1);
155 let value = Interpolate::cubic_bezier(cp0.value, input, output, cp1.value, nt);
156
157 Some((value, cp0, Some(cp1)))
158 }
159
160 Interpolation::__NonExhaustive => unreachable!(),
161 }
162 }
163
164 pub fn sample(&self, t: T) -> Option<V>
167 where T: Additive + One + Trigo + Mul<T, Output = T> + Div<T, Output = T> + PartialOrd,
168 V: Interpolate<T> {
169 self.sample_with_key(t).map(|(v, _, _)| v)
170 }
171
172 pub fn clamped_sample_with_key(&self, t: T) -> Option<(V, &Key<T, V>, Option<&Key<T, V>>)>
184 where T: Additive + One + Trigo + Mul<T, Output = T> + Div<T, Output = T> + PartialOrd,
185 V: Interpolate<T> {
186 if self.0.is_empty() {
187 return None;
188 }
189
190 self.sample_with_key(t).or_else(move || {
191 let first = self.0.first().unwrap();
192 if t <= first.t {
193 let second = if self.0.len() >= 2 { Some(&self.0[1]) } else { None };
194 Some((first.value, &first, second))
195 } else {
196 let last = self.0.last().unwrap();
197
198 if t >= last.t {
199 Some((last.value, &last, None))
200 } else {
201 None
202 }
203 }
204 })
205 }
206
207 pub fn clamped_sample(&self, t: T) -> Option<V>
209 where T: Additive + One + Trigo + Mul<T, Output = T> + Div<T, Output = T> + PartialOrd,
210 V: Interpolate<T> {
211 self.clamped_sample_with_key(t).map(|(v, _, _)| v)
212 }
213
214 pub fn add(&mut self, key: Key<T, V>) where T: PartialOrd {
216 self.0.push(key);
217 self.internal_sort();
218 }
219
220 pub fn remove(&mut self, index: usize) -> Option<Key<T, V>> {
222 if index >= self.0.len() {
223 None
224 } else {
225 Some(self.0.remove(index))
226 }
227 }
228
229 pub fn replace<F>(
239 &mut self,
240 index: usize,
241 f: F
242 ) -> Option<Key<T, V>>
243 where
244 F: FnOnce(&Key<T, V>) -> Key<T, V>,
245 T: PartialOrd
246 {
247 let key = self.remove(index)?;
248 self.add(f(&key));
249 Some(key)
250 }
251
252 pub fn get(&self, index: usize) -> Option<&Key<T, V>> {
254 self.0.get(index)
255 }
256
257 pub fn get_mut(&mut self, index: usize) -> Option<KeyMut<T, V>> {
259 self.0.get_mut(index).map(|key| KeyMut {
260 value: &mut key.value,
261 interpolation: &mut key.interpolation
262 })
263 }
264}
265
266pub struct KeyMut<'a, T, V> {
272 pub value: &'a mut V,
274 pub interpolation: &'a mut Interpolation<T, V>,
276}
277
278#[inline(always)]
280pub(crate) fn normalize_time<T, V>(
281 t: T,
282 cp: &Key<T, V>,
283 cp1: &Key<T, V>
284) -> T where T: Additive + Div<T, Output = T> + PartialEq {
285 assert!(cp1.t != cp.t, "overlapping keys");
286 (t - cp.t) / (cp1.t - cp.t)
287}
288
289fn search_lower_cp<T, V>(cps: &[Key<T, V>], t: T) -> Option<usize> where T: PartialOrd {
291 let mut i = 0;
292 let len = cps.len();
293
294 if len < 2 {
295 return None;
296 }
297
298 loop {
299 let cp = &cps[i];
300 let cp1 = &cps[i+1];
301
302 if t >= cp1.t {
303 if i >= len - 2 {
304 return None;
305 }
306
307 i += 1;
308 } else if t < cp.t {
309 if i == 0 {
310 return None;
311 }
312
313 i -= 1;
314 } else {
315 break; }
317 }
318
319 Some(i)
320}