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 ;; 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 (gf-block-erstellen
"gruppe" as-seite gf-nummer "gruppe" as-seite gf-nummer
(caddr startpunkt) (caddr startpunkt)
@@ -1326,7 +1328,7 @@
bR90 bR60 bR30 bR90 bR60 bR30
startpunkt last-ent nach-aus-pt entry-hz startpunkt last-ent nach-aus-pt entry-hz
(caddr (nth first-idx segmente)) (caddr (nth first-idx segmente))
es-seite) es-seite "0" "Schoenenberger Geruest")
(princ "\n\n=========================================") (princ "\n\n=========================================")
(princ (ssg-text "gf-status-fertig")) (princ (ssg-text "gf-status-fertig"))
@@ -1425,9 +1427,11 @@
bogen-L90 bogen-L60 bogen-L30 bogen-L90 bogen-L60 bogen-L30
bogen-R90 bogen-R60 bogen-R30 bogen-R90 bogen-R60 bogen-R30
startpunkt last-ent nach-aus-pt entry-hz L-first-seg 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-bname gf-ss ent gf-insert typ-str anzahl-gf
gf-winkel-str i gf-g10z gf-korr-dz gf-osmode-alt) 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 ;; Beschriftung: Mitte der ersten Geraden, 400mm senkrecht versetzt
(gf-make-label gf-nummer hoehe-von hoehe-bis deltaH deltaL (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) 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 "GF_Bogen_R_30" (itoa bogen-R30))
(cons "ANZAHL_SEPARATOR" (itoa n-separator)) (cons "ANZAHL_SEPARATOR" (itoa n-separator))
(cons "ANZAHL_SCANNER" (itoa n-scanner)) (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. ;; Aufsteigende, eindeutige ID vergeben (wie beim Kreisel), falls verfuegbar.
@@ -1526,8 +1532,10 @@
;; deltaL-total: gesamte Horizontaldistanz (fuer DELTA_L-Attribut) ;; deltaL-total: gesamte Horizontaldistanz (fuer DELTA_L-Attribut)
;; hz: Fahrtrichtung in Grad (0=Ost, 90=Nord, 180=West, 270=Sued) ;; 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 (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 as-block es-block endpunkt
gf-nummer last-ent rad-hz rad-v xu-incl gf-nummer last-ent rad-hz rad-v xu-incl
ein-hz rad-ein xu-ein ein-hz rad-ein xu-ein
@@ -1627,7 +1635,7 @@
1 0 1 0
0 0 0 0 0 0 0 0 0 0 0 0
startpunkt last-ent nach-aus-pt (float hz) (float L_stau) 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 ;; Edit-Metadaten (Fahrtrichtung, Gefaellewinkel, Element-Winkel) als XDATA
;; auf das GF_N-INSERT schreiben, damit GEFAELLESTRECKE_EDIT die Strecke ;; auf das GF_N-INSERT schreiben, damit GEFAELLESTRECKE_EDIT die Strecke
@@ -1657,15 +1665,18 @@
;; um die Angabe der Einfuegehoehe (Z). ;; um die Angabe der Einfuegehoehe (Z).
;; prefill: Assoziationsliste zur Vorbelegung (fuer GEFAELLESTRECKE_EDIT) mit ;; prefill: Assoziationsliste zur Vorbelegung (fuer GEFAELLESTRECKE_EDIT) mit
;; Schluesseln "deltaL" "winkel" "hz" "as-seite" "es-seite" "einfuegehoehe" ;; 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 ;; 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. ;; oder nil bei Abbruch / fehlendem Dialog.
(defun gf-dialog-eingabe ( prefill hoehe-vorbelegung / dcl-pfad dat ergebnis (defun gf-dialog-eingabe ( prefill hoehe-vorbelegung / dcl-pfad dat ergebnis
dlg-deltal dlg-hoehe dlg-winkel dlg-deltal dlg-hoehe dlg-winkel
dlg-richtung dlg-aus dlg-ein dlg-richtung dlg-aus dlg-ein
dlg-aus-winkel dlg-ein-winkel dlg-dim 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 dcl-pfad (strcat (getenv "DXFM_DCL") "/gefaellestrecke.dcl"))
(setq dat (load_dialog dcl-pfad)) (setq dat (load_dialog dcl-pfad))
(if (not (new_dialog "gefaellestrecke" dat)) (if (not (new_dialog "gefaellestrecke" dat))
@@ -1741,6 +1752,14 @@
(set_tile "ein_seite" (set_tile "ein_seite"
(if (and prefill (equal (cdr (assoc "es-seite" prefill)) "rechts")) "1" "0")) (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 ;; Actions
(action_tile "accept" (action_tile "accept"
(strcat (strcat
@@ -1753,6 +1772,8 @@
"(setq dlg-ein-winkel (get_tile \"ein_winkel\"))" "(setq dlg-ein-winkel (get_tile \"ein_winkel\"))"
"(setq dlg-ein (get_tile \"ein_seite\"))" "(setq dlg-ein (get_tile \"ein_seite\"))"
"(setq dlg-dim (get_tile \"dimension\"))" "(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)" "(done_dialog 1)"
) )
) )
@@ -1779,6 +1800,8 @@
(setq as-winkel (if (= dlg-aus-winkel "1") "30" "90")) (setq as-winkel (if (= dlg-aus-winkel "1") "30" "90"))
(setq es-winkel (if (= dlg-ein-winkel "1") "30" "90")) (setq es-winkel (if (= dlg-ein-winkel "1") "30" "90"))
(setq dim (if (= dlg-dim "1") "2D" "3D")) (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 (list
(atof dlg-deltal) (atof dlg-deltal)
(atof dlg-winkel) (atof dlg-winkel)
@@ -1788,7 +1811,9 @@
(atof dlg-hoehe) (atof dlg-hoehe)
as-winkel as-winkel
es-winkel es-winkel
dim) dim
geruest-einzelmodul
geruest-typ)
) )
(t nil) (t nil)
) )
@@ -1804,7 +1829,8 @@
;; wurde (Modus 1) - dann entfaellt die zusaetzliche Konsolen-Rueckfrage. ;; wurde (Modus 1) - dann entfaellt die zusaetzliche Konsolen-Rueckfrage.
;; Modus 2 (reine Konsoleneingabe, kein Dialog) uebergibt nil/weglassen. ;; Modus 2 (reine Konsoleneingabe, kein Dialog) uebergibt nil/weglassen.
(defun gf-modus12-abschluss (deltaL winkel hz-winkel as-seite es-seite startpunkt (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) rad sep-x L_stau antwort)
(if (null as-winkel) (setq as-winkel "90")) (if (null as-winkel) (setq as-winkel "90"))
(if (null es-winkel) (setq es-winkel "90")) (if (null es-winkel) (setq es-winkel "90"))
@@ -1842,7 +1868,8 @@
;; Bestaetigung - entfaellt, wenn bereits per Dialog-OK bestaetigt (Modus 1) ;; Bestaetigung - entfaellt, wenn bereits per Dialog-OK bestaetigt (Modus 1)
(setq antwort (if dialog-bestaetigt "1" (getstring (ssg-text "gf-prompt-einfuegen")))) (setq antwort (if dialog-bestaetigt "1" (getstring (ssg-text "gf-prompt-einfuegen"))))
(if (not (= antwort "2")) (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")) (princ (ssg-text "gf-status-abgebrochen"))
) )
) )
@@ -1851,7 +1878,7 @@
;; setzen, L_stau berechnen und einfuegen - ohne Zusammenfassung/Rueckfrage. ;; setzen, L_stau berechnen und einfuegen - ohne Zusammenfassung/Rueckfrage.
;; Rueckgabe: (ename deltaH deltaL) von gefaellestrecke-einfuegen oder nil. ;; Rueckgabe: (ename deltaH deltaL) von gefaellestrecke-einfuegen oder nil.
(defun gf-rebuild (deltaL winkel hz-winkel as-seite es-seite startpunkt (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) rad sep-x L_stau)
(if (null as-winkel) (setq as-winkel "90")) (if (null as-winkel) (setq as-winkel "90"))
(if (null es-winkel) (setq es-winkel "90")) (if (null es-winkel) (setq es-winkel "90"))
@@ -1867,7 +1894,8 @@
nil nil
) )
(gefaellestrecke-einfuegen (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 as-seite es-seite gf-as-winkel gf-es-winkel
line-points startpunkt endpunkt differenz line-points startpunkt endpunkt differenz
deltaX deltaY startpunkt-fuer-einfuegen hz-winkel deltaX deltaY startpunkt-fuer-einfuegen hz-winkel
dlg-werte) dlg-werte gf-dim gf-geruest-einzelmodul gf-geruest-typ)
(princ "\n=========================================") (princ "\n=========================================")
(princ (ssg-text "gf-banner-titel")) (princ (ssg-text "gf-banner-titel"))
@@ -1995,9 +2023,12 @@
(setq antwort (getstring (ssg-text "prompt-wahl-1-2"))) (setq antwort (getstring (ssg-text "prompt-wahl-1-2")))
(setq es-seite (if (= antwort "2") "rechts" "links")) (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 (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 ;; Modus 1: Manuelle Eingabe via DCL-Dialog
@@ -2020,7 +2051,10 @@
as-seite (nth 3 dlg-werte) as-seite (nth 3 dlg-werte)
es-seite (nth 4 dlg-werte) es-seite (nth 4 dlg-werte)
gf-as-winkel (nth 6 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 ;; Einfuegehoehe = Dialogwert (nth 5), der mit der gepickten Hoehe
;; vorbelegt wurde. So gewinnt die gepickte Hoehe standardmaessig, ;; vorbelegt wurde. So gewinnt die gepickte Hoehe standardmaessig,
;; bleibt aber im Dialog editierbar. Nur diese Z-Hoehe zaehlt (X/Y ;; 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))) (setq deltaL (ssg-cfg-or "gefaelle" "default_delta_l" 5000.0)))
(if (or (null winkel) (<= winkel 0)) (if (or (null winkel) (<= winkel 0))
(setq winkel (ssg-cfg-or "gefaelle" "default_winkel" 3.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 ;; Dialog-OK wurde bereits bestaetigt - keine zusaetzliche Rueckfrage
(gf-modus12-abschluss deltaL winkel hz-winkel as-seite es-seite (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))) (caddr gf-start)))
;; VF bauen; Rueckgabe (vf-insert vf-endpunkt), vf-endpunkt = tatsaechl. ;; VF bauen; Rueckgabe (vf-insert vf-endpunkt), vf-endpunkt = tatsaechl.
;; ES-KS_AUS als Weltpunkt (aus vfs-es-teil/insert-block-by-ks). ;; 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 (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)) (setq vf-insert (car vf-erg) vf-endpunkt (cadr vf-erg))
;; Selbstkorrektur: fertigen VF-Block so verschieben, dass sein ;; Selbstkorrektur: fertigen VF-Block so verschieben, dass sein
;; tatsaechliches ES-KS_AUS exakt auf ziel-es faellt (analog GF_n-Move; ;; 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. ;; Startpunkt neu auf. Rueckgabe: T bei Erfolg, nil wenn nicht nachbaubar.
(defun gf-konvertiere-ent (ent ziel-dim / ed bname attribs xd hz winkel (defun gf-konvertiere-ent (ent ziel-dim / ed bname attribs xd hz winkel
as-winkel es-winkel z-start deltaL startpunkt 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 ed (entget ent) bname (cdr (assoc 2 ed)))
(setq attribs (ssg-attrib-read ent)) (setq attribs (ssg-attrib-read ent))
(setq xd (gf-xdata-lesen ent)) (setq xd (gf-xdata-lesen ent))
@@ -2145,10 +2186,14 @@
deltaL (atof (nth 5 xd))) deltaL (atof (nth 5 xd)))
(setq as-seite (cond ((cdr (assoc "SEITE_AS" attribs))) ("links"))) (setq as-seite (cond ((cdr (assoc "SEITE_AS" attribs))) ("links")))
(setq es-seite (cond ((cdr (assoc "SEITE_ES" 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) (setq *ssg-ils-dim* ziel-dim)
(entdel ent) (entdel ent)
(gf-rebuild deltaL winkel hz as-seite es-seite (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) (setq *ssg-ils-dim* nil)
T) T)
nil)) nil))
@@ -2224,7 +2269,9 @@
(cons "as-winkel" as-winkel) (cons "as-winkel" as-winkel)
(cons "es-winkel" es-winkel) (cons "es-winkel" es-winkel)
;; Dimension aus XDATA erkennen (Default 3D, falls Alt-Block ohne Eintrag) ;; 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 ;; AS-Seite + untere Hoehe fuer den optionalen parallelen VF-Bau
(setq as-seite (cond ((cdr (assoc "SEITE_AS" attribs))) ("links"))) (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 0 dlg-werte) (nth 1 dlg-werte) (nth 2 dlg-werte)
(nth 3 dlg-werte) (nth 4 dlg-werte) (nth 3 dlg-werte) (nth 4 dlg-werte)
(list (car startpunkt) (cadr startpunkt) (nth 5 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) (setq *ssg-ils-dim* nil)
(princ (ssg-textf "gf-edit-neu-aufgebaut" (list bname))) (princ (ssg-textf "gf-edit-neu-aufgebaut" (list bname)))
) )
+22 -3
View File
@@ -87,6 +87,7 @@
("ANZAHL_SCANNER" "0") ("ANZAHL_SCANNER" "0")
("ANZAHL_RAMPEN" "0") ("ANZAHL_RAMPEN" "0")
("GERUEST_EINZELMODUL" "0") ("GERUEST_EINZELMODUL" "0")
("GERUEST_TYP" "Schoenenberger Geruest")
("DREHRICHTUNG" "UZS") ("DREHRICHTUNG" "UZS")
("DREHUNG" "0") ("DREHUNG" "0")
("NUMMER" "0")) ("NUMMER" "0"))
@@ -102,6 +103,8 @@
("DREHUNG" "0") ("DREHUNG" "0")
("NUMMER" "0") ("NUMMER" "0")
("HOEHE" "0") ("HOEHE" "0")
("GERUEST_EINZELMODUL" "0")
("GERUEST_TYP" "Schoenenberger Geruest")
("ID" "")) ("ID" ""))
) )
@@ -869,6 +872,7 @@
dcl-pfad dat ergebnis dcl-pfad dat ergebnis
dlg-name dlg-abstand dlg-hoehe dlg-ausrichtung dlg-name dlg-abstand dlg-hoehe dlg-ausrichtung
dlg-drehrichtung dlg-kreiselart dlg-geruest-einzelmodul dlg-drehrichtung dlg-kreiselart dlg-geruest-einzelmodul
dlg-geruest-typ
newAbstand newRotation ausrichtLabels) newAbstand newRotation ausrichtLabels)
;; Implied Selection VOR ssg-start pruefen (ssg-start hebt Selektion auf) ;; Implied Selection VOR ssg-start pruefen (ssg-start hebt Selektion auf)
@@ -966,6 +970,11 @@
(set_tile "geruest_einzelmodul" (set_tile "geruest_einzelmodul"
(if (equal (cdr (assoc "GERUEST_EINZELMODUL" attribs)) "1") "1" "0")) (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 ;; Actions
(action_tile "accept" (action_tile "accept"
(strcat (strcat
@@ -976,6 +985,7 @@
"(setq dlg-drehrichtung (get_tile \"drehrichtung\"))" "(setq dlg-drehrichtung (get_tile \"drehrichtung\"))"
"(setq dlg-kreiselart (get_tile \"kreiselart\"))" "(setq dlg-kreiselart (get_tile \"kreiselart\"))"
"(setq dlg-geruest-einzelmodul (get_tile \"geruest_einzelmodul\"))" "(setq dlg-geruest-einzelmodul (get_tile \"geruest_einzelmodul\"))"
"(setq dlg-geruest-typ (get_tile \"geruest_typ\"))"
"(done_dialog 1)" "(done_dialog 1)"
) )
) )
@@ -1004,6 +1014,8 @@
(assoc "DREHRICHTUNG" attribs) attribs)) (assoc "DREHRICHTUNG" attribs) attribs))
(setq attribs (subst (cons "GERUEST_EINZELMODUL" dlg-geruest-einzelmodul) (setq attribs (subst (cons "GERUEST_EINZELMODUL" dlg-geruest-einzelmodul)
(assoc "GERUEST_EINZELMODUL" attribs) attribs)) (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 ;; Alten Block loeschen
(command "_.ERASE" ent "") (command "_.ERASE" ent "")
@@ -1051,7 +1063,8 @@
;; 4. Hoehe aus Z-Koordinate oder manuell ;; 4. Hoehe aus Z-Koordinate oder manuell
;; -------------------------------------------- ;; --------------------------------------------
(defun c:ILS_Eckrad ( / ptTangent ptDir dx dy dist ux uy radius (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") (dbgf "c:ILS_Eckrad")
;; 1. Beruehrpunkt (Tangentenpunkt) ;; 1. Beruehrpunkt (Tangentenpunkt)
@@ -1106,8 +1119,14 @@
) )
(dbg 'hoehe) (dbg 'hoehe)
;; 5. Einfuegen (centerPt ist der Kreismittelpunkt) ;; 5. Geruest fuer Einzelmodul + Geruestoption abfragen
(ils-eckrad-insert (list (car centerPt) (cadr centerPt) hoehe) rotation nil) (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) (dbgreturn nil)
) )
+85 -18
View File
@@ -13,25 +13,39 @@
;; (ssg-start "Titel" '(("OSMODE") ("ORTHOMODE"))) ;; (ssg-start "Titel" '(("OSMODE") ("ORTHOMODE")))
;; ... Makrocode ... ;; ... Makrocode ...
;; (ssg-end) ;; (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 ;; titel - Anzeigename des Makros
;; zusatz-vars - Liste zusaetzlicher Variablen z.B. '(("OSMODE")("ORTHOMODE")) ;; zusatz-vars - Liste zusaetzlicher Variablen z.B. '(("OSMODE")("ORTHOMODE"))
;; Immer CLAYER und CMDECHO werden automatisch gesichert. ;; Immer CLAYER und CMDECHO werden automatisch gesichert.
(setq _ssg-olderr *error* (setq cavar (append '(("CLAYER") ("CMDECHO")) zusatz-vars)
*error* (function ssg-errhan) xlen (length cavar)
_ssg-cavar (append '(("CLAYER") ("CMDECHO")) zusatz-vars) xpos 0
xlen (length _ssg-cavar)
xpos 0
) )
(repeat xlen (repeat xlen
(setq xvar (car (nth xpos _ssg-cavar)) (setq xvar (car (nth xpos cavar))
_ssg-cavar (subst (cons xvar (getvar xvar)) cavar (subst (cons xvar (getvar xvar)) (nth xpos cavar) cavar)
(nth xpos _ssg-cavar) _ssg-cavar) xpos (1+ xpos)
xpos (1+ xpos)
) )
) )
(setq *ssg-start-stack* (cons (cons *error* cavar) *ssg-start-stack*))
(setq *error* (function ssg-errhan))
(setvar "CMDECHO" 0) (setvar "CMDECHO" 0)
(command "_undo" "_G") (command "_undo" "_G")
(graphscr) (graphscr)
@@ -39,26 +53,30 @@
(princ) (princ)
) )
(defun ssg-end (/ xpos xlen xvar) (defun ssg-end (/ frame cavar xpos xlen xvar)
(if _ssg-cavar (if *ssg-start-stack*
(progn (progn
(setq frame (car *ssg-start-stack*)
*ssg-start-stack* (cdr *ssg-start-stack*)
cavar (cdr frame)
)
(command) (command)
(command "_undo" "_E") (command "_undo" "_E")
(setq xpos 1 (setq xpos 1
xlen (length _ssg-cavar) xlen (length cavar)
) )
(if (/= (getvar "CLAYER") (caar _ssg-cavar)) (if (/= (getvar "CLAYER") (caar cavar))
(command "_LAYER" "_SE" (cdar _ssg-cavar) "") (command "_LAYER" "_SE" (cdar cavar) "")
) )
(repeat (1- xlen) (repeat (1- xlen)
(setq xvar (nth xpos _ssg-cavar) (setq xvar (nth xpos cavar)
xpos (1+ xpos) xpos (1+ xpos)
) )
(setvar (car xvar) (cdr xvar)) (setvar (car xvar) (cdr xvar))
) )
(setq *error* (car frame))
) )
) )
(if _ssg-olderr (setq *error* _ssg-olderr))
(princ) (princ)
) )
@@ -602,7 +620,56 @@
;; (einsegmentige Gefaellestrecke: 1; Streckengruppe: gezaehlt). ;; (einsegmentige Gefaellestrecke: 1; Streckengruppe: gezaehlt).
(setq *strecke-attr-hinten* (setq *strecke-attr-hinten*
'(("ANZAHL_SEPARATOR" "1") '(("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. ;; Geordnete ATTDEF-Definitionsliste fuer einen Strecken-Block-Typ.
;; typ "Gefaellestrecke" -> Vorderteil + Hinterteil (reduziert) ;; typ "Gefaellestrecke" -> Vorderteil + Hinterteil (reduziert)
+10 -1
View File
@@ -1062,8 +1062,11 @@
(defun vf-block-erstellen (anlage-typ seite vf-nummer n-scanner (defun vf-block-erstellen (anlage-typ seite vf-nummer n-scanner
hoehe-von hoehe-bis deltaH deltaL L_VF L_GF1 L_GF2 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
/ vf-bname vf-ss vf-e vf-insert montagehoehe-m attdef-ypos L_GF_m-str) / 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 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 ;; Beschriftungstext erzeugen
(vf-make-label vf-nummer hoehe-von hoehe-bis deltaH deltaL L_VF L_GF1 L_GF2 (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) richtung best-winkel 2 n-scanner startpunkt hz)
@@ -1134,6 +1137,8 @@
(cons "VF_WINKEL" (itoa best-winkel)) (cons "VF_WINKEL" (itoa best-winkel))
(cons "ANZAHL_SEPARATOR" "2") (cons "ANZAHL_SEPARATOR" "2")
(cons "ANZAHL_SCANNER" (itoa n-scanner)) (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) ;; 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)) (list deltaL deltaH richtung best-winkel L_GF1 L_GF2 L_VF startpunkt seite hz))
;; Gemeinsame VF_*-Block-Erstellung ;; 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 (setq vf-insert
(vf-block-erstellen anlage-typ seite vf-nummer n-scanner (vf-block-erstellen anlage-typ seite vf-nummer n-scanner
hoehe-von hoehe-bis deltaH deltaL L_VF L_GF1 L_GF2 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 ;; Standard-Bloecke aus dem interaktiven Konsolen-Ablauf ebenfalls mit der
;; SSG_VF_EDIT-XDATA markieren - sie sind (wie die Dialog-Variante) aus ;; 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, ;; Basis-Eingabe (Dialog 1): deltaL, deltaH, Richtung, Einfuegehoehe,
;; Fahrtrichtung, Seite. ;; Fahrtrichtung, Seite, Geruest fuer Einzelmodul, Geruestoption.
;; prefill: Assoziationsliste zur Vorbelegung (fuer VARIOFOERDERER_EDIT) mit ;; prefill: Assoziationsliste zur Vorbelegung (fuer VARIOFOERDERER_EDIT) mit
;; Schluesseln "deltaL" "deltaH" "richtung" "einfuegehoehe" "hz" "seite" ;; Schluesseln "deltaL" "deltaH" "richtung" "einfuegehoehe" "hz" "seite"
;; - oder nil fuer Neuanlage mit Defaults. ;; "geruest-einzelmodul" "geruest-typ" - oder nil fuer Neuanlage mit Defaults.
;; Rueckgabe: (deltaL deltaH richtung einfuegehoehe hz seite) oder nil bei Abbruch. ;; 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 (defun vfs-dialog-eingabe-basis (prefill / dcl-pfad dat ergebnis
dlg-deltal dlg-deltah dlg-richtung dlg-hoehe dlg-deltal dlg-deltah dlg-richtung dlg-hoehe
dlg-fahrtrichtung dlg-seite dlg-dimension 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 dcl-pfad (strcat (getenv "DXFM_DCL") "/variofoerderer.dcl"))
(setq dat (load_dialog dcl-pfad)) (setq dat (load_dialog dcl-pfad))
(if (not (new_dialog "variofoerderer_basis" dat)) (if (not (new_dialog "variofoerderer_basis" dat))
@@ -771,6 +774,13 @@
(end_list) (end_list)
(set_tile "dimension" (set_tile "dimension"
(if (equal (cond ((cdr (assoc "dim" prefill))) ((ssg-ils-dim-aktuell))) "2D") "1" "0")) (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 ;; Actions
(action_tile "accept" (action_tile "accept"
@@ -782,6 +792,8 @@
"(setq dlg-fahrtrichtung (get_tile \"fahrtrichtung\"))" "(setq dlg-fahrtrichtung (get_tile \"fahrtrichtung\"))"
"(setq dlg-seite (get_tile \"seite\"))" "(setq dlg-seite (get_tile \"seite\"))"
"(setq dlg-dimension (get_tile \"dimension\"))" "(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)" "(done_dialog 1)"
) )
) )
@@ -803,7 +815,9 @@
(t 0.0))) (t 0.0)))
(setq seite (if (= dlg-seite "1") "links" "rechts")) (setq seite (if (= dlg-seite "1") "links" "rechts"))
(setq dim (if (= dlg-dimension "1") "2D" "3D")) (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 nil
) )
@@ -955,7 +969,7 @@
;; winkel-prefill: Vorbelegung fuer vfs-dialog-winkel-verteilung oder nil. ;; winkel-prefill: Vorbelegung fuer vfs-dialog-winkel-verteilung oder nil.
;; ============================================================ ;; ============================================================
(defun vfs-standard-dialog-berechnen-einfuegen (vf-nummer deltaL deltaH richtung startpunkt hz seite (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 ergebnis ergebnis-liste gueltige-winkel horizontal-info
winkelwahl best-winkel L_GF L_VF L_GF1 L_GF2 verteilung-modus 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) n-scanner hoehe-von hoehe-bis lastEnt vf-insert vf-endpunkt staustrecke-basis)
@@ -1014,7 +1028,8 @@
(setq vf-insert (setq vf-insert
(vf-block-erstellen "standard" seite vf-nummer n-scanner (vf-block-erstellen "standard" seite vf-nummer n-scanner
hoehe-von hoehe-bis deltaH deltaL L_VF L_GF1 L_GF2 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)) (if vf-insert (vfs-xdata-schreiben vf-insert hz))
(princ "\n=========================================") (princ "\n=========================================")
) )
@@ -1029,7 +1044,8 @@
;; Neuanlage (Menue/Konsole -> Dialog): Startpunkt (X/Y) picken, Basis-Dialog, ;; Neuanlage (Menue/Konsole -> Dialog): Startpunkt (X/Y) picken, Basis-Dialog,
;; dann gemeinsame Berechnung/Winkel-Dialog/Einfuegung. ;; dann gemeinsame Berechnung/Winkel-Dialog/Einfuegung.
(defun vfs-standard-dialog-ablauf (vf-nummer / eingabe deltaL deltaH richtung (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"))) (setq startpunkt-xy (getpoint (ssg-text "vfc-prompt-startpunkt-aus")))
(if (null startpunkt-xy) (setq startpunkt-xy '(0 0 0))) (if (null startpunkt-xy) (setq startpunkt-xy '(0 0 0)))
@@ -1043,11 +1059,14 @@
z-start (nth 3 eingabe) z-start (nth 3 eingabe)
hz (nth 4 eingabe) hz (nth 4 eingabe)
seite (nth 5 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)) (setq startpunkt (list (car startpunkt-xy) (cadr startpunkt-xy) z-start))
;; Gewaehlte Dimension (2D/3D) fuer den Bau erzwingen (Override), danach zurueck. ;; Gewaehlte Dimension (2D/3D) fuer den Bau erzwingen (Override), danach zurueck.
(setq *ssg-ils-dim* dim) (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) (setq *ssg-ils-dim* nil)
) )
) )
@@ -1059,7 +1078,8 @@
;; per Override und baut am selben Startpunkt neu auf. Rueckgabe: T/nil. ;; 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 (defun vf-konvertiere-ent (ent ziel-dim / ed bname xd attribs startpunkt hz
deltaL deltaH richtung seite best-winkel L_GF_m-teile 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 ed (entget ent) bname (cdr (assoc 2 ed)))
(setq xd (vfs-xdata-lesen ent)) (setq xd (vfs-xdata-lesen ent))
(if (and (wcmatch bname "VF_*") xd (= (car xd) "standard")) (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_GF1 (* 1000.0 (atof (car L_GF_m-teile))))
(setq L_GF2 (* 1000.0 (atof (cadr 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"))))) (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-von (caddr startpunkt))
(setq hoehe-bis (cond ((= richtung "Auf") (+ hoehe-von deltaH)) (setq hoehe-bis (cond ((= richtung "Auf") (+ hoehe-von deltaH))
((= richtung "Ab") (- hoehe-von deltaH)) ((= richtung "Ab") (- hoehe-von deltaH))
@@ -1088,7 +1111,8 @@
(setq vf-insert (setq vf-insert
(vf-block-erstellen "standard" seite vf-nummer 0 (vf-block-erstellen "standard" seite vf-nummer 0
hoehe-von hoehe-bis deltaH deltaL L_VF L_GF1 L_GF2 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)) (if vf-insert (vfs-xdata-schreiben vf-insert hz))
(setq *ssg-ils-dim* nil) (setq *ssg-ils-dim* nil)
(if vf-insert T nil)) (if vf-insert T nil))
@@ -1108,7 +1132,8 @@
(defun c:VARIOFOERDERER_EDIT ( / ss ent ed bname startpunkt attribs xd (defun c:VARIOFOERDERER_EDIT ( / ss ent ed bname startpunkt attribs xd
deltaL deltaH richtung z-start hz seite dim deltaL deltaH richtung z-start hz seite dim
eingabe vf-nummer best-winkel-attr L_GF_m-teile 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) ;; Implied Selection VOR ssg-start pruefen (ssg-start hebt Selektion auf)
(setq ss (ssget "I")) (setq ss (ssget "I"))
(if (and ss (= (sslength ss) 1) (if (and ss (= (sslength ss) 1)
@@ -1149,7 +1174,9 @@
(list (cons "deltaL" deltaL) (cons "deltaH" deltaH) (cons "richtung" richtung) (list (cons "deltaL" deltaL) (cons "deltaH" deltaH) (cons "richtung" richtung)
(cons "einfuegehoehe" z-start) (cons "hz" hz) (cons "seite" seite) (cons "einfuegehoehe" z-start) (cons "hz" hz) (cons "seite" seite)
;; Dimension aus XDATA erkennen (Default 3D, falls Alt-Block ohne Eintrag) ;; 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)) (setq eingabe (vfs-dialog-eingabe-basis prefill-basis))
(if (null eingabe) (if (null eingabe)
@@ -1161,7 +1188,9 @@
z-start (nth 3 eingabe) z-start (nth 3 eingabe)
hz (nth 4 eingabe) hz (nth 4 eingabe)
seite (nth 5 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)) (setq startpunkt (list (car startpunkt) (cadr startpunkt) z-start))
;; Vorbelegung Winkel/Verteilung: bestehenden Winkel vorschlagen, L_GF- ;; Vorbelegung Winkel/Verteilung: bestehenden Winkel vorschlagen, L_GF-
@@ -1180,7 +1209,7 @@
(entdel ent) (entdel ent)
(setq vf-nummer (vf-next-number)) (setq vf-nummer (vf-next-number))
(vfs-standard-dialog-berechnen-einfuegen vf-nummer deltaL deltaH richtung (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) (setq *ssg-ils-dim* nil)
(princ (ssg-textf "vfs-edit-neu-aufgebaut" (list bname))) (princ (ssg-textf "vfs-edit-neu-aufgebaut" (list bname)))
) )
+31 -3
View File
@@ -31,6 +31,19 @@ pattern_ks_subblocks= KS_EIN, KS_AUS, K1, K2, K3, K4
[Planquadrate] [Planquadrate]
section=Planquadrate_AN 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 # 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) # 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
@@ -61,7 +74,22 @@ format= {x}/{y}
[Nachbarschaft] [Nachbarschaft]
# Toleranz fuer die Nachbarschaftserkennung beim CSV-Export (Spalte "Nachbarn"). # Toleranz fuer die Nachbarschaftserkennung beim CSV-Export (Spalte "Nachbarn").
# Die Bounding-Box jedes Elements wird um die Haelfte dieses Werts nach allen # Die Bounding-Box jedes Elements wird um die Haelfte dieses Werts nach allen
# Seiten erweitert, bevor per STRtree (shapely) auf Ueberschneidung mit anderen # Seiten erweitert, bevor auf Ueberschneidung mit anderen Elementen geprueft
# Elementen geprueft wird - zwei Elemente mit einem Abstand <= toleranz_mm # wird - zwei Elemente mit einem Abstand <= toleranz_mm (z.B. zwei Kreisel)
# (z.B. zwei Kreisel) gelten dann ebenfalls als benachbart. Wert in mm. # gelten dann ebenfalls als benachbart. Wert in mm. Siehe lib/export_neighbors.py.
toleranz_mm=200 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; ok_cancel;
+6
View File
@@ -52,6 +52,12 @@ kreisel_edit : dialog {
label = "Geruest fuer Einzelmodul"; label = "Geruest fuer Einzelmodul";
} }
: popup_list {
key = "geruest_typ";
label = "Geruestoption:";
width = 30;
}
} }
ok_cancel; 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; ok_cancel;
+4
View File
@@ -524,6 +524,10 @@
"gf-seite-rechts": "\n 2 - Rechts", "gf-seite-rechts": "\n 2 - Rechts",
"prompt-wahl-1-2": "\nIhre Wahl (1/2) [1]: ", "prompt-wahl-1-2": "\nIhre Wahl (1/2) [1]: ",
"prompt-wahl-1-2-3": "\nIhre Wahl (1/2/3) [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-lade-block": "\n Lade Block: %1 ...",
"gf-status-ok": " OK", "gf-status-ok": " OK",
"gf-warnung-kette-unterbrochen": "\n WARNUNG: Kette unterbrochen!", "gf-warnung-kette-unterbrochen": "\n WARNUNG: Kette unterbrochen!",
+4
View File
@@ -524,6 +524,10 @@
"gf-seite-rechts": "\n 2 - Right", "gf-seite-rechts": "\n 2 - Right",
"prompt-wahl-1-2": "\nYour choice (1/2) [1]: ", "prompt-wahl-1-2": "\nYour choice (1/2) [1]: ",
"prompt-wahl-1-2-3": "\nYour choice (1/2/3) [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-lade-block": "\n Loading block: %1 ...",
"gf-status-ok": " OK", "gf-status-ok": " OK",
"gf-warnung-kette-unterbrochen": "\n WARNING: chain interrupted!", "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 configparser
import fnmatch import fnmatch
import functools
import os import os
@@ -32,6 +33,25 @@ def cfg_path_from_env(default_dir=None):
return os.path.join(base, "cfg", "export.cfg") 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): def load_patterns(cfg_path=None):
"""Liest [blockpattern] aus export.cfg. """Liest [blockpattern] aus export.cfg.
@@ -40,8 +60,7 @@ def load_patterns(cfg_path=None):
""" """
if cfg_path is None: if cfg_path is None:
cfg_path = cfg_path_from_env() cfg_path = cfg_path_from_env()
parser = configparser.ConfigParser() parser = load_export_cfg(cfg_path)
parser.read(cfg_path, encoding="utf-8")
patterns = {} patterns = {}
if parser.has_section("blockpattern"): if parser.has_section("blockpattern"):
for key, value in parser.items("blockpattern"): for key, value in parser.items("blockpattern"):
@@ -49,7 +68,32 @@ def load_patterns(cfg_path=None):
return patterns 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): def matches_any(bname, patterns):
"""True, wenn bname (case-insensitiv) zu mindestens einem Muster passt.""" """True, wenn bname (case-insensitiv) zu mindestens einem Muster passt."""
upper = bname.upper() upper = bname.upper()
return any(fnmatch.fnmatchcase(upper, p.upper()) for p in patterns) 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> python export_csv.py <export_raw.json> <data_dir> <output.csv>
CSV-Format: 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 Position und Boundingbox stammen aus der von export.lsp (csv:get-bbox, per
vla-getboundingbox) ermittelten Bounding-Box je Block: 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 Planquadrat wird aus der x/y-Koordinate des Blocks berechnet, siehe
export_planquadrat.py ([Planquadrate] in cfg/export.cfg). export_planquadrat.py ([Planquadrate] in cfg/export.cfg).
Nachbarn = kommaseparierte TeileId-Liste ueberschneidender Elemente (Bounding- Nachbarn = kommaseparierte TeileId-Liste ueberschneidender Elemente (Bounding-
Box-Ueberschneidung in der x/y-Ebene per shapely-STRtree, Toleranz konfigurierbar Box-Ueberschneidung in der x/y-Ebene, reines Python ohne externe Abhaengigkeit,
ueber [Nachbarschaft] -> toleranz_mm in cfg/export.cfg), siehe export_neighbors.py. siehe export_neighbors.py). Geprueft wird NICHT global ueber alle Elemente,
Position, Boundingbox, Planquadrat und Nachbarn sind nur fuer EXPORTCSV sondern in drei getrennten Gruppen: 1) Kreisel/Eckrad gegen Kreisel/Eckrad,
vorhanden (nicht EXPORTSIVAS) - siehe csv:run-export. 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 json
import sys import sys
import os import os
from export_blockpatterns import load_patterns, matches_any from export_blockpatterns import load_patterns, matches_any, csv_quote, safe_float
from export_planquadrat import load_planquadrat_config, compute_planquadrat from export_planquadrat import load_planquadrat_config, resolve_origins, compute_planquadrat
from export_neighbors import load_neighbor_tolerance_mm, compute_neighbor_ids from export_neighbors import (
load_neighbor_tolerance_mm,
load_omniflo_cell_size_mm,
compute_neighbor_ids,
compute_neighbor_errors,
)
BLOCKPATTERNS = load_patterns() BLOCKPATTERNS = load_patterns()
PLANQUADRAT_CFG = load_planquadrat_config() PLANQUADRAT_CFG = load_planquadrat_config()
NEIGHBOR_TOLERANCE_MM = load_neighbor_tolerance_mm() 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.""" """Liest DREHUNG aus Block-Attributen. Fallback: CAD-Rotation."""
attribs = block.get("attribs", {}) attribs = block.get("attribs", {})
drehung_raw = attribs.get("DREHUNG") drehung_raw = attribs.get("DREHUNG")
if drehung_raw is not None: if drehung_raw is None:
try: return block.get("rotation", 0.0)
return float(drehung_raw) return safe_float(drehung_raw, block.get("rotation", 0.0))
except (ValueError, TypeError):
pass
return block.get("rotation", 0.0)
def build_bogen_merkmale(block, eintrag): def build_bogen_merkmale(block, eintrag):
@@ -145,10 +159,7 @@ def get_laenge_mm(block):
"""Liest LAENGE (oder A) aus Block-Attributen. Fallback: 2000mm.""" """Liest LAENGE (oder A) aus Block-Attributen. Fallback: 2000mm."""
attribs = block.get("attribs", {}) attribs = block.get("attribs", {})
laenge = attribs.get("LAENGE") or attribs.get("A") laenge = attribs.get("LAENGE") or attribs.get("A")
try: return safe_float(laenge, 2000.0)
return float(laenge)
except (TypeError, ValueError):
return 2000.0
def build_gerade_merkmale(block): 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): def build_kreisel_merkmale(block):
attribs = block.get("attribs", {}) attribs = block.get("attribs", {})
abstand_mm = attribs.get("ABSTAND", "2300") abstand_m = str(round(safe_float(attribs.get("ABSTAND", "2300"), 2300.0) / 1000.0, 2))
try: hoehe_m = str(round(safe_float(attribs.get("HOEHE", "0"), 0.0) / 1000.0, 2))
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"
return { return {
"Abstand (Kreiselachse A - Kreiselachse) in Meter": abstand_m, "Abstand (Kreiselachse A - Kreiselachse) in Meter": abstand_m,
"Anzahl der Separatoren": attribs.get("ANZAHL_SEPARATOR", attribs.get("N_SEPARATOREN", "2")), "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). """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 Leerer String, wenn keine Planquadrat-Konfiguration geladen werden konnte
(fehlende/unvollstaendige [Planquadrate]-Sektion in cfg/export.cfg). (fehlende/unvollstaendige [Planquadrate]-Sektion in cfg/export.cfg).
""" """
if PLANQUADRAT_CFG is None: if planquadrat_cfg is None:
return "" return ""
x = block.get("x") x = block.get("x")
y = block.get("y") y = block.get("y")
if x is None or y is None: if x is None or y is None:
return "" 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): 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 = [] items = []
elem_nr = 0 elem_nr = 0
bogen_count = 0 bogen_count = 0
@@ -322,7 +332,7 @@ def process_blocks(blocks, lookup):
"teileart": "Omniflo Kurve", "teileart": "Omniflo Kurve",
"teileid": shape_id, "teileid": shape_id,
"bezeichnung": f"OFBogen :{bogen_count}", "bezeichnung": f"OFBogen :{bogen_count}",
"planquadrat": planquadrat_column(block), "planquadrat": planquadrat_column(block, planquadrat_cfg),
"merkmale": build_bogen_merkmale(block, eintrag), "merkmale": build_bogen_merkmale(block, eintrag),
**bbox_columns(block), **bbox_columns(block),
}) })
@@ -335,7 +345,7 @@ def process_blocks(blocks, lookup):
"teileart": "Omniflo Weiche", "teileart": "Omniflo Weiche",
"teileid": shape_id, "teileid": shape_id,
"bezeichnung": f"OFWeiche :{weiche_count[wt]}", "bezeichnung": f"OFWeiche :{weiche_count[wt]}",
"planquadrat": planquadrat_column(block), "planquadrat": planquadrat_column(block, planquadrat_cfg),
"merkmale": build_weiche_merkmale(block, eintrag), "merkmale": build_weiche_merkmale(block, eintrag),
**bbox_columns(block), **bbox_columns(block),
}) })
@@ -362,7 +372,7 @@ def process_blocks(blocks, lookup):
"teileart": "Omniflo Gerade", "teileart": "Omniflo Gerade",
"teileid": block.get("attribs", {}).get("ID", "0000"), "teileid": block.get("attribs", {}).get("ID", "0000"),
"bezeichnung": f"OFGerade :{gerade_count}", "bezeichnung": f"OFGerade :{gerade_count}",
"planquadrat": planquadrat_column(block), "planquadrat": planquadrat_column(block, planquadrat_cfg),
"merkmale": build_gerade_merkmale(block), "merkmale": build_gerade_merkmale(block),
**bbox_columns(block), **bbox_columns(block),
}) })
@@ -378,7 +388,7 @@ def process_blocks(blocks, lookup):
"teileart": "ILS 2.0 Strecke", "teileart": "ILS 2.0 Strecke",
"teileid": block.get("attribs", {}).get("ID", "0000"), "teileid": block.get("attribs", {}).get("ID", "0000"),
"bezeichnung": f"VarioFoerderer :{vf_count}", "bezeichnung": f"VarioFoerderer :{vf_count}",
"planquadrat": planquadrat_column(block), "planquadrat": planquadrat_column(block, planquadrat_cfg),
"merkmale": build_variofoerderer_merkmale(block), "merkmale": build_variofoerderer_merkmale(block),
**bbox_columns(block), **bbox_columns(block),
}) })
@@ -393,7 +403,7 @@ def process_blocks(blocks, lookup):
"teileart": "ILS 2.0 Gefaellestrecke", "teileart": "ILS 2.0 Gefaellestrecke",
"teileid": block.get("attribs", {}).get("ID", "0000"), "teileid": block.get("attribs", {}).get("ID", "0000"),
"bezeichnung": f"Gefaellestrecke :{gf_count}", "bezeichnung": f"Gefaellestrecke :{gf_count}",
"planquadrat": planquadrat_column(block), "planquadrat": planquadrat_column(block, planquadrat_cfg),
"merkmale": build_variofoerderer_merkmale(block), "merkmale": build_variofoerderer_merkmale(block),
**bbox_columns(block), **bbox_columns(block),
}) })
@@ -409,7 +419,7 @@ def process_blocks(blocks, lookup):
"teileart": "ILS 2.0 Eckrad", "teileart": "ILS 2.0 Eckrad",
"teileid": block.get("attribs", {}).get("ID", "0000"), "teileid": block.get("attribs", {}).get("ID", "0000"),
"bezeichnung": f"Eckrad :{eckrad_count}", "bezeichnung": f"Eckrad :{eckrad_count}",
"planquadrat": planquadrat_column(block), "planquadrat": planquadrat_column(block, planquadrat_cfg),
"merkmale": build_kreisel_merkmale(block), "merkmale": build_kreisel_merkmale(block),
**bbox_columns(block), **bbox_columns(block),
}) })
@@ -424,7 +434,7 @@ def process_blocks(blocks, lookup):
"teileart": "ILS 2.0 Kreisel", "teileart": "ILS 2.0 Kreisel",
"teileid": block.get("attribs", {}).get("ID", "0000"), "teileid": block.get("attribs", {}).get("ID", "0000"),
"bezeichnung": f"Kreisel :{kreisel_count}", "bezeichnung": f"Kreisel :{kreisel_count}",
"planquadrat": planquadrat_column(block), "planquadrat": planquadrat_column(block, planquadrat_cfg),
"merkmale": build_kreisel_merkmale(block), "merkmale": build_kreisel_merkmale(block),
**bbox_columns(block), **bbox_columns(block),
}) })
@@ -439,7 +449,7 @@ def process_blocks(blocks, lookup):
"teileart": "ILS 2.0 Strecke - Modul", "teileart": "ILS 2.0 Strecke - Modul",
"teileid": block.get("attribs", {}).get("ID", "0000"), "teileid": block.get("attribs", {}).get("ID", "0000"),
"bezeichnung": f"Streckenmodul :{strecke_modul_count}", "bezeichnung": f"Streckenmodul :{strecke_modul_count}",
"planquadrat": planquadrat_column(block), "planquadrat": planquadrat_column(block, planquadrat_cfg),
"merkmale": {"Blockname": bname}, "merkmale": {"Blockname": bname},
**bbox_columns(block), **bbox_columns(block),
}) })
@@ -460,9 +470,12 @@ def process_blocks(blocks, lookup):
"boundingbox": "", "boundingbox": "",
}) })
neighbor_ids = compute_neighbor_ids(items, NEIGHBOR_TOLERANCE_MM) neighbor_ids = compute_neighbor_ids(
for item, nachbarn in zip(items, 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["nachbarn"] = nachbarn
item["fehler"] = fehler
return items return items
@@ -475,14 +488,15 @@ def format_csv_line(item):
merkmale_json = json.dumps(item["merkmale"], ensure_ascii=False) merkmale_json = json.dumps(item["merkmale"], ensure_ascii=False)
return ( return (
f'{item["nr"]}' f'{item["nr"]}'
f';"{item["teileart"]}"' f';"{csv_quote(item["teileart"])}"'
f';"{item["teileid"]}"' f';"{csv_quote(item["teileid"])}"'
f';"{item["bezeichnung"]}"' f';"{csv_quote(item["bezeichnung"])}"'
f';"{item["planquadrat"]}"' f';"{csv_quote(item["planquadrat"])}"'
f';1' f';1'
f';"{item["position"]}"' f';"{csv_quote(item["position"])}"'
f';"{item["boundingbox"]}"' f';"{csv_quote(item["boundingbox"])}"'
f';"{item["nachbarn"]}"' f';"{csv_quote(item["nachbarn"])}"'
f';"{csv_quote(item["fehler"])}"'
f';{merkmale_json}' f';{merkmale_json}'
) )
@@ -514,7 +528,7 @@ def main():
items = process_blocks(blocks, lookup) 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: with open(output_csv, "w", encoding="utf-8") as f:
f.write(header + "\n") f.write(header + "\n")
for item in items: for item in items:
+194 -44
View File
@@ -1,72 +1,222 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# -*- coding: utf-8 -*- # -*- 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 Reines Python (keine externe Abhaengigkeit wie shapely) - die Bloecke werden
x/y-Ebene (Grundriss, Z/Hoehe wird ignoriert) ueberschneiden. Um auch nah dazu in drei Gruppen eingeteilt und NUR innerhalb dieser Kombinationen
beieinander liegende, aber nicht direkt beruehrende Elemente (z.B. Kreisel) gegeneinander geprueft (nicht mehr alle Elemente einer Zeichnung gemeinsam):
als benachbart zu erkennen, wird jede Bounding-Box vor der Pruefung um die
Haelfte der konfigurierten Toleranz nach allen Seiten erweitert - zwei 1. Kreisel/Eckrad gegen Kreisel/Eckrad
Elemente mit einem Abstand <= toleranz_mm gelten dann ebenfalls als 2. Kreisel/Eckrad gegen Gefaellestrecke/Foerderer/Strecke-Modul - diese
benachbart. Die Toleranz wird aus cfg/export.cfg ([Nachbarschaft] -> drei Kategorien werden NICHT gegeneinander getestet (nur relevant, wo
toleranz_mm) gelesen. 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. 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 KREISEL_TEILEARTEN = {"ILS 2.0 Kreisel", "ILS 2.0 Eckrad"}
from shapely.strtree import STRtree 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): def load_neighbor_tolerance_mm(cfg_path=None):
"""Liest die Nachbarschafts-Toleranz (mm) aus export.cfg. Default: 0.""" """Liest die Nachbarschafts-Toleranz (mm) aus export.cfg. Default: 0."""
if cfg_path is None: if cfg_path is None:
cfg_path = cfg_path_from_env() cfg_path = cfg_path_from_env()
parser = configparser.ConfigParser(inline_comment_prefixes=("#",)) parser = load_export_cfg(cfg_path)
parser.read(cfg_path, encoding="utf-8")
return parser.getfloat("Nachbarschaft", "toleranz_mm", fallback=0.0) return parser.getfloat("Nachbarschaft", "toleranz_mm", fallback=0.0)
def compute_neighbor_ids(items, tolerance_mm): def load_omniflo_cell_size_mm(cfg_path=None):
"""Ermittelt je Item die IDs (item["teileid"]) ueberschneidender Nachbarn. """Liest die Rastergroesse (mm) fuer die Omniflo-Nachbarschaftspruefung.
items = Liste von dict mit "teileid" und optional "_bbox" Default 3000mm: groesser als die ueblichen Omniflo-Bauteile (AP110-
({"cx","cy","dx","dy",...}, siehe export.lsp csv:get-bbox / export_csv.py Geraden ca. 2000mm), damit ein Element nicht durch ein zu kleines
bbox_columns). Items ohne _bbox (z.B. die synthetische Omniflo-Sum-Zeile) Raster in mehr als eine Zelle ueberlappt.
haben keine Nachbarn. """
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 Rueckgabe: Liste von kommaseparierten Nachbar-ID-Strings, positionsgleich
zu items (nicht ueber die ID dedupliziert, da TeileId nicht zwingend zu items (nicht ueber die ID dedupliziert, da TeileId nicht zwingend
eindeutig ist). 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 half_tol = tolerance_mm / 2.0
geoms = [] result = [[] for _ in items]
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))
tree = STRtree(geoms) kreisel_group = []
for local_i, global_i in enumerate(idx_with_bbox): strecken_group = []
hits = tree.query(geoms[local_i], predicate="intersects") omniflo_group = []
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)
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) rundet die x/y-Koordinate eines Blocks (mm, wie im Roh-JSON von export.lsp)
je Achse auf die konfigurierte Schrittweite (in Metern) herunter. 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. 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 export_blockpatterns import cfg_path_from_env
def load_planquadrat_config(cfg_path=None): def load_planquadrat_config(cfg_path=None):
"""Liest die aktive Planquadrat-Konfiguration aus export.cfg. """Liest die aktive Planquadrat-Konfiguration aus export.cfg.
Rueckgabe: dict mit x_step_mm, x_alpha, y_step_mm, y_alpha, format, Rueckgabe: dict mit x_step_mm, x_alpha, y_step_mm, y_alpha,
oder None, wenn [Planquadrate] bzw. die referenzierte Sub-Sektion fehlt. 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: if cfg_path is None:
cfg_path = cfg_path_from_env() cfg_path = cfg_path_from_env()
# inline_comment_prefixes noetig, da export.cfg Werte wie parser = load_export_cfg(cfg_path)
# "numerisch # zahlen, von links nach rechts, 2m pro Spalte" nutzt.
parser = configparser.ConfigParser(inline_comment_prefixes=("#",))
parser.read(cfg_path, encoding="utf-8")
if not parser.has_section("Planquadrate"): if not parser.has_section("Planquadrate"):
return None return None
@@ -36,15 +38,48 @@ def load_planquadrat_config(cfg_path=None):
return None return None
sec = parser[section_name] 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 { return {
"x_step_mm": float(sec.get("x_step", "1")) * 1000.0, "x_step_mm": float(sec.get("x_step", "1")) * 1000.0,
"x_alpha": sec.get("x_description", "numerisch").strip().lower().startswith("alpha"), "x_alpha": sec.get("x_description", "numerisch").strip().lower().startswith("alpha"),
"y_step_mm": float(sec.get("y_step", "1")) * 1000.0, "y_step_mm": float(sec.get("y_step", "1")) * 1000.0,
"y_alpha": sec.get("y_description", "numerisch").strip().lower().startswith("alpha"), "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(), "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): def _index_to_alpha(n):
"""Wandelt einen 1-basierten Index in eine Buchstaben-Bezeichnung um. """Wandelt einen 1-basierten Index in eine Buchstaben-Bezeichnung um.
@@ -57,15 +92,22 @@ def _index_to_alpha(n):
return result return result
def _index_for(coord_mm, step_mm): def _index_for(coord_mm, step_mm, origin_mm=0.0):
"""1-basierter Planquadrat-Index einer Koordinate fuer eine Schrittweite.""" """1-basierter Planquadrat-Index einer Koordinate fuer eine Schrittweite.
return int(coord_mm // step_mm) + 1
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): def compute_planquadrat(x_mm, y_mm, cfg):
"""Berechnet die Planquadrat-Bezeichnung fuer eine x/y-Koordinate (mm).""" """Berechnet die Planquadrat-Bezeichnung fuer eine x/y-Koordinate (mm)."""
x_idx = _index_for(x_mm, cfg["x_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"]) 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) 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) 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) return cfg["format"].format(x=x_label, y=y_label)
+70 -69
View File
@@ -33,7 +33,7 @@ import json
import sys import sys
import os 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() BLOCKPATTERNS = load_patterns()
@@ -99,10 +99,7 @@ def build_gefaellestrecke_details(block):
attribs = block.get("attribs", {}) attribs = block.get("attribs", {})
def mm_to_m(key): def mm_to_m(key):
try: return str(round(safe_float(attribs.get(key, "0")) / 1000.0, 2))
return str(round(float(attribs.get(key, "0")) / 1000.0, 2))
except (ValueError, TypeError):
return "0"
return { return {
"Hoehe oben": mm_to_m("HOEHE_VON_mm"), "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 Separatoren": attribs.get("ANZAHL_SEPARATOR", "0"),
"Anzahl der Scanner": attribs.get("ANZAHL_SCANNER", "0"), "Anzahl der Scanner": attribs.get("ANZAHL_SCANNER", "0"),
"Typ": attribs.get("TYP", "Gefaellestrecke"), "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): def kreisel_signature(block):
""" """
Schluessel zur Gruppierung gleichartiger Kreisel: Kreiselart, Abstand, Schluessel zur Gruppierung gleichartiger Kreisel: Kreiselart, Abstand,
Anzahl der Separatoren, Anzahl der Scanner und Anzahl der Rampen Anzahl der Separatoren, Anzahl der Scanner, Anzahl der Rampen sowie
entscheiden, ob Kreisel in derselben Sivas-Zeile summiert werden. Geruest fuer Einzelmodul/Geruestoption entscheiden, ob Kreisel in
derselben Sivas-Zeile summiert werden.
""" """
attribs = block.get("attribs", {}) attribs = block.get("attribs", {})
return ( return (
@@ -129,14 +129,29 @@ def kreisel_signature(block):
attribs.get("ANZAHL_SCANNER", attribs.get("N_SCANNER", "0")), attribs.get("ANZAHL_SCANNER", attribs.get("N_SCANNER", "0")),
attribs.get("ANZAHL_RAMPEN", attribs.get("N_RAMPEN", "0")), attribs.get("ANZAHL_RAMPEN", attribs.get("N_RAMPEN", "0")),
attribs.get("GERUEST_EINZELMODUL", "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): def gefaellestrecke_signature(block):
""" """
Schluessel zur Gruppierung gleichartiger Gefaellestrecken: Bloecke mit Schluessel zur Gruppierung gleichartiger Gefaellestrecken: Bloecke mit
identischen Massen (Hoehe, Laenge, Winkel, Separatoren, Scanner, Typ) identischen Massen (Hoehe, Laenge, Winkel, Separatoren, Scanner, Typ,
landen in derselben Sivas-Zeile - nur IDs/Bezeichnung unterscheiden sich. Geruest fuer Einzelmodul/Geruestoption) landen in derselben Sivas-Zeile -
nur IDs/Bezeichnung unterscheiden sich.
""" """
attribs = block.get("attribs", {}) attribs = block.get("attribs", {})
return ( return (
@@ -147,6 +162,8 @@ def gefaellestrecke_signature(block):
attribs.get("ANZAHL_SEPARATOR", "0"), attribs.get("ANZAHL_SEPARATOR", "0"),
attribs.get("ANZAHL_SCANNER", "0"), attribs.get("ANZAHL_SCANNER", "0"),
attribs.get("TYP", "Gefaellestrecke"), 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", {}) attribs = block.get("attribs", {})
def to_int(key): def to_int(key):
try: return safe_int(attribs.get(key, "0") or "0")
return int(attribs.get(key, "0") or "0")
except (ValueError, TypeError):
return 0
return { return {
"Anzahl Foerdergruppen": to_int("ANZAHL_VF"), "Anzahl Foerdergruppen": to_int("ANZAHL_VF"),
@@ -212,22 +226,16 @@ def build_variofoerderer_details(block):
}, },
"Anzahl der Separatoren": to_int("ANZAHL_SEPARATOR"), "Anzahl der Separatoren": to_int("ANZAHL_SEPARATOR"),
"Anzahl der Scanner": to_int("ANZAHL_SCANNER"), "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): def build_kreisel_details(block):
"""Merkmale-Dict fuer einen ILS Kreisel.""" """Merkmale-Dict fuer einen ILS Kreisel."""
attribs = block.get("attribs", {}) attribs = block.get("attribs", {})
abstand_mm = attribs.get("ABSTAND", "2300") abstand_m = str(round(safe_float(attribs.get("ABSTAND", "2300"), 2300.0) / 1000.0, 2))
try: hoehe_m = str(round(safe_float(attribs.get("HOEHE", "0"), 0.0) / 1000.0, 2))
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"
return { return {
"Hoehe in m": hoehe_m, "Hoehe in m": hoehe_m,
"Kreiselart": attribs.get("KREISELART", "STANDARD"), "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 Scanner": attribs.get("ANZAHL_SCANNER", attribs.get("N_SCANNER", "0")),
"Anzahl der Rampen": attribs.get("ANZAHL_RAMPEN", attribs.get("N_RAMPEN", "0")), "Anzahl der Rampen": attribs.get("ANZAHL_RAMPEN", attribs.get("N_RAMPEN", "0")),
"Geruest fuer Einzelmodul": attribs.get("GERUEST_EINZELMODUL", "0") == "1", "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: artinr_str -> {anzahl, laenge_mm_total, ids}
gerade_groups = {} gerade_groups = {}
kreisel_list = [] # Liste von blocks kreisel_list = [] # Liste von blocks
eckrad_ids = [] # IDs aller Eckrad-Bloecke eckrad_groups = {} # eckrad_signature(block) -> {"ids", "bezeichnungen", "block"}
eckrad_bezeichnungen = [] # Bezeichnung-Attribut aller Eckrad-Bloecke
strecke_ids = [] # IDs loser Strecke-Elemente (Vario/Staustrecke ausserhalb VF_N) strecke_ids = [] # IDs loser Strecke-Elemente (Vario/Staustrecke ausserhalb VF_N)
strecke_bezeichnungen = [] # Bezeichnung-Attribut loser Strecke-Elemente strecke_bezeichnungen = [] # Bezeichnung-Attribut loser Strecke-Elemente
vario_list = [] # Liste von VarioFoerderer-Compound-Bloecken (VF_N), je einer Zeile 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", {}) attribs = block.get("attribs", {})
artinr = attribs.get("ARTINR", "") artinr = attribs.get("ARTINR", "")
key = artinr if artinr else "AP110" key = artinr if artinr else "AP110"
laenge = 2000.0
laenge_attr = attribs.get("LAENGE") or attribs.get("A") laenge_attr = attribs.get("LAENGE") or attribs.get("A")
if laenge_attr: laenge = safe_float(laenge_attr, 2000.0)
try:
laenge = float(laenge_attr)
except (ValueError, TypeError):
pass
if key not in gerade_groups: if key not in gerade_groups:
gerade_groups[key] = { gerade_groups[key] = {
"anzahl": 0, "laenge_mm": 0.0, "anzahl": 0, "laenge_mm": 0.0,
@@ -375,8 +387,12 @@ def process_blocks(blocks, lookup):
# ECKRAD_* mit ein, pattern_eckrad ist die praezisere Teilmenge) --- # ECKRAD_* mit ein, pattern_eckrad ist die praezisere Teilmenge) ---
if matches_any(bname, BLOCKPATTERNS.get("pattern_eckrad", [])): if matches_any(bname, BLOCKPATTERNS.get("pattern_eckrad", [])):
counters["anzahl_eckraeder"] += 1 counters["anzahl_eckraeder"] += 1
eckrad_ids.append(get_id(block)) sig = eckrad_signature(block)
eckrad_bezeichnungen.append(block.get("attribs", {}).get("Bezeichnung", "")) 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 continue
# --- ILS Kreisel --- # --- ILS Kreisel ---
@@ -384,17 +400,17 @@ def process_blocks(blocks, lookup):
kreisel_list.append(block) kreisel_list.append(block)
attribs = block.get("attribs", {}) attribs = block.get("attribs", {})
counters["anzahl_kreisel"] += 1 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") kreiselart = attribs.get("KREISELART", "STANDARD")
if kreiselart == "PIN": if kreiselart == "PIN":
counters["anzahl_kreisel_pinband"] += 1 counters["anzahl_kreisel_pinband"] += 1
counters["sep_kreisel_pin"] += n_sep counters["sep_kreisel_pin"] += n_sep
else: else:
counters["sep_kreisel_ohne_pin"] += n_sep 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["laengen_kreisel"] += abstand_mm / 1000.0
counters["anzahl_separatoren"] += n_sep 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: if counters["anzahl_streckengruppen"] == 0:
counters["anzahl_streckengruppen"] = 1 counters["anzahl_streckengruppen"] = 1
continue continue
@@ -406,18 +422,9 @@ def process_blocks(blocks, lookup):
attribs = block.get("attribs", {}) attribs = block.get("attribs", {})
counters["anzahl_variofoerderer"] += 1 counters["anzahl_variofoerderer"] += 1
vario_list.append(block) vario_list.append(block)
try: counters["laengen_variofoerderer"] += safe_float(attribs.get("L_VF_m", "0") or "0")
counters["laengen_variofoerderer"] += float(attribs.get("L_VF_m", "0") or "0") counters["anzahl_separatoren"] += safe_int(attribs.get("ANZAHL_SEPARATOR", "0") or "0")
except (ValueError, TypeError): counters["anzahl_scanner"] += safe_int(attribs.get("ANZAHL_SCANNER", "0") or "0")
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
if counters["anzahl_streckengruppen"] == 0: if counters["anzahl_streckengruppen"] == 0:
counters["anzahl_streckengruppen"] = 1 counters["anzahl_streckengruppen"] = 1
continue continue
@@ -428,18 +435,9 @@ def process_blocks(blocks, lookup):
attribs = block.get("attribs", {}) attribs = block.get("attribs", {})
counters["anzahl_gefaellestrecken"] += 1 counters["anzahl_gefaellestrecken"] += 1
gefaelle_list.append(block) gefaelle_list.append(block)
try: counters["laengen_gefaellestrecken"] += safe_float(attribs.get("L_GF_m", "0") or "0")
counters["laengen_gefaellestrecken"] += float(attribs.get("L_GF_m", "0") or "0") counters["anzahl_separatoren"] += safe_int(attribs.get("ANZAHL_SEPARATOR", "0") or "0")
except (ValueError, TypeError): counters["anzahl_scanner"] += safe_int(attribs.get("ANZAHL_SCANNER", "0") or "0")
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
if counters["anzahl_streckengruppen"] == 0: if counters["anzahl_streckengruppen"] == 0:
counters["anzahl_streckengruppen"] = 1 counters["anzahl_streckengruppen"] = 1
continue continue
@@ -526,19 +524,22 @@ def process_blocks(blocks, lookup):
}) })
nr += 1 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"] sivasnr, teileart = ILS_SIVASNR["eckrad"]
items.append({ items.append({
"nr": nr, "nr": nr,
"teileart": teileart, "teileart": teileart,
"sivasnr": sivasnr, "sivasnr": sivasnr,
"sivasnr_quoted": True, "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, "dispgruppe": 20,
"anzahl": counters["anzahl_eckraeder"], "anzahl": len(group["ids"]),
"laenge_mm": "", "laenge_mm": "",
"ids": eckrad_ids, "ids": group["ids"],
"details": {}, "details": build_eckrad_details(group["block"]),
}) })
nr += 1 nr += 1
@@ -654,17 +655,17 @@ def process_blocks(blocks, lookup):
def format_csv_line(item): def format_csv_line(item):
"""Formatiert eine CSV-Zeile im neuen Sivas-Format.""" """Formatiert eine CSV-Zeile im neuen Sivas-Format."""
details_json = json.dumps(item["details"], ensure_ascii=False) 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) ids_str = ", ".join(str(i) for i in item.get("ids", []) if i)
return ( return (
f'{item["nr"]}' f'{item["nr"]}'
f';"{item["teileart"]}"' f';"{csv_quote(item["teileart"])}"'
f';{sivasnr}' f';{sivasnr}'
f';"{item["bezeichnung"]}"' f';"{csv_quote(item["bezeichnung"])}"'
f';{item["dispgruppe"]}' f';{item["dispgruppe"]}'
f';{item["anzahl"]}' f';{item["anzahl"]}'
f';{item["laenge_mm"]}' f';{item["laenge_mm"]}'
f';"{ids_str}"' f';"{csv_quote(ids_str)}"'
f';{details_json}' f';{details_json}'
) )
+12 -12
View File
@@ -154,7 +154,7 @@ def read_ks(doc, name):
dx = end[0] - point[0] dx = end[0] - point[0]
dy = end[1] - point[1] dy = end[1] - point[1]
dz = end[2] - point[2] 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) axes[line.dxf.color] = (dx / length, dy / length, dz / length)
x_axis = axes.get(1, (1, 0, 0)) x_axis = axes.get(1, (1, 0, 0))
@@ -355,11 +355,11 @@ def k2_point_bogen(doc):
continue continue
s = (e.dxf.start[0], e.dxf.start[1]) s = (e.dxf.start[0], e.dxf.start[1])
end = (e.dxf.end[0], e.dxf.end[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 ds = math.dist(s, k2_junction)
de = ((end[0] - k2_junction[0])**2 + (end[1] - k2_junction[1])**2) ** 0.5 de = math.dist(end, k2_junction)
if ds > tol and de > tol: if ds > tol and de > tol:
continue continue
ln = ((end[0] - s[0])**2 + (end[1] - s[1])**2) ** 0.5 ln = math.dist(end, s)
if ln > best_line_len: if ln > best_line_len:
best_line_len = ln best_line_len = ln
if ds < tol: if ds < tol:
@@ -428,8 +428,8 @@ def _find_weiche_arc_branches(doc):
cy + r * math.sin(math.radians(ea))) cy + r * math.sin(math.radians(ea)))
# K1-Seite = naeher an K1 # K1-Seite = naeher an K1
d_start = ((arc_start[0] - k1_x)**2 + (arc_start[1] - k1_y)**2) ** 0.5 d_start = math.dist(arc_start, (k1_x, k1_y))
d_end = ((arc_end[0] - k1_x)**2 + (arc_end[1] - k1_y)**2) ** 0.5 d_end = math.dist(arc_end, (k1_x, k1_y))
if d_start < d_end: if d_start < d_end:
k2_junction = arc_end k2_junction = arc_end
@@ -445,11 +445,11 @@ def _find_weiche_arc_branches(doc):
continue continue
ls = (ent.dxf.start[0], ent.dxf.start[1]) ls = (ent.dxf.start[0], ent.dxf.start[1])
le = (ent.dxf.end[0], ent.dxf.end[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 ds = math.dist(ls, k2_junction)
de = ((le[0] - k2_junction[0])**2 + (le[1] - k2_junction[1])**2) ** 0.5 de = math.dist(le, k2_junction)
if ds > tol and de > tol: if ds > tol and de > tol:
continue continue
ln = ((le[0] - ls[0])**2 + (le[1] - ls[1])**2) ** 0.5 ln = math.dist(le, ls)
if ln > best_len: if ln > best_len:
best_len = ln best_len = ln
if ds < tol: if ds < tol:
@@ -541,13 +541,13 @@ def _find_weichenkoerper_diag_branches(doc):
dy = abs(le[1] - ls[1]) dy = abs(le[1] - ls[1])
if dx < 0.01 or dy < 0.01: if dx < 0.01 or dy < 0.01:
continue continue
ln = (dx**2 + dy**2) ** 0.5 ln = math.dist(ls, le)
if ln < 100: if ln < 100:
continue continue
# Das Ende naeher an K1 ist die Junction, das andere ist der K2/K3-Punkt # 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_start = math.dist(ls, (k1_x, k1_y))
d_end = ((le[0] - k1_x)**2 + (le[1] - k1_y)**2) ** 0.5 d_end = math.dist(le, (k1_x, k1_y))
if d_start < d_end: if d_start < d_end:
candidates.append((le, ls)) candidates.append((le, ls))
else: else:
-1
View File
@@ -3,5 +3,4 @@
ezdxf==1.4.1 ezdxf==1.4.1
pytest==9.0.2 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 Elementnummer;TeileArt;TeileId;Bezeichnung;Planquadrat;Anzahl;Position;Boundingbox;Nachbarn;Fehler;Merkmale
1;"Omniflo Kurve";"0000";"OFBogen :1";"A/A";1;"";"";"";{"Kurvenwinkel": 22.5, "Radius": 550.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104025"} 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;"";"";"";{"Kurvenwinkel": 22.5, "Radius": 550.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104025+0_B10090"} 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;"";"";"";{"Kurvenwinkel": 22.5, "Radius": 550.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104025+0_B10091"} 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;"";"";"";{"Kurvenwinkel": 45.0, "Radius": 400.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104021"} 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;"";"";"";{"Kurvenwinkel": 45.0, "Radius": 550.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104026"} 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;"";"";"";{"Kurvenwinkel": 45.0, "Radius": 550.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104026+0_B10071"} 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;"";"";"";{"Kurvenwinkel": 45.0, "Radius": 550.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104037"} 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;"";"";"";{"Kurvenwinkel": 45.0, "Radius": 550.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104029"} 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;"";"";"";{"Kurvenwinkel": 45.0, "Radius": 630.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104031"} 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;"";"";"";{"Kurvenwinkel": 45.0, "Radius": 630.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104031+0_B10060"} 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;"";"";"";{"Kurvenwinkel": 45.0, "Radius": 630.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104031+0_B10070"} 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;"";"";"";{"Kurvenwinkel": 67.5, "Radius": 400.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104024"} 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;"";"";"";{"Kurvenwinkel": 67.5, "Radius": 400.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104024+0_B10081"} 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;"";"";"";{"Kurvenwinkel": 67.5, "Radius": 550.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104027"} 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;"";"";"";{"Kurvenwinkel": 67.5, "Radius": 550.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104027+0_B10080"} 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;"";"";"";{"Kurvenwinkel": 67.5, "Radius": 550.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104028"} 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;"";"";"";{"Kurvenwinkel": 67.5, "Radius": 550.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104065"} 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;"";"";"";{"Kurvenwinkel": 90.0, "Radius": 400.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104022"} 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;"";"";"";{"Kurvenwinkel": 90.0, "Radius": 500.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104030"} 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;"";"";"";{"Kurvenwinkel": 90.0, "Radius": 630.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104033"} 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;"";"";"";{"Kurvenwinkel": 90.0, "Radius": 630.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104033+0_B10040"} 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;"";"";"";{"Kurvenwinkel": 90.0, "Radius": 630.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104033+0_B10050"} 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;"";"";"";{"Kurvenwinkel": 90.0, "Radius": 630.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104035"} 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;"";"";"";{"Kurvenwinkel": 90.0, "Radius": 630.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104041"} 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;"";"";"";{"Kurvenwinkel": 90.0, "Radius": 630.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104034"} 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;"";"";"";{"Kurvenwinkel": 90.0, "Radius": 550.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104066"} 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;"";"";"";{"Kurvenwinkel": 180.0, "Radius": 650.0, "Höhe": "2000", "Drehung": 0.0, "SivasNummer": "821104043"} 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;"";"";"";{"Weichentyp": "Einzelweiche", "Richtung": "1", "Weichenwinkel": 22.5, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834342011"} 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;"";"";"";{"Weichentyp": "Einzelweiche", "Richtung": "2", "Weichenwinkel": 22.5, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834342001"} 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;"";"";"";{"Weichentyp": "Einzelweiche", "Richtung": "1", "Weichenwinkel": 22.5, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834342012"} 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;"";"";"";{"Weichentyp": "Einzelweiche", "Richtung": "2", "Weichenwinkel": 22.5, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834342002"} 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;"";"";"";{"Weichentyp": "Doppelweiche", "Richtung": "3", "Weichenwinkel": 22.5, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834342100"} 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;"";"";"";{"Weichentyp": "Doppelweiche", "Richtung": "3", "Weichenwinkel": 22.5, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834342101"} 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;"";"";"";{"Weichentyp": "Dreiwegeweiche", "Richtung": "7", "Weichenwinkel": 22.5, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834342200"} 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;"";"";"";{"Weichentyp": "Dreiwegeweiche", "Richtung": "7", "Weichenwinkel": 22.5, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834342201"} 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;"";"";"";{"Weichentyp": "Einzelweiche", "Richtung": "1", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372001"} 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;"";"";"";{"Weichentyp": "Einzelweiche", "Richtung": "1", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372002"} 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;"";"";"";{"Weichentyp": "Einzelweiche", "Richtung": "1", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "834372002+0_BG090090"} 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;"";"";"";{"Weichentyp": "Einzelweiche", "Richtung": "2", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372004"} 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;"";"";"";{"Weichentyp": "Einzelweiche", "Richtung": "2", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372005"} 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;"";"";"";{"Weichentyp": "Einzelweiche", "Richtung": "2", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "834372005+0_BG090090"} 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;"";"";"";{"Weichentyp": "Einzelweiche", "Richtung": "1", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372007"} 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;"";"";"";{"Weichentyp": "Einzelweiche", "Richtung": "1", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372008"} 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;"";"";"";{"Weichentyp": "Einzelweiche", "Richtung": "1", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "834372008+0_BG190090"} 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;"";"";"";{"Weichentyp": "Einzelweiche", "Richtung": "2", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372010"} 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;"";"";"";{"Weichentyp": "Einzelweiche", "Richtung": "2", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372011"} 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;"";"";"";{"Weichentyp": "Einzelweiche", "Richtung": "2", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "834372011+0_BG190090"} 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;"";"";"";{"Weichentyp": "Einzelweiche", "Richtung": "1", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372021"} 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;"";"";"";{"Weichentyp": "Einzelweiche", "Richtung": "1", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372022"} 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;"";"";"";{"Weichentyp": "Einzelweiche", "Richtung": "2", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372024"} 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;"";"";"";{"Weichentyp": "Einzelweiche", "Richtung": "2", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372025"} 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;"";"";"";{"Weichentyp": "Einzelweiche", "Richtung": "1", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372027"} 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;"";"";"";{"Weichentyp": "Einzelweiche", "Richtung": "1", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372028"} 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;"";"";"";{"Weichentyp": "Einzelweiche", "Richtung": "1", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "834372028+0_BG080090"} 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;"";"";"";{"Weichentyp": "Einzelweiche", "Richtung": "2", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372030"} 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;"";"";"";{"Weichentyp": "Einzelweiche", "Richtung": "2", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372031"} 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;"";"";"";{"Weichentyp": "Einzelweiche", "Richtung": "2", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "834372031+0_BG080090"} 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;"";"";"";{"Weichentyp": "Einzelweiche", "Richtung": "1", "Weichenwinkel": 0.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372047"} 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;"";"";"";{"Weichentyp": "Einzelweiche", "Richtung": "1", "Weichenwinkel": 0.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372048"} 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;"";"";"";{"Weichentyp": "Einzelweiche", "Richtung": "2", "Weichenwinkel": 0.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372050"} 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;"";"";"";{"Weichentyp": "Einzelweiche", "Richtung": "2", "Weichenwinkel": 0.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372051"} 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;"";"";"";{"Weichentyp": "Doppelweiche", "Richtung": "3", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372100"} 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;"";"";"";{"Weichentyp": "Doppelweiche", "Richtung": "3", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372101"} 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;"";"";"";{"Weichentyp": "Doppelweiche", "Richtung": "3", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "0_BG090090+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;"";"";"";{"Weichentyp": "Doppelweiche", "Richtung": "3", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "834372101+0_BG090090"} 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;"";"";"";{"Weichentyp": "Doppelweiche", "Richtung": "3", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "0_BG090090+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;"";"";"";{"Weichentyp": "Doppelweiche", "Richtung": "3", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372103"} 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;"";"";"";{"Weichentyp": "Doppelweiche", "Richtung": "3", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372104"} 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;"";"";"";{"Weichentyp": "Doppelweiche", "Richtung": "3", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "0_BG190090+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;"";"";"";{"Weichentyp": "Doppelweiche", "Richtung": "3", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "834372104+0_BG190090"} 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;"";"";"";{"Weichentyp": "Doppelweiche", "Richtung": "3", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "0_BG190090+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;"";"";"";{"Weichentyp": "Doppelweiche", "Richtung": "3", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372106"} 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;"";"";"";{"Weichentyp": "Doppelweiche", "Richtung": "3", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372107"} 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;"";"";"";{"Weichentyp": "Doppelweiche", "Richtung": "3", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372109"} 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;"";"";"";{"Weichentyp": "Doppelweiche", "Richtung": "3", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372110"} 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;"";"";"";{"Weichentyp": "Doppelweiche", "Richtung": "3", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "0_BG080090+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;"";"";"";{"Weichentyp": "Doppelweiche", "Richtung": "3", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "834372110+0_BG080090"} 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;"";"";"";{"Weichentyp": "Doppelweiche", "Richtung": "3", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "0_BG080090+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;"";"";"";{"Weichentyp": "Doppelweiche", "Richtung": "3", "Weichenwinkel": 0.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372115"} 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;"";"";"";{"Weichentyp": "Doppelweiche", "Richtung": "3", "Weichenwinkel": 0.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372116"} 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;"";"";"";{"Weichentyp": "Dreiwegeweiche", "Richtung": "7", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372200"} 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;"";"";"";{"Weichentyp": "Dreiwegeweiche", "Richtung": "7", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372201"} 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;"";"";"";{"Weichentyp": "Dreiwegeweiche", "Richtung": "7", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "0_BG090090+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;"";"";"";{"Weichentyp": "Dreiwegeweiche", "Richtung": "7", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "834372201+0_BG090090"} 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;"";"";"";{"Weichentyp": "Dreiwegeweiche", "Richtung": "7", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "0_BG090090+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;"";"";"";{"Weichentyp": "Dreiwegeweiche", "Richtung": "7", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372203"} 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;"";"";"";{"Weichentyp": "Dreiwegeweiche", "Richtung": "7", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372204"} 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;"";"";"";{"Weichentyp": "Dreiwegeweiche", "Richtung": "7", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "0_BG190090+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;"";"";"";{"Weichentyp": "Dreiwegeweiche", "Richtung": "7", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "834372204+0_BG190090"} 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;"";"";"";{"Weichentyp": "Dreiwegeweiche", "Richtung": "7", "Weichenwinkel": 45.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "0_BG190090+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;"";"";"";{"Weichentyp": "Dreiwegeweiche", "Richtung": "7", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372206"} 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;"";"";"";{"Weichentyp": "Dreiwegeweiche", "Richtung": "7", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372207"} 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;"";"";"";{"Weichentyp": "Dreiwegeweiche", "Richtung": "7", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372209"} 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;"";"";"";{"Weichentyp": "Dreiwegeweiche", "Richtung": "7", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372210"} 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;"";"";"";{"Weichentyp": "Dreiwegeweiche", "Richtung": "7", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "0_BG080090+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;"";"";"";{"Weichentyp": "Dreiwegeweiche", "Richtung": "7", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "834372210+0_BG080090"} 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;"";"";"";{"Weichentyp": "Dreiwegeweiche", "Richtung": "7", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "0_BG080090+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;"";"";"";{"Weichentyp": "Dreiwegeweiche", "Richtung": "7", "Weichenwinkel": 0.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372215"} 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;"";"";"";{"Weichentyp": "Dreiwegeweiche", "Richtung": "7", "Weichenwinkel": 0.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372216"} 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;"";"";"";{"Weichentyp": "Dreifachweiche", "Richtung": "3", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372400"} 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;"";"";"";{"Weichentyp": "Dreifachweiche", "Richtung": "3", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372403"} 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;"";"";"";{"Weichentyp": "Dreifachweiche", "Richtung": "3", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372404"} 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;"";"";"";{"Weichentyp": "Dreifachweiche", "Richtung": "3", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "0_BG071090+834372404+0_BG071090"} 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;"";"";"";{"Weichentyp": "Dreifachweiche", "Richtung": "3", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "0_BG071090+834372404"} 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;"";"";"";{"Weichentyp": "Dreifachweiche", "Richtung": "3", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": true, "SivasNummer": "834372404+0_BG071090"} 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 :1";"K/A";1;"";"";"";{"Weichentyp": "Deltaweiche", "Richtung": "7", "Weichenwinkel": 90.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372401"} 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;"";"";"";{"Weichentyp": "Sternweiche", "Richtung": "3", "Weichenwinkel": 0.0, "Höhe": "2000", "Drehung": 0.0, "Antrieb Kurve": false, "SivasNummer": "834372420"} 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} 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 (vf-block-erstellen "standard" seite vf-nummer 0
hoehe-von hoehe-bis deltaH deltaL L_VF hoehe-von hoehe-bis deltaH deltaL L_VF
L_GF1 L_GF2 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. ;; lastEnt hinter den SEQEND des VF-Blocks schieben.
;; Ohne diesen Schritt wuerde entnext vom INSERT-Entity ;; Ohne diesen Schritt wuerde entnext vom INSERT-Entity
;; in die ATTRIB-Kette des gerade erstellten VF-Blocks ;; in die ATTRIB-Kette des gerade erstellten VF-Blocks
+7 -6
View File
@@ -203,7 +203,8 @@ class TestFoerdererExportCSV:
def test_header_felder(self): def test_header_felder(self):
"""CSV-Header muss korrekte Spaltenbezeichnungen haben.""" """CSV-Header muss korrekte Spaltenbezeichnungen haben."""
expected = ["Elementnummer", "TeileArt", "TeileId", "Bezeichnung", expected = ["Elementnummer", "TeileArt", "TeileId", "Bezeichnung",
"Planquadrat", "Anzahl", "Position", "Boundingbox", "Nachbarn", "Merkmale"] "Planquadrat", "Anzahl", "Position", "Boundingbox", "Nachbarn",
"Fehler", "Merkmale"]
for i, name in enumerate(expected): for i, name in enumerate(expected):
assert self.header[i] == name, ( assert self.header[i] == name, (
f"Header[{i}]: erwartet '{name}', ist '{self.header[i]}'" f"Header[{i}]: erwartet '{name}', ist '{self.header[i]}'"
@@ -235,10 +236,10 @@ class TestFoerdererExportCSV:
def test_merkmale_sind_valides_json(self): def test_merkmale_sind_valides_json(self):
"""Merkmale-Spalte muss valides JSON enthalten.""" """Merkmale-Spalte muss valides JSON enthalten."""
for i, row in enumerate(self.rows): for i, row in enumerate(self.rows):
if len(row) < 10: if len(row) < 11:
continue continue
try: try:
json.loads(row[9]) json.loads(row[10])
except json.JSONDecodeError as e: except json.JSONDecodeError as e:
pytest.fail(f"Zeile {i + 2}: Merkmale ist kein valides JSON: {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", required = {"Typ", "Winkel", "DeltaH_mm", "DeltaL_mm",
"L_VF_m", "Hoehe_Von_mm", "Hoehe_Bis_mm"} "L_VF_m", "Hoehe_Von_mm", "Hoehe_Bis_mm"}
for i, row in enumerate(self.rows): for i, row in enumerate(self.rows):
if len(row) < 10: if len(row) < 11:
continue continue
merkmale = json.loads(row[9]) merkmale = json.loads(row[10])
missing = required - set(merkmale.keys()) missing = required - set(merkmale.keys())
assert not missing, ( assert not missing, (
f"Zeile {i + 2}: Fehlende Merkmale-Felder: {missing}" f"Zeile {i + 2}: Fehlende Merkmale-Felder: {missing}"
@@ -290,7 +291,7 @@ class TestFoerdererExportSivas:
def test_header_felder(self): def test_header_felder(self):
"""Sivas-CSV-Header muss korrekte Spalten haben.""" """Sivas-CSV-Header muss korrekte Spalten haben."""
expected = ["Nr", "TeileArt", "SivasNummer", "Bezeichnung", expected = ["Nr", "TeileArt", "SivasNummer", "Bezeichnung",
"Dispogruppe", "Anzahl", "Laenge[mm]", "details"] "Dispogruppe", "Anzahl", "Laenge[mm]", "IDs", "details"]
for i, name in enumerate(expected): for i, name in enumerate(expected):
assert self.header[i] == name, ( assert self.header[i] == name, (
f"Header[{i}]: erwartet '{name}', ist '{self.header[i]}'" f"Header[{i}]: erwartet '{name}', ist '{self.header[i]}'"
+7 -7
View File
@@ -285,7 +285,7 @@
bR90 bR60 bR30 bR90 bR60 bR30
startpunkt last-ent nach-aus-pt entry-hz startpunkt last-ent nach-aus-pt entry-hz
(caddr (nth first-idx segmente)) (caddr (nth first-idx segmente))
es-seite)) es-seite "0" "Schoenenberger Geruest"))
gf-ins gf-ins
) )
) )
@@ -383,7 +383,7 @@
(setq gf-ins (setq gf-ins
(car (gefaellestrecke-einfuegen (car (gefaellestrecke-einfuegen
test-L_stau test-winkel (list 0 0 test-z-start) 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 (if gf-ins
(progn (progn
(setq attribs (ssg-attrib-read gf-ins)) (setq attribs (ssg-attrib-read gf-ins))
@@ -415,7 +415,7 @@
(setq gf-ins (setq gf-ins
(car (gefaellestrecke-einfuegen (car (gefaellestrecke-einfuegen
test-L_stau test-winkel (list 15000 0 test-z-start) 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 (if gf-ins
(progn (progn
(setq attribs (ssg-attrib-read gf-ins)) (setq attribs (ssg-attrib-read gf-ins))
@@ -447,7 +447,7 @@
(setq gf-ins (setq gf-ins
(car (gefaellestrecke-einfuegen (car (gefaellestrecke-einfuegen
test-L_stau test-winkel (list 0 -15000 test-z-start) 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 (if gf-ins
(progn (progn
(setq attribs (ssg-attrib-read gf-ins)) (setq attribs (ssg-attrib-read gf-ins))
@@ -479,7 +479,7 @@
(setq gf-ins (setq gf-ins
(car (gefaellestrecke-einfuegen (car (gefaellestrecke-einfuegen
test-L_stau test-winkel (list 15000 -15000 test-z-start) 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 (if gf-ins
(progn (progn
(setq attribs (ssg-attrib-read gf-ins)) (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) ") ...")) (princ (strcat "\n\n M2_hz000: Start=(0,-35000," (rtos test-z-start 2 0) ") ..."))
(setq ergebnis (setq ergebnis
(gefaellestrecke-einfuegen (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)) (setq gf-ins (car ergebnis))
(if gf-ins (if gf-ins
(progn (progn
@@ -735,7 +735,7 @@
(setq gf-ins (setq gf-ins
(car (gefaellestrecke-einfuegen (car (gefaellestrecke-einfuegen
w30-lstau test-winkel (list 30000 0 test-z-start) 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 (if gf-ins
(progn (progn
(setq attribs (ssg-attrib-read gf-ins)) (setq attribs (ssg-attrib-read gf-ins))
+1 -1
View File
@@ -107,7 +107,7 @@ class TestOmnifloExportUnit:
out_dir = _output_dir() out_dir = _output_dir()
os.makedirs(out_dir, exist_ok=True) os.makedirs(out_dir, exist_ok=True)
csv_path = os.path.join(out_dir, "omniflo_export.csv") 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: with open(csv_path, "w", encoding="utf-8") as f:
f.write(header + "\n") f.write(header + "\n")
for item in self.items: for item in self.items:
+18 -1
View File
@@ -146,7 +146,7 @@
namen befehl datei export-fn new-doc namen befehl datei export-fn new-doc
out-path dwg-pfad dxf-pfad old-json test-result out-path dwg-pfad dxf-pfad old-json test-result
old-filenames csv-name sivas-name csv-pfad 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-pfad (strcat (getenv "DXFMAKRO") "/tests"))
(setq tests-out-dir (strcat tests-pfad "/output")) (setq tests-out-dir (strcat tests-pfad "/output"))
@@ -267,7 +267,15 @@
(princ (strcat "\n DWG gespeichert: " dwg-pfad)) (princ (strcat "\n DWG gespeichert: " dwg-pfad))
) )
((and save-fmt (= (strcase save-fmt) "DXF")) ((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) (command "_.DXFOUT" out-path 6)
(setvar "FILEDIA" old-filedia)
(princ (strcat "\n DXF gespeichert: " out-path ".dxf")) (princ (strcat "\n DXF gespeichert: " out-path ".dxf"))
) )
(T (T
@@ -343,7 +351,16 @@
(setq dwg-pfad (strcat out-path ".dwg")) (setq dwg-pfad (strcat out-path ".dwg"))
(setq dxf-pfad (strcat out-path ".dxf")) (setq dxf-pfad (strcat out-path ".dxf"))
(vla-saveas new-doc dwg-pfad) (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) (command "_.DXFOUT" out-path 6)
(setvar "FILEDIA" old-filedia)
(vla-close new-doc :vlax-false) (vla-close new-doc :vlax-false)
(if (findfile dwg-pfad) (vl-file-delete dwg-pfad)) (if (findfile dwg-pfad) (vl-file-delete dwg-pfad))
(setq new-doc (vla-open (vla-get-documents app) dxf-pfad)) (setq new-doc (vla-open (vla-get-documents app) dxf-pfad))