Skip to main content

dear_implot/plots/
inf_lines.rs

1//! Infinite lines plot implementation
2
3use super::{
4    Plot, PlotDataLayout, PlotDataOffset, PlotDataStride, PlotError, PlotItemStyle,
5    plot_spec_with_style, with_plot_str_or_empty,
6};
7use crate::{InfLinesFlags, ItemFlags, sys};
8
9/// Builder for infinite lines plots
10pub struct InfLinesPlot<'a> {
11    label: &'a str,
12    positions: &'a [f64],
13    style: PlotItemStyle,
14    flags: InfLinesFlags,
15    item_flags: ItemFlags,
16    layout: PlotDataLayout,
17}
18
19impl<'a> super::PlotItemStyled for InfLinesPlot<'a> {
20    fn style_mut(&mut self) -> &mut PlotItemStyle {
21        &mut self.style
22    }
23}
24
25impl<'a> InfLinesPlot<'a> {
26    /// Create a new infinite lines plot with the given label and positions (vertical by default)
27    pub fn new(label: &'a str, positions: &'a [f64]) -> Self {
28        Self {
29            label,
30            positions,
31            style: PlotItemStyle::default(),
32            flags: InfLinesFlags::NONE,
33            item_flags: ItemFlags::NONE,
34            layout: PlotDataLayout::DEFAULT,
35        }
36    }
37
38    /// Make lines horizontal instead of vertical
39    pub fn horizontal(mut self) -> Self {
40        self.flags |= InfLinesFlags::HORIZONTAL;
41        self
42    }
43
44    /// Set common item flags for this plot item (applies to all plot types)
45    pub fn with_item_flags(mut self, flags: ItemFlags) -> Self {
46        self.item_flags = flags;
47        self
48    }
49
50    /// Set the data layout used to read positions.
51    ///
52    /// # Safety
53    ///
54    /// Every sample address computed from `layout` must refer to an initialized, properly aligned
55    /// `f64` within the allocation backing this builder's positions.
56    pub unsafe fn with_data_layout(mut self, layout: PlotDataLayout) -> Self {
57        self.layout = layout;
58        self
59    }
60
61    /// Set the sample-index offset used to read positions.
62    pub fn with_offset(mut self, offset: PlotDataOffset) -> Self {
63        self.layout = self.layout.with_offset(offset);
64        self
65    }
66
67    /// Set the byte stride used to read positions.
68    ///
69    /// # Safety
70    ///
71    /// Every strided sample read must remain initialized, aligned, and within the allocation
72    /// backing this builder's positions.
73    pub unsafe fn with_stride(mut self, stride: PlotDataStride) -> Self {
74        self.layout = self.layout.with_stride(stride);
75        self
76    }
77
78    /// Validate the plot data
79    pub fn validate(&self) -> Result<(), PlotError> {
80        if self.positions.is_empty() {
81            return Err(PlotError::EmptyData);
82        }
83        Ok(())
84    }
85}
86
87impl<'a> Plot for InfLinesPlot<'a> {
88    fn plot(&self, plot_ui: &crate::PlotUi<'_>) {
89        if self.validate().is_err() {
90            return;
91        }
92        let Ok(count) = i32::try_from(self.positions.len()) else {
93            return;
94        };
95        plot_ui.with_bound_context(|| {
96            with_plot_str_or_empty(self.label, |label_ptr| unsafe {
97                let spec = plot_spec_with_style(
98                    self.style,
99                    self.flags.bits() | self.item_flags.bits(),
100                    self.layout,
101                );
102                sys::ImPlot_PlotInfLines_doublePtr(label_ptr, self.positions.as_ptr(), count, spec);
103            })
104        })
105    }
106
107    fn label(&self) -> &str {
108        self.label
109    }
110}
111
112/// Convenience functions for quick inf-lines plotting
113impl<'ui> crate::PlotUi<'ui> {
114    /// Plot vertical infinite lines at given x positions
115    pub fn inf_lines_vertical(&self, label: &str, xs: &[f64]) -> Result<(), PlotError> {
116        let plot = InfLinesPlot::new(label, xs);
117        plot.validate()?;
118        plot.plot(self);
119        Ok(())
120    }
121
122    /// Plot horizontal infinite lines at given y positions
123    pub fn inf_lines_horizontal(&self, label: &str, ys: &[f64]) -> Result<(), PlotError> {
124        let plot = InfLinesPlot::new(label, ys).horizontal();
125        plot.validate()?;
126        plot.plot(self);
127        Ok(())
128    }
129}