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
103impl Polygon3 {
104    pub fn from_polygon2_with_transform(polygon: Polygon2, transform: Mat4) -> Self {
105        let vertices = polygon
106            .vertices
107            .into_iter()
108            .map(|v| (transform * v.extend(0.0).extend(1.0)).xyz())
109            .collect();
110
111        Self { vertices }
112    }
113
114    pub fn length(&self) -> f32 {
115        self.vertices
116            .iter()
117            .tuple_windows()
118            .map(|(a, b)| a.distance(*b))
119            .sum()
120    }
121
122    #[cfg(feature = "rerun")]
123    pub fn log_rerun<'a>(
124        rr: &rerun::RecordingStream,
125        name: &str,
126        polygons: impl IntoIterator<Item = &'a Self>,
127    ) {
128        use crate::utils::vec3_array;
129
130        rr.log(
131            name,
132            &rerun::LineStrips3D::new(
133                polygons
134                    .into_iter()
135                    .map(|p| p.vertices.iter().copied().map(vec3_array)),
136            ),
137        )
138        .unwrap();
139    }
140}