diff --git a/CLAUDE.md b/CLAUDE.md index c5c2f79..fc3b69c 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -12,14 +12,14 @@ AutoLISP-Makros (SSG_LIB) fuer BricsCAD Pro zur automatisierten Erstellung von F - **Hilfssprache**: Python (Export-Skripte in `lib/`) - **Datenformate**: DXF/DWG (Bloecke), JSON (Komponentendaten), CSV (Export) - **Dialoge**: DCL (Dialog Control Language, in `dcl/`) -- **Menu**: BricsCAD .mnu Format (in `menu/`) +- **Menu**: BricsCAD .mnu/.mnl Format (in `menu/`) ## Projektstruktur | Verzeichnis | Inhalt | |---|---| | `Lisp/` | AutoLISP-Makros und Kernbibliotheken | -| `bin/` | Hilfs-Skripte (setenv, on_start.lsp, startup.scr) | +| `bin/` | Hilfs-Skripte (setenv.bat, start_briscad.bat, on_start.lsp) | | `cfg/` | Konfigurationsdateien | | `data/` | JSON-Daten, DXF-Quellen, Block-Libraries | | `data/ils/` | DWG-Bloecke fuer ILS-Kreisel/Eckrad (AN8, SP8, AP-Typen) | @@ -28,27 +28,44 @@ AutoLISP-Makros (SSG_LIB) fuer BricsCAD Pro zur automatisierten Erstellung von F | `dcl/` | DCL-Dialogdefinitionen | | `doc/` | Dokumentation, Entwicklungsplan | | `lib/` | Python-Skripte (DXF-Bearbeitung, Export) | -| `menu/` | BricsCAD-Menudefinition (SSG_LIB.mnu) | +| `menu/` | BricsCAD-Menudefinition (SSG_LIB.mnu, SSG_LIB.mnl) | | `tests/` | Testskripte und Referenzdaten | -## Ladereihenfolge (wichtig) +## Lademechanismus (Lazy Loading via MNL) -`on_start.lsp` -> `ssg_load.lsp` -> Bibliotheken in Reihenfolge: +Das Laden der LISP-Module erfolgt **nicht** ueber Startup-Skripte, sondern ueber das Menuesystem: -1. `ssg_core.lsp` (Kernel: Umgebung, Layer, Block-Ops, Attribute, Fehlerbehandlung, Config) -2. `ssg_dbg.lsp` (Debug-Logging fuer alle nachfolgenden Module) -3. `ssg_dialog.lsp` (DCL-Dialog-Vorlagen) -4. `ssg_layer.lsp` (Layer-Verwaltung) -5. `KreiselInsert.lsp` (ILS Kreisel/Eckrad: Insert, Connect, Redraw, Edit, Labels) -6. `VarioFoerderer.lsp` (Vario-Foerderanlagen) -7. `Gefaellestrecke.lsp` (Gefaelle-Foerderanlage mit festem Neigungswinkel) -8. `export.lsp` (JSON-Export, EXPORTSIVAS, EXPORTCSV, OMNI_EXPORT, OMNI_UPDATE_ATTRIBS) -9. `tests.lsp` (Python-Integration, Export) -10. `OmniModulInsert.lsp` (Omniflo-Komponenten: Boegen, Weichen, Verbinder, OMNI_EDIT) -11. `SSG_LIB_Commands.lsp` (Dummy-Befehle fuer Menue, SSG_BLOCKEDIT Dispatcher) +1. Die Menuedatei `SSG_LIB.mnu` wird beim BricsCAD-Start als CUI geladen (einmalig via `_MENULOAD`) +2. BricsCAD laedt automatisch `SSG_LIB.mnl` (gleichnamige MNL-Datei) mit dem Menue +3. Die MNL definiert `ssg-ensure` (Lazy-Loader) und setzt `DBLCLKEDIT=0` +4. Beim ersten Menueklick laedt `ssg-ensure` automatisch die benoetigten Module: + - Zuerst die **Kern-Module**: `ssg_core` → `ssg_dbg` → `ssg_dialog` → `ssg_layer` + - Dann das angeforderte **Feature-Modul** (z.B. `KreiselInsert`, `OmniModulInsert`) +5. Bereits geladene Module werden uebersprungen (Flag-Variable `*ssg--loaded*`) -Nicht automatisch geladen (manuell/standalone): -- `menu-inventory.lsp` (BricsCAD Diagnostik: Menuegruppen, Plugins, LISP-Apps. Befehl: MenuInventory) +### Voraussetzung + +Umgebungsvariable `DXFM_LISP` muss gesetzt sein (via `bin/setenv.bat`). +Die `start_briscad.bat` ruft `setenv.bat` auf und startet BricsCAD ohne `/s` oder `/p`. + +### Modulzuordnung im Menue + +| Menue-Bereich | Modul | Befehle | +|---|---|---| +| Kreisel-Module | `KreiselInsert` | KreiselInsert, KreiselConnect, KreiselEdit, ILS_Eckrad | +| Zusatzmodul/Foerderer/Kurven | `SSG_LIB_Commands` | ILS_BTMT_*, ILS_ETF_*, ILS_K*_*, ILS_GK*_* | +| VarioFoerderer | `VarioFoerderer` | FOERDERANLAGE | +| Gefaellestrecke | `Gefaellestrecke` | GEFAELLESTRECKE | +| Omniflo (komplett) | `OmniModulInsert` | OMNI_APB_*, OMNI_W*_*, OMNI_AP*, OMNI_TEF_*, OMNI_TV_*, OMNI_EDIT | +| Export | `export` | EXPORTSIVAS, EXPORTCSV, CALLPYTHON | +| Doppelklick/Kontextmenue | `SSG_LIB_Commands` | SSG_BLOCKEDIT | + +### Legacy-Dateien (nicht mehr verwendet) + +- `bin/startup.scr` - Entfernt (war fuer `/s` Parameter) +- `bin/acaddoc.lsp` - Entfernt (war fuer ACAD-Pfad-basiertes Laden) +- `bin/on_start.lsp` - Nicht mehr fuer Lazy-Loading noetig, kann fuer manuelles Laden aller Module verwendet werden +- `Lisp/ssg_load.lsp` - Laedt alle Module auf einmal (Alternative zum Lazy-Loading) Detaillierte Dokumentation aller Funktionen und Befehle: siehe `Lisp/README.md`. @@ -57,11 +74,12 @@ Detaillierte Dokumentation aller Funktionen und Befehle: siehe `Lisp/README.md`. | Datei | Befehle | Beschreibung | |---|---|---| | `ssg_core.lsp` | - | Kernel: ssg-start/ssg-end, ssg-cfg-or, ssg-attrib-read/write, Layer/Block-Ops | +| `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` | FOERDERANLAGE | Vario-Foerderanlagen Generator | -| `Gefaellestrecke.lsp` | GEFAELLESTRECKE | Gefaelle-Foerderanlage (AUS → Staustrecke skaliert → Separator → EIN) | +| `Gefaellestrecke.lsp` | GEFAELLESTRECKE | Gefaelle-Foerderanlage (AUS -> Staustrecke skaliert -> Separator -> EIN) | | `export.lsp` | EXPORTSIVAS, EXPORTCSV, OMNI_EXPORT, OMNI_UPDATE_ATTRIBS | JSON-Sammlung und Export (Python-Aufruf oder LISP-nativ) | | `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_*, ILS_ETF_*, ILS_K*_*, ILS_GK*_*, SSG_BLOCKEDIT | Dummy-Befehle fuer Menue + Doppelklick/Kontextmenue-Dispatcher | @@ -75,10 +93,12 @@ Detaillierte Dokumentation aller Funktionen und Befehle: siehe `Lisp/README.md`. | `omniflo_boegen.dcl` | OMNI_APB_* (OmniModulInsert.lsp) | | `omniflo_weichen.dcl` | OMNI_W*_* (OmniModulInsert.lsp) | -## Menue (SSG_LIB.mnu) +## 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` bis `***POP4` - Hauptmenues (ILS, Omniflo, Geruest, Export) +- `***POP1` - Hauptmenue (ILS, Omniflo, Export) - `***DOUBLECLICK` - Doppelklick auf INSERT-Bloecke ruft SSG_BLOCKEDIT auf - `***POP501` - Rechtsklick-Kontextmenue (KreiselEdit, OMNI_EDIT, SSG_BLOCKEDIT) @@ -86,10 +106,12 @@ Detaillierte Dokumentation aller Funktionen und Befehle: siehe `Lisp/README.md`. Werden via `bin/setenv.bat` gesetzt. Wichtigste: - `DXFMAKRO` - Projektwurzel -- `DXFM_LISP` - Pfad zu Lisp-Dateien +- `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 ## Konventionen diff --git a/Lisp/KreiselInsert.lsp b/Lisp/KreiselInsert.lsp index f8fc29b..6d9d958 100644 --- a/Lisp/KreiselInsert.lsp +++ b/Lisp/KreiselInsert.lsp @@ -47,7 +47,8 @@ ("DREHUNG" "0") ("ABSTAND" "2300") ("NUMMER" "0") - ("HOEHE" "0")) + ("HOEHE" "0") + ("ID" "")) ) ;; Eckrad-Einstellungen @@ -59,7 +60,8 @@ ("DREHRICHTUNG" "UZS") ("DREHUNG" "0") ("NUMMER" "0") - ("HOEHE" "0")) + ("HOEHE" "0") + ("ID" "")) ) ;; Letzter gewaehlter Typ (gespeichert zwischen Aufrufen) @@ -455,7 +457,11 @@ (setq att-entity (entnext att-entity)) ) (entupd block-ent) - (princ (strcat "\n-> Kreisel #" (itoa kreisel-nummer) " eingefügt: " bname + ;; Eindeutige ID zuweisen + (if (atoms-family 1 '("ssg-id-generate")) + (ssg-id-generate block-ent) + ) + (princ (strcat "\n-> Kreisel #" (itoa kreisel-nummer) " eingefügt: " bname " (Höhe=" block-hoehe ")")) (entlast) ) diff --git a/Lisp/OmniModulInsert.lsp b/Lisp/OmniModulInsert.lsp index 1a08763..d4b9f5f 100644 --- a/Lisp/OmniModulInsert.lsp +++ b/Lisp/OmniModulInsert.lsp @@ -596,6 +596,10 @@ ;; 0. Attribute aus der Quell-.dwg lesen (vor ssg-start, da eigene INSERT/ERASE) (setq srcAttribs (ssg-attrib-read-dwg (strcat *block-path* blockname ".dwg"))) + ;; ID-Attribut hinzufuegen falls noch nicht vorhanden + (if (and srcAttribs (not (assoc "ID" srcAttribs))) + (setq srcAttribs (append srcAttribs (list (cons "ID" "")))) + ) (if (null srcAttribs) (progn (princ "\n[OMNI] Keine Attribute im Quell-Block gefunden.") nil) (progn @@ -711,6 +715,11 @@ (entmod ed) (entupd textEnt) + ;; Eindeutige ID zuweisen + (if (and blockEnt (atoms-family 1 '("ssg-id-generate"))) + (ssg-id-generate blockEnt) + ) + (princ (strcat "\n[OMNI] " bname " eingefuegt. Laenge=" laengeStr " mm")) (setq ok T) ) @@ -947,7 +956,7 @@ ;; hoehe = Hoehe in mm als String (wird als HOEHE-Attribut gesetzt) ;; drehung = Drehwinkel in Grad als String (Block-Rotation) ;; Rueckgabe: Einfuegepunkt oder nil bei Abbruch -(defun omni:insert-dxf (sivasnr-str hoehe drehung / dxf-pfad data-pfad pt angleDeg blockEnt) +(defun omni:insert-dxf (sivasnr-str hoehe drehung / dxf-pfad data-pfad pt angleDeg blockEnt attribs layer-name) (setq data-pfad (getenv "DXFM_DATA")) (if (null data-pfad) (progn @@ -980,16 +989,35 @@ (setq blockEnt (entlast)) - ;; HOEHE und DREHUNG Attribute setzen (if (and blockEnt (= (cdr (assoc 0 (entget blockEnt))) "INSERT")) - (ssg-attrib-set-on blockEnt - (list (cons "HOEHE" (if hoehe hoehe (ssg-cfg-or "omniflo" "default_hoehe" "2000"))) - (cons "DREHUNG" (if drehung drehung (ssg-cfg-or "omniflo" "default_drehung" "0"))))) + (progn + ;; HOEHE und DREHUNG Attribute setzen + (ssg-attrib-set-on blockEnt + (list (cons "HOEHE" (if hoehe hoehe (ssg-cfg-or "omniflo" "default_hoehe" "2000"))) + (cons "DREHUNG" (if drehung drehung (ssg-cfg-or "omniflo" "default_drehung" "0"))))) + + ;; Layer aus LAYER-Attribut lesen und Block verschieben + (setq attribs (ssg-attrib-read blockEnt)) + (setq layer-name (cdr (assoc "LAYER" attribs))) + (if (and layer-name (> (strlen layer-name) 0)) + (progn + (ssg-make-layer layer-name 7 nil) + (entmod (subst (cons 8 layer-name) (assoc 8 (entget blockEnt)) (entget blockEnt))) + (entupd blockEnt) + ) + ) + ) + ) + + ;; Eindeutige ID zuweisen + (if (and blockEnt (atoms-family 1 '("ssg-id-generate"))) + (ssg-id-generate blockEnt) ) (princ (strcat "\n[OMNI] " sivasnr-str " eingefuegt." " Hoehe=" (if hoehe hoehe (ssg-cfg-or "omniflo" "default_hoehe" "2000")) - " Drehung=" (if drehung drehung (ssg-cfg-or "omniflo" "default_drehung" "0")))) + " Drehung=" (if drehung drehung (ssg-cfg-or "omniflo" "default_drehung" "0")) + (if layer-name (strcat " Layer=" layer-name) ""))) (ssg-end) pt ) diff --git a/Lisp/export.lsp b/Lisp/export.lsp index c5bc849..d6b8f36 100644 --- a/Lisp/export.lsp +++ b/Lisp/export.lsp @@ -140,6 +140,13 @@ ;; csv-name = Ergebnis-CSV-Name (z.B. "export.csv") (defun csv:run-export (label py-name csv-name / ss i ename fh out-pfad py-skript ergebnis-pfad cmd first-block count) + ;; Vor dem Export: Doppelte IDs pruefen und korrigieren + (if (atoms-family 1 '("ssg-id-check-all")) + (progn + (princ (strcat "\n[" label "] Pruefe IDs auf Duplikate...")) + (ssg-id-check-all) + ) + ) ;; Vor dem Export HOEHE/DREHUNG aller Omniflo-Elemente aktualisieren (princ (strcat "\n[" label "] Aktualisiere Hoehe/Drehung...")) (omni:update-all-attribs)