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