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