Skip to content

Commit 7ab670f

Browse files
Fix #656: honor role=part for building footprints to prevent trees inside buildings
1 parent c0fad13 commit 7ab670f

1 file changed

Lines changed: 60 additions & 0 deletions

File tree

src/floodfill_cache.rs

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,12 @@ impl FloodFillCache {
438438
for_relation_ring_cells(rel, ProcessedMemberRole::Outer, xzbbox, |x, z| {
439439
footprints.set(x, z)
440440
});
441+
// type=building relations frequently carry geometry as role=part
442+
// members with no outer/inner shell; include those rings so
443+
// vegetation blockers see the full building footprint.
444+
for_relation_ring_cells(rel, ProcessedMemberRole::Part, xzbbox, |x, z| {
445+
footprints.set(x, z)
446+
});
441447
for_relation_ring_cells(rel, ProcessedMemberRole::Inner, xzbbox, |x, z| {
442448
footprints.clear(x, z)
443449
});
@@ -518,6 +524,60 @@ fn for_relation_ring_cells(
518524
}
519525
}
520526

527+
#[cfg(test)]
528+
mod tests {
529+
use super::*;
530+
use crate::osm_parser::{ProcessedMember, ProcessedNode, ProcessedRelation};
531+
use std::collections::HashMap;
532+
533+
fn node(id: u64, x: i32, z: i32) -> ProcessedNode {
534+
ProcessedNode {
535+
id,
536+
tags: HashMap::new(),
537+
x,
538+
z,
539+
}
540+
}
541+
542+
fn closed_square_way(id: u64, min_x: i32, min_z: i32, max_x: i32, max_z: i32) -> ProcessedWay {
543+
ProcessedWay {
544+
id,
545+
tags: HashMap::new(),
546+
nodes: vec![
547+
node(id * 10 + 1, min_x, min_z),
548+
node(id * 10 + 2, max_x, min_z),
549+
node(id * 10 + 3, max_x, max_z),
550+
node(id * 10 + 4, min_x, max_z),
551+
node(id * 10 + 5, min_x, min_z),
552+
],
553+
}
554+
}
555+
556+
#[test]
557+
fn building_relation_part_members_contribute_footprints() {
558+
let xzbbox = XZBBox::rect_from_min_max(0, 0, 40, 40).unwrap();
559+
let part_way = Arc::new(closed_square_way(11, 10, 10, 20, 20));
560+
561+
let relation = ProcessedRelation {
562+
id: 1,
563+
tags: HashMap::from([("type".to_string(), "building".to_string())]),
564+
members: vec![ProcessedMember {
565+
role: ProcessedMemberRole::Part,
566+
way: part_way,
567+
}],
568+
};
569+
570+
let elements = vec![ProcessedElement::Relation(relation)];
571+
let cache = FloodFillCache::new();
572+
let footprints = cache.collect_building_footprints(&elements, &xzbbox);
573+
574+
assert!(
575+
footprints.contains(15, 15),
576+
"role=part geometry in type=building relations must mark building footprint"
577+
);
578+
}
579+
}
580+
521581
/// Configures the global Rayon thread pool with a CPU usage cap.
522582
///
523583
/// Call this once at startup before any parallel operations.

0 commit comments

Comments
 (0)