diff --git a/CLAUDE.md b/CLAUDE.md index d2535cb..ba8f525 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -107,7 +107,7 @@ Detaillierte Dokumentation aller Funktionen und Befehle: siehe `Lisp/README.md`. | `OmniModulInsert.lsp` | OMNI_LOAD, OMNI_APB_*, OMNI_W*_*, OMNI_AP60/AP110, OMNI_TEF_*, OMNI_TV_*, OMNI_APBW_*, OMNI_EDIT | Omniflo-Komponenten: Boegen, Weichen, Verbinder, Transferwagen, Edit-Dialog | | `SSG_LIB_Commands.lsp` | ILS_BTMT_Beladung, ILS_BTMT_Entladung, ILS_SCANNER_INSERT, ILS_SEPARATOR_INSERT, ILS_EINGANG_INSERT, ILS_AUSGANG_INSERT, ILS_ETF_*, ILS_GK*_*, SSG_BLOCKEDIT, SSG_DIM_SWITCH, SSG_SPRACHE | BTMT Be-/Entladung (`ils-insert-station`: wiederholtes Einfuegen von `BTMT-Beladung` bzw. `SC_Entladung`, Drehung interaktiv, Layer aus `LAYER`-Attribut, Dimension via `ssg-ils-block-laden`) + Sensoren (`ils-insert-sensor`) + Eingang-/Ausgang-Symbol (frei platzierbar wie BTMT Be-/Entladung, ueber `ils-insert-station` mit den Rohnamen `Eingang`/`Ausgang`, Bloecke `Eingang_.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_ROHRABHAENGER, GERUEST_SAEULE_2ZOLL, GERUEST_SAEULE_1ZOLL, GERUEST_WANDBEFESTIGUNG | Geruest-Baugruppen aus `data/json/geruest.json` konfigurieren und einfuegen. Dialog (`dcl/geruest.dcl`): Basis-Variante aus `geometrie_varianten` (Dropdown), Anbauteile aus `anbaugruppen` (`list_box` mit `multiple_select` - im Projekt der erste), Laenge (gegen `attribute.Laenge` min/max geprueft, Retry-Schleife) und Farbe (`attribute.Farbe`, Freitext bei `frei_option`). Baugruppen ohne `attribute`-Block (Wandbefestigung) bekommen Laenge/Farbe gesperrt. Der Block wird - wie KREISEL_n/VF_n - SELBST zusammengebaut: Dummy-DWG aus `data/geruest` liefert nur Geometrie, das Attribut-Schema kommt aus `*geruest-attrib-defs*` (ARTINR, LAENGE, BEZEICHNUNG, TEILEART, FARBE, LAYER) und wird per `ssg-attrib-merge` mit den Dummy-Tags zusammengefuehrt - sonst verschluckt `ssg-attrib-set-on` stillschweigend jeden Tag, den die Dummy-DWG nicht als ATTDEF kennt. Blockname `GR__` (Kollisionszaehler wie in OmniModulInsert). **Das `GR_`-Praefix ist nicht kosmetisch**: `SSG_BLOCKEDIT` haelt JEDEN Block mit TEILEART-Attribut fuer ein Omniflo-Element, deshalb steht in `SSG_LIB_Commands.lsp` ein `GR_*`-Zweig VOR dem Omniflo-Zweig. ARTINR listet jede Sivas-ID so oft, wie `menge` es vorgibt (benannte Gruppen mit `teile` werden rekursiv aufgeloest); BEZEICHNUNG verkettet mit `" + "`, NICHT mit Komma - die Artikelbezeichnungen enthalten selbst Kommas ("ROHR R 1\" 33,7 x 2,6"). Zuordnung Menue -> JSON laeuft ueber das ASCII-Feld `id`, weil die aeusseren JSON-Schluessel Umlaute bzw. Anfuehrungszeichen tragen. Noch NICHT enthalten: Edit-Pfad (GERUEST_EDIT) und CSV-/Sivas-Export (`csv:collect-export-blocks` braucht dafuer ein `pattern_geruest = GR_*`) | +| `GeruestInsert.lsp` | GERUEST_ROHRABHAENGER, GERUEST_SAEULE_2ZOLL, GERUEST_SAEULE_1ZOLL, GERUEST_WANDBEFESTIGUNG | Geruest-Baugruppen aus `data/json/geruest.json` konfigurieren und einfuegen. Dialog (`dcl/geruest.dcl`): Basis-Variante aus `geometrie_varianten` (Dropdown), Anbauteile aus `anbaugruppen` (`list_box` mit `multiple_select` - im Projekt der erste), Laenge (gegen `attribute.Laenge` min/max geprueft, Retry-Schleife) und Farbe (`attribute.Farbe`, Freitext bei `frei_option`). Baugruppen ohne `attribute`-Block (Wandbefestigung) bekommen Laenge/Farbe gesperrt. Der Block wird - wie KREISEL_n/VF_n - SELBST zusammengebaut: Dummy-DWG aus `data/geruest` liefert nur Geometrie, das Attribut-Schema kommt aus `*geruest-attrib-defs*` (ARTINR, LAENGE, BEZEICHNUNG, TEILEART, FARBE, LAYER) und wird per `ssg-attrib-merge` mit den Dummy-Tags zusammengefuehrt - sonst verschluckt `ssg-attrib-set-on` stillschweigend jeden Tag, den die Dummy-DWG nicht als ATTDEF kennt. Blockname `GR__` (Kollisionszaehler wie in OmniModulInsert). **Das `GR_`-Praefix ist nicht kosmetisch**: `SSG_BLOCKEDIT` haelt JEDEN Block mit TEILEART-Attribut fuer ein Omniflo-Element, deshalb steht in `SSG_LIB_Commands.lsp` ein `GR_*`-Zweig VOR dem Omniflo-Zweig. ARTINR listet jede Sivas-ID so oft, wie `menge` es vorgibt (benannte Gruppen mit `teile` werden rekursiv aufgeloest); BEZEICHNUNG verkettet mit `" + "`, NICHT mit Komma - die Artikelbezeichnungen enthalten selbst Kommas ("ROHR R 1\" 33,7 x 2,6"). Zuordnung Menue -> JSON laeuft ueber das ASCII-Feld `id`, weil die aeusseren JSON-Schluessel Umlaute bzw. Anfuehrungszeichen tragen. CSV-/Sivas-Export: `pattern_geruest = GR_*` (cfg/export.cfg), `csv:collect-export-blocks`/`ssg-id-collect-blocks` sammeln GR_-Bloecke wie BTMT eigenstaendig; `*geruest-attrib-defs*` traegt zusaetzlich ein leeres `ID`-ATTDEF (Voraussetzung fuer `ssg-id-check-all`, das nur bestehende ATTRIBs beschreiben kann). ARTINR/BEZEICHNUNG/TEILEART/LAENGE landen in export_csv.py/export_sivas.py in festen Spalten, FARBE/LAYER (+ ARTINR bei export_csv.py) im Merkmale-/details-JSON. Noch NICHT enthalten: Edit-Pfad (GERUEST_EDIT) | | `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/GeruestInsert.lsp b/Lisp/GeruestInsert.lsp index 01e6938..2ce823c 100644 --- a/Lisp/GeruestInsert.lsp +++ b/Lisp/GeruestInsert.lsp @@ -24,9 +24,15 @@ ;; Attribut-Schema des Wrapper-Blocks. Die Dummy-DWG darf eigene Tags ;; mitbringen - die bleiben erhalten (ssg-attrib-merge). +;; "ID" (leer vorbelegt, wie bei Kreisel/VF_n/GF_n) ist Voraussetzung dafuer, +;; dass ssg-id-check-all dem Block ueberhaupt eine ID zuweisen kann - +;; ssg-attrib-set-on schreibt nur auf ein bereits vorhandenes ATTDEF, siehe +;; oben. Ohne diesen Eintrag bliebe ID fuer immer leer (csv:read-attribs +;; exportiert dann eben kein "ID"-Feld statt eines Werts). (if (null *geruest-attrib-defs*) (setq *geruest-attrib-defs* - '(("ARTINR" "") + '(("ID" "") + ("ARTINR" "") ("LAENGE" "") ("BEZEICHNUNG" "") ("TEILEART" "") diff --git a/Lisp/export.lsp b/Lisp/export.lsp index 6680688..6ecbfc1 100644 --- a/Lisp/export.lsp +++ b/Lisp/export.lsp @@ -198,12 +198,18 @@ ;; --- String fuer JSON escapen (Anfuehrungszeichen/Backslash) --- ;; Konvertiert nicht-String-Werte (z.B. T, nil, Zahlen) defensiv in String. +;; ssg-str-replace-all (ssg_lang.lsp) statt vl-string-subst: vl-string-subst +;; ersetzt nur das ERSTE Vorkommen, nicht alle - bei einem Attributwert mit +;; MEHREREN Anfuehrungszeichen (z.B. BEZEICHNUNG einer Geruest-Baugruppe mit +;; zwei Zoll-Angaben wie 'F. 2" UND 1" ROHR') blieb das zweite Vorkommen +;; unescaped stehen und brach die JSON-Struktur beim Python-Parsen (realer +;; Bug, behoben) - export_raw.json/EXPORTCSV. (defun csv:json-escape (s) (if (not (= (type s) 'STR)) (setq s (if s (vl-princ-to-string s) "")) ) - (setq s (vl-string-subst "\\\\" "\\" s)) - (vl-string-subst "\\\"" "\"" s) + (setq s (ssg-str-replace-all "\\\\" "\\" s)) + (ssg-str-replace-all "\\\"" "\"" s) ) @@ -1082,6 +1088,10 @@ ;; ils-insert-station in SSG_LIB_Commands.lsp). Anders als Separator/ ;; Scanner werden sie von KEINEM anderen Element mitgezaehlt - export_csv.py ;; UND export_sivas.py fuehren sie beide als eigene TeileArt-Zeilen. +;; GR_* = Geruest-Baugruppen (siehe pattern_geruest in cfg/export.cfg, +;; GeruestInsert.lsp). Wie BTMT eigenstaendig und von keinem anderen +;; Element mitgezaehlt - export_csv.py UND export_sivas.py fuehren sie +;; beide als eigene TeileArt-Zeilen. ;; Gibt Auswahlsatz zurueck oder nil. (defun csv:collect-export-blocks ( / ss-all ss-out i ename ed bname) (setq ss-all (ssget "X" (list (cons 0 "INSERT")))) @@ -1101,6 +1111,7 @@ (wcmatch bname (export:pattern "pattern_scanner" "Scanner*")) (wcmatch bname (export:pattern "pattern_btmt_beladung" "BTMT-Beladung*")) (wcmatch bname (export:pattern "pattern_btmt_entladung" "SC_Entladung*")) + (wcmatch bname (export:pattern "pattern_geruest" "GR_*")) ;; Rein numerische Namen = Omniflo SivasNr (Boegen/Weichen) ;; Rein LISP-intern (Python klassifiziert Omniflo stattdessen ;; ueber exakten Katalog-Match), daher fest im Code statt in diff --git a/Lisp/ssg_id.lsp b/Lisp/ssg_id.lsp index 913fd42..4a83c5e 100644 --- a/Lisp/ssg_id.lsp +++ b/Lisp/ssg_id.lsp @@ -38,6 +38,8 @@ ;; pattern_btmt_entladung in cfg/export.cfg) aus demselben Grund: sonst bleibt ;; ihre ID trotz ATTDEF leer und sie fehlen bei der zeichnungsweiten Duplikat- ;; pruefung/Maximum-Ermittlung (ssg-id-check-all). +;; GR_* (Geruest-Baugruppen, siehe pattern_geruest in cfg/export.cfg) ebenso - +;; das ID-ATTDEF steht seit *geruest-attrib-defs* zur Verfuegung. (defun ssg-id-collect-blocks ( / ss-all ss-out i ename ed bname) (dbgf "ssg-id-collect-blocks") (setq ss-all (ssget "X" (list (cons 0 "INSERT")))) @@ -55,6 +57,7 @@ (wcmatch bname "Vario*,Staustrecke*,AUS_Element*,EIN_Element*,VF_*,GF_*") (wcmatch bname "Separator_SP*,S-LP*,Scanner*") (wcmatch bname "BTMT-Beladung*,SC_Entladung*") + (wcmatch bname "GR_*") (wcmatch bname "#*") ) (ssadd ename ss-out) diff --git a/cfg/export.cfg b/cfg/export.cfg index 8110e3f..f2bbb6d 100644 --- a/cfg/export.cfg +++ b/cfg/export.cfg @@ -36,6 +36,10 @@ # fuehren sie daher beide als eigene TeileArt-Zeilen (export_sivas.py zusaetzlich # in den Summierungszaehlern "Anzahl aller BTBeladung"/"Anzahl aller # Abwurfstationen" der ILS-Automation-Zeile). +# +# pattern_geruest: Geruest-Baugruppen (GeruestInsert.lsp, GR__). +# Eigenstaendig wie BTMT, kein ANZAHL_*-Attribut an einem Carrier - export_csv.py +# UND export_sivas.py fuehren sie als eigene TeileArt-Zeilen. # ============================================================ [blockpattern] @@ -50,6 +54,7 @@ pattern_separator= Separator_SP*, S-LP* pattern_scanner= Scanner* pattern_btmt_beladung= BTMT-Beladung* pattern_btmt_entladung= SC_Entladung* +pattern_geruest= GR_* pattern_ks_subblocks= KS_EIN, KS_AUS, K1, K2, K3, K4 [python] diff --git a/data/json/geruest.json b/data/json/geruest.json index d1b36ad..3ef2d41 100644 --- a/data/json/geruest.json +++ b/data/json/geruest.json @@ -244,7 +244,7 @@ ] }, { - "name": "R 2\" Haltearm 2-ARMIG 90°", + "name": "R 2\" Haltearm 2-ARMIG 90 Grad", "teile": [ { "artikel": "BODENSÄULE R 2\" 60,3 MIT FUSSPLATTE", @@ -257,14 +257,14 @@ "menge": 1 }, { - "artikel": "HALTEARM FÜR BODENSÄULE R 2\" 2-ARMIG 90° KPL.", + "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°", + "name": "R 2\" Haltearm 2-ARMIG 180 Grad", "teile": [ { "artikel": "BODENSÄULE R 2\" 60,3 MIT FUSSPLATTE", @@ -277,7 +277,7 @@ "menge": 1 }, { - "artikel": "HALTEARM FÜR BODENSÄULE R 2\" 2-ARMIG 180° KPL.", + "artikel": "HALTEARM FÜR BODENSÄULE R 2\" 2-ARMIG 180 Grad KPL.", "sivas_id": 821004052, "menge": 1 } @@ -311,17 +311,17 @@ "menge": 2 }, { - "artikel": "KLEMMRING MIT MUFFE DOPPELT 90°, KPL.", + "artikel": "KLEMMRING MIT MUFFE DOPPELT 90 Grad, KPL.", "sivas_id": 825002009, "menge": 2 }, { - "artikel": "KLEMMRING MIT MUFFE DOPPELT 180°, KPL.", + "artikel": "KLEMMRING MIT MUFFE DOPPELT 180 Grad, KPL.", "sivas_id": 825002008, "menge": 2 }, { - "artikel": "KLEMMRING M. MUFFE DREIFACH 90°/180° KPL.", + "artikel": "KLEMMRING M. MUFFE DREIFACH 90 Grad/180 Grad KPL.", "sivas_id": 825002007, "menge": 2 }, @@ -336,7 +336,7 @@ "menge": 2 }, { - "artikel": "KREUZSCHELLE F. 2\" UND 1\" ROHR SCHWENKBAR 360°", + "artikel": "KREUZSCHELLE F. 2\" UND 1\" ROHR SCHWENKBAR 360 Grad", "sivas_id": 922083009, "menge": 2 } diff --git a/lib/export_csv.py b/lib/export_csv.py index 1ee048c..41fe681 100644 --- a/lib/export_csv.py +++ b/lib/export_csv.py @@ -263,6 +263,23 @@ def build_btmt_merkmale(block): } +def build_geruest_merkmale(block): + """Merkmale-Dict fuer einen GR_-Geruest-Baugruppenblock (siehe + pattern_geruest in cfg/export.cfg, GeruestInsert.lsp *geruest-attrib-defs*). + + ARTINR/LAENGE/BEZEICHNUNG wandern in feste CSV-Spalten (teileid/ + bezeichnung ueben in process_blocks unten), TEILEART/FARBE/LAYER bleiben + als Rest-Attribute in der Merkmale-JSON-Spalte - so wie bei Separator/ + Scanner/BTMT bereits ueblich.""" + attribs = block.get("attribs", {}) + return { + "TeileArt": attribs.get("TEILEART", ""), + "Farbe": attribs.get("FARBE", ""), + "Laenge": attribs.get("LAENGE", ""), + "Layer": attribs.get("LAYER", ""), + } + + def format_sensor_id(prefix, n): """Fallback-TeileId fuer Separator/Scanner-Zeilen im CSV-Export, falls das Block-Attribut "ID" (noch) leer ist. @@ -869,6 +886,7 @@ def process_blocks(blocks, lookup, dbg=None): scanner_count = 0 btmt_beladung_count = 0 btmt_entladung_count = 0 + geruest_count = 0 # Zaehlung fuer die Omniflo-Sum-Zeile (nur Bogen/Weiche/Gerade) cnt_wk = cnt_einzel = cnt_delta = cnt_doppel = cnt_stern = 0 @@ -1141,6 +1159,30 @@ def process_blocks(blocks, lookup, dbg=None): }) continue + # Geruest-Baugruppe (GR__) - eigene TeileArt-Zeile, + # analog zu BTMT: kein ANZAHL_*-Attribut an einem Carrier zaehlt sie + # mit. TeileId ist das echte ID-Attribut (ssg-id-check-all fuellt es + # vor jedem Export, siehe *geruest-attrib-defs*); ARTINR (Sivas-IDs, + # ggf. mehrere kommagetrennt) landet als eigene Spalte in den + # Merkmalen statt in "teileart" - anders als bei Kreisel/BTMT ist + # "TEILEART" hier ein FREIES Attribut (Rohrabhaenger/Saeule/...), keine + # feste Konstante. + if matches_any(bname, BLOCKPATTERNS.get("pattern_geruest", [])): + elem_nr += 1 + geruest_count += 1 + attribs = block.get("attribs", {}) + bezeichnung = attribs.get("BEZEICHNUNG", "").strip() + items.append({ + "nr": elem_nr, + "teileart": "Geruest", + "teileid": attribs.get("ID") or format_sensor_id("GR", geruest_count), + "bezeichnung": bezeichnung if bezeichnung else f"Geruest :{geruest_count}", + "planquadrat": planquadrat_column(block, planquadrat_cfg), + "merkmale": {"ARTINR": attribs.get("ARTINR", ""), **build_geruest_merkmale(block)}, + **bbox_columns(block), + }) + continue + if has_omniflo: elem_nr += 1 items.append({ diff --git a/lib/export_sivas.py b/lib/export_sivas.py index 9aff485..37dc0a9 100644 --- a/lib/export_sivas.py +++ b/lib/export_sivas.py @@ -288,6 +288,19 @@ def build_eckrad_details(block): } +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/LAYER bleiben als Rest-Attribute + hier.""" + attribs = block.get("attribs", {}) + return { + "Farbe": attribs.get("FARBE", ""), + "Layer": attribs.get("LAYER", ""), + } + + # --- Bekannte Bloecke ignorieren --- SKIP_BLOCKS = set(BLOCKPATTERNS.get("pattern_ks_subblocks", ["K1", "K2", "K3", "K4", "KS_EIN", "KS_AUS"])) @@ -339,6 +352,7 @@ def process_blocks(blocks, lookup): btmt_beladung_bezeichnungen = [] btmt_entladung_ids = [] # IDs aller SC_Entladung*-Bloecke (eine gruppierte Zeile) btmt_entladung_bezeichnungen = [] + geruest_list = [] # Liste von GR_-Geruest-Baugruppenbloecken, je einer Zeile counters = { "anzahl_boegen": 0, @@ -369,6 +383,7 @@ def process_blocks(blocks, lookup): "anzahl_scanner": 0, "anzahl_btbeladung": 0, "anzahl_abwurfstationen": 0, + "anzahl_geruest": 0, } for block in blocks: @@ -398,6 +413,18 @@ def process_blocks(blocks, lookup): counters["anzahl_abwurfstationen"] += 1 continue + # --- Geruest-Baugruppe --- + # Anders als BTMT/Separator je Block eine EIGENE Zeile statt gruppiert: + # ARTINR (Sivas-IDs) und Laenge/Farbe koennen von Block zu Block + # unterschiedlich sein (freie Basis-Variante+Anbauteile-Auswahl je + # GERUEST_*-Aufruf), eine Gruppierung wuerde das verschleiern - wie + # bei VF_N/Kreisel oben, die aus demselben Grund ebenfalls einzeln + # bleiben. + if matches_any(bname, BLOCKPATTERNS.get("pattern_geruest", [])): + geruest_list.append(block) + counters["anzahl_geruest"] += 1 + continue + # --- Omniflo Bogen oder Weiche (erkannt via Katalog) --- if bname in lookup: typ, eintrag = lookup[bname] @@ -702,6 +729,28 @@ def process_blocks(blocks, lookup): }) nr += 1 + # Geruest-Baugruppen (GR__) - je Block eine eigene Zeile + # (siehe Kommentar bei geruest_list oben). Sivasnr kommt direkt aus dem + # ARTINR-Attribut - kann bereits mehrere, kommagetrennte Sivas-IDs + # enthalten (Baugruppe aus mehreren Einzelteilen, siehe ssg-join in + # GeruestInsert.lsp), anders als bei den uebrigen Teilearten also KEIN + # fester Eintrag aus ILS_SIVASNR. + for block in geruest_list: + attribs = block.get("attribs", {}) + items.append({ + "nr": nr, + "teileart": attribs.get("TEILEART", "Geruest"), + "sivasnr": attribs.get("ARTINR", ""), + "sivasnr_quoted": True, + "bezeichnung": attribs.get("BEZEICHNUNG", ""), + "dispgruppe": 20, + "anzahl": 1, + "laenge_mm": attribs.get("LAENGE", ""), + "ids": [get_id(block)], + "details": build_geruest_details(block), + }) + nr += 1 + # VarioFoerderer-Compound-Bloecke (VF_N) - je Block eine eigene Zeile mit # vollstaendigen Gefaelle-/Angetrieben-Teilgruppen (immer TYP "Streckengruppe"). for block in vario_list: