# HW-Planung: Materialfluss, Symbole, Nummerierung Menue **SSG_LIB -> HW Planung**. Aus dem mechanischen Layout (Ursprungszeichnung) entstehen Materialfluss und E-Geraete-Symbole - je nach Wahl in der aktuellen Zeichnung oder in einer eigenen Planungsdatei (Vorgabe `_HW.dxf` in `DXFM_RESULTS`). Die Ursprungsdatei auf der Platte wird nie veraendert. ## Ausgabeziel (Dialog vor dem Erzeugen) Vor "Materialfluss erzeugen" und "Symbole erzeugen" (auch vor den Einzelbefehlen `HW_SYM_*`) fragt der Dialog `dcl/hw_ausgabe.dcl`, wohin: | Wahl | Ergebnis | |---|---| | **Aktuelle Zeichnung** | Materialfluss bzw. Symbole kommen in die offene Zeichnung, auf eigene Layer. Die fruehere Ausgabe desselben Befehls (erkannt an XDATA `SSG_HW_MF` bzw. `SSG_HW_SYM` je Geraeteart) wird ersetzt. Technisch: Python schreibt eine Zwischendatei `_HW_tmp.dxf` ohne Einheit, LISP fuegt sie bei 0,0 ein und loest den Block auf. Symbolbloecke, die es in der Zeichnung schon gibt, behalten ihre vorhandene Definition. | | **Bestehende Datei ergaenzen** | Datei ueber "Auswaehlen..." waehlen; der Befehl ersetzt dort nur seinen eigenen Anteil. So landen Materialfluss und Symbole nacheinander in derselben Datei. | | **Neue Datei** | Name eingeben (ohne Endung, Ordner `DXFM_RESULTS`). Gibt es die Datei schon, bleibt der Dialog mit einem Hinweis offen. | Die letzte Wahl wird fuer die Sitzung gemerkt. Die Datei muss beim Schreiben in BricsCAD geschlossen sein. "Symbole nummerieren" arbeitet in einer geoeffneten **DXF**-Zeichnung - bei Ausgabe in die aktuelle Zeichnung muss diese also eine DXF sein. ## Ablauf | Schritt | Menue / Befehl | Wo ausfuehren | Ergebnis | |---|---|---|---| | 1 | Materialfluss erzeugen (`HW_MATERIALFLUSS`) | Ursprungszeichnung | Polylinien des Materialflusses im gewaehlten Ziel | | 2 | Symbole erzeugen (`HW_SYMBOLE`) | Ursprungszeichnung | E-Geraete-Symbole mit ID-Vorlage (z.B. `MB1@@@`) im gewaehlten Ziel | | 3 | - | Zieldatei oeffnen | Renamer-Bereiche ziehen (Rahmen oder Polylinie, siehe unten) | | 4 | Symbole nummerieren (`HW_NUMMERIEREN`) | Zieldatei (DXF) | `@` in den Symbolen durch laufende Nummern ersetzt | Schritt 1 und 2 duerfen in beliebiger Reihenfolge und beliebig oft laufen: jeder ersetzt in der `_HW.dxf` nur seinen eigenen Anteil (Materialfluss = alles auf den `HW_*`-Layern, Symbole = Bloecke mit XDATA `SSG_HW_SYM` der jeweiligen Geraeteart). Was der Anwender selbst gezeichnet hat - Renamer-Bereiche, Polylinien, Notizen - bleibt stehen. Dafuer muss die `_HW.dxf` waehrend Schritt 1/2 in BricsCAD **geschlossen** sein (sonst ist sie gesperrt; das Skript meldet das). ## 1. Materialfluss (`lib/hw_materialfluss.py`) `HW_MATERIALFLUSS` ruft `EXPORTCSV` auf und zeichnet aus der CSV flach (Z = 0): | Element | Darstellung | Layer | |---|---|---| | Kreisel/Eckrad | geschlossenes Rechteck um die Laufbahn, Punktfolge in Drehrichtung, Pfeile | `HW_Kreisel`, `HW_Richtung` | | Strecke / Gefaellestrecke | Polylinie AS -> Separatoren -> ES (Spalte `TrackIds`), Endpfeil | `HW_Materialfluss`, `HW_Richtung` | | Weiche | kleiner Kreis am Beruehrpunkt zweier Kreisel | `HW_Weiche` | | BTMT Beladung | grosser Kreis auf K1, kleiner Kreis auf K2, Linie | `HW_Beladung` | | BTMT Entladung | kleiner Kreis auf K1, grosser Kreis auf K2, Linie | `HW_Entladung` | Layernamen/-farben: `cfg/layer.cfg`, Abschnitt `[hw_planung]`. ## 2. Symbole (`Lisp/HwPlanung.lsp` + `lib/hw_symbole.py`) Regelwerk `cfg/io_regeln.json`: - **bauteile**: Mechanik-Bloecke (`Separator_SP*`, `AS_Element*`, `AN8_*`, `SP8_*`, `Vario_Motorstation*`, ...) und die Rollen, die an jedem davon sitzen. Gefunden werden sie auch, wenn sie in `VF_n`/`GF_n`/`KREISEL_n` verschachtelt sind. - **rollen**: je Rolle Geraete-Praefix (MB, BG, MA, FC, GF, BX) und Symbol (Blockname); `block_nach_name` waehlt z.B. fuer eine rechte Vario-Motorstation den rechten Motor. - **io_vorlage**: die ID beim Erzeugen ist ``, Vorgabe `1@@@` -> `MB1@@@`. Die Platzhalter-ID des Katalogblocks in `VERW`/`BEZEICHNUNG` (z.B. `Motor MA0`) wird ebenfalls durch die Vorlage ersetzt. Symboldefinitionen `cfg/hw_symbole.json` - es gibt **keine Symbol-Bibliothek** als Referenzdokument, `hw_symbole.py` baut die Bloecke bei jedem Lauf neu daraus: - **vorlagen**: gemeinsames Aussehen, derzeit `io_750` (750 x 270, Sensoren, Ventile, Motoren, Motorschutz) und `geraet_800` (800 x 350, Encoder, Scanner, mit Schraffur): Rahmen und je Attribut Lage, Texthoehe, Sichtbarkeit, Farbe, Layer, Ausrichtung, Textstil, Breitenfaktor, Vorgabewert. - **symbole**: je Blockname Vorlage, Layer, Farbe, `versatz` (Lage des Rahmens zum Einfuegepunkt - Eingaenge und Motoren haengen im Katalog nach unten, `[0, -270]`), `attribute` (Abweichungen von der Vorlage je Tag), `ohne` (Attribute, die das Symbol nicht hat) und die Attributwerte (`IO` mit Platzhalter-ID wie `MB0`, `VERW`, `BEZEICHNUNG`, `KENNZEICHNUNG`, `ARTINR`, `BESCHR`, `SPS`). - Die Symbole tragen **dieselben Blocknamen wie die ILS-Katalogsymbole** in `kabellaengen/doc/Symbole/ILS-Symbole.dxf` und sind ihnen exakt nachgebaut (Einfuegepunkt, Rahmen, Schraffur, Lage/Hoehe/Stil/Farbe aller Attribute, Vorgabewerte), damit beim Mischen beider Fassungen in einer Zeichnung keine still abweichende Definition gilt. `tests/test_hw_symbole.py` (`test_symbole_gleichen_dem_katalog`) prueft das gegen den Katalog, sofern kabellaengen daneben liegt (oder `ILS_SYMBOLE_KATALOG` gesetzt ist). Aendert sich ein Katalogsymbol, schlaegt der Test fehl - dann hier nachziehen. - Jeder Lauf baut die Blockdefinitionen in der `_HW.dxf` neu auf, Katalogfassungen gleichen Namens werden dort also ueberschrieben. LISP sucht die Bauteile in der Ursprungszeichnung und schreibt je Rolle den **Zielpunkt** des Bauteils nach `DXFM_RESULTS/_hw_symbole.json`: Separator-Sensor, AS/ES-Element, Entladung, AN8/SP8-Zentrum (Kreisel-Motor bzw. Spannstation), Vario-Motor-/Umlenkstation, Scanner - jeweils deren Einfuegepunkt, flach auf Z = 0. `hw_symbole.py` rechnet daraus die Lage und setzt die Symbole in die `_HW.dxf`. ### Lage der Symbole - Die Marke **`REALE_POSITION`** (das kleine `x` am rechten Rahmenrand) liegt mit ihrem **x genau auf dem Zielpunkt**, der Kasten daneben (links davon). - Mehrere Symbole eines Bauteils stehen **luekenlos uebereinander**, in der Reihenfolge von `benoetigt` (erstes oben, z.B. Ventil ueber Sensor am Separator, Motor ueber Motorschutz), als Gruppe in y um das Ziel zentriert. Ein einzelnes Symbol hat seine Marke damit genau auf dem Ziel. - **Ohne Ueberlappung**: jede Gruppe wird gegen die 2D-Bounding-Boxen der schon gesetzten Rahmen geprueft (Mindestabstand `platzierung.abstand`). Beruehrt sie eine, wird sie nur in **y** verschoben (+-`schritt`, +-2*`schritt`, ... bis `max_verschiebung`) - x bleibt auf dem Ziel. Findet sich keine freie Lage, bleibt sie unverschoben und das Skript meldet die Anzahl. - Die Lage wird immer aus dem **ganzen** Plan berechnet; ein Einzelbefehl wie `HW_SYM_VENTILE` setzt die Ventile also genau dorthin, wo sie auch mit `HW_SYMBOLE` laegen. - Gegen die Materialfluss-Polylinien und andere Geometrie wird nicht geprueft, nur Symbol gegen Symbol. Mubea: 70 von 83 Bauteilgruppen liegen genau auf ihrem Ziel, 13 weichen in y aus (meist 50-600 mm, Scanner bis 1,7 m). Einzelbefehle (nicht im Menue, zum schrittweisen Erzeugen und Pruefen; jeder ersetzt nur seine Geraeteart): `HW_SYM_VENTILE` (MB), `HW_SYM_SENSOREN` (BG), `HW_SYM_MOTOREN` (MA), `HW_SYM_MOTORSCHUTZ` (FC), `HW_SYM_ENCODER` (GF), `HW_SYM_SCANNER` (BX); `HW_SYM_LOESCHEN` entfernt alle erzeugten Symbole aus der `_HW.dxf`. ## 3. Renamer-Bereiche Ein Renamer-Bereich ist ein Block auf einem der Layer aus `cfg/enumerate.cfg` (`ILS_RENAMER`, `Omniflo_RENAMER`), der eine **Polylinie** enthaelt und Attribute traegt - direkt oder zweistufig (aeusserer Block mit Polylinie + innerer Attribut-Block, wie die `ILS_Renamer-*`-Bloecke in `kabellaengen/doc/Symbole/ILS-Symbole.dxf`): | Attribut | Bedeutung | |---|---| | `NAME` bzw. `NAME1`..`NAME3` | Nummernmuster, z.B. `BG-1@@@`; die Anzahl `@` bestimmt die Stellen und muss zur `io_vorlage` passen | | `LAYER_NAME` bzw. `LAYER_NAME1`..`3` | Layer der Symbole, die mitgezaehlt werden (z.B. `ILS_Eingang`, `ILS_Ausgang`) | | `DIRECTION` | Reihenfolge, siehe unten | | `KENNZEICHNUNG` | Zuordnung zum Unterverteiler, z.B. `=A01+UC0100` | `DIRECTION`: - **Rechteck** (geschlossene Polylinie mit 4 Ecken): `LEFT_RIGHT`, `RIGHT_LEFT`, `TOP_BOTTOM`, `BOTTOM_TOP` und die Kombinationen `TOP_BOTTOM/LEFT_RIGHT`, `LEFT_RIGHT/TOP_BOTTOM` usw. (erste Angabe = Hauptsortierung). Mitgezaehlt werden die Symbole innerhalb des Rechtecks. - **`POLYLINE_PATH`**: Nummerierung **entlang der Polylinie** in Punktfolge. Mitgezaehlt werden die Symbole hoechstens `polyline_max_distance` (Vorgabe 500 mm, `cfg/enumerate.cfg`) von der Linie entfernt. Die Polylinie darf **kein Rechteck** sein: offen braucht sie mindestens 5 Punkte (genau 4 offene Punkte gelten als Rechteck), eine 2-Punkt-Linie wird nicht erkannt. Bereiche mit identischen Attributen (`NAME*`, `LAYER_NAME*`, `DIRECTION`, `KENNZEICHNUNG`) bilden eine Gruppe und werden fortlaufend gemeinsam nummeriert. Alle Symbole einer Gruppe teilen sich einen Zaehler, egal auf welchem Layer (z.B. BG 1001, BG 1002, MB 1003 in Reihenfolge entlang der Linie). ## 4. Nummerieren (`lib/create_numbers.py`) `HW_NUMMERIEREN` in der geoeffneten `_HW.dxf`: 1. speichert die Zeichnung (`QSAVE`; sie muss eine DXF sein), 2. ruft `create_numbers.py --dryrun --info ... --errorfile ...` auf, 3. traegt die Nummern in die offene Zeichnung ein (Zuordnung ueber Wert und Einfuegepunkt jedes Attributs mit `@`). Ergebnisdateien neben der Zeichnung: `_nummern.json` (alle Umbenennungen) und - nur bei Problemen - `_nummern_fehler.json`. Gemeldet werden u.a.: Symbol mit `@` ausserhalb jedes Bereichs, Symbol in mehreren Bereichen einer Gruppe, ueberlappende Rechteck-Bereiche, Bereich ohne passende Symbole, `DIRECTION` passt nicht zur Geometrie, Symbol im Bereich, aber auf einem nicht genannten Layer (Warnung). Direktaufruf (z.B. fuer eine DXF ausserhalb von BricsCAD): ```bat python lib\create_numbers.py --filename Anlage_HW.dxf [--config cfg\enumerate.cfg] [--info info.json] [--errorfile fehler.json] [--dryrun | --overwrite] [--show_symbol_frames] ``` Ohne `--dryrun`/`--overwrite` entsteht `_numbered.dxf`. Die Nummer wird **oktal** gebildet (`oct(counter)`, so gewollt): das 8. Symbol einer Gruppe bekommt `...010`. ## Herkunft `create_numbers.py`, `cfg/enumerate.cfg` und der Test `tests/test_create_numbers.py` sind am 2026-11-03 aus dem Kabeltool-Repo `kabellaengen` hierher umgezogen (dort entfernt). Es gibt nur diesen einen Codestand: die benoetigten Helfer aus `kabellaengen/lib/utils.py` stehen direkt in `create_numbers.py`, die Fehlersammlung `error_collector.py` ist durch zwei einfache Listen ersetzt (gleiches Format der Fehlerdatei; gegen das Original an sechs Testzeichnungen verglichen: identische Nummern und Fehlerdateien). Bewusst doppelt bleibt nur die Konfiguration `cfg/io_regeln.json` (gekuerzt) - beide Repos werden von verschiedenen Abteilungen gepflegt. Die Testszenen `Nummerierung1/2`, `BGMG`, `POT` (Erzeugung per `kabellaengen/lib/create_example.py`) bleiben in kabellaengen; der Modus `--all-examples` ist darum hier entfallen.