Skip to content

Commit

Permalink
Merge branch 'main' into enqueue-command-rename
Browse files Browse the repository at this point in the history
  • Loading branch information
spvky authored Dec 10, 2024
2 parents 4724001 + c60dcea commit 5395532
Show file tree
Hide file tree
Showing 8 changed files with 1,242 additions and 95 deletions.
130 changes: 129 additions & 1 deletion crates/bevy_math/src/common_traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ pub trait VectorSpace:
+ Div<f32, Output = Self>
+ Add<Self, Output = Self>
+ Sub<Self, Output = Self>
+ Neg
+ Neg<Output = Self>
+ Default
+ Debug
+ Clone
Expand Down Expand Up @@ -71,6 +71,89 @@ impl VectorSpace for f32 {
const ZERO: Self = 0.0;
}

/// A type consisting of formal sums of elements from `V` and `W`. That is,
/// each value `Sum(v, w)` is thought of as `v + w`, with no available
/// simplification. In particular, if `V` and `W` are [vector spaces], then
/// `Sum<V, W>` is a vector space whose dimension is the sum of those of `V`
/// and `W`, and the field accessors `.0` and `.1` are vector space projections.
///
/// [vector spaces]: VectorSpace
#[derive(Debug, Clone, Copy)]
pub struct Sum<V, W>(pub V, pub W);

impl<V, W> Mul<f32> for Sum<V, W>
where
V: VectorSpace,
W: VectorSpace,
{
type Output = Self;
fn mul(self, rhs: f32) -> Self::Output {
Sum(self.0 * rhs, self.1 * rhs)
}
}

impl<V, W> Div<f32> for Sum<V, W>
where
V: VectorSpace,
W: VectorSpace,
{
type Output = Self;
fn div(self, rhs: f32) -> Self::Output {
Sum(self.0 / rhs, self.1 / rhs)
}
}

impl<V, W> Add<Self> for Sum<V, W>
where
V: VectorSpace,
W: VectorSpace,
{
type Output = Self;
fn add(self, other: Self) -> Self::Output {
Sum(self.0 + other.0, self.1 + other.1)
}
}

impl<V, W> Sub<Self> for Sum<V, W>
where
V: VectorSpace,
W: VectorSpace,
{
type Output = Self;
fn sub(self, other: Self) -> Self::Output {
Sum(self.0 - other.0, self.1 - other.1)
}
}

impl<V, W> Neg for Sum<V, W>
where
V: VectorSpace,
W: VectorSpace,
{
type Output = Self;
fn neg(self) -> Self::Output {
Sum(-self.0, -self.1)
}
}

impl<V, W> Default for Sum<V, W>
where
V: VectorSpace,
W: VectorSpace,
{
fn default() -> Self {
Sum(V::default(), W::default())
}
}

impl<V, W> VectorSpace for Sum<V, W>
where
V: VectorSpace,
W: VectorSpace,
{
const ZERO: Self = Sum(V::ZERO, W::ZERO);
}

/// A type that supports the operations of a normed vector space; i.e. a norm operation in addition
/// to those of [`VectorSpace`]. Specifically, the implementor must guarantee that the following
/// relationships hold, within the limitations of floating point arithmetic:
Expand Down Expand Up @@ -410,3 +493,48 @@ impl_stable_interpolate_tuple!(
(T9, 9),
(T10, 10)
);

/// A type that has tangents.
pub trait HasTangent {
/// The tangent type.
type Tangent: VectorSpace;
}

/// A value with its derivative.
pub struct WithDerivative<T>
where
T: HasTangent,
{
/// The underlying value.
pub value: T,

/// The derivative at `value`.
pub derivative: T::Tangent,
}

/// A value together with its first and second derivatives.
pub struct WithTwoDerivatives<T>
where
T: HasTangent,
{
/// The underlying value.
pub value: T,

/// The derivative at `value`.
pub derivative: T::Tangent,

/// The second derivative at `value`.
pub second_derivative: <T::Tangent as HasTangent>::Tangent,
}

impl<V: VectorSpace> HasTangent for V {
type Tangent = V;
}

impl<M, N> HasTangent for (M, N)
where
M: HasTangent,
N: HasTangent,
{
type Tangent = Sum<M::Tangent, N::Tangent>;
}
159 changes: 159 additions & 0 deletions crates/bevy_math/src/cubic_splines/curve_impls.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
use super::{CubicSegment, RationalSegment};
use crate::common_traits::{VectorSpace, WithDerivative, WithTwoDerivatives};
use crate::curve::{
derivatives::{SampleDerivative, SampleTwoDerivatives},
Curve, Interval,
};

