Skip to main content

dear_implot/plots/
polygon.rs

1//! Polygon plot implementation
2
3use super::{
4    Plot, PlotDataLayout, PlotDataOffset, PlotDataStride, PlotError, PlotItemStyle,
5    plot_spec_with_style, validate_data_lengths, with_plot_str_or_empty,
6};
7use crate::{ItemFlags, PolygonFlags, sys};
8
9/// Builder for polygon plots.
10pub struct PolygonPlot<'a> {
11    label: &'a str,
12    x_data: &'a [f64],
13    y_data: &'a [f64],
14    style: PlotItemStyle,
15    flags: PolygonFlags,
16    item_flags: ItemFlags,
17    layout: PlotDataLayout,
18}
19
20impl<'a> super::PlotItemStyled for PolygonPlot<'a> {
21    fn style_mut(&mut self) -> &mut PlotItemStyle {
22        &mut self.style
23    }
24}
25
26impl<'a> PolygonPlot<'a> {
27    /// Create a new polygon plot with the given label and vertices.
28    pub fn new(label: &'a str, x_data: &'a [f64], y_data: &'a [f64]) -> Self {
29        Self {
30            label,
31            x_data,
32            y_data,
33            style: PlotItemStyle::default(),
34            flags: PolygonFlags::NONE,
35            item_flags: ItemFlags::NONE,
36            layout: PlotDataLayout::DEFAULT,
37        }
38    }
39
40    /// Replace the entire item style override for this polygon plot.
41    pub fn with_style(mut self, style: PlotItemStyle) -> Self {
42        self.style = style;
43        self
44    }
45
46    /// Set the line color. Use the alpha channel to control polygon outline transparency.
47    pub fn with_line_color(mut self, color: [f32; 4]) -> Self {
48        self.style = self.style.with_line_color(color);
49        self
50    }
51
52    /// Set the line width in pixels.
53    pub fn with_line_weight(mut self, weight: f32) -> Self {
54        self.style = self.style.with_line_weight(weight);
55        self
56    }
57
58    /// Set the fill color.
59    pub fn with_fill_color(mut self, color: [f32; 4]) -> Self {
60        self.style = self.style.with_fill_color(color);
61        self
62    }
63
64    /// Set the fill alpha multiplier.
65    pub fn with_fill_alpha(mut self, alpha: f32) -> Self {
66        self.style = self.style.with_fill_alpha(alpha);
67        self
68    }
69
70    /// Set polygon-specific flags.
71    pub fn with_flags(mut self, flags: PolygonFlags) -> Self {
72        self.flags = flags;
73        self
74    }
75
76    /// Set common item flags for this plot item.
77    pub fn with_item_flags(mut self, flags: ItemFlags) -> Self {
78        self.item_flags = flags;
79        self
80    }
81
82    /// Set the data layout used to read polygon vertices.
83    pub fn with_data_layout(mut self, layout: PlotDataLayout) -> Self {
84        self.layout = layout;
85        self
86    }
87
88    /// Set the sample-index offset used to read polygon vertices.
89    pub fn with_offset(mut self, offset: PlotDataOffset) -> Self {
90        self.layout = self.layout.with_offset(offset);
91        self
92    }
93
94    /// Set the byte stride used to read polygon vertices.
95    pub fn with_stride(mut self, stride: PlotDataStride) -> Self {
96        self.layout = self.layout.with_stride(stride);
97        self
98    }
99
100    /// Validate the polygon data.
101    pub fn validate(&self) -> Result<(), PlotError> {
102        validate_data_lengths(self.x_data, self.y_data)
103    }
104}
105
106impl<'a> Plot for PolygonPlot<'a> {
107    fn plot(&self) {
108        if self.validate().is_err() {
109            return;
110        }
111        let Ok(count) = i32::try_from(self.x_data.len()) else {
112            return;
113        };
114
115        with_plot_str_or_empty(self.label, |label_ptr| unsafe {
116            let spec = plot_spec_with_style(
117                self.style,
118                self.flags.bits() | self.item_flags.bits(),
119                self.layout,
120            );
121            sys::ImPlot_PlotPolygon_doublePtr(
122                label_ptr,
123                self.x_data.as_ptr(),
124                self.y_data.as_ptr(),
125                count,
126                spec,
127            );
128        })
129    }
130
131    fn label(&self) -> &str {
132        self.label
133    }
134}
135
136/// Convenience functions for quick polygon plotting.
137impl<'ui> crate::PlotUi<'ui> {
138    /// Plot a polygon with X and Y vertex data.
139    pub fn polygon_plot(
140        &self,
141        label: &str,
142        x_data: &[f64],
143        y_data: &[f64],
144    ) -> Result<(), PlotError> {
145        let plot = PolygonPlot::new(label, x_data, y_data);
146        plot.validate()?;
147        self.bind();
148        plot.plot();
149        Ok(())
150    }
151}
152
153#[cfg(test)]
154mod tests {
155    use super::*;
156
157    #[test]
158    fn polygon_plot_creation() {
159        let x_data = [0.0, 1.0, 1.0, 0.0];
160        let y_data = [0.0, 0.0, 1.0, 1.0];
161
162        let plot = PolygonPlot::new("poly", &x_data, &y_data);
163        assert_eq!(plot.label(), "poly");
164        assert!(plot.validate().is_ok());
165    }
166
167    #[test]
168    fn polygon_plot_validation() {
169        let x_data = [0.0, 1.0, 1.0];
170        let y_data = [0.0, 0.0];
171
172        let plot = PolygonPlot::new("poly", &x_data, &y_data);
173        assert!(plot.validate().is_err());
174    }
175}