@@ -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