feat(extract): Pipeline baut Straßen aus dem Graphen
run.py baut jetzt aus dem Straßengraphen (Tasks 3-11) statt aus den nachgezeichneten Straßenrändern: Fahrbahn, Bordstein, Gehweg und Restflächen aus build_street(), amerikanische Markierungen aus markings(). fit_to_carriageway() bringt Bodenplatte und Beläge auf dasselbe Loch wie die Fahrbahn und hält Palmen dabei von ihr fern - nach derselben Regel, mit der apply_street() sie schon von der Jefferson Avenue fernhält. split_by_chunk_all() bekommt dafür eine parametrisierbare Splittergrenze: Ein Strich der gestrichelten Linien ist 3 m x 10 cm = 0,3 m² und wäre an der bisherigen 0,5-m²-Grenze für Flächen verschwunden. Markierungen laufen deshalb über den neuen Helfer chunk_markings() mit eigener, kleinerer Grenze; alle anderen Aufrufer bleiben bei 0,5 m². Am echten Netz gemessen: 1.537 Knoten, 1.790 Kanten, 830 Bordsteinstücke, 171 Restflächen, 22.394 Markierungen, 56 Palmen an der Fahrbahn entfernt. Fahrbahn-, Gehweg- und Restflächen sowie die Bordsteinlänge treffen die vorab am echten Netz gemessenen Erwartungswerte auf 0,03-0,3 % genau. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
892558fc50
commit
2201be37bd
3 files changed
+181
-15
No files matched your search
@@ -0,0 +1,73 @@
|
||||
"""Die Reihenfolge, in der die Straßen entstehen — ohne den vollen Lauf."""
|
||||
from __future__ import annotations
|
||||
|
||||
from shapely.geometry import box
|
||||
from shapely.ops import unary_union
|
||||
|
||||
from leonida.emit import chunk_box_of
|
||||
from leonida.park import World
|
||||
from leonida.roads import Edge, Graph, Node
|
||||
from leonida.street import build_street, punch
|
||||
from run import chunk_markings, fit_to_carriageway
|
||||
|
||||
|
||||
def _gerade_wohnstrasse():
|
||||
"""100 m Wohnstraße entlang y = 0: Fahrbahn 7 m breit, also von y = -3,5 bis 3,5."""
|
||||
graph = 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")])
|
||||
return graph, build_street(graph, box(0, -6, 100, 6), bridges=[])
|
||||
|
||||
|
||||
def _welt(graph, *, surfaces=(), palms=()):
|
||||
return World(land=[box(-20, -50, 120, 50)], surfaces=list(surfaces), roads=[], graph=graph,
|
||||
buildings=[], palms=list(palms))
|
||||
|
||||
|
||||
def test_boden_und_belag_bekommen_dasselbe_loch():
|
||||
"""Vergisst run.py eine der beiden Schichten, liegt dort ein Belag über der Mulde oder die
|
||||
Bodenplatte schließt sie."""
|
||||
graph, street = _gerade_wohnstrasse()
|
||||
platte = box(-20, -50, 120, 50)
|
||||
welt = _welt(graph, surfaces=[(box(-20, -50, 50, 50), "urban"), (box(50, -50, 120, 50), "park")])
|
||||
out = fit_to_carriageway(welt, street.carriageway)
|
||||
boden = unary_union(out.land)
|
||||
assert boden.intersection(street.carriageway).area < 0.01, "die Fahrbahn liegt im Loch"
|
||||
loch = street.carriageway.intersection(platte).area
|
||||
assert abs(platte.area - boden.area - loch) < 0.01, "das Loch ist nicht größer als die Fahrbahn"
|
||||
for kind in ("urban", "park"):
|
||||
belag = unary_union([poly for poly, k in out.surfaces if k == kind])
|
||||
assert belag.intersection(street.carriageway).area < 0.01, f"kein Belag {kind} über der Mulde"
|
||||
assert abs(unary_union([poly for poly, _ in out.surfaces]).area - boden.area) < 0.01, "dasselbe Loch"
|
||||
|
||||
|
||||
def test_gehweg_liegt_nicht_im_loch():
|
||||
graph, street = _gerade_wohnstrasse()
|
||||
land = unary_union(punch([box(-20, -50, 120, 50)], street.carriageway))
|
||||
assert street.sidewalk.difference(land).area < 0.5, "der Gehweg liegt auf der Bodenplatte"
|
||||
|
||||
|
||||
def test_keine_palme_auf_oder_dicht_an_der_fahrbahn():
|
||||
"""Entwurf, Ablauf Schritt 7: Palmen werden nach dem Straßenbau neu gesetzt. Am echten Netz
|
||||
standen ohne diesen Schritt 24 Palmen auf der Fahrbahn und 32 weitere näher als PALM_KERB."""
|
||||
graph, street = _gerade_wohnstrasse()
|
||||
welt = _welt(graph, palms=[(50.0, 0.0), (50.0, 4.5), (50.0, 5.5)])
|
||||
out = fit_to_carriageway(welt, street.carriageway)
|
||||
assert out.palms == [(50.0, 5.5)], "auf der Fahrbahn und 1 m daneben weg, 2 m daneben bleibt"
|
||||
|
||||
|
||||
def test_striche_ueberleben_den_zuschnitt():
|
||||
"""Ein Strich der gestrichelten Mitte ist 3 m × 10 cm = 0,3 m². Mit der Splittergrenze der
|
||||
Flächen (0,5 m²) fiel am echten Netz jeder einzelne der 4.363 Striche weg."""
|
||||
zelle = chunk_box_of(0, 0)
|
||||
x, y = zelle.centroid.x, zelle.centroid.y
|
||||
stuecke = chunk_markings([(box(x, y, x + 3.0, y + 0.1), "gelb_gestrichelt")], 0, 0)
|
||||
assert [art for _, art in stuecke] == ["gelb_gestrichelt"]
|
||||
assert abs(stuecke[0][0].area - 0.3) < 1e-6
|
||||
|
||||
|
||||
def test_strich_ueber_der_chunkgrenze_wird_geteilt_nicht_verworfen():
|
||||
zelle = chunk_box_of(0, 0)
|
||||
grenze, y = zelle.bounds[2], zelle.centroid.y # rechte Kante von Chunk (0, 0)
|
||||
strich = [(box(grenze - 1.0, y, grenze + 2.0, y + 0.1), "weiss_gestrichelt")]
|
||||
assert [round(poly.area, 6) for poly, _ in chunk_markings(strich, 0, 0)] == [0.1]
|
||||
assert [round(poly.area, 6) for poly, _ in chunk_markings(strich, 1, 0)] == [0.2]
|
||||
Reference in new issue
Block a user