From ea0e46a4416055ed6a072525ef3a7f9dc9685620 Mon Sep 17 00:00:00 2001 From: Simon Hensch Date: Tue, 13 Oct 2026 11:02:23 +0200 Subject: [PATCH] feat: Omniflo-Fahrstrecke (OMNI_FAHRSTRECKE) + Geruest-Dialoge ueberarbeitet Fahrstrecke: - Neuer Befehl OMNI_FAHRSTRECKE (+ _BESCHRIFTEN) im Omniflo-Menue, Daten aus data/json/omniflo_fahrstrecke.json, Vorlage dcl/fahrstrecke.dcl - Nutzt die Linien-Logik des Geruest-Traegers (geruest-linien-starten, Dialog/Einfuegen/Beschriftung je Baugruppe parametriert) - Muffen-Dummy wie beim Traeger, farbig nur wo in der JSON gesetzt - Stueckliste: eigene Klasse "Omniflo Fahrstrecke" (GR_Fahrstrecke_*) Geruest-Dialoge: - DCL als statische Vorlagen mit //@NAME@-Platzhaltern (ssg-dcl-vorlage-fuellen in ssg_core), dcl/geruest.dcl neu - Ein Dialog je Bereich (keine Bereichsumschaltung mehr) - Varianten als Radiobuttons mit Artikelnummern im Label, "disabled": true graut Varianten aus - Eine Befestigungsspalte (Gesamtanzahl) + Zeile "Sonstiges", Art.-Nr. unter jedem Anbauteil - Winkel Platte (0/90): Anbauteile gedreht eingefuegt - Kennzeichnung geaenderter Konfiguration, Ueberspeichern per Enter - Traeger: Querstreben nur bei "mit_querstrebe": true Konfigurationen im alten Format (oben/unten) werden beim Laden uebernommen. Unit-Tests ergaenzt (599 gruen). --- CLAUDE.md | 14 +- Lisp/GeruestInsert.lsp | 1076 +++++++++++++-------- Lisp/OmniModulInsert.lsp | 21 + Lisp/ssg_core.lsp | 47 +- Lisp/ssg_stueckliste.lsp | 4 + data/json/geruest.json | 520 ++++------ data/json/geruest_traeger.json | 6 + data/json/omniflo_fahrstrecke.json | 157 +++ data/json/omniflo_ladeschleifen.json | 10 + data/json/omniflo_weichen.json | 494 +++++----- data/omniflo/2D/824604001.dwg | Bin 22371 -> 41034 bytes data/omniflo/2D/824604002.dwg | Bin 0 -> 32906 bytes data/omniflo/2D/824604011.dwg | Bin 0 -> 49710 bytes data/omniflo/2D/824604012.dwg | Bin 0 -> 44203 bytes dcl/fahrstrecke.dcl | 56 ++ dcl/geruest.dcl | 55 ++ dcl/geruest_traeger.dcl | 28 +- lang/de_DE.json | 26 +- lang/en_GB.json | 26 +- menu/SSG_LIB.cui | 947 +++++++++--------- menu/SSG_LIB.mnu | 60 +- tests/test_export_geruest_merkmale.py | 39 + tests/test_export_sivas_zusammenfassen.py | 52 + tests/test_lastent.lsp | 129 +++ tests/test_unit.lsp | 299 +++++- 25 files changed, 2597 insertions(+), 1469 deletions(-) create mode 100644 data/json/omniflo_fahrstrecke.json create mode 100644 data/json/omniflo_ladeschleifen.json create mode 100644 data/omniflo/2D/824604002.dwg create mode 100644 data/omniflo/2D/824604011.dwg create mode 100644 data/omniflo/2D/824604012.dwg create mode 100644 dcl/fahrstrecke.dcl create mode 100644 dcl/geruest.dcl create mode 100644 tests/test_export_geruest_merkmale.py create mode 100644 tests/test_export_sivas_zusammenfassen.py create mode 100644 tests/test_lastent.lsp diff --git a/CLAUDE.md b/CLAUDE.md index 462a468..48dbdc5 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -23,7 +23,7 @@ AutoLISP-Makros (SSG_LIB) fuer BricsCAD Pro zur automatisierten Erstellung von F | `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); Geruest: `geruest.json` (GERUEST-Dialog) und `geruest_traeger.json` (Traeger mit Linien-Logik) | +| `data/json/` | Komponentendaten (Masse, Sivas-IDs); Geruest: `geruest.json` (GERUEST-Dialog) und `geruest_traeger.json` (Traeger mit Linien-Logik); `omniflo_fahrstrecke.json` (Omniflo-Fahrstrecke, gleiche Linien-Logik) | | `data/block_libraries/` | DXF Block-Libraries (ils_library.dxf) | | `cfg/rahmen/` | DIN-Rahmen + Schriftkopf-DWGs (A0-A4, Kopf11 DE/EN/FR/IT), kopiert aus `\\infor-ln\SSG_Tools\ACADSST\KOEPFE`, fuer `DIN_FORMATE` (DinFormate.lsp) | | `dcl/` | DCL-Dialogdefinitionen | @@ -75,8 +75,8 @@ Die `start_briscad.bat` ruft `setenv.bat` auf und startet BricsCAD. | Zusatzmodul/Foerderer/Kurven | `SSG_LIB_Commands` | ILS_BTMT_*, ILS_ETF_*, 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_LADESCHLEIFE_*, OMNI_EDIT | -| Geruest | `GeruestInsert` | GERUEST_SAEULEN, GERUEST_ROHRABHAENGER, GERUEST_WANDBEFESTIGUNG (derselbe Dialog, im jeweiligen Bereich geoeffnet), GERUEST_TRAEGER (eigener Dialog), GERUEST_TRAEGER_BESCHRIFTEN (Untermenue Geruest -> Funktionen -> Traeger beschriften; alle Traeger der Zeichnung neu beschriften); Gattertraeger noch Platzhalter auf GERUEST | +| Omniflo (komplett) | `OmniModulInsert` + `GeruestInsert` | OMNI_APB_*, OMNI_W*_*, OMNI_AP*, OMNI_TEF_*, OMNI_TV_*, OMNI_LADESCHLEIFE_*, OMNI_EDIT; OMNI_FAHRSTRECKE / OMNI_FAHRSTRECKE_BESCHRIFTEN (GeruestInsert, Linien-Logik wie GERUEST_TRAEGER) | +| Geruest | `GeruestInsert` | GERUEST_SAEULEN, GERUEST_ROHRABHAENGER, GERUEST_WANDBEFESTIGUNG (je eigener Dialog aus der Vorlage geruest.dcl, keine Umschaltung), GERUEST_TRAEGER (eigener Dialog), GERUEST_TRAEGER_BESCHRIFTEN (Untermenue Geruest -> Funktionen -> Traeger beschriften; alle Traeger der Zeichnung neu beschriften); Gattertraeger noch Platzhalter auf GERUEST (zeigt nur einen Hinweis) | | Connections | `Connection_Edit` + `SSG_LIB_Commands` | CONNECTION_INSERT, CONNECTION_EDIT, ILS_EINGANG_INSERT, ILS_AUSGANG_INSERT | | Export | `export` | EXPORTSIVAS, EXPORTCSV, CALLPYTHON | | Werkzeuge | `ssg_blocktools`, `ssg_texttools`, `ssg_stueckliste`, `DinFormate` | SSG_BLOCK_COUNT, SSG_BLOCK_DELETE, SSG_ATTR_ERSETZEN, SSG_TEXT_ERSETZEN, SSG_TEXT_PARALLEL, SSG_TEXT_HOEHE, SSG_TEXT_STIL, SSG_FAEHNCHEN_STUECKLISTE, DIN_FORMATE | @@ -95,7 +95,7 @@ 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. Zentrale Helfer: `ssg-lisp-verzeichnis`/`ssg-lisp-datei-pfad` (Lisp-Pfad-Ermittlung), `ssg-rot-matrix-zy` (4x4 Rz(hz)*Ry(vert)-Rotationsmatrix, clusteruebergreifend), GUI-Aus-Schalter `*ssg-gui-aus*` + `ssg-gui-aus`/`ssg-gui-an`/`ssg-gui-p` (fuer automatische Tests: schaltet DCL-/Wizard-Dialoge ab, Module fallen auf Konsolen-/getXXX-Pfad zurueck; der Linienzug hat zusaetzlich `*vfl-headless*`, das die Konsolen-Rueckfrage selbst verbietet - siehe VarioFoerderer-Zeile). **Layer-Zuordnung**: `ssg-layer-cfg-load`/`-reset` (liest `cfg/layer.cfg` lazy), `ssg-layer-cfg-eintrag` (reine Aufloesung "Layername, Farbe" -> `(layer . farbe)`, in `tests/test_unit.lsp` getestet), `ssg-layer-eintrag` (Suchreihenfolge `[ils_]` -> `[allgemein]`), `ssg-layer-anlegen` (Layer mit cfg-Farbe anlegen, optional aktivieren) und `ssg-layer-setzen` (Blockreferenz auf den Baugruppen-Layer legen) - fuer ZUSAMMENGEBAUTE Baugruppen; `ssg-block-layer-vorgabe` (LAYER-Attribut -> `ssg-ils-block-ebene`) fuer nur EINGEFUEGTE Bloecke. Alle liefern nil, wenn nichts konfiguriert ist, und lassen den Layer dann unangetastet. **JSON**: drei Parser nebeneinander, bewusst nicht zusammengelegt - `ssg-load-json`/`ssg-parse-json-array` (flaches Array von Objekten) und `ssg-cfg-parse-nested` (genau 1 Ebene) sind ZEILENbasiert und koennen weder echte Verschachtelung noch mehrzeilige Arrays, maskierte Anfuehrungszeichen (`\"`) oder Kommas in Strings lesen; ihre Konsumenten (Konfiguration, Sprache, VF-Spec) sind auf dieses Verhalten eingestellt und bleiben unangetastet. Fuer alles andere `ssg-json-laden`/`ssg-json-parse`/`ssg-json-get` (rekursiver Descent-Parser ueber einen Positionszeiger): Objekt -> Alist, Array -> Liste, true -> T, false/null -> nil (beide nil, "Feld fehlt" ist also nicht von "Feld ist false" unterscheidbar), `\uXXXX` nur fuer ASCII. In `tests/test_unit.lsp` (`tu-tests-json`) gegen die echte Geruest-Datendatei getestet. Dazu `ssg-join` (Liste + Trennzeichen -> String). `ssg-lastent-ohne-attribute`: Startmarke fuer "alles Neue seit Marke per entnext einsammeln" - statt nacktem `(entlast)` verwenden, sonst laeuft `entnext` in die ATTRIBs/SEQEND eines vorherigen Attribut-Blocks und `_.-BLOCK` entfernt sie dort (realer Bug: per Strg+C/V kopierter GR_-Block verlor beim naechsten GERUEST seine Attribute; Test `tests/test_lastent.lsp`) | +| `ssg_core.lsp` | - | Kernel: ssg-start/ssg-end, ssg-cfg-or, ssg-attrib-read/write, Layer/Block-Ops. Zentrale Helfer: `ssg-lisp-verzeichnis`/`ssg-lisp-datei-pfad` (Lisp-Pfad-Ermittlung), `ssg-rot-matrix-zy` (4x4 Rz(hz)*Ry(vert)-Rotationsmatrix, clusteruebergreifend), GUI-Aus-Schalter `*ssg-gui-aus*` + `ssg-gui-aus`/`ssg-gui-an`/`ssg-gui-p` (fuer automatische Tests: schaltet DCL-/Wizard-Dialoge ab, Module fallen auf Konsolen-/getXXX-Pfad zurueck; der Linienzug hat zusaetzlich `*vfl-headless*`, das die Konsolen-Rueckfrage selbst verbietet - siehe VarioFoerderer-Zeile). **Layer-Zuordnung**: `ssg-layer-cfg-load`/`-reset` (liest `cfg/layer.cfg` lazy), `ssg-layer-cfg-eintrag` (reine Aufloesung "Layername, Farbe" -> `(layer . farbe)`, in `tests/test_unit.lsp` getestet), `ssg-layer-eintrag` (Suchreihenfolge `[ils_]` -> `[allgemein]`), `ssg-layer-anlegen` (Layer mit cfg-Farbe anlegen, optional aktivieren) und `ssg-layer-setzen` (Blockreferenz auf den Baugruppen-Layer legen) - fuer ZUSAMMENGEBAUTE Baugruppen; `ssg-block-layer-vorgabe` (LAYER-Attribut -> `ssg-ils-block-ebene`) fuer nur EINGEFUEGTE Bloecke. Alle liefern nil, wenn nichts konfiguriert ist, und lassen den Layer dann unangetastet. **JSON**: drei Parser nebeneinander, bewusst nicht zusammengelegt - `ssg-load-json`/`ssg-parse-json-array` (flaches Array von Objekten) und `ssg-cfg-parse-nested` (genau 1 Ebene) sind ZEILENbasiert und koennen weder echte Verschachtelung noch mehrzeilige Arrays, maskierte Anfuehrungszeichen (`\"`) oder Kommas in Strings lesen; ihre Konsumenten (Konfiguration, Sprache, VF-Spec) sind auf dieses Verhalten eingestellt und bleiben unangetastet. Fuer alles andere `ssg-json-laden`/`ssg-json-parse`/`ssg-json-get` (rekursiver Descent-Parser ueber einen Positionszeiger): Objekt -> Alist, Array -> Liste, true -> T, false/null -> nil (beide nil, "Feld fehlt" ist also nicht von "Feld ist false" unterscheidbar), `\uXXXX` nur fuer ASCII. In `tests/test_unit.lsp` (`tu-tests-json`) gegen die echte Geruest-Datendatei getestet. Dazu `ssg-join` (Liste + Trennzeichen -> String). **DCL-Vorlagen**: `ssg-dcl-vorlage-fuellen` (Vorlage lesen, Markerzeilen `//@NAME@` durch erzeugte Zeilen ersetzen - reiner Kern `ssg-dcl-zeilen-ersetzen`, getestet - und per `ssg-dcl-temp-schreiben` als Temp-Datei schreiben) fuer Dialoge mit fester Grundstruktur und einzelnen datenabhaengigen Bloecken. `ssg-lastent-ohne-attribute`: Startmarke fuer "alles Neue seit Marke per entnext einsammeln" - statt nacktem `(entlast)` verwenden, sonst laeuft `entnext` in die ATTRIBs/SEQEND eines vorherigen Attribut-Blocks und `_.-BLOCK` entfernt sie dort (realer Bug: per Strg+C/V kopierter GR_-Block verlor beim naechsten GERUEST seine Attribute; Test `tests/test_lastent.lsp`) | | `ssg_ks_insert.lsp` | - | Gemeinsame KS-Extraktion + Block-Einfuegeprimitiven (von VarioFoerderer UND Gefaellestrecke genutzt, frueher in beiden dupliziert): `vec-length`, `ks-line-axis`, `ks-normalize-name`, `ks-relativize`/`-absolutize`, `ensure-block-loaded`, `extract-ks-from-block[-raw]` (Cache `*ks-cache*`), `insert-block-by-ks` (nur Rz), `insert-inclined-scaled-block`/`insert-rotated-block-with-ks` (Rz*Ry). MNL laedt es als Core-Modul VOR Gefaellestrecke/VarioFoerderer; vf_core/Gefaellestrecke haben einen guarded Nachlade-Load fuers isolierte Test-Laden | | `ssg_lang.lsp` | - | Sprachumschaltung Deutsch/Englisch (ssg-text, ssg-textf, *ssg-lang*) | | `ssg_dbg.lsp` | - | Debug-Logging (dbgopen, dbgmsg, dbgflush, dbgclose) | @@ -113,7 +113,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_LADESCHLEIFE_AP110, OMNI_EDIT | Omniflo-Komponenten: Boegen, Weichen, Verbinder, Transferwagen, Ladeschleifen (`data/json/omniflo_ladeschleifen.json`, per `ssg-json-laden`, da die Beschreibungen Kommas enthalten; Blockdatei darf `.dwg` statt `.dxf` sein), 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_.dwg`/`Ausgang_.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_`) 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, GERUEST_SAEULEN, GERUEST_ROHRABHAENGER, GERUEST_WANDBEFESTIGUNG, GERUEST_TRAEGER, GERUEST_TRAEGER_BESCHRIFTEN | 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; fuer `dummy` ueber `geruest-dummy-wahl`: fehlt die DWG der Variante, Meldung + Rueckfall auf den Baugruppen-Dummy; ist der Dummy zugleich eine Teile-DWG, wird er per `geruest-ohne-pfad` nicht doppelt eingefuegt) - 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 Anzahl. **Zwei Mengenfelder im JSON, bewusst verschieden benannt**: `stueckzahl` = wie oft ein Teil TATSAECHLICH geschrieben wird (je Variante bzw. je Satz/Anbauteil, fehlt = 1), `anzahl_vorgabe` = NUR die Vorbelegung des Anzahl-Feldes im Dialog (Anbaugruppen, fehlt = 1); ein Anbauteil wird Anzahl x `stueckzahl` mal geschrieben, bei einer Gruppe (`teile`) zaehlt die Anzahl die Saetze (`geruest-stueckzahl`/`geruest-anzahl-vorgabe`). In Konfigurationen (`oben`/`unten`) heisst der gespeicherte Dialogwert `anzahl`. 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. **Teile-Geometrie**: jede ausgewaehlte Artikelnummer (Basis/oben/unten inkl. aufgeloester Gruppen), fuer die `data/geruest/.dwg` existiert, wird zusaetzlich einmal bei 0,0,0 mit in den Block eingefuegt (`geruest-teile-dwgs`, dedupliziert, fehlende DWGs still uebergangen) - reine visuelle Rueckmeldung, die Attribut-Logik bleibt davon unberuehrt. **TEILEFARBE** ist eine kommagetrennte Liste parallel zu ARTINR (z.B. `,,RAL7030,,RAL7030`): Teile mit `"farbig": true` in `geruest.json` (je Artikel; eine Gruppe vererbt es an ihre Teile, fehlend = false) bekommen die im Dialog gewaehlte Baugruppenfarbe, alle anderen einen leeren Eintrag. ARTINR und TEILEFARBE entstehen aus demselben Durchlauf (`geruest-teile-paare`/`-paare-n`, `geruest-farbliste`), sind also garantiert gleich lang. `export_sivas.py` schreibt daraus je Artikelnummer das Merkmal `{"108": ""}` in `details` (Nummer aus `cfg/export.cfg` `[Sivas] merkmal_teilefarbe`). Blockname `GR__` (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 Anzahl x `stueckzahl` es vorgeben - 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. **Attribut-Keys in `geruest.json` sind GROSS** (`LAENGE`, `TEILEFARBE`, ...) = die Block-Attribut-Tags; `ssg-json-get` unterscheidet Gross/Klein. **Rohr-Geruest-Traeger** (`GERUEST_TRAEGER`): Traeger-Baugruppen mit Linien-Logik liegen in einer EIGENEN Datei `data/json/geruest_traeger.json` (gleicher Aufbau wie geruest.json, eigener Lader/Cache `geruest-traeger-daten`, Suche `geruest-baugruppe id daten`; gemeinsamer Lader `geruest-json-laden-cache`) - sie tauchen darum nicht im Bereichs-Dropdown von GERUEST auf; dort kann spaeter auch der Gattertraeger hin. eigener fester Dialog `dcl/geruest_traeger.dcl` (Variante, Farbe, je eine Checkbox + Feld fuer `LAENGENABZUGANFANG`/`LAENGENABZUGENDE`, Vorgabe `vorgabe`/`aktiv` aus dem attribute-Block, je Variante ueberschreibbar via `geruest-attr-feld`); danach Einfuege-Schleife bis ESC/Enter: Startpunkt, dann Endpunkt ODER getippte Laenge (+ Richtung). Aktive Abzuege ruecken die Linie beidseitig ein (Strecke 1000, Abzug Anfang 20/Ende 35 -> Start 20 mm hinter dem Klick, Linie 945 mm); `LAENGE` = Netto-Laenge, gegen `LAENGE.min/max` geprueft. KEINE Dummy-DWG: die Geometrie ist eine per `entmake` erzeugte LINE (0,0,0)-(L,0,0) auf dem `layer` der Variante, eingefuegt mit dem Richtungswinkel (ANGBASE/ANGDIR/AUNITS dafuer kurz auf 0). **Querstreben + Muffe** als verschachtelte Dummy-DWGs im selben Block, reine Grafik ohne Export: `querstrebe.dummy` (`data/geruest/dummy_Strebe_30x4.dwg`, Basispunkt Strebenmitte, 30 mm laengs X) an jeder Strebenposition; fehlt die DWG, Rueckfall auf je eine 25-mm-Querlinie an Strebenanfang/-ende (`laenge`/`querlinie`, Standard 30/25 nur im Code). `muffe.dummy` (`dummy_Muffe_1zoll.dwg`, Basispunkt Muffenmitte) am Linienende, NUR bei Varianten mit ausdruecklichem `"mit_muffe": true` (nicht aus dem Namen geraten; bei "mit 2 Muffen" trotzdem nur eine am Ende); `querstrebe`/`muffe` per Variante ueberschreibbar (`geruest-variante-wert`). Dummys werden ohne Drehung eingefuegt (Traeger laeuft im Block entlang +X), ab dem zweiten Mal per Blockname (`geruest-dummy-einfuegen`). Verteilungs-Konfiguration `querstrebe` (`abstand`/`rand_min`/`rand_max`, Variante vor Baugruppe), Plan `geruest-traeger-streben-plan` -> (rand positionen): der Abstand zwischen zwei Streben ist IMMER genau `abstand`, beide Raender gleich (netto = k*abstand + 2*rand); gewaehlt wird die Strebenzahl, deren Rand am naechsten an `rand_min`..`rand_max` liegt (Gleichstand -> weniger Streben). Mit 500/100..250 geht das nur auf, wenn netto mod 500 = 0 oder in [200, 500) liegt (z.B. 1300 -> 150|500|500|150); sonst (1001..1199, unter 200 mm) liegt der Rand ausserhalb (1100 -> 300|500|300) - `geruest-traeger-rand-pruefen` zeigt dann eine Messagebox (ohne GUI: Konsole), der Traeger wird trotzdem eingefuegt. Schema `*geruest-traeger-attrib-defs*` = `*geruest-attrib-defs*` + die zwei Abzug-Tags; gemeinsamer Block-Schluss mit den anderen Bereichen in `geruest-block-abschliessen`. Reine Berechnung (`geruest-traeger-laenge`/`-start`/`-pruefen`, `geruest-mm-zahl`) in `tests/test_unit.lsp`. **Traeger-Beschriftung** (Checkbox im Dialog, Standard an; z.B. `RT 80/80 L=2650`): EIGENES TEXT-Objekt neben dem Block, abgeleitet NUR aus dem fertigen Block (Einfuegepunkt, DXF 50, Attribute `LAENGE` + `VARIANTE`) - darum nutzen Einfuegen und `GERUEST_TRAEGER_BESCHRIFTEN` dieselbe Funktion `geruest-traeger-beschriften`, und ein von Hand verschobener/gedrehter Traeger wird beim Neubeschriften korrekt erfasst. Verknuepfung Text -> Block per XDATA `SSG_GR_BESCHR` (1005 = Block-Handle): Neubeschriften ersetzt statt verdoppelt, der Sammelbefehl entfernt verwaiste Texte. JSON `beschriftung` (je FELD Variante vor Baugruppe, `geruest-obj-feld`): Inhalt `format` (`%1` Text, `%2` Laenge auf ganze mm) + `text` (fehlt -> Variantenname) und `layer` (je Variante verschieden, darum in JEDER Variante gepflegt - keine Baugruppen-Vorgabe; fehlt er doch, aktueller Layer); Formatierung NUR `stil`/`ausrichtung`/`hoehe` - alles andere regelt der Textstil ausserhalb, es wird kein Stil angelegt (fehlt er: Meldung, aktueller TEXTSTYLE). `ausrichtung` = Codes von TEXT "Ausrichten" (T/M/B + L/C/R), Bezugspunkt auf der Traegerlinie, L/R in LESErichtung. Textwinkel entlang des Traegers, DIN: fuer 90 < w <= 270 Grad um 180 gedreht (`geruest-text-winkel`). Noch NICHT enthalten: Edit-Pfad (GERUEST_EDIT) | +| `GeruestInsert.lsp` | GERUEST, GERUEST_SAEULEN, GERUEST_ROHRABHAENGER, GERUEST_WANDBEFESTIGUNG, GERUEST_TRAEGER, GERUEST_TRAEGER_BESCHRIFTEN, OMNI_FAHRSTRECKE, OMNI_FAHRSTRECKE_BESCHRIFTEN | Geruest-Baugruppen aus `data/json/geruest.json` konfigurieren und einfuegen. **Ein Dialog je Bereich**: Rohrabhaenger / Saeulen / Wandbefestigung oeffnen NUR ueber ihren eigenen Menuebefehl (`geruest-starten id`, Dialogtitel aus dem ASCII-Feld `titel`); eine Umschaltung im Dialog gibt es nicht (DCL hat kein Reiter-Tile), `GERUEST` ohne Bereich zeigt nur einen Hinweis. Der Dialogstand beginnt je Aufruf frisch. 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; fuer `dummy` ueber `geruest-dummy-wahl`: fehlt die DWG der Variante, Meldung + Rueckfall auf den Baugruppen-Dummy; ist der Dummy zugleich eine Teile-DWG, wird er per `geruest-ohne-pfad` nicht doppelt eingefuegt) - 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. **Das Layout steht als Vorlage in `dcl/geruest.dcl`** (bzw. `dcl/geruest_traeger.dcl`); nur die datenabhaengigen Bloecke - ein `radio_button` je Variante (Key `v`, `geruest-radio-key`/`-index`), Mengenfeld + Ankreuzfeld je Anbauteil - werden zur Laufzeit an Markerzeilen `//@NAME@` eingesetzt (`geruest-dcl-ersetzungen` -> `ssg-dcl-vorlage-fuellen` in ssg_core, Temp-Datei, nach `unload_dialog` geloescht). Grund: DCL kann Tiles weder zur Laufzeit erzeugen noch ausblenden, Radiobutton-Labels lassen sich per `set_tile` nicht aendern, und eine `list_box` kann keine Eingabefelder enthalten. Varianten bewusst als Radiobuttons statt `list_box`: BricsCAD zeichnet die Listenspalte nur halb so breit, und ein `tabs`-Wert passt nur schrift-/skalierungsabhaengig. Inhalt: Basis-Variante aus `geometrie_varianten` (`list_box` mit Einfachauswahl, Hoehe nach Variantenzahl, `geruest-dcl-listenhoehe`), **Winkel Platte** (0/90 Grad, `*geruest-winkel-werte*`): Ausrichtung der Anbauteile zur Basis - die Teile-DWGs aus oben/unten/sonstiges werden um diesen Winkel um Z gedreht in den Block eingefuegt, Basis und Dummy bleiben ungedreht (`geruest-teile-dwgs-rot`; in Konfigurationen als echter Wert `winkel_platte`, kein Block-Attribut), Laenge (gegen `attribute.Laenge` min/max geprueft, Retry-Schleife), Farbe (`attribute.Teilefarbe`, Freitext bei `frei_option`) und **eine Befestigungsspalte** "Befestigung oben und unten" mit allen `anbaugruppen.befestigung` - die Anzahl ist die GESAMTanzahl je Teil (oben und unten zusammen; Tile-Keys `b`/`bm`, Zustand `*geruest-dlg-bef*`). Unter jedem Teil (auch in Sonstiges) zeigt eine Textzeile "Art.-Nr. ..." die Artikelnummer(n) (`geruest-artnr-anzeige`: Einzelteil -> `sivas_id`, Gruppe -> eindeutige Nummern der Teile; DCL kennt keine Schriftgroesse, darum normale Groesse in eigener Zeile). `anbaugruppen` ist ein Objekt mit zwei Listen: `befestigung` (Befestigungsspalte) und `sonstiges` (Teile, die weder oben noch unten sitzen, z.B. die Saeulen-Haltearme) - letztere bekommen eine eigene Zeile darunter (nur wenn nicht leer), in ARTINR/BEZEICHNUNG nach "unten" als "sonstiges" (`geruest-anbau-liste`; ein altes flaches Array gilt als `befestigung`). **Zwei Mengenfelder im JSON, bewusst verschieden benannt**: `stueckzahl` = wie oft ein Teil TATSAECHLICH geschrieben wird (je Variante bzw. je Satz/Anbauteil, fehlt = 1), `anzahl_vorgabe` = NUR die Vorbelegung des Anzahl-Feldes im Dialog (Anbaugruppen, fehlt = 1); ein Anbauteil wird Anzahl x `stueckzahl` mal geschrieben, bei einer Gruppe (`teile`) zaehlt die Anzahl die Saetze (`geruest-stueckzahl`/`geruest-anzahl-vorgabe`). In Konfigurationen (`befestigung`/`sonstiges`, dazu `winkel_platte`) heisst der gespeicherte Dialogwert `anzahl`. Aeltere Konfigurationen mit getrennten `oben`/`unten`-Listen laden weiter: deren Mengen werden zur Gesamtanzahl addiert (`geruest-konfig-befestigung`), Sonstiges-Teile darin still in die Sonstiges-Zeile umgehaengt (`geruest-konfig-sonstiges`); beim naechsten Speichern steht alles im neuen Format. 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. **Geaenderte Konfiguration**: beim Anwenden wird der Dialogstand als Vergleichsbasis gemerkt (`*geruest-dlg-konfig-basis*`); jede Eingabe vergleicht den aktuellen Record damit (`geruest-dlg-aenderung-pruefen`, Vergleich statt Flag - Zuruecknehmen hebt die Markierung wieder auf) und kennzeichnet den Listeneintrag mit "(geaendert)" plus Statuszeile `kstatus`. Speichern bietet bei einer gewaehlten EIGENEN Konfiguration deren Namen als Vorgabe an (Enter = ueberschreiben, `geruest-konfig-name-vorgabe`); Bibliotheks-Konfigurationen brauchen einen neuen Namen. 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. **Teile-Geometrie**: jede ausgewaehlte Artikelnummer (Basis/oben/unten inkl. aufgeloester Gruppen), fuer die `data/geruest/.dwg` existiert, wird zusaetzlich einmal bei 0,0,0 mit in den Block eingefuegt (`geruest-teile-dwgs`, dedupliziert, fehlende DWGs still uebergangen) - reine visuelle Rueckmeldung, die Attribut-Logik bleibt davon unberuehrt. **TEILEFARBE** ist eine kommagetrennte Liste parallel zu ARTINR (z.B. `,,RAL7030,,RAL7030`): Teile mit `"farbig": true` in `geruest.json` (je Artikel; eine Gruppe vererbt es an ihre Teile, fehlend = false) bekommen die im Dialog gewaehlte Baugruppenfarbe, alle anderen einen leeren Eintrag. ARTINR und TEILEFARBE entstehen aus demselben Durchlauf (`geruest-teile-paare`/`-paare-n`, `geruest-farbliste`), sind also garantiert gleich lang. `export_sivas.py` schreibt daraus je Artikelnummer das Merkmal `{"108": ""}` in `details` (Nummer aus `cfg/export.cfg` `[Sivas] merkmal_teilefarbe`). Blockname `GR__` (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 Anzahl x `stueckzahl` es vorgeben - erst Basis, dann Befestigung, dann Sonstiges; 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 ("Befestigung 4x ...", "sonstiges 1x ...") 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. **Attribut-Keys in `geruest.json` sind GROSS** (`LAENGE`, `TEILEFARBE`, ...) = die Block-Attribut-Tags; `ssg-json-get` unterscheidet Gross/Klein. **Rohr-Geruest-Traeger** (`GERUEST_TRAEGER`): Traeger-Baugruppen mit Linien-Logik liegen in einer EIGENEN Datei `data/json/geruest_traeger.json` (gleicher Aufbau wie geruest.json, eigener Lader/Cache `geruest-traeger-daten`, Suche `geruest-baugruppe id daten`; gemeinsamer Lader `geruest-json-laden-cache`) - sie tauchen darum nicht im Bereichs-Dropdown von GERUEST auf; dort kann spaeter auch der Gattertraeger hin. eigener Dialog aus der Vorlage `dcl/geruest_traeger.dcl` (Variante als Radiobuttons, JEDE Variante - auch die mit Muffe - mit eigenem Button, Beschriftung "Name (Artikelnummern)" ueber `geruest-varianten-label`; Varianten mit `"disabled": true` erscheinen in allen drei Geruest-Dialogen ausgegraut und nicht waehlbar (`geruest-variante-gesperrt-p`, `geruest-varianten-sperren` per `mode_tile`; Vorauswahl ueber `geruest-variante-waehlbar`/`-erste-freie-variante`; eine Konfiguration mit gesperrter Variante laesst die Auswahl unveraendert und meldet `gr-konfig-variante-gesperrt`) - bleiben aber in den Daten, damit Konfigurationen und Neubeschriften sie weiter ueber den Namen finden; eine Muffen-Checkbox gab es zwischenzeitlich, sie wurde wieder entfernt, weil die Artikelnummer der Muffen-Variante dann im Dialog nicht sichtbar war; Farbe, je eine Checkbox + Feld fuer `LAENGENABZUGANFANG`/`LAENGENABZUGENDE`, Vorgabe `vorgabe`/`aktiv` aus dem attribute-Block, je Variante ueberschreibbar via `geruest-attr-feld`); danach Einfuege-Schleife bis ESC/Enter: Startpunkt, dann Endpunkt ODER getippte Laenge (+ Richtung). Aktive Abzuege ruecken die Linie beidseitig ein (Strecke 1000, Abzug Anfang 20/Ende 35 -> Start 20 mm hinter dem Klick, Linie 945 mm); `LAENGE` = Netto-Laenge, gegen `LAENGE.min/max` geprueft. KEINE Dummy-DWG: die Geometrie ist eine per `entmake` erzeugte LINE (0,0,0)-(L,0,0) auf dem `layer` der Variante, eingefuegt mit dem Richtungswinkel (ANGBASE/ANGDIR/AUNITS dafuer kurz auf 0). **Querstreben + Muffe** als verschachtelte Dummy-DWGs im selben Block, reine Grafik ohne Export: `querstrebe.dummy` (`data/geruest/dummy_Strebe_30x4.dwg`, Basispunkt Strebenmitte, 30 mm laengs X) an jeder Strebenposition, NUR bei Varianten mit ausdruecklichem `"mit_querstrebe": true` (z.B. nicht beim `Rohr 1"`); fehlt die DWG, Rueckfall auf je eine 25-mm-Querlinie an Strebenanfang/-ende (`laenge`/`querlinie`, Standard 30/25 nur im Code). `muffe.dummy` (`dummy_Muffe_1zoll.dwg`, Basispunkt Muffenmitte) am Linienende, NUR bei Varianten mit ausdruecklichem `"mit_muffe": true` (nicht aus dem Namen geraten; bei "mit 2 Muffen" trotzdem nur eine am Ende); `querstrebe`/`muffe` per Variante ueberschreibbar (`geruest-variante-wert`). Dummys werden ohne Drehung eingefuegt (Traeger laeuft im Block entlang +X), ab dem zweiten Mal per Blockname (`geruest-dummy-einfuegen`). Verteilungs-Konfiguration `querstrebe` (`abstand`/`rand_min`/`rand_max`, Variante vor Baugruppe), Plan `geruest-traeger-streben-plan` -> (rand positionen): der Abstand zwischen zwei Streben ist IMMER genau `abstand`, beide Raender gleich (netto = k*abstand + 2*rand); gewaehlt wird die Strebenzahl, deren Rand am naechsten an `rand_min`..`rand_max` liegt (Gleichstand -> weniger Streben). Mit 500/100..250 geht das nur auf, wenn netto mod 500 = 0 oder in [200, 500) liegt (z.B. 1300 -> 150|500|500|150); sonst (1001..1199, unter 200 mm) liegt der Rand ausserhalb (1100 -> 300|500|300) - `geruest-traeger-rand-pruefen` zeigt dann eine Messagebox (ohne GUI: Konsole), der Traeger wird trotzdem eingefuegt. Schema `*geruest-traeger-attrib-defs*` = `*geruest-attrib-defs*` + die zwei Abzug-Tags; gemeinsamer Block-Schluss mit den anderen Bereichen in `geruest-block-abschliessen`. Reine Berechnung (`geruest-traeger-laenge`/`-start`/`-pruefen`, `geruest-mm-zahl`) in `tests/test_unit.lsp`. **Traeger-Beschriftung** (Checkbox im Dialog, Standard an; z.B. `RT 80/80 L=2650`): EIGENES TEXT-Objekt neben dem Block, abgeleitet NUR aus dem fertigen Block (Einfuegepunkt, DXF 50, Attribute `LAENGE` + `VARIANTE`) - darum nutzen Einfuegen und `GERUEST_TRAEGER_BESCHRIFTEN` dieselbe Funktion `geruest-traeger-beschriften`, und ein von Hand verschobener/gedrehter Traeger wird beim Neubeschriften korrekt erfasst. Verknuepfung Text -> Block per XDATA `SSG_GR_BESCHR` (1005 = Block-Handle): Neubeschriften ersetzt statt verdoppelt, der Sammelbefehl entfernt verwaiste Texte. JSON `beschriftung` (je FELD Variante vor Baugruppe, `geruest-obj-feld`): Inhalt `format` (`%1` Text, `%2` Laenge auf ganze mm) + `text` (fehlt -> Variantenname) und `layer` (je Variante verschieden, darum in JEDER Variante gepflegt - keine Baugruppen-Vorgabe; fehlt er doch, aktueller Layer); Formatierung NUR `stil`/`ausrichtung`/`hoehe` - alles andere regelt der Textstil ausserhalb, es wird kein Stil angelegt (fehlt er: Meldung, aktueller TEXTSTYLE). `ausrichtung` = Codes von TEXT "Ausrichten" (T/M/B + L/C/R), Bezugspunkt auf der Traegerlinie, L/R in LESErichtung. Textwinkel entlang des Traegers, DIN: fuer 90 < w <= 270 Grad um 180 gedreht (`geruest-text-winkel`). **Omniflo-Fahrstrecke** (`OMNI_FAHRSTRECKE`, Daten `data/json/omniflo_fahrstrecke.json`, Vorlage `dcl/fahrstrecke.dcl`): dieselbe Linien-Logik wie der Traeger, Code geteilt - `geruest-linien-starten id daten dcl-datei dlg-name` (Dialog `geruest-traeger-dialog` mit Vorlage + Dialogname als Argument, Einfuegen `geruest-traeger-einfuegen`), Beschriftung `geruest-traeger-beschriften blockEnt bg` mit der Baugruppe als Argument, Sammelbefehle je Typ ueber `geruest-linien-beschriften id daten` (Bloecke `GR__*`; verwaiste Texte werden typunabhaengig entfernt). Unterschiede stehen nur in den Daten: keine Querstreben (kein `mit_querstrebe`), Muffen-Dummy wie beim Traeger ueber den `muffe`-Block der Baugruppe (nur Varianten mit `"mit_muffe": true`), `farbig` nur bei ST/STL, Muffen-Varianten nur fuer ST/STL. Der Dialogstand bleibt je Baugruppe erhalten (`*geruest-tr-id*`; Wechsel Traeger <-> Fahrstrecke setzt ihn zurueck). Meldungstexte `gr-tr-*` nennen den Bauteilnamen aus `titel` als Platzhalter. In der Stueckliste eigene Klasse `fahrstrecke` (`GR_Fahrstrecke_*` vor dem allgemeinen `GR_*`). Noch NICHT enthalten: Edit-Pfad (GERUEST_EDIT) | | `menu-inventory.lsp` | MenuInventory | BricsCAD Diagnostik (Menuegruppen, Plugins, Startdateien) | | `DinFormate.lsp` | DIN_FORMATE | Ersatz fuer das alte ACADSST-Makro `DINFORM.LSP`/`.DCL` (SSG2-Menue "DIN-FORMATE..."): fuegt einen DIN-Rahmen (A0-A3, A4 quer/hoch) und optional einen Schriftkopf (KOPF11, Sprachen DE/EN/FR/IT) per Dialog (`dcl/dinformate.dcl`) ein. Block-DWGs liegen flach in `cfg/rahmen/` (kopiert aus `\\infor-ln\SSG_Tools\ACADSST\KOEPFE` - nur die von DINFORM.LSP tatsaechlich referenzierten Dateien: `A0`/`A1`/`A2`/`A3`/`A4Q`/`A4H.DWG` + `Kopf11`/`Kopf11e`/`Kopf11f`/`Kopf11i.dwg`). Rahmen wird im Zeichenmassstab-Faktor eingefuegt, der Kopf im Faktor/100 (Kopf-DWG ist 100x groesser als die Rahmen-DWGs angelegt) - unveraendert aus dem Original-Massstabsschema uebernommen. Blockdefinitionen werden einmalig per `_.-INSERT ... _X 0` nachgeladen (`dinformate-block-laden`), falls noch nicht in der Zeichnung vorhanden. Lazy geladen ueber `(ssg-ensure "DinFormate")`, Menue: Werkzeuge > Din Formate. | | `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). | @@ -131,7 +131,9 @@ 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_traeger.dcl` | GERUEST_TRAEGER (GeruestInsert.lsp, `geruest-traeger-dialog`) | +| `geruest.dcl` | VORLAGE fuer GERUEST_SAEULEN/_ROHRABHAENGER/_WANDBEFESTIGUNG (GeruestInsert.lsp, `geruest-dialog`); Platzhalter `//@TITEL@`/`//@VARIANTEN@`/`//@BEFESTIGUNG@`/`//@SONSTIGES@` werden per `ssg-dcl-vorlage-fuellen` gefuellt, nicht direkt ladbar | +| `geruest_traeger.dcl` | VORLAGE fuer GERUEST_TRAEGER (GeruestInsert.lsp, `geruest-traeger-dialog`), Platzhalter `//@VARIANTEN@` | +| `fahrstrecke.dcl` | VORLAGE fuer OMNI_FAHRSTRECKE (GeruestInsert.lsp, `geruest-traeger-dialog`), gleiche Tile-Keys wie `geruest_traeger.dcl`, Platzhalter `//@VARIANTEN@` | | `dinformate.dcl` | DIN_FORMATE (DinFormate.lsp) | | `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` | diff --git a/Lisp/GeruestInsert.lsp b/Lisp/GeruestInsert.lsp index e38fde2..691a4d4 100644 --- a/Lisp/GeruestInsert.lsp +++ b/Lisp/GeruestInsert.lsp @@ -2,17 +2,22 @@ ;; GeruestInsert.lsp - Geruest-Baugruppen konfigurieren und einfuegen ;; ;; Liest data/json/geruest.json (rekursiv per ssg-json-laden), laesst den -;; Nutzer eine Basis-Variante, Anbauteile fuer "Befestigung oben" UND -;; "Befestigung unten" (je mit eigener Stueckzahl), Laenge und Farbe waehlen, -;; und fuegt das Ergebnis als Block GR__ ein. +;; Nutzer eine Basis-Variante, Anbauteile fuer die Befestigung (oben und +;; unten zusammen, Gesamtanzahl je Teil) und Sonstiges, Laenge und Farbe +;; waehlen, und fuegt das Ergebnis als Block GR__ ein. ;; Rohr-Geruest-Traeger (GERUEST_TRAEGER) lesen data/json/geruest_traeger.json. ;; -;; Beide Befestigungslisten enthalten ALLE Anbauteile der Baugruppe - dasselbe -;; Teil kann oben, unten oder gleichzeitig an beiden Positionen sitzen. +;; "anbaugruppen" hat zwei Listen: "befestigung" (eine Spalte "Befestigung +;; oben und unten", die Anzahl ist die Gesamtanzahl) und "sonstiges" (z.B. +;; Haltearme, eigene Zeile darunter; geruest-anbau-liste). Unter jedem Teil +;; zeigt der Dialog seine Artikelnummer(n). ;; -;; Die Dialogdefinition wird zur Laufzeit erzeugt (geruest-dcl-schreiben): -;; eine DCL-Liste kann keine Eingabefelder enthalten, ein Mengenfeld je Teil -;; ist also nur mit generierten Zeilen moeglich. +;; Das Dialog-Layout steht als Vorlage in dcl/geruest.dcl bzw. +;; dcl/geruest_traeger.dcl; nur die datenabhaengigen Bloecke (Radiobutton je +;; Variante, Mengenfeld + Ankreuzfeld je Anbauteil) werden zur Laufzeit an +;; //@NAME@-Platzhaltern eingesetzt (geruest-dcl-schreiben, +;; ssg-dcl-vorlage-fuellen) - DCL kann Tiles weder zur Laufzeit erzeugen noch +;; ausblenden. ;; ;; Konfigurationen kommen aus zwei getrennten Quellen: der gepflegten ;; Bibliothek in geruest.json und den eigenen in cfg/geruest_user.json. @@ -23,9 +28,10 @@ ;; die Dummy-DWG einen Tag nicht kennt (ssg-attrib-set-on schreibt nur Tags, ;; die als ATTDEF existieren). ;; -;; Zusaetzlich wird jede ausgewaehlte Artikelnummer (Basis, oben, unten, inkl. -;; aufgeloester Gruppen), fuer die data/geruest/.dwg existiert, einmal -;; bei 0,0,0 mit in den Block eingefuegt (geruest-teile-dwgs) - reine +;; Zusaetzlich wird jede ausgewaehlte Artikelnummer (Basis, oben, unten, +;; sonstiges, inkl. aufgeloester Gruppen), fuer die data/geruest/.dwg +;; existiert, einmal bei 0,0,0 mit in den Block eingefuegt (geruest-teile-dwgs, +;; Anbauteile im "Winkel Platte" gedreht) - reine ;; Geometrie als visuelle Rueckmeldung, die Attribute bleiben davon unberuehrt. ;; Teile ohne DWG werden still uebergangen. ;; @@ -37,13 +43,12 @@ ;; TEILEART-Attribut fuer ein Omniflo-Element (SSG_LIB_Commands.lsp). Der ;; Doppelklick-Dispatcher erkennt Geruest-Bloecke an diesem Praefix. ;; -;; Alle Bereiche liegen in EINEM Dialog; oben wird per Dropdown zwischen -;; Rohrabhaenger, Saeulen und Wandbefestigung umgeschaltet. DCL hat kein -;; Reiter-Tile, und da sich die Teilezeilen je Bereich unterscheiden, wird der -;; Dialog beim Wechsel geschlossen und neu aufgebaut - der Stand jedes -;; Bereichs bleibt dabei in *geruest-zustand* erhalten. +;; Jeder Bereich (Rohrabhaenger, Saeulen, Wandbefestigung) hat seinen eigenen +;; Menuebefehl und Dialog; eine Umschaltung im Dialog gibt es nicht. GERUEST +;; ohne Bereich zeigt nur einen Hinweis. ;; -;; Befehl: GERUEST +;; Befehle: GERUEST_SAEULEN, GERUEST_ROHRABHAENGER, GERUEST_WANDBEFESTIGUNG, +;; GERUEST_TRAEGER, GERUEST_TRAEGER_BESCHRIFTEN ;; ============================================================ (vl-load-com) @@ -149,21 +154,14 @@ (geruest-json-laden-cache "geruest_traeger.json" '*geruest-traeger-daten*) ) -;; Alle Baugruppen als ((id . objekt) ...) in Dateireihenfolge - diese -;; Reihenfolge bestimmt auch die Reihenfolge im Bereichs-Dropdown. Die -;; Traeger stehen in geruest_traeger.json und gehoeren nicht hierher. -(defun geruest-baugruppen-liste ( / erg) - (setq erg nil) - (foreach eintrag (geruest-daten) - (if (listp (cdr eintrag)) - (setq erg (append erg - (list (cons (ssg-json-get (cdr eintrag) "id") (cdr eintrag))))) - ) - ) - erg +;; Omniflo-Fahrstrecken (AP 110, APG 110, AP 60, ST, STL) - dieselbe +;; Linien-Logik wie der Traeger (Dialog, Laenge aus der Zeichnung, +;; Muffen-Checkbox, Beschriftung), aber eigene Datei und eigener Dialog. +(defun geruest-fahrstrecke-daten ( / ) + (geruest-json-laden-cache "omniflo_fahrstrecke.json" '*geruest-fahrstrecke-daten*) ) -;; Anzeigename einer Baugruppe fuer Dropdown und Kopfzeile. Bewusst das +;; Anzeigename einer Baugruppe fuer den Dialogtitel. Bewusst das ;; ASCII-Feld "titel" und nicht der aeussere JSON-Schluessel - der traegt ;; Umlaute ("Rohrabhänger", "Säulen"). (defun geruest-titel (bg / t1) @@ -183,6 +181,22 @@ (if (and w (/= w "")) w (ssg-json-get bg schluessel)) ) +;; Anbauteil-Liste einer Baugruppe. "anbaugruppen" ist ein Objekt mit zwei +;; Listen: "befestigung" (erscheint in den Spalten oben UND unten) und +;; "sonstiges" (eigene Zeile, z.B. Haltearme - weder oben noch unten). +;; schluessel = "befestigung" oder "sonstiges". Ein altes flaches Array gilt +;; als "befestigung". Unterscheidung: ein Objekt wird zur Alist mit +;; String-Schluesseln, ein Array von Objekten zur Liste von Alists. +(defun geruest-anbau-liste (bg schluessel / anb) + (setq anb (ssg-json-get bg "anbaugruppen")) + (cond + ((null anb) nil) + ((and (listp (car anb)) (= (type (car (car anb))) 'STR)) + (ssg-json-get anb schluessel)) + ((= schluessel "befestigung") anb) + ) +) + ;; Pfad der Dummy-DWG fuer den Block. Ein "dummy" in der Geometrie-Variante ;; wird bevorzugt; fehlt die Datei unter data/geruest, wird gemeldet und auf ;; den "dummy" der Baugruppe zurueckgefallen. Rueckgabe: (datei . pfad) - @@ -208,11 +222,12 @@ ) ) -;; Liste ohne die Eintraege, die (ohne Gross/Klein) gleich pfad sind. Damit -;; landet eine Teile-DWG, die zugleich der Dummy ist, nicht doppelt im Block. +;; Teile-Liste ((pfad . rot) ...) ohne die Eintraege, deren Pfad (ohne +;; Gross/Klein) gleich pfad ist. Damit landet eine Teile-DWG, die zugleich der +;; Dummy ist, nicht doppelt im Block. (defun geruest-ohne-pfad (pfad liste) (if pfad - (vl-remove-if '(lambda (p) (= (strcase p) (strcase pfad))) liste) + (vl-remove-if '(lambda (e) (= (strcase (car e)) (strcase pfad))) liste) liste ) ) @@ -316,6 +331,12 @@ (reverse erg) ) +;; Liste ohne die ersten n Elemente. +(defun geruest-rest-liste (lst n) + (repeat n (setq lst (cdr lst))) + lst +) + ;; Teile-DWGs zu einer Liste von Artikelnummern: data/geruest/.dwg, ;; soweit vorhanden. Jede Nummer nur einmal - alle Teile sitzen bei 0,0,0, ;; eine Mehrfach-Stueckzahl waere visuell nicht unterscheidbar. Fehlende @@ -332,6 +353,38 @@ (reverse erg) ) +;; Teile-DWGs mit Drehwinkel: ((pfad . rot) ...). Die Basis-Teile bleiben +;; ungedreht, die Anbauteile (oben/unten/sonstiges) bekommen den "Winkel +;; Platte" (Grad, Drehung um Z am Blockursprung). Ein Teil, das schon in der +;; Basis steckt, wird nicht ein zweites Mal als Anbauteil eingefuegt. +(defun geruest-teile-dwgs-rot (basis-pfade anbau-pfade winkel / erg) + (setq erg (mapcar '(lambda (p) (cons p 0.0)) basis-pfade)) + (foreach p anbau-pfade + (if (not (assoc p erg)) + (setq erg (append erg (list (cons p (float winkel))))) + ) + ) + erg +) + +;; "Winkel Platte" im Dialog: Tile-Index ("0"/"1") <-> Grad (0/90). +;; Konfigurationen speichern den echten Winkel, nicht den Listenindex. +(setq *geruest-winkel-werte* '(0 90)) + +(defun geruest-winkel-aus-index (idx-str / w) + (setq w (nth (atoi idx-str) *geruest-winkel-werte*)) + (if w w 0) +) + +(defun geruest-winkel-index (winkel / i idx) + (setq i 0 idx 0) + (foreach w *geruest-winkel-werte* + (if (and (numberp winkel) (equal (float w) (float winkel) 1e-6)) (setq idx i)) + (setq i (1+ i)) + ) + (itoa idx) +) + ;; ============================================================ ;; DIALOG @@ -479,47 +532,102 @@ ;; Listenindex einer Konfiguration im popup_list (0 = "", die ;; Konfigurationen beginnen deshalb bei 1). 0, wenn nicht gefunden. -(defun geruest-konfig-index (name / i idx) - (setq i 1 idx 0) +;; Eine eigene Konfiguration gewinnt vor einer gleichnamigen aus der +;; Bibliothek - gesucht wird nach dem Speichern, und gespeichert wird immer +;; eine eigene. +(defun geruest-konfig-index (name / i idx bib) + (setq i 1 idx 0 bib 0) (foreach k *geruest-konfig-liste* - (if (and (= idx 0) (equal (ssg-json-get (cdr k) "name") name)) - (setq idx i)) + (if (equal (ssg-json-get (cdr k) "name") name) + (if (car k) + (if (= idx 0) (setq idx i)) + (if (= bib 0) (setq bib i)))) (setq i (1+ i)) ) - idx + (if (> idx 0) idx bib) ) -;; Positionsliste ("oben"/"unten") einer Konfiguration auf die Anbauteile +;; Namensvorgabe beim Speichern: der Name der gewaehlten EIGENEN +;; Konfiguration (Enter ueberschreibt sie), sonst nil - die Bibliothek ist +;; schreibgeschuetzt. +(defun geruest-konfig-name-vorgabe (konfig-idx / k) + (setq k (if (> konfig-idx 0) (nth (1- konfig-idx) *geruest-konfig-liste*))) + (if (and k (car k)) (ssg-json-get (cdr k) "name")) +) + +;; Teileliste ("befestigung"/"sonstiges", in alten Konfigurationen auch +;; "oben"/"unten") einer Konfiguration auf die Anbauteile ;; abbilden. Rueckgabe: ein Eintrag je Anbauteil - nil (nicht gewaehlt) oder ;; die Anzahl (Feld "anzahl"). Ein unbekannter Artikelname wird gemeldet und ;; uebersprungen, statt die ganze Konfiguration scheitern zu lassen. -(defun geruest-konfig-position (konfig schluessel anbauteile / mengen idx n) +;; ausweich = Teileliste, deren Namen still uebersprungen werden (sie werden +;; von einem anderen Aufruf eingesammelt), oder T = nie melden. +(defun geruest-konfig-position (konfig schluessel anbauteile ausweich + / mengen idx n name) (setq mengen (geruest-nil-liste (length anbauteile))) (foreach e (ssg-json-get konfig schluessel) - (setq idx (geruest-name-index (ssg-json-get e "artikel") anbauteile)) - (if idx - (progn + (setq name (ssg-json-get e "artikel")) + (setq idx (geruest-name-index name anbauteile)) + (cond + (idx (setq n (ssg-json-get e "anzahl")) (setq mengen (geruest-liste-setzen mengen idx (if (and n (numberp n) (> n 0)) (fix n) 1))) ) - (princ (ssg-textf "gr-konfig-teil-unbekannt" - (list (ssg-json-get e "artikel") - (ssg-json-get konfig "name")))) + ((or (= ausweich T) (geruest-name-index name ausweich)) nil) + (T + (princ (ssg-textf "gr-konfig-teil-unbekannt" + (list name (ssg-json-get konfig "name"))))) ) ) mengen ) +;; Zwei Mengenlisten (nil oder Zahl je Teil) elementweise addieren. +(defun geruest-mengen-addieren (a b) + (mapcar '(lambda (x y) + (cond ((and x y) (+ x y)) (x x) (y y))) + a b) +) + +;; Befestigungs-Mengen einer Konfiguration (Gesamtanzahl je Teil). Aeltere +;; Konfigurationen fuehren die Befestigung getrennt unter "oben"/"unten" - +;; deren Mengen werden addiert; beim naechsten Speichern steht alles unter +;; "befestigung". Sonstiges-Teile werden hier still uebergangen (die sammelt +;; geruest-konfig-sonstiges ein). +(defun geruest-konfig-befestigung (konfig befestigung sonstiges) + (geruest-mengen-addieren + (geruest-konfig-position konfig "befestigung" befestigung sonstiges) + (geruest-mengen-addieren + (geruest-konfig-position konfig "oben" befestigung sonstiges) + (geruest-konfig-position konfig "unten" befestigung sonstiges))) +) + +;; Sonstiges-Mengen einer Konfiguration. Aeltere Konfigurationen kennen keine +;; Sonstiges-Liste und fuehren solche Teile (z.B. einen Haltearm) unter +;; "oben"/"unten"/"befestigung" - die werden hier still mit eingesammelt; +;; beim naechsten Speichern stehen sie dann unter "sonstiges". +(defun geruest-konfig-sonstiges (konfig sonstiges befestigung) + (geruest-mengen-addieren + (geruest-konfig-position konfig "sonstiges" sonstiges befestigung) + (geruest-mengen-addieren + (geruest-konfig-position konfig "befestigung" sonstiges T) + (geruest-mengen-addieren + (geruest-konfig-position konfig "oben" sonstiges T) + (geruest-konfig-position konfig "unten" sonstiges T)))) +) + ;; ============================================================ ;; DIALOGDEFINITION ERZEUGEN ;; ============================================================ -;; Die Anbauteil-Zeilen haengen an der Baugruppe, deshalb wird die DCL-Datei -;; pro Aufruf geschrieben statt fest vorgehalten: DCL kann weder Dateien -;; einbinden noch Tiles zur Laufzeit erzeugen, und eine Liste (list_box) kann -;; keine Eingabefelder enthalten - ohne Generierung gaebe es also kein -;; Mengenfeld je Teil. +;; Das Layout steht als Vorlage in dcl/geruest.dcl bzw. dcl/geruest_traeger.dcl. +;; Hier entstehen nur die datenabhaengigen Bloecke, die ssg-dcl-vorlage-fuellen +;; (ssg_core.lsp) an den //@NAME@-Platzhaltern einsetzt: ein Radiobutton je +;; Variante und Mengenfeld + Ankreuzfeld je Anbauteil. DCL kann weder Tiles +;; zur Laufzeit erzeugen noch ausblenden, Radiobutton-Labels lassen sich per +;; set_tile nicht aendern, und eine list_box kann keine Eingabefelder +;; enthalten. ;; Ein Anfuehrungszeichen im Artikelnamen wuerde das DCL-Label vorzeitig ;; beenden und die erzeugte Datei unbrauchbar machen (fuenf Bezeichnungen @@ -536,9 +644,104 @@ erg ) -;; Eine Befestigungsspalte. Das Mengenfeld steht LINKS vom Ankreuzfeld: die -;; Eingabefelder sind dadurch alle gleich breit und die Teilenamen beginnen -;; auf gleicher Hoehe - DCL richtet Zeileninhalte nicht von sich aus aus. +;; Pfad einer DCL-Vorlage unter DXFM_DCL bzw. DXFMAKRO/dcl, oder nil. +(defun geruest-dcl-vorlage-pfad (datei / basis) + (setq basis (cond ((getenv "DXFM_DCL")) + ((getenv "DXFMAKRO") (strcat (getenv "DXFMAKRO") "/dcl")))) + (if basis + (strcat (vl-string-translate "\\" "/" basis) "/" datei) + ) +) + +;; Radiobutton-Keys der Varianten: "v", i = Index in geometrie_varianten. +;; get_tile auf der radio_column liefert den Key des gewaehlten Buttons. +(defun geruest-radio-key (i) (strcat "v" (itoa i))) + +(defun geruest-radio-index (key) + (if (and key (> (strlen key) 1)) (atoi (substr key 2)) 0) +) + +;; (0 1 ... n-1) +(defun geruest-indizes (n / i erg) + (setq i (1- n) erg nil) + (while (>= i 0) (setq erg (cons i erg) i (1- i))) + erg +) + +;; Beschriftung einer Variante im Dialog: Name und dahinter die enthaltenen +;; Artikelnummern in Klammern, z.B. "R 2\" (821006051, 821004201)". Ohne +;; Nummern nur der Name. +(defun geruest-varianten-label (variante / nr) + (setq nr (geruest-artnr-anzeige variante)) + (if (/= nr "") + (strcat (geruest-eintrag-name variante) " (" nr ")") + (geruest-eintrag-name variante) + ) +) + +;; Gesperrte Varianten: "disabled": true in der JSON. Sie erscheinen im +;; Dialog ausgegraut (mode_tile) und sind nicht waehlbar - so laesst sich eine +;; Variante aus dem Angebot nehmen, ohne sie zu loeschen (Konfigurationen und +;; GERUEST_TRAEGER_BESCHRIFTEN finden sie weiter ueber den Namen). +(defun geruest-variante-gesperrt-p (variante) + (if (ssg-json-get variante "disabled") T nil) +) + +;; Index der ersten nicht gesperrten Variante; 0, wenn alle gesperrt sind. +(defun geruest-erste-freie-variante (varianten / i idx) + (setq i 0 idx nil) + (foreach v varianten + (if (and (null idx) (not (geruest-variante-gesperrt-p v))) (setq idx i)) + (setq i (1+ i)) + ) + (if idx idx 0) +) + +;; Gueltiger Varianten-Index fuer die Vorauswahl: idx selbst, wenn er +;; existiert und nicht gesperrt ist, sonst die erste freie Variante. +(defun geruest-variante-waehlbar (varianten idx) + (if (and idx (>= idx 0) (< idx (length varianten)) + (not (geruest-variante-gesperrt-p (nth idx varianten)))) + idx + (geruest-erste-freie-variante varianten) + ) +) + +;; Radiobuttons gesperrter Varianten ausgrauen (im laufenden Dialog). +(defun geruest-varianten-sperren (varianten / i) + (setq i 0) + (foreach v varianten + (if (geruest-variante-gesperrt-p v) (mode_tile (geruest-radio-key i) 1)) + (setq i (1+ i)) + ) +) + +;; Ein Radiobutton je Variante aus idx-liste (Indizes in varianten). +(defun geruest-dcl-varianten-zeilen (varianten idx-liste / erg) + (setq erg nil) + (foreach i idx-liste + (setq erg (append erg + (list (strcat " : radio_button { key = \"" (geruest-radio-key i) + "\"; label = \"" + (geruest-dcl-label (geruest-varianten-label (nth i varianten))) + "\"; }")))) + ) + erg +) + +;; Artikelnummer(n) eines Anbauteils fuer die Anzeige im Dialog: Einzelteil +;; -> seine sivas_id, Gruppe -> die Nummern ihrer Teile, jede nur einmal +;; (die Stueckzahl steckt in ARTINR, nicht in der Anzeige). +(defun geruest-artnr-anzeige (eintrag) + (ssg-join (geruest-eindeutig (geruest-artikelnummern eintrag)) ", ") +) + +;; Eine Anbauteil-Spalte als DCL-Zeilen. Je Teil: Mengenfeld LINKS, rechts +;; daneben Ankreuzfeld mit dem Teilenamen und darunter eine Textzeile mit der +;; Artikelnummer (DCL kennt keine Schriftgroesse - die Nummer steht darum in +;; normaler Groesse in einer eigenen Zeile). Das Mengenfeld links haelt die +;; Eingabefelder gleich breit und laesst die Teilenamen auf gleicher Hoehe +;; beginnen - DCL richtet Zeileninhalte nicht von sich aus aus. ;; ;; Zwei DCL-Eigenheiten muessen dafuer gesetzt werden: ;; - alignment = left, weil DCL Tiles in einer Spalte sonst ZENTRIERT: bei @@ -549,76 +752,60 @@ ;; klaffte dadurch eine wechselnd grosse Luecke. Mit fixed_width wird die ;; Zeile nur so breit wie ihr Inhalt, das Ankreuzfeld sitzt also direkt am ;; Mengenfeld. -(defun geruest-dcl-spalte (f anbauteile prefix titel / i) - (write-line " : boxed_column {" f) - (write-line (strcat " label = \"" titel "\";") f) - (write-line " alignment = left;" f) +(defun geruest-dcl-spalte (anbauteile prefix titel / i erg) + (setq erg (list " : boxed_column {" + (strcat " label = \"" titel "\";") + " alignment = left;")) (setq i 0) (foreach a anbauteile - (write-line " : row {" f) - (write-line " alignment = left;" f) - (write-line " fixed_width = true;" f) - (write-line (strcat " : edit_box { key = \"" prefix "m" (itoa i) - "\"; label = \"\"; edit_width = 3;" - " fixed_width = true; }") f) - (write-line (strcat " : toggle { key = \"" prefix (itoa i) - "\"; label = \"" - (geruest-dcl-label (geruest-eintrag-name a)) - "\"; fixed_width = true; }") f) - (write-line " }" f) + (setq erg (append erg + (list " : row {" + " alignment = left;" + " fixed_width = true;" + (strcat " : edit_box { key = \"" prefix "m" (itoa i) + "\"; label = \"\"; edit_width = 3; fixed_width = true; }") + " : column {" + " alignment = left;" + (strcat " : toggle { key = \"" prefix (itoa i) + "\"; label = \"" + (geruest-dcl-label (geruest-eintrag-name a)) + "\"; fixed_width = true; }") + (strcat " : text { label = \"Art.-Nr. " + (geruest-dcl-label (geruest-artnr-anzeige a)) + "\"; }") + " }" + " }"))) (setq i (1+ i)) ) - (write-line " }" f) + (append erg (list " }")) ) -;; Rueckgabe: Pfad der temporaeren DCL-Datei oder nil. -(defun geruest-dcl-schreiben (anbauteile / pfad f) - (setq pfad (vl-filename-mktemp "geruest" nil ".dcl")) - (setq f (open pfad "w")) - (if (null f) - nil - (progn - (write-line "geruest : dialog {" f) - (write-line " label = \"Geruest-Baugruppe konfigurieren\";" f) - ;; Bereichswechsel (Rohrabhaenger/Saeulen/Wandbefestigung). DCL hat kein - ;; Reiter-Tile, deshalb ein Dropdown; sein Rueckruf schliesst den Dialog - ;; und die Schleife baut ihn mit dem neuen Bereich neu auf - die - ;; Teilezeilen unterscheiden sich je Bereich und lassen sich zur - ;; Laufzeit nicht austauschen. - (write-line " : popup_list { key = \"bereich\"; label = \"Bereich:\"; width = 30; }" f) - (write-line " : text { key = \"kopf\"; label = \"\"; width = 64; }" f) - (write-line " : row {" f) - (write-line " : popup_list { key = \"konfig\"; label = \"Konfiguration:\"; width = 40; }" f) - (write-line " : button { key = \"kspeichern\"; label = \"Speichern...\"; fixed_width = true; }" f) - (write-line " : button { key = \"kloeschen\"; label = \"Loeschen\"; fixed_width = true; }" f) - (write-line " }" f) - (write-line " : boxed_column {" f) - (write-line " label = \"Basis\";" f) - (write-line " : popup_list { key = \"variante\"; label = \"Variante:\"; width = 56; }" f) - (write-line " : row {" f) - (write-line " : edit_box { key = \"laenge\"; label = \"Laenge (mm):\"; edit_width = 10; }" f) - (write-line " : popup_list { key = \"farbe\"; label = \"Farbe:\"; width = 25; }" f) - (write-line " : edit_box { key = \"farbe_frei\"; label = \"eigene:\"; edit_width = 12; }" f) - (write-line " }" f) - (write-line " }" f) - ;; Ohne Anbauteile bleiben die Spalten weg - ein leerer Cluster ist - ;; in DCL nicht zulaessig (betrifft z.B. die 1-Zoll-Saeule). - (if (> (length anbauteile) 0) - (progn - (write-line " : row {" f) - (geruest-dcl-spalte f anbauteile "o" "Befestigung oben (Anzahl / Teil)") - (geruest-dcl-spalte f anbauteile "u" "Befestigung unten (Anzahl / Teil)") - (write-line " }" f) - ) - ) - (write-line " ok_cancel;" f) - (write-line "}" f) - (close f) - pfad - ) +;; Ersetzungen fuer dcl/geruest.dcl. Ohne Teile entfallen die Blocks ganz - +;; ein leerer Cluster ist in DCL nicht zulaessig (z.B. Wandbefestigung ohne +;; Sonstiges). +(defun geruest-dcl-ersetzungen (titel anbauteile sonstiges varianten) + (list + (cons "TITEL" + (list (strcat " label = \"" (geruest-dcl-label (ssg-textf "gr-dlg-kopf" (list titel))) + "\";"))) + (cons "VARIANTEN" + (geruest-dcl-varianten-zeilen varianten (geruest-indizes (length varianten)))) + (cons "BEFESTIGUNG" + (if anbauteile + (geruest-dcl-spalte anbauteile "b" + "Befestigung oben und unten (Anzahl / Teil)"))) + (cons "SONSTIGES" + (if sonstiges + (geruest-dcl-spalte sonstiges "s" "Sonstiges (Anzahl / Teil)"))) ) ) +;; Rueckgabe: Pfad der gefuellten temporaeren DCL-Datei oder nil. +(defun geruest-dcl-schreiben (titel anbauteile sonstiges varianten) + (ssg-dcl-vorlage-fuellen (geruest-dcl-vorlage-pfad "geruest.dcl") "geruest" + (geruest-dcl-ersetzungen titel anbauteile sonstiges varianten)) +) + ;; ============================================================ ;; DIALOGZUSTAND @@ -629,20 +816,21 @@ ;; Dialogfunktion aus, auf deren Locals kaeme er nicht. ;; Ausgangszustand einer Spalte: nichts angehakt, Mengenfeld mit der -;; JSON-Vorgabe vorbelegt (beim Klemmring also 2). -(defun geruest-dlg-standard ( / erg) +;; JSON-Vorgabe vorbelegt (beim Klemmring also 2). teile = Anbauteile der +;; Spalte (befestigung oder sonstiges). +(defun geruest-dlg-standard (teile / erg) (setq erg nil) - (foreach a *geruest-anbauteile* + (foreach a teile (setq erg (append erg (list (cons "0" (itoa (geruest-anzahl-vorgabe a)))))) ) erg ) ;; Mengenliste (nil oder Zahl je Teil) in den Tile-Zustand umsetzen. -(defun geruest-anzahlen->tiles (mengen / erg i a) +(defun geruest-anzahlen->tiles (mengen teile / erg i a) (setq erg nil i 0) (foreach m mengen - (setq a (nth i *geruest-anbauteile*)) + (setq a (nth i teile)) (setq erg (append erg (list (if m (cons "1" (itoa m)) @@ -652,46 +840,65 @@ erg ) -(defun geruest-dlg-lesen ( / i n) - (setq *geruest-dlg-variante* (get_tile "variante")) +;; Tile-Zustand einer Spalte lesen: ((haken . menge) ...) je Teil. +;; prefix = "b"/"s" (Tile-Keys i und mi). +(defun geruest-dlg-spalte-lesen (prefix teile / i n erg) + (setq n (length teile) i 0 erg nil) + (while (< i n) + (setq erg (append erg + (list (cons (get_tile (strcat prefix (itoa i))) + (get_tile (strcat prefix "m" (itoa i))))))) + (setq i (1+ i)) + ) + erg +) + +(defun geruest-dlg-spalte-schreiben (prefix zustand / i) + (setq i 0) + (foreach paar zustand + (set_tile (strcat prefix (itoa i)) (car paar)) + (set_tile (strcat prefix "m" (itoa i)) (cdr paar)) + (setq i (1+ i)) + ) +) + +;; Tile-Keys einer Spalte (Haken und Mengenfeld je Teil) fuer action_tile. +(defun geruest-dlg-spalten-keys (prefix teile / i erg) + (setq i 0 erg nil) + (foreach a teile + (setq erg (append erg (list (strcat prefix (itoa i)) + (strcat prefix "m" (itoa i))))) + (setq i (1+ i)) + ) + erg +) + +(defun geruest-dlg-lesen ( / ) + ;; radio_column liefert den Key des gewaehlten Buttons ("v"); der + ;; Zustand fuehrt weiter den Index als String. + (setq *geruest-dlg-variante* + (itoa (geruest-radio-index (get_tile "variante")))) + (setq *geruest-dlg-winkel* (get_tile "winkel")) + (if (= *geruest-dlg-winkel* "") (setq *geruest-dlg-winkel* "0")) (setq *geruest-dlg-laenge* (get_tile "laenge")) (setq *geruest-dlg-farbe* (get_tile "farbe")) (setq *geruest-dlg-frei* (get_tile "farbe_frei")) (setq *geruest-dlg-konfig* (get_tile "konfig")) - (setq *geruest-dlg-bereich* (get_tile "bereich")) - (setq n (length *geruest-anbauteile*) i 0) - (setq *geruest-dlg-oben* nil *geruest-dlg-unten* nil) - (while (< i n) - (setq *geruest-dlg-oben* - (append *geruest-dlg-oben* - (list (cons (get_tile (strcat "o" (itoa i))) - (get_tile (strcat "om" (itoa i))))))) - (setq *geruest-dlg-unten* - (append *geruest-dlg-unten* - (list (cons (get_tile (strcat "u" (itoa i))) - (get_tile (strcat "um" (itoa i))))))) - (setq i (1+ i)) - ) + (setq *geruest-dlg-bef* (geruest-dlg-spalte-lesen "b" *geruest-anbauteile*)) + (setq *geruest-dlg-sonst* (geruest-dlg-spalte-lesen "s" *geruest-sonstiges*)) (princ) ) -(defun geruest-dlg-schreiben ( / i n paar) - (set_tile "variante" *geruest-dlg-variante*) +(defun geruest-dlg-schreiben ( / ) + (set_tile "variante" (geruest-radio-key (atoi *geruest-dlg-variante*))) (set_tile "laenge" *geruest-dlg-laenge*) ;; Nur setzen, wenn die Liste ueberhaupt gefuellt ist - ein Index auf eine ;; leere popup_list ist nicht definiert (Baugruppen ohne attribute-Block). (if *geruest-farb-liste* (set_tile "farbe" *geruest-dlg-farbe*)) (set_tile "farbe_frei" *geruest-dlg-frei*) - (setq n (length *geruest-anbauteile*) i 0) - (while (< i n) - (setq paar (nth i *geruest-dlg-oben*)) - (set_tile (strcat "o" (itoa i)) (car paar)) - (set_tile (strcat "om" (itoa i)) (cdr paar)) - (setq paar (nth i *geruest-dlg-unten*)) - (set_tile (strcat "u" (itoa i)) (car paar)) - (set_tile (strcat "um" (itoa i)) (cdr paar)) - (setq i (1+ i)) - ) + (set_tile "winkel" *geruest-dlg-winkel*) + (geruest-dlg-spalte-schreiben "b" *geruest-dlg-bef*) + (geruest-dlg-spalte-schreiben "s" *geruest-dlg-sonst*) (princ) ) @@ -736,12 +943,15 @@ ;; Konfiguration anwenden und die Tiles nachziehen. Wird direkt aus dem ;; popup_list-Rueckruf aufgerufen - set_tile aendert die Anzeige im laufenden ;; Dialog, ein Neuaufbau ist nicht noetig. Index 0 = "(keine)". +;; Danach wird der Stand als Vergleichsbasis gemerkt +;; (*geruest-dlg-konfig-basis*), damit eine spaetere Aenderung erkennbar ist. (defun geruest-dlg-konfig-waehlen (idx / k vidx farbe fidx) (setq *geruest-dlg-konfig* (itoa idx)) (if (<= idx 0) (progn - (setq *geruest-dlg-oben* (geruest-dlg-standard)) - (setq *geruest-dlg-unten* (geruest-dlg-standard)) + (setq *geruest-dlg-winkel* "0") + (setq *geruest-dlg-bef* (geruest-dlg-standard *geruest-anbauteile*)) + (setq *geruest-dlg-sonst* (geruest-dlg-standard *geruest-sonstiges*)) ) (progn (setq k (nth (1- idx) *geruest-konfig-liste*)) @@ -750,11 +960,17 @@ (setq k (cdr k)) (setq vidx (geruest-name-index (ssg-json-get k "variante") *geruest-varianten*)) - (if vidx - (setq *geruest-dlg-variante* (itoa vidx)) - (princ (ssg-textf "gr-konfig-variante-unbekannt" - (list (ssg-json-get k "variante") - (ssg-json-get k "name")))) + (cond + ((null vidx) + (princ (ssg-textf "gr-konfig-variante-unbekannt" + (list (ssg-json-get k "variante") + (ssg-json-get k "name"))))) + ;; gesperrte Variante: Auswahl bleibt, wie sie ist + ((geruest-variante-gesperrt-p (nth vidx *geruest-varianten*)) + (princ (ssg-textf "gr-konfig-variante-gesperrt" + (list (ssg-json-get k "variante") + (ssg-json-get k "name"))))) + (T (setq *geruest-dlg-variante* (itoa vidx))) ) (setq *geruest-dlg-laenge* (geruest-zahl-string (ssg-json-get k "laenge"))) @@ -769,12 +985,17 @@ (setq *geruest-dlg-farbe* (itoa *geruest-frei-idx*) *geruest-dlg-frei* farbe)) ) - (setq *geruest-dlg-oben* + (setq *geruest-dlg-bef* (geruest-anzahlen->tiles - (geruest-konfig-position k "oben" *geruest-anbauteile*))) - (setq *geruest-dlg-unten* + (geruest-konfig-befestigung k *geruest-anbauteile* *geruest-sonstiges*) + *geruest-anbauteile*)) + (setq *geruest-dlg-sonst* (geruest-anzahlen->tiles - (geruest-konfig-position k "unten" *geruest-anbauteile*))) + (geruest-konfig-sonstiges k *geruest-sonstiges* *geruest-anbauteile*) + *geruest-sonstiges*)) + ;; Fehlt in aelteren Konfigurationen -> 0 Grad + (setq *geruest-dlg-winkel* + (geruest-winkel-index (ssg-json-get k "winkel_platte"))) ) ) ) @@ -782,9 +1003,70 @@ (geruest-dlg-schreiben) (mode_tile "farbe_frei" (if (= (atoi *geruest-dlg-farbe*) *geruest-frei-idx*) 0 1)) + ;; Erst NACH dem Schreiben lesen: der Vergleichsstand soll genau das sein, + ;; was die Tiles zeigen (z.B. ein vom Dialog normalisiertes Mengenfeld). + (geruest-dlg-lesen) + (setq *geruest-dlg-konfig-basis* + (if (> idx 0) (geruest-dlg-record ""))) + (geruest-dlg-konfig-anzeigen) (princ) ) +;; Zwei Konfigurations-Records ohne Beachtung des Namens vergleichen. +(defun geruest-record-ohne-name (r) + (vl-remove-if '(lambda (e) (equal (car e) "name")) r) +) + +(defun geruest-record-gleich-p (a b) + (equal (geruest-record-ohne-name a) (geruest-record-ohne-name b)) +) + +;; T, wenn eine Konfiguration gewaehlt ist und der aktuelle Stand von ihr +;; abweicht. Bewusst ein Vergleich und kein "geaendert"-Flag: wer eine +;; Aenderung zuruecknimmt, hat wieder den Stand der Konfiguration. +(defun geruest-dlg-geaendert-p ( / ) + (and *geruest-dlg-konfig-basis* + (> (atoi *geruest-dlg-konfig*) 0) + (not (geruest-record-gleich-p *geruest-dlg-konfig-basis* + (geruest-dlg-record "")))) +) + +;; Konfig-Liste und Statuszeile nachziehen: der gewaehlte Eintrag bekommt bei +;; Abweichung den Zusatz "(geaendert)", die Statuszeile sagt, was Speichern +;; tut (eigene Konfiguration -> ueberschreiben, Bibliothek -> neuer Name). +(defun geruest-dlg-konfig-anzeigen ( / idx i k geaendert) + (setq idx (atoi *geruest-dlg-konfig*)) + (setq geaendert (geruest-dlg-geaendert-p)) + (start_list "konfig") + (add_list (ssg-text "gr-konfig-keine")) + (setq i 1) + (foreach k *geruest-konfig-liste* + (add_list (if (and geaendert (= i idx)) + (ssg-textf "gr-konfig-geaendert" (list (geruest-konfig-name k))) + (geruest-konfig-name k))) + (setq i (1+ i)) + ) + (end_list) + (set_tile "konfig" *geruest-dlg-konfig*) + (setq k (if (> idx 0) (nth (1- idx) *geruest-konfig-liste*))) + (set_tile "kstatus" + (cond + ((not geaendert) "") + ((car k) (ssg-textf "gr-konfig-status-geaendert" + (list (ssg-json-get (cdr k) "name")))) + (T (ssg-textf "gr-konfig-status-bibliothek" + (list (ssg-json-get (cdr k) "name")))) + ) + ) + (princ) +) + +;; Rueckruf aller Eingabe-Tiles: Stand lesen und Kennzeichnung nachziehen. +(defun geruest-dlg-aenderung-pruefen ( / ) + (geruest-dlg-lesen) + (geruest-dlg-konfig-anzeigen) +) + (defun geruest-name-farbindex (wert / i idx) (setq i 0 idx nil) (foreach f *geruest-farb-liste* @@ -798,10 +1080,10 @@ ;; Rueckgabe: (T . ((index . anzahl) ...)) oder nil bei ungueltigem Mengenfeld. ;; Das fuehrende T ist noetig, weil "nichts ausgewaehlt" ein gueltiges ;; Ergebnis ist und sich sonst nicht von einem Fehler unterscheiden liesse. -(defun geruest-anzahlen-lesen (zustand / erg i a m ok) +(defun geruest-anzahlen-lesen (zustand teile / erg i a m ok) (setq erg nil i 0 ok T) (foreach paar zustand - (setq a (nth i *geruest-anbauteile*)) + (setq a (nth i teile)) (if (and ok (= (car paar) "1")) (progn (setq m (geruest-anzahl-wert (cdr paar) (geruest-anzahl-vorgabe a))) @@ -827,15 +1109,16 @@ (nth (atoi *geruest-dlg-variante*) *geruest-varianten*))) (cons "laenge" *geruest-dlg-laenge*) (cons "teilefarbe" (geruest-dlg-farbwert)) - (cons "oben" (geruest-dlg-teile *geruest-dlg-oben*)) - (cons "unten" (geruest-dlg-teile *geruest-dlg-unten*)) + (cons "befestigung" (geruest-dlg-teile *geruest-dlg-bef* *geruest-anbauteile*)) + (cons "sonstiges" (geruest-dlg-teile *geruest-dlg-sonst* *geruest-sonstiges*)) + (cons "winkel_platte" (geruest-winkel-aus-index *geruest-dlg-winkel*)) ) ) -(defun geruest-dlg-teile (zustand / erg i a m) +(defun geruest-dlg-teile (zustand teile / erg i a m) (setq erg nil i 0) (foreach paar zustand - (setq a (nth i *geruest-anbauteile*)) + (setq a (nth i teile)) (if (= (car paar) "1") (progn (setq m (geruest-anzahl-wert (cdr paar) (geruest-anzahl-vorgabe a))) @@ -891,11 +1174,14 @@ (ssg-json-get k "laenge"))) "\",") f) (write-line (strcat " \"teilefarbe\": \"" (ssg-json-escape (ssg-json-get k "teilefarbe")) "\",") f) - (write-line " \"oben\": [" f) - (geruest-teile-schreiben f (ssg-json-get k "oben")) + (write-line (strcat " \"winkel_platte\": " + (itoa (fix (if (numberp (ssg-json-get k "winkel_platte")) + (ssg-json-get k "winkel_platte") 0))) ",") f) + (write-line " \"befestigung\": [" f) + (geruest-teile-schreiben f (ssg-json-get k "befestigung")) (write-line " ]," f) - (write-line " \"unten\": [" f) - (geruest-teile-schreiben f (ssg-json-get k "unten")) + (write-line " \"sonstiges\": [" f) + (geruest-teile-schreiben f (ssg-json-get k "sonstiges")) (write-line " ]" f) (write-line (if (< i n) " }," " }") f) ) @@ -983,45 +1269,22 @@ ) ) -;; Dialogzustand eines Bereichs sichern bzw. zurueckholen, damit ein -;; Bereichswechsel die Eingaben nicht verwirft. -(defun geruest-zustand-sichern (id) - (setq *geruest-zustand* - (geruest-alist-setzen *geruest-zustand* id - (list *geruest-dlg-variante* *geruest-dlg-laenge* *geruest-dlg-farbe* - *geruest-dlg-frei* *geruest-dlg-konfig* - *geruest-dlg-oben* *geruest-dlg-unten*))) -) - -;; Rueckgabe T, wenn ein passender Zustand gefunden und gesetzt wurde. Die -;; Laengenpruefung faengt den Fall ab, dass die Datendatei zwischen zwei -;; Aufrufen geaendert wurde und die Teilezahl nicht mehr passt. -(defun geruest-zustand-laden (id / z) - (setq z (cdr (assoc id *geruest-zustand*))) - (if (and z (= (length (nth 5 z)) (length *geruest-anbauteile*))) - (progn - (setq *geruest-dlg-variante* (nth 0 z) - *geruest-dlg-laenge* (nth 1 z) - *geruest-dlg-farbe* (nth 2 z) - *geruest-dlg-frei* (nth 3 z) - *geruest-dlg-konfig* (nth 4 z) - *geruest-dlg-oben* (nth 5 z) - *geruest-dlg-unten* (nth 6 z)) - T - ) - ) -) - ;; Dialog fuer einen Bereich zeigen. Rueckgabe: -;; ("OK" variante-index ((idx . anzahl) ...) ((idx . anzahl) ...) laenge farbe) -;; - drittes Element = Befestigung oben, viertes = unten -;; ("WECHSEL" bereich-index) - Nutzer hat den Bereich umgestellt +;; ("OK" variante-index befestigung laenge farbe sonstiges winkel) +;; - befestigung/sonstiges je ((idx . anzahl) ...) in +;; anbaugruppen.befestigung bzw. anbaugruppen.sonstiges; die Anzahl der +;; Befestigung ist die GESAMTanzahl (oben und unten zusammen). +;; - winkel = "Winkel Platte" in Grad (0/90) fuer die Anbauteile. ;; nil - abgebrochen -(defun geruest-dialog (bg bereich-idx bereiche / dcl-pfad dat attr laenge-def +;; Jeder Bereich hat seinen eigenen Menuebefehl; eine Umschaltung im Dialog +;; gibt es nicht (DCL kennt keine Reiter). Der Dialogstand beginnt je Aufruf frisch. +(defun geruest-dialog (bg / dcl-pfad dat attr laenge-def farb-opts min-l max-l fertig rueckgabe - ergebnis wert-l oben-m unten-m name neu-idx) + ergebnis wert-l bef-m sonst-m name + vorgabe tile) (setq *geruest-varianten* (ssg-json-get bg "geometrie_varianten")) - (setq *geruest-anbauteile* (ssg-json-get bg "anbaugruppen")) + (setq *geruest-anbauteile* (geruest-anbau-liste bg "befestigung")) + (setq *geruest-sonstiges* (geruest-anbau-liste bg "sonstiges")) (setq attr (ssg-json-get bg "attribute")) (setq laenge-def (if attr (ssg-json-get attr "LAENGE"))) (setq farb-opts (if attr (ssg-json-get attr "TEILEFARBE"))) @@ -1031,22 +1294,21 @@ (geruest-farb-liste-setzen farb-opts) (setq *geruest-konfig-liste* (geruest-konfigs bg)) - ;; Frueheren Stand dieses Bereichs wiederherstellen, sonst Ausgangszustand - (if (null (geruest-zustand-laden (ssg-json-get bg "id"))) - (progn - (setq *geruest-dlg-variante* "0" *geruest-dlg-laenge* "" - *geruest-dlg-farbe* "0" *geruest-dlg-frei* "" - *geruest-dlg-konfig* "0") - (setq *geruest-dlg-oben* (geruest-dlg-standard)) - (setq *geruest-dlg-unten* (geruest-dlg-standard)) - ) - ) + ;; Ausgangszustand + (setq *geruest-dlg-variante* (itoa (geruest-erste-freie-variante *geruest-varianten*)) + *geruest-dlg-laenge* "" + *geruest-dlg-farbe* "0" *geruest-dlg-frei* "" + *geruest-dlg-konfig* "0" *geruest-dlg-winkel* "0" + *geruest-dlg-konfig-basis* nil) + (setq *geruest-dlg-bef* (geruest-dlg-standard *geruest-anbauteile*)) + (setq *geruest-dlg-sonst* (geruest-dlg-standard *geruest-sonstiges*)) (setq fertig nil rueckgabe nil) - ;; Die Dialogdefinition haengt nur an der Teileliste, nicht am Zustand - - ;; einmal erzeugen und erst nach der Schleife loeschen (unload_dialog muss - ;; vorher gelaufen sein). - (setq dcl-pfad (geruest-dcl-schreiben *geruest-anbauteile*)) + ;; Die Dialogdefinition haengt nur an Varianten und Teilelisten, nicht am + ;; Zustand - einmal aus der Vorlage fuellen und erst nach der Schleife + ;; loeschen (unload_dialog muss vorher gelaufen sein). + (setq dcl-pfad (geruest-dcl-schreiben (geruest-titel bg) *geruest-anbauteile* + *geruest-sonstiges* *geruest-varianten*)) ;; Schleife: ungueltige Eingaben, Speichern und Loeschen zeigen den Dialog ;; mit dem bisherigen Stand erneut (Projektmuster, vgl. vf_linienzug). @@ -1058,23 +1320,6 @@ (setq fertig T) ) (progn - (start_list "bereich") - (foreach b bereiche (add_list (geruest-titel (cdr b)))) - (end_list) - (set_tile "bereich" (itoa bereich-idx)) - - (set_tile "kopf" (ssg-textf "gr-dlg-kopf" (list (geruest-titel bg)))) - - (start_list "konfig") - (add_list (ssg-text "gr-konfig-keine")) - (foreach k *geruest-konfig-liste* (add_list (geruest-konfig-name k))) - (end_list) - (set_tile "konfig" *geruest-dlg-konfig*) - - (start_list "variante") - (foreach v *geruest-varianten* (add_list (geruest-eintrag-name v))) - (end_list) - (if *geruest-farb-liste* (progn (start_list "farbe") @@ -1083,8 +1328,20 @@ ) ) + (start_list "winkel") + (foreach w *geruest-winkel-werte* + (add_list (ssg-textf "gr-winkel-grad" (list (itoa w) (chr 176))))) + (end_list) + ;; Alle Tiles aus dem Zustand fuellen (auch Haken und Mengenfelder) (geruest-dlg-schreiben) + (geruest-varianten-sperren *geruest-varianten*) + ;; Konfig-Liste inkl. "(geaendert)"-Kennzeichnung und Statuszeile - + ;; auch nach Speichern/Loeschen/Fehler-Neuaufbau aktuell + (geruest-dlg-konfig-anzeigen) + ;; Der Winkel wirkt nur auf Anbauteile + (if (and (null *geruest-anbauteile*) (null *geruest-sonstiges*)) + (mode_tile "winkel" 1)) ;; Laenge/Farbe nur bei Baugruppen mit "attribute"-Block (if (null laenge-def) (mode_tile "laenge" 1)) @@ -1093,7 +1350,8 @@ (mode_tile "farbe_frei" (if (= (atoi *geruest-dlg-farbe*) *geruest-frei-idx*) 0 1)) (action_tile "farbe" - "(mode_tile \"farbe_frei\" (if (= (atoi $value) *geruest-frei-idx*) 0 1))") + (strcat "(mode_tile \"farbe_frei\" (if (= (atoi $value) *geruest-frei-idx*) 0 1))" + " (geruest-dlg-aenderung-pruefen)")) ) (progn (mode_tile "farbe" 1) @@ -1102,9 +1360,12 @@ ) (action_tile "konfig" "(geruest-dlg-konfig-waehlen (atoi $value))") - ;; Bereichswechsel: Dialog schliessen, die Schleife in c:GERUEST baut - ;; ihn mit dem neuen Bereich neu auf. - (action_tile "bereich" "(geruest-dlg-lesen) (done_dialog 4)") + ;; Jede Eingabe prueft, ob der Stand noch der gewaehlten + ;; Konfiguration entspricht (Edit-Boxen melden sich beim Verlassen). + (foreach tile (append '("variante" "laenge" "farbe_frei" "winkel") + (geruest-dlg-spalten-keys "b" *geruest-anbauteile*) + (geruest-dlg-spalten-keys "s" *geruest-sonstiges*)) + (action_tile tile "(geruest-dlg-aenderung-pruefen)")) (action_tile "accept" "(geruest-dlg-lesen) (done_dialog 1)") (action_tile "kspeichern" "(geruest-dlg-lesen) (done_dialog 2)") (action_tile "kloeschen" "(geruest-dlg-lesen) (done_dialog 3)") @@ -1115,25 +1376,18 @@ (cond ((= ergebnis 0) (setq fertig T)) - ;; Bereichswechsel: Stand dieses Bereichs sichern und an den - ;; Aufrufer zurueckmelden, damit er den neuen Bereich oeffnet. - ((= ergebnis 4) - (setq neu-idx (atoi *geruest-dlg-bereich*)) - (geruest-zustand-sichern (ssg-json-get bg "id")) - (if (= neu-idx bereich-idx) - nil - (progn - (setq rueckgabe (list "WECHSEL" neu-idx)) - (setq fertig T) - ) - ) - ) - ;; Speichern: der Name wird NACH dem Schliessen abgefragt - ;; getstring funktioniert aus einem action_tile-Rueckruf heraus ;; nicht (dasselbe Muster wie die Punktwahl im VF-Assistenten). ((= ergebnis 2) - (setq name (getstring T (ssg-text "gr-konfig-name"))) + ;; Enter uebernimmt den Namen der gewaehlten eigenen + ;; Konfiguration und ueberschreibt sie damit. + (setq vorgabe (geruest-konfig-name-vorgabe (atoi *geruest-dlg-konfig*))) + (setq name (getstring T (if vorgabe + (ssg-textf "gr-konfig-name-vorgabe" (list vorgabe)) + (ssg-text "gr-konfig-name")))) + (if (and vorgabe (or (null name) (= (ssg-cfg-trim name) ""))) + (setq name vorgabe)) (if (and name (/= (ssg-cfg-trim name) "")) (progn (setq name (ssg-cfg-trim name)) @@ -1143,6 +1397,8 @@ ;; angezeigter Stand zusammenpassen (Index 0 = ""). (setq *geruest-dlg-konfig* (itoa (geruest-konfig-index name))) + ;; Gespeicherter Stand = neue Vergleichsbasis + (setq *geruest-dlg-konfig-basis* (geruest-dlg-record name)) ) (progn (princ (ssg-text "gr-abgebrochen")) @@ -1154,6 +1410,7 @@ ((= ergebnis 3) (geruest-konfig-entfernen bg) (setq *geruest-konfig-liste* (geruest-konfigs bg)) + (if (= *geruest-dlg-konfig* "0") (setq *geruest-dlg-konfig-basis* nil)) ) ;; Laenge pruefen - Bereichspruefung erfolgt im Projekt immer nach @@ -1170,18 +1427,19 @@ ) (T - (setq oben-m (geruest-anzahlen-lesen *geruest-dlg-oben*)) - (setq unten-m (geruest-anzahlen-lesen *geruest-dlg-unten*)) - (if (or (null oben-m) (null unten-m)) + (setq bef-m (geruest-anzahlen-lesen *geruest-dlg-bef* *geruest-anbauteile*)) + (setq sonst-m (geruest-anzahlen-lesen *geruest-dlg-sonst* *geruest-sonstiges*)) + (if (or (null bef-m) (null sonst-m)) (alert (ssg-text "gr-alert-menge")) (progn (setq rueckgabe (list "OK" (atoi *geruest-dlg-variante*) - (cdr oben-m) - (cdr unten-m) + (cdr bef-m) (if laenge-def *geruest-dlg-laenge* "") - (geruest-dlg-farbwert))) + (geruest-dlg-farbwert) + (cdr sonst-m) + (geruest-winkel-aus-index *geruest-dlg-winkel*))) (setq fertig T) ) ) @@ -1215,11 +1473,12 @@ ;; Dummy-Geometrie + eigene ATTDEFs zu einem Block zusammenfassen und am ;; gewaehlten Punkt einfuegen. werte = alist der berechneten Attributwerte, ;; variante = gewaehlte Geometrie-Variante (liefert ggf. eine eigene DWG). -;; teile-dwgs = Pfade der Teile-DWGs (geruest-teile-dwgs), die zusaetzlich -;; als reine Geometrie bei 0,0,0 mit in den Block wandern. +;; teile-dwgs = ((pfad . rot) ...) der Teile-DWGs (geruest-teile-dwgs-rot), +;; die zusaetzlich als reine Geometrie bei 0,0,0 mit in den Block wandern, +;; um rot Grad um Z gedreht ("Winkel Platte" der Anbauteile). ;; Rueckgabe: (blockname . entity) oder nil. (defun geruest-block-bauen (bg variante werte pt teile-dwgs / datei dummy lastEnt dummyEnt - dummy-attribs attribs) + dummy-attribs attribs winkel-vars) ;; Eine Variante darf eine eigene Dummy-DWG mitbringen; sonst (oder wenn ;; deren Datei fehlt) gilt die der Baugruppe. (setq datei (geruest-dummy-wahl variante bg)) @@ -1252,9 +1511,19 @@ ;; einfuegen - erst NACH dem Lesen des Dummys, damit dummyEnt auf den ;; Dummy zeigt. Nur Geometrie: die Sammelschleife unten nimmt die ;; INSERTs mit in den Block, das Attribut-Schema bleibt unberuehrt. + ;; Drehwinkel in Grad, gegen den Uhrzeigersinn ab +X - dafuer die + ;; Winkel-Systemvariablen nur fuer diese Einfuegungen auf 0 stellen. + ;; Die interaktive Drehung des fertigen Blocks danach soll wieder in den + ;; Einheiten des Benutzers laufen. + (setq winkel-vars (mapcar '(lambda (v) (cons v (getvar v))) + '("ANGBASE" "ANGDIR" "AUNITS"))) + (setvar "ANGBASE" 0.0) + (setvar "ANGDIR" 0) + (setvar "AUNITS" 0) (foreach teil teile-dwgs - (command "_.INSERT" teil (list 0.0 0.0 0.0) 1 1 0) + (command "_.INSERT" (car teil) (list 0.0 0.0 0.0) 1 1 (cdr teil)) ) + (foreach v winkel-vars (setvar (car v) (cdr v))) ;; Unser Schema gewinnt an Struktur, die Dummy-Werte an Inhalt: ;; ssg-attrib-merge legt alle Tags aus *geruest-attrib-defs* an und @@ -1346,24 +1615,27 @@ ) ;; Ausgewaehlte Konfiguration einfuegen. -;; wahl = (variante-index oben unten laenge farbe) - die Dialog-Rueckgabe ohne -;; das fuehrende "OK". -(defun geruest-einfuegen (bg wahl / varianten anbauteile variante teileart - paare artnr bezeichnung teile-namen werte pt ergebnis) +;; wahl = (variante-index befestigung laenge farbe sonstiges winkel) - die +;; Dialog-Rueckgabe ohne das fuehrende "OK". +(defun geruest-einfuegen (bg wahl / varianten anbauteile sonstiges variante teileart + paare artnr basis-nr bezeichnung teile-namen werte pt + ergebnis winkel) (setq varianten (ssg-json-get bg "geometrie_varianten")) - (setq anbauteile (ssg-json-get bg "anbaugruppen")) + (setq anbauteile (geruest-anbau-liste bg "befestigung")) + (setq sonstiges (geruest-anbau-liste bg "sonstiges")) (setq variante (nth (car wahl) varianten)) ;; TEILEART kann die Variante vorgeben (Saeule 1 Zoll vs. 2 Zoll) - ;; sonst gilt der Wert der Baugruppe. (setq teileart (geruest-variante-wert variante bg "teileart")) ;; ARTINR: jede Sivas-ID so oft wie die gewaehlte Stueckzahl, erst die - ;; Basis, dann Befestigung oben, dann unten. Dasselbe Teil an beiden - ;; Positionen erscheint entsprechend mehrfach. Die Paare tragen zusaetzlich - ;; das farbig-Flag je Teil fuer die TEILEFARBE-Liste (gleiche Reihenfolge). + ;; Basis, dann Befestigung (Gesamtanzahl oben + unten), dann Sonstiges. + ;; Die Paare tragen zusaetzlich das farbig-Flag je Teil fuer die + ;; TEILEFARBE-Liste (gleiche Reihenfolge). (setq paare (geruest-teile-paare variante nil)) + (setq basis-nr (mapcar 'car paare)) (setq paare (append paare (geruest-auswahl-paare (cadr wahl) anbauteile))) - (setq paare (append paare (geruest-auswahl-paare (caddr wahl) anbauteile))) + (setq paare (append paare (geruest-auswahl-paare (nth 4 wahl) sonstiges))) (setq artnr (mapcar 'car paare)) ;; BEZEICHNUNG: mit " + " verketten - die Artikelbezeichnungen enthalten @@ -1371,30 +1643,36 @@ (setq teile-namen (list teileart (geruest-eintrag-name variante))) (setq teile-namen (append teile-namen (geruest-auswahl-namen (cadr wahl) anbauteile - (ssg-text "gr-position-oben")))) + (ssg-text "gr-position-befestigung")))) (setq teile-namen (append teile-namen - (geruest-auswahl-namen (caddr wahl) anbauteile - (ssg-text "gr-position-unten")))) + (geruest-auswahl-namen (nth 4 wahl) sonstiges + (ssg-text "gr-position-sonstiges")))) (setq bezeichnung (ssg-join teile-namen " + ")) (setq werte (list (cons "ARTINR" (ssg-join artnr ",")) (cons "BEZEICHNUNG" bezeichnung) (cons "TEILEART" teileart))) - (if (/= (nth 3 wahl) "") - (setq werte (append werte (list (cons "LAENGE" (nth 3 wahl)))))) + (if (/= (nth 2 wahl) "") + (setq werte (append werte (list (cons "LAENGE" (nth 2 wahl)))))) ;; TEILEFARBE: je ARTINR-Eintrag die gewaehlte Farbe (farbiges Teil) oder ;; "" (z.B. ",,RAL7030,,RAL7030") - fuer den Sivas-Export je Artikelnummer. - (if (/= (nth 4 wahl) "") + (if (/= (nth 3 wahl) "") (setq werte (append werte (list (cons "TEILEFARBE" - (ssg-join (geruest-farbliste paare (nth 4 wahl)) ",")))))) + (ssg-join (geruest-farbliste paare (nth 3 wahl)) ",")))))) (setq pt (getpoint (ssg-text "gr-prompt-einfuegepunkt"))) (if (null pt) (princ (ssg-text "gr-abgebrochen")) (progn (ssg-start "Geruest" '(("OSMODE") ("ATTREQ") ("ATTDIA"))) + ;; Basis-Teile ungedreht, Anbauteile im "Winkel Platte" + (setq winkel (nth 5 wahl)) + (if (not (numberp winkel)) (setq winkel 0)) (setq ergebnis (geruest-block-bauen bg variante werte pt - (geruest-teile-dwgs artnr))) + (geruest-teile-dwgs-rot + (geruest-teile-dwgs basis-nr) + (geruest-teile-dwgs (geruest-rest-liste artnr (length basis-nr))) + winkel))) (ssg-end) (if ergebnis (princ (ssg-textf "gr-fertig" (list teileart (car ergebnis)))) @@ -1405,59 +1683,27 @@ ) -;; Index eines Bereichs ueber das ASCII-Feld "id" (nil, wenn unbekannt). -(defun geruest-bereich-index (id bereiche / i idx) - (setq i 0 idx nil) - (foreach b bereiche - (if (and (null idx) (equal (car b) id)) (setq idx i)) - (setq i (1+ i)) - ) - idx -) - -;; Ein Dialog fuer alle Geruest-Bereiche. Der Bereichswechsel laeuft ueber -;; diese Schleife, weil der Dialog dafuer neu aufgebaut werden muss. -;; start-id = "id" des Bereichs, mit dem der Dialog oeffnet (nil oder -;; unbekannt -> erster Bereich). Der Wechsel per Dropdown bleibt moeglich. -(defun geruest-starten (start-id / bereiche idx bg erg weiter) - (setq *geruest-zustand* nil) - (setq bereiche (geruest-baugruppen-liste)) - (if (null bereiche) - (princ (ssg-text "gr-fehler-keine-baugruppen")) - (progn - (setq idx (if start-id (geruest-bereich-index start-id bereiche))) - (if (null idx) (setq idx 0)) - (setq weiter T) - (while weiter - (setq bg (cdr (nth idx bereiche))) - (cond - ((null (ssg-json-get bg "geometrie_varianten")) - (princ (ssg-textf "gr-fehler-keine-varianten" - (list (ssg-json-get bg "id")))) - (setq weiter nil) - ) - (T - (setq erg (geruest-dialog bg idx bereiche)) - (cond - ((null erg) - (princ (ssg-text "gr-abgebrochen")) - (setq weiter nil)) - ((equal (car erg) "WECHSEL") (setq idx (cadr erg))) - (T - (setq weiter nil) - (geruest-einfuegen bg (cdr erg))) - ) - ) - ) - ) - ) +;; Dialog fuer genau einen Bereich (id = ASCII-Feld "id" der Baugruppe) +;; zeigen und das Ergebnis einfuegen. Jeder Bereich hat seinen eigenen +;; Menuebefehl - eine Umschaltung im Dialog gibt es nicht. +(defun geruest-starten (id / bg erg) + (setq bg (if (geruest-daten) (geruest-baugruppe id (geruest-daten)))) + (cond + ((null (geruest-daten)) (princ (ssg-text "gr-fehler-keine-baugruppen"))) + ((null bg) (princ (ssg-textf "gr-fehler-baugruppe" (list id)))) + ((null (ssg-json-get bg "geometrie_varianten")) + (princ (ssg-textf "gr-fehler-keine-varianten" (list id)))) + ((null (setq erg (geruest-dialog bg))) + (princ (ssg-text "gr-abgebrochen"))) + (T (geruest-einfuegen bg (cdr erg))) ) (princ) ) -(defun c:GERUEST ( / ) (geruest-starten nil)) +;; Ohne Bereich kein Dialog - die Bereiche oeffnen nur ihre eigenen Befehle. +(defun c:GERUEST ( / ) (princ (ssg-text "gr-bereich-waehlen")) (princ)) -;; Menue-Einstiege je Bereich - oeffnen denselben Dialog im passenden Bereich. +;; Menue-Einstiege je Bereich (defun c:GERUEST_SAEULEN ( / ) (geruest-starten "Saeulen")) (defun c:GERUEST_ROHRABHAENGER ( / ) (geruest-starten "Rohrabhaenger")) (defun c:GERUEST_WANDBEFESTIGUNG ( / ) (geruest-starten "Wandbefestigung")) @@ -1628,7 +1874,9 @@ ;; Querstreben-Konfiguration (Variante vor Baugruppe) als ;; (dummy laenge querlinie abstand rand-min rand-max) oder nil, wenn keine -;; "querstrebe" definiert ist. +;; "querstrebe" definiert ist oder die Variante kein "mit_querstrebe": true +;; traegt. Das Flag steht bewusst ausdruecklich je Variante (wie "mit_muffe"), +;; ein 1"-Rohr hat z.B. keine Querstreben. ;; dummy = DWG unter data/geruest (Basispunkt Strebenmitte, 30 mm laengs ;; X) oder nil ;; laenge/querlinie = nur fuer den Rueckfall ohne Dummy-DWG: zwei Querlinien @@ -1636,7 +1884,7 @@ ;; Fehlende Zahlenwerte -> Standard 30/25/500/100/250. (defun geruest-traeger-strebe-cfg (variante bg / q w d) (setq q (geruest-variante-wert variante bg "querstrebe")) - (if (and q (listp q)) + (if (and variante (ssg-json-get variante "mit_querstrebe") q (listp q)) (progn (setq d (ssg-json-get q "dummy")) (cons (if (and d (= (type d) 'STR) (/= d "")) d) @@ -1683,16 +1931,11 @@ (ssg-join teile " + ") ) -(defun geruest-traeger-dcl-pfad ( / basis) - (setq basis (cond ((getenv "DXFM_DCL")) - ((getenv "DXFMAKRO") (strcat (getenv "DXFMAKRO") "/dcl")))) - (if basis - (strcat (vl-string-translate "\\" "/" basis) "/geruest_traeger.dcl") - ) -) - ;; --- Dialogzustand (Globals, siehe Abschnitt DIALOGZUSTAND oben) --- -;; Bleibt zwischen zwei GERUEST_TRAEGER-Aufrufen erhalten. +;; Bleibt zwischen zwei Aufrufen derselben Baugruppe erhalten. +;; *geruest-tr-variante* = Index der Variante in geometrie_varianten (String). +;; Jede Variante - auch die mit Muffe - hat ihren eigenen Radiobutton, damit +;; ihre Artikelnummer im Dialog sichtbar ist. ;; Abzug-Vorgaben (aktiv + Wert) der Variante idx in den Zustand laden. (defun geruest-tr-vorgaben-laden (idx / v) @@ -1716,15 +1959,15 @@ (mode_tile "abzug_e_w" (if (= *geruest-tr-abzug-e* "1") 0 1)) ) -;; Variantenwechsel im Dialog: Abzug-Vorgaben der neuen Variante uebernehmen. -(defun geruest-tr-variante-gewaehlt (wert / ) - (setq *geruest-tr-variante* wert) - (geruest-tr-vorgaben-laden (atoi wert)) +;; Variantenwechsel: Abzug-Vorgaben der neuen Variante uebernehmen. +(defun geruest-tr-variante-gewaehlt (key / ) + (setq *geruest-tr-variante* (itoa (geruest-radio-index key))) + (geruest-tr-vorgaben-laden (atoi *geruest-tr-variante*)) (geruest-tr-abzug-schreiben) ) (defun geruest-tr-dlg-lesen ( / ) - (setq *geruest-tr-variante* (get_tile "variante")) + (setq *geruest-tr-variante* (itoa (geruest-radio-index (get_tile "variante")))) (setq *geruest-tr-farbe* (get_tile "farbe")) (setq *geruest-tr-frei* (get_tile "farbe_frei")) (setq *geruest-tr-abzug-a* (get_tile "abzug_a")) @@ -1739,44 +1982,60 @@ (if (= aktiv "1") (geruest-abzug-wert wert) 0.0) ) -;; Traeger-Dialog. Rueckgabe: +;; Dialog fuer Linien-Baugruppen (Rohr-Geruest-Traeger, Omniflo-Fahrstrecke). +;; dcl-datei = Vorlage unter dcl/ (z.B. "geruest_traeger.dcl"), dlg-name = +;; Dialogname darin. Rueckgabe: ;; (variante-index farbe abzug-anfang abzug-ende beschriften-p) oder nil bei -;; Abbruch. -(defun geruest-traeger-dialog (bg / varianten dcl-pfad dat fertig rueckgabe - ergebnis aw ew) +;; Abbruch. variante-index = Index in geometrie_varianten. +(defun geruest-traeger-dialog (bg dcl-datei dlg-name / varianten dcl-pfad dat + fertig rueckgabe ergebnis aw ew) (setq varianten (ssg-json-get bg "geometrie_varianten")) (setq *geruest-tr-bg* bg) + ;; Der Dialogstand bleibt zwischen zwei Aufrufen erhalten - aber nur fuer + ;; dieselbe Baugruppe: ein Varianten-Index des Traegers passt nicht zur + ;; Fahrstrecke. + (if (not (equal (ssg-json-get bg "id") *geruest-tr-id*)) + (setq *geruest-tr-id* (ssg-json-get bg "id") + *geruest-tr-variante* nil)) (geruest-farb-liste-setzen (ssg-json-get (ssg-json-get bg "attribute") "TEILEFARBE")) ;; Ausgangszustand beim ersten Aufruf bzw. wenn der gemerkte Index nach - ;; einer JSON-Aenderung nicht mehr passt. + ;; einer JSON-Aenderung nicht mehr passt oder die Variante gesperrt wurde. (if (or (null *geruest-tr-variante*) - (>= (atoi *geruest-tr-variante*) (length varianten))) + (/= (atoi *geruest-tr-variante*) + (geruest-variante-waehlbar varianten (atoi *geruest-tr-variante*)))) (progn - (setq *geruest-tr-variante* "0" *geruest-tr-farbe* "0" *geruest-tr-frei* "") - (geruest-tr-vorgaben-laden 0) + (setq *geruest-tr-variante* (itoa (geruest-erste-freie-variante varianten)) + *geruest-tr-farbe* "0" *geruest-tr-frei* "") + (geruest-tr-vorgaben-laden (atoi *geruest-tr-variante*)) ) ) ;; Beschriftung standardmaessig an; der Haken bleibt zwischen Aufrufen (if (null *geruest-tr-beschriftung*) (setq *geruest-tr-beschriftung* "1")) - (setq dcl-pfad (geruest-traeger-dcl-pfad)) + ;; Vorlage einmal fuellen (ein Radiobutton je Variante), nach der + ;; Schleife loeschen. + (setq dcl-pfad + (ssg-dcl-vorlage-fuellen (geruest-dcl-vorlage-pfad dcl-datei) + "grlinie" + (list (cons "VARIANTEN" + (geruest-dcl-varianten-zeilen varianten + (geruest-indizes (length varianten))))))) (setq fertig nil rueckgabe nil) ;; Schleife: ungueltige Eingaben zeigen den Dialog mit dem bisherigen ;; Stand erneut - DCL kann Zahlen nicht selbst pruefen. (while (not fertig) - (setq dat (if (and dcl-pfad (findfile dcl-pfad)) (load_dialog dcl-pfad) -1)) - (if (or (< dat 0) (not (new_dialog "geruest_traeger" dat))) + (setq dat (if dcl-pfad (load_dialog dcl-pfad) -1)) + (if (or (< dat 0) (not (new_dialog dlg-name dat))) (progn (alert (ssg-textf "gr-tr-fehler-dcl" - (list (if dcl-pfad dcl-pfad "geruest_traeger.dcl")))) + (list (cond ((geruest-dcl-vorlage-pfad dcl-datei)) + (dcl-datei))))) (setq fertig T) ) (progn - (start_list "variante") - (foreach v varianten (add_list (geruest-eintrag-name v))) - (end_list) - (set_tile "variante" *geruest-tr-variante*) + (set_tile "variante" (geruest-radio-key (atoi *geruest-tr-variante*))) + (geruest-varianten-sperren varianten) (if *geruest-farb-liste* (progn @@ -1827,6 +2086,7 @@ ) ) ) + (if dcl-pfad (vl-file-delete dcl-pfad)) rueckgabe ) @@ -1925,8 +2185,10 @@ abzug-a abzug-e min-l max-l bez werte-basis werte weiter p1 eingabe strecke winkel netto ergebnis anzahl strebe strebe-pfad muffe-pfad - beschriften) + beschriften titel) (setq variante (nth (car wahl) (ssg-json-get bg "geometrie_varianten"))) + ;; Bauteilname fuer die Meldungen ("Traeger", "Fahrstrecke") + (setq titel (geruest-titel bg)) (setq farbe (cadr wahl) abzug-a (caddr wahl) abzug-e (cadddr wahl) @@ -1965,7 +2227,7 @@ (setq weiter T anzahl 0) (while weiter (setq strecke nil) - (setq p1 (getpoint (ssg-text "gr-tr-prompt-start"))) + (setq p1 (getpoint (ssg-textf "gr-tr-prompt-start" (list titel)))) (if (null p1) (setq weiter nil) (progn @@ -2000,12 +2262,12 @@ ((null netto) (princ (ssg-textf "gr-tr-laenge-null" (list (geruest-mm-string strecke) - (geruest-mm-string (+ abzug-a abzug-e)))))) + (geruest-mm-string (+ abzug-a abzug-e)) titel)))) ((not (geruest-traeger-pruefen netto min-l max-l)) (princ (ssg-textf "gr-tr-laenge-bereich" (list (geruest-mm-string netto) (if min-l (geruest-mm-string min-l) "0") - (if max-l (geruest-mm-string max-l) "-"))))) + (if max-l (geruest-mm-string max-l) "-") titel)))) (T ;; Streben-Rand ausserhalb der Grenzen: informieren, aber trotzdem ;; einfuegen (der Abstand zwischen den Streben bleibt immer exakt) @@ -2019,13 +2281,13 @@ ;; Beschriftung aus dem fertigen Block ableiten (dieselbe Funktion ;; wie GERUEST_TRAEGER_BESCHRIFTEN) (if (and ergebnis beschriften) - (geruest-traeger-beschriften (cdr ergebnis))) + (geruest-traeger-beschriften (cdr ergebnis) bg)) (ssg-end) (if ergebnis (progn (setq anzahl (1+ anzahl)) (princ (ssg-textf "gr-tr-fertig" - (list (geruest-mm-string netto) (car ergebnis)))) + (list (geruest-mm-string netto) (car ergebnis) titel))) ) ) ) @@ -2033,7 +2295,7 @@ ) ) ) - (princ (ssg-textf "gr-tr-ende" (list (itoa anzahl)))) + (princ (ssg-textf "gr-tr-ende" (list (itoa anzahl) titel))) (princ) ) @@ -2185,14 +2447,15 @@ ) ) -;; Einen Traeger-Block beschriften (eine evtl. vorhandene Beschriftung wird -;; ersetzt). Rueckgabe: "ok", "ersatz" (Block ohne bekannte VARIANTE, mit den -;; Vorgaben der Baugruppe beschriftet) oder nil (nicht beschriftbar). -(defun geruest-traeger-beschriften (blockEnt / ed attribs bg vname idx variante +;; Einen Linien-Block (Traeger, Fahrstrecke) beschriften (eine evtl. +;; vorhandene Beschriftung wird ersetzt). bg = Baugruppe, aus deren JSON die +;; Formatierung kommt. Rueckgabe: "ok", "ersatz" (Block ohne bekannte +;; VARIANTE, mit den Vorgaben der Baugruppe beschriftet) oder nil (nicht +;; beschriftbar). +(defun geruest-traeger-beschriften (blockEnt bg / ed attribs vname idx variante cfg laenge lage lay handle code erg) (setq ed (entget blockEnt)) (setq attribs (ssg-attrib-read blockEnt)) - (setq bg (geruest-baugruppe "Traeger" (geruest-traeger-daten))) (setq laenge (atof (cond ((cdr (assoc "LAENGE" attribs))) ("0")))) (if (and bg (> laenge 0.0)) (progn @@ -2241,11 +2504,15 @@ erg ) -;; Alle Traeger der Zeichnung (neu) beschriften und Beschriftungen, deren -;; Block nicht mehr existiert, entfernen - unabhaengig von der Checkbox im -;; Einfuegedialog. -(defun c:GERUEST_TRAEGER_BESCHRIFTEN ( / ss i n-ok n-ersatz n-fehl n-weg e h ziel erg) +;; Alle Linien-Bloecke einer Baugruppe (Blockname GR__*) neu beschriften +;; und Beschriftungen, deren Block nicht mehr existiert, entfernen - +;; unabhaengig von der Checkbox im Einfuegedialog. Verwaiste Texte werden +;; unabhaengig vom Typ entfernt (am Text ist nicht erkennbar, zu welchem +;; Typ der geloeschte Block gehoerte). +(defun geruest-linien-beschriften-alle (bg / ss i n-ok n-ersatz n-fehl n-weg e h + ziel erg titel) (setq *geruest-beschr-gemeldet* nil) + (setq titel (geruest-titel bg)) (setq n-ok 0 n-ersatz 0 n-fehl 0 n-weg 0) (ssg-start nil nil) ;; Verwaiste Beschriftungen zuerst entfernen @@ -2264,38 +2531,73 @@ ) ) ) - (if (setq ss (ssget "_X" '((0 . "INSERT") (2 . "GR_Traeger_*")))) + (if (setq ss (ssget "_X" (list '(0 . "INSERT") + (cons 2 (strcat "GR_" (ssg-json-get bg "id") "_*"))))) (progn (setq i 0) (repeat (sslength ss) - (setq erg (geruest-traeger-beschriften (ssname ss i))) + (setq erg (geruest-traeger-beschriften (ssname ss i) bg)) (cond ((= erg "ok") (setq n-ok (1+ n-ok))) ((= erg "ersatz") (setq n-ersatz (1+ n-ersatz))) (T (setq n-fehl (1+ n-fehl)))) (setq i (1+ i)) ) (princ (ssg-textf "gr-tr-beschr-ergebnis" - (list (itoa (+ n-ok n-ersatz)) (itoa n-ersatz) (itoa n-fehl) (itoa n-weg)))) + (list (itoa (+ n-ok n-ersatz)) (itoa n-ersatz) (itoa n-fehl) (itoa n-weg) + titel))) ) - (princ (ssg-text "gr-tr-beschr-keine")) + (princ (ssg-textf "gr-tr-beschr-keine" (list titel))) ) (ssg-end) (princ) ) -(defun c:GERUEST_TRAEGER ( / bg wahl) - (setq bg (geruest-baugruppe "Traeger" (geruest-traeger-daten))) +;; Linien-Baugruppe aus ihrer Datendatei holen, Dialog zeigen, einfuegen. +;; id = "id" der Baugruppe, daten = geparste JSON, dcl-datei/dlg-name siehe +;; geruest-traeger-dialog. +(defun geruest-linien-starten (id daten dcl-datei dlg-name / bg wahl) + (setq bg (geruest-baugruppe id daten)) (cond ((null bg) - (princ (ssg-textf "gr-fehler-baugruppe" (list "Traeger")))) + (princ (ssg-textf "gr-fehler-baugruppe" (list id)))) ((null (ssg-json-get bg "geometrie_varianten")) - (princ (ssg-textf "gr-fehler-keine-varianten" (list "Traeger")))) - ((null (setq wahl (geruest-traeger-dialog bg))) + (princ (ssg-textf "gr-fehler-keine-varianten" (list id)))) + ((null (setq wahl (geruest-traeger-dialog bg dcl-datei dlg-name))) (princ (ssg-text "gr-abgebrochen"))) (T (geruest-traeger-einfuegen bg wahl)) ) (princ) ) -(princ "\nGeruestInsert.lsp geladen. Befehle: GERUEST, GERUEST_SAEULEN, GERUEST_ROHRABHAENGER, GERUEST_WANDBEFESTIGUNG, GERUEST_TRAEGER, GERUEST_TRAEGER_BESCHRIFTEN") +;; Beschriftung aller Bloecke einer Linien-Baugruppe (siehe +;; geruest-linien-beschriften-alle). +(defun geruest-linien-beschriften (id daten / bg) + (if (setq bg (geruest-baugruppe id daten)) + (geruest-linien-beschriften-alle bg) + (princ (ssg-textf "gr-fehler-baugruppe" (list id))) + ) + (princ) +) + +(defun c:GERUEST_TRAEGER ( / ) + (geruest-linien-starten "Traeger" (geruest-traeger-daten) + "geruest_traeger.dcl" "geruest_traeger") +) + +(defun c:GERUEST_TRAEGER_BESCHRIFTEN ( / ) + (geruest-linien-beschriften "Traeger" (geruest-traeger-daten)) +) + +;; Omniflo-Fahrstrecke: dieselbe Linien-Logik, Daten aus omniflo_fahrstrecke.json, +;; eigener Dialog dcl/fahrstrecke.dcl. +(defun c:OMNI_FAHRSTRECKE ( / ) + (geruest-linien-starten "Fahrstrecke" (geruest-fahrstrecke-daten) + "fahrstrecke.dcl" "fahrstrecke") +) + +(defun c:OMNI_FAHRSTRECKE_BESCHRIFTEN ( / ) + (geruest-linien-beschriften "Fahrstrecke" (geruest-fahrstrecke-daten)) +) + +(princ "\nGeruestInsert.lsp geladen. Befehle: GERUEST, GERUEST_SAEULEN, GERUEST_ROHRABHAENGER, GERUEST_WANDBEFESTIGUNG, GERUEST_TRAEGER, GERUEST_TRAEGER_BESCHRIFTEN, OMNI_FAHRSTRECKE, OMNI_FAHRSTRECKE_BESCHRIFTEN") (princ) diff --git a/Lisp/OmniModulInsert.lsp b/Lisp/OmniModulInsert.lsp index 5588753..181f136 100644 --- a/Lisp/OmniModulInsert.lsp +++ b/Lisp/OmniModulInsert.lsp @@ -1479,6 +1479,27 @@ (princ) ) +;; --- Omniflo / Türlösungen Schwenkschienen --- +;; Feste TEF-Bauteile ohne Sivas-Auswahl: Datei liegt direkt unter DXFM_OMNIFLO, +;; wird per omni:insert-dxf am gewaehlten Einfuegepunkt ohne Drehung eingefuegt. +(defun c:OMNI_SCHW_400_R () + (omni:insert-dxf "824604002" nil nil) + (princ) +) +(defun c:OMNI_SCHW_400_L () + (omni:insert-dxf "824604001" nil nil) + (princ) +) +(defun c:OMNI_SCHW_400_R_SENSORIK () + (omni:insert-dxf "824604012" nil nil) + (princ) +) +(defun c:OMNI_SCHW_400_L_SENSORIK () + (omni:insert-dxf "824604011" nil nil) + (princ) +) + + ;; --- Omniflo / TEF Elemente --- diff --git a/Lisp/ssg_core.lsp b/Lisp/ssg_core.lsp index cfe95c8..d344015 100644 --- a/Lisp/ssg_core.lsp +++ b/Lisp/ssg_core.lsp @@ -1643,10 +1643,9 @@ ;; Schreibt eine Liste von Textzeilen als temporaere DCL-Datei und liefert ;; deren Pfad zurueck (oder nil bei Fehler, z.B. wenn open scheitert). Der ;; Aufrufer ist fuer load_dialog/unload_dialog UND das Loeschen der Datei -;; (vl-file-delete) danach selbst verantwortlich - analog zum bestehenden -;; Muster in GeruestInsert.lsp (geruest-dcl-schreiben), hier nur als -;; generischer Baustein fuer WEITERE Aufrufer (GeruestInsert.lsp selbst -;; bleibt unveraendert, um dessen Code nicht anzufassen). +;; (vl-file-delete) danach selbst verantwortlich. Fuer Dialoge mit fester +;; Grundstruktur und nur einzelnen datenabhaengigen Bloecken siehe +;; ssg-dcl-vorlage-fuellen. (defun ssg-dcl-temp-schreiben (praefix zeilen / pfad f) (setq pfad (vl-filename-mktemp praefix nil ".dcl")) (if (setq f (open pfad "w")) @@ -1659,6 +1658,46 @@ ) ) +;; DCL-Vorlagen mit Platzhaltern: DCL kann Tiles weder zur Laufzeit erzeugen +;; noch ausblenden, und Labels von radio_button/toggle lassen sich per +;; set_tile nicht aendern. Datenabhaengige Teile (z.B. ein Radiobutton je +;; Variante) werden darum in eine statische .dcl-Vorlage eingesetzt: jede +;; Zeile, die getrimmt genau "//@NAME@" lautet, wird durch die Zeilen aus +;; ersetzungen (("NAME" . (zeile ...)) ...) ersetzt. Eine leere Liste +;; entfernt die Markerzeile; ein unbekannter Marker bleibt als DCL-Kommentar +;; stehen (harmlos). Das Layout bleibt so eine normale, lesbare .dcl-Datei. +(defun ssg-dcl-zeilen-ersetzen (zeilen ersetzungen / erg t1 name e) + (setq erg nil) + (foreach z zeilen + (setq t1 (vl-string-trim " \t" z)) + (setq name (if (and (> (strlen t1) 4) + (= (substr t1 1 3) "//@") + (= (substr t1 (strlen t1) 1) "@")) + (substr t1 4 (- (strlen t1) 4)))) + (if (and name (setq e (assoc name ersetzungen))) + (setq erg (append erg (cdr e))) + (setq erg (append erg (list z))) + ) + ) + erg +) + +;; Vorlage lesen, Platzhalter ersetzen (ssg-dcl-zeilen-ersetzen) und als +;; temporaere DCL-Datei schreiben. Rueckgabe: Pfad oder nil (Vorlage fehlt / +;; nicht lesbar / nicht schreibbar). Laden und Loeschen wie bei +;; ssg-dcl-temp-schreiben durch den Aufrufer. +(defun ssg-dcl-vorlage-fuellen (vorlage-pfad praefix ersetzungen / f z zeilen) + (if (and vorlage-pfad (findfile vorlage-pfad) (setq f (open vorlage-pfad "r"))) + (progn + (setq zeilen nil) + (while (setq z (read-line f)) (setq zeilen (cons z zeilen))) + (close f) + (ssg-dcl-temp-schreiben praefix + (ssg-dcl-zeilen-ersetzen (reverse zeilen) ersetzungen)) + ) + ) +) + ;; ------------------------------------------------------------ ;; REKURSIVER JSON-PARSER diff --git a/Lisp/ssg_stueckliste.lsp b/Lisp/ssg_stueckliste.lsp index 2960799..1843f6b 100644 --- a/Lisp/ssg_stueckliste.lsp +++ b/Lisp/ssg_stueckliste.lsp @@ -163,6 +163,10 @@ (cons "ils_kreisel" (ssg-text "sl-erk-kreisel"))) ((or (wcmatch b "VF_*") (wcmatch b "GF_*")) (cons "ils_strecke" (ssg-text "sl-erk-strecke"))) + ;; Fahrstrecke (OMNI_FAHRSTRECKE) entsteht ueber den Geruest-Baukasten und + ;; traegt darum ebenfalls das GR_-Praefix - VOR dem allgemeinen GR_-Zweig. + ((wcmatch b "GR_FAHRSTRECKE_*") + (cons "fahrstrecke" (ssg-text "sl-erk-fahrstrecke"))) ((wcmatch b "GR_*") (cons "geruest" (ssg-text "sl-erk-geruest"))) ((wcmatch b "AP60*") diff --git a/data/json/geruest.json b/data/json/geruest.json index d19f920..a8aa434 100644 --- a/data/json/geruest.json +++ b/data/json/geruest.json @@ -83,137 +83,99 @@ ] } ], - "anbaugruppen": [ - { - "artikel": "SPANNPRATZE ST - KH 8-11 KPL.SELBSTSICHERND", - "sivas_id": 821004120, - "farbig": false, - "stueckzahl": 1, - "anzahl_vorgabe": 1 - }, - { - "artikel": "SPANNPRATZE SELBSTSICHERND KPL.", - "sivas_id": 821004058, - "farbig": false, - "stueckzahl": 1, - "anzahl_vorgabe": 1 - }, - { - "name": "Schraubenset", - "anzahl_vorgabe": 1, - "teile": [ - { - "artikel": "Scheibe DIN 125 - A 10,5 - 140 HV - St", - "sivas_id": 913011010, - "farbig": false, - "stueckzahl": 1 - }, - { - "artikel": "Sechskantmutter DIN 934 - M10 - 8", - "sivas_id": 912011010, - "farbig": false, - "stueckzahl": 2 - }, - { - "artikel": "Sechskantschraube DIN 933 - M10 x 30 - 8.8", - "sivas_id": 911011008, - "farbig": false, - "stueckzahl": 1 - } - ] - }, - { - "artikel": "U-BÜGEL M7 41X49 FÜR PROFILGERÜST - BG", - "sivas_id": 825004049, - "farbig": false, - "stueckzahl": 1, - "anzahl_vorgabe": 1 - }, - { - "artikel": "ROHRKLAMMER 1\" KPL. VERTIKAL", - "sivas_id": 825004040, - "farbig": false, - "stueckzahl": 1, - "anzahl_vorgabe": 2 - }, - { - "artikel": "WINKEL 60X60X6X300", - "sivas_id": 821006043, - "farbig": false, - "stueckzahl": 1, - "anzahl_vorgabe": 1 - }, - { - "artikel": "WINKEL 60X60X6X60", - "sivas_id": 821006042, - "farbig": false, - "stueckzahl": 1, - "anzahl_vorgabe": 1 - }, - { - "artikel": "ROHRKLAMMER 1\" T-VERBINDUNG KPL.", - "sivas_id": 825004030, - "farbig": false, - "stueckzahl": 1, - "anzahl_vorgabe": 1 - }, - { - "artikel": "ROHRKLAMMER 1\" FLACH UND LANG, KPL.", - "sivas_id": 825002021, - "farbig": false, - "stueckzahl": 1, - "anzahl_vorgabe": 1 - }, - { - "artikel": "DURCHSTECKANKER HST M12X115X20", - "sivas_id": 922021003, - "farbig": false, - "stueckzahl": 1, - "anzahl_vorgabe": 1 - } - ], - "konfigurationen": [ - { - "name": "Abhaengung Spannpratze / Rohrklammer", - "variante": "ROHR R 1\" 33,7 x 2,6", - "laenge": 2000, - "teilefarbe": "RAL7035", - "oben": [ - { - "artikel": "SPANNPRATZE SELBSTSICHERND KPL.", - "anzahl": 1 - }, - { - "artikel": "Schraubenset", - "anzahl": 1 - } - ], - "unten": [ - { - "artikel": "ROHRKLAMMER 1\" KPL. VERTIKAL", - "anzahl": 2 - } - ] - }, - { - "name": "Abhaengung Duebel / T-Verbindung", - "variante": "ROHR R 1\" 33,7 x 2,6 einseitig gequetscht", - "laenge": 1500, - "teilefarbe": "RAL7035", - "oben": [ - { - "artikel": "DURCHSTECKANKER HST M12X115X20", - "anzahl": 2 - } - ], - "unten": [ - { - "artikel": "ROHRKLAMMER 1\" T-VERBINDUNG KPL.", - "anzahl": 1 - } - ] - } - ] + "anbaugruppen": { + "befestigung": [ + { + "artikel": "SPANNPRATZE ST - KH 8-11 KPL.SELBSTSICHERND", + "sivas_id": 821004120, + "farbig": false, + "stueckzahl": 1, + "anzahl_vorgabe": 1 + }, + { + "artikel": "SPANNPRATZE SELBSTSICHERND KPL.", + "sivas_id": 821004058, + "farbig": false, + "stueckzahl": 1, + "anzahl_vorgabe": 1 + }, + { + "name": "Schraubenset", + "anzahl_vorgabe": 1, + "teile": [ + { + "artikel": "Scheibe DIN 125 - A 10,5 - 140 HV - St", + "sivas_id": 913011010, + "farbig": false, + "stueckzahl": 1 + }, + { + "artikel": "Sechskantmutter DIN 934 - M10 - 8", + "sivas_id": 912011010, + "farbig": false, + "stueckzahl": 2 + }, + { + "artikel": "Sechskantschraube DIN 933 - M10 x 30 - 8.8", + "sivas_id": 911011008, + "farbig": false, + "stueckzahl": 1 + } + ] + }, + { + "artikel": "U-BÜGEL M7 41X49 FÜR PROFILGERÜST - BG", + "sivas_id": 825004049, + "farbig": false, + "stueckzahl": 1, + "anzahl_vorgabe": 1 + }, + { + "artikel": "ROHRKLAMMER 1\" KPL. VERTIKAL", + "sivas_id": 825004040, + "farbig": false, + "stueckzahl": 1, + "anzahl_vorgabe": 2 + }, + { + "artikel": "WINKEL 60X60X6X300", + "sivas_id": 821006043, + "farbig": false, + "stueckzahl": 1, + "anzahl_vorgabe": 1 + }, + { + "artikel": "WINKEL 60X60X6X60", + "sivas_id": 821006042, + "farbig": false, + "stueckzahl": 1, + "anzahl_vorgabe": 1 + }, + { + "artikel": "ROHRKLAMMER 1\" T-VERBINDUNG KPL.", + "sivas_id": 825004030, + "farbig": false, + "stueckzahl": 1, + "anzahl_vorgabe": 1 + }, + { + "artikel": "ROHRKLAMMER 1\" FLACH UND LANG, KPL.", + "sivas_id": 825002021, + "farbig": false, + "stueckzahl": 1, + "anzahl_vorgabe": 1 + }, + { + "artikel": "DURCHSTECKANKER HST M12X115X20", + "sivas_id": 922021003, + "farbig": false, + "stueckzahl": 1, + "anzahl_vorgabe": 1 + } + ], + "sonstiges": [] + }, + "konfigurationen": [] }, "Säulen": { "id": "Saeulen", @@ -273,126 +235,90 @@ ] } ], - "anbaugruppen": [ - { - "artikel": "KLEMMRING MIT MUFFE EINFACH KPL.", - "sivas_id": 825002019, - "farbig": false, - "stueckzahl": 1, - "anzahl_vorgabe": 2 - }, - { - "artikel": "KLEMMRING MIT MUFFE DOPPELT 90 Grad, KPL.", - "sivas_id": 825002009, - "farbig": false, - "stueckzahl": 1, - "anzahl_vorgabe": 2 - }, - { - "artikel": "KLEMMRING MIT MUFFE DOPPELT 180 Grad, KPL.", - "sivas_id": 825002008, - "farbig": false, - "stueckzahl": 1, - "anzahl_vorgabe": 2 - }, - { - "artikel": "KLEMMRING M. MUFFE DREIFACH 90 Grad/180 Grad KPL.", - "sivas_id": 825002007, - "farbig": false, - "stueckzahl": 1, - "anzahl_vorgabe": 2 - }, - { - "artikel": "KLEMMRING MIT LASCHE KPL. ZUSAMMENBAUZEICHNUNG", - "sivas_id": 825002020, - "farbig": false, - "stueckzahl": 1, - "anzahl_vorgabe": 2 - }, - { - "artikel": "QUERSCHELLE F. 1\" UND 2\" ROHR GESCHW./VZ. M. 4X M10X30 KPL.", - "sivas_id": 825002022, - "farbig": false, - "stueckzahl": 1, - "anzahl_vorgabe": 2 - }, - { - "artikel": "KREUZSCHELLE F. 2\" UND 1\" ROHR SCHWENKBAR 360 Grad", - "sivas_id": 922083009, - "farbig": false, - "stueckzahl": 1, - "anzahl_vorgabe": 2 - }, - { - "artikel": "HALTEARM FÜR BODENSÄULE R 2\" 1-ARMIG KPL.", - "sivas_id": 821004051, - "farbig": true, - "stueckzahl": 1, - "anzahl_vorgabe": 1 - }, - { - "artikel": "HALTEARM FÜR BODENSÄULE R 2\" 2-ARMIG 90 Grad KPL.", - "sivas_id": 821004054, - "farbig": true, - "stueckzahl": 1, - "anzahl_vorgabe": 1 - }, - { - "artikel": "HALTEARM FÜR BODENSÄULE R 2\" 2-ARMIG 180 Grad KPL.", - "sivas_id": 821004052, - "farbig": true, - "stueckzahl": 1, - "anzahl_vorgabe": 1 - }, - { - "artikel": "HALTEARM FÜR BODENSÄULE R 2\" 3-ARMIG KPL.", - "sivas_id": 821004053, - "farbig": true, - "stueckzahl": 1, - "anzahl_vorgabe": 1 - } - ], - "konfigurationen": [ - { - "name": "Bodensaeule 1 Zoll, Standardhoehe", - "variante": "R 1\"", - "laenge": 1000, - "teilefarbe": "RAL7035", - "oben": [], - "unten": [] - }, - { - "name": "Bodensaeule 2 Zoll, Haltearm 1-armig", - "variante": "R 2\" Haltearm 1-ARMIG", - "laenge": 1200, - "teilefarbe": "RAL7035", - "oben": [ - { - "artikel": "KLEMMRING MIT MUFFE EINFACH KPL.", - "anzahl": 2 - } - ], - "unten": [] - }, - { - "name": "Bodensaeule 2 Zoll, Haltearm 2-armig 90 Grad", - "variante": "R 2\" Haltearm 2-ARMIG 90 Grad", - "laenge": 1200, - "teilefarbe": "RAL7035", - "oben": [ - { - "artikel": "KLEMMRING MIT MUFFE DOPPELT 90 Grad, KPL.", - "anzahl": 2 - } - ], - "unten": [ - { - "artikel": "QUERSCHELLE F. 1\" UND 2\" ROHR GESCHW./VZ. M. 4X M10X30 KPL.", - "anzahl": 2 - } - ] - } - ] + "anbaugruppen": { + "befestigung": [ + { + "artikel": "KLEMMRING MIT MUFFE EINFACH KPL.", + "sivas_id": 825002019, + "farbig": false, + "stueckzahl": 1, + "anzahl_vorgabe": 2 + }, + { + "artikel": "KLEMMRING MIT MUFFE DOPPELT 90 Grad, KPL.", + "sivas_id": 825002009, + "farbig": false, + "stueckzahl": 1, + "anzahl_vorgabe": 2 + }, + { + "artikel": "KLEMMRING MIT MUFFE DOPPELT 180 Grad, KPL.", + "sivas_id": 825002008, + "farbig": false, + "stueckzahl": 1, + "anzahl_vorgabe": 2 + }, + { + "artikel": "KLEMMRING M. MUFFE DREIFACH 90 Grad/180 Grad KPL.", + "sivas_id": 825002007, + "farbig": false, + "stueckzahl": 1, + "anzahl_vorgabe": 2 + }, + { + "artikel": "KLEMMRING MIT LASCHE KPL. ZUSAMMENBAUZEICHNUNG", + "sivas_id": 825002020, + "farbig": false, + "stueckzahl": 1, + "anzahl_vorgabe": 2 + }, + { + "artikel": "QUERSCHELLE F. 1\" UND 2\" ROHR GESCHW./VZ. M. 4X M10X30 KPL.", + "sivas_id": 825002022, + "farbig": false, + "stueckzahl": 1, + "anzahl_vorgabe": 2 + }, + { + "artikel": "KREUZSCHELLE F. 2\" UND 1\" ROHR SCHWENKBAR 360 Grad", + "sivas_id": 922083009, + "farbig": false, + "stueckzahl": 1, + "anzahl_vorgabe": 2 + } + ], + "sonstiges": [ + { + "artikel": "HALTEARM FÜR BODENSÄULE R 2\" 1-ARMIG KPL.", + "sivas_id": 821004051, + "farbig": true, + "stueckzahl": 1, + "anzahl_vorgabe": 1 + }, + { + "artikel": "HALTEARM FÜR BODENSÄULE R 2\" 2-ARMIG 90 Grad KPL.", + "sivas_id": 821004054, + "farbig": true, + "stueckzahl": 1, + "anzahl_vorgabe": 1 + }, + { + "artikel": "HALTEARM FÜR BODENSÄULE R 2\" 2-ARMIG 180 Grad KPL.", + "sivas_id": 821004052, + "farbig": true, + "stueckzahl": 1, + "anzahl_vorgabe": 1 + }, + { + "artikel": "HALTEARM FÜR BODENSÄULE R 2\" 3-ARMIG KPL.", + "sivas_id": 821004053, + "farbig": true, + "stueckzahl": 1, + "anzahl_vorgabe": 1 + } + ] + }, + "konfigurationen": [] }, "Wandbefestigung": { "id": "Wandbefestigung", @@ -449,61 +375,41 @@ ] } ], - "anbaugruppen": [ - { - "name": "Nylondübel 12x60 inkl. Holzschrauben", - "anzahl_vorgabe": 2, - "teile": [ - { - "artikel": "HOLZSCHRAUB,10X70, 6KT DIN 571 VZ", - "sivas_id": 911271027, - "farbig": false, - "stueckzahl": 1 - }, - { - "artikel": "NYLON - DUEBEL 12X60 (TYP S)", - "sivas_id": 922013003, - "farbig": false, - "stueckzahl": 1 - } - ] - }, - { - "name": "HST M12X115X20", - "anzahl_vorgabe": 2, - "teile": [ - { - "artikel": "DURCHSTECKANKER HST M12X115X20 WANDABH.", - "sivas_id": 922021003, - "farbig": false, - "stueckzahl": 1 - } - ] - } - ], - "konfigurationen": [ - { - "name": "Wandflansch mit Duebeln", - "variante": "WANDFLANSCH EINZELTEIL", - "oben": [ - { - "artikel": "Nylondübel 12x60 inkl. Holzschrauben", - "anzahl": 2 - } - ], - "unten": [] - }, - { - "name": "Winkel 300 mit Schwerlastanker", - "variante": "WINKEL 60X60X6X300", - "oben": [ - { - "artikel": "HST M12X115X20", - "anzahl": 2 - } - ], - "unten": [] - } - ] + "anbaugruppen": { + "befestigung": [ + { + "name": "Nylondübel 12x60 inkl. Holzschrauben", + "anzahl_vorgabe": 2, + "teile": [ + { + "artikel": "HOLZSCHRAUB,10X70, 6KT DIN 571 VZ", + "sivas_id": 911271027, + "farbig": false, + "stueckzahl": 1 + }, + { + "artikel": "NYLON - DUEBEL 12X60 (TYP S)", + "sivas_id": 922013003, + "farbig": false, + "stueckzahl": 1 + } + ] + }, + { + "name": "HST M12X115X20", + "anzahl_vorgabe": 2, + "teile": [ + { + "artikel": "DURCHSTECKANKER HST M12X115X20 WANDABH.", + "sivas_id": 922021003, + "farbig": false, + "stueckzahl": 1 + } + ] + } + ], + "sonstiges": [] + }, + "konfigurationen": [] } } \ No newline at end of file diff --git a/data/json/geruest_traeger.json b/data/json/geruest_traeger.json index 19f0da3..8a6275d 100644 --- a/data/json/geruest_traeger.json +++ b/data/json/geruest_traeger.json @@ -89,6 +89,7 @@ "text": "DRT 80", "layer": "D-1-BEM" }, + "mit_querstrebe": true, "teileart": "Geruest Traeger", "layer": "D-1", "teile": [ @@ -107,6 +108,7 @@ "layer": "D-1-BEM" }, "mit_muffe": true, + "mit_querstrebe": true, "teileart": "Geruest Traeger", "layer": "D-1", "teile": [ @@ -124,6 +126,7 @@ "text": "DRT 114", "layer": "D-3-BEM" }, + "mit_querstrebe": true, "teileart": "Geruest Traeger", "layer": "D-3", "teile": [ @@ -142,6 +145,7 @@ "layer": "D-3-BEM" }, "mit_muffe": true, + "mit_querstrebe": true, "teileart": "Geruest Traeger", "layer": "D-3", "teile": [ @@ -159,6 +163,7 @@ "text": "RT 80/80", "layer": "D-5-BEM" }, + "mit_querstrebe": true, "teileart": "Geruest Traeger", "layer": "D-5", "teile": [ @@ -177,6 +182,7 @@ "layer": "D-5-BEM" }, "mit_muffe": true, + "mit_querstrebe": true, "teileart": "Geruest Traeger", "layer": "D-5", "teile": [ diff --git a/data/json/omniflo_fahrstrecke.json b/data/json/omniflo_fahrstrecke.json new file mode 100644 index 0000000..4cedcbf --- /dev/null +++ b/data/json/omniflo_fahrstrecke.json @@ -0,0 +1,157 @@ +{ + "Fahrstrecke": { + "id": "Fahrstrecke", + "titel": "Fahrstrecke", + "teileart": "Omniflo Fahrstrecke", + "muffe": { + "dummy": "dummy_Muffe_1zoll.dwg" + }, + "beschriftung": { + "format": "%1 L=%2", + "stil": "Lan", + "ausrichtung": "BL", + "hoehe": 100 + }, + "attribute": { + "LAENGE": { + "typ": "number", + "min": 0, + "max": 6000, + "einheit": "mm" + }, + "TEILEFARBE": { + "typ": "auswahl", + "optionen": [ + "RAL7035", + "RAL7030" + ], + "frei_erlaubt": true, + "frei_option": "Individuell" + } + }, + "geometrie_varianten": [ + { + "name": "AP 110", + "beschriftung": { + "text": "AP 110", + "layer": "A-7-BEM" + }, + "teileart": "Omniflo Fahrstrecke", + "layer": "A-7", + "teile": [ + { + "artikel": "AP 110", + "sivas_id": 821106001, + "stueckzahl": 1 + } + ] + }, + { + "name": "APG 110", + "beschriftung": { + "text": "APG 110", + "layer": "A-2-BEM" + }, + "teileart": "Omniflo Fahrstrecke", + "layer": "A-2", + "teile": [ + { + "artikel": "APG 110", + "sivas_id": 821106002, + "stueckzahl": 1 + } + ] + }, + { + "name": "AP 60", + "beschriftung": { + "text": "AP 60", + "layer": "A-4-BEM" + }, + "teileart": "Omniflo Fahrstrecke", + "layer": "A-4", + "teile": [ + { + "artikel": "AP 60", + "sivas_id": 821096001, + "stueckzahl": 1 + } + ] + }, + { + "name": "ST", + "beschriftung": { + "text": "ST", + "layer": "L-2-BEM" + }, + "mit_muffe": false, + "teileart": "Omniflo Fahrstrecke", + "layer": "L-2", + "teile": [ + { + "artikel": "ST", + "sivas_id": 821084000, + "farbig": true, + "stueckzahl": 1 + } + ] + }, + { + "name": "ST mit Muffen", + "disabled": true, + "beschriftung": { + "text": "ST", + "layer": "L-2-BEM" + }, + "mit_muffe": true, + "teileart": "Omniflo Fahrstrecke", + "layer": "L-2", + "teile": [ + { + "artikel": "ST mit Muffen", + "sivas_id": 821084007, + "farbig": true, + "stueckzahl": 1 + } + ] + }, + { + "name": "STL", + "beschriftung": { + "text": "STL", + "layer": "L-2-BEM" + }, + "mit_muffe": false, + "teileart": "Omniflo Fahrstrecke", + "layer": "L-2", + "teile": [ + { + "artikel": "STL", + "sivas_id": 821084050, + "farbig": true, + "stueckzahl": 1 + } + ] + }, + { + "name": "STL mit Muffen", + "disabled": true, + "beschriftung": { + "text": "STL", + "layer": "L-2-BEM" + }, + "mit_muffe": true, + "teileart": "Omniflo Fahrstrecke", + "layer": "L-2", + "teile": [ + { + "artikel": "STL mit Muffen", + "sivas_id": 821084057, + "farbig": true, + "stueckzahl": 1 + } + ] + } + ] + } +} \ No newline at end of file diff --git a/data/json/omniflo_ladeschleifen.json b/data/json/omniflo_ladeschleifen.json new file mode 100644 index 0000000..12128b1 --- /dev/null +++ b/data/json/omniflo_ladeschleifen.json @@ -0,0 +1,10 @@ +[ + { + "Sivasnr": 824331125, + "Beschreibung": "Ladeschleife - 6300, stufenlos ausziehbar, kpl.", + "Laenge": 6300, + "ProfilTyp": "AP 110", + "Stuetzfuß": 0, + "Antriebsart": 0 + } +] diff --git a/data/json/omniflo_weichen.json b/data/json/omniflo_weichen.json index a2be83d..03f2adb 100644 --- a/data/json/omniflo_weichen.json +++ b/data/json/omniflo_weichen.json @@ -1,76 +1,4 @@ [ - { - "Sivasnr": 834372001, - "ProfilTyp": "WEICHE S 45-L-350/700, KPL. MIT M", - "WeichenTyp": "Einzelweiche", - "KurvenWinkel": 45, - "Schaltungstyp": "M", - "Breite": 350, - "Länge": 700, - "KurvenRichtung": 1, - "SivasnrTEF": null, - "WeichenkörperLänge": 360 - }, - { - "Sivasnr": 834372002, - "ProfilTyp": "WEICHE S 45-L-350/700, KPL. MIT P", - "WeichenTyp": "Einzelweiche", - "KurvenWinkel": 45, - "Schaltungstyp": "P", - "Breite": 350, - "Länge": 700, - "KurvenRichtung": 1, - "SivasnrTEF": null, - "WeichenkörperLänge": 360 - }, - { - "Sivasnr": "834372002+0_BG090090", - "ProfilTyp": "WEICHE S 45-L-350/700, KPL. MIT P mit TEF Innen", - "WeichenTyp": "Einzelweiche", - "KurvenWinkel": 45, - "Schaltungstyp": "P", - "Breite": 350, - "Länge": 700, - "KurvenRichtung": 1, - "SivasnrTEF": "0_B10090+0_B10090", - "WeichenkörperLänge": 360 - }, - { - "Sivasnr": 834372004, - "ProfilTyp": "WEICHE S 45-R-350/700, KPL. MIT M", - "WeichenTyp": "Einzelweiche", - "KurvenWinkel": 45, - "Schaltungstyp": "M", - "Breite": 350, - "Länge": 700, - "KurvenRichtung": 2, - "SivasnrTEF": null, - "WeichenkörperLänge": 360 - }, - { - "Sivasnr": 834372005, - "ProfilTyp": "WEICHE S 45-R-350/700, KPL. MIT P", - "WeichenTyp": "Einzelweiche", - "KurvenWinkel": 45, - "Schaltungstyp": "P", - "Breite": 350, - "Länge": 700, - "KurvenRichtung": 2, - "SivasnrTEF": null, - "WeichenkörperLänge": 360 - }, - { - "Sivasnr": "834372005+0_BG090090", - "ProfilTyp": "WEICHE S 45-R-350/700, KPL. MIT P mit TEF Innen", - "WeichenTyp": "Einzelweiche", - "KurvenWinkel": 45, - "Schaltungstyp": "P", - "Breite": 350, - "Länge": 700, - "KurvenRichtung": 2, - "SivasnrTEF": "0_B10090+0_B10090", - "WeichenkörperLänge": 360 - }, { "Sivasnr": 834372007, "ProfilTyp": "WEICHE S 45-L-400/750, KPL. MIT M", @@ -144,53 +72,77 @@ "WeichenkörperLänge": 360 }, { - "Sivasnr": 834372021, - "ProfilTyp": "WEICHE S 90-L-500/600, KPL. MIT M", + "Sivasnr": 834372001, + "ProfilTyp": "WEICHE S 45-L-350/700, KPL. MIT M", "WeichenTyp": "Einzelweiche", - "KurvenWinkel": 90, + "KurvenWinkel": 45, "Schaltungstyp": "M", - "Breite": 500, - "Länge": 600, + "Breite": 350, + "Länge": 700, "KurvenRichtung": 1, "SivasnrTEF": null, "WeichenkörperLänge": 360 }, { - "Sivasnr": 834372022, - "ProfilTyp": "WEICHE S 90-L-500/600, KPL. MIT P", + "Sivasnr": 834372002, + "ProfilTyp": "WEICHE S 45-L-350/700, KPL. MIT P", "WeichenTyp": "Einzelweiche", - "KurvenWinkel": 90, + "KurvenWinkel": 45, "Schaltungstyp": "P", - "Breite": 500, - "Länge": 600, + "Breite": 350, + "Länge": 700, "KurvenRichtung": 1, "SivasnrTEF": null, "WeichenkörperLänge": 360 }, { - "Sivasnr": 834372024, - "ProfilTyp": "WEICHE S 90-R-500/600, KPL. MIT M", + "Sivasnr": "834372002+0_BG090090", + "ProfilTyp": "WEICHE S 45-L-350/700, KPL. MIT P mit TEF Innen", "WeichenTyp": "Einzelweiche", - "KurvenWinkel": 90, + "KurvenWinkel": 45, + "Schaltungstyp": "P", + "Breite": 350, + "Länge": 700, + "KurvenRichtung": 1, + "SivasnrTEF": "0_B10090+0_B10090", + "WeichenkörperLänge": 360 + }, + { + "Sivasnr": 834372004, + "ProfilTyp": "WEICHE S 45-R-350/700, KPL. MIT M", + "WeichenTyp": "Einzelweiche", + "KurvenWinkel": 45, "Schaltungstyp": "M", - "Breite": 500, - "Länge": 600, + "Breite": 350, + "Länge": 700, "KurvenRichtung": 2, "SivasnrTEF": null, "WeichenkörperLänge": 360 }, { - "Sivasnr": 834372025, - "ProfilTyp": "WEICHE S 90-R-500/600, KPL. MIT P", + "Sivasnr": 834372005, + "ProfilTyp": "WEICHE S 45-R-350/700, KPL. MIT P", "WeichenTyp": "Einzelweiche", - "KurvenWinkel": 90, + "KurvenWinkel": 45, "Schaltungstyp": "P", - "Breite": 500, - "Länge": 600, + "Breite": 350, + "Länge": 700, "KurvenRichtung": 2, "SivasnrTEF": null, "WeichenkörperLänge": 360 }, + { + "Sivasnr": "834372005+0_BG090090", + "ProfilTyp": "WEICHE S 45-R-350/700, KPL. MIT P mit TEF Innen", + "WeichenTyp": "Einzelweiche", + "KurvenWinkel": 45, + "Schaltungstyp": "P", + "Breite": 350, + "Länge": 700, + "KurvenRichtung": 2, + "SivasnrTEF": "0_B10090+0_B10090", + "WeichenkörperLänge": 360 + }, { "Sivasnr": 834372027, "ProfilTyp": "WEICHE S 90-L-700/700, KPL. MIT M", @@ -263,6 +215,54 @@ "SivasnrTEF": "0_B10080+0_B10090", "WeichenkörperLänge": 360 }, + { + "Sivasnr": 834372021, + "ProfilTyp": "WEICHE S 90-L-500/600, KPL. MIT M", + "WeichenTyp": "Einzelweiche", + "KurvenWinkel": 90, + "Schaltungstyp": "M", + "Breite": 500, + "Länge": 600, + "KurvenRichtung": 1, + "SivasnrTEF": null, + "WeichenkörperLänge": 360 + }, + { + "Sivasnr": 834372022, + "ProfilTyp": "WEICHE S 90-L-500/600, KPL. MIT P", + "WeichenTyp": "Einzelweiche", + "KurvenWinkel": 90, + "Schaltungstyp": "P", + "Breite": 500, + "Länge": 600, + "KurvenRichtung": 1, + "SivasnrTEF": null, + "WeichenkörperLänge": 360 + }, + { + "Sivasnr": 834372024, + "ProfilTyp": "WEICHE S 90-R-500/600, KPL. MIT M", + "WeichenTyp": "Einzelweiche", + "KurvenWinkel": 90, + "Schaltungstyp": "M", + "Breite": 500, + "Länge": 600, + "KurvenRichtung": 2, + "SivasnrTEF": null, + "WeichenkörperLänge": 360 + }, + { + "Sivasnr": 834372025, + "ProfilTyp": "WEICHE S 90-R-500/600, KPL. MIT P", + "WeichenTyp": "Einzelweiche", + "KurvenWinkel": 90, + "Schaltungstyp": "P", + "Breite": 500, + "Länge": 600, + "KurvenRichtung": 2, + "SivasnrTEF": null, + "WeichenkörperLänge": 360 + }, { "Sivasnr": 834372047, "ProfilTyp": "WEICHE S PARALLEL-L-200/750, KPL. MIT M", @@ -311,61 +311,6 @@ "SivasnrTEF": null, "WeichenkörperLänge": 360 }, - { - "Sivasnr": 834372100, - "ProfilTyp": "WEICHE S D 45-350/700, KPL. MIT M", - "WeichenTyp": "Doppelweiche", - "KurvenWinkel": 45, - "Schaltungstyp": "M", - "Breite": 350, - "Länge": 700, - "KurvenRichtung": 3, - "SivasnrTEF": null - }, - { - "Sivasnr": 834372101, - "ProfilTyp": "WEICHE S D 45-350/700, KPL. MIT P", - "WeichenTyp": "Doppelweiche", - "KurvenWinkel": 45, - "Schaltungstyp": "P", - "Breite": 350, - "Länge": 700, - "KurvenRichtung": 3, - "SivasnrTEF": null - }, - { - "Sivasnr": "0_BG090090+834372101", - "ProfilTyp": "WEICHE S D 45-350/700, KPL. MIT P mit TEF links", - "WeichenTyp": "Doppelweiche", - "KurvenWinkel": 45, - "Schaltungstyp": "P", - "Breite": 350, - "Länge": 700, - "KurvenRichtung": 3, - "SivasnrTEF": "0_B10090+0_B10090" - }, - { - "Sivasnr": "834372101+0_BG090090", - "ProfilTyp": "WEICHE S D 45-350/700, KPL. MIT P mit TEF rechts", - "WeichenTyp": "Doppelweiche", - "KurvenWinkel": 45, - "Schaltungstyp": "P", - "Breite": 350, - "Länge": 700, - "KurvenRichtung": 3, - "SivasnrTEF": "0_B10090+0_B10090" - }, - { - "Sivasnr": "0_BG090090+834372101+0_BG090090", - "ProfilTyp": "WEICHE S D 45-350/700, KPL. MIT P mit TEF beideseitig", - "WeichenTyp": "Doppelweiche", - "KurvenWinkel": 45, - "Schaltungstyp": "P", - "Breite": 350, - "Länge": 700, - "KurvenRichtung": 3, - "SivasnrTEF": "0_B10090+0_B10090+0_B10090+0_B10090" - }, { "Sivasnr": 834372103, "ProfilTyp": "WEICHE S D 45-400/750, KPL. MIT M", @@ -422,27 +367,60 @@ "SivasnrTEF": "0_B10090+0_B10090+0_B10090+0_B10090" }, { - "Sivasnr": 834372106, - "ProfilTyp": "WEICHE S D 90-500/600, KPL. MIT M", + "Sivasnr": 834372100, + "ProfilTyp": "WEICHE S D 45-350/700, KPL. MIT M", "WeichenTyp": "Doppelweiche", - "KurvenWinkel": 90, + "KurvenWinkel": 45, "Schaltungstyp": "M", - "Breite": 500, - "Länge": 600, + "Breite": 350, + "Länge": 700, "KurvenRichtung": 3, "SivasnrTEF": null }, { - "Sivasnr": 834372107, - "ProfilTyp": "WEICHE S D 90-500/600, KPL. MIT P", + "Sivasnr": 834372101, + "ProfilTyp": "WEICHE S D 45-350/700, KPL. MIT P", "WeichenTyp": "Doppelweiche", - "KurvenWinkel": 90, + "KurvenWinkel": 45, "Schaltungstyp": "P", - "Breite": 500, - "Länge": 600, + "Breite": 350, + "Länge": 700, "KurvenRichtung": 3, "SivasnrTEF": null }, + { + "Sivasnr": "0_BG090090+834372101", + "ProfilTyp": "WEICHE S D 45-350/700, KPL. MIT P mit TEF links", + "WeichenTyp": "Doppelweiche", + "KurvenWinkel": 45, + "Schaltungstyp": "P", + "Breite": 350, + "Länge": 700, + "KurvenRichtung": 3, + "SivasnrTEF": "0_B10090+0_B10090" + }, + { + "Sivasnr": "834372101+0_BG090090", + "ProfilTyp": "WEICHE S D 45-350/700, KPL. MIT P mit TEF rechts", + "WeichenTyp": "Doppelweiche", + "KurvenWinkel": 45, + "Schaltungstyp": "P", + "Breite": 350, + "Länge": 700, + "KurvenRichtung": 3, + "SivasnrTEF": "0_B10090+0_B10090" + }, + { + "Sivasnr": "0_BG090090+834372101+0_BG090090", + "ProfilTyp": "WEICHE S D 45-350/700, KPL. MIT P mit TEF beideseitig", + "WeichenTyp": "Doppelweiche", + "KurvenWinkel": 45, + "Schaltungstyp": "P", + "Breite": 350, + "Länge": 700, + "KurvenRichtung": 3, + "SivasnrTEF": "0_B10090+0_B10090+0_B10090+0_B10090" + }, { "Sivasnr": 834372109, "ProfilTyp": "WEICHE S D 90-700/700, KPL. MIT M", @@ -498,6 +476,28 @@ "KurvenRichtung": 3, "SivasnrTEF": "0_B10080+0_B10090+0_B10080+0_B10090" }, + { + "Sivasnr": 834372106, + "ProfilTyp": "WEICHE S D 90-500/600, KPL. MIT M", + "WeichenTyp": "Doppelweiche", + "KurvenWinkel": 90, + "Schaltungstyp": "M", + "Breite": 500, + "Länge": 600, + "KurvenRichtung": 3, + "SivasnrTEF": null + }, + { + "Sivasnr": 834372107, + "ProfilTyp": "WEICHE S D 90-500/600, KPL. MIT P", + "WeichenTyp": "Doppelweiche", + "KurvenWinkel": 90, + "Schaltungstyp": "P", + "Breite": 500, + "Länge": 600, + "KurvenRichtung": 3, + "SivasnrTEF": null + }, { "Sivasnr": 834372115, "ProfilTyp": "WEICHE S D PARALLEL-200/750, KPL. MIT M", @@ -520,61 +520,6 @@ "KurvenRichtung": 3, "SivasnrTEF": null }, - { - "Sivasnr": 834372200, - "ProfilTyp": "WEICHE S T 45-350/700, KPL. MIT M", - "WeichenTyp": "Dreiwegeweiche", - "KurvenWinkel": 45, - "Schaltungstyp": "M", - "Breite": 350, - "Länge": 700, - "KurvenRichtung": 7, - "SivasnrTEF": null - }, - { - "Sivasnr": 834372201, - "ProfilTyp": "WEICHE S T 45-350/700, KPL. MIT P", - "WeichenTyp": "Dreiwegeweiche", - "KurvenWinkel": 45, - "Schaltungstyp": "P", - "Breite": 350, - "Länge": 700, - "KurvenRichtung": 7, - "SivasnrTEF": null - }, - { - "Sivasnr": "0_BG090090+834372201", - "ProfilTyp": "WEICHE S T 45-350/700, KPL. MIT P mit TEF links", - "WeichenTyp": "Dreiwegeweiche", - "KurvenWinkel": 45, - "Schaltungstyp": "P", - "Breite": 350, - "Länge": 700, - "KurvenRichtung": 7, - "SivasnrTEF": "0_B10090+0_B10090" - }, - { - "Sivasnr": "834372201+0_BG090090", - "ProfilTyp": "WEICHE S T 45-350/700, KPL. MIT P mit TEF rechts", - "WeichenTyp": "Dreiwegeweiche", - "KurvenWinkel": 45, - "Schaltungstyp": "P", - "Breite": 350, - "Länge": 700, - "KurvenRichtung": 7, - "SivasnrTEF": "0_B10090+0_B10090" - }, - { - "Sivasnr": "0_BG090090+834372201+0_BG090090", - "ProfilTyp": "WEICHE S T 45-350/700, KPL. MIT P mit TEF beideseitig", - "WeichenTyp": "Dreiwegeweiche", - "KurvenWinkel": 45, - "Schaltungstyp": "P", - "Breite": 350, - "Länge": 700, - "KurvenRichtung": 7, - "SivasnrTEF": "0_B10090+0_B10090+0_B10090+0_B10090" - }, { "Sivasnr": 834372203, "ProfilTyp": "WEICHE S T 45-400/750, KPL. MIT M", @@ -631,27 +576,60 @@ "SivasnrTEF": "0_B10090+0_B10090+0_B10090+0_B10090" }, { - "Sivasnr": 834372206, - "ProfilTyp": "WEICHE S T 90-500/600, KPL. MIT M", + "Sivasnr": 834372200, + "ProfilTyp": "WEICHE S T 45-350/700, KPL. MIT M", "WeichenTyp": "Dreiwegeweiche", - "KurvenWinkel": 90, + "KurvenWinkel": 45, "Schaltungstyp": "M", - "Breite": 500, - "Länge": 600, + "Breite": 350, + "Länge": 700, "KurvenRichtung": 7, "SivasnrTEF": null }, { - "Sivasnr": 834372207, - "ProfilTyp": "WEICHE S T 90-500/600, KPL. MIT P", + "Sivasnr": 834372201, + "ProfilTyp": "WEICHE S T 45-350/700, KPL. MIT P", "WeichenTyp": "Dreiwegeweiche", - "KurvenWinkel": 90, + "KurvenWinkel": 45, "Schaltungstyp": "P", - "Breite": 500, - "Länge": 600, + "Breite": 350, + "Länge": 700, "KurvenRichtung": 7, "SivasnrTEF": null }, + { + "Sivasnr": "0_BG090090+834372201", + "ProfilTyp": "WEICHE S T 45-350/700, KPL. MIT P mit TEF links", + "WeichenTyp": "Dreiwegeweiche", + "KurvenWinkel": 45, + "Schaltungstyp": "P", + "Breite": 350, + "Länge": 700, + "KurvenRichtung": 7, + "SivasnrTEF": "0_B10090+0_B10090" + }, + { + "Sivasnr": "834372201+0_BG090090", + "ProfilTyp": "WEICHE S T 45-350/700, KPL. MIT P mit TEF rechts", + "WeichenTyp": "Dreiwegeweiche", + "KurvenWinkel": 45, + "Schaltungstyp": "P", + "Breite": 350, + "Länge": 700, + "KurvenRichtung": 7, + "SivasnrTEF": "0_B10090+0_B10090" + }, + { + "Sivasnr": "0_BG090090+834372201+0_BG090090", + "ProfilTyp": "WEICHE S T 45-350/700, KPL. MIT P mit TEF beideseitig", + "WeichenTyp": "Dreiwegeweiche", + "KurvenWinkel": 45, + "Schaltungstyp": "P", + "Breite": 350, + "Länge": 700, + "KurvenRichtung": 7, + "SivasnrTEF": "0_B10090+0_B10090+0_B10090+0_B10090" + }, { "Sivasnr": 834372209, "ProfilTyp": "WEICHE S T 90-700/700, KPL. MIT M", @@ -707,6 +685,28 @@ "KurvenRichtung": 7, "SivasnrTEF": "0_B10080+0_B10090+0_B10080+0_B10090" }, + { + "Sivasnr": 834372206, + "ProfilTyp": "WEICHE S T 90-500/600, KPL. MIT M", + "WeichenTyp": "Dreiwegeweiche", + "KurvenWinkel": 90, + "Schaltungstyp": "M", + "Breite": 500, + "Länge": 600, + "KurvenRichtung": 7, + "SivasnrTEF": null + }, + { + "Sivasnr": 834372207, + "ProfilTyp": "WEICHE S T 90-500/600, KPL. MIT P", + "WeichenTyp": "Dreiwegeweiche", + "KurvenWinkel": 90, + "Schaltungstyp": "P", + "Breite": 500, + "Länge": 600, + "KurvenRichtung": 7, + "SivasnrTEF": null + }, { "Sivasnr": 834372215, "ProfilTyp": "WEICHE S T PARALLEL-200/750, KPL. MIT M", @@ -729,30 +729,6 @@ "KurvenRichtung": 7, "SivasnrTEF": null }, - { - "Sivasnr": 834372400, - "ProfilTyp": "WEICHE S C DELTA 1400/700, KPL. M", - "WeichenTyp": "Deltaweiche", - "KurvenWinkel": 90, - "Schaltungstyp": "M", - "Breite": 1400, - "Länge": 700, - "KurvenRichtung": 3, - "SivasnrTEF": null, - "WeichenkörperLänge": 1400.4619 - }, - { - "Sivasnr": 834372401, - "ProfilTyp": "WEICHE S C DELTA 1400/700, KPL. P", - "WeichenTyp": "Deltaweiche", - "KurvenWinkel": 90, - "Schaltungstyp": "P", - "Breite": 1400, - "Länge": 700, - "KurvenRichtung": 7, - "SivasnrTEF": null, - "WeichenkörperLänge": 1400.4619 - }, { "Sivasnr": 834372403, "ProfilTyp": "WEICHE S C DELTA 1600/800, KPL. M", @@ -812,6 +788,30 @@ "KurvenRichtung": 3, "SivasnrTEF": "0_B10090+0_B10090+0_B10071", "WeichenkörperLänge": 1600.3844 + }, + { + "Sivasnr": 834372400, + "ProfilTyp": "WEICHE S C DELTA 1400/700, KPL. M", + "WeichenTyp": "Deltaweiche", + "KurvenWinkel": 90, + "Schaltungstyp": "M", + "Breite": 1400, + "Länge": 700, + "KurvenRichtung": 3, + "SivasnrTEF": null, + "WeichenkörperLänge": 1400.4619 + }, + { + "Sivasnr": 834372401, + "ProfilTyp": "WEICHE S C DELTA 1400/700, KPL. P", + "WeichenTyp": "Deltaweiche", + "KurvenWinkel": 90, + "Schaltungstyp": "P", + "Breite": 1400, + "Länge": 700, + "KurvenRichtung": 7, + "SivasnrTEF": null, + "WeichenkörperLänge": 1400.4619 }, { "Sivasnr": 834372420, @@ -927,4 +927,4 @@ "KurvenRichtung": 7, "SivasnrTEF": null } -] +] \ No newline at end of file diff --git a/data/omniflo/2D/824604001.dwg b/data/omniflo/2D/824604001.dwg index 5b691cb5170622f42abc0d1c1e382f02e562b6ff..3113bfd79b52a7b7b4ced9af6b462cb273a103f3 100644 GIT binary patch delta 28600 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

