use super::interval::*;
use super::Curve;
use crate::VectorSpace;
use core::any::type_name;
use core::fmt::{self, Debug};
use core::marker::PhantomData;
#[cfg(feature = "bevy_reflect")]
use bevy_reflect::{utility::GenericTypePathCell, FromReflect, Reflect, TypePath};
#[cfg(feature = "bevy_reflect")]
mod paths {
pub(super) const THIS_MODULE: &str = "bevy_math::curve::adaptors";
pub(super) const THIS_CRATE: &str = "bevy_math";
}
#[derive(Clone, Copy, Debug)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]
pub struct ConstantCurve<T> {
pub(crate) domain: Interval,
pub(crate) value: T,
}
impl<T> ConstantCurve<T>
where
T: Clone,
{
pub fn new(domain: Interval, value: T) -> Self {
Self { domain, value }
}
}
impl<T> Curve<T> for ConstantCurve<T>
where
T: Clone,
{
#[inline]
fn domain(&self) -> Interval {
self.domain
}
#[inline]
fn sample_unchecked(&self, _t: f32) -> T {
self.value.clone()
}
}
#[derive(Clone)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(
feature = "bevy_reflect",
derive(Reflect),
reflect(where T: TypePath),
reflect(from_reflect = false, type_path = false),
)]
pub struct FunctionCurve<T, F> {
pub(crate) domain: Interval,
#[cfg_attr(feature = "bevy_reflect", reflect(ignore))]
pub(crate) f: F,
#[cfg_attr(feature = "bevy_reflect", reflect(ignore))]
pub(crate) _phantom: PhantomData<fn() -> T>,
}
impl<T, F> Debug for FunctionCurve<T, F> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("FunctionCurve")
.field("domain", &self.domain)
.field("f", &type_name::<F>())
.finish()
}
}
#[cfg(feature = "bevy_reflect")]
impl<T, F> TypePath for FunctionCurve<T, F>
where
T: TypePath,
F: 'static,
{
fn type_path() -> &'static str {
static CELL: GenericTypePathCell = GenericTypePathCell::new();
CELL.get_or_insert::<Self, _>(|| {
format!(
"{}::FunctionCurve<{},{}>",
paths::THIS_MODULE,
T::type_path(),
type_name::<F>()
)
})
}
fn short_type_path() -> &'static str {
static CELL: GenericTypePathCell = GenericTypePathCell::new();
CELL.get_or_insert::<Self, _>(|| {
format!(
"FunctionCurve<{},{}>",
T::short_type_path(),
type_name::<F>()
)
})
}
fn type_ident() -> Option<&'static str> {
Some("FunctionCurve")
}
fn crate_name() -> Option<&'static str> {
Some(paths::THIS_CRATE)
}
fn module_path() -> Option<&'static str> {
Some(paths::THIS_MODULE)
}
}
impl<T, F> FunctionCurve<T, F>
where
F: Fn(f32) -> T,
{
pub fn new(domain: Interval, function: F) -> Self {
FunctionCurve {
domain,
f: function,
_phantom: PhantomData,
}
}
}
impl<T, F> Curve<T> for FunctionCurve<T, F>
where
F: Fn(f32) -> T,
{
#[inline]
fn domain(&self) -> Interval {
self.domain
}
#[inline]
fn sample_unchecked(&self, t: f32) -> T {
(self.f)(t)
}
}
#[derive(Clone)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(
feature = "bevy_reflect",
derive(Reflect),
reflect(where S: TypePath, T: TypePath, C: TypePath),
reflect(from_reflect = false, type_path = false),
)]
pub struct MapCurve<S, T, C, F> {
pub(crate) preimage: C,
#[cfg_attr(feature = "bevy_reflect", reflect(ignore))]
pub(crate) f: F,
#[cfg_attr(feature = "bevy_reflect", reflect(ignore))]
pub(crate) _phantom: PhantomData<(fn() -> S, fn(S) -> T)>,
}
impl<S, T, C, F> Debug for MapCurve<S, T, C, F>
where
C: Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("MapCurve")
.field("preimage", &self.preimage)
.field("f", &type_name::<F>())
.finish()
}
}
#[cfg(feature = "bevy_reflect")]
impl<S, T, C, F> TypePath for MapCurve<S, T, C, F>
where
S: TypePath,
T: TypePath,
C: TypePath,
F: 'static,
{
fn type_path() -> &'static str {
static CELL: GenericTypePathCell = GenericTypePathCell::new();
CELL.get_or_insert::<Self, _>(|| {
format!(
"{}::MapCurve<{},{},{},{}>",
paths::THIS_MODULE,
S::type_path(),
T::type_path(),
C::type_path(),
type_name::<F>()
)
})
}
fn short_type_path() -> &'static str {
static CELL: GenericTypePathCell = GenericTypePathCell::new();
CELL.get_or_insert::<Self, _>(|| {
format!(
"MapCurve<{},{},{},{}>",
S::type_path(),
T::type_path(),
C::type_path(),
type_name::<F>()
)
})
}
fn type_ident() -> Option<&'static str> {
Some("MapCurve")
}
fn crate_name() -> Option<&'static str> {
Some(paths::THIS_CRATE)
}
fn module_path() -> Option<&'static str> {
Some(paths::THIS_MODULE)
}
}
impl<S, T, C, F> Curve<T> for MapCurve<S, T, C, F>
where
C: Curve<S>,
F: Fn(S) -> T,
{
#[inline]
fn domain(&self) -> Interval {
self.preimage.domain()
}
#[inline]
fn sample_unchecked(&self, t: f32) -> T {
(self.f)(self.preimage.sample_unchecked(t))
}
}
#[derive(Clone)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(
feature = "bevy_reflect",
derive(Reflect),
reflect(where T: TypePath, C: TypePath),
reflect(from_reflect = false, type_path = false),
)]
pub struct ReparamCurve<T, C, F> {
pub(crate) domain: Interval,
pub(crate) base: C,
#[cfg_attr(feature = "bevy_reflect", reflect(ignore))]
pub(crate) f: F,
#[cfg_attr(feature = "bevy_reflect", reflect(ignore))]
pub(crate) _phantom: PhantomData<fn() -> T>,
}
impl<T, C, F> Debug for ReparamCurve<T, C, F>
where
C: Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ReparamCurve")
.field("domain", &self.domain)
.field("base", &self.base)
.field("f", &type_name::<F>())
.finish()
}
}
#[cfg(feature = "bevy_reflect")]
impl<T, C, F> TypePath for ReparamCurve<T, C, F>
where
T: TypePath,
C: TypePath,
F: 'static,
{
fn type_path() -> &'static str {
static CELL: GenericTypePathCell = GenericTypePathCell::new();
CELL.get_or_insert::<Self, _>(|| {
format!(
"{}::ReparamCurve<{},{},{}>",
paths::THIS_MODULE,
T::type_path(),
C::type_path(),
type_name::<F>()
)
})
}
fn short_type_path() -> &'static str {
static CELL: GenericTypePathCell = GenericTypePathCell::new();
CELL.get_or_insert::<Self, _>(|| {
format!(
"ReparamCurve<{},{},{}>",
T::type_path(),
C::type_path(),
type_name::<F>()
)
})
}
fn type_ident() -> Option<&'static str> {
Some("ReparamCurve")
}
fn crate_name() -> Option<&'static str> {
Some(paths::THIS_CRATE)
}
fn module_path() -> Option<&'static str> {
Some(paths::THIS_MODULE)
}
}
impl<T, C, F> Curve<T> for ReparamCurve<T, C, F>
where
C: Curve<T>,
F: Fn(f32) -> f32,
{
#[inline]
fn domain(&self) -> Interval {
self.domain
}
#[inline]
fn sample_unchecked(&self, t: f32) -> T {
self.base.sample_unchecked((self.f)(t))
}
}
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(
feature = "bevy_reflect",
derive(Reflect, FromReflect),
reflect(from_reflect = false)
)]
pub struct LinearReparamCurve<T, C> {
pub(crate) base: C,
pub(crate) new_domain: Interval,
#[cfg_attr(feature = "bevy_reflect", reflect(ignore))]
pub(crate) _phantom: PhantomData<fn() -> T>,
}
impl<T, C> Curve<T> for LinearReparamCurve<T, C>
where
C: Curve<T>,
{
#[inline]
fn domain(&self) -> Interval {
self.new_domain
}
#[inline]
fn sample_unchecked(&self, t: f32) -> T {
let f = self.new_domain.linear_map_to(self.base.domain()).unwrap();
self.base.sample_unchecked(f(t))
}
}
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(
feature = "bevy_reflect",
derive(Reflect, FromReflect),
reflect(from_reflect = false)
)]
pub struct CurveReparamCurve<T, C, D> {
pub(crate) base: C,
pub(crate) reparam_curve: D,
#[cfg_attr(feature = "bevy_reflect", reflect(ignore))]
pub(crate) _phantom: PhantomData<fn() -> T>,
}
impl<T, C, D> Curve<T> for CurveReparamCurve<T, C, D>
where
C: Curve<T>,
D: Curve<f32>,
{
#[inline]
fn domain(&self) -> Interval {
self.reparam_curve.domain()
}
#[inline]
fn sample_unchecked(&self, t: f32) -> T {
let sample_time = self.reparam_curve.sample_unchecked(t);
self.base.sample_unchecked(sample_time)
}
}
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(
feature = "bevy_reflect",
derive(Reflect, FromReflect),
reflect(from_reflect = false)
)]
pub struct GraphCurve<T, C> {
pub(crate) base: C,
#[cfg_attr(feature = "bevy_reflect", reflect(ignore))]
pub(crate) _phantom: PhantomData<fn() -> T>,
}
impl<T, C> Curve<(f32, T)> for GraphCurve<T, C>
where
C: Curve<T>,
{
#[inline]
fn domain(&self) -> Interval {
self.base.domain()
}
#[inline]
fn sample_unchecked(&self, t: f32) -> (f32, T) {
(t, self.base.sample_unchecked(t))
}
}
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(
feature = "bevy_reflect",
derive(Reflect, FromReflect),
reflect(from_reflect = false)
)]
pub struct ZipCurve<S, T, C, D> {
pub(crate) domain: Interval,
pub(crate) first: C,
pub(crate) second: D,
#[cfg_attr(feature = "bevy_reflect", reflect(ignore))]
pub(crate) _phantom: PhantomData<fn() -> (S, T)>,
}
impl<S, T, C, D> Curve<(S, T)> for ZipCurve<S, T, C, D>
where
C: Curve<S>,
D: Curve<T>,
{
#[inline]
fn domain(&self) -> Interval {
self.domain
}
#[inline]
fn sample_unchecked(&self, t: f32) -> (S, T) {
(
self.first.sample_unchecked(t),
self.second.sample_unchecked(t),
)
}
}
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(
feature = "bevy_reflect",
derive(Reflect, FromReflect),
reflect(from_reflect = false)
)]
pub struct ChainCurve<T, C, D> {
pub(crate) first: C,
pub(crate) second: D,
#[cfg_attr(feature = "bevy_reflect", reflect(ignore))]
pub(crate) _phantom: PhantomData<fn() -> T>,
}
impl<T, C, D> Curve<T> for ChainCurve<T, C, D>
where
C: Curve<T>,
D: Curve<T>,
{
#[inline]
fn domain(&self) -> Interval {
Interval::new(
self.first.domain().start(),
self.first.domain().end() + self.second.domain().length(),
)
.unwrap()
}
#[inline]
fn sample_unchecked(&self, t: f32) -> T {
if t > self.first.domain().end() {
self.second.sample_unchecked(
t - self.first.domain().end() + self.second.domain().start(),
)
} else {
self.first.sample_unchecked(t)
}
}
}
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(
feature = "bevy_reflect",
derive(Reflect, FromReflect),
reflect(from_reflect = false)
)]
pub struct ReverseCurve<T, C> {
pub(crate) curve: C,
#[cfg_attr(feature = "bevy_reflect", reflect(ignore))]
pub(crate) _phantom: PhantomData<fn() -> T>,
}
impl<T, C> Curve<T> for ReverseCurve<T, C>
where
C: Curve<T>,
{
#[inline]
fn domain(&self) -> Interval {
self.curve.domain()
}
#[inline]
fn sample_unchecked(&self, t: f32) -> T {
self.curve
.sample_unchecked(self.domain().end() - (t - self.domain().start()))
}
}
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(
feature = "bevy_reflect",
derive(Reflect, FromReflect),
reflect(from_reflect = false)
)]
pub struct RepeatCurve<T, C> {
pub(crate) domain: Interval,
pub(crate) curve: C,
#[cfg_attr(feature = "bevy_reflect", reflect(ignore))]
pub(crate) _phantom: PhantomData<fn() -> T>,
}
impl<T, C> Curve<T> for RepeatCurve<T, C>
where
C: Curve<T>,
{
#[inline]
fn domain(&self) -> Interval {
self.domain
}
#[inline]
fn sample_unchecked(&self, t: f32) -> T {
let d = self.curve.domain();
let cyclic_t = (t - d.start()).rem_euclid(d.length());
let t = if t != d.start() && cyclic_t == 0.0 {
d.end()
} else {
d.start() + cyclic_t
};
self.curve.sample_unchecked(t)
}
}
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(
feature = "bevy_reflect",
derive(Reflect, FromReflect),
reflect(from_reflect = false)
)]
pub struct ForeverCurve<T, C> {
pub(crate) curve: C,
#[cfg_attr(feature = "bevy_reflect", reflect(ignore))]
pub(crate) _phantom: PhantomData<fn() -> T>,
}
impl<T, C> Curve<T> for ForeverCurve<T, C>
where
C: Curve<T>,
{
#[inline]
fn domain(&self) -> Interval {
Interval::EVERYWHERE
}
#[inline]
fn sample_unchecked(&self, t: f32) -> T {
let d = self.curve.domain();
let cyclic_t = (t - d.start()).rem_euclid(d.length());
let t = if t != d.start() && cyclic_t == 0.0 {
d.end()
} else {
d.start() + cyclic_t
};
self.curve.sample_unchecked(t)
}
}
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(
feature = "bevy_reflect",
derive(Reflect, FromReflect),
reflect(from_reflect = false)
)]
pub struct PingPongCurve<T, C> {
pub(crate) curve: C,
#[cfg_attr(feature = "bevy_reflect", reflect(ignore))]
pub(crate) _phantom: PhantomData<fn() -> T>,
}
impl<T, C> Curve<T> for PingPongCurve<T, C>
where
C: Curve<T>,
{
#[inline]
fn domain(&self) -> Interval {
Interval::new(
self.curve.domain().start(),
self.curve.domain().end() + self.curve.domain().length(),
)
.unwrap()
}
#[inline]
fn sample_unchecked(&self, t: f32) -> T {
let final_t = if t > self.curve.domain().end() {
self.curve.domain().end() * 2.0 - t
} else {
t
};
self.curve.sample_unchecked(final_t)
}
}
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(
feature = "bevy_reflect",
derive(Reflect, FromReflect),
reflect(from_reflect = false)
)]
pub struct ContinuationCurve<T, C, D> {
pub(crate) first: C,
pub(crate) second: D,
pub(crate) offset: T,
#[cfg_attr(feature = "bevy_reflect", reflect(ignore))]
pub(crate) _phantom: PhantomData<fn() -> T>,
}
impl<T, C, D> Curve<T> for ContinuationCurve<T, C, D>
where
T: VectorSpace,
C: Curve<T>,
D: Curve<T>,
{
#[inline]
fn domain(&self) -> Interval {
Interval::new(
self.first.domain().start(),
self.first.domain().end() + self.second.domain().length(),
)
.unwrap()
}
#[inline]
fn sample_unchecked(&self, t: f32) -> T {
if t > self.first.domain().end() {
self.second.sample_unchecked(
t - self.first.domain().end() + self.second.domain().start(),
) + self.offset
} else {
self.first.sample_unchecked(t)
}
}
}