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>
65 lines
2.6 KiB
Python
65 lines
2.6 KiB
Python
"""Kanten an einer Sperrfläche schneiden und neue Kanten anhängen."""
|
|
from __future__ import annotations
|
|
|
|
from shapely.geometry import LineString, box
|
|
|
|
from leonida.roads import Edge, Graph, MIN_EDGE, Node, attach, cut_edges
|
|
|
|
|
|
def strecke() -> Graph:
|
|
return Graph(nodes=[Node((0.0, 0.0)), Node((100.0, 0.0))],
|
|
edges=[Edge(0, 1, [(0.0, 0.0), (100.0, 0.0)], 12.0, "wohnstrasse")])
|
|
|
|
|
|
def test_schnitt_in_der_mitte_gibt_zwei_kanten():
|
|
out = cut_edges(strecke(), box(40, -5, 60, 5))
|
|
assert len(out.edges) == 2
|
|
längen = sorted(round(LineString(e.points).length) for e in out.edges)
|
|
assert längen == [40, 40]
|
|
|
|
|
|
def test_reste_unter_der_mindestlaenge_fallen_weg():
|
|
# Schnitt bei 90..96: übrig bleiben 90 m; das 4-m-Stück von 96 bis 100 liegt unter MIN_EDGE
|
|
# und fällt weg. (Ein Schnitt bis ans Streckenende, z.B. 96..104, verschluckt den Rest schon
|
|
# geometrisch mit - das würde den MIN_EDGE-Filter gar nicht prüfen, weil dann kein Stück unter
|
|
# der Grenze übrig bliebe, das erst noch verworfen werden müsste.)
|
|
out = cut_edges(strecke(), box(90, -5, 96, 5))
|
|
assert len(out.edges) == 1
|
|
assert round(LineString(out.edges[0].points).length) == 90
|
|
assert MIN_EDGE == 5.0
|
|
|
|
|
|
def test_ganz_verdeckte_kante_verschwindet():
|
|
assert cut_edges(strecke(), box(-10, -10, 110, 10)).edges == []
|
|
|
|
|
|
def test_unberuehrte_kante_bleibt_wie_sie_ist():
|
|
out = cut_edges(strecke(), box(200, -5, 220, 5))
|
|
assert out.edges[0].points == [(0.0, 0.0), (100.0, 0.0)]
|
|
assert out.edges[0].klass == "wohnstrasse"
|
|
|
|
|
|
def test_kurze_reststuecke_werden_keine_schleifen():
|
|
# Genau das Fenster, das die Senkung von MIN_CENTERLINE (15 m) auf MIN_EDGE (5 m) geöffnet
|
|
# hat: ein 6-m-Rest liegt noch im 8-m-Anhängeradius seines eigenen alten Endpunkts. Ein
|
|
# Schnitt, der beide Enden über attach() sucht, würde dort denselben Knoten zweimal finden
|
|
# und aus dem geraden Stummel eine Schleife machen (Edge mit a == b).
|
|
out = cut_edges(strecke(), box(6, -5, 94, 5))
|
|
assert len(out.edges) == 2
|
|
assert all(e.a != e.b for e in out.edges), "ein gerader Stummel darf keine Schleife werden"
|
|
längen = sorted(round(LineString(e.points).length) for e in out.edges)
|
|
assert längen == [6, 6]
|
|
|
|
|
|
def test_attach_findet_einen_nahen_knoten():
|
|
graph = strecke()
|
|
assert attach(graph, (100.0, 3.0)) == 1, "3 m entfernt: derselbe Knoten"
|
|
assert len(graph.nodes) == 2
|
|
|
|
|
|
def test_attach_legt_sonst_einen_neuen_knoten_an():
|
|
graph = strecke()
|
|
neu = attach(graph, (100.0, 40.0))
|
|
assert neu == 2
|
|
assert graph.nodes[neu].point == (100.0, 40.0)
|