Skip to content

Commit 207226b

Browse files
committed
working rtree intersector impl
1 parent a36f696 commit 207226b

File tree

2 files changed

+72
-22
lines changed

2 files changed

+72
-22
lines changed

geo/CHANGES.md

+4
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@
33

44
## Unreleased
55

6+
* POSSIBLY BREAKING: `GeoFloat` types must now implement `num_traits::Signed` and `num_traits::Bounded`. This shouldn't
7+
affect you if you are using a standard `Geometry<f64>` or `Geometry<f32>` or `geo::GeoFloat` generically.
8+
* Speed up `Relate` and `Contains` traits for large LineStrings and Polygons by using an RTree to more efficiently
9+
inspect edges in our topology graph.
610
* Speed up intersection checks by using a preliminary bbox check
711
* Remove unneeded reference for `*MapCoords*` closure parameter.
812
* <https://github.com/georust/geo/pull/810>

geo/src/algorithm/relate/geomgraph/index/rstar_edge_set_intersector.rs

+68-22
Original file line numberDiff line numberDiff line change
@@ -5,41 +5,71 @@ use crate::GeoFloat;
55
use std::cell::RefCell;
66
use std::rc::Rc;
77

8+
use rstar::RTree;
9+
810
pub(crate) struct RstarEdgeSetIntersector;
911

1012
impl RstarEdgeSetIntersector {
1113
pub fn new() -> Self {
1214
RstarEdgeSetIntersector
1315
}
16+
}
1417

15-
fn compute_intersects<F: GeoFloat>(
16-
&mut self,
17-
edge0: &Rc<RefCell<Edge<F>>>,
18-
edge1: &Rc<RefCell<Edge<F>>>,
19-
segment_intersector: &mut SegmentIntersector<F>,
20-
) {
21-
let edge0_coords_len = edge0.borrow().coords().len() - 1;
22-
let edge1_coords_len = edge1.borrow().coords().len() - 1;
23-
for i0 in 0..edge0_coords_len {
24-
for i1 in 0..edge1_coords_len {
25-
segment_intersector.add_intersections(edge0, i0, edge1, i1);
26-
}
18+
struct Segment<'a, F: GeoFloat + rstar::RTreeNum> {
19+
i: usize,
20+
edge: &'a RefCell<Edge<F>>,
21+
envelope: rstar::AABB<crate::Coordinate<F>>,
22+
}
23+
24+
impl<'a, F> Segment<'a, F>
25+
where
26+
F: GeoFloat + rstar::RTreeNum,
27+
{
28+
fn new(i: usize, edge: &'a RefCell<Edge<F>>) -> Self {
29+
use crate::rstar::RTreeObject;
30+
let p1 = edge.borrow().coords()[i];
31+
let p2 = edge.borrow().coords()[i + 1];
32+
Self {
33+
i,
34+
edge,
35+
envelope: rstar::AABB::from_corners(p1, p2),
2736
}
2837
}
2938
}
3039

31-
impl<F: GeoFloat> EdgeSetIntersector<F> for RstarEdgeSetIntersector {
40+
impl<'a, F> rstar::RTreeObject for Segment<'a, F>
41+
where
42+
F: GeoFloat + rstar::RTreeNum,
43+
{
44+
type Envelope = rstar::AABB<crate::Coordinate<F>>;
45+
46+
fn envelope(&self) -> Self::Envelope {
47+
self.envelope
48+
}
49+
}
50+
51+
impl<F> EdgeSetIntersector<F> for RstarEdgeSetIntersector
52+
where
53+
F: GeoFloat + rstar::RTreeNum,
54+
{
3255
fn compute_intersections_within_set(
3356
&mut self,
3457
edges: &[Rc<RefCell<Edge<F>>>],
3558
check_for_self_intersecting_edges: bool,
3659
segment_intersector: &mut SegmentIntersector<F>,
3760
) {
38-
for edge0 in edges.iter() {
39-
for edge1 in edges.iter() {
40-
if check_for_self_intersecting_edges || edge0.as_ptr() != edge1.as_ptr() {
41-
self.compute_intersects(edge0, edge1, segment_intersector);
42-
}
61+
let segments: Vec<Segment<F>> = edges
62+
.iter()
63+
.flat_map(|edge| {
64+
let start_of_final_segment: usize = RefCell::borrow(edge).coords().len() - 1;
65+
(0..start_of_final_segment).map(|segment_i| Segment::new(segment_i, edge))
66+
})
67+
.collect();
68+
let tree = RTree::bulk_load(segments);
69+
70+
for (edge0, edge1) in tree.intersection_candidates_with_other_tree(&tree) {
71+
if check_for_self_intersecting_edges || edge0.edge.as_ptr() != edge1.edge.as_ptr() {
72+
segment_intersector.add_intersections(edge0.edge, edge0.i, edge1.edge, edge1.i);
4373
}
4474
}
4575
}
@@ -50,10 +80,26 @@ impl<F: GeoFloat> EdgeSetIntersector<F> for RstarEdgeSetIntersector {
5080
edges1: &[Rc<RefCell<Edge<F>>>],
5181
segment_intersector: &mut SegmentIntersector<F>,
5282
) {
53-
for edge0 in edges0 {
54-
for edge1 in edges1 {
55-
self.compute_intersects(edge0, edge1, segment_intersector);
56-
}
83+
let segments0: Vec<Segment<F>> = edges0
84+
.iter()
85+
.flat_map(|edge| {
86+
let start_of_final_segment: usize = RefCell::borrow(edge).coords().len() - 1;
87+
(0..start_of_final_segment).map(|segment_i| Segment::new(segment_i, edge))
88+
})
89+
.collect();
90+
let tree_0 = RTree::bulk_load(segments0);
91+
92+
let segments1: Vec<Segment<F>> = edges1
93+
.iter()
94+
.flat_map(|edge| {
95+
let start_of_final_segment: usize = RefCell::borrow(edge).coords().len() - 1;
96+
(0..start_of_final_segment).map(|segment_i| Segment::new(segment_i, edge))
97+
})
98+
.collect();
99+
let tree_1 = RTree::bulk_load(segments1);
100+
101+
for (edge0, edge1) in tree_0.intersection_candidates_with_other_tree(&tree_1) {
102+
segment_intersector.add_intersections(edge0.edge, edge0.i, edge1.edge, edge1.i);
57103
}
58104
}
59105
}

0 commit comments

Comments
 (0)