Execute a spatial join using R-tree probe. `indexed_side`: R-tree built on one collection. `probe_side`: entries from the other collection to probe against. `get_geometry`: callback to retrieve the full geometry for an entry ID (needed for exact predicate evaluation after R-tree bbox filter). `predicate`: which spatial predicate to apply (intersects, contains, etc.).
(
indexed_side: &RTree,
probe_entries: &[(u64, BoundingBox)],
get_indexed_geom: &dyn Fn(u64) -> Option<Geometry>,
get_probe_geom: &dyn Fn(u64) -> Option<Geometry>,
predicate: Spati
| 37 | /// (needed for exact predicate evaluation after R-tree bbox filter). |
| 38 | /// `predicate`: which spatial predicate to apply (intersects, contains, etc.). |
| 39 | pub fn spatial_join( |
| 40 | indexed_side: &RTree, |
| 41 | probe_entries: &[(u64, BoundingBox)], |
| 42 | get_indexed_geom: &dyn Fn(u64) -> Option<Geometry>, |
| 43 | get_probe_geom: &dyn Fn(u64) -> Option<Geometry>, |
| 44 | predicate: SpatialJoinPredicate, |
| 45 | ) -> SpatialJoinResult { |
| 46 | let mut pairs = Vec::new(); |
| 47 | let mut probes = 0; |
| 48 | let mut exact_evals = 0; |
| 49 | |
| 50 | for &(probe_id, ref probe_bbox) in probe_entries { |
| 51 | // R-tree range search: find indexed entries whose bbox intersects probe bbox. |
| 52 | let candidates = indexed_side.search(probe_bbox); |
| 53 | probes += 1; |
| 54 | |
| 55 | for candidate in &candidates { |
| 56 | // Exact predicate evaluation. |
| 57 | let Some(indexed_geom) = get_indexed_geom(candidate.id) else { |
| 58 | continue; |
| 59 | }; |
| 60 | let Some(probe_geom) = get_probe_geom(probe_id) else { |
| 61 | continue; |
| 62 | }; |
| 63 | exact_evals += 1; |
| 64 | |
| 65 | let matches = match predicate { |
| 66 | SpatialJoinPredicate::Intersects => { |
| 67 | predicates::st_intersects(&probe_geom, &indexed_geom) |
| 68 | } |
| 69 | SpatialJoinPredicate::Contains => { |
| 70 | predicates::st_contains(&probe_geom, &indexed_geom) |
| 71 | } |
| 72 | SpatialJoinPredicate::Within => predicates::st_within(&probe_geom, &indexed_geom), |
| 73 | SpatialJoinPredicate::DWithin(dist) => { |
| 74 | predicates::st_dwithin(&probe_geom, &indexed_geom, dist) |
| 75 | } |
| 76 | }; |
| 77 | |
| 78 | if matches { |
| 79 | pairs.push((probe_id, candidate.id)); |
| 80 | } |
| 81 | } |
| 82 | } |
| 83 | |
| 84 | SpatialJoinResult { |
| 85 | pairs, |
| 86 | probes, |
| 87 | exact_evals, |
| 88 | } |
| 89 | } |
| 90 | |
| 91 | /// Build an R-tree from a list of (entry_id, geometry) pairs for join. |
| 92 | pub fn build_join_index(entries: &[(u64, Geometry)]) -> RTree { |