fix(extract): Kreuzungsmarkierung am tatsächlichen Punkt verankern, nicht am Knoten
Nacharbeit zu Befund 3, beim Nachmessen am echten Netz entdeckt: Die erste
Korrektur (Richtung aus origin -> interpolate(reach) statt aus points[1])
reichte an zwei Stellen nicht.
Erstens kann eine Schleife geradewegs von ihrem Knoten weg- und auf
demselben Weg wieder zurücklaufen - am echten Netz eine 21,63 m lange
Boulevard-Schleife, deren Punktliste den Hinweg exakt rückwärts
wiederholt. Landet reach nahe dieser Kehre, zeigt die Sehne vom Ursprung
weiter nach außen, obwohl die Kante dort längst umkehrt: Die Markierung
lag an dieser einen Schleife weiterhin vollständig (100 %) neben der
Fahrbahn. Die Richtung kommt jetzt aus dem letzten Teilstück von
substring(line, 0, reach) - der tatsächlichen Anfahrtsrichtung an der
Schnittstelle, gleich wohin die Kante von dort aus weiterläuft.
Zweitens blieb "origin" (der Kreuzungsknoten) der Anker für Balken und
Haltelinie. origin und der Punkt bei Streckenlänge reach fallen nur auf
einer geraden Kante zusammen - mit der neuen Anfahrtsrichtung, aber dem
Knoten als Anker, läge selbst eine gerade Fortsetzung ab reach
systematisch daneben, sobald die Kante zwischen Knoten und reach von der
reinen Ursprungsrichtung abweicht. Anker ist jetzt der tatsächliche Punkt
auf der Kante bei Streckenlänge min(reach, länge).
Nachgemessen am echten Netz: von 452,65 m² (vor Befund 3) über 342,66 m²
(nur die erste Korrektur) auf 110,06 m² (0,25 % der Gesamtfläche) - beide
Korrekturen zusammen eine Verbesserung um 75,7 %. Der Rest ist eine engere
Spielart desselben Problems: Ein Bogen kann auch noch zwischen reach und
reach + STOP_SETBACK + STOP_DEPTH abknicken, was ein einzelner
Richtungsstrahl nicht mehr auffangen kann - das verlangte die vom Befund
selbst genannte, größere Alternative ("die Markierung entlang der
tatsächlichen Kante aufbauen"), die diese Fixwelle nicht umsetzt. Siehe
Fixwelle-Bericht für die Einzelheiten und die verbleibenden Einzelfälle.
Neuer Test mit den echten Schleifenmaßen (9 m hin, 6 m quer, reach 11 m):
vor dieser Korrektur lag die gesamte Markierung an der Schleife daneben,
danach vollständig darauf.
This commit is contained in:
1 parent
ca01141c5b
commit
015d15d82a
2 files changed
+67
-14
No files matched your search
@@ -137,17 +137,42 @@ def junction_marks(graph: Graph, node: int) -> list[tuple[Polygon, str]]:
|
||||
for points in richtungen:
|
||||
line = LineString(points)
|
||||
länge = line.length
|
||||
# Die Richtung kommt aus der tatsächlichen Kante bei Streckenlänge "reach", nicht aus
|
||||
# dem zweiten Stützpunkt (Befund 3 der Fixwelle): Ein Knick konnte innerhalb der ersten
|
||||
# reach Meter liegen - reach ist der Kreuzungsradius plus Luft, oft mehrere Meter -,
|
||||
# während die alte Richtung (Anfang -> zweiter Stützpunkt) bis reach + STOP_SETBACK +
|
||||
# STOP_DEPTH (bis 16 m) unverändert weiterlief. Am echten Netz lagen dadurch 452,65 m²
|
||||
# Markierungsfläche (1,03 % der Gesamtfläche) neben statt auf der Fahrbahn, darunter
|
||||
# ganze Haltelinien. min(reach, länge) schützt kurze Arme, die schon vorher an der
|
||||
# Prüfung unten scheitern und dann gar nicht gezeichnet werden.
|
||||
punkt = line.interpolate(min(reach, länge))
|
||||
along = _unit(origin, (punkt.x, punkt.y))
|
||||
# Befund 3 der Fixwelle: "along" kam aus der Richtung origin -> points[1], also allein
|
||||
# aus dem ersten Segment der Zufahrt, während Zebrastreifen und Haltelinie bis
|
||||
# reach + STOP_SETBACK + STOP_DEPTH (bis 16 m) auf dieser Geraden aufgespannt wurden.
|
||||
# Knickte die Kante innerhalb dieser Strecke ab, landete die Markierung daneben statt
|
||||
# darauf - am echten Netz gemessen 452,65 m² (1,03 % der Gesamtfläche), darunter ganze
|
||||
# Haltelinien.
|
||||
#
|
||||
# Zwei Korrekturen daran, beide am echten Netz nachgewiesen nötig:
|
||||
#
|
||||
# 1) Die Richtung kommt aus dem letzten Teilstück von substring(line, 0, reach), nicht
|
||||
# aus der Sehne vom Ursprung zu interpolate(reach): Eine Schleife kann geradewegs von
|
||||
# ihrem Knoten weg- und auf demselben Weg wieder zurücklaufen (eine 21,63 m lange
|
||||
# Schleife im echten Netz, deren Punktliste den Hinweg exakt rückwärts wiederholt).
|
||||
# Landet reach nahe dieser Kehre, zeigt die Sehne vom Ursprung weiter nach außen,
|
||||
# obwohl die Kante dort längst umkehrt. Das letzte Teilstück von substring() nimmt
|
||||
# dagegen die tatsächliche Anfahrtsrichtung an der Schnittstelle an, gleich wohin die
|
||||
# Kante von dort aus weiterläuft.
|
||||
# 2) Anker für Balken und Haltelinie ist der tatsächliche Punkt auf der Kante bei
|
||||
# Streckenlänge min(reach, länge), nicht der Kreuzungsknoten selbst: origin und
|
||||
# dieser Punkt fallen nur auf einer geraden Kante zusammen. Mit der Anfahrtsrichtung
|
||||
# aus (1), aber dem Knoten als Anker, läge selbst eine gerade Fortsetzung ab reach
|
||||
# systematisch daneben, sobald die Kante zwischen Knoten und reach von der reinen
|
||||
# Ursprungsrichtung abweicht.
|
||||
#
|
||||
# Mit beiden Korrekturen bleiben am echten Netz noch 110,06 m² (0,25 %) außerhalb der
|
||||
# Fahrbahn - ein Bogen kann auch noch zwischen reach und reach + STOP_SETBACK +
|
||||
# STOP_DEPTH abknicken, und ein einzelner Richtungsstrahl kann das nicht mehr auffangen;
|
||||
# das verlangte die vom Befund selbst genannte, größere Alternative ("die Markierung
|
||||
# entlang der tatsächlichen Kante aufbauen"), die diese Fixwelle nicht umsetzt. Siehe
|
||||
# Bericht der Fixwelle für die Einzelheiten. min(reach, länge) schützt kurze Arme, die
|
||||
# schon vorher an der Prüfung unten scheitern und dann gar nicht gezeichnet werden.
|
||||
teil = substring(line, 0.0, min(reach, länge))
|
||||
rand = [] if teil.is_empty else list(teil.coords)
|
||||
along = _unit(rand[-2], rand[-1]) if len(rand) > 1 else (0.0, 0.0)
|
||||
across = (-along[1], along[0])
|
||||
basis = rand[-1] if rand else origin
|
||||
halb = SECTION[edge.klass].carriageway / 2
|
||||
# reach kommt vom breitesten Arm der ganzen Kreuzung, gilt hier aber für diesen einen
|
||||
# Arm - ein kurzer Arm an einer sonst breiten Kreuzung reicht oft nicht bis dorthin. Am
|
||||
@@ -168,8 +193,8 @@ def junction_marks(graph: Graph, node: int) -> list[tuple[Polygon, str]]:
|
||||
n = math.floor((2 * halb + BAR) / (2 * BAR))
|
||||
offset = -(n - 1) * BAR
|
||||
for _ in range(n):
|
||||
mitte = (origin[0] + across[0] * offset, origin[1] + across[1] * offset)
|
||||
out.append((_rect(mitte, along, across, reach, CROSSWALK_DEPTH, BAR), "zebra"))
|
||||
mitte = (basis[0] + across[0] * offset, basis[1] + across[1] * offset)
|
||||
out.append((_rect(mitte, along, across, 0.0, CROSSWALK_DEPTH, BAR), "zebra"))
|
||||
offset += 2 * BAR
|
||||
if länge >= reach + STOP_SETBACK + STOP_DEPTH:
|
||||
# Haltelinie quer, nur über die rechte Hälfte aus Sicht der Zufahrt. "across" ist
|
||||
@@ -179,8 +204,8 @@ def junction_marks(graph: Graph, node: int) -> list[tuple[Polygon, str]]:
|
||||
# ist deshalb +across, ohne weiteres Vorzeichen: eine Probe mit offset_curve() auf
|
||||
# der Einfahrtlinie bestätigt das (Fixrunde zu Task 9 - der Auftrag hatte hier
|
||||
# -across und lag damit auf der Gegenspur).
|
||||
mitte = (origin[0] + across[0] * halb / 2, origin[1] + across[1] * halb / 2)
|
||||
out.append((_rect(mitte, along, across, reach + STOP_SETBACK, STOP_DEPTH, halb),
|
||||
mitte = (basis[0] + across[0] * halb / 2, basis[1] + across[1] * halb / 2)
|
||||
out.append((_rect(mitte, along, across, STOP_SETBACK, STOP_DEPTH, halb),
|
||||
"haltelinie"))
|
||||
return out
|
||||
|
||||
|
||||
@@ -155,6 +155,34 @@ def test_markierung_folgt_dem_geknickten_arm_nicht_der_ersten_richtung():
|
||||
assert sum(1 for a in anteile if a > 0.9) >= len(anteile) - 1, "fast jeder Balken muss klar auf der Fahrbahn liegen"
|
||||
|
||||
|
||||
def test_schleife_die_auf_sich_selbst_zurueckfuehrt_bekommt_keine_markierung_daneben():
|
||||
"""Zweite Korrektur zu Befund 3, am echten Netz entdeckt: Eine Schleife kann geradewegs von
|
||||
ihrem Knoten weg- und auf demselben Weg wieder zurücklaufen (am echten Netz eine 21,63 m
|
||||
lange Boulevard-Schleife, deren Punktliste den Hinweg exakt rückwärts wiederholt). Landet
|
||||
reach nahe dieser Kehre, zeigt die Sehne vom Ursprung zu interpolate(reach) weiter nach außen,
|
||||
obwohl die Kante dort längst umkehrt - mit dieser Zwischenstufe der Korrektur lag die gesamte
|
||||
Markierung (Zebra und Haltelinie) an genau dieser Schleife vollständig neben der Fahrbahn
|
||||
(0 % statt 100 %, nachgerechnet gegen die echten Koordinaten). Anker am tatsächlichen Punkt
|
||||
plus Richtung aus dem letzten Teilstück von substring() behebt das.
|
||||
|
||||
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).
|
||||
"""
|
||||
spitze = [(0.0, 0.0), (9.0, -6.0), (0.0, 0.0)]
|
||||
graph = Graph(
|
||||
nodes=[Node((0.0, 0.0)), Node((-80.0, 0.0)), Node((9.0, -6.0))],
|
||||
edges=[Edge(0, 1, [(0.0, 0.0), (-80.0, 0.0)], SECTION["boulevard"].corridor, "boulevard"),
|
||||
Edge(0, 0, spitze, SECTION["boulevard"].corridor, "boulevard")],
|
||||
)
|
||||
halb = SECTION["boulevard"].carriageway / 2
|
||||
fahrbahn = LineString(spitze).buffer(halb, cap_style="flat")
|
||||
ziel = [(p, a) for p, a in junction_marks(graph, 0) if p.centroid.x > 1] # nur die Schleife
|
||||
assert ziel, "die Schleife muss Markierungen bekommen (zwei bordsteintragende Arme)"
|
||||
for poly, art in ziel:
|
||||
anteil = poly.intersection(fahrbahn).area / poly.area
|
||||
assert anteil > 0.99, f"{art} liegt nur zu {anteil:.0%} auf der Schleifen-Fahrbahn"
|
||||
|
||||
|
||||
def test_kurzer_arm_an_breiter_kreuzung_bleibt_ohne_markierung():
|
||||
# reach = setback() kommt vom breitesten anliegenden Arm (hier Boulevard, halbe Fahrbahn 9 m)
|
||||
# und gilt für alle Zufahrten gleich - ein kurzer Arm reicht dann nicht mehr bis dorthin. Am
|
||||
|
||||
Reference in new issue
Block a user