1use super::interval::*;
4use super::Curve;
5
6use crate::VectorSpace;
7use core::any::type_name;
8use core::fmt::{self, Debug};
9use core::marker::PhantomData;
10
11#[cfg(feature = "bevy_reflect")]
12use bevy_reflect::{utility::GenericTypePathCell, FromReflect, Reflect, TypePath};
13
14#[cfg(feature = "bevy_reflect")]
15mod paths {
16 pub(super) const THIS_MODULE: &str = "bevy_math::curve::adaptors";
17 pub(super) const THIS_CRATE: &str = "bevy_math";
18}
19
20#[derive(Clone, Copy, Debug)]
38#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
39#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]
40pub struct ConstantCurve<T> {
41 pub(crate) domain: Interval,
42 pub(crate) value: T,
43}
44
45impl<T> ConstantCurve<T>
46where
47 T: Clone,
48{
49 pub fn new(domain: Interval, value: T) -> Self {
52 Self { domain, value }
53 }
54}
55
56impl<T> Curve<T> for ConstantCurve<T>
57where
58 T: Clone,
59{
60 #[inline]
61 fn domain(&self) -> Interval {
62 self.domain
63 }
64
65 #[inline]
66 fn sample_unchecked(&self, _t: f32) -> T {
67 self.value.clone()
68 }
69}
70
71#[derive(Clone)]
76#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
77#[cfg_attr(
78 feature = "bevy_reflect",
79 derive(Reflect),
80 reflect(where T: TypePath),
81 reflect(from_reflect = false, type_path = false),
82)]
83pub struct FunctionCurve<T, F> {
84 pub(crate) domain: Interval,
85 #[cfg_attr(feature = "bevy_reflect", reflect(ignore))]
86 pub(crate) f: F,
87 #[cfg_attr(feature = "bevy_reflect", reflect(ignore))]
88 pub(crate) _phantom: PhantomData<fn() -> T>,
89}
90
91impl<T, F> Debug for FunctionCurve<T, F> {
92 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
93 f.debug_struct("FunctionCurve")
94 .field("domain", &self.domain)
95 .field("f", &type_name::<F>())
96 .finish()
97 }
98}
99
100#[cfg(feature = "bevy_reflect")]
103impl<T, F> TypePath for FunctionCurve<T, F>
104where
105 T: TypePath,
106 F: 'static,
107{
108 fn type_path() -> &'static str {
109 static CELL: GenericTypePathCell = GenericTypePathCell::new();
110 CELL.get_or_insert::<Self, _>(|| {
111 format!(
112 "{}::FunctionCurve<{},{}>",
113 paths::THIS_MODULE,
114 T::type_path(),
115 type_name::<F>()
116 )
117 })
118 }
119
120 fn short_type_path() -> &'static str {
121 static CELL: GenericTypePathCell = GenericTypePathCell::new();
122 CELL.get_or_insert::<Self, _>(|| {
123 format!(
124 "FunctionCurve<{},{}>",
125 T::short_type_path(),
126 type_name::<F>()
127 )
128 })
129 }
130
131 fn type_ident() -> Option<&'static str> {
132 Some("FunctionCurve")
133 }
134
135 fn crate_name() -> Option<&'static str> {
136 Some(paths::THIS_CRATE)
137 }
138
139 fn module_path() -> Option<&'static str> {
140 Some(paths::THIS_MODULE)
141 }
142}
143
144impl<T, F> FunctionCurve<T, F>
145where
146 F: Fn(f32) -> T,
147{
148 pub fn new(domain: Interval, function: F) -> Self {
151 FunctionCurve {
152 domain,
153 f: function,
154 _phantom: PhantomData,
155 }
156 }
157}
158
159impl<T, F> Curve<T> for FunctionCurve<T, F>
160where
161 F: Fn(f32) -> T,
162{
163 #[inline]
164 fn domain(&self) -> Interval {
165 self.domain
166 }
167
168 #[inline]
169 fn sample_unchecked(&self, t: f32) -> T {
170 (self.f)(t)
171 }
172}
173
174#[derive(Clone)]
177#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
178#[cfg_attr(
179 feature = "bevy_reflect",
180 derive(Reflect),
181 reflect(where S: TypePath, T: TypePath, C: TypePath),
182 reflect(from_reflect = false, type_path = false),
183)]
184pub struct MapCurve<S, T, C, F> {
185 pub(crate) preimage: C,
186 #[cfg_attr(feature = "bevy_reflect", reflect(ignore))]
187 pub(crate) f: F,
188 #[cfg_attr(feature = "bevy_reflect", reflect(ignore))]
189 pub(crate) _phantom: PhantomData<(fn() -> S, fn(S) -> T)>,
190}
191
192impl<S, T, C, F> Debug for MapCurve<S, T, C, F>
193where
194 C: Debug,
195{
196 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
197 f.debug_struct("MapCurve")
198 .field("preimage", &self.preimage)
199 .field("f", &type_name::<F>())
200 .finish()
201 }
202}
203
204#[cfg(feature = "bevy_reflect")]
207impl<S, T, C, F> TypePath for MapCurve<S, T, C, F>
208where
209 S: TypePath,
210 T: TypePath,
211 C: TypePath,
212 F: 'static,
213{
214 fn type_path() -> &'static str {
215 static CELL: GenericTypePathCell = GenericTypePathCell::new();
216 CELL.get_or_insert::<Self, _>(|| {
217 format!(
218 "{}::MapCurve<{},{},{},{}>",
219 paths::THIS_MODULE,
220 S::type_path(),
221 T::type_path(),
222 C::type_path(),
223 type_name::<F>()
224 )
225 })
226 }
227
228 fn short_type_path() -> &'static str {
229 static CELL: GenericTypePathCell = GenericTypePathCell::new();
230 CELL.get_or_insert::<Self, _>(|| {
231 format!(
232 "MapCurve<{},{},{},{}>",
233 S::type_path(),
234 T::type_path(),
235 C::type_path(),
236 type_name::<F>()
237 )
238 })
239 }
240
241 fn type_ident() -> Option<&'static str> {
242 Some("MapCurve")
243 }
244
245 fn crate_name() -> Option<&'static str> {
246 Some(paths::THIS_CRATE)
247 }
248
249 fn module_path() -> Option<&'static str> {
250 Some(paths::THIS_MODULE)
251 }
252}
253
254impl<S, T, C, F> Curve<T> for MapCurve<S, T, C, F>
255where
256 C: Curve<S>,
257 F: Fn(S) -> T,
258{
259 #[inline]
260 fn domain(&self) -> Interval {
261 self.preimage.domain()
262 }
263
264 #[inline]
265 fn sample_unchecked(&self, t: f32) -> T {
266 (self.f)(self.preimage.sample_unchecked(t))
267 }
268}
269
270#[derive(Clone)]
273#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
274#[cfg_attr(
275 feature = "bevy_reflect",
276 derive(Reflect),
277 reflect(where T: TypePath, C: TypePath),
278 reflect(from_reflect = false, type_path = false),
279)]
280pub struct ReparamCurve<T, C, F> {
281 pub(crate) domain: Interval,
282 pub(crate) base: C,
283 #[cfg_attr(feature = "bevy_reflect", reflect(ignore))]
284 pub(crate) f: F,
285 #[cfg_attr(feature = "bevy_reflect", reflect(ignore))]
286 pub(crate) _phantom: PhantomData<fn() -> T>,
287}
288
289impl<T, C, F> Debug for ReparamCurve<T, C, F>
290where
291 C: Debug,
292{
293 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
294 f.debug_struct("ReparamCurve")
295 .field("domain", &self.domain)
296 .field("base", &self.base)
297 .field("f", &type_name::<F>())
298 .finish()
299 }
300}
301
302#[cfg(feature = "bevy_reflect")]
305impl<T, C, F> TypePath for ReparamCurve<T, C, F>
306where
307 T: TypePath,
308 C: TypePath,
309 F: 'static,
310{
311 fn type_path() -> &'static str {
312 static CELL: GenericTypePathCell = GenericTypePathCell::new();
313 CELL.get_or_insert::<Self, _>(|| {
314 format!(
315 "{}::ReparamCurve<{},{},{}>",
316 paths::THIS_MODULE,
317 T::type_path(),
318 C::type_path(),
319 type_name::<F>()
320 )
321 })
322 }
323
324 fn short_type_path() -> &'static str {
325 static CELL: GenericTypePathCell = GenericTypePathCell::new();
326 CELL.get_or_insert::<Self, _>(|| {
327 format!(
328 "ReparamCurve<{},{},{}>",
329 T::type_path(),
330 C::type_path(),
331 type_name::<F>()
332 )
333 })
334 }
335
336 fn type_ident() -> Option<&'static str> {
337 Some("ReparamCurve")
338 }
339
340 fn crate_name() -> Option<&'static str> {
341 Some(paths::THIS_CRATE)
342 }
343
344 fn module_path() -> Option<&'static str> {
345 Some(paths::THIS_MODULE)
346 }
347}
348
349impl<T, C, F> Curve<T> for ReparamCurve<T, C, F>
350where
351 C: Curve<T>,
352 F: Fn(f32) -> f32,
353{
354 #[inline]
355 fn domain(&self) -> Interval {
356 self.domain
357 }
358
359 #[inline]
360 fn sample_unchecked(&self, t: f32) -> T {
361 self.base.sample_unchecked((self.f)(t))
362 }
363}
364
365#[derive(Clone, Debug)]
368#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
369#[cfg_attr(
370 feature = "bevy_reflect",
371 derive(Reflect, FromReflect),
372 reflect(from_reflect = false)
373)]
374pub struct LinearReparamCurve<T, C> {
375 pub(crate) base: C,
377 pub(crate) new_domain: Interval,
379 #[cfg_attr(feature = "bevy_reflect", reflect(ignore))]
380 pub(crate) _phantom: PhantomData<fn() -> T>,
381}
382
383impl<T, C> Curve<T> for LinearReparamCurve<T, C>
384where
385 C: Curve<T>,
386{
387 #[inline]
388 fn domain(&self) -> Interval {
389 self.new_domain
390 }
391
392 #[inline]
393 fn sample_unchecked(&self, t: f32) -> T {
394 let f = self.new_domain.linear_map_to(self.base.domain()).unwrap();
396 self.base.sample_unchecked(f(t))
397 }
398}
399
400#[derive(Clone, Debug)]
403#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
404#[cfg_attr(
405 feature = "bevy_reflect",
406 derive(Reflect, FromReflect),
407 reflect(from_reflect = false)
408)]
409pub struct CurveReparamCurve<T, C, D> {
410 pub(crate) base: C,
411 pub(crate) reparam_curve: D,
412 #[cfg_attr(feature = "bevy_reflect", reflect(ignore))]
413 pub(crate) _phantom: PhantomData<fn() -> T>,
414}
415
416impl<T, C, D> Curve<T> for CurveReparamCurve<T, C, D>
417where
418 C: Curve<T>,
419 D: Curve<f32>,
420{
421 #[inline]
422 fn domain(&self) -> Interval {
423 self.reparam_curve.domain()
424 }
425
426 #[inline]
427 fn sample_unchecked(&self, t: f32) -> T {
428 let sample_time = self.reparam_curve.sample_unchecked(t);
429 self.base.sample_unchecked(sample_time)
430 }
431}
432
433#[derive(Clone, Debug)]
436#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
437#[cfg_attr(
438 feature = "bevy_reflect",
439 derive(Reflect, FromReflect),
440 reflect(from_reflect = false)
441)]
442pub struct GraphCurve<T, C> {
443 pub(crate) base: C,
444 #[cfg_attr(feature = "bevy_reflect", reflect(ignore))]
445 pub(crate) _phantom: PhantomData<fn() -> T>,
446}
447
448impl<T, C> Curve<(f32, T)> for GraphCurve<T, C>
449where
450 C: Curve<T>,
451{
452 #[inline]
453 fn domain(&self) -> Interval {
454 self.base.domain()
455 }
456
457 #[inline]
458 fn sample_unchecked(&self, t: f32) -> (f32, T) {
459 (t, self.base.sample_unchecked(t))
460 }
461}
462
463#[derive(Clone, Debug)]
466#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
467#[cfg_attr(
468 feature = "bevy_reflect",
469 derive(Reflect, FromReflect),
470 reflect(from_reflect = false)
471)]
472pub struct ZipCurve<S, T, C, D> {
473 pub(crate) domain: Interval,
474 pub(crate) first: C,
475 pub(crate) second: D,
476 #[cfg_attr(feature = "bevy_reflect", reflect(ignore))]
477 pub(crate) _phantom: PhantomData<fn() -> (S, T)>,
478}
479
480impl<S, T, C, D> Curve<(S, T)> for ZipCurve<S, T, C, D>
481where
482 C: Curve<S>,
483 D: Curve<T>,
484{
485 #[inline]
486 fn domain(&self) -> Interval {
487 self.domain
488 }
489
490 #[inline]
491 fn sample_unchecked(&self, t: f32) -> (S, T) {
492 (
493 self.first.sample_unchecked(t),
494 self.second.sample_unchecked(t),
495 )
496 }
497}
498
499#[derive(Clone, Debug)]
507#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
508#[cfg_attr(
509 feature = "bevy_reflect",
510 derive(Reflect, FromReflect),
511 reflect(from_reflect = false)
512)]
513pub struct ChainCurve<T, C, D> {
514 pub(crate) first: C,
515 pub(crate) second: D,
516 #[cfg_attr(feature = "bevy_reflect", reflect(ignore))]
517 pub(crate) _phantom: PhantomData<fn() -> T>,
518}
519
520impl<T, C, D> Curve<T> for ChainCurve<T, C, D>
521where
522 C: Curve<T>,
523 D: Curve<T>,
524{
525 #[inline]
526 fn domain(&self) -> Interval {
527 Interval::new(
530 self.first.domain().start(),
531 self.first.domain().end() + self.second.domain().length(),
532 )
533 .unwrap()
534 }
535
536 #[inline]
537 fn sample_unchecked(&self, t: f32) -> T {
538 if t > self.first.domain().end() {
539 self.second.sample_unchecked(
540 t - self.first.domain().end() + self.second.domain().start(),
542 )
543 } else {
544 self.first.sample_unchecked(t)
545 }
546 }
547}
548
549#[derive(Clone, Debug)]
557#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
558#[cfg_attr(
559 feature = "bevy_reflect",
560 derive(Reflect, FromReflect),
561 reflect(from_reflect = false)
562)]
563pub struct ReverseCurve<T, C> {
564 pub(crate) curve: C,
565 #[cfg_attr(feature = "bevy_reflect", reflect(ignore))]
566 pub(crate) _phantom: PhantomData<fn() -> T>,
567}
568
569impl<T, C> Curve<T> for ReverseCurve<T, C>
570where
571 C: Curve<T>,
572{
573 #[inline]
574 fn domain(&self) -> Interval {
575 self.curve.domain()
576 }
577
578 #[inline]
579 fn sample_unchecked(&self, t: f32) -> T {
580 self.curve
581 .sample_unchecked(self.domain().end() - (t - self.domain().start()))
582 }
583}
584
585#[derive(Clone, Debug)]
598#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
599#[cfg_attr(
600 feature = "bevy_reflect",
601 derive(Reflect, FromReflect),
602 reflect(from_reflect = false)
603)]
604pub struct RepeatCurve<T, C> {
605 pub(crate) domain: Interval,
606 pub(crate) curve: C,
607 #[cfg_attr(feature = "bevy_reflect", reflect(ignore))]
608 pub(crate) _phantom: PhantomData<fn() -> T>,
609}
610
611impl<T, C> Curve<T> for RepeatCurve<T, C>
612where
613 C: Curve<T>,
614{
615 #[inline]
616 fn domain(&self) -> Interval {
617 self.domain
618 }
619
620 #[inline]
621 fn sample_unchecked(&self, t: f32) -> T {
622 let d = self.curve.domain();
624 let cyclic_t = (t - d.start()).rem_euclid(d.length());
625 let t = if t != d.start() && cyclic_t == 0.0 {
626 d.end()
627 } else {
628 d.start() + cyclic_t
629 };
630 self.curve.sample_unchecked(t)
631 }
632}
633
634#[derive(Clone, Debug)]
647#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
648#[cfg_attr(
649 feature = "bevy_reflect",
650 derive(Reflect, FromReflect),
651 reflect(from_reflect = false)
652)]
653pub struct ForeverCurve<T, C> {
654 pub(crate) curve: C,
655 #[cfg_attr(feature = "bevy_reflect", reflect(ignore))]
656 pub(crate) _phantom: PhantomData<fn() -> T>,
657}
658
659impl<T, C> Curve<T> for ForeverCurve<T, C>
660where
661 C: Curve<T>,
662{
663 #[inline]
664 fn domain(&self) -> Interval {
665 Interval::EVERYWHERE
666 }
667
668 #[inline]
669 fn sample_unchecked(&self, t: f32) -> T {
670 let d = self.curve.domain();
672 let cyclic_t = (t - d.start()).rem_euclid(d.length());
673 let t = if t != d.start() && cyclic_t == 0.0 {
674 d.end()
675 } else {
676 d.start() + cyclic_t
677 };
678 self.curve.sample_unchecked(t)
679 }
680}
681
682#[derive(Clone, Debug)]
691#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
692#[cfg_attr(
693 feature = "bevy_reflect",
694 derive(Reflect, FromReflect),
695 reflect(from_reflect = false)
696)]
697pub struct PingPongCurve<T, C> {
698 pub(crate) curve: C,
699 #[cfg_attr(feature = "bevy_reflect", reflect(ignore))]
700 pub(crate) _phantom: PhantomData<fn() -> T>,
701}
702
703impl<T, C> Curve<T> for PingPongCurve<T, C>
704where
705 C: Curve<T>,
706{
707 #[inline]
708 fn domain(&self) -> Interval {
709 Interval::new(
712 self.curve.domain().start(),
713 self.curve.domain().end() + self.curve.domain().length(),
714 )
715 .unwrap()
716 }
717
718 #[inline]
719 fn sample_unchecked(&self, t: f32) -> T {
720 let final_t = if t > self.curve.domain().end() {
722 self.curve.domain().end() * 2.0 - t
723 } else {
724 t
725 };
726 self.curve.sample_unchecked(final_t)
727 }
728}
729
730#[derive(Clone, Debug)]
745#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
746#[cfg_attr(
747 feature = "bevy_reflect",
748 derive(Reflect, FromReflect),
749 reflect(from_reflect = false)
750)]
751pub struct ContinuationCurve<T, C, D> {
752 pub(crate) first: C,
753 pub(crate) second: D,
754 pub(crate) offset: T,
756 #[cfg_attr(feature = "bevy_reflect", reflect(ignore))]
757 pub(crate) _phantom: PhantomData<fn() -> T>,
758}
759
760impl<T, C, D> Curve<T> for ContinuationCurve<T, C, D>
761where
762 T: VectorSpace,
763 C: Curve<T>,
764 D: Curve<T>,
765{
766 #[inline]
767 fn domain(&self) -> Interval {
768 Interval::new(
771 self.first.domain().start(),
772 self.first.domain().end() + self.second.domain().length(),
773 )
774 .unwrap()
775 }
776
777 #[inline]
778 fn sample_unchecked(&self, t: f32) -> T {
779 if t > self.first.domain().end() {
780 self.second.sample_unchecked(
781 t - self.first.domain().end() + self.second.domain().start(),
783 ) + self.offset
784 } else {
785 self.first.sample_unchecked(t)
786 }
787 }
788}