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