Skip to main content

dear_implot/plots/
polygon.rs

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