#[cfg(feature = "alloc")]
use super::{CubicCurve, RationalCurve};

// -- CubicSegment

impl<P: VectorSpace> Curve<P> for CubicSegment<P> {
#[inline]
fn domain(&self) -> Interval {
Interval::UNIT
}

#[inline]
fn sample_unchecked(&self, t: f32) -> P {
self.position(t)
}
}

impl<P: VectorSpace> SampleDerivative<P> for CubicSegment<P> {
#[inline]
fn sample_with_derivative_unchecked(&self, t: f32) -> WithDerivative<P> {
WithDerivative {
value: self.position(t),
derivative: self.velocity(t),
}
}
}

impl<P: VectorSpace> SampleTwoDerivatives<P> for CubicSegment<P> {
#[inline]
fn sample_with_two_derivatives_unchecked(&self, t: f32) -> WithTwoDerivatives<P> {
WithTwoDerivatives {
value: self.position(t),
derivative: self.velocity(t),
second_derivative: self.acceleration(t),
}
}
}

// -- CubicCurve

#[cfg(feature = "alloc")]
impl<P: VectorSpace> Curve<P> for CubicCurve<P> {
#[inline]
fn domain(&self) -> Interval {
// The non-emptiness invariant guarantees that this succeeds.
Interval::new(0.0, self.segments.len() as f32)
.expect("CubicCurve is invalid because it has no segments")
}

#[inline]
fn sample_unchecked(&self, t: f32) -> P {
self.position(t)
}
}

#[cfg(feature = "alloc")]
impl<P: VectorSpace> SampleDerivative<P> for CubicCurve<P> {
#[inline]
fn sample_with_derivative_unchecked(&self, t: f32) -> WithDerivative<P> {
WithDerivative {
value: self.position(t),
derivative: self.velocity(t),
}
}
}

#[cfg(feature = "alloc")]
impl<P: VectorSpace> SampleTwoDerivatives<P> for CubicCurve<P> {
#[inline]
fn sample_with_two_derivatives_unchecked(&self, t: f32) -> WithTwoDerivatives<P> {
WithTwoDerivatives {
value: self.position(t),
derivative: self.velocity(t),
second_derivative: self.acceleration(t),
}
}
}

// -- RationalSegment

impl<P: VectorSpace> Curve<P> for RationalSegment<P> {
#[inline]
fn domain(&self) -> Interval {
Interval::UNIT
}

#[inline]
fn sample_unchecked(&self, t: f32) -> P {
self.position(t)
}
}

impl<P: VectorSpace> SampleDerivative<P> for RationalSegment<P> {
#[inline]
fn sample_with_derivative_unchecked(&self, t: f32) -> WithDerivative<P> {
WithDerivative {
value: self.position(t),
derivative: self.velocity(t),
}
}
}

impl<P: VectorSpace> SampleTwoDerivatives<P> for RationalSegment<P> {
#[inline]
fn sample_with_two_derivatives_unchecked(&self, t: f32) -> WithTwoDerivatives<P> {
WithTwoDerivatives {
value: self.position(t),
derivative: self.velocity(t),
second_derivative: self.acceleration(t),
}
}
}

// -- RationalCurve

#[cfg(feature = "alloc")]
impl<P: VectorSpace> Curve<P> for RationalCurve<P> {
#[inline]
fn domain(&self) -> Interval {
// The non-emptiness invariant guarantees the success of this.
Interval::new(0.0, self.length())
.expect("RationalCurve is invalid because it has zero length")
}

#[inline]
fn sample_unchecked(&self, t: f32) -> P {
self.position(t)
}
}

#[cfg(feature = "alloc")]
impl<P: VectorSpace> SampleDerivative<P> for RationalCurve<P> {
#[inline]
fn sample_with_derivative_unchecked(&self, t: f32) -> WithDerivative<P> {
WithDerivative {
value: self.position(t),
derivative: self.velocity(t),
}
}
}

#[cfg(feature = "alloc")]
impl<P: VectorSpace> SampleTwoDerivatives<P> for RationalCurve<P> {
#[inline]
fn sample_with_two_derivatives_unchecked(&self, t: f32) -> WithTwoDerivatives<P> {
WithTwoDerivatives {
value: self.position(t),
derivative: self.velocity(t),
second_derivative: self.acceleration(t),
}
}
}
Loading

0 comments on commit 5395532

Please sign in to comment.