BTMT Beladung/Entladung als Ein-/Ausgang des Materialfluss-Graphen erkannt

export_graph.py behandelte BTMT-Stationen bisher wie ein generisches
Durchlaufelement mit zwei Achs-Enden - dadurch entstanden mehrere,
teils widerspruechliche Kanten und die Rolle blieb "Element" statt
"Eingang"/"Ausgang". BTMT hat aber physisch nur EINEN Anschluss zum
Foerdersystem (sitzt als dritter Zweig einer Weiche auf der Kreisel-
Durchgangsbahn, der Kreisel bleibt dabei ein einzelner Verteiler-Knoten):
Beladung speist fest Material ein (kein Vorgaenger im Fluss), Entladung
nimmt es fest raus (kein Nachfolger).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-10 15:29:08 +02:00
parent 47724fcfe2
commit 90bfbd89b6
2 changed files with 178 additions and 3 deletions
+60 -3
View File
@@ -9,7 +9,8 @@ Aufruf:
Erzeugt neben <basispfad>.json (vollstaendiges Graph-Modell) auch
<basispfad>.dot (GraphViz) und <basispfad>.mmd (Mermaid) zur Visualisierung.
KNOTEN = ein Anlagenelement je CSV-Zeile (Kreisel, Gefaellestrecke, Strecke).
KNOTEN = ein Anlagenelement je CSV-Zeile (Kreisel, Gefaellestrecke, Strecke,
BTMT Beladung/Entladung als Ein-/Ausgang des Graphen).
KANTEN = eine Materialuebergabe zwischen zwei Elementen.
Warum nicht die CSV-Spalte "Nachbarn"?
@@ -42,9 +43,25 @@ Lisp/export.lsp), wird die Richtung heuristisch abgeleitet:
"Ab" = abwaerts) gegen die Partnerhoehen.
* Kreisel: Verteilknoten. Richtung ergibt sich aus den angeschlossenen
Elementen, nicht aus dem Kreisel selbst.
* BTMT Beladung/Entladung: FEST gerichtet (Beladung -> Partner, Partner ->
Entladung), unabhaengig von Hoehe/Antrieb - siehe naechster Abschnitt.
Jede Kante traegt daher ein Feld "richtung_quelle": "ks" (exakt, aus K1/K2),
"gefaelle", "antrieb" oder "unbestimmt".
"gefaelle", "antrieb", "btmt" oder "unbestimmt".
Ein-/Ausgaenge des Graphen: BTMT Beladung/Entladung
----------------------------------------------------
BTMT Beladung/Entladung sind die Ein- bzw. Ausgaenge des gesamten
Materialfluss-Graphen - eine Beladestation speist NEUES Material ein (kein
Vorgaenger im Fluss), eine Entladestation nimmt es endgueltig raus (kein
Nachfolger). Physisch sitzen sie AUF der Durchgangsbahn eines Kreisels
(der Kreisel laeuft an dieser Stelle durch UND die BTMT-Station zweigt dort
zusaetzlich ab/ein - wie eine Weiche mit einem fixen dritten Zweig). Der
Kreisel bleibt im Graphmodell trotzdem EIN Knoten (Rolle "Verteiler", keine
Aufteilung in Segmente); BTMT wird als eigener Knoten mit GENAU EINEM
Anschlusspunkt (Elementmitte statt zwei Achs-Enden, siehe _enden) und einer
fest gerichteten Kante zum Kreisel/Partner dargestellt (Rolle "Eingang"
bzw. "Ausgang", siehe _rolle/BTMT_ARTEN).
"""
import csv
@@ -68,6 +85,15 @@ KREISEL_ARTEN = {"ILS 2.0 Kreisel", "ILS 2.0 Eckrad"}
GEFAELLE_ARTEN = {"ILS 2.0 Gefaellestrecke"}
STRECKEN_ARTEN = {"ILS 2.0 Strecke", "ILS 2.0 Strecke - Modul"}
# Ein-/Ausgaenge des Materialfluss-Graphen: BTMT Beladung speist Material
# EIN (Graph-Quelle, kein Vorgaenger im Fluss), BTMT Entladung nimmt es
# AUS (Graph-Senke, kein Nachfolger). Anders als Kreisel/Strecken haben
# beide nur EINEN Anschluss zum Foerdersystem, keine zwei Enden einer
# Durchlaufachse - siehe _enden().
BTMT_BELADUNG_ARTEN = {"ILS 2.0 BTMT Beladung"}
BTMT_ENTLADUNG_ARTEN = {"ILS 2.0 BTMT Entladung"}
BTMT_ARTEN = BTMT_BELADUNG_ARTEN | BTMT_ENTLADUNG_ARTEN
# ------------------------------------------------------------------
# Dekodierung der Base64-Koordinatenstrings
@@ -193,7 +219,17 @@ def _footprint(element):
def _enden(element):
"""Die beiden Enden der Laengsachse als Anschlusspunkte im Grundriss."""
"""Anschlusspunkte eines Elements im Grundriss.
BTMT Beladung/Entladung haben nur EINEN Anschluss zum Foerdersystem
(Elementmitte) - anders als eine Durchlaufstrecke keine zwei Enden
einer Laengsachse. Mit der generischen Zwei-Enden-Logik wuerden sie
faelschlich als Durchlaufelement mit zwei Uebergabestellen behandelt
(siehe derive_flow/BTMT_ARTEN).
"""
if element["teileart"] in BTMT_ARTEN:
m = element["mitte"]
return {"a": (m["x"], m["y"])}
minx, maxx, miny, maxy = element["footprint"]
m = element["mitte"]
if element["achse"] == "x":
@@ -262,6 +298,12 @@ def derive_flow(elemente, anschluesse):
* Foerderer mit Antriebfahrtrichtung "Auf" -> vom tieferen zum hoeheren,
"Ab" -> umgekehrt.
Liegen K1/K2 vor, gewinnt diese exakte Angabe.
BTMT Beladung/Entladung sind die Ein-/Ausgaenge des gesamten Graphen
(siehe BTMT_ARTEN/_enden): ihr einziger Anschluss wird FEST gerichtet
(Beladung -> Partner, Partner -> Entladung), unabhaengig von Hoehe/
Antriebfahrtrichtung - eine Beladestation speist immer ein, eine
Entladestation nimmt immer aus, nie umgekehrt.
"""
# Anschluesse je Streckenelement sammeln
je_element = {}
@@ -273,6 +315,15 @@ def derive_flow(elemente, anschluesse):
el = elemente[idx]
art = el["teileart"]
if art in BTMT_BELADUNG_ARTEN:
for anschluss in liste:
kanten.append(_kante(idx, anschluss["b"], "btmt", anschluss["abstand"]))
continue
if art in BTMT_ENTLADUNG_ARTEN:
for anschluss in liste:
kanten.append(_kante(anschluss["b"], idx, "btmt", anschluss["abstand"]))
continue
# Exakte Richtung, sobald der Export K1/K2 liefert
if el["ks_ein"] and el["ks_aus"]:
kanten.extend(_kanten_aus_ks(elemente, idx, liste))
@@ -433,6 +484,10 @@ def _rolle(el):
return "Schwerkraftstrecke"
if el["teileart"] in STRECKEN_ARTEN:
return "Foerderer"
if el["teileart"] in BTMT_BELADUNG_ARTEN:
return "Eingang"
if el["teileart"] in BTMT_ENTLADUNG_ARTEN:
return "Ausgang"
return "Element"
@@ -440,6 +495,8 @@ STIL = {
"Verteiler": ("box3d", "#1f6feb"),
"Schwerkraftstrecke": ("box", "#8250df"),
"Foerderer": ("box", "#1a7f37"),
"Eingang": ("invhouse", "#bf8700"),
"Ausgang": ("house", "#bf8700"),
"Element": ("ellipse", "#57606a"),
}