mesh_graph/plane_slice/
hash_grid.rs

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