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))]
29pub struct TimeDataMap<T> {
30 #[cfg(not(feature = "interpolation"))]
32 pub values: BTreeMap<Time, T>,
33 #[cfg(feature = "interpolation")]
34 pub values: BTreeMap<Time, (T, Option<crate::Key<T>>)>,
35}
36
37impl<T: Eq> Eq for TimeDataMap<T> {}
39
40#[cfg(not(feature = "interpolation"))]
42impl<T> AsRef<BTreeMap<Time, T>> for TimeDataMap<T> {
43 fn as_ref(&self) -> &BTreeMap<Time, T> {
44 &self.values
45 }
46}
47
48impl<T> TimeDataMap<T> {
52 #[inline]
54 pub fn iter(&self) -> impl Iterator<Item = (&Time, &T)> {
55 #[cfg(not(feature = "interpolation"))]
56 {
57 self.values.iter()
58 }
59 #[cfg(feature = "interpolation")]
60 {
61 self.values.iter().map(|(t, (v, _))| (t, v))
62 }
63 }
64
65 #[inline]
67 pub fn is_empty(&self) -> bool {
68 self.values.is_empty()
69 }
70
71 #[inline]
73 pub fn len(&self) -> usize {
74 self.values.len()
75 }
76
77 #[inline]
81 pub fn remove(&mut self, time: &Time) -> Option<T> {
82 #[cfg(not(feature = "interpolation"))]
83 {
84 self.values.remove(time)
85 }
86 #[cfg(feature = "interpolation")]
87 {
88 self.values.remove(time).map(|(v, _)| v)
89 }
90 }
91}
92
93impl<T> From<BTreeMap<Time, T>> for TimeDataMap<T> {
95 fn from(values: BTreeMap<Time, T>) -> Self {
96 #[cfg(not(feature = "interpolation"))]
97 {
98 Self { values }
99 }
100 #[cfg(feature = "interpolation")]
101 {
102 Self {
103 values: values.into_iter().map(|(k, v)| (k, (v, None))).collect(),
104 }
105 }
106 }
107}
108
109#[enum_dispatch]
111pub trait TimeDataMapControl<T> {
112 fn len(&self) -> usize;
114 fn is_empty(&self) -> bool;
116 fn is_animated(&self) -> bool;
118}
119
120impl<T> TimeDataMapControl<T> for TimeDataMap<T> {
121 fn len(&self) -> usize {
122 self.values.len()
123 }
124
125 fn is_empty(&self) -> bool {
126 self.values.is_empty()
127 }
128
129 fn is_animated(&self) -> bool {
130 1 < self.values.len()
131 }
132}
133
134impl<T> crate::DataTypeOps for TimeDataMap<T>
135where
136 T: crate::DataTypeOps,
137{
138 fn data_type(&self) -> DataType {
139 #[cfg(not(feature = "interpolation"))]
141 {
142 self.values
143 .values()
144 .next()
145 .map(|v| v.data_type())
146 .unwrap_or(DataType::Real)
147 }
148 #[cfg(feature = "interpolation")]
149 {
150 self.values
151 .values()
152 .next()
153 .map(|(v, _)| v.data_type())
154 .unwrap_or(DataType::Real)
155 }
156 }
157
158 fn type_name(&self) -> &'static str {
159 #[cfg(not(feature = "interpolation"))]
161 {
162 self.values
163 .values()
164 .next()
165 .map(|v| v.type_name())
166 .unwrap_or("unknown")
167 }
168 #[cfg(feature = "interpolation")]
169 {
170 self.values
171 .values()
172 .next()
173 .map(|(v, _)| v.type_name())
174 .unwrap_or("unknown")
175 }
176 }
177}
178
179macro_rules! impl_from_at_time {
180 ($($t:ty),+) => {
181 $(
182 impl From<(Time, $t)> for TimeDataMap<$t> {
183 fn from((time, value): (Time, $t)) -> Self {
184 TimeDataMap::from(BTreeMap::from([(time, value)]))
185 }
186 }
187 )+
188 };
189}
190
191impl_from_at_time!(
192 Boolean, Real, Integer, String, Color, BooleanVec, RealVec, IntegerVec, StringVec, ColorVec,
193 Data
194);
195
196#[cfg(feature = "vector2")]
197impl_from_at_time!(Vector2);
198#[cfg(feature = "vector3")]
199impl_from_at_time!(Vector3);
200#[cfg(feature = "matrix3")]
201impl_from_at_time!(Matrix3);
202#[cfg(feature = "normal3")]
203impl_from_at_time!(Normal3);
204#[cfg(feature = "point3")]
205impl_from_at_time!(Point3);
206#[cfg(feature = "matrix4")]
207impl_from_at_time!(Matrix4);
208
209#[cfg(all(feature = "vector2", feature = "vec_variants"))]
210impl_from_at_time!(Vector2Vec);
211#[cfg(all(feature = "vector3", feature = "vec_variants"))]
212impl_from_at_time!(Vector3Vec);
213#[cfg(all(feature = "matrix3", feature = "vec_variants"))]
214impl_from_at_time!(Matrix3Vec);
215#[cfg(all(feature = "normal3", feature = "vec_variants"))]
216impl_from_at_time!(Normal3Vec);
217#[cfg(all(feature = "point3", feature = "vec_variants"))]
218impl_from_at_time!(Point3Vec);
219#[cfg(all(feature = "matrix4", feature = "vec_variants"))]
220impl_from_at_time!(Matrix4Vec);
221
222impl<T> TimeDataMap<T> {
223 pub fn insert(&mut self, time: Time, value: T) {
225 #[cfg(not(feature = "interpolation"))]
226 {
227 self.values.insert(time, value);
228 }
229 #[cfg(feature = "interpolation")]
230 {
231 self.values.insert(time, (value, None));
232 }
233 }
234
235 pub fn get(&self, time: &Time) -> Option<&T> {
237 #[cfg(not(feature = "interpolation"))]
238 {
239 self.values.get(time)
240 }
241 #[cfg(feature = "interpolation")]
242 {
243 self.values.get(time).map(|(v, _)| v)
244 }
245 }
246}
247
248impl<T> TimeDataMap<T>
249where
250 T: Clone + Add<Output = T> + Mul<f32, Output = T> + Sub<Output = T>,
251{
252 pub fn interpolate(&self, time: Time) -> T {
253 #[cfg(not(feature = "interpolation"))]
254 {
255 interpolate(&self.values, time)
256 }
257 #[cfg(feature = "interpolation")]
258 {
259 interpolate_with_specs(&self.values, time)
260 }
261 }
262}
263
264#[cfg(feature = "interpolation")]
266impl<T> TimeDataMap<T> {
267 pub fn insert_with_interpolation(&mut self, time: Time, value: T, spec: crate::Key<T>) {
272 self.values.insert(time, (value, Some(spec)));
273 }
274
275 pub fn get_interpolation(&self, time: &Time) -> Option<&crate::Key<T>> {
279 self.values.get(time)?.1.as_ref()
280 }
281
282 pub fn clear_interpolation(&mut self) {
286 for (_, interp) in self.values.values_mut() {
287 *interp = None;
288 }
289 }
290
291 pub fn has_interpolation(&self) -> bool {
295 self.values.values().any(|(_, interp)| interp.is_some())
296 }
297}
298
299impl<T, V> FromIterator<(Time, V)> for TimeDataMap<T>
300where
301 V: Into<T>,
302{
303 fn from_iter<I>(iter: I) -> Self
304 where
305 I: IntoIterator<Item = (Time, V)>,
306 {
307 Self::from(BTreeMap::from_iter(
308 iter.into_iter().map(|(t, v)| (t, v.into())),
309 ))
310 }
311}
312
313impl<T> TimeDataMap<T> {
314 pub fn closest_sample(&self, time: Time) -> &T {
315 #[cfg(not(feature = "interpolation"))]
316 {
317 let mut range = self.values.range(time..);
318 let greater_or_equal = range.next();
319
320 let mut range = self.values.range(..time);
321 let less_than = range.next_back();
322
323 match (less_than, greater_or_equal) {
324 (Some((lower_k, lower_v)), Some((upper_k, upper_v))) => {
325 if (time.as_ref() - lower_k.as_ref()).abs()
326 <= (upper_k.as_ref() - time.as_ref()).abs()
327 {
328 lower_v
329 } else {
330 upper_v
331 }
332 }
333 (Some(entry), None) | (None, Some(entry)) => entry.1,
334 (None, None) => {
335 unreachable!("TimeDataMap can never be empty")
336 }
337 }
338 }
339 #[cfg(feature = "interpolation")]
340 {
341 let mut range = self.values.range(time..);
342 let greater_or_equal = range.next();
343
344 let mut range = self.values.range(..time);
345 let less_than = range.next_back();
346
347 match (less_than, greater_or_equal) {
348 (Some((lower_k, (lower_v, _))), Some((upper_k, (upper_v, _)))) => {
349 if (time.as_ref() - lower_k.as_ref()).abs()
350 <= (upper_k.as_ref() - time.as_ref()).abs()
351 {
352 lower_v
353 } else {
354 upper_v
355 }
356 }
357 (Some((_, (v, _))), None) | (None, Some((_, (v, _)))) => v,
358 (None, None) => {
359 unreachable!("TimeDataMap can never be empty")
360 }
361 }
362 }
363 }
364
365 pub fn sample_at(&self, time: Time) -> Option<&T> {
367 self.get(&time)
368 }
369
370 pub fn sample_at_or_before(&self, time: Time) -> Option<&T> {
372 #[cfg(not(feature = "interpolation"))]
373 {
374 self.values.range(..=time).next_back().map(|(_, v)| v)
375 }
376 #[cfg(feature = "interpolation")]
377 {
378 self.values.range(..=time).next_back().map(|(_, (v, _))| v)
379 }
380 }
381
382 pub fn sample_at_or_after(&self, time: Time) -> Option<&T> {
384 #[cfg(not(feature = "interpolation"))]
385 {
386 self.values.range(time..).next().map(|(_, v)| v)
387 }
388 #[cfg(feature = "interpolation")]
389 {
390 self.values.range(time..).next().map(|(_, (v, _))| v)
391 }
392 }
393
394 pub fn sample_surrounding<const N: usize>(&self, time: Time) -> SmallVec<[(Time, &T); N]> {
399 let before_count = N / 2;
401
402 #[cfg(not(feature = "interpolation"))]
403 {
404 let mut result = self
405 .values
406 .range(..time)
407 .rev()
408 .take(before_count)
409 .map(|(t, v)| (*t, v))
410 .collect::<SmallVec<[_; N]>>();
411 result.reverse();
412
413 let after_count = N - result.len();
415 result.extend(
416 self.values
417 .range(time..)
418 .take(after_count)
419 .map(|(t, v)| (*t, v)),
420 );
421 result
422 }
423
424 #[cfg(feature = "interpolation")]
425 {
426 let mut result = self
427 .values
428 .range(..time)
429 .rev()
430 .take(before_count)
431 .map(|(t, (v, _))| (*t, v))
432 .collect::<SmallVec<[_; N]>>();
433 result.reverse();
434
435 let after_count = N - result.len();
437 result.extend(
438 self.values
439 .range(time..)
440 .take(after_count)
441 .map(|(t, (v, _))| (*t, v)),
442 );
443 result
444 }
445 }
446}
447
448#[cfg(feature = "matrix3")]
449#[inline(always)]
450pub(crate) fn interpolate_spherical_linear(
451 map: &BTreeMap<Time, nalgebra::Rotation2<f32>>,
452 time: Time,
453) -> nalgebra::Rotation2<f32> {
454 if map.len() == 1 {
455 return *map.values().next().unwrap();
456 }
457
458 let first = map.iter().next().unwrap();
459 let last = map.iter().next_back().unwrap();
460
461 if time <= *first.0 {
462 return *first.1;
463 }
464
465 if time >= *last.0 {
466 return *last.1;
467 }
468
469 let lower = map.range(..=time).next_back().unwrap();
470 let upper = map.range(time..).next().unwrap();
471
472 let (t0, r0): (f32, _) = (lower.0.into(), lower.1);
473 let (t1, r1): (f32, _) = (upper.0.into(), upper.1);
474
475 let t: f32 = (f32::from(time) - t0) / (t1 - t0);
477
478 r0.slerp(r1, t)
479}
480
481#[cfg(feature = "interpolation")]
484fn bezier_handle_to_slope<V>(
485 handle: &crate::BezierHandle<V>,
486 t1: f32,
487 t2: f32,
488 _v1: &V,
489 _v2: &V,
490) -> Option<V>
491where
492 V: Clone + Add<Output = V> + Sub<Output = V> + Mul<f32, Output = V>,
493{
494 match handle {
495 crate::BezierHandle::SlopePerSecond(s) => Some(s.clone()),
496 crate::BezierHandle::SlopePerFrame(s) => {
497 let frames = (t2 - t1).max(f32::EPSILON);
498 Some(s.clone() * (frames / (t2 - t1)))
499 }
500 crate::BezierHandle::Delta { time, value } => {
501 let time_f32: f32 = (*time).into();
502 if time_f32.abs() <= f32::EPSILON {
503 None
504 } else {
505 Some(value.clone() * (1.0 / time_f32))
506 }
507 }
508 crate::BezierHandle::Angle(_) => None, }
510}
511
512#[cfg(feature = "interpolation")]
513#[allow(clippy::too_many_arguments)]
514fn smooth_tangent<V>(
515 t1: f32,
516 v1: &V,
517 t2: f32,
518 v2: &V,
519 map: &BTreeMap<Time, (V, Option<crate::Key<V>>)>,
520 _time: Time,
521 anchor: Time,
522 incoming: bool,
523) -> V
524where
525 V: Clone + Add<Output = V> + Mul<f32, Output = V> + Sub<Output = V>,
526{
527 use smallvec::SmallVec;
528
529 let mut window = SmallVec::<[(Time, V); 2]>::new();
532
533 if incoming {
534 if let Some(prev) = map.range(..anchor).next_back() {
535 window.push((*prev.0, prev.1.0.clone()));
536 }
537 window.push((anchor, v1.clone()));
538 } else {
539 window.push((anchor, v1.clone()));
540 if let Some(next) = map.range(anchor..).nth(1) {
541 window.push((*next.0, next.1.0.clone()));
542 }
543 }
544
545 if window.len() == 2 {
546 let (t0, p0) = &window[0];
547 let (t1, p1) = &window[1];
548 let t0_f: f32 = (*t0).into();
549 let t1_f: f32 = (*t1).into();
550 let dt = (t1_f - t0_f).max(f32::EPSILON);
551 (p1.clone() - p0.clone()) * (1.0 / dt)
552 } else {
553 (v2.clone() - v1.clone()) * (1.0 / (t2 - t1).max(f32::EPSILON))
555 }
556}
557
558#[cfg(feature = "interpolation")]
559fn evaluate_mixed_bezier<V>(
560 time: Time,
561 t1: Time,
562 v1: &V,
563 slope_out: &V,
564 t2: Time,
565 v2: &V,
566 slope_in: &V,
567) -> V
568where
569 V: Clone + Add<Output = V> + Mul<f32, Output = V> + Sub<Output = V>,
570{
571 use crate::interpolation::bezier_helpers::*;
572
573 let (p1, p2) = control_points_from_slopes(t1.into(), v1, slope_out, t2.into(), v2, slope_in);
574
575 evaluate_bezier_component_wise(
576 time.into(),
577 (t1.into(), v1),
578 (p1.0, &p1.1),
579 (p2.0, &p2.1),
580 (t2.into(), v2),
581 )
582}
583
584#[cfg(feature = "interpolation")]
589#[inline(always)]
590pub(crate) fn interpolate_with_specs<V>(
591 map: &BTreeMap<Time, (V, Option<crate::Key<V>>)>,
592 time: Time,
593) -> V
594where
595 V: Clone + Add<Output = V> + Mul<f32, Output = V> + Sub<Output = V>,
596{
597 if map.len() == 1 {
598 return map.values().next().unwrap().0.clone();
599 }
600
601 let first = map.iter().next().unwrap();
602 let last = map.iter().next_back().unwrap();
603
604 if time <= *first.0 {
605 return first.1.0.clone();
606 }
607
608 if time >= *last.0 {
609 return last.1.0.clone();
610 }
611
612 let lower = map.range(..time).next_back().unwrap();
614 let upper = map.range(time..).next().unwrap();
615
616 if lower.0 == upper.0 {
618 return lower.1.0.clone();
619 }
620
621 let (t1, (v1, spec1)) = lower;
622 let (t2, (v2, spec2)) = upper;
623
624 let interp_out = spec1.as_ref().map(|s| &s.interpolation_out);
626 let interp_in = spec2.as_ref().map(|s| &s.interpolation_in);
627
628 match (interp_out, interp_in) {
632 (Some(crate::Interpolation::Hold), _) | (_, Some(crate::Interpolation::Hold)) => v1.clone(),
634
635 (
637 Some(crate::Interpolation::Bezier(out_handle)),
638 Some(crate::Interpolation::Bezier(in_handle)),
639 ) => {
640 use crate::interpolation::bezier_helpers::*;
641
642 if let (Some(slope_out), Some(slope_in)) = (
643 bezier_handle_to_slope(out_handle, (*t1).into(), (*t2).into(), v1, v2),
644 bezier_handle_to_slope(in_handle, (*t1).into(), (*t2).into(), v1, v2),
645 ) {
646 let (p1, p2) = control_points_from_slopes(
647 (*t1).into(),
648 v1,
649 &slope_out,
650 (*t2).into(),
651 v2,
652 &slope_in,
653 );
654
655 evaluate_bezier_component_wise(
656 time.into(),
657 ((*t1).into(), v1),
658 (p1.0, &p1.1),
659 (p2.0, &p2.1),
660 ((*t2).into(), v2),
661 )
662 } else {
663 linear_interp(*t1, *t2, v1, v2, time)
665 }
666 }
667
668 (Some(crate::Interpolation::Bezier(out_handle)), Some(crate::Interpolation::Smooth)) => {
670 if let Some(slope_out) =
671 bezier_handle_to_slope(out_handle, (*t1).into(), (*t2).into(), v1, v2)
672 {
673 let slope_in =
674 smooth_tangent((*t1).into(), v1, (*t2).into(), v2, map, time, *t1, false);
675
676 evaluate_mixed_bezier(time, *t1, v1, &slope_out, *t2, v2, &slope_in)
677 } else {
678 linear_interp(*t1, *t2, v1, v2, time)
679 }
680 }
681 (Some(crate::Interpolation::Smooth), Some(crate::Interpolation::Bezier(in_handle))) => {
682 if let Some(slope_in) =
683 bezier_handle_to_slope(in_handle, (*t1).into(), (*t2).into(), v1, v2)
684 {
685 let slope_out =
686 smooth_tangent((*t1).into(), v1, (*t2).into(), v2, map, time, *t1, true);
687
688 evaluate_mixed_bezier(time, *t1, v1, &slope_out, *t2, v2, &slope_in)
689 } else {
690 linear_interp(*t1, *t2, v1, v2, time)
691 }
692 }
693
694 (Some(crate::Interpolation::Smooth), Some(crate::Interpolation::Smooth)) | (None, None) => {
696 let values_only: BTreeMap<Time, V> =
697 map.iter().map(|(k, (v, _))| (*k, v.clone())).collect();
698 interpolate(&values_only, time)
699 }
700
701 _ => linear_interp(*t1, *t2, v1, v2, time),
703 }
704}
705
706#[inline(always)]
707pub(crate) fn interpolate<V>(map: &BTreeMap<Time, V>, time: Time) -> V
708where
709 V: Clone + Add<Output = V> + Mul<f32, Output = V> + Sub<Output = V>,
710{
711 if map.len() == 1 {
712 return map.values().next().unwrap().clone();
713 }
714
715 let first = map.iter().next().unwrap();
716 let last = map.iter().next_back().unwrap();
717
718 if time <= *first.0 {
719 return first.1.clone();
720 }
721
722 if time >= *last.0 {
723 return last.1.clone();
724 }
725
726 let lower = map.range(..time).next_back().unwrap();
727 let upper = map.range(time..).next().unwrap();
728
729 let mut window = SmallVec::<[(Time, &V); 4]>::new();
734
735 window.extend(map.range(..*lower.0).rev().take(2).map(|(k, v)| (*k, v)));
737
738 window.push((*lower.0, lower.1));
740
741 if lower.0 != upper.0 {
742 window.push((*upper.0, upper.1));
743 }
744
745 window.extend(map.range(*upper.0..).skip(1).take(1).map(|(k, v)| (*k, v)));
747
748 window.reverse();
750
751 match window.len() {
752 4 => {
753 let (t0, p0) = window[0];
754 let (t1, p1) = window[1];
755 let (t2, p2) = window[2];
756 let (t3, p3) = window[3];
757 hermite_interp(HermiteParams {
758 t0,
759 t1,
760 t2,
761 t3,
762 p0,
763 p1,
764 p2,
765 p3,
766 t: time,
767 })
768 }
769 3 => {
770 let (t0, p0) = window[0];
771 let (t1, p1) = window[1];
772 let (t2, p2) = window[2];
773 quadratic_interp(t0, t1, t2, p0, p1, p2, time)
774 }
775 2 => {
776 let (x0, y0) = window[0];
777 let (x1, y1) = window[1];
778 linear_interp(x0, x1, y0, y1, time)
779 }
780 1 => {
781 window[0].1.clone()
783 }
784 0 => {
785 panic!("Interpolation window is empty - this is a bug in token-value-map")
787 }
788 _ => {
789 let (t0, p0) = window[0];
791 let (t1, p1) = window[1];
792 let (t2, p2) = window[2];
793 let (t3, p3) = window[3];
794 hermite_interp(HermiteParams {
795 t0,
796 t1,
797 t2,
798 t3,
799 p0,
800 p1,
801 p2,
802 p3,
803 t: time,
804 })
805 }
806 }
807}
808
809#[inline(always)]
810fn linear_interp<V, T>(x0: T, x1: T, y0: &V, y1: &V, x: T) -> V
811where
812 V: Clone + Add<Output = V> + Mul<f32, Output = V> + Sub<Output = V>,
813 T: Into<f32>,
814{
815 let x0 = x0.into();
816 let x1 = x1.into();
817 let x = x.into();
818 let alpha = (x - x0) / (x1 - x0);
819 y0.clone() + (y1.clone() - y0.clone()) * alpha
820}
821
822#[inline(always)]
823fn quadratic_interp<V, T>(x0: T, x1: T, x2: T, y0: &V, y1: &V, y2: &V, x: T) -> V
824where
825 V: Clone + Add<Output = V> + Mul<f32, Output = V> + Sub<Output = V>,
826 T: Into<f32>,
827{
828 let x0 = x0.into();
829 let x1 = x1.into();
830 let x2 = x2.into();
831 let x = x.into();
832 let a = (x - x1) * (x - x2) / ((x0 - x1) * (x0 - x2));
833 let b = (x - x0) * (x - x2) / ((x1 - x0) * (x1 - x2));
834 let c = (x - x0) * (x - x1) / ((x2 - x0) * (x2 - x1));
835
836 y0.clone() * a + y1.clone() * b + y2.clone() * c
837}
838
839struct HermiteParams<V, T> {
840 t0: T,
841 t1: T,
842 t2: T,
843 t3: T,
844 p0: V,
845 p1: V,
846 p2: V,
847 p3: V,
848 t: T,
849}
850
851#[inline(always)]
852fn hermite_interp<V, T>(params: HermiteParams<&V, T>) -> V
853where
854 V: Clone + Add<Output = V> + Mul<f32, Output = V> + Sub<Output = V>,
855 T: Into<f32>,
856{
857 let t0 = params.t0.into();
858 let t1 = params.t1.into();
859 let t2 = params.t2.into();
860 let t3 = params.t3.into();
861 let t = params.t.into();
862
863 let tau = if (t2 - t1).abs() < f32::EPSILON {
865 0.0 } else {
867 (t - t1) / (t2 - t1)
868 };
869
870 let tension1 = if (t1 - t0).abs() < f32::EPSILON {
874 1.0
875 } else {
876 (t2 - t1) / (t1 - t0)
877 };
878 let tension2 = if (t3 - t2).abs() < f32::EPSILON {
879 1.0
880 } else {
881 (t2 - t1) / (t3 - t2)
882 };
883
884 let m1 = (params.p2.clone() - params.p0.clone()) * (0.5 * tension1);
886 let m2 = (params.p3.clone() - params.p1.clone()) * (0.5 * tension2);
887
888 let tau2 = tau * tau;
890 let tau3 = tau2 * tau;
891
892 let h00 = 2.0 * tau3 - 3.0 * tau2 + 1.0;
893 let h10 = tau3 - 2.0 * tau2 + tau;
894 let h01 = -2.0 * tau3 + 3.0 * tau2;
895 let h11 = tau3 - tau2;
896
897 params.p1.clone() * h00 + m1 * h10 + params.p2.clone() * h01 + m2 * h11
899}
900
901#[cfg(feature = "matrix3")]
902#[inline(always)]
903fn decompose_matrix(
904 matrix: &nalgebra::Matrix3<f32>,
905) -> (
906 nalgebra::Vector2<f32>,
907 nalgebra::Rotation2<f32>,
908 nalgebra::Matrix3<f32>,
909) {
910 let translation = nalgebra::Vector2::new(matrix[(0, 2)], matrix[(1, 2)]);
912
913 let linear_part = matrix.fixed_view::<2, 2>(0, 0).into_owned();
915
916 let svd = nalgebra::SVD::new(linear_part, true, true);
919 let rotation = nalgebra::Rotation2::from_matrix(&svd.u.unwrap().into_owned());
920
921 let singular_values = svd.singular_values;
923 let stretch = nalgebra::Matrix3::new(
924 singular_values[0],
925 0.0,
926 0.0,
927 0.0,
928 singular_values[1],
929 0.0,
930 0.0,
931 0.0,
932 1.0, );
934
935 (translation, rotation, stretch)
936}
937
938#[cfg(feature = "matrix3")]
939#[inline(always)]
940fn recompose_matrix(
941 translation: nalgebra::Vector2<f32>,
942 rotation: nalgebra::Rotation2<f32>,
943 stretch: nalgebra::Matrix3<f32>,
944) -> nalgebra::Matrix3<f32> {
945 let rotation = rotation.to_homogeneous();
946 let mut combined_linear = rotation * stretch;
947
948 combined_linear[(0, 2)] = translation.x;
949 combined_linear[(1, 2)] = translation.y;
950
951 combined_linear
952}