1use super::interval::*;
4use super::Curve;
5
6use crate::ops;
7use crate::VectorSpace;
8use core::any::type_name;
9use core::fmt::{self, Debug};
10use core::marker::PhantomData;
11
12#[cfg(feature = "bevy_reflect")]
13use {
14 alloc::format,
15 bevy_reflect::{utility::GenericTypePathCell, FromReflect, Reflect, TypePath},
16};
17
18#[cfg(feature = "bevy_reflect")]
19mod paths {
20 pub(super) const THIS_MODULE: &str = "bevy_math::curve::adaptors";
21 pub(super) const THIS_CRATE: &str = "bevy_math";
22}
23
24#[expect(unused, reason = "imported just for doc links")]
25use super::CurveExt;
26
27#[derive(Clone, Copy, Debug)]
45#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
46#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]
47pub struct ConstantCurve<T> {
48 pub(crate) domain: Interval,
49 pub(crate) value: T,
50}
51
52impl<T> ConstantCurve<T>
53where
54 T: Clone,
55{
56 pub fn new(domain: Interval, value: T) -> Self {
59 Self { domain, value }
60 }
61}
62
63impl<T> Curve<T> for ConstantCurve<T>
64where
65 T: Clone,
66{
67 #[inline]
68 fn domain(&self) -> Interval {
69 self.domain
70 }
71
72 #[inline]
73 fn sample_unchecked(&self, _t: f32) -> T {
74 self.value.clone()
75 }
76}
77
78#[derive(Clone)]
83#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
84#[cfg_attr(
85 feature = "bevy_reflect",
86 derive(Reflect),
87 reflect(where T: TypePath),
88 reflect(from_reflect = false, type_path = false),
89)]
90pub struct FunctionCurve<T, F> {
91 pub(crate) domain: Interval,
92 #[cfg_attr(feature = "bevy_reflect", reflect(ignore))]
93 pub(crate) f: F,
94 #[cfg_attr(feature = "serialize", serde(skip))]
95 #[cfg_attr(feature = "bevy_reflect", reflect(ignore, clone))]
96 pub(crate) _phantom: PhantomData<fn() -> T>,
97}
98
99impl<T, F> Debug for FunctionCurve<T, F> {
100 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
101 f.debug_struct("FunctionCurve")
102 .field("domain", &self.domain)
103 .field("f", &type_name::<F>())
104 .finish()
105 }
106}
107
108#[cfg(feature = "bevy_reflect")]
111impl<T, F> TypePath for FunctionCurve<T, F>
112where
113 T: TypePath,
114 F: 'static,
115{
116 fn type_path() -> &'static str {
117 static CELL: GenericTypePathCell = GenericTypePathCell::new();
118 CELL.get_or_insert::<Self, _>(|| {
119 format!(
120 "{}::FunctionCurve<{},{}>",
121 paths::THIS_MODULE,
122 T::type_path(),
123 type_name::<F>()
124 )
125 })
126 }
127
128 fn short_type_path() -> &'static str {
129 static CELL: GenericTypePathCell = GenericTypePathCell::new();
130 CELL.get_or_insert::<Self, _>(|| {
131 format!(
132 "FunctionCurve<{},{}>",
133 T::short_type_path(),
134 type_name::<F>()
135 )
136 })
137 }
138
139 fn type_ident() -> Option<&'static str> {
140 Some("FunctionCurve")
141 }
142
143 fn crate_name() -> Option<&'static str> {
144 Some(paths::THIS_CRATE)
145 }
146
147 fn module_path() -> Option<&'static str> {
148 Some(paths::THIS_MODULE)
149 }
150}
151
152impl<T, F> FunctionCurve<T, F>
153where
154 F: Fn(f32) -> T,
155{
156 pub fn new(domain: Interval, function: F) -> Self {
159 FunctionCurve {
160 domain,
161 f: function,
162 _phantom: PhantomData,
163 }
164 }
165}
166
167impl<T, F> Curve<T> for FunctionCurve<T, F>
168where
169 F: Fn(f32) -> T,
170{
171 #[inline]
172 fn domain(&self) -> Interval {
173 self.domain
174 }
175
176 #[inline]
177 fn sample_unchecked(&self, t: f32) -> T {
178 (self.f)(t)
179 }
180}
181
182#[derive(Clone)]
185#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
186#[cfg_attr(
187 feature = "bevy_reflect",
188 derive(Reflect),
189 reflect(where S: TypePath, T: TypePath, C: TypePath),
190 reflect(from_reflect = false, type_path = false),
191)]
192pub struct MapCurve<S, T, C, F> {
193 pub(crate) preimage: C,
194 #[cfg_attr(feature = "bevy_reflect", reflect(ignore))]
195 pub(crate) f: F,
196 #[cfg_attr(feature = "serialize", serde(skip))]
197 #[cfg_attr(feature = "bevy_reflect", reflect(ignore, clone))]
198 pub(crate) _phantom: PhantomData<(fn() -> S, fn(S) -> T)>,
199}
200
201impl<S, T, C, F> Debug for MapCurve<S, T, C, F>
202where
203 C: Debug,
204{
205 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
206 f.debug_struct("MapCurve")
207 .field("preimage", &self.preimage)
208 .field("f", &type_name::<F>())
209 .finish()
210 }
211}
212
213#[cfg(feature = "bevy_reflect")]
216impl<S, T, C, F> TypePath for MapCurve<S, T, C, F>
217where
218 S: TypePath,
219 T: TypePath,
220 C: TypePath,
221 F: 'static,
222{
223 fn type_path() -> &'static str {
224 static CELL: GenericTypePathCell = GenericTypePathCell::new();
225 CELL.get_or_insert::<Self, _>(|| {
226 format!(
227 "{}::MapCurve<{},{},{},{}>",
228 paths::THIS_MODULE,
229 S::type_path(),
230 T::type_path(),
231 C::type_path(),
232 type_name::<F>()
233 )
234 })
235 }
236
237 fn short_type_path() -> &'static str {
238 static CELL: GenericTypePathCell = GenericTypePathCell::new();
239 CELL.get_or_insert::<Self, _>(|| {
240 format!(
241 "MapCurve<{},{},{},{}>",
242 S::type_path(),
243 T::type_path(),
244 C::type_path(),
245 type_name::<F>()
246 )
247 })
248 }
249
250 fn type_ident() -> Option<&'static str> {
251 Some("MapCurve")
252 }
253
254 fn crate_name() -> Option<&'static str> {
255 Some(paths::THIS_CRATE)
256 }
257
258 fn module_path() -> Option<&'static str> {
259 Some(paths::THIS_MODULE)
260 }
261}
262
263impl<S, T, C, F> Curve<T> for MapCurve<S, T, C, F>
264where
265 C: Curve<S>,
266 F: Fn(S) -> T,
267{
268 #[inline]
269 fn domain(&self) -> Interval {
270 self.preimage.domain()
271 }
272
273 #[inline]
274 fn sample_unchecked(&self, t: f32) -> T {
275 (self.f)(self.preimage.sample_unchecked(t))
276 }
277}
278
279#[derive(Clone)]
282#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
283#[cfg_attr(
284 feature = "bevy_reflect",
285 derive(Reflect),
286 reflect(where T: TypePath, C: TypePath),
287 reflect(from_reflect = false, type_path = false),
288)]
289pub struct ReparamCurve<T, C, F> {
290 pub(crate) domain: Interval,
291 pub(crate) base: C,
292 #[cfg_attr(feature = "bevy_reflect", reflect(ignore))]
293 pub(crate) f: F,
294 #[cfg_attr(feature = "serialize", serde(skip))]
295 #[cfg_attr(feature = "bevy_reflect", reflect(ignore, clone))]
296 pub(crate) _phantom: PhantomData<fn() -> T>,
297}
298
299impl<T, C, F> Debug for ReparamCurve<T, C, F>
300where
301 C: Debug,
302{
303 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
304 f.debug_struct("ReparamCurve")
305 .field("domain", &self.domain)
306 .field("base", &self.base)
307 .field("f", &type_name::<F>())
308 .finish()
309 }
310}
311
312#[cfg(feature = "bevy_reflect")]
315impl<T, C, F> TypePath for ReparamCurve<T, C, F>
316where
317 T: TypePath,
318 C: TypePath,
319 F: 'static,
320{
321 fn type_path() -> &'static str {
322 static CELL: GenericTypePathCell = GenericTypePathCell::new();
323 CELL.get_or_insert::<Self, _>(|| {
324 format!(
325 "{}::ReparamCurve<{},{},{}>",
326 paths::THIS_MODULE,
327 T::type_path(),
328 C::type_path(),
329 type_name::<F>()
330 )
331 })
332 }
333
334 fn short_type_path() -> &'static str {
335 static CELL: GenericTypePathCell = GenericTypePathCell::new();
336 CELL.get_or_insert::<Self, _>(|| {
337 format!(
338 "ReparamCurve<{},{},{}>",
339 T::type_path(),
340 C::type_path(),
341 type_name::<F>()
342 )
343 })
344 }
345
346 fn type_ident() -> Option<&'static str> {
347 Some("ReparamCurve")
348 }
349
350 fn crate_name() -> Option<&'static str> {
351 Some(paths::THIS_CRATE)
352 }
353
354 fn module_path() -> Option<&'static str> {
355 Some(paths::THIS_MODULE)
356 }
357}
358
359impl<T, C, F> Curve<T> for ReparamCurve<T, C, F>
360where
361 C: Curve<T>,
362 F: Fn(f32) -> f32,
363{
364 #[inline]
365 fn domain(&self) -> Interval {
366 self.domain
367 }
368
369 #[inline]
370 fn sample_unchecked(&self, t: f32) -> T {
371 self.base.sample_unchecked((self.f)(t))
372 }
373}
374
375#[derive(Clone, Debug)]
378#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
379#[cfg_attr(
380 feature = "bevy_reflect",
381 derive(Reflect, FromReflect),
382 reflect(from_reflect = false)
383)]
384pub struct LinearReparamCurve<T, C> {
385 pub(crate) base: C,
387 pub(crate) new_domain: Interval,
389 #[cfg_attr(feature = "serialize", serde(skip))]
390 #[cfg_attr(feature = "bevy_reflect", reflect(ignore, clone))]
391 pub(crate) _phantom: PhantomData<fn() -> T>,
392}
393
394impl<T, C> Curve<T> for LinearReparamCurve<T, C>
395where
396 C: Curve<T>,
397{
398 #[inline]
399 fn domain(&self) -> Interval {
400 self.new_domain
401 }
402
403 #[inline]
404 fn sample_unchecked(&self, t: f32) -> T {
405 let f = self.new_domain.linear_map_to(self.base.domain()).unwrap();
407 self.base.sample_unchecked(f(t))
408 }
409}
410
411#[derive(Clone, Debug)]
414#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
415#[cfg_attr(
416 feature = "bevy_reflect",
417 derive(Reflect, FromReflect),
418 reflect(from_reflect = false)
419)]
420pub struct CurveReparamCurve<T, C, D> {
421 pub(crate) base: C,
422 pub(crate) reparam_curve: D,
423 #[cfg_attr(feature = "serialize", serde(skip))]
424 #[cfg_attr(feature = "bevy_reflect", reflect(ignore, clone))]
425 pub(crate) _phantom: PhantomData<fn() -> T>,
426}
427
428impl<T, C, D> Curve<T> for CurveReparamCurve<T, C, D>
429where
430 C: Curve<T>,
431 D: Curve<f32>,
432{
433 #[inline]
434 fn domain(&self) -> Interval {
435 self.reparam_curve.domain()
436 }
437
438 #[inline]
439 fn sample_unchecked(&self, t: f32) -> T {
440 let sample_time = self.reparam_curve.sample_unchecked(t);
441 self.base.sample_unchecked(sample_time)
442 }
443}
444
445#[derive(Clone, Debug)]
448#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
449#[cfg_attr(
450 feature = "bevy_reflect",
451 derive(Reflect, FromReflect),
452 reflect(from_reflect = false)
453)]
454pub struct GraphCurve<T, C> {
455 pub(crate) base: C,
456 #[cfg_attr(feature = "serialize", serde(skip))]
457 #[cfg_attr(feature = "bevy_reflect", reflect(ignore, clone))]
458 pub(crate) _phantom: PhantomData<fn() -> T>,
459}
460
461impl<T, C> Curve<(f32, T)> for GraphCurve<T, C>
462where
463 C: Curve<T>,
464{
465 #[inline]
466 fn domain(&self) -> Interval {
467 self.base.domain()
468 }
469
470 #[inline]
471 fn sample_unchecked(&self, t: f32) -> (f32, T) {
472 (t, self.base.sample_unchecked(t))
473 }
474}
475
476#[derive(Clone, Debug)]
479#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
480#[cfg_attr(
481 feature = "bevy_reflect",
482 derive(Reflect, FromReflect),
483 reflect(from_reflect = false)
484)]
485pub struct ZipCurve<S, T, C, D> {
486 pub(crate) domain: Interval,
487 pub(crate) first: C,
488 pub(crate) second: D,
489 #[cfg_attr(feature = "serialize", serde(skip))]
490 #[cfg_attr(feature = "bevy_reflect", reflect(ignore, clone))]
491 pub(crate) _phantom: PhantomData<fn() -> (S, T)>,
492}
493
494impl<S, T, C, D> Curve<(S, T)> for ZipCurve<S, T, C, D>
495where
496 C: Curve<S>,
497 D: Curve<T>,
498{
499 #[inline]
500 fn domain(&self) -> Interval {
501 self.domain
502 }
503
504 #[inline]
505 fn sample_unchecked(&self, t: f32) -> (S, T) {
506 (
507 self.first.sample_unchecked(t),
508 self.second.sample_unchecked(t),
509 )
510 }
511}
512
513#[derive(Clone, Debug)]
521#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
522#[cfg_attr(
523 feature = "bevy_reflect",
524 derive(Reflect, FromReflect),
525 reflect(from_reflect = false)
526)]
527pub struct ChainCurve<T, C, D> {
528 pub(crate) first: C,
529 pub(crate) second: D,
530 #[cfg_attr(feature = "serialize", serde(skip))]
531 #[cfg_attr(feature = "bevy_reflect", reflect(ignore, clone))]
532 pub(crate) _phantom: PhantomData<fn() -> T>,
533}
534
535impl<T, C, D> Curve<T> for ChainCurve<T, C, D>
536where
537 C: Curve<T>,
538 D: Curve<T>,
539{
540 #[inline]
541 fn domain(&self) -> Interval {
542 Interval::new(
545 self.first.domain().start(),
546 self.first.domain().end() + self.second.domain().length(),
547 )
548 .unwrap()
549 }
550
551 #[inline]
552 fn sample_unchecked(&self, t: f32) -> T {
553 if t > self.first.domain().end() {
554 self.second.sample_unchecked(
555 t - self.first.domain().end() + self.second.domain().start(),
557 )
558 } else {
559 self.first.sample_unchecked(t)
560 }
561 }
562}
563
564#[derive(Clone, Debug)]
572#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
573#[cfg_attr(
574 feature = "bevy_reflect",
575 derive(Reflect, FromReflect),
576 reflect(from_reflect = false)
577)]
578pub struct ReverseCurve<T, C> {
579 pub(crate) curve: C,
580 #[cfg_attr(feature = "serialize", serde(skip))]
581 #[cfg_attr(feature = "bevy_reflect", reflect(ignore, clone))]
582 pub(crate) _phantom: PhantomData<fn() -> T>,
583}
584
585impl<T, C> Curve<T> for ReverseCurve<T, C>
586where
587 C: Curve<T>,
588{
589 #[inline]
590 fn domain(&self) -> Interval {
591 self.curve.domain()
592 }
593
594 #[inline]
595 fn sample_unchecked(&self, t: f32) -> T {
596 self.curve
597 .sample_unchecked(self.domain().end() - (t - self.domain().start()))
598 }
599}
600
601#[derive(Clone, Debug)]
614#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
615#[cfg_attr(
616 feature = "bevy_reflect",
617 derive(Reflect, FromReflect),
618 reflect(from_reflect = false)
619)]
620pub struct RepeatCurve<T, C> {
621 pub(crate) domain: Interval,
622 pub(crate) curve: C,
623 #[cfg_attr(feature = "serialize", serde(skip))]
624 #[cfg_attr(feature = "bevy_reflect", reflect(ignore, clone))]
625 pub(crate) _phantom: PhantomData<fn() -> T>,
626}
627
628impl<T, C> Curve<T> for RepeatCurve<T, C>
629where
630 C: Curve<T>,
631{
632 #[inline]
633 fn domain(&self) -> Interval {
634 self.domain
635 }
636
637 #[inline]
638 fn sample_unchecked(&self, t: f32) -> T {
639 let t = self.base_curve_sample_time(t);
640 self.curve.sample_unchecked(t)
641 }
642}
643
644impl<T, C> RepeatCurve<T, C>
645where
646 C: Curve<T>,
647{
648 #[inline]
649 pub(crate) fn base_curve_sample_time(&self, t: f32) -> f32 {
650 let d = self.curve.domain();
652 let cyclic_t = ops::rem_euclid(t - d.start(), d.length());
653 if t != d.start() && cyclic_t == 0.0 {
654 d.end()
655 } else {
656 d.start() + cyclic_t
657 }
658 }
659}
660
661#[derive(Clone, Debug)]
674#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
675#[cfg_attr(
676 feature = "bevy_reflect",
677 derive(Reflect, FromReflect),
678 reflect(from_reflect = false)
679)]
680pub struct ForeverCurve<T, C> {
681 pub(crate) curve: C,
682 #[cfg_attr(feature = "serialize", serde(skip))]
683 #[cfg_attr(feature = "bevy_reflect", reflect(ignore, clone))]
684 pub(crate) _phantom: PhantomData<fn() -> T>,
685}
686
687impl<T, C> Curve<T> for ForeverCurve<T, C>
688where
689 C: Curve<T>,
690{
691 #[inline]
692 fn domain(&self) -> Interval {
693 Interval::EVERYWHERE
694 }
695
696 #[inline]
697 fn sample_unchecked(&self, t: f32) -> T {
698 let t = self.base_curve_sample_time(t);
699 self.curve.sample_unchecked(t)
700 }
701}
702
703impl<T, C> ForeverCurve<T, C>
704where
705 C: Curve<T>,
706{
707 #[inline]
708 pub(crate) fn base_curve_sample_time(&self, t: f32) -> f32 {
709 let d = self.curve.domain();
711 let cyclic_t = ops::rem_euclid(t - d.start(), d.length());
712 if t != d.start() && cyclic_t == 0.0 {
713 d.end()
714 } else {
715 d.start() + cyclic_t
716 }
717 }
718}
719
720#[derive(Clone, Debug)]
729#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
730#[cfg_attr(
731 feature = "bevy_reflect",
732 derive(Reflect, FromReflect),
733 reflect(from_reflect = false)
734)]
735pub struct PingPongCurve<T, C> {
736 pub(crate) curve: C,
737 #[cfg_attr(feature = "serialize", serde(skip))]
738 #[cfg_attr(feature = "bevy_reflect", reflect(ignore, clone))]
739 pub(crate) _phantom: PhantomData<fn() -> T>,
740}
741
742impl<T, C> Curve<T> for PingPongCurve<T, C>
743where
744 C: Curve<T>,
745{
746 #[inline]
747 fn domain(&self) -> Interval {
748 Interval::new(
751 self.curve.domain().start(),
752 self.curve.domain().end() + self.curve.domain().length(),
753 )
754 .unwrap()
755 }
756
757 #[inline]
758 fn sample_unchecked(&self, t: f32) -> T {
759 let final_t = if t > self.curve.domain().end() {
761 self.curve.domain().end() * 2.0 - t
762 } else {
763 t
764 };
765 self.curve.sample_unchecked(final_t)
766 }
767}
768
769#[derive(Clone, Debug)]
784#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
785#[cfg_attr(
786 feature = "bevy_reflect",
787 derive(Reflect, FromReflect),
788 reflect(from_reflect = false)
789)]
790pub struct ContinuationCurve<T, C, D> {
791 pub(crate) first: C,
792 pub(crate) second: D,
793 pub(crate) offset: T,
795 #[cfg_attr(feature = "serialize", serde(skip))]
796 #[cfg_attr(feature = "bevy_reflect", reflect(ignore, clone))]
797 pub(crate) _phantom: PhantomData<fn() -> T>,
798}
799
800impl<T, C, D> Curve<T> for ContinuationCurve<T, C, D>
801where
802 T: VectorSpace,
803 C: Curve<T>,
804 D: Curve<T>,
805{
806 #[inline]
807 fn domain(&self) -> Interval {
808 Interval::new(
811 self.first.domain().start(),
812 self.first.domain().end() + self.second.domain().length(),
813 )
814 .unwrap()
815 }
816
817 #[inline]
818 fn sample_unchecked(&self, t: f32) -> T {
819 if t > self.first.domain().end() {
820 self.second.sample_unchecked(
821 t - self.first.domain().end() + self.second.domain().start(),
823 ) + self.offset
824 } else {
825 self.first.sample_unchecked(t)
826 }
827 }
828}