fix(extract): Sperrflächen auch aus Zufahrtsflächen ausschneiden und davor warnen

Zufahrtsflächen (highway=service) wurden bisher ungeschnitten ausgegeben und nicht auf
Überschneidung mit Sperrflächen geprüft. Am echten Stand überlappte eine Zufahrt die
Sperrfläche "tribuene" um 42,17 m² ohne Schnitt und ohne Warnung. build_layout wendet
difference(blocked) jetzt auch auf Zufahrten an, die Warnschleife prüft Wege und
Zufahrten getrennt ("Parkweg schneidet ..." / "Zufahrt schneidet ...").

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
knsoandClaude Sonnet 5 committed 2026-09-16 07:20:41 +02:00
1 parent 26aafbbbd5
commit d756eccd77
2 files changed
+22 -4

No files matched your search

+13 -4
View File
@@ -338,23 +338,32 @@ def build_layout(elements: list[dict], config, fit: ParkFit) -> ParkLayout:
if kind is not None: if kind is not None:
surfaces[kind].extend(_polygons(game_poly.difference(blocked))) surfaces[kind].extend(_polygons(game_poly.difference(blocked)))
warnings, paths = [], [] warnings, paths, service_polys = [], [], []
if footways: if footways:
union = unary_union(footways) union = unary_union(footways)
warnings = [f"Parkweg schneidet die Sperrfläche {k.name}" warnings += _keepout_warnings(union, config.keepouts, keepouts, "Parkweg")
for k, polygon in zip(config.keepouts, keepouts) if union.intersects(polygon)]
paths = _polygons(union.difference(blocked)) paths = _polygons(union.difference(blocked))
if service:
service_union = unary_union(service)
warnings += _keepout_warnings(service_union, config.keepouts, keepouts, "Zufahrt")
service_polys = _polygons(service_union.difference(blocked))
return ParkLayout( return ParkLayout(
lawn=fit.game_quad, lawn=fit.game_quad,
surfaces=[(poly, kind) for kind in SURFACE_ORDER for poly in surfaces[kind]], surfaces=[(poly, kind) for kind in SURFACE_ORDER for poly in surfaces[kind]],
paths=paths, paths=paths,
service=_polygons(unary_union(service)) if service else [], service=service_polys,
buildings=buildings, buildings=buildings,
keepouts=keepouts, keepouts=keepouts,
warnings=warnings, warnings=warnings,
) )
def _keepout_warnings(union, config_keepouts, keepout_polys, label: str) -> list[str]:
"""Warnungstexte für alle Sperrflächen, die `union` (Parkwege oder Zufahrten) schneiden."""
return [f"{label} schneidet die Sperrfläche {k.name}"
for k, polygon in zip(config_keepouts, keepout_polys) if union.intersects(polygon)]
def _surface_kind(tags: dict) -> str | None: def _surface_kind(tags: dict) -> str | None:
sports = set(tags.get("sport", "").split(";")) sports = set(tags.get("sport", "").split(";"))
leisure = tags.get("leisure") leisure = tags.get("leisure")
+9
View File
@@ -137,3 +137,12 @@ def test_service_ways_become_six_metre_service_surfaces():
(service,) = result.service (service,) = result.service
assert service.contains(Point(1100, 1042.9)) and not service.contains(Point(1100, 1043.1)) assert service.contains(Point(1100, 1042.9)) and not service.contains(Point(1100, 1043.1))
assert result.paths == [] assert result.paths == []
def test_keepouts_cut_service_surfaces_and_warn():
keepout = Keepout("ort", (1100.0, 1100.0), 0.0, (-10.0, 10.0, -10.0, 10.0)) # Welt x 1090–1110, y 1090–1110
result = layout([way({"highway": "service"}, (30, 50), (70, 50))], # Welt x 1080–1120, y 1100
keepouts=[keepout])
hole = keepout_polygon(keepout)
assert result.service and all(poly.intersection(hole).area < 1e-6 for poly in result.service)
assert result.warnings == ["Zufahrt schneidet die Sperrfläche ort"]