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 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 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 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}