Files
gta6/tools/extract/tests/test_roads_insert.py
T
knsoandClaude Sonnet 5 1f09e7b1d9 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>
2026-09-17 17:26:42 +02:00

54 lines
2.8 KiB
Python

"""Eine von Hand ergänzte Straße ins Netz einfügen, mit echten Knoten an ihren Kreuzungen."""
from __future__ import annotations
from leonida.roads import Edge, Graph, Node, insert_edge
def kreuz() -> Graph:
"""Eine 100 m lange Straße bei y = 50, von (0,50) nach (100,50)."""
return Graph(nodes=[Node((0.0, 50.0)), Node((100.0, 50.0))],
edges=[Edge(0, 1, [(0.0, 50.0), (100.0, 50.0)], 12.0, "wohnstrasse")])
def test_kreuzung_in_der_mitte_bekommt_einen_knoten_mit_grad_4():
out = insert_edge(kreuz(), [(50.0, 0.0), (50.0, 100.0)], 12.0, "wohnstrasse")
knoten = next(k for k, n in enumerate(out.nodes) if n.point == (50.0, 50.0))
assert out.degree(knoten) == 4
assert not any(e.a == e.b for e in out.edges)
def t_kreuzung() -> Graph:
"""Ein T bei (50,0): die Strecke (0,0)-(100,0) durchgehend, ein Ast nach Norden - Grad 3."""
return Graph(nodes=[Node((0.0, 0.0)), Node((100.0, 0.0)), Node((50.0, 0.0)), Node((50.0, 50.0))],
edges=[Edge(0, 2, [(0.0, 0.0), (50.0, 0.0)], 12.0, "wohnstrasse"),
Edge(2, 1, [(50.0, 0.0), (100.0, 0.0)], 12.0, "wohnstrasse"),
Edge(2, 3, [(50.0, 0.0), (50.0, 50.0)], 12.0, "wohnstrasse")])
def test_neues_ende_haengt_sich_an_einen_knoten_mit_grad_3():
graph = t_kreuzung()
assert graph.degree(2) == 3
# (54,6) liegt 7,2 m von Knoten 2 entfernt (< JUNCTION_RADIUS), aber auf keiner der drei
# vorhandenen Kanten - reine Anhänge-Nähe, keine Kreuzung.
out = insert_edge(graph, [(54.0, 6.0), (94.0, 46.0)], 6.0, "gasse")
assert out.degree(2) == 4
assert len(out.nodes) == 5, "nur das ferne Ende der neuen Gasse ist ein neuer Knoten"
def kreuz_mit_nahem_knoten() -> Graph:
"""kreuz(), dazu ein Sackgassenfuss 5,7 m neben der kommenden Kreuzung bei (50,50)."""
return Graph(nodes=[Node((0.0, 50.0)), Node((100.0, 50.0)), Node((54.0, 54.0)), Node((54.0, 90.0))],
edges=[Edge(0, 1, [(0.0, 50.0), (100.0, 50.0)], 12.0, "wohnstrasse"),
Edge(2, 3, [(54.0, 54.0), (54.0, 90.0)], 6.0, "gasse")])
def test_kreuzungspunkt_nahe_einem_knoten_bekommt_keinen_zweiten():
"""Regel b: ein Kreuzungspunkt im 8-m-Umkreis eines vorhandenen Knotens bekommt keinen
eigenen neuen Knoten - sonst lägen zwei Knoten nur wenige Meter auseinander."""
out = insert_edge(kreuz_mit_nahem_knoten(), [(50.0, 0.0), (50.0, 100.0)], 12.0, "wohnstrasse")
assert not any(n.point == (50.0, 50.0) for n in out.nodes), "kein zweiter Knoten 5,7 m daneben"
assert len(out.nodes) == 6 # 4 vorhandene + 2 neue Sackgassen
# Am wiederverwendeten Knoten (54,54) treffen sich jetzt der alte Sackgassenfuss (Grad 1) und
# die neue Kreuzung selbst (zwei gekreuzte Straßen, je zweimal gespalten: Grad 4) - macht 5.
assert out.degree(2) == 5