diff --git a/tools/extract/tests/test_committed_roads.py b/tools/extract/tests/test_committed_roads.py index c6b888d..e4cc2bd 100644 --- a/tools/extract/tests/test_committed_roads.py +++ b/tools/extract/tests/test_committed_roads.py @@ -13,8 +13,19 @@ from pathlib import Path from shapely.geometry import LineString, Point, Polygon from shapely.ops import unary_union +from shapely.validation import explain_validity ROOT = Path(__file__).resolve().parents[3] / "public" / "data" / "vice-a" +# Die sieben Flächenschichten eines Chunks (Entwurf, Abschnitt "Chunk-Format"). `land` liegt roh +# als Liste von Ringlisten vor ([ring, loch, ...]), die übrigen sechs als Liste von +# {"poly": [ring, loch, ...]}-Objekten - _flaechen_polygone() unten gleicht das an. +AREA_LAYERS = ["carriageway", "land", "sidewalk", "surfaces", "lots", "bridges", "paths"] + + +def _flaechen_polygone(chunk: dict, layer: str) -> list[Polygon]: + entries = chunk.get(layer) or [] + ringlisten = entries if layer == "land" else [e["poly"] for e in entries] + return [Polygon(r[0], r[1:]) for r in ringlisten] def _chunks() -> list[dict]: @@ -87,3 +98,34 @@ def test_markierung_liegt_nicht_wesentlich_ausserhalb_der_fahrbahn(): f"{gesamt_ausserhalb:.2f} m² Markierungsfläche liegen außerhalb der Fahrbahn " "(Fixwelle-Stand: 110,06 m²) - das ist mehr als der dokumentierte Rest, nicht nur Rundung" ) + + +def test_alle_flaechenschichten_sind_gueltige_polygone(): + """Wächter aus der Nachprüfung der Fixwelle (zu Befund 5, emit.py): Die alte + Koordinatenrundung (jede Zahl unabhängig auf 2 Stellen) konnte einen Ring selbst schneiden - + acht Fälle in den damals ausgelieferten Chunks (carriageway 3, land 2, sidewalk 2, surfaces + 1), ohne dass ein Test es bemerkte. set_precision() behebt das (s. emit.py), aber bis zu + diesem Test hielt nichts fest, dass es dabei bleibt: Eine künftige Änderung an der Rundung + oder an set_precision() selbst könnte denselben Fehler wieder einschleppen, unbemerkt wie + beim ersten Mal. + + Prüft darum über alle 144 Chunks und alle sieben Flächenschichten (`carriageway`, `land`, + `sidewalk`, `surfaces`, `lots`, `bridges`, `paths`), dass jeder Ring ein gültiges Polygon + ergibt. Am committeten Stand: 4.190 Flächen geprüft, 0 ungültige (nachgemessen). Rot gegen den + Datenstand vor Commit a397892 (Koordinatenrundung statt set_precision): 9 ungültige Polygone in + 6 Chunks (dieselben acht Polygone wie im Befund - carriageway 3, land 2, sidewalk 2, surfaces 1 + -, plus ein neuntes, vorbestehendes `paths`-Polygon in Chunk (10, 6), das set_precision() als + Nebeneffekt mitheilt) - mit einer Kopie der damaligen Chunk-Dateien nachgestellt (`git show + 83140f8:...`), nicht mit dem heutigen Code. + """ + chunks = _chunks() + gesamt = 0 + ungueltig = [] + for c in chunks: + for layer in AREA_LAYERS: + for poly in _flaechen_polygone(c, layer): + gesamt += 1 + if not poly.is_valid: + ungueltig.append((tuple(c["chunk"]), layer, explain_validity(poly))) + assert gesamt > 4000, f"nur {gesamt} Flächen geprüft - fehlt eine Schicht oder ein Chunk?" + assert ungueltig == [], f"{len(ungueltig)} von {gesamt} Flächen sind kein gültiges Polygon: {ungueltig}" diff --git a/tools/extract/tests/test_marking_junction.py b/tools/extract/tests/test_marking_junction.py index 973cfbd..20f8339 100644 --- a/tools/extract/tests/test_marking_junction.py +++ b/tools/extract/tests/test_marking_junction.py @@ -167,6 +167,16 @@ def test_schleife_die_auf_sich_selbst_zurueckfuehrt_bekommt_keine_markierung_dan Nachgebaut mit denselben Maßen wie am echten Netz (9 m hin, 6 m quer, macht 21,63 m Umweg; reach=11 m, wie es der zweite Boulevard-Arm hier erzwingt). + + Gegengeprüft in der Gehwegtextur-Korrekturrunde: Die Nachprüfung der Fixwelle vermutete, der + Test unterscheide nicht (halb=9 m deckt jede kleine Markierung nahe am Knoten ab, gleich wohin + sie zeigt) und schlage auch mit dem alten Code an dieser Schleife grün an. Nachgestellt mit den + byte-genauen historischen Fassungen von junction_marks() (Commits 4bf670e "vor Befund 3" und + ca01141 "nach Befund 3, vor dieser Korrektur hier") und exakt dieser Testfunktion (nur + junction_marks per Monkeypatch getauscht): Beide Fassungen schlagen rot an (schlechtester + Anteil 64,9 % bzw. 85,3 %, an der Haltelinie und am äußersten Zebrabalken - die runde Fuge am + Schleifenscheitel deckt zwar die meisten Balken vollständig ab, aber nicht alle). Nur der + aktuelle Code besteht (100 %). Der Test bleibt deshalb unverändert. """ spitze = [(0.0, 0.0), (9.0, -6.0), (0.0, 0.0)] graph = Graph( diff --git a/tools/extract/tests/test_street.py b/tools/extract/tests/test_street.py index 24f8370..5974568 100644 --- a/tools/extract/tests/test_street.py +++ b/tools/extract/tests/test_street.py @@ -1,8 +1,6 @@ """Die Mulde: Löcher in der Bodenplatte, Bordsteinlinien, Gehwegflächen, Restflächen.""" from __future__ import annotations -import math - from shapely.geometry import LineString, Point, box from shapely.ops import unary_union @@ -260,29 +258,3 @@ def test_gehweg_schliesst_die_luecke_an_gewoehnlicher_kreuzungsecke(): luecke = sum(g.area for g in getattr(roh_rest, "geoms", [roh_rest]) if not g.is_empty and g.intersects(ecken) and g.area < LOT_MIN) assert luecke < 0.05, f"{luecke:.4f} m² Lücke an den Kreuzungsecken, sollte geschlossen sein" - - -def test_gehweg_waechst_auch_bei_engem_winkel_nicht_in_die_gasse(): - """Gegenprobe zu obigem Befund-7-Fix, am schärfsten denkbaren Fall: Die Rundung des - Kreuzungsanteils darf nicht wieder (wie in Fixrunde 4) über eine benachbarte Gasse - hinwegreichen, auch wenn die Gasse in einem enges Winkel zwischen zwei Armen mit Bordstein - liegt - der Fall, in dem eine Schließung am ehesten eine Nische neben der Gasse mitfüllen - könnte. Zwei Wohnstraßen-Arme bei 0° und 40°, eine Gasse dazwischen, bei 10° bis 30° in 5°- - Schritten durchprobiert: In jedem Fall bleibt der Gehweg außerhalb des Gassenkorridors, weil - die Gasse selbst nie einen Arm in die zu schließende Fläche liefert (kerb_only=True). - """ - for grad in (10.0, 15.0, 20.0, 25.0, 30.0): - rad = math.radians(grad) - a = (60.0, 0.0) - b = (60.0 * math.cos(math.radians(40.0)), 60.0 * math.sin(math.radians(40.0))) - g = (60.0 * math.cos(rad), 60.0 * math.sin(rad)) - graph = Graph( - nodes=[Node((0.0, 0.0)), Node(a), Node(b), Node(g)], - edges=[Edge(0, 1, [(0.0, 0.0), a], SECTION["wohnstrasse"].corridor, "wohnstrasse"), - Edge(0, 2, [(0.0, 0.0), b], SECTION["wohnstrasse"].corridor, "wohnstrasse"), - Edge(0, 3, [(0.0, 0.0), g], SECTION["gasse"].corridor, "gasse")]) - corridor = carriageway_area(graph).buffer(3.0, join_style="round") - street = build_street(graph, corridor, bridges=[]) - gassen_korridor = LineString([(0.0, 0.0), g]).buffer(SECTION["gasse"].corridor / 2, cap_style="flat") - leck = street.sidewalk.intersection(gassen_korridor).area - assert leck < 0.01, f"{leck:.4f} m² Gehweg im Gassenkorridor bei {grad}° Gassenwinkel"