Files
dxfmakros/doc/hw_planung.md
T
Michael StanglandClaude Opus 5.5 4100cbfb97 refactor: create_numbers ohne Kopie von error_collector
Fehler/Warnungen als zwei einfache Listen (neue_meldungen,
meldungen_als_dict) statt der aus kabellaengen kopierten
ErrorCollector-Klasse; lib/error_collector.py entfernt. Format der
Fehlerdatei unveraendert, an sechs Testzeichnungen gegen das Original
verglichen (identische Nummern und Fehlerdateien).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 17:00:42 +01:00

199 lines
11 KiB
Markdown

# 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 `<Zeichnung>_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 `<Zeichnung>_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 `<Praefix><io_vorlage>`, 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/<Zeichnung>_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: `<Name>_nummern.json` (alle Umbenennungen) und
- nur bei Problemen - `<Name>_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 `<Name>_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.