0f02fd83aa
Replaces the generic marker with one shape per type, so the types are distinguishable in the drawing without relying on colour. The shape belongs to the type, so it sits in tro_catalog next to the colour - colour groups (6 groups), shape identifies (10 types): 1Sep circle 1Sep1Swi triangle 1Sep2Swi pentagon 1Sep_SSCC 2 circles Vario rectangle Vario_workStation hexagon PinStore_Auto square EmptyCarrBuffer diamond LoadingBoom arrow 2Sep1Swi triangle down The visible attributes are now ID and TYPE, as those are what the dialog edits; FB_BLOCK stays visible under --fb and ITEMS/CONFIDENCE/SEPARATORS stay hidden data. Note this renames the former TRO_ID/TRO_TYPE tags, so drawings annotated with an earlier version need regenerating. Marker layers now take the *stroke* colour instead of the fill. A CAD symbol is line work, and the pastel fills of the palette were nearly invisible as lines - LoadingBoom in particular came out almost white on white. cad/tro_edit.dcl and cad/tro_edit.lsp add the TROEDIT command: pick a TRO_SYM_* block, edit ID and TYPE, write back on OK. TYPE is a picklist rather than free text so it cannot drift from the catalogue; the list comes from cad/tro_types.lsp, which "tro_annotate.py --emit-lisp" generates from TRO_CATALOG. If that file is missing the dialog degrades to the block's current type instead of failing. The dialog deliberately changes attributes only. The marker shape belongs to the block definition of the type and FB_BLOCK is derived from it, so both follow on the next annotation run - the dialog says so, and TROEDIT prints a reminder when the type was changed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
540 lines
20 KiB
Python
540 lines
20 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Absichtlich ohne Shebang: der Windows-py-Launcher wuerde daraus "python3"
|
|
# ableiten und scheitert, wenn keine PythonCore-Installation registriert ist.
|
|
"""
|
|
tro_catalog.py - Typdefinition der TROs (Transfer Route Objects).
|
|
|
|
Dieses Modul ist die **einzige** Quelle fuer alles, was zur Erzeugung eines TRO
|
|
gebraucht wird. Es liest keine Dateien und braucht kein Markdown zur Laufzeit -
|
|
die Herkunft der Daten steht nur noch in den Kommentaren.
|
|
|
|
Ein TRO-Typ wird durch fuenf Dinge beschrieben:
|
|
|
|
1. Name - Kurztyp, wie in FB_Main und connect.ini verwendet ("1Sep")
|
|
2. FB-Baustein - der Siemens-Funktionsbaustein ("FB_ILS_MTRO_1Sep")
|
|
3. Bauteile - welche Elemente in diesem TRO stecken und wie viele
|
|
(1Sep = 1x Separator, 1Sep1Swi = 1x Separator + 1x Weiche)
|
|
4. Farbe - Farbgruppe fuer Zeichnungen (Graphviz, Mermaid, CAD)
|
|
5. Symbol - Form des CAD-Markers, je Typ eine eigene (Kreis, Dreieck,
|
|
Rechteck, Raute ...)
|
|
|
|
Herkunft der Daten (Stand :data:`CATALOG_AS_OF`)
|
|
-----------------------------------------------
|
|
Einmalig uebernommen aus - danach hier gepflegt, nicht mehr nachgelesen:
|
|
|
|
doc/TRO_Katalog/TRO_Katalog.md
|
|
"Overview of all TRO types" -> Typname und FB-Baustein
|
|
"Color legend" -> Farbgruppen (siehe TroStyle)
|
|
doc/TRO_Typen.md
|
|
"Baukasten-Analyse" -> Bauteile je Typ (Sub-Bausteine/STRO)
|
|
doc/HundM/Json_Layout-Konzept.md
|
|
classDef-Farben -> die konkreten Farbwerte
|
|
doc/TRO_Katalog/scl_templates/*.scl
|
|
VAR-Deklarationen der lokal vorliegenden FBs - dort sind die Bauteile
|
|
direkt nachweisbar
|
|
|
|
Belegbarkeit der Bauteillisten
|
|
------------------------------
|
|
Nur vier FBs liegen als Quelle im Repo; deren Bauteile sind aus den
|
|
VAR-Deklarationen **verifiziert** (Kommentar "aus SCL belegt"). Die uebrigen
|
|
Typen sind `.liblink`-Referenzen auf die externe ILSLib - ihre Bauteile stammen
|
|
aus der Mapping-Tabelle in TRO_Typen.md (Kommentar "laut TRO_Typen.md").
|
|
|
|
Verwendung
|
|
----------
|
|
from tro_catalog import TroItem, get_tro, tro_names
|
|
|
|
tro = get_tro("1Sep1Swi")
|
|
tro.get_fb_block() -> "FB_ILS_MTRO_1Sep1Swi"
|
|
tro.get_item_count(TroItem.SWITCH) -> 1
|
|
tro.get_items() -> {"Separator": 1, "Switch": 1}
|
|
tro.describe_items() -> "1x Separator, 1x Switch"
|
|
tro.get_style().fill -> "#ffe4a0"
|
|
tro.get_dot_attrs() -> {"fillcolor": ..., "color": ...}
|
|
tro.set_item(TroItem.SCANNER, 1) -> Bauteil ergaenzen/aendern
|
|
|
|
TroDefinition ist ein Pydantic-Modell (v2). Neben den get_*/set_*-Methoden gibt
|
|
es damit Validierung bei jeder Zuweisung sowie model_dump()/model_dump_json()
|
|
und model_validate() fuer das geplante JSON-Layoutmodell.
|
|
Benoetigt `pydantic >= 2.0.0` (siehe requirements.txt, bin/install_py).
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from pydantic import BaseModel, ConfigDict, Field, field_validator
|
|
|
|
__all__ = [
|
|
"CATALOG_AS_OF",
|
|
"TroItem",
|
|
"TroStyle",
|
|
"TroSymbol",
|
|
"TroDefinition",
|
|
"ITEM_FB",
|
|
"STYLES",
|
|
"TRO_CATALOG",
|
|
"get_tro",
|
|
"tro_names",
|
|
"set_tro",
|
|
"catalog",
|
|
"mermaid_classdefs",
|
|
]
|
|
|
|
# Stand der Dokumente, aus denen die Typdefinition uebernommen wurde
|
|
CATALOG_AS_OF = "2026-07-20"
|
|
|
|
|
|
class TroItem:
|
|
"""
|
|
Bauteilarten, aus denen ein TRO zusammengesetzt ist.
|
|
|
|
Konstanten statt freier Strings, damit Tippfehler auffallen.
|
|
:data:`ITEM_FB` ordnet jeder Art ihren Sub-Funktionsbaustein zu.
|
|
"""
|
|
|
|
SEPARATOR = "Separator"
|
|
SWITCH = "Switch"
|
|
SCANNER = "Scanner"
|
|
VARIO_DRIVE = "VarioDrive"
|
|
WORK_STATION = "WorkStation"
|
|
STORAGE_LINE = "StorageLine"
|
|
ACCUMULATE = "Accumulate"
|
|
ENCODER = "Encoder"
|
|
SSCC = "SSCC"
|
|
BOOM = "Boom"
|
|
FOOT = "Foot"
|
|
TILT_SENSOR = "TiltSensor"
|
|
|
|
@classmethod
|
|
def all(cls) -> tuple[str, ...]:
|
|
"""Alle bekannten Bauteilarten."""
|
|
return tuple(
|
|
value
|
|
for key, value in vars(cls).items()
|
|
if key.isupper() and isinstance(value, str)
|
|
)
|
|
|
|
|
|
# Sub-Funktionsbaustein je Bauteilart. Leer = kein eigener FB (Hardware bzw.
|
|
# im Rahmenwerk des TRO umgesetzt).
|
|
ITEM_FB: dict[str, str] = {
|
|
TroItem.SEPARATOR: "FB_ILS_STRO_Sep",
|
|
TroItem.SWITCH: "FB_ILS_STRO_Switch",
|
|
TroItem.SCANNER: "FB_BarcodeReaderCognex",
|
|
TroItem.VARIO_DRIVE: "FB_ILS_STRO_Vario",
|
|
TroItem.WORK_STATION: "FB_ILS_STRO_Vario_WorkStation",
|
|
TroItem.STORAGE_LINE: "FB_ILS_STRO_Sep", # als Array[1..N]
|
|
TroItem.ACCUMULATE: "FB_CarrAccumulate1Sep",
|
|
TroItem.ENCODER: "",
|
|
TroItem.SSCC: "",
|
|
TroItem.BOOM: "FB_BoomWorkStation",
|
|
TroItem.FOOT: "FB_DistanceFoot",
|
|
TroItem.TILT_SENSOR: "FB_Tilt_TEST",
|
|
}
|
|
|
|
|
|
class TroSymbol:
|
|
"""
|
|
Zeichensymbole fuer die Marker in der Zeichnung.
|
|
|
|
Die Farbe gruppiert (siehe TroStyle), das Symbol unterscheidet den einzelnen
|
|
Typ. Alle TROs eines Typs bekommen dasselbe Symbol. Die Formen sind absichtlich
|
|
einfach - Kreis, Vielecke, Rechteck - damit sie in jedem Zoom erkennbar
|
|
bleiben und als LWPOLYLINE bzw. CIRCLE in den Block passen.
|
|
"""
|
|
|
|
CIRCLE = "circle" # Kreis
|
|
DOUBLE_CIRCLE = "double_circle" # Kreis mit zweitem Kreis innen
|
|
TRIANGLE = "triangle" # Dreieck, Spitze oben
|
|
TRIANGLE_DOWN = "triangle_down" # Dreieck, Spitze unten
|
|
SQUARE = "square" # Quadrat
|
|
DIAMOND = "diamond" # Raute
|
|
PENTAGON = "pentagon" # Fuenfeck
|
|
HEXAGON = "hexagon" # Sechseck
|
|
RECT = "rect" # liegendes Rechteck
|
|
ARROW = "arrow" # Pfeil/Fahne
|
|
|
|
@classmethod
|
|
def all(cls) -> tuple[str, ...]:
|
|
return tuple(
|
|
value
|
|
for key, value in vars(cls).items()
|
|
if key.isupper() and isinstance(value, str)
|
|
)
|
|
|
|
|
|
class TroStyle(BaseModel):
|
|
"""
|
|
Darstellung einer TRO-Typgruppe.
|
|
|
|
Farbwerte uebernommen aus der "Color legend" in TRO_Katalog.md bzw. den
|
|
classDef-Zeilen in Json_Layout-Konzept.md:
|
|
|
|
sep blau Separator (1Sep)
|
|
swi orange Weiche (1Sep1Swi, 1Sep2Swi, 2Sep1Swi)
|
|
sscc rot Scanner-Sonderfall (1Sep_SSCC)
|
|
vario violett Kettenfoerderer (Vario, Vario_workStation)
|
|
store gruen Speicher/Puffer (PinStore_Auto, EmptyCarrBuffer)
|
|
ext grau Systemgrenze, extern, Loading Boom
|
|
|
|
Wichtig: gruen bedeutet **Speicher**, nicht Foerderer. Der Vario ist
|
|
violett.
|
|
"""
|
|
|
|
model_config = ConfigDict(validate_assignment=True, extra="forbid",
|
|
str_strip_whitespace=True)
|
|
|
|
group: str = Field(min_length=1, description="Kurzname der Farbgruppe, z. B. 'vario'")
|
|
label: str = Field(min_length=1, description="Klartext, z. B. 'Kettenfoerderer'")
|
|
fill: str = Field(min_length=4, description="Fuellfarbe als Hex, z. B. '#e8d4f0'")
|
|
stroke: str = Field(min_length=4, description="Randfarbe als Hex")
|
|
font: str = Field(default="#111111", min_length=4, description="Schriftfarbe")
|
|
|
|
def get_group(self) -> str:
|
|
return self.group
|
|
|
|
def get_fill(self) -> str:
|
|
return self.fill
|
|
|
|
def get_stroke(self) -> str:
|
|
return self.stroke
|
|
|
|
def get_font(self) -> str:
|
|
return self.font
|
|
|
|
def dot_attrs(self) -> dict[str, str]:
|
|
"""Graphviz-Knotenattribute."""
|
|
return {"fillcolor": self.fill, "color": self.stroke, "fontcolor": self.font}
|
|
|
|
def mermaid_classdef(self) -> str:
|
|
"""Mermaid-classDef-Zeile fuer diese Gruppe."""
|
|
return (
|
|
f"classDef {self.group} fill:{self.fill},"
|
|
f"stroke:{self.stroke},color:{self.font}"
|
|
)
|
|
|
|
|
|
# Farbgruppen - eine Instanz je Gruppe, von den Typen unten referenziert.
|
|
STYLE_SEP = TroStyle(group="sep", label="Separator",
|
|
fill="#d4e8ff", stroke="#3388cc")
|
|
STYLE_SWI = TroStyle(group="swi", label="Weiche",
|
|
fill="#ffe4a0", stroke="#cc8800")
|
|
STYLE_SSCC = TroStyle(group="sscc", label="Scanner (SSCC)",
|
|
fill="#ffd4d4", stroke="#cc3333")
|
|
STYLE_VARIO = TroStyle(group="vario", label="Kettenfoerderer",
|
|
fill="#e8d4f0", stroke="#883388")
|
|
STYLE_STORE = TroStyle(group="store", label="Speicher / Puffer",
|
|
fill="#d4f0d4", stroke="#338833")
|
|
STYLE_EXT = TroStyle(group="ext", label="Systemgrenze / extern",
|
|
fill="#f0f0f0", stroke="#888888", font="#404040")
|
|
|
|
STYLES: tuple[TroStyle, ...] = (
|
|
STYLE_SEP, STYLE_SWI, STYLE_SSCC, STYLE_VARIO, STYLE_STORE, STYLE_EXT,
|
|
)
|
|
|
|
|
|
class TroDefinition(BaseModel):
|
|
"""
|
|
Ein TRO-Typ: Name, FB-Baustein, Bauteile und Darstellung.
|
|
|
|
Pydantic-Modell - die Felder werden bei Erzeugung *und* bei jeder Zuweisung
|
|
geprueft (`validate_assignment`). Damit ist ein TroDefinition-Objekt nie in
|
|
einem ungueltigen Zustand:
|
|
|
|
name nicht leer
|
|
fb_block nicht leer
|
|
items {Bauteilart: Anzahl}, Anzahl >= 1, Art nicht leer;
|
|
Eintraege mit Anzahl <= 0 werden verworfen
|
|
|
|
Positionsargumente sind weiter moeglich (`TroDefinition("1Sep", "FB_...")`),
|
|
ebenso benannte (`TroDefinition(name="1Sep", fb_block="FB_...")`).
|
|
|
|
Weil es ein BaseModel ist, gibt es Serialisierung gratis - nuetzlich fuer
|
|
das geplante JSON-Layoutmodell:
|
|
|
|
tro.model_dump() -> dict
|
|
tro.model_dump_json(indent=2) -> JSON
|
|
TroDefinition.model_validate(d) -> aus dict
|
|
TroDefinition.model_json_schema() -> JSON-Schema
|
|
"""
|
|
|
|
model_config = ConfigDict(
|
|
validate_assignment=True, # set_* darf nichts Ungueltiges hinterlassen
|
|
extra="forbid", # Tippfehler in Feldnamen fallen auf
|
|
str_strip_whitespace=True,
|
|
)
|
|
|
|
name: str = Field(
|
|
min_length=1,
|
|
description="Kurztyp, wie in FB_Main und connect.ini verwendet, z. B. '1Sep'",
|
|
)
|
|
fb_block: str = Field(
|
|
min_length=1,
|
|
description="Name des Siemens-Funktionsbausteins, z. B. 'FB_ILS_MTRO_1Sep'",
|
|
)
|
|
items: dict[str, int] = Field(
|
|
default_factory=dict,
|
|
description="Bauteilart -> Anzahl, z. B. {'Separator': 1, 'Switch': 1}",
|
|
)
|
|
style: TroStyle = Field(
|
|
default=STYLE_EXT,
|
|
description="Farbgruppe fuer Zeichnungen (Graphviz, Mermaid, CAD-Symbol)",
|
|
)
|
|
symbol: str = Field(
|
|
default=TroSymbol.CIRCLE,
|
|
min_length=1,
|
|
description="Zeichensymbol des Markers im CAD, z. B. 'triangle'",
|
|
)
|
|
|
|
def __init__(
|
|
self,
|
|
name: str | None = None,
|
|
fb_block: str | None = None,
|
|
items: dict[str, int] | None = None,
|
|
style: TroStyle | None = None,
|
|
symbol: str | None = None,
|
|
**data,
|
|
) -> None:
|
|
# Positionsargumente auf Feldnamen abbilden, damit die bisherige
|
|
# Aufrufform TroDefinition("1Sep", "FB_...", {...}) erhalten bleibt.
|
|
if name is not None:
|
|
data["name"] = name
|
|
if fb_block is not None:
|
|
data["fb_block"] = fb_block
|
|
if items is not None:
|
|
data["items"] = items
|
|
if style is not None:
|
|
data["style"] = style
|
|
if symbol is not None:
|
|
data["symbol"] = symbol
|
|
super().__init__(**data)
|
|
|
|
@field_validator("items", mode="after")
|
|
@classmethod
|
|
def _clean_items(cls, value: dict[str, int]) -> dict[str, int]:
|
|
"""Leere Bauteilarten ablehnen, Anzahlen <= 0 verwerfen."""
|
|
cleaned: dict[str, int] = {}
|
|
for item, count in value.items():
|
|
key = str(item).strip()
|
|
if not key:
|
|
raise ValueError("Bauteilart darf nicht leer sein")
|
|
if int(count) > 0:
|
|
cleaned[key] = int(count)
|
|
return cleaned
|
|
|
|
# -- get ---------------------------------------------------------------
|
|
|
|
def get_name(self) -> str:
|
|
"""Kurztyp, z. B. '1Sep1Swi'."""
|
|
return self.name
|
|
|
|
def get_fb_block(self) -> str:
|
|
"""Name des Siemens-Funktionsbausteins."""
|
|
return self.fb_block
|
|
|
|
def get_items(self) -> dict[str, int]:
|
|
"""Alle Bauteile als {Art: Anzahl} (Kopie - Aenderungen wirken nicht)."""
|
|
return dict(self.items)
|
|
|
|
def get_item_names(self) -> list[str]:
|
|
"""Enthaltene Bauteilarten, alphabetisch."""
|
|
return sorted(self.items)
|
|
|
|
def get_item_count(self, item: str) -> int:
|
|
"""Anzahl einer Bauteilart; 0 wenn nicht enthalten."""
|
|
return self.items.get(item, 0)
|
|
|
|
def has_item(self, item: str) -> bool:
|
|
"""Ist die Bauteilart enthalten?"""
|
|
return self.get_item_count(item) > 0
|
|
|
|
def get_item_fb(self, item: str) -> str:
|
|
"""Sub-Funktionsbaustein einer Bauteilart ('' wenn keiner)."""
|
|
return ITEM_FB.get(item, "")
|
|
|
|
def get_total_items(self) -> int:
|
|
"""Summe aller Bauteile."""
|
|
return sum(self.items.values())
|
|
|
|
def get_style(self) -> TroStyle:
|
|
"""Darstellung (Farbgruppe) dieses Typs."""
|
|
return self.style
|
|
|
|
def get_symbol(self) -> str:
|
|
"""Zeichensymbol des Markers, z. B. 'triangle'."""
|
|
return self.symbol
|
|
|
|
def get_group(self) -> str:
|
|
"""Kurzname der Farbgruppe, z. B. 'vario'."""
|
|
return self.style.group
|
|
|
|
def get_dot_attrs(self) -> dict[str, str]:
|
|
"""Graphviz-Knotenattribute dieses Typs."""
|
|
return self.style.dot_attrs()
|
|
|
|
# -- set ---------------------------------------------------------------
|
|
#
|
|
# Jede Zuweisung laeuft durch die Pydantic-Validierung, weil
|
|
# validate_assignment aktiv ist.
|
|
|
|
def set_name(self, name: str) -> None:
|
|
"""Kurztyp setzen."""
|
|
self.name = name
|
|
|
|
def set_fb_block(self, fb_block: str) -> None:
|
|
"""FB-Baustein setzen."""
|
|
self.fb_block = fb_block
|
|
|
|
def set_items(self, items: dict[str, int]) -> None:
|
|
"""Bauteilliste vollstaendig ersetzen."""
|
|
self.items = dict(items)
|
|
|
|
def set_style(self, style: TroStyle) -> None:
|
|
"""Darstellung (Farbgruppe) setzen."""
|
|
self.style = style
|
|
|
|
def set_symbol(self, symbol: str) -> None:
|
|
"""Zeichensymbol des Markers setzen."""
|
|
self.symbol = symbol
|
|
|
|
def set_item(self, item: str, count: int) -> None:
|
|
"""
|
|
Anzahl einer Bauteilart setzen.
|
|
|
|
count <= 0 entfernt das Bauteil. Unbekannte Arten sind erlaubt, damit
|
|
neue Bauteile ohne Aenderung an TroItem ergaenzt werden koennen.
|
|
"""
|
|
updated = dict(self.items)
|
|
key = str(item).strip()
|
|
if not key:
|
|
raise ValueError(f"{self.name}: Bauteilart darf nicht leer sein")
|
|
if int(count) <= 0:
|
|
updated.pop(key, None)
|
|
else:
|
|
updated[key] = int(count)
|
|
self.items = updated
|
|
|
|
def add_item(self, item: str, count: int = 1) -> None:
|
|
"""Anzahl einer Bauteilart erhoehen (oder Bauteil neu aufnehmen)."""
|
|
self.set_item(item, self.get_item_count(item) + int(count))
|
|
|
|
def remove_item(self, item: str) -> None:
|
|
"""Bauteilart entfernen."""
|
|
self.set_item(item, 0)
|
|
|
|
# -- Darstellung -------------------------------------------------------
|
|
|
|
def describe_items(self) -> str:
|
|
"""Bauteile als Text, z. B. '1x Separator, 1x Switch'."""
|
|
if not self.items:
|
|
return "-"
|
|
return ", ".join(f"{self.items[i]}x {i}" for i in self.get_item_names())
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Statische Typdefinition
|
|
# ---------------------------------------------------------------------------
|
|
#
|
|
# Quellen: doc/TRO_Typen.md (Baukasten-Analyse, Mapping-Tabelle) und
|
|
# doc/TRO_Katalog/scl_templates/*.scl (VAR-Deklarationen)
|
|
|
|
TRO_CATALOG: tuple[TroDefinition, ...] = (
|
|
# Basistyp: 1x Separator plus das Rahmenwerk, das jeder Typ besitzt
|
|
# (PriorityManager, JamArea Entry/Exit, HMI, Safety, MachineState).
|
|
TroDefinition("1Sep", "FB_ILS_MTRO_1Sep", {
|
|
TroItem.SEPARATOR: 1,
|
|
}, STYLE_SEP, TroSymbol.CIRCLE),
|
|
# laut TRO_Typen.md: Basis + 1x Switch-Modul
|
|
TroDefinition("1Sep1Swi", "FB_ILS_MTRO_1Sep1Swi", {
|
|
TroItem.SEPARATOR: 1,
|
|
TroItem.SWITCH: 1,
|
|
}, STYLE_SWI, TroSymbol.TRIANGLE),
|
|
# 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),
|
|
# 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),
|
|
# laut TRO_Typen.md: Basis + Vario-Antriebsmodul
|
|
TroDefinition("Vario", "FB_ILS_MTRO_Vario", {
|
|
TroItem.SEPARATOR: 1,
|
|
TroItem.VARIO_DRIVE: 1,
|
|
}, STYLE_VARIO, TroSymbol.RECT),
|
|
# laut TRO_Typen.md: Basis (Pin-Separator) + 19x Storage-Line + Scanner
|
|
# + Encoder + StorageRemoval-Schnittstelle
|
|
TroDefinition("PinStore_Auto", "FB_ILS_MTRO_PinStore_Auto", {
|
|
TroItem.SEPARATOR: 1,
|
|
TroItem.STORAGE_LINE: 19,
|
|
TroItem.SCANNER: 1,
|
|
TroItem.ENCODER: 1,
|
|
}, STYLE_STORE, TroSymbol.SQUARE),
|
|
# 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.
|
|
TroDefinition("Vario_workStation", "FB_ILS_MTRO_Vario_workStation", {
|
|
TroItem.SEPARATOR: 1,
|
|
TroItem.VARIO_DRIVE: 1,
|
|
TroItem.WORK_STATION: 1,
|
|
TroItem.ACCUMULATE: 1,
|
|
TroItem.SCANNER: 1,
|
|
}, STYLE_VARIO, TroSymbol.HEXAGON),
|
|
# 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
|
|
# (in der Referenzanlage z. B. TRO101_IN neben TRO101).
|
|
TroDefinition("EmptyCarrBuffer", "FB_EmptyCarrBuffer", {
|
|
TroItem.STORAGE_LINE: 5,
|
|
TroItem.ACCUMULATE: 5,
|
|
}, STYLE_STORE, TroSymbol.DIAMOND),
|
|
# aus SCL belegt (FB_LoadingBoom_INBOUND.scl): fbTiltSensor,
|
|
# fbDistanceFoot, fbWorkSation. Bewusst KEIN Separator und KEINE Weiche -
|
|
# der einzige nicht additive Typ.
|
|
TroDefinition("LoadingBoom", "FB_LoadingBoom_INBOUND", {
|
|
TroItem.BOOM: 1,
|
|
TroItem.FOOT: 1,
|
|
TroItem.TILT_SENSOR: 1,
|
|
}, STYLE_EXT, TroSymbol.ARROW),
|
|
# 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 -
|
|
# hier gilt der Code.
|
|
TroDefinition("2Sep1Swi", "FB_ILS_MTRO_2Sep1Swi", {
|
|
TroItem.SEPARATOR: 2,
|
|
TroItem.SWITCH: 1,
|
|
TroItem.SCANNER: 2,
|
|
}, STYLE_SWI, TroSymbol.TRIANGLE_DOWN),
|
|
)
|
|
|
|
_BY_NAME: dict[str, TroDefinition] = {t.get_name(): t for t in TRO_CATALOG}
|
|
|
|
|
|
def get_tro(name: str) -> TroDefinition | None:
|
|
"""Typdefinition nach Namen; None wenn unbekannt."""
|
|
return _BY_NAME.get(name)
|
|
|
|
|
|
def tro_names() -> list[str]:
|
|
"""Alle Typnamen in Katalogreihenfolge."""
|
|
return [t.get_name() for t in TRO_CATALOG]
|
|
|
|
|
|
def set_tro(definition: TroDefinition) -> None:
|
|
"""Typdefinition ergaenzen oder ersetzen (nur zur Laufzeit)."""
|
|
_BY_NAME[definition.get_name()] = definition
|
|
|
|
|
|
|
|
def catalog() -> dict[str, TroDefinition]:
|
|
"""Alle Typdefinitionen als {Name: TroDefinition} (Kopie der Zuordnung)."""
|
|
return dict(_BY_NAME)
|
|
|
|
|
|
def mermaid_classdefs() -> list[str]:
|
|
"""classDef-Zeilen fuer ein Mermaid-Diagramm, eine je Farbgruppe."""
|
|
return [style.mermaid_classdef() for style in STYLES]
|