bevy_gizmos/
curves.rs

1//! Additional [`GizmoBuffer`] Functions -- Curves
2//!
3//! Includes the implementation of [`GizmoBuffer::curve_2d`],
4//! [`GizmoBuffer::curve_3d`] and assorted support items.
5
6use bevy_color::Color;
7use bevy_math::{
8    curve::{Curve, CurveExt},
9    Vec2, Vec3,
10};
11
12use crate::{gizmos::GizmoBuffer, prelude::GizmoConfigGroup};
13
14impl<Config, Clear> GizmoBuffer<Config, Clear>
15where
16    Config: GizmoConfigGroup,
17    Clear: 'static + Send + Sync,
18{
19    /// Draw a curve, at the given time points, sampling in 2D.
20    ///
21    /// This should be called for each frame the curve needs to be rendered.
22    ///
23    /// Samples of time points outside of the curve's domain will be filtered out and won't
24    /// contribute to the rendering. If you wish to render the curve outside of its domain you need
25    /// to create a new curve with an extended domain.
26    ///
27    /// # Arguments
28    /// - `curve_2d` some type that implements the [`Curve`] trait and samples `Vec2`s
29    /// - `times` some iterable type yielding `f32` which will be used for sampling the curve
30    /// - `color` the color of the curve
31    ///
32    /// # Example
33    /// ```
34    /// # use bevy_gizmos::prelude::*;
35    /// # use bevy_math::prelude::*;
36    /// # use bevy_color::palettes::basic::{RED};
37    /// fn system(mut gizmos: Gizmos) {
38    ///     let domain = Interval::UNIT;
39    ///     let curve = FunctionCurve::new(domain, |t| Vec2::from(t.sin_cos()));
40    ///     gizmos.curve_2d(curve, (0..=100).map(|n| n as f32 / 100.0), RED);
41    /// }
42    /// # bevy_ecs::system::assert_is_system(system);
43    /// ```
44    pub fn curve_2d(
45        &mut self,
46        curve_2d: impl Curve<Vec2>,
47        times: impl IntoIterator<Item = f32>,
48        color: impl Into<Color>,
49    ) {
50        self.linestrip_2d(curve_2d.sample_iter(times).flatten(), color);
51    }
52
53    /// Draw a curve, at the given time points, sampling in 3D.
54    ///
55    /// This should be called for each frame the curve needs to be rendered.
56    ///
57    /// Samples of time points outside of the curve's domain will be filtered out and won't
58    /// contribute to the rendering. If you wish to render the curve outside of its domain you need
59    /// to create a new curve with an extended domain.
60    ///
61    /// # Arguments
62    /// - `curve_3d` some type that implements the [`Curve`] trait and samples `Vec3`s
63    /// - `times` some iterable type yielding `f32` which will be used for sampling the curve
64    /// - `color` the color of the curve
65    ///
66    /// # Example
67    /// ```
68    /// # use bevy_gizmos::prelude::*;
69    /// # use bevy_math::prelude::*;
70    /// # use bevy_color::palettes::basic::{RED};
71    /// fn system(mut gizmos: Gizmos) {
72    ///     let domain = Interval::UNIT;
73    ///     let curve = FunctionCurve::new(domain, |t| {
74    ///         let (x,y) = t.sin_cos();
75    ///         Vec3::new(x, y, t)
76    ///     });
77    ///     gizmos.curve_3d(curve, (0..=100).map(|n| n as f32 / 100.0), RED);
78    /// }
79    /// # bevy_ecs::system::assert_is_system(system);
80    /// ```
81    pub fn curve_3d(
82        &mut self,
83        curve_3d: impl Curve<Vec3>,
84        times: impl IntoIterator<Item = f32>,
85        color: impl Into<Color>,
86    ) {
87        self.linestrip(curve_3d.sample_iter(times).flatten(), color);
88    }
89
90    /// Draw a curve, at the given time points, sampling in 2D, with a color gradient.
91    ///
92    /// This should be called for each frame the curve needs to be rendered.
93    ///
94    /// Samples of time points outside of the curve's domain will be filtered out and won't
95    /// contribute to the rendering. If you wish to render the curve outside of its domain you need
96    /// to create a new curve with an extended domain.
97    ///
98    /// # Arguments
99    /// - `curve_2d` some type that implements the [`Curve`] trait and samples `Vec2`s
100    /// - `times_with_colors` some iterable type yielding `f32` which will be used for sampling
101    ///   the curve together with the color at this position
102    ///
103    /// # Example
104    /// ```
105    /// # use bevy_gizmos::prelude::*;
106    /// # use bevy_math::prelude::*;
107    /// # use bevy_color::{Mix, palettes::basic::{GREEN, RED}};
108    /// fn system(mut gizmos: Gizmos) {
109    ///     let domain = Interval::UNIT;
110    ///     let curve = FunctionCurve::new(domain, |t| Vec2::from(t.sin_cos()));
111    ///     gizmos.curve_gradient_2d(
112    ///         curve,
113    ///         (0..=100).map(|n| n as f32 / 100.0)
114    ///                  .map(|t| (t, GREEN.mix(&RED, t)))
115    ///     );
116    /// }
117    /// # bevy_ecs::system::assert_is_system(system);
118    /// ```
119    pub fn curve_gradient_2d<C>(
120        &mut self,
121        curve_2d: impl Curve<Vec2>,
122        times_with_colors: impl IntoIterator<Item = (f32, C)>,
123    ) where
124        C: Into<Color>,
125    {
126        self.linestrip_gradient_2d(
127            times_with_colors
128                .into_iter()
129                .filter_map(|(time, color)| curve_2d.sample(time).map(|sample| (sample, color))),
130        );
131    }
132
133    /// Draw a curve, at the given time points, sampling in 3D, with a color gradient.
134    ///
135    /// This should be called for each frame the curve needs to be rendered.
136    ///
137    /// Samples of time points outside of the curve's domain will be filtered out and won't
138    /// contribute to the rendering. If you wish to render the curve outside of its domain you need
139    /// to create a new curve with an extended domain.
140    ///
141    /// # Arguments
142    /// - `curve_3d` some type that implements the [`Curve`] trait and samples `Vec3`s
143    /// - `times_with_colors` some iterable type yielding `f32` which will be used for sampling
144    ///   the curve together with the color at this position
145    ///
146    /// # Example
147    /// ```
148    /// # use bevy_gizmos::prelude::*;
149    /// # use bevy_math::prelude::*;
150    /// # use bevy_color::{Mix, palettes::basic::{GREEN, RED}};
151    /// fn system(mut gizmos: Gizmos) {
152    ///     let domain = Interval::UNIT;
153    ///     let curve = FunctionCurve::new(domain, |t| {
154    ///         let (x,y) = t.sin_cos();
155    ///         Vec3::new(x, y, t)
156    ///     });
157    ///     gizmos.curve_gradient_3d(
158    ///         curve,
159    ///         (0..=100).map(|n| n as f32 / 100.0)
160    ///                  .map(|t| (t, GREEN.mix(&RED, t)))
161    ///     );
162    /// }
163    /// # bevy_ecs::system::assert_is_system(system);
164    /// ```
165    pub fn curve_gradient_3d<C>(
166        &mut self,
167        curve_3d: impl Curve<Vec3>,
168        times_with_colors: impl IntoIterator<Item = (f32, C)>,
169    ) where
170        C: Into<Color>,
171    {
172        self.linestrip_gradient(
173            times_with_colors
174                .into_iter()
175                .filter_map(|(time, color)| curve_3d.sample(time).map(|sample| (sample, color))),
176        );
177    }
178}