diff --git a/CLAUDE.md b/CLAUDE.md index 84ed02c..79b2df9 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -101,7 +101,7 @@ Detaillierte Dokumentation aller Funktionen und Befehle: siehe `Lisp/README.md`. | `ssg_layer.lsp` | - | Layer-Verwaltung. `ssg-layer-visible-p` (aus ODER gefroren), `ssg-layer-gefroren-p`/`ssg-ent-layer-gefroren-p` (NUR gefroren, fuer den Export) | | `KreiselInsert.lsp` | KreiselInsert, KreiselConnect, KreiselRedraw, KreiselQuick, KreiselEdit, KreiselParams, KreiselLabelSetup, KreiselLabelPos, KreiselLabelHoehe, ILS_Eckrad | ILS Kreisel und Eckrad komplett in AutoLISP | | `VarioFoerderer.lsp` (Wrapper fuer `vf_core.lsp`/`vf_standard.lsp`/`vf_etage.lsp`/`vf_linienzug.lsp`) | FOERDERANLAGE, VARIOFOERDERER_EDIT, VARIOFOERDERER_NACHRUESTEN, Vario_Kette_Merge, VF_SEKTION_RESTORE, VF_WIZARD_AN, VF_WIZARD_AUS | Vario-Foerderanlagen Generator (Typen Standard/Etage/Linienzug); Standard- UND Etage-Typ: Werteingabe per DCL-Dialog. Der Dialog-Ablauf ist zentral in vf_core (`vf-dialog-ablauf`/`vf-dialog-berechnen-einfuegen`, parametrisiert ueber Typ-Registry `*vf-typ-registry*` + Flag `horizontal-p`); `vfs-standard-dialog-ablauf`/`vfe-etage-dialog-ablauf` sind nur noch duenne Wrapper darauf. Beide nutzen dieselben Dialoge `vfs-dialog-eingabe-basis`/`vfs-dialog-winkel-verteilung` und den gemeinsamen L_GF/L_VF-Solve `vf-winkel-solve` (vf_core; berechne-alle-winkel/berechne-winkel-etage teilen ihn); Doppelklick auf VF_n-Block ruft VARIOFOERDERER_EDIT, das per SSG_VF_EDIT-XDATA-Marker ("standard"/"etage"/"linienzug") in den passenden Neuaufbau-Zweig dispatcht (`vfe-edit-ent` fuer Etage, `vfl-edit-ent` fuer Linienzug); Altbestand-Bloecke ohne Marker werden abgewiesen. Linienzug (Modus 1, `vf-linienzug-modus`) zeichnet jede interaktive Eingabe in einem Journal auf (`vfl-in-point`/`-string`/`-real`/`-int`) und schreibt es als XDATA auf den fertigen `VF_n`-Block; ein Abbruch (ESC) loescht dadurch nichts mehr, sondern wickelt die bis dahin gebaute Teil-Geometrie ebenso zu einem Block (`vfl-modus-abbruch-sichern`) - sie bleibt stehen und ist sofort per Doppelklick weiter editierbar/fortsetzbar. Der komplette Linienzug-Hauptstrang (Menue-Fragen von AS-Element bis Kettenende, inkl. GF-Bogen/Vario-Kurve/VF-Einheit-Fortsetzung) laeuft per Default ueber DCL-Dialoge statt Konsole (`*vfl-wizard-mode*`, Befehle VF_WIZARD_AN/VF_WIZARD_AUS): `vfl-in-string`/`-int`/`-real` zeigen bei aktivem Wizard-Modus generische Dialoge aus `dcl/vf_linienzug_wizard.dcl` (Zahl-Eingabe bzw. Mehrfachauswahl aus `vfl-menu`/`vfl-menu-int`) statt `getstring`/`getint`/`getreal` aufzurufen; die ORIGINALEN Konsolen-Fragen (princ + get*, de/en ueber ssg-text) bleiben unveraendert im Code (Fallback bei Fehlern via `vl-catch-all-apply`, siehe `doc/variofoerderer.md`). `vfl-edit-ent` liest das Journal, zeigt die Sektionen ueber einen DCL-Dialog (`vfl-dlg-position`, `dcl/vfl_edit.dcl`) an, kuerzt bei Bedarf auf eine gewaehlte Sektion (stummer Replay der behaltenen Eingaben, umgeht den Wizard-Zweig komplett) und baut danach interaktiv weiter. Linienzug Modus 2 (Pfad+Zielhoehe-Solver, `vf-linienzug-modus2`) nutzt dieselben Wrapper PLUS die neue Objektauswahl-Wrapper-Funktion `vfl-in-selection` (Pfad-Objekte als stabile Entity-Handles journalisiert, neue Journal-Art `"OBJS"`) und schreibt sein Journal unter dem eigenen XDATA-Marker `"linienzug2"`; Doppelklick baut hier NICHT abschnittsweise, sondern per vollem Reset 1:1 aus dem Journal neu auf (`vfl-edit-ent2`, dispatcht aus `vfl-edit-ent` per Marker) - Modus 3 (Vorwaerts-Nachbau) bleibt bewusst reine Konsole (im Code selbst als Legacy/"wird umgebaut" markiert). `Vario_Kette_Merge` (in vf_linienzug.lsp) fuehrt mehrere einzeln gebaute VF_n-Bloecke ab einem gewaehlten Start-Baustein ueber die reale KS_AUS->KS_EIN-Nachbarschaft zu einem Gesamt-Block zusammen (aggregierte Attribute, Luecken-Erkennung). Die interaktiven Editier-Pfade (`vfl-edit-ent` Sektions-Zweig, `vfl-edit-ent2`) rufen den Neuaufbau BEWUSST direkt auf, NICHT ueber `vl-catch-all-apply`: der alte Block ist beim Neuaufbau schon per `entdel` weg, und ein Catch faengt den Abbruch VOR `*error*` ab - der Abbruch-Wickler `vfl-modus-abbruch-sichern` kaeme nie zum Zug und die ganze Kette bliebe als lose Einzelteile ohne Block liegen (Fehlerbild "VF-Block aufgebrochen"). Nur der nicht-interaktive Batch-Konverter `vfl-konvertiere-ent` behaelt den Catch (die Batch-Schleife muss weiterlaufen) und meldet den betroffenen Block. Die Abbruch-Handler setzen zusaetzlich `*ssg-ils-dim*` zurueck, weil der Aufrufer, der das sonst tut, nach einem Abbruch nicht mehr erreicht wird. Recovery-Pfad fuer bereits aufgebrochene Ketten: `VF_SEKTION_RESTORE` (vf_linienzug.lsp) setzt das Ketten-Journal aus der XDATA der losen Objekte zusammen - `SSG_VF_EDIT_SEG` traegt pro Entity den Journal-Abschnitt DER ITERATION, in der es entstand (indiziert mit dem ersten Glied-Index darin; eine VF-Einheit mit eingebetteten Vario-Kurven erzeugt mehrere Glieder in einer Iteration), `SSG_VF_EDIT_PRE` auf den Entities des ersten Gliedes die Praeambel (Startpunkt/Starthoehe/AS). Die `.dbg`-Dateien sind reine AUSGABE und werden von keinem Befehl gelesen (dbgopen legt sie bei jedem Lauf neu an) - Wiederherstellungs-Daten gehoeren in die XDATA. `vf_konstanten.lsp` (von vf_core.lsp vor den drei Submodulen geladen) sammelt alle Laengen-/Winkel-/Toleranz-Magic-Numbers aus dem VarioFoerderer-Cluster als dokumentierte `*vfk-*`-Konstanten. Die Migration ist abgeschlossen: vf_core/vf_standard/vf_etage/vf_linienzug referenzieren durchgaengig die zentralen Konstanten statt roher Literale (Winkel, Stations-/Separator-Laengen, Mindestlaengen, AS/ES-Fallback-Versaetze, Text-/Label-Masse) - Ausnahmen sind in `vf_konstanten.lsp` selbst dokumentiert (Werte mit fuehrender Config-Anbindung via `ssg-cfg-or`, itoa-/Integer-Kontexte, Blocknamen-Strings, die 2000.0-mm/m-Umrechnung). `*vfk-gf-bogen-winkel*` (30/60/90, GF-Bogen + Vario-Kurve) und `*vfk-as-es-winkel*` ("30"/"90", AS/ES; bewusst STRING, da 2-wertig und im Journal als STR gefuehrt) sind Beispiele; vf_linienzug hat fuer beide einen Fallback, falls vf_konstanten nicht geladen wurde. **Nicht-interaktiver Betrieb**: `*vfl-headless*` (+ `vfl-headless-p`/`-abbruch`/`-notausgang`, Diagnose `*vfl-headless-fehler*`, optionaler Antwort-Hook `*vfl-headless-antwort-fn*`) verbietet jede Live-Eingabe - eine erschoepfte Replay-Queue ist damit ein harter Abbruch MIT Fundstelle (Art der Eingabe, Glied- und Eingabe-Nummer) statt eines stillen Rueckfalls auf `getpoint`/`getreal`; eingebaut in `vfl-in-value`/`-value-p`/`-selection`/`-abstand`. Die Bau-Pfade melden abgewiesene Sektionen ueber `vfl-meldung` (sammelt nach `*vfl-meldungen*` + `dbgmsg`, `alert` nur bei erlaubter GUI, sonst `princ`) statt per blockierendem `alert`; reine Interaktiv-Alerts (fehlendes DCL, "nicht editierbar", "kein Journal") bleiben `alert`. Genutzt von `tests/test_hm_recformat.lsp` (Replay der echten Aufzeichnungen) und von `vf_spec.lsp`; Fahrplan in `doc/TODO-plan-vf-interactive.md`. Details/Entscheidungsbaum: `doc/variofoerderer.md` | -| `vf_spec.lsp` (von vf_core.lsp NACH vf_linienzug.lsp geladen) | VF_SPEC_BAU | Linienzug-Ketten aus **Eingabedaten** bauen, ohne Dialog und ohne Konsolenfrage (Stufe 1 aus `doc/TODO-plan-vf-interactive.md`). Eine **Spec** beschreibt eine Kette in Domaenenwerten (`"links"`, `"winkel"`, `"aussen"`, ja/nein) statt in Menue-Codes; `vsp-journal` uebersetzt sie in ein Eingabe-Journal, `vsp-bau-aus-spec` spielt es per `vfl-journal-replay-start` durch den UNVERAENDERTEN `vf-linienzug-modus`. Damit traegt der fertige Block dasselbe `SSG_VF_EDIT`-Journal wie eine handgebaute Kette und bleibt per Doppelklick editier- und 2D/3D-konvertierbar - kein Journal-Konsument muss etwas von Specs wissen. Wichtige Regeln, die der Uebersetzer kennt: der Menue-Code haengt am Frame (erste Sektion 4 Optionen ohne GF-Bogen, danach 5), `hz` steht nur beim ERSTEN Segment im Journal, und `erst-hor` unterscheidet den horizontalen Erstkoerper einer VF-Einheit (Separator-/Endpunktfragen vorab) vom gewinkelten (keine Frage). Fehlerverhalten: fail fast - `vsp-pruefen` sammelt ALLE Spec-Fehler, gebaut wird dann nichts (nichts wird geraten). Ergebnis-Record je Kette mit `status` (`executed`/`warnung`/`desync`/`abbruch`/`spec-fehler`), Block/Handle/Einfuegepunkt/Attributen, `prompts` (muss 0 sein), `glieder_soll` vs. `glieder_ist` (Desync-Detektor, der auch bei aufgehender Queue greift) und den gesammelten `meldungen`. Headless-Rahmen `vsp-headless-an`/`-aus` (Save/Restore von `*vfl-headless*`, `*vfl-wizard-mode*`, `*ssg-gui-aus*` + zaehlende Eingabe-Stubs). Spec-Datei flach als JSON (`ssg-load-json` liest zeilenweise), erzeugt von `lib/vf_spec_export.py`. Gegenstueck/Referenz in Python: derselbe Emitter, gegen die 5 echten HundM-Ketten rundlaufgeprueft | +| `vf_spec.lsp` (von vf_core.lsp NACH vf_linienzug.lsp geladen) | VF_SPEC_BAU | Linienzug-Ketten aus **Eingabedaten** bauen, ohne Dialog und ohne Konsolenfrage (Stufe 1 aus `doc/TODO-plan-vf-interactive.md`). Eine **Spec** beschreibt eine Kette in Domaenenwerten (`"links"`, `"winkel"`, `"aussen"`, ja/nein) statt in Menue-Codes; `vsp-journal` uebersetzt sie in ein Eingabe-Journal, `vsp-bau-aus-spec` spielt es per `vfl-journal-replay-start` durch den UNVERAENDERTEN `vf-linienzug-modus` (Replay-Kern `vsp-bau-journal` - nimmt auch ein unveraendert uebernommenes, aufgezeichnetes Journal, z.B. aus `dxf_anlage_export.py`). Damit traegt der fertige Block dasselbe `SSG_VF_EDIT`-Journal wie eine handgebaute Kette und bleibt per Doppelklick editier- und 2D/3D-konvertierbar - kein Journal-Konsument muss etwas von Specs wissen. Wichtige Regeln, die der Uebersetzer kennt: der Menue-Code haengt am Frame (erste Sektion 4 Optionen ohne GF-Bogen, danach 5), `hz` steht nur beim ERSTEN Segment im Journal, und `erst-hor` unterscheidet den horizontalen Erstkoerper einer VF-Einheit (Separator-/Endpunktfragen vorab) vom gewinkelten (keine Frage). Fehlerverhalten: fail fast - `vsp-pruefen` sammelt ALLE Spec-Fehler, gebaut wird dann nichts (nichts wird geraten). Ergebnis-Record je Kette mit `status` (`executed`/`warnung`/`desync`/`abbruch`/`spec-fehler`), Block/Handle/Einfuegepunkt/Attributen, `prompts` (muss 0 sein), `glieder_soll` vs. `glieder_ist` (Desync-Detektor, der auch bei aufgehender Queue greift) und den gesammelten `meldungen`. Headless-Rahmen `vsp-headless-an`/`-aus` (Save/Restore von `*vfl-headless*`, `*vfl-wizard-mode*`, `*ssg-gui-aus*` + zaehlende Eingabe-Stubs). Spec-Datei flach als JSON (`ssg-load-json` liest zeilenweise), erzeugt von `lib/vf_spec_export.py`. Gegenstueck/Referenz in Python: derselbe Emitter, gegen die 5 echten HundM-Ketten rundlaufgeprueft | | `Gefaellestrecke.lsp` | GEFAELLESTRECKE, GEFAELLESTRECKE_EDIT | Gefaelle-Foerderanlage (AUS -> Staustrecke skaliert -> Separator -> EIN); Modus 1 per DCL-Dialog (Einfuegehoehe, Element-Winkel 30/90); Doppelklick auf GF_n-Block ruft GEFAELLESTRECKE_EDIT (Dialog vorbelegt, Neuaufbau) | | `export.lsp` | EXPORTSIVAS, EXPORTCSV, OMNI_UPDATE_ATTRIBS, CSV_EXPORT_KONFIG | JSON-Sammlung und Python-Export (Omniflo-Merkmale/Sum-Zeile via lib/export_csv.py). **Gefrorene Layer**: `csv:collect-export-blocks` laesst Bloecke auf gefrorenen Layern aus (ausgeschaltete Layer zaehlen NICHT), Schalter `*csv-gefrorene-ausschliessen*` (Standard an, Toggle im Dialog CSV_EXPORT_KONFIG). Die Hilfsobjekte eines gefrorenen VF_n/GF_n (Separator-/Element-Kopien, Einheiten-/AS-ES-Marker) liegen auf eigenen Layern und werden darum ueber `*csv-ausschluss-enames*` mit ausgelassen (gesetzt in `csv:export-vorbereiten` per `csv:hilfskopien-ausschluss`); erzeugt und nummeriert werden sie trotzdem, damit IDs stabil bleiben. DrawPlanquadrate nutzt dieselbe Sammlung und folgt dem Filter | | `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 | @@ -190,7 +190,8 @@ Abhaengigkeiten: `ezdxf`, Standard-Library. Benoetigen Umgebungsvariablen (`DXFM | `vf_journal_export.py` | Liest die Eingabe-Journale der `VF_n`-Bloecke (XDATA-App `SSG_VF_EDIT`, Marker `"linienzug"`) aus einer Zeichnung und schreibt sie als Frage-Antwort-Protokoll im Schema von `tests/testdata/linienzug_tests.json` (Gegenstueck zu `vfl-entry->string`; kein ezdxf, reine Gruppencode-Lesung). Optional `--csv ` fuer Strecken-ID und Erwartungswerte je Kette. Aufruf: `python vf_journal_export.py [--csv ...] [--kein-startpunkt-fix]` — erzeugt `tests/testdata/hm_recformat.json` aus `data/polylines.dxf` (die Aufzeichnung, aus der `tests/testdata/hundm05.json` als Spec abgeleitet wird) | | `dxf_vf_abbild.py` | Abbild der `VF_`/`GF_`-Wrapperbloecke einer Testzeichnung: Attribute UND Bausteinzusammensetzung je Kette, Ketten ueber den Einfuegepunkt der Spec zugeordnet (der Blockname taugt nicht - die VF-Nummer beginnt in jeder Zeichnung neu bei 1). Regressionsnetz fuer Umbauten am Bau-Ablauf: `--referenz` vergleicht gegen `tests/reference/hundm05_attribute.json` (Exit 1 bei Abweichung), `--schreibe-referenz` frischt sie nach einem GEPRUEFTEN Lauf auf. Faengt genau das, was der Ergebnis-Record nicht sieht - eine vertauschte `vfl-acc-*`-Reihenfolge (Komma-Listen `L_VF_m`/`L_GF_m`/`GF_WINKEL`, in der Zeichnung unsichtbar, im Sivas-Export falsch) und eine falsche Blockvariante. Liest ASCII-DXF streamend; binaere DXF kann `dxf_scan_components.py`. Genutzt von `tests/test_vf_geometrie.py` | | `vf_spec_export.py` | Uebersetzt ein Eingabe-Journal in eine **Spec** und zurueck (`spec_aus_journal` / `journal_aus_spec`) - Gegenstueck zu `vsp-journal` in `Lisp/vf_spec.lsp`, beide muessen dieselbe Tokenfolge liefern. Der Rundlauf `journal_aus_spec(spec_aus_journal(tok)) == tok` laeuft in `tests/test_vf_spec.py` gegen die 5 echten HundM-Ketten und beweist, dass die Spec das Journal verlustfrei abbildet. Schreibt das flache Spec-JSON (vom LISP-Parser lesbar). Objekte der Ziel-Datei, die keine Kette beschreiben (von Hand ergaenzte Anlagenteile mit `function`, z.B. Kreisel), werden beim Neuschreiben unveraendert ans Dateiende uebernommen - sonst waeren sie beim naechsten Lauf weg. Aufruf: `python vf_spec_export.py ` — erzeugt `tests/testdata/hundm05.json` (Spec, Eingabe fuer `TEST_HUNDM05`/`VF_SPEC_BAU`) aus `tests/testdata/hm_recformat.json` (Aufzeichnung) | -| `dxf_scan_components.py` | Erkennt ILS-/Omniflo-Komponenten in einer **fremden** Projektzeichnung (ohne unsere Wrapper-Bloecke) und schreibt sie im JSON-Schema aus `tests/testdata/object_data.md` — Grundlage fuer Nachbau-Testfaelle wie `tests/testdata/mubea.json`. Liest binaere DXF im GB-Bereich streamend per mmap (ezdxf-DOM waere zu gross), loest INSERTs inkl. OCS/Extrusionsrichtung rekursiv in Weltkoordinaten auf, paart AN8/SP8 zu Kreiseln und Antrieb/Umlenkung zu Foerderern. Aufruf: `python dxf_scan_components.py [--fenster X0 Y0 X1 Y1]` — ohne `--fenster` liefert eine Anlagenzeichnung leicht ueber 1300 Eintraege, zuviel fuer einen Testlauf | +| `dxf_anlage_export.py` | Gegenstueck zum Scanner: liest eine mit unseren Makros GEBAUTE (und von Hand nachbearbeitete) Anlage aus der Zeichnung zurueck in Nachbau-Testdaten - je Wrapper genau die Parameter, die auch dessen Edit-Befehl liest (KREISEL_n: Einfuegepunkt, `abstand` exakt aus der Blockdefinition; GF_n: SSG_GF_EDIT + SEITE_AS/ES, endet die GF auf einer Kreisel-Kette, wird dessen Hoehe `hoehe_ende_mm`; VF_n `standard`/`etage`: mubea-Schema wie `vfs-edit-basis-lesen`; VF_n `linienzug`: Journal UNVERAENDERT als `"typ": "linienzug_journal"` - bewusst keine Spec, weil der Bau-Dialog neuer ist als die Spec-Grammatik; uebrige Bloecke als Einzel-Insert ohne `_2D`/`_3D`-Suffix). Reihenfolge Kreisel, VF, GF, Einzelbloecke (VF vor GF wie mubea). Aufruf: `python dxf_anlage_export.py [--projekt NAME]` — erzeugt `tests/testdata/dematic_arvato.json` aus `Dematic_TST.dxf`. Test `tests/test_dxf_anlage_export.py` | +| `dxf_scan_components.py` | Erkennt ILS-/Omniflo-Komponenten in einer **fremden** Projektzeichnung (ohne unsere Wrapper-Bloecke) und schreibt sie im JSON-Schema aus `tests/testdata/object_data.md` — Grundlage fuer Nachbau-Testfaelle wie `tests/testdata/mubea.json`. Liest binaere DXF im GB-Bereich streamend per mmap (ezdxf-DOM waere zu gross), loest INSERTs inkl. OCS/Extrusionsrichtung rekursiv in Weltkoordinaten auf, paart AN8/SP8 zu Kreiseln und Antrieb/Umlenkung zu Foerderern. Gefaellestrecken, die als 3D-LINE auf einem Staustrecken-Layer gezeichnet sind (`GF_LINIE_LAYER`, z.B. `6-SP`), werden in einem zweiten Lesedurchgang zu Modus-1-Eintraegen: Start/Ende werden auf die Ketten der anschliessenden Kreisel verlaengert (gezeichnet ist nur die Staustrecke; `deltaL` reicht von AS- bis ES-Ursprung), AS-Seite aus dem Ausschleuselement am oberen Ende; dieses und Separatoren auf der Achse entfallen als Einzel-Insert (die GF baut beide selbst). Sitzt der AS am UNTEREN Ende, ist es ein Steigfoerderer und wird nur gemeldet (`gf_eintraege_aus_linien`, Test `tests/test_dxf_scan_gf.py`). `--ohne-hoehen` setzt alle Z auf 0, `--kreisel-hoehe X Y Z` gibt einem Kreisel seine Hoehe - die daran haengenden GF bekommen daraus `start_mm.z`/`hoehe_ende_mm`, den Winkel rechnet der Treiber (`dematic_arvato:gf-winkel` ueber `gf-winkel-berechnen`). Aufruf: `python dxf_scan_components.py [--fenster X0 Y0 X1 Y1]` — ohne `--fenster` liefert eine Anlagenzeichnung leicht ueber 1300 Eintraege, zuviel fuer einen Testlauf | ### Entwickler-Tools (`lib/`) - kein ezdxf, reine Text-/AutoLISP-Verarbeitung diff --git a/Lisp/vf_spec.lsp b/Lisp/vf_spec.lsp index 67b48ec..66609ff 100644 --- a/Lisp/vf_spec.lsp +++ b/Lisp/vf_spec.lsp @@ -903,15 +903,28 @@ ;; abgebrochene Kette bleibt also als lose Geometrie liegen und ist per ;; c:VF_SEKTION_RESTORE rettbar (vfl-segment-xdata-sichern hat pro Iteration ;; schon SSG_VF_EDIT_SEG/_PRE geschrieben). -(defun vsp-bau-aus-spec (spec / kopf sid journal rec vor-ent alt-error err - offen hl meld ist-glieder soll-glieder diff - ist-journal jdiff ent ed dim) +(defun vsp-bau-aus-spec (spec / kopf journal) (setq kopf (vsp-kopf spec)) - (setq sid (vsp-spec-id kopf)) + ;; vsp-journal sammelt seine Fehler in *vsp-fehler* - darum erst danach lesen. (setq journal (vsp-journal spec)) + (vsp-bau-journal (vsp-spec-id kopf) journal (ssg-val kopf "dim") *vsp-fehler*)) + +;; Eine Kette aus einem fertigen Eingabe-Journal bauen (Liste (art . wert) in +;; Bau-Reihenfolge, wie vfl-journal-replay-start sie erwartet). Gemeinsamer +;; Kern fuer Specs (vsp-bau-aus-spec, Journal per vsp-journal uebersetzt) und +;; fuer UNVERAENDERT uebernommene Aufzeichnungen - z.B. die SSG_VF_EDIT-XDATA +;; eines von Hand gebauten VF_n (tests/test_dematic_arvato.lsp, Journal per +;; vfl-string->entry gelesen). Letztere brauchen keinen Uebersetzer und +;; laufen darum auch dann, wenn der Dialog neuer ist als die Spec-Grammatik. +;; sid = Kennung im Record, dim = "2D"/"3D" oder nil (Sitzung), +;; fehler = Liste der Spec-Fehler (bei nil-Journal die Begruendung). +;; Erwartet den Headless-Rahmen (vsp-headless-an) beim Aufrufer. +(defun vsp-bau-journal (sid journal dim fehler / rec vor-ent alt-error err + offen hl meld ist-glieder soll-glieder diff + ist-journal jdiff ent ed) (setq soll-glieder (if journal (vfl-journal-glieder journal) nil)) (setq rec (vsp-rec-neu sid)) - (setq rec (vsp-set rec "spec_fehler" *vsp-fehler*)) + (setq rec (vsp-set rec "spec_fehler" fehler)) (setq rec (vsp-set rec "glieder_soll" soll-glieder)) (setq rec (vsp-set rec "eingaben_gesamt" (if journal (length journal) 0))) (princ (strcat "\n [SPEC] " sid)) @@ -919,9 +932,9 @@ (cond ;; --- Spec fehlerhaft: nichts bauen --- ((null journal) - (princ (strcat "\n " (itoa (length *vsp-fehler*)) + (princ (strcat "\n " (itoa (length fehler)) " Spec-Fehler, nichts gebaut:")) - (foreach f *vsp-fehler* (princ (strcat "\n - " f))) + (foreach f fehler (princ (strcat "\n - " f))) (setq rec (vsp-set rec "status" "spec-fehler")) (setq rec (vsp-set rec "dimension" (vsp-dim-text))) rec) @@ -934,7 +947,7 @@ ;; Feld in der Spec. Ist keines gesetzt, gilt die Sitzung. (setq dim (if (and (boundp '*vsp-dim-override*) *vsp-dim-override*) *vsp-dim-override* - (ssg-val kopf "dim"))) + dim)) (if dim (setq *ssg-ils-dim* dim)) (setq rec (vsp-set rec "dimension" (vsp-dim-text))) (princ (strcat " -> " (itoa (length journal)) " Journal-Eintraege, " diff --git a/lib/dxf_anlage_export.py b/lib/dxf_anlage_export.py new file mode 100644 index 0000000..c5e50e4 --- /dev/null +++ b/lib/dxf_anlage_export.py @@ -0,0 +1,408 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +dxf_anlage_export.py - Eine mit unseren Makros GEBAUTE (und von Hand +nachbearbeitete) Anlage aus der Zeichnung zurueck in Nachbau-Testdaten +schreiben. + +Gegenstueck zu lib/dxf_scan_components.py: der Scanner liest FREMDE +Zeichnungen (Rohbloecke, Linien) und muss vieles raten. Hier stehen unsere +Wrapper-Bloecke in der Zeichnung, und jeder traegt seine Bau-Parameter +selbst - als Attribute und XDATA, genau die Werte, die auch der jeweilige +Edit-Befehl (Doppelklick) zum Neuaufbau liest. Typischer Ablauf: Scanner- +Vorlage nachbauen, in BricsCAD von Hand korrigieren/ergaenzen, Zeichnung als +DXF speichern und mit diesem Skript die Testdaten aktualisieren. + +Je Wrapper (Felder wie in tests/testdata/object_data.md bzw. mubea.json): + + KREISEL_n -> Kreisel ("function": "insert", x/y/z = Einfuegepunkt, + abstand = Mittenabstand AN8-SP8 aus der Blockdefinition, + rotation, typ = KREISELART) + GF_n -> Gefaellestrecke Modus 1 (XDATA SSG_GF_EDIT wie + gf-xdata-lesen + SEITE_AS/SEITE_ES wie GEFAELLESTRECKE_EDIT). + Endet die Strecke auf der Kette eines Kreisels, wird statt + des gebauten Winkels dessen Hoehe als hoehe_ende_mm + uebernommen - der Treiber rechnet den Winkel daraus neu. + VF_n "standard"/"etage" + -> VarioFoerderer im mubea-Schema (Parameter wie + vfs-edit-basis-lesen: Einfuegepunkt, hz aus XDATA, DELTA_L/ + DELTA_H/ANTRIEBFAHRTRICHTUNG/SEITE_AS/MOTORSEITE, dazu + VF_WINKEL und L_GF1 aus L_GF_m) + VF_n "linienzug" + -> das Eingabe-Journal UNVERAENDERT ("typ": + "linienzug_journal"). Bewusst KEINE Spec: der Bau-Dialog ist + neuer als die Spec-Grammatik (vf_linienzug_grammatik.py, + vf_spec.lsp), eine Uebersetzung wuerde desynchronisieren. + Der Treiber spielt das Journal per vsp-bau-journal ab. + sonstige Bloecke (Separator, Scanner, ...) + -> Einzel-Insert ("function": "insert", "block" ohne + _2D/_3D-Suffix, damit die Dimension der Sitzung gilt) + +Nicht uebernommen (gemeldet): "linienzug2" (Modus 2 - Journal verweist auf +Pfad-Objekte der Zeichnung per Handle) und Bloecke ohne Bau-Parameter. + +Aufruf: + python dxf_anlage_export.py [--projekt NAME] + +Beispiel (Dematic/Arvato, Nachbau-Daten fuer TEST_DEMATIC_ARVATO): + python lib/dxf_anlage_export.py C:/develop/sps_skel/data/Dematic_TST.dxf \\ + tests/testdata/dematic_arvato.json --projekt Arvato + +Bewusst OHNE ezdxf: reine Gruppencode-Lesung (vf_journal_export.gruppen), +ASCII-DXF. +""" + +import argparse +import collections +import json +import math +import os +import re +import sys + +sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) +from vf_journal_export import TRENNER, gruppen # noqa: E402 +from dxf_scan_components import arrays_einzeilig, kreisel_anschluss # noqa: E402 + +PREFIX = "[dxf_anlage_export]" +RUND = 2 + +# Kreisel-Durchmesser (Radmitte bis Kette), wie component_defaults.json. +KREISEL_RADIUS = 400.0 + +# Bis zu diesem Abstand (mm) gilt ein GF-Ende als auf der Kette eines +# Kreisels (der GF-Bau legt AS-/ES-Ursprung genau auf die Kette). +GF_KREISEL_TOL = 50.0 + +DIM_SUFFIX = re.compile(r"_(2D|3D)$") + + +# ============================================================ +# DXF lesen +# ============================================================ + +def _float(v): + try: + return float(v) + except (TypeError, ValueError): + return 0.0 + + +def lese_zeichnung(dxf_pfad): + """Modelspace-INSERTs (mit Attributen und XDATA je App) und die INSERTs + jeder Blockdefinition. + + Rueckgabe: (inserts, block_inhalt) + inserts - Liste {name, handle, p, rot, attribs, xdata}; xdata ist + app -> Liste der 1000er-Werte in Reihenfolge + block_inhalt - blockname -> Liste {name, p} der direkt enthaltenen + INSERTs (fuer den Kreisel-Mittenabstand) + """ + paare = gruppen(dxf_pfad) + inserts = [] + block_inhalt = {} + section = None + block = None + i, n = 0, len(paare) + while i < n: + code, wert = paare[i] + if code != "0": + i += 1 + continue + if wert == "SECTION" and i + 1 < n: + section = paare[i + 1][1].strip() + elif wert == "ENDSEC": + section = None + elif wert == "BLOCK": + j = i + 1 + while j < n and paare[j][0] != "0": + if paare[j][0] == "2": + block = paare[j][1] + break + j += 1 + elif wert == "ENDBLK": + block = None + elif wert == "INSERT" and section in ("ENTITIES", "BLOCKS"): + e = {"name": None, "handle": None, "p": [0.0, 0.0, 0.0], + "rot": 0.0, "attribs": {}, "xdata": {}, "ps": 0} + app = None + j = i + 1 + while j < n and paare[j][0] != "0": + c, v = paare[j] + if c == "2" and e["name"] is None: + e["name"] = v + elif c == "5" and e["handle"] is None: + e["handle"] = v + elif c in ("10", "20", "30") and app is None: + e["p"][{"10": 0, "20": 1, "30": 2}[c]] = _float(v) + elif c == "50": + e["rot"] = _float(v) + elif c == "67": + e["ps"] = int(_float(v)) + elif c == "1001": + app = v + e["xdata"][app] = [] + elif c == "1000" and app: + e["xdata"][app].append(v) + j += 1 + # Attribute: ATTRIB-Entities bis SEQEND (Wert Code 1, Tag Code 2) + while j < n and paare[j] == ("0", "ATTRIB"): + k = j + 1 + tag = val = None + while k < n and paare[k][0] != "0": + if paare[k][0] == "2" and tag is None: + tag = paare[k][1] + elif paare[k][0] == "1" and val is None: + val = paare[k][1] + k += 1 + if tag: + e["attribs"][tag] = val if val is not None else "" + j = k + if section == "ENTITIES": + if e["ps"] != 1: + inserts.append(e) + elif block: + block_inhalt.setdefault(block, []).append( + {"name": e["name"], "p": e["p"]}) + i = j + continue + i += 1 + return inserts, block_inhalt + + +# ============================================================ +# Wrapper -> Eintraege +# ============================================================ + +def _nummer(name): + m = re.search(r"_(\d+)", name) + return int(m.group(1)) if m else 0 + + +def _r(v): + return round(float(v), RUND) + 0.0 + + +def _richtung(hz): + rad = math.radians(hz) + return (math.cos(rad), math.sin(rad)) + + +def kreisel_eintrag(e, block_inhalt, projekt): + """Kreisel wie hundm05:bau-kreisel ihn erwartet.""" + a = e["attribs"] + abstand = _float(a.get("ABSTAND")) + quelle = "Attribut ABSTAND (ganze mm)" + # Genauer aus der Blockdefinition: Mittenabstand der beiden Stationen + stationen = [s for s in block_inhalt.get(e["name"], []) + if s["name"] and s["name"].upper().startswith(("AN8", "SP8"))] + an = [s for s in stationen if s["name"].upper().startswith("AN8")] + sp = [s for s in stationen if s["name"].upper().startswith("SP8")] + if an and sp: + abstand = math.hypot(sp[0]["p"][0] - an[0]["p"][0], + sp[0]["p"][1] - an[0]["p"][1]) + quelle = "Blockdefinition (AN8 -> SP8)" + nr = int(_float(a.get("NUMMER"))) or _nummer(e["name"]) + return collections.OrderedDict([ + ("id", "Kreisel_%s_%02d" % (projekt, nr)), + ("function", "insert"), + ("x", _r(e["p"][0])), ("y", _r(e["p"][1])), ("z", _r(e["p"][2])), + ("abstand", _r(abstand)), + ("rotation", _r(e["rot"])), + ("typ", a.get("KREISELART") or "STANDARD"), + ("comment", "aus Zeichnung: %s (ID %s), abstand aus %s" + % (e["name"], a.get("ID", "?"), quelle)), + ]) + + +def kreisel_geo(kreisel): + """kreisel_geo-Form (siehe dxf_scan_components.kreisel_anschluss) aus + einem Kreisel-Eintrag: Achse ab AN8-Radmitte = Einfuegepunkt + Radius.""" + u = _richtung(kreisel["rotation"]) + return {"id": kreisel["id"], + "a": (kreisel["x"] + KREISEL_RADIUS * u[0], + kreisel["y"] + KREISEL_RADIUS * u[1]), + "u": u, "laenge": kreisel["abstand"], "r": KREISEL_RADIUS, + "z": kreisel["z"]} + + +def kreisel_an_punkt(p, richtung, geo): + """Kreisel, auf dessen Kette p liegt (oder None).""" + ans = kreisel_anschluss(p, richtung, geo) + if ans and abs(ans[2]) <= GF_KREISEL_TOL: + return ans[0] + return None + + +def gf_eintrag(e, geo, projekt, hinweise): + """Gefaellestrecke Modus 1 - Felder wie GEFAELLESTRECKE_EDIT sie liest.""" + a = e["attribs"] + xd = e["xdata"].get("SSG_GF_EDIT") + if not xd or len(xd) < 6: + hinweise.append("%s ohne SSG_GF_EDIT-XDATA - uebersprungen" % e["name"]) + return None + hz, winkel = _float(xd[0]), _float(xd[1]) + z_start, deltaL = _float(xd[4]), _float(xd[5]) + start = (e["p"][0], e["p"][1]) + r = _richtung(hz) + ende = (start[0] + deltaL * r[0], start[1] + deltaL * r[1]) + eintrag = collections.OrderedDict([ + ("test_id", "GF_%s_%02d" % (projekt, _nummer(e["name"]))), + ("modus", 1), + ("deltaL_mm", _r(deltaL)), + ("hz_grad", _r(hz)), + ("start_mm", [_r(start[0]), _r(start[1]), _r(z_start)]), + ("as_seite", a.get("SEITE_AS") or "links"), + ("es_seite", a.get("SEITE_ES") or "links"), + ("as_winkel", xd[2] or "90"), + ("es_winkel", xd[3] or "90"), + ]) + k_start = kreisel_an_punkt(start, r, geo) + k_ende = kreisel_an_punkt(ende, (-r[0], -r[1]), geo) + if k_start: + eintrag["kreisel_start"] = k_start["id"] + if k_ende: + eintrag["kreisel_ende"] = k_ende["id"] + eintrag["hoehe_ende_mm"] = k_ende["z"] + kommentar = ("Endhoehe = Hoehe von %s (%.1f), Winkel rechnet der " + "Treiber neu; gebaut war %.4f Grad -> HOEHE_BIS %s" + % (k_ende["id"], k_ende["z"], winkel, + a.get("HOEHE_BIS_mm", "?"))) + else: + eintrag["winkel_grad"] = round(winkel, 4) + kommentar = "kein Kreisel am Ende - gebauter Winkel uebernommen" + eintrag["comment"] = "aus Zeichnung: %s (ID %s); %s" % ( + e["name"], a.get("ID", "?"), kommentar) + return eintrag + + +def vf_standard_eintrag(e, projekt, typ): + """VarioFoerderer im mubea-Schema (mubea:vario-bauen).""" + a = e["attribs"] + xd = e["xdata"].get("SSG_VF_EDIT") or [] + l_gf = [t for t in (a.get("L_GF_m") or "").split(",") if t.strip()] + eintrag = collections.OrderedDict([ + ("test_id", "VF_%s_%02d" % (projekt, _nummer(e["name"]))), + ("typ", typ), + ("richtung", a.get("ANTRIEBFAHRTRICHTUNG") or "Auf"), + ("deltaL", _r(_float(a.get("DELTA_L_mm")))), + ("deltaH", _r(_float(a.get("DELTA_H_mm")))), + ("winkel", int(_float(a.get("VF_WINKEL")))), + ("L_GF1", _r(1000.0 * _float(l_gf[0])) if l_gf else 0.0), + ("seite", a.get("SEITE_AS") or "rechts"), + ("motorseite", (a.get("MOTORSEITE") or "rechts").split(",")[0]), + ("hz", _r(_float(xd[1]) if len(xd) > 1 else 0.0)), + ("x", _r(e["p"][0])), ("y", _r(e["p"][1])), ("z", _r(e["p"][2])), + ("comment", "aus Zeichnung: %s (ID %s), Hoehe %s -> %s; deltaL/" + "deltaH aus den (ganzzahligen) Attributen" + % (e["name"], a.get("ID", "?"), a.get("HOEHE_VON_mm", "?"), + a.get("HOEHE_BIS_mm", "?"))), + ]) + return eintrag + + +def vf_journal_eintrag(e, projekt, nr): + """Linienzug: Journal unveraendert (Tokens 'ART:wert').""" + a = e["attribs"] + roh = "".join(e["xdata"]["SSG_VF_EDIT"][1:]) + tokens = [t for t in roh.split(TRENNER) if t] + return collections.OrderedDict([ + ("test_id", "VF_%s_LZ_%02d" % (projekt, nr)), + ("typ", "linienzug_journal"), + ("journal", tokens), + ("comment", "aus Zeichnung: %s (ID %s), %d Eingaben, Hoehe %s -> %s; " + "wird 1:1 abgespielt (vsp-bau-journal)" + % (e["name"], a.get("ID", "?"), len(tokens), + a.get("HOEHE_VON_mm", "?"), a.get("HOEHE_BIS_mm", "?"))), + ]) + + +def einzel_eintrag(e): + a = e["attribs"] + info = ", ".join("%s %s" % (k, a[k]) for k in ("ID", "ZUORDNUNG", "ARTINR") + if a.get(k)) + return collections.OrderedDict([ + ("function", "insert"), + ("block", DIM_SUFFIX.sub("", e["name"])), + ("x", _r(e["p"][0])), ("y", _r(e["p"][1])), ("z", _r(e["p"][2])), + ("rotation", _r(e["rot"])), + ("comment", "aus Zeichnung: %s%s" % (e["name"], + (" (%s)" % info) if info else "")), + ]) + + +def baue_eintraege(inserts, block_inhalt, projekt): + """Reihenfolge wie mubea.json: Kreisel, VF, GF, Einzelbloecke - die VF + vor den GF, weil gf-init-bibliothek globale Elementmasse umsetzt.""" + kreisel, vf, lz, gf, einzel, hinweise = [], [], [], [], [], [] + for e in sorted(inserts, key=lambda e: (e["name"] or "", e["p"][0], e["p"][1])): + name = e["name"] or "" + if name.startswith("KREISEL_"): + kreisel.append(kreisel_eintrag(e, block_inhalt, projekt)) + geo = [kreisel_geo(k) for k in kreisel] + for e in inserts: + name = e["name"] or "" + if name.startswith("KREISEL_"): + continue + if name.startswith("GF_"): + g = gf_eintrag(e, geo, projekt, hinweise) + if g: + gf.append(g) + elif name.startswith("VF_"): + xd = e["xdata"].get("SSG_VF_EDIT") + marker = xd[0] if xd else None + if marker in ("standard", "etage"): + vf.append(vf_standard_eintrag(e, projekt, marker)) + elif marker == "linienzug": + lz.append(vf_journal_eintrag(e, projekt, len(lz) + 1)) + else: + hinweise.append("%s: Marker %r nicht nachbaubar - uebersprungen" + % (name, marker)) + elif name.startswith("*") or name.startswith("ZZ_"): + continue # anonyme Bloecke, Export-Marker + else: + einzel.append(einzel_eintrag(e)) + gf.sort(key=lambda g: g["test_id"]) + vf.sort(key=lambda v: v["test_id"]) + kreisel.sort(key=lambda k: k["id"]) + return kreisel + vf + lz + gf + einzel, hinweise + + +def main(): + p = argparse.ArgumentParser( + description="Gebaute Anlage (Wrapper-Bloecke) aus einer Zeichnung in " + "Nachbau-Testdaten schreiben.") + p.add_argument("dxf", help="Zeichnung (ASCII-DXF)") + p.add_argument("output", help="Ziel-JSON") + p.add_argument("--projekt", help="Kennung in den IDs (Default: Dateiname)") + args = p.parse_args() + if not os.path.isfile(args.dxf): + print("%s FEHLER: DXF nicht gefunden: %s" % (PREFIX, args.dxf)) + sys.exit(1) + projekt = args.projekt or os.path.splitext(os.path.basename(args.dxf))[0] + + print("%s lese %s ..." % (PREFIX, args.dxf)) + inserts, block_inhalt = lese_zeichnung(args.dxf) + eintraege, hinweise = baue_eintraege(inserts, block_inhalt, projekt) + + zaehler = collections.Counter( + "Kreisel" if "abstand" in e else + "GF" if "modus" in e else + "VF Linienzug" if e.get("typ") == "linienzug_journal" else + "VF %s" % e["typ"] if "typ" in e and "test_id" in e else + e.get("block", "?") for e in eintraege) + for k, v in sorted(zaehler.items()): + print("%s %-22s %d" % (PREFIX, k, v)) + for h in hinweise: + print("%s ! %s" % (PREFIX, h)) + + with open(args.output, "w", encoding="utf-8") as fh: + fh.write(arrays_einzeilig(json.dumps(eintraege, ensure_ascii=False, + indent=2))) + fh.write("\n") + print("%s %d Eintraege geschrieben -> %s" + % (PREFIX, len(eintraege), args.output)) + + +if __name__ == "__main__": + main() diff --git a/lib/dxf_scan_components.py b/lib/dxf_scan_components.py index 043bd20..5b179de 100644 --- a/lib/dxf_scan_components.py +++ b/lib/dxf_scan_components.py @@ -11,6 +11,11 @@ also so, dass die Anlage per JSON-Treiber mit den Produktionsmakros nachgebaut werden kann (Vorbild: tests/testdata/mubea.json, das bisher von Hand aus einem DXF abgeleitet wurde). +Gefaellestrecken, die nicht als Blockpaar, sondern als 3D-LINE auf einem +Staustrecken-Layer gezeichnet sind (GF_LINIE_LAYER), werden in einem zweiten +Lesedurchgang erkannt und als Modus-1-Eintraege (Schema 2.1) ausgegeben, +siehe gf_eintraege_aus_linien. + Aufruf: python dxf_scan_components.py [--fenster X0 Y0 X1 Y1] @@ -128,6 +133,43 @@ ACHSE_MAX_QUER = 1500.0 # der Antriebsstationen, ohne benachbarte Bauteile zu verwechseln. ZWILLING_MAX_ABSTAND = 1500.0 +# --- Gefaellestrecken aus Staustrecken-Linien ------------------------------- +# Manche Zeichnungen (Dematic_arvato_reduced.dxf) fuehren die Gefaellestrecke +# nicht als Blockpaar, sondern als einfache 3D-LINE auf einem Staustrecken- +# Layer vom hohen zum tiefen Kreisel (dort: 27 Linien auf "6-SP", 10654 mm +# lang, 370 mm Gefaelle). Nur Modelspace-LINEs; Muster wie FAMILIEN. +GF_LINIE_LAYER = ["6-SP"] + +# Mindest-Hoehendifferenz (mm), ab der eine Staustrecken-Linie als Gefaelle +# gilt. Darunter ist sie eine waagrechte Strecke - die liegen auf denselben +# Layern (Rueckfuehrungen, Kreisel-Verbindungen) und sind keine GF. +GF_LINIE_MIN_DZ = 100.0 + +# Suchbereich fuer das Ausschleuselement am oberen Linienende, gemessen im +# Linien-KS: "entlang" ab Linienstart in Gefaellerichtung, "quer" seitlich. +# In Dematic_arvato_reduced.dxf sitzt es 1158 mm entlang und 467 mm quer - +# der Nachbar-AS der Linie daneben (800 mm Raster) liegt nur 433 mm quer auf +# der ANDEREN Seite. Darum entscheidet die Seite aus dem Blocknamen (links/ +# rechts), nicht der kleinste Abstand. +GF_AS_MAX_ENTLANG = 2000.0 +GF_AS_MAX_QUER = 700.0 + +# Groesste Luecke (mm) zwischen Linienende und Kreisel-Kette, bis zu der die +# Linie an diesen Kreisel angeschlossen wird. Gezeichnet ist nur die +# Staustrecke: oben fehlt das Ausschleuselement (~430 mm), unten das +# Einschleuselement (~480 mm) bis zur Kette. +GF_KREISEL_MAX_LUECKE = 1500.0 + +# Separatoren auf der GF-Achse: die Gefaellestrecke baut ihren eigenen +# (Staustrecke_Separator_SP_300_mm), der gezeichnete waere doppelt. Gilt fuer +# Vorkommen bis GF_SEP_MAX_QUER (mm) neben der Achse. +GF_SEP_MUSTER = ["S-SP", "S-LP", "Separator*"] +GF_SEP_MAX_QUER = 300.0 + +# Abstand (mm), bis zu dem eine --kreisel-hoehe X Y Z dem Kreisel mit diesem +# Einfuegepunkt (Eintrag x/y) zugeordnet wird. +KREISEL_HOEHE_TOL = 50.0 + # --------------------------------------------------------------------------- # Hilfsfunktionen @@ -593,6 +635,62 @@ def lese_inserts(dxf_path): return ms_inserts, block_inserts, block_base, statistik, block_info +def lese_linien(dxf_path, layer_muster): + """Liest alle Modelspace-LINEs auf den Layern aus layer_muster. + + Eigener Durchlauf statt Erweiterung von lese_inserts: dessen Rueckgabe + nutzt auch lib/dxf_abbild.py, und die Linien braucht nur die + Gefaellestrecken-Erkennung. Kostet einen zweiten Lesedurchgang. + + Rueckgabe: Liste {"layer", "a": [x, y, z], "b": [x, y, z]} in WCS + (eine LINE ist immer in WCS angegeben, keine OCS-Umrechnung noetig). + """ + linien = [] + section = None + warte_auf_sectionname = False + rec = None + + def ablegen(r): + if r and r["ps"] != 1 and matches_any(r["layer"] or "", layer_muster): + linien.append({"layer": r["layer"], "a": r["a"], "b": r["b"]}) + + fh = io.open(dxf_path, "rb") + try: + mm = mmap.mmap(fh.fileno(), 0, access=mmap.ACCESS_READ) + except ValueError: + fh.close() + raise + try: + for code, value in iter_tags(mm): + if code == 0: + ablegen(rec) + rec = None + if value == "SECTION": + warte_auf_sectionname = True + elif value == "ENDSEC": + section = None + elif value == "LINE" and section == "ENTITIES": + rec = {"layer": None, "a": [0.0, 0.0, 0.0], + "b": [0.0, 0.0, 0.0], "ps": 0} + elif code == 2 and warte_auf_sectionname: + section = value + warte_auf_sectionname = False + elif rec is not None: + if code == 8: + rec["layer"] = value + elif code in (10, 20, 30): + rec["a"][{10: 0, 20: 1, 30: 2}[code]] = value + elif code in (11, 21, 31): + rec["b"][{11: 0, 21: 1, 31: 2}[code]] = value + elif code == 67: + rec["ps"] = value + ablegen(rec) + finally: + mm.close() + fh.close() + return linien + + def insert_matrix(rec, block_base): """Transformationsmatrix eines INSERT (inkl. Basispunkt des Zielblocks). @@ -1213,15 +1311,242 @@ def sensor_eintrag(t, bekannte_bloecke=None, hinweise=None, treffer=None): } +def as_am_ende(p, richtung, as_liste, belegt): + """Ausschleuselement an einem Linienende suchen. + + p = Linienende (x, y), richtung = Einheitsvektor (x, y) von dort in die + Linie hinein. Gesucht wird im Linien-KS (siehe GF_AS_MAX_ENTLANG/-QUER); + "quer" ist positiv LINKS der Richtung. Ein AS mit Seite im Blocknamen muss + auf dieser Seite liegen - das trennt ihn vom Nachbar-AS der Linie daneben. + Bereits vergebene AS (belegt = Menge von id()) zaehlen nicht. + + Rueckgabe: (treffer, zielblock, geraten) oder None. + """ + beste = None + for t in as_liste: + if id(t) in belegt: + continue + vx, vy = t["x"] - p[0], t["y"] - p[1] + entlang = vx * richtung[0] + vy * richtung[1] + quer = richtung[0] * vy - richtung[1] * vx + if not (0.0 <= entlang <= GF_AS_MAX_ENTLANG and abs(quer) <= GF_AS_MAX_QUER): + continue + block, geraten = mappe_block(t["block"]) + if "Seite=%s" % DEFAULT_SEITE not in (geraten or []): + if block.endswith("_links") and quer < 0: + continue + if block.endswith("_rechts") and quer > 0: + continue + if beste is None or abs(quer) < beste[0]: + beste = (abs(quer), t, block, geraten or []) + return beste[1:] if beste else None + + +def kreisel_anschluss(p, richtung, kreisel): + """Schnittpunkt einer GF-Achse mit der naechsten Kreisel-Kette. + + p = Linienende (x, y), richtung = Einheitsvektor (x, y) der GF-Achse. + Je Kreisel (siehe kreisel_geo in baue_eintraege: Achse von der AN8- zur + SP8-Radmitte, Kette im Abstand r beidseits) wird die Kette auf der Seite + von p genommen und die Achse bis dorthin verlaengert bzw. gekuerzt. Nur + Kreisel, an deren Laenge p liegt und deren Kette hoechstens + GF_KREISEL_MAX_LUECKE entfernt ist; bei mehreren gewinnt die kleinste + Verschiebung. + + Rueckgabe: (kreisel, punkt (x, y), verschiebung entlang richtung) oder None. + """ + beste = None + for k in kreisel: + ux, uy = k["u"] + nx, ny = -uy, ux + vx, vy = p[0] - k["a"][0], p[1] - k["a"][1] + t = vx * ux + vy * uy + q = vx * nx + vy * ny + if not (-k["r"] <= t <= k["laenge"] + k["r"]): + continue + if abs(abs(q) - k["r"]) > GF_KREISEL_MAX_LUECKE: + continue + dn = richtung[0] * nx + richtung[1] * ny + if abs(dn) < 1e-6: # GF parallel zum Kreisel + continue + kette = k["r"] if q >= 0 else -k["r"] + lam = (kette - q) / dn + if beste is None or abs(lam) < abs(beste[2]): + beste = (k, (p[0] + lam * richtung[0], p[1] + lam * richtung[1]), lam) + return beste + + +def gf_eintraege_aus_linien(linien, as_liste, kreisel=None, sep_liste=None, + winkel_default=3.0): + """Gefaellestrecken (Modus 1, Schema 2.1) aus Staustrecken-Linien. + + Eine Gefaellestrecke laeuft immer bergab: Start ist das HOEHERE + Linienende, unabhaengig von der Zeichenrichtung. Das Ausschleuselement + gehoert an dieses obere Ende. Sitzt es dagegen am UNTEREN Ende, faehrt + die Strecke vom tiefen Kreisel hinauf - das ist ein Steigfoerderer und + keine GF (Dematic_arvato_reduced.dxf: 3 solche Linien); sie wird + gemeldet und uebersprungen. + + Anschluss an die Kreisel: gezeichnet ist nur die Staustrecke. Das Makro + legt den Ursprung des AS-Elements auf start_mm und dessen Einlauf + (KS_EIN) seitlich daneben, auf gleicher Hoehe der Achse; ebenso liegt der + Auslauf des ES-Elements neben dessen Ursprung, und deltaL_mm reicht von + AS- bis ES-Ursprung (gemessen an GF_Mubea: 9510 -> 399.2 = 9110.8). Damit + beide die Kreisel-Kette treffen, werden Start und Ende auf die jeweils + naechste Kette geschoben (kreisel_anschluss). Ohne Kreisel in Reichweite + bleibt das Linienende stehen und es gibt einen Hinweis. + + Hoehen: tragen beide Kreisel eine Anwender-Hoehe ("z_anwender"), wird + start_mm.z die des oberen und hoehe_ende_mm die des unteren Kreisels - + den Winkel rechnet dann der LISP-Treiber mit gf-winkel-berechnen + (dieselbe Naeherung wie Modus 3, mit den Elementmassen der aktuellen + 2D/3D-Bibliothek). Sonst ist winkel_default ein Platzhalter. + + Rueckgabe: (eintraege, verbrauchte ids, hinweise). Verbraucht werden das + AS am oberen Ende und Separatoren auf der Achse (sep_liste) - beides baut + die Gefaellestrecke selbst mit, als Einzel-Insert stuenden sie doppelt in + der Zeichnung (und im Sivas-Export). Der AS eines uebersprungenen + Steigfoerderers bleibt unverbraucht. + """ + eintraege, hinweise = [], [] + belegt = set() + waagrecht = 0 + kandidaten = [] + for ln in linien: + a, b = ln["a"], ln["b"] + if abs(a[2] - b[2]) < GF_LINIE_MIN_DZ: + waagrecht += 1 + continue + hoch, tief = (a, b) if a[2] > b[2] else (b, a) + lxy = math.hypot(tief[0] - hoch[0], tief[1] - hoch[1]) + if lxy <= 0.0: + continue + kandidaten.append((hoch, tief, lxy, ln["layer"])) + kandidaten.sort(key=lambda k: (round(k[0][0], RUND), round(k[0][1], RUND))) + + for hoch, tief, lxy, layer in kandidaten: + r = ((tief[0] - hoch[0]) / lxy, (tief[1] - hoch[1]) / lxy) + oben = as_am_ende(hoch, r, as_liste, belegt) + if oben is None: + unten = as_am_ende(tief, (-r[0], -r[1]), as_liste, belegt) + if unten is not None: + # AS NICHT verbrauchen: er gehoert zum Steigfoerderer und + # bleibt als Einzel-Insert in der Ausgabe stehen. + hinweise.append( + "Staustrecken-Linie (%.0f, %.0f, %.0f) -> (%.0f, %.0f, " + "%.0f): Ausschleuselement am UNTEREN Ende - Steigfoerderer, " + "keine Gefaellestrecke, uebersprungen" + % (tief[0], tief[1], tief[2], hoch[0], hoch[1], hoch[2])) + continue + tid = "GF_%s_%02d" % (PROJEKT, len(eintraege) + 1) + kommentar = ("aus DXF: LINE auf Layer '%s' (%.2f, %.2f) -> (%.2f, " + "%.2f), Laenge XY %.2f" + % (layer, hoch[0], hoch[1], tief[0], tief[1], lxy)) + + # Start/Ende auf die Kreisel-Ketten schieben + start, ende = (hoch[0], hoch[1]), (tief[0], tief[1]) + k_start = k_ende = None + for wo, p, rr in (("oberen", hoch, r), ("unteren", tief, (-r[0], -r[1]))): + ans = kreisel_anschluss(p, rr, kreisel or []) + if ans is None: + hinweise.append("%s: kein Kreisel am %s Ende - Linienende " + "bleibt stehen" % (tid, wo)) + kommentar += "; am %s Ende kein Kreisel in Reichweite" % wo + continue + k, punkt, lam = ans + kommentar += ("; am %s Ende um %.1f mm bis zur Kette von %s " + "verlaengert" % (wo, -lam, k["id"])) + if wo == "oberen": + start, k_start = punkt, k + else: + ende, k_ende = punkt, k + laenge = (ende[0] - start[0]) * r[0] + (ende[1] - start[1]) * r[1] + + eintrag = { + "test_id": tid, + "modus": 1, + "deltaL_mm": round(laenge, RUND), + "hz_grad": round(math.degrees(math.atan2(r[1], r[0])) % 360.0, RUND) + 0.0, + "start_mm": [round(start[0], RUND) + 0.0, round(start[1], RUND) + 0.0, 0.0], + "as_seite": DEFAULT_SEITE, + "es_seite": "links", + "as_winkel": str(DEFAULT_SCHLEUS_WINKEL), + "es_winkel": str(DEFAULT_SCHLEUS_WINKEL), + } + if k_start: + eintrag["kreisel_start"] = k_start["id"] + if k_ende: + eintrag["kreisel_ende"] = k_ende["id"] + if (k_start and k_ende and k_start.get("z_anwender") is not None + and k_ende.get("z_anwender") is not None): + eintrag["start_mm"][2] = float(k_start["z_anwender"]) + eintrag["hoehe_ende_mm"] = float(k_ende["z_anwender"]) + eintrag["hoehe_quelle"] = "Anwender" + kommentar += ("; Hoehen vom Anwender (Kreisel %s / %s), den Winkel " + "rechnet der Treiber" % (k_start["id"], k_ende["id"])) + else: + eintrag["winkel_grad"] = winkel_default + eintrag["hoehe_unbekannt"] = True + kommentar += ("; Hoehen unbekannt - winkel_grad %.1f ist Platzhalter" + % winkel_default) + + if oben is not None: + t, block, geraten = oben + belegt.add(id(t)) + teile = block.split("_") # AS_Element__ + eintrag["as_winkel"], eintrag["as_seite"] = teile[2], teile[3] + kommentar += ("; AS aus Block '%s' bei (%.2f, %.2f) -> %s, als " + "Einzel-Insert entfernt (baut die GF selbst)" + % (t["block"], t["x"], t["y"], block)) + if geraten: + kommentar += " - geraten: %s" % ", ".join(geraten) + else: + kommentar += ("; KEIN Ausschleuselement am oberen Ende gefunden - " + "as_seite/as_winkel sind Defaults") + hinweise.append("%s ohne Ausschleuselement am oberen Ende" % tid) + + # Separatoren auf der Achse zwischen Start und Ende + weg = [] + for s in sep_liste or []: + if id(s) in belegt or not matches_any(s["block"], GF_SEP_MUSTER): + continue + vx, vy = s["x"] - start[0], s["y"] - start[1] + entlang = vx * r[0] + vy * r[1] + quer = r[0] * vy - r[1] * vx + if 0.0 <= entlang <= laenge and abs(quer) <= GF_SEP_MAX_QUER: + belegt.add(id(s)) + weg.append("%s bei (%.0f, %.0f)" % (s["block"], s["x"], s["y"])) + if weg: + kommentar += ("; Separator auf der Achse entfernt (die GF baut " + "ihren eigenen): %s" % ", ".join(weg)) + + kommentar += "; es_seite/es_winkel sind Defaults (kein ES im DXF)." + eintrag["comment"] = kommentar + eintraege.append(eintrag) + + if waagrecht: + hinweise.append("%d waagrechte Staustrecken-Linie(n) auf %s - keine " + "Gefaellestrecke, nicht ausgegeben" + % (waagrecht, "/".join(GF_LINIE_LAYER))) + return eintraege, belegt, hinweise + + def baue_eintraege(treffer, defaults, boegen, weichen, - bekannte_bloecke=None): - """Erkannte Vorkommen auf die Schemata aus object_data.md abbilden.""" + bekannte_bloecke=None, linien=None, kreisel_hoehen=None): + """Erkannte Vorkommen auf die Schemata aus object_data.md abbilden. + + kreisel_hoehen: Liste (x, y, z) vom Anwender - z gilt fuer den Kreisel, + dessen Einfuegepunkt (Eintrag x/y) hoechstens KREISEL_HOEHE_TOL entfernt + liegt, und fuer die Gefaellestrecken, die an ihm anschliessen. + """ nach_familie = {} for t in treffer: nach_familie.setdefault(t["familie"], []).append(t) eintraege = [] hinweise = [] + kreisel_geo = [] # Achse/Kette je Kreisel fuer kreisel_anschluss + offene_hoehen = list(kreisel_hoehen or []) # --- Kreisel: AN8 (Antriebsstation) + SP8 (Spannstation) -------------- durchmesser = defaults.get("kreisel", {}).get("durchmesser", 800.0) @@ -1275,10 +1600,47 @@ def baue_eintraege(treffer, defaults, boegen, weichen, sp["block"], sp["layer"], sp["x"], sp["y"], dist, rotation)) + hoehe_hinweis, }) + kreisel = eintraege[-1] + for h in offene_hoehen: + if math.hypot(h[0] - kreisel["x"], h[1] - kreisel["y"]) <= KREISEL_HOEHE_TOL: + kreisel["z"] = float(h[2]) + kreisel["hoehe_quelle"] = "Anwender" + kreisel["comment"] += " Hoehe %.1f vom Anwender." % h[2] + offene_hoehen.remove(h) + break + kreisel_geo.append({ + "id": kreisel["id"], + "a": (an["x"], an["y"]), + "u": (math.cos(richtung), math.sin(richtung)), + "laenge": dist, + "r": radius, + "z_anwender": kreisel["z"] if kreisel.get("hoehe_quelle") else None, + }) + for h in offene_hoehen: + hinweise.append("Kreisel-Hoehe %.1f bei (%.2f, %.2f): kein Kreisel-" + "Einfuegepunkt in %g mm - nicht verwendet" + % (h[2], h[0], h[1], KREISEL_HOEHE_TOL)) for sp in sp_liste: hinweise.append("SP8 bei (%.2f, %.2f) ohne AN8-Partner" % (sp["x"], sp["y"])) eintraege.append(sensor_eintrag(sp, bekannte_bloecke, hinweise, treffer)) + # --- Gefaellestrecken aus Staustrecken-Linien --------------------------- + # Nach den Kreiseln (Anschluss an deren Ketten) und vor dem Rest-Block: + # sie entnehmen ihre Ausschleuselemente und Separatoren aus den Familien + # (siehe gf_eintraege_aus_linien), der Rest-Block darf diese nicht mehr + # als Einzel-Insert ausgeben. + if linien: + as_liste = [t for t in nach_familie.get("schleuselement", []) + if mappe_block(t["block"])[0].startswith("AS_Element")] + gf, belegt, gf_hinweise = gf_eintraege_aus_linien( + linien, as_liste, kreisel_geo, nach_familie.get("sensor", []), + defaults.get("gefaelle", {}).get("default_winkel", 3.0)) + eintraege.extend(gf) + hinweise.extend(gf_hinweise) + for familie in ("schleuselement", "sensor"): + nach_familie[familie] = [t for t in nach_familie.get(familie, []) + if id(t) not in belegt] + # --- Foerderer: Antriebs- und Umlenkstation paaren --------------------- gf_winkel_min = defaults.get("gefaelle", {}).get("default_winkel", 3.0) paare, rest_a, rest_u = paare_bilden(nach_familie.get("foerderer_antrieb", []), @@ -1400,6 +1762,37 @@ def filtere_fenster(eintraege, fenster): return behalten, len(eintraege) - len(behalten), ohne_punkte +def hoehen_entfernen(eintraege): + """Alle Hoehen auf 0 setzen, ausser den vom Anwender vorgegebenen. + + Fuer Zeichnungen, deren Z-Werte (noch) nicht belastbar sind: lieber + gar keine Hoehe als eine, die nach Einbauhoehe aussieht und keine ist. + Ausgenommen sind Eintraege mit hoehe_quelle "Anwender" (--kreisel-hoehe + und die daran anschliessenden Gefaellestrecken). + Rueckgabe: Anzahl der geaenderten Eintraege. + """ + n = 0 + for e in eintraege: + if e.get("hoehe_quelle") == "Anwender": + continue + geaendert = False + for feld in ("z", "hoehe"): + if feld in e and e[feld] != 0.0: + e[feld] = 0.0 + geaendert = True + for feld in ("startpunkt", "start_mm", "endpunkt"): + p = e.get(feld) + if isinstance(p, list) and len(p) >= 3 and p[2] != 0.0: + p[2] = 0.0 + geaendert = True + if any(f in e for f in ("z", "hoehe", "startpunkt", "start_mm")): + e["hoehe_unbekannt"] = True + if geaendert: + e["comment"] = e.get("comment", "") + " [Hoehe entfernt: --ohne-hoehen]" + n += 1 + return n + + def arrays_einzeilig(text): """Zahlen-Arrays im JSON-Text auf eine Zeile ziehen. @@ -1471,6 +1864,15 @@ def main(): help="Nur Bauteile in diesem XY-Fenster (mm) " "ausgeben - fuer den Nachbau eines einzelnen " "Anlagenabschnitts statt der ganzen Zeichnung") + parser.add_argument("--ohne-hoehen", action="store_true", + help="Alle Hoehen auf 0 setzen (Z der Zeichnung nicht " + "belastbar); ausgenommen --kreisel-hoehe") + parser.add_argument("--kreisel-hoehe", nargs=3, type=float, action="append", + metavar=("X", "Y", "Z"), + help="Hoehe Z fuer den Kreisel mit Einfuegepunkt X/Y " + "(wie im Ausgabe-JSON); gilt auch fuer Start/Ende " + "der daran anschliessenden Gefaellestrecken. " + "Mehrfach angebbar") parser.add_argument("--projekt", help="Projektkennung in den erzeugten IDs " "(Default: Name der DXF-Datei ohne Endung)") @@ -1529,8 +1931,16 @@ def main(): dim_stat["attribute_uebernommen"], dim_stat["nur_2d"], dim_stat["nur_3d"], len(treffer))) + linien = lese_linien(dxf_path, GF_LINIE_LAYER) + print("%s %d Staustrecken-Linien auf %s" % (PREFIX, len(linien), + "/".join(GF_LINIE_LAYER))) + eintraege, hinweise = baue_eintraege(treffer, defaults, boegen, weichen, - bekannte_bloecke) + bekannte_bloecke, linien, + args.kreisel_hoehe) + if args.ohne_hoehen: + print("%s --ohne-hoehen: Hoehe in %d Eintraegen auf 0 gesetzt" + % (PREFIX, hoehen_entfernen(eintraege))) if fenster: vorher = len(eintraege) diff --git a/tests/test_dematic_arvato.lsp b/tests/test_dematic_arvato.lsp index 7823b7a..6fcb57c 100644 --- a/tests/test_dematic_arvato.lsp +++ b/tests/test_dematic_arvato.lsp @@ -1,30 +1,53 @@ ;; ============================================================ ;; test_dematic_arvato.lsp - Nachbau des Abschnitts Flowpuffer/Kreisel der -;; Anlage Dematic/Arvato aus der Scanner-Vorlage. +;; Anlage Dematic/Arvato. ;; -;; 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 +;; Datenquelle: tests/testdata/dematic_arvato.json. Entstehung in zwei +;; Stufen: +;; 1. Vorlage aus der Fremdzeichnung (Scanner, raet vieles): +;; python lib/dxf_scan_components.py \ +;; C:/develop/sps_skel/data/Dematic_arvato_reduced.dxf data \ +;; tests/testdata/dematic_arvato.json --projekt Arvato \ +;; --fenster -2534 -4549 49466 29451 --ohne-hoehen \ +;; --kreisel-hoehe 35860.37 12519.72 2437 \ +;; --kreisel-hoehe 36661.24 24878.8 1826 +;; 2. Vorlage mit diesem Treiber bauen, in BricsCAD von Hand korrigieren +;; und ergaenzen (VF-Ketten, Hoehen, Sensoren aufgeraeumt), als DXF +;; speichern und daraus die Testdaten neu schreiben - AKTUELLER STAND: +;; python lib/dxf_anlage_export.py \ +;; C:/develop/sps_skel/data/Dematic_TST.dxf \ +;; tests/testdata/dematic_arvato.json --projekt Arvato ;; -;; 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): +;; Eintragsarten: ;; "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 +;; kreisel-insert-script; x/y = Einfuegepunkt, +;; abstand = Mittenabstand AN8-SP8) +;; "function": "insert" + "block" -> Einzelblock (hundm05:bau-sensor) +;; "typ": "standard"/"etage" + "test_id" +;; -> VarioFoerderer ueber mubea:vario-bauen +;; (mubea-Schema: deltaL, deltaH, richtung, +;; winkel, L_GF1, seite, hz, x/y/z), optional +;; "motorseite" +;; "typ": "linienzug_journal" +;; -> Linienzug-Kette: das aufgezeichnete Eingabe- +;; Journal (SSG_VF_EDIT) wird 1:1 abgespielt +;; (vsp-bau-journal) - keine Spec, weil der +;; Dialog neuer ist als die Spec-Grammatik +;; "modus": 1 -> Gefaellestrecke ueber mubea:gf-bauen +;; (start_mm + deltaL_mm, kein Endpunkt). Mit +;; hoehe_ende_mm (Hoehe des Kreisels am Ende) +;; rechnet dematic_arvato:gf-winkel den Winkel, +;; sonst gilt winkel_grad. +;; "typ": "gerade" -> waagrechter Foerderer aus der Scanner-Vorlage - +;; kein Bau-Pfad, wird gemeldet und uebersprungen +;; +;; Reihenfolge wie mubea.json (VF vor GF): gf-init-bibliothek setzt die +;; globalen AS/ES-Masse um, siehe mubea:ensure-gf-init. ;; ;; Keine eigene Bau-Logik: hundm05:bau-kreisel/-sensor aus -;; tests/test_hundm05.lsp wird mitgeladen (die Datei definiert nur Funktionen). +;; tests/test_hundm05.lsp und mubea:gf-bauen/-vario-bauen aus +;; tests/test_mubea.lsp werden mitgeladen (beide Dateien definieren nur +;; Funktionen), Linienzug-Ketten laufen ueber vsp-bau-journal (vf_spec.lsp). ;; ;; Aufruf in BricsCAD: ;; (load (strcat (getenv "DXFMAKRO") "/tests/test_dematic_arvato.lsp")) @@ -40,12 +63,30 @@ (ssg-ensure "KreiselInsert") (ssg-ensure "VarioFoerderer") (ssg-ensure "SSG_LIB_Commands") +(ssg-ensure "Gefaellestrecke") (if (null (car (atoms-family 1 '("HUNDM05:BAU-SENSOR")))) (load (strcat (getenv "DXFMAKRO") "/tests/test_hundm05.lsp"))) +(if (null (car (atoms-family 1 '("MUBEA:VARIO-BAUEN")))) + (load (strcat (getenv "DXFMAKRO") "/tests/test_mubea.lsp"))) (defun dematic_arvato:datei () (strcat (getenv "DXFMAKRO") "/tests/testdata/dematic_arvato.json")) +;; Record um den gebauten Block ergaenzen (oder als Abbruch markieren). +(defun dematic_arvato:rec-block (rec ent fehlertext / ed) + (if (and ent (= (type ent) 'ENAME)) + (progn + (setq ed (entget ent)) + (princ (strcat " -> Block " (cdr (assoc 2 ed)))) + (setq rec (vsp-set rec "block_name" (cdr (assoc 2 ed)))) + (setq rec (vsp-set rec "block_handle" (cdr (assoc 5 ed)))) + (setq rec (vsp-set rec "insert_point" (cdr (assoc 10 ed)))) + (setq rec (vsp-set rec "attribs" (ssg-attrib-read ent))) + (vsp-set rec "status" "executed")) + (progn + (princ (strcat " FEHLER: " fehlertext)) + (vsp-set (vsp-set rec "status" "abbruch") "fehler_text" fehlertext)))) + ;; Foerderer "gerade": noch kein Bau-Pfad - nur melden. (defun dematic_arvato:gerade-melden (obj / tid rec) (setq tid (ssg-val obj "test_id")) @@ -56,15 +97,146 @@ (vsp-set (vsp-set rec "status" "uebersprungen") "fehler_text" "kein Bau-Pfad fuer typ gerade")) -(defun dematic_arvato:bau-eintrag (obj / kind res) +;; Gefaellewinkel aus Start- und Endhoehe - derselbe Loeser wie Modus 3 +;; (gf-winkel-berechnen, Gefaellestrecke.lsp) mit den AS/ES-Massen der +;; aktuellen 2D/3D-Bibliothek. Die Kette ist eine einzige Gerade plus der +;; eine Separator vor dem ES (extra-sep 1); ihre Laenge ohne AS/ES/Separator +;; ist deltaL - aus-dx - ein-dx - 300, damit ergibt der Loeser als +;; Gesamtlaenge wieder genau deltaL (deltaL reicht von AS- bis ES-Ursprung). +;; VORZEICHEN: vf-set-as-masse (vf_core) misst dz als KS_AUS.z - KS_EIN.z +;; (bei AS/ES negativ), gf-winkel-berechnen erwartet die Konvention von +;; gf-init-bibliothek (KS_EIN.z - KS_AUS.z, positiv) und zieht den Wert ab. +;; Mit der VF-Konvention wurde der feste AS/ES-Abfall addiert statt +;; abgezogen - real gebaut: 3.79 statt ~2.49 Grad, GF endete 258 mm unter +;; dem Kreisel (HOEHE_BIS 1568 statt 1826). Darum hier der Betrag. +(defun dematic_arvato:gf-winkel (deltaL hz as-seite es-seite as-winkel es-winkel + z-start z-ende / winkel) + (mubea:ensure-gf-init) + (vf-set-as-masse as-winkel as-seite) + (vf-set-es-masse es-winkel es-seite) + (setq aus-dz (abs (float aus-dz)) ein-dz (abs (float ein-dz))) + (setq winkel + (gf-winkel-berechnen + (list (list "Linie" hz (- deltaL (float aus-dx) (float ein-dx) 300.0) 0 "links")) + (- z-start z-ende) 1)) + (vf-set-as-masse "90" as-seite) + (vf-set-es-masse "90" es-seite) + winkel) + +;; Gefaellestrecke (Modus 1) bauen - Felder wie mubea:build-gf, ohne dessen +;; anzahl/delta-Vervielfaeltigung (jede GF steht einzeln in der Datei). +;; Mit "hoehe_ende_mm" (Hoehe des Kreisels am Ende) wird der Winkel daraus +;; gerechnet, sonst gilt "winkel_grad" (Default 3.0). +(defun dematic_arvato:bau-gf (obj / tid start deltaL hz winkel z-ende + as-seite es-seite as-winkel es-winkel rec) + (setq tid (ssg-val obj "test_id") + start (ssg-val obj "start_mm") + deltaL (ssg-val obj "deltaL_mm") + hz (ssg-val obj "hz_grad") + winkel (ssg-val obj "winkel_grad") + z-ende (ssg-val obj "hoehe_ende_mm") + as-seite (cond ((ssg-val obj "as_seite")) ("links")) + es-seite (cond ((ssg-val obj "es_seite")) ("links")) + as-winkel (cond ((ssg-val obj "as_winkel")) ("90")) + es-winkel (cond ((ssg-val obj "es_winkel")) ("90"))) + (setq rec (vsp-rec-neu (if tid tid "(ohne id)"))) + (setq rec (vsp-set rec "kind" "gefaellestrecke")) + (setq rec (vsp-set rec "dimension" (vsp-dim-text))) (cond + ((not (and (= (type start) 'LIST) (= (length start) 3) + (numberp deltaL) (numberp hz))) + (princ (strcat "\n [GF] " (if tid tid "?") + " - FEHLER: start_mm, deltaL_mm und hz_grad muessen gesetzt sein")) + (vsp-set (vsp-set rec "status" "spec-fehler") "fehler_text" + "start_mm, deltaL_mm oder hz_grad fehlt bzw. ist ungueltig")) + ((and (numberp z-ende) (>= z-ende (caddr start))) + (princ (strcat "\n [GF] " (if tid tid "?") + " - FEHLER: hoehe_ende_mm liegt nicht unter der Starthoehe")) + (vsp-set (vsp-set rec "status" "spec-fehler") "fehler_text" + "hoehe_ende_mm >= start_mm.z - kein Gefaelle")) + (T + (setq winkel + (cond + ((numberp z-ende) + (dematic_arvato:gf-winkel (float deltaL) (float hz) as-seite es-seite + as-winkel es-winkel + (float (caddr start)) (float z-ende))) + ((numberp winkel) (float winkel)) + (T 3.0))) + ;; Winkel und Soll-Endhoehe als Meldung (das Record-Schema aus vf_spec + ;; kennt dafuer kein Feld); die Ist-Endhoehe steht in attribs HOEHE_BIS. + (setq rec (vsp-set rec "meldungen" + (list (strcat "winkel_grad " (rtos winkel 2 3) + (if (numberp z-ende) + (strcat " aus Hoehe " (rtos (caddr start) 2 1) + " -> " (rtos z-ende 2 1)) + ""))))) + (dematic_arvato:rec-block rec + (mubea:gf-bauen tid (mapcar 'float start) (float deltaL) (float hz) + as-seite es-seite as-winkel es-winkel winkel) + "gefaellestrecke-einfuegen lieferte keinen GF-Block")))) + +;; VarioFoerderer "standard"/"etage" - mubea-Schema, Bau ueber +;; mubea:vario-bauen. "motorseite" wirkt wie im Edit-Dialog ueber den +;; Override *vf-motorseite* (vf-block-erstellen liest ihn). +(defun dematic_arvato:bau-vf (obj / tid typ rec ent) + (setq tid (ssg-val obj "test_id") + typ (cond ((ssg-val obj "typ")) ("standard"))) + (setq rec (vsp-rec-neu (if tid tid "(ohne id)"))) + (setq rec (vsp-set rec "kind" "vario")) + (setq rec (vsp-set rec "dimension" (vsp-dim-text))) + (setq *vf-motorseite* (ssg-val obj "motorseite")) + (setq ent + (vl-catch-all-apply 'mubea:vario-bauen + (list tid typ (ssg-val obj "richtung") + (float (ssg-val obj "deltaL")) (float (ssg-val obj "deltaH")) + (ssg-val obj "winkel") (float (cond ((ssg-val obj "L_GF1")) (0.0))) + (ssg-val obj "seite") (ssg-val obj "hz") + (list (float (ssg-val obj "x")) (float (ssg-val obj "y")) + (float (ssg-val obj "z")))))) + (setq *vf-motorseite* nil) + (if (vl-catch-all-error-p ent) + (vsp-set (vsp-set rec "status" "abbruch") "fehler_text" + (vl-catch-all-error-message ent)) + (dematic_arvato:rec-block rec ent + "kein VF-Block (deltaL beim gewuenschten Winkel nicht loesbar?)"))) + +;; Linienzug-Kette: aufgezeichnetes Journal ("ART:wert"-Tokens, wie in der +;; SSG_VF_EDIT-XDATA) 1:1 abspielen. Headless-Rahmen wie vsp-bau-datei; er +;; MUSS auch nach einem Fehler zurueck, sonst bleiben getstring/getpoint der +;; Sitzung ersetzt. +(defun dematic_arvato:bau-journal (obj / tid journal res) + (setq tid (cond ((ssg-val obj "test_id")) ("(ohne id)"))) + (setq journal (mapcar 'vfl-string->entry (ssg-val obj "journal"))) + (vsp-headless-an) + (setq res (vl-catch-all-apply 'vsp-bau-journal + (list tid journal nil + (if journal nil (list "Feld \"journal\" fehlt oder ist leer"))))) + (vsp-headless-aus) + (if (vl-catch-all-error-p res) + (vsp-set (vsp-set (vsp-rec-neu tid) "status" "abbruch") "fehler_text" + (vl-catch-all-error-message res)) + res)) + +(defun dematic_arvato:bau-eintrag (obj / kind res typ) + (setq typ (ssg-val obj "typ")) + (cond + ((ssg-val obj "modus") + (setq kind "gefaellestrecke") + (setq res (vl-catch-all-apply 'dematic_arvato:bau-gf (list obj)))) + ((= typ "linienzug_journal") + (setq kind "linienzug") + (setq res (dematic_arvato:bau-journal obj))) + ((and (member typ '("standard" "etage")) (ssg-val obj "test_id")) + (setq kind "vario") + (setq res (dematic_arvato:bau-vf obj))) ((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") + ((= typ "gerade") (setq kind "gerade") (setq res (dematic_arvato:gerade-melden obj))) (T @@ -76,6 +248,7 @@ (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 "test_id")) ((ssg-val obj "block")) ("?"))) "kind" kind) "status" "abbruch") @@ -85,11 +258,11 @@ (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 "\n TEST_DEMATIC_ARVATO - Abschnitt Flowpuffer/Kreisel") (princ (strcat "\n " datei)) (princ "\n================================================================") (cond - ((null (car (atoms-family 1 '("VSP-REC-NEU")))) + ((null (car (atoms-family 1 '("VSP-BAU-JOURNAL")))) (princ "\n[TEST_DEMATIC_ARVATO] FEHLER: vf_spec.lsp nicht geladen" " (VarioFoerderer laden).") (setq *dematic-arvato-records* nil)) @@ -104,6 +277,10 @@ (setvar "OSMODE" 0) (setvar "ATTREQ" 0) (setvar "ATTDIA" 0) + ;; Vario-Bibliothek (Bogen-/AS-/ES-Masse) wie C:TEST_MUBEA, und die + ;; GF-Elementmasse in jeder Zeichnung neu ermitteln. + (if (vsp-lib-noetig-p) (init-bibliothek)) + (setq *mubea-gf-init-done* nil) (setq out '()) (foreach obj daten (setq out (cons (dematic_arvato:bau-eintrag obj) out))) diff --git a/tests/test_dxf_anlage_export.py b/tests/test_dxf_anlage_export.py new file mode 100644 index 0000000..b934190 --- /dev/null +++ b/tests/test_dxf_anlage_export.py @@ -0,0 +1,140 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +test_dxf_anlage_export.py - Gebaute Anlage -> Nachbau-Testdaten +(lib/dxf_anlage_export.py). Laeuft ohne BricsCAD und ohne DXF: die +Wrapper-Daten sind die Werte aus Dematic_TST.dxf, von Hand nachgestellt +(Form wie lese_zeichnung sie liefert). + + 1. Kreisel: abstand exakt aus der Blockdefinition (AN8 -> SP8), nicht aus + dem ganzzahligen ABSTAND-Attribut. + 2. GF auf zwei Kreiselketten: Endhoehe = Hoehe des Kreisels am Ende, + der (falsch) gebaute Winkel wird NICHT uebernommen. + 3. GF ohne Kreisel am Ende: gebauter Winkel bleibt. + 4. VF "standard": Parameter wie vfs-edit-basis-lesen, L_GF1 aus L_GF_m. + 5. VF "linienzug": Journal unveraendert als Token-Liste. + 6. Einzelblock: _2D/_3D-Suffix entfaellt. +""" + +import os +import sys + +import pytest + +sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), + "..", "lib")) +import dxf_anlage_export as dae # noqa: E402 + + +def _insert(name, p, rot=0.0, attribs=None, xdata=None): + return {"name": name, "handle": "1", "p": list(p), "rot": rot, + "attribs": attribs or {}, "xdata": xdata or {}, "ps": 0} + + +KREISEL_OBEN = _insert("KREISEL_2_STANDARD_33044", (35860.37, 12519.72, 2437.0), + 180.0, {"ID": "0002", "NUMMER": "2", "ABSTAND": "33044", + "KREISELART": "STANDARD"}) +KREISEL_UNTEN = _insert("KREISEL_3_STANDARD_33470", (36661.24, 24878.8, 1826.0), + 180.0, {"ID": "0003", "NUMMER": "3", "ABSTAND": "33470", + "KREISELART": "STANDARD"}) +BLOCK_INHALT = { + "KREISEL_2_STANDARD_33044": [{"name": "AN8_3D", "p": [400.0, 0.0, 0.0]}, + {"name": "SP8_3D", "p": [33444.28, 0.0, 0.0]}], + "KREISEL_3_STANDARD_33470": [{"name": "AN8_3D", "p": [400.0, 0.0, 0.0]}, + {"name": "SP8_3D", "p": [33870.18, 0.0, 0.0]}], +} + + +def _geo(): + return [dae.kreisel_geo(dae.kreisel_eintrag(k, BLOCK_INHALT, "T")) + for k in (KREISEL_OBEN, KREISEL_UNTEN)] + + +def test_kreisel_abstand_aus_blockdefinition(): + k = dae.kreisel_eintrag(KREISEL_OBEN, BLOCK_INHALT, "T") + assert k["id"] == "Kreisel_T_02" + assert k["abstand"] == pytest.approx(33044.28, abs=0.01) + assert (k["x"], k["y"], k["z"], k["rotation"]) == (35860.37, 12519.72, 2437.0, 180.0) + ohne_block = dae.kreisel_eintrag(KREISEL_OBEN, {}, "T") + assert ohne_block["abstand"] == 33044.0 + + +def test_gf_zwischen_zwei_kreiseln_bekommt_endhoehe(): + gf = _insert("GF_1", (5833.56, 12919.72, 2437.0), 0.0, + {"ID": "0005", "SEITE_AS": "links", "SEITE_ES": "links", + "HOEHE_BIS_mm": "1568"}, + {"SSG_GF_EDIT": ["90", "3.7929", "90", "90", "2437", "11559.08"]}) + hinweise = [] + e = dae.gf_eintrag(gf, _geo(), "T", hinweise) + assert e["test_id"] == "GF_T_01" + assert e["start_mm"] == [5833.56, 12919.72, 2437.0] + assert e["deltaL_mm"] == 11559.08 and e["hz_grad"] == 90.0 + assert (e["kreisel_start"], e["kreisel_ende"]) == ("Kreisel_T_02", "Kreisel_T_03") + assert e["hoehe_ende_mm"] == 1826.0 + assert "winkel_grad" not in e + assert hinweise == [] + + +def test_gf_ohne_kreisel_behaelt_gebauten_winkel(): + gf = _insert("GF_7", (0.0, 0.0, 1000.0), 0.0, {}, + {"SSG_GF_EDIT": ["0", "3", "90", "30", "1000", "5000"]}) + e = dae.gf_eintrag(gf, _geo(), "T", []) + assert e["winkel_grad"] == 3.0 + assert "hoehe_ende_mm" not in e and "kreisel_ende" not in e + assert e["es_winkel"] == "30" + + +def test_gf_ohne_xdata_wird_gemeldet(): + hinweise = [] + assert dae.gf_eintrag(_insert("GF_9", (0, 0, 0)), [], "T", hinweise) is None + assert "SSG_GF_EDIT" in hinweise[0] + + +def test_vf_standard(): + vf = _insert("VF_2", (3314.07, 24478.8, 1826.0), 0.0, + {"ID": "0082", "DELTA_L_mm": "11559", "DELTA_H_mm": "611", + "ANTRIEBFAHRTRICHTUNG": "Auf", "SEITE_AS": "links", + "MOTORSEITE": "rechts", "VF_WINKEL": "15", + "L_GF_m": "1.907,1.907"}, + {"SSG_VF_EDIT": ["standard", "270"]}) + e = dae.vf_standard_eintrag(vf, "T", "standard") + assert e["test_id"] == "VF_T_02" + assert (e["richtung"], e["deltaL"], e["deltaH"], e["winkel"]) == ("Auf", 11559.0, 611.0, 15) + assert e["L_GF1"] == 1907.0 and e["hz"] == 270.0 + assert (e["seite"], e["motorseite"]) == ("links", "rechts") + assert (e["x"], e["y"], e["z"]) == (3314.07, 24478.8, 1826.0) + + +def test_vf_linienzug_journal_unveraendert(): + roh = ["linienzug", "PT:42161.679193,2448.319538,0^JREAL:2177^JSTR:1^JSTR:9", + "0^JSTEP:Linie-VF^JDL:9370.410886"] + vf = _insert("VF_26", (42161.68, 2448.32, 2177.0), 0.0, {"ID": "0184"}, + {"SSG_VF_EDIT": roh}) + e = dae.vf_journal_eintrag(vf, "T", 1) + assert e["typ"] == "linienzug_journal" and e["test_id"] == "VF_T_LZ_01" + # Chunk-Grenze mitten im Token ("STR:9" + "0") wird korrekt zusammengesetzt + assert e["journal"] == ["PT:42161.679193,2448.319538,0", "REAL:2177", "STR:1", + "STR:90", "STEP:Linie-VF", "DL:9370.410886"] + + +def test_einzelblock_ohne_dimensionssuffix(): + e = dae.einzel_eintrag(_insert("Separator_SP_3D", (3038.72, 12119.73, 2473.0), + 0.0, {"ID": "0043", "ZUORDNUNG": "0002"})) + assert e["block"] == "Separator_SP" + assert e["function"] == "insert" and e["z"] == 2473.0 + assert "ID 0043" in e["comment"] + + +def test_reihenfolge_vf_vor_gf(): + inserts = [ + _insert("GF_1", (5833.56, 12919.72, 2437.0), 0.0, {}, + {"SSG_GF_EDIT": ["90", "3", "90", "90", "2437", "11559.08"]}), + _insert("Scanner_3D", (1, 2, 3)), + _insert("VF_2", (0, 0, 0), 0.0, {}, {"SSG_VF_EDIT": ["standard", "0"]}), + KREISEL_OBEN, KREISEL_UNTEN, + _insert("*U12", (0, 0, 0)), + ] + eintraege, _ = dae.baue_eintraege(inserts, BLOCK_INHALT, "T") + art = ["K" if "abstand" in e else "GF" if "modus" in e else + "VF" if "typ" in e else e["block"] for e in eintraege] + assert art == ["K", "K", "VF", "GF", "Scanner"] diff --git a/tests/test_dxf_scan_gf.py b/tests/test_dxf_scan_gf.py new file mode 100644 index 0000000..65de3c1 --- /dev/null +++ b/tests/test_dxf_scan_gf.py @@ -0,0 +1,168 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +test_dxf_scan_gf.py - Gefaellestrecken aus Staustrecken-Linien +(gf_eintraege_aus_linien in lib/dxf_scan_components.py). Laeuft ohne +BricsCAD und ohne DXF: die Linien und Ausschleuselemente sind die +gemessenen Werte aus Dematic_arvato_reduced.dxf, von Hand nachgestellt. + + 1. Fallende Linie mit AS am oberen Ende -> GF, AS wird verbraucht. + 2. Der Nachbar-AS der Linie daneben (800 mm Raster, auf der anderen Seite + naeher dran) wird NICHT gegriffen - die Seite aus dem Blocknamen + entscheidet, nicht der kleinste Abstand. + 3. Rueckwaerts gezeichnete GF (tiefes Ende zuerst) -> Start bleibt oben. + 4. AS am UNTEREN Ende -> Steigfoerderer, keine GF, AS bleibt unverbraucht. + 5. Waagrechte Linie -> keine GF. + 6. Anschluss an die Kreisel: Start/Ende werden auf die Ketten geschoben, + deltaL reicht von Kette zu Kette; Hoehen kommen von den Kreiseln. + 7. Separator auf der Achse wird verbraucht, einer daneben nicht. + 8. hoehen_entfernen laesst nur Anwender-Hoehen stehen. +""" + +import os +import sys + +import pytest + +sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), + "..", "lib")) +import dxf_scan_components as dsc # noqa: E402 + +AS_LINKS = "Ausschleuselement links 200000217 Draufsicht" + + +def _as(x, y, z=3191.63, block=AS_LINKS): + return {"familie": "schleuselement", "block": block, + "x": x, "y": y, "z": z, "rot": 270.0} + + +def _linie(a, b, layer="6-SP"): + return {"layer": layer, "a": list(a), "b": list(b)} + + +@pytest.fixture(autouse=True) +def _projekt(monkeypatch): + monkeypatch.setattr(dsc, "PROJEKT", "Test") + + +# Die beiden Kreisel am GF-Feld (Radmitten AN8 -> SP8, r = 400), wie +# baue_eintraege sie als kreisel_geo anlegt. Ketten: oben y = 12919.72, +# unten y = 24478.8. +def _kreisel_oben(z=2437.0): + return {"id": "K_oben", "a": (35460.37, 12519.72), "u": (-1.0, 0.0), + "laenge": 33044.28, "r": 400.0, "z_anwender": z} + + +def _kreisel_unten(z=1826.0): + return {"id": "K_unten", "a": (36261.24, 24878.8), "u": (-1.0, 0.0), + "laenge": 33470.18, "r": 400.0, "z_anwender": z} + + +def test_gf_mit_as_am_oberen_ende(): + linie = _linie((5833.56, 13348.38, 3191.63), (5833.44, 24002.54, 2821.63)) + as_eigen = _as(5367.10, 14505.61) + eintraege, belegt, hinweise = dsc.gf_eintraege_aus_linien([linie], [as_eigen]) + assert len(eintraege) == 1 + gf = eintraege[0] + assert gf["test_id"] == "GF_Test_01" + assert gf["modus"] == 1 + # ohne Kreisel: Linienende bleibt stehen, Hoehe unbekannt -> Platzhalter + assert gf["start_mm"] == [5833.56, 13348.38, 0.0] + assert gf["deltaL_mm"] == pytest.approx(10654.16, abs=0.01) + assert gf["hz_grad"] == 90.0 + assert gf["winkel_grad"] == 3.0 + assert gf["hoehe_unbekannt"] is True + assert (gf["as_seite"], gf["as_winkel"]) == ("links", "90") + assert belegt == {id(as_eigen)} + assert len(hinweise) == 2 and all("kein Kreisel" in h for h in hinweise) + + +def test_anschluss_an_beide_kreisel_mit_hoehen(): + linie = _linie((5833.56, 13348.38, 3191.63), (5833.44, 24002.54, 2821.63)) + eintraege, _, hinweise = dsc.gf_eintraege_aus_linien( + [linie], [_as(5367.10, 14505.61)], [_kreisel_oben(), _kreisel_unten()]) + gf = eintraege[0] + assert gf["start_mm"][1] == pytest.approx(12919.72, abs=0.01) + assert gf["start_mm"][2] == 2437.0 + assert gf["hoehe_ende_mm"] == 1826.0 + assert gf["hoehe_quelle"] == "Anwender" + assert "winkel_grad" not in gf # rechnet der LISP-Treiber + assert gf["deltaL_mm"] == pytest.approx(24478.8 - 12919.72, abs=0.05) + assert (gf["kreisel_start"], gf["kreisel_ende"]) == ("K_oben", "K_unten") + assert hinweise == [] + + +def test_kreisel_ohne_hoehe_gibt_platzhalter(): + linie = _linie((5833.56, 13348.38, 3191.63), (5833.44, 24002.54, 2821.63)) + eintraege, _, _ = dsc.gf_eintraege_aus_linien( + [linie], [], [_kreisel_oben(z=None), _kreisel_unten()]) + assert eintraege[0]["kreisel_start"] == "K_oben" + assert "hoehe_ende_mm" not in eintraege[0] + assert eintraege[0]["winkel_grad"] == 3.0 + + +def test_separator_auf_achse_wird_verbraucht(): + linie = _linie((5833.56, 13348.38, 3191.63), (5833.44, 24002.54, 2821.63)) + sep_achse = {"familie": "sensor", "block": "S-SP", "x": 5834.0, "y": 23810.0} + sep_daneben = {"familie": "sensor", "block": "S-SP", "x": 6734.0, "y": 23810.0} + scanner = {"familie": "sensor", "block": "Scanner", "x": 5834.0, "y": 20000.0} + _, belegt, _ = dsc.gf_eintraege_aus_linien( + [linie], [], [_kreisel_oben(), _kreisel_unten()], + [sep_achse, sep_daneben, scanner]) + assert belegt == {id(sep_achse)} + + +def test_hoehen_entfernen_laesst_anwender_hoehen_stehen(): + eintraege = [ + {"id": "K1", "x": 0, "y": 0, "z": 2437.0, "hoehe_quelle": "Anwender"}, + {"block": "S-SP", "x": 0, "y": 0, "z": 2821.63, "comment": ""}, + {"test_id": "G", "typ": "gerade", "startpunkt": [0, 0, 5.0], + "endpunkt": [1, 0, 5.0]}, + ] + assert dsc.hoehen_entfernen(eintraege) == 2 + assert eintraege[0]["z"] == 2437.0 + assert eintraege[1]["z"] == 0.0 and eintraege[1]["hoehe_unbekannt"] is True + assert eintraege[2]["startpunkt"][2] == 0.0 and eintraege[2]["endpunkt"][2] == 0.0 + + +def test_nachbar_as_auf_falscher_seite_wird_nicht_gegriffen(): + # Linie bei x=5834; ihr AS 467 mm links, der AS der Nachbarlinie + # (x=6734) 433 mm RECHTS - also naeher, aber auf der falschen Seite. + linie = _linie((5833.56, 13348.38, 3191.63), (5833.44, 24002.54, 2821.63)) + as_eigen = _as(5367.10, 14505.61) + as_nachbar = _as(6267.10, 14505.61) + _, belegt, _ = dsc.gf_eintraege_aus_linien([linie], [as_nachbar, as_eigen]) + assert belegt == {id(as_eigen)} + + +def test_rueckwaerts_gezeichnete_gf_startet_oben(): + linie = _linie((5833.44, 24002.54, 2821.63), (5833.56, 13348.38, 3191.63)) + eintraege, _, _ = dsc.gf_eintraege_aus_linien([linie], [_as(5367.10, 14505.61)]) + assert eintraege[0]["start_mm"][:2] == [5833.56, 13348.38] + assert eintraege[0]["hz_grad"] == 90.0 + + +def test_as_am_unteren_ende_ist_steigfoerderer(): + # Gemessen: Linie x=2801 von 2822 hinauf auf 3192, AS am tiefen Ende. + linie = _linie((2801.42, 24043.0, 2821.63), (2801.42, 13389.0, 3191.63)) + as_unten = _as(3267.48, 22892.92, z=2821.63) + eintraege, belegt, hinweise = dsc.gf_eintraege_aus_linien([linie], [as_unten]) + assert eintraege == [] + assert belegt == set() + assert len(hinweise) == 1 and "Steigfoerderer" in hinweise[0] + + +def test_waagrechte_linie_ist_keine_gf(): + linie = _linie((36661.0, 10279.0, 2821.63), (36661.0, 24879.0, 2821.63)) + eintraege, belegt, hinweise = dsc.gf_eintraege_aus_linien([linie], []) + assert eintraege == [] + assert belegt == set() + assert any("waagrechte" in h for h in hinweise) + + +def test_ohne_as_defaults_und_hinweis(): + linie = _linie((0.0, 0.0, 1000.0), (5000.0, 0.0, 800.0)) + eintraege, _, hinweise = dsc.gf_eintraege_aus_linien([linie], []) + assert eintraege[0]["hz_grad"] == 0.0 + assert eintraege[0]["as_seite"] == dsc.DEFAULT_SEITE + assert any("ohne Ausschleuselement" in h for h in hinweise) diff --git a/tests/test_mubea.lsp b/tests/test_mubea.lsp index 3d92a29..a4f29bb 100644 --- a/tests/test_mubea.lsp +++ b/tests/test_mubea.lsp @@ -146,8 +146,18 @@ ;; gueltigen Winkel zu nehmen. L_GF1 aus JSON ist der Vorlauf-Zielwert; ;; L_GF2 (Nachlauf) ist der Rest (L_GF_gesamt - L_GF1). (defun mubea:build-vario-one (tid typ richtung deltaL deltaH winkel-soll gf1-ziel seite hz - startpunkt / ergebnis winkel-treffer best-winkel L_GF L_VF - gf1 gf2 hoehe-bis lastEnt ent vf-nummer) + startpunkt) + (mubea:ent-json tid "vario" + (mubea:vario-bauen tid typ richtung deltaL deltaH winkel-soll gf1-ziel seite hz + startpunkt))) + +;; Der eigentliche Bau ohne Ergebnis-Format - auch von +;; tests/test_dematic_arvato.lsp genutzt (dort mit vsp-Records). +;; Rueckgabe: Entity des VF_n-Blocks oder nil (auch, wenn deltaL beim +;; gewuenschten Winkel nicht loesbar ist). +(defun mubea:vario-bauen (tid typ richtung deltaL deltaH winkel-soll gf1-ziel seite hz + startpunkt / ergebnis winkel-treffer best-winkel L_GF L_VF + gf1 gf2 hoehe-bis lastEnt ent vf-nummer) (if (or (null seite) (= seite "")) (setq seite "links")) (if (or (null typ) (= typ "")) (setq typ "standard")) (if (null hz) (setq hz 0.0) (setq hz (float hz))) @@ -207,12 +217,12 @@ ;; Linienzug/Altbestand bleiben unmarkiert. (if (and ent (= (type ent) 'ENAME) (member typ '("standard" "etage"))) (vf-edit-xdata-schreiben ent typ hz)) - (mubea:ent-json tid "vario" ent)) + (if (and ent (= (type ent) 'ENAME)) ent nil)) (progn (princ (strcat "\n FEHLER: deltaL=" (rtos deltaL 2 0) " bei Winkel " (if winkel-soll (rtos winkel-soll 2 0) "auto") " nicht loesbar (kein gueltiges L_GF/L_VF).")) - (mubea:result-json tid "vario" "failed" nil nil nil nil))) + nil)) ) ;; --- Vario(s) aus einem Template-Eintrag bauen --- @@ -290,8 +300,15 @@ ;; sep_x = 300 * cos(v), v = Element-Winkel (winkel_grad, Default 3 Grad) ;; Die Zielhoehe ergibt sich aus L_stau/Winkel (kein Ziel-Hoehen-Parameter). ;; Rueckgabe: Ergebnis-JSON-String. -(defun mubea:build-gf-one (tid start-mm deltaL hz as-seite es-seite as-winkel es-winkel winkel / - rad sep-x test-L_stau ent) +(defun mubea:build-gf-one (tid start-mm deltaL hz as-seite es-seite as-winkel es-winkel winkel) + (mubea:ent-json tid "gefaellestrecke" + (mubea:gf-bauen tid start-mm deltaL hz as-seite es-seite as-winkel es-winkel winkel))) + +;; Der eigentliche Bau ohne Ergebnis-Format - auch von +;; tests/test_dematic_arvato.lsp genutzt (dort mit vsp-Records). +;; Rueckgabe: Entity des GF_n-Blocks oder nil. +(defun mubea:gf-bauen (tid start-mm deltaL hz as-seite es-seite as-winkel es-winkel winkel / + rad sep-x test-L_stau ent) (mubea:ensure-gf-init) ;; Element-Masse fuer die gewaehlte AS/ES-Variante setzen, damit aus-dx/ein-dx ;; zur Variante (90/30 Grad) passen. Danach wieder auf 90 zuruecksetzen. @@ -312,7 +329,7 @@ deltaL as-winkel es-winkel "0" "Schoenenberger Geruest"))) (vf-set-as-masse "90" as-seite) (vf-set-es-masse "90" es-seite) - (mubea:ent-json tid "gefaellestrecke" ent) + ent ) ;; --- Gefaellestrecke(n) aus einem Template-Eintrag bauen --- diff --git a/tests/testdata/dematic_arvato.json b/tests/testdata/dematic_arvato.json index b9c122c..26603ec 100644 --- a/tests/testdata/dematic_arvato.json +++ b/tests/testdata/dematic_arvato.json @@ -1,1381 +1,743 @@ [ + { + "id": "Kreisel_Arvato_01", + "function": "insert", + "x": 19204.0, + "y": 1703.66, + "z": 2177.0, + "abstand": 3619.14, + "rotation": 90.0, + "typ": "STANDARD", + "comment": "aus Zeichnung: KREISEL_1_STANDARD_3619 (ID 0001), abstand aus Blockdefinition (AN8 -> SP8)" + }, + { + "id": "Kreisel_Arvato_02", + "function": "insert", + "x": 35860.37, + "y": 12519.72, + "z": 2437.0, + "abstand": 33044.28, + "rotation": 180.0, + "typ": "STANDARD", + "comment": "aus Zeichnung: KREISEL_2_STANDARD_33044 (ID 0002), abstand aus Blockdefinition (AN8 -> SP8)" + }, { "id": "Kreisel_Arvato_03", "function": "insert", - "x": 18737.94, - "y": 165252.93, - "z": 0.0, - "abstand": 3619.15, - "rotation": 90.0, + "x": 36661.24, + "y": 24878.8, + "z": 1826.0, + "abstand": 33470.18, + "rotation": 180.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." + "comment": "aus Zeichnung: KREISEL_3_STANDARD_33470 (ID 0003), abstand aus Blockdefinition (AN8 -> SP8)" }, { "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, + "x": 42563.78, + "y": 1703.66, + "z": 2177.0, + "abstand": 3619.14, "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." + "comment": "aus Zeichnung: KREISEL_4_STANDARD_3619 (ID 0004), abstand aus Blockdefinition (AN8 -> SP8)" }, { - "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, + "test_id": "VF_Arvato_02", + "typ": "standard", + "richtung": "Auf", + "deltaL": 11559.0, + "deltaH": 611.0, + "winkel": 15, + "L_GF1": 1907.0, + "seite": "links", + "motorseite": "rechts", "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." + "x": 3314.07, + "y": 24478.8, + "z": 1826.0, + "comment": "aus Zeichnung: VF_2 (ID 0082), Hoehe 1826 -> 2437; deltaL/deltaH aus den (ganzzahligen) Attributen" }, { - "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": "VF_Arvato_03", + "typ": "standard", + "richtung": "Auf", + "deltaL": 11559.0, + "deltaH": 611.0, + "winkel": 15, + "L_GF1": 1907.0, + "seite": "links", + "motorseite": "rechts", + "hz": 270.0, + "x": 15285.06, + "y": 24478.8, + "z": 1826.0, + "comment": "aus Zeichnung: VF_3 (ID 0083), Hoehe 1826 -> 2437; deltaL/deltaH aus den (ganzzahligen) Attributen" }, { - "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": "VF_Arvato_05", + "typ": "standard", + "richtung": "Auf", + "deltaL": 11559.0, + "deltaH": 611.0, + "winkel": 15, + "L_GF1": 1907.0, + "seite": "links", + "motorseite": "rechts", + "hz": 270.0, + "x": 23843.05, + "y": 24478.8, + "z": 1826.0, + "comment": "aus Zeichnung: VF_5 (ID 0084), Hoehe 1826 -> 2437; deltaL/deltaH aus den (ganzzahligen) Attributen" }, { - "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, + "test_id": "VF_Arvato_06", + "typ": "standard", + "richtung": "Auf", + "deltaL": 22559.0, + "deltaH": 0.0, + "winkel": 12, + "L_GF1": 6852.0, + "seite": "rechts", + "motorseite": "rechts", "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." + "x": 42163.78, + "y": 4017.06, + "z": 2177.0, + "comment": "aus Zeichnung: VF_6 (ID 0085), Hoehe 2177 -> 2177; deltaL/deltaH aus den (ganzzahligen) Attributen" }, { - "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." + "test_id": "VF_Arvato_08", + "typ": "standard", + "richtung": "Auf", + "deltaL": 6852.0, + "deltaH": 260.0, + "winkel": 18, + "L_GF1": 767.0, + "seite": "links", + "motorseite": "rechts", + "hz": 90.0, + "x": 19551.49, + "y": 5265.19, + "z": 2177.0, + "comment": "aus Zeichnung: VF_8 (ID 0183), Hoehe 2177 -> 2437; deltaL/deltaH aus den (ganzzahligen) Attributen" + }, + { + "test_id": "VF_Arvato_LZ_01", + "typ": "linienzug_journal", + "journal": [ + "PT:42161.679193,2448.319538,0", + "REAL:2177", + "STR:1", + "STR:90", + "STR:2", + "STEP:Linie-VF", + "STR:4", + "DL:9370.410886", + "REAL:-180", + "STR:1", + "REAL:2800", + "INT:1", + "STR:2", + "STR:2", + "STR:2", + "STEP:Linie-GF", + "STR:2", + "STR:1", + "STR:3", + "DL:6187.72996", + "STR:1", + "STR:2", + "STR:2", + "REAL:3", + "STEP:Linie-VF", + "STR:3", + "DL:4572.938729", + "STR:2", + "INT:1", + "STR:3", + "STR:1", + "STEP:ES", + "STR:90", + "STR:1", + "DL:2872.479403", + "REAL:2100", + "STR:3", + "STR:1", + "STEP:ES", + "STR:90", + "STR:2", + "DL:2857.418974", + "REAL:2000", + "STR:3", + "STR:1", + "STEP:ES", + "STR:90", + "STR:2", + "DL:2850.93244", + "REAL:2177", + "INT:2", + "STR:2" + ], + "comment": "aus Zeichnung: VF_26 (ID 0184), 52 Eingaben, Hoehe 2177 -> 2174; wird 1:1 abgespielt (vsp-bau-journal)" + }, + { + "test_id": "GF_Arvato_01", + "modus": 1, + "deltaL_mm": 11559.08, + "hz_grad": 90.0, + "start_mm": [5833.56, 12919.72, 2437.0], + "as_seite": "links", + "es_seite": "links", + "as_winkel": "90", + "es_winkel": "90", + "kreisel_start": "Kreisel_Arvato_02", + "kreisel_ende": "Kreisel_Arvato_03", + "hoehe_ende_mm": 1826.0, + "comment": "aus Zeichnung: GF_1 (ID 0005); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 3.7929 Grad -> HOEHE_BIS 1568" + }, + { + "test_id": "GF_Arvato_02", + "modus": 1, + "deltaL_mm": 11559.08, + "hz_grad": 90.0, + "start_mm": [6733.56, 12919.72, 2437.0], + "as_seite": "links", + "es_seite": "links", + "as_winkel": "90", + "es_winkel": "90", + "kreisel_start": "Kreisel_Arvato_02", + "kreisel_ende": "Kreisel_Arvato_03", + "hoehe_ende_mm": 1826.0, + "comment": "aus Zeichnung: GF_2 (ID 0006); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 3.7929 Grad -> HOEHE_BIS 1568" + }, + { + "test_id": "GF_Arvato_03", + "modus": 1, + "deltaL_mm": 11559.08, + "hz_grad": 90.0, + "start_mm": [7533.56, 12919.72, 2437.0], + "as_seite": "links", + "es_seite": "links", + "as_winkel": "90", + "es_winkel": "90", + "kreisel_start": "Kreisel_Arvato_02", + "kreisel_ende": "Kreisel_Arvato_03", + "hoehe_ende_mm": 1826.0, + "comment": "aus Zeichnung: GF_3 (ID 0007); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 3.7929 Grad -> HOEHE_BIS 1568" + }, + { + "test_id": "GF_Arvato_04", + "modus": 1, + "deltaL_mm": 11559.08, + "hz_grad": 90.0, + "start_mm": [8333.56, 12919.72, 2437.0], + "as_seite": "links", + "es_seite": "links", + "as_winkel": "90", + "es_winkel": "90", + "kreisel_start": "Kreisel_Arvato_02", + "kreisel_ende": "Kreisel_Arvato_03", + "hoehe_ende_mm": 1826.0, + "comment": "aus Zeichnung: GF_4 (ID 0008); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 3.7929 Grad -> HOEHE_BIS 1568" + }, + { + "test_id": "GF_Arvato_05", + "modus": 1, + "deltaL_mm": 11559.08, + "hz_grad": 90.0, + "start_mm": [9383.57, 12919.72, 2437.0], + "as_seite": "links", + "es_seite": "links", + "as_winkel": "90", + "es_winkel": "90", + "kreisel_start": "Kreisel_Arvato_02", + "kreisel_ende": "Kreisel_Arvato_03", + "hoehe_ende_mm": 1826.0, + "comment": "aus Zeichnung: GF_5 (ID 0009); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 3.7929 Grad -> HOEHE_BIS 1568" + }, + { + "test_id": "GF_Arvato_06", + "modus": 1, + "deltaL_mm": 11559.08, + "hz_grad": 90.0, + "start_mm": [10183.57, 12919.72, 2437.0], + "as_seite": "links", + "es_seite": "links", + "as_winkel": "90", + "es_winkel": "90", + "kreisel_start": "Kreisel_Arvato_02", + "kreisel_ende": "Kreisel_Arvato_03", + "hoehe_ende_mm": 1826.0, + "comment": "aus Zeichnung: GF_6 (ID 0010); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 3.7929 Grad -> HOEHE_BIS 1568" + }, + { + "test_id": "GF_Arvato_07", + "modus": 1, + "deltaL_mm": 11559.08, + "hz_grad": 90.0, + "start_mm": [10983.57, 12919.72, 2437.0], + "as_seite": "links", + "es_seite": "links", + "as_winkel": "90", + "es_winkel": "90", + "kreisel_start": "Kreisel_Arvato_02", + "kreisel_ende": "Kreisel_Arvato_03", + "hoehe_ende_mm": 1826.0, + "comment": "aus Zeichnung: GF_7 (ID 0011); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 3.7929 Grad -> HOEHE_BIS 1568" + }, + { + "test_id": "GF_Arvato_08", + "modus": 1, + "deltaL_mm": 11559.08, + "hz_grad": 90.0, + "start_mm": [12323.57, 12919.72, 2437.0], + "as_seite": "links", + "es_seite": "links", + "as_winkel": "90", + "es_winkel": "90", + "kreisel_start": "Kreisel_Arvato_02", + "kreisel_ende": "Kreisel_Arvato_03", + "hoehe_ende_mm": 1826.0, + "comment": "aus Zeichnung: GF_8 (ID 0012); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 3.7929 Grad -> HOEHE_BIS 1568" + }, + { + "test_id": "GF_Arvato_09", + "modus": 1, + "deltaL_mm": 11559.08, + "hz_grad": 90.0, + "start_mm": [13123.57, 12919.72, 2437.0], + "as_seite": "links", + "es_seite": "links", + "as_winkel": "90", + "es_winkel": "90", + "kreisel_start": "Kreisel_Arvato_02", + "kreisel_ende": "Kreisel_Arvato_03", + "hoehe_ende_mm": 1826.0, + "comment": "aus Zeichnung: GF_9 (ID 0013); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 3.7929 Grad -> HOEHE_BIS 1568" + }, + { + "test_id": "GF_Arvato_10", + "modus": 1, + "deltaL_mm": 11559.08, + "hz_grad": 90.0, + "start_mm": [13923.57, 12919.72, 2437.0], + "as_seite": "links", + "es_seite": "links", + "as_winkel": "90", + "es_winkel": "90", + "kreisel_start": "Kreisel_Arvato_02", + "kreisel_ende": "Kreisel_Arvato_03", + "hoehe_ende_mm": 1826.0, + "comment": "aus Zeichnung: GF_10 (ID 0014); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 3.7929 Grad -> HOEHE_BIS 1568" + }, + { + "test_id": "GF_Arvato_11", + "modus": 1, + "deltaL_mm": 11559.08, + "hz_grad": 90.0, + "start_mm": [16733.57, 12919.72, 2437.0], + "as_seite": "links", + "es_seite": "links", + "as_winkel": "90", + "es_winkel": "90", + "kreisel_start": "Kreisel_Arvato_02", + "kreisel_ende": "Kreisel_Arvato_03", + "hoehe_ende_mm": 1826.0, + "comment": "aus Zeichnung: GF_11 (ID 0015); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 3.7929 Grad -> HOEHE_BIS 1568" + }, + { + "test_id": "GF_Arvato_12", + "modus": 1, + "deltaL_mm": 11559.08, + "hz_grad": 90.0, + "start_mm": [17533.57, 12919.72, 2437.0], + "as_seite": "links", + "es_seite": "links", + "as_winkel": "90", + "es_winkel": "90", + "kreisel_start": "Kreisel_Arvato_02", + "kreisel_ende": "Kreisel_Arvato_03", + "hoehe_ende_mm": 1826.0, + "comment": "aus Zeichnung: GF_12 (ID 0016); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 3.7929 Grad -> HOEHE_BIS 1568" + }, + { + "test_id": "GF_Arvato_13", + "modus": 1, + "deltaL_mm": 11559.08, + "hz_grad": 90.0, + "start_mm": [18333.57, 12919.72, 2437.0], + "as_seite": "links", + "es_seite": "links", + "as_winkel": "90", + "es_winkel": "90", + "kreisel_start": "Kreisel_Arvato_02", + "kreisel_ende": "Kreisel_Arvato_03", + "hoehe_ende_mm": 1826.0, + "comment": "aus Zeichnung: GF_13 (ID 0017); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 3.7929 Grad -> HOEHE_BIS 1568" + }, + { + "test_id": "GF_Arvato_14", + "modus": 1, + "deltaL_mm": 11559.08, + "hz_grad": 90.0, + "start_mm": [19381.07, 12919.72, 2437.0], + "as_seite": "links", + "es_seite": "links", + "as_winkel": "90", + "es_winkel": "90", + "kreisel_start": "Kreisel_Arvato_02", + "kreisel_ende": "Kreisel_Arvato_03", + "hoehe_ende_mm": 1826.0, + "comment": "aus Zeichnung: GF_14 (ID 0018); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 3.7929 Grad -> HOEHE_BIS 1568" + }, + { + "test_id": "GF_Arvato_15", + "modus": 1, + "deltaL_mm": 11559.08, + "hz_grad": 90.0, + "start_mm": [20281.07, 12919.72, 2437.0], + "as_seite": "links", + "es_seite": "links", + "as_winkel": "90", + "es_winkel": "90", + "kreisel_start": "Kreisel_Arvato_02", + "kreisel_ende": "Kreisel_Arvato_03", + "hoehe_ende_mm": 1826.0, + "comment": "aus Zeichnung: GF_15 (ID 0019); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 3.7929 Grad -> HOEHE_BIS 1568" + }, + { + "test_id": "GF_Arvato_16", + "modus": 1, + "deltaL_mm": 11559.08, + "hz_grad": 90.0, + "start_mm": [21081.07, 12919.72, 2437.0], + "as_seite": "links", + "es_seite": "links", + "as_winkel": "90", + "es_winkel": "90", + "kreisel_start": "Kreisel_Arvato_02", + "kreisel_ende": "Kreisel_Arvato_03", + "hoehe_ende_mm": 1826.0, + "comment": "aus Zeichnung: GF_16 (ID 0020); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 3.7929 Grad -> HOEHE_BIS 1568" + }, + { + "test_id": "GF_Arvato_17", + "modus": 1, + "deltaL_mm": 11559.08, + "hz_grad": 90.0, + "start_mm": [21881.07, 12919.72, 2437.0], + "as_seite": "links", + "es_seite": "links", + "as_winkel": "90", + "es_winkel": "90", + "kreisel_start": "Kreisel_Arvato_02", + "kreisel_ende": "Kreisel_Arvato_03", + "hoehe_ende_mm": 1826.0, + "comment": "aus Zeichnung: GF_17 (ID 0021); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 3.7929 Grad -> HOEHE_BIS 1568" + }, + { + "test_id": "GF_Arvato_18", + "modus": 1, + "deltaL_mm": 11559.08, + "hz_grad": 90.0, + "start_mm": [25541.07, 12919.72, 2437.0], + "as_seite": "links", + "es_seite": "links", + "as_winkel": "90", + "es_winkel": "90", + "kreisel_start": "Kreisel_Arvato_02", + "kreisel_ende": "Kreisel_Arvato_03", + "hoehe_ende_mm": 1826.0, + "comment": "aus Zeichnung: GF_18 (ID 0022); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 3.7929 Grad -> HOEHE_BIS 1568" + }, + { + "test_id": "GF_Arvato_19", + "modus": 1, + "deltaL_mm": 11559.08, + "hz_grad": 90.0, + "start_mm": [26341.07, 12919.72, 2437.0], + "as_seite": "links", + "es_seite": "links", + "as_winkel": "90", + "es_winkel": "90", + "kreisel_start": "Kreisel_Arvato_02", + "kreisel_ende": "Kreisel_Arvato_03", + "hoehe_ende_mm": 1826.0, + "comment": "aus Zeichnung: GF_19 (ID 0023); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 3.7929 Grad -> HOEHE_BIS 1568" + }, + { + "test_id": "GF_Arvato_20", + "modus": 1, + "deltaL_mm": 11559.08, + "hz_grad": 90.0, + "start_mm": [27841.06, 12919.72, 2437.0], + "as_seite": "links", + "es_seite": "links", + "as_winkel": "90", + "es_winkel": "90", + "kreisel_start": "Kreisel_Arvato_02", + "kreisel_ende": "Kreisel_Arvato_03", + "hoehe_ende_mm": 1826.0, + "comment": "aus Zeichnung: GF_20 (ID 0024); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 3.7929 Grad -> HOEHE_BIS 1568" + }, + { + "test_id": "GF_Arvato_21", + "modus": 1, + "deltaL_mm": 11559.08, + "hz_grad": 90.0, + "start_mm": [28741.06, 12919.72, 2437.0], + "as_seite": "links", + "es_seite": "links", + "as_winkel": "90", + "es_winkel": "90", + "kreisel_start": "Kreisel_Arvato_02", + "kreisel_ende": "Kreisel_Arvato_03", + "hoehe_ende_mm": 1826.0, + "comment": "aus Zeichnung: GF_21 (ID 0025); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 3.7929 Grad -> HOEHE_BIS 1568" + }, + { + "test_id": "GF_Arvato_22", + "modus": 1, + "deltaL_mm": 11559.08, + "hz_grad": 90.0, + "start_mm": [29541.06, 12919.72, 2437.0], + "as_seite": "links", + "es_seite": "links", + "as_winkel": "90", + "es_winkel": "90", + "kreisel_start": "Kreisel_Arvato_02", + "kreisel_ende": "Kreisel_Arvato_03", + "hoehe_ende_mm": 1826.0, + "comment": "aus Zeichnung: GF_22 (ID 0026); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 3.7929 Grad -> HOEHE_BIS 1568" + }, + { + "test_id": "GF_Arvato_23", + "modus": 1, + "deltaL_mm": 11559.08, + "hz_grad": 90.0, + "start_mm": [30341.06, 12919.72, 2437.0], + "as_seite": "links", + "es_seite": "links", + "as_winkel": "90", + "es_winkel": "90", + "kreisel_start": "Kreisel_Arvato_02", + "kreisel_ende": "Kreisel_Arvato_03", + "hoehe_ende_mm": 1826.0, + "comment": "aus Zeichnung: GF_23 (ID 0027); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 3.7929 Grad -> HOEHE_BIS 1568" + }, + { + "test_id": "GF_Arvato_24", + "modus": 1, + "deltaL_mm": 11559.08, + "hz_grad": 90.0, + "start_mm": [31891.06, 12919.72, 2437.0], + "as_seite": "links", + "es_seite": "links", + "as_winkel": "90", + "es_winkel": "90", + "kreisel_start": "Kreisel_Arvato_02", + "kreisel_ende": "Kreisel_Arvato_03", + "hoehe_ende_mm": 1826.0, + "comment": "aus Zeichnung: GF_24 (ID 0028); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 3.7929 Grad -> HOEHE_BIS 1568" + }, + { + "test_id": "GF_Arvato_25", + "modus": 1, + "deltaL_mm": 11559.08, + "hz_grad": 90.0, + "start_mm": [32791.06, 12919.72, 2437.0], + "as_seite": "links", + "es_seite": "links", + "as_winkel": "90", + "es_winkel": "90", + "kreisel_start": "Kreisel_Arvato_02", + "kreisel_ende": "Kreisel_Arvato_03", + "hoehe_ende_mm": 1826.0, + "comment": "aus Zeichnung: GF_25 (ID 0029); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 3.7929 Grad -> HOEHE_BIS 1568" + }, + { + "test_id": "GF_Arvato_26", + "modus": 1, + "deltaL_mm": 11559.08, + "hz_grad": 90.0, + "start_mm": [33591.06, 12919.72, 2437.0], + "as_seite": "links", + "es_seite": "links", + "as_winkel": "90", + "es_winkel": "90", + "kreisel_start": "Kreisel_Arvato_02", + "kreisel_ende": "Kreisel_Arvato_03", + "hoehe_ende_mm": 1826.0, + "comment": "aus Zeichnung: GF_26 (ID 0030); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 3.7929 Grad -> HOEHE_BIS 1568" + }, + { + "test_id": "GF_Arvato_27", + "modus": 1, + "deltaL_mm": 11559.08, + "hz_grad": 90.0, + "start_mm": [34391.06, 12919.72, 2437.0], + "as_seite": "links", + "es_seite": "links", + "as_winkel": "90", + "es_winkel": "90", + "kreisel_start": "Kreisel_Arvato_02", + "kreisel_ende": "Kreisel_Arvato_03", + "hoehe_ende_mm": 1826.0, + "comment": "aus Zeichnung: GF_27 (ID 0031); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 3.7929 Grad -> HOEHE_BIS 1568" }, { "function": "insert", - "block": "Vario_Motorstation_500mm_rechts", - "x": 41271.73, - "y": 171724.16, - "z": -370.0, + "block": "Separator_SP", + "x": 3038.72, + "y": 12119.73, + "z": 2473.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)" + "comment": "aus Zeichnung: Separator_SP_3D (ID 0043, ZUORDNUNG 0002, ARTINR 200000077)" }, { "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, + "block": "Separator_SP", + "x": 3482.38, + "y": 24478.8, + "z": 1826.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)" + "comment": "aus Zeichnung: Separator_SP_3D (ID 0044, ZUORDNUNG 0003, ARTINR 200000077)" }, { "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, + "block": "Separator_SP", + "x": 5094.1, + "y": 12919.72, + "z": 2473.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)" + "comment": "aus Zeichnung: Separator_SP_3D (ID 0045, ZUORDNUNG 0002, ARTINR 200000077)" }, { "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)" + "block": "Separator_SP", + "x": 15412.41, + "y": 24478.8, + "z": 1826.0, + "rotation": 0.0, + "comment": "aus Zeichnung: Separator_SP_3D (ID 0046, ZUORDNUNG 0003, ARTINR 200000077)" }, { "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, + "block": "Separator_SP", + "x": 15994.1, + "y": 12919.78, + "z": 2473.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)" + "comment": "aus Zeichnung: Separator_SP_3D (ID 0047, ZUORDNUNG 0002, ARTINR 200000077)" }, { "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, + "block": "Separator_SP", + "x": 19604.0, + "y": 5042.22, + "z": 2177.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)" + "comment": "aus Zeichnung: Separator_SP_3D (ID 0048, ZUORDNUNG 0001, ARTINR 200000077)" }, { "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)" + "block": "Separator_SP", + "x": 24002.04, + "y": 24478.8, + "z": 1826.0, + "rotation": 0.0, + "comment": "aus Zeichnung: Separator_SP_3D (ID 0049, ZUORDNUNG 0003, ARTINR 200000077)" }, { "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, + "block": "Separator_SP", + "x": 24794.1, + "y": 12919.82, + "z": 2473.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)" + "comment": "aus Zeichnung: Separator_SP_3D (ID 0050, ZUORDNUNG 0002, ARTINR 200000077)" }, { "function": "insert", - "block": "AS_Element_90_rechts", - "x": 42932.74, - "y": 167630.19, - "z": 0.0, + "block": "Separator_SP", + "x": 35050.37, + "y": 12919.72, + "z": 2437.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)" + "comment": "aus Zeichnung: Separator_SP_3D (ID 0051, ZUORDNUNG 0002, ARTINR 200000077)" }, { "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, + "block": "Separator_SP", + "x": 35857.18, + "y": 25278.8, + "z": 1826.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)" + "comment": "aus Zeichnung: Separator_SP_3D (ID 0052, ZUORDNUNG 0003, ARTINR 200000077)" }, { "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, + "block": "Separator_SP", + "x": 42163.99, + "y": 4269.52, + "z": 2177.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)" + "comment": "aus Zeichnung: Separator_SP_3D (ID 0053, ZUORDNUNG 0004, ARTINR 200000077)" }, { "function": "insert", "block": "Scanner", - "x": 3166.57, - "y": 188414.66, - "z": 0.0, + "x": 3632.63, + "y": 24865.38, + "z": 1826.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)" + "comment": "aus Zeichnung: Scanner_3D (ID 0073, ZUORDNUNG 0003, ARTINR 829534306)" }, { "function": "insert", "block": "Scanner", - "x": 4477.8, - "y": 176855.58, - "z": 370.0, + "x": 4943.86, + "y": 13306.31, + "z": 2473.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)" + "comment": "aus Zeichnung: Scanner_3D (ID 0074, ZUORDNUNG 0005, ARTINR 829534306)" }, { "function": "insert", "block": "Scanner", - "x": 15096.6, - "y": 188414.66, - "z": 0.0, + "x": 15562.65, + "y": 24865.38, + "z": 1826.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)" + "comment": "aus Zeichnung: Scanner_3D (ID 0075, ZUORDNUNG 0003, ARTINR 829534306)" }, { "function": "insert", "block": "Scanner", - "x": 15377.81, - "y": 176855.63, - "z": 370.0, + "x": 15843.86, + "y": 13306.36, + "z": 2473.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)" + "comment": "aus Zeichnung: Scanner_3D (ID 0076, ZUORDNUNG 0002, ARTINR 829534306)" }, { "function": "insert", "block": "Scanner", - "x": 23686.22, - "y": 188414.66, - "z": 0.0, + "x": 24152.28, + "y": 24865.38, + "z": 1826.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)" + "comment": "aus Zeichnung: Scanner_3D (ID 0077, ZUORDNUNG 0003, ARTINR 829534306)" }, { "function": "insert", "block": "Scanner", - "x": 24177.81, - "y": 176855.68, - "z": 370.0, + "x": 24643.86, + "y": 13306.4, + "z": 2473.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)" + "comment": "aus Zeichnung: Scanner_3D (ID 0078, ZUORDNUNG 0022, ARTINR 829534306)" } ]