TRO-Fluss: tro_overrides.ini standardmaessig aus, ungelistete Strecken-Separatoren lagerichtig verketten

- tro_flow/tro_annotate: cfg/tro_overrides.ini nur noch mit --use-overrides
  (die Abschnitte haengen an laufenden TRO-Nummern und am CSV-Namen und
  veralten mit jedem Export; [export.csv.connections] ersetzte alle
  abgeleiteten Kanten und liess TRO13-20 unverbunden)
- link_tros: Separatoren mit Zuordnung auf eine Strecke, die in keiner
  TrackIds-Liste stehen, per Projektion AS->ES in die Strecken-Kette
  einsortieren (Mubea VF_3: 0037/0038 erzeugten je 9 Fehlkanten;
  mubea 38 -> 22 Verbindungen, HundM05 unveraendert)
- tro_catalog: typ-eigene Fuellfarbe je TRO-Typ, Mermaid-classDefs je Typ
- tro_overrides/tro_flow: connect.ini zurueck einlesen (--from-connect)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Samer Ayadi
2026-10-01 10:50:40 +02:00
co-authored by Claude Opus 5.5
parent 1479519bdc
commit 02db9a95b0
4 changed files with 381 additions and 26 deletions
+54 -16
View File
@@ -231,6 +231,11 @@ class TroStyle(BaseModel):
Wichtig: gruen bedeutet **Speicher**, nicht Foerderer. Der Vario ist
violett.
Innerhalb einer Gruppe hat jeder Typ zusaetzlich eine eigene Fuellfarbe
(TroDefinition.fill, ein Ton im Farbton der Gruppe); der Rand bleibt die
Gruppenfarbe (stroke). So ist jeder Typ an Farbe UND Form eindeutig, und
die Gruppe bleibt am Farbton/Rand lesbar.
"""
model_config = ConfigDict(validate_assignment=True, extra="forbid",
@@ -337,6 +342,12 @@ class TroDefinition(BaseModel):
min_length=1,
description="Zeichensymbol des Markers im CAD, z. B. 'triangle'",
)
fill: str = Field(
default="",
description="Typ-eigene Fuellfarbe als Hex; leer = Fuellfarbe der Farbgruppe. "
"Der Rand bleibt immer in der Gruppenfarbe, damit die Gruppe "
"trotz eigener Typfarbe erkennbar bleibt.",
)
def __init__(
self,
@@ -345,6 +356,7 @@ class TroDefinition(BaseModel):
items: dict[str, int] | None = None,
style: TroStyle | None = None,
symbol: str | None = None,
fill: str | None = None,
**data,
) -> None:
# Positionsargumente auf Feldnamen abbilden, damit die bisherige
@@ -359,6 +371,8 @@ class TroDefinition(BaseModel):
data["style"] = style
if symbol is not None:
data["symbol"] = symbol
if fill is not None:
data["fill"] = fill
super().__init__(**data)
@field_validator("items", mode="after")
@@ -420,14 +434,32 @@ class TroDefinition(BaseModel):
"""Kurzname der Farbgruppe, z. B. 'vario'."""
return self.style.group
def get_fill(self) -> str:
"""Fuellfarbe dieses Typs: die typ-eigene, sonst die der Farbgruppe."""
return self.fill or self.style.fill
def get_dot_attrs(self) -> dict[str, str]:
"""Graphviz-Knotenattribute dieses Typs: Fuell-/Randfarbe der Farbgruppe
plus die typ-eigene Form (siehe TroSymbol/dot_shape_attrs) - Farbe
gruppiert verwandte Typen, Form unterscheidet den einzelnen Typ."""
"""Graphviz-Knotenattribute dieses Typs: typ-eigene Fuellfarbe, Rand in
der Farbe der Gruppe, plus die typ-eigene Form (siehe TroSymbol/
dot_shape_attrs) - Rand und Farbton gruppieren verwandte Typen,
Fuellung und Form unterscheiden den einzelnen Typ."""
attrs = self.style.dot_attrs()
attrs["fillcolor"] = self.get_fill()
attrs.update(dot_shape_attrs(self.symbol))
return attrs
def mermaid_class(self) -> str:
"""Mermaid-Klassenname dieses Typs (Typnamen beginnen teils mit einer
Ziffer, die Mermaid als Klassenname nicht erlaubt)."""
return f"t_{self.name}"
def mermaid_classdef(self) -> str:
"""Mermaid-classDef-Zeile fuer diesen Typ (eigene Fuellung, Gruppenrand)."""
return (
f"classDef {self.mermaid_class()} fill:{self.get_fill()},"
f"stroke:{self.style.stroke},color:{self.style.font}"
)
# -- set ---------------------------------------------------------------
#
# Jede Zuweisung laeuft durch die Pydantic-Validierung, weil
@@ -453,6 +485,10 @@ class TroDefinition(BaseModel):
"""Zeichensymbol des Markers setzen."""
self.symbol = symbol
def set_fill(self, fill: str) -> None:
"""Typ-eigene Fuellfarbe setzen ('' = Farbe der Gruppe)."""
self.fill = fill
def set_item(self, item: str, count: int) -> None:
"""
Anzahl einer Bauteilart setzen.
@@ -503,29 +539,29 @@ TRO_CATALOG: tuple[TroDefinition, ...] = (
# (PriorityManager, JamArea Entry/Exit, HMI, Safety, MachineState).
TroDefinition("1Sep", "FB_ILS_MTRO_1Sep", {
TroItem.SEPARATOR: 1,
}, STYLE_SEP, TroSymbol.CIRCLE),
}, STYLE_SEP, TroSymbol.CIRCLE, "#d4e8ff"),
# laut TRO_Typen.md: Basis + 1x Switch-Modul
TroDefinition("1Sep1Swi", "FB_ILS_MTRO_1Sep1Swi", {
TroItem.SEPARATOR: 1,
TroItem.SWITCH: 1,
}, STYLE_SWI, TroSymbol.TRIANGLE),
}, STYLE_SWI, TroSymbol.TRIANGLE, "#ffe4a0"),
# laut TRO_Typen.md: Basis + 2x Switch-Modul + Scanner-Modul
TroDefinition("1Sep2Swi", "FB_ILS_MTRO_1Sep2Swi", {
TroItem.SEPARATOR: 1,
TroItem.SWITCH: 2,
TroItem.SCANNER: 1,
}, STYLE_SWI, TroSymbol.PENTAGON),
}, STYLE_SWI, TroSymbol.PENTAGON, "#ffc766"),
# laut TRO_Typen.md: Basis + Scanner-Modul + SSCC-Modul (Messsensor + WCS)
TroDefinition("1Sep_SSCC", "FB_ILS_MTRO_1Sep_SSCC", {
TroItem.SEPARATOR: 1,
TroItem.SCANNER: 1,
TroItem.SSCC: 1,
}, STYLE_SSCC, TroSymbol.DOUBLE_CIRCLE),
}, STYLE_SSCC, TroSymbol.DOUBLE_CIRCLE, "#ffd4d4"),
# laut TRO_Typen.md: Basis + Vario-Antriebsmodul
TroDefinition("Vario", "FB_ILS_MTRO_Vario", {
TroItem.SEPARATOR: 1,
TroItem.VARIO_DRIVE: 1,
}, STYLE_VARIO, TroSymbol.RECT),
}, STYLE_VARIO, TroSymbol.RECT, "#e8d4f0"),
# laut TRO_Typen.md: Basis (Pin-Separator) + 19x Storage-Line + Scanner
# + Encoder + StorageRemoval-Schnittstelle
TroDefinition("PinStore_Auto", "FB_ILS_MTRO_PinStore_Auto", {
@@ -533,7 +569,7 @@ TRO_CATALOG: tuple[TroDefinition, ...] = (
TroItem.STORAGE_LINE: 19,
TroItem.SCANNER: 1,
TroItem.ENCODER: 1,
}, STYLE_STORE, TroSymbol.SQUARE),
}, STYLE_STORE, TroSymbol.SQUARE, "#d4f0d4"),
# aus SCL belegt (FB_ILS_MTRO_Vario_workStation.scl, VAR ab Zeile 77):
# fbSeparator1, fbConvVario, fbSepWait, fbBarcodeReader.
# Der Vario-Antrieb ist hier die WorkStation-Variante des STRO-Bausteins.
@@ -543,7 +579,7 @@ TRO_CATALOG: tuple[TroDefinition, ...] = (
TroItem.WORK_STATION: 1,
TroItem.ACCUMULATE: 1,
TroItem.SCANNER: 1,
}, STYLE_VARIO, TroSymbol.HEXAGON),
}, STYLE_VARIO, TroSymbol.HEXAGON, "#caa6e0"),
# aus SCL belegt (FB_EmptyCarrBuffer.scl): arfbSeparatorStorage als
# Array[1..5] of FB_ILS_STRO_Sep + 5x fbCarrierWaitStore.
# Kein eigener Eingangs-Separator - der "inTro" ist ein separater 1Sep-TRO
@@ -551,7 +587,7 @@ TRO_CATALOG: tuple[TroDefinition, ...] = (
TroDefinition("EmptyCarrBuffer", "FB_EmptyCarrBuffer", {
TroItem.STORAGE_LINE: 5,
TroItem.ACCUMULATE: 5,
}, STYLE_STORE, TroSymbol.DIAMOND),
}, STYLE_STORE, TroSymbol.DIAMOND, "#a6dca6"),
# aus SCL belegt (FB_LoadingBoom_INBOUND.scl): fbTiltSensor,
# fbDistanceFoot, fbWorkSation. Bewusst KEIN Separator und KEINE Weiche -
# der einzige nicht additive Typ.
@@ -559,7 +595,7 @@ TRO_CATALOG: tuple[TroDefinition, ...] = (
TroItem.BOOM: 1,
TroItem.FOOT: 1,
TroItem.TILT_SENSOR: 1,
}, STYLE_EXT, TroSymbol.ARROW),
}, STYLE_EXT, TroSymbol.ARROW, "#d9d9d9"),
# aus SCL belegt (FB_ILS_MTRO_2Sep1Swi.scl, VAR ab Zeile 115):
# fbSeparator1, fbSeparator2, fbSwitch1, fbBarcodeReader1, fbBarcodeReader2.
# Die Mapping-Tabelle in TRO_Typen.md nennt die beiden Scanner nicht -
@@ -568,7 +604,7 @@ TRO_CATALOG: tuple[TroDefinition, ...] = (
TroItem.SEPARATOR: 2,
TroItem.SWITCH: 1,
TroItem.SCANNER: 2,
}, STYLE_SWI, TroSymbol.TRIANGLE_DOWN),
}, STYLE_SWI, TroSymbol.TRIANGLE_DOWN, "#ffd6ad"),
# ACHTUNG - NICHT aus SCL belegt. Alle Typen oberhalb stammen aus
# vorhandenem Code bzw. der Mapping-Tabelle in TRO_Typen.md; dieser hier
# wurde am 2026-08-12 auf Anforderung aus dem Projekt 500573 (Mubea)
@@ -582,7 +618,7 @@ TRO_CATALOG: tuple[TroDefinition, ...] = (
TroItem.SEPARATOR: 2,
TroItem.SWITCH: 2,
TroItem.SCANNER: 2,
}, STYLE_SWI, TroSymbol.DOUBLE_TRIANGLE_DOWN),
}, STYLE_SWI, TroSymbol.DOUBLE_TRIANGLE_DOWN, "#f2a65a"),
)
_BY_NAME: dict[str, TroDefinition] = {t.get_name(): t for t in TRO_CATALOG}
@@ -610,5 +646,7 @@ def catalog() -> dict[str, TroDefinition]:
def mermaid_classdefs() -> list[str]:
"""classDef-Zeilen fuer ein Mermaid-Diagramm, eine je Farbgruppe."""
return [style.mermaid_classdef() for style in STYLES]
"""classDef-Zeilen fuer ein Mermaid-Diagramm: eine je Farbgruppe (u. a.
'ext' fuer die Systemgrenzen) plus eine je Typ (t_<Name>)."""
return ([style.mermaid_classdef() for style in STYLES]
+ [definition.mermaid_classdef() for definition in TRO_CATALOG])