1use super::{Plot, PlotError, validate_data_lengths, with_plot_str_or_empty};
4use crate::{ShadedFlags, sys};
5
6pub struct ShadedPlot<'a> {
8 label: &'a str,
9 x_data: &'a [f64],
10 y_data: &'a [f64],
11 y_ref: f64,
12 flags: ShadedFlags,
13 offset: i32,
14 stride: i32,
15}
16
17impl<'a> ShadedPlot<'a> {
18 pub fn new(label: &'a str, x_data: &'a [f64], y_data: &'a [f64]) -> Self {
20 Self {
21 label,
22 x_data,
23 y_data,
24 y_ref: 0.0, flags: ShadedFlags::NONE,
26 offset: 0,
27 stride: std::mem::size_of::<f64>() as i32,
28 }
29 }
30
31 pub fn with_y_ref(mut self, y_ref: f64) -> Self {
34 self.y_ref = y_ref;
35 self
36 }
37
38 pub fn with_flags(mut self, flags: ShadedFlags) -> Self {
40 self.flags = flags;
41 self
42 }
43
44 pub fn with_offset(mut self, offset: i32) -> Self {
46 self.offset = offset;
47 self
48 }
49
50 pub fn with_stride(mut self, stride: i32) -> Self {
52 self.stride = stride;
53 self
54 }
55
56 pub fn validate(&self) -> Result<(), PlotError> {
58 validate_data_lengths(self.x_data, self.y_data)
59 }
60}
61
62impl<'a> Plot for ShadedPlot<'a> {
63 fn plot(&self) {
64 if self.validate().is_err() {
65 return;
66 }
67 let Ok(count) = i32::try_from(self.x_data.len()) else {
68 return;
69 };
70 with_plot_str_or_empty(self.label, |label_ptr| unsafe {
71 sys::ImPlot_PlotShaded_doublePtrdoublePtrInt(
72 label_ptr,
73 self.x_data.as_ptr(),
74 self.y_data.as_ptr(),
75 count,
76 self.y_ref,
77 self.flags.bits() as sys::ImPlotShadedFlags,
78 self.offset,
79 self.stride,
80 );
81 })
82 }
83
84 fn label(&self) -> &str {
85 self.label
86 }
87}
88
89pub struct ShadedBetweenPlot<'a> {
91 label: &'a str,
92 x_data: &'a [f64],
93 y1_data: &'a [f64],
94 y2_data: &'a [f64],
95 flags: ShadedFlags,
96}
97
98impl<'a> ShadedBetweenPlot<'a> {
99 pub fn new(label: &'a str, x_data: &'a [f64], y1_data: &'a [f64], y2_data: &'a [f64]) -> Self {
101 Self {
102 label,
103 x_data,
104 y1_data,
105 y2_data,
106 flags: ShadedFlags::NONE,
107 }
108 }
109
110 pub fn with_flags(mut self, flags: ShadedFlags) -> Self {
112 self.flags = flags;
113 self
114 }
115
116 pub fn validate(&self) -> Result<(), PlotError> {
118 validate_data_lengths(self.x_data, self.y1_data)?;
119 validate_data_lengths(self.x_data, self.y2_data)?;
120 Ok(())
121 }
122}
123
124impl<'a> Plot for ShadedBetweenPlot<'a> {
125 fn plot(&self) {
126 if self.validate().is_err() {
127 return;
128 }
129 let Ok(count) = i32::try_from(self.x_data.len()) else {
130 return;
131 };
132
133 with_plot_str_or_empty(self.label, |label_ptr| unsafe {
136 sys::ImPlot_PlotShaded_doublePtrdoublePtrdoublePtr(
137 label_ptr,
138 self.x_data.as_ptr(),
139 self.y1_data.as_ptr(),
140 self.y2_data.as_ptr(),
141 count,
142 self.flags.bits() as sys::ImPlotShadedFlags,
143 0,
144 std::mem::size_of::<f64>() as i32,
145 );
146 })
147 }
148
149 fn label(&self) -> &str {
150 self.label
151 }
152}
153
154pub struct SimpleShadedPlot<'a> {
156 label: &'a str,
157 values: &'a [f64],
158 y_ref: f64,
159 x_scale: f64,
160 x_start: f64,
161}
162
163impl<'a> SimpleShadedPlot<'a> {
164 pub fn new(label: &'a str, values: &'a [f64]) -> Self {
166 Self {
167 label,
168 values,
169 y_ref: 0.0,
170 x_scale: 1.0,
171 x_start: 0.0,
172 }
173 }
174
175 pub fn with_y_ref(mut self, y_ref: f64) -> Self {
177 self.y_ref = y_ref;
178 self
179 }
180
181 pub fn with_x_scale(mut self, scale: f64) -> Self {
183 self.x_scale = scale;
184 self
185 }
186
187 pub fn with_x_start(mut self, start: f64) -> Self {
189 self.x_start = start;
190 self
191 }
192}
193
194impl<'a> Plot for SimpleShadedPlot<'a> {
195 fn plot(&self) {
196 if self.values.is_empty() {
197 return;
198 }
199 let Ok(count) = i32::try_from(self.values.len()) else {
200 return;
201 };
202
203 let x_data: Vec<f64> = (0..self.values.len())
205 .map(|i| self.x_start + i as f64 * self.x_scale)
206 .collect();
207
208 with_plot_str_or_empty(self.label, |label_ptr| unsafe {
209 sys::ImPlot_PlotShaded_doublePtrdoublePtrInt(
210 label_ptr,
211 x_data.as_ptr(),
212 self.values.as_ptr(),
213 count,
214 self.y_ref,
215 0, 0,
217 std::mem::size_of::<f64>() as i32,
218 );
219 })
220 }
221
222 fn label(&self) -> &str {
223 self.label
224 }
225}
226
227impl<'ui> crate::PlotUi<'ui> {
229 pub fn shaded_plot(
231 &self,
232 label: &str,
233 x_data: &[f64],
234 y_data: &[f64],
235 ) -> Result<(), PlotError> {
236 let plot = ShadedPlot::new(label, x_data, y_data);
237 plot.validate()?;
238 plot.plot();
239 Ok(())
240 }
241
242 pub fn shaded_plot_with_ref(
244 &self,
245 label: &str,
246 x_data: &[f64],
247 y_data: &[f64],
248 y_ref: f64,
249 ) -> Result<(), PlotError> {
250 let plot = ShadedPlot::new(label, x_data, y_data).with_y_ref(y_ref);
251 plot.validate()?;
252 plot.plot();
253 Ok(())
254 }
255
256 pub fn shaded_between_plot(
258 &self,
259 label: &str,
260 x_data: &[f64],
261 y1_data: &[f64],
262 y2_data: &[f64],
263 ) -> Result<(), PlotError> {
264 let plot = ShadedBetweenPlot::new(label, x_data, y1_data, y2_data);
265 plot.validate()?;
266 plot.plot();
267 Ok(())
268 }
269
270 pub fn simple_shaded_plot(&self, label: &str, values: &[f64]) -> Result<(), PlotError> {
272 if values.is_empty() {
273 return Err(PlotError::EmptyData);
274 }
275 let plot = SimpleShadedPlot::new(label, values);
276 plot.plot();
277 Ok(())
278 }
279}
280
281#[cfg(test)]
282mod tests {
283 use super::*;
284
285 #[test]
286 fn test_shaded_plot_creation() {
287 let x_data = [1.0, 2.0, 3.0, 4.0];
288 let y_data = [1.0, 4.0, 2.0, 3.0];
289
290 let plot = ShadedPlot::new("test", &x_data, &y_data);
291 assert_eq!(plot.label(), "test");
292 assert!(plot.validate().is_ok());
293 }
294
295 #[test]
296 fn test_shaded_plot_validation() {
297 let x_data = [1.0, 2.0, 3.0];
298 let y_data = [1.0, 4.0]; let plot = ShadedPlot::new("test", &x_data, &y_data);
301 assert!(plot.validate().is_err());
302 }
303
304 #[test]
305 fn test_shaded_between_plot() {
306 let x_data = [1.0, 2.0, 3.0, 4.0];
307 let y1_data = [1.0, 2.0, 3.0, 4.0];
308 let y2_data = [2.0, 3.0, 4.0, 5.0];
309
310 let plot = ShadedBetweenPlot::new("test", &x_data, &y1_data, &y2_data);
311 assert_eq!(plot.label(), "test");
312 assert!(plot.validate().is_ok());
313 }
314}