1use std::{collections::BTreeSet, marker::PhantomData};
6
7use i_overlay::{
8 core::{fill_rule::FillRule, overlay_rule::OverlayRule},
9 float::single::SingleFloatOverlay,
10 i_float::float::compatible::FloatPointCompatible,
11};
12
13use maplike::{Clear, Get, Insert, IntoIter, KeyedCollection, Push, Set};
14use num_traits::{FromPrimitive, ToPrimitive};
15use rstar::{
16 AABB, Envelope, RTree, RTreeNum, RTreeObject,
17 primitives::{GeomWithData, Rectangle},
18};
19use rstared::AsRefRTree;
20#[cfg(feature = "undoredo")]
21use std::collections::BTreeMap;
22#[cfg(feature = "undoredo")]
23use undoredo::{ApplyDelta, Delta, FlushDelta, Recorder};
24
25use crate::unionfind::UnionFind;
26
27#[cfg(feature = "std")]
28extern crate std;
29
30extern crate alloc;
32
33mod unionfind;
34
35#[derive(Clone, Debug)]
36pub struct Polygon<K, W = ()> {
37 pub vertices: Vec<Point<K>>,
38 pub weight: W,
39}
40
41#[derive(Clone, Copy, Debug)]
42pub struct Point<K> {
43 pub x: K,
44 pub y: K,
45}
46
47impl<K: Copy> From<[K; 2]> for Point<K> {
48 #[inline]
49 fn from(coords: [K; 2]) -> Self {
50 Self {
51 x: coords[0],
52 y: coords[1],
53 }
54 }
55}
56
57impl<K: FromPrimitive + ToPrimitive> FloatPointCompatible<f64> for Point<K>
58where
59 Point<K>: Copy,
60{
61 #[inline]
62 fn from_xy(x: f64, y: f64) -> Self {
63 Self {
64 x: K::from_f64(x).unwrap(),
65 y: K::from_f64(y).unwrap(),
66 }
67 }
68
69 #[inline]
70 fn x(&self) -> f64 {
71 self.x.to_f64().unwrap()
72 }
73
74 #[inline]
75 fn y(&self) -> f64 {
76 self.y.to_f64().unwrap()
77 }
78}
79
80#[derive(Clone, Debug)]
81pub struct PolygonUnionFind<
82 K: RTreeNum,
83 W = (),
84 PC: KeyedCollection = Vec<Polygon<K, W>>,
85 PR: KeyedCollection = AsRefRTree<GeomWithData<Rectangle<[K; 2]>, usize>>,
86 UFPC = Vec<usize>,
87 UFRC = Vec<usize>,
88> {
89 polygons: PC,
90 rtree: PR,
91 unionfind: UnionFind<UFPC, UFRC>,
92 scalar_marker: PhantomData<K>,
93 polygon_weight_marker: PhantomData<W>,
94}
95
96impl<
97 K: RTreeNum,
98 W,
99 PC: Default + KeyedCollection,
100 PR: Default + KeyedCollection,
101 UFPC: Default,
102 UFRC: Default,
103> PolygonUnionFind<K, W, PC, PR, UFPC, UFRC>
104{
105 #[inline]
106 pub fn new() -> Self {
107 Self {
108 polygons: Default::default(),
109 rtree: Default::default(),
110 unionfind: UnionFind::new(),
111 scalar_marker: PhantomData,
112 polygon_weight_marker: PhantomData,
113 }
114 }
115}
116
117impl<K: RTreeNum, W, PC: KeyedCollection, PR: KeyedCollection, UFPC, UFRC>
118 PolygonUnionFind<K, W, PC, PR, UFPC, UFRC>
119{
120 #[inline]
121 pub fn raw_polygons(&self) -> &PC {
122 &self.polygons
123 }
124
125 #[inline]
126 pub fn rtree(&self) -> &PR {
127 &self.rtree
128 }
129
130 #[inline]
131 pub fn unionfind(&self) -> &UnionFind<UFPC, UFRC> {
132 &self.unionfind
133 }
134
135 #[inline]
138 pub fn dissolve(self) -> (PC, PR, UnionFind<UFPC, UFRC>) {
139 (self.polygons, self.rtree, self.unionfind)
140 }
141}
142
143impl<
144 K: FromPrimitive + RTreeNum + ToPrimitive,
145 W,
146 PC: Clone + IntoIter<usize> + Get<usize, Value = Polygon<K, W>> + Push<usize> + Set<usize>,
147 PR: AsRef<RTree<GeomWithData<Rectangle<[K; 2]>, usize>>>
148 + Insert<GeomWithData<Rectangle<[K; 2]>, usize>, Value = ()>,
149 UFPC: Get<usize, Value = usize> + Push<usize> + Set<usize>,
150 UFRC: Get<usize, Value = usize> + Push<usize> + Set<usize>,
151> PolygonUnionFind<K, W, PC, PR, UFPC, UFRC>
152where
153 Point<K>: Copy,
154{
155 #[inline]
156 pub fn polygons(&mut self) -> impl Iterator<Item = &PC::Value> {
157 let mut deduplicating_set = BTreeSet::new();
158
159 for (i, _polygon) in self.polygons.clone().into_iter() {
160 deduplicating_set.insert(self.unionfind.find(i));
161 }
162
163 IntoIterator::into_iter(deduplicating_set).map(|i| self.polygons.get(&i).unwrap())
164 }
165}
166
167impl<
168 K: FromPrimitive + RTreeNum + ToPrimitive,
169 W: Clone,
170 PC: Get<usize, Value = Polygon<K, W>> + Push<usize> + Set<usize>,
171 PR: AsRef<RTree<GeomWithData<Rectangle<[K; 2]>, usize>>>
172 + Insert<GeomWithData<Rectangle<[K; 2]>, usize>, Value = ()>,
173 UFPC: Get<usize, Value = usize> + Push<usize> + Set<usize>,
174 UFRC: Get<usize, Value = usize> + Push<usize> + Set<usize>,
175> PolygonUnionFind<K, W, PC, PR, UFPC, UFRC>
176where
177 Point<K>: Copy,
178{
179 pub fn insert(&mut self, mut polygon: Polygon<K, W>) -> usize {
180 let new_polygon_index = self.unionfind.new_set();
181
182 let rectangle = Self::rectangle_from_polygon(&polygon);
183 self.rtree
184 .insert(GeomWithData::new(rectangle.clone(), new_polygon_index), ());
185
186 let id = self.polygons.push(polygon.clone());
187
188 for neighbor in self
189 .rtree
190 .as_ref()
191 .locate_in_envelope_intersecting(&rectangle.envelope())
192 {
193 let neighbor_representative = self.unionfind.find_compress(neighbor.data);
194
195 let vertices: Vec<[f64; 2]> = polygon
196 .vertices
197 .iter()
198 .map(|vertex| [vertex.x(), vertex.y()])
199 .collect();
200 let neighbor_vertices: Vec<[f64; 2]> = self
201 .polygons
202 .get(&neighbor_representative)
203 .unwrap()
204 .vertices
205 .iter()
206 .map(|vertex| [vertex.x(), vertex.y()])
207 .collect();
208 let union = vertices.overlay(&neighbor_vertices, OverlayRule::Union, FillRule::EvenOdd);
209
210 if union.len() >= 2 {
211 continue;
212 }
213
214 if let Some(union) = union.get(&0) {
215 self.unionfind
216 .union(neighbor_representative, new_polygon_index);
217
218 let representative = self.unionfind.find(new_polygon_index);
220 polygon = Polygon {
221 vertices: union[0]
222 .iter()
223 .map(|vertex| Point {
224 x: K::from_f64(vertex[0]).unwrap(),
225 y: K::from_f64(vertex[1]).unwrap(),
226 })
227 .collect(),
228 weight: self.polygons.get(&representative).unwrap().weight.clone(),
229 };
230 self.polygons.set(representative, polygon.clone());
231 }
232 }
233
234 id
235 }
236
237 pub fn set_weight(&mut self, id: usize, weight: W) {
238 let polygon = self.polygons.get(&id).unwrap();
239 self.polygons.set(
240 id,
241 Polygon {
242 vertices: polygon.vertices.clone(),
243 weight,
244 },
245 );
246 }
247
248 #[inline]
249 pub fn find(&self, index: usize) -> &Polygon<K, W> {
250 self.polygons.get(&self.unionfind.find(index)).unwrap()
251 }
252
253 pub fn find_compress(&mut self, index: usize) -> &Polygon<K, W> {
254 self.polygons
255 .get(&self.unionfind.find_compress(index))
256 .unwrap()
257 }
258
259 fn rectangle_from_polygon(polygon: &Polygon<K, W>) -> Rectangle<[K; 2]> {
260 Rectangle::from_aabb(
261 polygon
262 .vertices
263 .iter()
264 .fold(AABB::new_empty(), |aabb, vertex| {
265 aabb.merged(&AABB::from_point([vertex.x, vertex.y]))
266 }),
267 )
268 }
269}
270
271impl<K: RTreeNum, W, PC: Clear, PR: Clear, UFPC: Clear, UFRC: Clear>
272 PolygonUnionFind<K, W, PC, PR, UFPC, UFRC>
273{
274 pub fn clear(&mut self) {
275 self.polygons.clear();
276 self.rtree.clear();
277 self.unionfind.clear();
278 }
279}
280
281#[cfg(feature = "undoredo")]
282pub type RecordingPolygonUnionFind<K, W = ()> = PolygonUnionFind<
283 K,
284 W,
285 Recorder<Vec<Polygon<K, W>>, BTreeMap<usize, Polygon<K, W>>>,
286 Recorder<RTree<GeomWithData<Rectangle<[K; 2]>, usize>>>,
287 Recorder<Vec<usize>>,
288 Recorder<Vec<usize>>,
289>;
290
291#[cfg(feature = "undoredo")]
292pub type PolygonUnionFindDelta<K, W = ()> = PolygonUnionFind<
293 K,
294 W,
295 BTreeMap<usize, Polygon<K, W>>,
296 BTreeMap<GeomWithData<Rectangle<[K; 2]>, usize>, ()>,
297 BTreeMap<usize, usize>,
298 BTreeMap<usize, usize>,
299>;
300
301#[cfg(feature = "undoredo")]
302impl<
303 K: RTreeNum,
304 W: Clone,
305 PCE: Clone + KeyedCollection,
306 PC: KeyedCollection + Clone + ApplyDelta<PCE>,
307 PRE: Clone + KeyedCollection,
308 PR: KeyedCollection + Clone + ApplyDelta<PRE>,
309 UFPCE: Clone + KeyedCollection,
310 UFPC: Clone + ApplyDelta<UFPCE>,
311 UFRCE: Clone + KeyedCollection,
312 UFRC: Clone + ApplyDelta<UFRCE>,
313> ApplyDelta<PolygonUnionFind<K, W, PCE, PRE, UFPCE, UFRCE>>
314 for PolygonUnionFind<K, W, PC, PR, UFPC, UFRC>
315{
316 fn apply_delta(&mut self, delta: &Delta<PolygonUnionFind<K, W, PCE, PRE, UFPCE, UFRCE>>) {
317 let (removed, inserted) = delta.clone().dissolve();
318
319 let polygons_delta = Delta::with_removed_inserted(removed.polygons, inserted.polygons);
320 self.polygons.apply_delta(&polygons_delta);
321
322 let rtree_delta = Delta::with_removed_inserted(removed.rtree, inserted.rtree);
323 self.rtree.apply_delta(&rtree_delta);
324
325 let unionfind_delta = Delta::with_removed_inserted(removed.unionfind, inserted.unionfind);
326 self.unionfind.apply_delta(&unionfind_delta);
327 }
328}
329
330#[cfg(feature = "undoredo")]
331impl<
332 K: RTreeNum,
333 W: Clone,
334 PCE: Clone + KeyedCollection,
335 PC: KeyedCollection + FlushDelta<PCE>,
336 PRE: Clone + KeyedCollection,
337 PR: KeyedCollection + FlushDelta<PRE>,
338 UFPCE: Clone + KeyedCollection,
339 UFPC: FlushDelta<UFPCE>,
340 UFRCE: Clone + KeyedCollection,
341 UFRC: FlushDelta<UFRCE>,
342> FlushDelta<PolygonUnionFind<K, W, PCE, PRE, UFPCE, UFRCE>>
343 for PolygonUnionFind<K, W, PC, PR, UFPC, UFRC>
344{
345 fn flush_delta(&mut self) -> Delta<PolygonUnionFind<K, W, PCE, PRE, UFPCE, UFRCE>> {
346 let (removed_polygons, inserted_polygons) = self.polygons.flush_delta().dissolve();
347 let (removed_rtree, inserted_rtree) = self.rtree.flush_delta().dissolve();
348 let (removed_unionfind, inserted_unionfind) = self.unionfind.flush_delta().dissolve();
349
350 Delta::with_removed_inserted(
351 PolygonUnionFind {
352 polygons: removed_polygons,
353 rtree: removed_rtree,
354 unionfind: removed_unionfind,
355 scalar_marker: PhantomData,
356 polygon_weight_marker: PhantomData,
357 },
358 PolygonUnionFind {
359 polygons: inserted_polygons,
360 rtree: inserted_rtree,
361 unionfind: inserted_unionfind,
362 scalar_marker: PhantomData,
363 polygon_weight_marker: PhantomData,
364 },
365 )
366 }
367}
368
369#[cfg(test)]
370mod tests {
371 }