@@ -12,6 +12,10 @@ const MODEL_URL: &str = "https://arnismc.com/assets/3dmodels/stadium.glb";
1212const CACHE_FILE : & str = "stadium.glb" ;
1313
1414const MIN_SHORT_EXTENT_M : f32 = 10.0 ;
15+ /// Caps to avoid voxelizing absurd polygons (entire sports complexes mis-tagged as one stadium).
16+ const MAX_LONG_EXTENT_M : f32 = 500.0 ;
17+ const MAX_SHORT_EXTENT_M : f32 = 400.0 ;
18+ const MAX_HEIGHT_M : f32 = 200.0 ;
1519/// `leisure=stadium` qualifies on its own above this footprint area (m²).
1620const LARGE_STADIUM_AREA_M2 : f64 = 20_000.0 ;
1721/// Smaller `leisure=stadium` needs an inner `building=stadium` to qualify.
@@ -230,7 +234,7 @@ fn build_placement(element: &ProcessedElement, args_scale: f64) -> Option<Placem
230234 let ( long_blocks, short_blocks, theta) = principal_axis ( & points) ?;
231235 let long_m = ( long_blocks / args_scale) as f32 ;
232236 let short_m = ( short_blocks / args_scale) as f32 ;
233- if short_m < MIN_SHORT_EXTENT_M {
237+ if short_m < MIN_SHORT_EXTENT_M || long_m > MAX_LONG_EXTENT_M || short_m > MAX_SHORT_EXTENT_M {
234238 return None ;
235239 }
236240
@@ -239,7 +243,7 @@ fn build_placement(element: &ProcessedElement, args_scale: f64) -> Option<Placem
239243 . tags ( )
240244 . get ( "height" )
241245 . and_then ( |s| parse_meters ( s) )
242- . map ( |m| m as f32 ) ;
246+ . map ( |m| ( m as f32 ) . min ( MAX_HEIGHT_M ) ) ;
243247
244248 Some ( Placement {
245249 osm_id : element. id ( ) ,
@@ -835,6 +839,27 @@ mod tests {
835839 assert ! ( suppressed. contains( & ( "way" , 13 ) ) ) ;
836840 }
837841
842+ #[ test]
843+ fn prescan_rejects_oversize_stadium ( ) {
844+ // 1500×800 m — likely a whole sports complex mis-tagged. Above MAX_LONG_EXTENT_M.
845+ let mut tags = StdMap :: new ( ) ;
846+ tags. insert ( "leisure" . to_string ( ) , "stadium" . to_string ( ) ) ;
847+ let huge = ProcessedElement :: Way ( mk_way (
848+ 20 ,
849+ vec ! [
850+ mk_node( 200 , 0 , 0 ) ,
851+ mk_node( 201 , 1500 , 0 ) ,
852+ mk_node( 202 , 1500 , 800 ) ,
853+ mk_node( 203 , 0 , 800 ) ,
854+ ] ,
855+ tags,
856+ ) ) ;
857+ let empty = HashSet :: new ( ) ;
858+ let ( placements, suppressed) = prescan_offline ( & [ huge] , & empty) ;
859+ assert_eq ! ( placements. len( ) , 0 ) ;
860+ assert ! ( !suppressed. contains( & ( "way" , 20 ) ) ) ;
861+ }
862+
838863 #[ test]
839864 fn prescan_rejects_standalone_small_building_stadium ( ) {
840865 let mut tags = StdMap :: new ( ) ;
0 commit comments