From 4e39c64ec129da176410767357daad281c599ef1 Mon Sep 17 00:00:00 2001 From: Simon Hensch Date: Tue, 29 Sep 2026 12:07:00 +0200 Subject: [PATCH] [ADD] Geruest: Teile-DWGs (data/geruest/.dwg) als Geometrie im GR_-Block; TEILEFARBE als Liste parallel zu ARTINR (Flag farbig in geruest.json), Sivas-Merkmal 108 aus cfg [Sivas]; Menue-Befehle GERUEST_SAEULEN/_ROHRABHAENGER/_WANDBEFESTIGUNG [FIX] Sivas-Export las nicht existierendes Attribut FARBE --- CLAUDE.md | 6 +- Lisp/DrawPlanquadrate.lsp | 2 +- Lisp/Gefaellestrecke.lsp | 6 +- Lisp/GeruestInsert.lsp | 152 +++++++++++--- Lisp/KreiselInsert.lsp | 43 +--- Lisp/ssg_core.lsp | 22 +++ Lisp/vf_core.lsp | 24 +-- Lisp/vf_linienzug.lsp | 18 +- Lisp/vf_standard.lsp | 2 +- cfg/export.cfg | 12 +- cfg/sivas_merkmal_zuordnung.md | 11 +- data/json/geruest.json | 244 ++++++++++++----------- lib/export_sivas.py | 84 +++++--- menu/SSG_LIB.cui | 308 +++++++++++++++++------------ menu/SSG_LIB.mnu | 7 +- tests/alltests.json | 1 + tests/test_export_sivas_omniflo.py | 26 +++ tests/test_foerderer.lsp | 4 +- tests/test_gefaellestrecke.lsp | 2 +- tests/test_mubea.lsp | 2 +- tests/test_unit.lsp | 44 +++++ 21 files changed, 637 insertions(+), 383 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 9d5d154..882a3e7 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -75,7 +75,7 @@ Die `start_briscad.bat` ruft `setenv.bat` auf und startet BricsCAD. | VarioFoerderer | `VarioFoerderer` | FOERDERANLAGE, VARIOFOERDERER_EDIT, Vario_Kette_Merge | | Gefaellestrecke | `Gefaellestrecke` | GEFAELLESTRECKE, GEFAELLESTRECKE_EDIT | | Omniflo (komplett) | `OmniModulInsert` | OMNI_APB_*, OMNI_W*_*, OMNI_AP*, OMNI_TEF_*, OMNI_TV_*, OMNI_LADESCHLEIFE_*, OMNI_EDIT | -| Geruest | `GeruestInsert` | GERUEST (ein Dialog fuer alle Bereiche) | +| Geruest | `GeruestInsert` | GERUEST_SAEULEN, GERUEST_ROHRABHAENGER, GERUEST_WANDBEFESTIGUNG (derselbe Dialog, im jeweiligen Bereich geoeffnet; Rohr-Geruest-Traeger/Gattertraeger noch Platzhalter auf GERUEST) | | Connections | `Connection_Edit` + `SSG_LIB_Commands` | CONNECTION_INSERT, CONNECTION_EDIT, ILS_EINGANG_INSERT, ILS_AUSGANG_INSERT | | Export | `export` | EXPORTSIVAS, EXPORTCSV, CALLPYTHON | | Konfiguration | `SSG_LIB_Commands` + `DrawPlanquadrate` | SSG_DIM_SWITCH, SSG_SPRACHE, PLANQUADRATE_TOGGLE (DRAW_PLANQUADRATE/DELETE_PLANQUADRATE) | @@ -93,7 +93,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_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_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) | @@ -107,7 +107,7 @@ Detaillierte Dokumentation aller Funktionen und Befehle: siehe `Lisp/README.md`. | `OmniModulInsert.lsp` | OMNI_LOAD, OMNI_APB_*, OMNI_W*_*, OMNI_AP60/AP110, OMNI_TEF_*, OMNI_TV_*, OMNI_APBW_*, OMNI_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-Baugruppen aus `data/json/geruest.json` konfigurieren und einfuegen. **Ein Dialog fuer alle Bereiche**: oben ein Dropdown `bereich` (Rohrabhaenger / Saeulen / Wandbefestigung, Reihenfolge = Dateireihenfolge, Anzeigename aus dem ASCII-Feld `titel`). DCL hat **kein Reiter-Tile**, und da sich die Teilezeilen je Bereich unterscheiden, schliesst ein Bereichswechsel den Dialog (`done_dialog 4`) und die Schleife in `c:GERUEST` baut ihn neu auf; der Stand jedes Bereichs bleibt in `*geruest-zustand*` erhalten, ein versehentlicher Wechsel verwirft also nichts. 1"- und 2"-Saeulen liegen in EINER Baugruppe `Saeulen` mit gemeinsamer Anbauteil-Liste; **`teileart` und `dummy` duerfen je Geometrie-Variante ueberschrieben werden** (`geruest-variante-wert`, Variante gewinnt vor Baugruppe) - so liefert `R 1"` weiterhin TEILEART `Geruest Saeule 1 Zoll` und die `R 2"`-Varianten `Geruest Saeule 2 Zoll`, die Groessen bleiben im Export also unterscheidbar. **Die Dialogdefinition wird zur Laufzeit erzeugt** (`geruest-dcl-schreiben` -> temporaere Datei per `vl-filename-mktemp`, nach `unload_dialog` wieder geloescht) - es gibt KEINE `dcl/geruest.dcl`. Grund: je Anbauteil wird ein eigenes Mengenfeld gebraucht, und eine DCL-Liste (`list_box`) kann keine Eingabefelder enthalten; DCL kann weder Dateien einbinden noch Tiles zur Laufzeit erzeugen. Inhalt: Basis-Variante aus `geometrie_varianten` (Dropdown), Laenge (gegen `attribute.Laenge` min/max geprueft, Retry-Schleife), Farbe (`attribute.Teilefarbe`, Freitext bei `frei_option`) und **zwei Befestigungslisten** ("oben"/"unten"), die BEIDE alle `anbaugruppen` enthalten - dasselbe Teil kann oben, unten oder gleichzeitig an beiden Positionen sitzen, je mit eigener Stueckzahl (vorbelegt aus `menge`). Baugruppen ohne `attribute`-Block (Wandbefestigung) bekommen Laenge/Farbe gesperrt, Baugruppen ohne Anbauteile bekommen gar keine Spalten (ein leerer DCL-Cluster ist unzulaessig). Im generierten Label wird `"` zu `''` ersetzt (`geruest-dcl-label`) - fuenf Artikelnamen enthalten ein Anfuehrungszeichen, das das DCL-Label sonst vorzeitig beendet und die Datei zerstoert. **Konfigurationen**: gepflegte Bibliothek je Baugruppe unter `konfigurationen` in `geruest.json` (schreibgeschuetzt) plus eigene in `cfg/geruest_user.json` (gitignored, `geruest-user-schreiben`; getrennte Datei, damit Benutzerdaten und versionierte Bibliothek nicht kollidieren). Eigene Eintraege sind in der Liste mit `*` markiert und nur diese loeschbar. Konfigurationen verweisen ueber den ANZEIGENAMEN auf Variante und Anbauteile; ein unbekannter Name wird gemeldet und uebersprungen, statt die Konfiguration scheitern zu lassen. Speichern/Loeschen laufen ueber `done_dialog 2`/`3` (Dialog schliessen, Aktion, neu zeigen) - `getstring` funktioniert aus einem `action_tile`-Rueckruf heraus nicht. Der Block wird - wie KREISEL_n/VF_n - SELBST zusammengebaut: Dummy-DWG aus `data/geruest` liefert nur Geometrie, das Attribut-Schema kommt aus `*geruest-attrib-defs*` (ID, ARTINR, LAENGE, BEZEICHNUNG, TEILEART, TEILEFARBE, LAYER) und wird per `ssg-attrib-merge` mit den Dummy-Tags zusammengefuehrt - sonst verschluckt `ssg-attrib-set-on` stillschweigend jeden Tag, den die Dummy-DWG nicht als ATTDEF kennt. Blockname `GR__` (Kollisionszaehler wie in OmniModulInsert). **Das `GR_`-Praefix ist nicht kosmetisch**: `SSG_BLOCKEDIT` haelt JEDEN Block mit TEILEART-Attribut fuer ein Omniflo-Element, deshalb steht in `SSG_LIB_Commands.lsp` ein `GR_*`-Zweig VOR dem Omniflo-Zweig. ARTINR listet jede Sivas-ID so oft, wie die gewaehlte Stueckzahl es vorgibt - erst Basis, dann Befestigung oben, dann unten; bei einer benannten Gruppe (`teile`) wird das ganze Set n-mal wiederholt, die Mengen INNERHALB des Sets bleiben dabei erhalten (`geruest-artikelnummern-n`). BEZEICHNUNG nennt Position und Menge je Teil ("oben 2x ...") und verkettet mit `" + "`, NICHT mit Komma - die Artikelbezeichnungen enthalten selbst Kommas ("ROHR R 1\" 33,7 x 2,6"). Zuordnung Menue -> JSON laeuft ueber das ASCII-Feld `id`, weil die aeusseren JSON-Schluessel Umlaute bzw. Anfuehrungszeichen tragen. CSV-/Sivas-Export: `pattern_geruest = GR_*` (cfg/export.cfg), `csv:collect-export-blocks`/`ssg-id-collect-blocks` sammeln GR_-Bloecke wie BTMT eigenstaendig; `*geruest-attrib-defs*` traegt zusaetzlich ein leeres `ID`-ATTDEF (Voraussetzung fuer `ssg-id-check-all`, das nur bestehende ATTRIBs beschreiben kann). ARTINR/BEZEICHNUNG/TEILEART/LAENGE landen in export_csv.py/export_sivas.py in festen Spalten, TEILEFARBE/LAYER (+ ARTINR bei export_csv.py) im Merkmale-/details-JSON. Noch NICHT enthalten: Edit-Pfad (GERUEST_EDIT) | +| `GeruestInsert.lsp` | GERUEST, GERUEST_SAEULEN, GERUEST_ROHRABHAENGER, GERUEST_WANDBEFESTIGUNG | Geruest-Baugruppen aus `data/json/geruest.json` konfigurieren und einfuegen. **Ein Dialog fuer alle Bereiche**: oben ein Dropdown `bereich` (Rohrabhaenger / Saeulen / Wandbefestigung, Reihenfolge = Dateireihenfolge, Anzeigename aus dem ASCII-Feld `titel`). DCL hat **kein Reiter-Tile**, und da sich die Teilezeilen je Bereich unterscheiden, schliesst ein Bereichswechsel den Dialog (`done_dialog 4`) und die Schleife in `c:GERUEST` baut ihn neu auf; der Stand jedes Bereichs bleibt in `*geruest-zustand*` erhalten, ein versehentlicher Wechsel verwirft also nichts. 1"- und 2"-Saeulen liegen in EINER Baugruppe `Saeulen` mit gemeinsamer Anbauteil-Liste; **`teileart` und `dummy` duerfen je Geometrie-Variante ueberschrieben werden** (`geruest-variante-wert`, Variante gewinnt vor Baugruppe) - so liefert `R 1"` weiterhin TEILEART `Geruest Saeule 1 Zoll` und die `R 2"`-Varianten `Geruest Saeule 2 Zoll`, die Groessen bleiben im Export also unterscheidbar. **Die Dialogdefinition wird zur Laufzeit erzeugt** (`geruest-dcl-schreiben` -> temporaere Datei per `vl-filename-mktemp`, nach `unload_dialog` wieder geloescht) - es gibt KEINE `dcl/geruest.dcl`. Grund: je Anbauteil wird ein eigenes Mengenfeld gebraucht, und eine DCL-Liste (`list_box`) kann keine Eingabefelder enthalten; DCL kann weder Dateien einbinden noch Tiles zur Laufzeit erzeugen. Inhalt: Basis-Variante aus `geometrie_varianten` (Dropdown), Laenge (gegen `attribute.Laenge` min/max geprueft, Retry-Schleife), Farbe (`attribute.Teilefarbe`, Freitext bei `frei_option`) und **zwei Befestigungslisten** ("oben"/"unten"), die BEIDE alle `anbaugruppen` enthalten - dasselbe Teil kann oben, unten oder gleichzeitig an beiden Positionen sitzen, je mit eigener Stueckzahl (vorbelegt aus `menge`). Baugruppen ohne `attribute`-Block (Wandbefestigung) bekommen Laenge/Farbe gesperrt, Baugruppen ohne Anbauteile bekommen gar keine Spalten (ein leerer DCL-Cluster ist unzulaessig). Im generierten Label wird `"` zu `''` ersetzt (`geruest-dcl-label`) - fuenf Artikelnamen enthalten ein Anfuehrungszeichen, das das DCL-Label sonst vorzeitig beendet und die Datei zerstoert. **Konfigurationen**: gepflegte Bibliothek je Baugruppe unter `konfigurationen` in `geruest.json` (schreibgeschuetzt) plus eigene in `cfg/geruest_user.json` (gitignored, `geruest-user-schreiben`; getrennte Datei, damit Benutzerdaten und versionierte Bibliothek nicht kollidieren). Eigene Eintraege sind in der Liste mit `*` markiert und nur diese loeschbar. Konfigurationen verweisen ueber den ANZEIGENAMEN auf Variante und Anbauteile; ein unbekannter Name wird gemeldet und uebersprungen, statt die Konfiguration scheitern zu lassen. Speichern/Loeschen laufen ueber `done_dialog 2`/`3` (Dialog schliessen, Aktion, neu zeigen) - `getstring` funktioniert aus einem `action_tile`-Rueckruf heraus nicht. Der Block wird - wie KREISEL_n/VF_n - SELBST zusammengebaut: Dummy-DWG aus `data/geruest` liefert nur Geometrie, das Attribut-Schema kommt aus `*geruest-attrib-defs*` (ID, ARTINR, LAENGE, BEZEICHNUNG, TEILEART, TEILEFARBE, LAYER) und wird per `ssg-attrib-merge` mit den Dummy-Tags zusammengefuehrt - sonst verschluckt `ssg-attrib-set-on` stillschweigend jeden Tag, den die Dummy-DWG nicht als ATTDEF kennt. **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 die gewaehlte Stueckzahl es vorgibt - erst Basis, dann Befestigung oben, dann unten; bei einer benannten Gruppe (`teile`) wird das ganze Set n-mal wiederholt, die Mengen INNERHALB des Sets bleiben dabei erhalten (`geruest-artikelnummern-n`). BEZEICHNUNG nennt Position und Menge je Teil ("oben 2x ...") und verkettet mit `" + "`, NICHT mit Komma - die Artikelbezeichnungen enthalten selbst Kommas ("ROHR R 1\" 33,7 x 2,6"). Zuordnung Menue -> JSON laeuft ueber das ASCII-Feld `id`, weil die aeusseren JSON-Schluessel Umlaute bzw. Anfuehrungszeichen tragen. CSV-/Sivas-Export: `pattern_geruest = GR_*` (cfg/export.cfg), `csv:collect-export-blocks`/`ssg-id-collect-blocks` sammeln GR_-Bloecke wie BTMT eigenstaendig; `*geruest-attrib-defs*` traegt zusaetzlich ein leeres `ID`-ATTDEF (Voraussetzung fuer `ssg-id-check-all`, das nur bestehende ATTRIBs beschreiben kann). ARTINR/BEZEICHNUNG/TEILEART/LAENGE landen in export_csv.py/export_sivas.py in festen Spalten, TEILEFARBE/LAYER (+ ARTINR bei export_csv.py) im Merkmale-/details-JSON. Noch NICHT enthalten: Edit-Pfad (GERUEST_EDIT) | | `menu-inventory.lsp` | MenuInventory | BricsCAD Diagnostik (Menuegruppen, Plugins, Startdateien) | | `DrawPlanquadrate.lsp` | DRAW_PLANQUADRATE, DELETE_PLANQUADRATE, PLANQUADRATE_TOGGLE | Zeichnet auf Z=0 ein Planquadrat-Linienraster (senkrecht/waagerecht), im Abstand/Zaehlschema der aktiven `[Planquadrate]`-Konfiguration aus `cfg/export.cfg` (dieselbe Quelle wie `lib/export_planquadrat.py` fuer den CSV-Export). Bereich kommt NICHT aus den Zeichnungs-Extents, sondern aus derselben Blockmenge wie EXPORTCSV (`csv:collect-export-blocks`, export.lsp; siehe `plq-export-bbox`): Ursprung (Index 1) UND obere Grenze kommen BEIDE aus der tatsaechlichen Bounding-Box jedes Blocks (`csv:get-bbox`, wie `bbox_columns()`/`planquadrat_column()`/`_bbox_min()` in `lib/export_csv.py` bzw. `lib/export_planquadrat.py`), NICHT aus dem reinen Einfuegepunkt - bei einem gedrehten/exzentrisch eingefuegten Block (z.B. ein um 90 Grad gedrehter Kreisel) kann das Bounding-Box-Zentrum weit vom Einfuegepunkt abweichen; Ursprung und Zellzuordnung muessen auf derselben Referenz beruhen, sonst driften sie auseinander (realer Bug, behoben). Reine Hilfsgeometrie (Kreisel-Umfahrungsboegen als eigene Linien, Texte) zaehlt bewusst nicht mit, sonst weicht das Raster vom CSV-Export ab. `x_origin`/`y_origin` ueberschreiben den Ursprung, Fallback auf EXTMIN/EXTMAX falls keine Export-Bloecke vorhanden sind bzw. `csv:get-bbox` fuer einen Block scheitert. Spalten-/Zeilenzahl wird IMMER aufgerundet auf volle Rasterschritte, damit alle senkrechten Linien auf der letzten waagerechten enden und umgekehrt - das Raster bildet immer ein geschlossenes Rechteck. Zaehlung (alphabetisch/numerisch je Achse) als Text am linken/unteren Rand. Das fertige Raster (Linien+Texte) wird per `_.-BLOCK`/`_.INSERT` zu einem einzigen Block `ZZ_PLANQUADRATE` bei (0,0,0) zusammengefasst. Layer aus `cfg/layer.cfg` (`[allgemein]` Key `planquadrate`, Fallback `ZZ_Planquadrate`). DRAW_PLANQUADRATE entfernt vor dem Neuaufbau zuerst einen evtl. vorhandenen Block (`plq-block-entfernen`: INSERTs loeschen + `_-PURGE _B`), DELETE_PLANQUADRATE ruft nur diese Entfernung auf. PLANQUADRATE_TOGGLE ("Planquadrate an/aus", Menue: Konfiguration) prueft per `tblsearch`/`ssget "X"`, ob der Block existiert, und dispatcht auf Zeichnen bzw. Loeschen. Lazy geladen ueber `(ssg-ensure "DrawPlanquadrate")`, nicht in der Core-Ladereihenfolge. Die Planquadrat-SPALTE im CSV-Export (`export_csv.py::planquadrat_column`/`resolve_origins`, `lib/export_planquadrat.py::compute_planquadrat`/`_bbox_min`) rechnet ebenfalls durchgaengig auf Bounding-Box-Basis (nicht nur Einfuegepunkt) und liefert eine SPANNE ("A/1-J/1") statt nur einer Zelle, wenn ein Element mehr als eine Zelle ueberdeckt (Kreisel, lange VF-/GF-Ketten). | diff --git a/Lisp/DrawPlanquadrate.lsp b/Lisp/DrawPlanquadrate.lsp index ec37b2c..2a19e00 100644 --- a/Lisp/DrawPlanquadrate.lsp +++ b/Lisp/DrawPlanquadrate.lsp @@ -276,7 +276,7 @@ ;; Letztes Entity VOR dem Zeichnen merken, um danach per entnext ;; genau die neu erzeugten Objekte einzusammeln (wie ;; kreisel-make-label/draw-module in KreiselInsert.lsp). - (setq lastEnt (entlast)) + (setq lastEnt (ssg-lastent-ohne-attribute)) ;; Senkrechte Linien (konstantes X) + Spalten-Beschriftung unten. (setq i 0) diff --git a/Lisp/Gefaellestrecke.lsp b/Lisp/Gefaellestrecke.lsp index f4507e4..162b30b 100644 --- a/Lisp/Gefaellestrecke.lsp +++ b/Lisp/Gefaellestrecke.lsp @@ -958,11 +958,11 @@ (if (not (= antwort "2")) (progn ;; GF-Nummer und Entity-Grenze vor erster Einfuegung sichern. - ;; vf-lastent-ohne-attribute ueberspringt Attribut-Entities/SEQEND + ;; ssg-lastent-ohne-attribute ueberspringt Attribut-Entities/SEQEND ;; eines vorherigen GF_N/VF_N-Blocks, sonst rutschen sie in die ;; naechste Blockerstellung hinein. (setq gf-nummer (gf-next-number)) - (setq last-ent (vf-lastent-ohne-attribute)) + (setq last-ent (ssg-lastent-ohne-attribute)) ;; AUS-Element: KS_EIN so ausrichten, dass KS_AUS in Fahrtrichtung entry-hz zeigt. ;; Beweis: KS_AUS.xu = -yu(target-frame). Fuer KS_AUS||entry-hz gilt: @@ -1332,7 +1332,7 @@ ;; GF-Nummer und Entity-Grenze vor erster Einfuegung (setq gf-nummer (gf-next-number)) - (setq last-ent (vf-lastent-ohne-attribute)) + (setq last-ent (ssg-lastent-ohne-attribute)) ;; Fahrtrichtungsvektor (KS_AUS-Richtung, Basis fuer Staustrecke/Separator/ES) (setq rad-hz (* (float hz) (/ pi 180.0))) diff --git a/Lisp/GeruestInsert.lsp b/Lisp/GeruestInsert.lsp index 16732c8..436fe2f 100644 --- a/Lisp/GeruestInsert.lsp +++ b/Lisp/GeruestInsert.lsp @@ -22,6 +22,16 @@ ;; 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 +;; Geometrie als visuelle Rueckmeldung, die Attribute bleiben davon unberuehrt. +;; Teile ohne DWG werden still uebergangen. +;; +;; TEILEFARBE ist eine kommagetrennte Liste parallel zu ARTINR: jedes Teil mit +;; "farbig": true in geruest.json bekommt die im Dialog gewaehlte Farbe, alle +;; anderen einen leeren Eintrag (geruest-teile-paare/geruest-farbliste). +;; ;; Das GR_-Praefix ist nicht kosmetisch: SSG_BLOCKEDIT haelt jeden Block mit ;; TEILEART-Attribut fuer ein Omniflo-Element (SSG_LIB_Commands.lsp). Der ;; Doppelklick-Dispatcher erkennt Geruest-Bloecke an diesem Praefix. @@ -179,22 +189,65 @@ erg ) -;; Alle Artikelnummern eines Eintrags, jede gemaess "menge" wiederholt. -;; Benannte Gruppen ("teile") werden rekursiv aufgeloest. -(defun geruest-artikelnummern (eintrag / erg teile) +;; Alle Teile eines Eintrags als ((artnr . farbig) ...), jedes gemaess +;; "menge" wiederholt. Benannte Gruppen ("teile") werden rekursiv aufgeloest. +;; farbig = darf das Teil die Baugruppenfarbe tragen ("farbig" im JSON). Eine +;; Gruppe mit "farbig": true vererbt das an ihre Teile (erbe); ein Teil kann +;; die Vererbung nicht per false aufheben - false und "fehlt" sind beide nil. +;; ARTINR und TEILEFARBE entstehen aus DIESEM einen Durchlauf, damit beide +;; Listen garantiert gleich lang und gleich sortiert sind. +(defun geruest-teile-paare (eintrag erbe / erg teile farbig) (setq erg nil) + (setq farbig (if (or erbe (ssg-json-get eintrag "farbig")) T nil)) (setq teile (ssg-json-get eintrag "teile")) (if teile (foreach teil teile - (setq erg (append erg (geruest-artikelnummern teil))) + (setq erg (append erg (geruest-teile-paare teil farbig))) ) - (setq erg (geruest-wiederholen - (geruest-id-string (ssg-json-get eintrag "sivas_id")) - (geruest-menge eintrag))) + (setq erg (mapcar '(lambda (nr) (cons nr farbig)) + (geruest-wiederholen + (geruest-id-string (ssg-json-get eintrag "sivas_id")) + (geruest-menge eintrag)))) ) erg ) +;; Alle Artikelnummern eines Eintrags, jede gemaess "menge" wiederholt. +(defun geruest-artikelnummern (eintrag) + (mapcar 'car (geruest-teile-paare eintrag nil)) +) + +;; TEILEFARBE-Liste zu Teile-Paaren: die Baugruppenfarbe fuer jedes farbige +;; Teil, "" fuer alle anderen. +(defun geruest-farbliste (paare farbe) + (mapcar '(lambda (p) (if (cdr p) farbe "")) paare) +) + +;; Liste ohne Duplikate, Reihenfolge des ersten Auftretens bleibt erhalten. +(defun geruest-eindeutig (lst / erg) + (setq erg nil) + (foreach e lst + (if (not (member e erg)) (setq erg (cons e erg))) + ) + (reverse erg) +) + +;; 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 +;; DWGs werden still uebergangen. +(defun geruest-teile-dwgs (artnr-liste / erg pfad) + (setq erg nil) + (foreach nr (geruest-eindeutig artnr-liste) + (if (and nr + (setq pfad (geruest-dummy-pfad (strcat nr ".dwg"))) + (findfile pfad)) + (setq erg (cons pfad erg)) + ) + ) + (reverse erg) +) + ;; ============================================================ ;; DIALOG @@ -239,13 +292,14 @@ ;; Einzelteil: die Sivas-ID anzahl-mal. Benannte Gruppe ("teile"): das ;; komplette Set anzahl-mal - die Mengen INNERHALB des Sets bleiben erhalten ;; (ein Schraubenset bleibt 1 Scheibe + 2 Muttern + 1 Schraube je Satz). -(defun geruest-artikelnummern-n (eintrag anzahl / teile einmal erg i) +(defun geruest-teile-paare-n (eintrag anzahl / teile einmal erg i farbig) (setq teile (ssg-json-get eintrag "teile")) + (setq farbig (if (ssg-json-get eintrag "farbig") T nil)) (if teile (progn (setq einmal nil) (foreach teil teile - (setq einmal (append einmal (geruest-artikelnummern teil))) + (setq einmal (append einmal (geruest-teile-paare teil farbig))) ) (setq erg nil i 0) (while (< i anzahl) @@ -254,11 +308,16 @@ ) erg ) - (geruest-wiederholen - (geruest-id-string (ssg-json-get eintrag "sivas_id")) anzahl) + (mapcar '(lambda (nr) (cons nr farbig)) + (geruest-wiederholen + (geruest-id-string (ssg-json-get eintrag "sivas_id")) anzahl)) ) ) +(defun geruest-artikelnummern-n (eintrag anzahl) + (mapcar 'car (geruest-teile-paare-n eintrag anzahl)) +) + ;; Index eines Eintrags (Variante oder Anbauteil) ueber seinen Anzeigenamen. (defun geruest-name-index (name liste / i idx) (setq i 0 idx nil) @@ -1073,8 +1132,10 @@ ;; 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. ;; Rueckgabe: (blockname . entity) oder nil. -(defun geruest-block-bauen (bg variante werte pt / datei dummy lastEnt dummyEnt +(defun geruest-block-bauen (bg variante werte pt teile-dwgs / datei dummy lastEnt dummyEnt e ss bname blockEnt dummy-attribs attribs) ;; Eine Variante darf eine eigene Dummy-DWG mitbringen; sonst gilt die der ;; Baugruppe. @@ -1089,7 +1150,10 @@ (setvar "ATTREQ" 0) (setvar "ATTDIA" 0) (setvar "OSMODE" 0) - (setq lastEnt (entlast)) + ;; Nicht (entlast): ist das letzte Objekt ein Block mit Attributen (z.B. + ;; eine per Strg+C/V eingefuegte GR_-Kopie), wuerden dessen ATTRIBs mit + ;; eingesammelt und von _.-BLOCK entfernt. + (setq lastEnt (ssg-lastent-ohne-attribute)) ;; Dummy bei (0,0,0) einfuegen - seine Attribute liefern u.a. die ;; LAYER-Vorgabe. @@ -1097,6 +1161,14 @@ (setq dummyEnt (entlast)) (setq dummy-attribs (ssg-attrib-read dummyEnt)) + ;; Ausgewaehlte Teile mit eigener DWG als sichtbare Rueckmeldung + ;; 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. + (foreach teil teile-dwgs + (command "_.INSERT" teil (list 0.0 0.0 0.0) 1 1 0) + ) + ;; Unser Schema gewinnt an Struktur, die Dummy-Werte an Inhalt: ;; ssg-attrib-merge legt alle Tags aus *geruest-attrib-defs* an und ;; uebernimmt zusaetzlich alle Tags der Dummy-DWG. @@ -1150,12 +1222,13 @@ ;; ABLAUF ;; ============================================================ -;; Artikelnummern einer Befestigungsauswahl ((index . menge) ...). -(defun geruest-auswahl-artnr (auswahl anbauteile / erg) +;; Teile-Paare ((artnr . farbig) ...) einer Befestigungsauswahl +;; ((index . menge) ...). +(defun geruest-auswahl-paare (auswahl anbauteile / erg) (setq erg nil) (foreach paar auswahl (setq erg (append erg - (geruest-artikelnummern-n (nth (car paar) anbauteile) (cdr paar)))) + (geruest-teile-paare-n (nth (car paar) anbauteile) (cdr paar)))) ) erg ) @@ -1176,7 +1249,7 @@ ;; wahl = (variante-index oben unten laenge farbe) - die Dialog-Rueckgabe ohne ;; das fuehrende "OK". (defun geruest-einfuegen (bg wahl / varianten anbauteile variante teileart - artnr bezeichnung teile-namen werte pt ergebnis) + paare artnr bezeichnung teile-namen werte pt ergebnis) (setq varianten (ssg-json-get bg "geometrie_varianten")) (setq anbauteile (ssg-json-get bg "anbaugruppen")) (setq variante (nth (car wahl) varianten)) @@ -1186,10 +1259,12 @@ ;; 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. - (setq artnr (geruest-artikelnummern variante)) - (setq artnr (append artnr (geruest-auswahl-artnr (cadr wahl) anbauteile))) - (setq artnr (append artnr (geruest-auswahl-artnr (caddr wahl) anbauteile))) + ;; Positionen erscheint entsprechend mehrfach. Die Paare tragen zusaetzlich + ;; das farbig-Flag je Teil fuer die TEILEFARBE-Liste (gleiche Reihenfolge). + (setq paare (geruest-teile-paare variante nil)) + (setq paare (append paare (geruest-auswahl-paare (cadr wahl) anbauteile))) + (setq paare (append paare (geruest-auswahl-paare (caddr wahl) anbauteile))) + (setq artnr (mapcar 'car paare)) ;; BEZEICHNUNG: mit " + " verketten - die Artikelbezeichnungen enthalten ;; selbst Kommas ("ROHR R 1\" 33,7 x 2,6"). @@ -1207,15 +1282,19 @@ (cons "TEILEART" teileart))) (if (/= (nth 3 wahl) "") (setq werte (append werte (list (cons "LAENGE" (nth 3 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) "") - (setq werte (append werte (list (cons "TEILEFARBE" (nth 4 wahl)))))) + (setq werte (append werte (list (cons "TEILEFARBE" + (ssg-join (geruest-farbliste paare (nth 4 wahl)) ",")))))) (setq pt (getpoint (ssg-text "gr-prompt-einfuegepunkt"))) (if (null pt) (princ (ssg-text "gr-abgebrochen")) (progn (ssg-start "Geruest" '(("OSMODE") ("ATTREQ") ("ATTDIA"))) - (setq ergebnis (geruest-block-bauen bg variante werte pt)) + (setq ergebnis (geruest-block-bauen bg variante werte pt + (geruest-teile-dwgs artnr))) (ssg-end) (if ergebnis (princ (ssg-textf "gr-fertig" (list teileart (car ergebnis)))) @@ -1226,15 +1305,29 @@ ) +;; 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. -(defun c:GERUEST ( / bereiche idx bg erg weiter) +;; 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 0 weiter T) + (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 @@ -1262,5 +1355,12 @@ (princ) ) -(princ "\nGeruestInsert.lsp geladen. Befehl: GERUEST") +(defun c:GERUEST ( / ) (geruest-starten nil)) + +;; Menue-Einstiege je Bereich - oeffnen denselben Dialog im passenden Bereich. +(defun c:GERUEST_SAEULEN ( / ) (geruest-starten "Saeulen")) +(defun c:GERUEST_ROHRABHAENGER ( / ) (geruest-starten "Rohrabhaenger")) +(defun c:GERUEST_WANDBEFESTIGUNG ( / ) (geruest-starten "Wandbefestigung")) + +(princ "\nGeruestInsert.lsp geladen. Befehle: GERUEST, GERUEST_SAEULEN, GERUEST_ROHRABHAENGER, GERUEST_WANDBEFESTIGUNG") (princ) diff --git a/Lisp/KreiselInsert.lsp b/Lisp/KreiselInsert.lsp index 266d687..a2b2c40 100644 --- a/Lisp/KreiselInsert.lsp +++ b/Lisp/KreiselInsert.lsp @@ -403,26 +403,8 @@ (if (not block-exists) (progn ;; WICHTIG: Vor dem Zeichnen den aktuellen letzten Entity merken - ;; Aber wenn die Zeichnung leer ist, setzen wir lastEnt auf nil - (if (setq lastEnt (entlast)) - (progn - ;; Falls lastEnt ein INSERT mit Attributen ist, muessen wir - ;; bis zum SEQEND navigieren, da entnext sonst in die - ;; ATTRIB-Sub-Entities hineinlaeuft - (if (and (= (cdr (assoc 0 (entget lastEnt))) "INSERT") - (= (cdr (assoc 66 (entget lastEnt))) 1)) - (progn - (setq lastEnt (entnext lastEnt)) - (while (and lastEnt - (/= (cdr (assoc 0 (entget lastEnt))) "SEQEND")) - (setq lastEnt (entnext lastEnt)) - ) - ;; lastEnt ist jetzt SEQEND - entnext darauf gibt das naechste Top-Level-Entity - ) - ) - ) - (setq lastEnt nil) ;; Zeichnung ist leer - ) + ;; (SEQEND-Schutz fuer INSERT mit Attributen, nil bei leerer Zeichnung) + (setq lastEnt (ssg-lastent-ohne-attribute)) ;; AN8 Kreis (Antriebsstation) bei (radius, 0) - Dim-Suffix im Dateinamen (command "_.INSERT" (strcat *block-path* "AN8_" *ki-dxfm-dim* ".dwg") (list radius 0.0 0.0) 1 1 0) @@ -1220,24 +1202,9 @@ (progn (dbgp "Erzeuge neue Blockdefinition...") ;; Letzten Entity merken (mit SEQEND-Schutz wie bei draw-module) - (if (setq lastEnt (entlast)) - (progn - (dbgp (strcat "lastEnt Typ=" (cdr (assoc 0 (entget lastEnt))))) - (if (and (= (cdr (assoc 0 (entget lastEnt))) "INSERT") - (= (cdr (assoc 66 (entget lastEnt))) 1)) - (progn - (dbgp "lastEnt ist INSERT mit Attributen -> navigiere zu SEQEND") - (setq lastEnt (entnext lastEnt)) - (while (and lastEnt - (/= (cdr (assoc 0 (entget lastEnt))) "SEQEND")) - (setq lastEnt (entnext lastEnt)) - ) - (dbgp "SEQEND erreicht") - ) - ) - ) - (setq lastEnt nil) - ) + (setq lastEnt (ssg-lastent-ohne-attribute)) + (if lastEnt + (dbgp (strcat "lastEnt Typ=" (cdr (assoc 0 (entget lastEnt)))))) ;; AN8 Block einfuegen bei (0,0) - Eckrad ist ein einzelner Kreis (Dim-Suffix im Dateinamen) (dbgp (strcat "INSERT Block: " *block-path* "AN8_" *ki-dxfm-dim* ".dwg")) diff --git a/Lisp/ssg_core.lsp b/Lisp/ssg_core.lsp index 9bcd60d..298e43c 100644 --- a/Lisp/ssg_core.lsp +++ b/Lisp/ssg_core.lsp @@ -972,6 +972,28 @@ ) ) +;; Ermittelt den "letzten Entity" VOR einer neuen Einfuegung als Startmarke +;; fuer eine anschliessende (entnext marke)-Sammlung. (entlast) liefert nur +;; das Hauptobjekt; ist das ein INSERT mit Attributen (Gruppencode 66 = 1), +;; liefert (entnext insert) aber zuerst dessen ATTRIB-Subentities und SEQEND. +;; Die wuerden dann mit eingesammelt und von _.-BLOCK aus dem vorherigen +;; Block entfernt (realer Bug: per Strg+C/V kopierter GR_-Block verlor beim +;; naechsten GERUEST alle Attribute). Deshalb bis zum SEQEND vorlaufen. +;; Muss von JEDEM "alles Neue seit Marke einsammeln"-Aufrufer anstelle eines +;; nackten (entlast) verwendet werden. Rueckgabe: Entity oder nil (leer). +(defun ssg-lastent-ohne-attribute ( / ent) + (setq ent (entlast)) + (if (and ent (= (cdr (assoc 66 (entget ent))) 1)) + (progn + (setq ent (entnext ent)) + (while (and ent (/= (cdr (assoc 0 (entget ent))) "SEQEND")) + (setq ent (entnext ent)) + ) + ) + ) + ent +) + ;; Alle Attribute eines INSERT-Entity als Assoziationsliste lesen. ;; ent = Entity-Name eines INSERT mit Attributen. ;; Rueckgabe: (("TAG1" . "Wert1") ("TAG2" . "Wert2") ...) oder nil diff --git a/Lisp/vf_core.lsp b/Lisp/vf_core.lsp index 83df0c4..ec18f05 100644 --- a/Lisp/vf_core.lsp +++ b/Lisp/vf_core.lsp @@ -852,26 +852,6 @@ )) ) -;; Ermittelt den "letzten Entity" VOR einer neuen Einfuegung, so dass -;; nachfolgende Attribut-Entities/SEQEND eines vorherigen INSERT (z.B. eines -;; vorangegangenen VF_N-Blocks) nicht versehentlich in die naechste -;; vf-block-erstellen-Sammlung hineinfallen. Muss von JEDEM Aufrufer von -;; vf-block-erstellen anstelle eines nackten (entlast) verwendet werden. -(defun vf-lastent-ohne-attribute ( / ent) - (setq ent (entlast)) - (if (and ent - (= (cdr (assoc 0 (entget ent))) "INSERT") - (= (cdr (assoc 66 (entget ent))) 1)) - (progn - (setq ent (entnext ent)) - (while (and ent (/= (cdr (assoc 0 (entget ent))) "SEQEND")) - (setq ent (entnext ent)) - ) - ) - ) - ent -) - ;; --- Gemeinsamer VF_n-Wrapper-Rumpf (Standard/Etage UND Linienzug) ---------- ;; Der frueher in vf-block-erstellen (vf_core) und vfl-block-erstellen ;; (vf_linienzug) wortgleiche Rumpf: unsichtbare ATTDEFs am Startpunkt nach dem @@ -1057,7 +1037,7 @@ (cond ((= richtung "Auf") (+ hoehe-von deltaH)) ((= richtung "Ab") (- hoehe-von deltaH)) (t hoehe-von))) - (setq lastEnt (vf-lastent-ohne-attribute)) + (setq lastEnt (ssg-lastent-ohne-attribute)) (setq vf-endpunkt (apply einfuege-fn (list deltaL deltaH richtung best-winkel L_GF1 L_GF2 L_VF startpunkt seite hz))) @@ -1523,7 +1503,7 @@ (t hoehe-von))) ;; lastEnt VOR der Einfuegung merken - (setq lastEnt (vf-lastent-ohne-attribute)) + (setq lastEnt (ssg-lastent-ohne-attribute)) ;; Typ-spezifische Einfuegung (apply einfuege-fn diff --git a/Lisp/vf_linienzug.lsp b/Lisp/vf_linienzug.lsp index 4d11e93..3dbd70c 100644 --- a/Lisp/vf_linienzug.lsp +++ b/Lisp/vf_linienzug.lsp @@ -2285,7 +2285,7 @@ ;; Wird direkt nach dem Segment-Dispatch-cond in vf-linienzug-modus aufgerufen ;; (per vl-catch-all-apply abgesichert - ein Fehler hier darf den Hauptbau nie ;; abbrechen, rein additive Zusatz-XDATA). seg-lastEnt = Schnappschuss VOR -;; diesem Glied (vf-lastent-ohne-attribute, siehe Aufruf). wahl wird hier +;; diesem Glied (ssg-lastent-ohne-attribute, siehe Aufruf). wahl wird hier ;; nicht mehr gebraucht (das Label steckt schon im STEP-Eintrag des Journals ;; via vfl-journal-steplabel) - Parameter bleibt fuer eine spaetere dbgmsg- ;; Diagnose nuetzlich, daher weiterhin uebergeben. @@ -4048,7 +4048,7 @@ ;; (z.B. Anschluss an einen Kreisel), darum wird hier KS_EIN direkt ;; (xy-ref/z-ref="KS_EIN") auf den Klickpunkt gefluchtet - p0-real ist ;; dadurch einfach der Klickpunkt selbst, keine Nachmessung mehr noetig. - (setq checkpoint (vf-lastent-ohne-attribute)) + (setq checkpoint (ssg-lastent-ohne-attribute)) (setq p0-real p-aktuell) (setq p0x (car p0-real) p0y (cadr p0-real)) (setq theta-ref-rad (* (float theta-ref) (/ pi 180.0))) @@ -4091,7 +4091,7 @@ ;; GF_Bogen_L/R_xx- bzw. Separator-Attribute) - die Probe darf diese ;; Zaehler NICHT dauerhaft verfaelschen, darum sichern/zuruecksetzen. (setq acc-gfbogen-save *vfl-acc-gfbogen* acc-sep-save *vfl-acc-separator*) - (setq probe-checkpoint (vf-lastent-ohne-attribute)) + (setq probe-checkpoint (ssg-lastent-ohne-attribute)) (setq probe-frame (vfl-insert-gf-bogen-block frame bogen-winkel bogen-seite)) (setq hz2 (car (frame->hz-winkel probe-frame))) (setq bg2x (- (car (car probe-frame)) (car (car frame)))) @@ -4357,7 +4357,7 @@ ;; theta-ref) - NICHT theta-ref selbst (das ist E1's Fahrtrichtung). (setq dref-x (cos (* (float eintritt-hz) (/ pi 180.0)))) (setq dref-y (sin (* (float eintritt-hz) (/ pi 180.0)))) - (setq checkpoint (vf-lastent-ohne-attribute)) + (setq checkpoint (ssg-lastent-ohne-attribute)) (setq p0-real p-aktuell) (setq p0x (car p0-real) p0y (cadr p0-real)) (setq theta-ref-rad (* (float eintritt-hz) (/ pi 180.0))) @@ -4446,7 +4446,7 @@ (setq rad-s (* (float s-winkel) (/ pi 180.0))) (setq tan-s (/ (sin rad-s) (cos rad-s))) (setq acc-gfbogen-save *vfl-acc-gfbogen* acc-sep-save *vfl-acc-separator*) - (setq probe-checkpoint (vf-lastent-ohne-attribute)) + (setq probe-checkpoint (ssg-lastent-ohne-attribute)) (setq probe-frame-a (car (vfl-gf-bogen-uebergang frame (- (fix *vfk-gefaelle-winkel*))))) (setq probe-frame-a (vfl-gf-bogen-erweitern probe-frame-a "auf" (- (fix *vfk-gefaelle-winkel*)) extra-grad)) (setq probe-frame-a (vfl-gf-bogen-erweitern probe-frame-a "ab" (- s-winkel) extra-grad)) @@ -6495,7 +6495,7 @@ ;; dynamic scoping, gilt fuer die gesamte Laufzeit dieses Aufrufs, auch ;; tief verschachtelt z.B. in vfl-vf-einheit). (setq vfl-nummer (vf-next-number)) - (setq lastEnt (vf-lastent-ohne-attribute)) + (setq lastEnt (ssg-lastent-ohne-attribute)) (setq anzahl-gf 0 anzahl-vf 0 frame nil) (setq old-error *error*) ;; Scharfen Abbruch-Wickel-Handler installieren (gemeinsam fuer alle drei @@ -6581,7 +6581,7 @@ ;; (vfl-segment-xdata-sichern, siehe Ende der cond unten) - dieselbe ;; Hilfsfunktion wie beim Ketten-lastEnt (oben), damit ATTRIB/SEQEND- ;; Ketten eines vorherigen INSERTs konsistent uebersprungen werden. - (setq seg-lastEnt (vf-lastent-ohne-attribute)) + (setq seg-lastEnt (ssg-lastent-ohne-attribute)) (vfl-journal-mark "?") ;; Erzwungener QC-Modus (Linienzug-Modus 4/5 im Typ-Dispatcher ;; c:VarioFoerderer, *vfl-forciere-qc-modus* = "4"/"5"): das Menue @@ -9066,7 +9066,7 @@ (setq ent-fp (* (+ *vfl-gf-min-laenge* *vfk-separator-laenge* *vfk-stations-laenge*) (cos rad3))) (setq run-typ nil) (setq vfl-nummer (vf-next-number)) - (setq lastEnt (vf-lastent-ohne-attribute)) + (setq lastEnt (ssg-lastent-ohne-attribute)) (vfl-acc-reset) (setq anzahl-gf 0 anzahl-vf 0 frame nil) ;; --- Abbruch-Sicherung ab hier scharf (analog Modus 1/2) --- @@ -9856,7 +9856,7 @@ (setq aus (if as-vorhanden (if aus-dx aus-dx *vfk-as-es-fallback-dx*) 0.0) ein (if es-vorhanden (if ein-dx ein-dx *vfk-as-es-fallback-dx*) 0.0)) (setq vfl-nummer (vf-next-number)) - (setq lastEnt (vf-lastent-ohne-attribute)) + (setq lastEnt (ssg-lastent-ohne-attribute)) (vfl-acc-reset) ;; *vfl-journal*-Reset steht jetzt GANZ AM ANFANG der Funktion (vor der ;; Pfadauswahl/Praeambel) - siehe Kommentar dort. Hier NICHT mehr noetig diff --git a/Lisp/vf_standard.lsp b/Lisp/vf_standard.lsp index 96825ab..99e8daf 100644 --- a/Lisp/vf_standard.lsp +++ b/Lisp/vf_standard.lsp @@ -1178,7 +1178,7 @@ (setq *ssg-ils-dim* ziel-dim) (setq *vf-motorseite* motorseite) (entdel ent) - (setq lastEnt (vf-lastent-ohne-attribute)) + (setq lastEnt (ssg-lastent-ohne-attribute)) (apply einfuege-fn (list deltaL deltaH richtung best-winkel L_GF1 L_GF2 L_VF startpunkt seite hz)) (setq vf-nummer (vf-next-number)) diff --git a/cfg/export.cfg b/cfg/export.cfg index a631996..897ebb4 100644 --- a/cfg/export.cfg +++ b/cfg/export.cfg @@ -108,7 +108,6 @@ [blockpattern] pattern_kreisel= KR_*, KREISEL_*, ECKRAD_* pattern_eckrad= ECKRAD_* -pattern_gerade= AP110*, AP_110* pattern_strecke= Vario*, Staustrecke*, AUS_Element*, EIN_Element*, VF_*, GF_* pattern_variofoerderer= VF_* pattern_gefaellestrecke= GF_* @@ -121,13 +120,16 @@ pattern_btmt_beladung= BTMT-Beladung* pattern_btmt_entladung= SC_Entladung* pattern_eingang= Eingang* pattern_ausgang= Ausgang* -pattern_geruest= GR_* pattern_nested_bogen= Gefaellebogen_*, Vario_Bogen_*, Vario_Kurve_* pattern_nested_streckenelement= Staustrecke_SP_1000_mm* pattern_nested_umlenkstation= Vario_Umlenkstation_* pattern_nested_motorstation= Vario_Motorstation_* pattern_unit_marker= ZZ_UNIT_MARKER* pattern_ks_subblocks= KS_EIN, KS_AUS, K1, K2, K3, K4 +# Omniflo +pattern_gerade= AP110*, AP_110* +# Gerüst +pattern_geruest= GR_* [python] # Interpreter fuer die Export-Skripte (lib/export_csv.py, lib/export_sivas.py). @@ -315,3 +317,9 @@ senstol_mm=0 # ausgegeben. Wert in mm. strittig_diff_mm=500 +[Sivas] +# Sivas-Merkmalnummer je Block-Attribut fuer die details-Spalte von +# lib/export_sivas.py (Bezeichnung je Nummer: cfg/Merkmalsstamm_in_Sivas.xlsx). +# TEILEFARBE der Geruest-Baugruppen (GR_*): kommagetrennte Liste parallel zu +# ARTINR, je Artikelnummer eine Farbe (leer = Teil ohne Farbe). +merkmal_teilefarbe=108 diff --git a/cfg/sivas_merkmal_zuordnung.md b/cfg/sivas_merkmal_zuordnung.md index 1ecd8e1..700403a 100644 --- a/cfg/sivas_merkmal_zuordnung.md +++ b/cfg/sivas_merkmal_zuordnung.md @@ -139,7 +139,16 @@ Eckrad/Variofoerderer/Gefaellestrecke/BTMT) vorhanden ist. fuer Einzelmodul"`) - war nicht Teil der angefragten 5 Teilearten. - **Geruest-Baugruppen** (`build_geruest_details`, `GR_*`-Bloecke): eigenes Format ueber `ARTINR`/`BEZEICHNUNG`/`TEILEART`/`LAENGE` in den festen - CSV-Spalten, nur `FARBE` bleibt als details-Key - unveraendert. + CSV-Spalten (je Artikelnummer eine Zeile). Siehe eigener Abschnitt unten. + +## Geruest-Baugruppe (GR_*, je Artikelnummer eine Zeile, Dispogruppe 20) + +| Merkmalnr | Bezeichnung (Merkmalstamm) | Block-Attribut | Berechnung | +|---|---|---|---| +| 108 | Farbe | `TEILEFARBE` | kommagetrennte Liste parallel zu `ARTINR`; je Zeile der Eintrag an der Position der Artikelnummer. Leerer Eintrag (Teil ohne `"farbig": true` in `geruest.json`) -> Merkmal fehlt. Laenge passt nicht zu `ARTINR` (Altbestand) -> Warnung, ohne Farbe. Nummer aus `cfg/export.cfg` `[Sivas] merkmal_teilefarbe` | + +Gleiche Artikelnummer mit gleicher Farbe innerhalb eines Blocks -> eine Zeile +mit Anzahl > 1. - **Omniflo Bogen/Weiche/Gerade**: `details` bleibt leer (`{}`), keine Merkmalnummern-Zuordnung noetig. diff --git a/data/json/geruest.json b/data/json/geruest.json index 85d6b42..0868ae2 100644 --- a/data/json/geruest.json +++ b/data/json/geruest.json @@ -14,8 +14,8 @@ "Teilefarbe": { "typ": "auswahl", "optionen": [ - "RAL 7035 Lichtgrau", - "RAL 7030 Steingrau" + "RAL7035", + "RAL7030" ], "frei_erlaubt": true, "frei_option": "Individuell" @@ -28,11 +28,13 @@ { "artikel": "ROHR R 1\" 33,7 x 2,6", "sivas_id": 821006026, + "farbig": true, "menge": 1 }, { "artikel": "CAD - ROHRABH. 1\" NICHT GEQUETSCHT - MONTAGEELEMENTE KPL.", "sivas_id": 821004202, + "farbig": false, "menge": 1 } ] @@ -43,11 +45,13 @@ { "artikel": "ROHR R 1\" 33,7 x 2,6 einseitig gequetscht", "sivas_id": 821006034, + "farbig": true, "menge": 1 }, { "artikel": "CAD - ROHRABHÄNGER 1\" EINSEITIG GEQUETSCHT - MONTAGEELEMENTE KPL.", "sivas_id": 821004203, + "farbig": false, "menge": 1 } ] @@ -58,11 +62,13 @@ { "artikel": "ROHR R 1\" 33,7 x 2,6 beidseitig gequetscht", "sivas_id": 821006035, + "farbig": true, "menge": 1 }, { "artikel": "CAD - ROHRABHÄNGER 1\" BEIDSEITIG GEQUETSCHT - MONTAGEELEMENTE KPL.", "sivas_id": 821004204, + "farbig": false, "menge": 1 } ] @@ -72,11 +78,13 @@ { "artikel": "SPANNPRATZE ST - KH 8-11 KPL.SELBSTSICHERND", "sivas_id": 821004120, + "farbig": false, "menge": 1 }, { "artikel": "SPANNPRATZE SELBSTSICHERND KPL.", "sivas_id": 821004058, + "farbig": false, "menge": 1 }, { @@ -85,16 +93,19 @@ { "artikel": "Scheibe DIN 125 - A 10,5 - 140 HV - St", "sivas_id": 913011010, + "farbig": false, "menge": 1 }, { "artikel": "Sechskantmutter DIN 934 - M10 - 8", "sivas_id": 912011010, + "farbig": false, "menge": 2 }, { "artikel": "Sechskantschraube DIN 933 - M10 x 30 - 8.8", "sivas_id": 911011008, + "farbig": false, "menge": 1 } ] @@ -102,36 +113,43 @@ { "artikel": "U-BÜGEL M7 41X49 FÜR PROFILGERÜST - BG", "sivas_id": 825004049, + "farbig": false, "menge": 1 }, { "artikel": "ROHRKLAMMER 1\" KPL. VERTIKAL", "sivas_id": 825004040, + "farbig": false, "menge": 2 }, { "artikel": "WINKEL 60X60X6X300", "sivas_id": 821006043, + "farbig": false, "menge": 1 }, { "artikel": "WINKEL 60X60X6X60", "sivas_id": 821006042, + "farbig": false, "menge": 1 }, { "artikel": "ROHRKLAMMER 1\" T-VERBINDUNG KPL.", "sivas_id": 825004030, + "farbig": false, "menge": 1 }, { "artikel": "ROHRKLAMMER 1\" FLACH UND LANG, KPL.", "sivas_id": 825002021, + "farbig": false, "menge": 1 }, { "artikel": "DURCHSTECKANKER HST M12X115X20", "sivas_id": 922021003, + "farbig": false, "menge": 1 } ], @@ -140,25 +158,40 @@ "name": "Abhaengung Spannpratze / Rohrklammer", "variante": "ROHR R 1\" 33,7 x 2,6", "laenge": 2000, - "teilefarbe": "RAL 7035 Lichtgrau", + "teilefarbe": "RAL7035", "oben": [ - { "artikel": "SPANNPRATZE SELBSTSICHERND KPL.", "menge": 1 }, - { "artikel": "Schraubenset", "menge": 1 } + { + "artikel": "SPANNPRATZE SELBSTSICHERND KPL.", + "menge": 1 + }, + { + "artikel": "Schraubenset", + "menge": 1 + } ], "unten": [ - { "artikel": "ROHRKLAMMER 1\" KPL. VERTIKAL", "menge": 2 } + { + "artikel": "ROHRKLAMMER 1\" KPL. VERTIKAL", + "menge": 2 + } ] }, { "name": "Abhaengung Duebel / T-Verbindung", "variante": "ROHR R 1\" 33,7 x 2,6 einseitig gequetscht", "laenge": 1500, - "teilefarbe": "RAL 7035 Lichtgrau", + "teilefarbe": "RAL7035", "oben": [ - { "artikel": "DURCHSTECKANKER HST M12X115X20", "menge": 2 } + { + "artikel": "DURCHSTECKANKER HST M12X115X20", + "menge": 2 + } ], "unten": [ - { "artikel": "ROHRKLAMMER 1\" T-VERBINDUNG KPL.", "menge": 1 } + { + "artikel": "ROHRKLAMMER 1\" T-VERBINDUNG KPL.", + "menge": 1 + } ] } ] @@ -178,8 +211,8 @@ "Teilefarbe": { "typ": "auswahl", "optionen": [ - "RAL 7035 Lichtgrau", - "RAL 7030 Steingrau" + "RAL7035", + "RAL7030" ], "frei_erlaubt": true, "frei_option": "Individuell" @@ -198,6 +231,24 @@ ] }, "geometrie_varianten": [ + { + "name": "R 2\"", + "teileart": "Geruest Saeule 2 Zoll", + "teile": [ + { + "artikel": "BODENSÄULE R 2\" 60,3 MIT FUSSPLATTE", + "sivas_id": 821006051, + "farbig": true, + "menge": 1 + }, + { + "artikel": "CAD - BODENSÄULE R 2\" - DURCHSTECKANKER KPL.", + "sivas_id": 821004201, + "farbig": false, + "menge": 1 + } + ] + }, { "name": "R 1\"", "teileart": "Geruest Saeule 1 Zoll", @@ -205,111 +256,13 @@ { "artikel": "ROHR R 1\" 33,7 x 2,6", "sivas_id": 821006026, + "farbig": true, "menge": 1 }, { "artikel": "CAD - BODENSÄULE R 1\" - BODENPLATTE KPL.", "sivas_id": 821004200, - "menge": 1 - } - ] - }, - { - "name": "R 2\"", - "teileart": "Geruest Saeule 2 Zoll", - "teile": [ - { - "artikel": "BODENSÄULE R 2\" 60,3 MIT FUSSPLATTE", - "sivas_id": 821006051, - "menge": 1 - }, - { - "artikel": "CAD - BODENSÄULE R 2\" - DURCHSTECKANKER KPL.", - "sivas_id": 821004201, - "menge": 1 - } - ] - }, - { - "name": "R 2\" Haltearm 1-ARMIG", - "teileart": "Geruest Saeule 2 Zoll", - "teile": [ - { - "artikel": "BODENSÄULE R 2\" 60,3 MIT FUSSPLATTE", - "sivas_id": 821006051, - "menge": 1 - }, - { - "artikel": "CAD - BODENSÄULE R 2\" - DURCHSTECKANKER KPL.", - "sivas_id": 821004201, - "menge": 1 - }, - { - "artikel": "HALTEARM FÜR BODENSÄULE R 2\" 1-ARMIG KPL.", - "sivas_id": 821004051, - "menge": 1 - } - ] - }, - { - "name": "R 2\" Haltearm 2-ARMIG 90 Grad", - "teileart": "Geruest Saeule 2 Zoll", - "teile": [ - { - "artikel": "BODENSÄULE R 2\" 60,3 MIT FUSSPLATTE", - "sivas_id": 821006051, - "menge": 1 - }, - { - "artikel": "CAD - BODENSÄULE R 2\" - DURCHSTECKANKER KPL.", - "sivas_id": 821004201, - "menge": 1 - }, - { - "artikel": "HALTEARM FÜR BODENSÄULE R 2\" 2-ARMIG 90 Grad KPL.", - "sivas_id": 821004054, - "menge": 1 - } - ] - }, - { - "name": "R 2\" Haltearm 2-ARMIG 180 Grad", - "teileart": "Geruest Saeule 2 Zoll", - "teile": [ - { - "artikel": "BODENSÄULE R 2\" 60,3 MIT FUSSPLATTE", - "sivas_id": 821006051, - "menge": 1 - }, - { - "artikel": "CAD - BODENSÄULE R 2\" - DURCHSTECKANKER KPL.", - "sivas_id": 821004201, - "menge": 1 - }, - { - "artikel": "HALTEARM FÜR BODENSÄULE R 2\" 2-ARMIG 180 Grad KPL.", - "sivas_id": 821004052, - "menge": 1 - } - ] - }, - { - "name": "R 2\" Haltearm 3-ARMIG", - "teileart": "Geruest Saeule 2 Zoll", - "teile": [ - { - "artikel": "BODENSÄULE R 2\" 60,3 MIT FUSSPLATTE", - "sivas_id": 821006051, - "menge": 1 - }, - { - "artikel": "CAD - BODENSÄULE R 2\" - DURCHSTECKANKER KPL.", - "sivas_id": 821004201, - "menge": 1 - }, - { - "artikel": "HALTEARM FÜR BODENSÄULE R 2\" 3-ARMIG KPL.", - "sivas_id": 821004053, + "farbig": false, "menge": 1 } ] @@ -319,37 +272,68 @@ { "artikel": "KLEMMRING MIT MUFFE EINFACH KPL.", "sivas_id": 825002019, + "farbig": false, "menge": 2 }, { "artikel": "KLEMMRING MIT MUFFE DOPPELT 90 Grad, KPL.", "sivas_id": 825002009, + "farbig": false, "menge": 2 }, { "artikel": "KLEMMRING MIT MUFFE DOPPELT 180 Grad, KPL.", "sivas_id": 825002008, + "farbig": false, "menge": 2 }, { "artikel": "KLEMMRING M. MUFFE DREIFACH 90 Grad/180 Grad KPL.", "sivas_id": 825002007, + "farbig": false, "menge": 2 }, { "artikel": "KLEMMRING MIT LASCHE KPL. ZUSAMMENBAUZEICHNUNG", "sivas_id": 825002020, + "farbig": false, "menge": 2 }, { "artikel": "QUERSCHELLE F. 1\" UND 2\" ROHR GESCHW./VZ. M. 4X M10X30 KPL.", "sivas_id": 825002022, + "farbig": false, "menge": 2 }, { "artikel": "KREUZSCHELLE F. 2\" UND 1\" ROHR SCHWENKBAR 360 Grad", "sivas_id": 922083009, + "farbig": false, "menge": 2 + }, + { + "artikel": "HALTEARM FÜR BODENSÄULE R 2\" 1-ARMIG KPL.", + "sivas_id": 821004051, + "farbig": true, + "menge": 1 + }, + { + "artikel": "HALTEARM FÜR BODENSÄULE R 2\" 2-ARMIG 90 Grad KPL.", + "sivas_id": 821004054, + "farbig": true, + "menge": 1 + }, + { + "artikel": "HALTEARM FÜR BODENSÄULE R 2\" 2-ARMIG 180 Grad KPL.", + "sivas_id": 821004052, + "farbig": true, + "menge": 1 + }, + { + "artikel": "HALTEARM FÜR BODENSÄULE R 2\" 3-ARMIG KPL.", + "sivas_id": 821004053, + "farbig": true, + "menge": 1 } ], "konfigurationen": [ @@ -357,7 +341,7 @@ "name": "Bodensaeule 1 Zoll, Standardhoehe", "variante": "R 1\"", "laenge": 1000, - "teilefarbe": "RAL 7035 Lichtgrau", + "teilefarbe": "RAL7035", "oben": [], "unten": [] }, @@ -365,9 +349,12 @@ "name": "Bodensaeule 2 Zoll, Haltearm 1-armig", "variante": "R 2\" Haltearm 1-ARMIG", "laenge": 1200, - "teilefarbe": "RAL 7035 Lichtgrau", + "teilefarbe": "RAL7035", "oben": [ - { "artikel": "KLEMMRING MIT MUFFE EINFACH KPL.", "menge": 2 } + { + "artikel": "KLEMMRING MIT MUFFE EINFACH KPL.", + "menge": 2 + } ], "unten": [] }, @@ -375,12 +362,18 @@ "name": "Bodensaeule 2 Zoll, Haltearm 2-armig 90 Grad", "variante": "R 2\" Haltearm 2-ARMIG 90 Grad", "laenge": 1200, - "teilefarbe": "RAL 7035 Lichtgrau", + "teilefarbe": "RAL7035", "oben": [ - { "artikel": "KLEMMRING MIT MUFFE DOPPELT 90 Grad, KPL.", "menge": 2 } + { + "artikel": "KLEMMRING MIT MUFFE DOPPELT 90 Grad, KPL.", + "menge": 2 + } ], "unten": [ - { "artikel": "QUERSCHELLE F. 1\" UND 2\" ROHR GESCHW./VZ. M. 4X M10X30 KPL.", "menge": 2 } + { + "artikel": "QUERSCHELLE F. 1\" UND 2\" ROHR GESCHW./VZ. M. 4X M10X30 KPL.", + "menge": 2 + } ] } ] @@ -397,6 +390,7 @@ { "artikel": "WANDFLANSCH EINZELTEIL", "sivas_id": 821006031, + "farbig": false, "menge": 1 } ] @@ -407,6 +401,7 @@ { "artikel": "WINKEL 60X60X6X60", "sivas_id": 821006042, + "farbig": false, "menge": 1 } ] @@ -417,6 +412,7 @@ { "artikel": "WINKEL 60X60X6X300", "sivas_id": 821006043, + "farbig": false, "menge": 1 } ] @@ -427,6 +423,7 @@ { "artikel": "ROHRSCHELLE 1\" OBERTEIL", "sivas_id": 825006009, + "farbig": false, "menge": 1 } ] @@ -439,11 +436,13 @@ { "artikel": "HOLZSCHRAUB,10X70, 6KT DIN 571 VZ", "sivas_id": 911271027, + "farbig": false, "menge": 2 }, { "artikel": "NYLON - DUEBEL 12X60 (TYP S)", "sivas_id": 922013003, + "farbig": false, "menge": 2 } ] @@ -454,6 +453,7 @@ { "artikel": "DURCHSTECKANKER HST M12X115X20 WANDABH.", "sivas_id": 922021003, + "farbig": false, "menge": 2 } ] @@ -464,7 +464,10 @@ "name": "Wandflansch mit Duebeln", "variante": "WANDFLANSCH EINZELTEIL", "oben": [ - { "artikel": "Nylondübel 12x60 inkl. Holzschrauben", "menge": 1 } + { + "artikel": "Nylondübel 12x60 inkl. Holzschrauben", + "menge": 1 + } ], "unten": [] }, @@ -472,7 +475,10 @@ "name": "Winkel 300 mit Schwerlastanker", "variante": "WINKEL 60X60X6X300", "oben": [ - { "artikel": "HST M12X115X20", "menge": 1 } + { + "artikel": "HST M12X115X20", + "menge": 1 + } ], "unten": [] } diff --git a/lib/export_sivas.py b/lib/export_sivas.py index 7b42551..df1120b 100644 --- a/lib/export_sivas.py +++ b/lib/export_sivas.py @@ -54,12 +54,18 @@ import json import sys import os -from export_blockpatterns import load_patterns, matches_any, csv_quote, safe_float, safe_int +from export_blockpatterns import (load_patterns, load_export_cfg, cfg_path_from_env, + matches_any, csv_quote, safe_float, safe_int) from merkmalstamm import lade_merkmalstamm, bezeichnung_fuer import sivas_mapping BLOCKPATTERNS = load_patterns() +# Merkmalnummer fuer die Teilefarbe der Geruest-Baugruppen ([Sivas] in +# cfg/export.cfg; 108 = "Farbe" im Merkmalstamm). +MERKMAL_TEILEFARBE = load_export_cfg(cfg_path_from_env()).get( + "Sivas", "merkmal_teilefarbe", fallback="108").strip() + def load_json(path): """Laedt JSON, tolerant gegenueber BricsCAD-Ausgaben. @@ -310,17 +316,51 @@ def build_eckrad_details(block): return sivas_mapping.anwenden(SIVAS_MAPPING_ECKRAD, attribs, TRANSFORMS) -def build_geruest_details(block): - """Merkmale-Dict fuer eine GR_-Geruest-Baugruppe (siehe pattern_geruest in - cfg/export.cfg, GeruestInsert.lsp *geruest-attrib-defs*). ARTINR/ - BEZEICHNUNG/TEILEART/LAENGE wandern in feste Sivas-Spalten (sivasnr/ - bezeichnung/teileart/laenge_mm), FARBE bleibt als Rest-Attribut hier - (cfg/sivas.cfg [geruest]). LAYER ist reine BricsCAD-Zeichnungsinformation - ohne Sivas-Bedeutung und wird bewusst NICHT mit exportiert (anders als im - CSV-Export export_csv.py, wo sie fuer die Zuordnung in der Zeichnung - nuetzlich bleibt).""" - attribs = block.get("attribs", {}) - return sivas_mapping.anwenden(SIVAS_MAPPING_GERUEST, attribs, TRANSFORMS) +# def build_geruest_details(block): + #"""Merkmale-Dict fuer eine GR_-Geruest-Baugruppe (siehe pattern_geruest in + #cfg/export.cfg, GeruestInsert.lsp *geruest-attrib-defs*). ARTINR/ + #BEZEICHNUNG/TEILEART/LAENGE wandern in feste Sivas-Spalten (sivasnr/ + #bezeichnung/teileart/laenge_mm), FARBE bleibt als Rest-Attribut hier + #(cfg/sivas.cfg [geruest]). LAYER ist reine BricsCAD-Zeichnungsinformation + #ohne Sivas-Bedeutung und wird bewusst NICHT mit exportiert (anders als im + #CSV-Export export_csv.py, wo sie fuer die Zuordnung in der Zeichnung + #nuetzlich bleibt).""" + #attribs = block.get("attribs", {}) + #return sivas_mapping.anwenden(SIVAS_MAPPING_GERUEST, attribs, TRANSFORMS) + +def build_geruest_details(farbe): + """Merkmale-Dict fuer EINE Artikelnummer einer GR_-Geruest-Baugruppe + (siehe pattern_geruest in cfg/export.cfg, GeruestInsert.lsp + *geruest-attrib-defs*). ARTINR/BEZEICHNUNG/TEILEART/LAENGE wandern in + feste Sivas-Spalten (sivasnr/bezeichnung/teileart/laenge_mm); hier bleibt + nur die Teilefarbe dieser Artikelnummer als Merkmal MERKMAL_TEILEFARBE - + ohne Farbe (Teil darf keine tragen) ein leeres Dict. LAYER ist reine + BricsCAD-Zeichnungsinformation ohne Sivas-Bedeutung und wird bewusst + NICHT mit exportiert (anders als im CSV-Export export_csv.py, wo sie fuer + die Zuordnung in der Zeichnung nuetzlich bleibt).""" + return {MERKMAL_TEILEFARBE: farbe} if farbe else {} + + +def geruest_artinr_farben(attribs): + """(artinr, farbe)-Paare eines GR_-Blocks. TEILEFARBE ist eine + kommagetrennte Liste parallel zu ARTINR (GeruestInsert.lsp, + geruest-farbliste): je Artikelnummer die Baugruppenfarbe oder "". + Passt die Laenge nicht (Altbestand mit einem Einzelwert oder von Hand + geaendertes Attribut), wird gewarnt und ohne Farbe exportiert - eine + geratene Zuordnung waere schlimmer als keine. Leere Artikelnummern + werden verworfen.""" + artinr_roh = attribs.get("ARTINR", "").split(",") + farben_roh = attribs.get("TEILEFARBE", "") + farben = [f.strip() for f in farben_roh.split(",")] + if farben_roh.strip() == "": + farben = [""] * len(artinr_roh) + elif len(farben) != len(artinr_roh): + print(f"WARNUNG: Geruest-Block ID {attribs.get('ID', '?')}: TEILEFARBE " + f"({len(farben)} Eintraege) passt nicht zu ARTINR " + f"({len(artinr_roh)} Eintraege) - ohne Farbe exportiert.", + file=sys.stderr) + farben = [""] * len(artinr_roh) + return [(a.strip(), f) for a, f in zip(artinr_roh, farben) if a.strip()] # --- Bekannte Bloecke ignorieren --- @@ -706,14 +746,15 @@ def process_blocks(blocks): # zusammengefasst (wie omniflo_groups oben). Die volle # LAENGE der Baugruppe steht auf JEDER so entstandenen Zeile - Sivas hat # kein Konzept einer "gemeinsamen" Laenge ueber mehrere Zeilen hinweg. + # Die Teilefarbe steht je Artikelnummer in TEILEFARBE (parallele Liste), + # gruppiert wird darum ueber (Artikelnummer, Farbe). for block in geruest_list: attribs = block.get("attribs", {}) - artinr_list = [a.strip() for a in attribs.get("ARTINR", "").split(",") if a.strip()] artinr_groups = {} - for artinr in artinr_list: - artinr_groups.setdefault(artinr, 0) - artinr_groups[artinr] += 1 - for artinr, anzahl in artinr_groups.items(): + for paar in geruest_artinr_farben(attribs): + artinr_groups.setdefault(paar, 0) + artinr_groups[paar] += 1 + for (artinr, farbe), anzahl in artinr_groups.items(): items.append({ "nr": nr, "teileart": attribs.get("TEILEART", "Geruest"), @@ -724,7 +765,7 @@ def process_blocks(blocks): "anzahl": anzahl, "laenge_mm": attribs.get("LAENGE", ""), "ids": [get_id(block)], - "details": build_geruest_details(block), + "details": build_geruest_details(farbe), }) nr += 1 @@ -861,10 +902,9 @@ def format_csv_line(item, details=None): def details_mit_bezeichnung(details, merkmalstamm): """Kopie von details, bei der jeder Merkmalnummer-Key durch seine Klartext-Bezeichnung aus dem Merkmalstamm ersetzt wird (Wert bleibt - unveraendert). Keys, die keine reine Zahl sind (aktuell nur bei - Eckrad/Geruest, siehe build_eckrad_details/build_geruest_details - dort - noch beschreibende Klartext-Keys statt Merkmalnummern), bleiben - unveraendert.""" + unveraendert). Keys, die keine reine Zahl sind (aktuell nur beim + Eckrad, siehe build_eckrad_details - dort noch beschreibende + Klartext-Keys statt Merkmalnummern), bleiben unveraendert.""" neu = {} for key, value in details.items(): if key.isdigit(): diff --git a/menu/SSG_LIB.cui b/menu/SSG_LIB.cui index 03285bb..8299faa 100644 --- a/menu/SSG_LIB.cui +++ b/menu/SSG_LIB.cui @@ -536,217 +536,235 @@ ^C^C(ssg-ensure "OmniModulInsert") OMNI_EDIT - + - Geruest... + Rohr-Geruest-Traeger ^C^C(ssg-ensure "GeruestInsert") GERUEST + + + Saeulen + ^C^C(ssg-ensure "GeruestInsert") GERUEST_SAEULEN + + + + Rohrabhaenger + ^C^C(ssg-ensure "GeruestInsert") GERUEST_ROHRABHAENGER + + + + + Wandbefestigung + ^C^C(ssg-ensure "GeruestInsert") GERUEST_WANDBEFESTIGUNG + + + 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 - + 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) - + 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 @@ -763,16 +781,11 @@ SSG_LIB - - Geruest... - - - - - - - - + + + + + ILS @@ -1371,245 +1384,278 @@ - - SPS - - + + Geruest - Eingang + Rohr-Geruest-Traeger - + - Ausgang + Saeulen - + - SPS Schliessen - - - - - - - TRO - - Marker einfuegen + Rohrabhaenger - Marker bearbeiten + Wandbefestigung - Bearbeiten (Auto) + Gattertraeger - + - Connections + SPS + + - Verbindung einfuegen + Eingang - + - Verbindung bearbeiten + Ausgang + + + + + + SPS Schliessen + + + + + + + TRO + + Marker einfuegen + + Marker bearbeiten + + + + Bearbeiten (Auto) - + - + + Connections + + Verbindung einfuegen + + + + + + Verbindung bearbeiten + + + + + + Bearbeiten (Auto) + + + + + + Export Export Sivas - - - - - - Export CSV - - - - - - - Konfiguration - - Umschalten 2D und 3D - - - - - - Alle Bloecke auf 2D - - - - - - Alle Bloecke auf 3D - Sprache + Export CSV + + + Konfiguration - Planquadrate an/aus - - - - - - CSV-Export + Umschalten 2D und 3D - - - Tests - alle Tests ausfuehren und exportieren + Alle Bloecke auf 2D + + + + + + Alle Bloecke auf 3D - Tests ausfuehren und stehen lassen + Sprache - Export CSV/Sivas ALL + Planquadrate an/aus + + CSV-Export + + + + + + + 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 - + 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 cd6e675..ac9369e 100644 --- a/menu/SSG_LIB.mnu +++ b/menu/SSG_LIB.mnu @@ -111,7 +111,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 +[->Geruest]^C^C(ssg-ensure "GeruestInsert") GERUEST +[Rohr-Geruest-Traeger]^C^C(ssg-ensure "GeruestInsert") GERUEST +[Saeulen]^C^C(ssg-ensure "GeruestInsert") GERUEST_SAEULEN +[Rohrabhaenger]^C^C(ssg-ensure "GeruestInsert") GERUEST_ROHRABHAENGER +[Wandbefestigung]^C^C(ssg-ensure "GeruestInsert") GERUEST_WANDBEFESTIGUNG +[<-Gattertraeger]^C^C(ssg-ensure "GeruestInsert") GERUEST [->SPS] [->TRO] [Marker einfuegen]^C^C(ssg-ensure "Tro_Edit") TRO_INSERT diff --git a/tests/alltests.json b/tests/alltests.json index 2ff6624..dc98cb9 100644 --- a/tests/alltests.json +++ b/tests/alltests.json @@ -4,6 +4,7 @@ { "name": "linienzug", "save": "dwg", "module": "VarioFoerderer" }, { "name": "vfl_schema", "module": "VarioFoerderer" }, { "name": "vf_spec", "module": "VarioFoerderer" }, + { "name": "lastent", "module": "GeruestInsert" }, { "name": "omniflo", "save": "dxf", "module": "OmniModulInsert" }, { "name": "omniflo_strecke", "save": "dxf", "module": "OmniModulInsert" }, { "name": "gefaellestrecke", "save": "dwg", "module": "Gefaellestrecke" }, diff --git a/tests/test_export_sivas_omniflo.py b/tests/test_export_sivas_omniflo.py index 3c545ff..c087ee4 100644 --- a/tests/test_export_sivas_omniflo.py +++ b/tests/test_export_sivas_omniflo.py @@ -101,3 +101,29 @@ def test_geruest_unveraendert(): assert zeilen["825002022"]["teileart"] == "Geruest Saeule 2 Zoll" assert zeilen["825002022"]["ids"] == ["0060"] assert zeilen["825002022"]["dispgruppe"] == 20 + # Ohne TEILEFARBE kein Farb-Merkmal + assert zeilen["825002022"]["details"] == {} + + +def test_geruest_teilefarbe_je_artikelnummer(): + zeilen = _zeilen([ + _block("GR_Saeulen_20260929100000", "0061", "Geruest Saeule 2 Zoll", + "821006051,821004201,825002022,825002022", + TEILEFARBE=",RAL7030,RAL7030,RAL7030"), + ]) + merkmal = export_sivas.MERKMAL_TEILEFARBE + assert merkmal == "108" + assert zeilen["821006051"]["details"] == {} + assert zeilen["821004201"]["details"] == {merkmal: "RAL7030"} + assert zeilen["825002022"]["details"] == {merkmal: "RAL7030"} + assert zeilen["825002022"]["anzahl"] == 2 + + +def test_geruest_teilefarbe_laenge_passt_nicht(capsys): + zeilen = _zeilen([ + _block("GR_Saeulen_20260929100001", "0062", "Geruest Saeule 2 Zoll", + "821006051,821004201", TEILEFARBE="RAL7030"), + ]) + assert zeilen["821006051"]["details"] == {} + assert zeilen["821004201"]["details"] == {} + assert "TEILEFARBE" in capsys.readouterr().err diff --git a/tests/test_foerderer.lsp b/tests/test_foerderer.lsp index 298493b..45628b7 100644 --- a/tests/test_foerderer.lsp +++ b/tests/test_foerderer.lsp @@ -256,7 +256,7 @@ ;; Wie c:VarioFoerderer: Attribut-Entities/SEQEND des vorherigen ;; VF_N-Blocks ueberspringen, sonst rutschen sie in den naechsten ;; Block hinein (Blockerstellung faengt sonst am falschen Entity an). - (setq lastEnt (vf-lastent-ohne-attribute)) + (setq lastEnt (ssg-lastent-ohne-attribute)) (setq gf-split (foerderer:split-gf gf-verteilung L_GF)) (setq lastEnt (foerderer:baue-block startpunkt blk-nummer hoehe-von hoehe-bis @@ -300,7 +300,7 @@ (setq blk-nummer (1+ blk-nummer)) (setq hoehe-von 0) (setq hoehe-bis (- deltaH)) - (setq lastEnt (vf-lastent-ohne-attribute)) + (setq lastEnt (ssg-lastent-ohne-attribute)) ;; seite/gf-verteilung vom Elternfall erben (gleicher ;; Foerderer); winkel-soll ist hier nicht anwendbar - ;; berechne-horizontale-mitte hat keine Winkel-Kandidatenliste diff --git a/tests/test_gefaellestrecke.lsp b/tests/test_gefaellestrecke.lsp index 90b01fc..33eacae 100644 --- a/tests/test_gefaellestrecke.lsp +++ b/tests/test_gefaellestrecke.lsp @@ -193,7 +193,7 @@ ;; 7. GF-Nummer und Entity-Grenze vor erster Einfuegung (setq gf-nummer (gf-next-number)) - (setq last-ent (vf-lastent-ohne-attribute)) + (setq last-ent (ssg-lastent-ohne-attribute)) ;; 8. AUS-Element einfuegen ;; KS_EIN-Richtung so, dass KS_AUS in entry-hz zeigt: diff --git a/tests/test_mubea.lsp b/tests/test_mubea.lsp index 613336c..3d92a29 100644 --- a/tests/test_mubea.lsp +++ b/tests/test_mubea.lsp @@ -183,7 +183,7 @@ " L_GF2=" (rtos gf2 2 1))) (setq hoehe-bis (if (= richtung "Auf") deltaH (- deltaH))) - (setq lastEnt (vf-lastent-ohne-attribute)) + (setq lastEnt (ssg-lastent-ohne-attribute)) (if (= typ "etage") (etage-foerderanlage-einfuegen deltaL deltaH richtung best-winkel gf1 gf2 L_VF startpunkt seite hz) (variofoerderer-einfuegen deltaL deltaH richtung best-winkel gf1 gf2 L_VF startpunkt seite hz)) diff --git a/tests/test_unit.lsp b/tests/test_unit.lsp index d155da1..e8485db 100644 --- a/tests/test_unit.lsp +++ b/tests/test_unit.lsp @@ -823,6 +823,21 @@ (geruest-artikelnummern (ssg-json-parse "{\"artikel\": \"C\", \"sivas_id\": 333}"))) + ;; --- Teile-DWGs (visuelle Rueckmeldung im Block) --- + (tu-eq "geruest-eindeutig/dupl" '("1" "2" "3") + (geruest-eindeutig '("1" "2" "1" "3" "2"))) + (tu-eq "geruest-eindeutig/leer" nil (geruest-eindeutig nil)) + ;; Artikelnummer ohne DWG -> still uebergangen + (tu-eq "geruest-teile-dwgs/fehlt" nil + (geruest-teile-dwgs '("999999999"))) + ;; Vorhandene DWG (liegt im Repo) -> genau ein Pfad, auch bei Mehrfach- + ;; Stueckzahl und gemischt mit einer fehlenden Nummer + (setq _pfad (geruest-dummy-pfad "825002019.dwg")) + (if (and _pfad (findfile _pfad)) + (tu-eq "geruest-teile-dwgs/vorhanden" (list _pfad) + (geruest-teile-dwgs '("825002019" "999999999" "825002019"))) + ) + ;; --- Mengenfeld --- (tu-eq "geruest-zahl-p/ziffern" T (geruest-zahl-p "12")) (tu-eq "geruest-zahl-p/text" nil (geruest-zahl-p "1a")) @@ -841,6 +856,35 @@ (tu-eq "geruest-artnr-n/gruppe" '("111" "222" "222" "111" "222" "222") (geruest-artikelnummern-n _gruppe 2)) + ;; --- farbig-Flag / TEILEFARBE-Liste parallel zu ARTINR --- + ;; _eintrag hat kein "farbig" -> nicht farbig + (tu-eq "geruest-paare/ohne-flag" '(("825002019") ("825002019")) + (geruest-teile-paare _eintrag nil)) + (tu-eq "geruest-paare/farbig" '(("444" . T)) + (geruest-teile-paare + (ssg-json-parse "{\"artikel\": \"D\", \"sivas_id\": 444, \"farbig\": true}") + nil)) + (tu-eq "geruest-paare/false" '(("555")) + (geruest-teile-paare + (ssg-json-parse "{\"artikel\": \"E\", \"sivas_id\": 555, \"farbig\": false}") + nil)) + ;; Gruppe mit farbig vererbt an alle Teile, Mengen bleiben erhalten + (setq _teile (ssg-json-parse + (strcat "{\"name\": \"Set\", \"farbig\": true, \"teile\": [" + "{\"artikel\": \"A\", \"sivas_id\": 111}," + "{\"artikel\": \"B\", \"sivas_id\": 222, \"menge\": 2}]}"))) + (tu-eq "geruest-paare/gruppe-erbt" '(("111" . T) ("222" . T) ("222" . T)) + (geruest-teile-paare _teile nil)) + (tu-eq "geruest-paare-n/gruppe" 6 (length (geruest-teile-paare-n _teile 2))) + (tu-eq "geruest-paare-n/einzelteil-farbig" '(("444" . T) ("444" . T)) + (geruest-teile-paare-n + (ssg-json-parse "{\"artikel\": \"D\", \"sivas_id\": 444, \"farbig\": true}") + 2)) + (tu-eq "geruest-farbliste" '("" "RAL7030" "") + (geruest-farbliste '(("1") ("2" . T) ("3")) "RAL7030")) + (tu-eq "geruest-farbliste/join" ",RAL7030," + (ssg-join (geruest-farbliste '(("1") ("2" . T) ("3")) "RAL7030") ",")) + ;; --- DCL-Label: Anfuehrungszeichen wuerde die Datei zerstoeren --- (tu-eq "geruest-dcl-label/quote" "ROHRKLAMMER 1'' KPL. VERTIKAL" (geruest-dcl-label "ROHRKLAMMER 1\" KPL. VERTIKAL"))