TRO-Beschriftung wie das TRO-Fluss-SVG; Stationspfeile zeigen von der Kette weg
tro_flow: - _station_positionen: Richtung des Zu-/Ablaufpfeils mit groesstem Winkelabstand zu allen Kanten des Anker-TROs und zu bereits gesetzten Stationspfeilen (15-Grad-Raster), echte Stationsrichtung nur bei Gleichstand - vorher lag z. B. Mubea TRO02 -> SYS2 fast auf TRO02 -> TRO13 tro_annotate: - Symbole mit typ-eigener Fuellfarbe (Solid-Hatch) unter der Gruppenkontur - Kantenfarben/-layer wie im SVG: Uebergabe blau, Weiche orange, Materialeingang gruen, Materialausgang rot (TRO_WEICHE/_EINGANG/_AUSGANG) - Stationen als farbige Beschriftung am Pfeilende, Lage ueber tro_flow._station_positionen (ohne CONNECTION_ARROW-Block) - Legende wie im SVG: je vorkommendem Typ Fuellung/Rand/Form, dann Kantenfarben - CONNECTION_ARROW: FROM_TRO/TO_TRO unsichtbar (Daten bleiben), KIND auch weiche cfg/dxf_registration.json: mubea.csv|mubea.dxf und HundM05.csv|HundM05.dxf mit Versatz 0 (CSV aus derselben dxfmakros-Zeichnung; Auto-Ermittlung sieht die verschachtelten Separatoren nicht und war mehrdeutig); mubea.csv|500573_60_1.dxf neu ermittelt (36/46 Punkte). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
d0a3ac7e5a
commit
7b98c8b8d4
+34
-14
@@ -173,10 +173,8 @@ GENERATED_MARKER = "<!-- erzeugt von lib/tro_flow.py -->"
|
||||
COORD_SCALE = 0.1
|
||||
|
||||
# Zu-/Ablaufpfeil einer Station in der lagerichtigen Zeichnung: feste Laenge
|
||||
# (mm) ab dem angehaengten TRO und Faecherwinkel (Grad), wenn mehrere
|
||||
# Stationen am selben TRO haengen (siehe _station_positionen).
|
||||
# (mm) ab dem angehaengten TRO (siehe _station_positionen).
|
||||
COORD_PFEIL_LAENGE = 1300
|
||||
COORD_PFEIL_FAECHER = 45
|
||||
|
||||
# Groesste Luecke (mm) zwischen zwei benachbarten Knotenkoordinaten je Achse in
|
||||
# der lagerichtigen Zeichnung. Groessere Leerstrecken (lange Foerderer ohne
|
||||
@@ -1733,11 +1731,12 @@ def _station_positionen(
|
||||
"""Zeichenposition der Stationsbeschriftung (Ende des Zu-/Ablaufpfeils).
|
||||
|
||||
Feste Pfeillaenge COORD_PFEIL_LAENGE ab dem angehaengten TRO (Beladung:
|
||||
der TRO danach, Entladung: der TRO davor), Richtung zur echten Station -
|
||||
so bleibt der Pfeil sichtbar, auch wenn die Station praktisch auf dem TRO
|
||||
sitzt (Mubea SYS1 186 mm neben TRO04). Haengen mehrere Stationen am selben
|
||||
TRO, werden sie um COORD_PFEIL_FAECHER Grad aufgefaechert. Station ohne
|
||||
angehaengten TRO: echte Koordinate."""
|
||||
der TRO danach, Entladung: der TRO davor) - so bleibt der Pfeil sichtbar,
|
||||
auch wenn die Station praktisch auf dem TRO sitzt (Mubea SYS1 186 mm neben
|
||||
TRO04). Die Richtung haelt den groessten Winkelabstand zu allen Kanten des
|
||||
Anker-TROs und zu bereits gesetzten Stationspfeilen; die Richtung zur
|
||||
echten Station entscheidet nur bei Gleichstand. Station ohne angehaengten
|
||||
TRO: echte Koordinate."""
|
||||
tro_by_id = {t.tro_id: t for t in analysis.tros}
|
||||
je_tro: dict[str, list[Tro]] = {}
|
||||
ergebnis: dict[str, tuple[float, float]] = {}
|
||||
@@ -1751,17 +1750,38 @@ def _station_positionen(
|
||||
continue
|
||||
je_tro.setdefault(anker, []).append(station)
|
||||
|
||||
def _abstand(a: float, b: float) -> float:
|
||||
d = abs(a - b) % (2 * math.pi)
|
||||
return min(d, 2 * math.pi - d)
|
||||
|
||||
for anker, stationen in je_tro.items():
|
||||
ax, ay = tro_zeichen[anker]
|
||||
echt = tro_by_id[anker].position
|
||||
for k, station in enumerate(sorted(stationen, key=lambda s: s.tro_id)):
|
||||
dx = dy = 0.0
|
||||
# Richtungen der Kettenkanten am Anker-TRO - der Pfeil soll von der
|
||||
# Kette WEG zeigen, nicht auf ihr liegen (Review 2026-10-02: Mubea
|
||||
# TRO02 -> SYS2 lief fast deckungsgleich mit TRO02 -> TRO13).
|
||||
belegt: list[float] = []
|
||||
for src, dst in analysis.edges:
|
||||
anderer = dst if src == anker else src if dst == anker else None
|
||||
if anderer is None or anderer not in tro_zeichen:
|
||||
continue
|
||||
ox, oy = tro_zeichen[anderer]
|
||||
if (ox, oy) != (ax, ay):
|
||||
belegt.append(math.atan2(oy - ay, ox - ax))
|
||||
for station in sorted(stationen, key=lambda s: s.tro_id):
|
||||
wunsch = -math.pi / 2
|
||||
if echt and station.position:
|
||||
dx, dy = station.position[0] - echt[0], station.position[1] - echt[1]
|
||||
if math.hypot(dx, dy) < 1.0:
|
||||
dx, dy = 0.0, -1.0
|
||||
winkel = math.atan2(dy, dx) + math.radians(
|
||||
(k - (len(stationen) - 1) / 2) * COORD_PFEIL_FAECHER)
|
||||
if math.hypot(dx, dy) >= 1.0:
|
||||
wunsch = math.atan2(dy, dx)
|
||||
# Kandidaten im 15-Grad-Raster: groesster Mindestabstand zu allen
|
||||
# belegten Richtungen gewinnt, bei Gleichstand die zur echten
|
||||
# Station naechste Richtung.
|
||||
kandidaten = [math.radians(g) for g in range(0, 360, 15)]
|
||||
winkel = max(kandidaten, key=lambda w: (
|
||||
round(min((_abstand(w, b) for b in belegt), default=math.pi), 3),
|
||||
-_abstand(w, wunsch)))
|
||||
belegt.append(winkel)
|
||||
ergebnis[station.tro_id] = (ax + math.cos(winkel) * COORD_PFEIL_LAENGE,
|
||||
ay + math.sin(winkel) * COORD_PFEIL_LAENGE)
|
||||
return ergebnis
|
||||
|
||||
Reference in New Issue
Block a user