1use geo_traits::{
4 GeometryTrait, RectTrait, UnimplementedGeometryCollection, UnimplementedLine,
5 UnimplementedLineString, UnimplementedMultiLineString, UnimplementedMultiPoint,
6 UnimplementedMultiPolygon, UnimplementedPoint, UnimplementedPolygon, UnimplementedTriangle,
7};
8
9use crate::r#type::{Coord, IndexableNum};
10use crate::rtree::util::upper_bound;
11use crate::rtree::RTreeIndex;
12use core::mem::take;
13use std::marker::PhantomData;
14
15#[derive(Debug, Clone)]
17pub struct Node<'a, N: IndexableNum, T: RTreeIndex<N>> {
18 tree: &'a T,
20
21 pos: usize,
35
36 phantom: PhantomData<N>,
37}
38
39impl<'a, N: IndexableNum, T: RTreeIndex<N>> Node<'a, N, T> {
40 fn new(tree: &'a T, pos: usize) -> Self {
41 Self {
42 tree,
43 pos,
44 phantom: PhantomData,
45 }
46 }
47
48 pub(crate) fn from_root(tree: &'a T) -> Self {
49 let root_index = tree.boxes().len() - 4;
50 Self {
51 tree,
52 pos: root_index,
53 phantom: PhantomData,
54 }
55 }
56
57 #[inline]
59 pub fn min_x(&self) -> N {
60 self.tree.boxes()[self.pos]
61 }
62
63 #[inline]
65 pub fn min_y(&self) -> N {
66 self.tree.boxes()[self.pos + 1]
67 }
68
69 #[inline]
71 pub fn max_x(&self) -> N {
72 self.tree.boxes()[self.pos + 2]
73 }
74
75 #[inline]
77 pub fn max_y(&self) -> N {
78 self.tree.boxes()[self.pos + 3]
79 }
80
81 #[inline]
83 pub fn is_leaf(&self) -> bool {
84 self.pos < self.tree.num_items() as usize * 4
85 }
86
87 #[inline]
89 pub fn is_parent(&self) -> bool {
90 !self.is_leaf()
91 }
92
93 #[inline]
95 pub fn intersects<T2: RTreeIndex<N>>(&self, other: &Node<N, T2>) -> bool {
96 if self.max_x() < other.min_x() {
97 return false;
98 }
99
100 if self.max_y() < other.min_y() {
101 return false;
102 }
103
104 if self.min_x() > other.max_x() {
105 return false;
106 }
107
108 if self.min_y() > other.max_y() {
109 return false;
110 }
111
112 true
113 }
114
115 pub fn children(&self) -> Option<impl Iterator<Item = Node<'_, N, T>>> {
119 if self.is_parent() {
120 Some(self.children_unchecked())
121 } else {
122 None
123 }
124 }
125
126 pub fn children_unchecked(&self) -> impl Iterator<Item = Node<'_, N, T>> {
129 debug_assert!(self.is_parent());
130
131 let start_child_pos = self.tree.indices().get(self.pos >> 2);
133 let end_children_pos = (start_child_pos + self.tree.node_size() as usize * 4)
134 .min(upper_bound(start_child_pos, self.tree.level_bounds()));
135
136 (start_child_pos..end_children_pos)
137 .step_by(4)
138 .map(|pos| Node::new(self.tree, pos))
139 }
140
141 #[inline]
146 pub fn insertion_index(&self) -> Option<u32> {
147 if self.is_leaf() {
148 Some(self.insertion_index_unchecked())
149 } else {
150 None
151 }
152 }
153
154 #[inline]
157 pub fn insertion_index_unchecked(&self) -> u32 {
158 debug_assert!(self.is_leaf());
159 self.tree.indices().get(self.pos >> 2) as u32
160 }
161}
162
163impl<N: IndexableNum, T: RTreeIndex<N>> RectTrait for Node<'_, N, T> {
164 type CoordType<'a>
165 = Coord<N>
166 where
167 Self: 'a;
168
169 fn min(&self) -> Self::CoordType<'_> {
170 Coord {
171 x: self.min_x(),
172 y: self.min_y(),
173 }
174 }
175
176 fn max(&self) -> Self::CoordType<'_> {
177 Coord {
178 x: self.max_x(),
179 y: self.max_y(),
180 }
181 }
182}
183
184impl<N: IndexableNum, T: RTreeIndex<N>> GeometryTrait for Node<'_, N, T> {
185 type T = N;
186
187 type PointType<'a>
188 = UnimplementedPoint<N>
189 where
190 Self: 'a;
191
192 type LineStringType<'a>
193 = UnimplementedLineString<N>
194 where
195 Self: 'a;
196
197 type PolygonType<'a>
198 = UnimplementedPolygon<N>
199 where
200 Self: 'a;
201
202 type MultiPointType<'a>
203 = UnimplementedMultiPoint<N>
204 where
205 Self: 'a;
206
207 type MultiLineStringType<'a>
208 = UnimplementedMultiLineString<N>
209 where
210 Self: 'a;
211
212 type MultiPolygonType<'a>
213 = UnimplementedMultiPolygon<N>
214 where
215 Self: 'a;
216
217 type GeometryCollectionType<'a>
218 = UnimplementedGeometryCollection<N>
219 where
220 Self: 'a;
221
222 type RectType<'a>
223 = Node<'a, N, T>
224 where
225 Self: 'a;
226
227 type TriangleType<'a>
228 = UnimplementedTriangle<N>
229 where
230 Self: 'a;
231
232 type LineType<'a>
233 = UnimplementedLine<N>
234 where
235 Self: 'a;
236
237 fn dim(&self) -> geo_traits::Dimensions {
238 geo_traits::Dimensions::Xy
239 }
240
241 fn as_type(
242 &self,
243 ) -> geo_traits::GeometryType<
244 '_,
245 Self::PointType<'_>,
246 Self::LineStringType<'_>,
247 Self::PolygonType<'_>,
248 Self::MultiPointType<'_>,
249 Self::MultiLineStringType<'_>,
250 Self::MultiPolygonType<'_>,
251 Self::GeometryCollectionType<'_>,
252 Self::RectType<'_>,
253 Self::TriangleType<'_>,
254 Self::LineType<'_>,
255 > {
256 geo_traits::GeometryType::Rect(self)
257 }
258}
259
260pub(crate) struct IntersectionIterator<'a, N, T1, T2>
263where
264 N: IndexableNum,
265 T1: RTreeIndex<N>,
266 T2: RTreeIndex<N>,
267{
268 left: &'a T1,
269 right: &'a T2,
270 todo_list: Vec<(usize, usize)>,
271 candidates: Vec<usize>,
272 phantom: PhantomData<N>,
273}
274
275impl<'a, N, T1, T2> IntersectionIterator<'a, N, T1, T2>
276where
277 N: IndexableNum,
278 T1: RTreeIndex<N>,
279 T2: RTreeIndex<N>,
280{
281 pub(crate) fn from_trees(root1: &'a T1, root2: &'a T2) -> Self {
282 let mut intersections = IntersectionIterator {
283 left: root1,
284 right: root2,
285 todo_list: Vec::new(),
286 candidates: Vec::new(),
287 phantom: PhantomData,
288 };
289 intersections.add_intersecting_children(&root1.root(), &root2.root());
290 intersections
291 }
292
293 #[allow(dead_code)]
294 pub(crate) fn new(root1: &'a Node<N, T1>, root2: &'a Node<N, T2>) -> Self {
295 let mut intersections = IntersectionIterator {
296 left: root1.tree,
297 right: root2.tree,
298 todo_list: Vec::new(),
299 candidates: Vec::new(),
300 phantom: PhantomData,
301 };
302 intersections.add_intersecting_children(root1, root2);
303 intersections
304 }
305
306 fn push_if_intersecting(&mut self, node1: &'_ Node<N, T1>, node2: &'_ Node<N, T2>) {
307 if node1.intersects(node2) {
308 self.todo_list.push((node1.pos, node2.pos));
309 }
310 }
311
312 fn add_intersecting_children(&mut self, parent1: &'_ Node<N, T1>, parent2: &'_ Node<N, T2>) {
313 if !parent1.intersects(parent2) {
314 return;
315 }
316
317 let children1 = parent1
318 .children_unchecked()
319 .filter(|c1| c1.intersects(parent2));
320
321 let mut children2 = take(&mut self.candidates);
322 children2.extend(
323 parent2
324 .children_unchecked()
325 .filter(|c2| c2.intersects(parent1))
326 .map(|c| c.pos),
327 );
328
329 for child1 in children1 {
330 for child2 in &children2 {
331 self.push_if_intersecting(&child1, &Node::new(self.right, *child2));
332 }
333 }
334
335 children2.clear();
336 self.candidates = children2;
337 }
338}
339
340impl<N, T1, T2> Iterator for IntersectionIterator<'_, N, T1, T2>
341where
342 N: IndexableNum,
343 T1: RTreeIndex<N>,
344 T2: RTreeIndex<N>,
345{
346 type Item = (u32, u32);
347
348 fn next(&mut self) -> Option<Self::Item> {
349 while let Some((left_index, right_index)) = self.todo_list.pop() {
350 let left = Node::new(self.left, left_index);
351 let right = Node::new(self.right, right_index);
352 match (left.is_leaf(), right.is_leaf()) {
353 (true, true) => {
354 return Some((
355 left.insertion_index_unchecked(),
356 right.insertion_index_unchecked(),
357 ))
358 }
359 (true, false) => right
360 .children_unchecked()
361 .for_each(|c| self.push_if_intersecting(&left, &c)),
362 (false, true) => left
363 .children_unchecked()
364 .for_each(|c| self.push_if_intersecting(&c, &right)),
365 (false, false) => self.add_intersecting_children(&left, &right),
366 }
367 }
368 None
369 }
370}
371
372#[cfg(test)]
373mod test {
374 use super::*;
375 use crate::test::flatbush_js_test_index;
376
377 #[test]
378 fn test_node() {
379 let tree = flatbush_js_test_index();
380
381 let top_box = tree.boxes_at_level(2).unwrap();
382
383 assert_eq!(top_box.len(), 4);
385
386 let root_node = tree.root();
388 assert_eq!(root_node.min_x(), top_box[0]);
389 assert_eq!(root_node.min_y(), top_box[1]);
390 assert_eq!(root_node.max_x(), top_box[2]);
391 assert_eq!(root_node.max_y(), top_box[3]);
392
393 assert!(root_node.is_parent());
394
395 let level_1_boxes = tree.boxes_at_level(1).unwrap();
396 let level_1 = root_node.children_unchecked().collect::<Vec<_>>();
397 assert_eq!(level_1.len(), level_1_boxes.len() / 4);
398 }
399}
400
401#[cfg(test)]
402mod test_issue_42 {
403 use std::collections::HashSet;
404
405 use crate::rtree::sort::HilbertSort;
406 use crate::rtree::{RTreeBuilder, RTreeIndex};
407 use geo::Polygon;
408 use geo::{BoundingRect, Geometry};
409 use geozero::geo_types::GeoWriter;
410 use geozero::geojson::read_geojson_fc;
411 use rstar::primitives::GeomWithData;
412 use rstar::{primitives::Rectangle, AABB};
413 use zip::ZipArchive;
414
415 fn geo_contiguity(geom: &[Polygon]) -> HashSet<(usize, usize)> {
417 let to_insert = geom
418 .iter()
419 .enumerate()
420 .map(|(i, gi)| {
421 let rect = gi.bounding_rect().unwrap();
422 let aabb =
423 AABB::from_corners([rect.min().x, rect.min().y], [rect.max().x, rect.max().y]);
424
425 GeomWithData::new(Rectangle::from_aabb(aabb), i)
426 })
427 .collect::<Vec<_>>();
428
429 let tree = rstar::RTree::bulk_load(to_insert);
430 let candidates = tree
431 .intersection_candidates_with_other_tree(&tree)
432 .map(|(left_candidate, right_candidate)| (left_candidate.data, right_candidate.data));
433
434 HashSet::from_iter(candidates)
435 }
436
437 fn geo_index_contiguity(geoms: &Vec<Polygon>, node_size: u16) -> HashSet<(usize, usize)> {
439 let mut tree_builder = RTreeBuilder::new_with_node_size(geoms.len() as _, node_size);
440 for geom in geoms {
441 tree_builder.add_rect(&geom.bounding_rect().unwrap());
442 }
443 let tree = tree_builder.finish::<HilbertSort>();
444
445 let candidates = tree
446 .intersection_candidates_with_other_tree(&tree)
447 .map(|(l, r)| (l as usize, r as usize));
448
449 HashSet::from_iter(candidates)
450 }
451
452 #[test]
453 fn test_repro_issue_42() {
454 let file = std::fs::File::open("fixtures/issue_42.geojson.zip").unwrap();
455 let mut zip_archive = ZipArchive::new(file).unwrap();
456 let zipped_file = zip_archive.by_name("guerry.geojson").unwrap();
457 let reader = std::io::BufReader::new(zipped_file);
458
459 let mut geo_writer = GeoWriter::new();
460 read_geojson_fc(reader, &mut geo_writer).unwrap();
461
462 let geoms = match geo_writer.take_geometry().unwrap() {
463 Geometry::GeometryCollection(gc) => gc.0,
464 _ => panic!(),
465 };
466
467 let mut polys = vec![];
468 for geom in geoms {
469 let poly = match geom {
470 Geometry::Polygon(poly) => poly,
471 _ => panic!(),
472 };
473 polys.push(poly);
474 }
475
476 let geo_index_self_intersection = geo_index_contiguity(&polys, 10);
477 let geo_self_intersection = geo_contiguity(&polys);
478
479 assert_eq!(
480 geo_index_self_intersection, geo_self_intersection,
481 "The two intersections should match!"
482 );
483 }
484}