Path: blob/main/crates/bevy_math/src/curve/derivatives/mod.rs
6598 views
//! This module holds traits related to extracting derivatives from curves. In1//! applications, the derivatives of interest are chiefly the first and second;2//! in this module, these are provided by the traits [`CurveWithDerivative`]3//! and [`CurveWithTwoDerivatives`].4//!5//! These take ownership of the curve they are used on by default, so that6//! the resulting output may be used in more durable contexts. For example,7//! `CurveWithDerivative<T>` is not dyn-compatible, but `Curve<WithDerivative<T>>`8//! is, so if such a curve needs to be stored in a dynamic context, calling9//! [`with_derivative`] and then placing the result in a10//! `Box<Curve<WithDerivative<T>>>` is sensible.11//!12//! On the other hand, in more transient contexts, consuming a value merely to13//! sample derivatives is inconvenient, and in these cases, it is recommended14//! to use [`by_ref`] when possible to create a referential curve first, retaining15//! liveness of the original.16//!17//! This module also holds the [`SampleDerivative`] and [`SampleTwoDerivatives`]18//! traits, which can be used to easily implement `CurveWithDerivative` and its19//! counterpart.20//!21//! [`with_derivative`]: CurveWithDerivative::with_derivative22//! [`by_ref`]: crate::curve::CurveExt::by_ref2324pub mod adaptor_impls;2526use crate::{27common_traits::{HasTangent, WithDerivative, WithTwoDerivatives},28curve::{Curve, Interval},29};30use core::ops::Deref;3132#[cfg(feature = "bevy_reflect")]33use bevy_reflect::{FromReflect, Reflect};3435/// Trait for curves that have a well-defined notion of derivative, allowing for36/// derivatives to be extracted along with values.37///38/// This is implemented by implementing [`SampleDerivative`].39pub trait CurveWithDerivative<T>: SampleDerivative<T> + Sized40where41T: HasTangent,42{43/// This curve, but with its first derivative included in sampling.44///45/// Notably, the output type is a `Curve<WithDerivative<T>>`.46fn with_derivative(self) -> SampleDerivativeWrapper<Self>;47}4849/// Trait for curves that have a well-defined notion of second derivative,50/// allowing for two derivatives to be extracted along with values.51///52/// This is implemented by implementing [`SampleTwoDerivatives`].53pub trait CurveWithTwoDerivatives<T>: SampleTwoDerivatives<T> + Sized54where55T: HasTangent,56{57/// This curve, but with its first two derivatives included in sampling.58///59/// Notably, the output type is a `Curve<WithTwoDerivatives<T>>`.60fn with_two_derivatives(self) -> SampleTwoDerivativesWrapper<Self>;61}6263/// A trait for curves that can sample derivatives in addition to values.64///65/// Types that implement this trait automatically implement [`CurveWithDerivative`];66/// the curve produced by [`with_derivative`] uses the sampling defined in the trait67/// implementation.68///69/// [`with_derivative`]: CurveWithDerivative::with_derivative70pub trait SampleDerivative<T>: Curve<T>71where72T: HasTangent,73{74/// Sample this curve at the parameter value `t`, extracting the associated value75/// in addition to its derivative. This is the unchecked version of sampling, which76/// should only be used if the sample time `t` is already known to lie within the77/// curve's domain.78///79/// See [`Curve::sample_unchecked`] for more information.80fn sample_with_derivative_unchecked(&self, t: f32) -> WithDerivative<T>;8182/// Sample this curve's value and derivative at the parameter value `t`, returning83/// `None` if the point is outside of the curve's domain.84fn sample_with_derivative(&self, t: f32) -> Option<WithDerivative<T>> {85match self.domain().contains(t) {86true => Some(self.sample_with_derivative_unchecked(t)),87false => None,88}89}9091/// Sample this curve's value and derivative at the parameter value `t`, clamping `t`92/// to lie inside the domain of the curve.93fn sample_with_derivative_clamped(&self, t: f32) -> WithDerivative<T> {94let t = self.domain().clamp(t);95self.sample_with_derivative_unchecked(t)96}97}9899impl<T, C, D> SampleDerivative<T> for D100where101T: HasTangent,102C: SampleDerivative<T> + ?Sized,103D: Deref<Target = C>,104{105fn sample_with_derivative_unchecked(&self, t: f32) -> WithDerivative<T> {106<C as SampleDerivative<T>>::sample_with_derivative_unchecked(self, t)107}108}109110/// A trait for curves that can sample two derivatives in addition to values.111///112/// Types that implement this trait automatically implement [`CurveWithTwoDerivatives`];113/// the curve produced by [`with_two_derivatives`] uses the sampling defined in the trait114/// implementation.115///116/// [`with_two_derivatives`]: CurveWithTwoDerivatives::with_two_derivatives117pub trait SampleTwoDerivatives<T>: Curve<T>118where119T: HasTangent,120{121/// Sample this curve at the parameter value `t`, extracting the associated value122/// in addition to two derivatives. This is the unchecked version of sampling, which123/// should only be used if the sample time `t` is already known to lie within the124/// curve's domain.125///126/// See [`Curve::sample_unchecked`] for more information.127fn sample_with_two_derivatives_unchecked(&self, t: f32) -> WithTwoDerivatives<T>;128129/// Sample this curve's value and two derivatives at the parameter value `t`, returning130/// `None` if the point is outside of the curve's domain.131fn sample_with_two_derivatives(&self, t: f32) -> Option<WithTwoDerivatives<T>> {132match self.domain().contains(t) {133true => Some(self.sample_with_two_derivatives_unchecked(t)),134false => None,135}136}137138/// Sample this curve's value and two derivatives at the parameter value `t`, clamping `t`139/// to lie inside the domain of the curve.140fn sample_with_two_derivatives_clamped(&self, t: f32) -> WithTwoDerivatives<T> {141let t = self.domain().clamp(t);142self.sample_with_two_derivatives_unchecked(t)143}144}145146/// A wrapper that uses a [`SampleDerivative<T>`] curve to produce a `Curve<WithDerivative<T>>`.147#[derive(Copy, Clone, Debug, Default, PartialEq)]148#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]149#[cfg_attr(150feature = "bevy_reflect",151derive(Reflect, FromReflect),152reflect(from_reflect = false)153)]154pub struct SampleDerivativeWrapper<C>(C);155156impl<T, C> Curve<WithDerivative<T>> for SampleDerivativeWrapper<C>157where158T: HasTangent,159C: SampleDerivative<T>,160{161fn domain(&self) -> Interval {162self.0.domain()163}164165fn sample_unchecked(&self, t: f32) -> WithDerivative<T> {166self.0.sample_with_derivative_unchecked(t)167}168169fn sample(&self, t: f32) -> Option<WithDerivative<T>> {170self.0.sample_with_derivative(t)171}172173fn sample_clamped(&self, t: f32) -> WithDerivative<T> {174self.0.sample_with_derivative_clamped(t)175}176}177178/// A wrapper that uses a [`SampleTwoDerivatives<T>`] curve to produce a179/// `Curve<WithTwoDerivatives<T>>`.180#[derive(Copy, Clone, Debug, Default, PartialEq)]181#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]182#[cfg_attr(183feature = "bevy_reflect",184derive(Reflect, FromReflect),185reflect(from_reflect = false)186)]187pub struct SampleTwoDerivativesWrapper<C>(C);188189impl<T, C> Curve<WithTwoDerivatives<T>> for SampleTwoDerivativesWrapper<C>190where191T: HasTangent,192C: SampleTwoDerivatives<T>,193{194fn domain(&self) -> Interval {195self.0.domain()196}197198fn sample_unchecked(&self, t: f32) -> WithTwoDerivatives<T> {199self.0.sample_with_two_derivatives_unchecked(t)200}201202fn sample(&self, t: f32) -> Option<WithTwoDerivatives<T>> {203self.0.sample_with_two_derivatives(t)204}205206fn sample_clamped(&self, t: f32) -> WithTwoDerivatives<T> {207self.0.sample_with_two_derivatives_clamped(t)208}209}210211impl<T, C> CurveWithDerivative<T> for C212where213T: HasTangent,214C: SampleDerivative<T>,215{216fn with_derivative(self) -> SampleDerivativeWrapper<Self> {217SampleDerivativeWrapper(self)218}219}220221impl<T, C> CurveWithTwoDerivatives<T> for C222where223T: HasTangent,224C: SampleTwoDerivatives<T> + CurveWithDerivative<T>,225{226fn with_two_derivatives(self) -> SampleTwoDerivativesWrapper<Self> {227SampleTwoDerivativesWrapper(self)228}229}230231232