Skip to main content

mesh_graph/plane_slice/
hash_grid.rs

1use glam::{IVec2, Vec2};
2use hashbrown::{HashMap, HashSet};
3use slotmap::{SecondaryMap, SlotMap, new_key_type};
4use tracing::{error, instrument};
5
6use crate::plane_slice::{Polygon2, PolygonTerminal};
7#[cfg(feature = "rerun")]
8use crate::utils::vec2_array;
9
10new_key_type! { pub struct PolygonId; }
11
12#[derive(Default, Debug, Clone)]
13pub struct HashGrid {
14    map: HashMap<IVec2, Vec<(PolygonTerminal, PolygonId)>>,
15    min_bounds: Vec2,
16    cell_fac: Vec2,
17    polygons: SlotMap<PolygonId, Polygon2>,
18    polygon_cells: SecondaryMap<PolygonId, HashSet<IVec2>>,
19}
20
21impl HashGrid {
22    pub fn new(min_bounds: Vec2, max_bounds: Vec2) -> Self {
23        let width = (max_bounds.x - min_bounds.x).max(0.0001);
24        let height = (max_bounds.y - min_bounds.y).max(0.0001);
25
26        let grid_size_x = width.sqrt().ceil();
27        let grid_size_y = height.sqrt().ceil();
28
29        let cell_fac = Vec2::new(grid_size_x / width, grid_size_y / height);
30
31        HashGrid {
32            map: HashMap::new(),
33            min_bounds,
34            cell_fac,
35            polygons: SlotMap::default(),
36            polygon_cells: SecondaryMap::default(),
37        }
38    }
39
40    #[instrument(skip(self))]
41    pub fn try_take_connecting_polygon(
42        &mut self,
43        point: Vec2,
44    ) -> Option<(PolygonTerminal, PolygonId)> {
45        let key = self.vec2_to_grid(point);
46
47        let mut result = None;
48
49        self.map.entry(key).and_modify(|e| {
50            let mut index = None;
51
52            for (i, (terminal, polygon_id)) in e.iter().enumerate() {
53                let Some(polygon) = self.polygons.get(*polygon_id) else {
54                    error!("Polygon not found");
55                    continue;
56                };
57                let Some(existing_point) = polygon.terminal(*terminal) else {
58                    error!("Empty polygon");
59                    continue;
60                };
61
62                if existing_point.distance_squared(point) < 1e-6 {
63                    index = Some(i);
64                    break;
65                }
66            }
67
68            if let Some(index) = index {
69                let (terminal, polygon_id) = e.remove(index);
70                result = Some((terminal, polygon_id));
71
72                // check if the other end of the polygon is still in the cell
73                if !e.iter().any(|(_, id)| *id == polygon_id) {
74                    self.polygon_cells[polygon_id].retain(|k| *k != key);
75                }
76            }
77        });
78
79        result
80    }
81
82    pub fn remove_polygon_from_cell(&mut self, polygon_id: PolygonId, cell: IVec2) {
83        self.map.entry(cell).and_modify(|e| {
84            e.retain(|(_, id)| *id != polygon_id);
85        });
86    }
87
88    pub fn insert_polygon_by_terminal(
89        &mut self,
90        terminal: PolygonTerminal,
91        polygon_id: PolygonId,
92        terminal_point: Vec2,
93    ) {
94        let key = self.vec2_to_grid(terminal_point);
95
96        self.map
97            .entry(key)
98            .or_default()
99            .push((terminal, polygon_id));
100
101        self.polygon_cells
102            .entry(polygon_id)
103            .unwrap()
104            .or_default()
105            .insert(key);
106    }
107
108    pub fn insert_line(&mut self, point1: Vec2, point2: Vec2) {
109        #[cfg(feature = "rerun")]
110        {
111            crate::RR
112                .log("insert_line", &rerun::Clear::recursive())
113                .unwrap();
114            crate::RR
115                .log(
116                    "insert_line/line",
117                    &rerun::LineStrips3D::new([[vec2_array(point1), vec2_array(point2)]]),
118                )
119                .unwrap();
120        }
121
122        if let Some((terminal1, polygon_id1)) = self.try_take_connecting_polygon(point1) {
123            #[cfg(feature = "rerun")]
124            self.polygons[polygon_id1].log_rerun("insert_line/existing_poly1");
125
126            if let Some((terminal2, polygon_id2)) = self.try_take_connecting_polygon(point2) {
127                #[cfg(feature = "rerun")]
128                self.polygons[polygon_id2].log_rerun("insert_line/another_existing_poly2");
129
130                self.merge_polygons(polygon_id1, terminal1, polygon_id2, terminal2);
131            } else {
132                self.extend_polygon(polygon_id1, terminal1, point2);
133            }
134        } else if let Some((terminal2, polygon_id2)) = self.try_take_connecting_polygon(point2) {
135            #[cfg(feature = "rerun")]
136            self.polygons[polygon_id2].log_rerun("insert_line/existing_poly2");
137
138            self.extend_polygon(polygon_id2, terminal2, point1);
139        } else {
140            let new_polygon = Polygon2 {
141                vertices: [point1, point2].into(),
142            };
143            let new_polygon_id = self.polygons.insert(new_polygon);
144
145            self.insert_polygon_by_terminal(PolygonTerminal::Start, new_polygon_id, point1);
146            self.insert_polygon_by_terminal(PolygonTerminal::End, new_polygon_id, point2);
147        }
148    }
149
150    fn merge_polygons(
151        &mut self,
152        polygon_id1: PolygonId,
153        terminal1: PolygonTerminal,
154        polygon_id2: PolygonId,
155        terminal2: PolygonTerminal,
156    ) {
157        if polygon_id1 == polygon_id2 {
158            // this method is only called with valid polygon ids
159            let polygon = &mut self.polygons[polygon_id1];
160            polygon.close();
161
162            return;
163        }
164
165        for cell in self.polygon_cells[polygon_id2].clone() {
166            self.remove_polygon_from_cell(polygon_id2, cell);
167        }
168        self.polygon_cells.remove(polygon_id2);
169        let polygon2 = self.polygons.remove(polygon_id2).unwrap();
170
171        for cell in self.polygon_cells[polygon_id1].clone() {
172            self.remove_polygon_from_cell(polygon_id1, cell);
173        }
174        let polygon1 = &mut self.polygons[polygon_id1];
175
176        polygon1.merge_polygon(terminal1, polygon2, terminal2);
177
178        if polygon1.vertices.is_empty() {
179            return;
180        }
181
182        // checked that the polygon is not empty => we can unwrap the terminal vertices
183        let start_point = polygon1.terminal(PolygonTerminal::Start).unwrap();
184        let end_point = polygon1.terminal(PolygonTerminal::End).unwrap();
185
186        #[cfg(feature = "rerun")]
187        {
188            crate::RR
189                .log("insert_line", &rerun::Clear::recursive())
190                .unwrap();
191            polygon1.log_rerun("insert_line/merged");
192        }
193
194        self.insert_polygon_by_terminal(PolygonTerminal::Start, polygon_id1, start_point);
195        self.insert_polygon_by_terminal(PolygonTerminal::End, polygon_id1, end_point);
196    }
197
198    fn extend_polygon(
199        &mut self,
200        polygon_id: PolygonId,
201        terminal: PolygonTerminal,
202        new_point: Vec2,
203    ) {
204        let polygon = &mut self.polygons[polygon_id];
205        polygon.extend_by_line(terminal, new_point);
206
207        #[cfg(feature = "rerun")]
208        {
209            crate::RR
210                .log("insert_line", &rerun::Clear::recursive())
211                .unwrap();
212            polygon.log_rerun("insert_line/extended");
213        }
214
215        self.insert_polygon_by_terminal(terminal, polygon_id, new_point);
216    }
217
218    #[inline]
219    fn vec2_to_grid(&self, point: Vec2) -> IVec2 {
220        ((point - self.min_bounds) * self.cell_fac)
221            .floor()
222            .as_ivec2()
223    }
224
225    pub fn into_polygons(self) -> impl Iterator<Item = Polygon2> {
226        self.polygons.into_iter().map(|(_, polygon)| polygon)
227    }
228}