bambam_osm/algorithm/clustering/
clustering_rtree.rs1use crate::model::osm::graph::OsmNodeId;
2
3use super::ClusteredGeometry;
4use geo::{BoundingRect, Coord, Polygon};
5use itertools::Itertools;
6use kdam::tqdm;
7use rstar::primitives::{GeomWithData, Rectangle};
8use rstar::{RTree, RTreeObject};
9use wkt::ToWkt;
10
11pub type ClusteredIntersections = GeomWithData<Rectangle<(f32, f32)>, ClusteredGeometry>;
12
13pub fn build(
18 geometries: &[(OsmNodeId, Polygon<f32>)],
19) -> Result<RTree<ClusteredIntersections>, String> {
20 let mut rtree: RTree<ClusteredIntersections> = RTree::new();
23 let iter = tqdm!(
24 geometries.iter(),
25 total = geometries.len(),
26 desc = "spatial intersection"
27 );
28
29 for (index, polygon) in iter {
31 let rect = rect_from_geometries(&[polygon])?;
32 let query = GeomWithData::new(rect, ClusteredGeometry::new(*index, polygon.clone()));
33 let intersecting = rtree
34 .drain_in_envelope_intersecting(query.envelope())
35 .sorted_by_key(|obj| obj.data.ids())
36 .collect_vec();
37 if intersecting.is_empty() {
38 rtree.insert(query);
40 } else {
41 let mut new_cluster = ClusteredGeometry::new(*index, polygon.clone());
43
44 for obj in intersecting.into_iter() {
45 if obj.data.intersects(polygon) {
48 new_cluster.merge_and_sort_with(&obj.data);
50 } else {
51 rtree.insert(obj);
54 }
55 }
56
57 let new_rect = rect_from_geometries(&new_cluster.polygons())?;
58 let new_obj = GeomWithData::new(new_rect, new_cluster);
59 rtree.insert(new_obj);
60 }
61 }
62 eprintln!();
63
64 Ok(rtree)
65}
66
67fn rect_from_geometries(ps: &[&Polygon<f32>]) -> Result<Rectangle<(f32, f32)>, String> {
69 if ps.is_empty() {
70 return Err(String::from(
71 "rect_from_geometries called with empty collection",
72 ));
73 }
74 let mut mins = vec![];
75 let mut maxs = vec![];
76 for p in ps {
77 let bbox_rect = p.bounding_rect().ok_or_else(|| {
78 format!(
79 "internal error: cannot get bounds of geometry: '{}'",
80 p.to_wkt()
81 )
82 })?;
83 mins.push(bbox_rect.min());
84 maxs.push(bbox_rect.max());
85 }
86 let min_coord = mins
87 .into_iter()
88 .min_by_key(ordering_key)
89 .ok_or_else(|| String::from("internal error: empty 'mins' collection"))?;
90 let max_coord = maxs
91 .into_iter()
92 .max_by_key(ordering_key)
93 .ok_or_else(|| String::from("internal error: empty 'maxs' collection"))?;
94 let envelope = Rectangle::from_corners(min_coord.x_y(), max_coord.x_y());
95 Ok(envelope)
96}
97
98fn ordering_key(coord: &Coord<f32>) -> (i64, i64) {
102 let x = (coord.x * 100_000.0) as i64;
103 let y = (coord.y * 100_000.0) as i64;
104 (x, y)
105}