lT7Xjjbpd{RI8#mi$;;ni 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

  • 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 delta 9668 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 G)xQD8g%Q30 diff --git a/data/omniflo/2D/824604002.dwg b/data/omniflo/2D/824604002.dwg new file mode 100644 index 0000000000000000000000000000000000000000..258db6f69366f5ae98ec535835db0387efc048c3 GIT binary patch literal 32906 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 VsT&N9hGpxnE^c#iTtP?8{{n2{i4On( literal 0 HcmV?d00001 diff --git a/data/omniflo/2D/824604012.dwg b/data/omniflo/2D/824604012.dwg new file mode 100644 index 0000000000000000000000000000000000000000..c6258c475a48b0c80c170eb36b524a3a1416b571 GIT binary patch literal 44203 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 VwI}H3pe?)VH}t!Ccl6$d{{(rz, i = Index in geometrie_varianten) ersetzt +// (ssg-dcl-vorlage-fuellen, ssg_core.lsp). Das Ergebnis wird als Temp-Datei +// geladen. +// +// Jede Variante (auch die mit Muffe) hat einen eigenen Radiobutton, damit +// ihre Artikelnummer sichtbar ist. +// +// Die Laenge steht bewusst NICHT im Dialog - sie wird nach dem Dialog in der +// Zeichnung per Start-/Endpunkt (oder getippter Laenge) bestimmt. +// ============================================================ + +fahrstrecke : dialog { + label = "Fahrstrecke konfigurieren"; + + : boxed_column { + label = "Basis"; + : radio_column { + key = "variante"; + label = "Variante:"; + alignment = left; + //@VARIANTEN@ + } + : row { + : popup_list { key = "farbe"; label = "Farbe:"; width = 25; } + : edit_box { key = "farbe_frei"; label = "eigene:"; edit_width = 12; } + } + } + + : boxed_column { + label = "Längenabzug"; + : row { + : toggle { key = "abzug_a"; label = "Längenabzug Anfang"; width = 24; fixed_width = true; } + : edit_box { key = "abzug_a_w"; label = "mm:"; edit_width = 8; fixed_width = true; } + } + : row { + : toggle { key = "abzug_e"; label = "Längenabzug Ende"; width = 24; fixed_width = true; } + : edit_box { key = "abzug_e_w"; label = "mm:"; edit_width = 8; fixed_width = true; } + } + } + + : toggle { key = "beschriftung"; label = "Beschriftung einfügen"; } + + : text { key = "hinweis"; label = ""; width = 56; } + + ok_cancel; +} diff --git a/dcl/geruest.dcl b/dcl/geruest.dcl new file mode 100644 index 0000000..70034df --- /dev/null +++ b/dcl/geruest.dcl @@ -0,0 +1,55 @@ +// ============================================================ +// geruest.dcl - Geruest-Baugruppe konfigurieren (VORLAGE) +// Verwendet von: GERUEST_SAEULEN, GERUEST_ROHRABHAENGER, +// GERUEST_WANDBEFESTIGUNG (GeruestInsert.lsp, geruest-dialog) +// +// Diese Datei wird NICHT direkt geladen: Zeilen der Form //@NAME@ sind +// Platzhalter, die GeruestInsert.lsp zur Laufzeit durch datenabhaengige +// Bloecke ersetzt (ssg-dcl-vorlage-fuellen, ssg_core.lsp) - DCL kann Tiles +// weder zur Laufzeit erzeugen noch ausblenden, und Radiobutton-Labels lassen +// sich per set_tile nicht aendern. Das Ergebnis wird als Temp-Datei geladen. +// +// //@TITEL@ label-Zeile des Dialogs (Bereichsname) +// //@VARIANTEN@ ein radio_button je Geometrie-Variante (key v) +// //@BEFESTIGUNG@ Spalte "Befestigung oben und unten" (Tile-Keys b/bm, +// entfaellt ohne Teile - ein leerer Cluster ist in DCL +// unzulaessig) +// //@SONSTIGES@ Spalte "Sonstiges" (s/sm, entfaellt ohne Teile) +// Je Teil: Mengenfeld, Ankreuzfeld und darunter "Art.-Nr. ..." (sivas_id). +// ============================================================ + +geruest : dialog { + //@TITEL@ + : row { + : popup_list { key = "konfig"; label = "Konfiguration:"; width = 40; } + : button { key = "kspeichern"; label = "Speichern..."; fixed_width = true; } + : button { key = "kloeschen"; label = "Löschen"; fixed_width = true; } + } + // Zeigt an, ob der Stand noch der gewaehlten Konfiguration entspricht + // (geruest-dlg-aenderung-pruefen). + : text { key = "kstatus"; label = ""; width = 64; } + + : boxed_column { + label = "Basis"; + // Radiobuttons statt Liste: alle Varianten sichtbar, Einfachauswahl, + // Beschriftung in voller Breite. + : radio_column { + key = "variante"; + label = "Variante:"; + alignment = left; + //@VARIANTEN@ + } + : row { + : edit_box { key = "laenge"; label = "Laenge (mm):"; edit_width = 10; } + : popup_list { key = "farbe"; label = "Farbe:"; width = 25; } + : edit_box { key = "farbe_frei"; label = "eigene:"; edit_width = 12; } + } + // Ausrichtung, in der die Anbauteile mit der Basis zusammengebaut werden + : popup_list { key = "winkel"; label = "Winkel Platte:"; width = 22; fixed_width = true; } + } + + //@BEFESTIGUNG@ + //@SONSTIGES@ + + ok_cancel; +} diff --git a/dcl/geruest_traeger.dcl b/dcl/geruest_traeger.dcl index c33cfe1..e12ce11 100644 --- a/dcl/geruest_traeger.dcl +++ b/dcl/geruest_traeger.dcl @@ -1,18 +1,32 @@ // ============================================================ -// geruest_traeger.dcl - Rohr-Geruest-Traeger konfigurieren +// geruest_traeger.dcl - Rohr-Geruest-Traeger konfigurieren (VORLAGE) // Verwendet von: GERUEST_TRAEGER (GeruestInsert.lsp, geruest-traeger-dialog) // +// Diese Datei wird NICHT direkt geladen: //@VARIANTEN@ ist ein Platzhalter, +// den GeruestInsert.lsp zur Laufzeit durch einen radio_button je +// Variante (key v, i = Index in geometrie_varianten) ersetzt +// (ssg-dcl-vorlage-fuellen, ssg_core.lsp) - Radiobutton-Labels lassen sich +// per set_tile nicht aendern. Das Ergebnis wird als Temp-Datei geladen. +// +// Jede Variante (auch die mit Muffe) hat einen eigenen Radiobutton, damit +// ihre Artikelnummer sichtbar ist. +// // Die Laenge steht bewusst NICHT im Dialog - sie wird nach dem Dialog in der // Zeichnung per Start-/Endpunkt (oder getippter Laenge) bestimmt. Aktive // Laengenabzuege ruecken die Linie am Anfang bzw. Ende ein. // ============================================================ geruest_traeger : dialog { - label = "Rohr-Geruest-Traeger konfigurieren"; + label = "Rohr-Gerüst-Träger konfigurieren"; : boxed_column { label = "Basis"; - : popup_list { key = "variante"; label = "Variante:"; width = 56; } + : radio_column { + key = "variante"; + label = "Variante:"; + alignment = left; + //@VARIANTEN@ + } : row { : popup_list { key = "farbe"; label = "Farbe:"; width = 25; } : edit_box { key = "farbe_frei"; label = "eigene:"; edit_width = 12; } @@ -20,18 +34,18 @@ geruest_traeger : dialog { } : boxed_column { - label = "Laengenabzug"; + label = "Längenabzug"; : row { - : toggle { key = "abzug_a"; label = "Laengenabzug Anfang"; width = 24; fixed_width = true; } + : toggle { key = "abzug_a"; label = "Längenabzug Anfang"; width = 24; fixed_width = true; } : edit_box { key = "abzug_a_w"; label = "mm:"; edit_width = 8; fixed_width = true; } } : row { - : toggle { key = "abzug_e"; label = "Laengenabzug Ende"; width = 24; fixed_width = true; } + : toggle { key = "abzug_e"; label = "Längenabzug Ende"; width = 24; fixed_width = true; } : edit_box { key = "abzug_e_w"; label = "mm:"; edit_width = 8; fixed_width = true; } } } - : toggle { key = "beschriftung"; label = "Beschriftung einfuegen"; } + : toggle { key = "beschriftung"; label = "Beschriftung einfügen"; } : text { key = "hinweis"; label = ""; width = 56; } diff --git a/lang/de_DE.json b/lang/de_DE.json index c58221b..948709b 100644 --- a/lang/de_DE.json +++ b/lang/de_DE.json @@ -973,6 +973,7 @@ "gr-fehler-json-lesbar": "\nGeruest: Datendatei nicht lesbar: %1", "gr-fehler-baugruppe": "\nGeruest: Baugruppe '%1' steht nicht in der Datendatei.", "gr-fehler-keine-varianten": "\nGeruest: Baugruppe '%1' hat keine Geometrie-Varianten.", + "gr-bereich-waehlen": "\nGeruest: bitte einen Bereich ueber das Menue waehlen (GERUEST_SAEULEN, GERUEST_ROHRABHAENGER, GERUEST_WANDBEFESTIGUNG).", "gr-fehler-dummy": "\nGeruest: Dummy-Baugruppe nicht gefunden: %1", "gr-fehler-dummy-variante": "\nGeruest: Dummy der Variante nicht gefunden: %1 - verwende Dummy der Baugruppe (%2)", "gr-fehler-dcl": "Dialog geruest.dcl konnte nicht geladen werden.", @@ -982,10 +983,15 @@ "gr-abgebrochen": "\nAbgebrochen.", "gr-fertig": "\nGeruest-Baugruppe '%1' eingefuegt (Block %2).", "gr-alert-menge": "Ungueltige Anzahl. Erlaubt ist eine ganze Zahl ab 1; ein leeres Feld uebernimmt den Vorgabewert.", - "gr-position-oben": "oben", - "gr-position-unten": "unten", + "gr-position-befestigung": "Befestigung", + "gr-position-sonstiges": "sonstiges", "gr-konfig-keine": "", "gr-konfig-name": "\nName der Konfiguration: ", + "gr-konfig-name-vorgabe": "\nName der Konfiguration <%1>: ", + "gr-konfig-geaendert": "%1 (geaendert)", + "gr-konfig-status-geaendert": "Geaendert gegenueber '%1' - Speichern (Enter beim Namen) ueberschreibt sie.", + "gr-konfig-status-bibliothek": "Geaendert gegenueber '%1' (Bibliothek, schreibgeschuetzt) - zum Speichern einen neuen Namen vergeben.", + "gr-winkel-grad": "%1%2", "gr-konfig-gespeichert": "\nKonfiguration '%1' gespeichert.", "gr-konfig-geloescht": "\nKonfiguration '%1' geloescht.", "gr-konfig-loeschen-frage": "\nKonfiguration '%1' wirklich loeschen? [Ja/Nein] : ", @@ -993,25 +999,26 @@ "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-konfig-variante-gesperrt": "\nKonfiguration '%2': Variante '%1' ist gesperrt - Auswahl bleibt unveraendert.", "gr-fehler-schreiben": "\nGeruest: Datei konnte nicht geschrieben werden: %1", "gr-fehler-keine-baugruppen": "\nGeruest: Die Datendatei enthaelt keine Baugruppen.", "gr-tr-fehler-dcl": "Dialog %1 konnte nicht geladen werden.", "gr-tr-hinweis": "Die Laenge wird nach OK in der Zeichnung bestimmt.", "gr-tr-alert-abzug": "Laengenabzug ungueltig. Erlaubt ist eine Zahl ab 0 (mm); ein leeres Feld gilt als 0.", - "gr-tr-prompt-start": "\nStartpunkt des Traegers waehlen : ", + "gr-tr-prompt-start": "\nStartpunkt (%1) waehlen : ", "gr-tr-prompt-ende": "\nEndpunkt waehlen oder Laenge (mm) eingeben: ", "gr-tr-prompt-richtung": "\nRichtung angeben <0>: ", "gr-tr-eingabe-ungueltig": "\nEingabe '%1' ist weder Punkt noch Laenge.", - "gr-tr-laenge-null": "\nStrecke %1 mm ist nicht laenger als die Abzuege (%2 mm) - kein Traeger eingefuegt.", - "gr-tr-laenge-bereich": "\nTraegerlaenge %1 mm ausserhalb des erlaubten Bereichs %2 bis %3 mm - kein Traeger eingefuegt.", - "gr-tr-fertig": "\nTraeger %1 mm eingefuegt (Block %2).", - "gr-tr-ende": "\n%1 Traeger eingefuegt.", + "gr-tr-laenge-null": "\nStrecke %1 mm ist nicht laenger als die Abzuege (%2 mm) - nichts eingefuegt (%3).", + "gr-tr-laenge-bereich": "\n%4: Laenge %1 mm ausserhalb des erlaubten Bereichs %2 bis %3 mm - nichts eingefuegt.", + "gr-tr-fertig": "\n%3 %1 mm eingefuegt (Block %2).", + "gr-tr-ende": "\n%1x %2 eingefuegt.", "gr-tr-bez-abzug-anfang": "Abzug Anfang %1 mm", "gr-tr-bez-abzug-ende": "Abzug Ende %1 mm", "gr-tr-beschr-stil-fehlt": "\nTextstil %1 fehlt in der Zeichnung - Beschriftung mit aktuellem Stil %2.", "gr-tr-beschr-ausrichtung": "\nUnbekannte Ausrichtung %1 fuer die Traeger-Beschriftung - verwende BC.", - "gr-tr-beschr-ergebnis": "\n%1 Traeger beschriftet (davon %2 ohne bekannte Variante), %3 nicht beschriftbar, %4 verwaiste Beschriftungen entfernt.", - "gr-tr-beschr-keine": "\nKeine Rohr-Geruest-Traeger in der Zeichnung.", + "gr-tr-beschr-ergebnis": "\n%5: %1 beschriftet (davon %2 ohne bekannte Variante), %3 nicht beschriftbar, %4 verwaiste Beschriftungen entfernt.", + "gr-tr-beschr-keine": "\nKeine Bloecke vom Typ %1 in der Zeichnung.", "gr-tr-strebe-rand": "Traeger %1 mm: Der Randabstand der Querstreben betraegt %2 mm und liegt ausserhalb des erlaubten Bereichs %3 bis %4 mm (Strebenabstand %5 mm, %6 Streben). Der Traeger wird trotzdem eingefuegt.", "in-yesno-keys": "Ja Nein", "in-keys-bereich": "Alle Auswahl", @@ -1092,6 +1099,7 @@ "sl-erk-kreisel": "ILS Kreisel/Eckrad", "sl-erk-strecke": "ILS Streckengruppe (VarioFoerderer/Gefaellestrecke)", "sl-erk-geruest": "Rohrgeruest", + "sl-erk-fahrstrecke": "Omniflo Fahrstrecke", "sl-erk-ap60": "Omniflo Gerade AP60", "sl-erk-ap110": "Omniflo Gerade AP110", "sl-erk-apg110": "Omniflo Gerade APG110" diff --git a/lang/en_GB.json b/lang/en_GB.json index 3a8395b..ce4950c 100644 --- a/lang/en_GB.json +++ b/lang/en_GB.json @@ -973,6 +973,7 @@ "gr-fehler-json-lesbar": "\nScaffold: data file not readable: %1", "gr-fehler-baugruppe": "\nScaffold: assembly '%1' is not in the data file.", "gr-fehler-keine-varianten": "\nScaffold: assembly '%1' has no geometry variants.", + "gr-bereich-waehlen": "\nScaffold: please choose an area from the menu (GERUEST_SAEULEN, GERUEST_ROHRABHAENGER, GERUEST_WANDBEFESTIGUNG).", "gr-fehler-dummy": "\nScaffold: dummy assembly not found: %1", "gr-fehler-dummy-variante": "\nScaffold: dummy of the variant not found: %1 - using dummy of the assembly (%2)", "gr-fehler-dcl": "Dialog geruest.dcl could not be loaded.", @@ -982,10 +983,15 @@ "gr-abgebrochen": "\nCancelled.", "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-position-befestigung": "mounting", + "gr-position-sonstiges": "other", "gr-konfig-keine": "", "gr-konfig-name": "\nConfiguration name: ", + "gr-konfig-name-vorgabe": "\nConfiguration name <%1>: ", + "gr-konfig-geaendert": "%1 (modified)", + "gr-konfig-status-geaendert": "Modified compared to '%1' - Save (Enter at the name prompt) overwrites it.", + "gr-konfig-status-bibliothek": "Modified compared to '%1' (library, read-only) - enter a new name to save.", + "gr-winkel-grad": "%1%2", "gr-konfig-gespeichert": "\nConfiguration '%1' saved.", "gr-konfig-geloescht": "\nConfiguration '%1' deleted.", "gr-konfig-loeschen-frage": "\nReally delete configuration '%1'? [Ja/Nein] : ", @@ -993,25 +999,26 @@ "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-konfig-variante-gesperrt": "\nConfiguration '%2': variant '%1' is disabled - selection left unchanged.", "gr-fehler-schreiben": "\nScaffold: could not write file: %1", "gr-fehler-keine-baugruppen": "\nScaffold: the data file contains no assemblies.", "gr-tr-fehler-dcl": "Dialog %1 could not be loaded.", "gr-tr-hinweis": "The length is defined in the drawing after OK.", "gr-tr-alert-abzug": "Invalid length deduction. Allowed is a number from 0 (mm); an empty field counts as 0.", - "gr-tr-prompt-start": "\nSelect start point of the beam : ", + "gr-tr-prompt-start": "\nSelect start point (%1) : ", "gr-tr-prompt-ende": "\nSelect end point or enter length (mm): ", "gr-tr-prompt-richtung": "\nSpecify direction <0>: ", "gr-tr-eingabe-ungueltig": "\nInput '%1' is neither a point nor a length.", - "gr-tr-laenge-null": "\nDistance %1 mm is not longer than the deductions (%2 mm) - no beam inserted.", - "gr-tr-laenge-bereich": "\nBeam length %1 mm outside the allowed range %2 to %3 mm - no beam inserted.", - "gr-tr-fertig": "\nBeam %1 mm inserted (block %2).", - "gr-tr-ende": "\n%1 beam(s) inserted.", + "gr-tr-laenge-null": "\nDistance %1 mm is not longer than the deductions (%2 mm) - nothing inserted (%3).", + "gr-tr-laenge-bereich": "\n%4: length %1 mm outside the allowed range %2 to %3 mm - nothing inserted.", + "gr-tr-fertig": "\n%3 %1 mm inserted (block %2).", + "gr-tr-ende": "\n%1x %2 inserted.", "gr-tr-bez-abzug-anfang": "Deduction start %1 mm", "gr-tr-bez-abzug-ende": "Deduction end %1 mm", "gr-tr-beschr-stil-fehlt": "\nText style %1 missing in drawing - labelling with current style %2.", "gr-tr-beschr-ausrichtung": "\nUnknown justification %1 for beam label - using BC.", - "gr-tr-beschr-ergebnis": "\n%1 beam(s) labelled (%2 without known variant), %3 not labellable, %4 orphaned label(s) removed.", - "gr-tr-beschr-keine": "\nNo pipe scaffold beams in the drawing.", + "gr-tr-beschr-ergebnis": "\n%5: %1 labelled (%2 without known variant), %3 not labellable, %4 orphaned label(s) removed.", + "gr-tr-beschr-keine": "\nNo blocks of type %1 in the drawing.", "gr-tr-strebe-rand": "Beam %1 mm: the edge distance of the cross braces is %2 mm, outside the allowed range %3 to %4 mm (brace spacing %5 mm, %6 braces). The beam is inserted anyway.", "in-yesno-keys": "Yes No", "in-keys-bereich": "All Selection", @@ -1092,6 +1099,7 @@ "sl-erk-kreisel": "ILS roundabout/corner wheel", "sl-erk-strecke": "ILS conveyor section (VarioFoerderer/gravity conveyor)", "sl-erk-geruest": "Pipe scaffold", + "sl-erk-fahrstrecke": "Omniflo track", "sl-erk-ap60": "Omniflo straight AP60", "sl-erk-ap110": "Omniflo straight AP110", "sl-erk-apg110": "Omniflo straight APG110" diff --git a/menu/SSG_LIB.cui b/menu/SSG_LIB.cui index d4708bf..745d3c3 100644 --- a/menu/SSG_LIB.cui +++ b/menu/SSG_LIB.cui @@ -152,721 +152,757 @@ ^C^C(ssg-ensure "VarioFoerderer") QcLinieMitGfUForm + + + Fahrstrecke + ^C^C(ssg-ensure "GeruestInsert") OMNI_FAHRSTRECKE + + + + Fahrstrecken beschriften + ^C^C(ssg-ensure "GeruestInsert") OMNI_FAHRSTRECKE_BESCHRIFTEN + + + 90 ^C^C(ssg-ensure "OmniModulInsert") OMNI_APB_630_90 - + 67.5 ^C^C(ssg-ensure "OmniModulInsert") OMNI_APB_550_675 - + 45 ^C^C(ssg-ensure "OmniModulInsert") OMNI_APB_630_45 - + 22.5 ^C^C(ssg-ensure "OmniModulInsert") OMNI_APB_550_225 - + 180 ^C^C(ssg-ensure "OmniModulInsert") OMNI_APB_650_180 - + 90 ^C^C(ssg-ensure "OmniModulInsert") OMNI_APB60_90 - + AP 60 ^C^C(ssg-ensure "OmniModulInsert") OMNI_AP60 - + AP 110 ^C^C(ssg-ensure "OmniModulInsert") OMNI_AP110 - + APG 110 ^C^C(ssg-ensure "OmniModulInsert") OMNI_APG110 - + - Einfach 90 700/700 links M + Einfach 90 ^C^C(ssg-ensure "OmniModulInsert") OMNI_W90_Einfach - - - Doppel 90 700/700 M - ^C^C(ssg-ensure "OmniModulInsert") OMNI_W90_Doppel - - - - - Dreiwege 90 700/700 M - ^C^C(ssg-ensure "OmniModulInsert") OMNI_W90_Dreiwege - - - Einfach 45 350/700 links M - ^C^C(ssg-ensure "OmniModulInsert") OMNI_W45_Einfach + Doppel 90 + ^C^C(ssg-ensure "OmniModulInsert") OMNI_W90_Doppel - Doppel 45 350/700 M - ^C^C(ssg-ensure "OmniModulInsert") OMNI_W45_Doppel + Dreiwege 90 + ^C^C(ssg-ensure "OmniModulInsert") OMNI_W90_Dreiwege - + - Dreiwege 45 350/700 M - ^C^C(ssg-ensure "OmniModulInsert") OMNI_W45_Dreiwege + Einfach 45 + ^C^C(ssg-ensure "OmniModulInsert") OMNI_W45_Einfach - Einfach Parallel 200/750 links M - ^C^C(ssg-ensure "OmniModulInsert") OMNI_WP_Einfach + Doppel 45 + ^C^C(ssg-ensure "OmniModulInsert") OMNI_W45_Doppel - Doppel Parallel 200/750 M - ^C^C(ssg-ensure "OmniModulInsert") OMNI_WP_Doppel + Dreiwege 45 + ^C^C(ssg-ensure "OmniModulInsert") OMNI_W45_Dreiwege - + - Dreiwege Parallel 200/750 M - ^C^C(ssg-ensure "OmniModulInsert") OMNI_WP_Dreiwege + Einfach Parallel + ^C^C(ssg-ensure "OmniModulInsert") OMNI_WP_Einfach - Einfach 22.5 links M - ^C^C(ssg-ensure "OmniModulInsert") OMNI_WK_Einfach + Doppel Parallel + ^C^C(ssg-ensure "OmniModulInsert") OMNI_WP_Doppel - Doppel 22.5 M - ^C^C(ssg-ensure "OmniModulInsert") OMNI_WK_Doppel + Dreiwege Parallel + ^C^C(ssg-ensure "OmniModulInsert") OMNI_WP_Dreiwege - + - Dreiwege 22.5 M - ^C^C(ssg-ensure "OmniModulInsert") OMNI_WK_Dreiwege + Einfach 22.5 + ^C^C(ssg-ensure "OmniModulInsert") OMNI_WK_Einfach - Delta 1400/700 M - ^C^C(ssg-ensure "OmniModulInsert") OMNI_WKomb_Delta_1400 + Doppel 22.5 + ^C^C(ssg-ensure "OmniModulInsert") OMNI_WK_Doppel - Delta 1600/800 M + Dreiwege 22.5 + ^C^C(ssg-ensure "OmniModulInsert") OMNI_WK_Dreiwege + + + + + Delta 1600/800 ^C^C(ssg-ensure "OmniModulInsert") OMNI_WKomb_Delta_1600 - + - Star 1400/1400 M + Delta 1400/700 + ^C^C(ssg-ensure "OmniModulInsert") OMNI_WKomb_Delta_1400 + + + + + Star 1400/1400 ^C^C(ssg-ensure "OmniModulInsert") OMNI_WKomb_Star - + TEF Antriebst. rechts ^C^C(ssg-ensure "OmniModulInsert") OMNI_TEF_AntriebR - + TEF Umlenkspannst. rechts ^C^C(ssg-ensure "OmniModulInsert") OMNI_TEF_UmlenkR - + TEF Antriebst. links ^C^C(ssg-ensure "OmniModulInsert") OMNI_TEF_AntriebL - + TEF Umlenkspannst. links ^C^C(ssg-ensure "OmniModulInsert") OMNI_TEF_UmlenkL - + TEF Gerade auf Linie ^C^C(ssg-ensure "TEFInsert") TEF_FOERDERER_LINIE - + TEF Gerade ^C^C(ssg-ensure "OmniModulInsert") OMNI_TEF_Gerade - + Stopper AP ^C^C(ssg-ensure "OmniModulInsert") OMNI_STOPPER - + Scanner ^C^C(ssg-ensure "OmniModulInsert") OMNI_SCANNER - + Bürstenbremse ^C^C(ssg-ensure "OmniModulInsert") OMNI_BUERSTENBREMSE - + + + Schwenkschiene Schiebetür L + ^C^C(ssg-ensure "OmniModulInsert") OMNI_SCHW_400_L + + + + + Schwenkschiene Schiebetür R + ^C^C(ssg-ensure "OmniModulInsert") OMNI_SCHW_400_R + + + + + Schwenkschiene Schiebetür L mit Sensorik + ^C^C(ssg-ensure "OmniModulInsert") OMNI_SCHW_400_L_SENSORIK + + + + + Schwenkschiene Schiebetür R mit Sensorik + ^C^C(ssg-ensure "OmniModulInsert") OMNI_SCHW_400_R_SENSORIK + + + KettenFoerderer ^C^C(ssg-ensure "OmniModulInsert") OMNI_KettenFoerderer - + Ladeschleifen ^C^C(ssg-ensure "OmniModulInsert") OMNI_LADESCHLEIFE_AP110 - + TV W-W kpl ^C^C(ssg-ensure "OmniModulInsert") OMNI_TV_W_W - + TV W-AP110 kpl ^C^C(ssg-ensure "OmniModulInsert") OMNI_TV_W_AP110 - + TV W-AP60 oben kpl. ^C^C(ssg-ensure "OmniModulInsert") OMNI_TV_W_AP60 - + TV W-AP110-W kpl ^C^C(ssg-ensure "OmniModulInsert") OMNI_TV_W_AP110_W - + TV W-AP oben kpl ^C^C(ssg-ensure "OmniModulInsert") OMNI_TV_W_AP - + TV 80 ^C^C(ssg-ensure "OmniModulInsert") OMNI_TV_80 - + TV 50 ^C^C(ssg-ensure "OmniModulInsert") OMNI_TV_50 - + Endplatte Al-Profil AP schraubbar ^C^C(ssg-ensure "OmniModulInsert") OMNI_TV_ENDPLATTE - + Anschlag AP-Ende fuer Spulenzug ^C^C(ssg-ensure "OmniModulInsert") OMNI_TV_ANSCHLAG - + TV-A fuer AP110/AP60 kpl ^C^C(ssg-ensure "OmniModulInsert") OMNI_TV_A_AP110_AP60 - + TV-A fuer AP60/ST ^C^C(ssg-ensure "OmniModulInsert") OMNI_TV_A_AP60_ST - + TV-A fuer AP110/ST kpl ^C^C(ssg-ensure "OmniModulInsert") OMNI_TV_A_AP110_ST - + TV-SW II fuer SW-SW ^C^C(ssg-ensure "OmniModulInsert") OMNI_TV_SW_II_SW_SW - + TV-SW III fuer SW-AP110-SW ^C^C(ssg-ensure "OmniModulInsert") OMNI_TV_SW_III_AP110_SW - + TV-SW III fuer SW-AP110 ^C^C(ssg-ensure "OmniModulInsert") OMNI_TV_SW_III_AP110 - + TV-SW IV fuer Anschluss SW-AP60 ^C^C(ssg-ensure "OmniModulInsert") OMNI_TV_SW_IV_AP60 - + TV-SW IV fuer SW-ST ^C^C(ssg-ensure "OmniModulInsert") OMNI_TV_SW_IV_ST - + Muffe ^C^C(ssg-ensure "OmniModulInsert") OMNI_TV_MUFFE - + APB 110 R400/45 140 nur fuer Delta ^C^C(ssg-ensure "OmniModulInsert") OMNI_APBW_R400_45_140 - + APB 110 R550/45 194 nur fuer Delta ^C^C(ssg-ensure "OmniModulInsert") OMNI_APBW_R550_45_194 - + APBW 110 R550/22,5 360x248,5 ^C^C(ssg-ensure "OmniModulInsert") OMNI_APBW_R550_225_360 - + APBW 110 R550/22,5 410x298,5 ^C^C(ssg-ensure "OmniModulInsert") OMNI_APBW_R550_225_410A - + APBW 110 R550/22,5 410x78,5 ^C^C(ssg-ensure "OmniModulInsert") OMNI_APBW_R550_225_410B - + APBW 110 R550/22,5 410x98,5 ^C^C(ssg-ensure "OmniModulInsert") OMNI_APBW_R550_225_410C - + APBW 110 R550/67,5 360x598,5 ^C^C(ssg-ensure "OmniModulInsert") OMNI_APBW_R550_675_360 - + APBW 110 R400/67,5 260x398,5 ^C^C(ssg-ensure "OmniModulInsert") OMNI_APBW_R400_675_260 - + APBW 110 R550/45 77x160 ^C^C(ssg-ensure "OmniModulInsert") OMNI_APBW_R550_45_77 - + APBW 110 R550/67,5 125x83,5 ^C^C(ssg-ensure "OmniModulInsert") OMNI_APBW_R550_675_125 - + APBW 110 R750/90 200x290 ^C^C(ssg-ensure "OmniModulInsert") OMNI_APBW_R750_90_200 - + APBW 110 R650/90 300x190 ^C^C(ssg-ensure "OmniModulInsert") OMNI_APBW_R650_90_300 - + 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 - + - Rohr-Geruest-Traeger + Rohr-Gerüst-Traeger ^C^C(ssg-ensure "GeruestInsert") GERUEST_TRAEGER - + - Saeulen + Säulen ^C^C(ssg-ensure "GeruestInsert") GERUEST_SAEULEN - + - Rohrabhaenger + Rohrabhänger ^C^C(ssg-ensure "GeruestInsert") GERUEST_ROHRABHAENGER - + Wandbefestigung ^C^C(ssg-ensure "GeruestInsert") GERUEST_WANDBEFESTIGUNG - + - Gattertraeger + Gatterträger ^C^C(ssg-ensure "GeruestInsert") GERUEST - + Traeger beschriften ^C^C(ssg-ensure "GeruestInsert") GERUEST_TRAEGER_BESCHRIFTEN - + Marker einfuegen ^C^C(ssg-ensure "Tro_Edit") TRO_INSERT - + Marker bearbeiten ^C^C(ssg-ensure "Tro_Edit") TRO_EDIT - + Bearbeiten (Auto) ^C^C(ssg-ensure "SSG_LIB_Commands") SSG_BLOCKEDIT - + Verbindung einfuegen ^C^C(ssg-ensure "Connection_Edit") CONNECTION_INSERT - + Verbindung bearbeiten ^C^C(ssg-ensure "Connection_Edit") CONNECTION_EDIT - + Eingang ^C^C(ssg-ensure "SSG_LIB_Commands") ILS_EINGANG_INSERT - + Ausgang ^C^C(ssg-ensure "SSG_LIB_Commands") ILS_AUSGANG_INSERT - + SPS Schliessen ^C^C - + Export Sivas ^C^C(ssg-ensure "export") EXPORTSIVAS - + Export CSV ^C^C(ssg-ensure "export") EXPORTCSV - + Umschalten 2D und 3D ^C^C(ssg-ensure "SSG_LIB_Commands") SSG_DIM_SWITCH - + Alle Bloecke auf 2D ^C^C(ssg-ensure "SSG_LIB_Commands") SSG_DIM_ALL_2D - + Alle Bloecke auf 3D ^C^C(ssg-ensure "SSG_LIB_Commands") SSG_DIM_ALL_3D - + Sprache ^C^C(ssg-ensure "SSG_LIB_Commands") SSG_SPRACHE - + Planquadrate an/aus ^C^C(ssg-ensure "DrawPlanquadrate") PLANQUADRATE_TOGGLE - + CSV-Export ^C^C(ssg-ensure "export") CSV_EXPORT_KONFIG - + Bloecke zaehlen ^C^C(ssg-ensure "ssg_blocktools") SSG_BLOCK_COUNT - + Bloecke loeschen ^C^C(ssg-ensure "ssg_blocktools") SSG_BLOCK_DELETE - + Attribute ersetzen ^C^C(ssg-ensure "ssg_blocktools") SSG_ATTR_ERSETZEN - + Text ersetzen ^C^C(ssg-ensure "ssg_texttools") SSG_TEXT_ERSETZEN - + Text parallel beschriften ^C^C(ssg-ensure "ssg_texttools") SSG_TEXT_PARALLEL - + Texthoehe aendern ^C^C(ssg-ensure "ssg_texttools") SSG_TEXT_HOEHE - + Textstil aendern ^C^C(ssg-ensure "ssg_texttools") SSG_TEXT_STIL - + Faehnchen + Stueckliste aus Zeichnung ^C^C(ssg-ensure "ssg_stueckliste") SSG_FAEHNCHEN_STUECKLISTE - + Din Formate ^C^C(ssg-ensure "DinFormate") DIN_FORMATE - + alle Tests ausfuehren und exportieren ^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_run_all.lsp")) (c:SSG_RUN_ALL_TESTS_EXPORT) - + Tests ausfuehren und stehen lassen ^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_run_all.lsp")) (c:SSG_RUN_ALL_TESTS_OFFEN) - + Export CSV/Sivas ALL ^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_export_all.lsp")) (c:TEST_EXPORT_ALL) - + Kreisel ^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_kreisel.lsp")) (c:TEST_KREISEL) - + Foerderer ^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_foerderer.lsp")) (c:TEST_FOERDERER) - + Foerderer-Linienzug ^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_linienzug.lsp")) (c:TEST_LINIENZUG) (c:TEST_LINIENZUG_STUFE2) - + Omniflo ^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_omniflo.lsp")) (c:TEST_OMNIFLO) - + Omniflo Strecke ^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_omniflo_strecke.lsp")) (c:TEST_OMNIFLO_STRECKE) - + Gefaellestrecke ^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_gefaellestrecke.lsp")) (c:TEST_GEFAELLESTRECKE) - + Mubea Gesamtmodell ^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_mubea.lsp")) (c:TEST_MUBEA) - + HundM05 Kreisel-Abschnitt ^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_hundm05.lsp")) (c:TEST_HUNDM05) - + Dematic/Arvato Flowpuffer (Vorlage) ^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_dematic_arvato.lsp")) (c:TEST_DEMATIC_ARVATO) - + ILS 3.0 Showroom (Vorlage) ^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_showroom_ils.lsp")) (c:TEST_SHOWROOM_ILS) - + KS 2D/3D pruefen (CSV) ^C^C(load (strcat (getenv "DXFMAKRO") "/Lisp/ks_pruefung.lsp")) KS_PRUEFEN - + Kreisel bearbeiten (ssg-ensure "KreiselInsert") KreiselEdit - + Omniflo Element bearbeiten (ssg-ensure "OmniModulInsert") OMNI_EDIT - + Gefaellestrecke bearbeiten (ssg-ensure "Gefaellestrecke") GEFAELLESTRECKE_EDIT - + VarioFoerderer bearbeiten (ssg-ensure "VarioFoerderer") VARIOFOERDERER_EDIT - + TRO-Marker bearbeiten (ssg-ensure "Tro_Edit") TRO_EDIT - + Verbindung bearbeiten (ssg-ensure "Connection_Edit") CONNECTION_EDIT - + SSG Bearbeiten (Auto) (ssg-ensure "SSG_LIB_Commands") SSG_BLOCKEDIT @@ -883,12 +919,12 @@ SSG_LIB - - - - + + - + + + ILS @@ -1056,818 +1092,855 @@ Omniflo - - - - - - - - - - + + Fahrstrecke + + + + + + Fahrstrecken beschriften + + + + + + + + + + + + ~KettenFoerderer - + Ladeschleifen - + - - + + Element bearbeiten - + - + Boegen APB110 90 - - - - - - 67.5 - - - - - - 45 - - - - - - 22.5 - 180 + 67.5 - - - Boegen APB60 - 90 + 45 + + + + + + 22.5 + + 180 + + + + - + + Boegen APB60 + + 90 + + + + + + Aluprofil Gerade AP 60 - + AP 110 - + APG 110 - - - - - - - Weiche 90 Grad - - Einfach 90 700/700 links M - - - - - - Doppel 90 700/700 M + + + Weichen - Dreiwege 90 700/700 M + Einfach 90 - + - - - Weiche 45 Grad - Einfach 45 350/700 links M + Doppel 90 - Doppel 45 350/700 M + Dreiwege 90 + - Dreiwege 45 350/700 M + Einfach 45 - + - - - Weichen Parallel - Einfach Parallel 200/750 links M + Doppel 45 - Doppel Parallel 200/750 M + Dreiwege 45 + - Dreiwege Parallel 200/750 M + Einfach Parallel - + - - - Weichenkoerper - Einfach 22.5 links M + Doppel Parallel - Doppel 22.5 M + Dreiwege Parallel + - Dreiwege 22.5 M + Einfach 22.5 - + - - - Weichenkombinationen - Delta 1400/700 M + Doppel 22.5 - Delta 1600/800 M + Dreiwege 22.5 + - Star 1400/1400 M + Delta 1600/800 - + - - - TEF Elemente - TEF Antriebst. rechts + Delta 1400/700 - TEF Umlenkspannst. rechts + Star 1400/1400 - + + + TEF Elemente - TEF Antriebst. links + TEF Antriebst. rechts - TEF Umlenkspannst. links + TEF Umlenkspannst. rechts - TEF Gerade auf Linie + TEF Antriebst. links - TEF Gerade + TEF Umlenkspannst. links - - - Anbaugruppen + - Stopper AP + TEF Gerade auf Linie - Scanner + TEF Gerade + + + Anbaugruppen + + Stopper AP + + + + + + Scanner + + + + Bürstenbremse - + - - Verbinder + + Spez. Streckenelemente + + + + Türlösungen + + + + Schwenkschienen - ~TV W-W kpl - - - - - - ~TV W-AP110 kpl - - - - - - ~TV W-AP60 oben kpl. - - - - - - ~TV W-AP110-W kpl + Schwenkschiene Schiebetür L - ~TV W-AP oben kpl + Schwenkschiene Schiebetür R - ~TV 80 + Schwenkschiene Schiebetür L mit Sensorik - ~TV 50 + Schwenkschiene Schiebetür R mit Sensorik + + + Verbinder - ~Endplatte Al-Profil AP schraubbar - - - - - - ~Anschlag AP-Ende fuer Spulenzug - - - - - - ~TV-A fuer AP110/AP60 kpl - - - - - - ~TV-A fuer AP60/ST + ~TV W-W kpl - ~TV-A fuer AP110/ST kpl + ~TV W-AP110 kpl - ~TV-SW II fuer SW-SW + ~TV W-AP60 oben kpl. - ~TV-SW III fuer SW-AP110-SW + ~TV W-AP110-W kpl - ~TV-SW III fuer SW-AP110 + ~TV W-AP oben kpl - ~TV-SW IV fuer Anschluss SW-AP60 + ~TV 80 - ~TV-SW IV fuer SW-ST + ~TV 50 - ~Muffe + ~Endplatte Al-Profil AP schraubbar - - - Boegen fuer Weichen - ~APB 110 R400/45 140 nur fuer Delta + ~Anschlag AP-Ende fuer Spulenzug + + + + + + ~TV-A fuer AP110/AP60 kpl - ~APB 110 R550/45 194 nur fuer Delta + ~TV-A fuer AP60/ST - ~APBW 110 R550/22,5 360x248,5 + ~TV-A fuer AP110/ST kpl - ~APBW 110 R550/22,5 410x298,5 + ~TV-SW II fuer SW-SW - ~APBW 110 R550/22,5 410x78,5 + ~TV-SW III fuer SW-AP110-SW - ~APBW 110 R550/22,5 410x98,5 + ~TV-SW III fuer SW-AP110 - ~APBW 110 R550/67,5 360x598,5 + ~TV-SW IV fuer Anschluss SW-AP60 - ~APBW 110 R400/67,5 260x398,5 + ~TV-SW IV fuer SW-ST - ~APBW 110 R550/45 77x160 + ~Muffe + + + Boegen fuer Weichen - ~APBW 110 R550/67,5 125x83,5 - - - - - - ~APBW 110 R750/90 200x290 + ~APB 110 R400/45 140 nur fuer Delta - ~APBW 110 R650/90 300x190 + ~APB 110 R550/45 194 nur fuer Delta - ~APBW 110 R550/67,5 208x347 + ~APBW 110 R550/22,5 360x248,5 - ~APBW 110 R550/67,5 58x497 + ~APBW 110 R550/22,5 410x298,5 - - - Geruest - Rohr-Geruest-Traeger + ~APBW 110 R550/22,5 410x78,5 + + + + + + ~APBW 110 R550/22,5 410x98,5 + + + + + + ~APBW 110 R550/67,5 360x598,5 - Saeulen + ~APBW 110 R400/67,5 260x398,5 - Rohrabhaenger + ~APBW 110 R550/45 77x160 - Wandbefestigung + ~APBW 110 R550/67,5 125x83,5 - Gattertraeger + ~APBW 110 R750/90 200x290 - - - - Funktionen - Traeger beschriften + ~APBW 110 R650/90 300x190 + + + + + + ~APBW 110 R550/67,5 208x347 - - - SPS - - - Eingang + ~APBW 110 R550/67,5 58x497 - - - - - Ausgang - - - - - - SPS Schliessen - - + - - TRO + + Gerüst - Marker einfuegen - - - - - - Marker bearbeiten + Rohr-Gerüst-Traeger - Bearbeiten (Auto) + Säulen - - - Connections - Verbindung einfuegen + Rohrabhänger + + + + + + Wandbefestigung - Verbindung bearbeiten + Gatterträger + + + + Funktionen - Bearbeiten (Auto) + Traeger beschriften - + - - Export + + SPS + + - Export Sivas + Eingang + + + + + + Ausgang + + + + + + SPS Schliessen + + + + + + + TRO + + Marker einfuegen + + + + + + Marker bearbeiten - Export CSV + Bearbeiten (Auto) - Konfiguration + Connections - Umschalten 2D und 3D + Verbindung einfuegen - Alle Bloecke auf 2D + Verbindung bearbeiten - Alle Bloecke auf 3D + Bearbeiten (Auto) - - - - - Sprache - - - - - - Planquadrate an/aus - - - - - - CSV-Export - - + - Werkzeuge + Export - Bloecke zaehlen + Export Sivas - Bloecke loeschen + Export CSV + + + Konfiguration + + Umschalten 2D und 3D + + + + + + Alle Bloecke auf 2D + + + + + + Alle Bloecke auf 3D + + + + + + Sprache + + + + + + Planquadrate an/aus + + + + + + CSV-Export + + + + + + + Werkzeuge + + Bloecke zaehlen + + + + + + Bloecke loeschen + + + + Attribute ersetzen - + Text ersetzen - + Text parallel beschriften - + Texthoehe aendern - + Textstil aendern - + Faehnchen + Stueckliste aus Zeichnung - + Din Formate - + - + Tests alle Tests ausfuehren und exportieren - + Tests ausfuehren und stehen lassen - + Export CSV/Sivas ALL - + Kreisel - + Foerderer - + Foerderer-Linienzug - + Omniflo - + Omniflo Strecke - + Gefaellestrecke - + Mubea Gesamtmodell - + HundM05 Kreisel-Abschnitt - + Dematic/Arvato Flowpuffer (Vorlage) - + ILS 3.0 Showroom (Vorlage) - + KS 2D/3D pruefen (CSV) - + - + POP501 SSG_LIB Edit Context Kreisel bearbeiten - + Omniflo Element bearbeiten - + Gefaellestrecke bearbeiten - + VarioFoerderer bearbeiten - + TRO-Marker bearbeiten - + Verbindung bearbeiten - + SSG Bearbeiten (Auto) - + diff --git a/menu/SSG_LIB.mnu b/menu/SSG_LIB.mnu index 6f03637..023d66a 100644 --- a/menu/SSG_LIB.mnu +++ b/menu/SSG_LIB.mnu @@ -34,6 +34,9 @@ [QC Linie mit GF (automatische Auf-Ab-Berechnung)]^C^C(ssg-ensure "VarioFoerderer") QcLinieMitGf [<-<-QC Linie mit GF und U-Form]^C^C(ssg-ensure "VarioFoerderer") QcLinieMitGfUForm [->Omniflo] +[Fahrstrecke]^C^C(ssg-ensure "GeruestInsert") OMNI_FAHRSTRECKE +[Fahrstrecken beschriften]^C^C(ssg-ensure "GeruestInsert") OMNI_FAHRSTRECKE_BESCHRIFTEN +[--] [->Boegen APB110] [90]^C^C(ssg-ensure "OmniModulInsert") OMNI_APB_630_90 [67.5]^C^C(ssg-ensure "OmniModulInsert") OMNI_APB_550_675 @@ -46,26 +49,26 @@ [AP 60]^C^C(ssg-ensure "OmniModulInsert") OMNI_AP60 [AP 110]^C^C(ssg-ensure "OmniModulInsert") OMNI_AP110 [<-APG 110]^C^C(ssg-ensure "OmniModulInsert") OMNI_APG110 -[->Weiche 90 Grad] -[Einfach 90 700/700 links M]^C^C(ssg-ensure "OmniModulInsert") OMNI_W90_Einfach -[Doppel 90 700/700 M]^C^C(ssg-ensure "OmniModulInsert") OMNI_W90_Doppel -[<-Dreiwege 90 700/700 M]^C^C(ssg-ensure "OmniModulInsert") OMNI_W90_Dreiwege -[->Weiche 45 Grad] -[Einfach 45 350/700 links M]^C^C(ssg-ensure "OmniModulInsert") OMNI_W45_Einfach -[Doppel 45 350/700 M]^C^C(ssg-ensure "OmniModulInsert") OMNI_W45_Doppel -[<-Dreiwege 45 350/700 M]^C^C(ssg-ensure "OmniModulInsert") OMNI_W45_Dreiwege -[->Weichen Parallel] -[Einfach Parallel 200/750 links M]^C^C(ssg-ensure "OmniModulInsert") OMNI_WP_Einfach -[Doppel Parallel 200/750 M]^C^C(ssg-ensure "OmniModulInsert") OMNI_WP_Doppel -[<-Dreiwege Parallel 200/750 M]^C^C(ssg-ensure "OmniModulInsert") OMNI_WP_Dreiwege -[->Weichenkoerper] -[Einfach 22.5 links M]^C^C(ssg-ensure "OmniModulInsert") OMNI_WK_Einfach -[Doppel 22.5 M]^C^C(ssg-ensure "OmniModulInsert") OMNI_WK_Doppel -[<-Dreiwege 22.5 M]^C^C(ssg-ensure "OmniModulInsert") OMNI_WK_Dreiwege -[->Weichenkombinationen] -[Delta 1400/700 M]^C^C(ssg-ensure "OmniModulInsert") OMNI_WKomb_Delta_1400 -[Delta 1600/800 M]^C^C(ssg-ensure "OmniModulInsert") OMNI_WKomb_Delta_1600 -[<-Star 1400/1400 M]^C^C(ssg-ensure "OmniModulInsert") OMNI_WKomb_Star +[->Weichen] +[Einfach 90]^C^C(ssg-ensure "OmniModulInsert") OMNI_W90_Einfach +[Doppel 90]^C^C(ssg-ensure "OmniModulInsert") OMNI_W90_Doppel +[Dreiwege 90]^C^C(ssg-ensure "OmniModulInsert") OMNI_W90_Dreiwege +[--] +[Einfach 45]^C^C(ssg-ensure "OmniModulInsert") OMNI_W45_Einfach +[Doppel 45]^C^C(ssg-ensure "OmniModulInsert") OMNI_W45_Doppel +[Dreiwege 45]^C^C(ssg-ensure "OmniModulInsert") OMNI_W45_Dreiwege +[--] +[Einfach Parallel]^C^C(ssg-ensure "OmniModulInsert") OMNI_WP_Einfach +[Doppel Parallel]^C^C(ssg-ensure "OmniModulInsert") OMNI_WP_Doppel +[Dreiwege Parallel]^C^C(ssg-ensure "OmniModulInsert") OMNI_WP_Dreiwege +[--] +[Einfach 22.5]^C^C(ssg-ensure "OmniModulInsert") OMNI_WK_Einfach +[Doppel 22.5]^C^C(ssg-ensure "OmniModulInsert") OMNI_WK_Doppel +[Dreiwege 22.5]^C^C(ssg-ensure "OmniModulInsert") OMNI_WK_Dreiwege +[--] +[Delta 1600/800]^C^C(ssg-ensure "OmniModulInsert") OMNI_WKomb_Delta_1600 +[Delta 1400/700]^C^C(ssg-ensure "OmniModulInsert") OMNI_WKomb_Delta_1400 +[<-Star 1400/1400]^C^C(ssg-ensure "OmniModulInsert") OMNI_WKomb_Star [->TEF Elemente] [TEF Antriebst. rechts]^C^C(ssg-ensure "OmniModulInsert") OMNI_TEF_AntriebR [TEF Umlenkspannst. rechts]^C^C(ssg-ensure "OmniModulInsert") OMNI_TEF_UmlenkR @@ -79,6 +82,13 @@ [Stopper AP]^C^C(ssg-ensure "OmniModulInsert") OMNI_STOPPER [Scanner]^C^C(ssg-ensure "OmniModulInsert") OMNI_SCANNER [<-Bürstenbremse]^C^C(ssg-ensure "OmniModulInsert") OMNI_BUERSTENBREMSE +[->Spez. Streckenelemente] +[->Türlösungen] +[->Schwenkschienen] +[Schwenkschiene Schiebetür L]^C^C(ssg-ensure "OmniModulInsert") OMNI_SCHW_400_L +[Schwenkschiene Schiebetür R]^C^C(ssg-ensure "OmniModulInsert") OMNI_SCHW_400_R +[Schwenkschiene Schiebetür L mit Sensorik]^C^C(ssg-ensure "OmniModulInsert") OMNI_SCHW_400_L_SENSORIK +[<-<-<-Schwenkschiene Schiebetür R mit Sensorik]^C^C(ssg-ensure "OmniModulInsert") OMNI_SCHW_400_R_SENSORIK [~KettenFoerderer]^C^C(ssg-ensure "OmniModulInsert") OMNI_KettenFoerderer [Ladeschleifen]^C^C(ssg-ensure "OmniModulInsert") OMNI_LADESCHLEIFE_AP110 [->Verbinder] @@ -116,12 +126,12 @@ [~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]^C^C(ssg-ensure "GeruestInsert") GERUEST -[Rohr-Geruest-Traeger]^C^C(ssg-ensure "GeruestInsert") GERUEST_TRAEGER -[Saeulen]^C^C(ssg-ensure "GeruestInsert") GERUEST_SAEULEN -[Rohrabhaenger]^C^C(ssg-ensure "GeruestInsert") GERUEST_ROHRABHAENGER +[->Gerüst]^C^C(ssg-ensure "GeruestInsert") GERUEST +[Rohr-Gerüst-Traeger]^C^C(ssg-ensure "GeruestInsert") GERUEST_TRAEGER +[Säulen]^C^C(ssg-ensure "GeruestInsert") GERUEST_SAEULEN +[Rohrabhänger]^C^C(ssg-ensure "GeruestInsert") GERUEST_ROHRABHAENGER [Wandbefestigung]^C^C(ssg-ensure "GeruestInsert") GERUEST_WANDBEFESTIGUNG -[Gattertraeger]^C^C(ssg-ensure "GeruestInsert") GERUEST +[Gatterträger]^C^C(ssg-ensure "GeruestInsert") GERUEST [->Funktionen] [<-<-Traeger beschriften]^C^C(ssg-ensure "GeruestInsert") GERUEST_TRAEGER_BESCHRIFTEN [->SPS] diff --git a/tests/test_export_geruest_merkmale.py b/tests/test_export_geruest_merkmale.py new file mode 100644 index 0000000..2f411dd --- /dev/null +++ b/tests/test_export_geruest_merkmale.py @@ -0,0 +1,39 @@ +"""Merkmale der GR_-Geruest-Bloecke im CSV-Export (build_geruest_merkmale). + +Prueft die Teilefarbe (Attribut TEILEFARBE - das frueher gelesene FARBE gibt +es im Schema nicht) und die Laengenabzuege, die nur der Rohr-Geruest-Traeger +traegt und die bei den anderen GR_-Bloecken nicht auftauchen duerfen. +""" + +import os +import sys + +sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "lib")) + +from export_csv import build_geruest_merkmale # noqa: E402 + + +def test_teilefarbe_aus_teilefarbe_attribut(): + block = {"attribs": {"TEILEART": "Geruest Saeule 1 Zoll", + "TEILEFARBE": ",RAL7030", "LAENGE": "2000", + "LAYER": "D-6"}} + m = build_geruest_merkmale(block) + assert m["Farbe"] == ",RAL7030" + assert m["Laenge"] == "2000" + assert m["Layer"] == "D-6" + + +def test_ohne_abzug_keine_abzugsmerkmale(): + m = build_geruest_merkmale({"attribs": {"TEILEART": "Geruest Rohrabhaenger"}}) + assert "LaengenabzugAnfang" not in m + assert "LaengenabzugEnde" not in m + + +def test_traeger_abzuege(): + block = {"attribs": {"TEILEART": "Geruest Traeger 1 Zoll", "LAENGE": "965", + "LAENGENABZUGANFANG": "0", + "LAENGENABZUGENDE": "35"}} + m = build_geruest_merkmale(block) + assert m["Laenge"] == "965" + assert m["LaengenabzugAnfang"] == "0" + assert m["LaengenabzugEnde"] == "35" diff --git a/tests/test_export_sivas_zusammenfassen.py b/tests/test_export_sivas_zusammenfassen.py new file mode 100644 index 0000000..1ec24a4 --- /dev/null +++ b/tests/test_export_sivas_zusammenfassen.py @@ -0,0 +1,52 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +test_export_sivas_zusammenfassen.py - zusammengefasste Sivas-Kopie +(_zusammengefasst.csv, export_sivas.items_zusammenfassen). +Laeuft komplett ohne BricsCAD (reine Python-Logik). +""" + +import os +import sys + +sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "lib")) + +import export_sivas # noqa: E402 + + +def _geruest(teileid, laenge="2500"): + return {"block_name": f"GR_{teileid}", "x": 0.0, "y": 0.0, "z": 0.0, + "rotation": 0.0, + "attribs": {"ID": teileid, "TEILEART": "Geruest Saeule 2 Zoll", + "ARTINR": "821006051,825002022,825002022", + "TEILEFARBE": "RAL7035,,", + "BEZEICHNUNG": "Saeule", "LAENGE": laenge}} + + +def test_gleiche_zeilen_werden_summiert(): + items, _ = export_sivas.process_blocks( + [_geruest("0001"), _geruest("0002"), _geruest("0003", laenge="2800")]) + assert len(items) == 6 + zus = export_sivas.items_zusammenfassen(items) + # Laenge gehoert zum Schluessel: 2500er und 2800er bleiben getrennt + assert len(zus) == 4 + assert [z["nr"] for z in zus] == [1, 2, 3, 4] + z = {(z["sivasnr"], z["laenge_mm"]): z for z in zus} + assert z[("825002022", "2500")]["anzahl"] == 4 + assert z[("825002022", "2500")]["ids"] == ["0001", "0002"] + assert z[("821006051", "2500")]["anzahl"] == 2 + assert z[("821006051", "2500")]["details"] == {export_sivas.MERKMAL_TEILEFARBE: "RAL7035"} + assert z[("825002022", "2800")]["anzahl"] == 2 + assert z[("825002022", "2800")]["ids"] == ["0003"] + + +def test_eingabe_bleibt_unveraendert(): + items, _ = export_sivas.process_blocks([_geruest("0001"), _geruest("0002")]) + vorher = [export_sivas.format_csv_line(it) for it in items] + export_sivas.items_zusammenfassen(items) + assert [export_sivas.format_csv_line(it) for it in items] == vorher + + +def test_dateiname(): + assert export_sivas.zusammengefasster_dateiname("x/500651_sivas.csv") == \ + "x/500651_sivas_zusammengefasst.csv" diff --git a/tests/test_lastent.lsp b/tests/test_lastent.lsp new file mode 100644 index 0000000..d65ec8c --- /dev/null +++ b/tests/test_lastent.lsp @@ -0,0 +1,129 @@ +;; ============================================================ +;; test_lastent.lsp - Szenario-Test fuer ssg-lastent-ohne-attribute (ssg_core) +;; +;; Stellt den realen Bug nach: ein Block MIT Attributen (z.B. eine per +;; Strg+C/V eingefuegte GR_-Kopie) ist das letzte Objekt der Zeichnung. +;; Ein Makro merkt sich die Startmarke, zeichnet neue Objekte, sammelt +;; "alles ab (entnext marke)" ein und wickelt es per _.-BLOCK zu einem Block. +;; Mit nacktem (entlast) als Marke landeten dabei die ATTRIBs des alten +;; Blocks im Auswahlsatz und wurden entfernt. +;; +;; Aufruf in BricsCAD: +;; (load (strcat (getenv "DXFMAKRO") "/tests/test_lastent.lsp")) +;; TEST_LASTENT +;; +;; Speichert tests/output/lastent_results.json (Konvention test_run_all). +;; ============================================================ + +(setq *tle-pass* 0 *tle-fail* 0 *tle-fails* '()) + +;; Ein Assert: erwartet-Wert gleich ist-Wert (equal). Loggt Pass/Fail. +(defun tle-eq (name erwartet ist) + (if (equal erwartet ist) + (progn (setq *tle-pass* (1+ *tle-pass*)) + (princ (strcat "\n [PASS] " name))) + (progn (setq *tle-fail* (1+ *tle-fail*)) + (setq *tle-fails* (cons name *tle-fails*)) + (princ (strcat "\n [FAIL] " name + "\n erwartet: " (vl-princ-to-string erwartet) + "\n ist: " (vl-princ-to-string ist)))))) + +;; Blockdefinition mit zwei ATTDEFs anlegen (falls noch nicht vorhanden). +(defun tle-blockdef (name) + (if (not (tblsearch "BLOCK" name)) + (progn + (entmake (list '(0 . "BLOCK") (cons 2 name) '(70 . 2) '(10 0.0 0.0 0.0))) + (entmake '((0 . "LINE") (8 . "0") (10 0.0 0.0 0.0) (11 100.0 0.0 0.0))) + (foreach tag '("ID" "ARTINR") + (entmake (list '(0 . "ATTDEF") '(8 . "0") '(10 0.0 0.0 0.0) + '(40 . 10.0) '(1 . "") (cons 2 tag) (cons 3 tag) + '(70 . 0)))) + (entmake '((0 . "ENDBLK"))))) + name) + +;; INSERT mit Attributen per entmake (INSERT 66=1, ATTRIBs, SEQEND). +;; Rueckgabe: ename des INSERT. +(defun tle-insert-mit-attributen (name pt werte / ins) + (entmake (list '(0 . "INSERT") (cons 2 name) (cons 10 pt) '(66 . 1))) + (setq ins (entlast)) + (foreach paar werte + (entmake (list '(0 . "ATTRIB") '(8 . "0") (cons 10 pt) '(40 . 10.0) + (cons 1 (cdr paar)) (cons 2 (car paar)) '(70 . 0)))) + (entmake '((0 . "SEQEND"))) + ins) + +(defun lastent:tests ( / bname werte ins marke line ss e neu anz) + (setvar "CMDECHO" 0) + (setq bname (tle-blockdef "TLE_ATT_BLOCK")) + (setq werte (list (cons "ID" "4711") (cons "ARTINR" "A1,A2"))) + (setq ins (tle-insert-mit-attributen bname '(0.0 0.0 0.0) werte)) + + ;; --- Vorbedingung: Attribute lesbar, INSERT ist (entlast) --- + (tle-eq "vorher: attribute lesbar" werte (ssg-attrib-read ins)) + (tle-eq "vorher: entlast = insert" ins (entlast)) + + ;; --- Marke steht auf dem SEQEND des Attribut-Blocks --- + (setq marke (ssg-lastent-ohne-attribute)) + (tle-eq "marke ist SEQEND" "SEQEND" (cdr (assoc 0 (entget marke)))) + + ;; --- Neues Objekt zeichnen: entnext der Marke ist genau dieses Objekt --- + (entmake '((0 . "LINE") (8 . "0") (10 0.0 50.0 0.0) (11 100.0 50.0 0.0))) + (setq line (entlast)) + (tle-eq "entnext marke = neues objekt" line (entnext marke)) + + ;; --- Einsammeln + _.-BLOCK wie geruest-block-bauen --- + (setq ss (ssadd) anz 0 e (entnext marke)) + (while e (ssadd e ss) (setq anz (1+ anz)) (setq e (entnext e))) + (tle-eq "genau 1 objekt eingesammelt" 1 anz) + (setq neu (strcat "TLE_NEU_" (ssg-timestamp))) + (command "_.-BLOCK" neu '(0.0 0.0 0.0) ss "") + + ;; --- Kern des Bugs: der alte Block behaelt seine Attribute --- + (tle-eq "nachher: attribute erhalten" werte (ssg-attrib-read ins)) + (tle-eq "nachher: neuer block existiert" T (if (tblsearch "BLOCK" neu) T nil)) + + ;; --- Leere Zeichnung wird hier nicht getestet (Testzeichnung ist nie leer); + ;; ohne Attribute liefert der Helfer (entlast) unveraendert --- + (entmake '((0 . "LINE") (8 . "0") (10 0.0 90.0 0.0) (11 10.0 90.0 0.0))) + (tle-eq "ohne attribute: marke = entlast" (entlast) (ssg-lastent-ohne-attribute)) + + ;; Aufraeumen + (entdel ins) + (entdel (entlast)) + (princ)) + + +(defun lastent:export-results (out-dir / f pfad) + (setq pfad (strcat out-dir "/lastent_results.json")) + (setq f (open pfad "w")) + (if f + (progn + (write-line "{" f) + (write-line (strcat " \"pass\": " (itoa *tle-pass*) ",") f) + (write-line (strcat " \"fail\": " (itoa *tle-fail*) ",") f) + (write-line (strcat " \"status\": \"" + (if (= *tle-fail* 0) "OK" "FEHLER") "\"") f) + (write-line "}" f) + (close f) + (princ (strcat "\n Ergebnis: " pfad)))) + (princ)) + + +(defun c:TEST_LASTENT ( / ) + (setq *tle-pass* 0 *tle-fail* 0 *tle-fails* '()) + (princ "\n================================================================") + (princ "\n TEST_LASTENT - ssg-lastent-ohne-attribute (ssg_core.lsp)") + (princ "\n================================================================") + (lastent:tests) + (princ "\n\n----------------------------------------------------------------") + (princ (strcat "\n Ergebnis: " (itoa *tle-pass*) " PASS, " + (itoa *tle-fail*) " FAIL")) + (if (> *tle-fail* 0) + (progn + (princ "\n Fehlgeschlagen:") + (foreach n (reverse *tle-fails*) (princ (strcat "\n - " n))))) + (princ "\n================================================================") + (princ)) + +(princ "\nTEST_LASTENT geladen. Aufruf: TEST_LASTENT") +(princ) diff --git a/tests/test_unit.lsp b/tests/test_unit.lsp index b8296dc..892fb75 100644 --- a/tests/test_unit.lsp +++ b/tests/test_unit.lsp @@ -217,6 +217,21 @@ (setq *ssg-ils-dim* _lay-dim-alt *ssg-layer-cfg* _lay-cfg-alt *ssg-layer-cfg-versucht* _lay-vers-alt) + + ;; --- DCL-Vorlagen: Platzhalterzeilen //@NAME@ ersetzen --- + (tu-eq "ssg-dcl-zeilen-ersetzen/ersetzt" + '("a {" " x;" " y;" "}") + (ssg-dcl-zeilen-ersetzen '("a {" " //@L@" "}") '(("L" " x;" " y;")))) + (tu-eq "ssg-dcl-zeilen-ersetzen/leer-entfernt" + '("a {" "}") + (ssg-dcl-zeilen-ersetzen '("a {" "\t//@L@ " "}") '(("L")))) + (tu-eq "ssg-dcl-zeilen-ersetzen/mehrere" + '("1" "2") + (ssg-dcl-zeilen-ersetzen '("//@A@" "//@B@") '(("A" "1") ("B" "2")))) + ;; unbekannter Marker und normaler Kommentar bleiben stehen + (tu-eq "ssg-dcl-zeilen-ersetzen/unbekannt" + '("//@X@" "// Kommentar") + (ssg-dcl-zeilen-ersetzen '("//@X@" "// Kommentar") '(("A" "1")))) ) @@ -849,7 +864,7 @@ ) (defun tu-tests-geruest ( / _eintrag _gruppe _teile _konfig _rec _pfad _f - _zurueck _bgtest _saeulen) + _zurueck _bgtest _saeulen _vmq _alt _fs) (princ "\n[GeruestInsert]") ;; GeruestInsert ist ein lazy Feature-Modul (nicht in der Core-Ladeliste). ;; Geladen wird es zentral in test_unit.scr auf .scr-Top-Level; hier nur @@ -917,10 +932,10 @@ "{\"artikel\": \"X\", \"sivas_id\": 7, \"stueckzahl\": 2, \"anzahl_vorgabe\": 5}") 2)) ;; Dummy, der zugleich Teile-DWG ist, faellt aus der Teileliste - (tu-eq "geruest-ohne-pfad/entfernt" '("b/2.dwg") - (geruest-ohne-pfad "A/1.DWG" '("a/1.dwg" "b/2.dwg"))) - (tu-eq "geruest-ohne-pfad/nil" '("a/1.dwg") - (geruest-ohne-pfad nil '("a/1.dwg"))) + (tu-eq "geruest-ohne-pfad/entfernt" '(("b/2.dwg" . 90.0)) + (geruest-ohne-pfad "A/1.DWG" '(("a/1.dwg" . 0.0) ("b/2.dwg" . 90.0)))) + (tu-eq "geruest-ohne-pfad/nil" '(("a/1.dwg" . 0.0)) + (geruest-ohne-pfad nil '(("a/1.dwg" . 0.0)))) ;; Dummy-Wahl: Variante gewinnt, fehlende Varianten-DWG -> Baugruppe (setq _pfad (geruest-dummy-pfad "821006036.dwg")) (if (and _pfad (findfile _pfad)) @@ -1015,7 +1030,148 @@ "{\"artikel\": \"Schraubenset\", \"anzahl\": 3}," "{\"artikel\": \"unbekannt\", \"anzahl\": 1}]}"))) (tu-eq "geruest-konfig-position" '(nil 3) - (geruest-konfig-position _konfig "oben" _teile)) + (geruest-konfig-position _konfig "oben" _teile nil)) + + ;; --- anbaugruppen: befestigung / sonstiges --- + (setq _bgtest (ssg-json-parse + (strcat "{\"anbaugruppen\": {\"befestigung\": [{\"artikel\": \"K\"}]," + " \"sonstiges\": [{\"artikel\": \"H1\"}, {\"artikel\": \"H2\"}]}}"))) + (tu-eq "geruest-anbau-liste/befestigung" 1 + (length (geruest-anbau-liste _bgtest "befestigung"))) + (tu-eq "geruest-anbau-liste/sonstiges" '("H1" "H2") + (mapcar 'geruest-eintrag-name (geruest-anbau-liste _bgtest "sonstiges"))) + ;; altes flaches Array gilt als befestigung + (setq _rec (ssg-json-parse "{\"anbaugruppen\": [{\"artikel\": \"A\"}, {\"artikel\": \"B\"}]}")) + (tu-eq "geruest-anbau-liste/flach" 2 (length (geruest-anbau-liste _rec "befestigung"))) + (tu-nil "geruest-anbau-liste/flach-sonstiges" (geruest-anbau-liste _rec "sonstiges")) + (tu-nil "geruest-anbau-liste/leer" + (geruest-anbau-liste + (ssg-json-parse "{\"anbaugruppen\": {\"befestigung\": [], \"sonstiges\": []}}") + "sonstiges")) + (tu-nil "geruest-anbau-liste/fehlt" + (geruest-anbau-liste (ssg-json-parse "{\"id\": \"X\"}") "befestigung")) + (tu-eq "geruest-dlg-standard/teile" '(("0" . "1") ("0" . "1")) + (geruest-dlg-standard (geruest-anbau-liste _bgtest "sonstiges"))) + (tu-eq "geruest-mengen-addieren" '(nil 3 2 5) + (geruest-mengen-addieren '(nil 1 nil 2) '(nil 2 2 3))) + ;; Alte Konfiguration mit Haltearm unter "oben": landet in sonstiges + ;; (Mengen addiert), oben meldet ihn nicht als unbekannt + (setq _konfig (ssg-json-parse + (strcat "{\"name\": \"Alt\"," + " \"oben\": [{\"artikel\": \"K\", \"anzahl\": 2}, {\"artikel\": \"H2\", \"anzahl\": 1}]," + " \"unten\": [{\"artikel\": \"H2\", \"anzahl\": 2}]," + " \"sonstiges\": [{\"artikel\": \"H1\", \"anzahl\": 4}]}"))) + (tu-eq "geruest-konfig-position/ausweich" '(2) + (geruest-konfig-position _konfig "oben" + (geruest-anbau-liste _bgtest "befestigung") + (geruest-anbau-liste _bgtest "sonstiges"))) + ;; --- Winkel Platte: Basis ungedreht, Anbauteile gedreht, kein Doppel --- + (tu-eq "geruest-teile-dwgs-rot/90" '(("b.dwg" . 0.0) ("a.dwg" . 90.0)) + (geruest-teile-dwgs-rot '("b.dwg") '("b.dwg" "a.dwg") 90)) + (tu-eq "geruest-teile-dwgs-rot/0" '(("a.dwg" . 0.0)) + (geruest-teile-dwgs-rot nil '("a.dwg") 0)) + (tu-eq "geruest-rest-liste" '(3 4) (geruest-rest-liste '(1 2 3 4) 2)) + (tu-eq "geruest-winkel-aus-index/90" 90 (geruest-winkel-aus-index "1")) + (tu-eq "geruest-winkel-aus-index/leer" 0 (geruest-winkel-aus-index "")) + (tu-eq "geruest-winkel-index/90" "1" (geruest-winkel-index 90)) + (tu-eq "geruest-winkel-index/fehlt" "0" (geruest-winkel-index nil)) + ;; --- Radiobuttons der Varianten: Key "v" <-> Index --- + (tu-eq "geruest-radio-key" "v3" (geruest-radio-key 3)) + (tu-eq "geruest-radio-index" 3 (geruest-radio-index "v3")) + (tu-eq "geruest-radio-index/leer" 0 (geruest-radio-index "")) + (tu-eq "geruest-radio-index/nil" 0 (geruest-radio-index nil)) + (tu-eq "geruest-indizes" '(0 1 2) (geruest-indizes 3)) + (tu-nil "geruest-indizes/0" (geruest-indizes 0)) + (tu-eq "geruest-dcl-varianten-zeilen" + '(" : radio_button { key = \"v1\"; label = \"B 1''\"; }") + (geruest-dcl-varianten-zeilen + (list '(("name" . "A")) '(("name" . "B 1\""))) '(1))) + ;; Variante mit Teilen: Artikelnummern in Klammern, jede nur einmal + (tu-eq "geruest-varianten-label/nummern" "R 2\" (111, 222)" + (geruest-varianten-label + (ssg-json-parse + (strcat "{\"name\": \"R 2\\\"\", \"teile\": [" + "{\"artikel\": \"A\", \"sivas_id\": 111}," + "{\"artikel\": \"B\", \"sivas_id\": 222, \"stueckzahl\": 2}]}")))) + (tu-eq "geruest-varianten-label/ohne" "A" + (geruest-varianten-label '(("name" . "A")))) + ;; --- Gesperrte Varianten ("disabled": true) --- + (setq _rec (list '(("name" . "A") ("disabled" . T)) + '(("name" . "B")) + '(("name" . "C") ("disabled" . T)))) + (tu-true "geruest-variante-gesperrt-p/ja" (geruest-variante-gesperrt-p (nth 0 _rec))) + (tu-nil "geruest-variante-gesperrt-p/nein" (geruest-variante-gesperrt-p (nth 1 _rec))) + (tu-eq "geruest-erste-freie-variante" 1 (geruest-erste-freie-variante _rec)) + (tu-eq "geruest-erste-freie-variante/alle-gesperrt" 0 + (geruest-erste-freie-variante (list '(("disabled" . T))))) + (tu-eq "geruest-variante-waehlbar/frei" 1 (geruest-variante-waehlbar _rec 1)) + (tu-eq "geruest-variante-waehlbar/gesperrt" 1 (geruest-variante-waehlbar _rec 2)) + (tu-eq "geruest-variante-waehlbar/zu-gross" 1 (geruest-variante-waehlbar _rec 7)) + ;; Ersetzungen: ohne Teile entfallen die Bloecke (leerer Cluster) + (setq _rec (geruest-dcl-ersetzungen "Saeulen" nil nil + (list '(("name" . "A"))))) + (tu-nil "geruest-dcl-ersetzungen/ohne-befestigung" + (cdr (assoc "BEFESTIGUNG" _rec))) + (tu-nil "geruest-dcl-ersetzungen/ohne-sonstiges" + (cdr (assoc "SONSTIGES" _rec))) + (tu-eq "geruest-dcl-ersetzungen/varianten" 1 + (length (cdr (assoc "VARIANTEN" _rec)))) + ;; --- Geaenderte Konfiguration: Vergleich ohne Namen --- + (tu-true "geruest-record-gleich-p/name" + (geruest-record-gleich-p '(("name" . "A") ("laenge" . "100")) + '(("name" . "B") ("laenge" . "100")))) + (tu-nil "geruest-record-gleich-p/geaendert" + (geruest-record-gleich-p '(("name" . "A") ("laenge" . "100")) + '(("name" . "A") ("laenge" . "200")))) + ;; Eigene Konfiguration gewinnt vor gleichnamiger Bibliothek; nur eine + ;; eigene liefert eine Namensvorgabe (Ueberspeichern) + (setq _alt *geruest-konfig-liste*) + (setq *geruest-konfig-liste* + (list (cons nil '(("name" . "K"))) (cons T '(("name" . "K"))) + (cons nil '(("name" . "L"))))) + (tu-eq "geruest-konfig-index/eigene-zuerst" 2 (geruest-konfig-index "K")) + (tu-eq "geruest-konfig-index/bibliothek" 3 (geruest-konfig-index "L")) + (tu-eq "geruest-konfig-name-vorgabe/eigene" "K" (geruest-konfig-name-vorgabe 2)) + (tu-nil "geruest-konfig-name-vorgabe/bibliothek" (geruest-konfig-name-vorgabe 1)) + (tu-nil "geruest-konfig-name-vorgabe/keine" (geruest-konfig-name-vorgabe 0)) + (setq *geruest-konfig-liste* _alt) + (tu-eq "geruest-konfig-sonstiges/umhaengen" '(4 3) + (geruest-konfig-sonstiges _konfig + (geruest-anbau-liste _bgtest "sonstiges") + (geruest-anbau-liste _bgtest "befestigung"))) + ;; Befestigung = Gesamtanzahl: neues Feld "befestigung", altes oben + + ;; unten summiert; der Haltearm unter "oben" wird hier still uebergangen + (tu-eq "geruest-konfig-befestigung/alt" '(2) + (geruest-konfig-befestigung _konfig + (geruest-anbau-liste _bgtest "befestigung") + (geruest-anbau-liste _bgtest "sonstiges"))) + (tu-eq "geruest-konfig-befestigung/oben-unten" '(5) + (geruest-konfig-befestigung + (ssg-json-parse + (strcat "{\"name\": \"A\", \"oben\": [{\"artikel\": \"K\", \"anzahl\": 2}]," + " \"unten\": [{\"artikel\": \"K\", \"anzahl\": 3}]}")) + (geruest-anbau-liste _bgtest "befestigung") + (geruest-anbau-liste _bgtest "sonstiges"))) + (tu-eq "geruest-konfig-befestigung/neu" '(4) + (geruest-konfig-befestigung + (ssg-json-parse + "{\"name\": \"N\", \"befestigung\": [{\"artikel\": \"K\", \"anzahl\": 4}]}") + (geruest-anbau-liste _bgtest "befestigung") + (geruest-anbau-liste _bgtest "sonstiges"))) + ;; Artikelnummer(n) fuer die Anzeige: Einzelteil bzw. Gruppe eindeutig + (tu-eq "geruest-artnr-anzeige/einzelteil" "825002019" + (geruest-artnr-anzeige _eintrag)) + (tu-eq "geruest-artnr-anzeige/gruppe" "111, 222" + (geruest-artnr-anzeige _gruppe)) + ;; Eine Befestigungsspalte (Prefix b) mit Art.-Nr.-Zeile je Teil + (setq _rec (geruest-dcl-ersetzungen "Saeulen" (list _eintrag) nil + (list '(("name" . "A"))))) + (tu-true "geruest-dcl-ersetzungen/befestigung-key" + (vl-some '(lambda (z) (vl-string-search "key = \"bm0\"" z)) + (cdr (assoc "BEFESTIGUNG" _rec)))) + (tu-true "geruest-dcl-ersetzungen/artnr-zeile" + (vl-some '(lambda (z) (vl-string-search "Art.-Nr. 825002019" z)) + (cdr (assoc "BEFESTIGUNG" _rec)))) ;; --- Variante gewinnt vor Baugruppe (TEILEART/dummy) --- ;; Die zusammengefuehrte Saeulen-Baugruppe unterscheidet 1 Zoll und @@ -1032,9 +1188,7 @@ (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)))) + (setq _saeulen (geruest-baugruppe "Saeulen" (geruest-daten))) (tu-eq "geruest/saeulen-vorhanden" T (if _saeulen T nil)) (if _saeulen (progn @@ -1046,10 +1200,27 @@ (tu-geruest-artikel-unvollstaendig (ssg-json-get _saeulen "geometrie_varianten"))) (tu-eq "geruest/saeulen-anbauteile" T - (if (ssg-json-get _saeulen "anbaugruppen") T nil)) + (if (geruest-anbau-liste _saeulen "befestigung") T nil)) (tu-eq "geruest/saeulen-anbauteile-artikel" 0 (tu-geruest-artikel-unvollstaendig - (ssg-json-get _saeulen "anbaugruppen"))) + (geruest-anbau-liste _saeulen "befestigung"))) + ;; Haltearme passen weder oben noch unten -> eigene Sonstiges-Zeile + (tu-eq "geruest/saeulen-sonstiges" 4 + (length (geruest-anbau-liste _saeulen "sonstiges"))) + (tu-eq "geruest/saeulen-sonstiges-artikel" 0 + (tu-geruest-artikel-unvollstaendig + (geruest-anbau-liste _saeulen "sonstiges"))) + (tu-nil "geruest/saeulen-haltearm-nicht-befestigung" + (vl-some '(lambda (a) + (wcmatch (geruest-eintrag-name a) "HALTEARM*")) + (geruest-anbau-liste _saeulen "befestigung"))) + ;; Rohrabhaenger/Wandbefestigung haben keine Sonstiges-Teile + (foreach _e '("Rohrabhaenger" "Wandbefestigung") + (setq _rec (geruest-baugruppe _e (geruest-daten))) + (tu-true (strcat "geruest/" _e "-befestigung") + (geruest-anbau-liste _rec "befestigung")) + (tu-nil (strcat "geruest/" _e "-ohne-sonstiges") + (geruest-anbau-liste _rec "sonstiges"))) (tu-eq "geruest/saeulen-titel" "Saeulen" (geruest-titel _saeulen)) ;; Variante R 1" traegt die eigene TEILEART - per Name gesucht, ;; die Reihenfolge in geruest.json ist nicht fest. @@ -1136,20 +1307,33 @@ (tu-eqf "geruest-traeger-streben/6000-letzte" 5750.0 (last _rec)) ;; Konfiguration: fehlende Felder -> Standard, ohne querstrebe -> nil ;; Ergebnis (dummy laenge querlinie abstand rand-min rand-max) + ;; Streben nur bei Varianten mit "mit_querstrebe": true + (setq _vmq (ssg-json-parse "{\"name\": \"A\", \"mit_querstrebe\": true}")) (tu-eqf "geruest-traeger-strebe-cfg/standard" '(nil 30.0 25.0 500.0 100.0 250.0) - (geruest-traeger-strebe-cfg nil + (geruest-traeger-strebe-cfg _vmq (ssg-json-parse "{\"querstrebe\": {\"rand_min\": 100}}"))) (tu-eqf "geruest-traeger-strebe-cfg/dummy" '("s.dwg" 30.0 25.0 500.0 100.0 250.0) - (geruest-traeger-strebe-cfg nil + (geruest-traeger-strebe-cfg _vmq (ssg-json-parse "{\"querstrebe\": {\"dummy\": \"s.dwg\"}}"))) (tu-eqf "geruest-traeger-strebe-cfg/wert" '(nil 30.0 25.0 400.0 100.0 250.0) + (geruest-traeger-strebe-cfg _vmq + (ssg-json-parse "{\"querstrebe\": {\"abstand\": 400}}"))) + (tu-eqf "geruest-traeger-strebe-cfg/variante" '(nil 30.0 25.0 300.0 100.0 250.0) + (geruest-traeger-strebe-cfg + (ssg-json-parse + "{\"mit_querstrebe\": true, \"querstrebe\": {\"abstand\": 300}}") + (ssg-json-parse "{\"querstrebe\": {\"abstand\": 400}}"))) + (tu-nil "geruest-traeger-strebe-cfg/ohne-flag" + (geruest-traeger-strebe-cfg (ssg-json-parse "{\"name\": \"Rohr 1\"}") + (ssg-json-parse "{\"querstrebe\": {\"abstand\": 400}}"))) + (tu-nil "geruest-traeger-strebe-cfg/ohne-variante" (geruest-traeger-strebe-cfg nil (ssg-json-parse "{\"querstrebe\": {\"abstand\": 400}}"))) ;; Querlinien an Anfang und Ende der 30 mm langen Strebe (tu-eqf "geruest-traeger-strebe-enden" '(235.0 265.0) (geruest-traeger-strebe-enden 250.0 30.0)) (tu-nil "geruest-traeger-strebe-cfg/ohne" - (geruest-traeger-strebe-cfg nil (ssg-json-parse "{\"id\": \"X\"}"))) + (geruest-traeger-strebe-cfg _vmq (ssg-json-parse "{\"id\": \"X\"}"))) ;; Muffe nur bei "mit_muffe": true; Variante darf eigene Muffe mitbringen (setq _bgtest (ssg-json-parse "{\"muffe\": {\"dummy\": \"m.dwg\"}}")) (tu-eq "geruest-traeger-muffe-dummy/flag" "m.dwg" @@ -1271,13 +1455,8 @@ _bgtest "LAENGENABZUGENDE" "aktiv")) ;; --- Rohr-Geruest-Traeger in der echten Datendatei --- - ;; Eigene Datei data/json/geruest_traeger.json: im Bereichs-Dropdown von - ;; GERUEST darf er nicht auftauchen, ueber geruest-traeger-daten muss er - ;; auffindbar sein. - (setq _rec nil) - (foreach _e (geruest-baugruppen-liste) - (if (equal (car _e) "Traeger") (setq _rec T))) - (tu-nil "geruest/traeger-nicht-im-dropdown" _rec) + ;; Eigene Datei data/json/geruest_traeger.json: in geruest.json darf er + ;; nicht stehen, ueber geruest-traeger-daten muss er auffindbar sein. (tu-true "geruest/traeger-datei" (findfile (geruest-json-pfad "geruest_traeger.json"))) (setq _traeger (geruest-baugruppe "Traeger" (geruest-traeger-daten))) @@ -1297,12 +1476,26 @@ (geruest-attr-feld nil _traeger "LAENGE" "max")) (tu-eqf "geruest/traeger-querstrebe" '("dummy_Strebe_30x4.dwg" 30.0 25.0 500.0 100.0 250.0) - (geruest-traeger-strebe-cfg nil _traeger)) + (geruest-traeger-strebe-cfg _vmq _traeger)) + ;; Querstreben-Flag je Variante: alle ausser den beiden Rohr-1"-Varianten + (setq _rec 0) + (foreach _v (ssg-json-get _traeger "geometrie_varianten") + (if (geruest-traeger-strebe-cfg _v _traeger) (setq _rec (1+ _rec)))) + (tu-eq "geruest/traeger-querstreben-varianten" 6 _rec) + (tu-nil "geruest/traeger-rohr-ohne-querstrebe" + (geruest-traeger-strebe-cfg + (car (ssg-json-get _traeger "geometrie_varianten")) _traeger)) ;; Muffen-Flag ausdruecklich je Variante: genau die "mit (2) Muffe(n)" (setq _rec 0) (foreach _v (ssg-json-get _traeger "geometrie_varianten") (if (geruest-traeger-muffe-dummy _v _traeger) (setq _rec (1+ _rec)))) (tu-eq "geruest/traeger-muffen-varianten" 4 _rec) + ;; Dialog: ein Radiobutton je Variante, auch fuer die mit Muffe + (tu-eq "geruest/traeger-radiobuttons" 8 + (length (geruest-dcl-varianten-zeilen + (ssg-json-get _traeger "geometrie_varianten") + (geruest-indizes (length (ssg-json-get _traeger + "geometrie_varianten")))))) ;; Jede Variante definiert Beschriftungstext UND -layer selbst - der ;; Layer ist je Traegervariante verschieden, eine Vorgabe der ;; Baugruppe gibt es dafuer bewusst nicht. @@ -1327,6 +1520,44 @@ ) ) + ;; --- Omniflo-Fahrstrecke (data/json/omniflo_fahrstrecke.json) --- + ;; Gleiche Linien-Logik wie der Traeger: jede Variante ein Radiobutton, + ;; nur ST/STL gibt es mit Muffen, nur ST/STL sind farbig. + (setq _fs (geruest-baugruppe "Fahrstrecke" (geruest-fahrstrecke-daten))) + (tu-true "fahrstrecke/vorhanden" _fs) + (if _fs + (progn + (setq _rec (ssg-json-get _fs "geometrie_varianten")) + (tu-eq "fahrstrecke/titel" "Fahrstrecke" (geruest-titel _fs)) + (tu-eq "fahrstrecke/varianten" + '("AP 110" "APG 110" "AP 60" "ST" "ST mit Muffen" "STL" "STL mit Muffen") + (mapcar 'geruest-eintrag-name _rec)) + (tu-eq "fahrstrecke/mit-muffe" '("ST mit Muffen" "STL mit Muffen") + (mapcar 'geruest-eintrag-name + (vl-remove-if-not '(lambda (v) (ssg-json-get v "mit_muffe")) _rec))) + ;; AP 110 ohne "farbig" -> leerer TEILEFARBE-Eintrag, ST farbig + (tu-eq "fahrstrecke/ap110-nicht-farbig" '("") + (geruest-farbliste (geruest-teile-paare (nth 0 _rec) nil) "RAL7035")) + (tu-eq "fahrstrecke/st-farbig" '("RAL7035") + (geruest-farbliste + (geruest-teile-paare + (nth (geruest-name-index "ST" _rec) _rec) nil) + "RAL7035")) + ;; Keine Querstreben; Muffen-Dummy wie beim Traeger nur bei den + ;; Varianten mit "mit_muffe": true + (tu-nil "fahrstrecke/ohne-querstrebe" + (geruest-traeger-strebe-cfg (nth (geruest-name-index "ST" _rec) _rec) _fs)) + (tu-eq "fahrstrecke/muffe-dummy" "dummy_Muffe_1zoll.dwg" + (geruest-traeger-muffe-dummy + (nth (geruest-name-index "ST mit Muffen" _rec) _rec) _fs)) + (tu-nil "fahrstrecke/ohne-muffe-dummy" + (geruest-traeger-muffe-dummy + (nth (geruest-name-index "ST" _rec) _rec) _fs)) + ) + ) + (tu-true "fahrstrecke/dcl-vorlage" + (findfile (geruest-dcl-vorlage-pfad "fahrstrecke.dcl"))) + ;; --- Rundlauf Schreiber -> Parser --- ;; Prueft den Konfigurations-Schreiber ohne BricsCAD-Dialog. Bewusst in ;; eine temporaere Datei: ein Test darf cfg/geruest_user.json nicht @@ -1337,9 +1568,10 @@ (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 "anzahl" 2)))) - (cons "unten" nil))) + (cons "befestigung" (list (list (cons "artikel" "ROHRKLAMMER 1\" KPL. VERTIKAL") + (cons "anzahl" 2)))) + (cons "sonstiges" nil) + (cons "winkel_platte" 90))) (setq _pfad (vl-filename-mktemp "grtest" nil ".json")) (setq _f (open _pfad "w")) (write-line "{ \"Test\": [" _f) @@ -1356,12 +1588,16 @@ (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-anzahl" 2 - (ssg-json-get (car (ssg-json-get _zurueck "oben")) "anzahl")) - (tu-eq "geruest-schreiber/unten-leer" nil - (ssg-json-get _zurueck "unten")) + (tu-eq "geruest-schreiber/befestigung-artikel" "ROHRKLAMMER 1\" KPL. VERTIKAL" + (ssg-json-get (car (ssg-json-get _zurueck "befestigung")) "artikel")) + (tu-eq "geruest-schreiber/befestigung-anzahl" 2 + (ssg-json-get (car (ssg-json-get _zurueck "befestigung")) "anzahl")) + (tu-eq "geruest-schreiber/sonstiges-leer" nil + (ssg-json-get _zurueck "sonstiges")) + (tu-eq "geruest-schreiber/winkel" 90 + (ssg-json-get _zurueck "winkel_platte")) + ;; altes Format wird nicht mehr geschrieben + (tu-nil "geruest-schreiber/ohne-oben" (assoc "oben" _zurueck)) ) ) ) @@ -1713,6 +1949,7 @@ (tu-eq "ssg-sl-klasse/vf" "ils_strecke" (car (ssg-sl-klasse "VF_2"))) (tu-eq "ssg-sl-klasse/gf" "ils_strecke" (car (ssg-sl-klasse "GF_1"))) (tu-eq "ssg-sl-klasse/geruest" "geruest" (car (ssg-sl-klasse "GR_Saeulen_20260101120000"))) + (tu-eq "ssg-sl-klasse/fahrstrecke" "fahrstrecke" (car (ssg-sl-klasse "GR_Fahrstrecke_20260101120000"))) (tu-eq "ssg-sl-klasse/ap60" "ap60" (car (ssg-sl-klasse "AP60_20260101120000"))) (tu-eq "ssg-sl-klasse/apg110" "apg110" (car (ssg-sl-klasse "APG110_20260101120000"))) (tu-eq "ssg-sl-klasse/ap110" "ap110" (car (ssg-sl-klasse "AP110_20260101120000")))