1use crate::interpolate::{Interpolate, Interpolator};
4use crate::interpolation::Interpolation;
5use crate::key::Key;
6#[cfg(not(feature = "std"))]
7use alloc::vec::Vec;
8use core::cmp::Ordering;
9#[cfg(feature = "serde")]
10use serde::{Deserialize, Serialize};
11
12#[derive(Debug, Clone, Default)]
25#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
26pub struct Spline<T, V>(pub(crate) Vec<Key<T, V>>);
27
28impl<T, V> Spline<T, V> {
29 fn internal_sort(&mut self)
31 where
32 T: PartialOrd,
33 {
34 self
35 .0
36 .sort_by(|k0, k1| k0.t.partial_cmp(&k1.t).unwrap_or(Ordering::Less));
37 }
38
39 pub fn from_vec(keys: Vec<Key<T, V>>) -> Self
42 where
43 T: PartialOrd,
44 {
45 let mut spline = Spline(keys);
46 spline.internal_sort();
47 spline
48 }
49
50 #[inline]
53 pub fn clear(&mut self) {
54 self.0.clear()
55 }
56
57 pub fn keys(&self) -> &[Key<T, V>] {
59 &self.0
60 }
61
62 #[inline(always)]
64 pub fn len(&self) -> usize {
65 self.0.len()
66 }
67
68 #[inline(always)]
70 pub fn is_empty(&self) -> bool {
71 self.0.is_empty()
72 }
73
74 pub fn sample_with_key(&self, t: T) -> Option<SampledWithKey<V>>
90 where
91 T: Interpolator,
92 V: Interpolate<T>,
93 {
94 let keys = &self.0;
95 let i = search_lower_cp(keys, t)?;
96 let cp0 = &keys[i];
97
98 let value = match cp0.interpolation {
99 Interpolation::Step(threshold) => {
100 let cp1 = &keys[i + 1];
101 let nt = t.normalize(cp0.t, cp1.t);
102 let value = V::step(nt, threshold, cp0.value, cp1.value);
103
104 Some(value)
105 }
106
107 Interpolation::Linear => {
108 let cp1 = &keys[i + 1];
109 let nt = t.normalize(cp0.t, cp1.t);
110 let value = V::lerp(nt, cp0.value, cp1.value);
111
112 Some(value)
113 }
114
115 Interpolation::Cosine => {
116 let cp1 = &keys[i + 1];
117 let nt = t.normalize(cp0.t, cp1.t);
118 let value = V::cosine(nt, cp0.value, cp1.value);
119
120 Some(value)
121 }
122
123 Interpolation::CatmullRom => {
124 if i == 0 || i >= keys.len() - 2 {
127 None
128 } else {
129 let cp1 = &keys[i + 1];
130 let cpm0 = &keys[i - 1];
131 let cpm1 = &keys[i + 2];
132 let nt = t.normalize(cp0.t, cp1.t);
133 let value = V::cubic_hermite(
134 nt,
135 (cpm0.t, cpm0.value),
136 (cp0.t, cp0.value),
137 (cp1.t, cp1.value),
138 (cpm1.t, cpm1.value),
139 );
140
141 Some(value)
142 }
143 }
144
145 Interpolation::Bezier(u) | Interpolation::StrokeBezier(_, u) => {
146 let cp1 = &keys[i + 1];
148 let nt = t.normalize(cp0.t, cp1.t);
149
150 let value = match cp1.interpolation {
151 Interpolation::Bezier(v) => V::cubic_bezier_mirrored(nt, cp0.value, u, v, cp1.value),
152
153 Interpolation::StrokeBezier(v, _) => V::cubic_bezier(nt, cp0.value, u, v, cp1.value),
154
155 _ => V::quadratic_bezier(nt, cp0.value, u, cp1.value),
156 };
157
158 Some(value)
159 }
160 };
161
162 value.map(|value| SampledWithKey { value, key: i })
163 }
164
165 pub fn sample(&self, t: T) -> Option<V>
168 where
169 T: Interpolator,
170 V: Interpolate<T>,
171 {
172 self.sample_with_key(t).map(|sampled| sampled.value)
173 }
174
175 pub fn clamped_sample_with_key(&self, t: T) -> Option<SampledWithKey<V>>
187 where
188 T: Interpolator,
189 V: Interpolate<T>,
190 {
191 if self.0.is_empty() {
192 return None;
193 }
194
195 self.sample_with_key(t).or_else(move || {
196 let first = self.0.first().unwrap();
197
198 if t <= first.t {
199 let sampled = SampledWithKey {
200 value: first.value,
201 key: 0,
202 };
203 Some(sampled)
204 } else {
205 let last = self.0.last().unwrap();
206
207 if t >= last.t {
208 let sampled = SampledWithKey {
209 value: last.value,
210 key: self.0.len() - 1,
211 };
212 Some(sampled)
213 } else {
214 None
215 }
216 }
217 })
218 }
219
220 pub fn clamped_sample(&self, t: T) -> Option<V>
222 where
223 T: Interpolator,
224 V: Interpolate<T>,
225 {
226 self.clamped_sample_with_key(t).map(|sampled| sampled.value)
227 }
228
229 pub fn add(&mut self, key: Key<T, V>)
231 where
232 T: PartialOrd,
233 {
234 self.0.push(key);
235 self.internal_sort();
236 }
237
238 pub fn remove(&mut self, index: usize) -> Option<Key<T, V>> {
240 if index >= self.0.len() {
241 None
242 } else {
243 Some(self.0.remove(index))
244 }
245 }
246
247 pub fn replace<F>(&mut self, index: usize, f: F) -> Option<Key<T, V>>
257 where
258 F: FnOnce(&Key<T, V>) -> Key<T, V>,
259 T: PartialOrd,
260 {
261 let key = self.remove(index)?;
262 self.add(f(&key));
263 Some(key)
264 }
265
266 pub fn get(&self, index: usize) -> Option<&Key<T, V>> {
268 self.0.get(index)
269 }
270
271 pub fn get_mut(&mut self, index: usize) -> Option<KeyMut<T, V>> {
273 self.0.get_mut(index).map(|key| KeyMut {
274 value: &mut key.value,
275 interpolation: &mut key.interpolation,
276 })
277 }
278}
279
280impl<T, V> FromIterator<Key<T, V>> for Spline<T, V>
281where
282 T: PartialOrd,
283{
284 fn from_iter<I: IntoIterator<Item = Key<T, V>>>(iter: I) -> Self {
285 Self::from_vec(iter.into_iter().collect())
286 }
287}
288
289#[derive(Clone, Debug, Eq, Hash, PartialEq)]
291pub struct SampledWithKey<V> {
292 pub value: V,
294
295 pub key: usize,
297}
298
299#[derive(Debug)]
305pub struct KeyMut<'a, T, V> {
306 pub value: &'a mut V,
308 pub interpolation: &'a mut Interpolation<T, V>,
310}
311
312fn search_lower_cp<T, V>(cps: &[Key<T, V>], t: T) -> Option<usize>
315where
316 T: PartialOrd,
317{
318 let len = cps.len();
319 if len < 2 {
320 return None;
321 }
322 match cps.binary_search_by(|key| key.t.partial_cmp(&t).unwrap()) {
323 Err(i) if i >= len => None,
324 Err(0) => None,
325 Err(i) => Some(i - 1),
326 Ok(i) if i == len - 1 => None,
327 Ok(i) => Some(i),
328 }
329}