fix(extract): Markierungen folgen der Kante und stürzen nicht am Zickzack ab
Befund 3: In junction_marks() kam die Richtung einer Zufahrt aus origin -> points[1], also nur aus dem ersten Segment der Kante. Haltelinie und Zebrastreifen wurden aber bis reach + STOP_SETBACK + STOP_DEPTH (bis 16 m) auf dieser Geraden aufgespannt - knickte die Kante innerhalb dieser Strecke ab, landete die Markierung daneben statt darauf. Am echten Netz (gemessen über alle 144 committeten Chunks): 452,65 m² von 43.906 m² Markierungsfläche (1,03 %) liegen außerhalb der Fahrbahn, davon 291,44 m² Zebra und 147,68 m² Haltelinie; die schlimmsten Einzelfälle sind vollständige Haltelinien mit 5,41 m². Die Richtung kommt jetzt aus line.interpolate(min(reach, länge)) - dem tatsächlichen Punkt auf der Kante bei Streckenlänge reach - statt aus dem zweiten Stützpunkt. Befund 4: offset_curve() liefert bei einem engen Zickzack eine MultiLineString statt einer LineString; substring() in _dashed() akzeptiert nur LineString und wirft dann GeometryTypeError. Am heutigen Mosaik tritt das nicht auf, aber eine geänderte Korrektur oder eine eingehängte Kante mit engem Knick hätte den Vier-Minuten-Lauf abgebrochen. Zweiter, stiller Ast: Eine sehr spitze Kehre lässt offset_curve() leer zurückkommen; _solid() puffert das ungeprüft zu einem Nullflächen-Polygon. _offset() normalisiert jetzt auf eine Liste von LineStrings (leer -> [], MultiLineString -> ihre geoms), _dashed() und _solid() iterieren darüber; longitudinal() flacht die jetzt listenwertigen _solid()-Aufrufe ab. Beide Befunde mit Tests, die ohne die jeweilige Korrektur rot sind: der Zickzack-Fall bricht am unkorrigierten Code mit GeometryTypeError ab, der Kehre-Fall lieferte zwei Nullflächen-Polygone unter den Rand-/ Doppellinien.
This commit is contained in:
1 parent
ceb23bf912
commit
83140f89e1
3 files changed
+116
-19
No files matched your search
@@ -77,6 +77,38 @@ def test_linien_sind_zehn_zentimeter_breit():
|
||||
assert round(x1 - x0, 3) == DASH
|
||||
|
||||
|
||||
def test_dashed_stuerzt_bei_engem_zickzack_nicht_ab():
|
||||
"""Befund 4 der Fixwelle: offset_curve() liefert bei einem engen Zickzack eine
|
||||
MultiLineString statt einer LineString - substring() in _dashed() akzeptiert aber nur
|
||||
LineString und wirft sonst GeometryTypeError. Nachgestellt mit einer S-Kurve (1 m Amplitude):
|
||||
Bei LANE=3,5 m Versatz (Spurtrenner, nur ab Boulevard) spaltet offset_curve(-3,5) sie in zwei
|
||||
Teilstücke. Vor der Korrektur bricht das hier mit GeometryTypeError ab; das ist die
|
||||
Bestätigung, dass der Test ohne sie rot ist.
|
||||
"""
|
||||
zickzack = [(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (2.0, 1.0), (2.0, 0.0), (3.0, 0.0)]
|
||||
graph = Graph(nodes=[Node((0.0, 0.0)), Node((3.0, 0.0))],
|
||||
edges=[Edge(0, 1, zickzack, SECTION["boulevard"].corridor, "boulevard")])
|
||||
ergebnis = longitudinal(graph) # darf nicht mit GeometryTypeError abbrechen
|
||||
arten = {art for _, art in ergebnis}
|
||||
assert "weiss_gestrichelt" in arten, "der Spurtrenner entsteht trotz Zickzack (in Teilstücken)"
|
||||
|
||||
|
||||
def test_solid_erzeugt_kein_nullflaechen_polygon_bei_leerer_offset_curve():
|
||||
"""Befund 4 der Fixwelle, zweiter (stiller) Ast: An einer sehr spitzen Kehre liefert
|
||||
offset_curve() eine leere LineString. _solid() puffert sie ungeprüft zu einem
|
||||
Nullflächen-Polygon statt gar nichts zurückzugeben - kein Absturz, aber eine entartete
|
||||
Geometrie in der Ausgabe. Nachgestellt mit einer Kehre, die bei WIDTH (0,1 m, gelb_doppelt)
|
||||
und bei rand (7 m beim Boulevard, weiss_rand) je auf einer Seite ins Leere läuft.
|
||||
"""
|
||||
kehre = [(0.0, 0.0), (1.0, 0.0), (0.0, 0.01)]
|
||||
graph = Graph(nodes=[Node((0.0, 0.0)), Node((0.0, 0.01))],
|
||||
edges=[Edge(0, 1, kehre, SECTION["boulevard"].corridor, "boulevard")])
|
||||
flaechen = [p.area for p, art in longitudinal(graph) if art in ("gelb_doppelt", "weiss_rand")]
|
||||
assert all(a > 0.01 for a in flaechen), (
|
||||
f"eine leere offset_curve() darf kein Nullflächen-Polygon in der Ausgabe hinterlassen: {flaechen}"
|
||||
)
|
||||
|
||||
|
||||
def test_markierung_endet_am_kreuzungsrand():
|
||||
graph = Graph(nodes=[Node((0.0, 0.0)), Node((120.0, 0.0)), Node((120.0, 60.0)), Node((180.0, 0.0))],
|
||||
edges=[Edge(0, 1, [(0.0, 0.0), (120.0, 0.0)], 12.0, "wohnstrasse"),
|
||||
|
||||
Reference in new issue
Block a user