From 6ec85905d4542d68a0a29029eab9cad7708ae3e4 Mon Sep 17 00:00:00 2001 From: Simon Hensch Date: Fri, 2 Oct 2026 14:46:12 +0200 Subject: [PATCH 1/4] =?UTF-8?q?[ADD]=20Ger=C3=BCst=20Tr=C3=A4ger=20k=C3=B6?= =?UTF-8?q?nnen=20nun=20=C3=BCber=20das=20Men=C3=BC=20in=20Bricscad=20eing?= =?UTF-8?q?ef=C3=BCgt=20werden=20wie=20durch=20die=20Bihler=20Bibliothek;?= =?UTF-8?q?=20Beschriftungsausrichtung=20nach=20Norm=20korrigiert;=20Nacht?= =?UTF-8?q?r=C3=A4gliche=20Beschriftung=20=C3=BCber=20Makro=20f=C3=BCr=20a?= =?UTF-8?q?lle=20platzierten=20Tr=C3=A4ger=20m=C3=B6glich?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CLAUDE.md | 5 +- Lisp/GeruestInsert.lsp | 965 +++++++++++++++++++++++++++-- data/geruest/R2-Saeule_dummy.dwg | Bin 43832 -> 40311 bytes data/geruest/dummy_Muffe_1zoll.dwg | Bin 0 -> 17473 bytes data/geruest/dummy_Strebe_30x4.dwg | Bin 0 -> 17446 bytes data/json/geruest.json | 202 +++++- dcl/geruest_traeger.dcl | 39 ++ lang/de_DE.json | 19 +- lang/en_GB.json | 19 +- lib/export_csv.py | 19 +- menu/SSG_LIB.cui | 216 ++++--- menu/SSG_LIB.mnu | 6 +- tests/test_unit.lsp | 254 +++++++- 13 files changed, 1564 insertions(+), 180 deletions(-) create mode 100644 data/geruest/dummy_Muffe_1zoll.dwg create mode 100644 data/geruest/dummy_Strebe_30x4.dwg create mode 100644 dcl/geruest_traeger.dcl diff --git a/CLAUDE.md b/CLAUDE.md index ab00d03..2cb453f 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_SAEULEN, GERUEST_ROHRABHAENGER, GERUEST_WANDBEFESTIGUNG (derselbe Dialog, im jeweiligen Bereich geoeffnet; Rohr-Geruest-Traeger/Gattertraeger noch Platzhalter auf GERUEST) | +| Geruest | `GeruestInsert` | GERUEST_SAEULEN, GERUEST_ROHRABHAENGER, GERUEST_WANDBEFESTIGUNG (derselbe Dialog, im jeweiligen Bereich geoeffnet), GERUEST_TRAEGER (eigener Dialog), GERUEST_TRAEGER_BESCHRIFTEN (Untermenue Geruest -> Funktionen -> Traeger beschriften; alle Traeger der Zeichnung neu beschriften); Gattertraeger noch Platzhalter auf GERUEST | | Connections | `Connection_Edit` + `SSG_LIB_Commands` | CONNECTION_INSERT, CONNECTION_EDIT, ILS_EINGANG_INSERT, ILS_AUSGANG_INSERT | | Export | `export` | EXPORTSIVAS, EXPORTCSV, CALLPYTHON | | Konfiguration | `SSG_LIB_Commands` + `DrawPlanquadrate` | SSG_DIM_SWITCH, SSG_SPRACHE, PLANQUADRATE_TOGGLE (DRAW_PLANQUADRATE/DELETE_PLANQUADRATE) | @@ -107,7 +107,7 @@ Detaillierte Dokumentation aller Funktionen und Befehle: siehe `Lisp/README.md`. | `OmniModulInsert.lsp` | OMNI_LOAD, OMNI_APB_*, OMNI_W*_*, OMNI_AP60/AP110, OMNI_TEF_*, OMNI_TV_*, OMNI_APBW_*, OMNI_LADESCHLEIFE_AP110, OMNI_EDIT | Omniflo-Komponenten: Boegen, Weichen, Verbinder, Transferwagen, Ladeschleifen (`data/json/omniflo_ladeschleifen.json`, per `ssg-json-laden`, da die Beschreibungen Kommas enthalten; Blockdatei darf `.dwg` statt `.dxf` sein), Edit-Dialog | | `SSG_LIB_Commands.lsp` | ILS_BTMT_Beladung, ILS_BTMT_Entladung, ILS_SCANNER_INSERT, ILS_SEPARATOR_INSERT, ILS_EINGANG_INSERT, ILS_AUSGANG_INSERT, ILS_ETF_*, ILS_GK*_*, SSG_BLOCKEDIT, SSG_DIM_SWITCH, SSG_SPRACHE | BTMT Be-/Entladung (`ils-insert-station`: wiederholtes Einfuegen von `BTMT-Beladung` bzw. `SC_Entladung`, Drehung interaktiv, Layer aus `LAYER`-Attribut, Dimension via `ssg-ils-block-laden`) + Sensoren (`ils-insert-sensor`) + Eingang-/Ausgang-Symbol (frei platzierbar wie BTMT Be-/Entladung, ueber `ils-insert-station` mit den Rohnamen `Eingang`/`Ausgang`, Bloecke `Eingang_.dwg`/`Ausgang_.dwg` in data/ils) + Dummy-Befehle fuer Menue + Doppelklick/Kontextmenue-Dispatcher + Konfiguration (2D/3D, Sprache) | | `Tro_Edit.lsp` | TRO_INSERT, TRO_EDIT | TRO-Marker (Block `TRO_SYM_`) fuer sps_skel (lib/tro_annotate.py): TRO_INSERT fuegt eine bestehende Blockdefinition an einem gewaehlten Punkt ein und setzt ID/TYPE (bricht ab, wenn der Typ noch keine Blockdefinition in der Zeichnung hat - die entsteht nur ueber tro_annotate.py); TRO_EDIT aendert ID/TYPE eines bestehenden Markers per Dialog. Typliste aus `tro_types.lsp` (von `tro_annotate.py --emit-lisp` nach DXFM_LISP geschrieben). Der Dispatcher SSG_BLOCKEDIT leitet Blocknamen `TRO_*` zu TRO_EDIT. | -| `GeruestInsert.lsp` | GERUEST, GERUEST_SAEULEN, GERUEST_ROHRABHAENGER, GERUEST_WANDBEFESTIGUNG | Geruest-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) | +| `GeruestInsert.lsp` | GERUEST, GERUEST_SAEULEN, GERUEST_ROHRABHAENGER, GERUEST_WANDBEFESTIGUNG, GERUEST_TRAEGER, GERUEST_TRAEGER_BESCHRIFTEN | Geruest-Baugruppen aus `data/json/geruest.json` konfigurieren und einfuegen. **Ein Dialog fuer alle Bereiche**: oben ein Dropdown `bereich` (Rohrabhaenger / Saeulen / Wandbefestigung, Reihenfolge = Dateireihenfolge, Anzeigename aus dem ASCII-Feld `titel`). DCL hat **kein Reiter-Tile**, und da sich die Teilezeilen je Bereich unterscheiden, schliesst ein Bereichswechsel den Dialog (`done_dialog 4`) und die Schleife in `c:GERUEST` baut ihn neu auf; der Stand jedes Bereichs bleibt in `*geruest-zustand*` erhalten, ein versehentlicher Wechsel verwirft also nichts. 1"- und 2"-Saeulen liegen in EINER Baugruppe `Saeulen` mit gemeinsamer Anbauteil-Liste; **`teileart` und `dummy` duerfen je Geometrie-Variante ueberschrieben werden** (`geruest-variante-wert`, Variante gewinnt vor Baugruppe) - 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. **Attribut-Keys in `geruest.json` sind GROSS** (`LAENGE`, `TEILEFARBE`, ...) = die Block-Attribut-Tags; `ssg-json-get` unterscheidet Gross/Klein. **Rohr-Geruest-Traeger** (`GERUEST_TRAEGER`, Baugruppe mit `"einfuegeart": "linie"` - fehlt darum im Bereichs-Dropdown von GERUEST, gefunden ueber `geruest-baugruppe`): eigener fester Dialog `dcl/geruest_traeger.dcl` (Variante, Farbe, je eine Checkbox + Feld fuer `LAENGENABZUGANFANG`/`LAENGENABZUGENDE`, Vorgabe `vorgabe`/`aktiv` aus dem attribute-Block, je Variante ueberschreibbar via `geruest-attr-feld`); danach Einfuege-Schleife bis ESC/Enter: Startpunkt, dann Endpunkt ODER getippte Laenge (+ Richtung). Aktive Abzuege ruecken die Linie beidseitig ein (Strecke 1000, Abzug Anfang 20/Ende 35 -> Start 20 mm hinter dem Klick, Linie 945 mm); `LAENGE` = Netto-Laenge, gegen `LAENGE.min/max` geprueft. KEINE Dummy-DWG: die Geometrie ist eine per `entmake` erzeugte LINE (0,0,0)-(L,0,0) auf dem `layer` der Variante, eingefuegt mit dem Richtungswinkel (ANGBASE/ANGDIR/AUNITS dafuer kurz auf 0). **Querstreben + Muffe** als verschachtelte Dummy-DWGs im selben Block, reine Grafik ohne Export: `querstrebe.dummy` (`data/geruest/dummy_Strebe_30x4.dwg`, Basispunkt Strebenmitte, 30 mm laengs X) an jeder Strebenposition; fehlt die DWG, Rueckfall auf je eine 25-mm-Querlinie an Strebenanfang/-ende (`laenge`/`querlinie`, Standard 30/25 nur im Code). `muffe.dummy` (`dummy_Muffe_1zoll.dwg`, Basispunkt Muffenmitte) am Linienende, NUR bei Varianten mit ausdruecklichem `"mit_muffe": true` (nicht aus dem Namen geraten; bei "mit 2 Muffen" trotzdem nur eine am Ende); `querstrebe`/`muffe` per Variante ueberschreibbar (`geruest-variante-wert`). Dummys werden ohne Drehung eingefuegt (Traeger laeuft im Block entlang +X), ab dem zweiten Mal per Blockname (`geruest-dummy-einfuegen`). Verteilungs-Konfiguration `querstrebe` (`abstand_max`/`rand_min`/`rand_max`, Variante vor Baugruppe), Verteilung `geruest-traeger-streben`: so wenige Streben wie moeglich, beide Raender gleich; Abstand GENAU `abstand_max`, solange der Rand in `rand_min`..`rand_max` bleibt (1300 -> 150|500|500|150), sonst Rand = `rand_min` und Abstand etwas kleiner (1100 -> 100|450|450|100, mit fest 500 geht die Laenge nicht auf); Netto <= 2*rand_max -> eine Strebe mittig, < 2*rand_min -> keine. Schema `*geruest-traeger-attrib-defs*` = `*geruest-attrib-defs*` + die zwei Abzug-Tags; gemeinsamer Block-Schluss mit den anderen Bereichen in `geruest-block-abschliessen`. Reine Berechnung (`geruest-traeger-laenge`/`-start`/`-pruefen`, `geruest-mm-zahl`) in `tests/test_unit.lsp`. **Traeger-Beschriftung** (Checkbox im Dialog, Standard an; z.B. `RT 80/80 L=2650`): EIGENES TEXT-Objekt neben dem Block, abgeleitet NUR aus dem fertigen Block (Einfuegepunkt, DXF 50, Attribute `LAENGE` + `VARIANTE`) - darum nutzen Einfuegen und `GERUEST_TRAEGER_BESCHRIFTEN` dieselbe Funktion `geruest-traeger-beschriften`, und ein von Hand verschobener/gedrehter Traeger wird beim Neubeschriften korrekt erfasst. Verknuepfung Text -> Block per XDATA `SSG_GR_BESCHR` (1005 = Block-Handle): Neubeschriften ersetzt statt verdoppelt, der Sammelbefehl entfernt verwaiste Texte. JSON `beschriftung` (je FELD Variante vor Baugruppe, `geruest-obj-feld`): Inhalt `format` (`%1` Text, `%2` Laenge auf ganze mm) + `text` (fehlt -> Variantenname) und `layer` (je Variante verschieden, darum in JEDER Variante gepflegt - keine Baugruppen-Vorgabe; fehlt er doch, aktueller Layer); Formatierung NUR `stil`/`ausrichtung`/`hoehe` - alles andere regelt der Textstil ausserhalb, es wird kein Stil angelegt (fehlt er: Meldung, aktueller TEXTSTYLE). `ausrichtung` = Codes von TEXT "Ausrichten" (T/M/B + L/C/R), Bezugspunkt auf der Traegerlinie, L/R in LESErichtung. Textwinkel entlang des Traegers, DIN: fuer 90 < w <= 270 Grad um 180 gedreht (`geruest-text-winkel`). Noch NICHT enthalten: Edit-Pfad (GERUEST_EDIT) | | `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). | @@ -124,6 +124,7 @@ Detaillierte Dokumentation aller Funktionen und Befehle: siehe `Lisp/README.md`. | `sprache.dcl` | SSG_SPRACHE (SSG_LIB_Commands.lsp) | | `tro_insert.dcl` | TRO_INSERT (Tro_Edit.lsp) | | `tro_edit.dcl` | TRO_EDIT (Tro_Edit.lsp) | +| `geruest_traeger.dcl` | GERUEST_TRAEGER (GeruestInsert.lsp, `geruest-traeger-dialog`) | | `vfl_edit.dcl` | Linienzug-Editieren/Fortsetzen (vf_linienzug.lsp, `vfl-dlg-position`, aufgerufen aus `vfl-edit-ent`) | | `vf_linienzug_wizard.dcl` | Linienzug-Assistent (Modus 1, 2 UND 3): zwei generische Einzel-Dialoge (Zahl-Eingabe, Mehrfachauswahl; `vflw-zahl`/`vflw-wahl`, aufgerufen aus `vfl-in-real`/`vfl-in-string`/`vfl-in-int` bei aktivem `*vfl-wizard-mode*`) PLUS sieben Gruppen-Dialoge, die mehrere immer unmittelbar aufeinanderfolgende Fragen in einem Bildschirm zusammenfassen (Kettenstart, AS-Element, GF-Bogen, ES-Element, Vario-Kurve, Gefaelle festlegen, Ziel-Hoehe, Horizontales Stueck - inkl. Punktwahl-Button mit X/Y/Z-Anzeige; `vflw-gruppe-*-impl` in vf_linienzug.lsp fuellen dafuer vorab eine kleine Pending-Queue `*vflw-pending*`, die einzelnen `vfl-in-*`-Aufrufe bleiben dabei unveraendert) PLUS drei Segment-Gruppen-Dialoge fuer die segmentweise Klassifizierung in Modus 2/3 (`vflw_seg_linie_m2` = Typ+GF-Neigung, `vflw_seg_linie_m3` = 4-fach-Typ+kontextabh. Wertfeld, `vflw_seg_bogen` = Typ+Variante; `vflw-seg-*-impl`). Beide Modi heben vor der Frage das aktuelle Pfad-Segment (LINE/ARC) per `vfl-seg-highlight` (`redraw`) in der Zeichnung hervor und zeigen "Segment i/n ..." im Dialogkopf. Details: `doc/variofoerderer.md` | diff --git a/Lisp/GeruestInsert.lsp b/Lisp/GeruestInsert.lsp index 436fe2f..1788ed1 100644 --- a/Lisp/GeruestInsert.lsp +++ b/Lisp/GeruestInsert.lsp @@ -67,6 +67,24 @@ ) ) +;; Rohr-Geruest-Traeger: dasselbe Schema plus die beiden Laengenabzuege und +;; VARIANTE (Name der Geometrie-Variante). Bewusst ein eigenes Schema - die +;; anderen GR_-Bloecke behalten ihres. LAENGE ist beim Traeger die +;; NETTO-Laenge (Strecke minus Abzuege). VARIANTE macht den Block +;; selbstbeschreibend: GERUEST_TRAEGER_BESCHRIFTEN findet darueber die +;; Formatierung der Beschriftung, ohne den Dialog zu kennen. +;; Ohne null-Guard: ein Neuladen der Datei soll ein erweitertes Schema sofort +;; wirksam machen. +(setq *geruest-traeger-attrib-defs* + (append *geruest-attrib-defs* + '(("LAENGENABZUGANFANG" "") + ("LAENGENABZUGENDE" "") + ("VARIANTE" ""))) +) + +;; XDATA-App der Traeger-Beschriftung: Gruppe 1005 = Handle des Traeger-Blocks. +(setq *geruest-beschr-app* "SSG_GR_BESCHR") + (if (null *geruest-block-counter*) (setq *geruest-block-counter* 0)) @@ -116,10 +134,14 @@ ;; Alle Baugruppen als ((id . objekt) ...) in Dateireihenfolge - diese ;; Reihenfolge bestimmt auch die Reihenfolge im Bereichs-Dropdown. +;; Baugruppen mit "einfuegeart": "linie" (Rohr-Geruest-Traeger) fehlen hier: +;; sie haben einen eigenen Dialog und einen eigenen Einfuegeablauf +;; (c:GERUEST_TRAEGER) und gehoeren nicht in das Bereichs-Dropdown. (defun geruest-baugruppen-liste ( / erg) (setq erg nil) (foreach eintrag (geruest-daten) - (if (listp (cdr eintrag)) + (if (and (listp (cdr eintrag)) + (not (equal (ssg-json-get (cdr eintrag) "einfuegeart") "linie"))) (setq erg (append erg (list (cons (ssg-json-get (cdr eintrag) "id") (cdr eintrag))))) ) @@ -623,17 +645,44 @@ (princ) ) -;; Aktuell gewaehlte Farbe als Text. -(defun geruest-dlg-farbwert ( / idx) - (setq idx (atoi *geruest-dlg-farbe*)) +;; Farbliste des Dialogs aus der TEILEFARBE-Definition aufbauen: Optionen + +;; freie Option ans Listenende; deren Index merkt sich der Callback, um das +;; Freitextfeld freizuschalten. Genutzt vom GERUEST- und vom Traeger-Dialog. +(defun geruest-farb-liste-setzen (farb-opts / frei-opt) + (setq *geruest-farb-liste* nil *geruest-frei-idx* -1) + (if farb-opts + (progn + (setq *geruest-farb-liste* (ssg-json-get farb-opts "optionen")) + (if (ssg-json-get farb-opts "frei_erlaubt") + (progn + (setq frei-opt (ssg-json-get farb-opts "frei_option")) + (if (null frei-opt) (setq frei-opt "Individuell")) + (setq *geruest-frei-idx* (length *geruest-farb-liste*)) + (setq *geruest-farb-liste* + (append *geruest-farb-liste* (list frei-opt))) + ) + ) + ) + ) +) + +;; Gewaehlte Farbe als Text. idx-str = Tile-Wert der Farbliste, +;; frei = Inhalt des Freitextfelds. +(defun geruest-farbwert (idx-str frei / idx) + (setq idx (atoi idx-str)) (cond ((null *geruest-farb-liste*) "") - ((= idx *geruest-frei-idx*) *geruest-dlg-frei*) + ((= idx *geruest-frei-idx*) frei) ((nth idx *geruest-farb-liste*) (nth idx *geruest-farb-liste*)) (T "") ) ) +;; Aktuell gewaehlte Farbe des GERUEST-Dialogs als Text. +(defun geruest-dlg-farbwert ( / ) + (geruest-farbwert *geruest-dlg-farbe* *geruest-dlg-frei*) +) + ;; Konfiguration anwenden und die Tiles nachziehen. Wird direkt aus dem ;; popup_list-Rueckruf aufgerufen - set_tile aendert die Anzeige im laufenden ;; Dialog, ein Neuaufbau ist nicht noetig. Index 0 = "(keine)". @@ -919,33 +968,17 @@ ;; ("WECHSEL" bereich-index) - Nutzer hat den Bereich umgestellt ;; nil - abgebrochen (defun geruest-dialog (bg bereich-idx bereiche / dcl-pfad dat attr laenge-def - farb-opts frei-opt min-l max-l fertig rueckgabe + farb-opts min-l max-l fertig rueckgabe ergebnis wert-l oben-m unten-m name neu-idx) (setq *geruest-varianten* (ssg-json-get bg "geometrie_varianten")) (setq *geruest-anbauteile* (ssg-json-get bg "anbaugruppen")) (setq attr (ssg-json-get bg "attribute")) - (setq laenge-def (if attr (ssg-json-get attr "Laenge"))) - (setq farb-opts (if attr (ssg-json-get attr "Teilefarbe"))) + (setq laenge-def (if attr (ssg-json-get attr "LAENGE"))) + (setq farb-opts (if attr (ssg-json-get attr "TEILEFARBE"))) (setq min-l (if laenge-def (ssg-json-get laenge-def "min"))) (setq max-l (if laenge-def (ssg-json-get laenge-def "max"))) - ;; Farboptionen + freie Option ans Listenende; Index davon merkt sich der - ;; Callback, um das Freitextfeld freizuschalten. - (setq *geruest-farb-liste* nil *geruest-frei-idx* -1) - (if farb-opts - (progn - (setq *geruest-farb-liste* (ssg-json-get farb-opts "optionen")) - (if (ssg-json-get farb-opts "frei_erlaubt") - (progn - (setq frei-opt (ssg-json-get farb-opts "frei_option")) - (if (null frei-opt) (setq frei-opt "Individuell")) - (setq *geruest-frei-idx* (length *geruest-farb-liste*)) - (setq *geruest-farb-liste* - (append *geruest-farb-liste* (list frei-opt))) - ) - ) - ) - ) + (geruest-farb-liste-setzen farb-opts) (setq *geruest-konfig-liste* (geruest-konfigs bg)) ;; Frueheren Stand dieses Bereichs wiederherstellen, sonst Ausgangszustand @@ -1136,7 +1169,7 @@ ;; 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 teile-dwgs / datei dummy lastEnt dummyEnt - e ss bname blockEnt dummy-attribs attribs) + dummy-attribs attribs) ;; Eine Variante darf eine eigene Dummy-DWG mitbringen; sonst gilt die der ;; Baugruppe. (setq datei (geruest-variante-wert variante bg "dummy")) @@ -1173,46 +1206,59 @@ ;; ssg-attrib-merge legt alle Tags aus *geruest-attrib-defs* an und ;; uebernimmt zusaetzlich alle Tags der Dummy-DWG. (setq attribs (ssg-attrib-merge dummy-attribs *geruest-attrib-defs*)) - (foreach paar werte - (if (assoc (car paar) attribs) - (setq attribs (subst paar (assoc (car paar) attribs) attribs)) - (setq attribs (append attribs (list paar))) - ) - ) + ;; nil = Drehwinkel interaktiv am Cursor + (geruest-block-abschliessen bg attribs werte lastEnt pt nil) + ) + ) +) - (ssg-attrib-make-defs (ssg-attrib-alist-to-defs attribs) 50.0) +;; Gemeinsamer Schluss aller Geruest-Bloecke: Werte ins Schema eintragen, +;; ATTDEFs erzeugen, alles Neue seit lastEnt zu GR__ zusammenfassen +;; und bei pt einfuegen. +;; attribs = Schema-Alist (Tags + Vorgabewerte), werte = berechnete Werte +;; rot = Drehwinkel in Grad (Zahl) oder nil fuer interaktive Drehung. +;; Bei einer Zahl muss der Aufrufer ANGBASE/ANGDIR/AUNITS auf 0 +;; gesetzt haben, sonst deutet INSERT den Wert anders. +;; Rueckgabe: (blockname . entity) oder nil. +(defun geruest-block-abschliessen (bg attribs werte lastEnt pt rot + / e ss bname blockEnt) + (foreach paar werte + (if (assoc (car paar) attribs) + (setq attribs (subst paar (assoc (car paar) attribs) attribs)) + (setq attribs (append attribs (list paar))) + ) + ) - ;; Alles Neue seit lastEnt einsammeln (Dummy-INSERT + ATTDEFs) - (setq ss (ssadd)) - (setq e (if lastEnt (entnext lastEnt) (entnext))) - (while e - (ssadd e ss) - (setq e (entnext e)) - ) + (ssg-attrib-make-defs (ssg-attrib-alist-to-defs attribs) 50.0) - (setq bname (geruest-blockname (ssg-json-get bg "id"))) - (command "_.-BLOCK" bname (list 0.0 0.0 0.0) ss "") + ;; Alles Neue seit lastEnt einsammeln (Geometrie + ATTDEFs) + (setq ss (ssadd)) + (setq e (if lastEnt (entnext lastEnt) (entnext))) + (while e + (ssadd e ss) + (setq e (entnext e)) + ) - ;; Stand VOR dem Einfuegen merken: bricht der Nutzer die Drehung mit ESC - ;; ab, entsteht kein neues INSERT und (entlast) zeigt auf ein voellig - ;; fremdes Objekt - ohne diesen Vergleich wuerden dessen Attribute - ;; ueberschrieben. - (setq lastEnt (entlast)) - ;; pause = Drehwinkel interaktiv am Cursor - (command "_.INSERT" bname pt 1 1 pause) - ;; Laufende Einfuegung sicher beenden (z.B. ESC waehrend der Drehung) - (if (> (getvar "CMDACTIVE") 0) (command)) - (if (> (getvar "CMDACTIVE") 0) (command)) + (setq bname (geruest-blockname (ssg-json-get bg "id"))) + (command "_.-BLOCK" bname (list 0.0 0.0 0.0) ss "") - (setq blockEnt (entlast)) - (if (and blockEnt (not (eq blockEnt lastEnt)) - (= (cdr (assoc 0 (entget blockEnt))) "INSERT")) - (progn - (ssg-attrib-set-on blockEnt attribs) - (ssg-block-layer-vorgabe blockEnt bname attribs) - (cons bname blockEnt) - ) - ) + ;; Stand VOR dem Einfuegen merken: bricht der Nutzer die Drehung mit ESC + ;; ab, entsteht kein neues INSERT und (entlast) zeigt auf ein voellig + ;; fremdes Objekt - ohne diesen Vergleich wuerden dessen Attribute + ;; ueberschrieben. + (setq lastEnt (entlast)) + (command "_.INSERT" bname pt 1 1 (if rot rot pause)) + ;; Laufende Einfuegung sicher beenden (z.B. ESC waehrend der Drehung) + (if (> (getvar "CMDACTIVE") 0) (command)) + (if (> (getvar "CMDACTIVE") 0) (command)) + + (setq blockEnt (entlast)) + (if (and blockEnt (not (eq blockEnt lastEnt)) + (= (cdr (assoc 0 (entget blockEnt))) "INSERT")) + (progn + (ssg-attrib-set-on blockEnt attribs) + (ssg-block-layer-vorgabe blockEnt bname attribs) + (cons bname blockEnt) ) ) ) @@ -1362,5 +1408,800 @@ (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") + +;; ============================================================ +;; ROHR-GERUEST-TRAEGER (Baugruppe mit "einfuegeart": "linie") +;; ============================================================ +;; Eigener Dialog (dcl/geruest_traeger.dcl): Variante, Farbe und zwei +;; Laengenabzuege. Die Laenge selbst wird DANACH in der Zeichnung bestimmt - +;; Startpunkt, dann Endpunkt oder getippte Laenge (+ Richtung), wie beim +;; Kreisel. Aktive Abzuege ruecken die Linie beidseitig ein: Strecke 1000, +;; Abzug Anfang 20, Ende 35 -> Linie beginnt 20 mm hinter dem Startklick und +;; ist 945 mm lang. +;; +;; Keine Dummy-DWG: die Geometrie ist eine einzige LINE, die je Block eine +;; andere Laenge hat. Sie entsteht per entmake von (0,0,0) nach (L,0,0) auf +;; dem Layer der Variante; der Block wird am eingerueckten Startpunkt mit dem +;; Richtungswinkel eingefuegt. Es wird wiederholt eingefuegt, bis der Nutzer +;; ESC/Enter drueckt - jeder Traeger ist ein eigener GR_Traeger_-Block. + +;; Baugruppe ueber das ASCII-Feld "id" (auch solche, die +;; geruest-baugruppen-liste auslaesst). +(defun geruest-baugruppe (id / erg) + (setq erg nil) + (foreach eintrag (geruest-daten) + (if (and (null erg) (listp (cdr eintrag)) + (equal (ssg-json-get (cdr eintrag) "id") id)) + (setq erg (cdr eintrag)) + ) + ) + erg +) + +;; Feld einer Attribut-Definition (attribute -> TAG -> feld). Eine Variante +;; darf einen eigenen "attribute"-Block mitbringen, der vor dem der Baugruppe +;; gilt (z.B. ein anderer Laengenabzug bei einer Muffen-Variante). assoc +;; statt ssg-json-get, damit ein in der Variante gesetztes false (= nil) den +;; Wert der Baugruppe ueberschreibt, statt als "fehlt" durchzufallen. +(defun geruest-attr-feld (variante bg tag feld) + (geruest-obj-feld variante bg (list "attribute" tag) feld) +) + +;; Objekt unter einem Schluesselpfad, z.B. ("attribute" "LAENGE"); nil, wenn +;; ein Schluessel fehlt. +(defun geruest-json-pfad-get (obj pfad) + (foreach k pfad (setq obj (if (and obj (listp obj)) (ssg-json-get obj k)))) + obj +) + +;; Allgemeine Form von geruest-attr-feld: Feld unter pfad, Variante vor +;; Baugruppe, je FELD aufgeloest (eine Variante nennt nur, was abweicht). +;; Genutzt fuer "attribute" und "beschriftung". +(defun geruest-obj-feld (variante bg pfad feld / def paar) + (setq def (if variante (geruest-json-pfad-get variante pfad))) + (setq paar (if (and def (listp def)) (assoc feld def))) + (if paar + (cdr paar) + (ssg-json-get (geruest-json-pfad-get bg pfad) feld) + ) +) + +;; Millimeter-Eingabe als Zahl >= 0 (Komma wie Punkt), sonst nil. +;; Leere Eingabe -> nil. +(defun geruest-mm-zahl (s / w) + (setq s (vl-string-translate "," "." (ssg-cfg-trim (if s s "")))) + (if (and (/= s "") (setq w (distof s 2)) (>= w 0.0)) w) +) + +;; Abzug-Feld: leer -> 0, gueltige Zahl -> Zahl, sonst nil. +(defun geruest-abzug-wert (s) + (if (= (ssg-cfg-trim (if s s "")) "") + 0.0 + (geruest-mm-zahl s) + ) +) + +;; Millimeterwert fuer Attribute/Meldungen: ganze Zahl ohne Nachkommastelle, +;; sonst eine Stelle. +(defun geruest-mm-string (w / r) + (setq r (fix (+ w 0.5))) + (if (equal w r 1e-6) (itoa r) (rtos w 2 1)) +) + +;; Netto-Laenge der Linie: Strecke minus beide Abzuege, nil wenn <= 0. +(defun geruest-traeger-laenge (strecke abzug-a abzug-e / netto) + (setq netto (- strecke (if abzug-a abzug-a 0.0) (if abzug-e abzug-e 0.0))) + (if (> netto 1e-6) netto) +) + +;; Eingerueckter Startpunkt: abzug-a entlang winkel ab p1, Z von p1. +(defun geruest-traeger-start (p1 winkel abzug-a / p) + (setq p (polar p1 winkel (if abzug-a abzug-a 0.0))) + (list (car p) (cadr p) (if (caddr p1) (caddr p1) 0.0)) +) + +;; Positionen der Querstreben entlang der Traegerlinie (Abstand ab Linienanfang). +;; Regeln: Abstand zwischen zwei Streben hoechstens abstand-max, beide +;; Endabstaende gleich und in [rand-min, rand-max], so wenige Streben wie +;; moeglich. +;; netto <= 2*rand-max -> eine Strebe in der Mitte +;; sonst -> k = aufgerundet (netto - 2*rand-max) / abstand-max +;; Felder (= wenigste Streben). Rand +;; r = max(rand-min, (netto - k*abstand-max) / 2): +;; der Abstand ist damit GENAU abstand-max, solange der +;; Rand >= rand-min bleibt; nur sonst bleibt der Rand +;; bei rand-min und der Abstand wird etwas kleiner. +;; Mit genau abstand-max geht nicht jede Laenge auf (1100 mm: 2 Streben -> +;; Rand 300, 3 Streben -> Rand 50) - dort ergibt sich 100 | 450 | 450 | 100. +;; r <= rand-max ist durch die Wahl von k garantiert. +;; Kuerzer als 2*rand-min -> keine Strebe (der Mindestrand waere verletzt). +(defun geruest-traeger-streben (netto abstand-max rand-min rand-max / k r s i erg) + (cond + ((or (null netto) (< netto (- (* 2.0 rand-min) 1e-6))) nil) + ((<= netto (+ (* 2.0 rand-max) 1e-6)) (list (/ netto 2.0))) + (T + (setq k (/ (- netto (* 2.0 rand-max)) abstand-max)) + ;; aufrunden, Rundungsrauschen (z.B. 2.0000000001) nicht mitzaehlen + (setq k (if (equal k (fix k) 1e-6) (fix k) (1+ (fix k)))) + (setq r (max rand-min (/ (- netto (* k abstand-max)) 2.0))) + (setq s (/ (- netto (* 2.0 r)) k)) + (setq erg nil i k) + (while (>= i 0) + (setq erg (cons (+ r (* i s)) erg)) + (setq i (1- i)) + ) + erg + ) + ) +) + +;; Querstreben-Konfiguration (Variante vor Baugruppe) als +;; (dummy laenge querlinie abstand-max rand-min rand-max) oder nil, wenn keine +;; "querstrebe" definiert ist. +;; dummy = DWG unter data/geruest (Basispunkt Strebenmitte, 30 mm laengs +;; X) oder nil +;; laenge/querlinie = nur fuer den Rueckfall ohne Dummy-DWG: zwei Querlinien +;; im Abstand laenge, je querlinie lang +;; Fehlende Zahlenwerte -> Standard 30/25/500/100/250. +(defun geruest-traeger-strebe-cfg (variante bg / q w d) + (setq q (geruest-variante-wert variante bg "querstrebe")) + (if (and q (listp q)) + (progn + (setq d (ssg-json-get q "dummy")) + (cons (if (and d (= (type d) 'STR) (/= d "")) d) + (mapcar '(lambda (feld std) + (setq w (ssg-json-get q feld)) + (if (numberp w) (float w) std)) + '("laenge" "querlinie" "abstand_max" "rand_min" "rand_max") + '(30.0 25.0 500.0 100.0 250.0))) + ) + ) +) + +;; Muffen-Dummy einer Variante: nur bei "mit_muffe": true die "dummy"-Datei +;; aus "muffe" (Variante vor Baugruppe), sonst nil. Das Flag steht bewusst +;; ausdruecklich je Variante, statt aus dem Namen ("mit Muffe") geraten zu +;; werden. Bei "mit 2 Muffen" wird trotzdem nur eine Muffe gezeichnet. +(defun geruest-traeger-muffe-dummy (variante bg / m d) + (if (and variante (ssg-json-get variante "mit_muffe")) + (progn + (setq m (geruest-variante-wert variante bg "muffe")) + (setq d (if (and m (listp m)) (ssg-json-get m "dummy"))) + (if (and d (= (type d) 'STR) (/= d "")) d) + ) + ) +) + +;; Liegt netto in [min-l, max-l]? Fehlende Grenzen gelten nicht. +(defun geruest-traeger-pruefen (netto min-l max-l) + (and netto + (or (null min-l) (>= netto min-l)) + (or (null max-l) (<= netto max-l))) +) + +;; BEZEICHNUNG: Teileart + Variante + aktive Abzuege, mit " + " verkettet +;; (Artikelnamen enthalten Kommas, siehe geruest-einfuegen). +(defun geruest-traeger-bezeichnung (teileart variante-name abzug-a abzug-e / teile) + (setq teile (list teileart variante-name)) + (if (> abzug-a 0.0) + (setq teile (append teile (list (ssg-textf "gr-tr-bez-abzug-anfang" + (list (geruest-mm-string abzug-a))))))) + (if (> abzug-e 0.0) + (setq teile (append teile (list (ssg-textf "gr-tr-bez-abzug-ende" + (list (geruest-mm-string abzug-e))))))) + (ssg-join teile " + ") +) + +(defun geruest-traeger-dcl-pfad ( / basis) + (setq basis (cond ((getenv "DXFM_DCL")) + ((getenv "DXFMAKRO") (strcat (getenv "DXFMAKRO") "/dcl")))) + (if basis + (strcat (vl-string-translate "\\" "/" basis) "/geruest_traeger.dcl") + ) +) + +;; --- Dialogzustand (Globals, siehe Abschnitt DIALOGZUSTAND oben) --- +;; Bleibt zwischen zwei GERUEST_TRAEGER-Aufrufen erhalten. + +;; Abzug-Vorgaben (aktiv + Wert) der Variante idx in den Zustand laden. +(defun geruest-tr-vorgaben-laden (idx / v) + (setq v (nth idx (ssg-json-get *geruest-tr-bg* "geometrie_varianten"))) + (setq *geruest-tr-abzug-a* + (if (geruest-attr-feld v *geruest-tr-bg* "LAENGENABZUGANFANG" "aktiv") "1" "0")) + (setq *geruest-tr-abzug-a-w* + (geruest-zahl-string (geruest-attr-feld v *geruest-tr-bg* "LAENGENABZUGANFANG" "vorgabe"))) + (setq *geruest-tr-abzug-e* + (if (geruest-attr-feld v *geruest-tr-bg* "LAENGENABZUGENDE" "aktiv") "1" "0")) + (setq *geruest-tr-abzug-e-w* + (geruest-zahl-string (geruest-attr-feld v *geruest-tr-bg* "LAENGENABZUGENDE" "vorgabe"))) +) + +(defun geruest-tr-abzug-schreiben ( / ) + (set_tile "abzug_a" *geruest-tr-abzug-a*) + (set_tile "abzug_a_w" *geruest-tr-abzug-a-w*) + (set_tile "abzug_e" *geruest-tr-abzug-e*) + (set_tile "abzug_e_w" *geruest-tr-abzug-e-w*) + (mode_tile "abzug_a_w" (if (= *geruest-tr-abzug-a* "1") 0 1)) + (mode_tile "abzug_e_w" (if (= *geruest-tr-abzug-e* "1") 0 1)) +) + +;; Variantenwechsel im Dialog: Abzug-Vorgaben der neuen Variante uebernehmen. +(defun geruest-tr-variante-gewaehlt (wert / ) + (setq *geruest-tr-variante* wert) + (geruest-tr-vorgaben-laden (atoi wert)) + (geruest-tr-abzug-schreiben) +) + +(defun geruest-tr-dlg-lesen ( / ) + (setq *geruest-tr-variante* (get_tile "variante")) + (setq *geruest-tr-farbe* (get_tile "farbe")) + (setq *geruest-tr-frei* (get_tile "farbe_frei")) + (setq *geruest-tr-abzug-a* (get_tile "abzug_a")) + (setq *geruest-tr-abzug-a-w* (get_tile "abzug_a_w")) + (setq *geruest-tr-abzug-e* (get_tile "abzug_e")) + (setq *geruest-tr-abzug-e-w* (get_tile "abzug_e_w")) + (setq *geruest-tr-beschriftung* (get_tile "beschriftung")) +) + +;; Wert eines Abzugs aus dem Zustand: inaktiv -> 0, aktiv -> Zahl oder nil. +(defun geruest-tr-abzug (aktiv wert) + (if (= aktiv "1") (geruest-abzug-wert wert) 0.0) +) + +;; Traeger-Dialog. Rueckgabe: +;; (variante-index farbe abzug-anfang abzug-ende beschriften-p) oder nil bei +;; Abbruch. +(defun geruest-traeger-dialog (bg / varianten dcl-pfad dat fertig rueckgabe + ergebnis aw ew) + (setq varianten (ssg-json-get bg "geometrie_varianten")) + (setq *geruest-tr-bg* bg) + (geruest-farb-liste-setzen + (ssg-json-get (ssg-json-get bg "attribute") "TEILEFARBE")) + ;; Ausgangszustand beim ersten Aufruf bzw. wenn der gemerkte Index nach + ;; einer JSON-Aenderung nicht mehr passt. + (if (or (null *geruest-tr-variante*) + (>= (atoi *geruest-tr-variante*) (length varianten))) + (progn + (setq *geruest-tr-variante* "0" *geruest-tr-farbe* "0" *geruest-tr-frei* "") + (geruest-tr-vorgaben-laden 0) + ) + ) + ;; Beschriftung standardmaessig an; der Haken bleibt zwischen Aufrufen + (if (null *geruest-tr-beschriftung*) (setq *geruest-tr-beschriftung* "1")) + (setq dcl-pfad (geruest-traeger-dcl-pfad)) + (setq fertig nil rueckgabe nil) + + ;; Schleife: ungueltige Eingaben zeigen den Dialog mit dem bisherigen + ;; Stand erneut - DCL kann Zahlen nicht selbst pruefen. + (while (not fertig) + (setq dat (if (and dcl-pfad (findfile dcl-pfad)) (load_dialog dcl-pfad) -1)) + (if (or (< dat 0) (not (new_dialog "geruest_traeger" dat))) + (progn + (alert (ssg-textf "gr-tr-fehler-dcl" + (list (if dcl-pfad dcl-pfad "geruest_traeger.dcl")))) + (setq fertig T) + ) + (progn + (start_list "variante") + (foreach v varianten (add_list (geruest-eintrag-name v))) + (end_list) + (set_tile "variante" *geruest-tr-variante*) + + (if *geruest-farb-liste* + (progn + (start_list "farbe") + (foreach f *geruest-farb-liste* (add_list f)) + (end_list) + (set_tile "farbe" *geruest-tr-farbe*) + (mode_tile "farbe_frei" + (if (= (atoi *geruest-tr-farbe*) *geruest-frei-idx*) 0 1)) + (action_tile "farbe" + "(mode_tile \"farbe_frei\" (if (= (atoi $value) *geruest-frei-idx*) 0 1))") + ) + (progn + (mode_tile "farbe" 1) + (mode_tile "farbe_frei" 1) + ) + ) + (set_tile "farbe_frei" *geruest-tr-frei*) + (geruest-tr-abzug-schreiben) + (set_tile "beschriftung" *geruest-tr-beschriftung*) + (set_tile "hinweis" (ssg-text "gr-tr-hinweis")) + + (action_tile "variante" "(geruest-tr-variante-gewaehlt $value)") + (action_tile "abzug_a" + "(mode_tile \"abzug_a_w\" (if (= $value \"1\") 0 1))") + (action_tile "abzug_e" + "(mode_tile \"abzug_e_w\" (if (= $value \"1\") 0 1))") + (action_tile "accept" "(geruest-tr-dlg-lesen) (done_dialog 1)") + (action_tile "cancel" "(done_dialog 0)") + (setq ergebnis (start_dialog)) + (unload_dialog dat) + + (cond + ((= ergebnis 0) (setq fertig T)) + ((or (null (setq aw (geruest-tr-abzug *geruest-tr-abzug-a* *geruest-tr-abzug-a-w*))) + (null (setq ew (geruest-tr-abzug *geruest-tr-abzug-e* *geruest-tr-abzug-e-w*)))) + (alert (ssg-text "gr-tr-alert-abzug")) + ) + (T + (setq rueckgabe + (list (atoi *geruest-tr-variante*) + (geruest-farbwert *geruest-tr-farbe* *geruest-tr-frei*) + aw ew + (= *geruest-tr-beschriftung* "1"))) + (setq fertig T) + ) + ) + ) + ) + ) + rueckgabe +) + +;; X-Positionen der beiden Querlinien einer Strebe: Anfang und Ende des +;; Flacheisens, laenge mittig um die Strebenposition x. +(defun geruest-traeger-strebe-enden (x laenge) + (list (- x (/ laenge 2.0)) (+ x (/ laenge 2.0))) +) + +;; Querstrebe darstellen: an Anfang und Ende je eine Linie quer zum Traeger +;; (Laenge querlinie, mittig auf der Traegerlinie y = 0). +(defun geruest-traeger-strebe-zeichnen (x laenge querlinie lay / hq) + (setq hq (/ querlinie 2.0)) + (foreach xe (geruest-traeger-strebe-enden x laenge) + (entmake (list '(0 . "LINE") (cons 8 lay) + (list 10 xe (- hq) 0.0) (list 11 xe hq 0.0))) + ) +) + +;; Vollstaendiger Pfad einer Dummy-DWG unter data/geruest oder nil (mit +;; Meldung), wenn sie fehlt. datei = nil -> stilles nil (nichts konfiguriert). +(defun geruest-dummy-finden (datei / pfad) + (if datei + (progn + (setq pfad (geruest-dummy-pfad datei)) + (if (and pfad (findfile pfad)) + pfad + (progn + (princ (ssg-textf "gr-fehler-dummy" (list (if pfad pfad datei)))) + nil + ) + ) + ) + ) +) + +;; Dummy-DWG als verschachtelten Block bei pt (Drehung 0) einfuegen. Ist die +;; Blockdefinition (Dateiname ohne .dwg) schon in der Zeichnung, wird per +;; Blockname eingefuegt - sonst wuerde die DWG bei jeder Strebe neu gelesen +;; (und ggf. "Block neu definieren?" gefragt). ATTREQ/ATTDIA muss der Aufrufer +;; auf 0 gesetzt haben. +(defun geruest-dummy-einfuegen (pfad pt / bname) + (setq bname (vl-filename-base pfad)) + (command "_.INSERT" (if (tblsearch "BLOCK" bname) bname pfad) pt 1 1 0) +) + +;; Linie + Querstreben + Muffe + ATTDEFs zu einem Block zusammenfassen und am +;; Startpunkt mit dem Richtungswinkel einfuegen. Im Block laeuft der Traeger +;; entlang +X, die Dummys werden darum ohne Drehung eingefuegt. +;; strebe = Ergebnis von geruest-traeger-strebe-cfg (nil = keine Streben) +;; strebe-pfad = Pfad der Strebe-DWG oder nil -> Rueckfall auf Querlinien +;; muffe-pfad = Pfad der Muffen-DWG oder nil -> keine Muffe; sonst eine +;; Muffe (Basispunkt Muffenmitte) am Linienende +;; Der Aufrufer sichert die Systemvariablen per ssg-start. +;; Rueckgabe: (blockname . entity) oder nil. +(defun geruest-traeger-block-bauen (bg layer netto strebe strebe-pfad muffe-pfad + werte pt winkel / lastEnt lay) + (setvar "ATTREQ" 0) + (setvar "ATTDIA" 0) + (setvar "OSMODE" 0) + ;; Drehwinkel wird als Grad an INSERT uebergeben - nur eindeutig mit + ;; Winkel-Nullrichtung Ost, gegen den Uhrzeigersinn, Einheit Grad. + (setvar "ANGBASE" 0.0) + (setvar "ANGDIR" 0) + (setvar "AUNITS" 0) + ;; Nicht (entlast) - siehe geruest-block-bauen. + (setq lastEnt (ssg-lastent-ohne-attribute)) + + (setq lay (if (and layer (/= layer "")) layer "0")) + ;; Aktiv setzen, damit auch die verschachtelten Dummy-INSERTs auf dem + ;; Traeger-Layer landen (CLAYER sichert ssg-start immer mit). + (ssg-make-layer lay (ssg-layer-farbe-fuer-name lay) T) + (entmake (list '(0 . "LINE") (cons 8 lay) + '(10 0.0 0.0 0.0) (list 11 netto 0.0 0.0))) + ;; strebe = (dummy laenge querlinie abstand-max rand-min rand-max) + (if strebe + (foreach x (geruest-traeger-streben netto (nth 3 strebe) (nth 4 strebe) (nth 5 strebe)) + (if strebe-pfad + (geruest-dummy-einfuegen strebe-pfad (list x 0.0 0.0)) + (geruest-traeger-strebe-zeichnen x (nth 1 strebe) (nth 2 strebe) lay) + ) + ) + ) + (if muffe-pfad + (geruest-dummy-einfuegen muffe-pfad (list netto 0.0 0.0)) + ) + + (geruest-block-abschliessen bg + (ssg-attrib-merge nil *geruest-traeger-attrib-defs*) + werte lastEnt pt (* winkel (/ 180.0 pi))) +) + +;; Einfuege-Schleife: Startpunkt, Endpunkt oder Laenge, bis ESC/Enter. +;; wahl = Rueckgabe von geruest-traeger-dialog. +(defun geruest-traeger-einfuegen (bg wahl / variante teileart layer paare farbe + abzug-a abzug-e min-l max-l bez werte-basis + werte weiter p1 eingabe strecke winkel netto + ergebnis anzahl strebe strebe-pfad muffe-pfad + beschriften) + (setq variante (nth (car wahl) (ssg-json-get bg "geometrie_varianten"))) + (setq farbe (cadr wahl) + abzug-a (caddr wahl) + abzug-e (cadddr wahl) + beschriften (nth 4 wahl)) + (setq *geruest-beschr-gemeldet* nil) + (setq teileart (geruest-variante-wert variante bg "teileart")) + (setq layer (geruest-variante-wert variante bg "layer")) + (setq min-l (geruest-attr-feld variante bg "LAENGE" "min")) + (setq max-l (geruest-attr-feld variante bg "LAENGE" "max")) + (setq paare (geruest-teile-paare variante nil)) + (setq strebe (geruest-traeger-strebe-cfg variante bg)) + ;; DWGs einmal je Durchgang aufloesen - eine fehlende Datei wird so nur + ;; einmal gemeldet, nicht bei jedem Traeger. Fehlt die Strebe-DWG, werden + ;; stattdessen Querlinien gezeichnet; fehlt die Muffe, entfaellt sie. + (setq strebe-pfad (if strebe (geruest-dummy-finden (car strebe)))) + (setq muffe-pfad (geruest-dummy-finden (geruest-traeger-muffe-dummy variante bg))) + (setq bez (geruest-traeger-bezeichnung teileart + (geruest-eintrag-name variante) abzug-a abzug-e)) + + ;; Fuer alle Traeger dieses Durchgangs gleich - nur LAENGE aendert sich. + (setq werte-basis + (list (cons "ARTINR" (ssg-join (mapcar 'car paare) ",")) + (cons "BEZEICHNUNG" bez) + (cons "TEILEART" teileart) + (cons "LAENGENABZUGANFANG" (geruest-mm-string abzug-a)) + (cons "LAENGENABZUGENDE" (geruest-mm-string abzug-e)) + ;; Block selbstbeschreibend - die Beschriftung (auch spaeter per + ;; GERUEST_TRAEGER_BESCHRIFTEN) findet darueber ihre Formatierung + (cons "VARIANTE" (geruest-eintrag-name variante)))) + (if (and layer (/= layer "")) + (setq werte-basis (append werte-basis (list (cons "LAYER" layer))))) + (if (/= farbe "") + (setq werte-basis (append werte-basis (list (cons "TEILEFARBE" + (ssg-join (geruest-farbliste paare farbe) ",")))))) + + (setq weiter T anzahl 0) + (while weiter + (setq strecke nil) + (setq p1 (getpoint (ssg-text "gr-tr-prompt-start"))) + (if (null p1) + (setq weiter nil) + (progn + ;; 128 = beliebige Eingabe: ein Punkt liefert Laenge UND Richtung, + ;; eine getippte Zahl nur die Laenge (Richtung wird nachgefragt). + (initget 128) + (setq eingabe (getpoint p1 (ssg-text "gr-tr-prompt-ende"))) + ;; Reihenfolge wichtig: nil ist auch listp, und "" darf erst nach dem + ;; Punkt-Fall verglichen werden. + (cond + ((null eingabe) (setq weiter nil)) + ((listp eingabe) + ;; Laenge in der XY-Ebene, die Linie liegt auf Z des Startpunkts + (setq strecke (distance (list (car p1) (cadr p1)) + (list (car eingabe) (cadr eingabe)))) + (setq winkel (angle p1 eingabe)) + ) + ((= eingabe "") (setq weiter nil)) + ((setq strecke (geruest-mm-zahl eingabe)) + (setq winkel (getangle p1 (ssg-text "gr-tr-prompt-richtung"))) + (if (null winkel) (setq winkel 0.0)) + ) + (T (princ (ssg-textf "gr-tr-eingabe-ungueltig" (list eingabe)))) + ) + ) + ) + + (if (and weiter strecke) + (progn + (setq netto (geruest-traeger-laenge strecke abzug-a abzug-e)) + (cond + ((null netto) + (princ (ssg-textf "gr-tr-laenge-null" + (list (geruest-mm-string strecke) + (geruest-mm-string (+ abzug-a abzug-e)))))) + ((not (geruest-traeger-pruefen netto min-l max-l)) + (princ (ssg-textf "gr-tr-laenge-bereich" + (list (geruest-mm-string netto) + (if min-l (geruest-mm-string min-l) "0") + (if max-l (geruest-mm-string max-l) "-"))))) + (T + (setq werte (cons (cons "LAENGE" (geruest-mm-string netto)) werte-basis)) + (ssg-start nil '(("OSMODE") ("ATTREQ") ("ATTDIA") + ("ANGBASE") ("ANGDIR") ("AUNITS"))) + (setq ergebnis (geruest-traeger-block-bauen bg layer netto strebe + strebe-pfad muffe-pfad werte + (geruest-traeger-start p1 winkel abzug-a) winkel)) + ;; Beschriftung aus dem fertigen Block ableiten (dieselbe Funktion + ;; wie GERUEST_TRAEGER_BESCHRIFTEN) + (if (and ergebnis beschriften) + (geruest-traeger-beschriften (cdr ergebnis))) + (ssg-end) + (if ergebnis + (progn + (setq anzahl (1+ anzahl)) + (princ (ssg-textf "gr-tr-fertig" + (list (geruest-mm-string netto) (car ergebnis)))) + ) + ) + ) + ) + ) + ) + ) + (princ (ssg-textf "gr-tr-ende" (list (itoa anzahl)))) + (princ) +) + +;; ============================================================ +;; TRAEGER-BESCHRIFTUNG +;; ============================================================ +;; Eigenes TEXT-Objekt neben dem Block, z.B. "RT 80/80 L=2650". Es wird +;; AUSSCHLIESSLICH aus dem fertigen Block abgeleitet (Einfuegepunkt, Drehung, +;; Attribute LAENGE und VARIANTE) - darum nutzen das Einfuegen und +;; GERUEST_TRAEGER_BESCHRIFTEN dieselbe Funktion, und ein von Hand +;; verschobener/gedrehter Traeger wird beim Neubeschriften korrekt erfasst. +;; Der Text traegt per XDATA (*geruest-beschr-app*, 1005) den Handle seines +;; Blocks; so wird er beim Neubeschriften ersetzt statt verdoppelt. +;; +;; Formatierung aus geruest.json, "beschriftung" (Variante vor Baugruppe, je +;; Feld): NUR stil, ausrichtung, hoehe - alles andere regelt der Textstil +;; ausserhalb (es wird kein Stil angelegt). Dazu Inhalt (format/text) und +;; Layer. + +;; Winkel auf [0, 2pi) normieren. +(defun geruest-winkel-norm (w) + (setq w (rem w (* 2.0 pi))) + (if (< w 0.0) (+ w (* 2.0 pi)) w) +) + +;; Textwinkel entlang des Traegers nach DIN-Konvention (lesbar von unten und +;; von rechts): fuer 90 < w <= 270 Grad um 180 Grad gedreht, sonst w. +(defun geruest-text-winkel (w / e) + (setq w (geruest-winkel-norm w) e 1e-9) + (if (and (> w (+ (/ pi 2.0) e)) (<= w (+ (* 1.5 pi) e))) + (geruest-winkel-norm (+ w pi)) + w + ) +) + +;; Ausrichtungs-Code wie bei TEXT "Ausrichten" (T/M/B + L/C/R, z.B. "BC") -> +;; (dxf72 dxf73), nil bei unbekanntem Code. +(defun geruest-ausrichtung-codes (code / h v) + (if (and code (= (type code) 'STR) (= (strlen code) 2)) + (progn + (setq code (strcase code)) + (setq v (cdr (assoc (substr code 1 1) '(("T" . 3) ("M" . 2) ("B" . 1))))) + (setq h (cdr (assoc (substr code 2 1) '(("L" . 0) ("C" . 1) ("R" . 2))))) + (if (and v h) (list h v)) + ) + ) +) + +;; Lage des Textes: (punkt textwinkel dxf72 dxf73). p0 = Traeger-Startpunkt, +;; w = Traegerwinkel, laenge = Traegerlaenge. Der Bezugspunkt liegt auf der +;; Linie: L = in Leserichtung linkes Ende, C = Mitte, R = rechtes Ende. Nach +;; einer 180-Grad-Drehung ist "links" also das Linienende. Unbekannter Code +;; -> BC (die Meldung gibt der Aufrufer aus). +(defun geruest-traeger-text-lage (p0 w laenge code / codes tw p1 links rechts pt) + (setq codes (geruest-ausrichtung-codes code)) + (if (null codes) (setq codes '(1 1))) + (setq tw (geruest-text-winkel w)) + (setq p1 (polar p0 w laenge)) + ;; Projektion auf die Leserichtung entscheidet, welches Ende links liegt + (if (<= (+ (* (car p0) (cos tw)) (* (cadr p0) (sin tw))) + (+ (* (car p1) (cos tw)) (* (cadr p1) (sin tw)))) + (setq links p0 rechts p1) + (setq links p1 rechts p0) + ) + (setq pt (cond ((= (car codes) 0) links) + ((= (car codes) 2) rechts) + (T (polar p0 w (/ laenge 2.0))))) + (list pt tw (car codes) (cadr codes)) +) + +;; Alle Vorkommen von alt in s durch neu ersetzen. +(defun geruest-string-ersetzen (s alt neu / pos) + (setq pos (vl-string-search alt s)) + (while pos + (setq s (strcat (substr s 1 pos) neu (substr s (+ pos (strlen alt) 1)))) + (setq pos (vl-string-search alt s (+ pos (strlen neu)))) + ) + s +) + +;; Beschriftungstext: %1 = Text der Variante, %2 = Laenge auf ganze mm. +(defun geruest-traeger-text-string (fmt txt laenge) + (geruest-string-ersetzen + (geruest-string-ersetzen fmt "%1" txt) + "%2" (itoa (fix (+ laenge 0.5)))) +) + +;; Beschriftungs-Konfiguration als Alist (format text stil ausrichtung hoehe +;; layer), je Feld Variante vor Baugruppe vor Code-Standard. Fehlt "text", +;; gilt der Variantenname bzw. ersatz-text (Block ohne bekannte Variante). +;; stil/layer = nil -> aktueller Textstil/Layer. +(defun geruest-traeger-beschr-cfg (variante bg ersatz-text / txt h) + (setq txt (geruest-beschr-feld variante bg "text")) + (if (not (and txt (= (type txt) 'STR) (/= txt ""))) + (setq txt (if variante (geruest-eintrag-name variante) ersatz-text))) + (setq h (geruest-beschr-feld variante bg "hoehe")) + (list (cons "format" (cond ((geruest-beschr-feld variante bg "format")) ("%1 L=%2"))) + (cons "text" (if txt txt "")) + (cons "stil" (geruest-beschr-feld variante bg "stil")) + (cons "ausrichtung" (cond ((geruest-beschr-feld variante bg "ausrichtung")) ("BC"))) + (cons "hoehe" (if (numberp h) (float h) 50.0)) + (cons "layer" (geruest-beschr-feld variante bg "layer"))) +) + +(defun geruest-beschr-feld (variante bg feld) + (geruest-obj-feld variante bg '("beschriftung") feld) +) + +;; Handle des Traeger-Blocks aus der XDATA einer Beschriftung (oder nil). +(defun geruest-beschr-handle (ent / xd) + (setq xd (cadr (assoc -3 (entget ent (list *geruest-beschr-app*))))) + (if xd (cdr (assoc 1005 (cdr xd)))) +) + +;; Alle Beschriftungen der Zeichnung (Auswahlsatz oder nil). +(defun geruest-beschr-alle ( / ) + (ssget "_X" (list '(0 . "TEXT") (list -3 (list *geruest-beschr-app*)))) +) + +;; Beschriftung(en) zu einem Block-Handle loeschen. +(defun geruest-beschr-entfernen (handle / ss i e) + (if (and handle (setq ss (geruest-beschr-alle))) + (progn + (setq i 0) + (repeat (sslength ss) + (setq e (ssname ss i)) + (if (equal (geruest-beschr-handle e) handle) (entdel e)) + (setq i (1+ i)) + ) + ) + ) +) + +;; Textstil pruefen: vorhanden -> Name, sonst einmal je Lauf melden und den +;; aktuellen TEXTSTYLE nehmen. *geruest-beschr-gemeldet* setzt der Aufrufer +;; je Lauf zurueck. +(defun geruest-beschr-stil (stil / ) + (cond + ((and stil (/= stil "") (tblsearch "STYLE" stil)) stil) + (T + (if (and stil (/= stil "") (not (member stil *geruest-beschr-gemeldet*))) + (progn + (princ (ssg-textf "gr-tr-beschr-stil-fehlt" (list stil (getvar "TEXTSTYLE")))) + (setq *geruest-beschr-gemeldet* (cons stil *geruest-beschr-gemeldet*)) + ) + ) + (getvar "TEXTSTYLE") + ) + ) +) + +;; Einen Traeger-Block beschriften (eine evtl. vorhandene Beschriftung wird +;; ersetzt). Rueckgabe: "ok", "ersatz" (Block ohne bekannte VARIANTE, mit den +;; Vorgaben der Baugruppe beschriftet) oder nil (nicht beschriftbar). +(defun geruest-traeger-beschriften (blockEnt / ed attribs bg vname idx variante + cfg laenge lage lay handle code erg) + (setq ed (entget blockEnt)) + (setq attribs (ssg-attrib-read blockEnt)) + (setq bg (geruest-baugruppe "Traeger")) + (setq laenge (atof (cond ((cdr (assoc "LAENGE" attribs))) ("0")))) + (if (and bg (> laenge 0.0)) + (progn + (setq vname (cdr (assoc "VARIANTE" attribs))) + (setq idx (if (and vname (/= vname "")) + (geruest-name-index vname (ssg-json-get bg "geometrie_varianten")))) + (setq variante (if idx (nth idx (ssg-json-get bg "geometrie_varianten")))) + (setq cfg (geruest-traeger-beschr-cfg variante bg + (cond ((cdr (assoc "TEILEART" attribs))) ("")))) + (setq code (cdr (assoc "ausrichtung" cfg))) + (if (and (null (geruest-ausrichtung-codes code)) + (not (member code *geruest-beschr-gemeldet*))) + (progn + (princ (ssg-textf "gr-tr-beschr-ausrichtung" (list code))) + (setq *geruest-beschr-gemeldet* (cons code *geruest-beschr-gemeldet*)) + ) + ) + (setq lage (geruest-traeger-text-lage (cdr (assoc 10 ed)) (cdr (assoc 50 ed)) + laenge code)) + (setq lay (cdr (assoc "layer" cfg))) + (if (and lay (/= lay "")) + (ssg-make-layer lay (ssg-layer-farbe-fuer-name lay) nil) + (setq lay (getvar "CLAYER")) + ) + (setq handle (cdr (assoc 5 ed))) + (geruest-beschr-entfernen handle) + (if (not (tblsearch "APPID" *geruest-beschr-app*)) (regapp *geruest-beschr-app*)) + ;; 73 ist immer >= 1, damit gilt Gruppe 11 als Ausrichtungspunkt + (if (entmake (list '(0 . "TEXT") + (cons 8 lay) + (cons 7 (geruest-beschr-stil (cdr (assoc "stil" cfg)))) + (cons 10 (nth 0 lage)) + (cons 11 (nth 0 lage)) + (cons 40 (cdr (assoc "hoehe" cfg))) + (cons 1 (geruest-traeger-text-string + (cdr (assoc "format" cfg)) + (cdr (assoc "text" cfg)) laenge)) + (cons 50 (nth 1 lage)) + (cons 72 (nth 2 lage)) + (cons 73 (nth 3 lage)) + (list -3 (list *geruest-beschr-app* (cons 1005 handle))))) + (setq erg (if variante "ok" "ersatz")) + ) + ) + ) + erg +) + +;; Alle Traeger der Zeichnung (neu) beschriften und Beschriftungen, deren +;; Block nicht mehr existiert, entfernen - unabhaengig von der Checkbox im +;; Einfuegedialog. +(defun c:GERUEST_TRAEGER_BESCHRIFTEN ( / ss i n-ok n-ersatz n-fehl n-weg e h ziel erg) + (setq *geruest-beschr-gemeldet* nil) + (setq n-ok 0 n-ersatz 0 n-fehl 0 n-weg 0) + (ssg-start nil nil) + ;; Verwaiste Beschriftungen zuerst entfernen + (if (setq ss (geruest-beschr-alle)) + (progn + (setq i 0) + (repeat (sslength ss) + (setq e (ssname ss i)) + (setq h (geruest-beschr-handle e)) + (setq ziel (if h (handent h))) + (if (not (and ziel (entget ziel) + (= (cdr (assoc 0 (entget ziel))) "INSERT"))) + (progn (entdel e) (setq n-weg (1+ n-weg))) + ) + (setq i (1+ i)) + ) + ) + ) + (if (setq ss (ssget "_X" '((0 . "INSERT") (2 . "GR_Traeger_*")))) + (progn + (setq i 0) + (repeat (sslength ss) + (setq erg (geruest-traeger-beschriften (ssname ss i))) + (cond ((= erg "ok") (setq n-ok (1+ n-ok))) + ((= erg "ersatz") (setq n-ersatz (1+ n-ersatz))) + (T (setq n-fehl (1+ n-fehl)))) + (setq i (1+ i)) + ) + (princ (ssg-textf "gr-tr-beschr-ergebnis" + (list (itoa (+ n-ok n-ersatz)) (itoa n-ersatz) (itoa n-fehl) (itoa n-weg)))) + ) + (princ (ssg-text "gr-tr-beschr-keine")) + ) + (ssg-end) + (princ) +) + +(defun c:GERUEST_TRAEGER ( / bg wahl) + (setq bg (geruest-baugruppe "Traeger")) + (cond + ((null bg) + (princ (ssg-textf "gr-fehler-baugruppe" (list "Traeger")))) + ((null (ssg-json-get bg "geometrie_varianten")) + (princ (ssg-textf "gr-fehler-keine-varianten" (list "Traeger")))) + ((null (setq wahl (geruest-traeger-dialog bg))) + (princ (ssg-text "gr-abgebrochen"))) + (T (geruest-traeger-einfuegen bg wahl)) + ) + (princ) +) + +(princ "\nGeruestInsert.lsp geladen. Befehle: GERUEST, GERUEST_SAEULEN, GERUEST_ROHRABHAENGER, GERUEST_WANDBEFESTIGUNG, GERUEST_TRAEGER, GERUEST_TRAEGER_BESCHRIFTEN") (princ) diff --git a/data/geruest/R2-Saeule_dummy.dwg b/data/geruest/R2-Saeule_dummy.dwg index 7c508280971c1a05dd3d246ee202c691458fb249..d3b446c1615c2570a19707314d62317202423d36 100644 GIT binary patch delta 5747 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

t$izDi48^oh?)^=kuG9vWmv82VyiiO?DsP!G74l zJbV5_Tu1D?jr9DhQw4XI+OB`QEf@-p8f2|YlfZ#8L;@8o)`4DJaJDqqvFrNT5 zeCcg{%*Nc$_g=m}-Snxj>D>E*!GZ6EPu`q;BI2**OU)Km(vHxHFu^h;0=5UqVb1C~ zPx{|iEtLx$QcD-YrEva0&fFiRXDd^LQ=dsixY)}?I%?$#URu5}b#^0N!J8>}MB%bP zCeL9z&H%aX4E77F^&*!g19kla?PWcPPDa75M{Kx5Wv~4CczX6Mj~T&Q_sU94)1Bnr zN&)4|V#k4uueGC}W?oVCv&1(Kn(Bo;n8baDbj{tI?e-glN$Xo}*|CS$!|9lek;h&) z_T1q=A0N(k_a$$X&z(-5d4BrEJ?76F^S7J(s|L#_U!Q$FdGEAv7{lG&ZI8C~g&XzB zk_>|&PD@3P%^BlA-k&L%iXZ!U`d#Hn?5|i+GqzLmy4IOD)>#1=nyi&Jm-Au61Lp2- zGCAW_!X9j4dPY0=LNxNq8i)JGi{@$@Kd!&n9oO3Zt~;r{c&NX4?p@(49#_>1%olN= zIv)u7p3uH5>aXDEm@1U|ZKdYRQdROKYwp46(P&98vJYpVTDFwAibepWZ#}tN$I9M8 zDZTsF$aH(kubMCYZ@*t_T^Fd6|GQX}LeKlzeEsYF>B`#GxP{`Ew-a7<7dEBLeE9z7 zK|(u^wd2;*ziTFwo~;kGG&rPo%tfE!mv-~+Vxbh()6ssnGhb@!?G4tXEOE*uAwPB7 zO=kO~gY1=5eBAapVwRbbC$-37)VvMBMh7|eYz@^v5T)U-e85rZ()6{FTf#d@rqIfn zz*O+kHzxXpY%$(S-0Q@v6s5+vxcV+>K7MRYHiCc6qWy5WE5btC!9n^rHUOsKKgT=3 z@H8V6cf7(Bw8Kyjw_pU^CoV1cP@EjfhJU$okVKd`LGa#-@5mPAIc<2KYu{EG?fMq? zT|)R@**jqr-jFQ{oACG9E|4GB%2A|l=RHVIL^c+Oux5L$Jeuyjh%n0C|Lvd&;;}h$ X+}05D&_>w`DrqguZ$|$O=(_tc diff --git a/data/geruest/dummy_Muffe_1zoll.dwg b/data/geruest/dummy_Muffe_1zoll.dwg new file mode 100644 index 0000000000000000000000000000000000000000..0e6da7551f5c248849aa76f4f717ed3d9f73bb18 GIT binary patch literal 17473 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: ", + "gr-tr-prompt-ende": "\nEndpunkt waehlen oder Laenge (mm) eingeben: ", + "gr-tr-prompt-richtung": "\nRichtung angeben <0>: ", + "gr-tr-eingabe-ungueltig": "\nEingabe '%1' ist weder Punkt noch Laenge.", + "gr-tr-laenge-null": "\nStrecke %1 mm ist nicht laenger als die Abzuege (%2 mm) - kein Traeger eingefuegt.", + "gr-tr-laenge-bereich": "\nTraegerlaenge %1 mm ausserhalb des erlaubten Bereichs %2 bis %3 mm - kein Traeger eingefuegt.", + "gr-tr-fertig": "\nTraeger %1 mm eingefuegt (Block %2).", + "gr-tr-ende": "\n%1 Traeger eingefuegt.", + "gr-tr-bez-abzug-anfang": "Abzug Anfang %1 mm", + "gr-tr-bez-abzug-ende": "Abzug Ende %1 mm", + "gr-tr-beschr-stil-fehlt": "\nTextstil %1 fehlt in der Zeichnung - Beschriftung mit aktuellem Stil %2.", + "gr-tr-beschr-ausrichtung": "\nUnbekannte Ausrichtung %1 fuer die Traeger-Beschriftung - verwende BC.", + "gr-tr-beschr-ergebnis": "\n%1 Traeger beschriftet (davon %2 ohne bekannte Variante), %3 nicht beschriftbar, %4 verwaiste Beschriftungen entfernt.", + "gr-tr-beschr-keine": "\nKeine Rohr-Geruest-Traeger in der Zeichnung." } } diff --git a/lang/en_GB.json b/lang/en_GB.json index bea946d..95a93e9 100644 --- a/lang/en_GB.json +++ b/lang/en_GB.json @@ -1022,6 +1022,23 @@ "gr-konfig-teil-unbekannt": "\nScaffold: add-on part '%1' from configuration '%2' is unknown for this assembly - skipped.", "gr-konfig-variante-unbekannt": "\nScaffold: variant '%1' from configuration '%2' is unknown for this assembly - selection unchanged.", "gr-fehler-schreiben": "\nScaffold: could not write file: %1", - "gr-fehler-keine-baugruppen": "\nScaffold: the data file contains no assemblies." + "gr-fehler-keine-baugruppen": "\nScaffold: the data file contains no assemblies.", + "gr-tr-fehler-dcl": "Dialog %1 could not be loaded.", + "gr-tr-hinweis": "The length is defined in the drawing after OK.", + "gr-tr-alert-abzug": "Invalid length deduction. Allowed is a number from 0 (mm); an empty field counts as 0.", + "gr-tr-prompt-start": "\nSelect start point of the beam : ", + "gr-tr-prompt-ende": "\nSelect end point or enter length (mm): ", + "gr-tr-prompt-richtung": "\nSpecify direction <0>: ", + "gr-tr-eingabe-ungueltig": "\nInput '%1' is neither a point nor a length.", + "gr-tr-laenge-null": "\nDistance %1 mm is not longer than the deductions (%2 mm) - no beam inserted.", + "gr-tr-laenge-bereich": "\nBeam length %1 mm outside the allowed range %2 to %3 mm - no beam inserted.", + "gr-tr-fertig": "\nBeam %1 mm inserted (block %2).", + "gr-tr-ende": "\n%1 beam(s) inserted.", + "gr-tr-bez-abzug-anfang": "Deduction start %1 mm", + "gr-tr-bez-abzug-ende": "Deduction end %1 mm", + "gr-tr-beschr-stil-fehlt": "\nText style %1 missing in drawing - labelling with current style %2.", + "gr-tr-beschr-ausrichtung": "\nUnknown justification %1 for beam label - using BC.", + "gr-tr-beschr-ergebnis": "\n%1 beam(s) labelled (%2 without known variant), %3 not labellable, %4 orphaned label(s) removed.", + "gr-tr-beschr-keine": "\nNo pipe scaffold beams in the drawing." } } diff --git a/lib/export_csv.py b/lib/export_csv.py index e6e98ed..295f88a 100644 --- a/lib/export_csv.py +++ b/lib/export_csv.py @@ -319,16 +319,25 @@ def build_geruest_merkmale(block): 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.""" + bezeichnung ueben in process_blocks unten), TEILEART/TEILEFARBE/LAYER + bleiben als Rest-Attribute in der Merkmale-JSON-Spalte - so wie bei + Separator/Scanner/BTMT bereits ueblich. + + Die Laengenabzuege gibt es nur beim Rohr-Geruest-Traeger + (*geruest-traeger-attrib-defs*) und erscheinen darum nur, wenn der Block + sie traegt - die Merkmale der anderen GR_-Bloecke bleiben unveraendert.""" attribs = block.get("attribs", {}) - return { + merkmale = { "TeileArt": attribs.get("TEILEART", ""), - "Farbe": attribs.get("FARBE", ""), + "Farbe": attribs.get("TEILEFARBE", ""), "Laenge": attribs.get("LAENGE", ""), "Layer": attribs.get("LAYER", ""), } + for tag, name in (("LAENGENABZUGANFANG", "LaengenabzugAnfang"), + ("LAENGENABZUGENDE", "LaengenabzugEnde")): + if tag in attribs: + merkmale[name] = attribs[tag] + return merkmale def format_sensor_id(prefix, n): diff --git a/menu/SSG_LIB.cui b/menu/SSG_LIB.cui index 8299faa..0cd7164 100644 --- a/menu/SSG_LIB.cui +++ b/menu/SSG_LIB.cui @@ -539,7 +539,7 @@ Rohr-Geruest-Traeger - ^C^C(ssg-ensure "GeruestInsert") GERUEST + ^C^C(ssg-ensure "GeruestInsert") GERUEST_TRAEGER @@ -560,211 +560,223 @@ ^C^C(ssg-ensure "GeruestInsert") GERUEST_WANDBEFESTIGUNG - + + + Gattertraeger + ^C^C(ssg-ensure "GeruestInsert") GERUEST + + + + + Traeger beschriften + ^C^C(ssg-ensure "GeruestInsert") GERUEST_TRAEGER_BESCHRIFTEN + + + Marker einfuegen ^C^C(ssg-ensure "Tro_Edit") TRO_INSERT - + Marker bearbeiten ^C^C(ssg-ensure "Tro_Edit") TRO_EDIT - + Bearbeiten (Auto) ^C^C(ssg-ensure "SSG_LIB_Commands") SSG_BLOCKEDIT - + Verbindung einfuegen ^C^C(ssg-ensure "Connection_Edit") CONNECTION_INSERT - + Verbindung bearbeiten ^C^C(ssg-ensure "Connection_Edit") CONNECTION_EDIT - + Eingang ^C^C(ssg-ensure "SSG_LIB_Commands") ILS_EINGANG_INSERT - + Ausgang ^C^C(ssg-ensure "SSG_LIB_Commands") ILS_AUSGANG_INSERT - + SPS Schliessen ^C^C - + Export Sivas ^C^C(ssg-ensure "export") EXPORTSIVAS - + Export CSV ^C^C(ssg-ensure "export") EXPORTCSV - + Umschalten 2D und 3D ^C^C(ssg-ensure "SSG_LIB_Commands") SSG_DIM_SWITCH - + Alle Bloecke auf 2D ^C^C(ssg-ensure "SSG_LIB_Commands") SSG_DIM_ALL_2D - + Alle Bloecke auf 3D ^C^C(ssg-ensure "SSG_LIB_Commands") SSG_DIM_ALL_3D - + Sprache ^C^C(ssg-ensure "SSG_LIB_Commands") SSG_SPRACHE - + Planquadrate an/aus ^C^C(ssg-ensure "DrawPlanquadrate") PLANQUADRATE_TOGGLE - + CSV-Export ^C^C(ssg-ensure "export") CSV_EXPORT_KONFIG - + 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 @@ -782,10 +794,10 @@ - - - - + + + + ILS @@ -1413,249 +1425,259 @@ Gattertraeger - + + + + + + + Funktionen + + Traeger beschriften + + - + SPS - - + + Eingang - + 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 + + + Konfiguration - Alle Bloecke auf 2D - - - - - - Alle Bloecke auf 3D + Umschalten 2D und 3D - Sprache + Alle Bloecke auf 2D - Planquadrate an/aus + Alle Bloecke auf 3D - CSV-Export + Sprache + + 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 ac9369e..578eece 100644 --- a/menu/SSG_LIB.mnu +++ b/menu/SSG_LIB.mnu @@ -112,11 +112,13 @@ [<-~APBW 110 R550/67,5 58x497]^C^C(ssg-ensure "OmniModulInsert") OMNI_APBW_R550_675_58 [<-Element bearbeiten]^C^C(ssg-ensure "OmniModulInsert") OMNI_EDIT [->Geruest]^C^C(ssg-ensure "GeruestInsert") GERUEST -[Rohr-Geruest-Traeger]^C^C(ssg-ensure "GeruestInsert") GERUEST +[Rohr-Geruest-Traeger]^C^C(ssg-ensure "GeruestInsert") GERUEST_TRAEGER [Saeulen]^C^C(ssg-ensure "GeruestInsert") GERUEST_SAEULEN [Rohrabhaenger]^C^C(ssg-ensure "GeruestInsert") GERUEST_ROHRABHAENGER [Wandbefestigung]^C^C(ssg-ensure "GeruestInsert") GERUEST_WANDBEFESTIGUNG -[<-Gattertraeger]^C^C(ssg-ensure "GeruestInsert") GERUEST +[Gattertraeger]^C^C(ssg-ensure "GeruestInsert") GERUEST +[->Funktionen] +[<-<-Traeger beschriften]^C^C(ssg-ensure "GeruestInsert") GERUEST_TRAEGER_BESCHRIFTEN [->SPS] [->TRO] [Marker einfuegen]^C^C(ssg-ensure "Tro_Edit") TRO_INSERT diff --git a/tests/test_unit.lsp b/tests/test_unit.lsp index 8991c61..23d0ef2 100644 --- a/tests/test_unit.lsp +++ b/tests/test_unit.lsp @@ -754,9 +754,9 @@ (if (findfile _datei) (progn (setq _daten (ssg-json-laden _datei)) - ;; Drei Bereiche: Rohrabhaenger, Saeulen (1 und 2 Zoll zusammengefuehrt), - ;; Wandbefestigung - (tu-eq "json/geruest-baugruppen" 3 (length _daten)) + ;; Vier Baugruppen: Rohrabhaenger, Saeulen (1 und 2 Zoll + ;; zusammengefuehrt), Wandbefestigung, Rohr-Geruest-Traeger + (tu-eq "json/geruest-baugruppen" 4 (length _daten)) ;; Baugruppe ueber das ASCII-Feld "id" finden (aeusserer Schluessel ;; traegt Umlaute bzw. Anfuehrungszeichen) (setq _bg nil) @@ -773,11 +773,16 @@ (ssg-json-get _bg "teileart")) (tu-eq "json/geruest-dummy" "Rohrabhaenger_dummy.dwg" (ssg-json-get _bg "dummy")) - ;; Sivas-ID als Zahl geparst, Laengengrenze aus dem attribute-Block + ;; Sivas-ID als Zahl geparst, Laengengrenze aus dem attribute-Block. + ;; Die Keys unter "attribute" sind die Block-Attribut-Tags und darum + ;; GROSS geschrieben (ssg-json-get unterscheidet Gross/Klein). (tu-eq "json/geruest-sivas" 821006026 (ssg-json-get (car (ssg-json-get (car _var) "teile")) "sivas_id")) (tu-eq "json/geruest-max" 6000 - (ssg-json-get (ssg-json-get (ssg-json-get _bg "attribute") "Laenge") "max")) + (ssg-json-get (ssg-json-get (ssg-json-get _bg "attribute") "LAENGE") "max")) + (tu-eq "json/geruest-farboptionen" '("RAL7035" "RAL7030") + (ssg-json-get (ssg-json-get (ssg-json-get _bg "attribute") "TEILEFARBE") + "optionen")) ) ) ) @@ -978,6 +983,245 @@ (geruest-variante-wert (nth _rec (ssg-json-get _saeulen "geometrie_varianten")) _saeulen "teileart"))) + ;; Attribut-Keys GROSS - sonst findet geruest-dialog min/max und + ;; Farben nicht (Laengenfeld ohne Pruefung, leere Farbliste). + (tu-eq "geruest/saeulen-laenge-max" 6000 + (geruest-attr-feld nil _saeulen "LAENGE" "max")) + (tu-true "geruest/saeulen-farboptionen" + (geruest-attr-feld nil _saeulen "TEILEFARBE" "optionen")) + ) + ) + + ;; --- Rohr-Geruest-Traeger: reine Berechnung --- + ;; Netto-Laenge = Strecke minus beide Abzuege, nil wenn nichts uebrig + (tu-eqf "geruest-traeger-laenge/ende" 965.0 (geruest-traeger-laenge 1000.0 0.0 35.0)) + (tu-eqf "geruest-traeger-laenge/beide" 945.0 (geruest-traeger-laenge 1000.0 20.0 35.0)) + (tu-eqf "geruest-traeger-laenge/ohne" 1000.0 (geruest-traeger-laenge 1000.0 nil nil)) + (tu-nil "geruest-traeger-laenge/zu-kurz" (geruest-traeger-laenge 50.0 30.0 30.0)) + (tu-nil "geruest-traeger-laenge/genau-null" (geruest-traeger-laenge 60.0 30.0 30.0)) + ;; Startpunkt wird um den Anfangsabzug entlang der Richtung eingerueckt, + ;; Z bleibt die des Startklicks + (tu-eqf "geruest-traeger-start/0grad" '(20.0 0.0 500.0) + (geruest-traeger-start '(0.0 0.0 500.0) 0.0 20.0)) + (tu-eqf "geruest-traeger-start/90grad" '(100.0 220.0 0.0) + (geruest-traeger-start '(100.0 200.0 0.0) (/ pi 2.0) 20.0)) + (tu-eqf "geruest-traeger-start/2d-punkt" '(5.0 0.0 0.0) + (geruest-traeger-start '(5.0 0.0) 0.0 0.0)) + ;; Querstreben: Abstand max. 500, Rand 100..250 beidseitig gleich, + ;; so wenige wie moeglich + ;; Abstand genau 500, solange der Rand in 100..250 bleibt + (tu-eqf "geruest-traeger-streben/1200" '(100.0 600.0 1100.0) + (geruest-traeger-streben 1200.0 500.0 100.0 250.0)) + (tu-eqf "geruest-traeger-streben/1300" '(150.0 650.0 1150.0) + (geruest-traeger-streben 1300.0 500.0 100.0 250.0)) + ;; 1100 geht mit genau 500 nicht auf -> Rand 100, Abstand 450 + (tu-eqf "geruest-traeger-streben/1100" '(100.0 550.0 1000.0) + (geruest-traeger-streben 1100.0 500.0 100.0 250.0)) + (tu-eqf "geruest-traeger-streben/1500" '(250.0 750.0 1250.0) + (geruest-traeger-streben 1500.0 500.0 100.0 250.0)) + (tu-eqf "geruest-traeger-streben/1000" '(250.0 750.0) + (geruest-traeger-streben 1000.0 500.0 100.0 250.0)) + (tu-eqf "geruest-traeger-streben/eine" '(200.0) + (geruest-traeger-streben 400.0 500.0 100.0 250.0)) + (tu-eqf "geruest-traeger-streben/grenze-500" '(250.0) + (geruest-traeger-streben 500.0 500.0 100.0 250.0)) + (tu-eqf "geruest-traeger-streben/501" '(100.0 401.0) + (geruest-traeger-streben 501.0 500.0 100.0 250.0)) + (tu-nil "geruest-traeger-streben/zu-kurz" + (geruest-traeger-streben 150.0 500.0 100.0 250.0)) + (tu-eqf "geruest-traeger-streben/min-200" '(100.0) + (geruest-traeger-streben 200.0 500.0 100.0 250.0)) + ;; 6000 mm: 11 Felder a 500 -> 12 Streben, letzte bei 5750 + (setq _rec (geruest-traeger-streben 6000.0 500.0 100.0 250.0)) + (tu-eq "geruest-traeger-streben/6000-anzahl" 12 (length _rec)) + (tu-eqf "geruest-traeger-streben/6000-letzte" 5750.0 (last _rec)) + ;; Konfiguration: fehlende Felder -> Standard, ohne querstrebe -> nil + ;; Ergebnis (dummy laenge querlinie abstand-max rand-min rand-max) + (tu-eqf "geruest-traeger-strebe-cfg/standard" '(nil 30.0 25.0 500.0 100.0 250.0) + (geruest-traeger-strebe-cfg nil + (ssg-json-parse "{\"querstrebe\": {\"rand_min\": 100}}"))) + (tu-eqf "geruest-traeger-strebe-cfg/dummy" '("s.dwg" 30.0 25.0 500.0 100.0 250.0) + (geruest-traeger-strebe-cfg nil + (ssg-json-parse "{\"querstrebe\": {\"dummy\": \"s.dwg\"}}"))) + (tu-eqf "geruest-traeger-strebe-cfg/wert" '(nil 30.0 25.0 400.0 100.0 250.0) + (geruest-traeger-strebe-cfg nil + (ssg-json-parse "{\"querstrebe\": {\"abstand_max\": 400}}"))) + ;; Querlinien an Anfang und Ende der 30 mm langen Strebe + (tu-eqf "geruest-traeger-strebe-enden" '(235.0 265.0) + (geruest-traeger-strebe-enden 250.0 30.0)) + (tu-nil "geruest-traeger-strebe-cfg/ohne" + (geruest-traeger-strebe-cfg nil (ssg-json-parse "{\"id\": \"X\"}"))) + ;; Muffe nur bei "mit_muffe": true; Variante darf eigene Muffe mitbringen + (setq _bgtest (ssg-json-parse "{\"muffe\": {\"dummy\": \"m.dwg\"}}")) + (tu-eq "geruest-traeger-muffe-dummy/flag" "m.dwg" + (geruest-traeger-muffe-dummy + (ssg-json-parse "{\"name\": \"A\", \"mit_muffe\": true}") _bgtest)) + (tu-nil "geruest-traeger-muffe-dummy/ohne-flag" + (geruest-traeger-muffe-dummy + (ssg-json-parse "{\"name\": \"Rohr mit Muffe\"}") _bgtest)) + (tu-eq "geruest-traeger-muffe-dummy/variante" "m2.dwg" + (geruest-traeger-muffe-dummy + (ssg-json-parse + "{\"mit_muffe\": true, \"muffe\": {\"dummy\": \"m2.dwg\"}}") + _bgtest)) + (tu-nil "geruest-traeger-muffe-dummy/ohne-variante" + (geruest-traeger-muffe-dummy nil _bgtest)) + + ;; --- Traeger-Beschriftung: reine Berechnung --- + ;; Textwinkel entlang des Traegers, DIN: 90 < w <= 270 wird gedreht + (tu-eqf "geruest-text-winkel/0" 0.0 (geruest-text-winkel 0.0)) + (tu-eqf "geruest-text-winkel/45" (/ pi 4.0) (geruest-text-winkel (/ pi 4.0))) + (tu-eqf "geruest-text-winkel/90" (/ pi 2.0) (geruest-text-winkel (/ pi 2.0))) + (tu-eqf "geruest-text-winkel/91" (* 271 (/ pi 180.0)) + (geruest-text-winkel (* 91 (/ pi 180.0)))) + (tu-eqf "geruest-text-winkel/180" 0.0 (geruest-text-winkel pi)) + (tu-eqf "geruest-text-winkel/270" (/ pi 2.0) (geruest-text-winkel (* 1.5 pi))) + (tu-eqf "geruest-text-winkel/271" (* 271 (/ pi 180.0)) + (geruest-text-winkel (* 271 (/ pi 180.0)))) + ;; -90 = 270 -> gedreht auf 90 (von unten nach oben lesbar) + (tu-eqf "geruest-text-winkel/-90" (/ pi 2.0) (geruest-text-winkel (- (/ pi 2.0)))) + ;; Ausrichtungs-Codes wie TEXT "Ausrichten" -> (dxf72 dxf73) + (tu-eq "geruest-ausrichtung/TL" '(0 3) (geruest-ausrichtung-codes "TL")) + (tu-eq "geruest-ausrichtung/TC" '(1 3) (geruest-ausrichtung-codes "TC")) + (tu-eq "geruest-ausrichtung/TR" '(2 3) (geruest-ausrichtung-codes "TR")) + (tu-eq "geruest-ausrichtung/ML" '(0 2) (geruest-ausrichtung-codes "ML")) + (tu-eq "geruest-ausrichtung/MC" '(1 2) (geruest-ausrichtung-codes "MC")) + (tu-eq "geruest-ausrichtung/MR" '(2 2) (geruest-ausrichtung-codes "MR")) + (tu-eq "geruest-ausrichtung/BL" '(0 1) (geruest-ausrichtung-codes "BL")) + (tu-eq "geruest-ausrichtung/BC" '(1 1) (geruest-ausrichtung-codes "BC")) + (tu-eq "geruest-ausrichtung/BR" '(2 1) (geruest-ausrichtung-codes "BR")) + (tu-eq "geruest-ausrichtung/klein" '(1 1) (geruest-ausrichtung-codes "bc")) + (tu-nil "geruest-ausrichtung/unbekannt" (geruest-ausrichtung-codes "XY")) + (tu-nil "geruest-ausrichtung/nil" (geruest-ausrichtung-codes nil)) + ;; Textlage: Bezugspunkt auf der Linie, "links" in Leserichtung + (tu-eqf "geruest-text-lage/0-BC" '((1000.0 0.0 0.0) 0.0 1 1) + (geruest-traeger-text-lage '(0.0 0.0 0.0) 0.0 2000.0 "BC")) + (tu-eqf "geruest-text-lage/0-BL" '((0.0 0.0 0.0) 0.0 0 1) + (geruest-traeger-text-lage '(0.0 0.0 0.0) 0.0 2000.0 "BL")) + (tu-eqf "geruest-text-lage/0-BR" '((2000.0 0.0 0.0) 0.0 2 1) + (geruest-traeger-text-lage '(0.0 0.0 0.0) 0.0 2000.0 "BR")) + ;; Traeger nach links (180): Text gedreht auf 0, links = Linienende + (tu-eqf "geruest-text-lage/180-BL" '((-2000.0 0.0 0.0) 0.0 0 1) + (geruest-traeger-text-lage '(0.0 0.0 0.0) pi 2000.0 "BL")) + (tu-eqf "geruest-text-lage/180-BR" '((0.0 0.0 0.0) 0.0 2 1) + (geruest-traeger-text-lage '(0.0 0.0 0.0) pi 2000.0 "BR")) + (tu-eqf "geruest-text-lage/180-BC" '((-1000.0 0.0 0.0) 0.0 1 1) + (geruest-traeger-text-lage '(0.0 0.0 0.0) pi 2000.0 "BC")) + ;; Unbekannter Code -> BC + (tu-eqf "geruest-text-lage/ersatz" '((1000.0 0.0 0.0) 0.0 1 1) + (geruest-traeger-text-lage '(0.0 0.0 0.0) 0.0 2000.0 "XY")) + ;; Text: %1 = Variantentext, %2 = Laenge auf ganze mm + (tu-eq "geruest-text-string/beispiel" "RT 80/80 L=2650" + (geruest-traeger-text-string "%1 L=%2" "RT 80/80" 2649.5)) + (tu-eq "geruest-text-string/abrunden" "L=965 RT" + (geruest-traeger-text-string "L=%2 %1" "RT" 965.4)) + (tu-eq "geruest-text-string/mehrfach" "A A 10" + (geruest-traeger-text-string "%1 %1 %2" "A" 10.0)) + ;; Konfiguration je Feld: Variante vor Baugruppe vor Code-Standard + (setq _bgtest (ssg-json-parse + (strcat "{\"beschriftung\": {\"format\": \"%1 L=%2\", \"stil\": \"S1\"," + " \"ausrichtung\": \"BC\", \"hoehe\": 50, \"layer\": \"D-5-BEM\"}}"))) + (setq _rec (geruest-traeger-beschr-cfg + (ssg-json-parse + "{\"name\": \"RT 80/80 1 Zoll\", \"beschriftung\": {\"text\": \"RT 80/80\", \"layer\": \"D-6-BEM\"}}") + _bgtest "ERSATZ")) + (tu-eq "geruest-beschr-cfg/text" "RT 80/80" (cdr (assoc "text" _rec))) + (tu-eq "geruest-beschr-cfg/layer" "D-6-BEM" (cdr (assoc "layer" _rec))) + (tu-eq "geruest-beschr-cfg/stil" "S1" (cdr (assoc "stil" _rec))) + (tu-eqf "geruest-beschr-cfg/hoehe" 50.0 (cdr (assoc "hoehe" _rec))) + (setq _rec (geruest-traeger-beschr-cfg + (ssg-json-parse "{\"name\": \"Ohne Text\"}") _bgtest "ERSATZ")) + (tu-eq "geruest-beschr-cfg/text-name" "Ohne Text" (cdr (assoc "text" _rec))) + (tu-eq "geruest-beschr-cfg/layer-bg" "D-5-BEM" (cdr (assoc "layer" _rec))) + (setq _rec (geruest-traeger-beschr-cfg nil (ssg-json-parse "{\"id\": \"X\"}") "ERSATZ")) + (tu-eq "geruest-beschr-cfg/ersatz" "ERSATZ" (cdr (assoc "text" _rec))) + (tu-eq "geruest-beschr-cfg/std-format" "%1 L=%2" (cdr (assoc "format" _rec))) + (tu-eq "geruest-beschr-cfg/std-ausr" "BC" (cdr (assoc "ausrichtung" _rec))) + (tu-eqf "geruest-beschr-cfg/std-hoehe" 50.0 (cdr (assoc "hoehe" _rec))) + (tu-nil "geruest-beschr-cfg/std-layer" (cdr (assoc "layer" _rec))) + ;; Bereichspruefung auf der Netto-Laenge + (tu-true "geruest-traeger-pruefen/innen" (geruest-traeger-pruefen 965.0 0 6000)) + (tu-nil "geruest-traeger-pruefen/ueber" (geruest-traeger-pruefen 6001.0 0 6000)) + (tu-true "geruest-traeger-pruefen/grenze" (geruest-traeger-pruefen 6000.0 0 6000)) + (tu-true "geruest-traeger-pruefen/ohne" (geruest-traeger-pruefen 99999.0 nil nil)) + (tu-nil "geruest-traeger-pruefen/nil" (geruest-traeger-pruefen nil 0 6000)) + ;; Eingaben in mm: Komma wie Punkt, negativ/Text ungueltig + (tu-eqf "geruest-mm-zahl/ganz" 35.0 (geruest-mm-zahl "35")) + (tu-eqf "geruest-mm-zahl/komma" 17.5 (geruest-mm-zahl "17,5")) + (tu-nil "geruest-mm-zahl/text" (geruest-mm-zahl "abc")) + (tu-nil "geruest-mm-zahl/negativ" (geruest-mm-zahl "-5")) + (tu-nil "geruest-mm-zahl/leer" (geruest-mm-zahl "")) + (tu-eqf "geruest-abzug-wert/leer" 0.0 (geruest-abzug-wert "")) + (tu-nil "geruest-abzug-wert/text" (geruest-abzug-wert "x")) + (tu-eqf "geruest-tr-abzug/inaktiv" 0.0 (geruest-tr-abzug "0" "x")) + (tu-eqf "geruest-tr-abzug/aktiv" 35.0 (geruest-tr-abzug "1" "35")) + (tu-eq "geruest-mm-string/ganz" "965" (geruest-mm-string 965.0)) + (tu-eq "geruest-mm-string/dezimal" "17.5" (geruest-mm-string 17.5)) + ;; Variante darf Attribut-Felder ueberschreiben - auch mit false + (setq _bgtest (ssg-json-parse + "{\"attribute\": {\"LAENGENABZUGENDE\": {\"vorgabe\": 35, \"aktiv\": true}}}")) + (tu-eq "geruest-attr-feld/baugruppe" 35 + (geruest-attr-feld nil _bgtest "LAENGENABZUGENDE" "vorgabe")) + (tu-eq "geruest-attr-feld/variante" 50 + (geruest-attr-feld + (ssg-json-parse "{\"attribute\": {\"LAENGENABZUGENDE\": {\"vorgabe\": 50}}}") + _bgtest "LAENGENABZUGENDE" "vorgabe")) + (tu-nil "geruest-attr-feld/variante-false" + (geruest-attr-feld + (ssg-json-parse "{\"attribute\": {\"LAENGENABZUGENDE\": {\"aktiv\": false}}}") + _bgtest "LAENGENABZUGENDE" "aktiv")) + + ;; --- Rohr-Geruest-Traeger in der echten Datendatei --- + ;; Eigener Dialog: im Bereichs-Dropdown von GERUEST darf er fehlen, + ;; ueber geruest-baugruppe muss er aber auffindbar sein. + (setq _rec nil) + (foreach _e (geruest-baugruppen-liste) + (if (equal (car _e) "Traeger") (setq _rec T))) + (tu-nil "geruest/traeger-nicht-im-dropdown" _rec) + (setq _traeger (geruest-baugruppe "Traeger")) + (tu-true "geruest/traeger-vorhanden" _traeger) + (if _traeger + (progn + (tu-eq "geruest/traeger-einfuegeart" "linie" + (ssg-json-get _traeger "einfuegeart")) + (tu-eq "geruest/traeger-varianten-artikel" 0 + (tu-geruest-artikel-unvollstaendig + (ssg-json-get _traeger "geometrie_varianten"))) + (tu-true "geruest/traeger-layer" + (geruest-variante-wert + (car (ssg-json-get _traeger "geometrie_varianten")) + _traeger "layer")) + (tu-eq "geruest/traeger-max" 6000 + (geruest-attr-feld nil _traeger "LAENGE" "max")) + (tu-eqf "geruest/traeger-querstrebe" + '("dummy_Strebe_30x4.dwg" 30.0 25.0 500.0 100.0 250.0) + (geruest-traeger-strebe-cfg nil _traeger)) + ;; Muffen-Flag ausdruecklich je Variante: genau die "mit (2) Muffe(n)" + (setq _rec 0) + (foreach _v (ssg-json-get _traeger "geometrie_varianten") + (if (geruest-traeger-muffe-dummy _v _traeger) (setq _rec (1+ _rec)))) + (tu-eq "geruest/traeger-muffen-varianten" 4 _rec) + ;; Jede Variante definiert Beschriftungstext UND -layer selbst - der + ;; Layer ist je Traegervariante verschieden, eine Vorgabe der + ;; Baugruppe gibt es dafuer bewusst nicht. + (setq _rec 0) + (foreach _v (ssg-json-get _traeger "geometrie_varianten") + (setq _cfg (geruest-traeger-beschr-cfg _v _traeger "")) + (if (and (geruest-obj-feld _v _traeger '("beschriftung") "text") + (/= (cdr (assoc "text" _cfg)) "") + (geruest-json-pfad-get _v '("beschriftung" "layer")) + (geruest-ausrichtung-codes (cdr (assoc "ausrichtung" _cfg)))) + (setq _rec (1+ _rec)))) + (tu-eq "geruest/traeger-beschriftung-varianten" + (length (ssg-json-get _traeger "geometrie_varianten")) _rec) + ;; VARIANTE gehoert zum Traeger-Schema (Grundlage fuer das Neubeschriften) + (tu-true "geruest/traeger-attrib-variante" + (assoc "VARIANTE" *geruest-traeger-attrib-defs*)) + ;; Beide Dummy-DWGs liegen unter data/geruest + (tu-true "geruest/traeger-strebe-dwg" + (findfile (geruest-dummy-pfad "dummy_Strebe_30x4.dwg"))) + (tu-true "geruest/traeger-muffe-dwg" + (findfile (geruest-dummy-pfad "dummy_Muffe_1zoll.dwg"))) ) ) From fe5cb9664cc30502391024dc24f3158fe1b19212 Mon Sep 17 00:00:00 2001 From: Simon Hensch Date: Mon, 5 Oct 2026 09:49:20 +0200 Subject: [PATCH 2/4] =?UTF-8?q?[ADD]=20Ger=C3=BCst=20Dummydateien=20sowie?= =?UTF-8?q?=20Zeichnungsdateien=20hinzugef=C3=BCgt;=20[FIX]=20Anzahl=20und?= =?UTF-8?q?=20menge=20der=20Baugruppenteile=20unterscheidet=20sich=20nun?= =?UTF-8?q?=20mit=20dem=20vorgabe=20wert=20f=C3=BCr=20die=20Inputfelder;?= =?UTF-8?q?=20[CHANGE]=20Ger=C3=BCsttr=C3=A4ger=20in=20separates=20JSON=20?= =?UTF-8?q?FIle=20ausgelagert,=20da=20andere=20Einf=C3=BCgelogik?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CLAUDE.md | 4 +- Lisp/GeruestInsert.lsp | 197 +++++++---- data/geruest/821004200.dwg | Bin 0 -> 40599 bytes data/geruest/821006031.dwg | Bin 0 -> 48088 bytes data/geruest/821006036.dwg | Bin 0 -> 45271 bytes data/geruest/821006042.dwg | Bin 0 -> 47768 bytes data/geruest/821006043.dwg | Bin 0 -> 46745 bytes .../{R2-Saeule_dummy.dwg => 821006051.dwg} | Bin 40311 -> 45624 bytes data/geruest/825006009.dwg | Bin 0 -> 43287 bytes data/json/geruest.json | 334 +++++------------- data/json/geruest_traeger.json | 193 ++++++++++ lang/de_DE.json | 3 +- lang/en_GB.json | 1 + tests/test_unit.lsp | 104 ++++-- 14 files changed, 488 insertions(+), 348 deletions(-) create mode 100644 data/geruest/821004200.dwg create mode 100644 data/geruest/821006031.dwg create mode 100644 data/geruest/821006036.dwg create mode 100644 data/geruest/821006042.dwg create mode 100644 data/geruest/821006043.dwg rename data/geruest/{R2-Saeule_dummy.dwg => 821006051.dwg} (68%) create mode 100644 data/geruest/825006009.dwg create mode 100644 data/json/geruest_traeger.json diff --git a/CLAUDE.md b/CLAUDE.md index 2cb453f..84ed02c 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -23,7 +23,7 @@ AutoLISP-Makros (SSG_LIB) fuer BricsCAD Pro zur automatisierten Erstellung von F | `cfg/` | Konfigurationsdateien | | `data/` | JSON-Daten, DXF-Quellen, Block-Libraries | | `data/ils/` | DWG-Bloecke fuer ILS-Kreisel/Eckrad (AN8, SP8, AP-Typen) | -| `data/json/` | Komponentendaten (Masse, Sivas-IDs) | +| `data/json/` | Komponentendaten (Masse, Sivas-IDs); Geruest: `geruest.json` (GERUEST-Dialog) und `geruest_traeger.json` (Traeger mit Linien-Logik) | | `data/block_libraries/` | DXF Block-Libraries (ils_library.dxf) | | `dcl/` | DCL-Dialogdefinitionen | | `doc/` | Dokumentation, Entwicklungsplan | @@ -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_SAEULEN, GERUEST_ROHRABHAENGER, GERUEST_WANDBEFESTIGUNG, GERUEST_TRAEGER, GERUEST_TRAEGER_BESCHRIFTEN | Geruest-Baugruppen aus `data/json/geruest.json` konfigurieren und einfuegen. **Ein Dialog fuer alle Bereiche**: oben ein Dropdown `bereich` (Rohrabhaenger / Saeulen / Wandbefestigung, Reihenfolge = Dateireihenfolge, Anzeigename aus dem ASCII-Feld `titel`). DCL hat **kein Reiter-Tile**, und da sich die Teilezeilen je Bereich unterscheiden, schliesst ein Bereichswechsel den Dialog (`done_dialog 4`) und die Schleife in `c:GERUEST` baut ihn neu auf; der Stand jedes Bereichs bleibt in `*geruest-zustand*` erhalten, ein versehentlicher Wechsel verwirft also nichts. 1"- und 2"-Saeulen liegen in EINER Baugruppe `Saeulen` mit gemeinsamer Anbauteil-Liste; **`teileart` und `dummy` duerfen je Geometrie-Variante ueberschrieben werden** (`geruest-variante-wert`, Variante gewinnt vor Baugruppe) - 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. **Attribut-Keys in `geruest.json` sind GROSS** (`LAENGE`, `TEILEFARBE`, ...) = die Block-Attribut-Tags; `ssg-json-get` unterscheidet Gross/Klein. **Rohr-Geruest-Traeger** (`GERUEST_TRAEGER`, Baugruppe mit `"einfuegeart": "linie"` - fehlt darum im Bereichs-Dropdown von GERUEST, gefunden ueber `geruest-baugruppe`): eigener fester Dialog `dcl/geruest_traeger.dcl` (Variante, Farbe, je eine Checkbox + Feld fuer `LAENGENABZUGANFANG`/`LAENGENABZUGENDE`, Vorgabe `vorgabe`/`aktiv` aus dem attribute-Block, je Variante ueberschreibbar via `geruest-attr-feld`); danach Einfuege-Schleife bis ESC/Enter: Startpunkt, dann Endpunkt ODER getippte Laenge (+ Richtung). Aktive Abzuege ruecken die Linie beidseitig ein (Strecke 1000, Abzug Anfang 20/Ende 35 -> Start 20 mm hinter dem Klick, Linie 945 mm); `LAENGE` = Netto-Laenge, gegen `LAENGE.min/max` geprueft. KEINE Dummy-DWG: die Geometrie ist eine per `entmake` erzeugte LINE (0,0,0)-(L,0,0) auf dem `layer` der Variante, eingefuegt mit dem Richtungswinkel (ANGBASE/ANGDIR/AUNITS dafuer kurz auf 0). **Querstreben + Muffe** als verschachtelte Dummy-DWGs im selben Block, reine Grafik ohne Export: `querstrebe.dummy` (`data/geruest/dummy_Strebe_30x4.dwg`, Basispunkt Strebenmitte, 30 mm laengs X) an jeder Strebenposition; fehlt die DWG, Rueckfall auf je eine 25-mm-Querlinie an Strebenanfang/-ende (`laenge`/`querlinie`, Standard 30/25 nur im Code). `muffe.dummy` (`dummy_Muffe_1zoll.dwg`, Basispunkt Muffenmitte) am Linienende, NUR bei Varianten mit ausdruecklichem `"mit_muffe": true` (nicht aus dem Namen geraten; bei "mit 2 Muffen" trotzdem nur eine am Ende); `querstrebe`/`muffe` per Variante ueberschreibbar (`geruest-variante-wert`). Dummys werden ohne Drehung eingefuegt (Traeger laeuft im Block entlang +X), ab dem zweiten Mal per Blockname (`geruest-dummy-einfuegen`). Verteilungs-Konfiguration `querstrebe` (`abstand_max`/`rand_min`/`rand_max`, Variante vor Baugruppe), Verteilung `geruest-traeger-streben`: so wenige Streben wie moeglich, beide Raender gleich; Abstand GENAU `abstand_max`, solange der Rand in `rand_min`..`rand_max` bleibt (1300 -> 150|500|500|150), sonst Rand = `rand_min` und Abstand etwas kleiner (1100 -> 100|450|450|100, mit fest 500 geht die Laenge nicht auf); Netto <= 2*rand_max -> eine Strebe mittig, < 2*rand_min -> keine. Schema `*geruest-traeger-attrib-defs*` = `*geruest-attrib-defs*` + die zwei Abzug-Tags; gemeinsamer Block-Schluss mit den anderen Bereichen in `geruest-block-abschliessen`. Reine Berechnung (`geruest-traeger-laenge`/`-start`/`-pruefen`, `geruest-mm-zahl`) in `tests/test_unit.lsp`. **Traeger-Beschriftung** (Checkbox im Dialog, Standard an; z.B. `RT 80/80 L=2650`): EIGENES TEXT-Objekt neben dem Block, abgeleitet NUR aus dem fertigen Block (Einfuegepunkt, DXF 50, Attribute `LAENGE` + `VARIANTE`) - darum nutzen Einfuegen und `GERUEST_TRAEGER_BESCHRIFTEN` dieselbe Funktion `geruest-traeger-beschriften`, und ein von Hand verschobener/gedrehter Traeger wird beim Neubeschriften korrekt erfasst. Verknuepfung Text -> Block per XDATA `SSG_GR_BESCHR` (1005 = Block-Handle): Neubeschriften ersetzt statt verdoppelt, der Sammelbefehl entfernt verwaiste Texte. JSON `beschriftung` (je FELD Variante vor Baugruppe, `geruest-obj-feld`): Inhalt `format` (`%1` Text, `%2` Laenge auf ganze mm) + `text` (fehlt -> Variantenname) und `layer` (je Variante verschieden, darum in JEDER Variante gepflegt - keine Baugruppen-Vorgabe; fehlt er doch, aktueller Layer); Formatierung NUR `stil`/`ausrichtung`/`hoehe` - alles andere regelt der Textstil ausserhalb, es wird kein Stil angelegt (fehlt er: Meldung, aktueller TEXTSTYLE). `ausrichtung` = Codes von TEXT "Ausrichten" (T/M/B + L/C/R), Bezugspunkt auf der Traegerlinie, L/R in LESErichtung. Textwinkel entlang des Traegers, DIN: fuer 90 < w <= 270 Grad um 180 gedreht (`geruest-text-winkel`). Noch NICHT enthalten: Edit-Pfad (GERUEST_EDIT) | +| `GeruestInsert.lsp` | GERUEST, GERUEST_SAEULEN, GERUEST_ROHRABHAENGER, GERUEST_WANDBEFESTIGUNG, GERUEST_TRAEGER, GERUEST_TRAEGER_BESCHRIFTEN | Geruest-Baugruppen aus `data/json/geruest.json` konfigurieren und einfuegen. **Ein Dialog fuer alle Bereiche**: oben ein Dropdown `bereich` (Rohrabhaenger / Saeulen / Wandbefestigung, Reihenfolge = Dateireihenfolge, Anzeigename aus dem ASCII-Feld `titel`). DCL hat **kein Reiter-Tile**, und da sich die Teilezeilen je Bereich unterscheiden, schliesst ein Bereichswechsel den Dialog (`done_dialog 4`) und die Schleife in `c:GERUEST` baut ihn neu auf; der Stand jedes Bereichs bleibt in `*geruest-zustand*` erhalten, ein versehentlicher Wechsel verwirft also nichts. 1"- und 2"-Saeulen liegen in EINER Baugruppe `Saeulen` mit gemeinsamer Anbauteil-Liste; **`teileart` und `dummy` duerfen je Geometrie-Variante ueberschrieben werden** (`geruest-variante-wert`, Variante gewinnt vor Baugruppe; fuer `dummy` ueber `geruest-dummy-wahl`: fehlt die DWG der Variante, Meldung + Rueckfall auf den Baugruppen-Dummy; ist der Dummy zugleich eine Teile-DWG, wird er per `geruest-ohne-pfad` nicht doppelt eingefuegt) - so liefert `R 1"` weiterhin TEILEART `Geruest Saeule 1 Zoll` und die `R 2"`-Varianten `Geruest Saeule 2 Zoll`, die Groessen bleiben im Export also unterscheidbar. **Die Dialogdefinition wird zur Laufzeit erzeugt** (`geruest-dcl-schreiben` -> temporaere Datei per `vl-filename-mktemp`, nach `unload_dialog` wieder geloescht) - es gibt KEINE `dcl/geruest.dcl`. Grund: je Anbauteil wird ein eigenes Mengenfeld gebraucht, und eine DCL-Liste (`list_box`) kann keine Eingabefelder enthalten; DCL kann weder Dateien einbinden noch Tiles zur Laufzeit erzeugen. Inhalt: Basis-Variante aus `geometrie_varianten` (Dropdown), Laenge (gegen `attribute.Laenge` min/max geprueft, Retry-Schleife), Farbe (`attribute.Teilefarbe`, Freitext bei `frei_option`) und **zwei Befestigungslisten** ("oben"/"unten"), die BEIDE alle `anbaugruppen` enthalten - dasselbe Teil kann oben, unten oder gleichzeitig an beiden Positionen sitzen, je mit eigener Anzahl. **Zwei Mengenfelder im JSON, bewusst verschieden benannt**: `stueckzahl` = wie oft ein Teil TATSAECHLICH geschrieben wird (je Variante bzw. je Satz/Anbauteil, fehlt = 1), `anzahl_vorgabe` = NUR die Vorbelegung des Anzahl-Feldes im Dialog (Anbaugruppen, fehlt = 1); ein Anbauteil wird Anzahl x `stueckzahl` mal geschrieben, bei einer Gruppe (`teile`) zaehlt die Anzahl die Saetze (`geruest-stueckzahl`/`geruest-anzahl-vorgabe`). In Konfigurationen (`oben`/`unten`) heisst der gespeicherte Dialogwert `anzahl`. Baugruppen ohne `attribute`-Block (Wandbefestigung) bekommen Laenge/Farbe gesperrt, Baugruppen ohne Anbauteile bekommen gar keine Spalten (ein leerer DCL-Cluster ist unzulaessig). Im generierten Label wird `"` zu `''` ersetzt (`geruest-dcl-label`) - fuenf Artikelnamen enthalten ein Anfuehrungszeichen, das das DCL-Label sonst vorzeitig beendet und die Datei zerstoert. **Konfigurationen**: gepflegte Bibliothek je Baugruppe unter `konfigurationen` in `geruest.json` (schreibgeschuetzt) plus eigene in `cfg/geruest_user.json` (gitignored, `geruest-user-schreiben`; getrennte Datei, damit Benutzerdaten und versionierte Bibliothek nicht kollidieren). Eigene Eintraege sind in der Liste mit `*` markiert und nur diese loeschbar. Konfigurationen verweisen ueber den ANZEIGENAMEN auf Variante und Anbauteile; ein unbekannter Name wird gemeldet und uebersprungen, statt die Konfiguration scheitern zu lassen. Speichern/Loeschen laufen ueber `done_dialog 2`/`3` (Dialog schliessen, Aktion, neu zeigen) - `getstring` funktioniert aus einem `action_tile`-Rueckruf heraus nicht. Der Block wird - wie KREISEL_n/VF_n - SELBST zusammengebaut: Dummy-DWG aus `data/geruest` liefert nur Geometrie, das Attribut-Schema kommt aus `*geruest-attrib-defs*` (ID, ARTINR, LAENGE, BEZEICHNUNG, TEILEART, TEILEFARBE, LAYER) und wird per `ssg-attrib-merge` mit den Dummy-Tags zusammengefuehrt - sonst verschluckt `ssg-attrib-set-on` stillschweigend jeden Tag, den die Dummy-DWG nicht als ATTDEF kennt. **Teile-Geometrie**: jede ausgewaehlte Artikelnummer (Basis/oben/unten inkl. aufgeloester Gruppen), fuer die `data/geruest/.dwg` existiert, wird zusaetzlich einmal bei 0,0,0 mit in den Block eingefuegt (`geruest-teile-dwgs`, dedupliziert, fehlende DWGs still uebergangen) - reine visuelle Rueckmeldung, die Attribut-Logik bleibt davon unberuehrt. **TEILEFARBE** ist eine kommagetrennte Liste parallel zu ARTINR (z.B. `,,RAL7030,,RAL7030`): Teile mit `"farbig": true` in `geruest.json` (je Artikel; eine Gruppe vererbt es an ihre Teile, fehlend = false) bekommen die im Dialog gewaehlte Baugruppenfarbe, alle anderen einen leeren Eintrag. ARTINR und TEILEFARBE entstehen aus demselben Durchlauf (`geruest-teile-paare`/`-paare-n`, `geruest-farbliste`), sind also garantiert gleich lang. `export_sivas.py` schreibt daraus je Artikelnummer das Merkmal `{"108": ""}` in `details` (Nummer aus `cfg/export.cfg` `[Sivas] merkmal_teilefarbe`). Blockname `GR__` (Kollisionszaehler wie in OmniModulInsert). **Das `GR_`-Praefix ist nicht kosmetisch**: `SSG_BLOCKEDIT` haelt JEDEN Block mit TEILEART-Attribut fuer ein Omniflo-Element, deshalb steht in `SSG_LIB_Commands.lsp` ein `GR_*`-Zweig VOR dem Omniflo-Zweig. ARTINR listet jede Sivas-ID so oft, wie Anzahl x `stueckzahl` es vorgeben - erst Basis, dann Befestigung oben, dann unten; bei einer benannten Gruppe (`teile`) wird das ganze Set n-mal wiederholt, die Mengen INNERHALB des Sets bleiben dabei erhalten (`geruest-artikelnummern-n`). BEZEICHNUNG nennt Position und Menge je Teil ("oben 2x ...") und verkettet mit `" + "`, NICHT mit Komma - die Artikelbezeichnungen enthalten selbst Kommas ("ROHR R 1\" 33,7 x 2,6"). Zuordnung Menue -> JSON laeuft ueber das ASCII-Feld `id`, weil die aeusseren JSON-Schluessel Umlaute bzw. Anfuehrungszeichen tragen. CSV-/Sivas-Export: `pattern_geruest = GR_*` (cfg/export.cfg), `csv:collect-export-blocks`/`ssg-id-collect-blocks` sammeln GR_-Bloecke wie BTMT eigenstaendig; `*geruest-attrib-defs*` traegt zusaetzlich ein leeres `ID`-ATTDEF (Voraussetzung fuer `ssg-id-check-all`, das nur bestehende ATTRIBs beschreiben kann). ARTINR/BEZEICHNUNG/TEILEART/LAENGE landen in export_csv.py/export_sivas.py in festen Spalten, TEILEFARBE/LAYER (+ ARTINR bei export_csv.py) im Merkmale-/details-JSON. **Attribut-Keys in `geruest.json` sind GROSS** (`LAENGE`, `TEILEFARBE`, ...) = die Block-Attribut-Tags; `ssg-json-get` unterscheidet Gross/Klein. **Rohr-Geruest-Traeger** (`GERUEST_TRAEGER`): Traeger-Baugruppen mit Linien-Logik liegen in einer EIGENEN Datei `data/json/geruest_traeger.json` (gleicher Aufbau wie geruest.json, eigener Lader/Cache `geruest-traeger-daten`, Suche `geruest-baugruppe id daten`; gemeinsamer Lader `geruest-json-laden-cache`) - sie tauchen darum nicht im Bereichs-Dropdown von GERUEST auf; dort kann spaeter auch der Gattertraeger hin. eigener fester Dialog `dcl/geruest_traeger.dcl` (Variante, Farbe, je eine Checkbox + Feld fuer `LAENGENABZUGANFANG`/`LAENGENABZUGENDE`, Vorgabe `vorgabe`/`aktiv` aus dem attribute-Block, je Variante ueberschreibbar via `geruest-attr-feld`); danach Einfuege-Schleife bis ESC/Enter: Startpunkt, dann Endpunkt ODER getippte Laenge (+ Richtung). Aktive Abzuege ruecken die Linie beidseitig ein (Strecke 1000, Abzug Anfang 20/Ende 35 -> Start 20 mm hinter dem Klick, Linie 945 mm); `LAENGE` = Netto-Laenge, gegen `LAENGE.min/max` geprueft. KEINE Dummy-DWG: die Geometrie ist eine per `entmake` erzeugte LINE (0,0,0)-(L,0,0) auf dem `layer` der Variante, eingefuegt mit dem Richtungswinkel (ANGBASE/ANGDIR/AUNITS dafuer kurz auf 0). **Querstreben + Muffe** als verschachtelte Dummy-DWGs im selben Block, reine Grafik ohne Export: `querstrebe.dummy` (`data/geruest/dummy_Strebe_30x4.dwg`, Basispunkt Strebenmitte, 30 mm laengs X) an jeder Strebenposition; fehlt die DWG, Rueckfall auf je eine 25-mm-Querlinie an Strebenanfang/-ende (`laenge`/`querlinie`, Standard 30/25 nur im Code). `muffe.dummy` (`dummy_Muffe_1zoll.dwg`, Basispunkt Muffenmitte) am Linienende, NUR bei Varianten mit ausdruecklichem `"mit_muffe": true` (nicht aus dem Namen geraten; bei "mit 2 Muffen" trotzdem nur eine am Ende); `querstrebe`/`muffe` per Variante ueberschreibbar (`geruest-variante-wert`). Dummys werden ohne Drehung eingefuegt (Traeger laeuft im Block entlang +X), ab dem zweiten Mal per Blockname (`geruest-dummy-einfuegen`). Verteilungs-Konfiguration `querstrebe` (`abstand_max`/`rand_min`/`rand_max`, Variante vor Baugruppe), Verteilung `geruest-traeger-streben`: so wenige Streben wie moeglich, beide Raender gleich; Abstand GENAU `abstand_max`, solange der Rand in `rand_min`..`rand_max` bleibt (1300 -> 150|500|500|150), sonst Rand = `rand_min` und Abstand etwas kleiner (1100 -> 100|450|450|100, mit fest 500 geht die Laenge nicht auf); Netto <= 2*rand_max -> eine Strebe mittig, < 2*rand_min -> keine. Schema `*geruest-traeger-attrib-defs*` = `*geruest-attrib-defs*` + die zwei Abzug-Tags; gemeinsamer Block-Schluss mit den anderen Bereichen in `geruest-block-abschliessen`. Reine Berechnung (`geruest-traeger-laenge`/`-start`/`-pruefen`, `geruest-mm-zahl`) in `tests/test_unit.lsp`. **Traeger-Beschriftung** (Checkbox im Dialog, Standard an; z.B. `RT 80/80 L=2650`): EIGENES TEXT-Objekt neben dem Block, abgeleitet NUR aus dem fertigen Block (Einfuegepunkt, DXF 50, Attribute `LAENGE` + `VARIANTE`) - darum nutzen Einfuegen und `GERUEST_TRAEGER_BESCHRIFTEN` dieselbe Funktion `geruest-traeger-beschriften`, und ein von Hand verschobener/gedrehter Traeger wird beim Neubeschriften korrekt erfasst. Verknuepfung Text -> Block per XDATA `SSG_GR_BESCHR` (1005 = Block-Handle): Neubeschriften ersetzt statt verdoppelt, der Sammelbefehl entfernt verwaiste Texte. JSON `beschriftung` (je FELD Variante vor Baugruppe, `geruest-obj-feld`): Inhalt `format` (`%1` Text, `%2` Laenge auf ganze mm) + `text` (fehlt -> Variantenname) und `layer` (je Variante verschieden, darum in JEDER Variante gepflegt - keine Baugruppen-Vorgabe; fehlt er doch, aktueller Layer); Formatierung NUR `stil`/`ausrichtung`/`hoehe` - alles andere regelt der Textstil ausserhalb, es wird kein Stil angelegt (fehlt er: Meldung, aktueller TEXTSTYLE). `ausrichtung` = Codes von TEXT "Ausrichten" (T/M/B + L/C/R), Bezugspunkt auf der Traegerlinie, L/R in LESErichtung. Textwinkel entlang des Traegers, DIN: fuer 90 < w <= 270 Grad um 180 gedreht (`geruest-text-winkel`). Noch NICHT enthalten: Edit-Pfad (GERUEST_EDIT) | | `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 1788ed1..e331874 100644 --- a/Lisp/GeruestInsert.lsp +++ b/Lisp/GeruestInsert.lsp @@ -5,6 +5,7 @@ ;; Nutzer eine Basis-Variante, Anbauteile fuer "Befestigung oben" UND ;; "Befestigung unten" (je mit eigener Stueckzahl), Laenge und Farbe waehlen, ;; und fuegt das Ergebnis als Block GR__ ein. +;; Rohr-Geruest-Traeger (GERUEST_TRAEGER) lesen data/json/geruest_traeger.json. ;; ;; Beide Befestigungslisten enthalten ALLE Anbauteile der Baugruppe - dasselbe ;; Teil kann oben, unten oder gleichzeitig an beiden Positionen sitzen. @@ -100,9 +101,10 @@ ) ) -(defun geruest-json-pfad ( / basis) +;; Pfad einer Datendatei unter data/json, z.B. "geruest.json". +(defun geruest-json-pfad (datei / basis) (if (setq basis (geruest-data-verzeichnis)) - (strcat basis "/json/geruest.json") + (strcat basis "/json/" datei) ) ) @@ -112,36 +114,48 @@ ) ) -;; Datendatei einmal je Zeichnungssitzung laden. -(defun geruest-daten ( / pfad) - (if (null *geruest-daten*) +;; Datendatei unter data/json einmal je Zeichnungssitzung laden und im +;; globalen Symbol cache-sym ablegen. Rueckgabe: die geparsten Daten oder nil +;; (mit Meldung). +(defun geruest-json-laden-cache (datei cache-sym / pfad daten) + (if (null (eval cache-sym)) (progn - (setq pfad (geruest-json-pfad)) + (setq pfad (geruest-json-pfad datei)) (cond ((null pfad) (princ (ssg-text "gr-fehler-datenpfad"))) ((null (findfile pfad)) (princ (ssg-textf "gr-fehler-json-fehlt" (list pfad)))) (T - (setq *geruest-daten* (ssg-json-laden pfad)) - (if (null *geruest-daten*) + (setq daten (ssg-json-laden pfad)) + (set cache-sym daten) + (if (null daten) (princ (ssg-textf "gr-fehler-json-lesbar" (list pfad))) ) ) ) ) ) - *geruest-daten* + (eval cache-sym) +) + +;; Baugruppen des GERUEST-Dialogs (Rohrabhaenger, Saeulen, Wandbefestigung). +(defun geruest-daten ( / ) + (geruest-json-laden-cache "geruest.json" '*geruest-daten*) +) + +;; Traeger-Baugruppen mit Linien-Logik (Rohr-Geruest-Traeger, spaeter z.B. +;; Gattertraeger) - bewusst eine eigene Datei: eigener Dialog, Laenge aus der +;; Zeichnung, Streben/Muffe/Beschriftung statt Anbaugruppen/Konfigurationen. +(defun geruest-traeger-daten ( / ) + (geruest-json-laden-cache "geruest_traeger.json" '*geruest-traeger-daten*) ) ;; Alle Baugruppen als ((id . objekt) ...) in Dateireihenfolge - diese -;; Reihenfolge bestimmt auch die Reihenfolge im Bereichs-Dropdown. -;; Baugruppen mit "einfuegeart": "linie" (Rohr-Geruest-Traeger) fehlen hier: -;; sie haben einen eigenen Dialog und einen eigenen Einfuegeablauf -;; (c:GERUEST_TRAEGER) und gehoeren nicht in das Bereichs-Dropdown. +;; Reihenfolge bestimmt auch die Reihenfolge im Bereichs-Dropdown. Die +;; Traeger stehen in geruest_traeger.json und gehoeren nicht hierher. (defun geruest-baugruppen-liste ( / erg) (setq erg nil) (foreach eintrag (geruest-daten) - (if (and (listp (cdr eintrag)) - (not (equal (ssg-json-get (cdr eintrag) "einfuegeart") "linie"))) + (if (listp (cdr eintrag)) (setq erg (append erg (list (cons (ssg-json-get (cdr eintrag) "id") (cdr eintrag))))) ) @@ -169,6 +183,40 @@ (if (and w (/= w "")) w (ssg-json-get bg schluessel)) ) +;; Pfad der Dummy-DWG fuer den Block. Ein "dummy" in der Geometrie-Variante +;; wird bevorzugt; fehlt die Datei unter data/geruest, wird gemeldet und auf +;; den "dummy" der Baugruppe zurueckgefallen. Rueckgabe: (datei . pfad) - +;; pfad ist nil, wenn kein Datenverzeichnis bekannt ist; ob die +;; Rueckfall-Datei existiert, prueft der Aufrufer. +(defun geruest-dummy-wahl (variante bg / v pfad) + (setq v (if variante (ssg-json-get variante "dummy"))) + (if (and v (= (type v) 'STR) (/= v "") + (setq pfad (geruest-dummy-pfad v)) + (findfile pfad)) + (cons v pfad) + (progn + (if (and v (= (type v) 'STR) (/= v "")) + (princ (ssg-textf "gr-fehler-dummy-variante" + (list (if pfad pfad v) + (if (ssg-json-get bg "dummy") + (ssg-json-get bg "dummy") + "-")))) + ) + (setq v (ssg-json-get bg "dummy")) + (cons v (geruest-dummy-pfad v)) + ) + ) +) + +;; Liste ohne die Eintraege, die (ohne Gross/Klein) gleich pfad sind. Damit +;; landet eine Teile-DWG, die zugleich der Dummy ist, nicht doppelt im Block. +(defun geruest-ohne-pfad (pfad liste) + (if pfad + (vl-remove-if '(lambda (p) (= (strcase p) (strcase pfad))) liste) + liste + ) +) + ;; ============================================================ ;; TEILE AUSWERTEN @@ -184,9 +232,23 @@ ) ) -(defun geruest-menge (eintrag / m) - (setq m (ssg-json-get eintrag "menge")) - (if (and m (numberp m) (> m 0)) (fix m) 1) +;; Zwei Mengenfelder im JSON, bewusst verschieden benannt: +;; "stueckzahl" = wie oft das Teil TATSAECHLICH geschrieben wird - je +;; Einbau (Variante) bzw. je Satz/Anbauteil. Fehlt = 1. +;; "anzahl_vorgabe" = NUR die Vorbelegung des Anzahl-Feldes im Dialog +;; (Anbaugruppen). Fehlt = 1. +;; Ein Anbauteil wird Anzahl (Dialog) x stueckzahl mal geschrieben; bei einer +;; Gruppe ("teile") ist die Anzahl die Zahl der Saetze. +(defun geruest-positiv-int (w / ) + (if (and w (numberp w) (> w 0)) (fix w) 1) +) + +(defun geruest-stueckzahl (eintrag) + (geruest-positiv-int (ssg-json-get eintrag "stueckzahl")) +) + +(defun geruest-anzahl-vorgabe (eintrag) + (geruest-positiv-int (ssg-json-get eintrag "anzahl_vorgabe")) ) ;; Sivas-ID als String. Im JSON stehen rein numerische IDs als Zahl @@ -212,7 +274,7 @@ ) ;; Alle Teile eines Eintrags als ((artnr . farbig) ...), jedes gemaess -;; "menge" wiederholt. Benannte Gruppen ("teile") werden rekursiv aufgeloest. +;; "stueckzahl" 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. @@ -229,12 +291,12 @@ (setq erg (mapcar '(lambda (nr) (cons nr farbig)) (geruest-wiederholen (geruest-id-string (ssg-json-get eintrag "sivas_id")) - (geruest-menge eintrag)))) + (geruest-stueckzahl eintrag)))) ) erg ) -;; Alle Artikelnummern eines Eintrags, jede gemaess "menge" wiederholt. +;; Alle Artikelnummern eines Eintrags, jede gemaess "stueckzahl" wiederholt. (defun geruest-artikelnummern (eintrag) (mapcar 'car (geruest-teile-paare eintrag nil)) ) @@ -289,7 +351,7 @@ ;; Eingabe aus einem Mengenfeld auswerten. ;; Leer -> Vorgabewert aus dem JSON, gueltig -> Zahl >= 1, sonst nil. -(defun geruest-menge-wert (s vorgabe) +(defun geruest-anzahl-wert (s vorgabe) (setq s (ssg-cfg-trim (if s s ""))) (cond ((= s "") vorgabe) @@ -310,30 +372,18 @@ ) ) -;; Artikelnummern eines Eintrags bei frei gewaehlter Stueckzahl. -;; Einzelteil: die Sivas-ID anzahl-mal. Benannte Gruppe ("teile"): das -;; komplette Set anzahl-mal - die Mengen INNERHALB des Sets bleiben erhalten +;; Teile eines Anbauteils bei der im Dialog gewaehlten Anzahl: der Eintrag +;; (Einzelteil mit seiner "stueckzahl" bzw. benannte Gruppe als kompletter +;; Satz) anzahl-mal. Die Stueckzahlen INNERHALB eines Satzes bleiben erhalten ;; (ein Schraubenset bleibt 1 Scheibe + 2 Muttern + 1 Schraube je Satz). -(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-teile-paare teil farbig))) - ) - (setq erg nil i 0) - (while (< i anzahl) - (setq erg (append erg einmal)) - (setq i (1+ i)) - ) - erg - ) - (mapcar '(lambda (nr) (cons nr farbig)) - (geruest-wiederholen - (geruest-id-string (ssg-json-get eintrag "sivas_id")) anzahl)) +(defun geruest-teile-paare-n (eintrag anzahl / einmal erg i) + (setq einmal (geruest-teile-paare eintrag nil)) + (setq erg nil i 0) + (while (< i anzahl) + (setq erg (append erg einmal)) + (setq i (1+ i)) ) + erg ) (defun geruest-artikelnummern-n (eintrag anzahl) @@ -441,7 +491,7 @@ ;; Positionsliste ("oben"/"unten") einer Konfiguration auf die Anbauteile ;; abbilden. Rueckgabe: ein Eintrag je Anbauteil - nil (nicht gewaehlt) oder -;; die Stueckzahl. Ein unbekannter Artikelname wird gemeldet und +;; die Anzahl (Feld "anzahl"). Ein unbekannter Artikelname wird gemeldet und ;; uebersprungen, statt die ganze Konfiguration scheitern zu lassen. (defun geruest-konfig-position (konfig schluessel anbauteile / mengen idx n) (setq mengen (geruest-nil-liste (length anbauteile))) @@ -449,7 +499,7 @@ (setq idx (geruest-name-index (ssg-json-get e "artikel") anbauteile)) (if idx (progn - (setq n (ssg-json-get e "menge")) + (setq n (ssg-json-get e "anzahl")) (setq mengen (geruest-liste-setzen mengen idx (if (and n (numberp n) (> n 0)) (fix n) 1))) ) @@ -583,20 +633,20 @@ (defun geruest-dlg-standard ( / erg) (setq erg nil) (foreach a *geruest-anbauteile* - (setq erg (append erg (list (cons "0" (itoa (geruest-menge a)))))) + (setq erg (append erg (list (cons "0" (itoa (geruest-anzahl-vorgabe a)))))) ) erg ) ;; Mengenliste (nil oder Zahl je Teil) in den Tile-Zustand umsetzen. -(defun geruest-mengen->tiles (mengen / erg i a) +(defun geruest-anzahlen->tiles (mengen / erg i a) (setq erg nil i 0) (foreach m mengen (setq a (nth i *geruest-anbauteile*)) (setq erg (append erg (list (if m (cons "1" (itoa m)) - (cons "0" (itoa (geruest-menge a))))))) + (cons "0" (itoa (geruest-anzahl-vorgabe a))))))) (setq i (1+ i)) ) erg @@ -720,10 +770,10 @@ *geruest-dlg-frei* farbe)) ) (setq *geruest-dlg-oben* - (geruest-mengen->tiles + (geruest-anzahlen->tiles (geruest-konfig-position k "oben" *geruest-anbauteile*))) (setq *geruest-dlg-unten* - (geruest-mengen->tiles + (geruest-anzahlen->tiles (geruest-konfig-position k "unten" *geruest-anbauteile*))) ) ) @@ -745,16 +795,16 @@ ) ;; Angehakte Teile einer Spalte mit gueltiger Menge einsammeln. -;; Rueckgabe: (T . ((index . menge) ...)) oder nil bei ungueltigem Mengenfeld. +;; Rueckgabe: (T . ((index . anzahl) ...)) oder nil bei ungueltigem Mengenfeld. ;; Das fuehrende T ist noetig, weil "nichts ausgewaehlt" ein gueltiges ;; Ergebnis ist und sich sonst nicht von einem Fehler unterscheiden liesse. -(defun geruest-mengen-lesen (zustand / erg i a m ok) +(defun geruest-anzahlen-lesen (zustand / erg i a m ok) (setq erg nil i 0 ok T) (foreach paar zustand (setq a (nth i *geruest-anbauteile*)) (if (and ok (= (car paar) "1")) (progn - (setq m (geruest-menge-wert (cdr paar) (geruest-menge a))) + (setq m (geruest-anzahl-wert (cdr paar) (geruest-anzahl-vorgabe a))) (if m (setq erg (append erg (list (cons i m)))) (setq ok nil) @@ -788,11 +838,11 @@ (setq a (nth i *geruest-anbauteile*)) (if (= (car paar) "1") (progn - (setq m (geruest-menge-wert (cdr paar) (geruest-menge a))) + (setq m (geruest-anzahl-wert (cdr paar) (geruest-anzahl-vorgabe a))) (if m (setq erg (append erg (list (list (cons "artikel" (geruest-eintrag-name a)) - (cons "menge" m))))) + (cons "anzahl" m))))) ) ) ) @@ -818,7 +868,7 @@ (write-line (strcat " { \"artikel\": \"" (ssg-json-escape (ssg-json-get e "artikel")) - "\", \"menge\": " (itoa (ssg-json-get e "menge")) " }" + "\", \"anzahl\": " (itoa (ssg-json-get e "anzahl")) " }" (if (< i n) "," "")) f) ) @@ -963,7 +1013,7 @@ ) ;; Dialog fuer einen Bereich zeigen. Rueckgabe: -;; ("OK" variante-index ((idx . menge) ...) ((idx . menge) ...) laenge farbe) +;; ("OK" variante-index ((idx . anzahl) ...) ((idx . anzahl) ...) laenge farbe) ;; - drittes Element = Befestigung oben, viertes = unten ;; ("WECHSEL" bereich-index) - Nutzer hat den Bereich umgestellt ;; nil - abgebrochen @@ -1120,8 +1170,8 @@ ) (T - (setq oben-m (geruest-mengen-lesen *geruest-dlg-oben*)) - (setq unten-m (geruest-mengen-lesen *geruest-dlg-unten*)) + (setq oben-m (geruest-anzahlen-lesen *geruest-dlg-oben*)) + (setq unten-m (geruest-anzahlen-lesen *geruest-dlg-unten*)) (if (or (null oben-m) (null unten-m)) (alert (ssg-text "gr-alert-menge")) (progn @@ -1170,10 +1220,14 @@ ;; Rueckgabe: (blockname . entity) oder nil. (defun geruest-block-bauen (bg variante werte pt teile-dwgs / datei dummy lastEnt dummyEnt dummy-attribs attribs) - ;; Eine Variante darf eine eigene Dummy-DWG mitbringen; sonst gilt die der - ;; Baugruppe. - (setq datei (geruest-variante-wert variante bg "dummy")) - (setq dummy (geruest-dummy-pfad datei)) + ;; Eine Variante darf eine eigene Dummy-DWG mitbringen; sonst (oder wenn + ;; deren Datei fehlt) gilt die der Baugruppe. + (setq datei (geruest-dummy-wahl variante bg)) + (setq dummy (cdr datei) + datei (car datei)) + ;; Ist der Dummy zugleich eine Teile-DWG (z.B. 821006036.dwg beim + ;; T-Abhaenger), nicht ein zweites Mal einfuegen. + (setq teile-dwgs (geruest-ohne-pfad dummy teile-dwgs)) (if (or (null dummy) (null (findfile dummy))) (progn (princ (ssg-textf "gr-fehler-dummy" (list (if dummy dummy datei)))) @@ -1269,7 +1323,7 @@ ;; ============================================================ ;; Teile-Paare ((artnr . farbig) ...) einer Befestigungsauswahl -;; ((index . menge) ...). +;; ((index . anzahl) ...). (defun geruest-auswahl-paare (auswahl anbauteile / erg) (setq erg nil) (foreach paar auswahl @@ -1410,7 +1464,7 @@ ;; ============================================================ -;; ROHR-GERUEST-TRAEGER (Baugruppe mit "einfuegeart": "linie") +;; ROHR-GERUEST-TRAEGER (Daten: data/json/geruest_traeger.json) ;; ============================================================ ;; Eigener Dialog (dcl/geruest_traeger.dcl): Variante, Farbe und zwei ;; Laengenabzuege. Die Laenge selbst wird DANACH in der Zeichnung bestimmt - @@ -1425,11 +1479,10 @@ ;; Richtungswinkel eingefuegt. Es wird wiederholt eingefuegt, bis der Nutzer ;; ESC/Enter drueckt - jeder Traeger ist ein eigener GR_Traeger_-Block. -;; Baugruppe ueber das ASCII-Feld "id" (auch solche, die -;; geruest-baugruppen-liste auslaesst). -(defun geruest-baugruppe (id / erg) +;; Baugruppe ueber das ASCII-Feld "id" in daten (z.B. (geruest-traeger-daten)). +(defun geruest-baugruppe (id daten / erg) (setq erg nil) - (foreach eintrag (geruest-daten) + (foreach eintrag daten (if (and (null erg) (listp (cdr eintrag)) (equal (ssg-json-get (cdr eintrag) "id") id)) (setq erg (cdr eintrag)) @@ -2098,7 +2151,7 @@ cfg laenge lage lay handle code erg) (setq ed (entget blockEnt)) (setq attribs (ssg-attrib-read blockEnt)) - (setq bg (geruest-baugruppe "Traeger")) + (setq bg (geruest-baugruppe "Traeger" (geruest-traeger-daten))) (setq laenge (atof (cond ((cdr (assoc "LAENGE" attribs))) ("0")))) (if (and bg (> laenge 0.0)) (progn @@ -2190,7 +2243,7 @@ ) (defun c:GERUEST_TRAEGER ( / bg wahl) - (setq bg (geruest-baugruppe "Traeger")) + (setq bg (geruest-baugruppe "Traeger" (geruest-traeger-daten))) (cond ((null bg) (princ (ssg-textf "gr-fehler-baugruppe" (list "Traeger")))) diff --git a/data/geruest/821004200.dwg b/data/geruest/821004200.dwg new file mode 100644 index 0000000000000000000000000000000000000000..148b0a35f00d08ff1b5bae8330bd28bbd046faf2 GIT binary patch literal 40599 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 O^9BFoRFwUw;^FQqDEImx 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 ^@%mVFXN-VI#rrJ2-?BZV(|6RVd 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 Rt$yw1t1E&pHvf{h_uo-z#99CV literal 0 HcmV?d00001 diff --git a/data/geruest/821006042.dwg b/data/geruest/821006042.dwg new file mode 100644 index 0000000000000000000000000000000000000000..de1712de2e2c5f9a40c3d8b8bc7a8f5d2ff4bb07 GIT binary patch literal 47768 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 Z0^d_b?N;7aR_?mFVfeSJNBq9;zW|ZV3gZ9( literal 0 HcmV?d00001 diff --git a/data/geruest/821006043.dwg b/data/geruest/821006043.dwg new file mode 100644 index 0000000000000000000000000000000000000000..ad9fd9737ee6a7ec62042e72afbdc4212ed5d602 GIT binary patch literal 46745 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 TXl`mMcHLM%_`A)^XO{gRh)wLe literal 0 HcmV?d00001 diff --git a/data/geruest/R2-Saeule_dummy.dwg b/data/geruest/821006051.dwg similarity index 68% rename from data/geruest/R2-Saeule_dummy.dwg rename to data/geruest/821006051.dwg index d3b446c1615c2570a19707314d62317202423d36..cbf0558c76841ce643b94404a110210664fb2325 100644 GIT binary patch delta 8721 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 delta 3402 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 diff --git a/data/geruest/825006009.dwg b/data/geruest/825006009.dwg new file mode 100644 index 0000000000000000000000000000000000000000..640793e78ad8783d91fb968b352ca93c6b026716 GIT binary patch literal 43287 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", diff --git a/lang/en_GB.json b/lang/en_GB.json index 95a93e9..2714170 100644 --- a/lang/en_GB.json +++ b/lang/en_GB.json @@ -1003,6 +1003,7 @@ "gr-fehler-baugruppe": "\nScaffold: assembly '%1' is not in the data file.", "gr-fehler-keine-varianten": "\nScaffold: assembly '%1' has no geometry variants.", "gr-fehler-dummy": "\nScaffold: dummy assembly not found: %1", + "gr-fehler-dummy-variante": "\nScaffold: dummy of the variant not found: %1 - using dummy of the assembly (%2)", "gr-fehler-dcl": "Dialog geruest.dcl could not be loaded.", "gr-dlg-kopf": "Configure %1", "gr-alert-laenge": "Invalid length: '%1' mm. Allowed: %2 to %3 mm.", diff --git a/tests/test_unit.lsp b/tests/test_unit.lsp index 23d0ef2..7c8c66e 100644 --- a/tests/test_unit.lsp +++ b/tests/test_unit.lsp @@ -754,9 +754,9 @@ (if (findfile _datei) (progn (setq _daten (ssg-json-laden _datei)) - ;; Vier Baugruppen: Rohrabhaenger, Saeulen (1 und 2 Zoll - ;; zusammengefuehrt), Wandbefestigung, Rohr-Geruest-Traeger - (tu-eq "json/geruest-baugruppen" 4 (length _daten)) + ;; Drei Bereiche: Rohrabhaenger, Saeulen (1 und 2 Zoll zusammengefuehrt), + ;; Wandbefestigung. Die Traeger liegen in geruest_traeger.json. + (tu-eq "json/geruest-baugruppen" 3 (length _daten)) ;; Baugruppe ueber das ASCII-Feld "id" finden (aeusserer Schluessel ;; traegt Umlaute bzw. Anfuehrungszeichen) (setq _bg nil) @@ -768,7 +768,7 @@ (progn (setq _var (ssg-json-get _bg "geometrie_varianten")) (setq _anb (ssg-json-get _bg "anbaugruppen")) - (tu-eq "json/geruest-varianten" 3 (length _var)) + (tu-eq "json/geruest-varianten" 4 (length _var)) (tu-eq "json/geruest-teileart" "Geruest Rohrabhaenger" (ssg-json-get _bg "teileart")) (tu-eq "json/geruest-dummy" "Rohrabhaenger_dummy.dwg" @@ -824,24 +824,24 @@ (tu-eq "geruest-id-string/str" "0_B10071" (geruest-id-string "0_B10071")) (tu-eq "geruest-id-string/nil" nil (geruest-id-string nil)) - ;; Einzelteil mit menge 2 -> Artikelnummer zweimal (ARTINR-Regel) + ;; Einzelteil mit stueckzahl 2 -> Artikelnummer zweimal (ARTINR-Regel) (setq _eintrag (ssg-json-parse - "{\"artikel\": \"X\", \"sivas_id\": 825002019, \"menge\": 2}")) - (tu-eq "geruest-artnr/menge2" '("825002019" "825002019") + "{\"artikel\": \"X\", \"sivas_id\": 825002019, \"stueckzahl\": 2}")) + (tu-eq "geruest-artnr/stueckzahl2" '("825002019" "825002019") (geruest-artikelnummern _eintrag)) (tu-eq "geruest-name/artikel" "X" (geruest-eintrag-name _eintrag)) ;; Benannte Gruppe -> teile rekursiv aufloesen, Mengen beachten (setq _gruppe (ssg-json-parse (strcat "{\"name\": \"Schraubenset\", \"teile\": [" - "{\"artikel\": \"A\", \"sivas_id\": 111, \"menge\": 1}," - "{\"artikel\": \"B\", \"sivas_id\": 222, \"menge\": 2}]}"))) + "{\"artikel\": \"A\", \"sivas_id\": 111, \"stueckzahl\": 1}," + "{\"artikel\": \"B\", \"sivas_id\": 222, \"stueckzahl\": 2}]}"))) (tu-eq "geruest-artnr/gruppe" '("111" "222" "222") (geruest-artikelnummern _gruppe)) (tu-eq "geruest-name/gruppe" "Schraubenset" (geruest-eintrag-name _gruppe)) - ;; Fehlendes menge-Feld -> 1 - (tu-eq "geruest-artnr/ohne-menge" '("333") + ;; Fehlendes stueckzahl-Feld -> 1 + (tu-eq "geruest-artnr/ohne-stueckzahl" '("333") (geruest-artikelnummern (ssg-json-parse "{\"artikel\": \"C\", \"sivas_id\": 333}"))) @@ -859,21 +859,62 @@ (tu-eq "geruest-teile-dwgs/vorhanden" (list _pfad) (geruest-teile-dwgs '("825002019" "999999999" "825002019"))) ) + ;; --- Anzahl-Vorgabe (Dialogfeld) vs. stueckzahl (wirklich geschrieben) --- + (tu-eq "geruest-anzahl-vorgabe/gruppe" 2 + (geruest-anzahl-vorgabe (ssg-json-parse + "{\"name\": \"G\", \"anzahl_vorgabe\": 2, \"teile\": [{\"sivas_id\": 1, \"stueckzahl\": 1}]}"))) + ;; stueckzahl ist KEINE Vorgabe fuer das Dialogfeld + (tu-eq "geruest-anzahl-vorgabe/stueckzahl-zaehlt-nicht" 1 + (geruest-anzahl-vorgabe (ssg-json-parse "{\"sivas_id\": 1, \"stueckzahl\": 3}"))) + (tu-eq "geruest-anzahl-vorgabe/ohne" 1 + (geruest-anzahl-vorgabe (ssg-json-parse "{\"name\": \"G\", \"teile\": []}"))) + ;; anzahl_vorgabe bestimmt nur die Vorbelegung, nicht den Satzinhalt: + ;; 3 Saetze a (1 Schraube + 1 Duebel) = 6 Nummern + (tu-eq "geruest-artikelnummern-n/anzahl-vorgabe" '("1" "2" "1" "2" "1" "2") + (geruest-artikelnummern-n (ssg-json-parse + "{\"name\": \"G\", \"anzahl_vorgabe\": 2, \"teile\": [{\"sivas_id\": 1, \"stueckzahl\": 1}, {\"sivas_id\": 2, \"stueckzahl\": 1}]}") + 3)) + ;; Einzelteil-Anbauteil: Anzahl x stueckzahl + (tu-eq "geruest-artikelnummern-n/einzelteil-stueckzahl" '("7" "7" "7" "7") + (geruest-artikelnummern-n (ssg-json-parse + "{\"artikel\": \"X\", \"sivas_id\": 7, \"stueckzahl\": 2, \"anzahl_vorgabe\": 5}") + 2)) + ;; Dummy, der zugleich Teile-DWG ist, faellt aus der Teileliste + (tu-eq "geruest-ohne-pfad/entfernt" '("b/2.dwg") + (geruest-ohne-pfad "A/1.DWG" '("a/1.dwg" "b/2.dwg"))) + (tu-eq "geruest-ohne-pfad/nil" '("a/1.dwg") + (geruest-ohne-pfad nil '("a/1.dwg"))) + ;; Dummy-Wahl: Variante gewinnt, fehlende Varianten-DWG -> Baugruppe + (setq _pfad (geruest-dummy-pfad "821006036.dwg")) + (if (and _pfad (findfile _pfad)) + (tu-eq "geruest-dummy-wahl/variante" "821006036.dwg" + (car (geruest-dummy-wahl + (ssg-json-parse "{\"dummy\": \"821006036.dwg\"}") + (ssg-json-parse "{\"dummy\": \"basis.dwg\"}")))) + ) + (tu-eq "geruest-dummy-wahl/fehlt" "basis.dwg" + (car (geruest-dummy-wahl + (ssg-json-parse "{\"dummy\": \"gibtsnicht_999.dwg\"}") + (ssg-json-parse "{\"dummy\": \"basis.dwg\"}")))) + (tu-eq "geruest-dummy-wahl/ohne" "basis.dwg" + (car (geruest-dummy-wahl + (ssg-json-parse "{\"name\": \"X\"}") + (ssg-json-parse "{\"dummy\": \"basis.dwg\"}")))) ;; --- Mengenfeld --- (tu-eq "geruest-zahl-p/ziffern" T (geruest-zahl-p "12")) (tu-eq "geruest-zahl-p/text" nil (geruest-zahl-p "1a")) (tu-eq "geruest-zahl-p/leer" nil (geruest-zahl-p "")) ;; Leeres Feld uebernimmt die JSON-Vorgabe, ungueltiges liefert nil - (tu-eq "geruest-menge-wert/leer" 2 (geruest-menge-wert "" 2)) - (tu-eq "geruest-menge-wert/zahl" 5 (geruest-menge-wert "5" 2)) - (tu-eq "geruest-menge-wert/null" nil (geruest-menge-wert "0" 2)) - (tu-eq "geruest-menge-wert/text" nil (geruest-menge-wert "abc" 2)) - (tu-eq "geruest-menge-wert/negativ" nil (geruest-menge-wert "-3" 2)) + (tu-eq "geruest-anzahl-wert/leer" 2 (geruest-anzahl-wert "" 2)) + (tu-eq "geruest-anzahl-wert/zahl" 5 (geruest-anzahl-wert "5" 2)) + (tu-eq "geruest-anzahl-wert/null" nil (geruest-anzahl-wert "0" 2)) + (tu-eq "geruest-anzahl-wert/text" nil (geruest-anzahl-wert "abc" 2)) + (tu-eq "geruest-anzahl-wert/negativ" nil (geruest-anzahl-wert "-3" 2)) - ;; --- Stueckzahl ersetzt die JSON-Menge (Einzelteil) --- - (tu-eq "geruest-artnr-n/einzelteil" '("825002019" "825002019" "825002019") - (geruest-artikelnummern-n _eintrag 3)) + ;; --- Einzelteil: Anzahl (Dialog) x stueckzahl (JSON, hier 2) --- + (tu-eq "geruest-artnr-n/einzelteil" 6 + (length (geruest-artikelnummern-n _eintrag 3))) ;; --- Gruppe: ganzes Set n-mal, Mengen INNERHALB bleiben erhalten --- (tu-eq "geruest-artnr-n/gruppe" '("111" "222" "222" "111" "222" "222") (geruest-artikelnummern-n _gruppe 2)) @@ -894,7 +935,7 @@ (setq _teile (ssg-json-parse (strcat "{\"name\": \"Set\", \"farbig\": true, \"teile\": [" "{\"artikel\": \"A\", \"sivas_id\": 111}," - "{\"artikel\": \"B\", \"sivas_id\": 222, \"menge\": 2}]}"))) + "{\"artikel\": \"B\", \"sivas_id\": 222, \"stueckzahl\": 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))) @@ -934,8 +975,8 @@ ;; die ganze Konfiguration verworfen) (setq _konfig (ssg-json-parse (strcat "{\"name\": \"K1\", \"oben\": [" - "{\"artikel\": \"Schraubenset\", \"menge\": 3}," - "{\"artikel\": \"unbekannt\", \"menge\": 1}]}"))) + "{\"artikel\": \"Schraubenset\", \"anzahl\": 3}," + "{\"artikel\": \"unbekannt\", \"anzahl\": 1}]}"))) (tu-eq "geruest-konfig-position" '(nil 3) (geruest-konfig-position _konfig "oben" _teile)) @@ -1172,18 +1213,21 @@ _bgtest "LAENGENABZUGENDE" "aktiv")) ;; --- Rohr-Geruest-Traeger in der echten Datendatei --- - ;; Eigener Dialog: im Bereichs-Dropdown von GERUEST darf er fehlen, - ;; ueber geruest-baugruppe muss er aber auffindbar sein. + ;; Eigene Datei data/json/geruest_traeger.json: im Bereichs-Dropdown von + ;; GERUEST darf er nicht auftauchen, ueber geruest-traeger-daten muss er + ;; auffindbar sein. (setq _rec nil) (foreach _e (geruest-baugruppen-liste) (if (equal (car _e) "Traeger") (setq _rec T))) (tu-nil "geruest/traeger-nicht-im-dropdown" _rec) - (setq _traeger (geruest-baugruppe "Traeger")) + (tu-true "geruest/traeger-datei" + (findfile (geruest-json-pfad "geruest_traeger.json"))) + (setq _traeger (geruest-baugruppe "Traeger" (geruest-traeger-daten))) (tu-true "geruest/traeger-vorhanden" _traeger) + (tu-nil "geruest/traeger-nicht-in-geruest-json" + (geruest-baugruppe "Traeger" (geruest-daten))) (if _traeger (progn - (tu-eq "geruest/traeger-einfuegeart" "linie" - (ssg-json-get _traeger "einfuegeart")) (tu-eq "geruest/traeger-varianten-artikel" 0 (tu-geruest-artikel-unvollstaendig (ssg-json-get _traeger "geometrie_varianten"))) @@ -1236,7 +1280,7 @@ (cons "laenge" "2000") (cons "teilefarbe" "RAL 7035 Lichtgrau") (cons "oben" (list (list (cons "artikel" "ROHRKLAMMER 1\" KPL. VERTIKAL") - (cons "menge" 2)))) + (cons "anzahl" 2)))) (cons "unten" nil))) (setq _pfad (vl-filename-mktemp "grtest" nil ".json")) (setq _f (open _pfad "w")) @@ -1256,8 +1300,8 @@ (ssg-json-get _zurueck "teilefarbe")) (tu-eq "geruest-schreiber/oben-artikel" "ROHRKLAMMER 1\" KPL. VERTIKAL" (ssg-json-get (car (ssg-json-get _zurueck "oben")) "artikel")) - (tu-eq "geruest-schreiber/oben-menge" 2 - (ssg-json-get (car (ssg-json-get _zurueck "oben")) "menge")) + (tu-eq "geruest-schreiber/oben-anzahl" 2 + (ssg-json-get (car (ssg-json-get _zurueck "oben")) "anzahl")) (tu-eq "geruest-schreiber/unten-leer" nil (ssg-json-get _zurueck "unten")) ) From 1250864849283902a4438f47af686e1b6369f91a Mon Sep 17 00:00:00 2001 From: Samer Ayadi Date: Mon, 5 Oct 2026 15:39:11 +0200 Subject: [PATCH 3/4] [ADD] Dematic/Arvato: Nachbau-Vorlage tests/testdata/dematic_arvato.json (Abschnitt Flowpuffer/Kreisel) + Treiber TEST_DEMATIC_ARVATO (Menue Tests, in alltests.json vorerst disabled); [FIX] dxf_scan_components.py: liest jetzt auch ASCII-DXF, Kreisel-Paarung global nach Abstand und nur auf gemeinsamer Achse (vorher klaute ein AN8 die SP8 des Nachbarn), Kreisel-Position aus der Radmitte statt dem Einfuegepunkt (AN8/SP8 Pinband haben das Rad ~15 m daneben), Kreisel als insert mit Mittenabstand statt connect (war an beiden Enden einen Radius zu kurz), AN8/SP8 Pinband erkannt, Projektkennung in den IDs per --projekt statt fest HundM05; [FIX] hundm05:bau-sensor brach bei Eintraegen ohne id mit bad argument type ab Co-Authored-By: Claude Opus 5.5 --- lib/dxf_scan_components.py | 180 +++- menu/SSG_LIB.cui | 12 + menu/SSG_LIB.mnu | 1 + tests/alltests.json | 1 + tests/test_dematic_arvato.lsp | 138 +++ tests/test_hundm05.lsp | 4 + tests/testdata/dematic_arvato.json | 1381 ++++++++++++++++++++++++++++ 7 files changed, 1688 insertions(+), 29 deletions(-) create mode 100644 tests/test_dematic_arvato.lsp create mode 100644 tests/testdata/dematic_arvato.json diff --git a/lib/dxf_scan_components.py b/lib/dxf_scan_components.py index 2cb37f2..043bd20 100644 --- a/lib/dxf_scan_components.py +++ b/lib/dxf_scan_components.py @@ -44,6 +44,7 @@ import struct import sys from ezdxf.lldxf.types import BINARY_DATA, INT16, INT32, INT64, DOUBLE, BYTES +from ezdxf.lldxf.types import cast_tag_value from ezdxf.math import Matrix44, OCS sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) @@ -62,6 +63,10 @@ MAX_PAAR_ABSTAND = 60000.0 # 10 mm deckt Rundungs- und Zeichenungenauigkeiten der Fremdzeichnung ab. GERADE_MAX_DELTA_H = 10.0 +# Projektkennung in den erzeugten IDs (Kreisel__01 ...); main() +# setzt sie aus --projekt bzw. dem Namen der DXF-Datei. +PROJEKT = "HundM05" + # Toleranz fuer die Dedup-Rundung (Nachkommastellen). RUND = 2 @@ -190,6 +195,48 @@ def iter_binary_tags(mm): yield code, value +def iter_ascii_tags(mm): + """Streamt (code, value)-Tags aus einem ASCII-DXF. + + Gegenstueck zu iter_binary_tags fuer Zeichnungen, die als Text-DXF + gespeichert wurden (z.B. Dematic_arvato.dxf). Die Werte werden ueber die + ezdxf-Typtabelle in float/int gewandelt, damit lese_inserts dieselben + Typen sieht wie beim binaeren Lesen. + """ + i = 0 + n = len(mm) + while i < n: + end = mm.find(b"\n", i) + if end < 0: + break + code_raw = mm[i:end].strip() + i = end + 1 + end = mm.find(b"\n", i) + if end < 0: + end = n + value_raw = mm[i:end].rstrip(b"\r") + i = end + 1 + if not code_raw: + continue + code = int(code_raw) + value = decode_str(value_raw) + if code == 0: + value = value.strip() + else: + try: + value = cast_tag_value(code, value) + except ValueError: + pass + yield code, value + + +def iter_tags(mm): + """Binaer- oder ASCII-DXF anhand der Kopfzeile erkennen.""" + if mm[:22] == b"AutoCAD Binary DXF\r\n\x1a\x00": + return iter_binary_tags(mm) + return iter_ascii_tags(mm) + + # --------------------------------------------------------------------------- # Familien-Erkennung (Blockname -> Bauteilfamilie) # --------------------------------------------------------------------------- @@ -197,8 +244,8 @@ def iter_binary_tags(mm): # mit Wildcards - die Blocknamen der Fremdzeichnungen enthalten Umlaute und # Sonderzeichen (z.B. "3D_Schraegfoerderer_Antrieb", "TEF_Bogen_90Grad_..."). FAMILIEN = [ - ("kreisel_an", ["AN8", "AN8_*"]), - ("kreisel_sp", ["SP8", "SP8_*"]), + ("kreisel_an", ["AN8", "AN8_*", "AN8 Pinband*"]), + ("kreisel_sp", ["SP8", "SP8_*", "SP8 Pinband*"]), ("foerderer_antrieb", ["3D_TEF_Antrieb*", "3D_FF_Antrieb*", "3D_Schr*rderer_Antrieb*", "Antrieb FF"]), ("foerderer_umlenk", ["3D_TEF_Umlenk*", "3D_FF_Umlenk*", @@ -443,7 +490,7 @@ def lese_inserts(dxf_path): fh.close() raise try: - for code, value in iter_binary_tags(mm): + for code, value in iter_tags(mm): if code == 0: # Ein ATTRIB endet immer am naechsten 0-Tag. Erst hier steht # sicher fest, dass Tag UND Wert gelesen sind - in einem ATTRIB @@ -496,6 +543,19 @@ def lese_inserts(dxf_path): block_merken(aktueller_block)["kinder"].add(value) elif aktuell == "ATTRIB": attrib_tag = value + elif aktuell == "CIRCLE" and aktueller_block and code in (10, 20, 30): + # Mittelpunkt des ERSTEN Kreises der Blockdefinition merken - + # bei AN8/SP8 ist das das Rad. Die Pinband-Varianten in + # Dematic_arvato.dxf haben ihr Rad ~15 m neben dem + # Einfuegepunkt; ohne diesen Wert laege der Kreisel dort. + # Ein zweiter Kreis beginnt mit Code 10, waehrend "kreis" schon + # existiert - ab da ist der erste fertig (Code 30 ist optional). + info = block_merken(aktueller_block) + if code == 10 and "kreis" in info: + info["kreis_fertig"] = True + if not info.get("kreis_fertig"): + kreis = info.setdefault("kreis", [0.0, 0.0, 0.0]) + kreis[{10: 0, 20: 1, 30: 2}[code]] = value elif aktuell == "BLOCK" and aktueller_block and code in (10, 20, 30): block_base[aktueller_block][{10: 0, 20: 1, 30: 2}[code]] = value elif aktuell == "INSERT" and rec is not None: @@ -630,6 +690,13 @@ def sammle_vorkommen(ms_inserts, block_inserts, block_base, max_tiefe=12, xachse = mat.transform((1.0, 0.0, 0.0)) - ursprung rot = math.degrees(math.atan2(xachse.y, xachse.x)) % 360.0 fam = familie_von(rec["name"]) + # Kreisel-Stationen: Position = Radmitte, nicht Einfuegepunkt + # (siehe "kreis" in lese_inserts). Die Rotation oben bleibt die + # des Inserts. + kreis = ((block_info or {}).get(rec["name"], {}).get("kreis") + if fam in ("kreisel_an", "kreisel_sp") else None) + if kreis: + ursprung = mat.transform(tuple(kreis)) if fam: treffer.append({ "familie": fam, @@ -866,6 +933,48 @@ def zwillinge_zusammenfuehren(treffer): # Paarbildung und Schema-Abbildung # --------------------------------------------------------------------------- +# Querversatz (mm), bis zu dem AN8 und SP8 noch auf derselben Kreisel-Achse +# liegen. Beide Stationen sitzen auf der Mittellinie des Kreisels; in +# Dematic_arvato.dxf liegen echte Paare auf 0,2 mm genau auf einer Achse. +KREISEL_MAX_QUER = 100.0 + + +def kreisel_paare_bilden(an_liste, sp_liste): + """AN8 und SP8 zu Kreiseln paaren. + + Global nach Abstand (kuerzestes Paar zuerst) statt AN8 fuer AN8 in + X-Reihenfolge: dort griff sich ein frueh sortierter AN8 die naechste noch + freie SP8 eines Nachbar-Kreisels, und alle folgenden Paare rutschten mit + (Dematic_arvato: ein 33,5-m-Kreisel wurde mit der SP8 eines 3,6-m-Kreisels + 19 m daneben gepaart). Zusaetzlich muessen beide auf einer gemeinsamen + Achse liegen (Querversatz <= KREISEL_MAX_QUER). + + Rueckgabe: (paare [(an, sp, abstand)] nach AN-Position sortiert, + AN8 ohne Partner, SP8 ohne Partner) + """ + kandidaten = [] + for ia, an in enumerate(an_liste): + for isp, sp in enumerate(sp_liste): + dx = abs(sp["x"] - an["x"]) + dy = abs(sp["y"] - an["y"]) + if min(dx, dy) > KREISEL_MAX_QUER: + continue + kandidaten.append((math.hypot(dx, dy), ia, isp)) + kandidaten.sort() + an_frei = set(range(len(an_liste))) + sp_frei = set(range(len(sp_liste))) + paare = [] + for dist, ia, isp in kandidaten: + if ia in an_frei and isp in sp_frei: + an_frei.discard(ia) + sp_frei.discard(isp) + paare.append((an_liste[ia], sp_liste[isp], dist)) + paare.sort(key=lambda p: (p[0]["x"], p[0]["y"])) + return (paare, + [an_liste[i] for i in sorted(an_frei)], + [sp_liste[i] for i in sorted(sp_frei)]) + + def paare_bilden(antriebe, umlenkungen): """Gegenseitig naechste Nachbarn paaren. @@ -978,7 +1087,7 @@ def foerderer_eintrag(a, u, dist_xy, nummer, gf_winkel_min): # Die echte Hoehe liefert der 3D-Zwilling (siehe Zusammenfuehrung). if a.get("darstellung") == "2D": return { - "test_id": "GERADE_HundM05_%02d" % nummer, + "test_id": "GERADE_%s_%02d" % (PROJEKT, nummer), "typ": "gerade", "darstellung": "2D", "laenge": round(dist_xy, RUND), @@ -993,7 +1102,7 @@ def foerderer_eintrag(a, u, dist_xy, nummer, gf_winkel_min): if abs(dz) < GERADE_MAX_DELTA_H: return { - "test_id": "GERADE_HundM05_%02d" % nummer, + "test_id": "GERADE_%s_%02d" % (PROJEKT, nummer), "typ": "gerade", "darstellung": a.get("darstellung", "?"), "laenge": round(dist_xy, RUND), @@ -1008,7 +1117,7 @@ def foerderer_eintrag(a, u, dist_xy, nummer, gf_winkel_min): if dz < 0 and neigung >= gf_winkel_min: return { - "test_id": "GF_HundM05_%02d" % nummer, + "test_id": "GF_%s_%02d" % (PROJEKT, nummer), "modus": 1, "darstellung": a.get("darstellung", "?"), "deltaL_mm": round(dist_xy, RUND), @@ -1025,7 +1134,7 @@ def foerderer_eintrag(a, u, dist_xy, nummer, gf_winkel_min): } return { - "test_id": "VF_HundM05_%02d" % nummer, + "test_id": "VF_%s_%02d" % (PROJEKT, nummer), "typ": "standard", "darstellung": a.get("darstellung", "?"), "richtung": "Auf" if dz > 0 else "Ab", @@ -1116,16 +1225,12 @@ def baue_eintraege(treffer, defaults, boegen, weichen, # --- Kreisel: AN8 (Antriebsstation) + SP8 (Spannstation) -------------- durchmesser = defaults.get("kreisel", {}).get("durchmesser", 800.0) - an_liste = sorted(nach_familie.get("kreisel_an", []), key=lambda t: (t["x"], t["y"])) - sp_liste = list(nach_familie.get("kreisel_sp", [])) - for i, an in enumerate(an_liste, start=1): - if not sp_liste: - hinweise.append("AN8 bei (%.2f, %.2f) ohne SP8-Partner" % (an["x"], an["y"])) - eintraege.append(sensor_eintrag(an, bekannte_bloecke, hinweise, treffer)) - continue - sp = min(sp_liste, key=lambda s: math.hypot(s["x"] - an["x"], s["y"] - an["y"])) - sp_liste.remove(sp) - dist = math.hypot(sp["x"] - an["x"], sp["y"] - an["y"]) + kreisel_paare, an_rest, sp_liste = kreisel_paare_bilden( + nach_familie.get("kreisel_an", []), nach_familie.get("kreisel_sp", [])) + for an in an_rest: + hinweise.append("AN8 bei (%.2f, %.2f) ohne SP8-Partner" % (an["x"], an["y"])) + eintraege.append(sensor_eintrag(an, bekannte_bloecke, hinweise, treffer)) + for i, (an, sp, dist) in enumerate(kreisel_paare, start=1): rotation = math.degrees(math.atan2(sp["y"] - an["y"], sp["x"] - an["x"])) % 360.0 # AN8/SP8 sind flache 2D-Symbole auf Z=0 - die Einbauhoehe steht nicht # im DXF. Sie wird aus den 3D-Modellen in der Umgebung abgeleitet @@ -1144,19 +1249,31 @@ def baue_eintraege(treffer, defaults, boegen, weichen, hoehe_hinweis = (" ACHTUNG hoehe=%.1f ist NICHT belegt: " "AN8/SP8 sind flache 2D-Symbole auf Z=0 und " "%s." % (hoehe, grund)) + # an/sp sind Radmitten (siehe "kreis" in lese_inserts). draw-module + # (KreiselInsert.lsp) legt AN8 bei (radius, 0) und SP8 bei + # (radius + abstand, 0) in den Block: abstand ist also der + # Mittenabstand, und der Einfuegepunkt liegt einen Radius VOR der + # AN8-Mitte. Die fruehere "connect"-Ausgabe uebergab die Radmitten an + # kreisel-connect-script, das Aussenkanten erwartet - der Kreisel + # wurde dadurch an beiden Enden um einen Radius zu kurz. + radius = durchmesser / 2.0 + richtung = math.radians(rotation) eintraege.append({ - "id": "Kreisel_HundM05_%02d" % i, - "function": "connect", - "start_x": an["x"], "start_y": an["y"], "start_z": an["z"], - "end_x": sp["x"], "end_y": sp["y"], "end_z": sp["z"], + "id": "Kreisel_%s_%02d" % (PROJEKT, i), + "function": "insert", + "x": round(an["x"] - radius * math.cos(richtung), RUND) + 0.0, + "y": round(an["y"] - radius * math.sin(richtung), RUND) + 0.0, + "z": hoehe, + "abstand": round(dist, RUND), + "rotation": round(rotation, RUND) + 0.0, "typ": "STANDARD", "darstellung": an.get("darstellung", "?"), - "hoehe": hoehe, - "comment": ("aus DXF: AN8 (Layer %s) -> SP8 (Layer %s), Abstand " - "%.2f; daraus folgt produktionsseitig abstand = %.2f - " - "%.1f = %.2f und rotation = %.2f Grad." - % (an["layer"], sp["layer"], dist, dist, durchmesser, - dist - durchmesser, rotation)) + hoehe_hinweis, + "comment": ("aus DXF: Radmitte %s (Layer %s) (%.2f, %.2f) -> " + "%s (Layer %s) (%.2f, %.2f), Mittenabstand %.2f, " + "rotation %.2f Grad; x/y = AN8-Mitte minus Radius." + % (an["block"], an["layer"], an["x"], an["y"], + sp["block"], sp["layer"], sp["x"], sp["y"], dist, + rotation)) + hoehe_hinweis, }) for sp in sp_liste: hinweise.append("SP8 bei (%.2f, %.2f) ohne AN8-Partner" % (sp["x"], sp["y"])) @@ -1188,7 +1305,7 @@ def baue_eintraege(treffer, defaults, boegen, weichen, hinweise.append("Omniflo %s ohne Sivasnr: '%s' (%s)" % (typ, t["block"], grund)) eintraege.append({ - "id": sivasnr or ("%s_HundM05_%02d" % (typ.upper(), i)), + "id": sivasnr or ("%s_%s_%02d" % (typ.upper(), PROJEKT, i)), "type": typ, "sivasnr": sivasnr, "x": t["x"], "y": t["y"], "z": t["z"], @@ -1346,7 +1463,7 @@ def main(): description="Erkennt ILS-/Omniflo-Komponenten in einem fremden DXF " "und schreibt sie im JSON-Schema aus " "tests/testdata/object_data.md.") - parser.add_argument("dxf", help="Quellzeichnung (binaeres DXF)") + parser.add_argument("dxf", help="Quellzeichnung (binaeres oder ASCII-DXF)") parser.add_argument("data_dir", help="Datenverzeichnis mit json/") parser.add_argument("output", help="Ziel-JSON") parser.add_argument("--fenster", nargs=4, type=float, @@ -1354,8 +1471,13 @@ def main(): help="Nur Bauteile in diesem XY-Fenster (mm) " "ausgeben - fuer den Nachbau eines einzelnen " "Anlagenabschnitts statt der ganzen Zeichnung") + parser.add_argument("--projekt", + help="Projektkennung in den erzeugten IDs " + "(Default: Name der DXF-Datei ohne Endung)") args = parser.parse_args() dxf_path, data_dir, output_path = args.dxf, args.data_dir, args.output + global PROJEKT + PROJEKT = args.projekt or os.path.splitext(os.path.basename(dxf_path))[0] fenster = None if args.fenster: x0, y0, x1, y1 = args.fenster diff --git a/menu/SSG_LIB.cui b/menu/SSG_LIB.cui index 0cd7164..369b401 100644 --- a/menu/SSG_LIB.cui +++ b/menu/SSG_LIB.cui @@ -734,6 +734,12 @@ ^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_hundm05.lsp")) (c:TEST_HUNDM05) + + + Dematic/Arvato Flowpuffer (Vorlage) + ^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_dematic_arvato.lsp")) (c:TEST_DEMATIC_ARVATO) + + KS 2D/3D pruefen (CSV) @@ -1627,6 +1633,12 @@ + + Dematic/Arvato Flowpuffer (Vorlage) + + + + KS 2D/3D pruefen (CSV) diff --git a/menu/SSG_LIB.mnu b/menu/SSG_LIB.mnu index 578eece..703b508 100644 --- a/menu/SSG_LIB.mnu +++ b/menu/SSG_LIB.mnu @@ -154,6 +154,7 @@ [Gefaellestrecke]^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_gefaellestrecke.lsp")) (c:TEST_GEFAELLESTRECKE) [Mubea Gesamtmodell]^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_mubea.lsp")) (c:TEST_MUBEA) [HundM05 Kreisel-Abschnitt]^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_hundm05.lsp")) (c:TEST_HUNDM05) +[Dematic/Arvato Flowpuffer (Vorlage)]^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_dematic_arvato.lsp")) (c:TEST_DEMATIC_ARVATO) [<-KS 2D/3D pruefen (CSV)]^C^C(load (strcat (getenv "DXFMAKRO") "/Lisp/ks_pruefung.lsp")) KS_PRUEFEN ***DOUBLECLICK diff --git a/tests/alltests.json b/tests/alltests.json index dc98cb9..f427384 100644 --- a/tests/alltests.json +++ b/tests/alltests.json @@ -10,5 +10,6 @@ { "name": "gefaellestrecke", "save": "dwg", "module": "Gefaellestrecke" }, { "name": "mubea", "save": "dxf", "module": "KreiselInsert" }, { "name": "hundm05", "save": "dxf", "module": "VarioFoerderer" }, + { "name": "dematic_arvato", "save": "dxf", "module": "VarioFoerderer", "disabled": true }, { "name": "hm_recformat", "save": "dxf", "module": "VarioFoerderer", "disabled": true } ] diff --git a/tests/test_dematic_arvato.lsp b/tests/test_dematic_arvato.lsp new file mode 100644 index 0000000..7823b7a --- /dev/null +++ b/tests/test_dematic_arvato.lsp @@ -0,0 +1,138 @@ +;; ============================================================ +;; test_dematic_arvato.lsp - Nachbau des Abschnitts Flowpuffer/Kreisel der +;; Anlage Dematic/Arvato aus der Scanner-Vorlage. +;; +;; Datenquelle: tests/testdata/dematic_arvato.json, erzeugt mit +;; python lib/dxf_scan_components.py \ +;; C:/develop/sps_skel/data/Dematic_arvato.dxf data \ +;; tests/testdata/dematic_arvato.json --projekt Arvato \ +;; --fenster -3000 159000 49000 193000 +;; +;; Die Datei ist eine VORLAGE fuer den Nachbau, kein fertiger Testfall: +;; Hoehen fehlen (flaches 2D-Schema, alles auf Z=0), Seiten/Winkel einiger +;; Bloecke sind geraten (siehe "comment" je Eintrag). +;; +;; Eintragsarten (Schema von dxf_scan_components.py): +;; "function": "insert" ohne "block" -> Kreisel (hundm05:bau-kreisel -> +;; kreisel-insert-script; x/y = Einfuegepunkt +;; einen Radius vor der AN8-Radmitte, abstand = +;; Mittenabstand AN8-SP8) +;; "function": "insert" + "block" -> Einzelblock (hundm05:bau-sensor, +;; Fallback Separator_SP bei unbekanntem Block) +;; "typ": "gerade" -> waagrechter Foerderer Antrieb->Umlenkung - +;; dafuer gibt es noch keinen Bau-Pfad, wird +;; gemeldet und uebersprungen +;; +;; Keine eigene Bau-Logik: hundm05:bau-kreisel/-sensor aus +;; tests/test_hundm05.lsp wird mitgeladen (die Datei definiert nur Funktionen). +;; +;; Aufruf in BricsCAD: +;; (load (strcat (getenv "DXFMAKRO") "/tests/test_dematic_arvato.lsp")) +;; TEST_DEMATIC_ARVATO +;; ============================================================ + +(if (not (boundp '*dematic-arvato-records*)) (setq *dematic-arvato-records* nil)) + +;; Module und die Bau-Funktionen aus test_hundm05.lsp beim LADEN dieser Datei +;; holen, nicht erst in c:TEST_DEMATIC_ARVATO: in BricsCAD werden per load +;; definierte Funktionen erst nach Rueckkehr zum Top-Level sichtbar (siehe +;; tests/test_unit.scr). +(ssg-ensure "KreiselInsert") +(ssg-ensure "VarioFoerderer") +(ssg-ensure "SSG_LIB_Commands") +(if (null (car (atoms-family 1 '("HUNDM05:BAU-SENSOR")))) + (load (strcat (getenv "DXFMAKRO") "/tests/test_hundm05.lsp"))) + +(defun dematic_arvato:datei () + (strcat (getenv "DXFMAKRO") "/tests/testdata/dematic_arvato.json")) + +;; Foerderer "gerade": noch kein Bau-Pfad - nur melden. +(defun dematic_arvato:gerade-melden (obj / tid rec) + (setq tid (ssg-val obj "test_id")) + (princ (strcat "\n [GERADE] " (if tid tid "?") + " uebersprungen - waagrechter Foerderer noch nicht unterstuetzt")) + (setq rec (vsp-rec-neu (if tid tid "(ohne id)"))) + (setq rec (vsp-set rec "kind" "gerade")) + (vsp-set (vsp-set rec "status" "uebersprungen") "fehler_text" + "kein Bau-Pfad fuer typ gerade")) + +(defun dematic_arvato:bau-eintrag (obj / kind res) + (cond + ((and (= (ssg-val obj "function") "insert") (ssg-val obj "block")) + (setq kind "sensor") + (setq res (vl-catch-all-apply 'hundm05:bau-sensor (list obj)))) + ((= (ssg-val obj "function") "insert") + (setq kind "kreisel") + (setq res (vl-catch-all-apply 'hundm05:bau-kreisel (list obj)))) + ((= (ssg-val obj "typ") "gerade") + (setq kind "gerade") + (setq res (dematic_arvato:gerade-melden obj))) + (T + (setq kind "unbekannt") + (princ "\n WARNUNG: unbekannter Eintrag uebersprungen") + (setq res (vsp-set (vsp-rec-neu "(unbekannt)") "status" "uebersprungen")))) + (if (vl-catch-all-error-p res) + (progn + (princ (strcat "\n [" (strcase kind) "] Ausnahme: " + (vl-catch-all-error-message res))) + (vsp-set (vsp-set (vsp-set (vsp-rec-neu (cond ((ssg-val obj "id")) + ((ssg-val obj "block")) + ("?"))) + "kind" kind) "status" "abbruch") + "fehler_text" (vl-catch-all-error-message res))) + res)) + +(defun c:TEST_DEMATIC_ARVATO ( / datei daten out zaehler st) + (setq datei (dematic_arvato:datei)) + (princ "\n\n================================================================") + (princ "\n TEST_DEMATIC_ARVATO - Abschnitt Flowpuffer/Kreisel (Vorlage)") + (princ (strcat "\n " datei)) + (princ "\n================================================================") + (cond + ((null (car (atoms-family 1 '("VSP-REC-NEU")))) + (princ "\n[TEST_DEMATIC_ARVATO] FEHLER: vf_spec.lsp nicht geladen" + " (VarioFoerderer laden).") + (setq *dematic-arvato-records* nil)) + ((null (findfile datei)) + (princ (strcat "\n[TEST_DEMATIC_ARVATO] FEHLER: " datei " nicht gefunden!")) + (setq *dematic-arvato-records* nil)) + (T + (setq daten (ssg-json-laden datei)) + (princ (strcat "\n " (itoa (length daten)) " Eintraege geladen")) + (ssg-start "TEST_DEMATIC_ARVATO" + '(("OSMODE") ("CECOLOR") ("ATTREQ") ("ATTDIA"))) + (setvar "OSMODE" 0) + (setvar "ATTREQ" 0) + (setvar "ATTDIA" 0) + (setq out '()) + (foreach obj daten + (setq out (cons (dematic_arvato:bau-eintrag obj) out))) + (ssg-end) + (setq *dematic-arvato-records* (reverse out)) + ;; Zusammenfassung je Status + (setq zaehler '()) + (foreach r *dematic-arvato-records* + (setq st (cond ((ssg-val r "status")) ("?"))) + (if (assoc st zaehler) + (setq zaehler (subst (cons st (1+ (cdr (assoc st zaehler)))) + (assoc st zaehler) zaehler)) + (setq zaehler (cons (cons st 1) zaehler)))) + (princ "\n================================================================") + (foreach z (reverse zaehler) + (princ (strcat "\n " (car z) ": " (itoa (cdr z))))) + (princ "\n================================================================") + (command "_.ZOOM" "_E"))) + (princ)) + +;; Ergebnis-Export (Konvention :export-results fuer test_run_all.lsp) +(defun dematic_arvato:export-results (out-dir / pfad) + (if (null *dematic-arvato-records*) + (princ "\n Keine Dematic/Arvato-Ergebnisse vorhanden.") + (progn + (vl-mkdir out-dir) + (setq pfad (strcat out-dir "/dematic_arvato_results.json")) + (vsp-results-schreiben *dematic-arvato-records* pfad))) + (princ)) + +(princ "\nTEST_DEMATIC_ARVATO geladen. Aufruf: TEST_DEMATIC_ARVATO") +(princ) diff --git a/tests/test_hundm05.lsp b/tests/test_hundm05.lsp index e579570..4ca9f40 100644 --- a/tests/test_hundm05.lsp +++ b/tests/test_hundm05.lsp @@ -138,6 +138,10 @@ (defun hundm05:bau-sensor (obj / id blockname x y z rotation pt eff n vorher ent ed attribs rec) (setq id (ssg-val obj "id")) (setq blockname (ssg-val obj "block")) + ;; Eintraege aus lib/dxf_scan_components.py haben kein "id" - die + ;; Meldungen unten setzen id per strcat zusammen und brachen dann mit + ;; "bad argument type " ab. + (if (null id) (setq id (cond (blockname) ("(ohne id)")))) (setq x (ssg-val obj "x") y (ssg-val obj "y") z (ssg-val obj "z") diff --git a/tests/testdata/dematic_arvato.json b/tests/testdata/dematic_arvato.json new file mode 100644 index 0000000..b9c122c --- /dev/null +++ b/tests/testdata/dematic_arvato.json @@ -0,0 +1,1381 @@ +[ + { + "id": "Kreisel_Arvato_03", + "function": "insert", + "x": 18737.94, + "y": 165252.93, + "z": 0.0, + "abstand": 3619.15, + "rotation": 90.0, + "typ": "STANDARD", + "darstellung": "2D", + "comment": "aus DXF: Radmitte AN8 (Layer 1ANTR-800) (18737.94, 165652.93) -> SP8 (Layer 1SP-800) (18737.94, 169272.08), Mittenabstand 3619.15, rotation 90.00 Grad; x/y = AN8-Mitte minus Radius. ACHTUNG hoehe=0.0 ist NICHT belegt: AN8/SP8 sind flache 2D-Symbole auf Z=0 und nur 0 3D-Nachbarn in 3000 mm - zu wenige fuer eine belegbare Hoehe." + }, + { + "id": "Kreisel_Arvato_04", + "function": "insert", + "x": 35394.31, + "y": 176069.0, + "z": 370.0, + "abstand": 33044.28, + "rotation": 180.0, + "typ": "STANDARD", + "darstellung": "2D", + "comment": "aus DXF: Radmitte AN8 Pinband (Layer 1ANTR-800) (34994.31, 176069.00) -> SP8 Pinband (mit Inkrementalgeber 829522024) (Layer 1SP-800) (1950.03, 176069.00), Mittenabstand 33044.28, rotation 180.00 Grad; x/y = AN8-Mitte minus Radius. ACHTUNG hoehe=370.0 ist NICHT belegt: AN8/SP8 sind flache 2D-Symbole auf Z=0 und nur 0 3D-Nachbarn in 3000 mm - zu wenige fuer eine belegbare Hoehe." + }, + { + "id": "Kreisel_Arvato_05", + "function": "insert", + "x": 36195.18, + "y": 188428.08, + "z": 0.0, + "abstand": 33470.18, + "rotation": 180.0, + "typ": "STANDARD", + "darstellung": "2D", + "comment": "aus DXF: Radmitte AN8 (Layer 1ANTR-800) (35795.18, 188428.08) -> SP8 (Layer 1SP-800) (2325.00, 188428.08), Mittenabstand 33470.18, rotation 180.00 Grad; x/y = AN8-Mitte minus Radius. ACHTUNG hoehe=0.0 ist NICHT belegt: AN8/SP8 sind flache 2D-Symbole auf Z=0 und nur 0 3D-Nachbarn in 3000 mm - zu wenige fuer eine belegbare Hoehe." + }, + { + "id": "Kreisel_Arvato_06", + "function": "insert", + "x": 42097.73, + "y": 165252.93, + "z": 0.0, + "abstand": 3619.15, + "rotation": 90.0, + "typ": "STANDARD", + "darstellung": "2D", + "comment": "aus DXF: Radmitte AN8 (Layer 1ANTR-800) (42097.73, 165652.93) -> SP8 (Layer 1SP-800) (42097.72, 169272.08), Mittenabstand 3619.15, rotation 90.00 Grad; x/y = AN8-Mitte minus Radius. ACHTUNG hoehe=0.0 ist NICHT belegt: AN8/SP8 sind flache 2D-Symbole auf Z=0 und nur 0 3D-Nachbarn in 3000 mm - zu wenige fuer eine belegbare Hoehe." + }, + { + "test_id": "GERADE_Arvato_01", + "typ": "gerade", + "darstellung": "2D", + "laenge": 8313.39, + "hz": 90.0, + "startpunkt": [2334.97, 177818.67, 0.0], + "endpunkt": [2334.96, 186132.06, 0.0], + "hoehe_unbekannt": true, + "comment": "aus DXF: Antrieb FF -> Umlenkung FF (Layer z-3 / z-3), Achse 90 Grad, Laenge 8313.39, Querversatz 0.01 (Bezugspunkt-Unterschied), Neigung 0.00 Grad; 2D-Schema - Z ist dort keine Einbauhoehe, darum waagrechte Strecke und hoehe_unbekannt=true. Einbauhoehe nur ueber den 3D-Zwilling zu bekommen." + }, + { + "test_id": "GERADE_Arvato_09", + "typ": "gerade", + "darstellung": "2D", + "laenge": 8313.39, + "hz": 90.0, + "startpunkt": [14264.99, 177818.71, 0.0], + "endpunkt": [14264.99, 186132.1, 0.0], + "hoehe_unbekannt": true, + "comment": "aus DXF: Antrieb FF -> Umlenkung FF (Layer z-3 / z-3), Achse 90 Grad, Laenge 8313.39, Querversatz 0.00 (Bezugspunkt-Unterschied), Neigung 0.00 Grad; 2D-Schema - Z ist dort keine Einbauhoehe, darum waagrechte Strecke und hoehe_unbekannt=true. Einbauhoehe nur ueber den 3D-Zwilling zu bekommen." + }, + { + "test_id": "GERADE_Arvato_10", + "typ": "gerade", + "darstellung": "2D", + "laenge": 3183.28, + "hz": 270.0, + "startpunkt": [19545.38, 174003.47, 370.0], + "endpunkt": [19545.58, 170820.19, 0.0], + "hoehe_unbekannt": true, + "comment": "aus DXF: Antrieb FF -> Umlenkung FF (Layer z-3 / z-3), Achse 270 Grad, Laenge 3183.28, Querversatz 0.20 (Bezugspunkt-Unterschied), Neigung 6.63 Grad; 2D-Schema - Z ist dort keine Einbauhoehe, darum waagrechte Strecke und hoehe_unbekannt=true. Einbauhoehe nur ueber den 3D-Zwilling zu bekommen." + }, + { + "test_id": "GERADE_Arvato_11", + "typ": "gerade", + "darstellung": "2D", + "laenge": 17664.81, + "hz": 0.0, + "startpunkt": [21626.92, 167134.77, 0.0], + "endpunkt": [39291.73, 167134.97, 0.0], + "hoehe_unbekannt": true, + "comment": "aus DXF: Antrieb FF -> Umlenkung FF (Layer z-3 / z-3), Achse 0 Grad, Laenge 17664.81, Querversatz 0.20 (Bezugspunkt-Unterschied), Neigung 0.00 Grad; 2D-Schema - Z ist dort keine Einbauhoehe, darum waagrechte Strecke und hoehe_unbekannt=true. Einbauhoehe nur ueber den 3D-Zwilling zu bekommen." + }, + { + "test_id": "GERADE_Arvato_12", + "typ": "gerade", + "darstellung": "2D", + "laenge": 3124.62, + "hz": 0.0, + "startpunkt": [21626.97, 165578.18, 0.0], + "endpunkt": [24751.59, 165578.37, 0.0], + "hoehe_unbekannt": true, + "comment": "aus DXF: Antrieb FF -> Umlenkung FF (Layer z-3 / z-3), Achse 0 Grad, Laenge 3124.62, Querversatz 0.19 (Bezugspunkt-Unterschied), Neigung 0.00 Grad; 2D-Schema - Z ist dort keine Einbauhoehe, darum waagrechte Strecke und hoehe_unbekannt=true. Einbauhoehe nur ueber den 3D-Zwilling zu bekommen." + }, + { + "test_id": "GERADE_Arvato_13", + "typ": "gerade", + "darstellung": "2D", + "laenge": 8313.39, + "hz": 90.0, + "startpunkt": [22854.62, 177818.71, 0.0], + "endpunkt": [22854.61, 186132.1, 0.0], + "hoehe_unbekannt": true, + "comment": "aus DXF: Antrieb FF -> Umlenkung FF (Layer z-3 / z-3), Achse 90 Grad, Laenge 8313.39, Querversatz 0.01 (Bezugspunkt-Unterschied), Neigung 0.00 Grad; 2D-Schema - Z ist dort keine Einbauhoehe, darum waagrechte Strecke und hoehe_unbekannt=true. Einbauhoehe nur ueber den 3D-Zwilling zu bekommen." + }, + { + "test_id": "GERADE_Arvato_14", + "typ": "gerade", + "darstellung": "2D", + "laenge": 6717.41, + "hz": 0.0, + "startpunkt": [32574.32, 165578.18, 0.0], + "endpunkt": [39291.73, 165578.37, 0.0], + "hoehe_unbekannt": true, + "comment": "aus DXF: Antrieb FF -> Umlenkung FF (Layer z-3 / z-3), Achse 0 Grad, Laenge 6717.41, Querversatz 0.19 (Bezugspunkt-Unterschied), Neigung 0.00 Grad; 2D-Schema - Z ist dort keine Einbauhoehe, darum waagrechte Strecke und hoehe_unbekannt=true. Einbauhoehe nur ueber den 3D-Zwilling zu bekommen." + }, + { + "test_id": "GERADE_Arvato_15", + "typ": "gerade", + "darstellung": "2D", + "laenge": 3706.41, + "hz": 180.0, + "startpunkt": [34650.88, 173417.91, 0.0], + "endpunkt": [30944.47, 173408.89, 0.0], + "hoehe_unbekannt": true, + "comment": "aus DXF: Antrieb FF -> Umlenkung FF (Layer z-3 / z-3), Achse 180 Grad, Laenge 3706.41, Querversatz 9.02 (Bezugspunkt-Unterschied), Neigung 0.00 Grad; 2D-Schema - Z ist dort keine Einbauhoehe, darum waagrechte Strecke und hoehe_unbekannt=true. Einbauhoehe nur ueber den 3D-Zwilling zu bekommen." + }, + { + "test_id": "GERADE_Arvato_16", + "typ": "gerade", + "darstellung": "2D", + "laenge": 3566.48, + "hz": 270.0, + "startpunkt": [41688.71, 185921.64, 0.0], + "endpunkt": [41678.01, 182355.16, 0.0], + "hoehe_unbekannt": true, + "comment": "aus DXF: Antrieb FF -> Umlenkung FF (Layer z-3 / z-3), Achse 270 Grad, Laenge 3566.48, Querversatz 10.70 (Bezugspunkt-Unterschied), Neigung 0.00 Grad; 2D-Schema - Z ist dort keine Einbauhoehe, darum waagrechte Strecke und hoehe_unbekannt=true. Einbauhoehe nur ueber den 3D-Zwilling zu bekommen." + }, + { + "function": "insert", + "block": "Vario_Motorstation_500mm_rechts", + "x": 41271.73, + "y": 171724.16, + "z": -370.0, + "rotation": 0.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'Antrieb FF', Layer 'z-3', auf Makro-Block 'Vario_Motorstation_500mm_rechts' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Seite=rechts - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "Vario_Umlenkstation_500mm_rechts", + "x": 30282.95, + "y": 174208.89, + "z": 0.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'Umlenkung FF', Layer 'z-3', auf Makro-Block 'Vario_Umlenkstation_500mm_rechts' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Seite=rechts - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "Vario_Umlenkstation_500mm_rechts", + "x": 36190.75, + "y": 186482.16, + "z": 0.0, + "rotation": 0.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'Umlenkung FF', Layer 'z-3', auf Makro-Block 'Vario_Umlenkstation_500mm_rechts' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Seite=rechts - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "Vario_Kurve_rechts_30_TEF_aussen", + "x": 41377.46, + "y": 179475.63, + "z": 0.0, + "rotation": 0.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'tef30°', Layer '0', auf Makro-Block 'Vario_Kurve_rechts_30_TEF_aussen' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Lage=aussen, Seite=rechts - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "Vario_Kurve_rechts_30_TEF_aussen", + "x": 35984.01, + "y": 173395.48, + "z": 0.0, + "rotation": 120.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'tef30°außen', Layer '0', auf Makro-Block 'Vario_Kurve_rechts_30_TEF_aussen' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Seite=rechts - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "Vario_Kurve_rechts_30_TEF_aussen", + "x": 36210.84, + "y": 173622.64, + "z": 0.0, + "rotation": 150.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'tef30°außen', Layer '0', auf Makro-Block 'Vario_Kurve_rechts_30_TEF_aussen' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Seite=rechts - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "Vario_Kurve_rechts_30_TEF_aussen", + "x": 36296.49, + "y": 173937.59, + "z": 0.0, + "rotation": 180.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'tef30°außen', Layer '0', auf Makro-Block 'Vario_Kurve_rechts_30_TEF_aussen' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Seite=rechts - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "Vario_Kurve_rechts_30_TEF_aussen", + "x": 41169.03, + "y": 187345.02, + "z": 0.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'tef30°außen', Layer '0', auf Makro-Block 'Vario_Kurve_rechts_30_TEF_aussen' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Seite=rechts - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "Vario_Kurve_rechts_30_TEF_aussen", + "x": 41483.98, + "y": 187259.38, + "z": 0.0, + "rotation": 240.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'tef30°außen', Layer '0', auf Makro-Block 'Vario_Kurve_rechts_30_TEF_aussen' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Seite=rechts - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "Vario_Kurve_rechts_30_TEF_aussen", + "x": 41711.14, + "y": 187032.54, + "z": 0.0, + "rotation": 210.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'tef30°außen', Layer '0', auf Makro-Block 'Vario_Kurve_rechts_30_TEF_aussen' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Seite=rechts - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "Vario_Kurve_rechts_30_TEF_aussen", + "x": 41784.82, + "y": 180461.57, + "z": 0.0, + "rotation": 180.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'tef30°außen', Layer '0', auf Makro-Block 'Vario_Kurve_rechts_30_TEF_aussen' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Seite=rechts - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "AS_Element_90_links", + "x": 2801.42, + "y": 186442.19, + "z": 0.0, + "rotation": 90.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "AS_Element_90_links", + "x": 4901.05, + "y": 178054.88, + "z": 370.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "AS_Element_90_links", + "x": 5801.05, + "y": 178054.88, + "z": 370.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "AS_Element_90_links", + "x": 6601.05, + "y": 178054.88, + "z": 370.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "AS_Element_90_links", + "x": 7401.05, + "y": 178054.88, + "z": 370.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "AS_Element_90_links", + "x": 8451.06, + "y": 178054.88, + "z": 370.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "AS_Element_90_links", + "x": 9251.06, + "y": 178054.88, + "z": 370.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "AS_Element_90_links", + "x": 10051.06, + "y": 178054.88, + "z": 370.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "AS_Element_90_links", + "x": 11391.05, + "y": 178054.91, + "z": 370.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "AS_Element_90_links", + "x": 12191.05, + "y": 178054.91, + "z": 370.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "AS_Element_90_links", + "x": 12991.05, + "y": 178054.91, + "z": 370.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "AS_Element_90_links", + "x": 14731.45, + "y": 186442.19, + "z": 0.0, + "rotation": 90.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "AS_Element_90_links", + "x": 15801.05, + "y": 178054.88, + "z": 370.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "AS_Element_90_links", + "x": 16601.05, + "y": 178054.88, + "z": 370.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "AS_Element_90_links", + "x": 17401.05, + "y": 178054.88, + "z": 370.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "AS_Element_90_links", + "x": 18448.56, + "y": 178054.88, + "z": 370.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "AS_Element_90_links", + "x": 19348.56, + "y": 178054.88, + "z": 370.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "AS_Element_90_links", + "x": 20148.56, + "y": 178054.88, + "z": 370.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "AS_Element_90_links", + "x": 20948.56, + "y": 178054.88, + "z": 370.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "AS_Element_90_links", + "x": 23321.08, + "y": 186442.19, + "z": 0.0, + "rotation": 90.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "AS_Element_90_links", + "x": 24608.56, + "y": 178054.88, + "z": 370.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "AS_Element_90_links", + "x": 25408.56, + "y": 178054.88, + "z": 370.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "AS_Element_90_links", + "x": 26908.55, + "y": 178054.88, + "z": 370.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "AS_Element_90_links", + "x": 27808.55, + "y": 178054.88, + "z": 370.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "AS_Element_90_links", + "x": 28608.55, + "y": 178054.88, + "z": 370.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "AS_Element_90_links", + "x": 29408.55, + "y": 178054.88, + "z": 370.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "AS_Element_90_links", + "x": 30958.55, + "y": 178054.88, + "z": 370.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "AS_Element_90_links", + "x": 31858.55, + "y": 178054.88, + "z": 370.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "AS_Element_90_links", + "x": 32658.55, + "y": 178054.88, + "z": 370.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "AS_Element_90_links", + "x": 33458.55, + "y": 178054.88, + "z": 370.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "AS_Element_90_rechts", + "x": 42932.74, + "y": 166073.59, + "z": 0.0, + "rotation": 180.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'Ausschleuselement rechts 200000241 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_rechts' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "AS_Element_90_rechts", + "x": 42932.74, + "y": 167630.19, + "z": 0.0, + "rotation": 180.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'Ausschleuselement rechts 200000241 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_rechts' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "ES_Element_90_rechts", + "x": 4958.03, + "y": 166992.08, + "z": 0.0, + "rotation": 90.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'Einschleuselement rechts 200000146 Seitenansicht', Layer '4-EE', auf Makro-Block 'ES_Element_90_rechts' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "ES_Element_90_rechts", + "x": 8058.82, + "y": 168049.64, + "z": 0.0, + "rotation": 90.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'Einschleuselement rechts 200000146 Seitenansicht', Layer '4-EE', auf Makro-Block 'ES_Element_90_rechts' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "ES_Element_30_rechts", + "x": 20513.9, + "y": 187602.73, + "z": -4.49, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'Einschleuselement rechts 30° 200000688 Vorderansicht', Layer '0', auf Makro-Block 'ES_Element_30_rechts' abgebildet; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-LP", + "x": 2572.67, + "y": 175669.0, + "z": 370.0, + "rotation": 0.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-LP', Layer '5SEP-LP'; Block 'S-LP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-LP", + "x": 3016.33, + "y": 188028.08, + "z": 0.0, + "rotation": 0.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-LP', Layer '5SEP-LP'; Block 'S-LP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-LP", + "x": 4628.04, + "y": 176469.0, + "z": 370.0, + "rotation": 180.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-LP', Layer '5SEP-LP'; Block 'S-LP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-LP", + "x": 14946.35, + "y": 188028.08, + "z": 0.0, + "rotation": 0.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-LP', Layer '5SEP-LP'; Block 'S-LP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-LP", + "x": 15528.05, + "y": 176469.05, + "z": 370.0, + "rotation": 180.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-LP', Layer '5SEP-LP'; Block 'S-LP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-LP", + "x": 19137.94, + "y": 168591.49, + "z": 0.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-LP', Layer '5SEP-LP'; Block 'S-LP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-LP", + "x": 23535.98, + "y": 188028.08, + "z": 0.0, + "rotation": 0.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-LP', Layer '5SEP-LP'; Block 'S-LP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-LP", + "x": 24328.05, + "y": 176469.09, + "z": 370.0, + "rotation": 180.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-LP', Layer '5SEP-LP'; Block 'S-LP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-LP", + "x": 34584.31, + "y": 176469.0, + "z": 370.0, + "rotation": 180.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-LP', Layer '5SEP-LP'; Block 'S-LP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-LP", + "x": 35391.12, + "y": 188828.08, + "z": 0.0, + "rotation": 180.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-LP', Layer '5SEP-LP'; Block 'S-LP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-LP", + "x": 41697.93, + "y": 167818.8, + "z": 0.0, + "rotation": 90.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-LP', Layer '5SEP-LP'; Block 'S-LP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 2334.91, + "y": 186756.85, + "z": 0.0, + "rotation": 90.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 2334.97, + "y": 176994.56, + "z": 370.0, + "rotation": 90.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 5367.5, + "y": 187359.42, + "z": 0.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 6267.5, + "y": 187359.42, + "z": 0.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 7067.5, + "y": 187359.42, + "z": 0.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 7867.5, + "y": 187359.42, + "z": 0.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 8917.51, + "y": 187359.42, + "z": 0.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 9717.51, + "y": 187359.42, + "z": 0.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 10517.51, + "y": 187359.42, + "z": 0.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 11857.51, + "y": 187359.45, + "z": 0.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 12657.51, + "y": 187359.45, + "z": 0.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 13457.51, + "y": 187359.45, + "z": 0.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 14264.94, + "y": 186756.89, + "z": 0.0, + "rotation": 90.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 14264.99, + "y": 176994.61, + "z": 370.0, + "rotation": 90.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 16267.51, + "y": 187359.42, + "z": 0.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 17067.51, + "y": 187359.42, + "z": 0.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 17867.51, + "y": 187359.42, + "z": 0.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 18915.01, + "y": 187359.42, + "z": 0.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 19546.07, + "y": 170249.91, + "z": 370.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 19546.07, + "y": 175157.16, + "z": 370.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 19680.48, + "y": 167135.46, + "z": 0.0, + "rotation": 0.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 19680.53, + "y": 165578.85, + "z": 0.0, + "rotation": 0.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 19815.01, + "y": 187359.42, + "z": 0.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 20615.01, + "y": 187359.42, + "z": 0.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 21415.01, + "y": 187359.42, + "z": 0.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 22854.57, + "y": 186756.89, + "z": 0.0, + "rotation": 90.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 22854.62, + "y": 176994.61, + "z": 370.0, + "rotation": 90.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 25075.01, + "y": 187359.42, + "z": 0.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 25462.17, + "y": 165578.85, + "z": 0.0, + "rotation": 0.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 25875.01, + "y": 187359.42, + "z": 0.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 27375.0, + "y": 187359.42, + "z": 0.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 28275.0, + "y": 187359.42, + "z": 0.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 29075.0, + "y": 187359.42, + "z": 0.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 29875.0, + "y": 187359.42, + "z": 0.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 30851.32, + "y": 174208.89, + "z": 0.0, + "rotation": 0.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 30944.14, + "y": 165578.85, + "z": 0.0, + "rotation": 0.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 31425.0, + "y": 187359.42, + "z": 0.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 31494.84, + "y": 173408.89, + "z": 0.0, + "rotation": 0.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 32325.0, + "y": 187359.42, + "z": 0.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 33125.0, + "y": 187359.42, + "z": 0.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 33925.0, + "y": 187359.42, + "z": 0.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 36195.18, + "y": 187066.18, + "z": 0.0, + "rotation": 90.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 39889.85, + "y": 167135.46, + "z": 0.0, + "rotation": 0.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 39889.9, + "y": 165578.85, + "z": 0.0, + "rotation": 0.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 41439.64, + "y": 169070.08, + "z": 0.0, + "rotation": 120.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 41697.72, + "y": 182892.95, + "z": 0.0, + "rotation": 90.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "Scanner", + "x": 3166.57, + "y": 188414.66, + "z": 0.0, + "rotation": 90.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'SCAN', Layer 'ZZSCANNER', auf Makro-Block 'Scanner' abgebildet; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "Scanner", + "x": 4477.8, + "y": 176855.58, + "z": 370.0, + "rotation": 90.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'SCAN', Layer 'ZZSCANNER', auf Makro-Block 'Scanner' abgebildet; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "Scanner", + "x": 15096.6, + "y": 188414.66, + "z": 0.0, + "rotation": 90.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'SCAN', Layer 'ZZSCANNER', auf Makro-Block 'Scanner' abgebildet; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "Scanner", + "x": 15377.81, + "y": 176855.63, + "z": 370.0, + "rotation": 90.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'SCAN', Layer 'ZZSCANNER', auf Makro-Block 'Scanner' abgebildet; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "Scanner", + "x": 23686.22, + "y": 188414.66, + "z": 0.0, + "rotation": 90.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'SCAN', Layer 'ZZSCANNER', auf Makro-Block 'Scanner' abgebildet; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "Scanner", + "x": 24177.81, + "y": 176855.68, + "z": 370.0, + "rotation": 90.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'SCAN', Layer 'ZZSCANNER', auf Makro-Block 'Scanner' abgebildet; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "Scanner", + "x": 25618.13, + "y": 165246.94, + "z": 0.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'SCAN', Layer 'ZZSCANNER', auf Makro-Block 'Scanner' abgebildet; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "Scanner", + "x": 30966.81, + "y": 165246.94, + "z": 0.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'SCAN', Layer 'ZZSCANNER', auf Makro-Block 'Scanner' abgebildet; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "Scanner", + "x": 41298.05, + "y": 167879.95, + "z": 0.0, + "rotation": 180.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'SCAN', Layer 'ZZSCANNER', auf Makro-Block 'Scanner' abgebildet; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + } +] From 36b6fdb650c0fde94736aed80bf38699057bca96 Mon Sep 17 00:00:00 2001 From: Samer Ayadi Date: Mon, 5 Oct 2026 17:05:13 +0200 Subject: [PATCH 4/4] [ADD] doc/json-input-lisp.md: JSON-Eingabeformate je Element (Kreisel, Einzelbloecke, VF Standard/Etage, GF Modus 1-3, VF-Linienzug Spec/Journal, Omniflo, gerade) aus tests/testdata mit Feldern, Koordinaten-Bezug und Bau-Routine - ersetzt das geloeschte tests/testdata/object_data.md; [ADD] doc/lisp_methods.md: Uebersicht der LISP-Bau-Routinen je Einheit (Befehl + skriptfaehiger Kern, Signaturen, Rueckgaben, Voraussetzungen, Einfuegeprimitiven) Co-Authored-By: Claude Opus 5.5 --- doc/json-input-lisp.md | 437 +++++++++++++++++++++++++++++++++++++++++ doc/lisp_methods.md | 328 +++++++++++++++++++++++++++++++ 2 files changed, 765 insertions(+) create mode 100644 doc/json-input-lisp.md create mode 100644 doc/lisp_methods.md diff --git a/doc/json-input-lisp.md b/doc/json-input-lisp.md new file mode 100644 index 0000000..1c90257 --- /dev/null +++ b/doc/json-input-lisp.md @@ -0,0 +1,437 @@ +# JSON-Eingabe fuer den LISP-Bau + +Welche Objekte sich aus einer JSON-Datei an einer gegebenen x/y/z-Koordinate +erzeugen lassen, in welchem Format sie beschrieben werden und welche +LISP-Routine sie baut. Grundlage sind die Testdaten in `tests/testdata/*.json` +und die Treiber in `tests/test_*.lsp`, die sie lesen. + +Die zugehoerigen LISP-Routinen mit Signaturen stehen in +[lisp_methods.md](lisp_methods.md). Diese Seite ersetzt das fruehere +`tests/testdata/object_data.md` (geloescht in Commit `e147b89`, auf das Code- +Kommentare teilweise noch verweisen). + +--- + +## 0. Uebersicht + +| Objekt | Erkennungsmerkmal im JSON | Bau-Routine (Produktion) | Koordinaten-Eingang | Beispiel-Datei | +|---|---|---|---|---| +| [Kreisel (Insert)](#1-kreisel) | `"function": "insert"`, KEIN `block` | `kreisel-insert-script` | `x`,`y`,`z` = Einfuegepunkt | `kreisel_tests.json`, `mubea.json`, `hundm05.json`, `dematic_arvato.json` | +| [Kreisel (Connect)](#12-connect-start--und-endpunkt) | `"function": "connect"` | `kreisel-connect-script` | `start_*`, `end_*` | (nur `test_kreisel.lsp`, z.Z. kein Datensatz) | +| [Einzelblock](#2-einzelbloecke-separator-scanner-btmt-eingangausgang-vario-bausteine) (Separator, Scanner, BTMT, Eingang/Ausgang, Vario-Bausteine) | `"function": "insert"` + `"block"` | direktes `_.INSERT` nach `ssg-ils-block-laden` | `x`,`y`,`z` + `rotation` | `mubea.json`, `hundm05.json`, `dematic_arvato.json` | +| [VarioFoerderer Standard](#3-variofoerderer-standard-und-etage) | `test_id` beginnt mit `VF_`, `typ` fehlt oder `"standard"` | `berechne-alle-winkel` + `variofoerderer-einfuegen` + `vf-block-erstellen` | `x`,`y`,`z` = KS_EIN des AS-Elements | `mubea.json`, `foerderer_tests.json` | +| [VarioFoerderer Etage](#3-variofoerderer-standard-und-etage) | `test_id` `VF_*` + `"typ": "etage"` | `berechne-etage` + `etage-foerderanlage-einfuegen` + `vf-block-erstellen` | wie Standard | `mubea.json` | +| [Gefaellestrecke Modus 1](#4-gefaellestrecke) | `test_id` `GF_*` bzw. `"modus": 1` | `gefaellestrecke-einfuegen` (bzw. `gf-rebuild`) | `start_mm` = KS_EIN des AS-Elements | `mubea.json`, `gefaellestrecke_tests.json` | +| [Gefaellestrecke Modus 2](#42-modus-2---richtung-aus-zwei-punkten) | `"modus": 2` | wie Modus 1, `deltaL`/`hz` aus zwei Punkten | `start_mm` + `linie_start_mm`/`linie_ende_mm` | `gefaellestrecke_tests.json` | +| [Gefaellestrecke Modus 3](#43-modus-3---linienzug) | `"modus": 3` | nur ueber `test_gefaellestrecke.lsp` | `start_mm`, `ende_mm`, `bogen` | `gefaellestrecke_tests.json` | +| [VF-Linienzug-Kette (Spec)](#5-vf-linienzug-kette-spec) | Kopf mit `spec_id`, danach `glied`/`sub` | `vsp-bau-aus-spec` (Replay durch `vf-linienzug-modus`) | `start_punkt` = Kettenanfang | `hundm05.json` | +| [VF-Linienzug (Journal)](#6-vf-linienzug-eingabe-journal) | Kopf mit `test_id`, danach `typ` = `point_abs`/`real`/`string`/... | `vfl-journal-replay-start` + `vf-linienzug-modus` | erstes `point_abs` | `linienzug_tests.json`, `hm_recformat.json` | +| [Omniflo Bogen/Weiche](#71-bogen-und-weiche) | `"type": "bogen"` / `"weiche"` + `sivasnr` | `_.INSERT` der `.dxf` (Kern `omni:insert-dxf` fragt den Punkt interaktiv) | `x`,`y`, Z = `hoehe` | `omniflo_tests.json`, `omniflo_strecke_tests.json` | +| [Omniflo Gerade](#72-aluprofil-gerade) | `"type": "gerade"` + `profil` | `omni:make-gerade` | `x`,`y` -> `x_ende`,`y_ende`, Z = `hoehe` | `omniflo_strecke_tests.json` | +| [Waagrechte Foerderstrecke](#8-waagrechte-foerderstrecke-gerade---noch-ohne-bau-pfad) | `"typ": "gerade"` + `startpunkt` | **kein Bau-Pfad** (wird gemeldet und uebersprungen) | `startpunkt`, `endpunkt` | `dematic_arvato.json` | + +Nicht aus JSON baubar (es gibt keine Testdaten und keinen Treiber): Eckrad, +Geruest, TEF-Foerderer-Linie, TRO-Marker, Connections, Omniflo-Ladeschleife. +Fuer Eckrad und Geruest existiert ein skriptfaehiger Kern, siehe +[lisp_methods.md](lisp_methods.md). + +### Allgemeine Regeln + +- **Einheiten**: Laengen und Koordinaten in **mm**, Winkel in **Grad**. + Fahrtrichtung `hz`: 0 = +X (Ost), 90 = +Y (Nord), 180 = -X, 270 = -Y. +- **Z ist absolut**: `z` (bzw. Z in `start_mm`/`start_punkt`) ist die + Weltkoordinate des Einfuegepunkts, also die Einbauhoehe. +- **Dimension 2D/3D**: Gebaut wird in der aktuellen Dimension + (`ssg-ils-dim-aktuell`: `*ssg-ils-dim*` -> `DXFM_DIM`, Default 3D). + Das Feld `darstellung` in `dematic_arvato.json` ist reine Dokumentation und + wird nicht ausgewertet; `TEST_HUNDM05_2D`/`_3D` erzwingen die Dimension. +- **Flaches JSON**: Die meisten Dateien werden mit `ssg-load-json` gelesen + (zeilenweise, ein Objekt je `{`). Verschachtelte Objekte und mehrzeilige + Arrays darin funktionieren nicht - darum stehen z.B. die Glieder einer + Kette als eigene Objekte hinter ihrem Kopf-Objekt. Ausnahme: + `TEST_DEMATIC_ARVATO` liest mit dem rekursiven `ssg-json-laden`. +- **Reine Doku-Felder**: `comment`, `beschreibung`, `description`, `quelle`, + `row`, `seq`, `gruppe`, `assigned_to`, `hoehe_unbekannt`, `darstellung` + sowie alle `expect_*`/`erwartung_*`-Felder werden beim Bau nicht gelesen. + `expect_*` pruefen die Python-Tests gegen das Ergebnis. +- **Template-Felder** (nur `test_mubea.lsp`): `anzahl`, `delta_x`, `delta_y` + erzeugen aus einem Eintrag `anzahl` Kopien, jeweils um `delta_x`/`delta_y` + versetzt; `test_id` bekommt dann das Suffix `_01` ... `_nn`. Gilt fuer VF, + GF und Einzelbloecke. + +--- + +## 1. Kreisel + +Block `KREISEL_n`, gebaut von `KreiselInsert.lsp`. + +### 1.1 Insert (freier Punkt) + +```json +{ "id": "KR_Kreuz_Q1_0Grad", "function": "insert", + "x": 500, "y": 500, "z": 2500, + "abstand": 2000, "rotation": 0.0, "typ": "STANDARD" } +``` + +| Feld | Pflicht | Bedeutung | Default | +|---|---|---|---| +| `id` | ja (fuer den Treiber) | Kennung im Ergebnis; NICHT die Block-ID (die vergibt `ssg-id-generate`) | - | +| `function` | ja | `"insert"`; ohne `block` = Kreisel | - | +| `x`, `y` | ja | Einfuegepunkt. Liegt auf der Kreiselachse **einen Radius (400 mm) vor der Mitte des Antriebsrads (AN)**, also am aeussersten Punkt der AN-Seite | - | +| `z` | ja | Einbauhoehe; wird als `hoehe` uebergeben und in das Attribut `HOEHE` geschrieben | `kreisel.default_hoehe` (2000) | +| `abstand` | ja | Mittenabstand Antriebsrad - Spannrad | `kreisel.default_laenge` (2300) | +| `rotation` | nein | Drehung der Achse AN -> SP, frei (kein Raster) | 0.0 | +| `typ` | nein | `"STANDARD"` oder `"PIN"` -> Attribut `KREISELART` | `"STANDARD"` | + +Treiber: `kreisel:run-insert-test` (`test_kreisel.lsp`), `mubea:build-kreisel`, +`hundm05:bau-kreisel` (auch fuer `dematic_arvato.json`). + +### 1.2 Connect (Start- und Endpunkt) + +```json +{ "id": "K2", "function": "connect", + "start_x": 0, "start_y": 0, "start_z": 2000, + "end_x": 5000, "end_y": 0, "end_z": 2000, "typ": "STANDARD" } +``` + +`start_*` und `end_*` sind die aeussersten Punkte der AN- bzw. SP-Seite. +`abstand` (= Distanz - Kreiseldurchmesser 800) und `rotation` werden daraus +berechnet. Die Einbauhoehe kommt aus `start_z`. Nur `test_kreisel.lsp` kennt +`connect`; die anderen Treiber bauen ausschliesslich `insert`. + +--- + +## 2. Einzelbloecke (Separator, Scanner, BTMT, Eingang/Ausgang, Vario-Bausteine) + +Jeder Eintrag mit `"function": "insert"` UND `"block"` wird als einzelner +Block eingefuegt, ohne Wrapper-Block und ohne Verkettung. + +```json +{ "id": "HundM05_SCANNER_02", "function": "insert", "block": "Scanner", + "x": 4095.5, "y": 1164.1, "z": 2154, "rotation": 270 } +``` + +| Feld | Pflicht | Bedeutung | Default | +|---|---|---|---| +| `block` | ja | Blockname OHNE `_2D`/`_3D`-Suffix | - | +| `x`, `y`, `z` | ja | Einfuegepunkt = **Basispunkt der Block-DWG** (nicht KS_EIN) | - | +| `rotation` | nein | Drehung um Z | 0 | +| `id` / `test_id` | nein | Kennung im Ergebnis | `SEPARATOR_` bzw. Blockname | + +Ablauf: `ssg-ils-block-laden` loest den Namen auf `data/ils/_.dwg` +auf (3D-Fallback), danach `_.INSERT eff pt "" "" rotation` und +`ssg-id-generate`. **Fehlt die DWG, wird `Separator_SP` eingefuegt.** +Treiber: `mubea:build-separator`, `hundm05:bau-sensor` (auch Dematic). +Das Layer-Attribut `LAYER` wird dabei nicht angewendet; der Block landet auf +dem aktuellen Layer. + +### In den Testdaten verwendete Blocknamen + +| `block` | DWG in `data/ils` | Verwendet in | Hinweis | +|---|---|---|---| +| `Scanner` | `Scanner_2D/_3D.dwg` | mubea, hundm05, dematic_arvato | | +| `Separator_SP` | `Separator_SP_2D/_3D.dwg` | (Fallback) | Block von `ILS_SEPARATOR_INSERT` | +| `S-LP` | **fehlt** | mubea, hundm05, dematic_arvato | wird zu `Separator_SP` | +| `S-SP` | **fehlt** | dematic_arvato | wird zu `Separator_SP` | +| `BTMT-Beladung` | `BTMT-Beladung_2D/_3D.dwg` | mubea, hundm05 | wie `ILS_BTMT_Beladung` | +| `SC_Entladung` | `SC_Entladung_2D/_3D.dwg` | mubea, hundm05 | wie `ILS_BTMT_Entladung` | +| `Eingang` / `Ausgang` | `Eingang_*/Ausgang_*.dwg` | mubea | Symbole wie `ILS_EINGANG_INSERT`/`ILS_AUSGANG_INSERT` | +| `AS_Element_90_links` / `_rechts` | vorhanden | dematic_arvato | loses AS-Element (sonst Teil eines VF/GF) | +| `ES_Element_90_rechts`, `ES_Element_30_rechts` | vorhanden | dematic_arvato | loses ES-Element | +| `Vario_Motorstation_500mm_rechts` | vorhanden | dematic_arvato | lose Motorstation | +| `Vario_Umlenkstation_500mm_rechts` | vorhanden | dematic_arvato | lose Umlenkstation | +| `Vario_Kurve_rechts_30_TEF_aussen` | vorhanden | dematic_arvato | lose Vario-Kurve | + +Grundsaetzlich ist **jeder** Blockname aus `data/ils` erlaubt (es gibt keine +Whitelist). Die losen AS/ES-/Vario-Bausteine bilden aber keine Kette und keinen +`VF_n`/`GF_n`-Block - fuer eine zusammenhaengende Strecke Abschnitt 3-5 nutzen. + +--- + +## 3. VarioFoerderer Standard und Etage + +Block `VF_n`. Eingang sind die **Gesamtmasse** der Anlage; Winkel und +Teillaengen berechnet der Solver. + +```json +{ "test_id": "VF_Schnitt_C", "richtung": "Auf", + "deltaL": 9110, "deltaH": 474, "winkel": 21, + "gf_verteilung": "manuell", "L_GF1": 2298, "seite": "links", + "hz": 0.0, "x": 400, "y": 14120, "z": 1554 } +``` + +| Feld | Pflicht | Bedeutung | Default | +|---|---|---|---| +| `test_id` | ja | muss mit `VF_` beginnen (steuert den Dispatcher in `test_mubea.lsp`) | - | +| `typ` | nein | `"standard"` (AS/ES 90 Grad) oder `"etage"` (AS/ES 30 Grad, uebereinander) | `"standard"` | +| `richtung` | ja | `"Auf"` oder `"Ab"` | - | +| `deltaL` | ja | horizontale Gesamtlaenge inkl. AS/ES, Boegen, GF-Vor-/Nachlauf | - | +| `deltaH` | ja | Hoehendifferenz (Betrag; Vorzeichen kommt aus `richtung`) | - | +| `winkel` | nein | Bogenwinkel erzwingen, nur aus der Kandidatenliste (`vario.bogen_winkel`: 3, 6, 9, 12, 15, 18, 21, 27, 33, 39, 45, 51). Ist er nicht loesbar, wird NICHT gebaut | kleinster gueltiger Winkel | +| `L_GF1` | nein (mubea) | Vorlauf-Laenge (GF vor dem Foerderer); Nachlauf = Rest von `L_GF` | - | +| `gf_verteilung` | nein (foerderer) | `"gleichmaessig"`, `"vorne"`, `"hinten"`; in `mubea.json` nur Doku (dort zaehlt `L_GF1`) | `"gleichmaessig"` | +| `seite` | nein | `"links"`/`"rechts"` (Seite der AS/ES-Elemente) | `"links"` | +| `hz` | nein | Fahrtrichtung | 0.0 | +| `x`, `y`, `z` | ja (mubea) | Startpunkt = **KS_EIN des AS-Elements**; `z` = Einbauhoehe am Anfang | - | + +Hinweise: +- `foerderer_tests.json` hat statt `x/y/z` einen Kopf-Eintrag + `{"y_abstand": 600}`: alle Foerderer starten bei x = 0, z = 0 und werden um + `y_abstand` versetzt. Dieses Format kennt nur `test_foerderer.lsp`. +- `"Ab"` mit `deltaH` < 1 ist geometrisch unmoeglich und wird abgewiesen. +- Der Treiber schreibt nach dem Bau `vf-edit-xdata-schreiben` (Typ + `hz`), + damit der Block per Doppelklick editierbar ist. + +--- + +## 4. Gefaellestrecke + +Block `GF_n`: AS-Element -> Staustrecke (skaliert) -> Separator -> ES-Element. +Eingang ist die **horizontale Laenge**, nicht die Hoehendifferenz - die ergibt +sich aus Laenge und Neigung. + +### 4.1 Modus 1 - Werteingabe + +```json +{ "test_id": "GF_Mubea", "modus": 1, + "deltaL_mm": 9110, "hz_grad": 180.0, "winkel_grad": 2.27, + "start_mm": [9510, 12300, 2028], + "as_seite": "links", "es_seite": "links", + "as_winkel": "90", "es_winkel": "90" } +``` + +| Feld | Pflicht | Bedeutung | Default | +|---|---|---|---| +| `test_id` | ja | in `mubea.json` muss sie mit `GF_` beginnen | - | +| `modus` | nein | `1` | - | +| `deltaL_mm` | ja | horizontale Gesamtlaenge AS + Staustrecke + Separator + ES | - | +| `winkel_grad` | nein | Neigung der Staustrecke | 3.0 | +| `hz_grad` | nein | Fahrtrichtung | 0.0 | +| `start_mm` | ja | `[x, y, z]` = **KS_EIN des AS-Elements**; Z = Einbauhoehe oben | - | +| `as_seite`, `es_seite` | nein | `"links"`/`"rechts"` | `"links"` | +| `as_winkel`, `es_winkel` | nein | `"90"` oder `"30"` (als STRING) | `"90"` | + +Die Staustrecke ergibt sich aus +`L_stau = (deltaL - aus-dx - ein-dx - 300 * cos(w)) / cos(w)` +(300 = `gefaelle.separator_breite`). Eine Ziel-Hoehe gibt es nicht. + +In `gefaellestrecke_tests.json` stehen `deltaL_mm`, `winkel_grad` und +`z_start_mm` in einem gemeinsamen Kopf-Eintrag ohne `test_id` und gelten fuer +alle Faelle der Datei. + +### 4.2 Modus 2 - Richtung aus zwei Punkten + +Wie Modus 1, aber `deltaL` und `hz` werden aus `linie_start_mm` -> +`linie_ende_mm` berechnet (nur X/Y). `start_mm` bleibt der Einfuegepunkt und +ist unabhaengig von der Linie. + +```json +{ "test_id": "M2_hz000", "modus": 2, "start_mm": [0, -35000, 5000], + "linie_start_mm": [0, -35000, 0], "linie_ende_mm": [10000, -35000, 0], + "as_seite": "links", "es_seite": "links", "as_winkel": "90", "es_winkel": "90" } +``` + +### 4.3 Modus 3 - Linienzug + +In der Produktion nicht skriptbar (`gf-linienzug-modus` waehlt vorgezeichnete +LINE/ARC-Objekte per Maus). `test_gefaellestrecke.lsp` zeichnet die Leitlinie +selbst und baut sie nicht-interaktiv nach. Zwei Formen: + +```json +{ "test_id": "M3_Bogen", "modus": 3, + "start_mm": [30000, -50000, 2000], "ende_mm": [38500, -43500, 1800], + "bogen": {"winkel_grad": 90, "radius_mm": 500, "seite": "links"}, + "as_seite": "links", "es_seite": "links", "as_winkel": "90", "es_winkel": "90" } +{ "test_id": "M3_hz270", "modus": 3, "richtung": "Sued", + "start_mm": [0, -50000, 5000], + "deltaH_quelle": "M2_hz000", "deltaL_quelle": "M2_hz000", ... } +``` + +`deltaH_quelle`/`deltaL_quelle` uebernehmen die Masse eines frueher gebauten +Falls. Dieses Format ist an den Treiber gebunden. Fuer neue Anlagen besser +eine VF-Linienzug-Spec (Abschnitt 5) mit `Linie-GF`/`GF-Bogen` verwenden. + +--- + +## 5. VF-Linienzug-Kette (Spec) + +Beliebige Ketten aus GF-Linien, GF-Boegen, Vario-Kurven und VF-Einheiten, +**ohne Dialog** gebaut (`VF_SPEC_BAU`, `TEST_HUNDM05`). Eine Kette = ein +Kopf-Objekt, danach ihre Glieder (`glied`) und deren Unterknoten (`sub`) in +Baureihenfolge. Ergebnis ist ein `VF_n`-Block mit vollem `SSG_VF_EDIT`-Journal +(per Doppelklick editierbar). + +```json +{ "spec_id": "VF_spec_LZ_01", "modus": 1, + "start_punkt": [4912.2, 1230.9, 2154.0], "start_hoehe": 2154.0, + "as": 1, "as_winkel": "90", "as_seite": "links" } +{ "glied": "Linie-GF", "nr": 1, "dl": 2249.3, "hz": 90.0, + "gefaelle": "winkel", "winkel": 3.0, "ende": "nein" } +{ "glied": "Horizontal-VF", "nr": 2, "dl": 3256.9, "gf_verteilung": "einlauf", + "vf_sep_vor": 0, "vf_sep_nach": 0, "vf_ende": "nein", "vf_separator": 0 } +{ "sub": "vario-kurve", "winkel": 90, "seite": "rechts", "variante": "innen" } +{ "sub": "motorstation" } +{ "glied": "ES", "winkel": "90", "seite": "links" } +``` + +**Kopf** + +| Feld | Bedeutung | +|---|---| +| `spec_id` | Kennung der Kette | +| `modus` | `1` (nur Modus 1 hat einen Uebersetzer) | +| `start_punkt` | `[x, y, z]` Kettenanfang (KS_EIN des AS-Elements bzw. erstes Glied) | +| `start_hoehe` | Einbauhoehe am Start | +| `as` | `1` = AS-Element setzen, `0` = nicht | +| `as_winkel` / `as_seite` | `"90"`/`"30"` bzw. `"links"`/`"rechts"` | + +**Glieder** (`glied`) + +| `glied` | wichtigste Felder | +|---|---| +| `Linie-GF` | `dl`, `hz` (nur beim ersten Glied der Kette), `laenge_modus` (`endpunkt`/`hoehe`/`steigend`), `ende` (`ja-mit-es`/`ja-ohne-es`/`nein`), `sep_vor`, `sep_nach`, `gefaelle` (`hoehe`/`winkel`) + `hoehe` bzw. `winkel` | +| `GF-Bogen` | `winkel` (30/60/90), `seite` | +| `Vario-Kurve` | als eigenes Glied (Kettenanfang) vom Uebersetzer noch NICHT unterstuetzt -> Spec-Fehler; Vario-Kurven als `sub` einer VF-Einheit angeben | +| `Horizontal-VF` | `dl`, `eingang_hoehe`, `gf_verteilung` (`haelfte`/`einlauf`), `vf_sep_vor`, `vf_sep_nach`, `vf_ende` (`ja-mit-es`/`nein`/`automatisch`/`zielpunkt-ohne-es`), `vf_separator` (nur bei `vf_ende` = `nein`) + `sub`-Knoten | +| `Linie-VF` | `dl`, `hoehe`, optional `winkel_idx` + `sub`-Knoten | +| `Linie` | `dl`, `hoehe`, `segment_typ` (`GF`/`VF`), optional `winkel_idx` | +| `ES` | `winkel` (`"90"`/`"30"`), `seite` | + +**Unterknoten einer VF-Einheit** (`sub`): `horizontal` (`sep_vor`, `sep_nach`), +`vario-kurve` (`winkel`, `seite`, `variante` `aussen`/`innen`), `auf-ab` +(`richtung` `auf`/`ab`, `hoehe`), `motorstation`, `kettenende` (`es`, +`es_winkel`, `es_seite`). + +Ja/Nein-Felder (`as`, `sep_vor`, `vf_sep_vor`, `es`, ...) als `1`/`0` oder +`"ja"`/`"nein"`; mehrwertige Felder (`ende`, `vf_ende`) nur mit den genannten +Woertern. Vollstaendige Regeln +(Menue-Codes je Frame, `hz` nur einmal, Verhalten bei `winkel_idx`): +[variofoerderer.md, Abschnitt 8b](variofoerderer.md#spec-pfad-kette-aus-eingabedaten-vf_spec_bau). +Die Spec wird nicht von Hand geschrieben, sondern mit +`python lib/vf_spec_export.py ` aus einer +aufgezeichneten Kette erzeugt. Fehlerhafte Specs werden komplett abgewiesen +(`vsp-pruefen` sammelt alle Fehler, gebaut wird dann nichts). + +**Andere Objekte in derselben Datei**: Neben den Ketten darf `hundm05.json` +Kreisel (Abschnitt 1) und Einzelbloecke (Abschnitt 2) enthalten. Erkennbar +sind sie an `function`; `vsp-gruppieren` ueberspringt sie, und +`hundm05:bau-zusatzobjekte` baut sie nach den Ketten. `vf_spec_export.py` +haengt sie beim Neuerzeugen unveraendert ans Dateiende. + +--- + +## 6. VF-Linienzug (Eingabe-Journal) + +Das Rohformat hinter der Spec: die Antworten auf die Fragen des interaktiven +Linienzug-Ablaufs, in Reihenfolge. Nur fuer Regressionstests gedacht - fuer +neue Anlagen die Spec (Abschnitt 5) verwenden. + +```json +{ "test_id": "VF_hundm05_LZ_01", "anlagetyp": "linienzug", "modus": 1, ... } +{ "typ": "point_abs", "wert": [4912.2, 1230.9, 2154.0], "kommentar": "Startpunkt" } +{ "typ": "real", "wert": 2154.0, "kommentar": "Hoehe (Z)" } +{ "typ": "string", "wert": "1", "kommentar": "AS-Element? Ja" } +{ "typ": "step", "wert": "Linie-GF", "kommentar": "Glied-Marker" } +{ "typ": "point_rel", "dL": 2249.3, "hz": 90.0, "kommentar": "Endpunkt" } +{ "typ": "int", "wert": 90, "kommentar": "Vario-Kurve Winkel" } +``` + +`typ`: `point_abs` (absoluter Punkt), `point_rel` (Abstand `dL` + Richtung +`hz`, `hz` nur beim ersten Segment), `real`, `int`, `string` (Menue-Code als +String), `step` (Glied-Marker, beim Replay uebersprungen). Kopf-Feld heisst +`anlagetyp`, nicht `typ`, damit Kopf und Eingabe unterscheidbar bleiben. + +| Datei | Treiber | +|---|---| +| `linienzug_tests.json`, `linienzug_tests_stufe2.json` | `TEST_LINIENZUG`, `TEST_LINIENZUG_STUFE2` | +| `hm_recformat.json` (5 echte HundM-Ketten, erzeugt mit `lib/vf_journal_export.py`) | `TEST_HM_RECFORMAT` (in `alltests.json` abgeschaltet) | + +--- + +## 7. Omniflo + +### 7.1 Bogen und Weiche + +```json +{ "id": "821104025", "type": "bogen", "sivasnr": "821104025", + "x": 219.4, "y": 223.06, "hoehe": 2000, "drehung": 0.0 } +``` + +| Feld | Pflicht | Bedeutung | Default | +|---|---|---|---| +| `type` | ja | `"bogen"` oder `"weiche"` | - | +| `sivasnr` | ja | Sivas-Nummer = Dateiname `%DXFM_OMNIFLO%/.dxf` | - | +| `x`, `y` | ja | Einfuegepunkt (`$INSBASE` der DXF, gesetzt mit `set_einfuegepkt.py`) | - | +| `hoehe` | nein | Z des Einfuegepunkts UND Attribut `HOEHE` | 2000 | +| `drehung` | nein | Drehung + Attribut `DREHUNG` | 0 | + +Es gibt kein `z`: die Hoehe ist zugleich die Z-Koordinate. Gueltige +Sivas-Nummern: `data/json/omniflo_boegen.json`, `omniflo_weichen.json`. +Treiber: `omni:test-insert` (`test_omniflo.lsp`), `omnistr:insert-bogen` +(`test_omniflo_strecke.lsp`). + +### 7.2 Aluprofil-Gerade + +```json +{ "seq": 1, "type": "gerade", "profil": "AP110", "laenge": 1000.0, + "x": 2000.0, "y": 0.0, "x_ende": 3000.0, "y_ende": 0.0, + "drehung": 0.0, "hoehe": 2000, "id": "0003" } +``` + +`profil` = `"AP60"`, `"AP110"` oder `"APG110"`. Die Gerade laeuft von +(`x`,`y`) nach (`x_ende`,`y_ende`) auf Z = `hoehe`; Laenge und Drehung folgen +aus den Punkten (`laenge` ist nur Doku). Gebaut mit `omni:make-gerade`. + +--- + +## 8. Waagrechte Foerderstrecke (`gerade`) - noch ohne Bau-Pfad + +```json +{ "test_id": "GERADE_Arvato_01", "typ": "gerade", "laenge": 8313.39, "hz": 90.0, + "startpunkt": [2334.97, 177818.67, 0.0], "endpunkt": [2334.96, 186132.06, 0.0] } +``` + +Ein Antriebs-/Umlenkstation-Paar ohne Hoehendifferenz, so von +`lib/dxf_scan_components.py` ausgegeben (ein VarioFoerderer ist bei +`deltaH` = 0 nicht loesbar). `TEST_DEMATIC_ARVATO` meldet diese Eintraege und +ueberspringt sie. Passende Primitive waere `insert-hz-scaled-block-by-ks` +(`vf_etage.lsp`) mit `Staustrecke_SP_1000_mm`, siehe +[lisp_methods.md](lisp_methods.md). + +--- + +## 9. Testdaten-Dateien im Ueberblick + +| Datei | Inhalt | Treiber / Befehl | +|---|---|---| +| `kreisel_tests.json` | 8 Kreisel (`insert`) | `TEST_KREISEL` | +| `foerderer_tests.json` | Kopf `y_abstand` + 17 VF Standard | `TEST_FOERDERER` | +| `gefaellestrecke_tests.json` | Kopf + GF Modus 1/2/3 | `TEST_GEFAELLESTRECKE` | +| `omniflo_tests.json` | 27 Boegen, 80 Weichen | `TEST_OMNIFLO` | +| `omniflo_strecke_tests.json` | Streckenzug aus Geraden und Boegen | `TEST_OMNIFLO_STRECKE` | +| `linienzug_tests.json` / `_stufe2.json` | Eingabe-Journal je einer Kette | `TEST_LINIENZUG` / `TEST_LINIENZUG_STUFE2` | +| `hm_recformat.json` | 5 HundM-Ketten als Journal | `TEST_HM_RECFORMAT` | +| `hundm05.json` | 5 HundM-Ketten als Spec + Kreisel, Separatoren, Scanner, BTMT | `TEST_HUNDM05`, `VF_SPEC_BAU` | +| `mubea.json` | Gesamtanlage: Kreisel, VF Standard/Etage, GF-Template (20 Stueck), Separatoren, Scanner, BTMT, Eingang/Ausgang | `TEST_MUBEA` | +| `dematic_arvato.json` | Vorlage aus `dxf_scan_components.py`: Kreisel, Einzelbloecke, `gerade` (Hoehen fehlen) | `TEST_DEMATIC_ARVATO` (abgeschaltet) | +| `hundm05_linienzug_polylines.json` | Polylinien aus `extract_polylines.py` | kein Treiber (Analyse-Daten) | +| `vfl_journal_hm05_abbruch.json` | rohes Journal (`kind`/`value`) eines abgebrochenen Baus | kein Treiber | + +--- + +## 10. Eigene Anlage beschreiben - Kurzanleitung + +1. Kreisel als `insert` (Abschnitt 1): `x/y` am aeussersten Punkt der AN-Seite, + `z` = Einbauhoehe. +2. Einfache Steig-/Fall-Strecken mit fester Form als VF Standard/Etage + (Abschnitt 3) bzw. Gefaellestrecke Modus 1 (Abschnitt 4.1), Startpunkt + jeweils = KS_EIN des AS-Elements. +3. Ketten mit Kurven, mehreren VF-Einheiten oder GF-Boegen als Spec + (Abschnitt 5) - am einfachsten eine Kette einmal interaktiv bauen, mit + `lib/vf_journal_export.py` + `lib/vf_spec_export.py` als Spec exportieren + und Startpunkt/Laengen anpassen. +4. Separatoren, Scanner, BTMT-Stationen, Eingang/Ausgang als Einzelblock + (Abschnitt 2). +5. Aus Kreisel, Einzelbloecken und Specs gemischt baut derzeit nur der + HundM05-Treiber (`TEST_HUNDM05`); fuer VF Standard/Etage + GF zusammen mit + Kreiseln den Mubea-Treiber (`TEST_MUBEA`) als Vorlage nehmen. diff --git a/doc/lisp_methods.md b/doc/lisp_methods.md new file mode 100644 index 0000000..11d78d7 --- /dev/null +++ b/doc/lisp_methods.md @@ -0,0 +1,328 @@ +# LISP-Routinen zum Bau einzelner Einheiten + +Uebersicht ueber die LISP-Funktionen, die eine Einheit (Kreisel, Eckrad, +VarioFoerderer, Gefaellestrecke, Omniflo-Element, Geruest, Einzelblock) +erzeugen, mit Signatur, Parametern, Rueckgabe und Voraussetzungen. + +Zu jedem Element steht der interaktive **Befehl** (was der Anwender aufruft) +und der **skriptfaehige Kern** (ohne `getpoint`/Dialog, aus Code oder JSON +aufrufbar). Das JSON-Format, mit dem die Testtreiber diese Kerne aufrufen, +steht in [json-input-lisp.md](json-input-lisp.md); alle Befehle in +[kommandos.md](kommandos.md). + +Einheiten: mm und Grad. `hz` = Fahrtrichtung in der XY-Ebene, 0 = +X, +90 = +Y. Punkte sind Listen `(x y z)` in Weltkoordinaten. + +--- + +## 0. Uebersicht + +| Einheit | Befehl | Skriptfaehiger Kern | Ergebnis-Block | Modul | +|---|---|---|---|---| +| Kreisel | `KreiselInsert`, `KreiselConnect`, `KreiselQuick` | `kreisel-insert-script`, `kreisel-connect-script` | `KREISEL_n` | `KreiselInsert.lsp` | +| Eckrad | `ILS_Eckrad` | `ils-eckrad-insert` | `ECKRAD_n` | `KreiselInsert.lsp` | +| VF Standard | `StandardVarioFoerderer`, `FOERDERANLAGE` | `berechne-standard` + `variofoerderer-einfuegen` + `vf-block-erstellen` | `VF_n` | `vf_standard.lsp`, `vf_core.lsp` | +| VF Etage | `EtageVarioFoerderer` | `berechne-etage` + `etage-foerderanlage-einfuegen` + `vf-block-erstellen` | `VF_n` | `vf_etage.lsp`, `vf_core.lsp` | +| VF Linienzug | `LinienzugVarioFoerderer` | `vsp-bau-aus-spec` (Spec) bzw. `vfl-journal-replay-start` + `vf-linienzug-modus` | `VF_n` | `vf_linienzug.lsp`, `vf_spec.lsp` | +| Gefaellestrecke | `GEFAELLESTRECKE_EINFACH`/`_3DLINIE` | `gf-rebuild` bzw. `gefaellestrecke-einfuegen` | `GF_n` | `Gefaellestrecke.lsp` | +| Gefaellestrecke Linienzug | `GEFAELLESTRECKE_LINIENZUG` | - (nur interaktiv; Kern `gf-linienzug-einfuegen` braucht analysierte Segmente) | `GF_n` | `Gefaellestrecke.lsp` | +| Separator, Scanner | `ILS_SEPARATOR_INSERT`, `ILS_SCANNER_INSERT` | - (Schleife mit `getpoint`); Kern: `ssg-ils-block-laden` + `_.INSERT` | Einzelblock | `SSG_LIB_Commands.lsp`, `ssg_core.lsp` | +| BTMT, Eingang/Ausgang | `ILS_BTMT_*`, `ILS_EINGANG_INSERT`/`ILS_AUSGANG_INSERT` | wie Separator | Einzelblock | `SSG_LIB_Commands.lsp` | +| Omniflo Bogen/Weiche/TEF | `OMNI_APB_*`, `OMNI_W*_*`, `OMNI_TEF_*` ... | `_.INSERT` der `.dxf` (Kern `omni:insert-dxf` fragt den Punkt) | Einzelblock | `OmniModulInsert.lsp` | +| Omniflo Gerade | `OMNI_AP60`/`AP110`/`APG110` | `omni:make-gerade` | Compound-Block | `OmniModulInsert.lsp` | +| TEF-Foerderer-Linie | `TEF_FOERDERER_LINIE` | `tefl-insert-element` (ein Element) | Einzelbloecke | `TEFInsert.lsp` | +| Geruest (Saeule, Rohrabhaenger, Wandbefestigung) | `GERUEST`, `GERUEST_SAEULEN` ... | `geruest-block-bauen` | `GR__` | `GeruestInsert.lsp` | +| Geruest-Traeger | `GERUEST_TRAEGER` | `geruest-traeger-block-bauen` | `GR__` | `GeruestInsert.lsp` | + +--- + +## 1. Kreisel und Eckrad (`KreiselInsert.lsp`) + +### `kreisel-insert-script (pt abstand rotation typ hoehe)` + +Kreisel an einem freien Punkt. Ruft `draw-module` auf. + +| Parameter | Bedeutung | +|---|---| +| `pt` | Einfuegepunkt: aeusserster Punkt der AN-Seite auf der Achse (einen Radius = 400 mm vor der Mitte des Antriebsrads) | +| `abstand` | Mittenabstand Antriebsrad - Spannrad | +| `rotation` | Drehung der Achse AN -> SP in Grad | +| `typ` | `"STANDARD"` oder `"PIN"` (nil = `"STANDARD"`) -> Attribut `KREISELART` | +| `hoehe` | Einbauhoehe; nil = Z von `pt`, sonst `*kreisel-default-hoehe*` | + +Rueckgabe: Entity des `KREISEL_n`-Blocks oder nil. Setzt `ssg-start`/`ssg-end` +selbst. + +### `kreisel-connect-script (ptStart ptEnd typ hoehe)` + +Kreisel zwischen zwei aeussersten Punkten (AN-Seite, SP-Seite). Berechnet +`abstand` = Distanz - `*kreisel-durchmesser*` (800) und `rotation` aus den +Punkten. Rueckgabe wie oben. + +### `draw-module (basePoint abstand rotation attribs)` + +Gemeinsamer Bau-Kern beider Funktionen: setzt Antriebs- und Spannstation, +Tangenten, Beschriftung, fasst alles zu `KREISEL_n` zusammen, schreibt die +Attribute (`attribs` = Alist, wird mit `*kreisel-attrib-defs*` gemischt). +Direkt nur aufrufen, wenn zusaetzliche Attribute gesetzt werden muessen. + +### `ils-eckrad-insert (pt rotation attribs)` + +Eckrad als Compound-Block `ECKRAD_n`. + +| Parameter | Bedeutung | +|---|---| +| `pt` | **Radmitte** `(x y hoehe)` | +| `rotation` | Drehung in Grad | +| `attribs` | Alist mit Ueberschreibungen, z.B. `(("GERUEST_EINZELMODUL" . "1") ("GERUEST_TYP" . "Schoenenberger Geruest"))`; nil = Defaults | + +`c:ILS_Eckrad` berechnet die Radmitte aus Beruehrpunkt + Radius in Richtung +des zweiten Klicks. Rueckgabe: Entity des Blocks. + +--- + +## 2. VarioFoerderer Standard und Etage (`vf_core.lsp`, `vf_standard.lsp`, `vf_etage.lsp`) + +Ablauf in drei Schritten: **loesen** (Winkel und Teillaengen aus den +Gesamtmassen), **einfuegen** (Bausteine verketten), **Block bilden** +(`VF_n` mit Attributen). Der Dialog-Ablauf `vf-dialog-ablauf` / +`vf-dialog-berechnen-einfuegen` macht dasselbe, oeffnet aber Dialog 2 und ist +darum nicht skriptfaehig. + +### Vorbereitung + +| Funktion | Zweck | +|---|---| +| `init-bibliothek ()` | Bogen-, AS-/ES- und Stationsmasse aus den Bloecken lesen. Setzt `*lib-initialized*`. Wird von `berechne-standard` aufgerufen | +| `init-bibliothek-etage ()` | dasselbe fuer Etage, aufgerufen von `berechne-etage` | +| `vf-set-as-masse (winkel seite)` / `vf-set-es-masse (winkel seite)` | AS-/ES-Masse (`aus-dx`/`aus-dz`, `ein-dx`/`ein-dz`) fuer die Variante `"90"`/`"30"` + `"links"`/`"rechts"` setzen | + +### Loesen + +| Funktion | Rueckgabe | +|---|---| +| `berechne-standard (deltaL deltaH richtung seite)` | `(best-winkel L_GF L_VF ergebnis-liste)` | +| `berechne-alle-winkel (deltaL deltaH richtung feste-hz schon-flach)` | wie oben; `feste-hz` nil = 1600 mm feste Horizontale, `schon-flach` nil | +| `berechne-etage (deltaL deltaH richtung seite)` | wie oben, Etage-Geometrie (setzt die Gefaellebogen-Masse je `seite`) | +| `vf-winkel-solve (...)` | gemeinsamer L_GF/L_VF-Solve beider Typen (intern) | + +- `richtung` = `"Auf"`/`"Ab"`, `deltaH` als Betrag. +- `ergebnis-liste` = je Kandidatenwinkel `(winkel L_GF L_VF gueltig)`. + Kandidaten aus `vario.bogen_winkel` (3 ... 51). Einen bestimmten Winkel + erzwingen: Eintrag mit diesem `winkel` aus der Liste nehmen und + `gueltig`, `L_GF` > 0, `L_VF` > 0 pruefen (so `mubea:build-vario-one`). +- `L_GF` wird danach auf Vorlauf `L_GF1` und Nachlauf `L_GF2` aufgeteilt + (gleichmaessig / vorne / hinten / manuell, `foerderer:split-gf`). + +### Einfuegen + +``` +(variofoerderer-einfuegen deltaL deltaH richtung best-winkel L_GF1 L_GF2 L_VF startpunkt seite hz) +(etage-foerderanlage-einfuegen deltaL deltaH richtung best-winkel L_GF1 L_GF2 L_VF startpunkt seite hz) +``` + +Identische Signatur (Registry-Vertrag `*vf-typ-registry*`). `startpunkt` = +Lage von **KS_EIN des AS-Elements**, Z = Einbauhoehe am Anfang. `seite` = +`"links"`/`"rechts"`. Rueckgabe: Endpunkt (KS_AUS des ES-Elements). +`variofoerderer-einfuegen` ist aus Teilen zusammengesetzt (`vfs-as-teil`, +VF-Eingang/Koerper, `vfs-es-teil`), die auch der Linienzug nutzt. + +### Block bilden + +``` +(setq lastEnt (ssg-lastent-ohne-attribute)) ; VOR dem Einfuegen merken +...einfuegen... +(vf-block-erstellen anlage-typ seite (vf-next-number) n-scanner + hoehe-von hoehe-bis deltaH deltaL L_VF L_GF1 L_GF2 + richtung best-winkel startpunkt lastEnt hz + geruest-einzelmodul geruest-typ) +(vf-edit-xdata-schreiben ent anlage-typ hz) ; editierbar per Doppelklick +``` + +- `anlage-typ` = `"standard"`/`"etage"`; `hoehe-bis` = +deltaH bei `"Auf"`, + -deltaH bei `"Ab"`; `geruest-einzelmodul` `"0"`/`"1"` (nil = `"1"`), + `geruest-typ` einer aus `*ssg-geruest-optionen*`. +- Sammelt alle Objekte seit `lastEnt` zum Block `VF_n`, setzt Layer, Attribute, + ID (`ssg-id-generate`) und Dimension. Rueckgabe: Entity des Blocks. +- `lastEnt` immer mit `ssg-lastent-ohne-attribute` holen, nicht mit + `(entlast)` (siehe `CLAUDE.md`, ssg_core). +- Blocknummer immer ueber `vf-next-number`: eine feste Nummer fuehrt bei der + zweiten Anlage zu einer Rueckfrage von `_.-BLOCK` und einem haengenden Befehl. + +--- + +## 3. VF-Linienzug (`vf_linienzug.lsp`, `vf_spec.lsp`) + +Ketten mit Vario-Kurven, GF-Boegen und mehreren VF-Einheiten. Der Bau-Ablauf +ist ein Frage-Antwort-Assistent; jede Eingabe wird journalisiert und als XDATA +am `VF_n`-Block gespeichert. Nicht-interaktiv baut man ihn, indem man ein +Journal **abspielt**. + +| Funktion | Zweck | +|---|---| +| `vf-linienzug-modus ()` | Modus 1, frei zeichnend. Liest alle Eingaben ueber `vfl-in-point`/`-string`/`-real`/`-int` - aus der Replay-Queue, falls eine aktiv ist | +| `vf-linienzug-modus2 ()` | Modus 2, Pfad + Zielhoehe (Objektauswahl, eigenes Journal `"linienzug2"`) | +| `vfl-journal-replay-start (forward-journal)` | Journal als Antwort-Queue setzen; danach `vf-linienzug-modus` aufrufen | +| `vsp-journal (spec)` | Spec -> Journal (nil bei Spec-Fehlern, Fehler in `*vsp-fehler*`) | +| `vsp-pruefen (spec)` | alle Spec-Fehler sammeln | +| `vsp-bau-aus-spec (spec)` | eine Kette aus einer Spec bauen (headless, Replay, Ergebnis-Record mit `status`, Block, `prompts`, `glieder_soll`/`glieder_ist`) | +| `vsp-bau-liste (specs)` | mehrere Specs, je mit `vl-catch-all-apply` | +| `vsp-bau-datei (datei)` | Spec-Datei lesen (`vsp-json-laden` + `vsp-gruppieren`) und alle Ketten bauen; das ist `VF_SPEC_BAU` | +| `vsp-headless-an ()` / `vsp-headless-aus ()` | Headless-Rahmen: `*vfl-headless*`, Wizard aus, `*ssg-gui-aus*`, zaehlende Eingabe-Stubs | + +Ein Abbruch im Headless-Modus nennt die Stelle (`*vfl-headless-fehler*`), +statt auf eine Live-Eingabe zu warten. Details zum Ablauf und zu den +Journal-Regeln: [variofoerderer.md](variofoerderer.md), Abschnitte 5-8b. + +--- + +## 4. Gefaellestrecke (`Gefaellestrecke.lsp`) + +### `gf-rebuild (deltaL winkel hz-winkel as-seite es-seite startpunkt as-winkel es-winkel geruest-einzelmodul geruest-typ)` + +Der bequemste skriptfaehige Einstieg fuer Modus 1/2: setzt die AS-/ES-Masse, +berechnet die Staustrecke +`L_stau = (deltaL - aus-dx - ein-dx - separator_breite * cos(w)) / cos(w)` +und ruft `gefaellestrecke-einfuegen`. Ohne Zusammenfassung und Rueckfrage +(eigentlich fuer `GEFAELLESTRECKE_EDIT` gedacht). + +| Parameter | Bedeutung | +|---|---| +| `deltaL` | horizontale Gesamtlaenge AS + Staustrecke + Separator + ES | +| `winkel` | Neigung der Staustrecke in Grad (Default im Dialog 3.0) | +| `hz-winkel` | Fahrtrichtung | +| `as-seite`, `es-seite` | `"links"`/`"rechts"` | +| `startpunkt` | **KS_EIN des AS-Elements**, Z = Einbauhoehe oben | +| `as-winkel`, `es-winkel` | `"90"`/`"30"` als STRING (nil = `"90"`) | +| `geruest-einzelmodul`, `geruest-typ` | wie beim VF | + +Rueckgabe: `(ename deltaH deltaL)` oder nil (Staustrecke <= 0.1 mm -> `alert`). + +### `gefaellestrecke-einfuegen (L_stau winkel startpunkt as-seite es-seite hz deltaL-total as-winkel es-winkel geruest-einzelmodul geruest-typ)` + +Eigentlicher Bau: AS-Element, skalierte Staustrecke, Separator, ES-Element, +Block `GF_n` mit Attributen, XDATA `SSG_GF_EDIT` und ID. Erwartet die +fertige Staustreckenlaenge `L_stau` und passend gesetzte AS-/ES-Masse +(`vf-set-as-masse`/`vf-set-es-masse`). Rueckgabe wie `gf-rebuild`. + +### Weitere + +| Funktion | Zweck | +|---|---| +| `gf-modus12-abschluss (... dialog-bestaetigt ...)` | Abschluss Modus 1/2 mit Zusammenfassung; fragt ohne `dialog-bestaetigt` = T per Konsole nach | +| `gf-init-bibliothek ()` | AS-/ES-Masse fuer die GF lesen | +| `gf-linienzug-modus ()` | Modus 3, interaktiv (Auswahl vorhandener LINE/ARC) | +| `gf-linienzug-einfuegen (segmente grade startframe)` | Bau-Kern von Modus 3, erwartet die von `gf-analysiere-kette` aufbereiteten Segmente | + +**Falle `*lib-initialized*`**: `gefaellestrecke-einfuegen` initialisiert die +GF-Masse nur, wenn `*lib-initialized*` nil ist - dasselbe Flag setzt +`init-bibliothek` des VarioFoerderers. Wer in einem Lauf erst VF und dann GF +baut, muss `gf-init-bibliothek` einmal selbst erzwingen (so +`mubea:ensure-gf-init` in `tests/test_mubea.lsp`), sonst rechnet die GF mit +den Vario-Massen und landet auf falscher Hoehe. + +--- + +## 5. Einzelbloecke: Separator, Scanner, BTMT, Eingang/Ausgang + +| Funktion | Zweck | +|---|---| +| `ils-insert-sensor (fname)` | Befehls-Kern Separator/Scanner: fuegt in einer Schleife ein, Punkt per `getpoint`, Drehung per `pause` - **nicht skriptfaehig** | +| `ils-insert-station (rohname)` | dasselbe fuer BTMT-Beladung, SC_Entladung, Eingang, Ausgang; setzt zusaetzlich den Layer aus dem `LAYER`-Attribut | +| `ssg-ils-block-laden (blockname)` | Blockdefinition `data/ils/_.dwg` einmal je Zeichnung laden; Rueckgabe: effektiver Blockname mit Suffix oder nil | +| `ssg-ils-block-datei (blockname)` | nur den Dateipfad aufloesen (3D-Fallback) | +| `ssg-block-layer-vorgabe` | `LAYER`-Attribut eines eingefuegten Blocks als Ziel-Layer anwenden | +| `ssg-id-generate (ent)` | eindeutige `ID` vergeben (nur wenn der Block ein ID-Attribut hat) | + +Skriptfaehig bauen (Muster aus `hundm05:bau-sensor`): + +```lisp +(setq eff (ssg-ils-block-laden "Scanner")) ; nicht per (and ...) verketten! +(command "_.INSERT" eff (list x y z) "" "" rotation) +(while (and (> (getvar "CMDACTIVE") 0) (< n 5)) (command "") (setq n (1+ n))) +(ssg-id-generate (entlast)) +``` + +`ATTREQ`/`ATTDIA` vorher auf 0 setzen. Restliche Prompts gezaehlt mit Enter +beantworten, nicht ungebremst: eine Rueckfrage, die Enter ablehnt, haelt +`CMDACTIVE` sonst dauerhaft > 0. + +--- + +## 6. Omniflo (`OmniModulInsert.lsp`) + +| Funktion | Zweck | +|---|---| +| `omni:insert-dxf (sivasnr-str hoehe drehung)` | `%DXFM_OMNIFLO%/.dxf` einfuegen, `HOEHE`/`DREHUNG` setzen, Layer. **Einfuegepunkt per Maus** (`pause`); Rueckgabe: Einfuegepunkt oder nil | +| `omni:insert-from-entry (dlg-result)` | Dialog-Ergebnis von Bogen/Weiche -> `omni:insert-dxf` | +| `omni:make-gerade (blockname pt pt2 srcAttribs textHeight textGap textEnt)` | **skriptfaehig**: Aluprofil-Gerade `"AP60"`/`"AP110"`/`"APG110"` von `pt` nach `pt2` als Compound-Block mit Text. `srcAttribs` per `omni:read-src-attribs`, `textEnt` nil. Kein `ssg-start` - Aufrufer setzt OSMODE/ATTREQ/ATTDIA = 0. Rueckgabe: Entity | +| `omni:insert-block (blockname laengemax)` | Befehls-Kern der Geraden (fragt `pt`/`pt2` per `getpoint`) | +| `omni:ladeschleifen-dialog (profiltyp init-hoehe)` | Dialog Ladeschleife, danach `omni:insert-dxf` | + +Skriptfaehig fuer Boegen/Weichen: `_.INSERT` der DXF direkt mit Punkt +`(x y hoehe)` und Drehung, danach `ssg-attrib-set-on` mit `HOEHE`/`DREHUNG` +(`omni:test-insert` in `tests/test_omniflo.lsp`). Die festen TEF-/Zubehoer- +Befehle (`OMNI_TEF_*`, `OMNI_STOPPER` ...) rufen `omni:insert-dxf` mit fester +Sivas-Nummer. `OMNI_TV_*` und `OMNI_APBW_*` sind Platzhalter ohne Bau-Logik. + +--- + +## 7. TEF-Foerderer-Linie (`TEFInsert.lsp`) + +| Funktion | Zweck | +|---|---| +| `c:TEF_FOERDERER_LINIE` | Start-/Endpunkt abfragen, Linie zeichnen, 1000-mm-TEF-Geraden (`0_B10030.dxf`) aneinanderreihen; das letzte Stueck wird zurueckversetzt, damit der Foerderer genau am Linienende endet | +| `tefl-insert-element (start richtung-einheit s hz winkel)` | ein Element an Position `s` (mm ab `start`) entlang der Linie, Rz(hz)*Ry(winkel) | +| `tefl-ensure-block-loaded (dxf-pfad)` | Blockdefinition einmal laden | + +--- + +## 8. Geruest (`GeruestInsert.lsp`) + +| Funktion | Zweck | +|---|---| +| `geruest-einfuegen (bg wahl)` | Befehls-Kern Saeulen/Rohrabhaenger/Wandbefestigung: baut aus der Dialog-Auswahl `wahl` = `(variante-index oben unten laenge farbe)` die Werte (ARTINR, BEZEICHNUNG, TEILEART, LAENGE, TEILEFARBE), fragt dann den Punkt per `getpoint` | +| `geruest-block-bauen (bg variante werte pt teile-dwgs)` | **skriptfaehiger Kern**: Dummy-DWG + Teile-DWGs bei `pt`, Block `GR__`. `bg` = Baugruppe aus `geruest.json`, `werte` = Attribut-Alist, `teile-dwgs` aus `geruest-teile-dwgs` | +| `geruest-traeger-einfuegen (bg wahl)` | Befehls-Kern Traeger: Schleife Startpunkt -> Endpunkt oder Laenge | +| `geruest-traeger-block-bauen (bg layer netto strebe strebe-pfad muffe-pfad werte pt winkel)` | **skriptfaehiger Kern** Traeger: LINE (0,0,0)-(netto,0,0), Streben, Muffe, Block bei `pt` mit `winkel` (Radiant). Rueckgabe: `(blockname . entity)` | +| `geruest-traeger-laenge`, `-start`, `-streben`, `-pruefen` | reine Berechnung (Netto-Laenge nach Abzuegen, Startpunkt, Strebenverteilung, min/max) - in `tests/test_unit.lsp` getestet | +| `geruest-traeger-beschriften (blockEnt)` | Beschriftungstext aus dem fertigen Block | +| `geruest-block-abschliessen (bg attribs werte lastEnt pt rot)` | gemeinsamer Schluss aller Geruest-Bloecke (ATTDEFs, Block bilden, einfuegen, ID) | + +Fuer Geruest gibt es noch keinen JSON-Treiber. + +--- + +## 9. Einfuegeprimitiven (`ssg_ks_insert.lsp`, `vf_etage.lsp`) + +Grundbausteine, auf denen VF, GF und Linienzug aufsetzen. Alle legen **KS_EIN** +des Blocks (nicht den Block-Ursprung) auf den Startpunkt und geben den +Weltpunkt von **KS_AUS** zurueck - damit lassen sich Bausteine verketten. + +| Funktion | Zweck | +|---|---| +| `ensure-block-loaded (name)` | Block einmal ins Dokument laden | +| `extract-ks-from-block (block-obj)` | KS_EIN/KS_AUS eines eingefuegten Blocks (VLA-Objekt) lesen, Cache `*ks-cache*` je Blockname | +| `insert-block-by-ks (blockname einfuegepunkt hz)` | Block nur um Z gedreht (AS/ES-Elemente, Stationen) | +| `insert-inclined-scaled-block (blockname startpunkt laenge winkel hz)` | Block in X auf `laenge` skaliert und um `winkel` geneigt, Rz(hz)*Ry(winkel) (Staustrecken) | +| `insert-rotated-block-with-ks (blockname startpunkt winkel block-dx block-dz hz)` | Block gedreht, `block-dx`/`block-dz` nur als Fallback ohne KS_AUS (Boegen) | +| `insert-hz-scaled-block-by-ks (blockname startpunkt laenge hz-winkel vert-winkel)` | waagrechter, auf `laenge` skalierter Block (`Staustrecke_SP_1000_mm`, Massstab `laenge/1000`); Kandidat fuer die noch fehlende waagrechte Foerderstrecke. Bricht bei fehlender Blockdatei mit `(exit)` ab - vorher mit `ssg-ils-block-laden` pruefen | +| `ssg-rot-matrix-zy (chz shz cv sv)` | 4x4-Rotationsmatrix Rz(hz)*Ry(vert) aus Cosinus/Sinus beider Winkel (`ssg_core.lsp`) | + +--- + +## 10. Gemeinsame Regeln fuer eigene Treiber + +- Systemvariablen ueber `ssg-start`/`ssg-end` sichern; `OSMODE` 0, + `ATTREQ` 0, `ATTDIA` 0 setzen, sonst fragt `_.INSERT` nach Attributen. +- Module vorher laden: `(ssg-ensure "KreiselInsert")`, `"VarioFoerderer"`, + `"Gefaellestrecke"`, `"SSG_LIB_Commands"`. +- Die Dimension folgt `ssg-ils-dim-aktuell`; fuer einen festen Lauf + `*ssg-ils-dim*` (bzw. `*vsp-dim-override*` beim Spec-Bau) setzen und danach + zuruecksetzen. +- Rueckgaben nicht mit `and`/`or` verketten - die liefern in AutoLISP nur + T/nil (siehe `CLAUDE.md`, Konventionen). +- Interaktive GUI abschalten: `ssg-gui-aus` bzw. `vsp-headless-an`. +- Vorbilder: `tests/test_mubea.lsp` (Kreisel, VF Standard/Etage, GF, + Einzelbloecke), `tests/test_hundm05.lsp` (Spec-Ketten, Kreisel, + Einzelbloecke), `tests/test_omniflo_strecke.lsp` (Omniflo).