bevy_math/common_traits.rs
1//! This module contains abstract mathematical traits shared by types used in `bevy_math`.
2
3use crate::{ops, Dir2, Dir3, Dir3A, Quat, Rot2, Vec2, Vec3, Vec3A, Vec4};
4use core::{
5 fmt::Debug,
6 ops::{Add, Div, Mul, Neg, Sub},
7};
8use variadics_please::all_tuples_enumerated;
9
10/// A type that supports the mathematical operations of a real vector space, irrespective of dimension.
11/// In particular, this means that the implementing type supports:
12/// - Scalar multiplication and division on the right by elements of `f32`
13/// - Negation
14/// - Addition and subtraction
15/// - Zero
16///
17/// Within the limitations of floating point arithmetic, all the following are required to hold:
18/// - (Associativity of addition) For all `u, v, w: Self`, `(u + v) + w == u + (v + w)`.
19/// - (Commutativity of addition) For all `u, v: Self`, `u + v == v + u`.
20/// - (Additive identity) For all `v: Self`, `v + Self::ZERO == v`.
21/// - (Additive inverse) For all `v: Self`, `v - v == v + (-v) == Self::ZERO`.
22/// - (Compatibility of multiplication) For all `a, b: f32`, `v: Self`, `v * (a * b) == (v * a) * b`.
23/// - (Multiplicative identity) For all `v: Self`, `v * 1.0 == v`.
24/// - (Distributivity for vector addition) For all `a: f32`, `u, v: Self`, `(u + v) * a == u * a + v * a`.
25/// - (Distributivity for scalar addition) For all `a, b: f32`, `v: Self`, `v * (a + b) == v * a + v * b`.
26///
27/// Note that, because implementing types use floating point arithmetic, they are not required to actually
28/// implement `PartialEq` or `Eq`.
29pub trait VectorSpace:
30 Mul<f32, Output = Self>
31 + Div<f32, Output = Self>
32 + Add<Self, Output = Self>
33 + Sub<Self, Output = Self>
34 + Neg<Output = Self>
35 + Default
36 + Debug
37 + Clone
38 + Copy
39{
40 /// The zero vector, which is the identity of addition for the vector space type.
41 const ZERO: Self;
42
43 /// Perform vector space linear interpolation between this element and another, based
44 /// on the parameter `t`. When `t` is `0`, `self` is recovered. When `t` is `1`, `rhs`
45 /// is recovered.
46 ///
47 /// Note that the value of `t` is not clamped by this function, so extrapolating outside
48 /// of the interval `[0,1]` is allowed.
49 #[inline]
50 fn lerp(self, rhs: Self, t: f32) -> Self {
51 self * (1. - t) + rhs * t
52 }
53}
54
55impl VectorSpace for Vec4 {
56 const ZERO: Self = Vec4::ZERO;
57}
58
59impl VectorSpace for Vec3 {
60 const ZERO: Self = Vec3::ZERO;
61}
62
63impl VectorSpace for Vec3A {
64 const ZERO: Self = Vec3A::ZERO;
65}
66
67impl VectorSpace for Vec2 {
68 const ZERO: Self = Vec2::ZERO;
69}
70
71impl VectorSpace for f32 {
72 const ZERO: Self = 0.0;
73}
74
75/// A type consisting of formal sums of elements from `V` and `W`. That is,
76/// each value `Sum(v, w)` is thought of as `v + w`, with no available
77/// simplification. In particular, if `V` and `W` are [vector spaces], then
78/// `Sum<V, W>` is a vector space whose dimension is the sum of those of `V`
79/// and `W`, and the field accessors `.0` and `.1` are vector space projections.
80///
81/// [vector spaces]: VectorSpace
82#[derive(Debug, Clone, Copy)]
83#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
84#[cfg_attr(feature = "bevy_reflect", derive(bevy_reflect::Reflect))]
85pub struct Sum<V, W>(pub V, pub W);
86
87impl<V, W> Mul<f32> for Sum<V, W>
88where
89 V: VectorSpace,
90 W: VectorSpace,
91{
92 type Output = Self;
93 fn mul(self, rhs: f32) -> Self::Output {
94 Sum(self.0 * rhs, self.1 * rhs)
95 }
96}
97
98impl<V, W> Div<f32> for Sum<V, W>
99where
100 V: VectorSpace,
101 W: VectorSpace,
102{
103 type Output = Self;
104 fn div(self, rhs: f32) -> Self::Output {
105 Sum(self.0 / rhs, self.1 / rhs)
106 }
107}
108
109impl<V, W> Add<Self> for Sum<V, W>
110where
111 V: VectorSpace,
112 W: VectorSpace,
113{
114 type Output = Self;
115 fn add(self, other: Self) -> Self::Output {
116 Sum(self.0 + other.0, self.1 + other.1)
117 }
118}
119
120impl<V, W> Sub<Self> for Sum<V, W>
121where
122 V: VectorSpace,
123 W: VectorSpace,
124{
125 type Output = Self;
126 fn sub(self, other: Self) -> Self::Output {
127 Sum(self.0 - other.0, self.1 - other.1)
128 }
129}
130
131impl<V, W> Neg for Sum<V, W>
132where
133 V: VectorSpace,
134 W: VectorSpace,
135{
136 type Output = Self;
137 fn neg(self) -> Self::Output {
138 Sum(-self.0, -self.1)
139 }
140}
141
142impl<V, W> Default for Sum<V, W>
143where
144 V: VectorSpace,
145 W: VectorSpace,
146{
147 fn default() -> Self {
148 Sum(V::default(), W::default())
149 }
150}
151
152impl<V, W> VectorSpace for Sum<V, W>
153where
154 V: VectorSpace,
155 W: VectorSpace,
156{
157 const ZERO: Self = Sum(V::ZERO, W::ZERO);
158}
159
160/// A type that supports the operations of a normed vector space; i.e. a norm operation in addition
161/// to those of [`VectorSpace`]. Specifically, the implementor must guarantee that the following
162/// relationships hold, within the limitations of floating point arithmetic:
163/// - (Nonnegativity) For all `v: Self`, `v.norm() >= 0.0`.
164/// - (Positive definiteness) For all `v: Self`, `v.norm() == 0.0` implies `v == Self::ZERO`.
165/// - (Absolute homogeneity) For all `c: f32`, `v: Self`, `(v * c).norm() == v.norm() * c.abs()`.
166/// - (Triangle inequality) For all `v, w: Self`, `(v + w).norm() <= v.norm() + w.norm()`.
167///
168/// Note that, because implementing types use floating point arithmetic, they are not required to actually
169/// implement `PartialEq` or `Eq`.
170pub trait NormedVectorSpace: VectorSpace {
171 /// The size of this element. The return value should always be nonnegative.
172 fn norm(self) -> f32;
173
174 /// The squared norm of this element. Computing this is often faster than computing
175 /// [`NormedVectorSpace::norm`].
176 #[inline]
177 fn norm_squared(self) -> f32 {
178 self.norm() * self.norm()
179 }
180
181 /// The distance between this element and another, as determined by the norm.
182 #[inline]
183 fn distance(self, rhs: Self) -> f32 {
184 (rhs - self).norm()
185 }
186
187 /// The squared distance between this element and another, as determined by the norm. Note that
188 /// this is often faster to compute in practice than [`NormedVectorSpace::distance`].
189 #[inline]
190 fn distance_squared(self, rhs: Self) -> f32 {
191 (rhs - self).norm_squared()
192 }
193}
194
195impl NormedVectorSpace for Vec4 {
196 #[inline]
197 fn norm(self) -> f32 {
198 self.length()
199 }
200
201 #[inline]
202 fn norm_squared(self) -> f32 {
203 self.length_squared()
204 }
205}
206
207impl NormedVectorSpace for Vec3 {
208 #[inline]
209 fn norm(self) -> f32 {
210 self.length()
211 }
212
213 #[inline]
214 fn norm_squared(self) -> f32 {
215 self.length_squared()
216 }
217}
218
219impl NormedVectorSpace for Vec3A {
220 #[inline]
221 fn norm(self) -> f32 {
222 self.length()
223 }
224
225 #[inline]
226 fn norm_squared(self) -> f32 {
227 self.length_squared()
228 }
229}
230
231impl NormedVectorSpace for Vec2 {
232 #[inline]
233 fn norm(self) -> f32 {
234 self.length()
235 }
236
237 #[inline]
238 fn norm_squared(self) -> f32 {
239 self.length_squared()
240 }
241}
242
243impl NormedVectorSpace for f32 {
244 #[inline]
245 fn norm(self) -> f32 {
246 ops::abs(self)
247 }
248
249 #[inline]
250 fn norm_squared(self) -> f32 {
251 self * self
252 }
253}
254
255/// A type with a natural interpolation that provides strong subdivision guarantees.
256///
257/// Although the only required method is `interpolate_stable`, many things are expected of it:
258///
259/// 1. The notion of interpolation should follow naturally from the semantics of the type, so
260/// that inferring the interpolation mode from the type alone is sensible.
261///
262/// 2. The interpolation recovers something equivalent to the starting value at `t = 0.0`
263/// and likewise with the ending value at `t = 1.0`. They do not have to be data-identical, but
264/// they should be semantically identical. For example, [`Quat::slerp`] doesn't always yield its
265/// second rotation input exactly at `t = 1.0`, but it always returns an equivalent rotation.
266///
267/// 3. Importantly, the interpolation must be *subdivision-stable*: for any interpolation curve
268/// between two (unnamed) values and any parameter-value pairs `(t0, p)` and `(t1, q)`, the
269/// interpolation curve between `p` and `q` must be the *linear* reparameterization of the original
270/// interpolation curve restricted to the interval `[t0, t1]`.
271///
272/// The last of these conditions is very strong and indicates something like constant speed. It
273/// is called "subdivision stability" because it guarantees that breaking up the interpolation
274/// into segments and joining them back together has no effect.
275///
276/// Here is a diagram depicting it:
277/// ```text
278/// top curve = u.interpolate_stable(v, t)
279///
280/// t0 => p t1 => q
281/// |-------------|---------|-------------|
282/// 0 => u / \ 1 => v
283/// / \
284/// / \
285/// / linear \
286/// / reparameterization \
287/// / t = t0 * (1 - s) + t1 * s \
288/// / \
289/// |-------------------------------------|
290/// 0 => p 1 => q
291///
292/// bottom curve = p.interpolate_stable(q, s)
293/// ```
294///
295/// Note that some common forms of interpolation do not satisfy this criterion. For example,
296/// [`Quat::lerp`] and [`Rot2::nlerp`] are not subdivision-stable.
297///
298/// Furthermore, this is not to be used as a general trait for abstract interpolation.
299/// Consumers rely on the strong guarantees in order for behavior based on this trait to be
300/// well-behaved.
301///
302/// [`Quat::slerp`]: crate::Quat::slerp
303/// [`Quat::lerp`]: crate::Quat::lerp
304/// [`Rot2::nlerp`]: crate::Rot2::nlerp
305pub trait StableInterpolate: Clone {
306 /// Interpolate between this value and the `other` given value using the parameter `t`. At
307 /// `t = 0.0`, a value equivalent to `self` is recovered, while `t = 1.0` recovers a value
308 /// equivalent to `other`, with intermediate values interpolating between the two.
309 /// See the [trait-level documentation] for details.
310 ///
311 /// [trait-level documentation]: StableInterpolate
312 fn interpolate_stable(&self, other: &Self, t: f32) -> Self;
313
314 /// A version of [`interpolate_stable`] that assigns the result to `self` for convenience.
315 ///
316 /// [`interpolate_stable`]: StableInterpolate::interpolate_stable
317 fn interpolate_stable_assign(&mut self, other: &Self, t: f32) {
318 *self = self.interpolate_stable(other, t);
319 }
320
321 /// Smoothly nudge this value towards the `target` at a given decay rate. The `decay_rate`
322 /// parameter controls how fast the distance between `self` and `target` decays relative to
323 /// the units of `delta`; the intended usage is for `decay_rate` to generally remain fixed,
324 /// while `delta` is something like `delta_time` from an updating system. This produces a
325 /// smooth following of the target that is independent of framerate.
326 ///
327 /// More specifically, when this is called repeatedly, the result is that the distance between
328 /// `self` and a fixed `target` attenuates exponentially, with the rate of this exponential
329 /// decay given by `decay_rate`.
330 ///
331 /// For example, at `decay_rate = 0.0`, this has no effect.
332 /// At `decay_rate = f32::INFINITY`, `self` immediately snaps to `target`.
333 /// In general, higher rates mean that `self` moves more quickly towards `target`.
334 ///
335 /// # Example
336 /// ```
337 /// # use bevy_math::{Vec3, StableInterpolate};
338 /// # let delta_time: f32 = 1.0 / 60.0;
339 /// let mut object_position: Vec3 = Vec3::ZERO;
340 /// let target_position: Vec3 = Vec3::new(2.0, 3.0, 5.0);
341 /// // Decay rate of ln(10) => after 1 second, remaining distance is 1/10th
342 /// let decay_rate = f32::ln(10.0);
343 /// // Calling this repeatedly will move `object_position` towards `target_position`:
344 /// object_position.smooth_nudge(&target_position, decay_rate, delta_time);
345 /// ```
346 fn smooth_nudge(&mut self, target: &Self, decay_rate: f32, delta: f32) {
347 self.interpolate_stable_assign(target, 1.0 - ops::exp(-decay_rate * delta));
348 }
349}
350
351// Conservatively, we presently only apply this for normed vector spaces, where the notion
352// of being constant-speed is literally true. The technical axioms are satisfied for any
353// VectorSpace type, but the "natural from the semantics" part is less clear in general.
354impl<V> StableInterpolate for V
355where
356 V: NormedVectorSpace,
357{
358 #[inline]
359 fn interpolate_stable(&self, other: &Self, t: f32) -> Self {
360 self.lerp(*other, t)
361 }
362}
363
364impl StableInterpolate for Rot2 {
365 #[inline]
366 fn interpolate_stable(&self, other: &Self, t: f32) -> Self {
367 self.slerp(*other, t)
368 }
369}
370
371impl StableInterpolate for Quat {
372 #[inline]
373 fn interpolate_stable(&self, other: &Self, t: f32) -> Self {
374 self.slerp(*other, t)
375 }
376}
377
378impl StableInterpolate for Dir2 {
379 #[inline]
380 fn interpolate_stable(&self, other: &Self, t: f32) -> Self {
381 self.slerp(*other, t)
382 }
383}
384
385impl StableInterpolate for Dir3 {
386 #[inline]
387 fn interpolate_stable(&self, other: &Self, t: f32) -> Self {
388 self.slerp(*other, t)
389 }
390}
391
392impl StableInterpolate for Dir3A {
393 #[inline]
394 fn interpolate_stable(&self, other: &Self, t: f32) -> Self {
395 self.slerp(*other, t)
396 }
397}
398
399macro_rules! impl_stable_interpolate_tuple {
400 ($(#[$meta:meta])* $(($n:tt, $T:ident)),*) => {
401 $(#[$meta])*
402 impl<$($T: StableInterpolate),*> StableInterpolate for ($($T,)*) {
403 fn interpolate_stable(&self, other: &Self, t: f32) -> Self {
404 (
405 $(
406 <$T as StableInterpolate>::interpolate_stable(&self.$n, &other.$n, t),
407 )*
408 )
409 }
410 }
411 };
412}
413
414all_tuples_enumerated!(
415 #[doc(fake_variadic)]
416 impl_stable_interpolate_tuple,
417 1,
418 11,
419 T
420);
421
422/// A type that has tangents.
423pub trait HasTangent {
424 /// The tangent type.
425 type Tangent: VectorSpace;
426}
427
428/// A value with its derivative.
429#[derive(Debug, Clone, Copy)]
430#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
431#[cfg_attr(feature = "bevy_reflect", derive(bevy_reflect::Reflect))]
432pub struct WithDerivative<T>
433where
434 T: HasTangent,
435{
436 /// The underlying value.
437 pub value: T,
438
439 /// The derivative at `value`.
440 pub derivative: T::Tangent,
441}
442
443/// A value together with its first and second derivatives.
444#[derive(Debug, Clone, Copy)]
445#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
446#[cfg_attr(feature = "bevy_reflect", derive(bevy_reflect::Reflect))]
447pub struct WithTwoDerivatives<T>
448where
449 T: HasTangent,
450{
451 /// The underlying value.
452 pub value: T,
453
454 /// The derivative at `value`.
455 pub derivative: T::Tangent,
456
457 /// The second derivative at `value`.
458 pub second_derivative: <T::Tangent as HasTangent>::Tangent,
459}
460
461impl<V: VectorSpace> HasTangent for V {
462 type Tangent = V;
463}
464
465impl<M, N> HasTangent for (M, N)
466where
467 M: HasTangent,
468 N: HasTangent,
469{
470 type Tangent = Sum<M::Tangent, N::Tangent>;
471}