fix(extract): _sidewalk() legt nur dort Gehweg an, wo die Klasse ihn vorsieht

Der eigene Fix aus der letzten Runde (_lots() zieht carriage.buffer(WALK_MAX) ab)
hatte einen neuen Fehler eingeführt: Der klassenunabhängige 3-m-Abzug frisst bei
der Gasse (walk=0,0, gar kein Gehweg) und bei der Wohnstraße (walk=2,5, nicht 3,0)
mehr weg, als dort tatsächlich Gehweg ist - eine echte Pflasterfläche neben einer
Gasse wurde bis zu WALK_MAX komplett als Gehweg gezählt statt als Restfläche.

An der Wurzel behoben: _kerbless_zone(graph, extra) berechnet den Korridor aller
Klassen ohne Bordstein aus der vollen Kantenmittellinie, mit extra als Parameter
statt festem Wert - _kerb_lines() ruft sie mit extra=0.2 auf (schmale Fuge an der
physischen Kante, unveraendert), _sidewalk() mit extra=WALK_MAX (muss die volle
Gehweg-Reichweite abdecken, sonst bliebe ein bis zu 2,8 m breiter Streifen
faelschlich Gehweg). Ein einzelner fester Radius fuer beide Zwecke funktioniert
nicht: zu schmal laesst echten Gehweg als Gehweg einer Klasse ohne Gehweg stehen,
zu breit schneidet er benachbarten, legitimen Bordstein weg - nachgerechnet mit
der vom Fix-Auftrag selbst vorgeschlagenen Testfixture, bevor der feste Wert
uebernommen wurde.

_lots() rechnet jetzt exakt (corridor.difference(carriage).difference(sidewalk))
statt mit einem eigenen Puffer, wie vorgegeben.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
knsoandClaude Sonnet 5 committed 2026-09-17 05:35:34 +02:00
1 parent 377a95f3dd
commit 167af5fc0b
2 files changed
+66 -26

No files matched your search

+29 -3
View File
@@ -32,9 +32,9 @@ def test_gasse_bekommt_weder_gehweg_noch_bordstein():
street = build_street(strasse("gasse"), korridor("gasse"), bridges=[])
assert street.sidewalk.area < 0.01
assert street.kerb == []
# Der Grenzfall fuer die MultiPolygon-Zusage: ein leeres Ergebnis kaeme ohne Normalisierung
# als leeres Polygon zurueck, nicht als leeres MultiPolygon (wie carriageway_area() es seit
# Task 6 zusagt) - Task 10/12 iterieren ueber .geoms und wuerden daran brechen.
# Der Grenzfall für die MultiPolygon-Zusage: ein leeres Ergebnis käme ohne Normalisierung
# als leeres Polygon zurück, nicht als leeres MultiPolygon (wie carriageway_area() es seit
# Task 6 zusagt) - Task 10/12 iterieren über .geoms und würden daran brechen.
assert street.sidewalk.geom_type == "MultiPolygon"
@@ -104,3 +104,29 @@ def test_bordstein_frei_an_kurzer_gasseneinmuendung():
gassenkorridor = LineString([(50.0, 0.0), (50.0, -5.0)]).buffer(SECTION["gasse"].carriageway / 2)
for line in street.kerb:
assert not gassenkorridor.intersects(line), "die Zufahrt bleibt frei, kein Bordstein quer davor"
def test_pflasterflaeche_neben_der_gasse_ist_restflaeche_kein_gehweg():
# Fixrunde 2: die Gasse hat laut SECTION überhaupt keinen Gehweg (walk=0.0). Eine echte,
# 3 m tiefe, 100 m lange Pflasterfläche direkt neben ihr - z.B. ein durchgehender Hofstreifen,
# den die Kartierung mit zur Straßenfläche zählt - darf nicht zu Gehweg werden, nur weil
# WALK_MAX=3.0 dort zufällig genau hinreicht. Sie muss als Restfläche erscheinen.
pflaster = box(0, 3, 100, 6)
weit = unary_union([korridor("gasse"), pflaster])
street = build_street(strasse("gasse"), weit, bridges=[])
assert street.sidewalk.area < 0.01, "die Gasse bekommt so wenig Gehweg wie sonst: keinen"
assert any(lot.area > 250 for lot in street.lots), "die Pflasterfläche bleibt als Restfläche"
def test_fahrbahn_gehweg_und_rest_ergeben_wieder_den_korridor():
# Die drei Teile dürfen sich weder überlappen noch eine Lücke lassen - unabhängig vom
# LOT_MIN-Filter in street.lots prüfen wir hier den *rohen* Rest (vor dem Filter), denn nur
# der ergänzt Fahrbahn und Gehweg exakt wieder zum Korridor.
weit = unary_union([korridor(), box(40, 6, 70, 36), box(10, 8, 12, 9)])
street = build_street(strasse(), weit, bridges=[])
roh = weit.difference(street.carriageway).difference(street.sidewalk)
assert street.carriageway.intersection(street.sidewalk).area < 1e-6
assert street.carriageway.intersection(roh).area < 1e-6
assert street.sidewalk.intersection(roh).area < 1e-6
bilanz = street.carriageway.area + street.sidewalk.area + roh.area
assert abs(bilanz - weit.area) < 1e-6