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}