dear_implot/plots/
digital.rs

1//! Digital plot implementation
2
3use super::{PlotData, PlotError, safe_cstring, validate_data_lengths};
4use crate::DigitalFlags;
5use crate::sys;
6
7/// Builder for digital plots with extensive customization options
8///
9/// Digital plots are used to display digital signals (0/1, high/low, etc.)
10/// They do not respond to y drag or zoom, and are always referenced to the bottom of the plot.
11pub struct DigitalPlot<'a> {
12    label: &'a str,
13    x_data: &'a [f64],
14    y_data: &'a [f64],
15    flags: DigitalFlags,
16    offset: i32,
17    stride: i32,
18}
19
20impl<'a> DigitalPlot<'a> {
21    /// Create a new digital plot with the given label and data
22    pub fn new(label: &'a str, x_data: &'a [f64], y_data: &'a [f64]) -> Self {
23        Self {
24            label,
25            x_data,
26            y_data,
27            flags: DigitalFlags::NONE,
28            offset: 0,
29            stride: std::mem::size_of::<f64>() as i32,
30        }
31    }
32
33    /// Set digital flags for customization
34    pub fn with_flags(mut self, flags: DigitalFlags) -> Self {
35        self.flags = flags;
36        self
37    }
38
39    /// Set data offset for partial plotting
40    pub fn with_offset(mut self, offset: i32) -> Self {
41        self.offset = offset;
42        self
43    }
44
45    /// Set data stride for non-contiguous data
46    pub fn with_stride(mut self, stride: i32) -> Self {
47        self.stride = stride;
48        self
49    }
50
51    /// Validate the plot data
52    pub fn validate(&self) -> Result<(), PlotError> {
53        validate_data_lengths(self.x_data, self.y_data)?;
54
55        // Digital plots should have binary-like data (0/1, but we allow any values)
56        // The validation is mainly for data length consistency
57        Ok(())
58    }
59
60    /// Plot the digital signal
61    pub fn plot(self) {
62        let label_cstring = safe_cstring(self.label);
63
64        unsafe {
65            sys::ImPlot_PlotDigital_doublePtr(
66                label_cstring.as_ptr(),
67                self.x_data.as_ptr(),
68                self.y_data.as_ptr(),
69                self.x_data.len() as i32,
70                self.flags.bits() as i32,
71                self.offset,
72                self.stride,
73            );
74        }
75    }
76}
77
78impl<'a> PlotData for DigitalPlot<'a> {
79    fn label(&self) -> &str {
80        self.label
81    }
82
83    fn data_len(&self) -> usize {
84        self.x_data.len().min(self.y_data.len())
85    }
86}
87
88/// Digital plot for f32 data
89pub struct DigitalPlotF32<'a> {
90    label: &'a str,
91    x_data: &'a [f32],
92    y_data: &'a [f32],
93    flags: DigitalFlags,
94}
95
96impl<'a> DigitalPlotF32<'a> {
97    /// Create a new digital plot with f32 data
98    pub fn new(label: &'a str, x_data: &'a [f32], y_data: &'a [f32]) -> Self {
99        Self {
100            label,
101            x_data,
102            y_data,
103            flags: DigitalFlags::NONE,
104        }
105    }
106
107    /// Set digital flags for customization
108    pub fn with_flags(mut self, flags: DigitalFlags) -> Self {
109        self.flags = flags;
110        self
111    }
112
113    /// Validate the plot data
114    pub fn validate(&self) -> Result<(), PlotError> {
115        if self.x_data.len() != self.y_data.len() {
116            return Err(PlotError::DataLengthMismatch {
117                x_len: self.x_data.len(),
118                y_len: self.y_data.len(),
119            });
120        }
121        if self.x_data.is_empty() {
122            return Err(PlotError::EmptyData);
123        }
124        Ok(())
125    }
126
127    /// Plot the digital signal
128    pub fn plot(self) {
129        let label_cstring = safe_cstring(self.label);
130
131        unsafe {
132            sys::ImPlot_PlotDigital_FloatPtr(
133                label_cstring.as_ptr(),
134                self.x_data.as_ptr(),
135                self.y_data.as_ptr(),
136                self.x_data.len() as i32,
137                self.flags.bits() as i32,
138                0,
139                std::mem::size_of::<f32>() as i32,
140            );
141        }
142    }
143}
144
145impl<'a> PlotData for DigitalPlotF32<'a> {
146    fn label(&self) -> &str {
147        self.label
148    }
149
150    fn data_len(&self) -> usize {
151        self.x_data.len().min(self.y_data.len())
152    }
153}
154
155/// Simple digital plot for single array data (y values only, x is auto-generated)
156pub struct SimpleDigitalPlot<'a> {
157    label: &'a str,
158    y_data: &'a [f64],
159    flags: DigitalFlags,
160    x_scale: f64,
161    x_start: f64,
162}
163
164impl<'a> SimpleDigitalPlot<'a> {
165    /// Create a new simple digital plot with only y data
166    pub fn new(label: &'a str, y_data: &'a [f64]) -> Self {
167        Self {
168            label,
169            y_data,
170            flags: DigitalFlags::NONE,
171            x_scale: 1.0,
172            x_start: 0.0,
173        }
174    }
175
176    /// Set the x scale (spacing between points)
177    pub fn with_x_scale(mut self, x_scale: f64) -> Self {
178        self.x_scale = x_scale;
179        self
180    }
181
182    /// Set the x start value
183    pub fn with_x_start(mut self, x_start: f64) -> Self {
184        self.x_start = x_start;
185        self
186    }
187
188    /// Set digital flags
189    pub fn with_flags(mut self, flags: DigitalFlags) -> Self {
190        self.flags = flags;
191        self
192    }
193
194    /// Validate the plot data
195    pub fn validate(&self) -> Result<(), PlotError> {
196        if self.y_data.is_empty() {
197            return Err(PlotError::EmptyData);
198        }
199        Ok(())
200    }
201
202    /// Plot the digital signal
203    pub fn plot(self) {
204        // Generate x data
205        let x_data: Vec<f64> = (0..self.y_data.len())
206            .map(|i| self.x_start + i as f64 * self.x_scale)
207            .collect();
208
209        let label_cstring = safe_cstring(self.label);
210
211        unsafe {
212            sys::ImPlot_PlotDigital_doublePtr(
213                label_cstring.as_ptr(),
214                x_data.as_ptr(),
215                self.y_data.as_ptr(),
216                self.y_data.len() as i32,
217                self.flags.bits() as i32,
218                0,
219                std::mem::size_of::<f64>() as i32,
220            );
221        }
222    }
223}
224
225impl<'a> PlotData for SimpleDigitalPlot<'a> {
226    fn label(&self) -> &str {
227        self.label
228    }
229
230    fn data_len(&self) -> usize {
231        self.y_data.len()
232    }
233}
234
235/// Digital plot for boolean data (true/false converted to 1.0/0.0)
236pub struct BooleanDigitalPlot<'a> {
237    label: &'a str,
238    x_data: &'a [f64],
239    y_data: &'a [bool],
240    flags: DigitalFlags,
241}
242
243impl<'a> BooleanDigitalPlot<'a> {
244    /// Create a new digital plot with boolean data
245    pub fn new(label: &'a str, x_data: &'a [f64], y_data: &'a [bool]) -> Self {
246        Self {
247            label,
248            x_data,
249            y_data,
250            flags: DigitalFlags::NONE,
251        }
252    }
253
254    /// Set digital flags for customization
255    pub fn with_flags(mut self, flags: DigitalFlags) -> Self {
256        self.flags = flags;
257        self
258    }
259
260    /// Validate the plot data
261    pub fn validate(&self) -> Result<(), PlotError> {
262        if self.x_data.len() != self.y_data.len() {
263            return Err(PlotError::DataLengthMismatch {
264                x_len: self.x_data.len(),
265                y_len: self.y_data.len(),
266            });
267        }
268        if self.x_data.is_empty() {
269            return Err(PlotError::EmptyData);
270        }
271        Ok(())
272    }
273
274    /// Plot the digital signal
275    pub fn plot(self) {
276        // Convert boolean data to f64
277        let y_data_f64: Vec<f64> = self
278            .y_data
279            .iter()
280            .map(|&b| if b { 1.0 } else { 0.0 })
281            .collect();
282
283        let label_cstring = safe_cstring(self.label);
284
285        unsafe {
286            sys::ImPlot_PlotDigital_doublePtr(
287                label_cstring.as_ptr(),
288                self.x_data.as_ptr(),
289                y_data_f64.as_ptr(),
290                self.x_data.len() as i32,
291                self.flags.bits() as i32,
292                0,
293                std::mem::size_of::<f64>() as i32,
294            );
295        }
296    }
297}
298
299impl<'a> PlotData for BooleanDigitalPlot<'a> {
300    fn label(&self) -> &str {
301        self.label
302    }
303
304    fn data_len(&self) -> usize {
305        self.x_data.len().min(self.y_data.len())
306    }
307}