fix(extract): cut_edges() bildet keine Schleifen mehr, Straßen kreuzen das Netz statt es zu überlagern

Fixrunde 1 zu Task 11, zwei von der Koordination gefundene und am echten Netz nachgemessene
Fehler, beide durch die Senkung von MIN_CENTERLINE (15 m) auf MIN_EDGE (5 m) erst möglich:

1. cut_edges() hängte beide Enden eines Schnittstücks über attach() an - dessen 8-m-Umkreis fand
   bei einem Reststück zwischen 5 und 8 m Länge für beide Enden denselben ursprünglichen Knoten
   und machte aus dem geraden Stummel eine Schleife. section.py hält jeden Knoten ab Grad 3 für
   eine Kreuzung; an einem Sackgassenende wären dort Kreuzungsfläche, Zebrastreifen und
   Haltelinie entstanden. Die neue _cut_end() sucht nicht mehr im Umkreis, sondern nur noch nach
   exakter Übereinstimmung mit einem der beiden ursprünglichen Kantenenden.

2. apply_street() hängte die Jefferson Avenue nur mit einem attach()-Paar an ihre beiden Enden.
   Am echten Netz liegt ihr Nordende 23,2 m von jedem Knoten entfernt, aber die Straße kreuzt auf
   dem Weg zu ihrem Südende (6,6 m von Knoten 561) die 11th Street mittendrin, ohne dass dort ein
   Knoten entsteht - zwei Fahrbahnen hätten sich unverbunden überlagert. Die neue insert_edge()
   bricht jede gekreuzte Kante am Kreuzungspunkt auf und teilt sich dort einen Knoten mit der
   neuen Straße (mit attach() für die Knotenwahl, wie gehabt); apply_street() benutzt sie jetzt
   statt des attach()-Paars.

Am echten Netz (1.537 Knoten, 1.790 Kanten vor Flamingo Park) bestätigt: Jefferson Avenue bricht
jetzt korrekt an der 11th Street auf (neuer Knoten, Grad 4) und hängt am Südende weiterhin an
Knoten 561 (Grad 3 -> 4); die Meldezeile und die Sperrflächen-Warnung blieben wörtlich. Die
Schleifenzahl im Gesamtnetz sank von 196 auf 193 (die Park-Anlage schneidet alte Schleifen im
Parkgebiet weg), keine der verbliebenen 193 entstand neu - jede hat ein Vor-Park-Gegenstück im
5-m-Umkreis. Keine Kante unter 1 m, weder vorher noch nachher.

Neue Tests: test_roads_cut.py (Schleifenregression), test_roads_insert.py (drei Szenarien:
Kreuzung in der Mitte, Anhängen an einen Grad-3-Knoten, Kreuzungspunkt nahe einem vorhandenen
Knoten), test_park_street.py (Knotengrad an beiden Kreuzungen der Park-Zufahrtsstraße).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
knsoandClaude Sonnet 5 committed 2026-09-17 17:26:42 +02:00
1 parent 8bc8ca19fc
commit 1f09e7b1d9
5 files changed
+166 -11

No files matched your search

+15 -2
View File
@@ -51,14 +51,27 @@ def test_alley_centerline_shrinks_to_its_stubs_and_the_street_gets_its_own():
wählten ihre Straßenseite über den Listenindex und liefen an der Kreuzung sonst ins Leere -
entfällt, sobald eine spätere Aufgabe die Seite aus der Geometrie bestimmt statt aus der
Liste. Die beiden 11-m-Enden bleiben deshalb jetzt als eigene, kurze Kanten stehen.
Die neue Straße kreuzt dabei selbst beide Querstraßen bei y=650 und y=330 (insert_edge(),
Fixrunde 1): an beiden Stellen muss ein echter Knoten mit Grad >= 3 entstehen, sonst läge die
neue Fahrbahn nur unverbunden über der alten - genau der Fehler, den ein reines attach() an
den beiden Enden nicht gesehen hätte, weil die Kreuzung nicht an einem Ende liegt, sondern
mittendrin. Die Straße selbst zerfällt deshalb jetzt in drei Stücke statt eines.
"""
result = apply_street(world(), STREET)
lines = [LineString(e.points) for e in result.graph.edges]
assert sorted(round(line.length) for line in lines if line.length < 15) == [11, 11]
assert sorted(round(line.length) for line in lines if line.length < 15) == [10, 10, 11, 11]
assert all(line.distance(Point(100, 500)) > 40 for line in lines)
assert any(e.points == [tuple(STREET.start), tuple(STREET.end)] for e in result.graph.edges)
assert all(line.length >= MIN_EDGE for line in lines)
for x, y in ((150.0, 650.0), (150.0, 330.0)):
knoten = next(k for k, n in enumerate(result.graph.nodes) if n.point == (x, y))
assert result.graph.degree(knoten) >= 3, f"Kreuzung bei ({x:g}, {y:g}) ohne echten Knoten"
assert any(e.points == [(150.0, 660.0), (150.0, 650.0)] for e in result.graph.edges)
assert any(e.points == [(150.0, 650.0), (150.0, 330.0)] for e in result.graph.edges)
assert any(e.points == [(150.0, 330.0), (150.0, 320.0)] for e in result.graph.edges)
def test_freed_ground_becomes_urban_but_not_under_the_street_buildings_or_old_urban():
result = apply_street(world(), STREET)