Merge Geruest-Feature mit 2D/3D-Umschaltung zusammengefuehrt

Konflikte in Gefaellestrecke.lsp und vf_standard.lsp aufgeloest - beide Features behalten. Dialog-Rueckgaben: dim vor den Geruest-Werten. Modus-1 (c:GEFAELLESTRECKE) und die Batch-Konverter (gf-/vf-konvertiere-ent) an die um Geruest-Parameter erweiterten Signaturen (gf-rebuild, gefaellestrecke-einfuegen, vf-block-erstellen) angepasst.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-23 14:28:29 +02:00
28 changed files with 894 additions and 383 deletions
+71 -23
View File
@@ -1311,7 +1311,9 @@
;; delta-l-gf bereits vor der Zusammenfassung berechnet
;; Block mit allen Attributen erstellen
;; Block mit allen Attributen erstellen. Geruest fuer Einzelmodul/
;; Geruestoption sind in diesem Linienzug-Ablauf (Modus 3, keine DCL-
;; Eingabe) nicht abfragbar - bleiben auf Schema-Default.
(gf-block-erstellen
"gruppe" as-seite gf-nummer
(caddr startpunkt)
@@ -1326,7 +1328,7 @@
bR90 bR60 bR30
startpunkt last-ent nach-aus-pt entry-hz
(caddr (nth first-idx segmente))
es-seite)
es-seite "0" "Schoenenberger Geruest")
(princ "\n\n=========================================")
(princ (ssg-text "gf-status-fertig"))
@@ -1425,9 +1427,11 @@
bogen-L90 bogen-L60 bogen-L30
bogen-R90 bogen-R60 bogen-R30
startpunkt last-ent nach-aus-pt entry-hz L-first-seg
es-seite /
es-seite geruest-einzelmodul geruest-typ /
gf-bname gf-ss ent gf-insert typ-str anzahl-gf
gf-winkel-str i gf-g10z gf-korr-dz gf-osmode-alt)
(if (null geruest-einzelmodul) (setq geruest-einzelmodul "0"))
(if (null geruest-typ) (setq geruest-typ (ssg-geruest-idx-to-typ (ssg-geruest-typ-to-idx nil))))
;; Beschriftung: Mitte der ersten Geraden, 400mm senkrecht versetzt
(gf-make-label gf-nummer hoehe-von hoehe-bis deltaH deltaL
L-gf-str winkel n-separator nach-aus-pt entry-hz L-first-seg)
@@ -1511,6 +1515,8 @@
(cons "GF_Bogen_R_30" (itoa bogen-R30))
(cons "ANZAHL_SEPARATOR" (itoa n-separator))
(cons "ANZAHL_SCANNER" (itoa n-scanner))
(cons "GERUEST_EINZELMODUL" geruest-einzelmodul)
(cons "GERUEST_TYP" geruest-typ)
)
)
;; Aufsteigende, eindeutige ID vergeben (wie beim Kreisel), falls verfuegbar.
@@ -1526,8 +1532,10 @@
;; deltaL-total: gesamte Horizontaldistanz (fuer DELTA_L-Attribut)
;; hz: Fahrtrichtung in Grad (0=Ost, 90=Nord, 180=West, 270=Sued)
;; geruest-einzelmodul/geruest-typ: an gf-block-erstellen durchgereicht (Attribute
;; GERUEST_EINZELMODUL/GERUEST_TYP, siehe *ssg-geruest-optionen* in ssg_core.lsp)
(defun gefaellestrecke-einfuegen (L_stau winkel startpunkt as-seite es-seite hz deltaL-total
as-winkel es-winkel /
as-winkel es-winkel geruest-einzelmodul geruest-typ /
as-block es-block endpunkt
gf-nummer last-ent rad-hz rad-v xu-incl
ein-hz rad-ein xu-ein
@@ -1627,7 +1635,7 @@
1 0
0 0 0 0 0 0
startpunkt last-ent nach-aus-pt (float hz) (float L_stau)
es-seite))
es-seite geruest-einzelmodul geruest-typ))
;; Edit-Metadaten (Fahrtrichtung, Gefaellewinkel, Element-Winkel) als XDATA
;; auf das GF_N-INSERT schreiben, damit GEFAELLESTRECKE_EDIT die Strecke
@@ -1657,15 +1665,18 @@
;; um die Angabe der Einfuegehoehe (Z).
;; prefill: Assoziationsliste zur Vorbelegung (fuer GEFAELLESTRECKE_EDIT) mit
;; Schluesseln "deltaL" "winkel" "hz" "as-seite" "es-seite" "einfuegehoehe"
;; "as-winkel" "es-winkel" - oder nil fuer Neuanlage (Modus 1) mit Defaults.
;; "as-winkel" "es-winkel" "geruest-einzelmodul" "geruest-typ" - oder nil
;; fuer Neuanlage (Modus 1) mit Defaults.
;; Rueckgabe: (deltaL winkel hz-winkel as-seite es-seite einfuegehoehe
;; as-winkel es-winkel)
;; as-winkel es-winkel geruest-einzelmodul geruest-typ)
;; oder nil bei Abbruch / fehlendem Dialog.
(defun gf-dialog-eingabe ( prefill hoehe-vorbelegung / dcl-pfad dat ergebnis
dlg-deltal dlg-hoehe dlg-winkel
dlg-richtung dlg-aus dlg-ein
dlg-aus-winkel dlg-ein-winkel dlg-dim
hz-winkel as-seite es-seite as-winkel es-winkel dim)
dlg-geruest-einzelmodul dlg-geruest-typ
hz-winkel as-seite es-seite as-winkel es-winkel dim
geruest-einzelmodul geruest-typ)
(setq dcl-pfad (strcat (getenv "DXFM_DCL") "/gefaellestrecke.dcl"))
(setq dat (load_dialog dcl-pfad))
(if (not (new_dialog "gefaellestrecke" dat))
@@ -1741,6 +1752,14 @@
(set_tile "ein_seite"
(if (and prefill (equal (cdr (assoc "es-seite" prefill)) "rechts")) "1" "0"))
(set_tile "geruest_einzelmodul"
(if (and prefill (equal (cdr (assoc "geruest-einzelmodul" prefill)) "1")) "1" "0"))
(start_list "geruest_typ")
(foreach opt *ssg-geruest-optionen* (add_list opt))
(end_list)
(set_tile "geruest_typ"
(itoa (ssg-geruest-typ-to-idx (if prefill (cdr (assoc "geruest-typ" prefill)) nil))))
;; Actions
(action_tile "accept"
(strcat
@@ -1753,6 +1772,8 @@
"(setq dlg-ein-winkel (get_tile \"ein_winkel\"))"
"(setq dlg-ein (get_tile \"ein_seite\"))"
"(setq dlg-dim (get_tile \"dimension\"))"
"(setq dlg-geruest-einzelmodul (get_tile \"geruest_einzelmodul\"))"
"(setq dlg-geruest-typ (get_tile \"geruest_typ\"))"
"(done_dialog 1)"
)
)
@@ -1779,6 +1800,8 @@
(setq as-winkel (if (= dlg-aus-winkel "1") "30" "90"))
(setq es-winkel (if (= dlg-ein-winkel "1") "30" "90"))
(setq dim (if (= dlg-dim "1") "2D" "3D"))
(setq geruest-einzelmodul dlg-geruest-einzelmodul)
(setq geruest-typ (ssg-geruest-idx-to-typ (atoi dlg-geruest-typ)))
(list
(atof dlg-deltal)
(atof dlg-winkel)
@@ -1788,7 +1811,9 @@
(atof dlg-hoehe)
as-winkel
es-winkel
dim)
dim
geruest-einzelmodul
geruest-typ)
)
(t nil)
)
@@ -1804,7 +1829,8 @@
;; wurde (Modus 1) - dann entfaellt die zusaetzliche Konsolen-Rueckfrage.
;; Modus 2 (reine Konsoleneingabe, kein Dialog) uebergibt nil/weglassen.
(defun gf-modus12-abschluss (deltaL winkel hz-winkel as-seite es-seite startpunkt
as-winkel es-winkel dialog-bestaetigt /
as-winkel es-winkel dialog-bestaetigt
geruest-einzelmodul geruest-typ /
rad sep-x L_stau antwort)
(if (null as-winkel) (setq as-winkel "90"))
(if (null es-winkel) (setq es-winkel "90"))
@@ -1842,7 +1868,8 @@
;; Bestaetigung - entfaellt, wenn bereits per Dialog-OK bestaetigt (Modus 1)
(setq antwort (if dialog-bestaetigt "1" (getstring (ssg-text "gf-prompt-einfuegen"))))
(if (not (= antwort "2"))
(gefaellestrecke-einfuegen L_stau (fix winkel) startpunkt as-seite es-seite hz-winkel deltaL as-winkel es-winkel)
(gefaellestrecke-einfuegen L_stau (fix winkel) startpunkt as-seite es-seite hz-winkel deltaL as-winkel es-winkel
geruest-einzelmodul geruest-typ)
(princ (ssg-text "gf-status-abgebrochen"))
)
)
@@ -1851,7 +1878,7 @@
;; setzen, L_stau berechnen und einfuegen - ohne Zusammenfassung/Rueckfrage.
;; Rueckgabe: (ename deltaH deltaL) von gefaellestrecke-einfuegen oder nil.
(defun gf-rebuild (deltaL winkel hz-winkel as-seite es-seite startpunkt
as-winkel es-winkel /
as-winkel es-winkel geruest-einzelmodul geruest-typ /
rad sep-x L_stau)
(if (null as-winkel) (setq as-winkel "90"))
(if (null es-winkel) (setq es-winkel "90"))
@@ -1867,7 +1894,8 @@
nil
)
(gefaellestrecke-einfuegen
L_stau (fix winkel) startpunkt as-seite es-seite hz-winkel deltaL as-winkel es-winkel)
L_stau (fix winkel) startpunkt as-seite es-seite hz-winkel deltaL as-winkel es-winkel
geruest-einzelmodul geruest-typ)
)
)
@@ -1912,7 +1940,7 @@
as-seite es-seite gf-as-winkel gf-es-winkel
line-points startpunkt endpunkt differenz
deltaX deltaY startpunkt-fuer-einfuegen hz-winkel
dlg-werte)
dlg-werte gf-dim gf-geruest-einzelmodul gf-geruest-typ)
(princ "\n=========================================")
(princ (ssg-text "gf-banner-titel"))
@@ -1995,9 +2023,12 @@
(setq antwort (getstring (ssg-text "prompt-wahl-1-2")))
(setq es-seite (if (= antwort "2") "rechts" "links"))
;; Gemeinsamer Abschluss (Masse, Laenge, Zusammenfassung, Einfuegen)
;; Gemeinsamer Abschluss (Masse, Laenge, Zusammenfassung, Einfuegen).
;; Geruest fuer Einzelmodul/Geruestoption sind in Modus 2 (reine
;; Konsoleneingabe, kein Dialog) nicht abfragbar - bleiben auf Default.
(gf-modus12-abschluss deltaL winkel hz-winkel as-seite es-seite
startpunkt-fuer-einfuegen gf-as-winkel gf-es-winkel)
startpunkt-fuer-einfuegen gf-as-winkel gf-es-winkel nil
"0" "Schoenenberger Geruest")
)
;; Modus 1: Manuelle Eingabe via DCL-Dialog
@@ -2020,7 +2051,10 @@
as-seite (nth 3 dlg-werte)
es-seite (nth 4 dlg-werte)
gf-as-winkel (nth 6 dlg-werte)
gf-es-winkel (nth 7 dlg-werte))
gf-es-winkel (nth 7 dlg-werte)
gf-dim (nth 8 dlg-werte)
gf-geruest-einzelmodul (nth 9 dlg-werte)
gf-geruest-typ (nth 10 dlg-werte))
;; Einfuegehoehe = Dialogwert (nth 5), der mit der gepickten Hoehe
;; vorbelegt wurde. So gewinnt die gepickte Hoehe standardmaessig,
;; bleibt aber im Dialog editierbar. Nur diese Z-Hoehe zaehlt (X/Y
@@ -2034,9 +2068,13 @@
(setq deltaL (ssg-cfg-or "gefaelle" "default_delta_l" 5000.0)))
(if (or (null winkel) (<= winkel 0))
(setq winkel (ssg-cfg-or "gefaelle" "default_winkel" 3.0)))
;; Gewaehlte Dimension (2D/3D) fuer den Bau erzwingen (Override), danach zurueck.
(setq *ssg-ils-dim* gf-dim)
;; Dialog-OK wurde bereits bestaetigt - keine zusaetzliche Rueckfrage
(gf-modus12-abschluss deltaL winkel hz-winkel as-seite es-seite
startpunkt-fuer-einfuegen gf-as-winkel gf-es-winkel T)
startpunkt-fuer-einfuegen gf-as-winkel gf-es-winkel T
gf-geruest-einzelmodul gf-geruest-typ)
(setq *ssg-ils-dim* nil)
)
)
)
@@ -2101,8 +2139,11 @@
(caddr gf-start)))
;; VF bauen; Rueckgabe (vf-insert vf-endpunkt), vf-endpunkt = tatsaechl.
;; ES-KS_AUS als Weltpunkt (aus vfs-es-teil/insert-block-by-ks).
;; Geruest fuer Einzelmodul/Geruestoption sind fuer diesen automatisch
;; nebenan gebauten VF nicht abfragbar - bleiben auf Schema-Default.
(setq vf-erg (vfs-standard-dialog-berechnen-einfuegen
(vf-next-number) deltaL deltaH "Auf" vf-start hz-vf vf-seite nil))
(vf-next-number) deltaL deltaH "Auf" vf-start hz-vf vf-seite nil
"0" "Schoenenberger Geruest"))
(setq vf-insert (car vf-erg) vf-endpunkt (cadr vf-erg))
;; Selbstkorrektur: fertigen VF-Block so verschieben, dass sein
;; tatsaechliches ES-KS_AUS exakt auf ziel-es faellt (analog GF_n-Move;
@@ -2128,7 +2169,7 @@
;; Startpunkt neu auf. Rueckgabe: T bei Erfolg, nil wenn nicht nachbaubar.
(defun gf-konvertiere-ent (ent ziel-dim / ed bname attribs xd hz winkel
as-winkel es-winkel z-start deltaL startpunkt
as-seite es-seite)
as-seite es-seite geruest-einzelmodul geruest-typ)
(setq ed (entget ent) bname (cdr (assoc 2 ed)))
(setq attribs (ssg-attrib-read ent))
(setq xd (gf-xdata-lesen ent))
@@ -2145,10 +2186,14 @@
deltaL (atof (nth 5 xd)))
(setq as-seite (cond ((cdr (assoc "SEITE_AS" attribs))) ("links")))
(setq es-seite (cond ((cdr (assoc "SEITE_ES" attribs))) ("links")))
;; bestehende Geruest-Einstellungen erhalten
(setq geruest-einzelmodul (cond ((cdr (assoc "GERUEST_EINZELMODUL" attribs))) ("0")))
(setq geruest-typ (cdr (assoc "GERUEST_TYP" attribs)))
(setq *ssg-ils-dim* ziel-dim)
(entdel ent)
(gf-rebuild deltaL winkel hz as-seite es-seite
(list (car startpunkt) (cadr startpunkt) z-start) as-winkel es-winkel)
(list (car startpunkt) (cadr startpunkt) z-start) as-winkel es-winkel
geruest-einzelmodul geruest-typ)
(setq *ssg-ils-dim* nil)
T)
nil))
@@ -2224,7 +2269,9 @@
(cons "as-winkel" as-winkel)
(cons "es-winkel" es-winkel)
;; Dimension aus XDATA erkennen (Default 3D, falls Alt-Block ohne Eintrag)
(cons "dim" (cond ((ssg-dim-xdata-lesen ent)) ("3D")))))
(cons "dim" (cond ((ssg-dim-xdata-lesen ent)) ("3D")))
(cons "geruest-einzelmodul" (cond ((cdr (assoc "GERUEST_EINZELMODUL" attribs))) ("0")))
(cons "geruest-typ" (cdr (assoc "GERUEST_TYP" attribs)))))
;; AS-Seite + untere Hoehe fuer den optionalen parallelen VF-Bau
(setq as-seite (cond ((cdr (assoc "SEITE_AS" attribs))) ("links")))
@@ -2253,7 +2300,8 @@
(nth 0 dlg-werte) (nth 1 dlg-werte) (nth 2 dlg-werte)
(nth 3 dlg-werte) (nth 4 dlg-werte)
(list (car startpunkt) (cadr startpunkt) (nth 5 dlg-werte))
(nth 6 dlg-werte) (nth 7 dlg-werte))
(nth 6 dlg-werte) (nth 7 dlg-werte)
(nth 9 dlg-werte) (nth 10 dlg-werte))
(setq *ssg-ils-dim* nil)
(princ (ssg-textf "gf-edit-neu-aufgebaut" (list bname)))
)
+22 -3
View File
@@ -87,6 +87,7 @@
("ANZAHL_SCANNER" "0")
("ANZAHL_RAMPEN" "0")
("GERUEST_EINZELMODUL" "0")
("GERUEST_TYP" "Schoenenberger Geruest")
("DREHRICHTUNG" "UZS")
("DREHUNG" "0")
("NUMMER" "0"))
@@ -102,6 +103,8 @@
("DREHUNG" "0")
("NUMMER" "0")
("HOEHE" "0")
("GERUEST_EINZELMODUL" "0")
("GERUEST_TYP" "Schoenenberger Geruest")
("ID" ""))
)
@@ -869,6 +872,7 @@
dcl-pfad dat ergebnis
dlg-name dlg-abstand dlg-hoehe dlg-ausrichtung
dlg-drehrichtung dlg-kreiselart dlg-geruest-einzelmodul
dlg-geruest-typ
newAbstand newRotation ausrichtLabels)
;; Implied Selection VOR ssg-start pruefen (ssg-start hebt Selektion auf)
@@ -966,6 +970,11 @@
(set_tile "geruest_einzelmodul"
(if (equal (cdr (assoc "GERUEST_EINZELMODUL" attribs)) "1") "1" "0"))
(start_list "geruest_typ")
(foreach opt *ssg-geruest-optionen* (add_list opt))
(end_list)
(set_tile "geruest_typ" (itoa (ssg-geruest-typ-to-idx (cdr (assoc "GERUEST_TYP" attribs)))))
;; Actions
(action_tile "accept"
(strcat
@@ -976,6 +985,7 @@
"(setq dlg-drehrichtung (get_tile \"drehrichtung\"))"
"(setq dlg-kreiselart (get_tile \"kreiselart\"))"
"(setq dlg-geruest-einzelmodul (get_tile \"geruest_einzelmodul\"))"
"(setq dlg-geruest-typ (get_tile \"geruest_typ\"))"
"(done_dialog 1)"
)
)
@@ -1004,6 +1014,8 @@
(assoc "DREHRICHTUNG" attribs) attribs))
(setq attribs (subst (cons "GERUEST_EINZELMODUL" dlg-geruest-einzelmodul)
(assoc "GERUEST_EINZELMODUL" attribs) attribs))
(setq attribs (subst (cons "GERUEST_TYP" (ssg-geruest-idx-to-typ (atoi dlg-geruest-typ)))
(assoc "GERUEST_TYP" attribs) attribs))
;; Alten Block loeschen
(command "_.ERASE" ent "")
@@ -1051,7 +1063,8 @@
;; 4. Hoehe aus Z-Koordinate oder manuell
;; --------------------------------------------
(defun c:ILS_Eckrad ( / ptTangent ptDir dx dy dist ux uy radius
centerPt rotation hoehe)
centerPt rotation hoehe
geruest-einzelmodul geruest-typ)
(dbgf "c:ILS_Eckrad")
;; 1. Beruehrpunkt (Tangentenpunkt)
@@ -1106,8 +1119,14 @@
)
(dbg 'hoehe)
;; 5. Einfuegen (centerPt ist der Kreismittelpunkt)
(ils-eckrad-insert (list (car centerPt) (cadr centerPt) hoehe) rotation nil)
;; 5. Geruest fuer Einzelmodul + Geruestoption abfragen
(setq geruest-einzelmodul (if (ssg-ques (ssg-text "kreisel-eckrad-geruest-frage") nil) "0" "1"))
(setq geruest-typ (ssg-ask-geruest-typ))
;; 6. Einfuegen (centerPt ist der Kreismittelpunkt)
(ils-eckrad-insert (list (car centerPt) (cadr centerPt) hoehe) rotation
(list (cons "GERUEST_EINZELMODUL" geruest-einzelmodul)
(cons "GERUEST_TYP" geruest-typ)))
(dbgreturn nil)
)
+85 -18
View File
@@ -13,25 +13,39 @@
;; (ssg-start "Titel" '(("OSMODE") ("ORTHOMODE")))
;; ... Makrocode ...
;; (ssg-end)
;;
;; Nestbar ueber *ssg-start-stack*: jedes ssg-start legt einen eigenen
;; Frame (vorheriger *error*-Handler + Variablenwerte) oben auf den
;; Stack, ssg-end nimmt genau diesen Frame wieder herunter. Noetig, weil
;; z.B. ein Test-Wrapper (ssg-start "TEST_KREISEL" ...) selbst wieder
;; Makros aufruft, die ihrerseits ssg-start/ssg-end nutzen - mit einer
;; einzelnen globalen Variable statt eines Stacks wuerde der innere
;; Aufruf den *error*-Handler und die CLAYER/CMDECHO/...-Werte des
;; aeusseren Aufrufs ueberschreiben. Ergebnis waere ein *error* wird
;; nach dem aeusseren ssg-end dauerhaft an ssg-errhan haengen bleiben
;; (statt zum urspruenglichen Default-Handler zurueckzukehren) und bei
;; jedem folgenden Fehler faelschlich veraltete CLAYER/CECOLOR-Werte
;; ueber "_LAYER"/"_undo" auf die Kommandozeile schreiben.
;; ------------------------------------------------------------
(defun ssg-start (titel zusatz-vars / xlen xpos xvar)
(if (not (boundp '*ssg-start-stack*)) (setq *ssg-start-stack* nil))
(defun ssg-start (titel zusatz-vars / cavar xlen xpos xvar)
;; titel - Anzeigename des Makros
;; zusatz-vars - Liste zusaetzlicher Variablen z.B. '(("OSMODE")("ORTHOMODE"))
;; Immer CLAYER und CMDECHO werden automatisch gesichert.
(setq _ssg-olderr *error*
*error* (function ssg-errhan)
_ssg-cavar (append '(("CLAYER") ("CMDECHO")) zusatz-vars)
xlen (length _ssg-cavar)
xpos 0
(setq cavar (append '(("CLAYER") ("CMDECHO")) zusatz-vars)
xlen (length cavar)
xpos 0
)
(repeat xlen
(setq xvar (car (nth xpos _ssg-cavar))
_ssg-cavar (subst (cons xvar (getvar xvar))
(nth xpos _ssg-cavar) _ssg-cavar)
xpos (1+ xpos)
(setq xvar (car (nth xpos cavar))
cavar (subst (cons xvar (getvar xvar)) (nth xpos cavar) cavar)
xpos (1+ xpos)
)
)
(setq *ssg-start-stack* (cons (cons *error* cavar) *ssg-start-stack*))
(setq *error* (function ssg-errhan))
(setvar "CMDECHO" 0)
(command "_undo" "_G")
(graphscr)
@@ -39,26 +53,30 @@
(princ)
)
(defun ssg-end (/ xpos xlen xvar)
(if _ssg-cavar
(defun ssg-end (/ frame cavar xpos xlen xvar)
(if *ssg-start-stack*
(progn
(setq frame (car *ssg-start-stack*)
*ssg-start-stack* (cdr *ssg-start-stack*)
cavar (cdr frame)
)
(command)
(command "_undo" "_E")
(setq xpos 1
xlen (length _ssg-cavar)
xlen (length cavar)
)
(if (/= (getvar "CLAYER") (caar _ssg-cavar))
(command "_LAYER" "_SE" (cdar _ssg-cavar) "")
(if (/= (getvar "CLAYER") (caar cavar))
(command "_LAYER" "_SE" (cdar cavar) "")
)
(repeat (1- xlen)
(setq xvar (nth xpos _ssg-cavar)
(setq xvar (nth xpos cavar)
xpos (1+ xpos)
)
(setvar (car xvar) (cdr xvar))
)
(setq *error* (car frame))
)
)
(if _ssg-olderr (setq *error* _ssg-olderr))
(princ)
)
@@ -602,7 +620,56 @@
;; (einsegmentige Gefaellestrecke: 1; Streckengruppe: gezaehlt).
(setq *strecke-attr-hinten*
'(("ANZAHL_SEPARATOR" "1")
("ANZAHL_SCANNER" "0")))
("ANZAHL_SCANNER" "0")
("GERUEST_EINZELMODUL" "0")
("GERUEST_TYP" "Schoenenberger Geruest")))
;; ============================================================
;; GERUESTOPTION - gemeinsame Combobox-Werte fuer Kreisel, Eckrad,
;; VarioFoerderer und Gefaellestrecke (Attribut GERUEST_TYP).
;; Reihenfolge = Reihenfolge in der Dialog-Combobox. Index 2
;; ("Schoenenberger Geruest") ist der Default.
;; ============================================================
(setq *ssg-geruest-optionen*
'("IPE-Geruest abgestuft"
"Obergeruest oben"
"Schoenenberger Geruest"
"nur Doppelrohrtraeger")
)
;; Geruest-Typ (String) -> Combobox-Index. Unbekannter/leerer Wert -> Default (2).
(defun ssg-geruest-typ-to-idx (typ / idx i gefunden)
(setq idx 2 i 0 gefunden nil)
(foreach opt *ssg-geruest-optionen*
(if (and (not gefunden) (equal typ opt))
(progn (setq idx i) (setq gefunden T))
)
(setq i (1+ i))
)
idx
)
;; Combobox-Index -> Geruest-Typ (String).
(defun ssg-geruest-idx-to-typ (idx)
(nth idx *ssg-geruest-optionen*)
)
;; Geruestoption per Kommandozeilen-Menue abfragen (fuer Module ohne DCL-Dialog,
;; z.B. ILS_Eckrad). Rueckgabe: Geruest-Typ-String aus *ssg-geruest-optionen*.
(defun ssg-ask-geruest-typ ( / i opt antwort idx)
(princ (ssg-text "geruest-typ-header"))
(setq i 1)
(foreach opt *ssg-geruest-optionen*
(princ (ssg-textf "geruest-typ-opt" (list i opt)))
(setq i (1+ i))
)
(setq antwort (getint (ssg-textf "geruest-typ-prompt" (list (itoa (1+ (ssg-geruest-typ-to-idx nil)))))))
(if (or (null antwort) (< antwort 1) (> antwort (length *ssg-geruest-optionen*)))
(setq idx (ssg-geruest-typ-to-idx nil))
(setq idx (1- antwort))
)
(ssg-geruest-idx-to-typ idx)
)
;; Geordnete ATTDEF-Definitionsliste fuer einen Strecken-Block-Typ.
;; typ "Gefaellestrecke" -> Vorderteil + Hinterteil (reduziert)
+10 -1
View File
@@ -1062,8 +1062,11 @@
(defun vf-block-erstellen (anlage-typ seite vf-nummer n-scanner
hoehe-von hoehe-bis deltaH deltaL L_VF L_GF1 L_GF2
richtung best-winkel startpunkt lastEnt hz
geruest-einzelmodul geruest-typ
/ vf-bname vf-ss vf-e vf-insert montagehoehe-m attdef-ypos L_GF_m-str)
(if (null hz) (setq hz 0.0))
(if (null geruest-einzelmodul) (setq geruest-einzelmodul "0"))
(if (null geruest-typ) (setq geruest-typ (ssg-geruest-idx-to-typ (ssg-geruest-typ-to-idx nil))))
;; Beschriftungstext erzeugen
(vf-make-label vf-nummer hoehe-von hoehe-bis deltaH deltaL L_VF L_GF1 L_GF2
richtung best-winkel 2 n-scanner startpunkt hz)
@@ -1134,6 +1137,8 @@
(cons "VF_WINKEL" (itoa best-winkel))
(cons "ANZAHL_SEPARATOR" "2")
(cons "ANZAHL_SCANNER" (itoa n-scanner))
(cons "GERUEST_EINZELMODUL" geruest-einzelmodul)
(cons "GERUEST_TYP" geruest-typ)
)
)
;; Typ-spezifische Bogen-Zaehler (Etage: 2x Gefaellebogen je Seite)
@@ -1439,10 +1444,14 @@
(list deltaL deltaH richtung best-winkel L_GF1 L_GF2 L_VF startpunkt seite hz))
;; Gemeinsame VF_*-Block-Erstellung
;; Geruest fuer Einzelmodul/Geruestoption sind in diesem interaktiven
;; Konsolen-Ablauf (Etage/Linienzug) nicht abfragbar - bleiben auf
;; Schema-Default (analog Kreisel: nur ueber Dialog editierbar).
(setq vf-insert
(vf-block-erstellen anlage-typ seite vf-nummer n-scanner
hoehe-von hoehe-bis deltaH deltaL L_VF L_GF1 L_GF2
richtung best-winkel startpunkt lastEnt hz))
richtung best-winkel startpunkt lastEnt hz
"0" "Schoenenberger Geruest"))
;; Standard-Bloecke aus dem interaktiven Konsolen-Ablauf ebenfalls mit der
;; SSG_VF_EDIT-XDATA markieren - sie sind (wie die Dialog-Variante) aus
+45 -16
View File
@@ -709,15 +709,18 @@
;; ============================================================
;; Basis-Eingabe (Dialog 1): deltaL, deltaH, Richtung, Einfuegehoehe,
;; Fahrtrichtung, Seite.
;; Fahrtrichtung, Seite, Geruest fuer Einzelmodul, Geruestoption.
;; prefill: Assoziationsliste zur Vorbelegung (fuer VARIOFOERDERER_EDIT) mit
;; Schluesseln "deltaL" "deltaH" "richtung" "einfuegehoehe" "hz" "seite"
;; - oder nil fuer Neuanlage mit Defaults.
;; Rueckgabe: (deltaL deltaH richtung einfuegehoehe hz seite) oder nil bei Abbruch.
;; "geruest-einzelmodul" "geruest-typ" - oder nil fuer Neuanlage mit Defaults.
;; Rueckgabe: (deltaL deltaH richtung einfuegehoehe hz seite
;; geruest-einzelmodul geruest-typ) oder nil bei Abbruch.
(defun vfs-dialog-eingabe-basis (prefill / dcl-pfad dat ergebnis
dlg-deltal dlg-deltah dlg-richtung dlg-hoehe
dlg-fahrtrichtung dlg-seite dlg-dimension
deltaL deltaH richtung hz seite z-start dim)
dlg-geruest-einzelmodul dlg-geruest-typ
deltaL deltaH richtung hz seite z-start dim
geruest-einzelmodul geruest-typ)
(setq dcl-pfad (strcat (getenv "DXFM_DCL") "/variofoerderer.dcl"))
(setq dat (load_dialog dcl-pfad))
(if (not (new_dialog "variofoerderer_basis" dat))
@@ -771,6 +774,13 @@
(end_list)
(set_tile "dimension"
(if (equal (cond ((cdr (assoc "dim" prefill))) ((ssg-ils-dim-aktuell))) "2D") "1" "0"))
(set_tile "geruest_einzelmodul"
(if (and prefill (equal (cdr (assoc "geruest-einzelmodul" prefill)) "1")) "1" "0"))
(start_list "geruest_typ")
(foreach opt *ssg-geruest-optionen* (add_list opt))
(end_list)
(set_tile "geruest_typ"
(itoa (ssg-geruest-typ-to-idx (if prefill (cdr (assoc "geruest-typ" prefill)) nil))))
;; Actions
(action_tile "accept"
@@ -782,6 +792,8 @@
"(setq dlg-fahrtrichtung (get_tile \"fahrtrichtung\"))"
"(setq dlg-seite (get_tile \"seite\"))"
"(setq dlg-dimension (get_tile \"dimension\"))"
"(setq dlg-geruest-einzelmodul (get_tile \"geruest_einzelmodul\"))"
"(setq dlg-geruest-typ (get_tile \"geruest_typ\"))"
"(done_dialog 1)"
)
)
@@ -803,7 +815,9 @@
(t 0.0)))
(setq seite (if (= dlg-seite "1") "links" "rechts"))
(setq dim (if (= dlg-dimension "1") "2D" "3D"))
(list deltaL deltaH richtung z-start hz seite dim)
(setq geruest-einzelmodul dlg-geruest-einzelmodul)
(setq geruest-typ (ssg-geruest-idx-to-typ (atoi dlg-geruest-typ)))
(list deltaL deltaH richtung z-start hz seite dim geruest-einzelmodul geruest-typ)
)
nil
)
@@ -955,7 +969,7 @@
;; winkel-prefill: Vorbelegung fuer vfs-dialog-winkel-verteilung oder nil.
;; ============================================================
(defun vfs-standard-dialog-berechnen-einfuegen (vf-nummer deltaL deltaH richtung startpunkt hz seite
winkel-prefill /
winkel-prefill geruest-einzelmodul geruest-typ /
ergebnis ergebnis-liste gueltige-winkel horizontal-info
winkelwahl best-winkel L_GF L_VF L_GF1 L_GF2 verteilung-modus
n-scanner hoehe-von hoehe-bis lastEnt vf-insert vf-endpunkt staustrecke-basis)
@@ -1014,7 +1028,8 @@
(setq vf-insert
(vf-block-erstellen "standard" seite vf-nummer n-scanner
hoehe-von hoehe-bis deltaH deltaL L_VF L_GF1 L_GF2
richtung best-winkel startpunkt lastEnt hz))
richtung best-winkel startpunkt lastEnt hz
geruest-einzelmodul geruest-typ))
(if vf-insert (vfs-xdata-schreiben vf-insert hz))
(princ "\n=========================================")
)
@@ -1029,7 +1044,8 @@
;; Neuanlage (Menue/Konsole -> Dialog): Startpunkt (X/Y) picken, Basis-Dialog,
;; dann gemeinsame Berechnung/Winkel-Dialog/Einfuegung.
(defun vfs-standard-dialog-ablauf (vf-nummer / eingabe deltaL deltaH richtung
z-start hz seite startpunkt startpunkt-xy dim)
z-start hz seite startpunkt startpunkt-xy dim
geruest-einzelmodul geruest-typ)
(setq startpunkt-xy (getpoint (ssg-text "vfc-prompt-startpunkt-aus")))
(if (null startpunkt-xy) (setq startpunkt-xy '(0 0 0)))
@@ -1043,11 +1059,14 @@
z-start (nth 3 eingabe)
hz (nth 4 eingabe)
seite (nth 5 eingabe)
dim (nth 6 eingabe))
dim (nth 6 eingabe)
geruest-einzelmodul (nth 7 eingabe)
geruest-typ (nth 8 eingabe))
(setq startpunkt (list (car startpunkt-xy) (cadr startpunkt-xy) z-start))
;; Gewaehlte Dimension (2D/3D) fuer den Bau erzwingen (Override), danach zurueck.
(setq *ssg-ils-dim* dim)
(vfs-standard-dialog-berechnen-einfuegen vf-nummer deltaL deltaH richtung startpunkt hz seite nil)
(vfs-standard-dialog-berechnen-einfuegen vf-nummer deltaL deltaH richtung startpunkt hz seite nil
geruest-einzelmodul geruest-typ)
(setq *ssg-ils-dim* nil)
)
)
@@ -1059,7 +1078,8 @@
;; per Override und baut am selben Startpunkt neu auf. Rueckgabe: T/nil.
(defun vf-konvertiere-ent (ent ziel-dim / ed bname xd attribs startpunkt hz
deltaL deltaH richtung seite best-winkel L_GF_m-teile
L_GF1 L_GF2 L_VF hoehe-von hoehe-bis lastEnt vf-insert vf-nummer)
L_GF1 L_GF2 L_VF hoehe-von hoehe-bis lastEnt vf-insert vf-nummer
geruest-einzelmodul geruest-typ)
(setq ed (entget ent) bname (cdr (assoc 2 ed)))
(setq xd (vfs-xdata-lesen ent))
(if (and (wcmatch bname "VF_*") xd (= (car xd) "standard"))
@@ -1076,6 +1096,9 @@
(setq L_GF1 (* 1000.0 (atof (car L_GF_m-teile))))
(setq L_GF2 (* 1000.0 (atof (cadr L_GF_m-teile))))
(setq L_VF (* 1000.0 (atof (cond ((cdr (assoc "L_VF_m" attribs))) ("0.0")))))
;; bestehende Geruest-Einstellungen erhalten
(setq geruest-einzelmodul (cond ((cdr (assoc "GERUEST_EINZELMODUL" attribs))) ("0")))
(setq geruest-typ (cdr (assoc "GERUEST_TYP" attribs)))
(setq hoehe-von (caddr startpunkt))
(setq hoehe-bis (cond ((= richtung "Auf") (+ hoehe-von deltaH))
((= richtung "Ab") (- hoehe-von deltaH))
@@ -1088,7 +1111,8 @@
(setq vf-insert
(vf-block-erstellen "standard" seite vf-nummer 0
hoehe-von hoehe-bis deltaH deltaL L_VF L_GF1 L_GF2
richtung best-winkel startpunkt lastEnt hz))
richtung best-winkel startpunkt lastEnt hz
geruest-einzelmodul geruest-typ))
(if vf-insert (vfs-xdata-schreiben vf-insert hz))
(setq *ssg-ils-dim* nil)
(if vf-insert T nil))
@@ -1108,7 +1132,8 @@
(defun c:VARIOFOERDERER_EDIT ( / ss ent ed bname startpunkt attribs xd
deltaL deltaH richtung z-start hz seite dim
eingabe vf-nummer best-winkel-attr L_GF_m-teile
prefill-basis prefill-winkel)
prefill-basis prefill-winkel
geruest-einzelmodul geruest-typ)
;; Implied Selection VOR ssg-start pruefen (ssg-start hebt Selektion auf)
(setq ss (ssget "I"))
(if (and ss (= (sslength ss) 1)
@@ -1149,7 +1174,9 @@
(list (cons "deltaL" deltaL) (cons "deltaH" deltaH) (cons "richtung" richtung)
(cons "einfuegehoehe" z-start) (cons "hz" hz) (cons "seite" seite)
;; Dimension aus XDATA erkennen (Default 3D, falls Alt-Block ohne Eintrag)
(cons "dim" (cond ((ssg-dim-xdata-lesen ent)) ("3D")))))
(cons "dim" (cond ((ssg-dim-xdata-lesen ent)) ("3D")))
(cons "geruest-einzelmodul" (cond ((cdr (assoc "GERUEST_EINZELMODUL" attribs))) ("0")))
(cons "geruest-typ" (cdr (assoc "GERUEST_TYP" attribs)))))
(setq eingabe (vfs-dialog-eingabe-basis prefill-basis))
(if (null eingabe)
@@ -1161,7 +1188,9 @@
z-start (nth 3 eingabe)
hz (nth 4 eingabe)
seite (nth 5 eingabe)
dim (nth 6 eingabe))
dim (nth 6 eingabe)
geruest-einzelmodul (nth 7 eingabe)
geruest-typ (nth 8 eingabe))
(setq startpunkt (list (car startpunkt) (cadr startpunkt) z-start))
;; Vorbelegung Winkel/Verteilung: bestehenden Winkel vorschlagen, L_GF-
@@ -1180,7 +1209,7 @@
(entdel ent)
(setq vf-nummer (vf-next-number))
(vfs-standard-dialog-berechnen-einfuegen vf-nummer deltaL deltaH richtung
startpunkt hz seite prefill-winkel)
startpunkt hz seite prefill-winkel geruest-einzelmodul geruest-typ)
(setq *ssg-ils-dim* nil)
(princ (ssg-textf "vfs-edit-neu-aufgebaut" (list bname)))
)
+34 -6
View File
@@ -31,9 +31,22 @@ pattern_ks_subblocks= KS_EIN, KS_AUS, K1, K2, K3, K4
[Planquadrate]
section=Planquadrate_AN
# x_origin/y_origin (in m, DXF-Koordinate der Planquadrat-Ecke A/1 bzw. 1/1):
# Der Zeichnungsnullpunkt (0,0) liegt in der Regel NICHT in der Gebaeudeecke -
# Bauteile mit negativer x/y-Koordinate wuerden ohne Offset einen Planquadrat-
# Index <= 0 ergeben und damit ein leeres Label (z.B. "/" oder "A/") liefern.
# Leer lassen/weglassen = automatisch: der Ursprung wird bei jedem Export neu
# auf das jeweils am weitesten links (x_origin) bzw. am weitesten unten
# (y_origin) liegende Element der aktuellen Zeichnung gesetzt, damit gilt
# immer Index 1 = dieses Element. Nur explizit setzen, wenn ein fester
# Bezug zur realen Gebaeudeecke gebraucht wird (z.B. Vergleich ueber
# mehrere Exportlaeufe/Zeichnungen hinweg).
x_origin=
y_origin=
# hier kann man im csv Export aus den Koordinaten der Bauteile die Planquadrate berechnen lassen, in denen sie liegen
# Zählung ist numerisch oder Alphabetisch möglich, Schrittweite in m (z.B. 2m pro Spalte, 4m pro Zeile)
# liegt man im ersten Quadrat, ist diese A/1, oder 1/1 oder 1/A, je nach Formatierung. Die Zählung beginnt immer bei 1
# liegt man im ersten Quadrat, ist diese A/1, oder 1/1 oder 1/A, je nach Formatierung. Die Zählung beginnt immer bei 1
[Planquadrate_NA]
# z.B. 1/A
x_step=2
@@ -48,7 +61,7 @@ x_step=2
x_description=alphabetisch # Buchstaben, von links nach rechts, 2m pro Spalte
y_step=2
y_description=alphabetisch # Zahlen von unten nach oben, 2m pro Zeile
format= {x}/{y}
format= {x}/{y}
[Planquadrate_NN]
# z.B. 2/5
@@ -61,7 +74,22 @@ format= {x}/{y}
[Nachbarschaft]
# Toleranz fuer die Nachbarschaftserkennung beim CSV-Export (Spalte "Nachbarn").
# Die Bounding-Box jedes Elements wird um die Haelfte dieses Werts nach allen
# Seiten erweitert, bevor per STRtree (shapely) auf Ueberschneidung mit anderen
# Elementen geprueft wird - zwei Elemente mit einem Abstand <= toleranz_mm
# (z.B. zwei Kreisel) gelten dann ebenfalls als benachbart. Wert in mm.
toleranz_mm=200
# Seiten erweitert, bevor auf Ueberschneidung mit anderen Elementen geprueft
# wird - zwei Elemente mit einem Abstand <= toleranz_mm (z.B. zwei Kreisel)
# gelten dann ebenfalls als benachbart. Wert in mm. Siehe lib/export_neighbors.py.
toleranz_mm=200
# Rastergroesse (mm) fuer die Omniflo-Nachbarschaftspruefung (Bogen/Weiche/
# Gerade gegen Bogen/Weiche/Gerade). Omniflo-Elemente werden vor dem
# Ueberschneidungstest nach x/y-Koordinate in Quadranten dieser Groesse
# eingeteilt, geprueft wird dann nur innerhalb derselben und der 8
# angrenzenden Zellen (statt jedes Element gegen jedes). Sollte groesser
# als die ueblichen Omniflo-Bauteile sein (AP110-Geraden ca. 2000mm).
omniflo_zellgroesse_mm=3000
[Boundingbox]
# Mindesthoehe (Z-Ausdehnung) der von export.lsp (csv:get-bbox, per
# vla-getboundingbox) ermittelten Bounding-Box. Flache 2D-Bloecke (Draufsicht)
# haben oft dz=0 - wird auf diesen Wert angehoben. Wert in mm. Default 1, falls
# nicht gesetzt.
bb_minimum_height_mm=1
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+14
View File
@@ -90,6 +90,20 @@ gefaellestrecke : dialog {
}
}
: boxed_column {
label = "Geruest";
: toggle {
key = "geruest_einzelmodul";
label = "Geruest fuer Einzelmodul";
}
: popup_list {
key = "geruest_typ";
label = "Geruestoption:";
width = 30;
}
}
}
ok_cancel;
+6
View File
@@ -52,6 +52,12 @@ kreisel_edit : dialog {
label = "Geruest fuer Einzelmodul";
}
: popup_list {
key = "geruest_typ";
label = "Geruestoption:";
width = 30;
}
}
ok_cancel;
+14
View File
@@ -66,6 +66,20 @@ variofoerderer_basis : dialog {
}
}
: boxed_column {
label = "Geruest";
: toggle {
key = "geruest_einzelmodul";
label = "Geruest fuer Einzelmodul";
}
: popup_list {
key = "geruest_typ";
label = "Geruestoption:";
width = 30;
}
}
}
ok_cancel;
+4
View File
@@ -524,6 +524,10 @@
"gf-seite-rechts": "\n 2 - Rechts",
"prompt-wahl-1-2": "\nIhre Wahl (1/2) [1]: ",
"prompt-wahl-1-2-3": "\nIhre Wahl (1/2/3) [1]: ",
"geruest-typ-header": "\n\nGeruestoption waehlen:",
"geruest-typ-opt": "\n %1 - %2",
"geruest-typ-prompt": "\nGeruestoption (1-4) [%1]: ",
"kreisel-eckrad-geruest-frage": "Geruest fuer Einzelmodul?",
"gf-lade-block": "\n Lade Block: %1 ...",
"gf-status-ok": " OK",
"gf-warnung-kette-unterbrochen": "\n WARNUNG: Kette unterbrochen!",
+4
View File
@@ -524,6 +524,10 @@
"gf-seite-rechts": "\n 2 - Right",
"prompt-wahl-1-2": "\nYour choice (1/2) [1]: ",
"prompt-wahl-1-2-3": "\nYour choice (1/2/3) [1]: ",
"geruest-typ-header": "\n\nSelect scaffold option:",
"geruest-typ-opt": "\n %1 - %2",
"geruest-typ-prompt": "\nScaffold option (1-4) [%1]: ",
"kreisel-eckrad-geruest-frage": "Scaffold for single module?",
"gf-lade-block": "\n Loading block: %1 ...",
"gf-status-ok": " OK",
"gf-warnung-kette-unterbrochen": "\n WARNING: chain interrupted!",
+46 -2
View File
@@ -20,6 +20,7 @@ inhaltlich Teilmengen der groben Lisp-Kategorien sind.
import configparser
import fnmatch
import functools
import os
@@ -32,6 +33,25 @@ def cfg_path_from_env(default_dir=None):
return os.path.join(base, "cfg", "export.cfg")
@functools.lru_cache(maxsize=None)
def load_export_cfg(cfg_path):
"""Liest und parst export.cfg genau einmal je Pfad (Prozess-Cache).
Gemeinsam genutzt von export_blockpatterns/export_neighbors/
export_planquadrat, damit export.cfg pro Exportlauf nur einmal von der
Platte gelesen/geparst wird statt bei jedem der bisher unabhaengigen
load_*-Aufrufe erneut. inline_comment_prefixes=("#",) ist noetig, da
export.cfg Werte wie "numerisch # zahlen, von links nach rechts" mit
Inline-Kommentaren nutzt (siehe [Planquadrate_*]-Sektionen).
cfg_path muss bereits aufgeloest sein (siehe cfg_path_from_env) - der
Cache ist sonst nicht treffsicher (ein "None"-Schluessel wuerde nie den
tatsaechlichen Pfad abbilden).
"""
parser = configparser.ConfigParser(inline_comment_prefixes=("#",))
parser.read(cfg_path, encoding="utf-8")
return parser
def load_patterns(cfg_path=None):
"""Liest [blockpattern] aus export.cfg.
@@ -40,8 +60,7 @@ def load_patterns(cfg_path=None):
"""
if cfg_path is None:
cfg_path = cfg_path_from_env()
parser = configparser.ConfigParser()
parser.read(cfg_path, encoding="utf-8")
parser = load_export_cfg(cfg_path)
patterns = {}
if parser.has_section("blockpattern"):
for key, value in parser.items("blockpattern"):
@@ -49,7 +68,32 @@ def load_patterns(cfg_path=None):
return patterns
def safe_float(value, default=0.0):
"""Wandelt value in float um; bei fehlendem/ungueltigem Wert Fallback default."""
try:
return float(value)
except (TypeError, ValueError):
return default
def safe_int(value, default=0):
"""Wandelt value in int um; bei fehlendem/ungueltigem Wert Fallback default."""
try:
return int(value)
except (TypeError, ValueError):
return default
def matches_any(bname, patterns):
"""True, wenn bname (case-insensitiv) zu mindestens einem Muster passt."""
upper = bname.upper()
return any(fnmatch.fnmatchcase(upper, p.upper()) for p in patterns)
def csv_quote(value):
"""Escapt einen Wert fuer ein doppelt-angefuehrtes, semikolon-getrenntes CSV-Feld.
Verdoppelt eingebettete Anfuehrungszeichen (RFC 4180), damit z.B. eine
Bezeichnung mit einem '"' das Feldende nicht vortaeuscht.
"""
return str(value).replace('"', '""')
+63 -49
View File
@@ -11,7 +11,7 @@ Aufruf:
python export_csv.py <export_raw.json> <data_dir> <output.csv>
CSV-Format:
Elementnummer;TeileArt;TeileId;Bezeichnung;Planquadrat;Anzahl;Position;Boundingbox;Nachbarn;Merkmale
Elementnummer;TeileArt;TeileId;Bezeichnung;Planquadrat;Anzahl;Position;Boundingbox;Nachbarn;Fehler;Merkmale
Position und Boundingbox stammen aus der von export.lsp (csv:get-bbox, per
vla-getboundingbox) ermittelten Bounding-Box je Block:
@@ -20,23 +20,40 @@ vla-getboundingbox) ermittelten Bounding-Box je Block:
Planquadrat wird aus der x/y-Koordinate des Blocks berechnet, siehe
export_planquadrat.py ([Planquadrate] in cfg/export.cfg).
Nachbarn = kommaseparierte TeileId-Liste ueberschneidender Elemente (Bounding-
Box-Ueberschneidung in der x/y-Ebene per shapely-STRtree, Toleranz konfigurierbar
ueber [Nachbarschaft] -> toleranz_mm in cfg/export.cfg), siehe export_neighbors.py.
Position, Boundingbox, Planquadrat und Nachbarn sind nur fuer EXPORTCSV
vorhanden (nicht EXPORTSIVAS) - siehe csv:run-export.
Box-Ueberschneidung in der x/y-Ebene, reines Python ohne externe Abhaengigkeit,
siehe export_neighbors.py). Geprueft wird NICHT global ueber alle Elemente,
sondern in drei getrennten Gruppen: 1) Kreisel/Eckrad gegen Kreisel/Eckrad,
2) Kreisel/Eckrad gegen Gefaellestrecke/Foerderer/Strecke-Modul (diese drei
nicht gegeneinander), 3) Omniflo-Elemente gegen Omniflo-Elemente (rasterbasiert
vorgefiltert nach x/y-Koordinate). Toleranz und Omniflo-Rastergroesse
konfigurierbar ueber [Nachbarschaft] in cfg/export.cfg.
Fehler = "unverbunden" (keine Partner, aber mindestens einer noetig),
"nur ein Partner" (ein Partner, aber mindestens zwei noetig) oder leer
(Mindestanzahl erreicht bzw. TeileArt wird nicht geprueft). Kreisel/Eckrad/
Omniflo-Elemente brauchen mindestens einen Partner, Gefaellestrecke/
Foerderer/Strecke-Modul mindestens zwei (siehe export_neighbors.py
MIN_PARTNER).
Position, Boundingbox, Planquadrat, Nachbarn und Fehler sind nur fuer
EXPORTCSV vorhanden (nicht EXPORTSIVAS) - siehe csv:run-export.
"""
import json
import sys
import os
from export_blockpatterns import load_patterns, matches_any
from export_planquadrat import load_planquadrat_config, compute_planquadrat
from export_neighbors import load_neighbor_tolerance_mm, compute_neighbor_ids
from export_blockpatterns import load_patterns, matches_any, csv_quote, safe_float
from export_planquadrat import load_planquadrat_config, resolve_origins, compute_planquadrat
from export_neighbors import (
load_neighbor_tolerance_mm,
load_omniflo_cell_size_mm,
compute_neighbor_ids,
compute_neighbor_errors,
)
BLOCKPATTERNS = load_patterns()
PLANQUADRAT_CFG = load_planquadrat_config()
NEIGHBOR_TOLERANCE_MM = load_neighbor_tolerance_mm()
NEIGHBOR_OMNIFLO_CELL_SIZE_MM = load_omniflo_cell_size_mm()
# ---------------------------------------------------------------------------
@@ -91,12 +108,9 @@ def get_drehung(block):
"""Liest DREHUNG aus Block-Attributen. Fallback: CAD-Rotation."""
attribs = block.get("attribs", {})
drehung_raw = attribs.get("DREHUNG")
if drehung_raw is not None:
try:
return float(drehung_raw)
except (ValueError, TypeError):
pass
return block.get("rotation", 0.0)
if drehung_raw is None:
return block.get("rotation", 0.0)
return safe_float(drehung_raw, block.get("rotation", 0.0))
def build_bogen_merkmale(block, eintrag):
@@ -145,10 +159,7 @@ def get_laenge_mm(block):
"""Liest LAENGE (oder A) aus Block-Attributen. Fallback: 2000mm."""
attribs = block.get("attribs", {})
laenge = attribs.get("LAENGE") or attribs.get("A")
try:
return float(laenge)
except (TypeError, ValueError):
return 2000.0
return safe_float(laenge, 2000.0)
def build_gerade_merkmale(block):
@@ -211,16 +222,8 @@ def build_omni_sum_merkmale(cnt_boegen, cnt_wk, cnt_einzel, cnt_delta, cnt_doppe
def build_kreisel_merkmale(block):
attribs = block.get("attribs", {})
abstand_mm = attribs.get("ABSTAND", "2300")
try:
abstand_m = str(round(float(abstand_mm) / 1000.0, 2))
except (ValueError, TypeError):
abstand_m = "2.3"
hoehe_mm = attribs.get("HOEHE", "0")
try:
hoehe_m = str(round(float(hoehe_mm) / 1000.0, 2))
except (ValueError, TypeError):
hoehe_m = "0"
abstand_m = str(round(safe_float(attribs.get("ABSTAND", "2300"), 2300.0) / 1000.0, 2))
hoehe_m = str(round(safe_float(attribs.get("HOEHE", "0"), 0.0) / 1000.0, 2))
return {
"Abstand (Kreiselachse A - Kreiselachse) in Meter": abstand_m,
"Anzahl der Separatoren": attribs.get("ANZAHL_SEPARATOR", attribs.get("N_SEPARATOREN", "2")),
@@ -258,19 +261,21 @@ def bbox_columns(block):
}
def planquadrat_column(block):
def planquadrat_column(block, planquadrat_cfg):
"""Berechnet das Planquadrat aus x/y des Blocks (siehe export_planquadrat.py).
planquadrat_cfg = Rueckgabe von resolve_origins() fuer den aktuellen
Exportlauf (x_origin_mm/y_origin_mm bereits aufgeloest).
Leerer String, wenn keine Planquadrat-Konfiguration geladen werden konnte
(fehlende/unvollstaendige [Planquadrate]-Sektion in cfg/export.cfg).
"""
if PLANQUADRAT_CFG is None:
if planquadrat_cfg is None:
return ""
x = block.get("x")
y = block.get("y")
if x is None or y is None:
return ""
return compute_planquadrat(float(x), float(y), PLANQUADRAT_CFG)
return compute_planquadrat(float(x), float(y), planquadrat_cfg)
# ---------------------------------------------------------------------------
@@ -285,6 +290,11 @@ SKIP_BLOCKS = set(BLOCKPATTERNS.get("pattern_ks_subblocks", ["K1", "K2", "K3", "
# ---------------------------------------------------------------------------
def process_blocks(blocks, lookup):
# x_origin_mm/y_origin_mm einmalig fuer diesen Exportlauf aufloesen (siehe
# export_planquadrat.resolve_origins): automatisch aus den Bloecken, falls
# nicht explizit in [Planquadrate] konfiguriert.
planquadrat_cfg = resolve_origins(PLANQUADRAT_CFG, blocks)
items = []
elem_nr = 0
bogen_count = 0
@@ -322,7 +332,7 @@ def process_blocks(blocks, lookup):
"teileart": "Omniflo Kurve",
"teileid": shape_id,
"bezeichnung": f"OFBogen :{bogen_count}",
"planquadrat": planquadrat_column(block),
"planquadrat": planquadrat_column(block, planquadrat_cfg),
"merkmale": build_bogen_merkmale(block, eintrag),
**bbox_columns(block),
})
@@ -335,7 +345,7 @@ def process_blocks(blocks, lookup):
"teileart": "Omniflo Weiche",
"teileid": shape_id,
"bezeichnung": f"OFWeiche :{weiche_count[wt]}",
"planquadrat": planquadrat_column(block),
"planquadrat": planquadrat_column(block, planquadrat_cfg),
"merkmale": build_weiche_merkmale(block, eintrag),
**bbox_columns(block),
})
@@ -362,7 +372,7 @@ def process_blocks(blocks, lookup):
"teileart": "Omniflo Gerade",
"teileid": block.get("attribs", {}).get("ID", "0000"),
"bezeichnung": f"OFGerade :{gerade_count}",
"planquadrat": planquadrat_column(block),
"planquadrat": planquadrat_column(block, planquadrat_cfg),
"merkmale": build_gerade_merkmale(block),
**bbox_columns(block),
})
@@ -378,7 +388,7 @@ def process_blocks(blocks, lookup):
"teileart": "ILS 2.0 Strecke",
"teileid": block.get("attribs", {}).get("ID", "0000"),
"bezeichnung": f"VarioFoerderer :{vf_count}",
"planquadrat": planquadrat_column(block),
"planquadrat": planquadrat_column(block, planquadrat_cfg),
"merkmale": build_variofoerderer_merkmale(block),
**bbox_columns(block),
})
@@ -393,7 +403,7 @@ def process_blocks(blocks, lookup):
"teileart": "ILS 2.0 Gefaellestrecke",
"teileid": block.get("attribs", {}).get("ID", "0000"),
"bezeichnung": f"Gefaellestrecke :{gf_count}",
"planquadrat": planquadrat_column(block),
"planquadrat": planquadrat_column(block, planquadrat_cfg),
"merkmale": build_variofoerderer_merkmale(block),
**bbox_columns(block),
})
@@ -409,7 +419,7 @@ def process_blocks(blocks, lookup):
"teileart": "ILS 2.0 Eckrad",
"teileid": block.get("attribs", {}).get("ID", "0000"),
"bezeichnung": f"Eckrad :{eckrad_count}",
"planquadrat": planquadrat_column(block),
"planquadrat": planquadrat_column(block, planquadrat_cfg),
"merkmale": build_kreisel_merkmale(block),
**bbox_columns(block),
})
@@ -424,7 +434,7 @@ def process_blocks(blocks, lookup):
"teileart": "ILS 2.0 Kreisel",
"teileid": block.get("attribs", {}).get("ID", "0000"),
"bezeichnung": f"Kreisel :{kreisel_count}",
"planquadrat": planquadrat_column(block),
"planquadrat": planquadrat_column(block, planquadrat_cfg),
"merkmale": build_kreisel_merkmale(block),
**bbox_columns(block),
})
@@ -439,7 +449,7 @@ def process_blocks(blocks, lookup):
"teileart": "ILS 2.0 Strecke - Modul",
"teileid": block.get("attribs", {}).get("ID", "0000"),
"bezeichnung": f"Streckenmodul :{strecke_modul_count}",
"planquadrat": planquadrat_column(block),
"planquadrat": planquadrat_column(block, planquadrat_cfg),
"merkmale": {"Blockname": bname},
**bbox_columns(block),
})
@@ -460,9 +470,12 @@ def process_blocks(blocks, lookup):
"boundingbox": "",
})
neighbor_ids = compute_neighbor_ids(items, NEIGHBOR_TOLERANCE_MM)
for item, nachbarn in zip(items, neighbor_ids):
neighbor_ids = compute_neighbor_ids(
items, NEIGHBOR_TOLERANCE_MM, NEIGHBOR_OMNIFLO_CELL_SIZE_MM)
neighbor_errors = compute_neighbor_errors(items, neighbor_ids)
for item, nachbarn, fehler in zip(items, neighbor_ids, neighbor_errors):
item["nachbarn"] = nachbarn
item["fehler"] = fehler
return items
@@ -475,14 +488,15 @@ def format_csv_line(item):
merkmale_json = json.dumps(item["merkmale"], ensure_ascii=False)
return (
f'{item["nr"]}'
f';"{item["teileart"]}"'
f';"{item["teileid"]}"'
f';"{item["bezeichnung"]}"'
f';"{item["planquadrat"]}"'
f';"{csv_quote(item["teileart"])}"'
f';"{csv_quote(item["teileid"])}"'
f';"{csv_quote(item["bezeichnung"])}"'
f';"{csv_quote(item["planquadrat"])}"'
f';1'
f';"{item["position"]}"'
f';"{item["boundingbox"]}"'
f';"{item["nachbarn"]}"'
f';"{csv_quote(item["position"])}"'
f';"{csv_quote(item["boundingbox"])}"'
f';"{csv_quote(item["nachbarn"])}"'
f';"{csv_quote(item["fehler"])}"'
f';{merkmale_json}'
)
@@ -514,7 +528,7 @@ def main():
items = process_blocks(blocks, lookup)
header = "Elementnummer;TeileArt;TeileId;Bezeichnung;Planquadrat;Anzahl;Position;Boundingbox;Nachbarn;Merkmale"
header = "Elementnummer;TeileArt;TeileId;Bezeichnung;Planquadrat;Anzahl;Position;Boundingbox;Nachbarn;Fehler;Merkmale"
with open(output_csv, "w", encoding="utf-8") as f:
f.write(header + "\n")
for item in items:
+194 -44
View File
@@ -1,72 +1,222 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
export_neighbors.py - Ermittelt benachbarte Elemente ueber die Bounding-Box (STRtree).
export_neighbors.py - Ermittelt benachbarte Elemente ueber Bounding-Box-
Ueberschneidung in der x/y-Ebene (Grundriss, Z/Hoehe wird ignoriert).
Zwei Elemente gelten als benachbart, wenn ihre Bounding-Boxes sich in der
x/y-Ebene (Grundriss, Z/Hoehe wird ignoriert) ueberschneiden. Um auch nah
beieinander liegende, aber nicht direkt beruehrende Elemente (z.B. Kreisel)
als benachbart zu erkennen, wird jede Bounding-Box vor der Pruefung um die
Haelfte der konfigurierten Toleranz nach allen Seiten erweitert - zwei
Elemente mit einem Abstand <= toleranz_mm gelten dann ebenfalls als
benachbart. Die Toleranz wird aus cfg/export.cfg ([Nachbarschaft] ->
toleranz_mm) gelesen.
Reines Python (keine externe Abhaengigkeit wie shapely) - die Bloecke werden
dazu in drei Gruppen eingeteilt und NUR innerhalb dieser Kombinationen
gegeneinander geprueft (nicht mehr alle Elemente einer Zeichnung gemeinsam):
1. Kreisel/Eckrad gegen Kreisel/Eckrad
2. Kreisel/Eckrad gegen Gefaellestrecke/Foerderer/Strecke-Modul - diese
drei Kategorien werden NICHT gegeneinander getestet (nur relevant, wo
sie an einen Kreisel/Eckrad anschliessen)
3. Omniflo-Elemente (Bogen/Weiche/Gerade) gegen Omniflo-Elemente
Omniflo-Anlagen koennen mehrere hundert Elemente enthalten - ein Test jedes
gegen jedes (O(n^2)) waere dort zu teuer. Die Omniflo-Gruppe wird daher vorab
per Raster (Zellgroesse siehe [Nachbarschaft] -> omniflo_zellgroesse_mm in
cfg/export.cfg) nach x/y-Koordinate in Quadranten/Zellen eingeteilt; jedes
Element wird nur gegen Elemente in derselben und den 8 angrenzenden Zellen
geprueft (3x3-Nachbarschaft, damit auch Elemente knapp jenseits einer
Zellgrenze noch erkannt werden).
Zwei Bounding-Boxes gelten als benachbart, wenn sie sich (nach Erweiterung
um die halbe Toleranz je Seite) in x/y ueberschneiden. Toleranz aus
cfg/export.cfg ([Nachbarschaft] -> toleranz_mm), Wert in mm.
compute_neighbor_errors() prueft zusaetzlich, ob jedes Element die fuer
seine TeileArt noetige Mindestanzahl an Partnern (Nachbarn) hat (siehe
MIN_PARTNER) - Ergebnis ist die CSV-Spalte "Fehler" in export_csv.py.
Nur von export_csv.py genutzt (EXPORTCSV), nicht von export_sivas.py.
"""
import configparser
from export_blockpatterns import cfg_path_from_env, load_export_cfg
from shapely.geometry import box
from shapely.strtree import STRtree
KREISEL_TEILEARTEN = {"ILS 2.0 Kreisel", "ILS 2.0 Eckrad"}
STRECKEN_TEILEARTEN = {"ILS 2.0 Gefaellestrecke", "ILS 2.0 Strecke", "ILS 2.0 Strecke - Modul"}
OMNIFLO_TEILEARTEN = {"Omniflo Kurve", "Omniflo Weiche", "Omniflo Gerade"}
from export_blockpatterns import cfg_path_from_env
# Mindestanzahl Partner (Nachbarn) je TeileArt fuer die Fehlerspalte "Fehler"
# (siehe compute_neighbor_errors): Kreisel/Eckrad und Omniflo-Elemente
# brauchen mindestens einen Partner, Gefaellestrecke/Foerderer/Strecke-Modul
# muessen an zwei Seiten anschliessen (mindestens zwei Partner). TeileArten,
# die hier nicht auftauchen (z.B. die synthetische "Omniflo Sum"-Zeile),
# werden nicht geprueft.
MIN_PARTNER = {}
MIN_PARTNER.update({t: 1 for t in KREISEL_TEILEARTEN})
MIN_PARTNER.update({t: 1 for t in OMNIFLO_TEILEARTEN})
MIN_PARTNER.update({t: 2 for t in STRECKEN_TEILEARTEN})
def load_neighbor_tolerance_mm(cfg_path=None):
"""Liest die Nachbarschafts-Toleranz (mm) aus export.cfg. Default: 0."""
if cfg_path is None:
cfg_path = cfg_path_from_env()
parser = configparser.ConfigParser(inline_comment_prefixes=("#",))
parser.read(cfg_path, encoding="utf-8")
parser = load_export_cfg(cfg_path)
return parser.getfloat("Nachbarschaft", "toleranz_mm", fallback=0.0)
def compute_neighbor_ids(items, tolerance_mm):
"""Ermittelt je Item die IDs (item["teileid"]) ueberschneidender Nachbarn.
def load_omniflo_cell_size_mm(cfg_path=None):
"""Liest die Rastergroesse (mm) fuer die Omniflo-Nachbarschaftspruefung.
items = Liste von dict mit "teileid" und optional "_bbox"
({"cx","cy","dx","dy",...}, siehe export.lsp csv:get-bbox / export_csv.py
bbox_columns). Items ohne _bbox (z.B. die synthetische Omniflo-Sum-Zeile)
haben keine Nachbarn.
Default 3000mm: groesser als die ueblichen Omniflo-Bauteile (AP110-
Geraden ca. 2000mm), damit ein Element nicht durch ein zu kleines
Raster in mehr als eine Zelle ueberlappt.
"""
if cfg_path is None:
cfg_path = cfg_path_from_env()
parser = load_export_cfg(cfg_path)
return parser.getfloat("Nachbarschaft", "omniflo_zellgroesse_mm", fallback=3000.0)
def _bounds(bbox, half_tol):
"""(minx, maxx, miny, maxy) einer Bounding-Box, je Seite um half_tol erweitert."""
return (
bbox["cx"] - bbox["dx"] / 2.0 - half_tol,
bbox["cx"] + bbox["dx"] / 2.0 + half_tol,
bbox["cy"] - bbox["dy"] / 2.0 - half_tol,
bbox["cy"] + bbox["dy"] / 2.0 + half_tol,
)
def _overlaps(bounds_a, bounds_b):
"""True, wenn sich zwei (minx, maxx, miny, maxy)-Rechtecke in x/y ueberschneiden."""
a_minx, a_maxx, a_miny, a_maxy = bounds_a
b_minx, b_maxx, b_miny, b_maxy = bounds_b
return a_minx <= b_maxx and b_minx <= a_maxx and a_miny <= b_maxy and b_miny <= a_maxy
def _add_neighbor(result, idx_a, idx_b, id_a, id_b):
result[idx_a].append(id_b)
result[idx_b].append(id_a)
def _test_group_pairs(group, result):
"""Alle Paare EINER Gruppe gegeneinander testen (O(n^2) - fuer Kreisel/
Eckrad-Stueckzahlen pro Zeichnung unkritisch)."""
n = len(group)
for a in range(n):
idx_a, bounds_a, id_a = group[a]
for b in range(a + 1, n):
idx_b, bounds_b, id_b = group[b]
if _overlaps(bounds_a, bounds_b):
_add_neighbor(result, idx_a, idx_b, id_a, id_b)
def _test_group_against_group(group_a, group_b, result):
"""Jedes Element aus group_a gegen jedes Element aus group_b testen.
group_b wird NICHT gegen sich selbst getestet (Aufgabe des Aufrufers)."""
for idx_a, bounds_a, id_a in group_a:
for idx_b, bounds_b, id_b in group_b:
if _overlaps(bounds_a, bounds_b):
_add_neighbor(result, idx_a, idx_b, id_a, id_b)
def _grid_cell(bbox, cell_size_mm):
"""Rasterzelle (Quadrant) einer Bounding-Box nach ihrem Mittelpunkt."""
return (int(bbox["cx"] // cell_size_mm), int(bbox["cy"] // cell_size_mm))
def _test_omniflo_grid(group, cell_size_mm, result):
"""Omniflo-Elemente nur gegen Elemente in derselben oder einer der 8
angrenzenden Rasterzellen testen (3x3-Nachbarschaft) statt gegen alle -
haelt den Aufwand bei mehreren hundert Omniflo-Elementen niedrig, ohne
Ueberschneidungen an Zellgrenzen zu verpassen."""
buckets = {}
for entry in group:
idx, bounds, teileid, bbox = entry
buckets.setdefault(_grid_cell(bbox, cell_size_mm), []).append(entry)
checked = set()
for (cx, cy), cell_items in buckets.items():
candidates = []
for dx in (-1, 0, 1):
for dy in (-1, 0, 1):
candidates.extend(buckets.get((cx + dx, cy + dy), []))
for idx_a, bounds_a, id_a, _ in cell_items:
for idx_b, bounds_b, id_b, _ in candidates:
if idx_a >= idx_b:
continue
pair = (idx_a, idx_b)
if pair in checked:
continue
checked.add(pair)
if _overlaps(bounds_a, bounds_b):
_add_neighbor(result, idx_a, idx_b, id_a, id_b)
def compute_neighbor_ids(items, tolerance_mm, omniflo_cell_size_mm=3000.0):
"""Ermittelt je Item die IDs (item["teileid"]) benachbarter Elemente.
items = Liste von dict mit "teileart", "teileid" und optional "_bbox"
({"cx","cy","dx","dy",...}, siehe export_csv.py bbox_columns). Items
ohne _bbox (z.B. die synthetische Omniflo-Sum-Zeile) bleiben ohne
Nachbarn.
Rueckgabe: Liste von kommaseparierten Nachbar-ID-Strings, positionsgleich
zu items (nicht ueber die ID dedupliziert, da TeileId nicht zwingend
eindeutig ist).
"""
idx_with_bbox = [i for i, it in enumerate(items) if it.get("_bbox")]
result = [""] * len(items)
if len(idx_with_bbox) < 2:
return result
half_tol = tolerance_mm / 2.0
geoms = []
for i in idx_with_bbox:
bb = items[i]["_bbox"]
minx = bb["cx"] - bb["dx"] / 2.0 - half_tol
maxx = bb["cx"] + bb["dx"] / 2.0 + half_tol
miny = bb["cy"] - bb["dy"] / 2.0 - half_tol
maxy = bb["cy"] + bb["dy"] / 2.0 + half_tol
geoms.append(box(minx, miny, maxx, maxy))
result = [[] for _ in items]
tree = STRtree(geoms)
for local_i, global_i in enumerate(idx_with_bbox):
hits = tree.query(geoms[local_i], predicate="intersects")
neighbor_ids = [
items[idx_with_bbox[int(local_j)]]["teileid"]
for local_j in hits
if int(local_j) != local_i
]
result[global_i] = ", ".join(neighbor_ids)
kreisel_group = []
strecken_group = []
omniflo_group = []
return result
for idx, item in enumerate(items):
bbox = item.get("_bbox")
if not bbox:
continue
teileart = item.get("teileart", "")
teileid = item.get("teileid", "")
bounds = _bounds(bbox, half_tol)
if teileart in KREISEL_TEILEARTEN:
kreisel_group.append((idx, bounds, teileid))
elif teileart in STRECKEN_TEILEARTEN:
strecken_group.append((idx, bounds, teileid))
elif teileart in OMNIFLO_TEILEARTEN:
omniflo_group.append((idx, bounds, teileid, bbox))
# 1. Kreisel/Eckrad gegen Kreisel/Eckrad
_test_group_pairs(kreisel_group, result)
# 2. Kreisel/Eckrad gegen Gefaellestrecke/Foerderer/Strecke-Modul -
# diese drei Kategorien nicht gegeneinander (siehe Modul-Docstring)
_test_group_against_group(kreisel_group, strecken_group, result)
# 3. Omniflo gegen Omniflo, rasterbasiert vorgefiltert
_test_omniflo_grid(omniflo_group, omniflo_cell_size_mm, result)
return [", ".join(neighbor_ids) for neighbor_ids in result]
def compute_neighbor_errors(items, neighbor_ids):
"""Prueft je Item die Mindestanzahl an Partnern (siehe MIN_PARTNER).
items = dieselbe Liste wie bei compute_neighbor_ids (braucht "teileart").
neighbor_ids = Rueckgabe von compute_neighbor_ids (positionsgleich zu items).
Rueckgabe: Liste von Fehlertexten, positionsgleich zu items:
"unverbunden" - keine Partner, obwohl mindestens einer noetig waere
"nur ein Partner" - genau ein Partner, obwohl mindestens zwei noetig waeren
"" - Mindestanzahl erreicht, oder TeileArt wird nicht geprueft
"""
errors = []
for item, nachbarn in zip(items, neighbor_ids):
min_partner = MIN_PARTNER.get(item.get("teileart", ""))
if min_partner is None:
errors.append("")
continue
anzahl = len([p for p in nachbarn.split(",") if p.strip()])
if anzahl == 0:
errors.append("unverbunden")
elif anzahl == 1 and min_partner >= 2:
errors.append("nur ein Partner")
else:
errors.append("")
return errors
+56 -14
View File
@@ -8,26 +8,28 @@ Liest die aktive Planquadrat-Konfiguration aus cfg/export.cfg
rundet die x/y-Koordinate eines Blocks (mm, wie im Roh-JSON von export.lsp)
je Achse auf die konfigurierte Schrittweite (in Metern) herunter.
x_origin/y_origin ([Planquadrate], in m) legen die DXF-Koordinate der
Planquadrat-Ecke A/1 fest. Sind sie leer/nicht gesetzt, ermittelt
resolve_origins() sie automatisch je Exportlauf aus den zu exportierenden
Bloecken (am weitesten links/unten liegendes Element = Ursprung) - siehe dort.
Nur von export_csv.py genutzt (EXPORTCSV), nicht von export_sivas.py.
"""
import configparser
from export_blockpatterns import cfg_path_from_env
from export_blockpatterns import cfg_path_from_env, load_export_cfg
def load_planquadrat_config(cfg_path=None):
"""Liest die aktive Planquadrat-Konfiguration aus export.cfg.
Rueckgabe: dict mit x_step_mm, x_alpha, y_step_mm, y_alpha, format,
oder None, wenn [Planquadrate] bzw. die referenzierte Sub-Sektion fehlt.
Rueckgabe: dict mit x_step_mm, x_alpha, y_step_mm, y_alpha,
x_origin_mm/y_origin_mm (None, falls in [Planquadrate] nicht gesetzt -
siehe resolve_origins()) und format, oder None, wenn [Planquadrate]
bzw. die referenzierte Sub-Sektion fehlt.
"""
if cfg_path is None:
cfg_path = cfg_path_from_env()
# inline_comment_prefixes noetig, da export.cfg Werte wie
# "numerisch # zahlen, von links nach rechts, 2m pro Spalte" nutzt.
parser = configparser.ConfigParser(inline_comment_prefixes=("#",))
parser.read(cfg_path, encoding="utf-8")
parser = load_export_cfg(cfg_path)
if not parser.has_section("Planquadrate"):
return None
@@ -36,15 +38,48 @@ def load_planquadrat_config(cfg_path=None):
return None
sec = parser[section_name]
def _origin_mm(key):
raw = parser.get("Planquadrate", key, fallback="").strip()
return float(raw) * 1000.0 if raw else None
return {
"x_step_mm": float(sec.get("x_step", "1")) * 1000.0,
"x_alpha": sec.get("x_description", "numerisch").strip().lower().startswith("alpha"),
"y_step_mm": float(sec.get("y_step", "1")) * 1000.0,
"y_alpha": sec.get("y_description", "numerisch").strip().lower().startswith("alpha"),
"x_origin_mm": _origin_mm("x_origin"),
"y_origin_mm": _origin_mm("y_origin"),
"format": sec.get("format", "{x}/{y}").strip(),
}
def resolve_origins(cfg, blocks):
"""Loest x_origin_mm/y_origin_mm auf, falls in export.cfg nicht gesetzt.
cfg = Rueckgabe von load_planquadrat_config() (kann None sein).
blocks = alle Bloecke des aktuellen Exportlaufs (Liste von dicts mit
"x"/"y", wie im Roh-JSON von export.lsp).
Automatik: das am weitesten links liegende Element (min x) setzt
x_origin, das am weitesten unten liegende (min y) setzt y_origin -
beide landen damit exakt in Planquadrat-Index 1 auf ihrer Achse.
Explizit in export.cfg gesetzte Werte werden nicht ueberschrieben.
Rueckgabe: neues dict (cfg bleibt unveraendert) oder None, wenn cfg None ist.
"""
if cfg is None:
return None
resolved = dict(cfg)
if resolved.get("x_origin_mm") is None:
xs = [float(b["x"]) for b in blocks if b.get("x") is not None]
resolved["x_origin_mm"] = min(xs) if xs else 0.0
if resolved.get("y_origin_mm") is None:
ys = [float(b["y"]) for b in blocks if b.get("y") is not None]
resolved["y_origin_mm"] = min(ys) if ys else 0.0
return resolved
def _index_to_alpha(n):
"""Wandelt einen 1-basierten Index in eine Buchstaben-Bezeichnung um.
@@ -57,15 +92,22 @@ def _index_to_alpha(n):
return result
def _index_for(coord_mm, step_mm):
"""1-basierter Planquadrat-Index einer Koordinate fuer eine Schrittweite."""
return int(coord_mm // step_mm) + 1
def _index_for(coord_mm, step_mm, origin_mm=0.0):
"""1-basierter Planquadrat-Index einer Koordinate fuer eine Schrittweite.
origin_mm ist die Koordinate der Planquadrat-Ecke A/1 (x_origin/y_origin
aus cfg/export.cfg) - Koordinaten werden vor der Index-Berechnung um
diesen Nullpunkt verschoben, damit reale Layouts mit negativen
DXF-Koordinaten (Zeichnungsursprung liegt nicht in der Gebaeudeecke)
trotzdem ab Index 1 gezaehlt werden.
"""
return int((coord_mm - origin_mm) // step_mm) + 1
def compute_planquadrat(x_mm, y_mm, cfg):
"""Berechnet die Planquadrat-Bezeichnung fuer eine x/y-Koordinate (mm)."""
x_idx = _index_for(x_mm, cfg["x_step_mm"])
y_idx = _index_for(y_mm, cfg["y_step_mm"])
x_idx = _index_for(x_mm, cfg["x_step_mm"], cfg.get("x_origin_mm", 0.0))
y_idx = _index_for(y_mm, cfg["y_step_mm"], cfg.get("y_origin_mm", 0.0))
x_label = _index_to_alpha(x_idx) if cfg["x_alpha"] else str(x_idx)
y_label = _index_to_alpha(y_idx) if cfg["y_alpha"] else str(y_idx)
return cfg["format"].format(x=x_label, y=y_label)
+70 -69
View File
@@ -33,7 +33,7 @@ import json
import sys
import os
from export_blockpatterns import load_patterns, matches_any
from export_blockpatterns import load_patterns, matches_any, csv_quote, safe_float, safe_int
BLOCKPATTERNS = load_patterns()
@@ -99,10 +99,7 @@ def build_gefaellestrecke_details(block):
attribs = block.get("attribs", {})
def mm_to_m(key):
try:
return str(round(float(attribs.get(key, "0")) / 1000.0, 2))
except (ValueError, TypeError):
return "0"
return str(round(safe_float(attribs.get(key, "0")) / 1000.0, 2))
return {
"Hoehe oben": mm_to_m("HOEHE_VON_mm"),
@@ -112,14 +109,17 @@ def build_gefaellestrecke_details(block):
"Anzahl der Separatoren": attribs.get("ANZAHL_SEPARATOR", "0"),
"Anzahl der Scanner": attribs.get("ANZAHL_SCANNER", "0"),
"Typ": attribs.get("TYP", "Gefaellestrecke"),
"Geruest fuer Einzelmodul": attribs.get("GERUEST_EINZELMODUL", "0") == "1",
"Geruestoption fuer Einzelmodul": attribs.get("GERUEST_TYP", "Schoenenberger Geruest"),
}
def kreisel_signature(block):
"""
Schluessel zur Gruppierung gleichartiger Kreisel: Kreiselart, Abstand,
Anzahl der Separatoren, Anzahl der Scanner und Anzahl der Rampen
entscheiden, ob Kreisel in derselben Sivas-Zeile summiert werden.
Anzahl der Separatoren, Anzahl der Scanner, Anzahl der Rampen sowie
Geruest fuer Einzelmodul/Geruestoption entscheiden, ob Kreisel in
derselben Sivas-Zeile summiert werden.
"""
attribs = block.get("attribs", {})
return (
@@ -129,14 +129,29 @@ def kreisel_signature(block):
attribs.get("ANZAHL_SCANNER", attribs.get("N_SCANNER", "0")),
attribs.get("ANZAHL_RAMPEN", attribs.get("N_RAMPEN", "0")),
attribs.get("GERUEST_EINZELMODUL", "0"),
attribs.get("GERUEST_TYP", "Schoenenberger Geruest"),
)
def eckrad_signature(block):
"""
Schluessel zur Gruppierung gleichartiger Eckraeder: Geruest fuer
Einzelmodul/Geruestoption entscheiden, ob Eckraeder in derselben
Sivas-Zeile summiert werden.
"""
attribs = block.get("attribs", {})
return (
attribs.get("GERUEST_EINZELMODUL", "0"),
attribs.get("GERUEST_TYP", "Schoenenberger Geruest"),
)
def gefaellestrecke_signature(block):
"""
Schluessel zur Gruppierung gleichartiger Gefaellestrecken: Bloecke mit
identischen Massen (Hoehe, Laenge, Winkel, Separatoren, Scanner, Typ)
landen in derselben Sivas-Zeile - nur IDs/Bezeichnung unterscheiden sich.
identischen Massen (Hoehe, Laenge, Winkel, Separatoren, Scanner, Typ,
Geruest fuer Einzelmodul/Geruestoption) landen in derselben Sivas-Zeile -
nur IDs/Bezeichnung unterscheiden sich.
"""
attribs = block.get("attribs", {})
return (
@@ -147,6 +162,8 @@ def gefaellestrecke_signature(block):
attribs.get("ANZAHL_SEPARATOR", "0"),
attribs.get("ANZAHL_SCANNER", "0"),
attribs.get("TYP", "Gefaellestrecke"),
attribs.get("GERUEST_EINZELMODUL", "0"),
attribs.get("GERUEST_TYP", "Schoenenberger Geruest"),
)
@@ -177,10 +194,7 @@ def build_variofoerderer_details(block):
attribs = block.get("attribs", {})
def to_int(key):
try:
return int(attribs.get(key, "0") or "0")
except (ValueError, TypeError):
return 0
return safe_int(attribs.get(key, "0") or "0")
return {
"Anzahl Foerdergruppen": to_int("ANZAHL_VF"),
@@ -212,22 +226,16 @@ def build_variofoerderer_details(block):
},
"Anzahl der Separatoren": to_int("ANZAHL_SEPARATOR"),
"Anzahl der Scanner": to_int("ANZAHL_SCANNER"),
"Geruest fuer Einzelmodul": attribs.get("GERUEST_EINZELMODUL", "0") == "1",
"Geruestoption fuer Einzelmodul": attribs.get("GERUEST_TYP", "Schoenenberger Geruest"),
}
def build_kreisel_details(block):
"""Merkmale-Dict fuer einen ILS Kreisel."""
attribs = block.get("attribs", {})
abstand_mm = attribs.get("ABSTAND", "2300")
try:
abstand_m = str(round(float(abstand_mm) / 1000.0, 2))
except (ValueError, TypeError):
abstand_m = "2.3"
hoehe_mm = attribs.get("HOEHE", "0")
try:
hoehe_m = str(round(float(hoehe_mm) / 1000.0, 2))
except (ValueError, TypeError):
hoehe_m = "0"
abstand_m = str(round(safe_float(attribs.get("ABSTAND", "2300"), 2300.0) / 1000.0, 2))
hoehe_m = str(round(safe_float(attribs.get("HOEHE", "0"), 0.0) / 1000.0, 2))
return {
"Hoehe in m": hoehe_m,
"Kreiselart": attribs.get("KREISELART", "STANDARD"),
@@ -236,6 +244,16 @@ def build_kreisel_details(block):
"Anzahl der Scanner": attribs.get("ANZAHL_SCANNER", attribs.get("N_SCANNER", "0")),
"Anzahl der Rampen": attribs.get("ANZAHL_RAMPEN", attribs.get("N_RAMPEN", "0")),
"Geruest fuer Einzelmodul": attribs.get("GERUEST_EINZELMODUL", "0") == "1",
"Geruestoption fuer Einzelmodul": attribs.get("GERUEST_TYP", "Schoenenberger Geruest"),
}
def build_eckrad_details(block):
"""Merkmale-Dict fuer ein ILS Eckrad."""
attribs = block.get("attribs", {})
return {
"Geruest fuer Einzelmodul": attribs.get("GERUEST_EINZELMODUL", "0") == "1",
"Geruestoption fuer Einzelmodul": attribs.get("GERUEST_TYP", "Schoenenberger Geruest"),
}
@@ -274,8 +292,7 @@ def process_blocks(blocks, lookup):
# Gerade: artinr_str -> {anzahl, laenge_mm_total, ids}
gerade_groups = {}
kreisel_list = [] # Liste von blocks
eckrad_ids = [] # IDs aller Eckrad-Bloecke
eckrad_bezeichnungen = [] # Bezeichnung-Attribut aller Eckrad-Bloecke
eckrad_groups = {} # eckrad_signature(block) -> {"ids", "bezeichnungen", "block"}
strecke_ids = [] # IDs loser Strecke-Elemente (Vario/Staustrecke ausserhalb VF_N)
strecke_bezeichnungen = [] # Bezeichnung-Attribut loser Strecke-Elemente
vario_list = [] # Liste von VarioFoerderer-Compound-Bloecken (VF_N), je einer Zeile
@@ -353,13 +370,8 @@ def process_blocks(blocks, lookup):
attribs = block.get("attribs", {})
artinr = attribs.get("ARTINR", "")
key = artinr if artinr else "AP110"
laenge = 2000.0
laenge_attr = attribs.get("LAENGE") or attribs.get("A")
if laenge_attr:
try:
laenge = float(laenge_attr)
except (ValueError, TypeError):
pass
laenge = safe_float(laenge_attr, 2000.0)
if key not in gerade_groups:
gerade_groups[key] = {
"anzahl": 0, "laenge_mm": 0.0,
@@ -375,8 +387,12 @@ def process_blocks(blocks, lookup):
# ECKRAD_* mit ein, pattern_eckrad ist die praezisere Teilmenge) ---
if matches_any(bname, BLOCKPATTERNS.get("pattern_eckrad", [])):
counters["anzahl_eckraeder"] += 1
eckrad_ids.append(get_id(block))
eckrad_bezeichnungen.append(block.get("attribs", {}).get("Bezeichnung", ""))
sig = eckrad_signature(block)
if sig not in eckrad_groups:
eckrad_groups[sig] = {"ids": [], "bezeichnungen": [], "block": block}
eckrad_groups[sig]["ids"].append(get_id(block))
eckrad_groups[sig]["bezeichnungen"].append(
block.get("attribs", {}).get("Bezeichnung", ""))
continue
# --- ILS Kreisel ---
@@ -384,17 +400,17 @@ def process_blocks(blocks, lookup):
kreisel_list.append(block)
attribs = block.get("attribs", {})
counters["anzahl_kreisel"] += 1
n_sep = int(attribs.get("ANZAHL_SEPARATOR", attribs.get("N_SEPARATOREN", "2")) or "2")
n_sep = safe_int(attribs.get("ANZAHL_SEPARATOR", attribs.get("N_SEPARATOREN", "2")) or "2", 2)
kreiselart = attribs.get("KREISELART", "STANDARD")
if kreiselart == "PIN":
counters["anzahl_kreisel_pinband"] += 1
counters["sep_kreisel_pin"] += n_sep
else:
counters["sep_kreisel_ohne_pin"] += n_sep
abstand_mm = float(attribs.get("ABSTAND", "2300") or "2300")
abstand_mm = safe_float(attribs.get("ABSTAND", "2300") or "2300", 2300.0)
counters["laengen_kreisel"] += abstand_mm / 1000.0
counters["anzahl_separatoren"] += n_sep
counters["anzahl_scanner"] += int(attribs.get("ANZAHL_SCANNER", attribs.get("N_SCANNER", "0")) or "0")
counters["anzahl_scanner"] += safe_int(attribs.get("ANZAHL_SCANNER", attribs.get("N_SCANNER", "0")) or "0")
if counters["anzahl_streckengruppen"] == 0:
counters["anzahl_streckengruppen"] = 1
continue
@@ -406,18 +422,9 @@ def process_blocks(blocks, lookup):
attribs = block.get("attribs", {})
counters["anzahl_variofoerderer"] += 1
vario_list.append(block)
try:
counters["laengen_variofoerderer"] += float(attribs.get("L_VF_m", "0") or "0")
except (ValueError, TypeError):
pass
try:
counters["anzahl_separatoren"] += int(attribs.get("ANZAHL_SEPARATOR", "0") or "0")
except (ValueError, TypeError):
pass
try:
counters["anzahl_scanner"] += int(attribs.get("ANZAHL_SCANNER", "0") or "0")
except (ValueError, TypeError):
pass
counters["laengen_variofoerderer"] += safe_float(attribs.get("L_VF_m", "0") or "0")
counters["anzahl_separatoren"] += safe_int(attribs.get("ANZAHL_SEPARATOR", "0") or "0")
counters["anzahl_scanner"] += safe_int(attribs.get("ANZAHL_SCANNER", "0") or "0")
if counters["anzahl_streckengruppen"] == 0:
counters["anzahl_streckengruppen"] = 1
continue
@@ -428,18 +435,9 @@ def process_blocks(blocks, lookup):
attribs = block.get("attribs", {})
counters["anzahl_gefaellestrecken"] += 1
gefaelle_list.append(block)
try:
counters["laengen_gefaellestrecken"] += float(attribs.get("L_GF_m", "0") or "0")
except (ValueError, TypeError):
pass
try:
counters["anzahl_separatoren"] += int(attribs.get("ANZAHL_SEPARATOR", "0") or "0")
except (ValueError, TypeError):
pass
try:
counters["anzahl_scanner"] += int(attribs.get("ANZAHL_SCANNER", "0") or "0")
except (ValueError, TypeError):
pass
counters["laengen_gefaellestrecken"] += safe_float(attribs.get("L_GF_m", "0") or "0")
counters["anzahl_separatoren"] += safe_int(attribs.get("ANZAHL_SEPARATOR", "0") or "0")
counters["anzahl_scanner"] += safe_int(attribs.get("ANZAHL_SCANNER", "0") or "0")
if counters["anzahl_streckengruppen"] == 0:
counters["anzahl_streckengruppen"] = 1
continue
@@ -526,19 +524,22 @@ def process_blocks(blocks, lookup):
})
nr += 1
if counters["anzahl_eckraeder"] > 0:
# Gleichartige Eckraeder (gleiches Geruest fuer Einzelmodul/Geruestoption)
# zu einer Zeile zusammenfassen - nur IDs/Bezeichnung bleiben je Block
# unterschiedlich.
for group in eckrad_groups.values():
sivasnr, teileart = ILS_SIVASNR["eckrad"]
items.append({
"nr": nr,
"teileart": teileart,
"sivasnr": sivasnr,
"sivasnr_quoted": True,
"bezeichnung": ", ".join(b for b in eckrad_bezeichnungen if b),
"bezeichnung": ", ".join(b for b in group["bezeichnungen"] if b),
"dispgruppe": 20,
"anzahl": counters["anzahl_eckraeder"],
"anzahl": len(group["ids"]),
"laenge_mm": "",
"ids": eckrad_ids,
"details": {},
"ids": group["ids"],
"details": build_eckrad_details(group["block"]),
})
nr += 1
@@ -654,17 +655,17 @@ def process_blocks(blocks, lookup):
def format_csv_line(item):
"""Formatiert eine CSV-Zeile im neuen Sivas-Format."""
details_json = json.dumps(item["details"], ensure_ascii=False)
sivasnr = f'"{item["sivasnr"]}"' if item["sivasnr_quoted"] else item["sivasnr"]
sivasnr = f'"{csv_quote(item["sivasnr"])}"' if item["sivasnr_quoted"] else item["sivasnr"]
ids_str = ", ".join(str(i) for i in item.get("ids", []) if i)
return (
f'{item["nr"]}'
f';"{item["teileart"]}"'
f';"{csv_quote(item["teileart"])}"'
f';{sivasnr}'
f';"{item["bezeichnung"]}"'
f';"{csv_quote(item["bezeichnung"])}"'
f';{item["dispgruppe"]}'
f';{item["anzahl"]}'
f';{item["laenge_mm"]}'
f';"{ids_str}"'
f';"{csv_quote(ids_str)}"'
f';{details_json}'
)
+12 -12
View File
@@ -154,7 +154,7 @@ def read_ks(doc, name):
dx = end[0] - point[0]
dy = end[1] - point[1]
dz = end[2] - point[2]
length = (dx**2 + dy**2 + dz**2) ** 0.5
length = math.dist(point, (end[0], end[1], end[2]))
axes[line.dxf.color] = (dx / length, dy / length, dz / length)
x_axis = axes.get(1, (1, 0, 0))
@@ -355,11 +355,11 @@ def k2_point_bogen(doc):
continue
s = (e.dxf.start[0], e.dxf.start[1])
end = (e.dxf.end[0], e.dxf.end[1])
ds = ((s[0] - k2_junction[0])**2 + (s[1] - k2_junction[1])**2) ** 0.5
de = ((end[0] - k2_junction[0])**2 + (end[1] - k2_junction[1])**2) ** 0.5
ds = math.dist(s, k2_junction)
de = math.dist(end, k2_junction)
if ds > tol and de > tol:
continue
ln = ((end[0] - s[0])**2 + (end[1] - s[1])**2) ** 0.5
ln = math.dist(end, s)
if ln > best_line_len:
best_line_len = ln
if ds < tol:
@@ -428,8 +428,8 @@ def _find_weiche_arc_branches(doc):
cy + r * math.sin(math.radians(ea)))
# K1-Seite = naeher an K1
d_start = ((arc_start[0] - k1_x)**2 + (arc_start[1] - k1_y)**2) ** 0.5
d_end = ((arc_end[0] - k1_x)**2 + (arc_end[1] - k1_y)**2) ** 0.5
d_start = math.dist(arc_start, (k1_x, k1_y))
d_end = math.dist(arc_end, (k1_x, k1_y))
if d_start < d_end:
k2_junction = arc_end
@@ -445,11 +445,11 @@ def _find_weiche_arc_branches(doc):
continue
ls = (ent.dxf.start[0], ent.dxf.start[1])
le = (ent.dxf.end[0], ent.dxf.end[1])
ds = ((ls[0] - k2_junction[0])**2 + (ls[1] - k2_junction[1])**2) ** 0.5
de = ((le[0] - k2_junction[0])**2 + (le[1] - k2_junction[1])**2) ** 0.5
ds = math.dist(ls, k2_junction)
de = math.dist(le, k2_junction)
if ds > tol and de > tol:
continue
ln = ((le[0] - ls[0])**2 + (le[1] - ls[1])**2) ** 0.5
ln = math.dist(le, ls)
if ln > best_len:
best_len = ln
if ds < tol:
@@ -541,13 +541,13 @@ def _find_weichenkoerper_diag_branches(doc):
dy = abs(le[1] - ls[1])
if dx < 0.01 or dy < 0.01:
continue
ln = (dx**2 + dy**2) ** 0.5
ln = math.dist(ls, le)
if ln < 100:
continue
# Das Ende naeher an K1 ist die Junction, das andere ist der K2/K3-Punkt
d_start = ((ls[0] - k1_x)**2 + (ls[1] - k1_y)**2) ** 0.5
d_end = ((le[0] - k1_x)**2 + (le[1] - k1_y)**2) ** 0.5
d_start = math.dist(ls, (k1_x, k1_y))
d_end = math.dist(le, (k1_x, k1_y))
if d_start < d_end:
candidates.append((le, ls))
else:
-1
View File
@@ -3,5 +3,4 @@
ezdxf==1.4.1
pytest==9.0.2
shapely==2.1.2
+109 -109
View File
@@ -1,109 +1,109 @@
Elementnummer;TeileArt;TeileId;Bezeichnung;Planquadrat;Anzahl;Position;Boundingbox;Nachbarn;Merkmale
1;"Omniflo Kurve";"0000";"OFBogen :1";"A/A";1;"";"";"";{"Kurvenwinkel": 22.5, "Radius": 550.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104025"}
2;"Omniflo Kurve";"0000";"OFBogen :2";"A/A";1;"";"";"";{"Kurvenwinkel": 22.5, "Radius": 550.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104025+0_B10090"}
3;"Omniflo Kurve";"0000";"OFBogen :3";"A/A";1;"";"";"";{"Kurvenwinkel": 22.5, "Radius": 550.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104025+0_B10091"}
4;"Omniflo Kurve";"0000";"OFBogen :4";"A/A";1;"";"";"";{"Kurvenwinkel": 45.0, "Radius": 400.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104021"}
5;"Omniflo Kurve";"0000";"OFBogen :5";"A/A";1;"";"";"";{"Kurvenwinkel": 45.0, "Radius": 550.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104026"}
6;"Omniflo Kurve";"0000";"OFBogen :6";"A/A";1;"";"";"";{"Kurvenwinkel": 45.0, "Radius": 550.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104026+0_B10071"}
7;"Omniflo Kurve";"0000";"OFBogen :7";"A/A";1;"";"";"";{"Kurvenwinkel": 45.0, "Radius": 550.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104037"}
8;"Omniflo Kurve";"0000";"OFBogen :8";"A/A";1;"";"";"";{"Kurvenwinkel": 45.0, "Radius": 550.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104029"}
9;"Omniflo Kurve";"0000";"OFBogen :9";"A/A";1;"";"";"";{"Kurvenwinkel": 45.0, "Radius": 630.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104031"}
10;"Omniflo Kurve";"0000";"OFBogen :10";"A/A";1;"";"";"";{"Kurvenwinkel": 45.0, "Radius": 630.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104031+0_B10060"}
11;"Omniflo Kurve";"0000";"OFBogen :11";"B/A";1;"";"";"";{"Kurvenwinkel": 45.0, "Radius": 630.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104031+0_B10070"}
12;"Omniflo Kurve";"0000";"OFBogen :12";"B/A";1;"";"";"";{"Kurvenwinkel": 67.5, "Radius": 400.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104024"}
13;"Omniflo Kurve";"0000";"OFBogen :13";"B/A";1;"";"";"";{"Kurvenwinkel": 67.5, "Radius": 400.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104024+0_B10081"}
14;"Omniflo Kurve";"0000";"OFBogen :14";"B/A";1;"";"";"";{"Kurvenwinkel": 67.5, "Radius": 550.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104027"}
15;"Omniflo Kurve";"0000";"OFBogen :15";"B/A";1;"";"";"";{"Kurvenwinkel": 67.5, "Radius": 550.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104027+0_B10080"}
16;"Omniflo Kurve";"0000";"OFBogen :16";"B/A";1;"";"";"";{"Kurvenwinkel": 67.5, "Radius": 550.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104028"}
17;"Omniflo Kurve";"0000";"OFBogen :17";"B/A";1;"";"";"";{"Kurvenwinkel": 67.5, "Radius": 550.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104065"}
18;"Omniflo Kurve";"0000";"OFBogen :18";"B/A";1;"";"";"";{"Kurvenwinkel": 90.0, "Radius": 400.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104022"}
19;"Omniflo Kurve";"0000";"OFBogen :19";"B/A";1;"";"";"";{"Kurvenwinkel": 90.0, "Radius": 500.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104030"}
20;"Omniflo Kurve";"0000";"OFBogen :20";"B/A";1;"";"";"";{"Kurvenwinkel": 90.0, "Radius": 630.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104033"}
21;"Omniflo Kurve";"0000";"OFBogen :21";"C/A";1;"";"";"";{"Kurvenwinkel": 90.0, "Radius": 630.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104033+0_B10040"}
22;"Omniflo Kurve";"0000";"OFBogen :22";"C/A";1;"";"";"";{"Kurvenwinkel": 90.0, "Radius": 630.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104033+0_B10050"}
23;"Omniflo Kurve";"0000";"OFBogen :23";"C/A";1;"";"";"";{"Kurvenwinkel": 90.0, "Radius": 630.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104035"}
24;"Omniflo Kurve";"0000";"OFBogen :24";"C/A";1;"";"";"";{"Kurvenwinkel": 90.0, "Radius": 630.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104041"}
25;"Omniflo Kurve";"0000";"OFBogen :25";"C/A";1;"";"";"";{"Kurvenwinkel": 90.0, "Radius": 630.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104034"}
26;"Omniflo Kurve";"0000";"OFBogen :26";"C/A";1;"";"";"";{"Kurvenwinkel": 90.0, "Radius": 550.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104066"}
27;"Omniflo Kurve";"0000";"OFBogen :27";"C/A";1;"";"";"";{"Kurvenwinkel": 180.0, "Radius": 650.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104043"}
28;"Omniflo Weiche";"0000";"OFWeiche :1";"C/A";1;"";"";"";{"Weichentyp": "Einzelweiche", "Richtung": "1", "Weichenwinkel": 22.5, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834342011"}
29;"Omniflo Weiche";"0000";"OFWeiche :2";"C/A";1;"";"";"";{"Weichentyp": "Einzelweiche", "Richtung": "2", "Weichenwinkel": 22.5, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834342001"}
30;"Omniflo Weiche";"0000";"OFWeiche :3";"C/A";1;"";"";"";{"Weichentyp": "Einzelweiche", "Richtung": "1", "Weichenwinkel": 22.5, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834342012"}
31;"Omniflo Weiche";"0000";"OFWeiche :4";"D/A";1;"";"";"";{"Weichentyp": "Einzelweiche", "Richtung": "2", "Weichenwinkel": 22.5, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834342002"}
32;"Omniflo Weiche";"0000";"OFWeiche :1";"D/A";1;"";"";"";{"Weichentyp": "Doppelweiche", "Richtung": "3", "Weichenwinkel": 22.5, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834342100"}
33;"Omniflo Weiche";"0000";"OFWeiche :2";"D/A";1;"";"";"";{"Weichentyp": "Doppelweiche", "Richtung": "3", "Weichenwinkel": 22.5, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834342101"}
34;"Omniflo Weiche";"0000";"OFWeiche :1";"D/A";1;"";"";"";{"Weichentyp": "Dreiwegeweiche", "Richtung": "7", "Weichenwinkel": 22.5, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834342200"}
35;"Omniflo Weiche";"0000";"OFWeiche :2";"D/A";1;"";"";"";{"Weichentyp": "Dreiwegeweiche", "Richtung": "7", "Weichenwinkel": 22.5, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834342201"}
36;"Omniflo Weiche";"0000";"OFWeiche :5";"D/A";1;"";"";"";{"Weichentyp": "Einzelweiche", "Richtung": "1", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372001"}
37;"Omniflo Weiche";"0000";"OFWeiche :6";"D/A";1;"";"";"";{"Weichentyp": "Einzelweiche", "Richtung": "1", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372002"}
38;"Omniflo Weiche";"0000";"OFWeiche :7";"D/A";1;"";"";"";{"Weichentyp": "Einzelweiche", "Richtung": "1", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "834372002+0_BG090090"}
39;"Omniflo Weiche";"0000";"OFWeiche :8";"D/A";1;"";"";"";{"Weichentyp": "Einzelweiche", "Richtung": "2", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372004"}
40;"Omniflo Weiche";"0000";"OFWeiche :9";"D/A";1;"";"";"";{"Weichentyp": "Einzelweiche", "Richtung": "2", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372005"}
41;"Omniflo Weiche";"0000";"OFWeiche :10";"E/A";1;"";"";"";{"Weichentyp": "Einzelweiche", "Richtung": "2", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "834372005+0_BG090090"}
42;"Omniflo Weiche";"0000";"OFWeiche :11";"E/A";1;"";"";"";{"Weichentyp": "Einzelweiche", "Richtung": "1", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372007"}
43;"Omniflo Weiche";"0000";"OFWeiche :12";"E/A";1;"";"";"";{"Weichentyp": "Einzelweiche", "Richtung": "1", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372008"}
44;"Omniflo Weiche";"0000";"OFWeiche :13";"E/A";1;"";"";"";{"Weichentyp": "Einzelweiche", "Richtung": "1", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "834372008+0_BG190090"}
45;"Omniflo Weiche";"0000";"OFWeiche :14";"E/A";1;"";"";"";{"Weichentyp": "Einzelweiche", "Richtung": "2", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372010"}
46;"Omniflo Weiche";"0000";"OFWeiche :15";"E/A";1;"";"";"";{"Weichentyp": "Einzelweiche", "Richtung": "2", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372011"}
47;"Omniflo Weiche";"0000";"OFWeiche :16";"E/A";1;"";"";"";{"Weichentyp": "Einzelweiche", "Richtung": "2", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "834372011+0_BG190090"}
48;"Omniflo Weiche";"0000";"OFWeiche :17";"E/A";1;"";"";"";{"Weichentyp": "Einzelweiche", "Richtung": "1", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372021"}
49;"Omniflo Weiche";"0000";"OFWeiche :18";"E/A";1;"";"";"";{"Weichentyp": "Einzelweiche", "Richtung": "1", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372022"}
50;"Omniflo Weiche";"0000";"OFWeiche :19";"E/A";1;"";"";"";{"Weichentyp": "Einzelweiche", "Richtung": "2", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372024"}
51;"Omniflo Weiche";"0000";"OFWeiche :20";"F/A";1;"";"";"";{"Weichentyp": "Einzelweiche", "Richtung": "2", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372025"}
52;"Omniflo Weiche";"0000";"OFWeiche :21";"F/A";1;"";"";"";{"Weichentyp": "Einzelweiche", "Richtung": "1", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372027"}
53;"Omniflo Weiche";"0000";"OFWeiche :22";"F/A";1;"";"";"";{"Weichentyp": "Einzelweiche", "Richtung": "1", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372028"}
54;"Omniflo Weiche";"0000";"OFWeiche :23";"F/A";1;"";"";"";{"Weichentyp": "Einzelweiche", "Richtung": "1", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "834372028+0_BG080090"}
55;"Omniflo Weiche";"0000";"OFWeiche :24";"F/A";1;"";"";"";{"Weichentyp": "Einzelweiche", "Richtung": "2", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372030"}
56;"Omniflo Weiche";"0000";"OFWeiche :25";"F/A";1;"";"";"";{"Weichentyp": "Einzelweiche", "Richtung": "2", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372031"}
57;"Omniflo Weiche";"0000";"OFWeiche :26";"F/A";1;"";"";"";{"Weichentyp": "Einzelweiche", "Richtung": "2", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "834372031+0_BG080090"}
58;"Omniflo Weiche";"0000";"OFWeiche :27";"F/A";1;"";"";"";{"Weichentyp": "Einzelweiche", "Richtung": "1", "Weichenwinkel": 0.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372047"}
59;"Omniflo Weiche";"0000";"OFWeiche :28";"F/A";1;"";"";"";{"Weichentyp": "Einzelweiche", "Richtung": "1", "Weichenwinkel": 0.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372048"}
60;"Omniflo Weiche";"0000";"OFWeiche :29";"F/A";1;"";"";"";{"Weichentyp": "Einzelweiche", "Richtung": "2", "Weichenwinkel": 0.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372050"}
61;"Omniflo Weiche";"0000";"OFWeiche :30";"G/A";1;"";"";"";{"Weichentyp": "Einzelweiche", "Richtung": "2", "Weichenwinkel": 0.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372051"}
62;"Omniflo Weiche";"0000";"OFWeiche :3";"G/A";1;"";"";"";{"Weichentyp": "Doppelweiche", "Richtung": "3", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372100"}
63;"Omniflo Weiche";"0000";"OFWeiche :4";"G/A";1;"";"";"";{"Weichentyp": "Doppelweiche", "Richtung": "3", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372101"}
64;"Omniflo Weiche";"0000";"OFWeiche :5";"G/A";1;"";"";"";{"Weichentyp": "Doppelweiche", "Richtung": "3", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "0_BG090090+834372101"}
65;"Omniflo Weiche";"0000";"OFWeiche :6";"G/A";1;"";"";"";{"Weichentyp": "Doppelweiche", "Richtung": "3", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "834372101+0_BG090090"}
66;"Omniflo Weiche";"0000";"OFWeiche :7";"G/A";1;"";"";"";{"Weichentyp": "Doppelweiche", "Richtung": "3", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "0_BG090090+834372101+0_BG090090"}
67;"Omniflo Weiche";"0000";"OFWeiche :8";"G/A";1;"";"";"";{"Weichentyp": "Doppelweiche", "Richtung": "3", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372103"}
68;"Omniflo Weiche";"0000";"OFWeiche :9";"G/A";1;"";"";"";{"Weichentyp": "Doppelweiche", "Richtung": "3", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372104"}
69;"Omniflo Weiche";"0000";"OFWeiche :10";"G/A";1;"";"";"";{"Weichentyp": "Doppelweiche", "Richtung": "3", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "0_BG190090+834372104"}
70;"Omniflo Weiche";"0000";"OFWeiche :11";"G/A";1;"";"";"";{"Weichentyp": "Doppelweiche", "Richtung": "3", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "834372104+0_BG190090"}
71;"Omniflo Weiche";"0000";"OFWeiche :12";"H/A";1;"";"";"";{"Weichentyp": "Doppelweiche", "Richtung": "3", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "0_BG190090+834372104+0_BG190090"}
72;"Omniflo Weiche";"0000";"OFWeiche :13";"H/A";1;"";"";"";{"Weichentyp": "Doppelweiche", "Richtung": "3", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372106"}
73;"Omniflo Weiche";"0000";"OFWeiche :14";"H/A";1;"";"";"";{"Weichentyp": "Doppelweiche", "Richtung": "3", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372107"}
74;"Omniflo Weiche";"0000";"OFWeiche :15";"H/A";1;"";"";"";{"Weichentyp": "Doppelweiche", "Richtung": "3", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372109"}
75;"Omniflo Weiche";"0000";"OFWeiche :16";"H/A";1;"";"";"";{"Weichentyp": "Doppelweiche", "Richtung": "3", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372110"}
76;"Omniflo Weiche";"0000";"OFWeiche :17";"H/A";1;"";"";"";{"Weichentyp": "Doppelweiche", "Richtung": "3", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "0_BG080090+834372110"}
77;"Omniflo Weiche";"0000";"OFWeiche :18";"H/A";1;"";"";"";{"Weichentyp": "Doppelweiche", "Richtung": "3", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "834372110+0_BG080090"}
78;"Omniflo Weiche";"0000";"OFWeiche :19";"H/A";1;"";"";"";{"Weichentyp": "Doppelweiche", "Richtung": "3", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "0_BG080090+834372110+0_BG080090"}
79;"Omniflo Weiche";"0000";"OFWeiche :20";"H/A";1;"";"";"";{"Weichentyp": "Doppelweiche", "Richtung": "3", "Weichenwinkel": 0.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372115"}
80;"Omniflo Weiche";"0000";"OFWeiche :21";"H/A";1;"";"";"";{"Weichentyp": "Doppelweiche", "Richtung": "3", "Weichenwinkel": 0.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372116"}
81;"Omniflo Weiche";"0000";"OFWeiche :3";"I/A";1;"";"";"";{"Weichentyp": "Dreiwegeweiche", "Richtung": "7", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372200"}
82;"Omniflo Weiche";"0000";"OFWeiche :4";"I/A";1;"";"";"";{"Weichentyp": "Dreiwegeweiche", "Richtung": "7", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372201"}
83;"Omniflo Weiche";"0000";"OFWeiche :5";"I/A";1;"";"";"";{"Weichentyp": "Dreiwegeweiche", "Richtung": "7", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "0_BG090090+834372201"}
84;"Omniflo Weiche";"0000";"OFWeiche :6";"I/A";1;"";"";"";{"Weichentyp": "Dreiwegeweiche", "Richtung": "7", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "834372201+0_BG090090"}
85;"Omniflo Weiche";"0000";"OFWeiche :7";"I/A";1;"";"";"";{"Weichentyp": "Dreiwegeweiche", "Richtung": "7", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "0_BG090090+834372201+0_BG090090"}
86;"Omniflo Weiche";"0000";"OFWeiche :8";"I/A";1;"";"";"";{"Weichentyp": "Dreiwegeweiche", "Richtung": "7", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372203"}
87;"Omniflo Weiche";"0000";"OFWeiche :9";"I/A";1;"";"";"";{"Weichentyp": "Dreiwegeweiche", "Richtung": "7", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372204"}
88;"Omniflo Weiche";"0000";"OFWeiche :10";"I/A";1;"";"";"";{"Weichentyp": "Dreiwegeweiche", "Richtung": "7", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "0_BG190090+834372204"}
89;"Omniflo Weiche";"0000";"OFWeiche :11";"I/A";1;"";"";"";{"Weichentyp": "Dreiwegeweiche", "Richtung": "7", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "834372204+0_BG190090"}
90;"Omniflo Weiche";"0000";"OFWeiche :12";"I/A";1;"";"";"";{"Weichentyp": "Dreiwegeweiche", "Richtung": "7", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "0_BG190090+834372204+0_BG190090"}
91;"Omniflo Weiche";"0000";"OFWeiche :13";"J/A";1;"";"";"";{"Weichentyp": "Dreiwegeweiche", "Richtung": "7", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372206"}
92;"Omniflo Weiche";"0000";"OFWeiche :14";"J/A";1;"";"";"";{"Weichentyp": "Dreiwegeweiche", "Richtung": "7", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372207"}
93;"Omniflo Weiche";"0000";"OFWeiche :15";"J/A";1;"";"";"";{"Weichentyp": "Dreiwegeweiche", "Richtung": "7", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372209"}
94;"Omniflo Weiche";"0000";"OFWeiche :16";"J/A";1;"";"";"";{"Weichentyp": "Dreiwegeweiche", "Richtung": "7", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372210"}
95;"Omniflo Weiche";"0000";"OFWeiche :17";"J/A";1;"";"";"";{"Weichentyp": "Dreiwegeweiche", "Richtung": "7", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "0_BG080090+834372210"}
96;"Omniflo Weiche";"0000";"OFWeiche :18";"J/A";1;"";"";"";{"Weichentyp": "Dreiwegeweiche", "Richtung": "7", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "834372210+0_BG080090"}
97;"Omniflo Weiche";"0000";"OFWeiche :19";"J/A";1;"";"";"";{"Weichentyp": "Dreiwegeweiche", "Richtung": "7", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "0_BG080090+834372210+0_BG080090"}
98;"Omniflo Weiche";"0000";"OFWeiche :20";"J/A";1;"";"";"";{"Weichentyp": "Dreiwegeweiche", "Richtung": "7", "Weichenwinkel": 0.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372215"}
99;"Omniflo Weiche";"0000";"OFWeiche :21";"J/A";1;"";"";"";{"Weichentyp": "Dreiwegeweiche", "Richtung": "7", "Weichenwinkel": 0.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372216"}
100;"Omniflo Weiche";"0000";"OFWeiche :1";"J/A";1;"";"";"";{"Weichentyp": "Dreifachweiche", "Richtung": "3", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372400"}
101;"Omniflo Weiche";"0000";"OFWeiche :2";"K/A";1;"";"";"";{"Weichentyp": "Dreifachweiche", "Richtung": "3", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372403"}
102;"Omniflo Weiche";"0000";"OFWeiche :3";"K/A";1;"";"";"";{"Weichentyp": "Dreifachweiche", "Richtung": "3", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372404"}
103;"Omniflo Weiche";"0000";"OFWeiche :4";"K/A";1;"";"";"";{"Weichentyp": "Dreifachweiche", "Richtung": "3", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "0_BG071090+834372404+0_BG071090"}
104;"Omniflo Weiche";"0000";"OFWeiche :5";"K/A";1;"";"";"";{"Weichentyp": "Dreifachweiche", "Richtung": "3", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "0_BG071090+834372404"}
105;"Omniflo Weiche";"0000";"OFWeiche :6";"K/A";1;"";"";"";{"Weichentyp": "Dreifachweiche", "Richtung": "3", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "834372404+0_BG071090"}
106;"Omniflo Weiche";"0000";"OFWeiche :1";"K/A";1;"";"";"";{"Weichentyp": "Deltaweiche", "Richtung": "7", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372401"}
107;"Omniflo Weiche";"0000";"OFWeiche :1";"K/A";1;"";"";"";{"Weichentyp": "Sternweiche", "Richtung": "3", "Weichenwinkel": 0.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372420"}
108;"Omniflo Sum";"autogenerated_of_json";"Omniflo sum";"";1;"";"";"";{"Anzahl Bögen": 27, "Anzahl Weichengrundkörper": 0, "Anzahl Einwegweichen": 30, "Anzahl Deltaweichen": 7, "Anzahl Doppelweichen und Dreiwegeweichen": 42, "Anzahl Sternweichen": 1, "Gesamtlänge AP110": 0.0, "Gesamtlänge AP60": 0.0}
Elementnummer;TeileArt;TeileId;Bezeichnung;Planquadrat;Anzahl;Position;Boundingbox;Nachbarn;Fehler;Merkmale
1;"Omniflo Kurve";"0000";"OFBogen :1";"A/A";1;"";"";"";"unverbunden";{"Kurvenwinkel": 22.5, "Radius": 550.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104025"}
2;"Omniflo Kurve";"0000";"OFBogen :2";"A/A";1;"";"";"";"unverbunden";{"Kurvenwinkel": 22.5, "Radius": 550.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104025, 0_B10090"}
3;"Omniflo Kurve";"0000";"OFBogen :3";"A/A";1;"";"";"";"unverbunden";{"Kurvenwinkel": 22.5, "Radius": 550.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104025, 0_B10091"}
4;"Omniflo Kurve";"0000";"OFBogen :4";"A/A";1;"";"";"";"unverbunden";{"Kurvenwinkel": 45.0, "Radius": 400.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104021"}
5;"Omniflo Kurve";"0000";"OFBogen :5";"A/A";1;"";"";"";"unverbunden";{"Kurvenwinkel": 45.0, "Radius": 550.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104026"}
6;"Omniflo Kurve";"0000";"OFBogen :6";"A/A";1;"";"";"";"unverbunden";{"Kurvenwinkel": 45.0, "Radius": 550.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104026, 0_B10071"}
7;"Omniflo Kurve";"0000";"OFBogen :7";"A/A";1;"";"";"";"unverbunden";{"Kurvenwinkel": 45.0, "Radius": 550.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104037"}
8;"Omniflo Kurve";"0000";"OFBogen :8";"A/A";1;"";"";"";"unverbunden";{"Kurvenwinkel": 45.0, "Radius": 550.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104029"}
9;"Omniflo Kurve";"0000";"OFBogen :9";"A/A";1;"";"";"";"unverbunden";{"Kurvenwinkel": 45.0, "Radius": 630.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104031"}
10;"Omniflo Kurve";"0000";"OFBogen :10";"A/A";1;"";"";"";"unverbunden";{"Kurvenwinkel": 45.0, "Radius": 630.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104031, 0_B10060"}
11;"Omniflo Kurve";"0000";"OFBogen :11";"B/A";1;"";"";"";"unverbunden";{"Kurvenwinkel": 45.0, "Radius": 630.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104031, 0_B10070"}
12;"Omniflo Kurve";"0000";"OFBogen :12";"B/A";1;"";"";"";"unverbunden";{"Kurvenwinkel": 67.5, "Radius": 400.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104024"}
13;"Omniflo Kurve";"0000";"OFBogen :13";"B/A";1;"";"";"";"unverbunden";{"Kurvenwinkel": 67.5, "Radius": 400.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104024, 0_B10081"}
14;"Omniflo Kurve";"0000";"OFBogen :14";"B/A";1;"";"";"";"unverbunden";{"Kurvenwinkel": 67.5, "Radius": 550.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104027"}
15;"Omniflo Kurve";"0000";"OFBogen :15";"B/A";1;"";"";"";"unverbunden";{"Kurvenwinkel": 67.5, "Radius": 550.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104027, 0_B10080"}
16;"Omniflo Kurve";"0000";"OFBogen :16";"B/A";1;"";"";"";"unverbunden";{"Kurvenwinkel": 67.5, "Radius": 550.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104028"}
17;"Omniflo Kurve";"0000";"OFBogen :17";"B/A";1;"";"";"";"unverbunden";{"Kurvenwinkel": 67.5, "Radius": 550.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104065"}
18;"Omniflo Kurve";"0000";"OFBogen :18";"B/A";1;"";"";"";"unverbunden";{"Kurvenwinkel": 90.0, "Radius": 400.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104022"}
19;"Omniflo Kurve";"0000";"OFBogen :19";"B/A";1;"";"";"";"unverbunden";{"Kurvenwinkel": 90.0, "Radius": 500.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104030"}
20;"Omniflo Kurve";"0000";"OFBogen :20";"B/A";1;"";"";"";"unverbunden";{"Kurvenwinkel": 90.0, "Radius": 630.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104033"}
21;"Omniflo Kurve";"0000";"OFBogen :21";"C/A";1;"";"";"";"unverbunden";{"Kurvenwinkel": 90.0, "Radius": 630.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104033, 0_B10040"}
22;"Omniflo Kurve";"0000";"OFBogen :22";"C/A";1;"";"";"";"unverbunden";{"Kurvenwinkel": 90.0, "Radius": 630.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104033, 0_B10050"}
23;"Omniflo Kurve";"0000";"OFBogen :23";"C/A";1;"";"";"";"unverbunden";{"Kurvenwinkel": 90.0, "Radius": 630.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104035"}
24;"Omniflo Kurve";"0000";"OFBogen :24";"C/A";1;"";"";"";"unverbunden";{"Kurvenwinkel": 90.0, "Radius": 630.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104041"}
25;"Omniflo Kurve";"0000";"OFBogen :25";"C/A";1;"";"";"";"unverbunden";{"Kurvenwinkel": 90.0, "Radius": 630.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104034"}
26;"Omniflo Kurve";"0000";"OFBogen :26";"C/A";1;"";"";"";"unverbunden";{"Kurvenwinkel": 90.0, "Radius": 550.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104066"}
27;"Omniflo Kurve";"0000";"OFBogen :27";"C/A";1;"";"";"";"unverbunden";{"Kurvenwinkel": 180.0, "Radius": 650.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104043"}
28;"Omniflo Weiche";"0000";"OFWeiche :1";"C/A";1;"";"";"";"unverbunden";{"Weichentyp": "Einzelweiche", "Richtung": "1", "Weichenwinkel": 22.5, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834342011"}
29;"Omniflo Weiche";"0000";"OFWeiche :2";"C/A";1;"";"";"";"unverbunden";{"Weichentyp": "Einzelweiche", "Richtung": "2", "Weichenwinkel": 22.5, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834342001"}
30;"Omniflo Weiche";"0000";"OFWeiche :3";"C/A";1;"";"";"";"unverbunden";{"Weichentyp": "Einzelweiche", "Richtung": "1", "Weichenwinkel": 22.5, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834342012"}
31;"Omniflo Weiche";"0000";"OFWeiche :4";"D/A";1;"";"";"";"unverbunden";{"Weichentyp": "Einzelweiche", "Richtung": "2", "Weichenwinkel": 22.5, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834342002"}
32;"Omniflo Weiche";"0000";"OFWeiche :1";"D/A";1;"";"";"";"unverbunden";{"Weichentyp": "Doppelweiche", "Richtung": "3", "Weichenwinkel": 22.5, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834342100"}
33;"Omniflo Weiche";"0000";"OFWeiche :2";"D/A";1;"";"";"";"unverbunden";{"Weichentyp": "Doppelweiche", "Richtung": "3", "Weichenwinkel": 22.5, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834342101"}
34;"Omniflo Weiche";"0000";"OFWeiche :1";"D/A";1;"";"";"";"unverbunden";{"Weichentyp": "Dreiwegeweiche", "Richtung": "7", "Weichenwinkel": 22.5, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834342200"}
35;"Omniflo Weiche";"0000";"OFWeiche :2";"D/A";1;"";"";"";"unverbunden";{"Weichentyp": "Dreiwegeweiche", "Richtung": "7", "Weichenwinkel": 22.5, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834342201"}
36;"Omniflo Weiche";"0000";"OFWeiche :5";"D/A";1;"";"";"";"unverbunden";{"Weichentyp": "Einzelweiche", "Richtung": "1", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372001"}
37;"Omniflo Weiche";"0000";"OFWeiche :6";"D/A";1;"";"";"";"unverbunden";{"Weichentyp": "Einzelweiche", "Richtung": "1", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372002"}
38;"Omniflo Weiche";"0000";"OFWeiche :7";"D/A";1;"";"";"";"unverbunden";{"Weichentyp": "Einzelweiche", "Richtung": "1", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "834372002, 0_BG090090"}
39;"Omniflo Weiche";"0000";"OFWeiche :8";"D/A";1;"";"";"";"unverbunden";{"Weichentyp": "Einzelweiche", "Richtung": "2", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372004"}
40;"Omniflo Weiche";"0000";"OFWeiche :9";"D/A";1;"";"";"";"unverbunden";{"Weichentyp": "Einzelweiche", "Richtung": "2", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372005"}
41;"Omniflo Weiche";"0000";"OFWeiche :10";"E/A";1;"";"";"";"unverbunden";{"Weichentyp": "Einzelweiche", "Richtung": "2", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "834372005, 0_BG090090"}
42;"Omniflo Weiche";"0000";"OFWeiche :11";"E/A";1;"";"";"";"unverbunden";{"Weichentyp": "Einzelweiche", "Richtung": "1", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372007"}
43;"Omniflo Weiche";"0000";"OFWeiche :12";"E/A";1;"";"";"";"unverbunden";{"Weichentyp": "Einzelweiche", "Richtung": "1", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372008"}
44;"Omniflo Weiche";"0000";"OFWeiche :13";"E/A";1;"";"";"";"unverbunden";{"Weichentyp": "Einzelweiche", "Richtung": "1", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "834372008, 0_BG190090"}
45;"Omniflo Weiche";"0000";"OFWeiche :14";"E/A";1;"";"";"";"unverbunden";{"Weichentyp": "Einzelweiche", "Richtung": "2", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372010"}
46;"Omniflo Weiche";"0000";"OFWeiche :15";"E/A";1;"";"";"";"unverbunden";{"Weichentyp": "Einzelweiche", "Richtung": "2", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372011"}
47;"Omniflo Weiche";"0000";"OFWeiche :16";"E/A";1;"";"";"";"unverbunden";{"Weichentyp": "Einzelweiche", "Richtung": "2", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "834372011, 0_BG190090"}
48;"Omniflo Weiche";"0000";"OFWeiche :17";"E/A";1;"";"";"";"unverbunden";{"Weichentyp": "Einzelweiche", "Richtung": "1", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372021"}
49;"Omniflo Weiche";"0000";"OFWeiche :18";"E/A";1;"";"";"";"unverbunden";{"Weichentyp": "Einzelweiche", "Richtung": "1", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372022"}
50;"Omniflo Weiche";"0000";"OFWeiche :19";"E/A";1;"";"";"";"unverbunden";{"Weichentyp": "Einzelweiche", "Richtung": "2", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372024"}
51;"Omniflo Weiche";"0000";"OFWeiche :20";"F/A";1;"";"";"";"unverbunden";{"Weichentyp": "Einzelweiche", "Richtung": "2", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372025"}
52;"Omniflo Weiche";"0000";"OFWeiche :21";"F/A";1;"";"";"";"unverbunden";{"Weichentyp": "Einzelweiche", "Richtung": "1", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372027"}
53;"Omniflo Weiche";"0000";"OFWeiche :22";"F/A";1;"";"";"";"unverbunden";{"Weichentyp": "Einzelweiche", "Richtung": "1", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372028"}
54;"Omniflo Weiche";"0000";"OFWeiche :23";"F/A";1;"";"";"";"unverbunden";{"Weichentyp": "Einzelweiche", "Richtung": "1", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "834372028, 0_BG080090"}
55;"Omniflo Weiche";"0000";"OFWeiche :24";"F/A";1;"";"";"";"unverbunden";{"Weichentyp": "Einzelweiche", "Richtung": "2", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372030"}
56;"Omniflo Weiche";"0000";"OFWeiche :25";"F/A";1;"";"";"";"unverbunden";{"Weichentyp": "Einzelweiche", "Richtung": "2", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372031"}
57;"Omniflo Weiche";"0000";"OFWeiche :26";"F/A";1;"";"";"";"unverbunden";{"Weichentyp": "Einzelweiche", "Richtung": "2", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "834372031, 0_BG080090"}
58;"Omniflo Weiche";"0000";"OFWeiche :27";"F/A";1;"";"";"";"unverbunden";{"Weichentyp": "Einzelweiche", "Richtung": "1", "Weichenwinkel": 0.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372047"}
59;"Omniflo Weiche";"0000";"OFWeiche :28";"F/A";1;"";"";"";"unverbunden";{"Weichentyp": "Einzelweiche", "Richtung": "1", "Weichenwinkel": 0.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372048"}
60;"Omniflo Weiche";"0000";"OFWeiche :29";"F/A";1;"";"";"";"unverbunden";{"Weichentyp": "Einzelweiche", "Richtung": "2", "Weichenwinkel": 0.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372050"}
61;"Omniflo Weiche";"0000";"OFWeiche :30";"G/A";1;"";"";"";"unverbunden";{"Weichentyp": "Einzelweiche", "Richtung": "2", "Weichenwinkel": 0.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372051"}
62;"Omniflo Weiche";"0000";"OFWeiche :3";"G/A";1;"";"";"";"unverbunden";{"Weichentyp": "Doppelweiche", "Richtung": "3", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372100"}
63;"Omniflo Weiche";"0000";"OFWeiche :4";"G/A";1;"";"";"";"unverbunden";{"Weichentyp": "Doppelweiche", "Richtung": "3", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372101"}
64;"Omniflo Weiche";"0000";"OFWeiche :5";"G/A";1;"";"";"";"unverbunden";{"Weichentyp": "Doppelweiche", "Richtung": "3", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "0_BG090090, 834372101"}
65;"Omniflo Weiche";"0000";"OFWeiche :6";"G/A";1;"";"";"";"unverbunden";{"Weichentyp": "Doppelweiche", "Richtung": "3", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "834372101, 0_BG090090"}
66;"Omniflo Weiche";"0000";"OFWeiche :7";"G/A";1;"";"";"";"unverbunden";{"Weichentyp": "Doppelweiche", "Richtung": "3", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "0_BG090090, 834372101, 0_BG090090"}
67;"Omniflo Weiche";"0000";"OFWeiche :8";"G/A";1;"";"";"";"unverbunden";{"Weichentyp": "Doppelweiche", "Richtung": "3", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372103"}
68;"Omniflo Weiche";"0000";"OFWeiche :9";"G/A";1;"";"";"";"unverbunden";{"Weichentyp": "Doppelweiche", "Richtung": "3", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372104"}
69;"Omniflo Weiche";"0000";"OFWeiche :10";"G/A";1;"";"";"";"unverbunden";{"Weichentyp": "Doppelweiche", "Richtung": "3", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "0_BG190090, 834372104"}
70;"Omniflo Weiche";"0000";"OFWeiche :11";"G/A";1;"";"";"";"unverbunden";{"Weichentyp": "Doppelweiche", "Richtung": "3", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "834372104, 0_BG190090"}
71;"Omniflo Weiche";"0000";"OFWeiche :12";"H/A";1;"";"";"";"unverbunden";{"Weichentyp": "Doppelweiche", "Richtung": "3", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "0_BG190090, 834372104, 0_BG190090"}
72;"Omniflo Weiche";"0000";"OFWeiche :13";"H/A";1;"";"";"";"unverbunden";{"Weichentyp": "Doppelweiche", "Richtung": "3", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372106"}
73;"Omniflo Weiche";"0000";"OFWeiche :14";"H/A";1;"";"";"";"unverbunden";{"Weichentyp": "Doppelweiche", "Richtung": "3", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372107"}
74;"Omniflo Weiche";"0000";"OFWeiche :15";"H/A";1;"";"";"";"unverbunden";{"Weichentyp": "Doppelweiche", "Richtung": "3", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372109"}
75;"Omniflo Weiche";"0000";"OFWeiche :16";"H/A";1;"";"";"";"unverbunden";{"Weichentyp": "Doppelweiche", "Richtung": "3", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372110"}
76;"Omniflo Weiche";"0000";"OFWeiche :17";"H/A";1;"";"";"";"unverbunden";{"Weichentyp": "Doppelweiche", "Richtung": "3", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "0_BG080090, 834372110"}
77;"Omniflo Weiche";"0000";"OFWeiche :18";"H/A";1;"";"";"";"unverbunden";{"Weichentyp": "Doppelweiche", "Richtung": "3", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "834372110, 0_BG080090"}
78;"Omniflo Weiche";"0000";"OFWeiche :19";"H/A";1;"";"";"";"unverbunden";{"Weichentyp": "Doppelweiche", "Richtung": "3", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "0_BG080090, 834372110, 0_BG080090"}
79;"Omniflo Weiche";"0000";"OFWeiche :20";"H/A";1;"";"";"";"unverbunden";{"Weichentyp": "Doppelweiche", "Richtung": "3", "Weichenwinkel": 0.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372115"}
80;"Omniflo Weiche";"0000";"OFWeiche :21";"H/A";1;"";"";"";"unverbunden";{"Weichentyp": "Doppelweiche", "Richtung": "3", "Weichenwinkel": 0.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372116"}
81;"Omniflo Weiche";"0000";"OFWeiche :3";"I/A";1;"";"";"";"unverbunden";{"Weichentyp": "Dreiwegeweiche", "Richtung": "7", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372200"}
82;"Omniflo Weiche";"0000";"OFWeiche :4";"I/A";1;"";"";"";"unverbunden";{"Weichentyp": "Dreiwegeweiche", "Richtung": "7", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372201"}
83;"Omniflo Weiche";"0000";"OFWeiche :5";"I/A";1;"";"";"";"unverbunden";{"Weichentyp": "Dreiwegeweiche", "Richtung": "7", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "0_BG090090, 834372201"}
84;"Omniflo Weiche";"0000";"OFWeiche :6";"I/A";1;"";"";"";"unverbunden";{"Weichentyp": "Dreiwegeweiche", "Richtung": "7", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "834372201, 0_BG090090"}
85;"Omniflo Weiche";"0000";"OFWeiche :7";"I/A";1;"";"";"";"unverbunden";{"Weichentyp": "Dreiwegeweiche", "Richtung": "7", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "0_BG090090, 834372201, 0_BG090090"}
86;"Omniflo Weiche";"0000";"OFWeiche :8";"I/A";1;"";"";"";"unverbunden";{"Weichentyp": "Dreiwegeweiche", "Richtung": "7", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372203"}
87;"Omniflo Weiche";"0000";"OFWeiche :9";"I/A";1;"";"";"";"unverbunden";{"Weichentyp": "Dreiwegeweiche", "Richtung": "7", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372204"}
88;"Omniflo Weiche";"0000";"OFWeiche :10";"I/A";1;"";"";"";"unverbunden";{"Weichentyp": "Dreiwegeweiche", "Richtung": "7", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "0_BG190090, 834372204"}
89;"Omniflo Weiche";"0000";"OFWeiche :11";"I/A";1;"";"";"";"unverbunden";{"Weichentyp": "Dreiwegeweiche", "Richtung": "7", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "834372204, 0_BG190090"}
90;"Omniflo Weiche";"0000";"OFWeiche :12";"I/A";1;"";"";"";"unverbunden";{"Weichentyp": "Dreiwegeweiche", "Richtung": "7", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "0_BG190090, 834372204, 0_BG190090"}
91;"Omniflo Weiche";"0000";"OFWeiche :13";"J/A";1;"";"";"";"unverbunden";{"Weichentyp": "Dreiwegeweiche", "Richtung": "7", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372206"}
92;"Omniflo Weiche";"0000";"OFWeiche :14";"J/A";1;"";"";"";"unverbunden";{"Weichentyp": "Dreiwegeweiche", "Richtung": "7", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372207"}
93;"Omniflo Weiche";"0000";"OFWeiche :15";"J/A";1;"";"";"";"unverbunden";{"Weichentyp": "Dreiwegeweiche", "Richtung": "7", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372209"}
94;"Omniflo Weiche";"0000";"OFWeiche :16";"J/A";1;"";"";"";"unverbunden";{"Weichentyp": "Dreiwegeweiche", "Richtung": "7", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372210"}
95;"Omniflo Weiche";"0000";"OFWeiche :17";"J/A";1;"";"";"";"unverbunden";{"Weichentyp": "Dreiwegeweiche", "Richtung": "7", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "0_BG080090, 834372210"}
96;"Omniflo Weiche";"0000";"OFWeiche :18";"J/A";1;"";"";"";"unverbunden";{"Weichentyp": "Dreiwegeweiche", "Richtung": "7", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "834372210, 0_BG080090"}
97;"Omniflo Weiche";"0000";"OFWeiche :19";"J/A";1;"";"";"";"unverbunden";{"Weichentyp": "Dreiwegeweiche", "Richtung": "7", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "0_BG080090, 834372210, 0_BG080090"}
98;"Omniflo Weiche";"0000";"OFWeiche :20";"J/A";1;"";"";"";"unverbunden";{"Weichentyp": "Dreiwegeweiche", "Richtung": "7", "Weichenwinkel": 0.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372215"}
99;"Omniflo Weiche";"0000";"OFWeiche :21";"J/A";1;"";"";"";"unverbunden";{"Weichentyp": "Dreiwegeweiche", "Richtung": "7", "Weichenwinkel": 0.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372216"}
100;"Omniflo Weiche";"0000";"OFWeiche :1";"J/A";1;"";"";"";"unverbunden";{"Weichentyp": "Deltaweiche", "Richtung": "3", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372400"}
101;"Omniflo Weiche";"0000";"OFWeiche :2";"K/A";1;"";"";"";"unverbunden";{"Weichentyp": "Deltaweiche", "Richtung": "3", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372403"}
102;"Omniflo Weiche";"0000";"OFWeiche :3";"K/A";1;"";"";"";"unverbunden";{"Weichentyp": "Deltaweiche", "Richtung": "3", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372404"}
103;"Omniflo Weiche";"0000";"OFWeiche :4";"K/A";1;"";"";"";"unverbunden";{"Weichentyp": "Deltaweiche", "Richtung": "3", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "0_BG071090, 834372404, 0_BG071090"}
104;"Omniflo Weiche";"0000";"OFWeiche :5";"K/A";1;"";"";"";"unverbunden";{"Weichentyp": "Deltaweiche", "Richtung": "3", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "0_BG071090, 834372404"}
105;"Omniflo Weiche";"0000";"OFWeiche :6";"K/A";1;"";"";"";"unverbunden";{"Weichentyp": "Deltaweiche", "Richtung": "3", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "834372404, 0_BG071090"}
106;"Omniflo Weiche";"0000";"OFWeiche :7";"K/A";1;"";"";"";"unverbunden";{"Weichentyp": "Deltaweiche", "Richtung": "7", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372401"}
107;"Omniflo Weiche";"0000";"OFWeiche :1";"K/A";1;"";"";"";"unverbunden";{"Weichentyp": "Sternweiche", "Richtung": "3", "Weichenwinkel": 0.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372420"}
108;"Omniflo Sum";"autogenerated_of_json";"Omniflo sum";"";1;"";"";"";"";{"Anzahl Bögen": 27, "Anzahl Weichengrundkörper": 0, "Anzahl Einwegweichen": 30, "Anzahl Deltaweichen": 7, "Anzahl Doppelweichen und Dreiwegeweichen": 42, "Anzahl Sternweichen": 1, "Gesamtlänge AP110": 0.0, "Gesamtlänge AP60": 0.0}
Can't render this file because it contains an unexpected character in line 2 and column 57.
+2 -1
View File
@@ -106,7 +106,8 @@
(vf-block-erstellen "standard" seite vf-nummer 0
hoehe-von hoehe-bis deltaH deltaL L_VF
L_GF1 L_GF2
richtung best-winkel startpunkt lastEnt 0.0)
richtung best-winkel startpunkt lastEnt 0.0
"0" "Schoenenberger Geruest")
;; lastEnt hinter den SEQEND des VF-Blocks schieben.
;; Ohne diesen Schritt wuerde entnext vom INSERT-Entity
;; in die ATTRIB-Kette des gerade erstellten VF-Blocks
+7 -6
View File
@@ -203,7 +203,8 @@ class TestFoerdererExportCSV:
def test_header_felder(self):
"""CSV-Header muss korrekte Spaltenbezeichnungen haben."""
expected = ["Elementnummer", "TeileArt", "TeileId", "Bezeichnung",
"Planquadrat", "Anzahl", "Position", "Boundingbox", "Nachbarn", "Merkmale"]
"Planquadrat", "Anzahl", "Position", "Boundingbox", "Nachbarn",
"Fehler", "Merkmale"]
for i, name in enumerate(expected):
assert self.header[i] == name, (
f"Header[{i}]: erwartet '{name}', ist '{self.header[i]}'"
@@ -235,10 +236,10 @@ class TestFoerdererExportCSV:
def test_merkmale_sind_valides_json(self):
"""Merkmale-Spalte muss valides JSON enthalten."""
for i, row in enumerate(self.rows):
if len(row) < 10:
if len(row) < 11:
continue
try:
json.loads(row[9])
json.loads(row[10])
except json.JSONDecodeError as e:
pytest.fail(f"Zeile {i + 2}: Merkmale ist kein valides JSON: {e}")
@@ -247,9 +248,9 @@ class TestFoerdererExportCSV:
required = {"Typ", "Winkel", "DeltaH_mm", "DeltaL_mm",
"L_VF_m", "Hoehe_Von_mm", "Hoehe_Bis_mm"}
for i, row in enumerate(self.rows):
if len(row) < 10:
if len(row) < 11:
continue
merkmale = json.loads(row[9])
merkmale = json.loads(row[10])
missing = required - set(merkmale.keys())
assert not missing, (
f"Zeile {i + 2}: Fehlende Merkmale-Felder: {missing}"
@@ -290,7 +291,7 @@ class TestFoerdererExportSivas:
def test_header_felder(self):
"""Sivas-CSV-Header muss korrekte Spalten haben."""
expected = ["Nr", "TeileArt", "SivasNummer", "Bezeichnung",
"Dispogruppe", "Anzahl", "Laenge[mm]", "details"]
"Dispogruppe", "Anzahl", "Laenge[mm]", "IDs", "details"]
for i, name in enumerate(expected):
assert self.header[i] == name, (
f"Header[{i}]: erwartet '{name}', ist '{self.header[i]}'"
+7 -7
View File
@@ -285,7 +285,7 @@
bR90 bR60 bR30
startpunkt last-ent nach-aus-pt entry-hz
(caddr (nth first-idx segmente))
es-seite))
es-seite "0" "Schoenenberger Geruest"))
gf-ins
)
)
@@ -383,7 +383,7 @@
(setq gf-ins
(car (gefaellestrecke-einfuegen
test-L_stau test-winkel (list 0 0 test-z-start)
"links" "links" 0.0 test-deltaL "90" "90")))
"links" "links" 0.0 test-deltaL "90" "90" "0" "Schoenenberger Geruest")))
(if gf-ins
(progn
(setq attribs (ssg-attrib-read gf-ins))
@@ -415,7 +415,7 @@
(setq gf-ins
(car (gefaellestrecke-einfuegen
test-L_stau test-winkel (list 15000 0 test-z-start)
"links" "links" 90.0 test-deltaL "90" "90")))
"links" "links" 90.0 test-deltaL "90" "90" "0" "Schoenenberger Geruest")))
(if gf-ins
(progn
(setq attribs (ssg-attrib-read gf-ins))
@@ -447,7 +447,7 @@
(setq gf-ins
(car (gefaellestrecke-einfuegen
test-L_stau test-winkel (list 0 -15000 test-z-start)
"links" "links" 180.0 test-deltaL "90" "90")))
"links" "links" 180.0 test-deltaL "90" "90" "0" "Schoenenberger Geruest")))
(if gf-ins
(progn
(setq attribs (ssg-attrib-read gf-ins))
@@ -479,7 +479,7 @@
(setq gf-ins
(car (gefaellestrecke-einfuegen
test-L_stau test-winkel (list 15000 -15000 test-z-start)
"links" "links" 270.0 test-deltaL "90" "90")))
"links" "links" 270.0 test-deltaL "90" "90" "0" "Schoenenberger Geruest")))
(if gf-ins
(progn
(setq attribs (ssg-attrib-read gf-ins))
@@ -529,7 +529,7 @@
(princ (strcat "\n\n M2_hz000: Start=(0,-35000," (rtos test-z-start 2 0) ") ..."))
(setq ergebnis
(gefaellestrecke-einfuegen
test-L_stau test-winkel m2-start "links" "links" 0.0 test-deltaL "90" "90"))
test-L_stau test-winkel m2-start "links" "links" 0.0 test-deltaL "90" "90" "0" "Schoenenberger Geruest"))
(setq gf-ins (car ergebnis))
(if gf-ins
(progn
@@ -735,7 +735,7 @@
(setq gf-ins
(car (gefaellestrecke-einfuegen
w30-lstau test-winkel (list 30000 0 test-z-start)
"links" "links" 0.0 test-deltaL "30" "30")))
"links" "links" 0.0 test-deltaL "30" "30" "0" "Schoenenberger Geruest")))
(if gf-ins
(progn
(setq attribs (ssg-attrib-read gf-ins))
+1 -1
View File
@@ -107,7 +107,7 @@ class TestOmnifloExportUnit:
out_dir = _output_dir()
os.makedirs(out_dir, exist_ok=True)
csv_path = os.path.join(out_dir, "omniflo_export.csv")
header = "Elementnummer;TeileArt;TeileId;Bezeichnung;Planquadrat;Anzahl;Position;Boundingbox;Nachbarn;Merkmale"
header = "Elementnummer;TeileArt;TeileId;Bezeichnung;Planquadrat;Anzahl;Position;Boundingbox;Nachbarn;Fehler;Merkmale"
with open(csv_path, "w", encoding="utf-8") as f:
f.write(header + "\n")
for item in self.items:
+18 -1
View File
@@ -146,7 +146,7 @@
namen befehl datei export-fn new-doc
out-path dwg-pfad dxf-pfad old-json test-result
old-filenames csv-name sivas-name csv-pfad
sivas-pfad csv-ok sivas-ok)
sivas-pfad csv-ok sivas-ok old-filedia)
(setq tests-pfad (strcat (getenv "DXFMAKRO") "/tests"))
(setq tests-out-dir (strcat tests-pfad "/output"))
@@ -267,7 +267,15 @@
(princ (strcat "\n DWG gespeichert: " dwg-pfad))
)
((and save-fmt (= (strcase save-fmt) "DXF"))
;; FILEDIA=0 erzwingen: sonst oeffnet "_.DXFOUT" den nativen
;; Speichern-Dialog (blockiert im Skriptlauf) statt die
;; Kommandozeilen-Prompts (Dateiname/Genauigkeit) zu nutzen -
;; das brachte den nachfolgenden vla-close aus dem Takt
;; (siehe Kontroll-Modus-Zweig weiter unten fuer Details).
(setq old-filedia (getvar "FILEDIA"))
(setvar "FILEDIA" 0)
(command "_.DXFOUT" out-path 6)
(setvar "FILEDIA" old-filedia)
(princ (strcat "\n DXF gespeichert: " out-path ".dxf"))
)
(T
@@ -343,7 +351,16 @@
(setq dwg-pfad (strcat out-path ".dwg"))
(setq dxf-pfad (strcat out-path ".dxf"))
(vla-saveas new-doc dwg-pfad)
;; FILEDIA=0 erzwingen: sonst oeffnet "_.DXFOUT" den nativen
;; Speichern-Dialog statt der Kommandozeilen-Prompts - der
;; Skriptlauf haengt dann in einem offenen Dialog fest, und
;; der nachfolgende vla-close (auf dem noch "belegten"
;; Dokument) bricht mit "bad argument type <0>" ab, weil
;; new-doc dabei ungueltig wird.
(setq old-filedia (getvar "FILEDIA"))
(setvar "FILEDIA" 0)
(command "_.DXFOUT" out-path 6)
(setvar "FILEDIA" old-filedia)
(vla-close new-doc :vlax-false)
(if (findfile dwg-pfad) (vl-file-delete dwg-pfad))
(setq new-doc (vla-open (vla-get-documents app) dxf-pfad))