bevy_math/common_traits.rs
1//! This module contains abstract mathematical traits shared by types used in `bevy_math`.
2
3use crate::{ops, DVec2, DVec3, DVec4, Dir2, Dir3, Dir3A, Quat, Rot2, Vec2, Vec3, Vec3A, Vec4};
4use core::{
5 convert::Infallible,
6 fmt::Debug,
7 ops::{Add, Div, Mul, Neg, Sub},
8};
9use thiserror::Error;
10use variadics_please::all_tuples_enumerated;
11
12/// A type that supports the mathematical operations of a real vector space, irrespective of dimension.
13/// In particular, this means that the implementing type supports:
14/// - Scalar multiplication and division on the right by elements of `Self::Scalar`
15/// - Negation
16/// - Addition and subtraction
17/// - Zero
18///
19/// Within the limitations of floating point arithmetic, all the following are required to hold:
20/// - (Associativity of addition) For all `u, v, w: Self`, `(u + v) + w == u + (v + w)`.
21/// - (Commutativity of addition) For all `u, v: Self`, `u + v == v + u`.
22/// - (Additive identity) For all `v: Self`, `v + Self::ZERO == v`.
23/// - (Additive inverse) For all `v: Self`, `v - v == v + (-v) == Self::ZERO`.
24/// - (Compatibility of multiplication) For all `a, b: Self::Scalar`, `v: Self`, `v * (a * b) == (v * a) * b`.
25/// - (Multiplicative identity) For all `v: Self`, `v * 1.0 == v`.
26/// - (Distributivity for vector addition) For all `a: Self::Scalar`, `u, v: Self`, `(u + v) * a == u * a + v * a`.
27/// - (Distributivity for scalar addition) For all `a, b: Self::Scalar`, `v: Self`, `v * (a + b) == v * a + v * b`.
28///
29/// Note that, because implementing types use floating point arithmetic, they are not required to actually
30/// implement `PartialEq` or `Eq`.
31pub trait VectorSpace:
32 Mul<Self::Scalar, Output = Self>
33 + Div<Self::Scalar, Output = Self>
34 + Add<Self, Output = Self>
35 + Sub<Self, Output = Self>
36 + Neg<Output = Self>
37 + Default
38 + Debug
39 + Clone
40 + Copy
41{
42 /// The scalar type of this vector space.
43 type Scalar: ScalarField;
44
45 /// The zero vector, which is the identity of addition for the vector space type.
46 const ZERO: Self;
47
48 /// Perform vector space linear interpolation between this element and another, based
49 /// on the parameter `t`. When `t` is `0`, `self` is recovered. When `t` is `1`, `rhs`
50 /// is recovered.
51 ///
52 /// Note that the value of `t` is not clamped by this function, so extrapolating outside
53 /// of the interval `[0,1]` is allowed.
54 #[inline]
55 fn lerp(self, rhs: Self, t: Self::Scalar) -> Self {
56 self * (Self::Scalar::ONE - t) + rhs * t
57 }
58}
59
60impl VectorSpace for Vec4 {
61 type Scalar = f32;
62 const ZERO: Self = Vec4::ZERO;
63}
64
65impl VectorSpace for Vec3 {
66 type Scalar = f32;
67 const ZERO: Self = Vec3::ZERO;
68}
69
70impl VectorSpace for Vec3A {
71 type Scalar = f32;
72 const ZERO: Self = Vec3A::ZERO;
73}
74
75impl VectorSpace for Vec2 {
76 type Scalar = f32;
77 const ZERO: Self = Vec2::ZERO;
78}
79
80impl VectorSpace for DVec4 {
81 type Scalar = f64;
82 const ZERO: Self = DVec4::ZERO;
83}
84
85impl VectorSpace for DVec3 {
86 type Scalar = f64;
87 const ZERO: Self = DVec3::ZERO;
88}
89
90impl VectorSpace for DVec2 {
91 type Scalar = f64;
92 const ZERO: Self = DVec2::ZERO;
93}
94
95// Every scalar field is a 1-dimensional vector space over itself.
96impl<T: ScalarField> VectorSpace for T {
97 type Scalar = Self;
98 const ZERO: Self = Self::ZERO;
99}
100
101/// A type that supports the operations of a scalar field. An implementation should support:
102/// - Addition and subtraction
103/// - Multiplication and division
104/// - Negation
105/// - Zero (additive identity)
106/// - One (multiplicative identity)
107///
108/// Within the limitations of floating point arithmetic, all the following are required to hold:
109/// - (Associativity of addition) For all `u, v, w: Self`, `(u + v) + w == u + (v + w)`.
110/// - (Commutativity of addition) For all `u, v: Self`, `u + v == v + u`.
111/// - (Additive identity) For all `v: Self`, `v + Self::ZERO == v`.
112/// - (Additive inverse) For all `v: Self`, `v - v == v + (-v) == Self::ZERO`.
113/// - (Associativity of multiplication) For all `u, v, w: Self`, `(u * v) * w == u * (v * w)`.
114/// - (Commutativity of multiplication) For all `u, v: Self`, `u * v == v * u`.
115/// - (Multiplicative identity) For all `v: Self`, `v * Self::ONE == v`.
116/// - (Multiplicative inverse) For all `v: Self`, `v / v == v * v.inverse() == Self::ONE`.
117/// - (Distributivity over addition) For all `a, b: Self`, `u, v: Self`, `(u + v) * a == u * a + v * a`.
118pub trait ScalarField:
119 Mul<Self, Output = Self>
120 + Div<Self, Output = Self>
121 + Add<Self, Output = Self>
122 + Sub<Self, Output = Self>
123 + Neg<Output = Self>
124 + Default
125 + Debug
126 + Clone
127 + Copy
128{
129 /// The additive identity.
130 const ZERO: Self;
131 /// The multiplicative identity.
132 const ONE: Self;
133
134 /// The multiplicative inverse of this element. This is equivalent to `1.0 / self`.
135 fn recip(self) -> Self {
136 Self::ONE / self
137 }
138}
139
140impl ScalarField for f32 {
141 const ZERO: Self = 0.0;
142 const ONE: Self = 1.0;
143}
144
145impl ScalarField for f64 {
146 const ZERO: Self = 0.0;
147 const ONE: Self = 1.0;
148}
149
150/// A type consisting of formal sums of elements from `V` and `W`. That is,
151/// each value `Sum(v, w)` is thought of as `v + w`, with no available
152/// simplification. In particular, if `V` and `W` are [vector spaces], then
153/// `Sum<V, W>` is a vector space whose dimension is the sum of those of `V`
154/// and `W`, and the field accessors `.0` and `.1` are vector space projections.
155///
156/// [vector spaces]: VectorSpace
157#[derive(Debug, Clone, Copy)]
158#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
159#[cfg_attr(feature = "bevy_reflect", derive(bevy_reflect::Reflect))]
160pub struct Sum<V, W>(pub V, pub W);
161
162impl<F: ScalarField, V, W> Mul<F> for Sum<V, W>
163where
164 V: VectorSpace<Scalar = F>,
165 W: VectorSpace<Scalar = F>,
166{
167 type Output = Self;
168 fn mul(self, rhs: F) -> Self::Output {
169 Sum(self.0 * rhs, self.1 * rhs)
170 }
171}
172
173impl<F: ScalarField, V, W> Div<F> for Sum<V, W>
174where
175 V: VectorSpace<Scalar = F>,
176 W: VectorSpace<Scalar = F>,
177{
178 type Output = Self;
179 fn div(self, rhs: F) -> Self::Output {
180 Sum(self.0 / rhs, self.1 / rhs)
181 }
182}
183
184impl<V, W> Add<Self> for Sum<V, W>
185where
186 V: VectorSpace,
187 W: VectorSpace,
188{
189 type Output = Self;
190 fn add(self, other: Self) -> Self::Output {
191 Sum(self.0 + other.0, self.1 + other.1)
192 }
193}
194
195impl<V, W> Sub<Self> for Sum<V, W>
196where
197 V: VectorSpace,
198 W: VectorSpace,
199{
200 type Output = Self;
201 fn sub(self, other: Self) -> Self::Output {
202 Sum(self.0 - other.0, self.1 - other.1)
203 }
204}
205
206impl<V, W> Neg for Sum<V, W>
207where
208 V: VectorSpace,
209 W: VectorSpace,
210{
211 type Output = Self;
212 fn neg(self) -> Self::Output {
213 Sum(-self.0, -self.1)
214 }
215}
216
217impl<V, W> Default for Sum<V, W>
218where
219 V: VectorSpace,
220 W: VectorSpace,
221{
222 fn default() -> Self {
223 Sum(V::default(), W::default())
224 }
225}
226
227impl<F: ScalarField, V, W> VectorSpace for Sum<V, W>
228where
229 V: VectorSpace<Scalar = F>,
230 W: VectorSpace<Scalar = F>,
231{
232 type Scalar = F;
233 const ZERO: Self = Sum(V::ZERO, W::ZERO);
234}
235
236/// A type that supports the operations of a normed vector space; i.e. a norm operation in addition
237/// to those of [`VectorSpace`]. Specifically, the implementor must guarantee that the following
238/// relationships hold, within the limitations of floating point arithmetic:
239/// - (Nonnegativity) For all `v: Self`, `v.norm() >= 0.0`.
240/// - (Positive definiteness) For all `v: Self`, `v.norm() == 0.0` implies `v == Self::ZERO`.
241/// - (Absolute homogeneity) For all `c: Self::Scalar`, `v: Self`, `(v * c).norm() == v.norm() * c.abs()`.
242/// - (Triangle inequality) For all `v, w: Self`, `(v + w).norm() <= v.norm() + w.norm()`.
243///
244/// Note that, because implementing types use floating point arithmetic, they are not required to actually
245/// implement `PartialEq` or `Eq`.
246pub trait NormedVectorSpace: VectorSpace {
247 /// The size of this element. The return value should always be nonnegative.
248 fn norm(self) -> Self::Scalar;
249
250 /// The squared norm of this element. Computing this is often faster than computing
251 /// [`NormedVectorSpace::norm`].
252 #[inline]
253 fn norm_squared(self) -> Self::Scalar {
254 self.norm() * self.norm()
255 }
256
257 /// The distance between this element and another, as determined by the norm.
258 #[inline]
259 fn distance(self, rhs: Self) -> Self::Scalar {
260 (rhs - self).norm()
261 }
262
263 /// The squared distance between this element and another, as determined by the norm. Note that
264 /// this is often faster to compute in practice than [`NormedVectorSpace::distance`].
265 #[inline]
266 fn distance_squared(self, rhs: Self) -> Self::Scalar {
267 (rhs - self).norm_squared()
268 }
269}
270
271impl NormedVectorSpace for Vec4 {
272 #[inline]
273 fn norm(self) -> f32 {
274 self.length()
275 }
276
277 #[inline]
278 fn norm_squared(self) -> f32 {
279 self.length_squared()
280 }
281}
282
283impl NormedVectorSpace for Vec3 {
284 #[inline]
285 fn norm(self) -> f32 {
286 self.length()
287 }
288
289 #[inline]
290 fn norm_squared(self) -> f32 {
291 self.length_squared()
292 }
293}
294
295impl NormedVectorSpace for Vec3A {
296 #[inline]
297 fn norm(self) -> f32 {
298 self.length()
299 }
300
301 #[inline]
302 fn norm_squared(self) -> f32 {
303 self.length_squared()
304 }
305}
306
307impl NormedVectorSpace for Vec2 {
308 #[inline]
309 fn norm(self) -> f32 {
310 self.length()
311 }
312
313 #[inline]
314 fn norm_squared(self) -> f32 {
315 self.length_squared()
316 }
317}
318
319impl NormedVectorSpace for f32 {
320 #[inline]
321 fn norm(self) -> f32 {
322 ops::abs(self)
323 }
324}
325
326impl NormedVectorSpace for DVec4 {
327 #[inline]
328 fn norm(self) -> f64 {
329 self.length()
330 }
331
332 #[inline]
333 fn norm_squared(self) -> f64 {
334 self.length_squared()
335 }
336}
337
338impl NormedVectorSpace for DVec3 {
339 #[inline]
340 fn norm(self) -> f64 {
341 self.length()
342 }
343
344 #[inline]
345 fn norm_squared(self) -> f64 {
346 self.length_squared()
347 }
348}
349
350impl NormedVectorSpace for DVec2 {
351 #[inline]
352 fn norm(self) -> f64 {
353 self.length()
354 }
355
356 #[inline]
357 fn norm_squared(self) -> f64 {
358 self.length_squared()
359 }
360}
361
362impl NormedVectorSpace for f64 {
363 #[inline]
364 #[cfg(feature = "std")]
365 fn norm(self) -> f64 {
366 f64::abs(self)
367 }
368
369 #[inline]
370 #[cfg(all(any(feature = "libm", feature = "nostd-libm"), not(feature = "std")))]
371 fn norm(self) -> f64 {
372 libm::fabs(self)
373 }
374}
375
376/// A type with a natural interpolation that provides strong subdivision guarantees.
377///
378/// Although the only required method is `interpolate_stable`, many things are expected of it:
379///
380/// 1. The notion of interpolation should follow naturally from the semantics of the type, so
381/// that inferring the interpolation mode from the type alone is sensible.
382///
383/// 2. The interpolation recovers something equivalent to the starting value at `t = 0.0`
384/// and likewise with the ending value at `t = 1.0`. They do not have to be data-identical, but
385/// they should be semantically identical. For example, [`Quat::slerp`] doesn't always yield its
386/// second rotation input exactly at `t = 1.0`, but it always returns an equivalent rotation.
387///
388/// 3. Importantly, the interpolation must be *subdivision-stable*: for any interpolation curve
389/// between two (unnamed) values and any parameter-value pairs `(t0, p)` and `(t1, q)`, the
390/// interpolation curve between `p` and `q` must be the *linear* reparameterization of the original
391/// interpolation curve restricted to the interval `[t0, t1]`.
392///
393/// The last of these conditions is very strong and indicates something like constant speed. It
394/// is called "subdivision stability" because it guarantees that breaking up the interpolation
395/// into segments and joining them back together has no effect.
396///
397/// Here is a diagram depicting it:
398/// ```text
399/// top curve = u.interpolate_stable(v, t)
400///
401/// t0 => p t1 => q
402/// |-------------|---------|-------------|
403/// 0 => u / \ 1 => v
404/// / \
405/// / \
406/// / linear \
407/// / reparameterization \
408/// / t = t0 * (1 - s) + t1 * s \
409/// / \
410/// |-------------------------------------|
411/// 0 => p 1 => q
412///
413/// bottom curve = p.interpolate_stable(q, s)
414/// ```
415///
416/// Note that some common forms of interpolation do not satisfy this criterion. For example,
417/// [`Quat::lerp`] and [`Rot2::nlerp`] are not subdivision-stable.
418///
419/// Furthermore, this is not to be used as a general trait for abstract interpolation.
420/// Consumers rely on the strong guarantees in order for behavior based on this trait to be
421/// well-behaved.
422///
423/// [`Quat::slerp`]: crate::Quat::slerp
424/// [`Quat::lerp`]: crate::Quat::lerp
425/// [`Rot2::nlerp`]: crate::Rot2::nlerp
426pub trait StableInterpolate: Clone {
427 /// Interpolate between this value and the `other` given value using the parameter `t`. At
428 /// `t = 0.0`, a value equivalent to `self` is recovered, while `t = 1.0` recovers a value
429 /// equivalent to `other`, with intermediate values interpolating between the two.
430 /// See the [trait-level documentation] for details.
431 ///
432 /// [trait-level documentation]: StableInterpolate
433 fn interpolate_stable(&self, other: &Self, t: f32) -> Self;
434
435 /// A version of [`interpolate_stable`] that assigns the result to `self` for convenience.
436 ///
437 /// A manual implementation can be provided to optimize in-place mutation, such as avoiding memory allocations.
438 ///
439 /// [`interpolate_stable`]: StableInterpolate::interpolate_stable
440 fn interpolate_stable_assign(&mut self, other: &Self, t: f32) {
441 *self = self.interpolate_stable(other, t);
442 }
443
444 /// Smoothly nudge this value towards the `target` at a given decay rate. The `decay_rate`
445 /// parameter controls how fast the distance between `self` and `target` decays relative to
446 /// the units of `delta`; the intended usage is for `decay_rate` to generally remain fixed,
447 /// while `delta` is something like `delta_time` from an updating system. This produces a
448 /// smooth following of the target that is independent of framerate.
449 ///
450 /// More specifically, when this is called repeatedly, the result is that the distance between
451 /// `self` and a fixed `target` attenuates exponentially, with the rate of this exponential
452 /// decay given by `decay_rate`.
453 ///
454 /// For example, at `decay_rate = 0.0`, this has no effect.
455 /// At `decay_rate = f32::INFINITY`, `self` immediately snaps to `target`.
456 /// In general, higher rates mean that `self` moves more quickly towards `target`.
457 ///
458 /// # Example
459 /// ```
460 /// # use bevy_math::{Vec3, StableInterpolate};
461 /// # let delta_time: f32 = 1.0 / 60.0;
462 /// let mut object_position: Vec3 = Vec3::ZERO;
463 /// let target_position: Vec3 = Vec3::new(2.0, 3.0, 5.0);
464 /// // Decay rate of ln(10) => after 1 second, remaining distance is 1/10th
465 /// let decay_rate = f32::ln(10.0);
466 /// // Calling this repeatedly will move `object_position` towards `target_position`:
467 /// object_position.smooth_nudge(&target_position, decay_rate, delta_time);
468 /// ```
469 fn smooth_nudge(&mut self, target: &Self, decay_rate: f32, delta: f32) {
470 self.interpolate_stable_assign(target, 1.0 - ops::exp(-decay_rate * delta));
471 }
472}
473
474// Conservatively, we presently only apply this for normed vector spaces, where the notion
475// of being constant-speed is literally true. The technical axioms are satisfied for any
476// VectorSpace type, but the "natural from the semantics" part is less clear in general.
477impl<V> StableInterpolate for V
478where
479 V: NormedVectorSpace<Scalar = f32>,
480{
481 #[inline]
482 fn interpolate_stable(&self, other: &Self, t: f32) -> Self {
483 self.lerp(*other, t)
484 }
485}
486
487impl StableInterpolate for Rot2 {
488 #[inline]
489 fn interpolate_stable(&self, other: &Self, t: f32) -> Self {
490 self.slerp(*other, t)
491 }
492}
493
494impl StableInterpolate for Quat {
495 #[inline]
496 fn interpolate_stable(&self, other: &Self, t: f32) -> Self {
497 self.slerp(*other, t)
498 }
499}
500
501impl StableInterpolate for Dir2 {
502 #[inline]
503 fn interpolate_stable(&self, other: &Self, t: f32) -> Self {
504 self.slerp(*other, t)
505 }
506}
507
508impl StableInterpolate for Dir3 {
509 #[inline]
510 fn interpolate_stable(&self, other: &Self, t: f32) -> Self {
511 self.slerp(*other, t)
512 }
513}
514
515impl StableInterpolate for Dir3A {
516 #[inline]
517 fn interpolate_stable(&self, other: &Self, t: f32) -> Self {
518 self.slerp(*other, t)
519 }
520}
521
522macro_rules! impl_stable_interpolate_tuple {
523 ($(#[$meta:meta])* $(($n:tt, $T:ident)),*) => {
524 $(#[$meta])*
525 impl<$($T: StableInterpolate),*> StableInterpolate for ($($T,)*) {
526 fn interpolate_stable(&self, other: &Self, t: f32) -> Self {
527 (
528 $(
529 <$T as StableInterpolate>::interpolate_stable(&self.$n, &other.$n, t),
530 )*
531 )
532 }
533 }
534 };
535}
536
537all_tuples_enumerated!(
538 #[doc(fake_variadic)]
539 impl_stable_interpolate_tuple,
540 1,
541 11,
542 T
543);
544
545impl<T: StableInterpolate, const LEN: usize> StableInterpolate for [T; LEN] {
546 fn interpolate_stable(&self, other: &Self, t: f32) -> Self {
547 core::array::from_fn(|i| self[i].interpolate_stable(&other[i], t))
548 }
549}
550
551/// Error produced when the values to be interpolated are not in the same units.
552#[derive(Clone, Debug, Error)]
553#[error("cannot interpolate between two values of different units")]
554pub struct MismatchedUnitsError;
555
556/// A trait that indicates that a value _may_ be interpolable via [`StableInterpolate`]. An
557/// interpolation may fail if the values have different units - for example, attempting to
558/// interpolate between [`Val::Px`] and [`Val::Percent`] will fail,
559/// even though they are the same Rust type.
560///
561/// Fallible interpolation can be used for animated transitions, which can be set up to fail
562/// gracefully if the values cannot be interpolated. For example, a transition could smoothly
563/// go from `Val::Px(10)` to `Val::Px(20)`, but if the user attempts to go from `Val::Px(10)` to
564/// `Val::Percent(10)`, the animation player can detect the failure and simply snap to the new
565/// value without interpolating.
566///
567/// An animation clip system can incorporate fallible interpolation to support a broad set of
568/// sequenced parameter values. This can include numeric types, which always interpolate,
569/// enum types, which may or may not interpolate depending on the units, and non-interpolable
570/// types, which always jump immediately to the new value without interpolation. This means, for
571/// example, that you can have an animation track whose value type is a boolean or a string.
572///
573/// Interpolation for simple number and coordinate types will always succeed, as will any type
574/// that implements [`StableInterpolate`]. Types which have different variants such as
575/// [`Val`] and [`Color`] will only fail if the units are different.
576/// Note that [`Color`] has its own, non-fallible mixing methods, but those entail
577/// automatically converting between different color spaces, and is both expensive and complex.
578/// [`TryStableInterpolate`] is more conservative, and doesn't automatically convert between
579/// color spaces. This produces a color interpolation that has more predictable performance.
580///
581/// [`Val::Px`]: https://docs.rs/bevy/latest/bevy/ui/enum.Val.html#variant.Px
582/// [`Val::Percent`]: https://docs.rs/bevy/latest/bevy/ui/enum.Val.html#variant.Percent
583/// [`Val`]: https://docs.rs/bevy/latest/bevy/ui/enum.Val.html
584/// [`Color`]: https://docs.rs/bevy/latest/bevy/color/enum.Color.html
585pub trait TryStableInterpolate: Clone {
586 /// Error produced when the value cannot be interpolated.
587 type Error;
588
589 /// Attempt to interpolate the value. This may fail if the two interpolation values have
590 /// different units, or if the type is not interpolable.
591 fn try_interpolate_stable(&self, other: &Self, t: f32) -> Result<Self, Self::Error>;
592
593 /// A version of [`try_interpolate_stable`] that assigns the result to `self` for convenience.
594 /// On failure, `self` remains unchanged.
595 ///
596 /// A manual implementation can be provided to optimize in-place mutation, such as avoiding memory allocations.
597 ///
598 /// [`try_interpolate_stable`]: TryStableInterpolate::try_interpolate_stable
599 fn try_interpolate_stable_assign(&mut self, other: &Self, t: f32) -> Result<(), Self::Error> {
600 *self = self.try_interpolate_stable(other, t)?;
601 Ok(())
602 }
603
604 /// Like [`StableInterpolate::smooth_nudge`] but fallible.
605 fn try_smooth_nudge(
606 &mut self,
607 target: &Self,
608 decay_rate: f32,
609 delta: f32,
610 ) -> Result<(), Self::Error> {
611 self.try_interpolate_stable_assign(target, 1.0 - ops::exp(-decay_rate * delta))?;
612 Ok(())
613 }
614}
615
616impl<T: StableInterpolate> TryStableInterpolate for T {
617 type Error = Infallible;
618 fn try_interpolate_stable(&self, other: &Self, t: f32) -> Result<Self, Self::Error> {
619 Ok(self.interpolate_stable(other, t))
620 }
621
622 fn try_interpolate_stable_assign(&mut self, other: &Self, t: f32) -> Result<(), Self::Error> {
623 self.interpolate_stable_assign(other, t);
624 Ok(())
625 }
626}
627
628/// Errors produced when interpolating dynamically-sized arrays
629#[cfg(feature = "alloc")]
630#[derive(Clone, Debug, Error)]
631pub enum VecInterpolateError<E> {
632 /// Produced when arrays to be interpolated are of different lengths
633 #[error("cannot interpolate between two arrays of different lengths")]
634 MismatchedLength,
635 /// Produced when an error occurs interpolating an array element
636 #[error(transparent)]
637 Inner(E),
638}
639
640#[cfg(feature = "alloc")]
641impl<E, T: TryStableInterpolate<Error = E>> TryStableInterpolate for alloc::vec::Vec<T> {
642 type Error = VecInterpolateError<E>;
643 fn try_interpolate_stable(&self, other: &Self, t: f32) -> Result<Self, Self::Error> {
644 if self.len() == other.len() {
645 (0..self.len())
646 .map(|i| self[i].try_interpolate_stable(&other[i], t))
647 .collect::<Result<alloc::vec::Vec<_>, _>>()
648 .map_err(VecInterpolateError::Inner)
649 } else {
650 Err(VecInterpolateError::MismatchedLength)
651 }
652 }
653
654 fn try_interpolate_stable_assign(&mut self, other: &Self, t: f32) -> Result<(), Self::Error> {
655 if self.len() == other.len() {
656 for i in 0..self.len() {
657 self[i]
658 .try_interpolate_stable_assign(&other[i], t)
659 .map_err(VecInterpolateError::Inner)?;
660 }
661 Ok(())
662 } else {
663 Err(VecInterpolateError::MismatchedLength)
664 }
665 }
666}
667
668/// A type that has tangents.
669pub trait HasTangent {
670 /// The tangent type.
671 type Tangent: VectorSpace;
672}
673
674/// A value with its derivative.
675#[derive(Debug, Clone, Copy)]
676#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
677#[cfg_attr(feature = "bevy_reflect", derive(bevy_reflect::Reflect))]
678pub struct WithDerivative<T>
679where
680 T: HasTangent,
681{
682 /// The underlying value.
683 pub value: T,
684
685 /// The derivative at `value`.
686 pub derivative: T::Tangent,
687}
688
689/// A value together with its first and second derivatives.
690#[derive(Debug, Clone, Copy)]
691#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
692#[cfg_attr(feature = "bevy_reflect", derive(bevy_reflect::Reflect))]
693pub struct WithTwoDerivatives<T>
694where
695 T: HasTangent,
696{
697 /// The underlying value.
698 pub value: T,
699
700 /// The derivative at `value`.
701 pub derivative: T::Tangent,
702
703 /// The second derivative at `value`.
704 pub second_derivative: <T::Tangent as HasTangent>::Tangent,
705}
706
707impl<V: VectorSpace> HasTangent for V {
708 type Tangent = V;
709}
710
711impl<F, U, V, M, N> HasTangent for (M, N)
712where
713 F: ScalarField,
714 U: VectorSpace<Scalar = F>,
715 V: VectorSpace<Scalar = F>,
716 M: HasTangent<Tangent = U>,
717 N: HasTangent<Tangent = V>,
718{
719 type Tangent = Sum<M::Tangent, N::Tangent>;
720}
721
722#[cfg(test)]
723mod tests {
724 use alloc::{vec, vec::Vec};
725 use core::assert_matches;
726
727 use super::{StableInterpolate, TryStableInterpolate, VecInterpolateError};
728
729 #[test]
730 fn interpolate_static_arrays() {
731 let a = [0.0, 1.0];
732 let b = [1.0, 0.0];
733
734 assert_matches!(a.interpolate_stable(&b, 0.25), [0.25, 0.75]);
735 assert_matches!(a.interpolate_stable(&b, 0.5), [0.5, 0.5]);
736 assert_matches!(a.interpolate_stable(&b, 0.75), [0.75, 0.25]);
737 }
738
739 #[test]
740 fn interpolate_dynamic_arrays() {
741 let mut a = vec![0.0, 1.0];
742 let b = vec![1.0, 0.0];
743
744 assert_matches!(a.try_interpolate_stable(&b, 0.25), Ok(v) if v == vec![0.25, 0.75]);
745 assert_matches!(a.try_interpolate_stable(&b, 0.5), Ok(v) if v == vec![0.5, 0.5]);
746 assert_matches!(a.try_interpolate_stable(&b, 0.75), Ok(v) if v == vec![0.75, 0.25]);
747
748 assert_matches!(a.try_interpolate_stable_assign(&b, 0.25), Ok(()));
749 assert_eq!(a, vec![0.25, 0.75]);
750 assert_matches!(a.try_interpolate_stable_assign(&b, 0.5), Ok(()));
751 assert_eq!(a, vec![0.625, 0.375]);
752 assert_matches!(a.try_interpolate_stable_assign(&b, 0.75), Ok(()));
753 assert_eq!(a, vec![0.90625, 0.09375]);
754 }
755
756 #[test]
757 fn interpolate_dynamic_arrays_different_lengths() {
758 let mut a = vec![0.0, 1.0];
759 let b = vec![1.0, 0.0, 1.0];
760
761 assert_matches!(
762 a.try_interpolate_stable(&b, 0.5),
763 Err(VecInterpolateError::MismatchedLength)
764 );
765
766 assert_matches!(
767 a.try_interpolate_stable_assign(&b, 0.5),
768 Err(VecInterpolateError::MismatchedLength)
769 );
770
771 let mut a: Vec<Vec<f32>> = vec![vec![0.0, 1.0], vec![1.0, 0.0]];
772 let b: Vec<Vec<f32>> = vec![vec![1.0, 0.0], vec![0.0, 1.0, 0.0]];
773
774 assert_matches!(
775 a.try_interpolate_stable(&b, 0.5),
776 Err(VecInterpolateError::Inner(
777 VecInterpolateError::MismatchedLength
778 ))
779 );
780
781 assert_matches!(
782 a.try_interpolate_stable_assign(&b, 0.5),
783 Err(VecInterpolateError::Inner(
784 VecInterpolateError::MismatchedLength
785 ))
786 );
787 }
788}