1use crate::*;
2use enum_dispatch::enum_dispatch;
3
4use std::{
5 collections::BTreeMap,
6 iter::FromIterator,
7 ops::{Add, Mul, Sub},
8};
9
10mod sample;
11pub use sample::*;
12
13#[derive(Clone, Debug, PartialEq, Hash)]
26#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
27#[cfg_attr(feature = "facet", derive(Facet))]
28#[cfg_attr(feature = "facet", facet(opaque))]
29#[cfg_attr(feature = "rkyv", derive(Archive, RkyvSerialize, RkyvDeserialize))]
30pub struct TimeDataMap<T> {
31 #[cfg(not(feature = "interpolation"))]
33 pub values: BTreeMap<Time, T>,
34 #[cfg(feature = "interpolation")]
35 pub values: BTreeMap<Time, (T, Option<crate::Key<T>>)>,
36}
37
38impl<T: Eq> Eq for TimeDataMap<T> {}
40
41#[cfg(not(feature = "interpolation"))]
43impl<T> AsRef<BTreeMap<Time, T>> for TimeDataMap<T> {
44 fn as_ref(&self) -> &BTreeMap<Time, T> {
45 &self.values
46 }
47}
48
49impl<T> TimeDataMap<T> {
53 #[inline]
55 pub fn iter(&self) -> impl Iterator<Item = (&Time, &T)> {
56 #[cfg(not(feature = "interpolation"))]
57 {
58 self.values.iter()
59 }
60 #[cfg(feature = "interpolation")]
61 {
62 self.values.iter().map(|(t, (v, _))| (t, v))
63 }
64 }
65
66 #[inline]
68 pub fn is_empty(&self) -> bool {
69 self.values.is_empty()
70 }
71
72 #[inline]
74 pub fn len(&self) -> usize {
75 self.values.len()
76 }
77
78 #[inline]
82 pub fn remove(&mut self, time: &Time) -> Option<T> {
83 #[cfg(not(feature = "interpolation"))]
84 {
85 self.values.remove(time)
86 }
87 #[cfg(feature = "interpolation")]
88 {
89 self.values.remove(time).map(|(v, _)| v)
90 }
91 }
92}
93
94impl<T> From<BTreeMap<Time, T>> for TimeDataMap<T> {
96 fn from(values: BTreeMap<Time, T>) -> Self {
97 #[cfg(not(feature = "interpolation"))]
98 {
99 Self { values }
100 }
101 #[cfg(feature = "interpolation")]
102 {
103 Self {
104 values: values.into_iter().map(|(k, v)| (k, (v, None))).collect(),
105 }
106 }
107 }
108}
109
110#[enum_dispatch]
112pub trait TimeDataMapControl<T> {
113 fn len(&self) -> usize;
115 fn is_empty(&self) -> bool;
117 fn is_animated(&self) -> bool;
119}
120
121impl<T> TimeDataMapControl<T> for TimeDataMap<T> {
122 fn len(&self) -> usize {
123 self.values.len()
124 }
125
126 fn is_empty(&self) -> bool {
127 self.values.is_empty()
128 }
129
130 fn is_animated(&self) -> bool {
131 self.values.len() > 1
132 }
133}
134
135#[cfg(feature = "builtin-types")]
136impl<T> crate::DataTypeOps for TimeDataMap<T>
137where
138 T: crate::DataTypeOps,
139{
140 fn data_type(&self) -> crate::DataType {
141 #[cfg(not(feature = "interpolation"))]
143 {
144 self.values
145 .values()
146 .next()
147 .map(|v| v.data_type())
148 .unwrap_or(DataType::Real)
149 }
150 #[cfg(feature = "interpolation")]
151 {
152 self.values
153 .values()
154 .next()
155 .map(|(v, _)| v.data_type())
156 .unwrap_or(DataType::Real)
157 }
158 }
159
160 fn type_name(&self) -> &'static str {
161 #[cfg(not(feature = "interpolation"))]
163 {
164 self.values
165 .values()
166 .next()
167 .map(|v| v.type_name())
168 .unwrap_or("unknown")
169 }
170 #[cfg(feature = "interpolation")]
171 {
172 self.values
173 .values()
174 .next()
175 .map(|(v, _)| v.type_name())
176 .unwrap_or("unknown")
177 }
178 }
179}
180
181#[cfg(feature = "builtin-types")]
183macro_rules! impl_from_at_time {
184 ($($t:ty),+) => {
185 $(
186 impl From<(Time, $t)> for TimeDataMap<$t> {
187 fn from((time, value): (Time, $t)) -> Self {
188 TimeDataMap::from(BTreeMap::from([(time, value)]))
189 }
190 }
191 )+
192 };
193}
194
195#[cfg(feature = "builtin-types")]
196impl_from_at_time!(
197 Boolean, Real, Integer, String, Color, BooleanVec, RealVec, IntegerVec, StringVec, ColorVec,
198 Data
199);
200
201#[cfg(all(feature = "builtin-types", feature = "vector2"))]
202impl_from_at_time!(Vector2);
203#[cfg(all(feature = "builtin-types", feature = "vector3"))]
204impl_from_at_time!(Vector3);
205#[cfg(all(feature = "builtin-types", feature = "matrix3"))]
206impl_from_at_time!(Matrix3);
207#[cfg(all(feature = "builtin-types", feature = "normal3"))]
208impl_from_at_time!(Normal3);
209#[cfg(all(feature = "builtin-types", feature = "point3"))]
210impl_from_at_time!(Point3);
211#[cfg(all(feature = "builtin-types", feature = "matrix4"))]
212impl_from_at_time!(Matrix4);
213
214#[cfg(all(
215 feature = "builtin-types",
216 feature = "vector2",
217 feature = "vec_variants"
218))]
219impl_from_at_time!(Vector2Vec);
220#[cfg(all(
221 feature = "builtin-types",
222 feature = "vector3",
223 feature = "vec_variants"
224))]
225impl_from_at_time!(Vector3Vec);
226#[cfg(all(
227 feature = "builtin-types",
228 feature = "matrix3",
229 feature = "vec_variants"
230))]
231impl_from_at_time!(Matrix3Vec);
232#[cfg(all(
233 feature = "builtin-types",
234 feature = "normal3",
235 feature = "vec_variants"
236))]
237impl_from_at_time!(Normal3Vec);
238#[cfg(all(
239 feature = "builtin-types",
240 feature = "point3",
241 feature = "vec_variants"
242))]
243impl_from_at_time!(Point3Vec);
244#[cfg(all(
245 feature = "builtin-types",
246 feature = "matrix4",
247 feature = "vec_variants"
248))]
249impl_from_at_time!(Matrix4Vec);
250
251impl<T> TimeDataMap<T> {
252 pub fn insert(&mut self, time: Time, value: T) {
254 #[cfg(not(feature = "interpolation"))]
255 {
256 self.values.insert(time, value);
257 }
258 #[cfg(feature = "interpolation")]
259 {
260 self.values.insert(time, (value, None));
261 }
262 }
263
264 pub fn get(&self, time: &Time) -> Option<&T> {
266 #[cfg(not(feature = "interpolation"))]
267 {
268 self.values.get(time)
269 }
270 #[cfg(feature = "interpolation")]
271 {
272 self.values.get(time).map(|(v, _)| v)
273 }
274 }
275}
276
277impl<T> TimeDataMap<T>
278where
279 T: Clone + Add<Output = T> + Mul<f32, Output = T> + Sub<Output = T>,
280{
281 pub fn interpolate(&self, time: Time) -> T {
282 #[cfg(not(feature = "interpolation"))]
283 {
284 interpolate(&self.values, time)
285 }
286 #[cfg(feature = "interpolation")]
287 {
288 interpolate_with_specs(&self.values, time)
289 }
290 }
291}
292
293#[cfg(feature = "interpolation")]
295impl<T> TimeDataMap<T> {
296 pub fn insert_with_interpolation(&mut self, time: Time, value: T, spec: crate::Key<T>) {
301 self.values.insert(time, (value, Some(spec)));
302 }
303
304 pub fn interpolation(&self, time: &Time) -> Option<&crate::Key<T>> {
308 self.values.get(time)?.1.as_ref()
309 }
310
311 pub fn set_interpolation_at(&mut self, time: &Time, key: crate::Key<T>) -> crate::Result<()> {
316 if let Some(entry) = self.values.get_mut(time) {
317 entry.1 = Some(key);
318 Ok(())
319 } else {
320 Err(crate::Error::TimeNotFound { time: *time })
321 }
322 }
323
324 pub fn clear_interpolation(&mut self) {
328 for (_, interp) in self.values.values_mut() {
329 *interp = None;
330 }
331 }
332
333 pub fn has_interpolation(&self) -> bool {
337 self.values.values().any(|(_, interp)| interp.is_some())
338 }
339}
340
341impl<T, V> FromIterator<(Time, V)> for TimeDataMap<T>
342where
343 V: Into<T>,
344{
345 fn from_iter<I>(iter: I) -> Self
346 where
347 I: IntoIterator<Item = (Time, V)>,
348 {
349 Self::from(BTreeMap::from_iter(
350 iter.into_iter().map(|(t, v)| (t, v.into())),
351 ))
352 }
353}
354
355impl<T> TimeDataMap<T> {
356 pub fn closest_sample(&self, time: Time) -> &T {
357 #[cfg(not(feature = "interpolation"))]
358 {
359 let mut range = self.values.range(time..);
360 let greater_or_equal = range.next();
361
362 let mut range = self.values.range(..time);
363 let less_than = range.next_back();
364
365 match (less_than, greater_or_equal) {
366 (Some((lower_k, lower_v)), Some((upper_k, upper_v))) => {
367 if (time.as_ref() - lower_k.as_ref()).abs()
368 <= (upper_k.as_ref() - time.as_ref()).abs()
369 {
370 lower_v
371 } else {
372 upper_v
373 }
374 }
375 (Some(entry), None) | (None, Some(entry)) => entry.1,
376 (None, None) => {
377 unreachable!("TimeDataMap can never be empty")
378 }
379 }
380 }
381 #[cfg(feature = "interpolation")]
382 {
383 let mut range = self.values.range(time..);
384 let greater_or_equal = range.next();
385
386 let mut range = self.values.range(..time);
387 let less_than = range.next_back();
388
389 match (less_than, greater_or_equal) {
390 (Some((lower_k, (lower_v, _))), Some((upper_k, (upper_v, _)))) => {
391 if (time.as_ref() - lower_k.as_ref()).abs()
392 <= (upper_k.as_ref() - time.as_ref()).abs()
393 {
394 lower_v
395 } else {
396 upper_v
397 }
398 }
399 (Some((_, (v, _))), None) | (None, Some((_, (v, _)))) => v,
400 (None, None) => {
401 unreachable!("TimeDataMap can never be empty")
402 }
403 }
404 }
405 }
406
407 pub fn sample_at(&self, time: Time) -> Option<&T> {
409 self.get(&time)
410 }
411
412 pub fn sample_at_or_before(&self, time: Time) -> Option<&T> {
414 #[cfg(not(feature = "interpolation"))]
415 {
416 self.values.range(..=time).next_back().map(|(_, v)| v)
417 }
418 #[cfg(feature = "interpolation")]
419 {
420 self.values.range(..=time).next_back().map(|(_, (v, _))| v)
421 }
422 }
423
424 pub fn sample_at_or_after(&self, time: Time) -> Option<&T> {
426 #[cfg(not(feature = "interpolation"))]
427 {
428 self.values.range(time..).next().map(|(_, v)| v)
429 }
430 #[cfg(feature = "interpolation")]
431 {
432 self.values.range(time..).next().map(|(_, (v, _))| v)
433 }
434 }
435
436 pub fn sample_surrounding<const N: usize>(&self, time: Time) -> SmallVec<[(Time, &T); N]> {
441 let before_count = N / 2;
443
444 #[cfg(not(feature = "interpolation"))]
445 {
446 let mut result = self
447 .values
448 .range(..time)
449 .rev()
450 .take(before_count)
451 .map(|(t, v)| (*t, v))
452 .collect::<SmallVec<[_; N]>>();
453 result.reverse();
454
455 let after_count = N - result.len();
457 result.extend(
458 self.values
459 .range(time..)
460 .take(after_count)
461 .map(|(t, v)| (*t, v)),
462 );
463 result
464 }
465
466 #[cfg(feature = "interpolation")]
467 {
468 let mut result = self
469 .values
470 .range(..time)
471 .rev()
472 .take(before_count)
473 .map(|(t, (v, _))| (*t, v))
474 .collect::<SmallVec<[_; N]>>();
475 result.reverse();
476
477 let after_count = N - result.len();
479 result.extend(
480 self.values
481 .range(time..)
482 .take(after_count)
483 .map(|(t, (v, _))| (*t, v)),
484 );
485 result
486 }
487 }
488}
489
490#[cfg(feature = "matrix3")]
497#[derive(Clone)]
498struct Trans2(f32, f32);
499
500#[cfg(feature = "matrix3")]
501impl Add for Trans2 {
502 type Output = Self;
503 fn add(self, rhs: Self) -> Self {
504 Trans2(self.0 + rhs.0, self.1 + rhs.1)
505 }
506}
507
508#[cfg(feature = "matrix3")]
509impl Sub for Trans2 {
510 type Output = Self;
511 fn sub(self, rhs: Self) -> Self {
512 Trans2(self.0 - rhs.0, self.1 - rhs.1)
513 }
514}
515
516#[cfg(feature = "matrix3")]
517impl Mul<f32> for Trans2 {
518 type Output = Self;
519 fn mul(self, s: f32) -> Self {
520 Trans2(self.0 * s, self.1 * s)
521 }
522}
523
524#[cfg(feature = "matrix3")]
526#[derive(Clone)]
527struct DiagStretch(f32, f32);
528
529#[cfg(feature = "matrix3")]
530impl Add for DiagStretch {
531 type Output = Self;
532 fn add(self, rhs: Self) -> Self {
533 DiagStretch(self.0 + rhs.0, self.1 + rhs.1)
534 }
535}
536
537#[cfg(feature = "matrix3")]
538impl Sub for DiagStretch {
539 type Output = Self;
540 fn sub(self, rhs: Self) -> Self {
541 DiagStretch(self.0 - rhs.0, self.1 - rhs.1)
542 }
543}
544
545#[cfg(feature = "matrix3")]
546impl Mul<f32> for DiagStretch {
547 type Output = Self;
548 fn mul(self, s: f32) -> Self {
549 DiagStretch(self.0 * s, self.1 * s)
550 }
551}
552
553#[cfg(feature = "matrix3")]
555#[inline(always)]
556fn interpolate_rotation(map: &BTreeMap<Time, f32>, time: Time) -> f32 {
557 if map.len() == 1 {
558 return *map.values().next().unwrap();
559 }
560
561 let first = map.iter().next().unwrap();
562 let last = map.iter().next_back().unwrap();
563
564 if time <= *first.0 {
565 return *first.1;
566 }
567
568 if time >= *last.0 {
569 return *last.1;
570 }
571
572 let lower = map.range(..=time).next_back().unwrap();
573 let upper = map.range(time..).next().unwrap();
574
575 let t0 = f32::from(*lower.0);
576 let t1 = f32::from(*upper.0);
577 let a0 = *lower.1;
578 let a1 = *upper.1;
579
580 let t: f32 = (f32::from(time) - t0) / (t1 - t0);
582
583 use std::f32::consts::{PI, TAU};
585 let mut diff = a1 - a0;
586 if diff > PI {
587 diff -= TAU;
588 } else if diff < -PI {
589 diff += TAU;
590 }
591 a0 + diff * t
592}
593
594#[cfg(feature = "interpolation")]
597fn bezier_handle_to_slope<V>(
598 handle: &crate::BezierHandle<V>,
599 t1: f32,
600 t2: f32,
601 _v1: &V,
602 _v2: &V,
603) -> Option<V>
604where
605 V: Clone + Add<Output = V> + Sub<Output = V> + Mul<f32, Output = V>,
606{
607 match handle {
608 crate::BezierHandle::SlopePerSecond(s) => Some(s.clone()),
609 crate::BezierHandle::SlopePerFrame(s) => {
610 let frames = (t2 - t1).max(f32::EPSILON);
611 Some(s.clone() * (frames / (t2 - t1)))
612 }
613 crate::BezierHandle::Delta { time, value } => {
614 let time_f32: f32 = (*time).into();
615 if time_f32.abs() <= f32::EPSILON {
616 None
617 } else {
618 Some(value.clone() * (1.0 / time_f32))
619 }
620 }
621 crate::BezierHandle::Angle(_) => None, }
623}
624
625#[cfg(feature = "interpolation")]
626#[allow(clippy::too_many_arguments)]
627fn smooth_tangent<V>(
628 t1: f32,
629 v1: &V,
630 t2: f32,
631 v2: &V,
632 map: &BTreeMap<Time, (V, Option<crate::Key<V>>)>,
633 _time: Time,
634 anchor: Time,
635 incoming: bool,
636) -> V
637where
638 V: Clone + Add<Output = V> + Mul<f32, Output = V> + Sub<Output = V>,
639{
640 use smallvec::SmallVec;
641
642 let mut window = SmallVec::<[(Time, V); 2]>::new();
645
646 if incoming {
647 if let Some(prev) = map.range(..anchor).next_back() {
648 window.push((*prev.0, prev.1.0.clone()));
649 }
650 window.push((anchor, v1.clone()));
651 } else {
652 window.push((anchor, v1.clone()));
653 if let Some(next) = map.range(anchor..).nth(1) {
654 window.push((*next.0, next.1.0.clone()));
655 }
656 }
657
658 if window.len() == 2 {
659 let (t0, p0) = &window[0];
660 let (t1, p1) = &window[1];
661 let t0_f: f32 = (*t0).into();
662 let t1_f: f32 = (*t1).into();
663 let dt = (t1_f - t0_f).max(f32::EPSILON);
664 (p1.clone() - p0.clone()) * (1.0 / dt)
665 } else {
666 (v2.clone() - v1.clone()) * (1.0 / (t2 - t1).max(f32::EPSILON))
668 }
669}
670
671#[cfg(feature = "interpolation")]
672fn evaluate_mixed_bezier<V>(
673 time: Time,
674 t1: Time,
675 v1: &V,
676 slope_out: &V,
677 t2: Time,
678 v2: &V,
679 slope_in: &V,
680) -> V
681where
682 V: Clone + Add<Output = V> + Mul<f32, Output = V> + Sub<Output = V>,
683{
684 use crate::interpolation::bezier_helpers::*;
685
686 let (p1, p2) = control_points_from_slopes(t1.into(), v1, slope_out, t2.into(), v2, slope_in);
687
688 evaluate_bezier_component_wise(
689 time.into(),
690 (t1.into(), v1),
691 (p1.0, &p1.1),
692 (p2.0, &p2.1),
693 (t2.into(), v2),
694 )
695}
696
697#[cfg(feature = "interpolation")]
702#[inline(always)]
703pub(crate) fn interpolate_with_specs<V>(
704 map: &BTreeMap<Time, (V, Option<crate::Key<V>>)>,
705 time: Time,
706) -> V
707where
708 V: Clone + Add<Output = V> + Mul<f32, Output = V> + Sub<Output = V>,
709{
710 if map.len() == 1 {
711 return map.values().next().unwrap().0.clone();
712 }
713
714 let first = map.iter().next().unwrap();
715 let last = map.iter().next_back().unwrap();
716
717 if time <= *first.0 {
718 return first.1.0.clone();
719 }
720
721 if time >= *last.0 {
722 return last.1.0.clone();
723 }
724
725 let lower = map.range(..time).next_back().unwrap();
727 let upper = map.range(time..).next().unwrap();
728
729 if lower.0 == upper.0 {
731 return lower.1.0.clone();
732 }
733
734 let (t1, (v1, spec1)) = lower;
735 let (t2, (v2, spec2)) = upper;
736
737 let interp_out = spec1.as_ref().map(|s| &s.interpolation_out);
739 let interp_in = spec2.as_ref().map(|s| &s.interpolation_in);
740
741 match (interp_out, interp_in) {
745 (Some(crate::Interpolation::Hold), _) | (_, Some(crate::Interpolation::Hold)) => v1.clone(),
747
748 (
750 Some(crate::Interpolation::Bezier(out_handle)),
751 Some(crate::Interpolation::Bezier(in_handle)),
752 ) => {
753 use crate::interpolation::bezier_helpers::*;
754
755 if let (Some(slope_out), Some(slope_in)) = (
756 bezier_handle_to_slope(out_handle, (*t1).into(), (*t2).into(), v1, v2),
757 bezier_handle_to_slope(in_handle, (*t1).into(), (*t2).into(), v1, v2),
758 ) {
759 let (p1, p2) = control_points_from_slopes(
760 (*t1).into(),
761 v1,
762 &slope_out,
763 (*t2).into(),
764 v2,
765 &slope_in,
766 );
767
768 evaluate_bezier_component_wise(
769 time.into(),
770 ((*t1).into(), v1),
771 (p1.0, &p1.1),
772 (p2.0, &p2.1),
773 ((*t2).into(), v2),
774 )
775 } else {
776 linear_interp(*t1, *t2, v1, v2, time)
778 }
779 }
780
781 (Some(crate::Interpolation::Bezier(out_handle)), Some(crate::Interpolation::Smooth)) => {
783 if let Some(slope_out) =
784 bezier_handle_to_slope(out_handle, (*t1).into(), (*t2).into(), v1, v2)
785 {
786 let slope_in =
787 smooth_tangent((*t1).into(), v1, (*t2).into(), v2, map, time, *t1, false);
788
789 evaluate_mixed_bezier(time, *t1, v1, &slope_out, *t2, v2, &slope_in)
790 } else {
791 linear_interp(*t1, *t2, v1, v2, time)
792 }
793 }
794 (Some(crate::Interpolation::Smooth), Some(crate::Interpolation::Bezier(in_handle))) => {
795 if let Some(slope_in) =
796 bezier_handle_to_slope(in_handle, (*t1).into(), (*t2).into(), v1, v2)
797 {
798 let slope_out =
799 smooth_tangent((*t1).into(), v1, (*t2).into(), v2, map, time, *t1, true);
800
801 evaluate_mixed_bezier(time, *t1, v1, &slope_out, *t2, v2, &slope_in)
802 } else {
803 linear_interp(*t1, *t2, v1, v2, time)
804 }
805 }
806
807 (Some(crate::Interpolation::Smooth), Some(crate::Interpolation::Smooth)) | (None, None) => {
809 let values_only: BTreeMap<Time, V> =
810 map.iter().map(|(k, (v, _))| (*k, v.clone())).collect();
811 interpolate(&values_only, time)
812 }
813
814 _ => linear_interp(*t1, *t2, v1, v2, time),
816 }
817}
818
819#[inline(always)]
820pub(crate) fn interpolate<V>(map: &BTreeMap<Time, V>, time: Time) -> V
821where
822 V: Clone + Add<Output = V> + Mul<f32, Output = V> + Sub<Output = V>,
823{
824 if map.len() == 1 {
825 return map.values().next().unwrap().clone();
826 }
827
828 let first = map.iter().next().unwrap();
829 let last = map.iter().next_back().unwrap();
830
831 if time <= *first.0 {
832 return first.1.clone();
833 }
834
835 if time >= *last.0 {
836 return last.1.clone();
837 }
838
839 let lower = map.range(..time).next_back().unwrap();
840 let upper = map.range(time..).next().unwrap();
841
842 let mut window = SmallVec::<[(Time, &V); 4]>::new();
847
848 window.extend(map.range(..*lower.0).rev().take(2).map(|(k, v)| (*k, v)));
850
851 window.push((*lower.0, lower.1));
853
854 if lower.0 != upper.0 {
855 window.push((*upper.0, upper.1));
856 }
857
858 window.extend(map.range(*upper.0..).skip(1).take(1).map(|(k, v)| (*k, v)));
860
861 window.reverse();
863
864 match window.len() {
865 4 => {
866 let (t0, p0) = window[0];
867 let (t1, p1) = window[1];
868 let (t2, p2) = window[2];
869 let (t3, p3) = window[3];
870 hermite_interp(HermiteParams {
871 t0,
872 t1,
873 t2,
874 t3,
875 p0,
876 p1,
877 p2,
878 p3,
879 t: time,
880 })
881 }
882 3 => {
883 let (t0, p0) = window[0];
884 let (t1, p1) = window[1];
885 let (t2, p2) = window[2];
886 quadratic_interp(t0, t1, t2, p0, p1, p2, time)
887 }
888 2 => {
889 let (x0, y0) = window[0];
890 let (x1, y1) = window[1];
891 linear_interp(x0, x1, y0, y1, time)
892 }
893 1 => {
894 window[0].1.clone()
896 }
897 0 => {
898 panic!("Interpolation window is empty - this is a bug in token-value-map")
900 }
901 _ => {
902 let (t0, p0) = window[0];
904 let (t1, p1) = window[1];
905 let (t2, p2) = window[2];
906 let (t3, p3) = window[3];
907 hermite_interp(HermiteParams {
908 t0,
909 t1,
910 t2,
911 t3,
912 p0,
913 p1,
914 p2,
915 p3,
916 t: time,
917 })
918 }
919 }
920}
921
922#[inline(always)]
923fn linear_interp<V, T>(x0: T, x1: T, y0: &V, y1: &V, x: T) -> V
924where
925 V: Clone + Add<Output = V> + Mul<f32, Output = V> + Sub<Output = V>,
926 T: Into<f32>,
927{
928 let x0 = x0.into();
929 let x1 = x1.into();
930 let x = x.into();
931 let alpha = (x - x0) / (x1 - x0);
932 y0.clone() + (y1.clone() - y0.clone()) * alpha
933}
934
935#[inline(always)]
936fn quadratic_interp<V, T>(x0: T, x1: T, x2: T, y0: &V, y1: &V, y2: &V, x: T) -> V
937where
938 V: Clone + Add<Output = V> + Mul<f32, Output = V> + Sub<Output = V>,
939 T: Into<f32>,
940{
941 let x0 = x0.into();
942 let x1 = x1.into();
943 let x2 = x2.into();
944 let x = x.into();
945 let a = (x - x1) * (x - x2) / ((x0 - x1) * (x0 - x2));
946 let b = (x - x0) * (x - x2) / ((x1 - x0) * (x1 - x2));
947 let c = (x - x0) * (x - x1) / ((x2 - x0) * (x2 - x1));
948
949 y0.clone() * a + y1.clone() * b + y2.clone() * c
950}
951
952struct HermiteParams<V, T> {
953 t0: T,
954 t1: T,
955 t2: T,
956 t3: T,
957 p0: V,
958 p1: V,
959 p2: V,
960 p3: V,
961 t: T,
962}
963
964#[inline(always)]
965fn hermite_interp<V, T>(params: HermiteParams<&V, T>) -> V
966where
967 V: Clone + Add<Output = V> + Mul<f32, Output = V> + Sub<Output = V>,
968 T: Into<f32>,
969{
970 let t0 = params.t0.into();
971 let t1 = params.t1.into();
972 let t2 = params.t2.into();
973 let t3 = params.t3.into();
974 let t = params.t.into();
975
976 let tau = if (t2 - t1).abs() < f32::EPSILON {
978 0.0 } else {
980 (t - t1) / (t2 - t1)
981 };
982
983 let tension1 = if (t1 - t0).abs() < f32::EPSILON {
987 1.0
988 } else {
989 (t2 - t1) / (t1 - t0)
990 };
991 let tension2 = if (t3 - t2).abs() < f32::EPSILON {
992 1.0
993 } else {
994 (t2 - t1) / (t3 - t2)
995 };
996
997 let m1 = (params.p2.clone() - params.p0.clone()) * (0.5 * tension1);
999 let m2 = (params.p3.clone() - params.p1.clone()) * (0.5 * tension2);
1000
1001 let tau2 = tau * tau;
1003 let tau3 = tau2 * tau;
1004
1005 let h00 = 2.0 * tau3 - 3.0 * tau2 + 1.0;
1006 let h10 = tau3 - 2.0 * tau2 + tau;
1007 let h01 = -2.0 * tau3 + 3.0 * tau2;
1008 let h11 = tau3 - tau2;
1009
1010 params.p1.clone() * h00 + m1 * h10 + params.p2.clone() * h01 + m2 * h11
1012}
1013
1014#[cfg(feature = "matrix3")]
1019#[inline(always)]
1020fn decompose_matrix(matrix: &crate::math::Mat3Impl) -> (Trans2, f32, DiagStretch) {
1021 use crate::math::mat3;
1022
1023 let tx = mat3(matrix, 0, 2);
1025 let ty = mat3(matrix, 1, 2);
1026
1027 let a = mat3(matrix, 0, 0);
1029 let b = mat3(matrix, 0, 1);
1030 let c = mat3(matrix, 1, 0);
1031 let d = mat3(matrix, 1, 1);
1032
1033 let e = (a + d) * 0.5;
1035 let f = (a - d) * 0.5;
1036 let g = (c + b) * 0.5;
1037 let h = (c - b) * 0.5;
1038
1039 let q = (e * e + h * h).sqrt();
1040 let r = (f * f + g * g).sqrt();
1041
1042 let s1 = q + r;
1043 let s2 = q - r;
1044
1045 let theta1 = g.atan2(f);
1046 let theta2 = h.atan2(e);
1047
1048 let rotation_angle = (theta2 + theta1) * 0.5;
1050
1051 (Trans2(tx, ty), rotation_angle, DiagStretch(s1, s2))
1052}
1053
1054#[cfg(feature = "matrix3")]
1058#[inline(always)]
1059fn recompose_matrix(
1060 translation: Trans2,
1061 rotation_angle: f32,
1062 stretch: DiagStretch,
1063) -> crate::math::Mat3Impl {
1064 let cos = rotation_angle.cos();
1065 let sin = rotation_angle.sin();
1066
1067 crate::math::mat3_from_column_slice(&[
1069 stretch.0 * cos,
1070 stretch.0 * sin,
1071 0.0,
1072 -stretch.1 * sin,
1073 stretch.1 * cos,
1074 0.0,
1075 translation.0,
1076 translation.1,
1077 1.0,
1078 ])
1079}