[ADD] Gerüstoptionen werden nun mit dem Befehl GERUEST in Bricscad aufgerufen; Über ein Dropdown in den Oberflächen kann zwischen verschiedenen Arten (Säulen, Abhänger,...) umgeschaltet werden, dann erscheint ein neues Menü; Zusammenstellung der Anbauteile über die Oberfläche mit Anzahl und Checkbox; Speichern von konfigurierten Zusammenstellungen noch fehlerhaft

This commit is contained in:
Simon Hensch
2026-09-16 09:54:13 +02:00
parent 6d569072ec
commit 5193f4018c
12 changed files with 1239 additions and 276 deletions
+4
View File
@@ -190,6 +190,10 @@ data/block_libraries/ils_library.dxf
# Tool-Caches
.skylos/
# Eigene Geruest-Konfigurationen (vom Dialog GERUEST_* geschrieben).
# Benutzerdaten - die gepflegte Bibliothek steht in data/json/geruest.json.
cfg/geruest_user.json
# Grosse Test-Zeichnungen (Arbeitsstaende, gehoeren nicht ins Repo)
/tests/test.dwg
/tests/test.dxf
+2 -3
View File
@@ -75,7 +75,7 @@ Die `start_briscad.bat` ruft `setenv.bat` auf und startet BricsCAD.
| 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 |
| Geruest | `GeruestInsert` | GERUEST_ROHRABHAENGER, GERUEST_SAEULE_2ZOLL, GERUEST_SAEULE_1ZOLL, GERUEST_WANDBEFESTIGUNG |
| Geruest | `GeruestInsert` | GERUEST (ein Dialog fuer alle Bereiche) |
| Connections | `Connection_Edit` + `SSG_LIB_Commands` | CONNECTION_INSERT, CONNECTION_EDIT, ILS_EINGANG_INSERT, ILS_AUSGANG_INSERT |
| Export | `export` | EXPORTSIVAS, EXPORTCSV, CALLPYTHON |
| Konfiguration | `SSG_LIB_Commands` + `DrawPlanquadrate` | SSG_DIM_SWITCH, SSG_SPRACHE, PLANQUADRATE_TOGGLE (DRAW_PLANQUADRATE/DELETE_PLANQUADRATE) |
@@ -107,7 +107,7 @@ Detaillierte Dokumentation aller Funktionen und Befehle: siehe `Lisp/README.md`.
| `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_EINGANG_INSERT, ILS_AUSGANG_INSERT, ILS_ETF_*, 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`) + Eingang-/Ausgang-Symbol (frei platzierbar wie BTMT Be-/Entladung, ueber `ils-insert-station` mit den Rohnamen `Eingang`/`Ausgang`, Bloecke `Eingang_<DIM>.dwg`/`Ausgang_<DIM>.dwg` in data/ils) + 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. |
| `GeruestInsert.lsp` | GERUEST_ROHRABHAENGER, GERUEST_SAEULE_2ZOLL, GERUEST_SAEULE_1ZOLL, GERUEST_WANDBEFESTIGUNG | Geruest-Baugruppen aus `data/json/geruest.json` konfigurieren und einfuegen. Dialog (`dcl/geruest.dcl`): Basis-Variante aus `geometrie_varianten` (Dropdown), Anbauteile aus `anbaugruppen` (`list_box` mit `multiple_select` - im Projekt der erste), Laenge (gegen `attribute.Laenge` min/max geprueft, Retry-Schleife) und Farbe (`attribute.Farbe`, Freitext bei `frei_option`). Baugruppen ohne `attribute`-Block (Wandbefestigung) bekommen Laenge/Farbe gesperrt. Der Block wird - wie KREISEL_n/VF_n - SELBST zusammengebaut: Dummy-DWG aus `data/geruest` liefert nur Geometrie, das Attribut-Schema kommt aus `*geruest-attrib-defs*` (ARTINR, LAENGE, BEZEICHNUNG, TEILEART, FARBE, LAYER) und wird per `ssg-attrib-merge` mit den Dummy-Tags zusammengefuehrt - sonst verschluckt `ssg-attrib-set-on` stillschweigend jeden Tag, den die Dummy-DWG nicht als ATTDEF kennt. Blockname `GR_<id>_<ssg-timestamp>` (Kollisionszaehler wie in OmniModulInsert). **Das `GR_`-Praefix ist nicht kosmetisch**: `SSG_BLOCKEDIT` haelt JEDEN Block mit TEILEART-Attribut fuer ein Omniflo-Element, deshalb steht in `SSG_LIB_Commands.lsp` ein `GR_*`-Zweig VOR dem Omniflo-Zweig. ARTINR listet jede Sivas-ID so oft, wie `menge` es vorgibt (benannte Gruppen mit `teile` werden rekursiv aufgeloest); BEZEICHNUNG verkettet mit `" + "`, NICHT mit Komma - die Artikelbezeichnungen enthalten selbst Kommas ("ROHR R 1\" 33,7 x 2,6"). Zuordnung Menue -> JSON laeuft ueber das ASCII-Feld `id`, weil die aeusseren JSON-Schluessel Umlaute bzw. Anfuehrungszeichen tragen. CSV-/Sivas-Export: `pattern_geruest = GR_*` (cfg/export.cfg), `csv:collect-export-blocks`/`ssg-id-collect-blocks` sammeln GR_-Bloecke wie BTMT eigenstaendig; `*geruest-attrib-defs*` traegt zusaetzlich ein leeres `ID`-ATTDEF (Voraussetzung fuer `ssg-id-check-all`, das nur bestehende ATTRIBs beschreiben kann). ARTINR/BEZEICHNUNG/TEILEART/LAENGE landen in export_csv.py/export_sivas.py in festen Spalten, FARBE/LAYER (+ ARTINR bei export_csv.py) im Merkmale-/details-JSON. Noch NICHT enthalten: Edit-Pfad (GERUEST_EDIT) |
| `GeruestInsert.lsp` | GERUEST | Geruest-Baugruppen aus `data/json/geruest.json` konfigurieren und einfuegen. **Ein Dialog fuer alle Bereiche**: oben ein Dropdown `bereich` (Rohrabhaenger / Saeulen / Wandbefestigung, Reihenfolge = Dateireihenfolge, Anzeigename aus dem ASCII-Feld `titel`). DCL hat **kein Reiter-Tile**, und da sich die Teilezeilen je Bereich unterscheiden, schliesst ein Bereichswechsel den Dialog (`done_dialog 4`) und die Schleife in `c:GERUEST` baut ihn neu auf; der Stand jedes Bereichs bleibt in `*geruest-zustand*` erhalten, ein versehentlicher Wechsel verwirft also nichts. 1"- und 2"-Saeulen liegen in EINER Baugruppe `Saeulen` mit gemeinsamer Anbauteil-Liste; **`teileart` und `dummy` duerfen je Geometrie-Variante ueberschrieben werden** (`geruest-variante-wert`, Variante gewinnt vor Baugruppe) - so liefert `R 1"` weiterhin TEILEART `Geruest Saeule 1 Zoll` und die `R 2"`-Varianten `Geruest Saeule 2 Zoll`, die Groessen bleiben im Export also unterscheidbar. **Die Dialogdefinition wird zur Laufzeit erzeugt** (`geruest-dcl-schreiben` -> temporaere Datei per `vl-filename-mktemp`, nach `unload_dialog` wieder geloescht) - es gibt KEINE `dcl/geruest.dcl`. Grund: je Anbauteil wird ein eigenes Mengenfeld gebraucht, und eine DCL-Liste (`list_box`) kann keine Eingabefelder enthalten; DCL kann weder Dateien einbinden noch Tiles zur Laufzeit erzeugen. Inhalt: Basis-Variante aus `geometrie_varianten` (Dropdown), Laenge (gegen `attribute.Laenge` min/max geprueft, Retry-Schleife), Farbe (`attribute.Teilefarbe`, Freitext bei `frei_option`) und **zwei Befestigungslisten** ("oben"/"unten"), die BEIDE alle `anbaugruppen` enthalten - dasselbe Teil kann oben, unten oder gleichzeitig an beiden Positionen sitzen, je mit eigener Stueckzahl (vorbelegt aus `menge`). Baugruppen ohne `attribute`-Block (Wandbefestigung) bekommen Laenge/Farbe gesperrt, Baugruppen ohne Anbauteile bekommen gar keine Spalten (ein leerer DCL-Cluster ist unzulaessig). Im generierten Label wird `"` zu `''` ersetzt (`geruest-dcl-label`) - fuenf Artikelnamen enthalten ein Anfuehrungszeichen, das das DCL-Label sonst vorzeitig beendet und die Datei zerstoert. **Konfigurationen**: gepflegte Bibliothek je Baugruppe unter `konfigurationen` in `geruest.json` (schreibgeschuetzt) plus eigene in `cfg/geruest_user.json` (gitignored, `geruest-user-schreiben`; getrennte Datei, damit Benutzerdaten und versionierte Bibliothek nicht kollidieren). Eigene Eintraege sind in der Liste mit `*` markiert und nur diese loeschbar. Konfigurationen verweisen ueber den ANZEIGENAMEN auf Variante und Anbauteile; ein unbekannter Name wird gemeldet und uebersprungen, statt die Konfiguration scheitern zu lassen. Speichern/Loeschen laufen ueber `done_dialog 2`/`3` (Dialog schliessen, Aktion, neu zeigen) - `getstring` funktioniert aus einem `action_tile`-Rueckruf heraus nicht. Der Block wird - wie KREISEL_n/VF_n - SELBST zusammengebaut: Dummy-DWG aus `data/geruest` liefert nur Geometrie, das Attribut-Schema kommt aus `*geruest-attrib-defs*` (ID, ARTINR, LAENGE, BEZEICHNUNG, TEILEART, TEILEFARBE, LAYER) und wird per `ssg-attrib-merge` mit den Dummy-Tags zusammengefuehrt - sonst verschluckt `ssg-attrib-set-on` stillschweigend jeden Tag, den die Dummy-DWG nicht als ATTDEF kennt. Blockname `GR_<id>_<ssg-timestamp>` (Kollisionszaehler wie in OmniModulInsert). **Das `GR_`-Praefix ist nicht kosmetisch**: `SSG_BLOCKEDIT` haelt JEDEN Block mit TEILEART-Attribut fuer ein Omniflo-Element, deshalb steht in `SSG_LIB_Commands.lsp` ein `GR_*`-Zweig VOR dem Omniflo-Zweig. ARTINR listet jede Sivas-ID so oft, wie die gewaehlte Stueckzahl es vorgibt - erst Basis, dann Befestigung oben, dann unten; bei einer benannten Gruppe (`teile`) wird das ganze Set n-mal wiederholt, die Mengen INNERHALB des Sets bleiben dabei erhalten (`geruest-artikelnummern-n`). BEZEICHNUNG nennt Position und Menge je Teil ("oben 2x ...") und verkettet mit `" + "`, NICHT mit Komma - die Artikelbezeichnungen enthalten selbst Kommas ("ROHR R 1\" 33,7 x 2,6"). Zuordnung Menue -> JSON laeuft ueber das ASCII-Feld `id`, weil die aeusseren JSON-Schluessel Umlaute bzw. Anfuehrungszeichen tragen. CSV-/Sivas-Export: `pattern_geruest = GR_*` (cfg/export.cfg), `csv:collect-export-blocks`/`ssg-id-collect-blocks` sammeln GR_-Bloecke wie BTMT eigenstaendig; `*geruest-attrib-defs*` traegt zusaetzlich ein leeres `ID`-ATTDEF (Voraussetzung fuer `ssg-id-check-all`, das nur bestehende ATTRIBs beschreiben kann). ARTINR/BEZEICHNUNG/TEILEART/LAENGE landen in export_csv.py/export_sivas.py in festen Spalten, TEILEFARBE/LAYER (+ ARTINR bei export_csv.py) im Merkmale-/details-JSON. Noch NICHT enthalten: Edit-Pfad (GERUEST_EDIT) |
| `menu-inventory.lsp` | MenuInventory | BricsCAD Diagnostik (Menuegruppen, Plugins, Startdateien) |
| `DrawPlanquadrate.lsp` | DRAW_PLANQUADRATE, DELETE_PLANQUADRATE, PLANQUADRATE_TOGGLE | Zeichnet auf Z=0 ein Planquadrat-Linienraster (senkrecht/waagerecht), im Abstand/Zaehlschema der aktiven `[Planquadrate]`-Konfiguration aus `cfg/export.cfg` (dieselbe Quelle wie `lib/export_planquadrat.py` fuer den CSV-Export). Bereich kommt NICHT aus den Zeichnungs-Extents, sondern aus derselben Blockmenge wie EXPORTCSV (`csv:collect-export-blocks`, export.lsp; siehe `plq-export-bbox`): Ursprung (Index 1) UND obere Grenze kommen BEIDE aus der tatsaechlichen Bounding-Box jedes Blocks (`csv:get-bbox`, wie `bbox_columns()`/`planquadrat_column()`/`_bbox_min()` in `lib/export_csv.py` bzw. `lib/export_planquadrat.py`), NICHT aus dem reinen Einfuegepunkt - bei einem gedrehten/exzentrisch eingefuegten Block (z.B. ein um 90 Grad gedrehter Kreisel) kann das Bounding-Box-Zentrum weit vom Einfuegepunkt abweichen; Ursprung und Zellzuordnung muessen auf derselben Referenz beruhen, sonst driften sie auseinander (realer Bug, behoben). Reine Hilfsgeometrie (Kreisel-Umfahrungsboegen als eigene Linien, Texte) zaehlt bewusst nicht mit, sonst weicht das Raster vom CSV-Export ab. `x_origin`/`y_origin` ueberschreiben den Ursprung, Fallback auf EXTMIN/EXTMAX falls keine Export-Bloecke vorhanden sind bzw. `csv:get-bbox` fuer einen Block scheitert. Spalten-/Zeilenzahl wird IMMER aufgerundet auf volle Rasterschritte, damit alle senkrechten Linien auf der letzten waagerechten enden und umgekehrt - das Raster bildet immer ein geschlossenes Rechteck. Zaehlung (alphabetisch/numerisch je Achse) als Text am linken/unteren Rand. Das fertige Raster (Linien+Texte) wird per `_.-BLOCK`/`_.INSERT` zu einem einzigen Block `ZZ_PLANQUADRATE` bei (0,0,0) zusammengefasst. Layer aus `cfg/layer.cfg` (`[allgemein]` Key `planquadrate`, Fallback `ZZ_Planquadrate`). DRAW_PLANQUADRATE entfernt vor dem Neuaufbau zuerst einen evtl. vorhandenen Block (`plq-block-entfernen`: INSERTs loeschen + `_-PURGE _B`), DELETE_PLANQUADRATE ruft nur diese Entfernung auf. PLANQUADRATE_TOGGLE ("Planquadrate an/aus", Menue: Konfiguration) prueft per `tblsearch`/`ssget "X"`, ob der Block existiert, und dispatcht auf Zeichnen bzw. Loeschen. Lazy geladen ueber `(ssg-ensure "DrawPlanquadrate")`, nicht in der Core-Ladereihenfolge. Die Planquadrat-SPALTE im CSV-Export (`export_csv.py::planquadrat_column`/`resolve_origins`, `lib/export_planquadrat.py::compute_planquadrat`/`_bbox_min`) rechnet ebenfalls durchgaengig auf Bounding-Box-Basis (nicht nur Einfuegepunkt) und liefert eine SPANNE ("A/1-J/1") statt nur einer Zelle, wenn ein Element mehr als eine Zelle ueberdeckt (Kreisel, lange VF-/GF-Ketten). |
@@ -123,7 +123,6 @@ Detaillierte Dokumentation aller Funktionen und Befehle: siehe `Lisp/README.md`.
| `sprache.dcl` | SSG_SPRACHE (SSG_LIB_Commands.lsp) |
| `tro_insert.dcl` | TRO_INSERT (Tro_Edit.lsp) |
| `tro_edit.dcl` | TRO_EDIT (Tro_Edit.lsp) |
| `geruest.dcl` | Alle GERUEST_*-Befehle (GeruestInsert.lsp, `geruest-dialog`) - ein Dialog fuer alle Baugruppen, Listen zur Laufzeit gefuellt |
| `vfl_edit.dcl` | Linienzug-Editieren/Fortsetzen (vf_linienzug.lsp, `vfl-dlg-position`, aufgerufen aus `vfl-edit-ent`) |
| `vf_linienzug_wizard.dcl` | Linienzug-Assistent (Modus 1, 2 UND 3): zwei generische Einzel-Dialoge (Zahl-Eingabe, Mehrfachauswahl; `vflw-zahl`/`vflw-wahl`, aufgerufen aus `vfl-in-real`/`vfl-in-string`/`vfl-in-int` bei aktivem `*vfl-wizard-mode*`) PLUS sieben Gruppen-Dialoge, die mehrere immer unmittelbar aufeinanderfolgende Fragen in einem Bildschirm zusammenfassen (Kettenstart, AS-Element, GF-Bogen, ES-Element, Vario-Kurve, Gefaelle festlegen, Ziel-Hoehe, Horizontales Stueck - inkl. Punktwahl-Button mit X/Y/Z-Anzeige; `vflw-gruppe-*-impl` in vf_linienzug.lsp fuellen dafuer vorab eine kleine Pending-Queue `*vflw-pending*`, die einzelnen `vfl-in-*`-Aufrufe bleiben dabei unveraendert) PLUS drei Segment-Gruppen-Dialoge fuer die segmentweise Klassifizierung in Modus 2/3 (`vflw_seg_linie_m2` = Typ+GF-Neigung, `vflw_seg_linie_m3` = 4-fach-Typ+kontextabh. Wertfeld, `vflw_seg_bogen` = Typ+Variante; `vflw-seg-*-impl`). Beide Modi heben vor der Frage das aktuelle Pfad-Segment (LINE/ARC) per `vfl-seg-highlight` (`redraw`) in der Zeichnung hervor und zeigen "Segment i/n ..." im Dialogkopf. Details: `doc/variofoerderer.md` |
+930 -152
View File
File diff suppressed because it is too large Load Diff
+27
View File
@@ -1767,6 +1767,33 @@
(cdr (assoc key obj))
)
;; String fuer die Ausgabe in JSON maskieren (Gegenstueck zu ssg-json-string).
;; Der Backslash MUSS zuerst geprueft werden, sonst wuerde die Maskierung der
;; Anfuehrungszeichen gleich wieder mitmaskiert.
;; Hinweis: csv:json-escape in export.lsp leistet dasselbe, ist aber modul-lokal
;; am Export-Modul - bewusst nicht zusammengelegt, das waere ein eigener Schritt.
(defun ssg-json-escape (s / i c erg)
(if (null s) (setq s ""))
(setq erg "" i 1)
(while (<= i (strlen s))
(setq c (substr s i 1))
(setq erg
(strcat erg
(cond
((= c "\\") "\\\\")
((= c "\"") "\\\"")
((= c (chr 10)) "\\n")
((= c (chr 13)) "\\r")
((= c (chr 9)) "\\t")
(T c)
)
)
)
(setq i (1+ i))
)
erg
)
;; Verschachteltes JSON-Objekt parsen (1 Ebene tief)
;; {"section": {"key": val, ...}, ...}
Binary file not shown.
Binary file not shown.
+107 -45
View File
@@ -1,6 +1,7 @@
{
"Rohrabhänger": {
"id": "Rohrabhaenger",
"titel": "Rohrabhaenger",
"teileart": "Geruest Rohrabhaenger",
"dummy": "Rohrabhaenger_dummy.dwg",
"attribute": {
@@ -10,11 +11,11 @@
"max": 6000,
"einheit": "mm"
},
"Farbe": {
"Teilefarbe": {
"typ": "auswahl",
"optionen": [
"RAL7035",
"RAL7030"
"RAL 7035 Lichtgrau",
"RAL 7030 Steingrau"
],
"frei_erlaubt": true,
"frei_option": "Individuell"
@@ -133,50 +134,39 @@
"sivas_id": 922021003,
"menge": 1
}
]
},
"1\" Säulen": {
"id": "Saeulen_1Zoll",
"teileart": "Geruest Saeule 1 Zoll",
"dummy": "R2-Saeule_dummy.dwg",
"attribute": {
"Laenge": {
"typ": "number",
"min": 0,
"max": 6000,
"einheit": "mm"
},
"Farbe": {
"typ": "auswahl",
"optionen": [
"RAL7035",
"RAL7030"
],
"frei_erlaubt": true,
"frei_option": "Individuell"
}
},
"geometrie_varianten": [
],
"konfigurationen": [
{
"name": "R 1\"",
"teile": [
{
"artikel": "ROHR R 1\" 33,7 x 2,6",
"sivas_id": 821006026,
"menge": 1
},
{
"artikel": "CAD - BODENSÄULE R 1\" - BODENPLATTE KPL.",
"sivas_id": 821004200,
"menge": 1
}
"name": "Abhaengung Spannpratze / Rohrklammer",
"variante": "ROHR R 1\" 33,7 x 2,6",
"laenge": 2000,
"teilefarbe": "RAL 7035 Lichtgrau",
"oben": [
{ "artikel": "SPANNPRATZE SELBSTSICHERND KPL.", "menge": 1 },
{ "artikel": "Schraubenset", "menge": 1 }
],
"unten": [
{ "artikel": "ROHRKLAMMER 1\" KPL. VERTIKAL", "menge": 2 }
]
},
{
"name": "Abhaengung Duebel / T-Verbindung",
"variante": "ROHR R 1\" 33,7 x 2,6 einseitig gequetscht",
"laenge": 1500,
"teilefarbe": "RAL 7035 Lichtgrau",
"oben": [
{ "artikel": "DURCHSTECKANKER HST M12X115X20", "menge": 2 }
],
"unten": [
{ "artikel": "ROHRKLAMMER 1\" T-VERBINDUNG KPL.", "menge": 1 }
]
}
]
},
"2\" Säulen": {
"id": "Saeulen_2Zoll",
"teileart": "Geruest Saeule 2 Zoll",
"Säulen": {
"id": "Saeulen",
"titel": "Saeulen",
"teileart": "Geruest Saeule",
"dummy": "R2-Saeule_dummy.dwg",
"attribute": {
"Laenge": {
@@ -185,11 +175,11 @@
"max": 6000,
"einheit": "mm"
},
"Farbe": {
"Teilefarbe": {
"typ": "auswahl",
"optionen": [
"RAL7035",
"RAL7030"
"RAL 7035 Lichtgrau",
"RAL 7030 Steingrau"
],
"frei_erlaubt": true,
"frei_option": "Individuell"
@@ -208,8 +198,25 @@
]
},
"geometrie_varianten": [
{
"name": "R 1\"",
"teileart": "Geruest Saeule 1 Zoll",
"teile": [
{
"artikel": "ROHR R 1\" 33,7 x 2,6",
"sivas_id": 821006026,
"menge": 1
},
{
"artikel": "CAD - BODENSÄULE R 1\" - BODENPLATTE KPL.",
"sivas_id": 821004200,
"menge": 1
}
]
},
{
"name": "R 2\"",
"teileart": "Geruest Saeule 2 Zoll",
"teile": [
{
"artikel": "BODENSÄULE R 2\" 60,3 MIT FUSSPLATTE",
@@ -225,6 +232,7 @@
},
{
"name": "R 2\" Haltearm 1-ARMIG",
"teileart": "Geruest Saeule 2 Zoll",
"teile": [
{
"artikel": "BODENSÄULE R 2\" 60,3 MIT FUSSPLATTE",
@@ -245,6 +253,7 @@
},
{
"name": "R 2\" Haltearm 2-ARMIG 90 Grad",
"teileart": "Geruest Saeule 2 Zoll",
"teile": [
{
"artikel": "BODENSÄULE R 2\" 60,3 MIT FUSSPLATTE",
@@ -265,6 +274,7 @@
},
{
"name": "R 2\" Haltearm 2-ARMIG 180 Grad",
"teileart": "Geruest Saeule 2 Zoll",
"teile": [
{
"artikel": "BODENSÄULE R 2\" 60,3 MIT FUSSPLATTE",
@@ -285,6 +295,7 @@
},
{
"name": "R 2\" Haltearm 3-ARMIG",
"teileart": "Geruest Saeule 2 Zoll",
"teile": [
{
"artikel": "BODENSÄULE R 2\" 60,3 MIT FUSSPLATTE",
@@ -340,10 +351,43 @@
"sivas_id": 922083009,
"menge": 2
}
],
"konfigurationen": [
{
"name": "Bodensaeule 1 Zoll, Standardhoehe",
"variante": "R 1\"",
"laenge": 1000,
"teilefarbe": "RAL 7035 Lichtgrau",
"oben": [],
"unten": []
},
{
"name": "Bodensaeule 2 Zoll, Haltearm 1-armig",
"variante": "R 2\" Haltearm 1-ARMIG",
"laenge": 1200,
"teilefarbe": "RAL 7035 Lichtgrau",
"oben": [
{ "artikel": "KLEMMRING MIT MUFFE EINFACH KPL.", "menge": 2 }
],
"unten": []
},
{
"name": "Bodensaeule 2 Zoll, Haltearm 2-armig 90 Grad",
"variante": "R 2\" Haltearm 2-ARMIG 90 Grad",
"laenge": 1200,
"teilefarbe": "RAL 7035 Lichtgrau",
"oben": [
{ "artikel": "KLEMMRING MIT MUFFE DOPPELT 90 Grad, KPL.", "menge": 2 }
],
"unten": [
{ "artikel": "QUERSCHELLE F. 1\" UND 2\" ROHR GESCHW./VZ. M. 4X M10X30 KPL.", "menge": 2 }
]
}
]
},
"Wandbefestigung": {
"id": "Wandbefestigung",
"titel": "Wandbefestigung",
"teileart": "Geruest Wandbefestigung",
"dummy": "Rohrabhaenger_dummy.dwg",
"geometrie_varianten": [
@@ -414,6 +458,24 @@
}
]
}
],
"konfigurationen": [
{
"name": "Wandflansch mit Duebeln",
"variante": "WANDFLANSCH EINZELTEIL",
"oben": [
{ "artikel": "Nylondübel 12x60 inkl. Holzschrauben", "menge": 1 }
],
"unten": []
},
{
"name": "Winkel 300 mit Schwerlastanker",
"variante": "WINKEL 60X60X6X300",
"oben": [
{ "artikel": "HST M12X115X20", "menge": 1 }
],
"unten": []
}
]
}
}
-61
View File
@@ -1,61 +0,0 @@
// ============================================================
// geruest.dcl - Konfiguration einer Geruest-Baugruppe
// Ein Dialog fuer ALLE Baugruppen (Rohrabhaenger, Saeulen, Wandbefestigung).
// Kopfzeile, Varianten-Dropdown, Farbliste und Anbauteil-Liste werden zur
// Laufzeit aus data/json/geruest.json befuellt - siehe
// Lisp/GeruestInsert.lsp, Abschnitt "DIALOG".
// Baugruppen ohne "attribute"-Block (z.B. Wandbefestigung) bekommen die
// Laengen- und Farbfelder per mode_tile gesperrt.
// ============================================================
geruest : dialog {
label = "Geruest-Baugruppe konfigurieren";
: text {
key = "kopf";
label = "";
width = 64;
}
: boxed_column {
label = "Basis";
: popup_list {
key = "variante";
label = "Variante:";
width = 56;
}
: row {
: edit_box {
key = "laenge";
label = "Laenge (mm):";
edit_width = 10;
}
: popup_list {
key = "farbe";
label = "Farbe:";
width = 18;
}
: edit_box {
key = "farbe_frei";
label = "eigene:";
edit_width = 12;
}
}
}
: boxed_column {
label = "Anbauteile (Mehrfachauswahl mit Strg)";
: list_box {
key = "anbau";
label = "";
multiple_select = true;
width = 64;
height = 12;
}
}
ok_cancel;
}
+15 -1
View File
@@ -981,6 +981,20 @@
"gr-alert-laenge": "Laenge ungueltig: '%1' mm. Erlaubt: %2 bis %3 mm.",
"gr-prompt-einfuegepunkt": "\nEinfuegepunkt waehlen: ",
"gr-abgebrochen": "\nAbgebrochen.",
"gr-fertig": "\nGeruest-Baugruppe '%1' eingefuegt (Block %2)."
"gr-fertig": "\nGeruest-Baugruppe '%1' eingefuegt (Block %2).",
"gr-alert-menge": "Ungueltige Stueckzahl. Erlaubt ist eine ganze Zahl ab 1; ein leeres Feld uebernimmt den Vorgabewert.",
"gr-position-oben": "oben",
"gr-position-unten": "unten",
"gr-konfig-keine": "<keine>",
"gr-konfig-name": "\nName der Konfiguration: ",
"gr-konfig-gespeichert": "\nKonfiguration '%1' gespeichert.",
"gr-konfig-geloescht": "\nKonfiguration '%1' geloescht.",
"gr-konfig-loeschen-frage": "\nKonfiguration '%1' wirklich loeschen? [Ja/Nein] <Nein>: ",
"gr-konfig-nichts-gewaehlt": "\nKeine Konfiguration gewaehlt.",
"gr-konfig-bibliothek-fest": "\nKonfigurationen der Bibliothek koennen nicht geloescht werden - nur eigene (mit * markiert).",
"gr-konfig-teil-unbekannt": "\nGeruest: Anbauteil '%1' aus Konfiguration '%2' ist bei dieser Baugruppe unbekannt - uebersprungen.",
"gr-konfig-variante-unbekannt": "\nGeruest: Variante '%1' aus Konfiguration '%2' ist bei dieser Baugruppe unbekannt - Auswahl unveraendert.",
"gr-fehler-schreiben": "\nGeruest: Datei konnte nicht geschrieben werden: %1",
"gr-fehler-keine-baugruppen": "\nGeruest: Die Datendatei enthaelt keine Baugruppen."
}
}
+15 -1
View File
@@ -981,6 +981,20 @@
"gr-alert-laenge": "Invalid length: '%1' mm. Allowed: %2 to %3 mm.",
"gr-prompt-einfuegepunkt": "\nSelect insertion point: ",
"gr-abgebrochen": "\nCancelled.",
"gr-fertig": "\nScaffold assembly '%1' inserted (block %2)."
"gr-fertig": "\nScaffold assembly '%1' inserted (block %2).",
"gr-alert-menge": "Invalid quantity. Enter a whole number of 1 or more; an empty field uses the default.",
"gr-position-oben": "top",
"gr-position-unten": "bottom",
"gr-konfig-keine": "<none>",
"gr-konfig-name": "\nConfiguration name: ",
"gr-konfig-gespeichert": "\nConfiguration '%1' saved.",
"gr-konfig-geloescht": "\nConfiguration '%1' deleted.",
"gr-konfig-loeschen-frage": "\nReally delete configuration '%1'? [Ja/Nein] <Nein>: ",
"gr-konfig-nichts-gewaehlt": "\nNo configuration selected.",
"gr-konfig-bibliothek-fest": "\nLibrary configurations cannot be deleted - only your own (marked with *).",
"gr-konfig-teil-unbekannt": "\nScaffold: add-on part '%1' from configuration '%2' is unknown for this assembly - skipped.",
"gr-konfig-variante-unbekannt": "\nScaffold: variant '%1' from configuration '%2' is unknown for this assembly - selection unchanged.",
"gr-fehler-schreiben": "\nScaffold: could not write file: %1",
"gr-fehler-keine-baugruppen": "\nScaffold: the data file contains no assemblies."
}
}
+1 -6
View File
@@ -110,12 +110,7 @@
[~APBW 110 R550/67,5 208x347]^C^C(ssg-ensure "OmniModulInsert") OMNI_APBW_R550_675_208
[<-~APBW 110 R550/67,5 58x497]^C^C(ssg-ensure "OmniModulInsert") OMNI_APBW_R550_675_58
[<-Element bearbeiten]^C^C(ssg-ensure "OmniModulInsert") OMNI_EDIT
[->Geruest]
[Rohrabhaenger]^C^C(ssg-ensure "GeruestInsert") GERUEST_ROHRABHAENGER
[->Saeulen]
[2 Zoll Saeulen]^C^C(ssg-ensure "GeruestInsert") GERUEST_SAEULE_2ZOLL
[<-1 Zoll Saeulen]^C^C(ssg-ensure "GeruestInsert") GERUEST_SAEULE_1ZOLL
[<-Wandbefestigung]^C^C(ssg-ensure "GeruestInsert") GERUEST_WANDBEFESTIGUNG
[Geruest...]^C^C(ssg-ensure "GeruestInsert") GERUEST
[->SPS]
[->TRO]
[Marker einfuegen]^C^C(ssg-ensure "Tro_Edit") TRO_INSERT
+138 -7
View File
@@ -471,12 +471,27 @@
(tu-eq "json/escape-newline" (chr 10)
(ssg-json-get (ssg-json-parse "{\"a\": \"\\n\"}") "a"))
;; ssg-json-escape: Gegenstueck zum Parser
(tu-eq "json-escape/quote" "a\\\"b" (ssg-json-escape "a\"b"))
(tu-eq "json-escape/backslash" "a\\\\b" (ssg-json-escape "a\\b"))
(tu-eq "json-escape/newline" "a\\nb" (ssg-json-escape (strcat "a" (chr 10) "b")))
(tu-eq "json-escape/leer" "" (ssg-json-escape nil))
;; Rundlauf: maskieren -> parsen ergibt den Originaltext zurueck
(tu-eq "json-escape/rundlauf" "ROHRKLAMMER 1\" KPL. VERTIKAL"
(ssg-json-get
(ssg-json-parse
(strcat "{\"a\": \""
(ssg-json-escape "ROHRKLAMMER 1\" KPL. VERTIKAL") "\"}"))
"a"))
;; Echte Datendatei: der eigentliche Praxisfall
(setq _datei (strcat (getenv "DXFMAKRO") "/data/json/geruest.json"))
(if (findfile _datei)
(progn
(setq _daten (ssg-json-laden _datei))
(tu-eq "json/geruest-baugruppen" 4 (length _daten))
;; Drei Bereiche: Rohrabhaenger, Saeulen (1 und 2 Zoll zusammengefuehrt),
;; Wandbefestigung
(tu-eq "json/geruest-baugruppen" 3 (length _daten))
;; Baugruppe ueber das ASCII-Feld "id" finden (aeusserer Schluessel
;; traegt Umlaute bzw. Anfuehrungszeichen)
(setq _bg nil)
@@ -509,7 +524,8 @@
;; ------------------------------------------------------------
;; TESTS: GeruestInsert.lsp - reine Hilfsfunktionen
;; ------------------------------------------------------------
(defun tu-tests-geruest ( / _eintrag _gruppe)
(defun tu-tests-geruest ( / _eintrag _gruppe _teile _konfig _rec _pfad _f
_zurueck _bgtest _saeulen)
(princ "\n[GeruestInsert]")
(if (and (null (atoms-family 1 '("GERUEST-ARTIKELNUMMERN")))
(atoms-family 1 '("SSG-ENSURE")))
@@ -518,11 +534,6 @@
(if (null (atoms-family 1 '("GERUEST-ARTIKELNUMMERN")))
(tu-record nil "geruest/modul" "GeruestInsert.lsp nicht geladen")
(progn
;; Indizes aus get_tile bei multiple_select
(tu-eq "geruest-indizes/leer" '() (geruest-indizes ""))
(tu-eq "geruest-indizes/eins" '(0) (geruest-indizes "0"))
(tu-eq "geruest-indizes/drei" '(0 3 5) (geruest-indizes "0 3 5"))
(tu-eq "geruest-id-string/int" "821006026" (geruest-id-string 821006026))
(tu-eq "geruest-id-string/str" "0_B10071" (geruest-id-string "0_B10071"))
(tu-eq "geruest-id-string/nil" nil (geruest-id-string nil))
@@ -547,6 +558,126 @@
(tu-eq "geruest-artnr/ohne-menge" '("333")
(geruest-artikelnummern
(ssg-json-parse "{\"artikel\": \"C\", \"sivas_id\": 333}")))
;; --- Mengenfeld ---
(tu-eq "geruest-zahl-p/ziffern" T (geruest-zahl-p "12"))
(tu-eq "geruest-zahl-p/text" nil (geruest-zahl-p "1a"))
(tu-eq "geruest-zahl-p/leer" nil (geruest-zahl-p ""))
;; Leeres Feld uebernimmt die JSON-Vorgabe, ungueltiges liefert nil
(tu-eq "geruest-menge-wert/leer" 2 (geruest-menge-wert "" 2))
(tu-eq "geruest-menge-wert/zahl" 5 (geruest-menge-wert "5" 2))
(tu-eq "geruest-menge-wert/null" nil (geruest-menge-wert "0" 2))
(tu-eq "geruest-menge-wert/text" nil (geruest-menge-wert "abc" 2))
(tu-eq "geruest-menge-wert/negativ" nil (geruest-menge-wert "-3" 2))
;; --- Stueckzahl ersetzt die JSON-Menge (Einzelteil) ---
(tu-eq "geruest-artnr-n/einzelteil" '("825002019" "825002019" "825002019")
(geruest-artikelnummern-n _eintrag 3))
;; --- Gruppe: ganzes Set n-mal, Mengen INNERHALB bleiben erhalten ---
(tu-eq "geruest-artnr-n/gruppe" '("111" "222" "222" "111" "222" "222")
(geruest-artikelnummern-n _gruppe 2))
;; --- DCL-Label: Anfuehrungszeichen wuerde die Datei zerstoeren ---
(tu-eq "geruest-dcl-label/quote" "ROHRKLAMMER 1'' KPL. VERTIKAL"
(geruest-dcl-label "ROHRKLAMMER 1\" KPL. VERTIKAL"))
(tu-eq "geruest-dcl-label/ohne" "WINKEL 60X60X6X60"
(geruest-dcl-label "WINKEL 60X60X6X60"))
;; --- Hilfslisten ---
(tu-eq "geruest-nil-liste" '(nil nil nil) (geruest-nil-liste 3))
(tu-eq "geruest-liste-setzen" '(nil 7 nil)
(geruest-liste-setzen (geruest-nil-liste 3) 1 7))
(tu-eq "geruest-alist-setzen/neu" '(("a" . 1))
(geruest-alist-setzen nil "a" 1))
(tu-eq "geruest-alist-setzen/ersetzt" '(("a" . 2))
(geruest-alist-setzen '(("a" . 1)) "a" 2))
(tu-eq "geruest-zahl-string/int" "2000" (geruest-zahl-string 2000))
(tu-eq "geruest-zahl-string/leer" "" (geruest-zahl-string nil))
;; --- Konfiguration auf Anbauteile abbilden ---
(setq _teile (list _eintrag _gruppe))
(tu-eq "geruest-name-index/treffer" 1
(geruest-name-index "Schraubenset" _teile))
(tu-eq "geruest-name-index/fehlt" nil
(geruest-name-index "gibt es nicht" _teile))
;; Bekanntes Teil wird uebernommen, unbekanntes uebersprungen (nicht
;; die ganze Konfiguration verworfen)
(setq _konfig (ssg-json-parse
(strcat "{\"name\": \"K1\", \"oben\": ["
"{\"artikel\": \"Schraubenset\", \"menge\": 3},"
"{\"artikel\": \"unbekannt\", \"menge\": 1}]}")))
(tu-eq "geruest-konfig-position" '(nil 3)
(geruest-konfig-position _konfig "oben" _teile))
;; --- Variante gewinnt vor Baugruppe (TEILEART/dummy) ---
;; Die zusammengefuehrte Saeulen-Baugruppe unterscheidet 1 Zoll und
;; 2 Zoll nur noch ueber das teileart-Feld der Variante.
(setq _bgtest (ssg-json-parse
"{\"teileart\": \"Basis\", \"dummy\": \"basis.dwg\"}"))
(tu-eq "geruest-variante-wert/variante-gewinnt" "Speziell"
(geruest-variante-wert
(ssg-json-parse "{\"teileart\": \"Speziell\"}") _bgtest "teileart"))
(tu-eq "geruest-variante-wert/rueckfall" "Basis"
(geruest-variante-wert
(ssg-json-parse "{\"name\": \"X\"}") _bgtest "teileart"))
(tu-eq "geruest-variante-wert/ohne-variante" "basis.dwg"
(geruest-variante-wert nil _bgtest "dummy"))
;; --- Zusammengefuehrte Saeulen-Baugruppe ---
(setq _saeulen nil)
(foreach _e (geruest-baugruppen-liste)
(if (equal (car _e) "Saeulen") (setq _saeulen (cdr _e))))
(tu-eq "geruest/saeulen-vorhanden" T (if _saeulen T nil))
(if _saeulen
(progn
(tu-eq "geruest/saeulen-varianten" 6
(length (ssg-json-get _saeulen "geometrie_varianten")))
(tu-eq "geruest/saeulen-anbauteile" 7
(length (ssg-json-get _saeulen "anbaugruppen")))
(tu-eq "geruest/saeulen-titel" "Saeulen" (geruest-titel _saeulen))
;; R 1" ist die erste Variante und traegt die eigene TEILEART
(tu-eq "geruest/saeulen-1zoll-teileart" "Geruest Saeule 1 Zoll"
(geruest-variante-wert
(car (ssg-json-get _saeulen "geometrie_varianten"))
_saeulen "teileart"))
)
)
;; --- Rundlauf Schreiber -> Parser ---
;; Prueft den Konfigurations-Schreiber ohne BricsCAD-Dialog. Bewusst in
;; eine temporaere Datei: ein Test darf cfg/geruest_user.json nicht
;; ueberschreiben. Die Testdaten enthalten absichtlich Anfuehrungs-
;; zeichen - genau daran wuerde eine fehlende Maskierung scheitern.
(setq _rec
(list (cons "name" "Mein \"Satz\"")
(cons "variante" "ROHR R 1\" 33,7 x 2,6")
(cons "laenge" "2000")
(cons "teilefarbe" "RAL 7035 Lichtgrau")
(cons "oben" (list (list (cons "artikel" "ROHRKLAMMER 1\" KPL. VERTIKAL")
(cons "menge" 2))))
(cons "unten" nil)))
(setq _pfad (vl-filename-mktemp "grtest" nil ".json"))
(setq _f (open _pfad "w"))
(write-line "{ \"Test\": [" _f)
(geruest-konfig-liste-schreiben _f (list _rec))
(write-line "] }" _f)
(close _f)
(setq _zurueck (car (ssg-json-get (ssg-json-laden _pfad) "Test")))
(vl-file-delete _pfad)
(tu-eq "geruest-schreiber/name" "Mein \"Satz\""
(ssg-json-get _zurueck "name"))
(tu-eq "geruest-schreiber/variante" "ROHR R 1\" 33,7 x 2,6"
(ssg-json-get _zurueck "variante"))
(tu-eq "geruest-schreiber/laenge" "2000"
(ssg-json-get _zurueck "laenge"))
(tu-eq "geruest-schreiber/farbe" "RAL 7035 Lichtgrau"
(ssg-json-get _zurueck "teilefarbe"))
(tu-eq "geruest-schreiber/oben-artikel" "ROHRKLAMMER 1\" KPL. VERTIKAL"
(ssg-json-get (car (ssg-json-get _zurueck "oben")) "artikel"))
(tu-eq "geruest-schreiber/oben-menge" 2
(ssg-json-get (car (ssg-json-get _zurueck "oben")) "menge"))
(tu-eq "geruest-schreiber/unten-leer" nil
(ssg-json-get _zurueck "unten"))
)
)
)