82ce795b53
Abbruch (ESC) im Linienzug-Baumodus loescht die bereits eingefuegte Geometrie nicht mehr, sondern wickelt sie wie ein fertiger Bau zu einem VF_n-Block und schreibt das volle Eingabe-Journal als XDATA drauf (vfl-modus-abbruch-sichern, ersetzt das bisherige Loesch-Rollback). Die Teil-Kette bleibt damit stehen und ist sofort per Doppelklick weiter editierbar/fortsetzbar - unabhaengig davon, ob der Abbruch beim frischen Bauen oder mitten in einem Editier-Neuaufbau passiert. Der bisherige Menuepunkt "Letzten Abbruch fortsetzen" (Session-Variable) entfaellt dadurch ersatzlos. vfl-edit-ent (Doppelklick-Editieren) fragt die Sektion, auf die zurueckgesetzt werden soll, jetzt per neuem DCL-Dialog ab (dcl/vfl_edit.dcl, vfl-dlg-position: Combobox 1..N + OK/Abbrechen) statt per Text-Prompt. Vorbelegung auf die letzte Sektion, damit Doppelklick + sofort OK einen abgebrochenen Bau nahtlos fortsetzt. Die *error*-Handler-Installation wandert vor den allerersten Prompt (vorher: nach Startpunkt/AS-Frage), damit ein ESC in diesem Fenster nicht mehr auf den ungeschuetzten vorherigen Handler faellt. Das Wickeln im Abbruch-Pfad ist per vl-catch-all-apply abgesichert, da vfl-block-erstellen intern einen BKS-Wechsel per (command "_.UCS" ...) macht. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
184 lines
14 KiB
Markdown
184 lines
14 KiB
Markdown
|
||
# dxfmakros - Projektanweisungen
|
||
|
||
## Projektbeschreibung
|
||
|
||
AutoLISP-Makros (SSG_LIB) fuer BricsCAD Pro zur automatisierten Erstellung von Foerderanlagen-Layouts (ILS Kreisel, Omniflo, Variofoerderer, Geruest). Ziel ist der Ersatz proprietaerer Tools (Bihler Omniflo, Bihler Geruest, Ruledesigner) durch eigene parametrische Makros.
|
||
|
||
## Technologie-Stack
|
||
|
||
- **CAD-System**: BricsCAD Pro (AutoCAD-kompatibel)
|
||
- **Hauptsprache**: AutoLISP (.lsp)
|
||
- **Hilfssprache**: Python (Export-Skripte in `lib/`)
|
||
- **Datenformate**: DXF/DWG (Bloecke), JSON (Komponentendaten), CSV (Export)
|
||
- **Dialoge**: DCL (Dialog Control Language, in `dcl/`)
|
||
- **Menu**: BricsCAD .mnu/.mnl Format (in `menu/`)
|
||
|
||
## Projektstruktur
|
||
|
||
| Verzeichnis | Inhalt |
|
||
|---|---|
|
||
| `Lisp/` | AutoLISP-Makros und Kernbibliotheken |
|
||
| `bin/` | Hilfs-Skripte (setenv.bat, start_briscad.bat) |
|
||
| `cfg/` | Konfigurationsdateien |
|
||
| `data/` | JSON-Daten, DXF-Quellen, Block-Libraries |
|
||
| `data/ils/` | DWG-Bloecke fuer ILS-Kreisel/Eckrad (AN8, SP8, AP-Typen) |
|
||
| `data/json/` | Komponentendaten (Masse, Sivas-IDs) |
|
||
| `data/block_libraries/` | DXF Block-Libraries (ils_library.dxf) |
|
||
| `dcl/` | DCL-Dialogdefinitionen |
|
||
| `doc/` | Dokumentation, Entwicklungsplan |
|
||
| `lib/` | Python-Skripte (DXF-Bearbeitung, Export) |
|
||
| `menu/` | BricsCAD-Menudefinition (SSG_LIB.mnu, SSG_LIB.mnl) |
|
||
| `tests/` | Testskripte und Referenzdaten |
|
||
|
||
## Lademechanismus (Lazy Loading via MNL)
|
||
|
||
Das Laden der LISP-Module erfolgt ueber das Menuesystem. Voraussetzung ist, dass das
|
||
Menue einmalig in BricsCAD geladen wurde (siehe unten: "Menue einrichten").
|
||
|
||
1. BricsCAD laedt beim Start automatisch `SSG_LIB.mnl` (gleichnamige MNL-Datei zum Menue)
|
||
2. Die MNL laedt alle Kern- und Feature-Module direkt per `ssg-ensure`
|
||
3. `ssg-ensure` ueberspringt bereits geladene Module (Flag `*ssg-<modul>-loaded*`)
|
||
|
||
### Menue einrichten (einmalig pro BricsCAD-Installation)
|
||
|
||
1. `bin/setenv.bat` ausfuehren (setzt `DXFM_LISP`, `DXFMAKRO` u.a.)
|
||
2. BricsCAD starten
|
||
3. In der BricsCAD-Kommandozeile: `_MENULOAD` eingeben
|
||
4. Im Dialog: `menu/SSG_LIB.mnu` auswaehlen und laden
|
||
5. BricsCAD laedt automatisch `SSG_LIB.mnl` mit – alle Module werden initialisiert
|
||
|
||
Alternativ per LISP-Kommandozeile in BricsCAD:
|
||
```lisp
|
||
(command "_.MENULOAD" (strcat (getenv "DXFMAKRO") "/menu/SSG_LIB.mnu"))
|
||
```
|
||
|
||
Das Menue bleibt dauerhaft registriert. Nach einem Update der `.mnu`-Datei
|
||
genuegt es, BricsCAD neu zu starten oder `_MENULOAD` erneut aufzurufen.
|
||
|
||
### Voraussetzung
|
||
|
||
Umgebungsvariable `DXFM_LISP` muss gesetzt sein (via `bin/setenv.bat`).
|
||
Die `start_briscad.bat` ruft `setenv.bat` auf und startet BricsCAD.
|
||
|
||
### Modulzuordnung im Menue
|
||
|
||
| Menue-Bereich | Modul | Befehle |
|
||
|---|---|---|
|
||
| Kreisel-Module | `KreiselInsert` | KreiselInsert, KreiselConnect, KreiselEdit, ILS_Eckrad |
|
||
| TRO | `Tro_Edit` | TRO_INSERT, TRO_EDIT |
|
||
| Zusatzmodul/Foerderer/Kurven | `SSG_LIB_Commands` | ILS_BTMT_*, ILS_ETF_*, ILS_K*_*, ILS_GK*_* |
|
||
| VarioFoerderer | `VarioFoerderer` | FOERDERANLAGE, VARIOFOERDERER_EDIT, Vario_Kette_Merge |
|
||
| Gefaellestrecke | `Gefaellestrecke` | GEFAELLESTRECKE, GEFAELLESTRECKE_EDIT |
|
||
| Omniflo (komplett) | `OmniModulInsert` | OMNI_APB_*, OMNI_W*_*, OMNI_AP*, OMNI_TEF_*, OMNI_TV_*, OMNI_EDIT |
|
||
| Export | `export` | EXPORTSIVAS, EXPORTCSV, CALLPYTHON |
|
||
| Konfiguration | `SSG_LIB_Commands` | SSG_DIM_SWITCH, SSG_SPRACHE |
|
||
| Doppelklick/Kontextmenue | `SSG_LIB_Commands` | SSG_BLOCKEDIT (dispatcht Kreisel->KreiselEdit, Omniflo->OMNI_EDIT, GF_*->GEFAELLESTRECKE_EDIT, VF_*->VARIOFOERDERER_EDIT) |
|
||
|
||
### Entfernte Legacy-Dateien
|
||
|
||
- `bin/startup.scr` - Entfernt (war fuer `/s` Parameter)
|
||
- `bin/acaddoc.lsp` - Entfernt (war fuer ACAD-Pfad-basiertes Laden)
|
||
- `bin/on_start.lsp` - Entfernt; Menue wird jetzt manuell per `_MENULOAD` eingerichtet
|
||
|
||
Detaillierte Dokumentation aller Funktionen und Befehle: siehe `Lisp/README.md`.
|
||
|
||
## AutoLISP-Module
|
||
|
||
| Datei | Befehle | Beschreibung |
|
||
|---|---|---|
|
||
| `ssg_core.lsp` | - | Kernel: ssg-start/ssg-end, ssg-cfg-or, ssg-attrib-read/write, Layer/Block-Ops |
|
||
| `ssg_lang.lsp` | - | Sprachumschaltung Deutsch/Englisch (ssg-text, ssg-textf, *ssg-lang*) |
|
||
| `ssg_dbg.lsp` | - | Debug-Logging (dbgopen, dbgmsg, dbgflush, dbgclose) |
|
||
| `ssg_dialog.lsp` | - | DCL-Dialog-Vorlagen und Hilfsfunktionen |
|
||
| `ssg_layer.lsp` | - | Layer-Verwaltung |
|
||
| `KreiselInsert.lsp` | KreiselInsert, KreiselConnect, KreiselRedraw, KreiselQuick, KreiselEdit, KreiselParams, KreiselLabelSetup, KreiselLabelPos, KreiselLabelHoehe, ILS_Eckrad | ILS Kreisel und Eckrad komplett in AutoLISP |
|
||
| `VarioFoerderer.lsp` (Wrapper fuer `vf_core.lsp`/`vf_standard.lsp`/`vf_etage.lsp`/`vf_linienzug.lsp`) | FOERDERANLAGE, VARIOFOERDERER_EDIT, VARIOFOERDERER_NACHRUESTEN, Vario_Kette_Merge | Vario-Foerderanlagen Generator (Typen Standard/Etage/Linienzug); Standard- UND Etage-Typ: Werteingabe per DCL-Dialog (`vfs-standard-dialog-ablauf` in vf_standard.lsp bzw. `vfe-etage-dialog-ablauf` in vf_etage.lsp, beide nutzen dieselben Dialoge `vfs-dialog-eingabe-basis`/`vfs-dialog-winkel-verteilung`); Doppelklick auf VF_n-Block ruft VARIOFOERDERER_EDIT, das per SSG_VF_EDIT-XDATA-Marker ("standard"/"etage"/"linienzug") in den passenden Neuaufbau-Zweig dispatcht (`vfe-edit-ent` fuer Etage, `vfl-edit-ent` fuer Linienzug); Altbestand-Bloecke ohne Marker werden abgewiesen. Linienzug (Modus 1, `vf-linienzug-modus`) zeichnet jede interaktive Eingabe in einem Journal auf (`vfl-in-point`/`-string`/`-real`/`-int`) und schreibt es als XDATA auf den fertigen `VF_n`-Block; ein Abbruch (ESC) loescht dadurch nichts mehr, sondern wickelt die bis dahin gebaute Teil-Geometrie ebenso zu einem Block (`vfl-modus-abbruch-sichern`) - sie bleibt stehen und ist sofort per Doppelklick weiter editierbar/fortsetzbar. `vfl-edit-ent` liest das Journal, zeigt die Sektionen ueber einen DCL-Dialog (`vfl-dlg-position`, `dcl/vfl_edit.dcl`) an, kuerzt bei Bedarf auf eine gewaehlte Sektion (stummer Replay der behaltenen Eingaben) und baut danach interaktiv weiter; `Vario_Kette_Merge` (in vf_linienzug.lsp) fuehrt mehrere einzeln gebaute VF_n-Bloecke ab einem gewaehlten Start-Baustein ueber die reale KS_AUS->KS_EIN-Nachbarschaft zu einem Gesamt-Block zusammen (aggregierte Attribute, Luecken-Erkennung) |
|
||
| `Gefaellestrecke.lsp` | GEFAELLESTRECKE, GEFAELLESTRECKE_EDIT | Gefaelle-Foerderanlage (AUS -> Staustrecke skaliert -> Separator -> EIN); Modus 1 per DCL-Dialog (Einfuegehoehe, Element-Winkel 30/90); Doppelklick auf GF_n-Block ruft GEFAELLESTRECKE_EDIT (Dialog vorbelegt, Neuaufbau) |
|
||
| `export.lsp` | EXPORTSIVAS, EXPORTCSV, OMNI_UPDATE_ATTRIBS | JSON-Sammlung und Python-Export (Omniflo-Merkmale/Sum-Zeile via lib/export_csv.py) |
|
||
| `OmniModulInsert.lsp` | OMNI_LOAD, OMNI_APB_*, OMNI_W*_*, OMNI_AP60/AP110, OMNI_TEF_*, OMNI_TV_*, OMNI_APBW_*, OMNI_EDIT | Omniflo-Komponenten: Boegen, Weichen, Verbinder, Transferwagen, Edit-Dialog |
|
||
| `SSG_LIB_Commands.lsp` | ILS_BTMT_Beladung, ILS_BTMT_Entladung, ILS_SCANNER_INSERT, ILS_SEPARATOR_INSERT, ILS_ETF_*, ILS_K*_*, ILS_GK*_*, SSG_BLOCKEDIT, SSG_DIM_SWITCH, SSG_SPRACHE | BTMT Be-/Entladung (`ils-insert-station`: wiederholtes Einfuegen von `BTMT-Beladung` bzw. `SC_Entladung`, Drehung interaktiv, Layer aus `LAYER`-Attribut, Dimension via `ssg-ils-block-laden`) + Sensoren (`ils-insert-sensor`) + Dummy-Befehle fuer Menue + Doppelklick/Kontextmenue-Dispatcher + Konfiguration (2D/3D, Sprache) |
|
||
| `Tro_Edit.lsp` | TRO_INSERT, TRO_EDIT | TRO-Marker (Block `TRO_SYM_<Typ>`) fuer sps_skel (lib/tro_annotate.py): TRO_INSERT fuegt eine bestehende Blockdefinition an einem gewaehlten Punkt ein und setzt ID/TYPE (bricht ab, wenn der Typ noch keine Blockdefinition in der Zeichnung hat - die entsteht nur ueber tro_annotate.py); TRO_EDIT aendert ID/TYPE eines bestehenden Markers per Dialog. Typliste aus `tro_types.lsp` (von `tro_annotate.py --emit-lisp` nach DXFM_LISP geschrieben). Der Dispatcher SSG_BLOCKEDIT leitet Blocknamen `TRO_*` zu TRO_EDIT. |
|
||
| `menu-inventory.lsp` | MenuInventory | BricsCAD Diagnostik (Menuegruppen, Plugins, Startdateien) |
|
||
|
||
## DCL-Dialoge
|
||
|
||
| Datei | Verwendet von |
|
||
|---|---|
|
||
| `kreisel_edit.dcl` | KreiselEdit (KreiselInsert.lsp) |
|
||
| `gefaellestrecke.dcl` | GEFAELLESTRECKE Modus 1 (Gefaellestrecke.lsp, `gf-dialog-eingabe`) |
|
||
| `variofoerderer.dcl` | FOERDERANLAGE Standardfall + Werteingabe (vf_standard.lsp, `vfs-dialog-eingabe-basis`/`vfs-dialog-winkel-verteilung`) |
|
||
| `omniflo_boegen.dcl` | OMNI_APB_* (OmniModulInsert.lsp) |
|
||
| `omniflo_weichen.dcl` | OMNI_W*_* (OmniModulInsert.lsp) |
|
||
| `sprache.dcl` | SSG_SPRACHE (SSG_LIB_Commands.lsp) |
|
||
| `tro_insert.dcl` | TRO_INSERT (Tro_Edit.lsp) |
|
||
| `tro_edit.dcl` | TRO_EDIT (Tro_Edit.lsp) |
|
||
| `vfl_edit.dcl` | Linienzug-Editieren/Fortsetzen (vf_linienzug.lsp, `vfl-dlg-position`, aufgerufen aus `vfl-edit-ent`) |
|
||
|
||
## Menue (SSG_LIB.mnu + SSG_LIB.mnl)
|
||
|
||
- `SSG_LIB.mnu` - Menuedefinition mit Lazy-Loading (`(ssg-ensure "Modul") Befehl`)
|
||
- `SSG_LIB.mnl` - Automatisch geladen mit dem Menue, definiert `ssg-ensure` Loader
|
||
- `***MENUGROUP=SSG_LIB` - Menuegruppenname
|
||
- `***POP1` - Hauptmenue (ILS, Omniflo, Export, Konfiguration)
|
||
- `***DOUBLECLICK` - Doppelklick auf INSERT-Bloecke ruft SSG_BLOCKEDIT auf
|
||
- `***POP501` - Rechtsklick-Kontextmenue (KreiselEdit, OMNI_EDIT, SSG_BLOCKEDIT)
|
||
|
||
## Umgebungsvariablen
|
||
|
||
Werden via `bin/setenv.bat` gesetzt. Wichtigste:
|
||
- `DXFMAKRO` - Projektwurzel
|
||
- `DXFM_LISP` - Pfad zu Lisp-Dateien (benoetigt fuer ssg-ensure Lazy-Loader)
|
||
- `DXFM_BLOCKS` - Pfad zu DWG-Bloecken
|
||
- `DXFM_DATA` - Datenverzeichnis (JSON, DXF)
|
||
- `DXFM_LOG` - Log-Verzeichnis
|
||
- `DXFM_DCL` - Pfad zu DCL-Dialogdateien
|
||
- `DXFM_CFG` - Konfigurationsverzeichnis
|
||
- `DXFM_LANG` - Aktive Sprache (`de_DE`/`en_GB`), persistiert von `SSG_SPRACHE`; Default `de_DE`
|
||
|
||
## Konventionen
|
||
|
||
- AutoLISP-Funktionsnamen: `ssg-*` fuer Kernfunktionen, `C:BEFEHLSNAME` fuer User-Commands
|
||
- Alle Texte in Dateien ohne Umlaute (ae, oe, ue statt ae, oe, ue)
|
||
- Bloecke werden als DWG **flach** in `data/ils/` abgelegt (Block-Libraries als DXF in `data/block_libraries/`). Die Dimension steckt seit dem Flach-Refactor im **Dateinamen bzw. Blocknamen** als Suffix `_2D`/`_3D` (z.B. `AN8_2D.dwg`, `Vario_Bogen_auf_3_TEF_rechts_3D.dwg`), damit 2D- und 3D-Variante gleichzeitig in einer Zeichnung stehen koennen. Zentrale Aufloesung: `ssg-ils-blockname[-dim]` / `ssg-ils-block-datei[-dim]` / `ssg-ils-block-laden[-dim]` in `ssg_core.lsp`. Ausnahmen ohne Suffix: `KS_EIN`/`KS_AUS`/`K1`-`K4` und die Wrapper-Bloecke `VF_*`/`GF_*`/`KREISEL_*`/`ECKRAD_*`. Alle Feature-Module (Kreisel, VarioFoerderer, Gefaellestrecke) folgen der aktuellen Dimension (`ssg-ils-dim-aktuell`: transienter Override `*ssg-ils-dim*` -> `DXFM_DIM`) mit automatischem 3D-Fallback, sodass 2D- und 3D-Aufbau funktionieren. (Die alten Unterordner `data/ils/2D` und `data/ils/3D` bleiben uebergangsweise als Quelle der Batch-/Attribut-Tools bestehen.)
|
||
- Komponentendaten (Masse, Sivas-IDs) liegen als JSON in `data/json/`
|
||
- Sprache im Code und Kommentaren: Deutsch
|
||
|
||
## Python-Bibliotheken
|
||
|
||
### Standalone-Skripte (`lib/`) - laufen extern mit ezdxf
|
||
|
||
Abhaengigkeiten: `ezdxf`, Standard-Library. Benoetigen Umgebungsvariablen (`DXFM_DATA`, `DXFM_RESULTS`, `DXFM_CFG`).
|
||
|
||
| Skript | Beschreibung |
|
||
|---|---|
|
||
| `omniflo_utils.py` | Gemeinsame Hilfsfunktionen fuer Omniflo-Skripte: `ROW_GROUPS` (Reihen-Gruppierung), `SWITCH_FILTERS` (Schalter-Filter), `build_row_layout`, `import_element_as_block`, `draw_cross`, `load_omniflo_data` |
|
||
| `set_einfuegepkt.py` | Setzt `$INSBASE` (Einfuegepunkt) in Omniflo-DXF-Dateien. Schalter je Typ: `--boegen`, `--weichen45`, `--weichen90`, `--weichenkoerper`, `--weichen-parallel`, `--delta`, `--dreifachweiche`, `--sternweiche`, `--show-omniflo` |
|
||
| `set_koords.py` | Setzt Koordinatensystem-Bloecke (K1-K4) in Omniflo-DXF-Dateien. Schalter: `--k1set` bis `--k4set`, `--set-all`, `--force`, `--show-omniflo`, `--test`, `--number` |
|
||
| `export_sivas.py` | Erzeugt Sivas-Export-CSV mit Summierungszeilen (ILS Automation, Omniflo Sum). Aufruf: `python export_sivas.py <export_raw.json> <data_dir> <output.csv>` |
|
||
| `export_csv.py` | Erzeugt einfache Item-Liste als CSV (ohne Summierung). Aufruf: `python export_csv.py <export_raw.json> <data_dir> <output.csv>` |
|
||
| `split_block_library.py` | Teilt `ils_library.dxf` in einzelne DXF-Dateien pro Block auf (mit Abhaengigkeiten). Export-Prefixe: Vario_, Staustrecke_, _3D_AS_, _3D_ES_ |
|
||
| `dxf_scan_components.py` | Erkennt ILS-/Omniflo-Komponenten in einer **fremden** Projektzeichnung (ohne unsere Wrapper-Bloecke) und schreibt sie im JSON-Schema aus `tests/testdata/object_data.md` — Grundlage fuer Nachbau-Testfaelle wie `tests/testdata/hundm05.json`. Liest binaere DXF im GB-Bereich streamend per mmap (ezdxf-DOM waere zu gross), loest INSERTs inkl. OCS/Extrusionsrichtung rekursiv in Weltkoordinaten auf, paart AN8/SP8 zu Kreiseln und Antrieb/Umlenkung zu Foerderern. Aufruf: `python dxf_scan_components.py <dxf> <data_dir> <output.json> [--fenster X0 Y0 X1 Y1]` — ohne `--fenster` liefert eine Anlagenzeichnung leicht ueber 1300 Eintraege, zuviel fuer einen Testlauf |
|
||
|
||
### Entwickler-Tools (`lib/`) - kein ezdxf, reine Text-/AutoLISP-Verarbeitung
|
||
|
||
| Skript | Beschreibung |
|
||
|---|---|
|
||
| `dbg2lsp.py` | Instrumentiert AutoLISP-Funktionen automatisch mit `ssg_dbg.lsp` (`dbgf`/`dbg`/`dbgreturn`/`dbgopen`/`dbgclose`). Schalter: `--method` (Funktion instrumentieren), `--recursive` (Aufrufgraph mitverfolgen), `--add-open DATEI METHODE` (Debug-Datei oeffnen/schliessen), `--dry-run`. Details: `doc/dbg2lsp.md` |
|
||
|
||
### Typische Verarbeitungskette (Omniflo-DXF)
|
||
|
||
1. `set_einfuegepkt.py` - Einfuegepunkte berechnen und setzen
|
||
2. `set_koords.py` - Koordinatensysteme (K1-K4) setzen
|
||
3. `export_sivas.py` / `export_csv.py` - Export aus Zeichnung
|
||
|
||
## Entwicklungsstand
|
||
|
||
Siehe `doc/Entwicklungsplan.md` fuer Meilensteinplanung und Aufwandsschaetzung.
|
||
Fertig (DONE): ILS Kreisel, ILS Eckrad, ILS Variofoerderer, ILS BTMT Be-/Entladung (Einfuegen), Omniflo Boegen, Omniflo Weichen.
|
||
|
||
## Debug
|
||
Wenn Werte für das Debug in der Bricscad Konsole ausgegeben werden z.B. mit princ, soll der Benutzer dazu ermuntert werden, statt dessen die Lisp dbg Routinen zu verwenden, welche dann eine .dbg file im log folder erzeugen. Diese können ja über eine zentrale globale Sammlung von Schalter an und abgeschaltet werden, so dass die Files per default auch nicht geschrieben werden, nur wenn der passende Schalter auf 1 gesetzt wird. Damit können debug aufrufe auch im Code verbleiben.
|
||
Biete diese Architektur jeden an, der viele Werte ins Bricscad Fenster raus schreibt.
|
||
|