Skip to main content

mesh_graph/plane_slice/
polygon.rs

1use std::collections::VecDeque;
2
3use glam::{Mat4, Vec2, Vec3, Vec4Swizzles};
4use itertools::Itertools;
5
6#[derive(Debug, Clone, Copy)]
7pub enum PolygonTerminal {
8    Start,
9    End,
10}
11
12#[derive(Debug, Clone, PartialEq)]
13pub struct Polygon2 {
14    pub vertices: VecDeque<Vec2>,
15}
16
17#[derive(Debug, Clone, PartialEq)]
18pub struct Polygon3 {
19    pub vertices: VecDeque<Vec3>,
20}
21
22impl Polygon2 {
23    pub fn terminal(&self, terminal: PolygonTerminal) -> Vec2 {
24        match terminal {
25            PolygonTerminal::Start => self.vertices[0],
26            PolygonTerminal::End => self.vertices[self.vertices.len() - 1],
27        }
28    }
29
30    pub fn extend_by_line(&mut self, terminal: PolygonTerminal, other_line_end: Vec2) {
31        match terminal {
32            PolygonTerminal::Start => self.vertices.push_front(other_line_end),
33            PolygonTerminal::End => self.vertices.push_back(other_line_end),
34        }
35    }
36
37    /// This assumes that the polygon to be merged doesn't contain any vertices that are already part of this polygon.
38    pub fn merge_polygon(
39        &mut self,
40        my_terminal: PolygonTerminal,
41        mut other: Polygon2,
42        other_terminal: PolygonTerminal,
43    ) {
44        let mut vertices = VecDeque::new();
45
46        match my_terminal {
47            PolygonTerminal::Start => {
48                match other_terminal {
49                    PolygonTerminal::Start => vertices.extend(other.vertices.into_iter().rev()),
50                    PolygonTerminal::End => vertices.append(&mut other.vertices),
51                }
52
53                vertices.append(&mut self.vertices);
54            }
55            PolygonTerminal::End => {
56                vertices.append(&mut self.vertices);
57
58                match other_terminal {
59                    PolygonTerminal::Start => vertices.append(&mut other.vertices),
60                    PolygonTerminal::End => vertices.extend(other.vertices.into_iter().rev()),
61                }
62            }
63        }
64
65        self.vertices = vertices;
66    }
67
68    pub fn is_closed(&self) -> bool {
69        if let (Some(front), Some(back)) = (self.vertices.front(), self.vertices.back()) {
70            front.distance_squared(*back) < 1e-6
71        } else {
72            false
73        }
74    }
75
76    pub fn close(&mut self) {
77        if !self.is_closed() {
78            self.vertices.push_back(self.vertices[0]);
79        }
80    }
81
82    pub fn length(&self) -> f32 {
83        self.vertices
84            .iter()
85            .tuple_windows()
86            .map(|(a, b)| a.distance(*b))
87            .sum()
88    }
89
90    #[cfg(feature = "rerun")]
91    pub fn log_rerun(&self, name: &str) {
92        use crate::utils::vec2_array;
93
94        crate::RR
95            .log(
96                name,
97                &rerun::LineStrips3D::new([self.vertices.iter().copied().map(vec2_array)]),
98            )
99            .unwrap();
100    }
101
102    pub fn min_max(&self) -> (Vec2, Vec2) {
103        let mut min = Vec2::MAX;
104        let mut max = Vec2::MIN;
105
106        for vertex in &self.vertices {
107            min = min.min(*vertex);
108            max = max.max(*vertex);
109        }
110
111        (min, max)
112    }
113
114    /// Wether a point is inside the polygon.
115    ///
116    /// Assumes that the polygon is closed.
117    pub fn contains_point(&self, point: Vec2) -> bool {
118        // Use ray casting algorithm in 2D. Taken from https://wrfranklin.org/Research/Short_Notes/pnpoly.html
119
120        let mut inside = false;
121
122        for (a, b) in self.vertices.iter().tuple_windows() {
123            if ((a.y > point.y) != (b.y > point.y))
124                && (point.x < (b.x - a.x) * (point.y - a.y) / (b.y - a.y) + a.x)
125            {
126                inside = !inside;
127            }
128        }
129
130        inside
131    }
132}
133
134impl Polygon3 {
135    pub fn from_polygon2_with_transform(polygon: Polygon2, transform: Mat4) -> Self {
136        let vertices = polygon
137            .vertices
138            .into_iter()
139            .map(|v| (transform * v.extend(0.0).extend(1.0)).xyz())
140            .collect();
141
142        Self { vertices }
143    }
144
145    pub fn length(&self) -> f32 {
146        self.vertices
147            .iter()
148            .tuple_windows()
149            .map(|(a, b)| a.distance(*b))
150            .sum()
151    }
152
153    #[cfg(feature = "rerun")]
154    pub fn log_rerun<'a>(
155        rr: &rerun::RecordingStream,
156        name: &str,
157        polygons: impl IntoIterator<Item = &'a Self>,
158    ) {
159        use crate::utils::vec3_array;
160
161        rr.log(
162            name,
163            &rerun::LineStrips3D::new(
164                polygons
165                    .into_iter()
166                    .map(|p| p.vertices.iter().copied().map(vec3_array)),
167            ),
168        )
169        .unwrap();
170    }
171}