1use super::{Plot, PlotError, safe_cstring, validate_data_lengths};
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
68 let label_cstr = safe_cstring(self.label);
69
70 unsafe {
71 sys::ImPlot_PlotShaded_doublePtrdoublePtrInt(
72 label_cstr.as_ptr(),
73 self.x_data.as_ptr(),
74 self.y_data.as_ptr(),
75 self.x_data.len() as i32,
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
130 let label_cstr = safe_cstring(self.label);
131
132 unsafe {
135 sys::ImPlot_PlotShaded_doublePtrdoublePtrdoublePtr(
136 label_cstr.as_ptr(),
137 self.x_data.as_ptr(),
138 self.y1_data.as_ptr(),
139 self.y2_data.as_ptr(),
140 self.x_data.len() as i32,
141 self.flags.bits() as sys::ImPlotShadedFlags,
142 0,
143 std::mem::size_of::<f64>() as i32,
144 );
145 }
146 }
147
148 fn label(&self) -> &str {
149 self.label
150 }
151}
152
153pub struct SimpleShadedPlot<'a> {
155 label: &'a str,
156 values: &'a [f64],
157 y_ref: f64,
158 x_scale: f64,
159 x_start: f64,
160}
161
162impl<'a> SimpleShadedPlot<'a> {
163 pub fn new(label: &'a str, values: &'a [f64]) -> Self {
165 Self {
166 label,
167 values,
168 y_ref: 0.0,
169 x_scale: 1.0,
170 x_start: 0.0,
171 }
172 }
173
174 pub fn with_y_ref(mut self, y_ref: f64) -> Self {
176 self.y_ref = y_ref;
177 self
178 }
179
180 pub fn with_x_scale(mut self, scale: f64) -> Self {
182 self.x_scale = scale;
183 self
184 }
185
186 pub fn with_x_start(mut self, start: f64) -> Self {
188 self.x_start = start;
189 self
190 }
191}
192
193impl<'a> Plot for SimpleShadedPlot<'a> {
194 fn plot(&self) {
195 if self.values.is_empty() {
196 return;
197 }
198
199 let label_cstr = safe_cstring(self.label);
200
201 let x_data: Vec<f64> = (0..self.values.len())
203 .map(|i| self.x_start + i as f64 * self.x_scale)
204 .collect();
205
206 unsafe {
207 sys::ImPlot_PlotShaded_doublePtrdoublePtrInt(
208 label_cstr.as_ptr(),
209 x_data.as_ptr(),
210 self.values.as_ptr(),
211 self.values.len() as i32,
212 self.y_ref,
213 0, 0,
215 std::mem::size_of::<f64>() as i32,
216 );
217 }
218 }
219
220 fn label(&self) -> &str {
221 self.label
222 }
223}
224
225impl<'ui> crate::PlotUi<'ui> {
227 pub fn shaded_plot(
229 &self,
230 label: &str,
231 x_data: &[f64],
232 y_data: &[f64],
233 ) -> Result<(), PlotError> {
234 let plot = ShadedPlot::new(label, x_data, y_data);
235 plot.validate()?;
236 plot.plot();
237 Ok(())
238 }
239
240 pub fn shaded_plot_with_ref(
242 &self,
243 label: &str,
244 x_data: &[f64],
245 y_data: &[f64],
246 y_ref: f64,
247 ) -> Result<(), PlotError> {
248 let plot = ShadedPlot::new(label, x_data, y_data).with_y_ref(y_ref);
249 plot.validate()?;
250 plot.plot();
251 Ok(())
252 }
253
254 pub fn shaded_between_plot(
256 &self,
257 label: &str,
258 x_data: &[f64],
259 y1_data: &[f64],
260 y2_data: &[f64],
261 ) -> Result<(), PlotError> {
262 let plot = ShadedBetweenPlot::new(label, x_data, y1_data, y2_data);
263 plot.validate()?;
264 plot.plot();
265 Ok(())
266 }
267
268 pub fn simple_shaded_plot(&self, label: &str, values: &[f64]) -> Result<(), PlotError> {
270 if values.is_empty() {
271 return Err(PlotError::EmptyData);
272 }
273 let plot = SimpleShadedPlot::new(label, values);
274 plot.plot();
275 Ok(())
276 }
277}
278
279#[cfg(test)]
280mod tests {
281 use super::*;
282
283 #[test]
284 fn test_shaded_plot_creation() {
285 let x_data = [1.0, 2.0, 3.0, 4.0];
286 let y_data = [1.0, 4.0, 2.0, 3.0];
287
288 let plot = ShadedPlot::new("test", &x_data, &y_data);
289 assert_eq!(plot.label(), "test");
290 assert!(plot.validate().is_ok());
291 }
292
293 #[test]
294 fn test_shaded_plot_validation() {
295 let x_data = [1.0, 2.0, 3.0];
296 let y_data = [1.0, 4.0]; let plot = ShadedPlot::new("test", &x_data, &y_data);
299 assert!(plot.validate().is_err());
300 }
301
302 #[test]
303 fn test_shaded_between_plot() {
304 let x_data = [1.0, 2.0, 3.0, 4.0];
305 let y1_data = [1.0, 2.0, 3.0, 4.0];
306 let y2_data = [2.0, 3.0, 4.0, 5.0];
307
308 let plot = ShadedBetweenPlot::new("test", &x_data, &y1_data, &y2_data);
309 assert_eq!(plot.label(), "test");
310 assert!(plot.validate().is_ok());
311 }
312}