[MERGE] Gerüständerungen mergen

This commit is contained in:
2026-10-09 14:42:15 +02:00
75 changed files with 16170 additions and 1099 deletions
+10 -5
View File
File diff suppressed because one or more lines are too long
+612 -65
View File
@@ -714,16 +714,161 @@
prev-hz
)
;; Dialog fuer Modus 3 (Linienzug), Teil 1: AUS-/EIN-Element Winkel+Seite -
;; ersetzt die vier Konsolenfragen (AUS-Winkel, AUS-Seite, EIN-Winkel,
;; EIN-Seite). Muss VOR der Segmentlaengen-Anpassung/Winkelberechnung
;; laufen (die braucht aus-dx/ein-dx aus vf-set-as-masse/-es-masse), darum
;; eigener, frueherer Dialog statt zusammen mit dem Winkel-Vorschlag.
;; prefill: Alist (("as-winkel" . "90"|"30") ("as-seite" . "links"|"rechts")
;; ("es-winkel" . ...) ("es-seite" . ...)) fuer den Edit-Nachbau, oder nil
;; fuer die Defaults (90/links) beim Neu-Bauen.
;; Rueckgabe: (as-winkel as-seite es-winkel es-seite) bei OK, 'ABBRUCH wenn
;; der Nutzer bewusst abbricht (Aufrufer bricht dann den GANZEN Befehl ab,
;; KEIN Rueckfall auf die Konsole), nil wenn der Dialog gar nicht gezeigt
;; werden konnte/durfte (GUI aus) - NUR dann Konsolen-Rueckfall.
(defun gf-dialog-linienzug-aus-ein (prefill / dcl-pfad dat ergebnis
dlg-aus-winkel dlg-aus dlg-ein-winkel dlg-ein
as-seite es-seite as-winkel es-winkel)
(if (or (not (car (atoms-family 1 '("SSG-GUI-P")))) (ssg-gui-p))
(progn
(setq dcl-pfad (strcat (getenv "DXFM_DCL") "/gefaellestrecke.dcl"))
(setq dat (load_dialog dcl-pfad))
(if (not (new_dialog "gefaellestrecke_linienzug" dat))
(progn (if (and dat (>= dat 0)) (unload_dialog dat)) nil)
(progn
(set_tile "zusammenfassung" (ssg-text "gf-dlg-linienzug-vorlauf"))
(mode_tile "winkel" 1)
(start_list "aus_winkel")
(add_list "90")
(add_list "30")
(end_list)
(set_tile "aus_winkel"
(if (and prefill (equal (cdr (assoc "as-winkel" prefill)) "30")) "1" "0"))
(start_list "aus_seite")
(add_list (ssg-text "gf-dlg-links"))
(add_list (ssg-text "gf-dlg-rechts"))
(end_list)
(set_tile "aus_seite"
(if (and prefill (equal (cdr (assoc "as-seite" prefill)) "rechts")) "1" "0"))
(start_list "ein_winkel")
(add_list "90")
(add_list "30")
(end_list)
(set_tile "ein_winkel"
(if (and prefill (equal (cdr (assoc "es-winkel" prefill)) "30")) "1" "0"))
(start_list "ein_seite")
(add_list (ssg-text "gf-dlg-links"))
(add_list (ssg-text "gf-dlg-rechts"))
(end_list)
(set_tile "ein_seite"
(if (and prefill (equal (cdr (assoc "es-seite" prefill)) "rechts")) "1" "0"))
(action_tile "accept"
(strcat
"(setq dlg-aus-winkel (get_tile \"aus_winkel\"))"
"(setq dlg-aus (get_tile \"aus_seite\"))"
"(setq dlg-ein-winkel (get_tile \"ein_winkel\"))"
"(setq dlg-ein (get_tile \"ein_seite\"))"
"(done_dialog 1)"
)
)
(action_tile "cancel" "(done_dialog 0)")
(setq ergebnis (start_dialog))
(unload_dialog dat)
(cond
((= ergebnis 1)
(setq as-winkel (if (= dlg-aus-winkel "1") "30" "90"))
(setq as-seite (if (= dlg-aus "1") "rechts" "links"))
(setq es-winkel (if (= dlg-ein-winkel "1") "30" "90"))
(setq es-seite (if (= dlg-ein "1") "rechts" "links"))
(list as-winkel as-seite es-winkel es-seite)
)
(t 'ABBRUCH)
)
)
)
)
nil
)
)
;; Dialog fuer Modus 3, Teil 2: Gefaellewinkel-Bestaetigung VOR der
;; iterativen AS/ES-Korrekturschleife (die braucht den vom Nutzer
;; gewaehlten/bestaetigten Ausgangswinkel, berechnet selbst aber nicht
;; interaktiv weiter) - ersetzt die "Berechneten Winkel verwenden?"-Frage
;; samt optionalem manuellem Winkel. Ersetzt zugleich die SPAETERE finale
;; Einfuegen-Bestaetigung: nach diesem OK baut der Aufrufer direkt, ohne
;; weitere Rueckfrage (analog "dialog-bestaetigt" bei Modus 1/2) - die
;; Zusammenfassung mit dem Vorschlag genuegt als Entscheidungsgrundlage,
;; eine zweite Bestaetigung NACH der (rein automatischen) Korrekturschleife
;; waere redundant. Das AS/ES-Auswahlpaar wird hier nur noch ANGEZEIGT
;; (disabled), nicht erneut editierbar - es ist schon in die Segmentlaengen
;; eingerechnet.
;; zusammenfassung-zeilen: Liste bereits fertig formatierter Strings.
;; Rueckgabe: Gefaellewinkel (Grad) bei OK, 'ABBRUCH wenn der Nutzer bewusst
;; abbricht (Aufrufer bricht dann den GANZEN Befehl ab, KEIN Rueckfall auf
;; die Konsole), nil wenn der Dialog gar nicht gezeigt werden konnte/durfte
;; (GUI aus) - NUR dann Konsolen-Rueckfall (inkl. der spaeteren finalen
;; Einfuegen-Bestaetigung, die in diesem Fall unveraendert bleibt).
(defun gf-dialog-linienzug-winkel (zusammenfassung-zeilen winkel-vorschlag
as-winkel as-seite es-winkel es-seite /
dcl-pfad dat ergebnis dlg-winkel grade)
(if (or (not (car (atoms-family 1 '("SSG-GUI-P")))) (ssg-gui-p))
(progn
(setq dcl-pfad (strcat (getenv "DXFM_DCL") "/gefaellestrecke.dcl"))
(setq dat (load_dialog dcl-pfad))
(if (not (new_dialog "gefaellestrecke_linienzug" dat))
(progn (if (and dat (>= dat 0)) (unload_dialog dat)) nil)
(progn
(set_tile "zusammenfassung" (ssg-join zusammenfassung-zeilen " | "))
(start_list "aus_winkel") (add_list as-winkel) (end_list)
(set_tile "aus_winkel" "0")
(start_list "aus_seite") (add_list as-seite) (end_list)
(set_tile "aus_seite" "0")
(start_list "ein_winkel") (add_list es-winkel) (end_list)
(set_tile "ein_winkel" "0")
(start_list "ein_seite") (add_list es-seite) (end_list)
(set_tile "ein_seite" "0")
(mode_tile "aus_winkel" 1) (mode_tile "aus_seite" 1)
(mode_tile "ein_winkel" 1) (mode_tile "ein_seite" 1)
(set_tile "winkel" (rtos winkel-vorschlag 2 3))
(action_tile "accept"
"(setq dlg-winkel (get_tile \"winkel\")) (done_dialog 1)")
(action_tile "cancel" "(done_dialog 0)")
(setq ergebnis (start_dialog))
(unload_dialog dat)
(cond
((= ergebnis 1)
(setq grade (atof dlg-winkel))
(if (<= grade 0) (setq grade winkel-vorschlag))
grade
)
(t 'ABBRUCH)
)
)
)
)
nil
)
)
;; Hauptfunktion Modus 3
(defun gf-linienzug-modus ( /
ss n i j obj obj-liste kette segmente seg
startpunkt endpunkt-ref deltaH grade antwort idx
as-seite es-seite as-block es-block
gf-as-winkel gf-es-winkel
gf-as-winkel gf-es-winkel dlg-aus-ein dlg-winkel-erg
entry-hz exit-hz
first-idx last-idx neu-l
aktuell-frame nach-aus-pt
gf-nummer last-ent
gf-nummer last-ent gf-lz-insert
L-gf-str delta-l-gf laengen-liste first-l l-item
bL90 bL60 bL30 bR90 bR60 bR30
ein-hz-as rad-h-as rad-v-as xu-entry
@@ -787,29 +932,41 @@
(setq entry-hz (cadr (car segmente)))
(setq exit-hz (gf-exit-hz segmente))
;; AUS-Element: 30/90 (vor Seite), dann Seite (vor Winkelberechnung, da die
;; Laengenanpassung von der AS/ES-Masse abhaengt). Masse fuer Variante setzen.
(princ (ssg-text "vf-winkel-aus-header"))
(princ (ssg-text "vf-winkel-90"))
(princ (ssg-text "vf-winkel-30"))
(setq gf-as-winkel (vf-frage-element-winkel "vf-winkel-aus-header"))
(princ (ssg-text "gf-seite-aus-header"))
(princ (ssg-text "gf-seite-links"))
(princ (ssg-text "gf-seite-rechts"))
(setq antwort (getstring (ssg-text "prompt-wahl-1-2")))
(setq as-seite (if (= antwort "2") "rechts" "links"))
(vf-set-as-masse gf-as-winkel as-seite)
;; AUS-/EIN-Element: 30/90 + Seite, in EINEM Dialog (vor Winkelberechnung,
;; da die Laengenanpassung von der AS/ES-Masse abhaengt). Rueckfall auf die
;; alten Konsolenfragen, wenn der Dialog nicht gezeigt werden kann/darf.
(setq dlg-aus-ein (gf-dialog-linienzug-aus-ein nil))
(if (eq dlg-aus-ein 'ABBRUCH)
(progn (princ (ssg-text "vfc-vorgang-abgebrochen")) (exit))
)
(if dlg-aus-ein
(setq gf-as-winkel (nth 0 dlg-aus-ein)
as-seite (nth 1 dlg-aus-ein)
gf-es-winkel (nth 2 dlg-aus-ein)
es-seite (nth 3 dlg-aus-ein))
(progn
(princ (ssg-text "vf-winkel-aus-header"))
(princ (ssg-text "vf-winkel-90"))
(princ (ssg-text "vf-winkel-30"))
(setq gf-as-winkel (vf-frage-element-winkel "vf-winkel-aus-header"))
(princ (ssg-text "gf-seite-aus-header"))
(princ (ssg-text "gf-seite-links"))
(princ (ssg-text "gf-seite-rechts"))
(setq antwort (getstring (ssg-text "prompt-wahl-1-2")))
(setq as-seite (if (= antwort "2") "rechts" "links"))
;; EIN-Element: 30/90 + Seite
(princ (ssg-text "vf-winkel-ein-header"))
(princ (ssg-text "vf-winkel-90"))
(princ (ssg-text "vf-winkel-30"))
(setq gf-es-winkel (vf-frage-element-winkel "vf-winkel-ein-header"))
(princ (ssg-text "gf-seite-ein-header"))
(princ (ssg-text "gf-seite-links"))
(princ (ssg-text "gf-seite-rechts"))
(setq antwort (getstring (ssg-text "prompt-wahl-1-2")))
(setq es-seite (if (= antwort "2") "rechts" "links"))
(princ (ssg-text "vf-winkel-ein-header"))
(princ (ssg-text "vf-winkel-90"))
(princ (ssg-text "vf-winkel-30"))
(setq gf-es-winkel (vf-frage-element-winkel "vf-winkel-ein-header"))
(princ (ssg-text "gf-seite-ein-header"))
(princ (ssg-text "gf-seite-links"))
(princ (ssg-text "gf-seite-rechts"))
(setq antwort (getstring (ssg-text "prompt-wahl-1-2")))
(setq es-seite (if (= antwort "2") "rechts" "links"))
)
)
(vf-set-as-masse gf-as-winkel as-seite)
(vf-set-es-masse gf-es-winkel es-seite)
(setq as-block (strcat "AS_Element_" gf-as-winkel "_" as-seite))
@@ -881,14 +1038,30 @@
(princ (ssg-text "gf-status-berechne-winkel"))
(setq grade (gf-winkel-berechnen segmente deltaH 1))
;; Manuelle Anpassung
(setq antwort
(getstring (ssg-textf "gf-prompt-winkel-verwenden"
(list (rtos grade 2 3) grad-zeichen))))
(if (= (strcase antwort) "N")
;; Manuelle Anpassung per Dialog (ersetzt zugleich die SPAETERE finale
;; Einfuegen-Bestaetigung, siehe gf-dialog-linienzug-winkel) - Rueckfall
;; auf die alten Konsolenfragen, wenn der Dialog nicht gezeigt werden
;; kann/darf; dann bleibt auch die spaetere Einfuegen-Bestaetigung aktiv.
(setq dlg-winkel-erg
(gf-dialog-linienzug-winkel
(list (ssg-textf "gf-status-zus-segmente" (list (length segmente)))
(ssg-textf "gf-status-zus-deltah" (list delta-sym (rtos deltaH 2 2))))
grade gf-as-winkel as-seite gf-es-winkel es-seite))
(if (eq dlg-winkel-erg 'ABBRUCH)
(progn (princ (ssg-text "vfc-vorgang-abgebrochen")) (exit))
)
(if dlg-winkel-erg
(setq grade dlg-winkel-erg)
(progn
(setq grade (getreal (ssg-text "gf-prompt-gefaellewinkel")))
(if (or (null grade) (<= grade 0)) (setq grade 3.0))
(setq antwort
(getstring (ssg-textf "gf-prompt-winkel-verwenden"
(list (rtos grade 2 3) grad-zeichen))))
(if (= (strcase antwort) "N")
(progn
(setq grade (getreal (ssg-text "gf-prompt-gefaellewinkel")))
(if (or (null grade) (<= grade 0)) (setq grade 3.0))
)
)
)
)
(setq grade (float grade))
@@ -953,8 +1126,9 @@
(princ (ssg-textf "gf-status-zus-ein-element" (list es-block)))
(princ "\n=========================================")
;; Bestaetigung
(setq antwort (getstring (ssg-text "gf-prompt-einfuegen")))
;; Bestaetigung - entfaellt, wenn der Dialog oben bereits bestaetigt hat
;; (dlg-winkel-erg ist dann eine Zahl, kein nil/'ABBRUCH).
(setq antwort (if dlg-winkel-erg "1" (getstring (ssg-text "gf-prompt-einfuegen"))))
(if (not (= antwort "2"))
(progn
;; GF-Nummer und Entity-Grenze vor erster Einfuegung sichern.
@@ -1004,15 +1178,20 @@
(- (sin rad-v-es))))
(setq sep-frame (make-frame-from-dir sep-endpunkt xu-exit))
;; EIN-Element: KS_EIN bleibt in X/Y auf dem Ketten-Pfad (sep-frame),
;; seine eigene Achse verlaeuft damit trivial durch diesen Punkt.
;; Die Z-Hoehe wird jedoch an KS_AUS gemessen, damit KS_AUS.Z exakt
;; auf endpunkt-ref.Z landet (garantiert die gewuenschte DeltaH).
;; EIN-Element: reine KS-zu-KS-Verkettung (wie bei Modus 1/2 in
;; gefaellestrecke-einfuegen) statt insert-block-mixed-to-ks mit
;; erzwungener Ziel-Z. sep-frame richtet KS_EIN des ES-Elements exakt
;; am Ketten-Pfad (Position UND Neigung) aus; die Endhoehe ergibt sich
;; danach von selbst aus KS_AUS, es wird nichts nachtraeglich
;; verschoben. Zwei vorherige Versuche waren beide falsch: endpunkt-ref
;; (Mausklick-Z, meist = Starthoehe) UND z-ref="KS_AUS" bei
;; insert-block-mixed-to-ks (zwang den BLOCKAUSGANG statt -eingang auf
;; die Zielhoehe, Rest-Versatz = Blockinnenhoehe KS_EIN<->KS_AUS,
;; ~65mm). endpunkt-ref/der zweite Mausklick dient weiterhin nur zur
;; groben deltaH-Schaetzung fuer den Winkel-Vorschlag im Dialog.
(setq es-aus-frame (insert-block-ks-to-ks es-block sep-frame))
(princ (ssg-textf "gf-status-ein-element-detail"
(list es-block (rtos (caddr endpunkt-ref) 2 1))))
(setq es-aus-frame
(insert-block-mixed-to-ks es-block sep-frame
(caddr endpunkt-ref) "KS_EIN" "KS_AUS"))
(list es-block (rtos (caddr sep-endpunkt) 2 1))))
(princ (ssg-textf "gf-status-z-hoehe-ks-aus" (list (rtos (caddr (car es-aus-frame)) 2 1))))
;; --- GF_N-Block erstellen ---
@@ -1052,27 +1231,37 @@
)
;; delta-l-gf bereits vor der Zusammenfassung berechnet
;; Block mit allen Attributen erstellen. Geruest fuer Einzelmodul/
;; Geruestoption sind in diesem Linienzug-Ablauf (Modus 3, keine DCL-
;; Eingabe) nicht abfragbar - bleiben auf Schema-Default.
(gf-block-erstellen
"gruppe" as-seite gf-nummer
(caddr startpunkt)
(caddr endpunkt-ref)
deltaH
delta-l-gf
L-gf-str
grade
;; n-separator/n-scanner = 0: interne Ketten-Separatoren zaehlen nicht;
;; die echte Anzahl setzt der Export aus platzierten Symbolen.
0
0
bL90 bL60 bL30
bR90 bR60 bR30
startpunkt last-ent nach-aus-pt entry-hz
(caddr (nth first-idx segmente))
es-seite "0" "Schoenenberger Geruest"
gf-as-winkel gf-es-winkel)
;; Block mit allen Attributen erstellen. HOEHE_BIS_mm kommt aus der
;; TATSAECHLICH gebauten Endhoehe (es-aus-frame), nicht aus der
;; geklickten endpunkt-ref.Z - sonst wiche das Attribut von der
;; echten Geometrie ab (derselbe Bug wie bei der ES-Platzierung oben).
;; Geruest fuer Einzelmodul/Geruestoption sind in diesem Linienzug-
;; Ablauf (Modus 3, keine DCL-Eingabe) nicht abfragbar - bleiben auf
;; Schema-Default.
(setq gf-lz-insert
(gf-block-erstellen
"gruppe" as-seite gf-nummer
(caddr startpunkt)
(caddr (car es-aus-frame))
deltaH
delta-l-gf
L-gf-str
grade
;; n-separator/n-scanner = 0: interne Ketten-Separatoren zaehlen nicht;
;; die echte Anzahl setzt der Export aus platzierten Symbolen.
0
0
bL90 bL60 bL30
bR90 bR60 bR30
startpunkt last-ent nach-aus-pt entry-hz
(caddr (nth first-idx segmente))
es-seite "0" "Schoenenberger Geruest"
gf-as-winkel gf-es-winkel))
;; Segmentliste + Startpunkt fuer den Doppelklick-Nachbau sichern (siehe
;; c:GEFAELLESTRECKE_EDIT) - ohne diese XDATA war eine per Linienzug
;; gebaute Streckengruppe bisher nicht editierbar.
(gf-lz-xdata-schreiben gf-lz-insert segmente startpunkt)
(princ "\n\n=========================================")
(princ (ssg-text "gf-status-fertig"))
@@ -1082,6 +1271,217 @@
)
)
;; Doppelklick-Nachbau fuer eine per GEFAELLESTRECKE_LINIENZUG (Modus 3)
;; gebaute Streckengruppe - Gegenstueck zu gf-rebuild (Modus 1/2), aufgerufen
;; aus c:GEFAELLESTRECKE_EDIT. Anders als beim Neu-Bauen (gf-linienzug-modus)
;; sind die Segmentlaengen hier bereits FINAL (AS-/ES-dx und Separator-
;; Abzuege sind laengst eingerechnet, siehe gf-lz-xdata-schreiben) - die
;; Segmentlisten-Anpassungsschleife aus gf-linienzug-modus entfaellt darum
;; komplett, nur AS-/ES-Winkel+Seite und der Gefaellewinkel bleiben ueber
;; dieselben zwei Dialoge editierbar (gf-dialog-linienzug-aus-ein/-winkel,
;; diesmal mit Prefill aus den Block-Attributen). Baut am gleichen
;; startpunkt neu, loescht den alten Block NACH erfolgreichem Neuaufbau.
;; segmente/startpunkt: aus gf-lz-xdata-lesen. alt-ent: der zu ersetzende
;; GF_n-Block. prefill: Alist wie gf-dialog-linienzug-aus-ein (AS/ES aus den
;; aktuellen Attributen des Blocks).
(defun gf-linienzug-rebuild (segmente startpunkt alt-ent prefill /
deltaH entry-hz exit-hz as-seite es-seite
gf-as-winkel gf-es-winkel as-block es-block
dlg-aus-ein dlg-winkel-erg grade
first-idx j seg end-z endpunkt-ref delta-l-gf
aktuell-frame nach-aus-pt ein-hz-as rad-h-as xu-entry
sep-endpunkt rad-h-es rad-v-es xu-exit sep-frame es-aus-frame
gf-nummer last-ent gf-lz-insert
L-gf-str laengen-liste first-l l-item
bL90 bL60 bL30 bR90 bR60 bR30
rad-v-korr ein-hz-as-k rad-h-as-k xu-as-meas
rad-h-es-k xu-es-meas dz-as-ist dz-es-ist
dH-korr grade-prev iter)
(if (or (null segmente) (< (length segmente) 1))
(progn (alert (ssg-text "gf-alert-keine-kette")) (exit))
)
(setq entry-hz (cadr (car segmente)))
(setq exit-hz (gf-exit-hz segmente))
;; AUS-/EIN-Element, vorbelegt aus den aktuellen Attributen
(setq dlg-aus-ein (gf-dialog-linienzug-aus-ein prefill))
(if (eq dlg-aus-ein 'ABBRUCH)
(progn (princ (ssg-text "vfc-vorgang-abgebrochen")) (exit))
)
(if (null dlg-aus-ein)
(progn (alert (ssg-text "gf-alert-lz-edit-kein-dialog")) (exit))
)
(setq gf-as-winkel (nth 0 dlg-aus-ein)
as-seite (nth 1 dlg-aus-ein)
gf-es-winkel (nth 2 dlg-aus-ein)
es-seite (nth 3 dlg-aus-ein))
(vf-set-as-masse gf-as-winkel as-seite)
(vf-set-es-masse gf-es-winkel es-seite)
(setq as-block (strcat "AS_Element_" gf-as-winkel "_" as-seite))
(setq es-block (strcat "ES_Element_" gf-es-winkel "_" es-seite))
;; Index des ersten "Linie"-Segments (fuer die Label-Laenge) - KEINE
;; Laengenanpassung, die Segmentlaengen sind bereits final.
(setq first-idx -1 j 0)
(while (and (< j (length segmente)) (< first-idx 0))
(if (= (car (nth j segmente)) "Linie") (setq first-idx j))
(setq j (1+ j))
)
(if (< first-idx 0) (setq first-idx 0))
;; Ziel-Endhoehe aus dem Z-Attribut HOEHE_BIS_mm des alten Blocks (X/Y des
;; wirklichen Endpunkts wird erst NACH dem Bau aus der Geometrie selbst
;; bestimmt, siehe unten - sie ist nicht separat in der XDATA gespeichert
;; und nur fuer die Zusammenfassung/das Label relevant, nicht fuer den Bau
;; selbst, der komplett der Segmentliste folgt).
(setq end-z (atof (cond ((cdr (assoc "HOEHE_BIS_mm" (ssg-attrib-read alt-ent)))) ("0"))))
(setq deltaH (abs (- (caddr startpunkt) end-z)))
(princ (ssg-text "gf-status-berechne-winkel"))
(setq grade (gf-winkel-berechnen segmente deltaH 1))
(setq dlg-winkel-erg
(gf-dialog-linienzug-winkel
(list (ssg-textf "gf-status-zus-segmente" (list (length segmente)))
(ssg-textf "gf-status-zus-deltah" (list delta-sym (rtos deltaH 2 2))))
grade gf-as-winkel as-seite gf-es-winkel es-seite))
(if (eq dlg-winkel-erg 'ABBRUCH)
(progn (princ (ssg-text "vfc-vorgang-abgebrochen")) (exit))
)
(if (null dlg-winkel-erg)
(progn (alert (ssg-text "gf-alert-lz-edit-kein-dialog")) (exit))
)
(setq grade (float dlg-winkel-erg))
;; Winkelkorrektur (identisch zu gf-linienzug-modus)
(if (and *gf-L-ohne-as-es* (> *gf-L-ohne-as-es* 0.1))
(progn
(princ (ssg-text "gf-status-messe-absenkung"))
(setq grade-prev -999.0 iter 0)
(while (and (< iter 4) (> (abs (- grade grade-prev)) 0.001))
(setq grade-prev grade)
(setq rad-v-korr (* grade (/ pi 180.0)))
(setq ein-hz-as-k (- entry-hz
(vf-element-plan-turn (strcat "AS_Element_" gf-as-winkel "_" as-seite))))
(setq rad-h-as-k (* (float ein-hz-as-k) (/ pi 180.0)))
(setq xu-as-meas (list (cos rad-h-as-k) (sin rad-h-as-k) 0.0))
(setq rad-h-es-k (* (float exit-hz) (/ pi 180.0)))
(setq xu-es-meas (list (* (cos rad-h-es-k)(cos rad-v-korr))
(* (sin rad-h-es-k)(cos rad-v-korr))
(- (sin rad-v-korr))))
(setq dz-as-ist (gf-messe-dz-block as-block xu-as-meas))
(setq dz-es-ist (gf-messe-dz-block es-block xu-es-meas))
(setq dH-korr (- (float deltaH) dz-as-ist dz-es-ist (float *gf-sum-dz-bogen*)))
(if (and (> dH-korr 0.0) (< (/ dH-korr *gf-L-ohne-as-es*) 1.0))
(setq grade (* (asin (/ dH-korr *gf-L-ohne-as-es*)) (/ 180.0 pi)))
(progn
(princ (ssg-text "gf-warnung-korrektur-bereich"))
(setq grade-prev grade)
)
)
(setq iter (1+ iter))
)
(princ (ssg-textf "gf-status-korrigierter-winkel"
(list (rtos grade 2 3) grad-zeichen (itoa iter))))
)
)
;; Alten Block ERST NACH erfolgreichem Neuaufbau loeschen (siehe unten) -
;; die GF-Nummer/last-ent-Grenze muss aber VOR dem Neu-Einfuegen stehen.
(setq gf-nummer (gf-next-number))
(setq last-ent (ssg-lastent-ohne-attribute))
(setq ein-hz-as (- entry-hz
(vf-element-plan-turn (strcat "AS_Element_" gf-as-winkel "_" as-seite))))
(setq rad-h-as (* (float ein-hz-as) (/ pi 180.0)))
(setq xu-entry (list (cos rad-h-as) (sin rad-h-as) 0.0))
(setq aktuell-frame
(insert-block-mixed-to-ks as-block (make-frame-from-dir startpunkt xu-entry)
(caddr startpunkt) nil "KS_EIN"))
(setq nach-aus-pt (car aktuell-frame))
(setq aktuell-frame (gf-linienzug-einfuegen segmente grade aktuell-frame))
(setq sep-endpunkt
(gf-insert-hz-with-ks "Staustrecke_Separator_SP_300_mm"
(car aktuell-frame) exit-hz grade 300 0))
(setq rad-h-es (* (float exit-hz) (/ pi 180.0)))
(setq rad-v-es (* (float grade) (/ pi 180.0)))
(setq xu-exit (list (* (cos rad-h-es)(cos rad-v-es))
(* (sin rad-h-es)(cos rad-v-es))
(- (sin rad-v-es))))
(setq sep-frame (make-frame-from-dir sep-endpunkt xu-exit))
;; Reine KS-zu-KS-Verkettung wie in gf-linienzug-modus (siehe dortiger
;; Kommentar) - end-z (gespeicherte Soll-Endhoehe) wird nur zur
;; deltaH-Schaetzung fuer die Winkelberechnung oben gebraucht, nicht hier.
(setq es-aus-frame (insert-block-ks-to-ks es-block sep-frame))
;; Echter Endpunkt (fuer DELTA_L-Attribut/Label) erst jetzt aus der
;; gebauten Geometrie bekannt - KS_AUS des ES-Elements.
(setq endpunkt-ref (car es-aus-frame))
(setq delta-l-gf
(sqrt (+ (expt (- (car endpunkt-ref) (car startpunkt)) 2)
(expt (- (cadr endpunkt-ref) (cadr startpunkt)) 2))))
(setq laengen-liste '() first-l t)
(foreach seg segmente
(if (= (car seg) "Linie")
(setq laengen-liste
(append laengen-liste (list (rtos (/ (caddr seg) 1000.0) 2 3))))
)
)
(setq L-gf-str "")
(foreach l-item laengen-liste
(if first-l
(progn (setq L-gf-str l-item) (setq first-l nil))
(setq L-gf-str (strcat L-gf-str "," l-item))
)
)
(setq bL90 0 bL60 0 bL30 0 bR90 0 bR60 0 bR30 0)
(foreach seg segmente
(if (= (car seg) "Bogen")
(cond
((and (= (nth 4 seg) "links") (= (nth 3 seg) 90)) (setq bL90 (1+ bL90)))
((and (= (nth 4 seg) "links") (= (nth 3 seg) 60)) (setq bL60 (1+ bL60)))
((and (= (nth 4 seg) "links") (= (nth 3 seg) 30)) (setq bL30 (1+ bL30)))
((and (= (nth 4 seg) "rechts") (= (nth 3 seg) 90)) (setq bR90 (1+ bR90)))
((and (= (nth 4 seg) "rechts") (= (nth 3 seg) 60)) (setq bR60 (1+ bR60)))
((and (= (nth 4 seg) "rechts") (= (nth 3 seg) 30)) (setq bR30 (1+ bR30)))
)
)
)
(setq gf-lz-insert
(gf-block-erstellen
"gruppe" as-seite gf-nummer
(caddr startpunkt)
(caddr endpunkt-ref)
deltaH
delta-l-gf
L-gf-str
grade
0 0
bL90 bL60 bL30
bR90 bR60 bR30
startpunkt last-ent nach-aus-pt entry-hz
(caddr (nth first-idx segmente))
es-seite "0" "Schoenenberger Geruest"
gf-as-winkel gf-es-winkel))
(gf-lz-xdata-schreiben gf-lz-insert segmente startpunkt)
;; Alten Block erst jetzt entfernen - der Neuaufbau ist bereits vollstaendig
;; abgeschlossen, ein Fehler davor haette ihn stehen gelassen.
(if (and alt-ent (entget alt-ent)) (entdel alt-ent))
(princ "\n\n=========================================")
(princ (ssg-text "gf-status-fertig"))
(princ "\n=========================================")
gf-lz-insert
)
;; ============================================================
;; TEIL 4.5: GF-BLOCK-SYSTEM (Nummerierung, Label, Attribute)
;; ============================================================
@@ -1704,6 +2104,124 @@
)
)
;; ============================================================
;; XDATA fuer den Linienzug-Nachbau (Modus 3, App "SSG_GF_LZ").
;; Die Segmentliste (gf-analysiere-kette) hat variable Laenge - anders als
;; gf-xdata-schreiben (feste Skalare fuer Modus 1/2) braucht sie ein eigenes
;; String-Format + Chunking (255-Byte-Limit je 1000-Gruppe), analog zur
;; Sepliste-XDATA in ssg_ks_insert.lsp (ssg-sepliste-chunk-string/-split-feld/
;; -explode-chars werden von dort wiederverwendet statt dupliziert).
;; AS-/ES-Winkel+Seite stehen bereits als Attribute (WINKEL_AS/SEITE_AS/
;; WINKEL_ES/SEITE_ES) auf dem Block - nur die Segmentliste UND der gebaute
;; Startpunkt (fuer den Neuaufbau-Ursprung) fehlen dort und muessen hier
;; gesichert werden.
;; ============================================================
(if (null *gf-lz-xdata-app*) (setq *gf-lz-xdata-app* "SSG_GF_LZ"))
;; Ein Segment "(Typ hz laenge winkel seite)" -> "Typ:hz:laenge:winkel:seite".
(defun gf-segment->string (seg)
(strcat (nth 0 seg) ":" (rtos (float (nth 1 seg)) 2 4) ":"
(rtos (float (nth 2 seg)) 2 4) ":" (itoa (fix (nth 3 seg))) ":"
(nth 4 seg))
)
;; Gegenstueck: "Typ:hz:laenge:winkel:seite" -> (Typ hz laenge winkel seite).
(defun gf-string->segment (s / feld)
(setq feld (ssg-sepliste-split-feld s ":"))
(if (= (length feld) 5)
(list (nth 0 feld) (atof (nth 1 feld)) (atof (nth 2 feld))
(atoi (nth 3 feld)) (nth 4 feld))
nil
)
)
;; Segmentliste -> ein einzelner kommagetrennter String.
(defun gf-segmente->string (segmente / out first)
(setq out "" first t)
(foreach seg segmente
(if first
(progn (setq out (gf-segment->string seg)) (setq first nil))
(setq out (strcat out "," (gf-segment->string seg)))
)
)
out
)
;; Gegenstueck zu gf-segmente->string - nutzt denselben Zeichen-Explode wie
;; die Sepliste (ssg_ks_insert.lsp), da Segment-Trenner "," mit dem inneren
;; Feld-Trenner ":" nicht kollidiert.
(defun gf-string->segmente (s / out teile eintraege seg)
(setq out '())
(if (> (strlen s) 0)
(progn
(setq eintraege '() teile "")
(foreach c (ssg-sepliste-explode-chars s)
(if (= c ",")
(progn (setq eintraege (cons teile eintraege)) (setq teile ""))
(setq teile (strcat teile c))
)
)
(setq eintraege (reverse (cons teile eintraege)))
(foreach eintrag eintraege
(if (setq seg (gf-string->segment eintrag)) (setq out (cons seg out)))
)
)
)
(reverse out)
)
;; Segmentliste + Nachbau-Startpunkt als XDATA schreiben. Marker "linienzug"
;; als erster Wert (Platz fuer kuenftige Varianten, analog SSG_VF_EDIT).
(defun gf-lz-xdata-schreiben (ent segmente startpunkt / chunks appentry)
(if (and ent segmente)
(progn
(regapp *gf-lz-xdata-app*)
(setq chunks
(ssg-sepliste-chunk-string
(strcat (rtos (car startpunkt) 2 4) ";" (rtos (cadr startpunkt) 2 4) ";"
(rtos (caddr startpunkt) 2 4) ";" (gf-segmente->string segmente))
250))
(setq appentry
(cons *gf-lz-xdata-app*
(cons (cons 1000 "linienzug")
(mapcar (function (lambda (c) (cons 1000 c))) chunks))))
(entmod (append (entget ent) (list (list -3 appentry))))
)
)
ent
)
;; XDATA lesen -> (startpunkt segmente) oder nil (kein/unbekanntes Linienzug-
;; XDATA am Entity).
(defun gf-lz-xdata-lesen (ent / xd app-data werte roh teile sp-x sp-y sp-z rest)
(setq xd (entget ent (list *gf-lz-xdata-app*)))
(setq app-data (cdr (assoc -3 xd)))
(if app-data
(progn
(setq werte (mapcar 'cdr (cdr (car app-data))))
(if (and werte (= (car werte) "linienzug"))
(progn
(setq roh (apply 'strcat (cdr werte)))
(setq teile (ssg-sepliste-split-feld roh ";"))
(if (>= (length teile) 4)
(progn
(setq sp-x (atof (nth 0 teile)) sp-y (atof (nth 1 teile))
sp-z (atof (nth 2 teile)))
;; Rest nach dem 3. ";" wieder zusammenfuegen (Segmentliste
;; selbst enthaelt kein ";").
(setq rest (nth 3 teile))
(list (list sp-x sp-y sp-z) (gf-string->segmente rest))
)
nil
)
)
nil
)
)
nil
)
)
;; ============================================================
;; TEIL 6: HAUPTBEFEHL
;; ============================================================
@@ -1994,7 +2512,8 @@
(defun c:GEFAELLESTRECKE_EDIT ( / ss ent ed bname startpunkt attribs xd
hz winkel as-winkel es-winkel z-start deltaL
as-seite hoehe-bis prefill dlg-werte)
as-seite hoehe-bis prefill dlg-werte
lz-xd lz-segmente lz-startpunkt lz-prefill)
;; Implied Selection VOR ssg-start pruefen (ssg-start hebt Selektion auf)
(setq ss (ssget "I"))
(if (and ss (= (sslength ss) 1)
@@ -2022,9 +2541,37 @@
(setq startpunkt (cdr (assoc 10 ed)))
(setq attribs (ssg-attrib-read ent))
;; Streckengruppe (mit Bogen) aus GEFAELLESTRECKE_LINIENZUG: eigener
;; Rebuild-Pfad ueber die Segmentliste in SSG_GF_LZ-XDATA (siehe
;; gf-linienzug-rebuild), NICHT ueber den einfachen gefaellestrecke-Dialog
;; unten - der kennt keine Segmentliste/Boegen. Streckengruppe OHNE diese
;; XDATA (Altbestand/VF-Kombi) bleibt wie bisher nicht editierbar.
(if (= (cond ((cdr (assoc "TYP" attribs))) ("")) "Streckengruppe")
(progn
(setq lz-xd (gf-lz-xdata-lesen ent))
(cond
(lz-xd
(setq lz-startpunkt (nth 0 lz-xd))
(setq lz-segmente (nth 1 lz-xd))
(setq lz-prefill
(list (cons "as-winkel" (cond ((cdr (assoc "WINKEL_AS" attribs))) ("90")))
(cons "as-seite" (cond ((cdr (assoc "SEITE_AS" attribs))) ("links")))
(cons "es-winkel" (cond ((cdr (assoc "WINKEL_ES" attribs))) ("90")))
(cons "es-seite" (cond ((cdr (assoc "SEITE_ES" attribs))) ("links")))))
(gf-linienzug-rebuild lz-segmente lz-startpunkt ent lz-prefill)
)
(t
(alert (ssg-textf "gf-edit-nur-einfach"
(list (cond ((cdr (assoc "TYP" attribs))) ("?")))))
)
)
(ssg-end)
(exit)
)
)
;; Nur einfache Gefaellestrecken (TYP "Gefaellestrecke") lassen sich ueber den
;; Dialog verlustfrei nachbauen. Streckengruppen (mit Bogen / Linienzug / VF)
;; wuerden beim Neuaufbau ihre Bogengeometrie verlieren -> abbrechen.
;; Dialog verlustfrei nachbauen.
(if (/= (cond ((cdr (assoc "TYP" attribs))) ("")) "Gefaellestrecke")
(progn
(alert (ssg-textf "gf-edit-nur-einfach"
+13 -9
View File
@@ -691,21 +691,25 @@
;; ============================================================
;; Kreisel per Script einfuegen (Insert)
;; pt : Einfuegepunkt (x y z)
;; abstand : Abstand in mm
;; rotation : Drehwinkel in Grad
;; typ : Kreiselart ("STANDARD", "PIN", ...)
;; hoehe : Hoehe in mm (oder nil fuer Z aus pt)
;; pt : Einfuegepunkt (x y z)
;; abstand : Abstand in mm
;; rotation : Drehwinkel in Grad
;; typ : Kreiselart ("STANDARD", "PIN", ...)
;; hoehe : Hoehe in mm (oder nil fuer Z aus pt)
;; drehrichtung : "GUZ"/"UZS" (optional, nil -> Default aus *kreisel-attrib-defs*)
;; Rueckgabe: Entity-Name des erzeugten Blocks oder nil
(defun kreisel-insert-script (pt abstand rotation typ hoehe / z blockEnt)
(defun kreisel-insert-script (pt abstand rotation typ hoehe drehrichtung
/ z blockEnt attribs)
(ssg-start (ssg-text "kreisel-start-script-insert") '(("OSMODE") ("CECOLOR")))
(if (null typ) (setq typ "STANDARD"))
(setq z (if hoehe hoehe
(if (and pt (caddr pt)) (caddr pt) *kreisel-default-hoehe*)))
(setq attribs (list (cons "KREISELART" typ)
(cons "HOEHE" (rtos z 2 0))))
(if drehrichtung
(setq attribs (cons (cons "DREHRICHTUNG" drehrichtung) attribs)))
(setq blockEnt
(draw-module (list (car pt) (cadr pt) z) abstand rotation
(list (cons "KREISELART" typ)
(cons "HOEHE" (rtos z 2 0)))))
(draw-module (list (car pt) (cadr pt) z) abstand rotation attribs))
(ssg-end)
blockEnt
)
+265 -54
View File
@@ -15,14 +15,17 @@ _MENULOAD → menu/SSG_LIB.mnu auswaehlen
```
BricsCAD laedt daraufhin automatisch `SSG_LIB.mnl`, welches alle Module
per `ssg-ensure` initialisiert (Kern: ssg_core/lang/dbg/dialog/layer, dann
alle Feature-Module). Details: siehe `../CLAUDE.md` Abschnitt "Lademechanismus".
per `ssg-ensure` initialisiert. Kern-Reihenfolge (muss vor den Feature-Modulen
stehen): `ssg_core`, `ssg_lang`, `ssg_dbg`, `ssg_dialog`, `ssg_layer`, `ssg_id`,
`ssg_ks_insert` (Letzteres wird von Gefaellestrecke UND VarioFoerderer genutzt).
Details: siehe `../CLAUDE.md` Abschnitt "Lademechanismus".
**Manuell laden (Notfall / Entwicklung):**
**Manuell laden (Notfall / Entwicklung, z.B. fuer .scr-Testskripte):**
```lisp
(load (strcat (getenv "DXFMAKRO") "/Lisp/ssg_load.lsp"))
```
`ssg_load.lsp` laedt alle Module in der richtigen Reihenfolge ohne Menueabhaengigkeit.
`ssg_load.lsp` ist der Headless-Loader (genutzt von `tests/test_unit.scr` u.ae.)
und laedt dieselbe Kern-Reihenfolge wie `SSG_LIB.mnl`, ohne Menueabhaengigkeit.
---
@@ -35,16 +38,22 @@ am Label-Anfang, bei Submenue-Schliessern hinter dem `<-` (`[<-~Label]`).
| Menuebereich | Eintraege | Definiert in |
| --- | --- | --- |
| ILS ▸ Foerderer | Durch TEF angetriebene Strecke; Kurven 90/60/30 links/rechts angetrieben Aussen + Innen (12) | `SSG_LIB_Commands.lsp` |
| ILS ▸ Gefaellestrecke | Kurven 90/60/30 links/rechts Gefaellestrecke (6) | `SSG_LIB_Commands.lsp` |
| Omniflo ▸ TEF Elemente | UmlenkR/L, AntriebL/R, TEF Gerade, KettenFoerderer (6) | `OmniModulInsert.lsp` |
| Omniflo ▸ Anbaugruppen | `OMNI_KettenFoerderer` | `OmniModulInsert.lsp` |
| Omniflo ▸ Verbinder | alle `OMNI_TV_*` (18) | `OmniModulInsert.lsp` |
| Omniflo ▸ Boegen fuer Weichen | alle `OMNI_APBW_*` (14) | `OmniModulInsert.lsp` |
| ILS ▸ Zusatzmodule/Kurven | `ILS_ETF_Etagenfoerderer`, `ILS_K{90,60,30}{L,R}{A,I}` (12), `ILS_Gefaellestrecke` | `SSG_LIB_Commands.lsp` |
| Geruest | `GERUEST` (Gattertraeger-Platzhalter, derselbe Befehl wie Saeulen/Rohrabhaenger/Wandbefestigung) | `GeruestInsert.lsp` |
Aktiv (implementiert) sind u.a.: Kreisel, Eckrad, VarioFoerderer, EtageVarioFoerderer,
Gefaellestrecke, BTMT Be-/Entladung, Scanner/Separator, Omniflo Boegen (APB),
Aluprofil-Geraden (AP), alle Weichen (W90/W45/WP/WK/WKomb), Export (Sivas/CSV)
und die Tests.
`OMNI_TEF_*` (UmlenkR/L, AntriebL/R, TEF Gerade) sind entgegen frueherem Stand
**implementiert** (echtes `omni:insert-dxf`), nur `OMNI_KettenFoerderer` ist
weiterhin Dummy.
Aktiv (implementiert) sind u.a.: Kreisel, Eckrad, VarioFoerderer (Standard/Etage/
Linienzug), Gefaellestrecke, Geruest (Saeulen/Rohrabhaenger/Wandbefestigung/
Rohr-Geruest-Traeger), TRO-Marker, Connections, BTMT Be-/Entladung, Scanner/
Separator, Omniflo Boegen (APB)/TEF-Elemente/Aluprofil-Geraden (AP)/alle Weichen
(W90/W45/WP/WK/WKomb)/Ladeschleifen, Export (Sivas/CSV), Werkzeuge (Block-/
Text-Tools, Planquadrate) und die Tests.
---
@@ -181,7 +190,7 @@ Interne Parser-Funktionen (nicht direkt aufrufen):
### `ssg_lang.lsp` – Sprachumschaltung (Deutsch/Englisch)
Zentrale Textverwaltung fuer benutzersichtbare Meldungen. Kern-Modul, wird direkt nach `ssg_core` geladen. Wird schrittweise auf weitere Module ausgerollt (siehe `doc/translate.md`).
Zentrale Textverwaltung fuer benutzersichtbare Meldungen. Kern-Modul, wird direkt nach `ssg_core` geladen. Wird schrittweise auf weitere Module ausgerollt (siehe `doc/plan/translate.md`).
| Funktion | Beschreibung |
| --- | --- |
@@ -323,50 +332,155 @@ Benutzerfreundliche BricsCAD-Befehle für Layer-Operationen. Alle Befehle sicher
---
### `ssg_load.lsp` – Laderoutine
### `ssg_input.lsp` – Generische Eingabe-Wrapper
Lädt alle Module in der richtigen Reihenfolge. Ermittelt den Pfad automatisch über `findfile`. Ruft direkt nach `ssg_core.lsp` die Funktion `ssg-load-config` auf, damit die JSON-Konfiguration für alle nachfolgenden Module verfügbar ist.
---
### `VarioFoerderer.lsp` – Vario-Förderer
Kompatibilitäts-Wrapper, der `vf_core.lsp` lädt (Plugin-Dispatcher-Architektur; lädt seinerseits `vf_standard.lsp`, `vf_etage.lsp`, `vf_linienzug.lsp`). Parametrischer Generator für ILS Vario-Förderanlagen. Liest Block-Geometrie aus einer DWG-Bibliothek (`DXFM_BLOCKS`). Alle Konstanten (Abstände, Winkel, Skalierung) werden via `ssg-cfg-or` aus `component_defaults.json` (Sektion `vario`) gelesen.
**Befehl:** `c:FOERDERANLAGE` / `c:VarioFoerderer` – wählt zuerst den Anlagen-Typ (Standard/Etage/Linienzug):
- **Typ „standard“ + Werteingabe:** läuft über den DCL-Dialog
[`dcl/variofoerderer.dcl`](../dcl/variofoerderer.dcl) (zwei Dialoge, `vfs-standard-dialog-ablauf`
in `vf_standard.lsp`): Dialog 1 (`vfs-dialog-eingabe-basis`) erfasst deltaL, deltaH,
Förderrichtung (Auf/Ab), Einfügehöhe, Fahrtrichtung und Seite; anschließend berechnet
`berechne-standard` die gültigen Winkel-Varianten, und Dialog 2
(`vfs-dialog-winkel-verteilung`) lässt Winkel und L_GF-Verteilung (vorne/hinten) wählen.
Startpunkt (X/Y) wird wie bei der Gefällestrecke vorher in der Zeichnung gepickt.
- **Typ „standard“ + 3D-Linie**, sowie **Typ „etage“** und **„linienzug“** bleiben
vollständig interaktiv (Kommandozeile), unverändert gegenüber dem bisherigen Ablauf.
**Bearbeiten (`c:VARIOFOERDERER_EDIT`):** Doppelklick auf einen `VF_n`-Block – bzw.
Rechtsklick-Kontextmenü/`SSG_BLOCKEDIT` – öffnet dieselben Dialoge, vorbelegt mit den
aktuellen Parametern, und baut die Strecke bei OK am selben Startpunkt neu auf (neue
`VF_n`-Nummer). Da `VF_n`-Blöcke auch von Etage- und Linienzug-Anlagen erzeugt werden
(deren komplexere Geometrie ein einfacher Neuaufbau zerstören würde), markiert
`vfs-xdata-schreiben` nur per Standard-Dialog erstellte Blöcke mit XDATA (App
`SSG_VF_EDIT`, Fahrtrichtung `hz`); Blöcke ohne diese Markierung weist
`c:VARIOFOERDERER_EDIT` mit einer Meldung ab, statt sie zu verändern. Winkel und L_GF1
werden aus den Sivas-Attributen (`VF_WINKEL`, `L_GF_m`) vorbelegt (Verteilung stets als
„Eigene Werte“ mit dem exakten aktuellen L_GF1).
**Wichtige interne Funktionen** (werden auch von `Gefaellestrecke.lsp` genutzt):
Abfragen mit Vorgabewert (`<..>` im Prompt, Enter = Vorgabe). Steht neben den VF-spezifischen `vfl-in-*` (`vf_linienzug.lsp`); diese bleiben unveraendert. Kein Journal, aber ein optionaler Hook. ESC bricht wie ueblich ueber `*error*` ab.
| Funktion | Beschreibung |
| --- | --- |
| `init-bibliothek` | Block-Bibliothek aus DWG laden und Geometriedaten extrahieren |
| `ensure-block-loaded name` | Block aus Bibliothek in aktives Dokument laden (einmalig) |
| `insert-block-by-ks name ks-nr pt` | Block anhand Koordinatensystem-Punkt einfügen |
| `insert-inclined-scaled-block name laenge winkel pt` | Geneigten, skalierten Block einfügen |
| `insert-rotated-block-with-ks name rot pt` | Rotierten Block mit KS-Offset einfügen |
| `get-line-start-end-points ename` | Start- und Endpunkt einer LINE-Entity ermitteln |
| `punkt-differenz p1 p2` | Differenzvektor zweier Punkte |
| `ssg-in-real text default` | Reelle Zahl (`getreal`), Vorgabe ohne ueberfluessige Nullen angezeigt |
| `ssg-in-int text default` | Ganzzahl (`getint`) |
| `ssg-in-string text default` | String mit Leerzeichen; Enter ohne Eingabe liefert die Vorgabe (ohne Vorgabe `nil`) |
| `ssg-in-point text default base` | Punkt, `base` = Gummiband-Basispunkt oder `nil` |
| `ssg-in-dist text default base` | Abstand (`getdist`) |
| `ssg-in-keyword text schluessel default` | Schluesselwort im `initget`-Format, z.B. `"Alle Auswahl"` |
| `ssg-in-yesno text default` | Ja/Nein, **T = Ja**; `default` T = Enter bedeutet Ja. Woerter aus `ssg-text "in-yesno-keys"` |
| `ssg-in-default wert default`, `ssg-in-fmt-real`, `ssg-in-fmt-pt`, `ssg-in-prompt`, `ssg-in-first-word`, `ssg-in-second-word` | Reine Hilfsfunktionen (in `tests/test_unit.lsp` getestet) |
Hook (z.B. fuer ein Eingabe-Journal): `(setq *ssg-in-hook* 'meine-funktion)` mit `(defun meine-funktion (art prompt wert) ...)`; `art` ist `"REAL"`, `"INT"`, `"STRING"`, `"POINT"`, `"DIST"`, `"KEYWORD"` oder `"YESNO"`. Ein Hook, der einen Fehler wirft, wird abgeschaltet.
---
### `ssg_id.lsp` – Eindeutige Block-IDs
Jedes exportierbare Element bekommt ein Attribut `ID` mit einer eindeutigen,
vierstelligen Nummer. Kern-Modul (nach `ssg_layer`, vor `ssg_ks_insert`).
| Befehl / Funktion | Beschreibung |
| --- | --- |
| `c:IDGENERATE` | Weist dem zuletzt eingefuegten Block eine neue ID zu |
| `c:IDSCHECK` | Prueft alle Bloecke auf doppelte IDs und korrigiert sie |
| `ssg-id-format n` | Zahl als 4-stelligen String formatieren (`1` → `"0001"`) |
| `ssg-id-max` | Hoechste bereits vergebene ID in der Zeichnung |
| `ssg-id-generate ent` | Neue ID erzeugen und auf den Block setzen |
| `ssg-id-check-all` | Zeichnungsweit auf Doubletten pruefen und korrigieren |
| `ssg-id-collect-blocks` | Alle ID-faehigen INSERT-Entities sammeln (gleiche Muster wie `csv:collect-export-blocks`, inkl. Separator/Scanner/BTMT) |
---
### `ssg_ks_insert.lsp` – KS-Extraktion und Block-Einfuegeprimitiven
Gemeinsame Basis fuer VarioFoerderer (`vf_core.lsp`) UND Gefaellestrecke –
frueher in beiden Modulen dupliziert, jetzt einzige Quelle. Muss laut MNL **vor**
Gefaellestrecke/`vf_core` geladen sein; Kern-Modul.
| Funktion | Beschreibung |
| --- | --- |
| `vec-length v` | Laenge eines 3er-Vektors |
| `ks-line-axis laenge` | Achsenkennung (X/Y/Z) aus Linienlaenge der KS-Hilfslinie |
| `ks-normalize-name nm` | Historische KS-Blocknamen (`KSYS_EIN`/`-AUS`) auf `KS_EIN`/`KS_AUS` normalisieren |
| `ks-relativize` / `ks-absolutize` | KS-Punkte zwischen relativem und Welt-Koordinatensystem umrechnen |
| `ensure-block-loaded name` | Block aus der Bibliothek einmalig ins aktive Dokument laden |
| `extract-ks-from-block[-raw] name` | KS_EIN/KS_AUS-Punkte eines Blocks ermitteln (Cache `*ks-cache*`) |
| `insert-block-by-ks name ks-nr pt` | Block anhand KS-Punkt einfuegen (nur Rz-Rotation) |
| `insert-inclined-scaled-block` / `insert-rotated-block-with-ks` | Geneigten/rotierten Block mit KS-Offset einfuegen (Rz*Ry) |
---
### `ssg_blocktools.lsp` – Block-Werkzeuge
Ursprung: ACADSST `TOOLS.LSP` (`BLKANZAHL`, `BLKENTF`), `DINGEN2` (`g-bli`), `ssg.lsp` (`suchen-aendern`). Arbeitet im **aktuellen Layout-Reiter**. Blocknamen werden ueber den wirksamen Namen verglichen (dynamische Bloecke); Muster mit `wcmatch` (`*`, `?`, `#`, ohne Gross-/Kleinschreibung).
| Befehl | Beschreibung |
| --- | --- |
| `SSG_BLOCK_COUNT` | Block anklicken, `Name` fuer ein Muster, oder Enter fuer eine Statistik aller Bloecke |
| `SSG_BLOCK_DELETE` | Alle Einfuegungen eines Blocks/Musters loeschen; Rueckfrage (Vorgabe Nein), Einfuegungen auf gesperrten Layern bleiben stehen; eine Undo-Gruppe |
| `SSG_ATTR_ERSETZEN` | Attributwerte suchen/ersetzen: Bereich (Alle mit Blockname-Muster / Auswahl), Tag-Muster, Suchtext, Ersatz, Modus Teil (Teilstring) oder Gesamt (ganzer Wert). Zeigt vorab die Anzahl und fragt nach |
| Funktion | Beschreibung |
| --- | --- |
| `ssg-bt-inserts muster` | Entity-Liste aller Einfuegungen im Layout (optional nach Muster) |
| `ssg-bt-statistik muster` | `((NAME . ANZAHL) ...)` alphabetisch |
| `ssg-bt-attr-ersetzen-ent ent tag suche ersatz teil-p probe-p` | Attribute EINER Einfuegung ersetzen bzw. nur zaehlen (`probe-p`); Rueckgabe Anzahl |
| `ssg-bt-attr-ersetzen-liste ents tag suche ersatz teil-p probe-p` | Dasselbe fuer eine Entity-Liste |
| `ssg-bt-wert-neu wert suche ersatz teil-p` | Reiner Kern: neuer Wert oder `nil` (unveraendert); beachtet Gross-/Kleinschreibung |
| `ssg-bt-name-passt-p`, `ssg-bt-zaehle-namen`, `ssg-bt-muster-escape` | Reine Hilfsfunktionen (getestet) |
---
### `ssg_texttools.lsp` – Text-Werkzeuge
Ursprung: ACADSST `CHGTEXT.LSP`, `PARTEXT.LSP`, `ALTHOEHE.LSP`, `ALTSTIL.LSP`. Laden **nach** `ssg_blocktools` (nutzt `ssg-bt-wert-neu` und `ssg-bt-attr-ersetzen-liste`). Arbeitet in der XY-Ebene des Welt-KS.
| Befehl | Beschreibung |
| --- | --- |
| `SSG_TEXT_ERSETZEN` | Suchen/Ersetzen in TEXT, MTEXT **und** Block-Attributen; Bereich Alle (Layout) oder Auswahl; Vorschau mit Anzahl, Rueckfrage |
| `SSG_TEXT_PARALLEL` | Linie/Polylinie/Bogen anklicken, Text wird parallel (lesbar, nie auf dem Kopf) mit Abstand gesetzt; Hoehe, Abstand und letzter Text werden fuer die Sitzung gemerkt; Enter beendet |
| `SSG_TEXT_HOEHE` | Texthoehe gewaehlter TEXT/MTEXT aendern |
| `SSG_TEXT_STIL` | Textstil gewaehlter TEXT/MTEXT aendern (Stil muss existieren) |
Reine Kerne (getestet): `ssg-tt-lesbarer-winkel` (Winkel 90 Grad bis 270 Grad um 180 Grad drehen, Ergebnis in [0, 2 pi)), `ssg-tt-versetzt`.
Nicht uebernommen aus Walz: `Export`/`Import` von Texten (besser per Python/ezdxf), `KREISTXT`, `TXTBOXED`, `CHTEXT`/`ASCTEXT`/`PTEXT` (Autodesk 1990, durch BricsCAD-Standard ersetzt).
---
### `ssg_load.lsp` – Laderoutine
Headless-Loader fuer .scr-Testskripte (z.B. `tests/test_unit.scr`). Laedt alle
Kern- und Feature-Module in derselben Reihenfolge wie `SSG_LIB.mnl`, ohne
Menueabhaengigkeit. Ermittelt den Pfad automatisch über `findfile`. Ruft direkt
nach `ssg_core.lsp` die Funktion `ssg-load-config` auf, damit die JSON-Konfiguration
für alle nachfolgenden Module verfügbar ist.
---
### `VarioFoerderer.lsp` – Vario-Förderer (Wrapper)
Kompatibilitäts-Wrapper, der `vf_core.lsp` lädt (Plugin-Dispatcher-Architektur
über `*vf-typ-registry*`; lädt seinerseits `vf_konstanten.lsp`, `vf_standard.lsp`,
`vf_etage.lsp`, `vf_linienzug.lsp`, danach `vf_spec.lsp`). Parametrischer Generator
für ILS Vario-Förderanlagen (Typen Standard/Etage/Linienzug). Liest Block-Geometrie
aus einer DWG-Bibliothek (`DXFM_BLOCKS`) über die Primitiven aus `ssg_ks_insert.lsp`.
Alle Konstanten (Abstände, Winkel, Skalierung) werden über `ssg-cfg-or`
(`component_defaults.json`, Sektion `vario`) bzw. die zentralen `*vfk-*`-Konstanten
aus `vf_konstanten.lsp` gelesen.
**Befehl:** `c:FOERDERANLAGE` / `c:VarioFoerderer` – wählt zuerst den Anlagen-Typ (Standard/Etage/Linienzug):
- **Typ „standard“ und „etage“ + Werteingabe:** laufen über denselben,
typ-parametrisierten Dialog-Ablauf (`vf-dialog-ablauf` in `vf_core.lsp`;
`vfs-standard-dialog-ablauf`/`vfe-etage-dialog-ablauf` sind nur noch duenne
Wrapper darauf) mit den Dialogen `vfs-dialog-eingabe-basis`/
`vfs-dialog-winkel-verteilung` ([`dcl/variofoerderer.dcl`](../dcl/variofoerderer.dcl)):
Dialog 1 erfasst deltaL, Förderrichtung, Einfügehöhe/deltaH, Fahrtrichtung und
Seite/Motorseite; Dialog 2 lässt Winkel und L_GF-Verteilung (vorne/hinten) wählen.
Startpunkt (X/Y) wird vorher in der Zeichnung gepickt.
- **Typ „standard“/„etage“ + 3D-Linie** laufen ueber denselben Basis-Dialog statt
rein interaktiv auf der Konsole.
- **Typ „linienzug“** (Streckengruppe, `vf-linienzug-modus` in `vf_linienzug.lsp`)
hat drei Modi (manuell/Wizard, 3D-Objekte+Zielhoehe, Vorwaerts-Nachbau) und
zeichnet jede Eingabe in einem Journal auf (XDATA `SSG_VF_EDIT` am `VF_n`-Block);
Standard laeuft per Default ueber DCL-Dialoge (`VF_WIZARD_AN`/`VF_WIZARD_AUS`
schalten um). Details, Journal-Format, Headless-Modus (`*vfl-headless*`) und
Spec-basierter Bau ohne Dialog (`vf_spec.lsp`, `VF_SPEC_BAU`): siehe
[`../doc/variofoerderer.md`](../doc/variofoerderer.md) und `../CLAUDE.md`.
**Bearbeiten (`c:VARIOFOERDERER_EDIT`):** Doppelklick auf einen `VF_n`-Block – bzw.
Rechtsklick-Kontextmenü/`SSG_BLOCKEDIT` – dispatcht per XDATA-Marker
(`"standard"`/`"etage"`/`"linienzug"`) in den passenden Neuaufbau-Zweig
(`vfe-edit-ent` fuer Etage, `vfl-edit-ent` fuer Linienzug) und öffnet dieselben
Dialoge, vorbelegt mit den aktuellen Parametern; der Block wird am selben
Startpunkt neu aufgebaut (neue `VF_n`-Nummer). Altbestand-Blöcke ohne
Marker werden mit einer Meldung abgewiesen, statt sie zu verändern. Winkel und
L_GF1 werden aus den Sivas-Attributen (`VF_WINKEL`, `L_GF_m`) vorbelegt.
Die Block-Einfuege-Primitiven (`ensure-block-loaded`, `insert-block-by-ks`,
`insert-inclined-scaled-block`, `insert-rotated-block-with-ks` u.a.) sind seit
der Konsolidierung zentral in [`ssg_ks_insert.lsp`](#ssg_ks_insertlsp--ks-extraktion-und-block-einfuegeprimitiven)
definiert (von `vf_core.lsp`, `Gefaellestrecke.lsp` und `TEFInsert.lsp` genutzt).
Weitere interne Helfer: `init-bibliothek` (Block-Bibliothek aus DWG laden),
`get-line-start-end-points ename`, `punkt-differenz p1 p2`.
---
@@ -414,6 +528,19 @@ Der Neuaufbau läuft über `gf-rebuild` (nicht-interaktiv, ohne Konsolen-Rückfr
---
### `TEFInsert.lsp` – TEF-Geradenstuecke entlang einer Linie
**Befehl:** `c:TEF_FOERDERER_LINIE`. Zeichnet eine Linie zwischen zwei gewaehlten
Punkten und reiht darauf 1000-mm-TEF-Geradenelemente (`0_B10030` aus
`DXFM_OMNIFLO`) aneinander; ist die Linienlaenge kein exaktes Vielfaches,
wird ein zusaetzliches, zurueckverschobenes Element eingefuegt, sodass der
Foerderer exakt am Linienende endet (keine Luecke, kein abgeschnittenes
Element). Die Linie darf geneigt sein (3D) – Elemente werden dann analog zu
`vf_core.lsp`/`ssg_ks_insert.lsp` (Rz*Ry-Rotation) gekippt eingefuegt. Nicht
zu verwechseln mit den einzelnen `OMNI_TEF_*`-Befehlen in `OmniModulInsert.lsp`.
---
### `export.lsp` – Export-Funktionen
Sammelt INSERT-Blöcke aus der Zeichnung und exportiert sie als JSON oder ruft Python-Skripte für den Sivas-Export auf.
@@ -572,11 +699,16 @@ AutoLISP-Implementierung fuer alle Omniflo-Komponenten: Boegen, Weichen, Verbind
| Weichen | `OMNI_W90_*`, `OMNI_W45_*`, `OMNI_WP_*`, `OMNI_WK_*`, `OMNI_WKomb_*` | Omniflo-Weichen (Einfach/Doppel/Dreiwege, Delta, Stern) |
| Geraden | `OMNI_AP60`, `OMNI_AP110`, `OMNI_APG110` | Omniflo-Geradenstuecke |
| Ladeschleifen | `OMNI_LADESCHLEIFE_AP110` | Ladeschleife aus `omniflo_ladeschleifen.json` ueber DCL-Dialog (`dcl/omniflo_ladeschleifen.dcl`) einfuegen; Daten per `ssg-json-laden` (Beschreibungen enthalten Kommas). Blockdatei `<Sivasnr>.dwg` unter `DXFM_OMNIFLO` (`omni:insert-dxf` faellt auf `.dwg` zurueck, wenn keine `.dxf` existiert). Per `OMNI_EDIT` editierbar |
| TEF ⚠️ | `OMNI_TEF_UmlenkR/L`, `OMNI_TEF_AntriebL/R`, `OMNI_TEF_Gerade`, `OMNI_KettenFoerderer` | **Dummy** (noch nicht implementiert, im Menue ausgegraut) |
| TEF Elemente | `OMNI_TEF_UmlenkR/L`, `OMNI_TEF_AntriebL/R`, `OMNI_TEF_Gerade` | Feste TEF-Bauteile ohne Sivas-Auswahl, direkt per `omni:insert-dxf` an gewaehltem Punkt eingefuegt (Dateien unter `DXFM_OMNIFLO`) |
| Anbaugruppen ⚠️ | `OMNI_KettenFoerderer` | **Dummy** (noch nicht implementiert, im Menue ausgegraut); `OMNI_STOPPER`/`OMNI_SCANNER`/`OMNI_BUERSTENBREMSE` sind implementiert |
| Transferwagen ⚠️ | `OMNI_TV_*` | **Dummy** (noch nicht implementiert, im Menue ausgegraut) |
| Bogenweichen ⚠️ | `OMNI_APBW_*` | **Dummy** (noch nicht implementiert, im Menue ausgegraut) |
| Bearbeiten | `OMNI_EDIT` | Omniflo-Block selektieren und Attribute bearbeiten |
Daneben zeichnet [`TEFInsert.lsp`](#tefinsertlsp--tef-geradenstuecke-entlang-einer-linie) (`TEF_FOERDERER_LINIE`) eine
Kette von TEF-Geradenelementen (1000 mm) entlang einer frei gewaehlten Linie –
nicht zu verwechseln mit den einzelnen `OMNI_TEF_*`-Befehlen oben.
---
### `SSG_LIB_Commands.lsp` – BTMT, Sensoren, Dummy-Befehle, Konfiguration und SSG_BLOCKEDIT
@@ -623,6 +755,10 @@ Entladung" bzw. "BT - Beladung ..."/"Abwurf fuer Klammerbuegel ..."); im
Sivas-Export zusaetzlich in den Summenzaehlern "Anzahl aller BTBeladung"/
"Anzahl aller Abwurfstationen" der ILS-Automation-Zeile.
**Eingang-/Ausgang-Symbol:** `ILS_EINGANG_INSERT`/`ILS_AUSGANG_INSERT` nutzen
dieselbe `ils-insert-station`-Routine wie BTMT Be-/Entladung (frei platzierbar,
Blöcke `Eingang_<DIM>.dwg`/`Ausgang_<DIM>.dwg` in `data/ils`).
Registrierte Dummy-Befehle:
| Gruppe | Befehle |
@@ -643,11 +779,86 @@ Registrierte Dummy-Befehle:
**SSG_BLOCKEDIT** – Doppelklick/Kontextmenue-Dispatcher:
Erkennt den Blocktyp des selektierten INSERT-Blocks und ruft den passenden Bearbeitungsbefehl auf:
Erkennt den Blocktyp des selektierten INSERT-Blocks und ruft den passenden Bearbeitungsbefehl auf (Reihenfolge wichtig: `GR_*` **vor** dem Omniflo-Zweig, da Geruest-Bloecke ebenfalls ein TEILEART-Attribut tragen):
| Blockmuster | Aktion |
| --- | --- |
| `KREISEL_*` | `KreiselEdit` |
| `ECKRAD_*` | `BEDIT` (Block-Editor) |
| `GF_*` | `GEFAELLESTRECKE_EDIT` |
| `VF_*` | `VARIOFOERDERER_EDIT` |
| `GR_*` | Geruest – `BEDIT` (kein eigener Edit-Pfad; siehe `GeruestInsert.lsp`) |
| `TRO_*` | `TRO_EDIT` |
| Omniflo (TEILEART-Attribut, AP110*, numerisch) | `OMNI_EDIT` |
| Sonstige | `BEDIT` (Block-Editor) |
---
### `GeruestInsert.lsp` – Geruest-Baugruppen
Rohr-Geruest-Baugruppen (Saeulen, Rohrabhaenger, Wandbefestigung, Rohr-Geruest-Traeger)
aus [`data/json/geruest.json`](../data/json/geruest.json) bzw.
[`data/json/geruest_traeger.json`](../data/json/geruest_traeger.json) konfigurieren
und einfuegen. Die Dialogdefinition wird **zur Laufzeit erzeugt**
(`geruest-dcl-schreiben`, temporaere DCL-Datei) – es gibt keine feste
`dcl/geruest.dcl`, weil je Anbauteil ein eigenes Mengenfeld gebraucht wird.
Ausfuehrliche Beschreibung (Konfigurationen, Attribut-Schema, Querstreben/Muffe,
Traeger-Beschriftung): siehe `../CLAUDE.md` Abschnitt "AutoLISP-Module".
| Befehl | Beschreibung |
| --- | --- |
| `c:GERUEST` | Dialog ohne Vorgabe-Bereich (Dropdown Rohrabhaenger/Saeulen/Wandbefestigung) |
| `c:GERUEST_SAEULEN` / `c:GERUEST_ROHRABHAENGER` / `c:GERUEST_WANDBEFESTIGUNG` | Dialog mit vorgewaehltem Bereich (derselbe Dialog wie `GERUEST`) |
| `c:GERUEST_TRAEGER` | Eigener fester Dialog (`dcl/geruest_traeger.dcl`): Rohr-Geruest-Traeger mit Linien-Logik (Start-/Endpunkt oder Laenge, Laengenabzuege, Querstreben/Muffe-Verteilung) |
| `c:GERUEST_TRAEGER_BESCHRIFTEN` | Alle Traeger der Zeichnung neu beschriften (eigenes TEXT-Objekt, verknuepft per XDATA `SSG_GR_BESCHR`) |
Block-Praefix `GR_<id>_<timestamp>` – **nicht kosmetisch**: `SSG_BLOCKEDIT` muss
`GR_*` vor dem Omniflo-Zweig abfangen, da Geruest-Bloecke ebenfalls ein
TEILEART-Attribut tragen. Export-Pattern `pattern_geruest = GR_*` (`cfg/export.cfg`).
---
### `Tro_Edit.lsp` – TRO-Marker
TRO-Marker (Block `TRO_SYM_<Typ>`) fuer `sps_skel`/`lib/tro_annotate.py`.
| Befehl | Beschreibung |
| --- | --- |
| `c:TRO_INSERT` | Bestehende Blockdefinition an gewaehltem Punkt einfuegen, setzt ID/TYPE; bricht ab, wenn der Typ noch keine Blockdefinition in der Zeichnung hat (entsteht nur ueber `tro_annotate.py`) |
| `c:TRO_EDIT` | ID/TYPE eines bestehenden Markers per Dialog aendern |
Typliste kommt aus [`tro_types.lsp`](../Lisp/tro_types.lsp) (von
`tro_annotate.py --emit-lisp` nach `DXFM_LISP` geschrieben). `SSG_BLOCKEDIT`
leitet Blocknamen `TRO_*` zu `TRO_EDIT`.
---
### `Connection_Edit.lsp` – Verbindungen (SPS)
Verbindungslinien zwischen zwei Punkten/Bausteinen fuer SPS-Dokumentation.
| Befehl | Beschreibung |
| --- | --- |
| `c:CONNECTION_INSERT` | Verbindung zwischen zwei Punkten einfuegen (Laenge/Winkel/Mitte werden berechnet) |
| `c:CONNECTION_EDIT` | Bestehende Verbindung bearbeiten |
---
### `DrawPlanquadrate.lsp` – Planquadrat-Raster
Zeichnet auf Z=0 ein Planquadrat-Linienraster (senkrecht/waagerecht) im
Abstand/Zaehlschema der aktiven `[Planquadrate]`-Konfiguration aus
`cfg/export.cfg` – dieselbe Quelle wie `lib/export_planquadrat.py` fuer den
CSV-Export. Bereich und Ursprung kommen aus der **Bounding-Box** derselben
Blockmenge wie `EXPORTCSV` (`csv:collect-export-blocks`), nicht aus dem reinen
Einfuegepunkt oder den Zeichnungs-Extents. Lazy geladen ueber
`(ssg-ensure "DrawPlanquadrate")`, nicht Teil der Core-Ladereihenfolge.
| Befehl | Beschreibung |
| --- | --- |
| `c:DRAW_PLANQUADRATE` | Raster neu aufbauen (entfernt zuerst einen evtl. vorhandenen Block) |
| `c:DELETE_PLANQUADRATE` | Raster-Block entfernen |
| `c:PLANQUADRATE_TOGGLE` | Dispatcht auf Zeichnen bzw. Loeschen, je nachdem ob der Block existiert |
Das fertige Raster (Linien + Zaehl-Texte) wird zu einem einzigen Block
`ZZ_PLANQUADRATE` bei (0,0,0) zusammengefasst; Layer aus `cfg/layer.cfg`.
+311
View File
@@ -0,0 +1,311 @@
;; ============================================================
;; SSG_BLOCKTOOLS.LSP - Block-Werkzeuge fuer die aktuelle Zeichnung
;;
;; Ursprung: ACADSST/MENU/TOOLS.LSP (BLKANZAHL, BLKENTF), DINGEN2
;; (g-bli) und ssg.lsp (suchen-aendern) - neu geschrieben im ssg-Stil
;; (Undo-Gruppe, i18n, Ja/Nein-Rueckfrage, keine Globals).
;;
;; Befehle:
;; SSG_BLOCK_COUNT Einfuegungen zaehlen (ein Block, Namensmuster
;; oder Statistik aller Bloecke)
;; SSG_BLOCK_DELETE Alle Einfuegungen eines Blocks/Namensmusters
;; loeschen (mit Rueckfrage)
;; SSG_ATTR_ERSETZEN Attributwerte zeichnungsweit oder in einer
;; Auswahl suchen und ersetzen (mit Vorschau)
;;
;; Blocknamen werden ueber den WIRKSAMEN Namen verglichen (dynamische
;; Bloecke: EffectiveName statt "*U12"). Muster arbeiten mit wcmatch
;; (Platzhalter * ? #, ohne Beachtung der Gross-/Kleinschreibung).
;; Es wird nur der aktuelle Layout-Reiter (Modell ODER Papierbereich)
;; durchsucht.
;;
;; Setzt ssg_core.lsp, ssg_lang.lsp und ssg_input.lsp voraus.
;; ============================================================
(vl-load-com)
;; ------------------------------------------------------------
;; REINE HILFSFUNKTIONEN (in test_unit getestet)
;; ------------------------------------------------------------
;; T, wenn name auf das wcmatch-Muster passt (ohne Gross-/Kleinschreibung).
;; muster nil oder "" -> alle Namen passen.
(defun ssg-bt-name-passt-p (name muster)
(if (or (null muster) (= muster ""))
T
(if (wcmatch (strcase name) (strcase muster)) T nil)
)
)
;; Liste von Namen -> Alist ((NAME . ANZAHL) ...), alphabetisch sortiert
;; (ohne Beachtung der Gross-/Kleinschreibung).
(defun ssg-bt-zaehle-namen (namen / alist eintrag)
(foreach name namen
(setq eintrag (assoc name alist))
(if eintrag
(setq alist (subst (cons name (1+ (cdr eintrag))) eintrag alist))
(setq alist (cons (cons name 1) alist))
)
)
(vl-sort alist '(lambda (a b) (< (strcase (car a)) (strcase (car b)))))
)
;; Sonderzeichen eines Blocknamens fuer wcmatch maskieren (Backquote), damit
;; ein per Pick gewaehlter Name nur sich selbst trifft.
(defun ssg-bt-muster-escape (name / res i c)
(setq res "" i 1)
(while (<= i (strlen name))
(setq c (substr name i 1))
(if (vl-string-search c "#@.*?~[],`")
(setq res (strcat res "`"))
)
(setq res (strcat res c)
i (1+ i))
)
res
)
;; Muster ohne Maskier-Backquotes (fuer Meldungen)
(defun ssg-bt-muster-anzeige (muster)
(ssg-str-replace-all "" "`" muster)
)
;; Neuer Attributwert oder nil, wenn der Wert unveraendert bleibt.
;; teil-p = T : suche wird als Teilstring ueberall ersetzt
;; teil-p = nil: nur ersetzen, wenn der GESAMTE Wert gleich suche ist
;; Leere suche aendert nichts. Gross-/Kleinschreibung wird beachtet.
(defun ssg-bt-wert-neu (wert suche ersatz teil-p)
(cond
((or (null suche) (= suche "") (null wert)) nil)
(teil-p
(if (vl-string-search suche wert)
(ssg-str-replace-all ersatz suche wert)
nil
)
)
((= wert suche) ersatz)
(t nil)
)
)
;; ------------------------------------------------------------
;; ZEICHNUNGSZUGRIFF
;; ------------------------------------------------------------
;; Wirksamer Blockname einer Einfuegung (dynamische Bloecke beachten)
(defun ssg-bt-effname (ent / res)
(setq res (vl-catch-all-apply 'vla-get-effectivename
(list (vlax-ename->vla-object ent))))
(if (vl-catch-all-error-p res)
(cdr (assoc 2 (entget ent)))
res
)
)
;; T, wenn der Layer der Entity gesperrt ist
(defun ssg-bt-layer-gesperrt-p (ent / lay)
(setq lay (tblsearch "LAYER" (cdr (assoc 8 (entget ent)))))
(and lay (= 4 (logand 4 (cdr (assoc 70 lay)))))
)
;; Alle Einfuegungen im aktuellen Layout, optional gefiltert nach Namensmuster.
;; Rueckgabe: Liste von Entity-Namen (kann leer sein).
(defun ssg-bt-inserts (muster / ss i ent res)
(setq ss (ssget "_X" (list '(0 . "INSERT") (cons 410 (getvar "CTAB")))))
(if ss
(progn
(setq i 0)
(while (setq ent (ssname ss i))
(if (ssg-bt-name-passt-p (ssg-bt-effname ent) muster)
(setq res (cons ent res))
)
(setq i (1+ i))
)
)
)
(reverse res)
)
;; Statistik: ((NAME . ANZAHL) ...) fuer alle Einfuegungen passend zum Muster
(defun ssg-bt-statistik (muster)
(ssg-bt-zaehle-namen (mapcar 'ssg-bt-effname (ssg-bt-inserts muster)))
)
;; Block per Pick oder Namensmuster waehlen.
;; Rueckgabe: Namensmuster (String) oder nil bei Enter ("alle").
(defun ssg-bt-muster-waehlen (text / sel ed)
(initget "Name")
(setq sel (entsel text))
(cond
((null sel) nil)
((= (type sel) 'STR)
(setq sel (getstring T (ssg-text "bt-prompt-muster")))
(if (= sel "") nil sel)
)
(t
(setq ed (entget (car sel)))
(if (= (cdr (assoc 0 ed)) "INSERT")
(ssg-bt-muster-escape (ssg-bt-effname (car sel)))
(progn (prompt (ssg-text "bt-kein-block")) nil)
)
)
)
)
;; Attribute EINER Einfuegung ersetzen (oder nur zaehlen, wenn probe-p).
;; tag = wcmatch-Muster fuer den Attribut-Tag ("*" = alle).
;; Rueckgabe: Anzahl betroffener Attribute.
(defun ssg-bt-attr-ersetzen-ent (ent tag suche ersatz teil-p probe-p
/ e ed neu n)
(setq n 0
e (entnext ent))
(while (and e
(= "ATTRIB" (cdr (assoc 0 (setq ed (entget e))))))
(if (and (ssg-bt-name-passt-p (cdr (assoc 2 ed)) tag)
(setq neu (ssg-bt-wert-neu (cdr (assoc 1 ed)) suche ersatz teil-p)))
(progn
(setq n (1+ n))
(if (not probe-p)
(entmod (subst (cons 1 neu) (assoc 1 ed) ed))
)
)
)
(setq e (entnext e))
)
(if (and (> n 0) (not probe-p)) (entupd ent))
n
)
;; Attribute einer Liste von Einfuegungen ersetzen. Rueckgabe: Anzahl.
(defun ssg-bt-attr-ersetzen-liste (ents tag suche ersatz teil-p probe-p / n)
(setq n 0)
(foreach ent ents
(setq n (+ n (ssg-bt-attr-ersetzen-ent ent tag suche ersatz teil-p probe-p)))
)
n
)
;; Auswahlsatz -> Liste von Entity-Namen (nur INSERT)
(defun ssg-bt-ss-inserts (ss / i ent res)
(if ss
(progn
(setq i 0)
(while (setq ent (ssname ss i))
(if (= (cdr (assoc 0 (entget ent))) "INSERT")
(setq res (cons ent res))
)
(setq i (1+ i))
)
)
)
(reverse res)
)
;; ------------------------------------------------------------
;; BEFEHLE
;; ------------------------------------------------------------
(defun c:SSG_BLOCK_COUNT ( / muster stat summe)
(setq muster (ssg-bt-muster-waehlen (ssg-text "bt-prompt-waehlen-count")))
(setq stat (ssg-bt-statistik muster))
(cond
((null stat)
(prompt (if muster
(ssg-textf "bt-count-keine" (list (ssg-bt-muster-anzeige muster)))
(ssg-text "bt-count-keine-alle")))
)
((and muster (null (cdr stat)))
(prompt (ssg-textf "bt-count-ergebnis" (list (cdar stat) (caar stat))))
)
(t
(setq summe 0)
(foreach z stat
(prompt (ssg-textf "bt-count-zeile" (list (car z) (cdr z))))
(setq summe (+ summe (cdr z)))
)
(prompt (ssg-textf "bt-count-summe" (list summe (length stat))))
)
)
(princ)
)
(defun c:SSG_BLOCK_DELETE ( / muster ents frei gesperrt n)
(setq muster (ssg-bt-muster-waehlen (ssg-text "bt-prompt-waehlen-delete")))
(if (null muster)
(prompt (ssg-text "bt-delete-kein-muster"))
(progn
(setq ents (ssg-bt-inserts muster))
(foreach ent ents
(if (ssg-bt-layer-gesperrt-p ent)
(setq gesperrt (cons ent gesperrt))
(setq frei (cons ent frei))
)
)
(cond
((null ents)
(prompt (ssg-textf "bt-count-keine" (list (ssg-bt-muster-anzeige muster)))))
((null frei)
(prompt (ssg-textf "bt-delete-alle-gesperrt" (list (length gesperrt)))))
((ssg-in-yesno (ssg-textf "bt-delete-frage" (list (length frei) (ssg-bt-muster-anzeige muster))) nil)
(ssg-start (ssg-text "bt-delete-titel") nil)
(setq n 0)
(foreach ent frei
(if (entdel ent) (setq n (1+ n)))
)
(ssg-end)
(prompt (ssg-textf "bt-delete-ergebnis" (list n)))
(if gesperrt
(prompt (ssg-textf "bt-delete-gesperrt" (list (length gesperrt)))))
)
(t (prompt (ssg-text "bt-abgebrochen")))
)
)
)
(princ)
)
(defun c:SSG_ATTR_ERSETZEN ( / k-bereich k-modus bereich ents muster tag suche ersatz modus teil-p n)
(setq k-bereich (ssg-text "in-keys-bereich")
k-modus (ssg-text "in-keys-modus")
bereich (ssg-in-keyword (ssg-text "bt-attr-bereich") k-bereich
(ssg-in-first-word k-bereich)))
(if (= bereich (ssg-in-first-word k-bereich))
(progn
(setq muster (ssg-in-string (ssg-text "bt-attr-muster") "*"))
(setq ents (ssg-bt-inserts muster))
)
(progn
(prompt (ssg-text "bt-attr-auswahl"))
(setq ents (ssg-bt-ss-inserts (ssget '((0 . "INSERT")))))
)
)
(cond
((null ents) (prompt (ssg-text "bt-attr-keine-bloecke")))
(t
(setq tag (ssg-in-string (ssg-text "bt-attr-tag") "*")
suche (ssg-in-string (ssg-text "bt-attr-suche") nil))
(if (or (null suche) (= suche ""))
(prompt (ssg-text "bt-abgebrochen"))
(progn
(setq ersatz (ssg-in-string (ssg-text "bt-attr-ersatz") "")
modus (ssg-in-keyword (ssg-text "bt-attr-modus") k-modus
(ssg-in-first-word k-modus))
teil-p (= modus (ssg-in-first-word k-modus)))
(setq n (ssg-bt-attr-ersetzen-liste ents tag suche ersatz teil-p T))
(cond
((= n 0) (prompt (ssg-text "bt-attr-nichts")))
((ssg-in-yesno (ssg-textf "bt-attr-frage" (list n (length ents))) T)
(ssg-start (ssg-text "bt-attr-titel") nil)
(setq n (ssg-bt-attr-ersetzen-liste ents tag suche ersatz teil-p nil))
(ssg-end)
(prompt (ssg-textf "bt-attr-ergebnis" (list n))))
(t (prompt (ssg-text "bt-abgebrochen")))
)
)
)
)
)
(princ)
)
(princ)
+38
View File
@@ -1622,6 +1622,44 @@
)
;; ------------------------------------------------------------
;; DCL ZUR LAUFZEIT GENERIEREN
;; ------------------------------------------------------------
;; Escaped Anfuehrungszeichen in einem DCL-Label-String ("->''), damit ein
;; Label mit Anfuehrungszeichen (z.B. aus Nutzerdaten oder Zoll-Angaben) die
;; DCL-Zeile nicht vorzeitig beendet. Fachlich identisch zu
;; geruest-dcl-label (GeruestInsert.lsp), aber hier als generischer
;; Kernel-Helfer fuer jeden Aufrufer, der DCL-Text zusammenbaut.
(defun ssg-dcl-label-escape (text / i c out)
(setq i 0 out "")
(while (< i (strlen text))
(setq c (substr text (1+ i) 1))
(setq out (strcat out (if (= c "\"") "''" c)))
(setq i (1+ i))
)
out
)
;; Schreibt eine Liste von Textzeilen als temporaere DCL-Datei und liefert
;; deren Pfad zurueck (oder nil bei Fehler, z.B. wenn open scheitert). Der
;; Aufrufer ist fuer load_dialog/unload_dialog UND das Loeschen der Datei
;; (vl-file-delete) danach selbst verantwortlich - analog zum bestehenden
;; Muster in GeruestInsert.lsp (geruest-dcl-schreiben), hier nur als
;; generischer Baustein fuer WEITERE Aufrufer (GeruestInsert.lsp selbst
;; bleibt unveraendert, um dessen Code nicht anzufassen).
(defun ssg-dcl-temp-schreiben (praefix zeilen / pfad f)
(setq pfad (vl-filename-mktemp praefix nil ".dcl"))
(if (setq f (open pfad "w"))
(progn
(foreach zeile zeilen (write-line zeile f))
(close f)
pfad
)
nil
)
)
;; ------------------------------------------------------------
;; REKURSIVER JSON-PARSER
;; ------------------------------------------------------------
+162
View File
@@ -0,0 +1,162 @@
;; ============================================================
;; SSG_INPUT.LSP - Generische Eingabe-Wrapper (ssg-in-*)
;;
;; Allgemeingueltige Abfragen mit Vorgabewert, Anzeige "<Vorgabe>" im
;; Prompt und Enter = Vorgabe (Idee von g_in/g_ky aus den ACADSST-
;; Makros). Steht NEBEN den VF-spezifischen vfl-in-* aus
;; vf_linienzug.lsp; diese bleiben unveraendert.
;;
;; Alle Funktionen liefern den eingegebenen Wert oder die Vorgabe.
;; ESC bricht wie ueblich ueber *error* ab (z.B. ssg-errhan).
;; Ist kein Wert eingegeben und keine Vorgabe da, ist die Rueckgabe nil.
;;
;; Optionaler Hook (z.B. fuer ein Eingabe-Journal):
;; (setq *ssg-in-hook* 'meine-funktion)
;; (defun meine-funktion (art prompt wert) ...) ;; art = "REAL" "INT"
;; ;; "STRING" "POINT"
;; ;; "DIST" "KEYWORD"
;; ;; "YESNO"
;; Ein Hook, der einen Fehler wirft, wird abgeschaltet.
;;
;; Setzt ssg_core.lsp (und fuer ssg-in-yesno ssg_lang.lsp) voraus.
;; ============================================================
(vl-load-com)
;; ------------------------------------------------------------
;; REINE HILFSFUNKTIONEN (ohne Zeichnung, in test_unit getestet)
;; ------------------------------------------------------------
;; Vorgabe einsetzen, wenn kein Wert eingegeben wurde
(defun ssg-in-default (wert default)
(if wert wert default)
)
;; Reelle Zahl ohne ueberfluessige Nullen: 5.0 -> "5", 2.50 -> "2.5"
(defun ssg-in-fmt-real (v / s)
(setq s (rtos v 2 6))
(if (vl-string-position 46 s)
(progn
(while (= (substr s (strlen s)) "0")
(setq s (substr s 1 (1- (strlen s))))
)
(if (= (substr s (strlen s)) ".")
(setq s (substr s 1 (1- (strlen s))))
)
)
)
s
)
;; Punkt als "x,y,z" (fehlende Z-Werte als 0)
(defun ssg-in-fmt-pt (p)
(strcat (ssg-in-fmt-real (car p)) ","
(ssg-in-fmt-real (cadr p)) ","
(ssg-in-fmt-real (if (caddr p) (caddr p) 0.0)))
)
;; Prompt aufbauen: "<text> <default>: " bzw. "<text>: " ohne Vorgabe
(defun ssg-in-prompt (text default-str)
(strcat text
(if default-str (strcat " <" default-str ">") "")
": ")
)
;; Erstes Wort eines Schluesselwort-Strings: "Ja Nein" -> "Ja"
(defun ssg-in-first-word (schluessel / pos)
(if (setq pos (vl-string-search " " schluessel))
(substr schluessel 1 pos)
schluessel
)
)
;; Zweites Wort: "Ja Nein" -> "Nein"
(defun ssg-in-second-word (schluessel / pos)
(if (setq pos (vl-string-search " " schluessel))
(substr schluessel (+ pos 2))
""
)
)
;; ------------------------------------------------------------
;; HOOK
;; ------------------------------------------------------------
(defun ssg-in-notify (art text wert / res)
(if *ssg-in-hook*
(progn
(setq res (vl-catch-all-apply *ssg-in-hook* (list art text wert)))
(if (vl-catch-all-error-p res) (setq *ssg-in-hook* nil))
)
)
wert
)
;; ------------------------------------------------------------
;; ABFRAGEN
;; text = Prompt ohne Doppelpunkt, z.B. "\nHoehe"
;; ------------------------------------------------------------
(defun ssg-in-real (text default / w)
(setq w (getreal (ssg-in-prompt text (if default (ssg-in-fmt-real default)))))
(ssg-in-notify "REAL" text (ssg-in-default w default))
)
(defun ssg-in-int (text default / w)
(setq w (getint (ssg-in-prompt text (if default (itoa default)))))
(ssg-in-notify "INT" text (ssg-in-default w default))
)
;; String (mit Leerzeichen). Enter ohne Eingabe -> Vorgabe.
(defun ssg-in-string (text default / w)
(setq w (getstring T (ssg-in-prompt text default)))
(if (= w "") (setq w nil))
(ssg-in-notify "STRING" text (ssg-in-default w default))
)
;; Punkt. base = Gummiband-Basispunkt oder nil, default = Punkt oder nil.
(defun ssg-in-point (text default base / w)
(setq w (if base
(getpoint base (ssg-in-prompt text (if default (ssg-in-fmt-pt default))))
(getpoint (ssg-in-prompt text (if default (ssg-in-fmt-pt default))))
))
(ssg-in-notify "POINT" text (ssg-in-default w default))
)
;; Abstand. base = Basispunkt oder nil.
(defun ssg-in-dist (text default base / w)
(setq w (if base
(getdist base (ssg-in-prompt text (if default (ssg-in-fmt-real default))))
(getdist (ssg-in-prompt text (if default (ssg-in-fmt-real default))))
))
(ssg-in-notify "DIST" text (ssg-in-default w default))
)
;; Schluesselwort ohne Hook (intern, auch von ssg-in-yesno genutzt).
(defun ssg-in-keyword-raw (text schluessel default / w)
(initget 0 schluessel)
(setq w (getkword
(ssg-in-prompt
(strcat text " [" (vl-string-translate " " "/" schluessel) "]")
default)))
(ssg-in-default w default)
)
;; Schluesselwort. schluessel im initget-Format, z.B. "Alle Auswahl".
;; Rueckgabe: gewaehltes Schluesselwort (volle Schreibweise) oder default.
(defun ssg-in-keyword (text schluessel default)
(ssg-in-notify "KEYWORD" text (ssg-in-keyword-raw text schluessel default))
)
;; Ja/Nein-Abfrage, Rueckgabe T bei Ja, nil bei Nein (anders als ssg-ques,
;; das T fuer die NICHT-vorgegebene Antwort liefert).
;; default = T -> Enter bedeutet Ja, nil -> Enter bedeutet Nein.
;; Die Schluesselwoerter kommen aus ssg-text "in-yesno-keys" (z.B. "Ja Nein").
(defun ssg-in-yesno (text default / schluessel ja nein w)
(setq schluessel (ssg-text "in-yesno-keys")
ja (ssg-in-first-word schluessel)
nein (ssg-in-second-word schluessel))
(setq w (ssg-in-keyword-raw text schluessel (if default ja nein)))
(ssg-in-notify "YESNO" text (= w ja))
)
(princ)
+5 -1
View File
@@ -28,6 +28,7 @@
(load (strcat base-path "ssg_dbg.lsp") "ssg_dbg.lsp nicht gefunden")
(load (strcat base-path "ssg_dialog.lsp") "ssg_dialog.lsp nicht gefunden")
(load (strcat base-path "ssg_layer.lsp") "ssg_layer.lsp nicht gefunden")
(load (strcat base-path "ssg_input.lsp") "ssg_input.lsp nicht gefunden")
;; Gemeinsame KS-Extraktion + Einfuegeprimitiven - MUSS vor VarioFoerderer
;; und Gefaellestrecke geladen werden (beide nutzen sie).
(load (strcat base-path "ssg_ks_insert.lsp") "ssg_ks_insert.lsp nicht gefunden")
@@ -39,7 +40,10 @@
(load (strcat base-path "Tro_Edit.lsp") "Tro_Edit.lsp nicht gefunden")
(load (strcat base-path "Connection_Edit.lsp") "Connection_Edit.lsp nicht gefunden")
(load (strcat base-path "SSG_LIB_Commands.lsp") "SSG_LIB_Commands.lsp nicht gefunden")
(prompt "\nSSG-Bibliotheken geladen: ssg_core, ssg_lang, ssg_dbg, ssg_dialog, ssg_layer, KreiselInsert, VarioFoerderer, Gefaellestrecke, export, OmniModulInsert, SSG_LIB_Commands")
;; Werkzeuge: ssg_texttools nutzt ssg_blocktools, beide nutzen ssg_input
(load (strcat base-path "ssg_blocktools.lsp") "ssg_blocktools.lsp nicht gefunden")
(load (strcat base-path "ssg_texttools.lsp") "ssg_texttools.lsp nicht gefunden")
(prompt "\nSSG-Bibliotheken geladen: ssg_core, ssg_lang, ssg_dbg, ssg_dialog, ssg_layer, ssg_input, KreiselInsert, VarioFoerderer, Gefaellestrecke, export, OmniModulInsert, SSG_LIB_Commands, ssg_blocktools, ssg_texttools")
(princ)
)
+285
View File
@@ -0,0 +1,285 @@
;; ============================================================
;; SSG_TEXTTOOLS.LSP - Text-Werkzeuge
;;
;; Ursprung: ACADSST/MENU/CHGTEXT.LSP (Suchen/Ersetzen), PARTEXT.LSP
;; (Tbpl: parallel beschriften), ALTHOEHE.LSP (Tsz), ALTSTIL.LSP (Ts).
;; Neu geschrieben im ssg-Stil (Undo-Gruppe, i18n, ssg-in-*).
;;
;; Befehle:
;; SSG_TEXT_ERSETZEN Zeichenketten in TEXT, MTEXT und Block-
;; Attributen suchen/ersetzen (mit Vorschau)
;; SSG_TEXT_PARALLEL Text parallel zu Linie/Polylinie/Bogen setzen
;; (lesbar ausgerichtet, mit Abstand zur Linie)
;; SSG_TEXT_HOEHE Texthoehe von TEXT/MTEXT aendern
;; SSG_TEXT_STIL Textstil von TEXT/MTEXT aendern
;;
;; Arbeitet in der XY-Ebene des Welt-KS (Textrotation = WKS-Winkel).
;; Setzt ssg_core.lsp, ssg_lang.lsp, ssg_input.lsp und ssg_blocktools.lsp
;; (ssg-bt-wert-neu, ssg-bt-attr-ersetzen-ent) voraus.
;; ============================================================
(vl-load-com)
;; ------------------------------------------------------------
;; REINE HILFSFUNKTIONEN (in test_unit getestet)
;; ------------------------------------------------------------
;; Winkel (Bogenmass) so drehen, dass ein Text lesbar bleibt: Winkel im
;; Bereich (90 Grad, 270 Grad] werden um 180 Grad gedreht. Ergebnis in
;; [0, 2*pi).
(defun ssg-tt-lesbarer-winkel (a)
(setq a (rem a (* 2.0 pi)))
(if (< a 0.0) (setq a (+ a (* 2.0 pi))))
(if (and (> a (+ (/ pi 2.0) 1e-9))
(<= a (+ (* 1.5 pi) 1e-9)))
(setq a (- a pi))
)
(if (< a 0.0) (setq a (+ a (* 2.0 pi))))
a
)
;; Punkt um abstand in Richtung winkel verschieben (2D, Z bleibt erhalten)
(defun ssg-tt-versetzt (p winkel abstand)
(list (+ (car p) (* abstand (cos winkel)))
(+ (cadr p) (* abstand (sin winkel)))
(if (caddr p) (caddr p) 0.0))
)
;; ------------------------------------------------------------
;; AUSWAHL
;; ------------------------------------------------------------
;; Auswahlsatz der angegebenen Typen holen (z.B. "TEXT,MTEXT,INSERT").
;; alle-p = T -> alle im aktuellen Layout, nil -> Benutzerwahl
(defun ssg-tt-ss-holen (alle-p typen)
(if alle-p
(ssget "_X" (list (cons 0 typen) (cons 410 (getvar "CTAB"))))
(ssget (list (cons 0 typen)))
)
)
;; Auswahlsatz -> Liste von Entity-Namen mit Typ-Filter ("TEXT" "MTEXT" ...)
(defun ssg-tt-ss-liste (ss typen / i ent res)
(if ss
(progn
(setq i 0)
(while (setq ent (ssname ss i))
(if (member (cdr (assoc 0 (entget ent))) typen)
(setq res (cons ent res))
)
(setq i (1+ i))
)
)
)
(reverse res)
)
;; ------------------------------------------------------------
;; SUCHEN / ERSETZEN
;; ------------------------------------------------------------
;; TEXT/MTEXT-Inhalte ersetzen (oder nur zaehlen). Rueckgabe: Anzahl Texte.
(defun ssg-tt-text-ersetzen-liste (ents suche ersatz teil-p probe-p
/ n obj alt neu)
(setq n 0)
(foreach ent ents
(setq obj (vlax-ename->vla-object ent)
alt (vla-get-textstring obj)
neu (ssg-bt-wert-neu alt suche ersatz teil-p))
(if neu
(if probe-p
(setq n (1+ n))
(if (not (vl-catch-all-error-p
(vl-catch-all-apply 'vla-put-textstring (list obj neu))))
(setq n (1+ n))
)
)
)
)
n
)
;; Texte + Attribute in einem Auswahlsatz ersetzen/zaehlen.
;; Rueckgabe: (anzahl-texte . anzahl-attribute)
(defun ssg-tt-ersetzen-ss (ss suche ersatz teil-p probe-p)
(cons
(ssg-tt-text-ersetzen-liste
(ssg-tt-ss-liste ss '("TEXT" "MTEXT")) suche ersatz teil-p probe-p)
(ssg-bt-attr-ersetzen-liste
(ssg-tt-ss-liste ss '("INSERT")) "*" suche ersatz teil-p probe-p)
)
)
(defun c:SSG_TEXT_ERSETZEN ( / k-bereich k-modus alle-p ss suche ersatz modus teil-p z)
(setq k-bereich (ssg-text "in-keys-bereich")
k-modus (ssg-text "in-keys-modus")
alle-p (= (ssg-in-keyword (ssg-text "tt-bereich") k-bereich
(ssg-in-first-word k-bereich))
(ssg-in-first-word k-bereich)))
(if (not alle-p) (prompt (ssg-text "tt-auswahl")))
(setq ss (ssg-tt-ss-holen alle-p "TEXT,MTEXT,INSERT"))
(if (null ss)
(prompt (ssg-text "tt-keine-objekte"))
(progn
(setq suche (ssg-in-string (ssg-text "tt-suche") nil))
(if (or (null suche) (= suche ""))
(prompt (ssg-text "tt-abgebrochen"))
(progn
(setq ersatz (ssg-in-string (ssg-text "tt-ersatz") "")
modus (ssg-in-keyword (ssg-text "tt-modus") k-modus
(ssg-in-first-word k-modus))
teil-p (= modus (ssg-in-first-word k-modus)))
(setq z (ssg-tt-ersetzen-ss ss suche ersatz teil-p T))
(cond
((= 0 (+ (car z) (cdr z))) (prompt (ssg-text "tt-nichts")))
((ssg-in-yesno (ssg-textf "tt-frage" (list (car z) (cdr z))) T)
(ssg-start (ssg-text "tt-ersetzen-titel") nil)
(setq z (ssg-tt-ersetzen-ss ss suche ersatz teil-p nil))
(ssg-end)
(prompt (ssg-textf "tt-ergebnis" (list (car z) (cdr z)))))
(t (prompt (ssg-text "tt-abgebrochen")))
)
)
)
)
)
(princ)
)
;; ------------------------------------------------------------
;; PARALLEL BESCHRIFTEN
;; ------------------------------------------------------------
;; Winkel der Kurve (Linie, Polylinie, Bogen, ...) am Punkt pt (WKS).
;; Rueckgabe: Winkel in Bogenmass oder nil, wenn nicht ermittelbar.
(defun ssg-tt-kurven-winkel (ent pt / obj cp param deriv)
(setq obj (vlax-ename->vla-object ent))
(setq cp (vl-catch-all-apply 'vlax-curve-getclosestpointto (list obj pt)))
(if (or (vl-catch-all-error-p cp) (null cp))
nil
(progn
(setq param (vl-catch-all-apply 'vlax-curve-getparamatpoint (list obj cp)))
(if (or (vl-catch-all-error-p param) (null param))
nil
(progn
(setq deriv (vl-catch-all-apply 'vlax-curve-getfirstderiv (list obj param)))
(if (or (vl-catch-all-error-p deriv) (null deriv))
nil
(list (atan (cadr deriv) (car deriv)) cp)
)
)
)
)
)
)
;; TEXT erzeugen (unten mittig, Gruppe 73 = 1 damit Gruppe 11 gilt)
(defun ssg-tt-text-machen (p hoehe string winkel)
(entmake (list '(0 . "TEXT")
(cons 8 (getvar "CLAYER"))
(cons 7 (getvar "TEXTSTYLE"))
(cons 10 p)
(cons 11 p)
(cons 40 hoehe)
(cons 1 string)
(cons 50 winkel)
(cons 72 1)
(cons 73 1)))
)
(defun c:SSG_TEXT_PARALLEL ( / sel info a ar p text)
(ssg-start (ssg-text "tt-parallel-titel") nil)
(if (or (null *ssg-tt-hoehe*) (<= *ssg-tt-hoehe* 0.0))
(setq *ssg-tt-hoehe* (if (> (getvar "TEXTSIZE") 0.0) (getvar "TEXTSIZE") 2.5))
)
(setq *ssg-tt-hoehe* (ssg-in-real (ssg-text "tt-hoehe") *ssg-tt-hoehe*))
(if (null *ssg-tt-abstand*)
(setq *ssg-tt-abstand* (* 0.5 *ssg-tt-hoehe*))
)
(setq *ssg-tt-abstand* (ssg-in-real (ssg-text "tt-abstand") *ssg-tt-abstand*))
(while (setq sel (entsel (ssg-text "tt-parallel-waehlen")))
(setq info (ssg-tt-kurven-winkel (car sel) (trans (cadr sel) 1 0)))
(if (null info)
(prompt (ssg-text "tt-parallel-keine-kurve"))
(progn
(setq a (car info)
ar (ssg-tt-lesbarer-winkel a)
p (ssg-tt-versetzt (cadr info) (+ ar (/ pi 2.0)) *ssg-tt-abstand*)
text (ssg-in-string (ssg-text "tt-text") *ssg-tt-text*))
(if (and text (/= text ""))
(progn
(setq *ssg-tt-text* text)
(if (not (ssg-tt-text-machen p *ssg-tt-hoehe* text ar))
(prompt (ssg-text "tt-parallel-fehler"))
)
)
)
)
)
)
(ssg-end)
(princ)
)
;; ------------------------------------------------------------
;; HOEHE / STIL AENDERN
;; ------------------------------------------------------------
(defun c:SSG_TEXT_HOEHE ( / ents hoehe n)
(prompt (ssg-text "tt-auswahl"))
(setq ents (ssg-tt-ss-liste (ssget '((0 . "TEXT,MTEXT"))) '("TEXT" "MTEXT")))
(if (null ents)
(prompt (ssg-text "tt-keine-objekte"))
(progn
(setq hoehe (ssg-in-real (ssg-text "tt-hoehe")
(if (> (getvar "TEXTSIZE") 0.0) (getvar "TEXTSIZE") nil)))
(if (or (null hoehe) (<= hoehe 0.0))
(prompt (ssg-text "tt-abgebrochen"))
(progn
(ssg-start (ssg-text "tt-hoehe-titel") nil)
(setq n 0)
(foreach ent ents
(if (not (vl-catch-all-error-p
(vl-catch-all-apply 'vla-put-height
(list (vlax-ename->vla-object ent) hoehe))))
(setq n (1+ n))
)
)
(ssg-end)
(prompt (ssg-textf "tt-geaendert" (list n)))
)
)
)
)
(princ)
)
(defun c:SSG_TEXT_STIL ( / ents stil n)
(prompt (ssg-text "tt-auswahl"))
(setq ents (ssg-tt-ss-liste (ssget '((0 . "TEXT,MTEXT"))) '("TEXT" "MTEXT")))
(if (null ents)
(prompt (ssg-text "tt-keine-objekte"))
(progn
(setq stil (ssg-in-string (ssg-text "tt-stil") (getvar "TEXTSTYLE")))
(cond
((or (null stil) (null (tblsearch "STYLE" stil)))
(prompt (ssg-textf "tt-stil-fehlt" (list (if stil stil "")))))
(t
(ssg-start (ssg-text "tt-stil-titel") nil)
(setq n 0)
(foreach ent ents
(if (not (vl-catch-all-error-p
(vl-catch-all-apply 'vla-put-stylename
(list (vlax-ename->vla-object ent) stil))))
(setq n (1+ n))
)
)
(ssg-end)
(prompt (ssg-textf "tt-geaendert" (list n))))
)
)
)
(princ)
)
(princ)
+229 -333
View File
@@ -80,6 +80,11 @@
;; Von den Menue-Wrappern gesetzt, damit die Konsolen-/Dialog-Frage
;; entfaellt. nil = interaktiv fragen (Direktaufruf VarioFoerderer).
(if (null *vf-vorauswahl-eingabemodus*) (setq *vf-vorauswahl-eingabemodus* nil))
;; Vorauswahl des Linienzug-Modus (1-5): von jedem der fuenf Linienzug-
;; Menue-Wrapper (c:LinienzugVarioFoerdererManuell/-Zielhoehe/-Stueckweise,
;; c:QcLinieMitGf/-UForm) gesetzt - der frueher hier noetige Modus-Dialog/
;; Konsolen-Fallback ist dadurch komplett entfallen (siehe c:VarioFoerderer).
(if (null *vf-vorauswahl-linienzug-modus*) (setq *vf-vorauswahl-linienzug-modus* nil))
;; Registriert einen Foerderanlagen-Typ.
;; berechne-fn: '(lambda (deltaL deltaH richtung seite) ...)
@@ -703,36 +708,23 @@
(setq i (1+ i)))
eingabe)
(defun vf-eingabe-abfragen ( / eingabe-modus line-points startpunkt endpunkt differenz
deltaL deltaH deltaX deltaY richtung antwort hz-winkel)
;; Eingabemodus: von einem Menue-Wrapper vorbelegt (dann keine Frage) oder
;; interaktiv. Die Vorauswahl gilt nur EINMAL und wird hier verbraucht,
;; damit ein spaeterer Direktaufruf wieder fragt.
(if *vf-vorauswahl-eingabemodus*
(setq antwort *vf-vorauswahl-eingabemodus*
*vf-vorauswahl-eingabemodus* nil)
;; 3D-Linie picken und daraus deltaL/deltaH/richtung/hz/startpunkt (inkl. Z)
;; ableiten - fuer den GUI-Ablauf (vf-dialog-ablauf): ersetzt dort die
;; separate Startpunkt-Auswahl UND liefert die Geometrie-Felder als Prefill
;; fuer den Basis-Dialog (vfs-dialog-eingabe-basis). Rueckgabe: (deltaL
;; deltaH richtung startpunkt hz) oder nil, wenn keine gueltige Linie
;; gewaehlt wurde (Aufrufer bricht dann ab, statt wie frueher per (exit)
;; die ganze Befehlssitzung zu beenden).
(defun vfc-3dlinie-erfassen ( / line-points startpunkt endpunkt differenz
deltaL deltaH deltaX deltaY richtung hz-winkel)
(princ (ssg-text "vfc-modus-3dlinie-header"))
(command "BKS" "W")
(princ (ssg-text "vfc-bks-weltkoordinaten"))
(setq line-points
(get-line-start-end-points (ssg-text "vfc-bitte-3dlinie-foerderstrecke")))
(if (null line-points)
(progn (alert (ssg-text "vfc-alert-keine-gueltige-linie")) nil)
(progn
(princ (ssg-text "vfc-eingabemodus-header"))
(princ (ssg-text "vfc-eingabemodus-3dlinie"))
(princ (ssg-text "vfc-eingabemodus-werte"))
(setq antwort (getstring (ssg-text "vfc-prompt-wahl-1-2-ohne-default")))
)
)
(cond
((= antwort "1") (setq eingabe-modus "Linie"))
((= antwort "2") (setq eingabe-modus "Wert"))
(t (setq eingabe-modus "Linie") (princ (ssg-text "vfc-modus-3dlinie-fallback")))
)
(if (= eingabe-modus "Linie")
(progn
(princ (ssg-text "vfc-modus-3dlinie-header"))
(command "BKS" "W")
(princ (ssg-text "vfc-bks-weltkoordinaten"))
(setq line-points
(get-line-start-end-points (ssg-text "vfc-bitte-3dlinie-foerderstrecke")))
(if (null line-points)
(progn (alert (ssg-text "vfc-alert-keine-gueltige-linie")) (exit))
)
(setq startpunkt (car line-points)
endpunkt (cadr line-points))
(setq differenz (punkt-differenz startpunkt endpunkt))
@@ -750,41 +742,14 @@
(progn (setq richtung "Ab") (setq deltaH (abs deltaH))
(princ (ssg-text "vfc-foerderrichtung-ab")))
)
)
(progn
(princ (ssg-text "vfc-modus-werteingabe-header"))
(setq deltaL (getreal (ssg-textf "vfc-prompt-delta-l" (list (chr 916)))))
(if (null deltaL) (setq deltaL 15000))
(setq deltaH (getreal (ssg-textf "vfc-prompt-delta-h" (list (chr 916)))))
(if (null deltaH) (setq deltaH 3000))
;; Foerderrichtung bleibt eine einfache Auf/Ab-Frage - die horizontale
;; Zwischenstrecke ist geometrisch NUR bei "Ab" ueberhaupt erreichbar
;; (die festen 3-Grad-Elemente wirken immer absenkend) und wird daher
;; erst SPAETER, nach Bibliotheks-Init, als Zusatzoption in der
;; Winkel-Auswahl angeboten (siehe c:VarioFoerderer) - einheitlich fuer
;; Werteingabe UND 3D-Linie.
(princ (ssg-text "vfc-foerderrichtung-menu"))
(setq antwort (getstring (ssg-text "vfc-prompt-wahl-1-2-ohne-default")))
(if (= antwort "2") (setq richtung "Ab") (setq richtung "Auf"))
(setq startpunkt (getpoint (ssg-text "vfc-prompt-startpunkt-aus")))
(if (null startpunkt) (setq startpunkt '(0 0 0)))
;; Horizontale Fahrtrichtung waehlen (analog Gefaellestrecke Modus 1)
(princ (ssg-text "vfc-fahrtrichtung-header"))
(princ (ssg-textf "vfc-fahrtrichtung-0" (list grad-zeichen)))
(princ (ssg-textf "vfc-fahrtrichtung-90" (list grad-zeichen)))
(princ (ssg-textf "vfc-fahrtrichtung-180" (list grad-zeichen)))
(princ (ssg-textf "vfc-fahrtrichtung-270" (list grad-zeichen)))
(setq antwort (getstring (ssg-text "prompt-wahl-1-2-3-4")))
(cond
((= antwort "2") (setq hz-winkel 90.0))
((= antwort "3") (setq hz-winkel 180.0))
((= antwort "4") (setq hz-winkel 270.0))
(t (setq hz-winkel 0.0))
)
(princ (ssg-textf "vfc-fahrtrichtung-ergebnis" (list (rtos hz-winkel 2 1) grad-zeichen)))
;; Einfuegehoehe (Z des Startpunkts) wird NICHT mehr hier auf der
;; Konsole abgefragt - sie geht als Prefill "einfuegehoehe" in den
;; Basis-Dialog (vfs-dialog-eingabe-basis) ein, der dasselbe Feld
;; ohnehin per GUI anzeigt und ueberschreibbar macht (Vorschlag = Z
;; des Linien-Startpunkts, wie zuvor beim getreal-Prompt).
(list deltaL deltaH richtung startpunkt hz-winkel)
)
)
(list deltaL deltaH richtung startpunkt hz-winkel eingabe-modus)
)
;; ============================================================
@@ -1055,26 +1020,144 @@
(list vf-insert vf-endpunkt)
)
;; Neuanlage (Menue/Konsole -> Dialog) fuer einen Registry-Typ: Startpunkt
;; (X/Y) picken, Basis-Dialog, dann vf-dialog-berechnen-einfuegen.
;; Startpunkt der Anlage per Dialog waehlen (Punktwahl-Button + Anzeige,
;; dcl/variofoerderer.dcl Tile vfc_startpunkt) - dasselbe "Schliessen-
;; Picken-Neu-Zeigen"-Muster wie der Linienzug-Wizard
;; (vflw-gruppe-punkt-hoehe-impl, vf_linienzug.lsp:697), aber ohne dessen
;; Wizard-Pending-Queue: der Punkt wird direkt zurueckgegeben. kopf/
;; pt_anzeige kommen per set_tile aus ssg-text - anders als
;; vfc-dialog-typ-waehlen also KEIN *ssg-lang*-Gate noetig, der Dialog
;; funktioniert in jeder Sprache. Rueckgabe: Punkt (Liste X Y Z) oder nil,
;; wenn kein Dialog gezeigt werden konnte/durfte (GUI aus) ODER abgebrochen
;; wurde - der Aufrufer (vf-dialog-ablauf) faellt dann auf den alten
;; Konsolen-getpoint zurueck.
(defun vfc-dialog-startpunkt-waehlen (kopf-key / dcl-pfad dat ergebnis gpunkt fertig)
(if (or (not (car (atoms-family 1 '("SSG-GUI-P")))) (ssg-gui-p))
(progn
(setq fertig nil)
(while (not fertig)
(setq dcl-pfad (strcat (getenv "DXFM_DCL") "/variofoerderer.dcl"))
(setq dat (load_dialog dcl-pfad))
(if (not (new_dialog "vfc_startpunkt" dat))
(progn
(if (and dat (>= dat 0)) (unload_dialog dat))
(setq fertig t gpunkt nil)
)
(progn
(set_tile "kopf" (ssg-text "vfc-dlg-startpunkt-kopf"))
(if gpunkt
(set_tile "pt_anzeige"
(strcat "X=" (rtos (car gpunkt) 2 1)
" Y=" (rtos (cadr gpunkt) 2 1)
" Z=" (rtos (caddr gpunkt) 2 1)))
)
(action_tile "pick" "(done_dialog 2)")
(action_tile "accept" "(done_dialog 1)")
(action_tile "cancel" "(done_dialog 0)")
(setq ergebnis (start_dialog))
(unload_dialog dat)
(cond
((= ergebnis 2) (setq gpunkt (getpoint (ssg-text kopf-key))))
((= ergebnis 1) (setq fertig t))
(t (setq fertig t gpunkt nil))
)
)
)
)
gpunkt
)
nil
)
)
;; Neuanlage (Menue/Konsole -> Dialog) fuer einen Registry-Typ. Zwei
;; Eingabemodi fuer die Geometrie (deltaL/deltaH/richtung/hz/Startpunkt):
;; "1" 3D-Linie: Linie picken (vfc-3dlinie-erfassen), die abgeleiteten
;; Werte gehen als Prefill in den Basis-Dialog - NUR Seite/
;; Motorseite/Darstellung/Geruest bleiben dort fuer den Anwender offen.
;; "2" Werte: wie bisher Startpunkt (X/Y) picken, Basis-Dialog ohne
;; Geometrie-Prefill (Defaults).
;; Eingabemodus kommt per Vorauswahl (Menue-Wrapper c:StandardVarioFoerderer3D
;; / c:EtageVarioFoerderer3D setzen *vf-vorauswahl-eingabemodus* "1"/"2") oder
;; wird - wie zuvor im Konsolen-Ablauf - interaktiv erfragt; die Vorauswahl
;; gilt nur einmal. Ersetzt den frueheren Rueckfall auf den rein interaktiven
;; Konsolen-Ablauf (vf-eingabe-abfragen, entfernt) fuer die 3D-Linie: dieser
;; lief komplett an der GUI vorbei und fragte Seite/Fahrtrichtung/etc. erneut
;; auf der Kommandozeile ab, obwohl der Basis-Dialog dieselben Felder laengst
;; per GUI anbietet.
(defun vf-dialog-ablauf (typ vf-nummer horizontal-p / eingabe deltaL deltaH richtung
z-start hz seite startpunkt startpunkt-xy dim
geruest-einzelmodul geruest-typ motorseite)
(setq startpunkt-xy (getpoint (ssg-text "vfc-prompt-startpunkt-aus")))
(if (null startpunkt-xy) (setq startpunkt-xy '(0 0 0)))
(setq eingabe (vfs-dialog-eingabe-basis nil))
(if (null eingabe)
geruest-einzelmodul geruest-typ motorseite
antwort dlg-modus linie-erg basis-prefill abbruch)
(setq abbruch nil)
(if *vf-vorauswahl-eingabemodus*
(setq antwort *vf-vorauswahl-eingabemodus*
*vf-vorauswahl-eingabemodus* nil)
(progn
(setq dlg-modus (vfc-dialog-eingabemodus-waehlen))
(cond
((eq dlg-modus 'ABBRUCH) (setq antwort "2" abbruch t))
(dlg-modus (setq antwort dlg-modus))
(t
;; Dialog nicht verfuegbar/nicht erlaubt (GUI aus, andere Sprache)
;; - alte Konsolen-Abfrage unveraendert.
(princ (ssg-text "vfc-eingabemodus-header"))
(princ (ssg-text "vfc-eingabemodus-3dlinie"))
(princ (ssg-text "vfc-eingabemodus-werte"))
(setq antwort (getstring (ssg-text "vfc-prompt-wahl-1-2-ohne-default")))
)
)
)
)
(if (not abbruch)
(if (= antwort "1")
(progn
(setq linie-erg (vfc-3dlinie-erfassen))
(if (null linie-erg)
(setq abbruch t)
(progn
(setq deltaL (nth 0 linie-erg)
deltaH (nth 1 linie-erg)
richtung (nth 2 linie-erg)
startpunkt (nth 3 linie-erg)
hz (nth 4 linie-erg))
(setq basis-prefill
(list (cons "deltaL" deltaL) (cons "deltaH" deltaH) (cons "richtung" richtung)
(cons "einfuegehoehe" (caddr startpunkt)) (cons "hz" hz)))
)
)
)
(progn
(setq startpunkt-xy (vfc-dialog-startpunkt-waehlen "vfc-prompt-startpunkt-aus"))
(if (null startpunkt-xy)
(setq startpunkt-xy (getpoint (ssg-text "vfc-prompt-startpunkt-aus"))))
(if (null startpunkt-xy) (setq startpunkt-xy '(0 0 0)))
(setq startpunkt startpunkt-xy)
(setq basis-prefill nil)
)
)
)
(if abbruch
(princ (ssg-text "vfc-vorgang-abgebrochen"))
(progn
(vf-basis-eingabe-entpacken eingabe)
(setq startpunkt (list (car startpunkt-xy) (cadr startpunkt-xy) z-start))
;; Gewaehlte Dimension (2D/3D) + Motorseite fuer den Bau erzwingen, danach zurueck.
(setq *ssg-ils-dim* dim)
(setq *vf-motorseite* motorseite)
(vf-dialog-berechnen-einfuegen typ vf-nummer deltaL deltaH richtung startpunkt hz seite nil
geruest-einzelmodul geruest-typ horizontal-p)
(setq *ssg-ils-dim* nil)
(setq *vf-motorseite* nil)
(setq eingabe (vfs-dialog-eingabe-basis basis-prefill))
(if (null eingabe)
(princ (ssg-text "vfc-vorgang-abgebrochen"))
(progn
(vf-basis-eingabe-entpacken eingabe)
;; X/Y kommen aus dem Linien-Startpunkt (Modus 1) oder der
;; separaten Punktwahl (Modus 2); Z immer aus dem Basis-Dialog
;; (dort vorbelegt, aber ueberschreibbar).
(setq startpunkt (list (car startpunkt) (cadr startpunkt) z-start))
;; Gewaehlte Dimension (2D/3D) + Motorseite fuer den Bau erzwingen, danach zurueck.
(setq *ssg-ils-dim* dim)
(setq *vf-motorseite* motorseite)
(vf-dialog-berechnen-einfuegen typ vf-nummer deltaL deltaH richtung startpunkt hz seite nil
geruest-einzelmodul geruest-typ horizontal-p)
(setq *ssg-ils-dim* nil)
(setq *vf-motorseite* nil)
)
)
)
)
)
@@ -1108,14 +1191,14 @@
)
;; ============================================================
;; TEIL 11b: DIALOG-AUSWAHL FUER TYP/LINIENZUG-MODUS (Radio-Buttons)
;; TEIL 11b: DIALOG-AUSWAHL FUER TYP (Radio-Buttons)
;; ============================================================
;; Ersetzen die beiden Konsolen-Listen am Anfang von c:VarioFoerderer durch
;; Radio-Button-Dialoge (dcl/variofoerderer.dcl, vfc_typ/vfc_linienzug_modus)
;; - alle Optionen sofort sichtbar statt Dropdown. WICHTIG: Radio-Button-
;; Ersetzt die Konsolen-Liste am Anfang von c:VarioFoerderer durch einen
;; Radio-Button-Dialog (dcl/variofoerderer.dcl, vfc_typ) - alle Optionen
;; sofort sichtbar statt Dropdown. WICHTIG: Radio-Button-
;; Labels sind im DCL fest auf Deutsch einprogrammiert (set_tile kann das
;; Label eines radio_button nicht setzen, nur den Zustand - siehe DCL-
;; Kommentar). Beide Funktionen geben deshalb nur dann etwas anderes als nil
;; Kommentar). Die Funktion gibt deshalb nur dann etwas anderes als nil
;; zurueck, wenn GUI erlaubt ist (Tests: ssg-gui-aus) UND Deutsch aktiv ist -
;; sonst faellt der Aufrufer automatisch auf die alte, vollstaendig
;; uebersetzte Konsolen-Liste zurueck (unveraendert im Code stehen
@@ -1161,35 +1244,30 @@
)
)
;; "Zurueck" springt zur Anlagen-Typ-Frage zurueck - Rueckgabe 'ZURUECK, vom
;; Aufrufer (c:VarioFoerderer) ausgewertet (dort erneuter Aufruf von
;; vfc-dialog-typ-waehlen statt hier lokal aufzuloesen).
(defun vfc-dialog-linienzug-modus-waehlen ( / dcl-pfad dat gmodus ergebnis)
;; Eingabemodus (3D-Linie / Werte manuell) per Dialog waehlen - ersetzt die
;; fruehere getstring-Konsolenabfrage in vf-dialog-ablauf. Gleiches Muster/
;; gleiche Einschraenkung wie vfc-dialog-typ-waehlen: nur bei aktiver GUI und
;; Deutsch, sonst nil (Aufrufer faellt dann auf die alte Konsolen-Abfrage
;; zurueck). Keine "Zurueck"-Taste noetig (direkt nach der Typ-Wahl, die
;; selbst schon ein "Zurueck" hat). Rueckgabe: "1" (3D-Linie), "2" (Werte)
;; oder 'ABBRUCH.
(defun vfc-dialog-eingabemodus-waehlen ( / dcl-pfad dat gmodus ergebnis)
(if (and (or (not (car (atoms-family 1 '("SSG-GUI-P")))) (ssg-gui-p))
(= *ssg-lang* "de_DE"))
(progn
(setq dcl-pfad (strcat (getenv "DXFM_DCL") "/variofoerderer.dcl"))
(setq dat (load_dialog dcl-pfad))
(if (not (new_dialog "vfc_linienzug_modus" dat))
(if (not (new_dialog "vfc_eingabemodus" dat))
(progn (if (and dat (>= dat 0)) (unload_dialog dat)) nil)
(progn
(set_tile "modus_1" "1")
(set_tile "modus_3dlinie" "1")
(action_tile "accept"
"(setq gmodus (cond ((= (get_tile \"modus_2\") \"1\") 2)
((= (get_tile \"modus_3\") \"1\") 3)
((= (get_tile \"modus_4\") \"1\") 4)
((= (get_tile \"modus_5\") \"1\") 5)
(t 1)))
"(setq gmodus (if (= (get_tile \"modus_werte\") \"1\") \"2\" \"1\"))
(done_dialog 1)")
(action_tile "cancel" "(done_dialog 0)")
(action_tile "back" "(done_dialog 2)")
(setq ergebnis (start_dialog))
(unload_dialog dat)
(cond
((= ergebnis 1) gmodus)
((= ergebnis 2) 'ZURUECK)
(t 'ABBRUCH)
)
(if (= ergebnis 1) gmodus 'ABBRUCH)
)
)
)
@@ -1200,20 +1278,14 @@
;; ============================================================
;; TEIL 12: DISPATCHER c:VarioFoerderer
;; ============================================================
;; Erzwungener QC-Modus (Linienzug-Modus 4/5, vfc-dialog-linienzug-modus-
;; waehlen/Konsolen-Fallback unten): "4"/"5" waehrend des naechsten
;; Erzwungener QC-Modus (Linienzug-Modus 4/5, siehe *vf-vorauswahl-linienzug-
;; modus* oben/c:QcLinieMitGf*): "4"/"5" waehrend des naechsten
;; vf-linienzug-modus-Laufs, sonst nil. Von vf-linienzug-modus (vf_linienzug.
;; lsp, spaeter geladen) gelesen/geleert - globale Vorab-Deklaration hier,
;; damit sie unabhaengig von der Lade-Reihenfolge existiert.
(if (not (boundp '*vfl-forciere-qc-modus*)) (setq *vfl-forciere-qc-modus* nil))
(defun c:VarioFoerderer ( / typ-eintr anlage-typ berechne-fn einfuege-fn
eingabe deltaL deltaH richtung startpunkt seite hz
eingabe-modus ergebnis ergebnis-liste gueltige-winkel
horizontal-info
best-winkel L_GF L_GF1 L_GF2 L_VF
idx eintrag wahl antwort verteilung-modus
n-scanner vf-nummer hoehe-von hoehe-bis lastEnt
staustrecke-basis vf-insert dlg-typ dlg-modus zurueck-zu-typ)
idx wahl vf-nummer dlg-typ zurueck-zu-typ)
(princ "\n=========================================")
(princ (ssg-text "vfc-banner-titel"))
@@ -1272,24 +1344,13 @@
;; Kette mit gemischten GF/VF-Segmenten), passt nicht in das berechne-fn/
;; einfuege-fn-Schema fuer ein einzelnes durchgehendes Segment - siehe
;; vf_linienzug.lsp. Dispatcht hier direkt und beendet den Standard-Ablauf.
;; Jeder Aufrufer (Menue-Wrapper c:LinienzugVarioFoerderer*/c:QcLinieMitGf*)
;; setzt *vf-vorauswahl-linienzug-modus* VOR dem Aufruf - der frueher
;; hier gefuehrte Modus-Dialog/Konsolen-Fallback ist dadurch entfallen.
(if (= anlage-typ "linienzug")
(progn
(setq dlg-modus (vfc-dialog-linienzug-modus-waehlen))
(cond
((eq dlg-modus 'ABBRUCH) (exit))
((eq dlg-modus 'ZURUECK) (setq zurueck-zu-typ t))
(dlg-modus (setq wahl dlg-modus))
(t
;; Dialog nicht verfuegbar/nicht erlaubt - alte Konsolen-Liste.
(princ (ssg-text "vfc-linienzug-modus-header"))
(princ (ssg-text "vfc-linienzug-modus-1"))
(princ (ssg-text "vfc-linienzug-modus-2"))
(princ (ssg-text "vfc-linienzug-modus-3"))
(princ (ssg-text "vfc-linienzug-modus-4"))
(princ (ssg-text "vfc-linienzug-modus-5"))
(setq wahl (getint (ssg-text "prompt-wahl-1-5")))
)
)
(setq wahl *vf-vorauswahl-linienzug-modus*
*vf-vorauswahl-linienzug-modus* nil)
(if (not zurueck-zu-typ)
(progn
;; Konsolen-Nummer -> interne Funktion:
@@ -1321,215 +1382,26 @@
(setq vf-nummer (vf-next-number))
(princ (ssg-textf "vfc-naechste-vf-nummer" (list (itoa vf-nummer))))
;; 2b. Standard- ODER Etage-Typ + Werteingabe -> DCL-Dialog
;; (dcl/variofoerderer.dcl; Standard: vfs-standard-dialog-ablauf in
;; vf_standard.lsp, Etage: vfe-etage-dialog-ablauf in vf_etage.lsp - beide
;; nutzen dieselben Dialoge vfs-dialog-eingabe-basis/-winkel-verteilung).
;; 3D-Linie-Eingabe und der Typ Linienzug bleiben unveraendert interaktiv
;; (fallen unten in den Konsolen-Ablauf, der die Eingabemodus-Frage erneut
;; stellt - siehe vf-eingabe-abfragen).
;; 2b. Standard- ODER Etage-Typ -> DCL-Dialog (dcl/variofoerderer.dcl;
;; Standard: vfs-standard-dialog-ablauf in vf_standard.lsp, Etage:
;; vfe-etage-dialog-ablauf in vf_etage.lsp - beide duenne Wrapper um
;; vf-dialog-ablauf). Die Eingabemodus-Frage (3D-Linie vs. Werte) stellt
;; vf-dialog-ablauf selbst, VOR dem Basis-Dialog - bei 3D-Linie gehen
;; deltaL/deltaH/Richtung/Einfuegehoehe als Prefill in denselben
;; Basis-Dialog ein, den auch die Werteingabe nutzt (siehe dortiger
;; Kopfkommentar). Damit entfaellt der fruehere rein interaktive
;; Konsolen-Ablauf (Schritte 3-11, vf-eingabe-abfragen) komplett - er lief
;; bei 3D-Linie an der GUI vorbei und fragte Seite/Fahrtrichtung/Verteilung
;; erneut auf der Kommandozeile ab, obwohl der Dialog dieselben Felder
;; laengst per GUI anbietet.
(if (member anlage-typ '("standard" "etage"))
(progn
;; Eingabemodus: Vorauswahl (Menue-Wrapper) hat Vorrang, sonst fragen.
(if *vf-vorauswahl-eingabemodus*
(setq antwort *vf-vorauswahl-eingabemodus*)
(progn
(princ (ssg-text "vfc-eingabemodus-header"))
(princ (ssg-text "vfc-eingabemodus-3dlinie"))
(princ (ssg-text "vfc-eingabemodus-werte"))
(setq antwort (getstring (ssg-text "vfc-prompt-wahl-1-2-ohne-default")))
)
)
(if (= antwort "2")
(progn
(if (= anlage-typ "etage")
(vfe-etage-dialog-ablauf vf-nummer)
(vfs-standard-dialog-ablauf vf-nummer))
(exit)
)
)
)
)
;; 3. Gemeinsame Eingabe (deltaL, deltaH, richtung, startpunkt) - richtung
;; steht bei beiden Eingabemodi (Werteingabe UND 3D-Linie) bereits fest.
(setq eingabe (vf-eingabe-abfragen))
(setq deltaL (nth 0 eingabe)
deltaH (nth 1 eingabe)
richtung (nth 2 eingabe)
startpunkt (nth 3 eingabe)
hz (nth 4 eingabe)
eingabe-modus (nth 5 eingabe))
;; 4. Seite-Auswahl (vor Berechnung, weil Etage-Typ sie fuer Geometrie braucht)
(princ (ssg-text "vfc-seite-header"))
(princ (ssg-text "vfc-seite-rechts"))
(princ (ssg-text "vfc-seite-links"))
(setq antwort (getstring (ssg-text "prompt-wahl-1-2")))
(if (= antwort "2") (setq seite "links") (setq seite "rechts"))
(princ (ssg-textf "vfc-seite-gewaehlt" (list seite)))
;; 5. Typ-spezifische Berechnung (init + Winkelsuche)
(setq ergebnis (apply berechne-fn (list deltaL deltaH richtung seite)))
(setq ergebnis-liste (cadddr ergebnis))
;; 5b. Horizontale Zwischenstrecke als Zusatzoption: geometrisch NUR bei
;; "Ab" ueberhaupt erreichbar (die festen 3-Grad-Elemente wirken immer
;; absenkend) - "Auf" wird deshalb gar nicht erst geprueft. Gilt einheitlich
;; fuer Werteingabe UND 3D-Linie, da richtung hier in jedem Fall feststeht.
;; Bibliothek ist durch den berechne-fn-Aufruf oben bereits initialisiert.
(if (and (= anlage-typ "standard") (= richtung "Ab"))
(progn
(setq horizontal-info (berechne-horizontale-mitte deltaL deltaH "Ab" nil))
(if (and horizontal-info (caddr horizontal-info))
(progn
(setq ergebnis-liste
(append ergebnis-liste
(list (list 0 (car horizontal-info) (cadr horizontal-info) T))))
(princ (ssg-textf "vfc-hinweis-horizontal-moeglich" (list (chr 176) (chr 916))))
)
(setq horizontal-info nil)
)
)
)
;; Konfiguration (nach ssg_core-Init verfuegbar).
(setq staustrecke-basis (ssg-cfg-or "vario" "staustrecke_basis" 1000))
;; 7. Gueltige Winkel ermitteln
(setq gueltige-winkel
(mapcar 'car
(vl-remove-if-not
(function (lambda (e) (and (nth 3 e)
(numberp (nth 1 e)) (numberp (nth 2 e))
(>= (nth 1 e) 0) (>= (nth 2 e) 0))))
ergebnis-liste)))
(if (null gueltige-winkel)
(progn
(alert (ssg-textf "vfc-alert-kein-winkel"
(list (chr 916) (rtos deltaL 2 0) (rtos deltaH 2 0) richtung)))
(if (= anlage-typ "etage")
(vfe-etage-dialog-ablauf vf-nummer)
(vfs-standard-dialog-ablauf vf-nummer))
(exit)
)
)
;; 8. Winkelauswahl (automatisch oder interaktiv)
;; Sentinel-Winkel 0 = horizontale Zwischenstrecke (Schritt 6/11 bei 0
;; Grad, Boegen fest auf_3/ab_3) - siehe berechne-horizontale-mitte.
(if (= (length gueltige-winkel) 1)
(progn
(setq best-winkel (car gueltige-winkel))
(setq eintrag (assoc best-winkel ergebnis-liste))
(setq L_GF (nth 1 eintrag) L_VF (nth 2 eintrag))
(if (= best-winkel 0)
(princ (ssg-text "vfc-einzige-variante-horizontal"))
(princ (ssg-textf "vfc-einziger-winkel" (list (itoa best-winkel) (chr 176))))
)
)
(progn
(princ (ssg-text "vfc-mehrere-winkel-header"))
(setq idx 1)
(foreach w gueltige-winkel
(setq eintrag (assoc w ergebnis-liste))
(if (= w 0)
(princ (ssg-textf "vfc-winkel-option-horizontal"
(list idx (chr 176)
(rtos (nth 1 eintrag) 2 1) (rtos (nth 2 eintrag) 2 1))))
(princ (ssg-textf "vfc-winkel-option"
(list idx (itoa w) (chr 176)
(rtos (nth 1 eintrag) 2 1) (rtos (nth 2 eintrag) 2 1))))
)
(setq idx (1+ idx))
)
(setq wahl (getint (ssg-textf "vfc-prompt-winkel-waehlen"
(list (length gueltige-winkel)))))
(if (or (null wahl) (< wahl 1) (> wahl (length gueltige-winkel)))
(setq wahl 1))
(setq best-winkel (nth (1- wahl) gueltige-winkel))
(setq eintrag (assoc best-winkel ergebnis-liste))
(setq L_GF (nth 1 eintrag) L_VF (nth 2 eintrag))
)
)
(princ "\n\n=========================================")
(if (= best-winkel 0)
(princ (ssg-textf "vfc-zus-horizontal"
(list (rtos L_GF 2 2) (rtos L_VF 2 2))))
(princ (ssg-textf "vfc-zus-winkel"
(list (itoa best-winkel) (chr 176) (rtos L_GF 2 2) (rtos L_VF 2 2))))
)
(princ "\n=========================================")
;; 9. L_GF Verteilung
(princ (ssg-text "vfc-gf-verteilung-header"))
(princ (ssg-text "vfc-gf-verteilung-1"))
(princ (ssg-text "vfc-gf-verteilung-2"))
(princ (ssg-text "vfc-gf-verteilung-3"))
(princ (ssg-text "vfc-gf-verteilung-4"))
(setq verteilung-modus (getstring (ssg-text "prompt-wahl-1-2-3-4")))
(if (= verteilung-modus "") (setq verteilung-modus "1"))
(cond
((= verteilung-modus "1")
(setq L_GF1 (/ L_GF 2.0) L_GF2 (/ L_GF 2.0)))
((= verteilung-modus "2")
(setq L_GF1 (float staustrecke-basis))
(setq L_GF2 (max 0.0 (- L_GF (float staustrecke-basis)))))
((= verteilung-modus "3")
(setq L_GF2 (float staustrecke-basis))
(setq L_GF1 (max 0.0 (- L_GF (float staustrecke-basis)))))
((= verteilung-modus "4")
(setq L_GF1 (getreal (ssg-textf "vfc-prompt-lgf1-vorne"
(list (rtos (/ L_GF 2.0) 2 2)))))
(if (null L_GF1) (setq L_GF1 (/ L_GF 2.0)))
(setq L_GF2 (max 0.0 (- L_GF L_GF1)))
(princ (ssg-textf "vfc-lgf2-hinten" (list (rtos L_GF2 2 2)))))
(t (setq L_GF1 (/ L_GF 2.0) L_GF2 (/ L_GF 2.0)))
)
(princ (ssg-textf "vfc-zus-lgf" (list (rtos L_GF1 2 2) (rtos L_GF2 2 2))))
;; Scanner-Anzahl wird nicht mehr abgefragt (Attribut ANZAHL_SCANNER bleibt 0).
(setq n-scanner 0)
;; 11. Bestaetigung
(princ (ssg-text "vfc-einfuegen-frage"))
(princ (ssg-text "vfc-einfuegen-optionen"))
(setq antwort (getstring (ssg-text "vfc-prompt-wahl-1-2-ohne-default")))
(if (= antwort "1")
(progn
;; Hoehenangaben fuer Attribute und Beschriftung
(setq hoehe-von (caddr startpunkt))
(setq hoehe-bis (cond
((= richtung "Auf") (+ hoehe-von deltaH))
((= richtung "Ab") (- hoehe-von deltaH))
(t hoehe-von)))
;; lastEnt VOR der Einfuegung merken
(setq lastEnt (ssg-lastent-ohne-attribute))
;; Typ-spezifische Einfuegung
(apply einfuege-fn
(list deltaL deltaH richtung best-winkel L_GF1 L_GF2 L_VF startpunkt seite hz))
;; Gemeinsame VF_*-Block-Erstellung
;; Geruest fuer Einzelmodul/Geruestoption sind in diesem interaktiven
;; Konsolen-Ablauf (Etage/Linienzug) nicht abfragbar - bleiben auf
;; Schema-Default (analog Kreisel: nur ueber Dialog editierbar).
(setq vf-insert
(vf-block-erstellen anlage-typ seite vf-nummer n-scanner
hoehe-von hoehe-bis deltaH deltaL L_VF L_GF1 L_GF2
richtung best-winkel startpunkt lastEnt hz
"0" "Schoenenberger Geruest"))
;; Standard- UND Etage-Bloecke aus dem interaktiven Konsolen-Ablauf mit der
;; SSG_VF_EDIT-XDATA markieren - sie sind (wie die Dialog-Variante) aus
;; Attributen + hz verlustfrei rekonstruierbar, also per Doppelklick
;; (c:VARIOFOERDERER_EDIT) editierbar. Linienzug bleibt unmarkiert.
(if (and vf-insert (member anlage-typ '("standard" "etage")))
(vf-edit-xdata-schreiben vf-insert anlage-typ hz))
(princ "\n=========================================")
)
(princ (ssg-text "vfc-vorgang-abgebrochen"))
)
nil
)
@@ -1540,7 +1412,6 @@
;; Menue-Wrapper: jeder feste Endpunkt der VarioFoerderer-Erzeugung ist
;; direkt aufrufbar (Typ + Eingabemodus vorbelegt, keine Rueckfrage).
;; Nur der Linienzug fragt intern noch Modus 1/2/3 (komplexer Fall).
;; Eingabemodus-Vorauswahl: "2" = Werte manuell (DCL-Dialog),
;; "1" = aus 3D-Linie (Linie picken).
@@ -1568,9 +1439,34 @@
(c:VarioFoerderer)
)
;; --- Linienzug (bleibt interaktiv: fragt Modus 1/2/3) ---
(defun c:LinienzugVarioFoerderer ()
(setq *vf-vorauswahl-typ* "linienzug")
;; --- Linienzug/Streckengruppe (Modus 1/2/3, Typ+Modus vorbelegt) ---
(defun c:LinienzugVarioFoerdererManuell ()
(setq *vf-vorauswahl-typ* "linienzug"
*vf-vorauswahl-linienzug-modus* 1)
(c:VarioFoerderer)
)
(defun c:LinienzugVarioFoerdererZielhoehe ()
(setq *vf-vorauswahl-typ* "linienzug"
*vf-vorauswahl-linienzug-modus* 2)
(c:VarioFoerderer)
)
(defun c:LinienzugVarioFoerdererStueckweise ()
(setq *vf-vorauswahl-typ* "linienzug"
*vf-vorauswahl-linienzug-modus* 3)
(c:VarioFoerderer)
)
;; --- QC-Linie (Linienzug-Modus 4/5, Typ+Modus vorbelegt) ---
;; Menue: ILS -> Gefaellestrecke (gehoeren inhaltlich dorthin, technisch
;; weiterhin ueber den Linienzug-Ablauf/*vfl-forciere-qc-modus* gebaut).
(defun c:QcLinieMitGf ()
(setq *vf-vorauswahl-typ* "linienzug"
*vf-vorauswahl-linienzug-modus* 4)
(c:VarioFoerderer)
)
(defun c:QcLinieMitGfUForm ()
(setq *vf-vorauswahl-typ* "linienzug"
*vf-vorauswahl-linienzug-modus* 5)
(c:VarioFoerderer)
)
+105 -23
View File
@@ -1033,7 +1033,17 @@
;; "Neue Linie: GF" - Separator VOR/NACH (2 Ja/Nein-Toggles in einem
;; Bildschirm). Siehe dcl/vf_linienzug_wizard.dcl (vflw_sep_gf).
(defun vflw-gruppe-sep-gf-impl ( / dat ergebnis gsepvor gsepnach)
;; es-folgt-sep: T, wenn dieses GF-Stueck das Kettenende MIT ES-Element ist
;; (gf-kettenende-antwort steht beim Aufruf schon fest, siehe Aufrufer) -
;; dann baut vfl-insert-es-element ohnehin IMMER seinen eigenen Separator
;; VOR dem ES-Block, ein zusaetzlicher "Separator NACH" waere ein zweiter,
;; direkt anschliessender Separator. Statt die Frage zu stellen und die
;; Antwort hinterher zu verwerfen (Nutzer-Feedback 2026-10-08: verwirrend),
;; wird die Kachel hier direkt deaktiviert+abgehakt - der bestehende
;; Konsolen-/Sicherheitsnetz-Pfad (siehe Aufrufer, "ueberschrieben"-Meldung)
;; bleibt UNVERAENDERT bestehen (deckt weiterhin den reinen Konsolen-Fall ab,
;; wo diese Dialog-Funktion gar nicht laeuft).
(defun vflw-gruppe-sep-gf-impl (es-folgt-sep / dat ergebnis gsepvor gsepnach)
(setq dat (load_dialog (vflw-dcl-pfad)))
(if (not (new_dialog "vflw_sep_gf" dat))
(if (and dat (>= dat 0)) (unload_dialog dat))
@@ -1041,6 +1051,7 @@
(set_tile "kopf" (vflw-clean (ssg-text "vfl-sep-gf-header")))
(set_tile "sepvor" "0")
(set_tile "sepnach" "0")
(if es-folgt-sep (mode_tile "sepnach" 1))
(action_tile "accept"
"(setq gsepvor (get_tile \"sepvor\")) (setq gsepnach (get_tile \"sepnach\")) (done_dialog 1)")
(action_tile "cancel" "(done_dialog 0)")
@@ -1516,11 +1527,11 @@
(princ))
;; "Naechstes Element waehlen" - Hauptmenue des Linienzug-Aufbaus (Modus 1).
;; Kettenanfang (frame=nil): alle 6 Optionen waehlbar, Vario-Kurve inklusive
;; (kann nur als allererstes Kettenglied gewaehlt werden - siehe Kommentar an
;; der Aufrufstelle). Sonst (Frame vorhanden): Vario-Kurve per mode_tile
;; deaktiviert, die uebrigen 5 Optionen behalten dieselbe Reihenfolge/
;; Bedeutung wie im Konsolen-Menue, nur ohne die Luecke. Pusht die
;; Kettenanfang (frame=nil): alle 5 Radio-Optionen waehlbar, Vario-Kurve
;; inklusive (kann nur als allererstes Kettenglied gewaehlt werden - siehe
;; Kommentar an der Aufrufstelle). Sonst (Frame vorhanden): Vario-Kurve per
;; mode_tile deaktiviert, die uebrigen 4 Optionen behalten dieselbe
;; Reihenfolge/Bedeutung wie im Konsolen-Menue, nur ohne die Luecke. Pusht die
;; POSITIONELLE Antwort ("1".."6" bzw. "1".."5"), identisch zur bisherigen
;; Konsolen-Nummerierung, damit Journal/Replay unveraendert bleiben - die
;; Radio-Buttons selbst tragen daher STABILE, kontextunabhaengige Keys
@@ -1531,9 +1542,20 @@
;; - eindeutig als VF erkannt (Startpunkt liegt auf einer bestehenden
;; VF-Kette) macht "GF-Bogen"/"Neue Linie: GF" als DIREKTE Fortsetzung keinen
;; Sinn (kein GF-Baustein wird an dieser Stelle einfach an ein VF-Teil
;; angeflanscht) - diese beiden Optionen werden dann ausgegraut. "Neue Linie
;; BIS Kettenende" bleibt immer waehlbar (hat ihre eigene GF/VF-Erkennung).
(defun vflw-gruppe-naechstes-element-impl (kettenanfang familie / dat ergebnis slot gwahl)
;; angeflanscht) - diese beiden Optionen werden dann ausgegraut.
;; as-eben-eingefuegt: T, wenn der Anwender die AS-Frage ("AS-Element
;; setzen?") explizit mit Ja beantwortet hat (as-vorhanden in
;; vf-linienzug-modus) - das AS-Element braucht danach zuerst ein GERADES
;; Segment (Linie-GF/Linie-VF/Horizontal-VF), eine horizontale Kurve direkt
;; im Anschluss (GF-Bogen/Vario-Kurve) ergibt keinen Sinn und wird ebenfalls
;; ausgegraut. Greift nur, wenn familie nicht schon "VF" ist (dort ist
;; wahl_gfbogen bereits deaktiviert); nil, wenn der Startpunkt automatisch
;; auf einer bestehenden Kette erkannt wurde (as-vorhanden dann ohnehin nil).
;; "Neue Linie BIS Kettenende" ist kein Radio mehr, sondern der eigene Button
;; "abschliessen" (done_dialog 3) - er setzt slot direkt auf 6 und ignoriert
;; die aktuelle Radio-Auswahl (hat ihre eigene GF/VF-Erkennung, bleibt daher
;; immer waehlbar, auch wenn GF-Bogen/Neue Linie: GF ausgegraut sind).
(defun vflw-gruppe-naechstes-element-impl (kettenanfang familie as-eben-eingefuegt / dat ergebnis slot gwahl)
(setq dat (load_dialog (vflw-dcl-pfad)))
(if (not (new_dialog "vflw_naechstes_element" dat))
(if (and dat (>= dat 0)) (unload_dialog dat))
@@ -1546,20 +1568,31 @@
(mode_tile "wahl_gfbogen" 1)
(mode_tile "wahl_liniegf" 1)
(set_tile "wahl_variokurve" "1")))
;; Unmittelbar nach einem explizit eingefuegten AS-Element ergibt eine
;; horizontale Kurve (GF-Bogen/Vario-Kurve) als DIREKTE Fortsetzung
;; keinen Sinn - das AS-Element braucht zuerst ein gerades Segment
;; (Linie-GF/Linie-VF/Horizontal-VF). Nur relevant am Kettenanfang und
;; nur, wenn nicht schon durch familie="VF" abgedeckt (dort ist
;; wahl_gfbogen bereits deaktiviert).
(if (and kettenanfang as-eben-eingefuegt (not (equal familie "VF")))
(progn
(mode_tile "wahl_gfbogen" 1)
(mode_tile "wahl_variokurve" 1)
(set_tile "wahl_liniegf" "1")))
(action_tile "accept"
"(setq slot (cond ((= (get_tile \"wahl_gfbogen\") \"1\") 1)
((= (get_tile \"wahl_variokurve\") \"1\") 2)
((= (get_tile \"wahl_linievf\") \"1\") 4)
((= (get_tile \"wahl_horizontalvf\") \"1\") 5)
((= (get_tile \"wahl_linieende\") \"1\") 6)
(t 3)))
(done_dialog 1)")
(action_tile "abschliessen" "(setq slot 6) (done_dialog 3)")
(action_tile "cancel" "(done_dialog 0)")
(action_tile "back" "(done_dialog 2)")
(setq ergebnis (start_dialog))
(unload_dialog dat)
(cond
((= ergebnis 1)
((or (= ergebnis 1) (= ergebnis 3))
(setq gwahl (if (or kettenanfang (<= slot 2)) slot (1- slot)))
(vflw-pending-push-all (list (itoa gwahl))))
((= ergebnis 2) (setq *vfl-wizard-abbruch-grund* "zurueck"))
@@ -6594,7 +6627,8 @@
(progn
(if (vfl-wizard-aktiv)
(vl-catch-all-apply 'vflw-gruppe-naechstes-element-impl
(list (null frame) (if (null frame) startpunkt-familie nil))))
(list (null frame) (if (null frame) startpunkt-familie nil)
(if (null frame) as-vorhanden nil))))
(if frame
(progn
(princ (ssg-text "vfl-menu-gf-bogen-1"))
@@ -7008,7 +7042,7 @@
(setq hz-neu (car (frame->hz-winkel frame)))
)
(setq rad3 (* gf-max-winkel (/ pi 180.0)))
(if (vfl-wizard-aktiv) (vl-catch-all-apply 'vflw-gruppe-sep-gf-impl nil))
(if (vfl-wizard-aktiv) (vl-catch-all-apply 'vflw-gruppe-sep-gf-impl (list (= gf-kettenende-antwort "1"))))
(princ (ssg-text "vfl-sep-vor-gf-frage"))
(princ (ssg-text "vfl-ja"))
(princ (ssg-text "vfl-nein"))
@@ -7050,9 +7084,16 @@
(if (> sep-anzahl 0)
(setq deltaH (max 0.0 (- deltaH (* sep-anzahl *vfk-separator-laenge* (sin rad3))))))
;; ES-Fussabdruck VORAB reservieren, siehe Kommentar bei
;; gf-kettenende-antwort oben.
;; gf-kettenende-antwort oben. ES bringt IMMER seinen eigenen
;; Separator mit (vfl-insert-es-element, siehe Kommentar oben
;; "bringt seinen eigenen Separator VOR dem ES-Block schon
;; mit") - dessen Hoehenanteil fehlte hier bisher komplett
;; (realer Bug, Nutzer-Meldung 2026-10-08: Kette baute zu lang/
;; zu tief, weil der automatische Kettenende-Separator anders
;; als die optionalen vor/nach-Separatoren oben NICHT reserviert
;; wurde).
(if (= gf-kettenende-antwort "1")
(setq deltaH (max 0.0 (- deltaH (abs ein-dz)))))
(setq deltaH (max 0.0 (- deltaH (* *vfk-separator-laenge* (sin rad3)) (abs ein-dz)))))
(if (vfl-wizard-aktiv)
(vl-catch-all-apply 'vflw-gruppe-gefaelle-impl
(list (vfl-gf-hoehe-vorschlag (caddr p-aktuell)) t nil)))
@@ -7116,7 +7157,7 @@
;; gepickten deltaL abgezogen, damit die Kette exakt am
;; gepickten Punkt endet statt danach ueberzustehen.
(setq rad3 (* gf-max-winkel (/ pi 180.0)))
(if (vfl-wizard-aktiv) (vl-catch-all-apply 'vflw-gruppe-sep-gf-impl nil))
(if (vfl-wizard-aktiv) (vl-catch-all-apply 'vflw-gruppe-sep-gf-impl (list (= gf-kettenende-antwort "1"))))
(princ (ssg-text "vfl-sep-vor-gf-frage"))
(princ (ssg-text "vfl-ja"))
(princ (ssg-text "vfl-nein"))
@@ -7139,9 +7180,15 @@
(if (> sep-anzahl 0)
(setq deltaL (- deltaL (* sep-anzahl *vfk-separator-laenge* (cos rad3)))))
;; ES-Fussabdruck VORAB reservieren, siehe Kommentar bei
;; gf-kettenende-antwort oben.
;; gf-kettenende-antwort oben. ES bringt IMMER seinen
;; eigenen Separator mit (vfl-insert-es-element) - dessen
;; Laenge fehlte hier bisher komplett (realer Bug,
;; Nutzer-Meldung 2026-10-08: Kette baute ca. 300mm*cos(w)
;; zu lang, weil der automatische Kettenende-Separator
;; anders als die optionalen vor/nach-Separatoren oben
;; NICHT reserviert wurde).
(if (= gf-kettenende-antwort "1")
(setq deltaL (- deltaL (abs ein-dx))))
(setq deltaL (- deltaL (* *vfk-separator-laenge* (cos rad3)) (abs ein-dx))))
(if (< deltaL 1.0)
(progn (princ (ssg-text "vfl-fehler-linie-zu-kurz")) (setq gf-ok nil)))
(if gf-ok
@@ -8985,6 +9032,12 @@
(princ (ssg-text "vfl-vwnb-titel"))
(princ "\n=========================================")
;; "Zurueck"/"Abbrechen"-Flag ganz am Anfang zuruecksetzen - identischer Fix
;; wie in vf-linienzug-modus/-modus2 (siehe dortiger Kommentar): sonst
;; wuerde ein von einem VORHERIGEN Lauf noch gesetztes Flag den allerersten
;; vfl-in-*-Aufruf dieses NEUEN Laufs sofort wieder abbrechen.
(setq *vfl-wizard-abbruch-grund* nil)
;; --- Debug-Session (Schalter "vfl-modus3", DEFAULT AN) -------------------
;; Bei Bedarf abschaltbar: (dbg-schalter-off "vfl-modus3") in der Konsole.
;; Alle interaktiven Eingaben (Punkte, Hoehen, Seiten, Winkel, Menue-
@@ -9503,6 +9556,7 @@
nonclimber-cnt nkurve kurve-chords run-span
hor-koerper-len hor-pairs flat-p flat-zone-erste fill-len wahl3
rad3v feste-vf dH-adj dir-x dir-y fill-D end-hz
laengs-wert quer-wert soll-korrigiert
es-vek-fix es-along-fix
gf-total br-gf-mode br-gf2-exp filler-A-len filler-a-done
as-vorhanden es-vorhanden dbg-an dbg-old-error
@@ -9512,6 +9566,16 @@
(princ (ssg-text "vfl-m3-titel"))
(princ "\n=========================================")
;; "Zurueck"/"Abbrechen"-Flag ganz am Anfang zuruecksetzen (auch schon vor
;; der ersten Praeambel-Frage) - sonst wuerde ein von einem VORHERIGEN Lauf
;; (egal ob Modus 1/2/3) noch gesetztes Flag (z.B. nach "Abbrechen") den
;; allerersten vfl-in-*-Aufruf DIESES NEUEN Laufs sofort wieder abbrechen
;; (siehe zentraler Check in vfl-in-value/-value-p) - identischer Fix wie in
;; vf-linienzug-modus (Modus 1). Realer Bug: ein zweiter Modus-2-Aufruf in
;; derselben Zeichnung/Session brach sofort mit "ABBRUCH-TRIGGER:
;; *vfl-wizard-abbruch-grund*=abbrechen" ab, ohne ueberhaupt die
;; Pfad-Auswahl anzuzeigen (Livetest 2026-09-21).
(setq *vfl-wizard-abbruch-grund* nil)
;; *vfl-journal* VOR dem allerersten vfl-in-*-Aufruf zuruecksetzen (nicht
;; *vfl-replay-queue*, siehe Kommentar bei vfl-journal-reset-lauf und die
;; analoge Korrektur in vf-linienzug-modus). Frueher stand dieser Reset erst
@@ -10304,12 +10368,30 @@
;; ~0 sein (Endpunkt liegt auf der KS_AUS-Achse), Laengs = ES-Ausladung.
(setq end-hz (car (frame->hz-winkel frame))) ; KS_AUS-Achsrichtung
(setq dir-x (cos (* end-hz (/ pi 180.0))) dir-y (sin (* end-hz (/ pi 180.0))))
(princ (ssg-textf "vfl-m3-laengs-quer"
(list (rtos (+ (* (- (car ist-ende) (car soll-ende)) dir-x)
(* (- (cadr ist-ende) (cadr soll-ende)) dir-y)) 2 1)
(rtos (+ (* (- (car ist-ende) (car soll-ende)) (- dir-y))
(* (- (cadr ist-ende) (cadr soll-ende)) dir-x)) 2 1))))
(setq laengs-wert (+ (* (- (car ist-ende) (car soll-ende)) dir-x)
(* (- (cadr ist-ende) (cadr soll-ende)) dir-y)))
(setq quer-wert (+ (* (- (car ist-ende) (car soll-ende)) (- dir-y))
(* (- (cadr ist-ende) (cadr soll-ende)) dir-x)))
(princ (ssg-textf "vfl-m3-laengs-quer" (list (rtos laengs-wert 2 1) (rtos quer-wert 2 1))))
(princ (ssg-text "vfl-m3-achse-hinweis"))
;; Soll (ES-korrigiert): der gepickte Zielpunkt, verschoben um den bereits
;; oben gemessenen Laengs-Wert entlang der KS_AUS-Achse - zeigt, dass die
;; Abweichung oben keine Unsicherheit ist, sondern GENAU der ES-eigene
;; Fussabdruck (90/30-Grad-Schwenk, siehe doc/VarioFoerderer_Linienzug_
;; Prinzipien.md Abschnitt 6/14.11: "seitliche ES-Ausladung, kein Fehler").
;; Bewusst aus dem bereits gemessenen Laengs-Wert abgeleitet statt ueber
;; eine zweite, eigenstaendige vf-element-ks-info-Neuberechnung - das waere
;; ein zweiter Rechenweg fuer dieselbe Information mit eigenem Bug-Risiko,
;; hier reicht die Umkehrung der bereits validierten Laengs/Quer-Zerlegung.
(setq soll-korrigiert (list (+ (car soll-ende) (* laengs-wert dir-x))
(+ (cadr soll-ende) (* laengs-wert dir-y))
(caddr soll-ende)))
(princ (ssg-textf "vfl-m3-ziel-soll-es-korrigiert"
(list (rtos (car soll-korrigiert) 2 1) (rtos (cadr soll-korrigiert) 2 1) (rtos (caddr soll-korrigiert) 2 1))))
(princ (ssg-textf "vfl-m3-abweichung-es-korrigiert"
(list (rtos (- (car ist-ende) (car soll-korrigiert)) 2 1)
(rtos (- (cadr ist-ende) (cadr soll-korrigiert)) 2 1)
(rtos (- (caddr ist-ende) (caddr soll-korrigiert)) 2 1))))
(princ "\n=========================================")
(if dbg-an
+22 -9
View File
@@ -1,7 +1,7 @@
;; ============================================================
;; vf_spec.lsp - VF-Linienzug aus Eingabedaten bauen (ohne GUI/Konsole)
;; ============================================================
;; Stufe 1 des Fahrplans in doc/TODO-plan-vf-interactive.md.
;; Stufe 1 des Fahrplans in doc/todo/plan-vf-interactive.md.
;;
;; Eine SPEC beschreibt eine Kette in Domaenenwerten ("links", "winkel",
;; "aussen", ja/nein) statt in Menue-Codes: lesbar, schreibbar, versionierbar.
@@ -903,15 +903,28 @@
;; abgebrochene Kette bleibt also als lose Geometrie liegen und ist per
;; c:VF_SEKTION_RESTORE rettbar (vfl-segment-xdata-sichern hat pro Iteration
;; schon SSG_VF_EDIT_SEG/_PRE geschrieben).
(defun vsp-bau-aus-spec (spec / kopf sid journal rec vor-ent alt-error err
offen hl meld ist-glieder soll-glieder diff
ist-journal jdiff ent ed dim)
(defun vsp-bau-aus-spec (spec / kopf journal)
(setq kopf (vsp-kopf spec))
(setq sid (vsp-spec-id kopf))
;; vsp-journal sammelt seine Fehler in *vsp-fehler* - darum erst danach lesen.
(setq journal (vsp-journal spec))
(vsp-bau-journal (vsp-spec-id kopf) journal (ssg-val kopf "dim") *vsp-fehler*))
;; Eine Kette aus einem fertigen Eingabe-Journal bauen (Liste (art . wert) in
;; Bau-Reihenfolge, wie vfl-journal-replay-start sie erwartet). Gemeinsamer
;; Kern fuer Specs (vsp-bau-aus-spec, Journal per vsp-journal uebersetzt) und
;; fuer UNVERAENDERT uebernommene Aufzeichnungen - z.B. die SSG_VF_EDIT-XDATA
;; eines von Hand gebauten VF_n (tests/test_dematic_arvato.lsp, Journal per
;; vfl-string->entry gelesen). Letztere brauchen keinen Uebersetzer und
;; laufen darum auch dann, wenn der Dialog neuer ist als die Spec-Grammatik.
;; sid = Kennung im Record, dim = "2D"/"3D" oder nil (Sitzung),
;; fehler = Liste der Spec-Fehler (bei nil-Journal die Begruendung).
;; Erwartet den Headless-Rahmen (vsp-headless-an) beim Aufrufer.
(defun vsp-bau-journal (sid journal dim fehler / rec vor-ent alt-error err
offen hl meld ist-glieder soll-glieder diff
ist-journal jdiff ent ed)
(setq soll-glieder (if journal (vfl-journal-glieder journal) nil))
(setq rec (vsp-rec-neu sid))
(setq rec (vsp-set rec "spec_fehler" *vsp-fehler*))
(setq rec (vsp-set rec "spec_fehler" fehler))
(setq rec (vsp-set rec "glieder_soll" soll-glieder))
(setq rec (vsp-set rec "eingaben_gesamt" (if journal (length journal) 0)))
(princ (strcat "\n [SPEC] " sid))
@@ -919,9 +932,9 @@
(cond
;; --- Spec fehlerhaft: nichts bauen ---
((null journal)
(princ (strcat "\n " (itoa (length *vsp-fehler*))
(princ (strcat "\n " (itoa (length fehler))
" Spec-Fehler, nichts gebaut:"))
(foreach f *vsp-fehler* (princ (strcat "\n - " f)))
(foreach f fehler (princ (strcat "\n - " f)))
(setq rec (vsp-set rec "status" "spec-fehler"))
(setq rec (vsp-set rec "dimension" (vsp-dim-text)))
rec)
@@ -934,7 +947,7 @@
;; Feld in der Spec. Ist keines gesetzt, gilt die Sitzung.
(setq dim (if (and (boundp '*vsp-dim-override*) *vsp-dim-override*)
*vsp-dim-override*
(ssg-val kopf "dim")))
dim))
(if dim (setq *ssg-ils-dim* dim))
(setq rec (vsp-set rec "dimension" (vsp-dim-text)))
(princ (strcat " -> " (itoa (length journal)) " Journal-Eintraege, "
+310 -29
View File
@@ -803,11 +803,26 @@
;; ============================================================
;; DCL-DIALOG (Standardfall) - dcl/variofoerderer.dcl
;; Ersetzt die interaktive Werteingabe aus vf-eingabe-abfragen
;; (Konsolen-Modus "Werteingabe") fuer anlage-typ "standard" durch
;; zwei DCL-Dialoge: Basis-Eingabe und Winkel/Verteilung. Die
;; 3D-Linie-Eingabe sowie die Typen "etage"/"linienzug" bleiben
;; unveraendert interaktiv (siehe Verzweigung in c:VarioFoerderer).
;; Ersetzt die frueher komplett interaktive Werteingabe fuer anlage-typ
;; "standard" durch zwei DCL-Dialoge: Basis-Eingabe und Winkel/Verteilung.
;; Beide Eingabemodi (3D-Linie UND Werteingabe, siehe vf-dialog-ablauf in
;; vf_core.lsp) laufen seitdem ueber denselben Basis-Dialog - bei 3D-Linie
;; nur mit deltaL/deltaH/Richtung/Einfuegehoehe vorbelegt. Nur der Typ
;; "linienzug" bleibt unveraendert interaktiv (siehe Verzweigung in
;; c:VarioFoerderer).
;;
;; Beide Dialoge existieren je in zwei Varianten:
;; -popup (Dropdowns, urspruengliche Implementierung, unveraendert) und
;; -radio (Radio-Buttons statt Dropdown). Radio-Button-Labels lassen sich
;; nach new_dialog nicht per set_tile aendern (DCL-Limitierung) - die
;; -radio-Varianten loesen das, indem sie ihre DCL-Datei bei JEDEM Aufruf
;; frisch per ssg-dcl-temp-schreiben (ssg_core.lsp) schreiben und die
;; Labels dabei direkt mit dem schon von ssg-text/ssg-textf aufgeloesten
;; String befuellen - funktioniert dadurch in jeder Sprache, keine
;; Sprachweiche noetig (anders als vfc-dialog-typ-waehlen). Die
;; namenlosen Dispatcher-Funktionen (ohne Suffix) bevorzugen -radio und
;; fallen nur bei einem technischen Fehler (Temp-Datei nicht schreibbar/
;; ladbar, Sentinel 'FEHLER) auf -popup zurueck.
;; ============================================================
;; Bau-Parameter eines bestehenden VF_n-Blocks aus XDATA + Attributen lesen -
@@ -846,14 +861,76 @@
(cons "hz" hz)
(cons "z-start" z-start)))
;; Basis-Eingabe (Dialog 1): deltaL, deltaH, Richtung, Einfuegehoehe,
;; Fahrtrichtung, Seite, Geruest fuer Einzelmodul, Geruestoption.
;; Baut die DCL-Zeilen einer boxed_radio_column mit einem radio_button pro
;; Eintrag in "labels" (Tile-Keys "<prefix>_0".."<prefix>_(n-1)"). labels
;; sind bereits fertige, uebersetzte Strings (ssg-text/ssg-textf) - werden
;; hier nur noch fuer die DCL-Syntax escaped (ssg-dcl-label-escape).
;; Genutzt von vfs-dialog-eingabe-basis-radio fuer die drei verbleibenden
;; Radio-Gruppen (Seite, Motorseite, Geruestoption).
(defun vfs-dcl-radio-gruppe-zeilen (prefix box-label labels / zeilen i)
(setq zeilen (list
": boxed_radio_column {"
(strcat " label = \"" (ssg-dcl-label-escape box-label) "\";")
(strcat " key = \"" prefix "\";")))
(setq i 0)
(foreach lbl labels
(setq zeilen (append zeilen (list
(strcat " : radio_button { key = \"" prefix "_" (itoa i) "\"; label = \""
(ssg-dcl-label-escape lbl) "\"; }"))))
(setq i (1+ i))
)
(append zeilen (list "}"))
)
;; Baut das (cond ...)-Fragment (als String), das innerhalb eines
;; action_tile-Callbacks den gewaehlten Index 0..(n-1) einer per
;; vfs-dcl-radio-gruppe-zeilen erzeugten Gruppe ermittelt. n ist die
;; tatsaechliche Options-Anzahl zum Generierungszeitpunkt - dadurch bleibt
;; z.B. die Geruesttyp- oder Winkel-Gruppe korrekt, auch wenn deren Anzahl
;; sich einmal aendert (kein hartkodiertes "_1"/"_2"/"_3" im Aufrufer).
(defun vfs-dcl-radio-idx-cond (prefix n / s i)
(setq s "(cond " i 1)
(while (< i n)
(setq s (strcat s "((= (get_tile \"" prefix "_" (itoa i) "\") \"1\") " (itoa i) ")"))
(setq i (1+ i))
)
(strcat s "(t 0))")
)
;; L_GF1/L_GF2 aus dem gewaehlten Verteilungsmodus ("0".."3") berechnen -
;; gemeinsam genutzt von der Popup- UND der Radio-Variante von
;; vfs-dialog-winkel-verteilung (frueher inline in beiden dupliziert).
;; Rueckgabe: (L_GF1 L_GF2).
(defun vfs-verteilung-berechnen (verteilung-modus L_GF staustrecke-basis lgf1-manuell-str /
L_GF1 L_GF2)
(cond
((= verteilung-modus "0")
(setq L_GF1 (/ L_GF 2.0) L_GF2 (/ L_GF 2.0)))
((= verteilung-modus "1")
(setq L_GF1 (float staustrecke-basis))
(setq L_GF2 (max 0.0 (- L_GF (float staustrecke-basis)))))
((= verteilung-modus "2")
(setq L_GF2 (float staustrecke-basis))
(setq L_GF1 (max 0.0 (- L_GF (float staustrecke-basis)))))
((= verteilung-modus "3")
(setq L_GF1 (atof lgf1-manuell-str))
(if (or (null L_GF1) (< L_GF1 0)) (setq L_GF1 (/ L_GF 2.0)))
(if (> L_GF1 L_GF) (setq L_GF1 L_GF))
(setq L_GF2 (max 0.0 (- L_GF L_GF1))))
(t (setq L_GF1 (/ L_GF 2.0) L_GF2 (/ L_GF 2.0)))
)
(list L_GF1 L_GF2)
)
;; Basis-Eingabe (Dialog 1, Popup-Variante): deltaL, deltaH, Richtung,
;; Einfuegehoehe, Fahrtrichtung, Seite, Geruest fuer Einzelmodul,
;; Geruestoption.
;; prefill: Assoziationsliste zur Vorbelegung (fuer VARIOFOERDERER_EDIT) mit
;; Schluesseln "deltaL" "deltaH" "richtung" "einfuegehoehe" "hz" "seite"
;; "geruest-einzelmodul" "geruest-typ" - oder nil fuer Neuanlage mit Defaults.
;; Rueckgabe: (deltaL deltaH richtung einfuegehoehe hz seite
;; geruest-einzelmodul geruest-typ) oder nil bei Abbruch.
(defun vfs-dialog-eingabe-basis (prefill / dcl-pfad dat ergebnis
(defun vfs-dialog-eingabe-basis-popup (prefill / dcl-pfad dat ergebnis
dlg-deltal dlg-deltah dlg-richtung dlg-hoehe
dlg-fahrtrichtung dlg-seite dlg-motorseite dlg-dimension
dlg-geruest-einzelmodul dlg-geruest-typ
@@ -973,17 +1050,189 @@
)
)
;; Winkel/Verteilung-Eingabe (Dialog 2): Winkel-Popup aus den vorher
;; Basis-Eingabe (Dialog 1, dynamische Variante) - siehe Kopfkommentar
;; des DCL-DIALOG-Abschnitts. Nur "Seite", "Motorseite" und "Geruestoption"
;; bleiben als Radio-Button-Gruppen (alle Optionen sofort sichtbar); alle
;; anderen Felder (Foerderrichtung, Fahrtrichtung, Darstellung 2D/3D) sind
;; wieder Comboboxen (popup_list), wie der uebrige Dialog. Gleiche
;; prefill-Struktur/Rueckgabe wie -popup; 'FEHLER bei technischem Fehler
;; (Dispatcher faellt dann zurueck).
(defun vfs-dialog-eingabe-basis-radio (prefill / zeilen dcl-pfad dat ergebnis
dlg-deltal dlg-deltah dlg-hoehe
dlg-richtung-idx dlg-fahrt-idx dlg-seite-idx
dlg-motorseite-idx dlg-dim-idx
dlg-geruest-einzelmodul dlg-geruest-typ-idx
deltaL deltaH richtung hz seite z-start dim
motorseite geruest-einzelmodul geruest-typ
sel-richtung sel-fahrt sel-seite sel-motorseite
sel-dim sel-geruest-typ n-geruest-typ)
;; Vorbelegte Auswahl-Indizes aus prefill ableiten - gleiche Logik wie
;; -popup, nur als Index statt als Popup-Tile-Wert.
(setq sel-richtung
(if (and prefill (equal (cdr (assoc "richtung" prefill)) "Ab")) 1 0))
(setq sel-fahrt
(if prefill
(cond ((equal (cdr (assoc "hz" prefill)) 90.0 0.1) 1)
((equal (cdr (assoc "hz" prefill)) 180.0 0.1) 2)
((equal (cdr (assoc "hz" prefill)) 270.0 0.1) 3)
(t 0))
0))
(setq sel-seite
(if (and prefill (equal (cdr (assoc "seite" prefill)) "links")) 1 0))
(setq sel-motorseite
(if (and prefill (equal (cdr (assoc "motorseite" prefill)) "links")) 1 0))
(setq sel-dim
(if (equal (cond ((cdr (assoc "dim" prefill))) ((ssg-ils-dim-aktuell))) "2D") 1 0))
(setq n-geruest-typ (length *ssg-geruest-optionen*))
(setq sel-geruest-typ
(ssg-geruest-typ-to-idx (if prefill (cdr (assoc "geruest-typ" prefill)) nil)))
(setq zeilen (list
"vfs_basis_dyn : dialog {"
" label = \"VarioFoerderer (Standard) - Eingabe\";"
" : column {"
" : boxed_column {"
" label = \"Geometrie\";"
" : row {"
" : edit_box { key = \"deltal\"; label = \"Horizontale Distanz deltaL (mm):\"; edit_width = 10; }"
" : popup_list { key = \"richtung\"; label = \"Foerderrichtung:\"; width = 16; }"
" }"
" : row {"
" : edit_box { key = \"einfuegehoehe\"; label = \"Einfuegehoehe (mm):\"; edit_width = 10; }"
" : edit_box { key = \"deltah\"; label = \"Hoehenunterschied deltaH (mm):\"; edit_width = 10; }"
" }"
" }"
" : boxed_column {"
" label = \"Ausrichtung\";"
" : popup_list { key = \"fahrtrichtung\"; label = \"Fahrtrichtung:\"; width = 30; }"
" : row {"))
(setq zeilen (append zeilen
(vfs-dcl-radio-gruppe-zeilen "seite" "Seite:"
(list (ssg-text "gf-dlg-rechts") (ssg-text "gf-dlg-links")))))
(setq zeilen (append zeilen
(vfs-dcl-radio-gruppe-zeilen "motorseite" "Motorseite:"
(list (ssg-text "gf-dlg-rechts") (ssg-text "gf-dlg-links")))))
(setq zeilen (append zeilen (list
" }"
" : popup_list { key = \"dimension\"; label = \"Darstellung (2D/3D):\"; width = 20; }"
" }"
" : boxed_column {"
" label = \"Geruest\";"
" : toggle { key = \"geruest_einzelmodul\"; label = \"Geruest fuer Einzelmodul\"; }")))
(setq zeilen (append zeilen
(vfs-dcl-radio-gruppe-zeilen "geruest_typ" "Geruestoption:" *ssg-geruest-optionen*)))
(setq zeilen (append zeilen (list
" }"
" }"
" ok_cancel;"
"}")))
(setq dcl-pfad (ssg-dcl-temp-schreiben "vfsbasis" zeilen))
(if (null dcl-pfad)
'FEHLER
(progn
(setq dat (load_dialog dcl-pfad))
(if (not (new_dialog "vfs_basis_dyn" dat))
(progn
(if (and dat (>= dat 0)) (unload_dialog dat))
(vl-file-delete dcl-pfad)
'FEHLER
)
(progn
(set_tile "deltal" (if prefill (rtos (cdr (assoc "deltaL" prefill)) 2 0) "15000"))
(set_tile "deltah" (if prefill (rtos (cdr (assoc "deltaH" prefill)) 2 0) "3000"))
(set_tile "einfuegehoehe" (if prefill (rtos (cdr (assoc "einfuegehoehe" prefill)) 2 1) "0"))
(start_list "richtung")
(add_list (ssg-text "vfs-dlg-richtung-auf"))
(add_list (ssg-text "vfs-dlg-richtung-ab"))
(end_list)
(set_tile "richtung" (itoa sel-richtung))
(start_list "fahrtrichtung")
(add_list (ssg-textf "gf-dlg-richtung-0" (list grad-zeichen)))
(add_list (ssg-textf "gf-dlg-richtung-90" (list grad-zeichen)))
(add_list (ssg-textf "gf-dlg-richtung-180" (list grad-zeichen)))
(add_list (ssg-textf "gf-dlg-richtung-270" (list grad-zeichen)))
(end_list)
(set_tile "fahrtrichtung" (itoa sel-fahrt))
(set_tile (strcat "seite_" (itoa sel-seite)) "1")
(set_tile (strcat "motorseite_" (itoa sel-motorseite)) "1")
(start_list "dimension")
(add_list "3D")
(add_list "2D")
(end_list)
(set_tile "dimension" (itoa sel-dim))
(set_tile "geruest_einzelmodul"
(if (or (null prefill) (equal (cdr (assoc "geruest-einzelmodul" prefill)) "1")) "1" "0"))
(set_tile (strcat "geruest_typ_" (itoa sel-geruest-typ)) "1")
(action_tile "accept"
(strcat
"(setq dlg-deltal (get_tile \"deltal\"))"
"(setq dlg-deltah (get_tile \"deltah\"))"
"(setq dlg-hoehe (get_tile \"einfuegehoehe\"))"
"(setq dlg-richtung-idx (atoi (get_tile \"richtung\")))"
"(setq dlg-fahrt-idx (atoi (get_tile \"fahrtrichtung\")))"
"(setq dlg-seite-idx " (vfs-dcl-radio-idx-cond "seite" 2) ")"
"(setq dlg-motorseite-idx " (vfs-dcl-radio-idx-cond "motorseite" 2) ")"
"(setq dlg-dim-idx (atoi (get_tile \"dimension\")))"
"(setq dlg-geruest-einzelmodul (get_tile \"geruest_einzelmodul\"))"
"(setq dlg-geruest-typ-idx " (vfs-dcl-radio-idx-cond "geruest_typ" n-geruest-typ) ")"
"(done_dialog 1)"
)
)
(action_tile "cancel" "(done_dialog 0)")
(setq ergebnis (start_dialog))
(unload_dialog dat)
(vl-file-delete dcl-pfad)
(if (= ergebnis 1)
(progn
(setq deltaL (atof dlg-deltal))
(setq deltaH (atof dlg-deltah))
(setq richtung (nth dlg-richtung-idx '("Auf" "Ab")))
(setq z-start (atof dlg-hoehe))
(setq hz (nth dlg-fahrt-idx '(0.0 90.0 180.0 270.0)))
(setq seite (nth dlg-seite-idx '("rechts" "links")))
(setq motorseite (nth dlg-motorseite-idx '("rechts" "links")))
(setq dim (nth dlg-dim-idx '("3D" "2D")))
(setq geruest-einzelmodul dlg-geruest-einzelmodul)
(setq geruest-typ (ssg-geruest-idx-to-typ dlg-geruest-typ-idx))
(list deltaL deltaH richtung z-start hz seite dim geruest-einzelmodul geruest-typ motorseite)
)
nil
)
)
)
)
)
)
;; Dispatcher: bevorzugt die dynamisch generierte Variante (Seite/
;; Motorseite/Geruestoption als Radio, Rest als Combobox - siehe
;; Kopfkommentar des DCL-DIALOG-Abschnitts), Rueckfall auf die reine
;; Popup-Variante nur bei technischem Fehler.
(defun vfs-dialog-eingabe-basis (prefill / ergebnis)
(setq ergebnis (vfs-dialog-eingabe-basis-radio prefill))
(if (eq ergebnis 'FEHLER) (vfs-dialog-eingabe-basis-popup prefill) ergebnis)
)
;; Winkel/Verteilung-Eingabe (Dialog 2, Popup-Variante): Winkel-Popup aus den vorher
;; berechneten gueltigen Varianten (gueltige-winkel/ergebnis-liste, siehe
;; berechne-alle-winkel), plus L_GF-Verteilung vorne/hinten (analog Schritt
;; 8+9 in c:VarioFoerderer).
;; prefill: Assoziationsliste ("winkel" . best-winkel) ("verteilung-idx" . "0".."3")
;; ("lgf1" . mm) - oder nil fuer Vorbelegung mit dem kleinsten gueltigen Winkel.
;; Rueckgabe: (best-winkel L_GF L_VF L_GF1 L_GF2 verteilung-modus) oder nil bei Abbruch.
(defun vfs-dialog-winkel-verteilung (gueltige-winkel ergebnis-liste staustrecke-basis prefill /
(defun vfs-dialog-winkel-verteilung-popup (gueltige-winkel ergebnis-liste staustrecke-basis prefill /
dcl-pfad dat ergebnis w eintrag idx sel-idx init-verteilung
dlg-winkel dlg-verteilung dlg-lgf1
best-winkel L_GF L_VF verteilung-modus L_GF1 L_GF2)
best-winkel L_GF L_VF verteilung-modus L_GF1 L_GF2 lgf-paar)
(setq dcl-pfad (strcat (getenv "DXFM_DCL") "/variofoerderer.dcl"))
(setq dat (load_dialog dcl-pfad))
(if (not (new_dialog "variofoerderer_winkel" dat))
@@ -1052,22 +1301,8 @@
(setq eintrag (assoc best-winkel ergebnis-liste))
(setq L_GF (nth 1 eintrag) L_VF (nth 2 eintrag))
(setq verteilung-modus dlg-verteilung)
(cond
((= verteilung-modus "0")
(setq L_GF1 (/ L_GF 2.0) L_GF2 (/ L_GF 2.0)))
((= verteilung-modus "1")
(setq L_GF1 (float staustrecke-basis))
(setq L_GF2 (max 0.0 (- L_GF (float staustrecke-basis)))))
((= verteilung-modus "2")
(setq L_GF2 (float staustrecke-basis))
(setq L_GF1 (max 0.0 (- L_GF (float staustrecke-basis)))))
((= verteilung-modus "3")
(setq L_GF1 (atof dlg-lgf1))
(if (or (null L_GF1) (< L_GF1 0)) (setq L_GF1 (/ L_GF 2.0)))
(if (> L_GF1 L_GF) (setq L_GF1 L_GF))
(setq L_GF2 (max 0.0 (- L_GF L_GF1))))
(t (setq L_GF1 (/ L_GF 2.0) L_GF2 (/ L_GF 2.0)))
)
(setq lgf-paar (vfs-verteilung-berechnen verteilung-modus L_GF staustrecke-basis dlg-lgf1))
(setq L_GF1 (car lgf-paar) L_GF2 (cadr lgf-paar))
(list best-winkel L_GF L_VF L_GF1 L_GF2 verteilung-modus)
)
nil
@@ -1076,6 +1311,14 @@
)
)
;; Winkel/Verteilung-Eingabe: Dialog nutzt durchgaengig Comboboxen
;; (variofoerderer_winkel in dcl/variofoerderer.dcl) - keine Radio-Variante
;; mehr noetig, da weder "winkel" noch "verteilung" als Radio bleiben
;; (siehe Kopfkommentar des DCL-DIALOG-Abschnitts).
(defun vfs-dialog-winkel-verteilung (gueltige-winkel ergebnis-liste staustrecke-basis prefill)
(vfs-dialog-winkel-verteilung-popup gueltige-winkel ergebnis-liste staustrecke-basis prefill)
)
;; ============================================================
;; XDATA-Metadaten fuer den Edit-Nachbau (App "SSG_VF_EDIT").
;; Markiert ein VF_n-INSERT als "mit dem Standard-Dialog erstellt" und
@@ -1310,6 +1553,38 @@
;; Neuanlage 0). Wer hz nicht kennt: der Wert steht in der urspruenglichen
;; Bau-Eingabe (z.B. mubea.json "hz") bzw. ergibt sich aus der Ausrichtung.
;; Bereits markierte Bloecke und Nicht-VF-Bloecke werden uebersprungen.
;; Baurichtung (hz) fuer EINEN Fund per Dialog abfragen - ersetzt den
;; frueheren getreal-Prompt in c:VARIOFOERDERER_NACHRUESTEN. "kopf" per
;; set_tile aus ssg-text befuellt (Blockname + erkannter Typ), deshalb
;; sprachunabhaengig. Rueckgabe: hz (Real) bei OK, 'ABBRUCH wenn der Nutzer
;; bewusst abbricht (Aufrufer uebernimmt dann default-hz, OHNE nochmal auf
;; der Konsole zu fragen), nil wenn der Dialog gar nicht gezeigt werden
;; konnte/durfte (GUI aus) - NUR dann faellt der Aufrufer auf den alten
;; getreal-Prompt zurueck.
(defun vfs-dialog-nachruesten-hz (bname typ default-hz / dcl-pfad dat ergebnis hz)
(if (or (not (car (atoms-family 1 '("SSG-GUI-P")))) (ssg-gui-p))
(progn
(setq dcl-pfad (strcat (getenv "DXFM_DCL") "/variofoerderer.dcl"))
(setq dat (load_dialog dcl-pfad))
(if (not (new_dialog "vfs_nachruesten_hz" dat))
(progn (if (and dat (>= dat 0)) (unload_dialog dat)) nil)
(progn
(set_tile "kopf" (ssg-textf "vfs-nachruesten-erkannt" (list bname typ)))
(set_tile "hz" (rtos default-hz 2 1))
(action_tile "accept"
"(setq hz (distof (get_tile \"hz\") 2)) (done_dialog 1)")
(action_tile "cancel" "(done_dialog 0)")
(setq ergebnis (start_dialog))
(unload_dialog dat)
(cond ((and (= ergebnis 1) hz) hz) (t 'ABBRUCH))
)
)
)
nil
)
)
(defun c:VARIOFOERDERER_NACHRUESTEN ( / ss i ent ed bname attribs xd typ hz
n-neu n-skip default-hz)
(ssg-start "VARIOFOERDERER_NACHRUESTEN" nil)
@@ -1337,8 +1612,14 @@
(if (or (assoc "GF_Bogen_R_60" attribs) (assoc "GF_Bogen_L_60" attribs))
"etage" "standard"))
(princ (ssg-textf "vfs-nachruesten-erkannt" (list bname typ)))
(setq hz (getreal (ssg-textf "vfs-nachruesten-prompt-hz" (list (rtos default-hz 2 1)))))
(if (null hz) (setq hz default-hz))
(setq hz (vfs-dialog-nachruesten-hz bname typ default-hz))
(cond
((eq hz 'ABBRUCH) (setq hz default-hz))
((null hz)
(setq hz (getreal (ssg-textf "vfs-nachruesten-prompt-hz" (list (rtos default-hz 2 1)))))
(if (null hz) (setq hz default-hz))
)
)
(setq default-hz hz)
(vf-edit-xdata-schreiben ent typ hz)
(princ (ssg-textf "vfs-nachruesten-markiert" (list (rtos hz 2 1))))
+68 -161
View File
@@ -1,6 +1,6 @@
# dxfmakros
AutoLISP-Makros fuer BricsCAD Pro zur automatisierten Erstellung von Foerderanlagen- und Kreisel-Layouts.
AutoLISP-Makros (SSG_LIB) fuer BricsCAD Pro zur automatisierten Erstellung von Foerderanlagen-Layouts (ILS Kreisel, Omniflo, VarioFoerderer, Gefaellestrecke, Geruest).
## Menustruktur (SSG_LIB)
@@ -14,164 +14,70 @@ SSG_LIB
│ │ └── Eckrad → ILS_Eckrad
│ ├── Zusatzmodul
│ │ ├── BTMT-Beladung → ILS_BTMT_Beladung
│ │ └── BTMT-Entladung → ILS_BTMT_Entladung
│ │ ├── BTMT-Entladung → ILS_BTMT_Entladung
│ │ ├── Scanner einfuegen → ILS_SCANNER_INSERT
│ │ └── Separator einfuegen → ILS_SEPARATOR_INSERT
│ ├── Foerderer
│ │ ├── VarioFoerderer → FOERDERANLAGE
│ │ └── Gefaellestrecke → ILS_G{K90,K60,K30}{L,R}
│ └── ILS Schliessen
│ │ ├── Standard → StandardVarioFoerderer / StandardVarioFoerderer3D
│ │ ├── Etage → EtageVarioFoerderer / EtageVarioFoerderer3D
│ │ ├── Streckengruppe (Linienzug) → LinienzugVarioFoerdererManuell / -Zielhoehe / -Stueckweise
│ │ └── Vario_Kette_Merge / VARIOFOERDERER_NACHRUESTEN
│ └── Gefaellestrecke
│ ├── einfach → GEFAELLESTRECKE_EINFACH
│ ├── aus 3D-Linie → GEFAELLESTRECKE_3DLINIE
│ └── aus Linienzug → GEFAELLESTRECKE_LINIENZUG
├── Omniflo
│ ├── Boegen
│ │ ├── 90 → OMNI_APB_630_90
│ │ ├── 67.5 → OMNI_APB_550_675
│ │ ├── 45 → OMNI_APB_630_45
│ │ ├── 22.5 → OMNI_APB_550_225
│ │ └── 180 → OMNI_APB_650_180
│ ├── Aluprofil Gerade
│ │ ├── AP 60 → OMNI_AP60
│ │ ├── AP 110 → OMNI_AP110
│ │ └── APG 110 → OMNI_APG110
│ ├── Weiche 90 Grad
│ │ ├── Einfach → OMNI_W90_Einfach
│ │ ├── Doppel → OMNI_W90_Doppel
│ │ └── Dreiwege → OMNI_W90_Dreiwege
│ ├── Weiche 45 Grad
│ │ ├── Einfach → OMNI_W45_Einfach
│ │ ├── Doppel → OMNI_W45_Doppel
│ │ └── Dreiwege → OMNI_W45_Dreiwege
│ ├── Weichen Parallel
│ │ ├── Einfach → OMNI_WP_Einfach
│ │ ├── Doppel → OMNI_WP_Doppel
│ │ └── Dreiwege → OMNI_WP_Dreiwege
│ ├── Weichenkoerper
│ │ ├── Einfach → OMNI_WK_Einfach
│ │ ├── Doppel → OMNI_WK_Doppel
│ │ └── Dreiwege → OMNI_WK_Dreiwege
│ ├── Weichenkombinationen
│ │ ├── Delta 1400/700 → OMNI_WKomb_Delta_1400
│ │ ├── Delta 1600/800 → OMNI_WKomb_Delta_1600
│ │ └── Star → OMNI_WKomb_Star
│ ├── TEF Elemente
│ │ ├── Umlenkspannst. rechts → OMNI_TEF_UmlenkR
│ │ ├── Umlenkspannst. links → OMNI_TEF_UmlenkL
│ │ ├── Antriebst. links → OMNI_TEF_AntriebL
│ │ ├── Antriebst. rechts → OMNI_TEF_AntriebR
│ │ └── TEF Gerade → OMNI_TEF_Gerade
│ ├── KettenFoerderer → OMNI_KettenFoerderer
│ └── Ladeschleifen
│ └── AP 110 → OMNI_LADESCHLEIFE_AP110
│ ├── Boegen APB110/APB60
│ ├── Aluprofil Gerade (AP60/AP110/APG110)
│ ├── Weichen (90/45/Parallel/Weichenkoerper/Weichenkombinationen)
│ ├── TEF Elemente, Anbaugruppen, Verbinder, Boegen fuer Weichen
│ ├── Element bearbeiten → OMNI_EDIT
│ └── Ladeschleifen (AP110) → OMNI_LADESCHLEIFE_AP110
├── Geruest
│ ├── Rohr-Geruest-Traeger → GERUEST_TRAEGER
│ ├── Saeulen / Rohrabhaenger / Wandbefestigung → GERUEST
│ └── Funktionen ▸ Traeger beschriften → GERUEST_TRAEGER_BESCHRIFTEN
├── SPS
│ ├── TRO (Marker einfuegen/bearbeiten) → TRO_INSERT / TRO_EDIT
│ └── Connections (einfuegen/bearbeiten, Eingang/Ausgang) → CONNECTION_INSERT / CONNECTION_EDIT / ILS_EINGANG_INSERT / ILS_AUSGANG_INSERT
├── Export
│ ├── Export Sivas → EXPORTSIVAS
│ └── Export CSV → EXPORTCSV
├── Konfiguration
│ ├── Umschalten 2D und 3D → SSG_DIM_SWITCH
│ └── Sprache → SSG_SPRACHE
└── External
├── Call Python → CALLPYTHON
├── Export Sivas → EXPORTSIVAS
└── Export CSV → EXPORTCSV
│ ├── Sprache → SSG_SPRACHE
│ └── Planquadrate an/aus → PLANQUADRATE_TOGGLE
├── Werkzeuge
│ ├── Bloecke zaehlen/loeschen, Attribute ersetzen → ssg_blocktools
│ └── Text ersetzen/parallel/Hoehe/Stil → ssg_texttools
└── Tests (Testsuiten ausfuehren und exportieren)
```
## Befehle nach Modul
Vollstaendige, laufend aktualisierte Befehls-/Modulzuordnung: siehe `CLAUDE.md` (Abschnitt "Modulzuordnung im Menue") und `menu/SSG_LIB.mnu`.
### KreiselInsert.lsp - Kreisel Modul-Einfuegesystem
## Lademechanismus
Zeichnet ILS-Kreiselmodule als Compound-Bloecke mit konfigurierbarem Abstand, Typ und Attributen.
Module werden per Lazy-Loading ueber das Menuesystem geladen (`ssg-ensure` in `SSG_LIB.mnl`). Einmalige Einrichtung pro BricsCAD-Installation:
| Befehl | Beschreibung |
| --- | --- |
| `KreiselInsert` | Modul an manuell gewaehltem Punkt einfuegen (Abstand, Drehung, Hoehe, Typ interaktiv) |
| `KreiselConnect` | Smart Connect: Kreisel zwischen zwei parallelen Linien einfuegen, berechnet Position/Abstand/Rotation automatisch |
| `KreiselEdit` | Bestehenden Kreisel per DCL-Dialog bearbeiten (Name, Abstand, Hoehe, Ausrichtung, Drehrichtung, Typ) |
| `KreiselRedraw` | Kreisel mit optionalem neuem Abstand/Hoehe neu zeichnen, Attribute bleiben erhalten |
| `KreiselQuick` | Schnelleinfuegen mit Standardparametern (horizontal) |
| `KreiselParams` | Aktuelle Kreisel-Parameterkonfiguration anzeigen |
| `ILS_Eckrad` | Einzelnen AN8-Block (Antriebs-/Eckrad) an gewaehltem Punkt einfuegen |
| `KreiselLabelPos` | Label-Position (X/Y-Offset) konfigurieren |
| `KreiselLabelHoehe` | Label-Texthoehe konfigurieren |
| `KreiselLabelSetup` | Label-Darstellung konfigurieren (Hoehe, Farbe, Abstand, Schriftart) |
1. `bin/setenv.bat` ausfuehren (setzt `DXFM_LISP` u.a.)
2. BricsCAD starten
3. In der Kommandozeile `_MENULOAD` eingeben, `menu/SSG_LIB.mnu` auswaehlen
### OmniModulInsert.lsp - Omniflo Komponenten
Einfuegen von Omniflo-Standardkomponenten (Boegen, Geraden, Weichen, TEF-Elemente).
| Befehl | Beschreibung |
| --- | --- |
| `OMNI_LOAD` | Omniflo-Komponentendaten aus JSON-Dateien laden |
| `OMNI_INFO_BOGEN` | Info zu einem Omniflo-Bogen nach Sivas-ID anzeigen |
| `OMNI_INFO_WEICHE` | Info zu einer Omniflo-Weiche nach Sivas-ID anzeigen |
| `OMNI_APB_*` | Boegen einfuegen (90, 67.5, 45, 22.5, 180 Grad) |
| `OMNI_AP60/AP110/APG110` | Aluprofil-Geraden einfuegen |
| `OMNI_W90/W45/WP/WK_*` | Weichen einfuegen (Einfach, Doppel, Dreiwege) |
| `OMNI_WKomb_Delta_1400/1600, OMNI_WKomb_Star` | Weichenkombinationen einfuegen |
| `OMNI_TEF_*` | TEF-Elemente einfuegen (Umlenk-/Antriebsstationen, Gerade) |
| `OMNI_KettenFoerderer` | Kettenfoerderer einfuegen |
| `OMNI_LADESCHLEIFE_AP110` | Ladeschleife (AP 110) ueber DCL-Dialog einfuegen |
### VarioFoerderer.lsp - Foerderanlage Generator (v24.4)
Generiert komplette Vario-Foerderanlagen mit Vertikalboegen, Motor-/Spannstationen, Staustrecken und Ein-/Ausschleus-Elementen.
| Befehl | Beschreibung |
| --- | --- |
| `FOERDERANLAGE` | Interaktiver Generator: Zwei Punkte oder manuelle Distanz/Hoehe, berechnet optimalen Bogenwinkel |
| `FOERDERTEST` | Automatischer Testlauf (Distanz=6000, Hoehe=2000, Richtung=Auf), speichert als DXF |
Unterstuetzte Bogenwinkel: 3, 9, 12, 15, 24, 36, 48 Grad
### ssg_layer.lsp - Layerverwaltung
| Befehl | Beschreibung |
| --- | --- |
| `SSG-LayerSet` | Objekt anklicken, dessen Layer wird aktiv |
| `SSG-LayerInfo` | Layer eines angeklickten Objekts anzeigen |
| `SSG-LayerMove` | Selektierte Objekte auf Ziel-Layer verschieben |
| `SSG-LayerCopy` | Selektierte Objekte auf Ziel-Layer kopieren |
| `SSG-LayerMoveType` | Alle Objekte gleichen Typs von Referenz- auf Ziel-Layer verschieben |
| `SSG-LayerOff` | Layer per Klick ausschalten (mehrfach moeglich) |
| `SSG-LayerFreeze` | Layer per Klick einfrieren (mehrfach moeglich) |
| `SSG-FreezeAll` | Alle Layer ausser dem angeklickten einfrieren |
| `SSG-ThawAll` | Alle eingefrorenen Layer auftauen |
| `SSG-LayerOnAll` | Alle ausgeschalteten Layer einschalten |
| `SSG-LayerDelete` | Layer und alle Objekte darauf loeschen (mit Bestaetigung) |
### SSG_LIB_Commands.lsp - Konfiguration
| Befehl | Beschreibung |
| --- | --- |
| `SSG_DIM_SWITCH` | Schaltet zwischen 2D- und 3D-Bloecken um |
| `SSG_SPRACHE` | Sprache umschalten (Deutsch/Englisch), persistiert ueber `DXFM_LANG` |
### tests.lsp - Export und Python-Integration
| Befehl | Beschreibung |
| --- | --- |
| `CALLPYTHON` | Python-Skripte via CLI aufrufen, Ausgabe loggen |
| `EXPORTSIVAS` | Daten im Sivas-Format exportieren |
| `EXPORTCSV` | Zeichnungsdaten als CSV exportieren |
## Kernbibliotheken (Lisp/)
| Datei | Beschreibung |
| --- | --- |
| `ssg_core.lsp` | Kernel: Umgebung, Layer-Ops, Block-Ops, Attribut-Ops, Fehlerbehandlung |
| `ssg_lang.lsp` | Sprachumschaltung Deutsch/Englisch (`ssg-text`, `ssg-textf`, `*ssg-lang*`) |
| `ssg_dialog.lsp` | Dialog-Vorlagen: Slide-Preview, Modul-Dialog, Block-Einfuegesequenz |
| `ssg_layer.lsp` | Layer-Verwaltungsbefehle |
| `ssg_load.lsp` | Loader: Laedt alle SSG-Bibliotheken in korrekter Reihenfolge |
| `on_start.lsp` | Startup-Skript: Setzt Umgebung und laedt Libraries |
Details und die Core-Ladereihenfolge: siehe `CLAUDE.md` Abschnitt "Lademechanismus (Lazy Loading via MNL)".
## Projektstruktur
```text
dxfmakros/
├── Blocks/ # DWG-Bloecke (AN8, SP8, Vertikalboegen, etc.)
├── Lisp/ # AutoLISP-Makros und Kernbibliotheken
├── bin/ # Hilfs-Skripte (setenv, create_tests, etc.)
├── cfg/ # Konfigurationsdateien (export.cfg, block_suffix.cfg)
├── data/ # Quelldaten (JSON, DXF) - nicht im Git
├── dcl/ # DCL-Dialogdefinitionen (kreisel_edit.dcl)
├── doc/ # Dokumentation und Referenz-DXFs
├── examples/ # Beispieldateien
├── lib/ # Python-Skripte (export_csv.py, etc.)
├── logs/ # Logdateien - nicht im Git
├── menu/ # BricsCAD-Menudefinition (SSG_LIB.mnu)
├── Lisp/ # AutoLISP-Makros und Kernbibliotheken (Details: Lisp/README.md)
├── bin/ # Hilfs-Skripte (setenv.bat, start_briscad.bat)
├── cfg/ # Konfigurationsdateien
├── data/ # JSON-Daten, DXF-Quellen, Block-Libraries - nicht im Git
├── dcl/ # DCL-Dialogdefinitionen
├── doc/ # Dokumentation (doc/plan Architektur/Analysen, doc/todo offene Fahrplaene)
├── lib/ # Python-Skripte (DXF-Bearbeitung, Export)
├── log/ # Logdateien - nicht im Git
├── menu/ # BricsCAD-Menudefinition (SSG_LIB.mnu, SSG_LIB.mnl)
├── results/ # Ergebnisse / Exporte - nicht im Git
├── tests/ # Testskripte und Referenzdaten
├── LICENSE
@@ -181,33 +87,34 @@ dxfmakros/
## Umgebungsvariablen
Werden via `bin/setenv.bat` gesetzt. Wichtigste:
| Variable | Beschreibung |
| --- | --- |
| `DXFMAKRO` | Wurzelverzeichnis des Projekts |
| `DXFM_BLOCKS` | Pfad zum Blocks-Verzeichnis |
| `DXFM_LISP` | Pfad zu den LISP-Dateien |
| `DXFM_RESULTS` | Pfad fuer DXF-Exporte |
| `DXFM_BIN` | Skriptverzeichnis |
| `DXFM_LIB` | Python-Quellcode |
| `DXFM_CFG` | Konfigurationsdateien |
| `DXFM_TESTS` | Testverzeichnis |
| `DXFM_DATA` | Datenverzeichnis |
| `DXFM_LISP` | Pfad zu den LISP-Dateien (benoetigt fuer `ssg-ensure`) |
| `DXFM_BLOCKS` | Pfad zu DWG-Bloecken |
| `DXFM_DATA` | Datenverzeichnis (JSON, DXF) |
| `DXFM_LOG` | Log-Verzeichnis |
| `DXFM_DCL` | Pfad zu DCL-Dialogdateien |
| `DXFM_CFG` | Konfigurationsverzeichnis |
| `DXFM_LANG` | Aktive Sprache (`de_DE`/`en_GB`), persistiert von `SSG_SPRACHE`; Default `de_DE` |
| `BRICSCAD` | Pfad zur BricsCAD-Executable |
## Einrichtung
1. `bin\setenv.bat` ausfuehren (setzt alle Umgebungsvariablen)
2. BricsCAD starten - `on_start.lsp` laedt alle Libraries automatisch via `startup.scr`
3. Menu `SSG_LIB` nutzen oder Befehle in der Kommandozeile ausfuehren
| `DXFM_VF_SPEC` | Spec-Datei fuer `VF_SPEC_BAU` (optional) |
| `BRICSCAD` | Pfad zur BricsCAD-Executable (fuer headless Testlauf) |
## Tests
Headless-Unit-Tests (file- und zeichnungsfrei):
```bat
bin\create_tests.bat
bin\run_tests.bat --lisp
```
Erzeugt eine Test-DXF, fuehrt Kreisel-Einfuege- und Exportbefehle aus, und validiert die Ergebnisse gegen Referenzdateien in `tests/references/`.
Zeichnungs-/Szenario-Tests laufen interaktiv in BricsCAD ueber das Menue `Tests` bzw. `SSG_RUN_ALL_TESTS`. Details: `doc/LispTests.md`, `tests/README.md`.
## Dokumentation
Ausfuehrliche Modul- und Befehlsdokumentation: `CLAUDE.md` (Projektanweisungen) und `Lisp/README.md`. Weitere Anwender-/Entwickler-Themen direkt in `doc/` (u.a. `variofoerderer.md`, `csv-export.md`, `faq.md`, `kommandos.md`). Architektur-Analysen und Planungsdokumente in `doc/plan/` (u.a. `translate.md`, `Entwicklungsplan.md`), offene Fahrplaene/TODOs in `doc/todo/`.
## Lizenz
+13
View File
@@ -0,0 +1,13 @@
@echo off
REM ================================================================
REM Mit unseren Makros gebaute (und von Hand nachbearbeitete) Anlage
REM aus einer Zeichnung in Nachbau-Testdaten zurueckschreiben.
REM Siehe doc/kommandos.md, doc/json-input-lisp.md.
REM
REM Aufruf:
REM bin\dxf_anlage_export.bat <dxf> <output.json> [--projekt NAME]
REM ================================================================
call "%~dp0setenv.bat"
python "%DXFM_LIB%\dxf_anlage_export.py" %*
+14
View File
@@ -0,0 +1,14 @@
@echo off
REM ================================================================
REM Erkennt ILS-/Omniflo-Komponenten in einer FREMDEN Projektzeichnung
REM (ohne unsere Wrapper-Bloecke) und schreibt sie als Nachbau-JSON.
REM Siehe doc/kommandos.md, doc/json-input-lisp.md.
REM
REM Aufruf:
REM bin\dxf_scan_components.bat <dxf> <data_dir> <output.json>
REM [--fenster X0 Y0 X1 Y1] [--projekt NAME]
REM ================================================================
call "%~dp0setenv.bat"
python "%DXFM_LIB%\dxf_scan_components.py" %*
+14
View File
@@ -0,0 +1,14 @@
@echo off
REM ================================================================
REM Attribut-/Bausteinabbild der VF_/GF_-Wrapperbloecke einer
REM Testzeichnung - Regressionsnetz fuer Umbauten am Bau-Ablauf.
REM Siehe doc/kommandos.md.
REM
REM Aufruf:
REM bin\dxf_vf_abbild.bat <dxf> [--spec S] [--json J] [--referenz R]
REM [--schreibe-referenz] [--praefix VF_,GF_]
REM ================================================================
call "%~dp0setenv.bat"
python "%DXFM_LIB%\dxf_vf_abbild.py" %*
+1 -1
View File
@@ -1,6 +1,6 @@
@echo off
REM ================================================================
REM Setzt Einfuegepunkte fuer Omniflo DXF-Dateien
REM Setzt Koordinatensystem-Bloecke (K1-K4) in Omniflo DXF-Dateien
REM ================================================================
call "%~dp0setenv.bat"
+58 -6
View File
@@ -6,11 +6,12 @@ REM Zeichnet jede Zeile der Export-CSV (EXPORTCSV) als achsparalleles
REM Rechteck aus Position + Boundingbox, mit Legende und Tooltip je
REM Rechteck sowie den Anschluss-Koordinatensystemen K1-K4 (rotes Kreuz,
REM blaue Linie K1->K2->K3->K4), und oeffnet das Ergebnis im Browser.
REM Optional zusaetzlich Materialfluss- und Bahnzusammenhang-Graph.
REM Optional zusaetzlich Materialfluss-, Bahnzusammenhang- und TRO-Fluss-Graph.
REM
REM Die Darstellung uebernimmt sps_skel (bin\material_flow.bat,
REM Option --show-bbs). sps_skel wird neben dxfmakros erwartet
REM (..\sps_skel) oder ueber die Umgebungsvariable SPS_SKEL_HOME.
REM Option --show-bbs, bzw. bin\tro_flow.bat fuer 'tro'). sps_skel wird
REM neben dxfmakros erwartet (..\sps_skel) oder ueber die Umgebungs-
REM variable SPS_SKEL_HOME.
REM
REM Aufruf:
REM bin\show_exportcsv.bat results\export.csv, alle Zeilen
@@ -18,17 +19,51 @@ REM bin\show_exportcsv.bat meine_export.csv andere CSV in results\ (oder Pf
REM bin\show_exportcsv.bat export.csv flow ohne VF/GF-Einzelbausteine
REM bin\show_exportcsv.bat export.csv mflow zusaetzlich Materialfluss-Graph
REM bin\show_exportcsv.bat export.csv track zusaetzlich Bahnzusammenhang-Graph
REM bin\show_exportcsv.bat export.csv flow mflow track alles kombiniert
REM bin\show_exportcsv.bat export.csv tro zusaetzlich TRO-Fluss-Graph (lagerichtig)
REM bin\show_exportcsv.bat export.csv flow mflow track tro alles kombiniert
REM
REM mflow/track brauchen Graphviz ('dot' im PATH).
REM mflow/track/tro brauchen Graphviz ('dot' bzw. 'neato' im PATH).
REM
REM Ergebnis: %SKEL_RESULTS%\<name>_bbs.svg
REM %SKEL_RESULTS%\<name>_material_flow.svg (nur mit 'mflow')
REM %SKEL_RESULTS%\<name>_track.svg (nur mit 'track')
REM %SKEL_RESULTS%\<name>_tro_flow.svg (nur mit 'tro')
REM ================================================================
setlocal
if /i "%~1"=="--help" goto :help
if /i "%~1"=="-h" goto :help
if "%~1"=="/?" goto :help
goto :main
:help
echo Aufruf:
echo bin\show_exportcsv.bat results\export.csv, alle Zeilen
echo bin\show_exportcsv.bat meine_export.csv andere CSV in results\ ^(oder Pfad^)
echo bin\show_exportcsv.bat export.csv flow ohne VF/GF-Einzelbausteine
echo bin\show_exportcsv.bat export.csv mflow zusaetzlich Materialfluss-Graph
echo bin\show_exportcsv.bat export.csv track zusaetzlich Bahnzusammenhang-Graph
echo bin\show_exportcsv.bat export.csv tro zusaetzlich TRO-Fluss-Graph ^(lagerichtig^)
echo bin\show_exportcsv.bat export.csv flow mflow track tro alles kombiniert
echo.
echo Schalter ^(2.-5. Argument, Reihenfolge beliebig^):
echo all Darstellungsmodus: alle Zeilen ^(Default^)
echo flow Darstellungsmodus: ohne VF/GF-Einzelbausteine
echo mflow zusaetzlich Materialfluss-SVG erzeugen und oeffnen
echo track zusaetzlich Bahnzusammenhang-SVG erzeugen und oeffnen
echo tro zusaetzlich TRO-Fluss-SVG ^(lagerichtig^) erzeugen und oeffnen
echo.
echo mflow/track/tro brauchen Graphviz ^('dot' bzw. 'neato' im PATH^).
echo.
echo Ergebnis:
echo %%SKEL_RESULTS%%\^<name^>_bbs.svg
echo %%SKEL_RESULTS%%\^<name^>_material_flow.svg ^(nur mit 'mflow'^)
echo %%SKEL_RESULTS%%\^<name^>_track.svg ^(nur mit 'track'^)
echo %%SKEL_RESULTS%%\^<name^>_tro_flow.svg ^(nur mit 'tro'^)
endlocal & exit /b 0
:main
REM Umgebung dxfmakros (DXFM_RESULTS ...)
call "%~dp0setenv.bat" >nul
@@ -58,20 +93,24 @@ for %%F in ("%CSV%") do (
set "SVG=%SKEL_RESULTS%\%%~nF_bbs.svg"
set "MF_SVG=%SKEL_RESULTS%\%%~nF_material_flow.svg"
set "TRACK_SVG=%SKEL_RESULTS%\%%~nF_track.svg"
set "TRO_SVG=%SKEL_RESULTS%\%%~nF_tro_flow.svg"
)
REM Weitere Argumente (Reihenfolge beliebig):
REM all (Default) / flow - Darstellungsmodus der Boundingbox-Ansicht
REM mflow - zusaetzlich Materialfluss-SVG erzeugen und oeffnen
REM track - zusaetzlich Bahnzusammenhang-SVG erzeugen und oeffnen
REM tro - zusaetzlich TRO-Fluss-SVG (lagerichtig) erzeugen und oeffnen
set "MODE=all"
set "MFLOW="
set "TRACK="
for %%A in (%2 %3 %4) do (
set "TRO="
for %%A in (%2 %3 %4 %5) do (
if /i "%%~A"=="all" set "MODE=all"
if /i "%%~A"=="flow" set "MODE=flow"
if /i "%%~A"=="mflow" set "MFLOW=1"
if /i "%%~A"=="track" set "TRACK=1"
if /i "%%~A"=="tro" set "TRO=1"
)
REM Beide Graphen entstehen erst mit --tosvg (Graphviz 'dot')
@@ -83,10 +122,15 @@ REM Alte SVGs entfernen, damit nie eine veraltete Ansicht geoeffnet wird
if exist "%SVG%" del "%SVG%"
if defined MFLOW if exist "%MF_SVG%" del "%MF_SVG%"
if defined TRACK if exist "%TRACK_SVG%" del "%TRACK_SVG%"
if defined TRO if exist "%TRO_SVG%" del "%TRO_SVG%"
call "%SPS_SKEL_HOME%\bin\material_flow.bat" --file "%CSV%" --show-bbs %MODE% --show-kx %OPTS%
set "RC=%ERRORLEVEL%"
if defined TRO (
call "%SPS_SKEL_HOME%\bin\tro_flow.bat" --file "%CSV%" --tosvg --use-cords
)
if not exist "%SVG%" (
echo FEHLER: SVG wurde nicht erzeugt ^(material_flow Exit-Code %RC%^).
endlocal & exit /b 1
@@ -115,6 +159,14 @@ if defined TRACK (
echo WARNUNG: Bahnzusammenhang-SVG wurde nicht erzeugt ^(Graphviz 'dot' vorhanden?^).
)
)
if defined TRO (
if exist "%TRO_SVG%" (
echo TRO-Fluss: %TRO_SVG%
start "" "%TRO_SVG%"
) else (
echo WARNUNG: TRO-Fluss-SVG wurde nicht erzeugt ^(Graphviz 'neato' vorhanden?^).
)
)
endlocal & exit /b 0
+8 -8
View File
@@ -64,14 +64,14 @@
# Code (bedingte Umbenennung bzw. Umrechnung mm->m).
[eckrad]
# Bewusst (noch) beschreibende Klartext-Keys statt Merkmalnummern (kein
# bekanntes Sivas-Merkmal fuer Eckrad-Geruest hinterlegt) - details_mit_
# bezeichnung() in export_sivas.py laesst nicht-numerische Keys unveraendert.
# "ist_eins" liefert ein ECHTES bool (True/False), NICHT "Ja"/"Nein" wie
# ja_nein bei Kreisel/Gefaellestrecke - json.dumps schreibt dann true/false
# ohne Anfuehrungszeichen (bisheriges Verhalten von build_eckrad_details).
Geruest fuer Einzelmodul= GERUEST_EINZELMODUL : 0 | ist_eins
Geruestoption fuer Einzelmodul= GERUEST_TYP : Schoenenberger Geruest
# Dieselben Sivas-Merkmalnummern wie bei Kreisel (siehe oben), aus
# Merkmalsstamm_in_Sivas.xlsx: 3992 "Geruest fuer Einzelmodul", 3993
# "Geruestoption fuer Einzelmodul". "ist_eins" liefert ein ECHTES bool
# (True/False), NICHT "Ja"/"Nein" wie ja_nein bei Kreisel/Gefaellestrecke -
# json.dumps schreibt dann true/false ohne Anfuehrungszeichen (bisheriges
# Verhalten von build_eckrad_details).
3992= GERUEST_EINZELMODUL : 0 | ist_eins
3993= GERUEST_TYP : Schoenenberger Geruest | geruest_typ_anzeige
[geruest]
Farbe= FARBE
+69
View File
@@ -6,6 +6,14 @@
// Eingaben entsprechen dem interaktiven Skript Gefaellestrecke.lsp:
// Abstand deltaL, Gefaellewinkel, Fahrtrichtung,
// Seite AUS-Element, Seite EIN-Element.
//
// gefaellestrecke_linienzug: Modus 3 (aus Linienzug LINE+ARC) - ersetzt die
// Konsolenfragen AUS-/EIN-Element Winkel+Seite, Winkelbestaetigung und die
// finale Einfuegen-Bestaetigung in EINEM Dialog (gf-dialog-linienzug in
// Gefaellestrecke.lsp). Die Objektauswahl (ssget LINE/ARC) UND die
// Start-/Endpunktwahl bleiben davor Zeichnung/Konsole - der automatisch
// berechnete Vorschlagswinkel wird als Vorbelegung des Winkel-Feldes
// gezeigt, mit einer kurzen Zusammenfassung der Segmentanalyse darueber.
// ============================================================
gefaellestrecke : dialog {
@@ -108,3 +116,64 @@ gefaellestrecke : dialog {
ok_cancel;
}
// Modus 3 (aus Linienzug): AUS-/EIN-Element Winkel+Seite, Gefaellewinkel
// (Vorschlag vorbelegt, ueberschreibbar) und eine kurze Zusammenfassung der
// automatisch analysierten Segmentkette. "zusammenfassung" wird per
// set_tile aus mehreren ssg-textf-Zeilen zusammengesetzt (gf-dialog-
// linienzug, Gefaellestrecke.lsp) - sprachunabhaengig, nur das Label-Chrome
// bleibt hart deutsch wie der Rest dieser Datei.
gefaellestrecke_linienzug : dialog {
label = "Gefaellestrecke aus Linienzug";
: column {
: boxed_column {
label = "Segmentanalyse";
: text { key = "zusammenfassung"; label = ""; width = 55; }
}
: boxed_row {
label = "AUS-Element";
: popup_list {
key = "aus_winkel";
label = "Winkel:";
width = 12;
}
: popup_list {
key = "aus_seite";
label = "Seite:";
width = 14;
}
}
: boxed_row {
label = "EIN-Element";
: popup_list {
key = "ein_winkel";
label = "Winkel:";
width = 12;
}
: popup_list {
key = "ein_seite";
label = "Seite:";
width = 14;
}
}
: boxed_column {
label = "Gefaellewinkel";
: edit_box {
key = "winkel";
label = "Gefaellewinkel (Grad):";
edit_width = 10;
}
}
}
ok_cancel;
}
+133 -51
View File
@@ -3,14 +3,47 @@
// Dialoge fuer c:VarioFoerderer (vf_core.lsp):
// vfc_typ: Anlagen-Typ waehlen (Standard/Etage/Linienzug) - ersetzt die
// Konsolen-Liste am Befehlsanfang. Radio-Buttons statt Dropdown, daher
// Labels FEST auf Deutsch (siehe Kommentar bei vfc_linienzug_modus).
// vfc_linienzug_modus: NUR bei Typ "Linienzug" - Modus 1/2/3 waehlen.
// variofoerderer_basis/variofoerderer_winkel: Werteingabe fuer den
// Standardfall (anlage-typ "standard"): deltaL, deltaH, Foerderrichtung,
// Einfuegehoehe, Fahrtrichtung, Seite, Winkel, GF-Verteilung.
// Die 3D-Linie-Eingabe (Modus "3D-Linie"), der Etage-Typ und die
// Linienzug-Kette selbst (nach der Modus-Wahl) bleiben interaktiv
// (Kommandozeile bzw. eigener Wizard in vf_linienzug_wizard.dcl).
// Labels FEST auf Deutsch.
// vfc_startpunkt: Startpunkt der Anlage picken (Punktwahl-Button +
// X/Y/Z-Anzeige) - ersetzt den reinen Konsolen-getpoint fuer
// Standard UND Etage (vfc-dialog-startpunkt-waehlen, vf_core.lsp).
// variofoerderer_basis/variofoerderer_winkel: Popup-Fallback-Varianten
// der Werteingabe (deltaL, deltaH, Foerderrichtung, Einfuegehoehe,
// Fahrtrichtung, Seite, Motorseite, Dimension, Geruest, Winkel,
// GF-Verteilung) - gemeinsam genutzt von Standard UND Etage. Die
// bevorzugte Variante (vfs_basis_dyn) wird zur Laufzeit generiert
// (vfs-dialog-eingabe-basis-radio in vf_standard.lsp) und steht NICHT
// in dieser Datei - NUR "Seite", "Motorseite" und "Geruestoption"
// bleiben dort Radio-Button-Gruppen (sofort sichtbare Optionen), alle
// anderen Felder sind Comboboxen wie hier. variofoerderer_basis hier
// ist nur noch der Fallback, falls das Schreiben/Laden der Temp-DCL
// mal scheitert. variofoerderer_winkel (Winkel/Verteilung) hat KEINE
// generierte Variante mehr und wird direkt verwendet (komplett
// Combobox, siehe vfs-dialog-winkel-verteilung in vf_standard.lsp).
// vfc_eingabemodus: Eingabemodus (3D-Linie / Werte manuell) waehlen -
// ersetzt die Konsolen-Abfrage am Anfang von vf-dialog-ablauf fuer
// Standard UND Etage (vfc-dialog-eingabemodus-waehlen, vf_core.lsp).
// Die 3D-Linie SELBST (Objektauswahl) bleibt danach Zeichnung/Konsole
// (get-line-start-end-points) - eine Linie laesst sich nicht durch ein
// Formularfeld ersetzen; alle abgeleiteten Werte (deltaL/deltaH/hz/
// Einfuegehoehe) landen danach als Prefill im bestehenden Basis-Dialog
// (variofoerderer_basis), der sie ganz normal ueberschreibbar anzeigt.
// Der Etage-Typ und die Linienzug-Kette selbst bleiben interaktiv
// (Kommandozeile bzw. eigener Wizard in vf_linienzug_wizard.dcl). Der
// Linienzug-Modus (1/2/3/4/5) wird seit den Menue-Wrappern
// c:LinienzugVarioFoerderer*/c:QcLinieMitGf* nicht mehr per Dialog erfragt,
// sondern ist je Menuepunkt fest vorbelegt - der frueher hier gefuehrte
// Dialog vfc_linienzug_modus ist dadurch entfallen.
//
// Dialog fuer c:VARIOFOERDERER_NACHRUESTEN (vf_standard.lsp):
// vfs_nachruesten_hz: Baurichtung (hz) je unmarkiertem VF_n-Fund abfragen
// - ersetzt den fruehren getreal-Prompt. Die Objektauswahl selbst
// (ssget) bleibt Zeichnung/Konsole; je Fund OHNE SSG_VF_EDIT-Marker
// zeigt der Befehl diesen Dialog einmal, mit dem zuletzt eingegebenen
// Wert als Vorgabe (vfs-dialog-nachruesten-hz in vf_standard.lsp).
// "Abbrechen" uebernimmt fuer diesen Fund den Vorgabewert, OHNE auf die
// alte Konsolenfrage zurueckzufallen (die bleibt reiner Rueckfall fuer
// den Fall, dass der Dialog gar nicht gezeigt werden kann/darf).
// ============================================================
// Anlagen-Typ waehlen (Standard/Etage/Linienzug). Radio-Buttons statt
@@ -39,7 +72,7 @@ vfc_typ : dialog {
}
: radio_button {
key = "typ_linienzug";
label = "3D-Linienzug (gemischte GF/VF-Kette)";
label = "Streckengruppe (gemischte GF/VF-Kette)";
}
}
@@ -57,50 +90,75 @@ vfc_typ : dialog {
}
}
// Linienzug-Modus waehlen (nur wenn Anlagen-Typ = Linienzug). Radio-Buttons,
// gleicher Deutsch-fest-Grund wie bei vfc_typ oben.
vfc_linienzug_modus : dialog {
label = "VarioFoerderer - Linienzug Modus";
// Eingabemodus waehlen (3D-Linie / Werte manuell) - Radio-Buttons, gleiches
// Muster und dieselbe Sprach-/GUI-Einschraenkung wie vfc_typ oben (Labels
// hart deutsch, Rueckfall auf Konsolen-Liste bei DXFM_LANG=en_GB oder
// abgeschalteter GUI - siehe vfc-dialog-eingabemodus-waehlen, vf_core.lsp).
vfc_eingabemodus : dialog {
label = "VarioFoerderer - Eingabemodus";
: boxed_radio_column {
label = "Linienzug-Modus waehlen:";
label = "Eingabemodus waehlen:";
key = "modus";
: radio_button {
key = "modus_1";
label = "Manuelle Eingabe (Punkte klicken)";
key = "modus_3dlinie";
label = "3D-Linie auswaehlen (Start- und Endpunkt mit Hoehe)";
value = "1";
}
: radio_button {
key = "modus_2";
label = "3D-Objekte + Ziel-Hoehe (Randwert-Solver, fertig)";
}
: radio_button {
key = "modus_3";
label = "3D-Objekte stueckweise (Vorwaerts-Nachbau, in Arbeit)";
}
: radio_button {
key = "modus_4";
label = "QC Linie mit GF (automatische Auf-Ab-Berechnung)";
}
: radio_button {
key = "modus_5";
label = "QC Linie mit GF und U-Form";
key = "modus_werte";
label = "Werte manuell eingeben";
}
}
// "Zurueck" springt hier sinnvoll zur Anlagen-Typ-Frage zurueck (siehe
// vfc-dialog-linienzug-modus-waehlen/c:VarioFoerderer).
: row {
alignment = centered;
: button { key = "back"; label = "Zurueck"; fixed_width = true; width = 12; }
spacer;
: button { key = "accept"; label = "Ok Weiter"; is_default = true; fixed_width = true; width = 12; }
spacer;
: button { key = "cancel"; label = "Abbrechen"; is_cancel = true; fixed_width = true; width = 12; }
}
}
// Startpunkt der Anlage waehlen - Punktwahl-Button + Anzeige, analog
// vflw_punkt_zahl (dcl/vf_linienzug_wizard.dcl): der Button schliesst den
// Dialog (done_dialog 2), DANACH laeuft getpoint auf der Kommandozeile
// (aus einem action_tile-Callback heraus funktioniert getpoint in BricsCAD
// nicht), der Dialog wird danach mit der Anzeige erneut aufgebaut. "kopf"
// und "pt_anzeige" werden per set_tile aus ssg-text befuellt (siehe
// vfc-dialog-startpunkt-waehlen, vf_core.lsp) - deshalb sprachunabhaengig
// nutzbar. Button-Chrome bleibt hart deutsch, wie im Rest dieser Datei.
vfc_startpunkt : dialog {
label = "VarioFoerderer - Startpunkt";
: column {
: text {
key = "kopf";
label = "";
width = 50;
}
: row {
: button {
key = "pick";
label = "Punkt waehlen...";
fixed_width = true;
width = 18;
}
: text {
key = "pt_anzeige";
label = "(kein Punkt gewaehlt)";
}
}
}
: row {
alignment = centered;
: button { key = "accept"; label = "Ok Weiter"; is_default = true; fixed_width = true; width = 12; }
spacer;
: button { key = "cancel"; label = "Abbrechen"; is_cancel = true; fixed_width = true; width = 12; }
}
}
variofoerderer_basis : dialog {
label = "VarioFoerderer (Standard) - Eingabe";
@@ -115,24 +173,24 @@ variofoerderer_basis : dialog {
label = "Horizontale Distanz deltaL (mm):";
edit_width = 10;
}
: edit_box {
key = "deltah";
label = "Hoehenunterschied deltaH (mm):";
edit_width = 10;
}
}
: row {
: popup_list {
key = "richtung";
label = "Foerderrichtung:";
width = 16;
}
}
: row {
: edit_box {
key = "einfuegehoehe";
label = "Einfuegehoehe (mm):";
edit_width = 10;
}
: edit_box {
key = "deltah";
label = "Hoehenunterschied deltaH (mm):";
edit_width = 10;
}
}
}
@@ -144,15 +202,17 @@ variofoerderer_basis : dialog {
label = "Fahrtrichtung:";
width = 30;
}
: popup_list {
key = "seite";
label = "Seite:";
width = 16;
}
: popup_list {
key = "motorseite";
label = "Motorseite:";
width = 16;
: row {
: popup_list {
key = "seite";
label = "Seite:";
width = 16;
}
: popup_list {
key = "motorseite";
label = "Motorseite:";
width = 16;
}
}
: popup_list {
key = "dimension";
@@ -211,3 +271,25 @@ variofoerderer_winkel : dialog {
ok_cancel;
}
// Baurichtung (hz) je unmarkiertem VF_n-Fund abfragen (VARIOFOERDERER_
// NACHRUESTEN). "kopf" per set_tile aus ssg-text befuellt (Blockname +
// erkannter Typ), deshalb sprachunabhaengig nutzbar - Button-Chrome bleibt
// hart deutsch wie der Rest dieser Datei. "Abbrechen" bricht nur den
// aktuellen Fund ab: der vorbelegte default-hz wird fuer DIESEN Fund
// uebernommen (Aufrufer sieht 'ABBRUCH, kein Rueckfall auf die Konsole) -
// die ganze Nachruesten-Schleife laeuft weiter, kein Gesamtabbruch.
vfs_nachruesten_hz : dialog {
label = "VarioFoerderer nachruesten - Baurichtung";
: column {
: text { key = "kopf"; label = ""; width = 50; }
: edit_box {
key = "hz";
label = "Baurichtung hz (Grad):";
edit_width = 10;
}
}
ok_cancel;
}
+18 -10
View File
@@ -523,12 +523,18 @@ vflw_horizontal : dialog {
}
// "Naechstes Element waehlen" - Hauptmenue des Linienzug-Aufbaus (Modus 1).
// IMMER alle 6 Optionen im Dialog vorhanden (stabile Keys) - "Vario-Kurve"
// IMMER alle 5 Optionen im Dialog vorhanden (stabile Keys) - "Vario-Kurve"
// wird per mode_tile deaktiviert, wenn kein echter Kettenanfang vorliegt
// (siehe vflw-gruppe-naechstes-element-impl, das dort auch die Positions-
// Nummerierung passend umrechnet). Radio-Buttons statt Dropdown, Labels fest
// deutsch, OHNE Nummern-Prefix (anders als die Konsolen-Variante - hier
// braucht es keine Zifferneingabe).
// braucht es keine Zifferneingabe). GF-Optionen stehen zuerst, VF-Optionen
// danach (nur Reihenfolge, kein echtes 2-Spalten-Layout: radio_button-Tiles
// muessen DIREKTE Kinder EINES Clusters sein, sonst ist die gegenseitige
// Ausschliesslichkeit kaputt - siehe Warnung bei vflw_winkel_hoehen unten,
// per Test bestaetigt). "Neue Linie BIS Kettenende" ist kein Radio mehr,
// sondern der eigene Button "OK und Abschliessen" unten (ruft direkt Slot 6
// auf, ohne vorher eine Radio-Auswahl zu verlangen).
vflw_naechstes_element : dialog {
label = "VarioFoerderer Assistent";
@@ -542,27 +548,29 @@ vflw_naechstes_element : dialog {
key = "wahl";
label = "";
: radio_button { key = "wahl_gfbogen"; label = "GF-Bogen (horizontale Kurve)"; }
: radio_button { key = "wahl_variokurve"; label = "Vario-Kurve (horizontale Kurve, 30/60/90 Grad)"; }
: radio_button { key = "wahl_liniegf"; label = "Neue Linie: GF (Gefaellestrecke)"; value = "1"; }
: radio_button { key = "wahl_variokurve"; label = "Vario-Kurve (horizontale Kurve, 30/60/90 Grad)"; }
: radio_button { key = "wahl_linievf"; label = "Neue Linie: Ab/Auf VF (VarioFoerderer-Einheit)"; }
: radio_button { key = "wahl_horizontalvf"; label = "Neue VF mit horizontalem Anfang (Horizontal-Stueck)"; }
: radio_button { key = "wahl_linieende"; label = "Neue Linie BIS Kettenende (danach Separator + ES-Element)"; }
}
}
// PROTOTYP "Zurueck"-Button (siehe Plan curious-prancing-parasol.md): ersetzt
// ok_cancel durch eine eigene 3-Button-Zeile. done_dialog-Codes: 0=Abbrechen
// ok_cancel durch eine eigene 4-Button-Zeile. done_dialog-Codes: 0=Abbrechen
// (unveraendert, is_cancel -> ESC/Leertaste wirkt weiterhin), 1=Weiter
// (unveraendert, is_default), NEU 2=Zurueck (verwirft das zuletzt gebaute
// (unveraendert, is_default), 2=Zurueck (verwirft das zuletzt gebaute
// Kettenglied und fragt es neu ab, siehe vflw-gruppe-naechstes-element-impl/
// vfl-modus-abbruch-sichern).
// vfl-modus-abbruch-sichern), NEU 3=Abschliessen (entspricht der fruehen
// Radio-Option "Neue Linie BIS Kettenende" - ignoriert die Radio-Auswahl).
: row {
alignment = centered;
: button { key = "back"; label = "Zurueck"; fixed_width = true; width = 12; }
: button { key = "back"; label = "Zurueck"; fixed_width = true; width = 12; }
spacer;
: button { key = "accept"; label = "Ok Weiter"; is_default = true; fixed_width = true; width = 12; }
: button { key = "accept"; label = "Ok Weiter"; is_default = true; fixed_width = true; width = 12; }
spacer;
: button { key = "cancel"; label = "Abbrechen"; is_cancel = true; fixed_width = true; width = 12; }
: button { key = "abschliessen"; label = "OK und Abschliessen"; fixed_width = true; width = 18; }
spacer;
: button { key = "cancel"; label = "Abbrechen"; is_cancel = true; fixed_width = true; width = 12; }
}
}
+319 -40
View File
@@ -1,85 +1,364 @@
# FAQ - Dokumentation
- [FAQ - Dokumentation](#faq---dokumentation)
- [Allgemein](#allgemein)
- [Darf ich Baugruppen kopieren?](#darf-ich-baugruppen-kopieren)
- [Darf ich Baugruppen auflösen?](#darf-ich-baugruppen-auflösen)
- [Darf ich Attribute in den Baugruppen manuell ändern?](#darf-ich-attribute-in-den-baugruppen-manuell-ändern)
- [Darf ich Baugruppen mustern?](#darf-ich-baugruppen-mustern)
- [1. Kreisel](#1-kreisel)
- [1.1 Zusammensetzung, Abhängigkeiten, Randbedingungen](#11-zusammensetzung-abhängigkeiten-randbedingungen)
- [Zusammensetzung einer Kreiselbaugruppe](#zusammensetzung-einer-kreiselbaugruppe)
- [Einfügepunkt und Koordinatensystem](#einfügepunkt-und-koordinatensystem)
- [Höhe (Laufprofil und Unterkante)](#höhe-laufprofil-und-unterkante)
- [1.2 Funktionen](#12-funktionen)
- [Wie füge ich einen Kreisel ein?](#wie-füge-ich-einen-kreisel-ein)
- [Wie drehe ich einen Kreisel?](#wie-drehe-ich-einen-kreisel)
- [Wie ändere ich die Höhe eines Kreisels?](#wie-ändere-ich-die-höhe-eines-kreisels)
- [Wie ändere ich die Länge eines Kreisels?](#wie-ändere-ich-die-länge-eines-kreisels)
- [2. Gefällestrecke](#2-gefällestrecke)
- [2.1 Zusammensetzung, Abhängigkeiten, Randbedingungen](#21-zusammensetzung-abhängigkeiten-randbedingungen)
- [Zusammensetzung einer Gefällestrecke](#zusammensetzung-einer-gefällestrecke)
- [Einfügepunkt und Koordinatensystem](#einfügepunkt-und-koordinatensystem-1)
- [Höhe und Übergang zu Kreiselkoordinatensystem (Unterkante SP \<-\> Oberkante LP)](#höhe-und-übergang-zu-kreiselkoordinatensystem-unterkante-sp---oberkante-lp)
- [2.2 Funktionen](#22-funktionen)
- [Wie füge ich eine Gefällestrecke ein?](#wie-füge-ich-eine-gefällestrecke-ein)
- [Wie drehe ich eine Gefällestrecke?](#wie-drehe-ich-eine-gefällestrecke)
- [Wie ändere ich die Länge einer Gefällestrecke?](#wie-ändere-ich-die-länge-einer-gefällestrecke)
- [Wie baue ich eine Gefällestrecke mit einer bestimmten Kapazität als Puffer (freie Länge des Stauprofils)](#wie-baue-ich-eine-gefällestrecke-mit-einer-bestimmten-kapazität-als-puffer-freie-länge-des-stauprofils)
- [Wie baue ich eine Gefällestrecke zwischen zwei Kreiseln mit definiertem Abstand?](#wie-baue-ich-eine-gefällestrecke-zwischen-zwei-kreiseln-mit-definiertem-abstand)
- [Wie baue ich eine Gefällestrecke mit Kurven als Übergang zwischen zwei Kreiseln mit unterschiedlicher Höhe?](#wie-baue-ich-eine-gefällestrecke-mit-kurven-als-übergang-zwischen-zwei-kreiseln-mit-unterschiedlicher-höhe)
- [Wie baue ich eine Gefällestrecke mit manueller Höhenüberwindung ohne VF (QS-Platz Mubea)](#wie-baue-ich-eine-gefällestrecke-mit-manueller-höhenüberwindung-ohne-vf-qs-platz-mubea)
- [3. Varioförderer](#3-varioförderer)
- [3.1 Zusammensetzung, Abhängigkeiten, Randbedingungen](#31-zusammensetzung-abhängigkeiten-randbedingungen)
- [Zusammensetzung eines Varioförderer mit allen möglichen Komponenten](#zusammensetzung-eines-varioförderer-mit-allen-möglichen-komponenten)
- [Verfügbare Steigungen](#verfügbare-steigungen)
- [Einfügepunkt und Koordinatensystem](#einfügepunkt-und-koordinatensystem-2)
- [Höhe und Übergang zu Kreiselkoordinatensystem (Unterkante SP \<-\> Oberkante LP)](#höhe-und-übergang-zu-kreiselkoordinatensystem-unterkante-sp---oberkante-lp-1)
- [3.2 Funktionen](#32-funktionen)
- [Welche Einfügemodi gibt es und wie unterscheiden sich diese?](#welche-einfügemodi-gibt-es-und-wie-unterscheiden-sich-diese)
- [Wie baue ich einen VF in einem Puffer mit Gefällestrecken als Umschleusung?](#wie-baue-ich-einen-vf-in-einem-puffer-mit-gefällestrecken-als-umschleusung)
- [Wie baue ich einen VF zur Anfahrung einer bestimmten Höhe (Arbeitsplatz)?](#wie-baue-ich-einen-vf-zur-anfahrung-einer-bestimmten-höhe-arbeitsplatz)
- [Wie baue ich einen VF als Übergang zwischen zwei verschiedenen Kreiseln (unterschiedliche Höhe und Position x/y/z)](#wie-baue-ich-einen-vf-als-übergang-zwischen-zwei-verschiedenen-kreiseln-unterschiedliche-höhe-und-position-xyz)
- [Wie baue ich einen Förderer zu Ebenenüberquerung zwischen zwei Pufferblöcken, welche übereinander positioniert sind?](#wie-baue-ich-einen-förderer-zu-ebenenüberquerung-zwischen-zwei-pufferblöcken-welche-übereinander-positioniert-sind)
- [Wie baue ich eine Strecke mit mehreren VF und Gefällestrecken hintereinander zur Überbrückung von großen Entfernungen?](#wie-baue-ich-eine-strecke-mit-mehreren-vf-und-gefällestrecken-hintereinander-zur-überbrückung-von-großen-entfernungen)
- [4. Scanner und Separator](#4-scanner-und-separator)
- [4.1 Zusammensetzung, Abhängigkeiten, Randbedingungen](#41-zusammensetzung-abhängigkeiten-randbedingungen)
- [Einfügepunkt und Koordinatensystem](#einfügepunkt-und-koordinatensystem-3)
- [In welchen Baugruppen sind Scanner und Separatoren bereits eingebaut (Blöcke)?](#in-welchen-baugruppen-sind-scanner-und-separatoren-bereits-eingebaut-blöcke)
- [Zuordnung der frei platzierten Scanner und Separatoren zu einem Kreisel, Gefällestrecke oder VF](#zuordnung-der-frei-platzierten-scanner-und-separatoren-zu-einem-kreisel-gefällestrecke-oder-vf)
- [4.2 Funktionen](#42-funktionen)
- [Wie füge ich einen Scanner ein?](#wie-füge-ich-einen-scanner-ein)
- [Wie füge ich einen Separator ein?](#wie-füge-ich-einen-separator-ein)
- [5. Be- und Entladung](#5-be--und-entladung)
- [5.1 Zusammensetzung, Abhängigkeiten, Randbedingungen](#51-zusammensetzung-abhängigkeiten-randbedingungen)
- [Einfügepunkt und Koordinatensystem](#einfügepunkt-und-koordinatensystem-4)
- [Übergang zu Rutschstange (Oberkante LP \<-\> Oberkante Rutschprofil)](#übergang-zu-rutschstange-oberkante-lp---oberkante-rutschprofil)
- [5.2 Funktionen](#52-funktionen)
- [Wie füge ich eine Beladung oder Entladung ein?](#wie-füge-ich-eine-beladung-oder-entladung-ein)
- [Wie binde ich einen FLEX Förderer an die Entladung an?](#wie-binde-ich-einen-flex-förderer-an-die-entladung-an)
## Allgemein
- Darf ich Baugruppen kopieren?
- Darf ich Baugruppen auflösen?
- Darf ich Attribute in den Baugruppen manuell ändern?
- Darf ich Baugruppen mustern?
### Darf ich Baugruppen kopieren?
Natürlich darf man eine erzeugte Baugruppe kopieren. Beim Export erhält es dann eine neue eigene ID, so dass keine Verwechslungen im CSV File auftreten können.
### Darf ich Baugruppen auflösen?
**Nein**. Der Export erkennt Baugruppen anhand ihres Blocknamens. Wird eine Baugruppe aufgelöst (EXPLODE), fällt sie komplett aus dem Export heraus: keine ID-Vergabe, keine Export-Zeile, keine Scanner-/Separator-Zuordnung. Zusätzlich gehen die Attribute dabei verloren, da sie nicht mehr mit einem Block verknüpft sind.
### Darf ich Attribute in den Baugruppen manuell ändern?
Grundsätzlich **ja**, dafür gibt es teilweise auch eigene Dialoge (z.B. zum Bearbeiten eines Kreisels). Zwei Punkte sind dabei zu beachten:
- **ID**: Wird eine ID manuell auf einen bereits vergebenen Wert gesetzt, wird das beim nächsten Export als Duplikat erkannt und der zweiten gefundenen Baugruppe automatisch eine neue ID zugewiesen – der manuell gesetzte Wert kann also überschrieben werden.
- **Artikelnummer / Teileart**: Hier gibt es keine automatische Prüfung. Ein falsch gesetzter Wert führt zu einer falschen Merkmalszuordnung im Sivas-Export, ohne dass das vorher auffällt.
Andere Attribute (Bezeichnung, Höhe, Abstand etc.) können bedenkenlos manuell angepasst werden, sollten aber nach Möglichkeit über die vorgesehenen Edit-Befehle statt direkt am Attribut geändert werden, damit die Geometrie konsistent bleibt.
![Attribute](images/Kreisel-attribute.png)
*Abbildung: Attribute eines Kreisels*
### Darf ich Baugruppen mustern?
**Ja**. Gemusterte Kopien tragen zunächst dieselbe ID wie das Original, beim nächsten Export-Lauf wird das als Duplikat erkannt und den weiteren Instanzen automatisch eine neue, eindeutige ID zugewiesen. Die Eindeutigkeit ist also am Ende gewährleistet, sobald einmal der Export (oder die ID-Prüfung) gelaufen ist.
## 1. Kreisel
### 1.1 Zusammensetzung, Abhängigkeiten, Randbedingungen
- Zusammensetzung einer Kreiselbaugruppe
- Einfügepunkt und Koordinatensystem
- Höhe (Laufprofil und Unterkante)
#### Zusammensetzung einer Kreiselbaugruppe
Eine Kreiselbaugruppe besteht aus:
- einem **AN8-Kreis** (Antriebsstation)
- einem **SP8-Kreis** (Spannstation)
- zwei **Tangentenlinien** (oben/unten)
- optional zwei **PIN-Linien** (nur bei Kreiselart "PIN")
- einem **Beschriftungstext** ("KREISEL n: Art_Abstand")
- Attributen wie ID, Bezeichnung, Artikelnummer, Montagehöhe, Kreiselart, Abstand, Anzahl Separator/Scanner/Rampen, Gerüsttyp, Drehrichtung, Drehung, Nummer
Das verwandte Eckrad besteht nur aus einem AN8-Kreis plus eigenen Attributen – ohne Tangenten, PIN-Linien oder Beschriftung.
#### Einfügepunkt und Koordinatensystem
Bei Rotation 0 (horizontal) liegt der Einfügepunkt auf der linken Kreistangente der AN-Seite (Antriebsstation); die Spannstation liegt im Abstand "Abstand" dahinter. Die Rotation dreht den gesamten Kreisel um diesen Punkt.
Beim Verbinden zweier Kreisel ist der Startpunkt explizit der äusserste AN-Punkt (Antriebsstation) und der Endpunkt der äusserste SP-Punkt (Spannstation); Abstand und Rotation werden aus Distanz und Winkel der beiden Klickpunkte berechnet. Beim Eckrad ist der Einfügepunkt der berechnete Kreismittelpunkt (Berührpunkt + Radius in Klickrichtung).
#### Höhe (Laufprofil und Unterkante)
Die Höhe wird über die Z-Koordinate des Einfügepunkts gesteuert (ein separates Laufprofil/Unterkante-Konzept gibt es beim Kreisel nicht). Wird beim Einfügen ein Punkt mit Höhe > 0 gewählt, gilt diese; ansonsten greift ein konfigurierbarer Standardwert (Default 2000 mm). Über den Bearbeiten-Dialog kann die Höhe jederzeit nachträglich geändert werden – der Kreisel wird dann mit der neuen Höhe neu aufgebaut.
> **Hinweis**: Eine getrennte Betrachtung von "Laufprofil" und "Unterkante" (zwei unterschiedliche Bezugsebenen) ist technisch nicht hinterlegt – nur ein einziger Höhenwert steuert die Position. Der Zusammenhang zu Gefällestrecke/VF-Übergängen (siehe unten) ist eine reine Konstruktionsfrage.
### 1.2 Funktionen
- Wie füge ich einen Kreisel ein?
- Wie drehe ich einen Kreisel?
- Wie ändere ich die Höhe eines Kreisels?
- Wie ändere ich die Länge eines Kreisels?
#### Wie füge ich einen Kreisel ein?
Unter *ILS -> Kreisel-Module -> Einfuegen*. Dann die Fragen nach Anfangspunkt, Länge und Höhe des Kreisels beantworten. Alternativ *ILS -> Kreisel-Module -> Verbinden*, um einen Kreisel direkt an einen bestehenden anzuschliessen.
#### Wie drehe ich einen Kreisel?
Am einfachsten durch einen Doppelklick auf den Kreisel und der Auswahl des Dropdowns Ausrichtung (Horizontal, Vertikal). Alternativ über *ILS -> Kreisel-Module -> Bearbeiten* (oder per Rechtsklick auf den Kreisel -> *Kreisel bearbeiten*).
![Oberfläche Kreisel](images/Kreisel-mit-gui.png)
*Abbildung: Kreisel-Dialog mit GUI-Eingabe*
#### Wie ändere ich die Höhe eines Kreisels?
Durch einen Doppelklick auf den Kreisel und der Eingabe der neuen Höhe unter Hoehe (mm). Alternativ über *ILS -> Kreisel-Module -> Bearbeiten* (oder per Rechtsklick auf den Kreisel -> *Kreisel bearbeiten*).
#### Wie ändere ich die Länge eines Kreisels?
Durch einen Doppelklick auf den Kreisel und der Eingabe des neuen Abstands im Bearbeiten-Dialog. Alternativ über *ILS -> Kreisel-Module -> Bearbeiten* (oder per Rechtsklick auf den Kreisel -> *Kreisel bearbeiten*).
## 2. Gefällestrecke
- einfach
- aus 3D Linie
- aus Linienzug
- QC mit 30 Grad ES/AS
- QC mit 90 Grad ES/AS
### 2.1 Zusammensetzung, Abhängigkeiten, Randbedingungen
- Zusammensetzung einer Gefällestrecke
- Einfügepunkt und Koordinatensystem
- Höhe und Übergang zu Kreiselkoordinatensystem (Unterkante SP <-> Oberkante LP)
#### Zusammensetzung einer Gefällestrecke
Im Standardfall besteht eine Gefällestrecke aus vier in Reihe eingefügten Bausteinen:
1. **AUS-Element**
2. **Staustrecke** (auf die gewünschte Länge skaliert, um den Gefällewinkel geneigt)
3. **Separator**
4. **EIN-Element**
Beim Aufbau entlang eines frei gezeichneten Linienzugs kommen zusätzlich Gefällebogen-Bausteine hinzu; vor jedem Bogen wird automatisch ein weiterer Separator eingefügt.
![Gefaellestrecke](images/gefaellestrecke.png)
*Abbildung: Gefällestrecke*
#### Einfügepunkt und Koordinatensystem
Jeder Baustein hat ein Ein- und ein Ausgangskoordinatensystem, über die die Bausteine beim Verketten passgenau aneinandergesetzt werden. Beim Verketten kommt das Eingangskoordinatensystem (nicht der Block-Ursprung) auf den Zielpunkt zu liegen.
Der vom Anwender gepickte Startpunkt der Gefällestrecke entspricht dem Eingangskoordinatensystem des AUS-Elements; die Förderstrecken-Mittelachse läuft durch diesen Punkt. Am Kettenende wird die Höhe hingegen am Ausgangskoordinatensystem des EIN-Elements gemessen, damit dieses exakt der Zielhöhe entspricht.
#### Höhe und Übergang zu Kreiselkoordinatensystem (Unterkante SP <-> Oberkante LP)
> **Hinweis**: Eine feste Höhenbeziehung zwischen "Unterkante SP" (Stauprofil) und "Oberkante LP" (Laufprofil eines Kreisels) ist nicht hinterlegt – das ist eine reine Konstruktionsfrage. Die Anschlusshöhe wird vom Konstrukteur über die Parameter Einfügehöhe/Zielhöhe gesteuert.
### 2.2 Funktionen
- Wie füge ich eine Gefällestrecke ein?
- Wie drehe ich eine Gefällestrecke?
- Wie ändere ich die Länge einer Gefällestrecke?
- Wie baue ich eine Gefällestrecke mit einer bestimmten Kapazität als Puffer (freie Länge des Stauprofils)
- Wie baue ich eine Gefällestrecke zwischen zwei Kreiseln mit definiertem Abstand?
- Wie baue ich eine Gefällestrecke mit Kurven als Übergang zwischen zwei Kreiseln mit unterschiedlicher Höhe?
- Wie baue ich eine Gefällestrecke mit manueller Höhenüberwindung ohne VF (QS-Platz Mubea)
#### Wie füge ich eine Gefällestrecke ein?
Unter *ILS -> Gefaellestrecke -> einfach* für den Standardfall (Anfangspunkt, Länge, Höhe, Winkel über Dialog). Für eine Gefällestrecke entlang einer vorgezeichneten 3D-Linie *ILS -> Gefaellestrecke -> aus 3D-Linie*, für einen Linienzug aus mehreren Linien/Bögen *ILS -> Gefaellestrecke -> aus Linienzug (LINE + ARC)*.
#### Wie drehe ich eine Gefällestrecke?
Durch einen Doppelklick auf die Gefällestrecke (öffnet den Bearbeiten-Dialog mit denselben Eingaben wie beim Einfügen) oder per Rechtsklick -> *Gefaellestrecke bearbeiten*.
#### Wie ändere ich die Länge einer Gefällestrecke?
Durch einen Doppelklick auf die Gefällestrecke und Eingabe der neuen Länge im Bearbeiten-Dialog, oder per Rechtsklick -> *Gefaellestrecke bearbeiten*.
#### Wie baue ich eine Gefällestrecke mit einer bestimmten Kapazität als Puffer (freie Länge des Stauprofils)
#### Wie baue ich eine Gefällestrecke zwischen zwei Kreiseln mit definiertem Abstand?
#### Wie baue ich eine Gefällestrecke mit Kurven als Übergang zwischen zwei Kreiseln mit unterschiedlicher Höhe?
#### Wie baue ich eine Gefällestrecke mit manueller Höhenüberwindung ohne VF (QS-Platz Mubea)
#### Was sind "QC mit 30/90 Grad ES/AS" und "QC mit U-Form"?
Zwei Spezialbefehle fürs Zeichnen eines Linienzugs vorab, bei denen die
komplette Kette danach **automatisch ohne weitere Rückfragen** gebaut wird
(`QcLinieMitGf`/`QcLinieMitGfUForm`, technisch über den Linienzug-Ablauf
(Streckengruppe) mit einem erzwungenen Modus gebaut, im Menü aber bewusst
unter *ILS -> Gefaellestrecke* eingeordnet, da das Ergebnis eine reine
Gefällestrecke von AS bis ES ist): Statt bei jedem Schritt zu fragen "Welches
Element als nächstes?", wird direkt die Gefällestrecke zwischen den beiden
gewählten Punkten gebaut. "QC mit U-Form" (`QcLinieMitGfUForm`) löst
zusätzlich eine gefaltete (U-förmige) Linienführung: zwei Gefällestrecken-
Abschnitte mit unterschiedlicher Neigung (3°/9°) werden über ein
Gleichungssystem aus Höhen- und Lagebilanz passend zur Zielgeometrie
berechnet, nur am Kettenanfang nutzbar.
## 3. Varioförderer
Varioförderer können auf verschiedene Arten gebaut werden:
1. Standard
2. Etage
3. Streckengruppe
- Manuelle Eingabe
- 3D-OBjekte mit Ziel-höhe
- 3D Objekte Stückweise (wird gerade noch implementiert bzw. ist expirementell)
Der **"Standard Förderer"** ist die Verbindung von zwei Kreiseln mit einem definierten Abstand und (wenn nötig) einer Höhendifferenz. (z.B. für eine Umschleusung in einem Gefällepuffer)
Ein **Etagenförderer** hat 30° Aussschleuselemente und wird verwendet, um zwei Kreisel über eine Etage zu verbinden. Diese beiden Kreisel müssen dabei übereinander liegen.
Standard und Etage können aufgerufen werden mit _"Werte manuell"_ oder _"3D - Linie"_.
- Bei "_Werte Manuell_" definiert man den Verlauf durch Höhe und Länge über die Eingabe in einer Oberfläche.
- bei "_3D Linie_" ist die Auswahl einer Gerade im Raum möglich. Damit wird Richtung, Länge und Höhendifferenz angegeben. Dadurch werden diese Werte in die Oberfläche übernommen. Der beliebige Winkel in der Ebene kann durch die Linie festgelegt werden und ist nicht auf die Raster 0,90,270 Grad festgelegt
Die **Variablen Förderer** könne auf drei verschiedene Arten definiert werden:
- die _manuelle Eingabe_ frägt nach der Definition des AS Elementes ab, ob man abwechselnd eine GF oder einen VF definieren möchte. Mit einem Knopf unten kann man den Assistenten abschliessen und das ES erzeugen
- _Eine 3D Linie_ muss aus Geraden und Bögen (Winkel 30° mit dem Radius 500mm) bestehen. Wenn eine 3D Linie für Verlauf mit der korrekten Zielhöhe existiert, kann man iterativ die Einzelelemente (oder auch mehrere) dieser Einzellinien Linie anwählen, um den nächsten Förderer oder den nöchsten Gefälle-Anteil zu definieren.
### 3.1 Zusammensetzung, Abhängigkeiten, Randbedingungen
- Zusammensetzung eines Varioförderer mit allen möglichen Komponenten
- Verfügbare Steigungen
- Einfügepunkt und Koordinatensystem
- Höhe und Übergang zu Kreiselkoordinatensystem (Unterkante SP <-> Oberkante LP)
#### Zusammensetzung eines Varioförderer mit allen möglichen Komponenten
Es gibt drei Anlagentypen:
- **Standard**: gerade AS-/ES-Elemente + Staustrecke + Umlenk-/Motorstation + Separatoren, feste horizontale Blöcke.
- **Etage**: wie Standard, aber mit Etagen-Schrägsektion/-Bögen statt gerader AS-/ES-Elemente.
- **Linienzug**: frei aus der Zeichnung gebaute Kette aus AS-/ES-Element, Gefälle-Bogen, Vario-Kurve, horizontalem/geneigtem Förderer-Segment, Separatoren und Umlenk-/Motorstation.
Der Bauteilablauf folgt dabei grundsätzlich: Startpunkt → optionales AS-Element → beliebige Folge aus Bogen / Gerade / Auf-Ab-Förderer / Horizontal-Förderer (mit Vario-Kurve bzw. horizontalem Zwischenstück) → Kettenende mit optionalem ES-Element. Jede Förderer-Einheit besteht aus Umlenkstation + Motorstation plus Separator(en).
![Variofoerderer](images/variofoerderer.png)
*Abbildung: Varioförderer Standard*
#### Verfügbare Steigungen
Zwei getrennte Winkel-Systeme:
1. **Vertikale Neigung** (Gefälle/Steigung in Fahrtrichtung): aus einer festen Winkel-Tabelle (3, 6, 9, 12, 15, 18, 21, 27, 33, 39, 45, 51 Grad), maximal 51 Grad.
2. **Horizontale Kurven** (Gefälle-Bogen und Vario-Kurve): 30, 60 oder 90 Grad.
**Wichtige Ausnahme**: AS-/ES-Elemente haben nur **30 und 90 Grad**, explizit **keine** 60-Grad-Variante. Die 30/60/90-Grad-Dreiteilung gilt also für Bögen/Vario-Kurve, nicht für AS-/ES-Elemente.
#### Einfügepunkt und Koordinatensystem
Identisch zum Gefällestrecke-Mechanismus: Die Verkettung erfolgt über Ein- und Ausgangskoordinatensysteme jedes Bausteins, das Eingangskoordinatensystem kommt dabei auf den Zielpunkt zu liegen.
Beim Standard-Typ wird vor dem ersten Dialog der Startpunkt (X/Y) gepickt, die Z-Höhe kommt separat aus dem Dialogfeld "Einfügehöhe". Bei Etage ebenso. Im Linienzug-Modus ist der Startpunkt der erste Punktwahl-Schritt, die Starthöhe ein separates Zahlenfeld mit Default = Z des Punkts.
#### Höhe und Übergang zu Kreiselkoordinatensystem (Unterkante SP <-> Oberkante LP)
> **Hinweis**: Wie bei der Gefällestrecke gibt es keine feste Höhenbeziehung zwischen "Unterkante SP" und "Oberkante LP" eines Kreisels. Anschlusshöhen werden über die Parameter Einfügehöhe/Zielhöhe gesteuert – das ist eine reine Konstruktionsfrage.
### 3.2 Funktionen
- Welche Einfügemodi gibt es und wie unterscheiden sich diese?
- Wie baue ich einen VF in einem Puffer mit Gefällestrecken als Umschleusung?
- Wie baue ich einen VF zur Anfahrung einer bestimmten Höhe (Arbeitsplatz)?
- Wie baue ich einen VF als Übergang zwischen zwei verschiedenen Kreiseln (unterschiedliche Höhe und Position x/y/z)
- Wie baue ich einen Förderer zu Ebenenüberquerung zwischen zwei Pufferblöcken, welche übereinander positioniert sind?
- Wie baue ich eine Strecke mit mehreren VF und Gefällestrecken hintereinander zur Überbrückung von großen Entfernungen?
#### Welche Einfügemodi gibt es und wie unterscheiden sich diese?
Unter *ILS -> Foerderer* stehen folgende Einfügemodi zur Verfügung:
- **Standard -> Werte manuell**: alle Werte (Längen, Winkel, Höhen) werden über einen Dialog abgefragt.
- **Standard -> aus 3D-Linie**: wie Standard, aber entlang einer vorgezeichneten 3D-Linie.
- **Etage -> Werte manuell** / **Etage -> aus 3D-Linie**: wie Standard, jedoch mit Etagen-Schrägsektion/-Bögen statt gerader AS-/ES-Elemente.
- **Streckengruppe**: frei aus der Zeichnung gebaute Kette, Schritt für Schritt über Dialoge/Konsole abgefragt (AS-Element, Bögen, Vario-Kurven, horizontale/geneigte Abschnitte, ES-Element).
![Variofoerderer dialog1](images/vf-gui1.png)
*Abbildung: Varioförderer Dialog zur Erzeugung*
![Variofoerderer dialog2](images/vf-gui2.png)
*Abbildung: Varioförderer Dialog zur Winkelbestimmung*
#### Wie baue ich einen VF in einem Puffer mit Gefällestrecken als Umschleusung?
Ich baue eine Gefällestrecke und kann dann mit einem Klick einen Varioförderer daneben bauen. Dazu die Gefällestrecke doppelklicken und dann auf den Knopf "VarioFoerderer daneben bauen" klicken.
![Variofoerderer dialog2](images/gf-vf-kombination.png)
*Abbildung: Erzeugung eines Varioförderers passend zur Gefällestrecke*
#### Wie baue ich einen VF zur Anfahrung einer bestimmten Höhe (Arbeitsplatz)?
Das macht man aus einer Streckengruppe aus aus mindestens einer GF und einer VF und den entsprechend nötigen Bögen. Eventuell noch die Verwendung eines horizontalen Anteils beim Varioförderer, um die Zielhöhe zu erreichen.
#### Wie baue ich einen VF als Übergang zwischen zwei verschiedenen Kreiseln (unterschiedliche Höhe und Position x/y/z)
Standardfall. Höhenunterschiede und Einfügehöhe einfach in Interface angeben.
![Variofoerderer dialog1](images/vf-gui1.png)
*Abbildung: Varioförderer Dialog zur Erzeugung*
#### Wie baue ich einen Förderer zu Ebenenüberquerung zwischen zwei Pufferblöcken, welche übereinander positioniert sind?
Dafür ist der sogenannte Etagenförderer vorgesehen.
*ILS -> Foerderer-> Etage*
#### Wie baue ich eine Strecke mit mehreren VF und Gefällestrecken hintereinander zur Überbrückung von großen Entfernungen?
Dies kann nur Stückweise erfolgen, indem man ausprobiert, welche GF VF Kombination welche Länge erreicht und dabei eine gewünschte Höhe nicht überschreitet. Danach kann man die einzelnen Einheiten zu Einem Mergen.
## 4. Scanner und Separator
### 4.1 Zusammensetzung, Abhängigkeiten, Randbedingungen
- Einfügepunkt und Koordinatensystem
- In welchen Baugruppen sind Scanner und Separatoren bereits eingebaut (Blöcke)?
- Zuordnung der frei platzierten Scanner und Separatoren zu einem Kreisel, Gefällestrecke oder VF
#### Einfügepunkt und Koordinatensystem
Scanner und Separatoren werden als frei platzierbare Einzel-Blöcke eingefügt. Der Einfügepunkt ist ein frei gewählter Punkt, die Rotation wird im Anschluss interaktiv am Cursor festgelegt.
Es gibt hier **kein** Koordinatensystem-Verkettungssystem wie bei Gefällestrecke/Varioförderer – der Block wird direkt an seinem Ursprung auf dem gewählten Punkt platziert.
#### In welchen Baugruppen sind Scanner und Separatoren bereits eingebaut (Blöcke)?
Innerhalb von **Gefällestrecken-** und **Varioförderer**-Ketten wird intern automatisch ein Separator eingefügt (als Trennsteg zwischen den Staustrecken-Segmenten). Diese verpackten Separatoren werden beim Export erkannt und in den Attributen "Anzahl Separator"/"Anzahl Scanner" der jeweiligen Baugruppe mitgezählt.
Reine Scanner-Blöcke sind dagegen **nicht** standardmässig in Gefällestrecke/Varioförderer/Kreisel verbaut – sie kommen nur als frei platzierte Einzelblöcke vor.
#### Zuordnung der frei platzierten Scanner und Separatoren zu einem Kreisel, Gefällestrecke oder VF
Es gibt **keine feste Verknüpfung** zum Zeitpunkt des Einfügens. Die Zuordnung erfolgt erst **nachträglich beim Export** über die geometrische Nähe: Scanner außerhalb einer Baugruppen-Umgrenzung werden per Abstand der nächstgelegenen Baugruppe zugeordnet; ist der Abstand zu mehreren Kandidaten nahezu gleich, wird das als "strittig" markiert und im Export entsprechend vermerkt.
Für Separatoren, die bereits in einer Kette verbaut sind, ist die Zuordnung dagegen von vornherein eindeutig.
**Fazit**: Die Zuordnung frei platzierter Scanner/Separatoren ist rein geometrisch (Abstand), keine feste Verknüpfung.
### 4.2 Funktionen
- Wie füge ich einen Scanner ein?
- Wie füge ich einen Separator ein?
#### Wie füge ich einen Scanner ein?
Unter *ILS -> Zusatzmodul -> Scanner einfuegen*. Dann Anfangspunkt auswählen und über den zweiten Klick den Winkel festsetzen.
#### Wie füge ich einen Separator ein?
Unter *ILS -> Zusatzmodul -> Separator einfuegen*. Dann Anfangspunkt auswählen und über den zweiten Klick den Winkel festsetzen.
## 5. Be- und Entladung
### 5.1 Zusammensetzung, Abhängigkeiten, Randbedingungen
- Einfügepunkt und Koordinatensystem
- Übergang zu Rutschstange (Oberkante LP <-> Oberkante Rutschprofil)
#### Einfügepunkt und Koordinatensystem
Be- und Entladung werden als frei platzierbare Einzel-Blöcke eingefügt. Wie bei Scanner/Separator ist der Einfügepunkt ein frei gewählter Punkt, die Rotation wird interaktiv am Cursor festgelegt – es gibt keine Koordinatensystem-Verkettung zu einer vorgelagerten Strecke, die Station steht für sich allein in der Zeichnung.
Bemerkenswert: Der Entladungsblock sitzt intern schräg im Raum, sodass bei der Koordinatenberechnung im Export eine zusätzliche Korrektur nötig ist, damit die Weltkoordinaten nicht verzerrt bzw. gespiegelt werden.
#### Übergang zu Rutschstange (Oberkante LP <-> Oberkante Rutschprofil)
> **Hinweis**: Eine feste Höhenbeziehung zwischen "Oberkante LP" und "Oberkante Rutschprofil" ist nicht hinterlegt. Diese Frage ist eine reine Konstruktionsfrage und sollte entsprechend beantwortet werden.
### 5.2 Funktionen
- Wie füge ich eine Beladung oder Entladung ein?
- Wie binde ich einen FLEX Förderer an die Entladung an?
#### Wie füge ich eine Beladung oder Entladung ein?
Unter *ILS -> Zusatzmodul -> BTMT-Beladung* bzw. *BTMT-Entladung*. Dann Anfangspunkt auswählen und über den zweiten Klick den Winkel festsetzen.
#### Wie binde ich einen FLEX Förderer an die Entladung an?
+7834
View File
File diff suppressed because it is too large Load Diff
Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

+449
View File
@@ -0,0 +1,449 @@
# JSON-Eingabe fuer den LISP-Bau
Welche Objekte sich aus einer JSON-Datei an einer gegebenen x/y/z-Koordinate
erzeugen lassen, in welchem Format sie beschrieben werden und welche
LISP-Routine sie baut. Grundlage sind die Testdaten in `tests/testdata/*.json`
und die Treiber in `tests/test_*.lsp`, die sie lesen.
Die zugehoerigen LISP-Routinen mit Signaturen stehen in
[lisp_methods.md](lisp_methods.md). Diese Seite ersetzt das fruehere
`tests/testdata/object_data.md` (geloescht in Commit `e147b89`, auf das Code-
Kommentare teilweise noch verweisen).
**Feldnamen als Python-Konstanten**: `lib/testdata_schema.py` buendelt die
Feldnamen/festen Werte der Abschnitte 1 (Kreisel), 2 (Einzelbloecke), 3 (VF
Standard/Etage) und 4.1 (Gefaellestrecke Modus 1) als benannte Konstanten
(`sch.F_ABSTAND`, `sch.SEITE_LINKS`, ...), genutzt von `lib/dxf_anlage_export.py`
(eigene, mit unseren Makros gebaute Zeichnungen). `lib/dxf_scan_components.py`
(fremde Zeichnungen) hat dieselben Feldnamen weiterhin als eigene String-
Literale - gleiches Schema, noch nicht auf das gemeinsame Modul umgestellt.
---
## 0. Uebersicht
| Objekt | Erkennungsmerkmal im JSON | Bau-Routine (Produktion) | Koordinaten-Eingang | Beispiel-Datei |
|---|---|---|---|---|
| [Kreisel (Insert)](#1-kreisel) | `"function": "insert"`, KEIN `block` | `kreisel-insert-script` | `x`,`y`,`z` = Einfuegepunkt | `kreisel_tests.json`, `mubea.json`, `hundm05.json`, `dematic_arvato.json` |
| [Kreisel (Connect)](#12-connect-start--und-endpunkt) | `"function": "connect"` | `kreisel-connect-script` | `start_*`, `end_*` | (nur `test_kreisel.lsp`, z.Z. kein Datensatz) |
| [Einzelblock](#2-einzelbloecke-separator-scanner-btmt-eingangausgang-vario-bausteine) (Separator, Scanner, BTMT, Eingang/Ausgang, Vario-Bausteine) | `"function": "insert"` + `"block"` | direktes `_.INSERT` nach `ssg-ils-block-laden` | `x`,`y`,`z` + `rotation` | `mubea.json`, `hundm05.json`, `dematic_arvato.json` |
| [VarioFoerderer Standard](#3-variofoerderer-standard-und-etage) | `test_id` beginnt mit `VF_`, `typ` fehlt oder `"standard"` | `berechne-alle-winkel` + `variofoerderer-einfuegen` + `vf-block-erstellen` | `x`,`y`,`z` = KS_EIN des AS-Elements | `mubea.json`, `foerderer_tests.json` |
| [VarioFoerderer Etage](#3-variofoerderer-standard-und-etage) | `test_id` `VF_*` + `"typ": "etage"` | `berechne-etage` + `etage-foerderanlage-einfuegen` + `vf-block-erstellen` | wie Standard | `mubea.json` |
| [Gefaellestrecke Modus 1](#4-gefaellestrecke) | `test_id` `GF_*` bzw. `"modus": 1` | `gefaellestrecke-einfuegen` (bzw. `gf-rebuild`) | `start_mm` = KS_EIN des AS-Elements | `mubea.json`, `gefaellestrecke_tests.json` |
| [Gefaellestrecke Modus 2](#42-modus-2---richtung-aus-zwei-punkten) | `"modus": 2` | wie Modus 1, `deltaL`/`hz` aus zwei Punkten | `start_mm` + `linie_start_mm`/`linie_ende_mm` | `gefaellestrecke_tests.json` |
| [Gefaellestrecke Modus 3](#43-modus-3---linienzug) | `"modus": 3` | nur ueber `test_gefaellestrecke.lsp` | `start_mm`, `ende_mm`, `bogen` | `gefaellestrecke_tests.json` |
| [VF-Linienzug-Kette (Spec)](#5-vf-linienzug-kette-spec) | Kopf mit `spec_id`, danach `glied`/`sub` | `vsp-bau-aus-spec` (Replay durch `vf-linienzug-modus`) | `start_punkt` = Kettenanfang | `hundm05.json` |
| [VF-Linienzug (Journal)](#6-vf-linienzug-eingabe-journal) | Kopf mit `test_id`, danach `typ` = `point_abs`/`real`/`string`/... | `vfl-journal-replay-start` + `vf-linienzug-modus` | erstes `point_abs` | `linienzug_tests.json`, `hm_recformat.json` |
| [Omniflo Bogen/Weiche](#71-bogen-und-weiche) | `"type": "bogen"` / `"weiche"` + `sivasnr` | `_.INSERT` der `<sivasnr>.dxf` (Kern `omni:insert-dxf` fragt den Punkt interaktiv) | `x`,`y`, Z = `hoehe` | `omniflo_tests.json`, `omniflo_strecke_tests.json` |
| [Omniflo Gerade](#72-aluprofil-gerade) | `"type": "gerade"` + `profil` | `omni:make-gerade` | `x`,`y` -> `x_ende`,`y_ende`, Z = `hoehe` | `omniflo_strecke_tests.json` |
| [Waagrechte Foerderstrecke](#8-waagrechte-foerderstrecke-gerade---noch-ohne-bau-pfad) | `"typ": "gerade"` + `startpunkt` | **kein Bau-Pfad** (wird gemeldet und uebersprungen) | `startpunkt`, `endpunkt` | `dematic_arvato.json` |
Nicht aus JSON baubar (es gibt keine Testdaten und keinen Treiber): Eckrad,
Geruest, TEF-Foerderer-Linie, TRO-Marker, Connections, Omniflo-Ladeschleife.
Fuer Eckrad und Geruest existiert ein skriptfaehiger Kern, siehe
[lisp_methods.md](lisp_methods.md).
### Allgemeine Regeln
- **Einheiten**: Laengen und Koordinaten in **mm**, Winkel in **Grad**.
Fahrtrichtung `hz`: 0 = +X (Ost), 90 = +Y (Nord), 180 = -X, 270 = -Y.
- **Z ist absolut**: `z` (bzw. Z in `start_mm`/`start_punkt`) ist die
Weltkoordinate des Einfuegepunkts, also die Einbauhoehe.
- **Dimension 2D/3D**: Gebaut wird in der aktuellen Dimension
(`ssg-ils-dim-aktuell`: `*ssg-ils-dim*` -> `DXFM_DIM`, Default 3D).
Das Feld `darstellung` in `dematic_arvato.json` ist reine Dokumentation und
wird nicht ausgewertet; `TEST_HUNDM05_2D`/`_3D` erzwingen die Dimension.
- **Flaches JSON**: Die meisten Dateien werden mit `ssg-load-json` gelesen
(zeilenweise, ein Objekt je `{`). Verschachtelte Objekte und mehrzeilige
Arrays darin funktionieren nicht - darum stehen z.B. die Glieder einer
Kette als eigene Objekte hinter ihrem Kopf-Objekt. Ausnahme:
`TEST_DEMATIC_ARVATO` liest mit dem rekursiven `ssg-json-laden`.
- **Reine Doku-Felder**: `comment`, `beschreibung`, `description`, `quelle`,
`row`, `seq`, `gruppe`, `assigned_to`, `hoehe_unbekannt`, `darstellung`
sowie alle `expect_*`/`erwartung_*`-Felder werden beim Bau nicht gelesen.
`expect_*` pruefen die Python-Tests gegen das Ergebnis.
- **Template-Felder** (nur `test_mubea.lsp`): `anzahl`, `delta_x`, `delta_y`
erzeugen aus einem Eintrag `anzahl` Kopien, jeweils um `delta_x`/`delta_y`
versetzt; `test_id` bekommt dann das Suffix `_01` ... `_nn`. Gilt fuer VF,
GF und Einzelbloecke.
---
## 1. Kreisel
Block `KREISEL_n`, gebaut von `KreiselInsert.lsp`.
### 1.1 Insert (freier Punkt)
```json
{ "id": "KR_Kreuz_Q1_0Grad", "function": "insert",
"x": 500, "y": 500, "z": 2500,
"abstand": 2000, "rotation": 0.0, "typ": "STANDARD" }
```
| Feld | Pflicht | Bedeutung | Default |
|---|---|---|---|
| `id` | ja (fuer den Treiber) | Kennung im Ergebnis; NICHT die Block-ID (die vergibt `ssg-id-generate`) | - |
| `function` | ja | `"insert"`; ohne `block` = Kreisel | - |
| `x`, `y` | ja | Einfuegepunkt. Liegt auf der Kreiselachse **einen Radius (400 mm) vor der Mitte des Antriebsrads (AN)**, also am aeussersten Punkt der AN-Seite | - |
| `z` | ja | Einbauhoehe; wird als `hoehe` uebergeben und in das Attribut `HOEHE` geschrieben | `kreisel.default_hoehe` (2000) |
| `abstand` | ja | Mittenabstand Antriebsrad - Spannrad | `kreisel.default_laenge` (2300) |
| `rotation` | nein | Drehung der Achse AN -> SP, frei (kein Raster) | 0.0 |
| `typ` | nein | `"STANDARD"` oder `"PIN"` -> Attribut `KREISELART` | `"STANDARD"` |
| `drehrichtung` | nein | `"GUZ"` oder `"UZS"` -> Attribut `DREHRICHTUNG` | `"UZS"` |
Treiber: `kreisel:run-insert-test` (`test_kreisel.lsp`), `mubea:build-kreisel`,
`hundm05:bau-kreisel` (auch fuer `dematic_arvato.json`/`showroom_ils.json`).
Nur `hundm05:bau-kreisel` liest `drehrichtung` aus und reicht sie an
`kreisel-insert-script` weiter; `mubea:build-kreisel` setzt es (noch) nicht um.
### 1.2 Connect (Start- und Endpunkt)
```json
{ "id": "K2", "function": "connect",
"start_x": 0, "start_y": 0, "start_z": 2000,
"end_x": 5000, "end_y": 0, "end_z": 2000, "typ": "STANDARD" }
```
`start_*` und `end_*` sind die aeussersten Punkte der AN- bzw. SP-Seite.
`abstand` (= Distanz - Kreiseldurchmesser 800) und `rotation` werden daraus
berechnet. Die Einbauhoehe kommt aus `start_z`. Nur `test_kreisel.lsp` kennt
`connect`; die anderen Treiber bauen ausschliesslich `insert`.
---
## 2. Einzelbloecke (Separator, Scanner, BTMT, Eingang/Ausgang, Vario-Bausteine)
Jeder Eintrag mit `"function": "insert"` UND `"block"` wird als einzelner
Block eingefuegt, ohne Wrapper-Block und ohne Verkettung.
```json
{ "id": "HundM05_SCANNER_02", "function": "insert", "block": "Scanner",
"x": 4095.5, "y": 1164.1, "z": 2154, "rotation": 270 }
```
| Feld | Pflicht | Bedeutung | Default |
|---|---|---|---|
| `block` | ja | Blockname OHNE `_2D`/`_3D`-Suffix | - |
| `x`, `y`, `z` | ja | Einfuegepunkt = **Basispunkt der Block-DWG** (nicht KS_EIN) | - |
| `rotation` | nein | Drehung um Z | 0 |
| `id` / `test_id` | nein | Kennung im Ergebnis | `SEPARATOR_<n>` bzw. Blockname |
Ablauf: `ssg-ils-block-laden` loest den Namen auf `data/ils/<block>_<DIM>.dwg`
auf (3D-Fallback), danach `_.INSERT eff pt "" "" rotation` und
`ssg-id-generate`. **Fehlt die DWG, wird `Separator_SP` eingefuegt.**
Treiber: `mubea:build-separator`, `hundm05:bau-sensor` (auch Dematic).
Das Layer-Attribut `LAYER` wird dabei nicht angewendet; der Block landet auf
dem aktuellen Layer.
### In den Testdaten verwendete Blocknamen
| `block` | DWG in `data/ils` | Verwendet in | Hinweis |
|---|---|---|---|
| `Scanner` | `Scanner_2D/_3D.dwg` | mubea, hundm05, dematic_arvato | |
| `Separator_SP` | `Separator_SP_2D/_3D.dwg` | (Fallback) | Block von `ILS_SEPARATOR_INSERT` |
| `S-LP` | **fehlt** | mubea, hundm05, dematic_arvato | wird zu `Separator_SP` |
| `S-SP` | **fehlt** | dematic_arvato | wird zu `Separator_SP` |
| `BTMT-Beladung` | `BTMT-Beladung_2D/_3D.dwg` | mubea, hundm05 | wie `ILS_BTMT_Beladung` |
| `SC_Entladung` | `SC_Entladung_2D/_3D.dwg` | mubea, hundm05 | wie `ILS_BTMT_Entladung` |
| `Eingang` / `Ausgang` | `Eingang_*/Ausgang_*.dwg` | mubea | Symbole wie `ILS_EINGANG_INSERT`/`ILS_AUSGANG_INSERT` |
| `AS_Element_90_links` / `_rechts` | vorhanden | dematic_arvato | loses AS-Element (sonst Teil eines VF/GF) |
| `ES_Element_90_rechts`, `ES_Element_30_rechts` | vorhanden | dematic_arvato | loses ES-Element |
| `Vario_Motorstation_500mm_rechts` | vorhanden | dematic_arvato | lose Motorstation |
| `Vario_Umlenkstation_500mm_rechts` | vorhanden | dematic_arvato | lose Umlenkstation |
| `Vario_Kurve_rechts_30_TEF_aussen` | vorhanden | dematic_arvato | lose Vario-Kurve |
Grundsaetzlich ist **jeder** Blockname aus `data/ils` erlaubt (es gibt keine
Whitelist). Die losen AS/ES-/Vario-Bausteine bilden aber keine Kette und keinen
`VF_n`/`GF_n`-Block - fuer eine zusammenhaengende Strecke Abschnitt 3-5 nutzen.
---
## 3. VarioFoerderer Standard und Etage
Block `VF_n`. Eingang sind die **Gesamtmasse** der Anlage; Winkel und
Teillaengen berechnet der Solver.
```json
{ "test_id": "VF_Schnitt_C", "richtung": "Auf",
"deltaL": 9110, "deltaH": 474, "winkel": 21,
"gf_verteilung": "manuell", "L_GF1": 2298, "seite": "links",
"hz": 0.0, "x": 400, "y": 14120, "z": 1554 }
```
| Feld | Pflicht | Bedeutung | Default |
|---|---|---|---|
| `test_id` | ja | muss mit `VF_` beginnen (steuert den Dispatcher in `test_mubea.lsp`) | - |
| `typ` | nein | `"standard"` (AS/ES 90 Grad) oder `"etage"` (AS/ES 30 Grad, uebereinander) | `"standard"` |
| `richtung` | ja | `"Auf"` oder `"Ab"` | - |
| `deltaL` | ja | horizontale Gesamtlaenge inkl. AS/ES, Boegen, GF-Vor-/Nachlauf | - |
| `deltaH` | ja | Hoehendifferenz (Betrag; Vorzeichen kommt aus `richtung`) | - |
| `winkel` | nein | Bogenwinkel erzwingen, nur aus der Kandidatenliste (`vario.bogen_winkel`: 3, 6, 9, 12, 15, 18, 21, 27, 33, 39, 45, 51). Ist er nicht loesbar, wird NICHT gebaut | kleinster gueltiger Winkel |
| `L_GF1` | nein (mubea) | Vorlauf-Laenge (GF vor dem Foerderer); Nachlauf = Rest von `L_GF` | - |
| `gf_verteilung` | nein (foerderer) | `"gleichmaessig"`, `"vorne"`, `"hinten"`; in `mubea.json` nur Doku (dort zaehlt `L_GF1`) | `"gleichmaessig"` |
| `seite` | nein | `"links"`/`"rechts"` (Seite der AS/ES-Elemente) | `"links"` |
| `hz` | nein | Fahrtrichtung | 0.0 |
| `x`, `y`, `z` | ja (mubea) | Startpunkt = **KS_EIN des AS-Elements**; `z` = Einbauhoehe am Anfang | - |
Hinweise:
- `foerderer_tests.json` hat statt `x/y/z` einen Kopf-Eintrag
`{"y_abstand": 600}`: alle Foerderer starten bei x = 0, z = 0 und werden um
`y_abstand` versetzt. Dieses Format kennt nur `test_foerderer.lsp`.
- `"Ab"` mit `deltaH` < 1 ist geometrisch unmoeglich und wird abgewiesen.
- Der Treiber schreibt nach dem Bau `vf-edit-xdata-schreiben` (Typ + `hz`),
damit der Block per Doppelklick editierbar ist.
---
## 4. Gefaellestrecke
Block `GF_n`: AS-Element -> Staustrecke (skaliert) -> Separator -> ES-Element.
Eingang ist die **horizontale Laenge**, nicht die Hoehendifferenz - die ergibt
sich aus Laenge und Neigung.
### 4.1 Modus 1 - Werteingabe
```json
{ "test_id": "GF_Mubea", "modus": 1,
"deltaL_mm": 9110, "hz_grad": 180.0, "winkel_grad": 2.27,
"start_mm": [9510, 12300, 2028],
"as_seite": "links", "es_seite": "links",
"as_winkel": "90", "es_winkel": "90" }
```
| Feld | Pflicht | Bedeutung | Default |
|---|---|---|---|
| `test_id` | ja | in `mubea.json` muss sie mit `GF_` beginnen | - |
| `modus` | nein | `1` | - |
| `deltaL_mm` | ja | horizontale Gesamtlaenge AS + Staustrecke + Separator + ES | - |
| `winkel_grad` | nein | Neigung der Staustrecke | 3.0 |
| `hz_grad` | nein | Fahrtrichtung | 0.0 |
| `start_mm` | ja | `[x, y, z]` = **KS_EIN des AS-Elements**; Z = Einbauhoehe oben | - |
| `as_seite`, `es_seite` | nein | `"links"`/`"rechts"` | `"links"` |
| `as_winkel`, `es_winkel` | nein | `"90"` oder `"30"` (als STRING) | `"90"` |
Die Staustrecke ergibt sich aus
`L_stau = (deltaL - aus-dx - ein-dx - 300 * cos(w)) / cos(w)`
(300 = `gefaelle.separator_breite`). Eine Ziel-Hoehe gibt es nicht.
In `gefaellestrecke_tests.json` stehen `deltaL_mm`, `winkel_grad` und
`z_start_mm` in einem gemeinsamen Kopf-Eintrag ohne `test_id` und gelten fuer
alle Faelle der Datei.
### 4.2 Modus 2 - Richtung aus zwei Punkten
Wie Modus 1, aber `deltaL` und `hz` werden aus `linie_start_mm` ->
`linie_ende_mm` berechnet (nur X/Y). `start_mm` bleibt der Einfuegepunkt und
ist unabhaengig von der Linie.
```json
{ "test_id": "M2_hz000", "modus": 2, "start_mm": [0, -35000, 5000],
"linie_start_mm": [0, -35000, 0], "linie_ende_mm": [10000, -35000, 0],
"as_seite": "links", "es_seite": "links", "as_winkel": "90", "es_winkel": "90" }
```
### 4.3 Modus 3 - Linienzug
In der Produktion nicht skriptbar (`gf-linienzug-modus` waehlt vorgezeichnete
LINE/ARC-Objekte per Maus). `test_gefaellestrecke.lsp` zeichnet die Leitlinie
selbst und baut sie nicht-interaktiv nach. Zwei Formen:
```json
{ "test_id": "M3_Bogen", "modus": 3,
"start_mm": [30000, -50000, 2000], "ende_mm": [38500, -43500, 1800],
"bogen": {"winkel_grad": 90, "radius_mm": 500, "seite": "links"},
"as_seite": "links", "es_seite": "links", "as_winkel": "90", "es_winkel": "90" }
{ "test_id": "M3_hz270", "modus": 3, "richtung": "Sued",
"start_mm": [0, -50000, 5000],
"deltaH_quelle": "M2_hz000", "deltaL_quelle": "M2_hz000", ... }
```
`deltaH_quelle`/`deltaL_quelle` uebernehmen die Masse eines frueher gebauten
Falls. Dieses Format ist an den Treiber gebunden. Fuer neue Anlagen besser
eine VF-Linienzug-Spec (Abschnitt 5) mit `Linie-GF`/`GF-Bogen` verwenden.
---
## 5. VF-Linienzug-Kette (Spec)
Beliebige Ketten aus GF-Linien, GF-Boegen, Vario-Kurven und VF-Einheiten,
**ohne Dialog** gebaut (`VF_SPEC_BAU`, `TEST_HUNDM05`). Eine Kette = ein
Kopf-Objekt, danach ihre Glieder (`glied`) und deren Unterknoten (`sub`) in
Baureihenfolge. Ergebnis ist ein `VF_n`-Block mit vollem `SSG_VF_EDIT`-Journal
(per Doppelklick editierbar).
```json
{ "spec_id": "VF_spec_LZ_01", "modus": 1,
"start_punkt": [4912.2, 1230.9, 2154.0], "start_hoehe": 2154.0,
"as": 1, "as_winkel": "90", "as_seite": "links" }
{ "glied": "Linie-GF", "nr": 1, "dl": 2249.3, "hz": 90.0,
"gefaelle": "winkel", "winkel": 3.0, "ende": "nein" }
{ "glied": "Horizontal-VF", "nr": 2, "dl": 3256.9, "gf_verteilung": "einlauf",
"vf_sep_vor": 0, "vf_sep_nach": 0, "vf_ende": "nein", "vf_separator": 0 }
{ "sub": "vario-kurve", "winkel": 90, "seite": "rechts", "variante": "innen" }
{ "sub": "motorstation" }
{ "glied": "ES", "winkel": "90", "seite": "links" }
```
**Kopf**
| Feld | Bedeutung |
|---|---|
| `spec_id` | Kennung der Kette |
| `modus` | `1` (nur Modus 1 hat einen Uebersetzer) |
| `start_punkt` | `[x, y, z]` Kettenanfang (KS_EIN des AS-Elements bzw. erstes Glied) |
| `start_hoehe` | Einbauhoehe am Start |
| `as` | `1` = AS-Element setzen, `0` = nicht |
| `as_winkel` / `as_seite` | `"90"`/`"30"` bzw. `"links"`/`"rechts"` |
**Glieder** (`glied`)
| `glied` | wichtigste Felder |
|---|---|
| `Linie-GF` | `dl`, `hz` (nur beim ersten Glied der Kette), `laenge_modus` (`endpunkt`/`hoehe`/`steigend`), `ende` (`ja-mit-es`/`ja-ohne-es`/`nein`), `sep_vor`, `sep_nach`, `gefaelle` (`hoehe`/`winkel`) + `hoehe` bzw. `winkel` |
| `GF-Bogen` | `winkel` (30/60/90), `seite` |
| `Vario-Kurve` | als eigenes Glied (Kettenanfang) vom Uebersetzer noch NICHT unterstuetzt -> Spec-Fehler; Vario-Kurven als `sub` einer VF-Einheit angeben |
| `Horizontal-VF` | `dl`, `eingang_hoehe`, `gf_verteilung` (`haelfte`/`einlauf`), `vf_sep_vor`, `vf_sep_nach`, `vf_ende` (`ja-mit-es`/`nein`/`automatisch`/`zielpunkt-ohne-es`), `vf_separator` (nur bei `vf_ende` = `nein`) + `sub`-Knoten |
| `Linie-VF` | `dl`, `hoehe`, optional `winkel_idx` + `sub`-Knoten |
| `Linie` | `dl`, `hoehe`, `segment_typ` (`GF`/`VF`), optional `winkel_idx` |
| `ES` | `winkel` (`"90"`/`"30"`), `seite` |
**Unterknoten einer VF-Einheit** (`sub`): `horizontal` (`sep_vor`, `sep_nach`),
`vario-kurve` (`winkel`, `seite`, `variante` `aussen`/`innen`), `auf-ab`
(`richtung` `auf`/`ab`, `hoehe`), `motorstation`, `kettenende` (`es`,
`es_winkel`, `es_seite`).
Ja/Nein-Felder (`as`, `sep_vor`, `vf_sep_vor`, `es`, ...) als `1`/`0` oder
`"ja"`/`"nein"`; mehrwertige Felder (`ende`, `vf_ende`) nur mit den genannten
Woertern. Vollstaendige Regeln
(Menue-Codes je Frame, `hz` nur einmal, Verhalten bei `winkel_idx`):
[variofoerderer.md, Abschnitt 8b](variofoerderer.md#spec-pfad-kette-aus-eingabedaten-vf_spec_bau).
Die Spec wird nicht von Hand geschrieben, sondern mit
`python lib/vf_spec_export.py <protokoll.json> <spec.json>` aus einer
aufgezeichneten Kette erzeugt. Fehlerhafte Specs werden komplett abgewiesen
(`vsp-pruefen` sammelt alle Fehler, gebaut wird dann nichts).
**Andere Objekte in derselben Datei**: Neben den Ketten darf `hundm05.json`
Kreisel (Abschnitt 1) und Einzelbloecke (Abschnitt 2) enthalten. Erkennbar
sind sie an `function`; `vsp-gruppieren` ueberspringt sie, und
`hundm05:bau-zusatzobjekte` baut sie nach den Ketten. `vf_spec_export.py`
haengt sie beim Neuerzeugen unveraendert ans Dateiende.
---
## 6. VF-Linienzug (Eingabe-Journal)
Das Rohformat hinter der Spec: die Antworten auf die Fragen des interaktiven
Linienzug-Ablaufs, in Reihenfolge. Nur fuer Regressionstests gedacht - fuer
neue Anlagen die Spec (Abschnitt 5) verwenden.
```json
{ "test_id": "VF_hundm05_LZ_01", "anlagetyp": "linienzug", "modus": 1, ... }
{ "typ": "point_abs", "wert": [4912.2, 1230.9, 2154.0], "kommentar": "Startpunkt" }
{ "typ": "real", "wert": 2154.0, "kommentar": "Hoehe (Z)" }
{ "typ": "string", "wert": "1", "kommentar": "AS-Element? Ja" }
{ "typ": "step", "wert": "Linie-GF", "kommentar": "Glied-Marker" }
{ "typ": "point_rel", "dL": 2249.3, "hz": 90.0, "kommentar": "Endpunkt" }
{ "typ": "int", "wert": 90, "kommentar": "Vario-Kurve Winkel" }
```
`typ`: `point_abs` (absoluter Punkt), `point_rel` (Abstand `dL` + Richtung
`hz`, `hz` nur beim ersten Segment), `real`, `int`, `string` (Menue-Code als
String), `step` (Glied-Marker, beim Replay uebersprungen). Kopf-Feld heisst
`anlagetyp`, nicht `typ`, damit Kopf und Eingabe unterscheidbar bleiben.
| Datei | Treiber |
|---|---|
| `linienzug_tests.json`, `linienzug_tests_stufe2.json` | `TEST_LINIENZUG`, `TEST_LINIENZUG_STUFE2` |
| `hm_recformat.json` (5 echte HundM-Ketten, erzeugt mit `lib/vf_journal_export.py`) | `TEST_HM_RECFORMAT` (in `alltests.json` abgeschaltet) |
---
## 7. Omniflo
### 7.1 Bogen und Weiche
```json
{ "id": "821104025", "type": "bogen", "sivasnr": "821104025",
"x": 219.4, "y": 223.06, "hoehe": 2000, "drehung": 0.0 }
```
| Feld | Pflicht | Bedeutung | Default |
|---|---|---|---|
| `type` | ja | `"bogen"` oder `"weiche"` | - |
| `sivasnr` | ja | Sivas-Nummer = Dateiname `%DXFM_OMNIFLO%/<sivasnr>.dxf` | - |
| `x`, `y` | ja | Einfuegepunkt (`$INSBASE` der DXF, gesetzt mit `set_einfuegepkt.py`) | - |
| `hoehe` | nein | Z des Einfuegepunkts UND Attribut `HOEHE` | 2000 |
| `drehung` | nein | Drehung + Attribut `DREHUNG` | 0 |
Es gibt kein `z`: die Hoehe ist zugleich die Z-Koordinate. Gueltige
Sivas-Nummern: `data/json/omniflo_boegen.json`, `omniflo_weichen.json`.
Treiber: `omni:test-insert` (`test_omniflo.lsp`), `omnistr:insert-bogen`
(`test_omniflo_strecke.lsp`).
### 7.2 Aluprofil-Gerade
```json
{ "seq": 1, "type": "gerade", "profil": "AP110", "laenge": 1000.0,
"x": 2000.0, "y": 0.0, "x_ende": 3000.0, "y_ende": 0.0,
"drehung": 0.0, "hoehe": 2000, "id": "0003" }
```
`profil` = `"AP60"`, `"AP110"` oder `"APG110"`. Die Gerade laeuft von
(`x`,`y`) nach (`x_ende`,`y_ende`) auf Z = `hoehe`; Laenge und Drehung folgen
aus den Punkten (`laenge` ist nur Doku). Gebaut mit `omni:make-gerade`.
---
## 8. Waagrechte Foerderstrecke (`gerade`) - noch ohne Bau-Pfad
```json
{ "test_id": "GERADE_Arvato_01", "typ": "gerade", "laenge": 8313.39, "hz": 90.0,
"startpunkt": [2334.97, 177818.67, 0.0], "endpunkt": [2334.96, 186132.06, 0.0] }
```
Ein Antriebs-/Umlenkstation-Paar ohne Hoehendifferenz, so von
`lib/dxf_scan_components.py` ausgegeben (ein VarioFoerderer ist bei
`deltaH` = 0 nicht loesbar). `TEST_DEMATIC_ARVATO` meldet diese Eintraege und
ueberspringt sie. Passende Primitive waere `insert-hz-scaled-block-by-ks`
(`vf_etage.lsp`) mit `Staustrecke_SP_1000_mm`, siehe
[lisp_methods.md](lisp_methods.md).
---
## 9. Testdaten-Dateien im Ueberblick
| Datei | Inhalt | Treiber / Befehl |
|---|---|---|
| `kreisel_tests.json` | 8 Kreisel (`insert`) | `TEST_KREISEL` |
| `foerderer_tests.json` | Kopf `y_abstand` + 17 VF Standard | `TEST_FOERDERER` |
| `gefaellestrecke_tests.json` | Kopf + GF Modus 1/2/3 | `TEST_GEFAELLESTRECKE` |
| `omniflo_tests.json` | 27 Boegen, 80 Weichen | `TEST_OMNIFLO` |
| `omniflo_strecke_tests.json` | Streckenzug aus Geraden und Boegen | `TEST_OMNIFLO_STRECKE` |
| `linienzug_tests.json` / `_stufe2.json` | Eingabe-Journal je einer Kette | `TEST_LINIENZUG` / `TEST_LINIENZUG_STUFE2` |
| `hm_recformat.json` | 5 HundM-Ketten als Journal | `TEST_HM_RECFORMAT` |
| `hundm05.json` | 5 HundM-Ketten als Spec + Kreisel, Separatoren, Scanner, BTMT | `TEST_HUNDM05`, `VF_SPEC_BAU` |
| `mubea.json` | Gesamtanlage: Kreisel, VF Standard/Etage, GF-Template (20 Stueck), Separatoren, Scanner, BTMT, Eingang/Ausgang | `TEST_MUBEA` |
| `dematic_arvato.json` | Vorlage aus `dxf_scan_components.py`: Kreisel, Einzelbloecke, `gerade` (Hoehen fehlen) | `TEST_DEMATIC_ARVATO` (abgeschaltet) |
| `showroom_ils.json` | ILS-3.0-Showroom-Vorlage aus `dxf_scan_components.py` (Kreisel, Gefaellestrecken; Hoehen teils Platzhalter), gleicher Treiber wie `dematic_arvato.json` | `TEST_SHOWROOM_ILS` |
| `hundm05_linienzug_polylines.json` | Polylinien aus `extract_polylines.py` | kein Treiber (Analyse-Daten) |
| `vfl_journal_hm05_abbruch.json` | rohes Journal (`kind`/`value`) eines abgebrochenen Baus | kein Treiber |
---
## 10. Eigene Anlage beschreiben - Kurzanleitung
1. Kreisel als `insert` (Abschnitt 1): `x/y` am aeussersten Punkt der AN-Seite,
`z` = Einbauhoehe.
2. Einfache Steig-/Fall-Strecken mit fester Form als VF Standard/Etage
(Abschnitt 3) bzw. Gefaellestrecke Modus 1 (Abschnitt 4.1), Startpunkt
jeweils = KS_EIN des AS-Elements.
3. Ketten mit Kurven, mehreren VF-Einheiten oder GF-Boegen als Spec
(Abschnitt 5) - am einfachsten eine Kette einmal interaktiv bauen, mit
`lib/vf_journal_export.py` + `lib/vf_spec_export.py` als Spec exportieren
und Startpunkt/Laengen anpassen.
4. Separatoren, Scanner, BTMT-Stationen, Eingang/Ausgang als Einzelblock
(Abschnitt 2).
5. Aus Kreisel, Einzelbloecken und Specs gemischt baut derzeit nur der
HundM05-Treiber (`TEST_HUNDM05`); fuer VF Standard/Etage + GF zusammen mit
Kreiseln den Mubea-Treiber (`TEST_MUBEA`) als Vorlage nehmen.
+304
View File
@@ -0,0 +1,304 @@
# Kommandouebersicht
Diese Seite listet alle Kommandos des Projekts auf einen Blick:
1. [BricsCAD-Befehle (AutoLISP)](#1-bricscad-befehle-autolisp) - an der BricsCAD-Kommandozeile einzugeben
2. [Test-Befehle in BricsCAD](#2-test-befehle-in-bricscad)
3. [Batch-/Shell-Skripte (`bin/`)](#3-batch-shell-skripte-bin)
4. [Python-Kommandozeilen (`lib/`)](#4-python-kommandozeilen-lib)
5. [Python-Tests (`pytest`)](#5-python-tests-pytest)
Ausfuehrliche Beschreibungen stehen in `Lisp/README.md`, `doc/variofoerderer.md`,
`doc/tools.md` (set_einfuegepunkt/set_koords), `doc/dbg2lsp.md`, `doc/csv-export.md`
und `doc/LispTests.md`. Diese Seite ist nur der Einstieg.
**Voraussetzung fuer alle BricsCAD-Befehle**: Menue `menu/SSG_LIB.mnu` einmalig per
`_MENULOAD` geladen (siehe `CLAUDE.md`, "Menue einrichten"). Die MNL laedt die Module
dann beim Start. Befehle, die nicht im Menue stehen, lassen sich trotzdem an der
Kommandozeile aufrufen, sofern ihr Modul geladen ist - sonst vorher
`(ssg-ensure "Modulname")` eingeben.
---
## 1. BricsCAD-Befehle (AutoLISP)
Gross-/Kleinschreibung spielt an der Kommandozeile keine Rolle.
### ILS Kreisel / Eckrad (`KreiselInsert.lsp`)
| Befehl | Beschreibung |
|---|---|
| `KreiselInsert` | Kreisel einfuegen: Position und Parameter (Abstand, Typ, Rotation, Hoehe) manuell eingeben |
| `KreiselConnect` | Kreisel zwischen zwei gewaehlten Punkten einfuegen (Abstand und Drehung aus den Punkten) |
| `KreiselQuick` | Kreisel schnell mit Standardwerten (horizontal) einfuegen |
| `KreiselEdit` | Bestehenden Kreisel per Dialog (`kreisel_edit.dcl`) bearbeiten und neu aufbauen |
| `KreiselRedraw` | Kreisel aus seinen Block-Attributen neu zeichnen (z.B. mit neuem Abstand) |
| `KreiselParams` | Aktuelle Kreisel-Parameter anzeigen |
| `KreiselLabelSetup` | Beschriftung einstellen (Hoehe, Farbe, Abstand, Schriftart) |
| `KreiselLabelPos` | Versatz der Beschriftung (dx/dy) einstellen |
| `KreiselLabelHoehe` | Texthoehe der Beschriftung einstellen |
| `ILS_Eckrad` | Eckrad an einem Tangentenpunkt mit Richtung einfuegen |
### VarioFoerderer (`VarioFoerderer.lsp` -> `vf_core`/`vf_standard`/`vf_etage`/`vf_linienzug`/`vf_spec`)
| Befehl | Beschreibung |
|---|---|
| `FOERDERANLAGE` / `VarioFoerderer` | Hauptbefehl, fragt den Anlagentyp (Standard/Etage/Linienzug) ab |
| `StandardVarioFoerderer` | Standardtyp (AS/ES 90 Grad), Werte per DCL-Dialog |
| `StandardVarioFoerderer3D` | Standardtyp aus einer gewaehlten 3D-Linie |
| `EtageVarioFoerderer` | Etagentyp (AS/ES 30 Grad), Werte per DCL-Dialog |
| `EtageVarioFoerderer3D` | Etagentyp aus einer gewaehlten 3D-Linie |
| `LinienzugVarioFoerdererManuell` | Streckengruppe, Modus 1 (manuelle Eingabe, Punkte klicken) |
| `LinienzugVarioFoerdererZielhoehe` | Streckengruppe, Modus 2 (3D-Objekte + Ziel-Hoehe, Randwert-Solver) |
| `LinienzugVarioFoerdererStueckweise` | Streckengruppe, Modus 3 (3D-Objekte stueckweise, in Arbeit) |
| `QcLinieMitGf` | Streckengruppe Modus 4 (QC-Linie mit GF, automatische Auf-Ab-Berechnung); Menue unter Gefaellestrecke |
| `QcLinieMitGfUForm` | Streckengruppe Modus 5 (QC-Linie mit GF und U-Form); Menue unter Gefaellestrecke |
| `VARIOFOERDERER_EDIT` | VF_n-Block editieren (dispatcht per XDATA-Marker auf Standard/Etage/Linienzug); auch per Doppelklick |
| `VARIOFOERDERER_NACHRUESTEN` / `VF_NACHRUESTEN` | Altbestand-VF_n-Bloecke ohne `SSG_VF_EDIT`-Marker editierbar machen |
| `Vario_Kette_Merge` | Mehrere einzeln gebaute VF_n-Bloecke ab einem Start-Baustein zu einem Gesamt-Block zusammenfuehren |
| `VF_SEKTION_RESTORE` | Aufgebrochene Linienzug-Kette aus der XDATA der losen Objekte wieder zu einem Block mit Journal zusammensetzen |
| `VF_WIZARD_AN` / `VF_WIZARD_AUS` | Linienzug-Fragen per DCL-Assistent (Standard) bzw. per Konsole stellen |
| `VF_SPEC_BAU` | Linienzug-Ketten ohne Dialog aus einer Spec-Datei bauen (`DXFM_VF_SPEC`, Default `tests/testdata/hundm05.json`) |
| `VFL_KS_DIAG` | Diagnose: inneren Aufbau eines Blocks anzeigen (Lage von KS_EIN/KS_AUS) |
### Gefaellestrecke (`Gefaellestrecke.lsp`)
| Befehl | Beschreibung |
|---|---|
| `GEFAELLESTRECKE` | Fragt den Eingabemodus per Konsole ab |
| `GEFAELLESTRECKE_EINFACH` | Modus 1: Werteingabe per DCL-Dialog |
| `GEFAELLESTRECKE_3DLINIE` | Modus 2: aus einer 3D-Linie |
| `GEFAELLESTRECKE_LINIENZUG` | Modus 3: aus einem Linienzug (LINE + ARC) |
| `GEFAELLESTRECKE_EDIT` | GF_n-Block editieren (Dialog vorbelegt, Neuaufbau); auch per Doppelklick |
### ILS-Zusatzmodule, Sensoren, Ein-/Ausgang (`SSG_LIB_Commands.lsp`)
| Befehl | Beschreibung |
|---|---|
| `ILS_BTMT_Beladung` | BTMT-Beladung wiederholt einfuegen (Drehung interaktiv) |
| `ILS_BTMT_Entladung` | BTMT-Entladung wiederholt einfuegen |
| `ILS_EINGANG_INSERT` / `ILS_AUSGANG_INSERT` | Eingang-/Ausgang-Symbol frei platzieren |
| `ILS_SCANNER_INSERT` | Scanner einfuegen |
| `ILS_SEPARATOR_INSERT` | Separator einfuegen |
| `TEF_FOERDERER_LINIE` (`TEFInsert.lsp`) | Linie zwischen zwei Punkten zeichnen und mit 1000-mm-TEF-Geraden belegen |
### Omniflo (`OmniModulInsert.lsp`)
| Befehl(e) | Beschreibung |
|---|---|
| `OMNI_LOAD` | Omniflo-Komponentendaten laden |
| `OMNI_INFO_BOGEN` / `OMNI_INFO_WEICHE` | Daten eines Bogens / einer Weiche anzeigen |
| `OMNI_APB60_90`, `OMNI_APB_630_90`, `OMNI_APB_630_45`, `OMNI_APB_550_675`, `OMNI_APB_550_225`, `OMNI_APB_650_180` | Boegen einfuegen (Dialog `omniflo_boegen.dcl`) |
| `OMNI_AP60`, `OMNI_AP110`, `OMNI_APG110` | Gerade Profile einfuegen |
| `OMNI_W90_Einfach`/`_Doppel`/`_Dreiwege` | Weichen 90 Grad (Dialog `omniflo_weichen.dcl`) |
| `OMNI_W45_Einfach`/`_Doppel`/`_Dreiwege` | Weichen 45 Grad |
| `OMNI_WP_Einfach`/`_Doppel`/`_Dreiwege` | Parallelweichen |
| `OMNI_WK_Einfach`/`_Doppel`/`_Dreiwege` | Weichenkoerper |
| `OMNI_WKomb_Delta_1400`, `OMNI_WKomb_Delta_1600`, `OMNI_WKomb_Star` | Weichenkombinationen (Delta, Stern) |
| `OMNI_APBW_R400_45_140`, `OMNI_APBW_R400_675_260`, `OMNI_APBW_R550_45_77`, `OMNI_APBW_R550_45_194`, `OMNI_APBW_R550_225_360`, `OMNI_APBW_R550_225_410A`/`B`/`C`, `OMNI_APBW_R550_675_58`/`_125`/`_208`/`_360`, `OMNI_APBW_R650_90_300`, `OMNI_APBW_R750_90_200` | Boegen fuer Weichen (fest, ohne Dialog) |
| `OMNI_TEF_UmlenkL`/`R`, `OMNI_TEF_AntriebL`/`R`, `OMNI_TEF_Gerade` | TEF-Elemente (fest, ohne Drehung) |
| `OMNI_STOPPER`, `OMNI_SCANNER`, `OMNI_BUERSTENBREMSE` | Anbaugruppen |
| `OMNI_TV_W_W`, `OMNI_TV_W_AP`, `OMNI_TV_W_AP60`, `OMNI_TV_W_AP110`, `OMNI_TV_W_AP110_W`, `OMNI_TV_50`, `OMNI_TV_80`, `OMNI_TV_ENDPLATTE`, `OMNI_TV_ANSCHLAG`, `OMNI_TV_MUFFE`, `OMNI_TV_A_AP110_AP60`, `OMNI_TV_A_AP60_ST`, `OMNI_TV_A_AP110_ST`, `OMNI_TV_SW_II_SW_SW`, `OMNI_TV_SW_III_AP110`, `OMNI_TV_SW_III_AP110_SW`, `OMNI_TV_SW_IV_AP60`, `OMNI_TV_SW_IV_ST` | Verbinder |
| `OMNI_LADESCHLEIFE_AP110` | Ladeschleife (Dialog `omniflo_ladeschleifen.dcl`) |
| `OMNI_KettenFoerderer` | Platzhalter (noch ohne Funktion) |
| `OMNI_EDIT` | Omniflo-Element per Dialog bearbeiten; auch per Doppelklick |
### Geruest (`GeruestInsert.lsp`)
| Befehl | Beschreibung |
|---|---|
| `GERUEST` | Geruest-Dialog (Bereich frei waehlbar) |
| `GERUEST_SAEULEN` / `GERUEST_ROHRABHAENGER` / `GERUEST_WANDBEFESTIGUNG` | Derselbe Dialog, im jeweiligen Bereich geoeffnet |
| `GERUEST_TRAEGER` | Rohr-Geruest-Traeger: Dialog (`geruest_traeger.dcl`), danach Start-/Endpunkt oder Laenge bis ESC/Enter |
| `GERUEST_TRAEGER_BESCHRIFTEN` | Alle Traeger der Zeichnung neu beschriften, verwaiste Beschriftungen entfernen |
### TRO und Connections (`Tro_Edit.lsp`, `Connection_Edit.lsp`)
| Befehl | Beschreibung |
|---|---|
| `TRO_INSERT` | TRO-Marker (`TRO_SYM_<Typ>`) einfuegen und ID/TYPE setzen (Blockdefinition muss existieren) |
| `TRO_EDIT` | ID/TYPE eines TRO-Markers per Dialog aendern |
| `CONNECTION_INSERT` | Verbindungspfeil (Fluss) zwischen zwei Elementen zeichnen |
| `CONNECTION_EDIT` | Quelle/Ziel einer Verbindung aendern |
### Export und IDs (`export.lsp`, `ssg_id.lsp`, `count_sep_scan.lsp`, `check_hoehen.lsp`)
| Befehl | Beschreibung |
|---|---|
| `EXPORTSIVAS` | Sivas-Export-CSV mit Summierungszeilen (ruft `lib/export_sivas.py`) |
| `EXPORTCSV` | Einfache Item-Liste aller Bloecke inkl. Bounding-Box/Planquadrat (ruft `lib/export_csv.py`) |
| `CSV_EXPORT_KONFIG` | Export-Einstellungen per Dialog (u.a. gefrorene Layer ausschliessen) |
| `OMNI_UPDATE_ATTRIBS` | HOEHE und DREHUNG aller Omniflo-Elemente aus der Geometrie aktualisieren |
| `IDSCHECK` | Alle Bloecke auf doppelte IDs pruefen und korrigieren |
| `IDGENERATE` | Gewaehltem Block eine neue ID zuweisen |
| `ZAEHLE_SEP_SCAN` | Scanner/Separatoren je Kreisel/VF/GF zaehlen und in ANZAHL_SCANNER/ANZAHL_SEPARATOR schreiben (laeuft auch automatisch vor jedem Export) |
| `HOEHEN_CHECK` | Hoehen von Kreiseln/VF/GF messen und in HOEHE/HOEHE_VON_mm/HOEHE_BIS_mm/MONTAGEHOEHE_m schreiben |
| `CALLPYTHON` (`external_call.lsp`) | Test des LISP->Python-Aufrufs (`lib/testpycall.py`) |
### Konfiguration, Planquadrate, Doppelklick
| Befehl | Beschreibung |
|---|---|
| `SSG_DIM_SWITCH` | Globalen Modus 2D/3D umschalten (`DXFM_DIM`) |
| `SSG_DIM_ALL_2D` / `SSG_DIM_ALL_3D` | Alle VF_n-/GF_n-Bloecke der Zeichnung nach 2D bzw. 3D umbauen |
| `SSG_SPRACHE` | Sprache Deutsch/Englisch waehlen (`DXFM_LANG`) |
| `DRAW_PLANQUADRATE` | Planquadrat-Raster (Block `ZZ_PLANQUADRATE`) zeichnen bzw. neu aufbauen |
| `DELETE_PLANQUADRATE` | Planquadrat-Raster entfernen |
| `PLANQUADRATE_TOGGLE` | Raster an/aus (zeichnen, falls keins existiert, sonst entfernen) |
| `SSG_BLOCKEDIT` | Doppelklick-/Kontextmenue-Dispatcher: Kreisel, Omniflo, GF_*, VF_*, GR_*, TRO_* auf den passenden Edit-Befehl |
| `EATTEDIT` | Ueberschreibt den nativen Befehl, leitet an `SSG_BLOCKEDIT` weiter (Fallback `_.EATTEDIT`) |
### Layer-Werkzeuge (`ssg_layer.lsp`)
| Befehl | Beschreibung |
|---|---|
| `SSG-LayerSet` | Layer eines angeklickten Objekts aktiv setzen |
| `SSG-LayerInfo` | Layer eines Objekts anzeigen |
| `SSG-LayerMove` | Objekte auf einen anderen Layer verschieben |
| `SSG-LayerCopy` | Objekte auf einen anderen Layer kopieren |
| `SSG-LayerMoveType` | Alle Objekte eines Typs (Referenzobjekt) vom gleichen Layer auf einen neuen Layer verschieben |
| `SSG-LayerOff` / `SSG-LayerFreeze` | Layer per Anklicken aus-/einfrieren |
| `SSG-FreezeAll` | Alle Layer ausser dem aktiven einfrieren |
| `SSG-ThawAll` / `SSG-LayerOnAll` | Alle Layer auftauen / einschalten |
| `SSG-LayerDelete` | Alle Objekte eines Layers und den Layer loeschen (mit Sicherheitsabfrage) |
### Block-Pflege und Diagnose (Entwickler)
Arbeiten auf den Block-DWGs in `data/ils` (Voraussetzung `DXFM_DATA`).
| Befehl | Beschreibung |
|---|---|
| `ILS_ATTR_SYNC` (`addattribute.lsp`) | ATTDEFs der DWGs mit `data/ils/allocations.json` abgleichen; Modus Ergaenzen/Ersetzen |
| `ILS_ATTR_REPLACE` | Direkt Modus "Ersetzen" (Sicherheitsfrage bleibt) |
| `ILS_ATTR_COLLECT` (`collect_attributes.lsp`) | Aktuelle ATTDEF-Werte aller DWGs nach `allocations_collected.json` schreiben |
| `ILS_BLOCK_LIST` (`list_blocks.lsp`) | Sub-Block-Definitionen aller DWGs nach `blocks_collected.json` schreiben (Kollisionen 2D/3D finden) |
| `ILS_BLOCK_PURGE` (`purge_blocks.lsp`) | Unbenutzte Bloecke/Layer in allen DWGs entfernen |
| `KS_PRUEFEN` (`ks_pruefung.lsp`) | KS_EIN/KS_AUS der 2D- gegen die 3D-Variante vergleichen, Ergebnis als CSV |
| `MenuInventory` (`menu-inventory.lsp`) | Menuegruppen, Plugins und Startdateien von BricsCAD auflisten |
---
## 2. Test-Befehle in BricsCAD
Aus dem Menue "Tests" bzw. der Kommandozeile; Details in `doc/LispTests.md`.
| Befehl | Beschreibung |
|---|---|
| `SSG_RUN_ALL_TESTS` | Alle in `tests/alltests.json` aktivierten Szenarien ausfuehren (fragt den Modus ab) |
| `SSG_RUN_ALL_TESTS_EXPORT` | Dito, Automatik: speichern + CSV/Sivas-Export + schliessen |
| `SSG_RUN_ALL_TESTS_OFFEN` | Dito, Kontrolle: Zeichnungen bleiben offen, kein Export |
| `TEST_EXPORT_ALL` | Jede Zeichnung aus `tests/output/` oeffnen und exportieren |
| `TEST_UNIT` | File- und zeichnungsfreie Unit-Tests (`tests/test_unit.lsp`), Ergebnis `tests/output/unit_results.txt` |
| `TEST_VF_SPEC` | Unit-Test Spec-Uebersetzer (`vsp-journal`) |
| `TEST_VFL_SCHEMA` | Unit-Test Glied-Schema des Linienzugs |
| `TEST_KREISEL` | Kreisel-Szenario |
| `TEST_FOERDERER` | VarioFoerderer-Szenario |
| `TEST_GEFAELLESTRECKE` | Gefaellestrecke-Szenario |
| `TEST_LINIENZUG` / `TEST_LINIENZUG_STUFE2` | Linienzug-Szenarien |
| `TEST_OMNIFLO` | Alle Omniflo-Testbloecke einfuegen |
| `TEST_OMNIFLO_STRECKE` | Omniflo-Streckenzug aufbauen |
| `TEST_HM_RECFORMAT` (`_2D`/`_3D`) | Echte HundM-Aufzeichnungen per Journal-Replay nachbauen |
| `TEST_HUNDM05` (`_2D`/`_3D`) | HundM05-Anlage aus der Spec bauen |
| `TEST_MUBEA` | Mubea-Nachbau aus `tests/testdata/mubea.json` |
| `TEST_DEMATIC_ARVATO` | Dematic/Arvato-Nachbau (Flowpuffer/Kreisel) |
| `TEST_SHOWROOM_ILS` | ILS-3.0-Showroom-Nachbau (Kreisel, Gefaellestrecken; Hoehen noch Platzhalter) |
---
## 3. Batch-/Shell-Skripte (`bin/`)
Alle Skripte rufen zuerst `setenv.bat` (bzw. `setenv.sh`) auf.
| Skript | Beschreibung |
|---|---|
| `setenv.bat` / `setenv.sh` | Umgebungsvariablen setzen (`DXFMAKRO`, `DXFM_LISP`, `DXFM_DATA`, `BRICSCAD` ...); `.sh` muss gesourct werden |
| `start_briscad.bat` | Umgebung setzen und BricsCAD starten |
| `get_cmd.bat` / `get_cmd.sh` | Shell mit gesetzter Umgebung oeffnen |
| `install_py.bat` / `install_py.sh` | `.venv` anlegen und `requirements.txt` installieren (nur wenn noch nicht vorhanden) |
| `activate_venv.bat` / `activate_venv.sh` | `.venv` aktivieren, Python-Version und Pakete anzeigen |
| `run_tests.bat` | Testausfuehrung, siehe unten |
| `create_tests.bat` | Kompletter ILS-Testlauf: Basis-DXF erzeugen, BricsCAD mit `ILS_test.scr`, Ergebnisse validieren |
| `set_einfuegepunkt.bat [schalter]` | Wrapper fuer `lib/set_einfuegepkt.py` (siehe `doc/tools.md`) |
| `set_coords.bat [schalter]` | Wrapper fuer `lib/set_koords.py` (siehe `doc/tools.md`) |
| `dbg2lsp.bat [argumente]` | Wrapper fuer `lib/dbg2lsp.py` (siehe `doc/dbg2lsp.md`) |
| `show_exportcsv.bat [csv] [flow] [mflow] [track]` | Export-CSV mit sps_skel als SVG darstellen; `flow` ohne VF/GF-Einzelbausteine, `mflow` Materialfluss-Graph, `track` Bahnzusammenhang (beide brauchen Graphviz) |
| `dxf_anlage_export.bat <dxf> <output.json> [--projekt NAME]` | Wrapper fuer `lib/dxf_anlage_export.py` |
| `dxf_scan_components.bat <dxf> <data_dir> <output.json> [--fenster X0 Y0 X1 Y1] [--projekt NAME]` | Wrapper fuer `lib/dxf_scan_components.py` |
| `dxf_vf_abbild.bat <dxf> [--spec S] [--json J] [--referenz R] [--schreibe-referenz] [--praefix VF_,GF_]` | Wrapper fuer `lib/dxf_vf_abbild.py` |
### `run_tests.bat`
```
bin\run_tests.bat --lisp BricsCAD headless (/b tests\test_unit.scr), TEST_UNIT, Auswertung unit_results.txt
bin\run_tests.bat --check [test_xyz.py] pytest-Validierung (alle oder eine Datei)
bin\run_tests.bat --diff_references [datei] CSVs tests\reference vs. tests\output vergleichen, bei Unterschieden meld
bin\run_tests.bat Hilfe
```
---
## 4. Python-Kommandozeilen (`lib/`)
Aufruf mit aktivierter `.venv` (bzw. ueber `setenv`, damit `DXFM_*` gesetzt sind).
`python <skript> --help` zeigt bei den argparse-Skripten alle Optionen.
### Export (normalerweise von `EXPORTSIVAS`/`EXPORTCSV` aufgerufen)
| Aufruf | Beschreibung |
|---|---|
| `python export_sivas.py <export_raw.json> <data_dir> <output.csv> [--mit-bezeichnung]` | Sivas-CSV mit Summierungszeilen, zusaetzlich `<output>_zusammengefasst.csv` |
| `python export_csv.py <export_raw.json> <data_dir> <output.csv>` | Einfache Item-Liste (Planquadrat, Bounding-Box, Nachbarn, Merkmale) |
| `python export_graph.py <export.csv> [<ausgabe-basispfad>]` | Materialfluss-Graph aus dem CSV-Export als `.json`, `.dot` und `.mmd` |
Reine Bibliotheken ohne eigene Kommandozeile: `export_blockpatterns.py`,
`export_neighbors.py`, `export_planquadrat.py`, `merkmalstamm.py`, `sivas_mapping.py`,
`omniflo_utils.py`, `vf_linienzug_grammatik.py`.
### Omniflo-DXF-Aufbereitung
| Aufruf | Beschreibung |
|---|---|
| `python set_einfuegepkt.py [--boegen] [--weichen45] [--weichen90] [--weichenkoerper] [--weichen-parallel] [--delta] [--dreifachweiche] [--sternweiche] [--number SIVASNR] [--show-omniflo]` | `$INSBASE` der Omniflo-DXFs setzen |
| `python set_koords.py [--k1set] [--k2set] [--k3set] [--k4set] [--set-all] [--force] [--test] [--number SIVASNR] [--show-omniflo]` | KS-Bloecke K1-K4 in die Omniflo-DXFs setzen |
| `python split_block_library.py` | `data/block_libraries/ils_library.dxf` in einzelne DXFs je Block aufteilen |
### VarioFoerderer-Journal und Spec
| Aufruf | Beschreibung |
|---|---|
| `python vf_journal_export.py <dxf> <output.json> [--csv <sivas.csv>] [--kein-startpunkt-fix]` | `SSG_VF_EDIT`-Journale der VF_n-Bloecke als Frage-Antwort-Protokoll (z.B. `tests/testdata/hm_recformat.json`) |
| `python vf_spec_export.py <protokoll.json> <spec.json>` | Protokoll in eine Spec uebersetzen (z.B. `tests/testdata/hundm05.json`) |
| `python dxf_vf_abbild.py <dxf> [--spec S] [--json J] [--referenz R] [--schreibe-referenz] [--praefix VF_,GF_]` | Attribut-/Bausteinabbild der VF_/GF_-Bloecke; `--referenz` vergleicht (Exit 1 bei Abweichung) |
| `python dxf_anlage_export.py <dxf> <output.json> [--projekt NAME]` | Mit unseren Makros GEBAUTE (und von Hand nachbearbeitete) Anlage aus der Zeichnung in Nachbau-Testdaten zurueckschreiben (Gegenstueck zu `dxf_scan_components.py`); erzeugt z.B. `tests/testdata/dematic_arvato.json` |
| `python dump_vf_wrapper_inhalt.py <dxf-oder-dwg>` | Diagnose: Sub-INSERTs je VF_n/GF_n-Wrapper in Baureihenfolge |
| `python dump_vf_kette_inhalt.py <spec.json> [<export_raw.json>]` | Diagnose: Glied-Folge der Spec gegen die tatsaechliche Separatorliste |
### Fremdzeichnungen auswerten
| Aufruf | Beschreibung |
|---|---|
| `python dxf_scan_components.py <dxf> <data_dir> <output.json> [--fenster X0 Y0 X1 Y1] [--projekt NAME]` | ILS-/Omniflo-Komponenten einer fremden Zeichnung als Nachbau-JSON erkennen |
| `python dxf_abbild.py <dxf> <output.json> [--fenster X0 Y0 X1 Y1] [--max-tiefe N] [--ohne-geometrie-container]` | Getreue Abbildung aller Bauteile (ohne Interpretation) als JSON |
| `python extract_polylines.py <dxf> <output.json> [--layer Z-6]` | LWPOLYLINEs eines Layers mit Stuetzpunkten und Laengen als JSON |
### Entwickler-Tools
| Aufruf | Beschreibung |
|---|---|
| `python dbg2lsp.py <datei.lsp> --method NAME [--recursive] [--max-depth N] [--search-dir D] [--exclude NAME] [--add-open DATEI METHODE] [--dbg-file F] [--dbg-envvar V] [--force] [--dry-run]` | LISP-Funktionen mit `ssg_dbg.lsp`-Aufrufen instrumentieren (siehe `doc/dbg2lsp.md`) |
| `python testpycall.py [<log_dir>]` | Gegenstueck zu `CALLPYTHON` |
---
## 5. Python-Tests (`pytest`)
```
pytest tests/ alle Python-Tests
pytest tests/test_vf_spec.py einzelne Datei
bin\run_tests.bat --check dasselbe ueber das Batch-Skript
```
Die Szenario-Tests (`test_kreisel.py`, `test_foerderer.py`, `test_hundm05.py` ...)
validieren die Ausgaben der zugehoerigen BricsCAD-Testbefehle in `tests/output/`
gegen `tests/reference/`; reine Python-Tests wie `test_vf_spec.py`,
`test_vf_journal_grammatik.py` oder `test_export_graph.py` laufen ohne BricsCAD.
+329
View File
@@ -0,0 +1,329 @@
# LISP-Routinen zum Bau einzelner Einheiten
Uebersicht ueber die LISP-Funktionen, die eine Einheit (Kreisel, Eckrad,
VarioFoerderer, Gefaellestrecke, Omniflo-Element, Geruest, Einzelblock)
erzeugen, mit Signatur, Parametern, Rueckgabe und Voraussetzungen.
Zu jedem Element steht der interaktive **Befehl** (was der Anwender aufruft)
und der **skriptfaehige Kern** (ohne `getpoint`/Dialog, aus Code oder JSON
aufrufbar). Das JSON-Format, mit dem die Testtreiber diese Kerne aufrufen,
steht in [json-input-lisp.md](json-input-lisp.md); alle Befehle in
[kommandos.md](kommandos.md).
Einheiten: mm und Grad. `hz` = Fahrtrichtung in der XY-Ebene, 0 = +X,
90 = +Y. Punkte sind Listen `(x y z)` in Weltkoordinaten.
---
## 0. Uebersicht
| Einheit | Befehl | Skriptfaehiger Kern | Ergebnis-Block | Modul |
|---|---|---|---|---|
| Kreisel | `KreiselInsert`, `KreiselConnect`, `KreiselQuick` | `kreisel-insert-script`, `kreisel-connect-script` | `KREISEL_n` | `KreiselInsert.lsp` |
| Eckrad | `ILS_Eckrad` | `ils-eckrad-insert` | `ECKRAD_n` | `KreiselInsert.lsp` |
| VF Standard | `StandardVarioFoerderer`, `FOERDERANLAGE` | `berechne-standard` + `variofoerderer-einfuegen` + `vf-block-erstellen` | `VF_n` | `vf_standard.lsp`, `vf_core.lsp` |
| VF Etage | `EtageVarioFoerderer` | `berechne-etage` + `etage-foerderanlage-einfuegen` + `vf-block-erstellen` | `VF_n` | `vf_etage.lsp`, `vf_core.lsp` |
| VF Linienzug | `LinienzugVarioFoerdererManuell`/`-Zielhoehe`/`-Stueckweise`, `QcLinieMitGf`/`-UForm` | `vsp-bau-aus-spec` (Spec) bzw. `vfl-journal-replay-start` + `vf-linienzug-modus` | `VF_n` | `vf_linienzug.lsp`, `vf_spec.lsp` |
| Gefaellestrecke | `GEFAELLESTRECKE_EINFACH`/`_3DLINIE` | `gf-rebuild` bzw. `gefaellestrecke-einfuegen` | `GF_n` | `Gefaellestrecke.lsp` |
| Gefaellestrecke Linienzug | `GEFAELLESTRECKE_LINIENZUG` | - (nur interaktiv; Kern `gf-linienzug-einfuegen` braucht analysierte Segmente) | `GF_n` | `Gefaellestrecke.lsp` |
| Separator, Scanner | `ILS_SEPARATOR_INSERT`, `ILS_SCANNER_INSERT` | - (Schleife mit `getpoint`); Kern: `ssg-ils-block-laden` + `_.INSERT` | Einzelblock | `SSG_LIB_Commands.lsp`, `ssg_core.lsp` |
| BTMT, Eingang/Ausgang | `ILS_BTMT_*`, `ILS_EINGANG_INSERT`/`ILS_AUSGANG_INSERT` | wie Separator | Einzelblock | `SSG_LIB_Commands.lsp` |
| Omniflo Bogen/Weiche/TEF | `OMNI_APB_*`, `OMNI_W*_*`, `OMNI_TEF_*` ... | `_.INSERT` der `<sivasnr>.dxf` (Kern `omni:insert-dxf` fragt den Punkt) | Einzelblock | `OmniModulInsert.lsp` |
| Omniflo Gerade | `OMNI_AP60`/`AP110`/`APG110` | `omni:make-gerade` | Compound-Block | `OmniModulInsert.lsp` |
| TEF-Foerderer-Linie | `TEF_FOERDERER_LINIE` | `tefl-insert-element` (ein Element) | Einzelbloecke | `TEFInsert.lsp` |
| Geruest (Saeule, Rohrabhaenger, Wandbefestigung) | `GERUEST`, `GERUEST_SAEULEN` ... | `geruest-block-bauen` | `GR_<id>_<ts>` | `GeruestInsert.lsp` |
| Geruest-Traeger | `GERUEST_TRAEGER` | `geruest-traeger-block-bauen` | `GR_<id>_<ts>` | `GeruestInsert.lsp` |
---
## 1. Kreisel und Eckrad (`KreiselInsert.lsp`)
### `kreisel-insert-script (pt abstand rotation typ hoehe drehrichtung)`
Kreisel an einem freien Punkt. Ruft `draw-module` auf.
| Parameter | Bedeutung |
|---|---|
| `pt` | Einfuegepunkt: aeusserster Punkt der AN-Seite auf der Achse (einen Radius = 400 mm vor der Mitte des Antriebsrads) |
| `abstand` | Mittenabstand Antriebsrad - Spannrad |
| `rotation` | Drehung der Achse AN -> SP in Grad |
| `typ` | `"STANDARD"` oder `"PIN"` (nil = `"STANDARD"`) -> Attribut `KREISELART` |
| `hoehe` | Einbauhoehe; nil = Z von `pt`, sonst `*kreisel-default-hoehe*` |
| `drehrichtung` | `"GUZ"`/`"UZS"` -> Attribut `DREHRICHTUNG` (optional, nil = Default `"UZS"` aus `*kreisel-attrib-defs*`) |
Rueckgabe: Entity des `KREISEL_n`-Blocks oder nil. Setzt `ssg-start`/`ssg-end`
selbst.
### `kreisel-connect-script (ptStart ptEnd typ hoehe)`
Kreisel zwischen zwei aeussersten Punkten (AN-Seite, SP-Seite). Berechnet
`abstand` = Distanz - `*kreisel-durchmesser*` (800) und `rotation` aus den
Punkten. Rueckgabe wie oben.
### `draw-module (basePoint abstand rotation attribs)`
Gemeinsamer Bau-Kern beider Funktionen: setzt Antriebs- und Spannstation,
Tangenten, Beschriftung, fasst alles zu `KREISEL_n` zusammen, schreibt die
Attribute (`attribs` = Alist, wird mit `*kreisel-attrib-defs*` gemischt).
Direkt nur aufrufen, wenn zusaetzliche Attribute gesetzt werden muessen.
### `ils-eckrad-insert (pt rotation attribs)`
Eckrad als Compound-Block `ECKRAD_n`.
| Parameter | Bedeutung |
|---|---|
| `pt` | **Radmitte** `(x y hoehe)` |
| `rotation` | Drehung in Grad |
| `attribs` | Alist mit Ueberschreibungen, z.B. `(("GERUEST_EINZELMODUL" . "1") ("GERUEST_TYP" . "Schoenenberger Geruest"))`; nil = Defaults |
`c:ILS_Eckrad` berechnet die Radmitte aus Beruehrpunkt + Radius in Richtung
des zweiten Klicks. Rueckgabe: Entity des Blocks.
---
## 2. VarioFoerderer Standard und Etage (`vf_core.lsp`, `vf_standard.lsp`, `vf_etage.lsp`)
Ablauf in drei Schritten: **loesen** (Winkel und Teillaengen aus den
Gesamtmassen), **einfuegen** (Bausteine verketten), **Block bilden**
(`VF_n` mit Attributen). Der Dialog-Ablauf `vf-dialog-ablauf` /
`vf-dialog-berechnen-einfuegen` macht dasselbe, oeffnet aber Dialog 2 und ist
darum nicht skriptfaehig.
### Vorbereitung
| Funktion | Zweck |
|---|---|
| `init-bibliothek ()` | Bogen-, AS-/ES- und Stationsmasse aus den Bloecken lesen. Setzt `*lib-initialized*`. Wird von `berechne-standard` aufgerufen |
| `init-bibliothek-etage ()` | dasselbe fuer Etage, aufgerufen von `berechne-etage` |
| `vf-set-as-masse (winkel seite)` / `vf-set-es-masse (winkel seite)` | AS-/ES-Masse (`aus-dx`/`aus-dz`, `ein-dx`/`ein-dz`) fuer die Variante `"90"`/`"30"` + `"links"`/`"rechts"` setzen |
### Loesen
| Funktion | Rueckgabe |
|---|---|
| `berechne-standard (deltaL deltaH richtung seite)` | `(best-winkel L_GF L_VF ergebnis-liste)` |
| `berechne-alle-winkel (deltaL deltaH richtung feste-hz schon-flach)` | wie oben; `feste-hz` nil = 1600 mm feste Horizontale, `schon-flach` nil |
| `berechne-etage (deltaL deltaH richtung seite)` | wie oben, Etage-Geometrie (setzt die Gefaellebogen-Masse je `seite`) |
| `vf-winkel-solve (...)` | gemeinsamer L_GF/L_VF-Solve beider Typen (intern) |
- `richtung` = `"Auf"`/`"Ab"`, `deltaH` als Betrag.
- `ergebnis-liste` = je Kandidatenwinkel `(winkel L_GF L_VF gueltig)`.
Kandidaten aus `vario.bogen_winkel` (3 ... 51). Einen bestimmten Winkel
erzwingen: Eintrag mit diesem `winkel` aus der Liste nehmen und
`gueltig`, `L_GF` > 0, `L_VF` > 0 pruefen (so `mubea:build-vario-one`).
- `L_GF` wird danach auf Vorlauf `L_GF1` und Nachlauf `L_GF2` aufgeteilt
(gleichmaessig / vorne / hinten / manuell, `foerderer:split-gf`).
### Einfuegen
```
(variofoerderer-einfuegen deltaL deltaH richtung best-winkel L_GF1 L_GF2 L_VF startpunkt seite hz)
(etage-foerderanlage-einfuegen deltaL deltaH richtung best-winkel L_GF1 L_GF2 L_VF startpunkt seite hz)
```
Identische Signatur (Registry-Vertrag `*vf-typ-registry*`). `startpunkt` =
Lage von **KS_EIN des AS-Elements**, Z = Einbauhoehe am Anfang. `seite` =
`"links"`/`"rechts"`. Rueckgabe: Endpunkt (KS_AUS des ES-Elements).
`variofoerderer-einfuegen` ist aus Teilen zusammengesetzt (`vfs-as-teil`,
VF-Eingang/Koerper, `vfs-es-teil`), die auch der Linienzug nutzt.
### Block bilden
```
(setq lastEnt (ssg-lastent-ohne-attribute)) ; VOR dem Einfuegen merken
...einfuegen...
(vf-block-erstellen anlage-typ seite (vf-next-number) n-scanner
hoehe-von hoehe-bis deltaH deltaL L_VF L_GF1 L_GF2
richtung best-winkel startpunkt lastEnt hz
geruest-einzelmodul geruest-typ)
(vf-edit-xdata-schreiben ent anlage-typ hz) ; editierbar per Doppelklick
```
- `anlage-typ` = `"standard"`/`"etage"`; `hoehe-bis` = +deltaH bei `"Auf"`,
-deltaH bei `"Ab"`; `geruest-einzelmodul` `"0"`/`"1"` (nil = `"1"`),
`geruest-typ` einer aus `*ssg-geruest-optionen*`.
- Sammelt alle Objekte seit `lastEnt` zum Block `VF_n`, setzt Layer, Attribute,
ID (`ssg-id-generate`) und Dimension. Rueckgabe: Entity des Blocks.
- `lastEnt` immer mit `ssg-lastent-ohne-attribute` holen, nicht mit
`(entlast)` (siehe `CLAUDE.md`, ssg_core).
- Blocknummer immer ueber `vf-next-number`: eine feste Nummer fuehrt bei der
zweiten Anlage zu einer Rueckfrage von `_.-BLOCK` und einem haengenden Befehl.
---
## 3. VF-Linienzug (`vf_linienzug.lsp`, `vf_spec.lsp`)
Ketten mit Vario-Kurven, GF-Boegen und mehreren VF-Einheiten. Der Bau-Ablauf
ist ein Frage-Antwort-Assistent; jede Eingabe wird journalisiert und als XDATA
am `VF_n`-Block gespeichert. Nicht-interaktiv baut man ihn, indem man ein
Journal **abspielt**.
| Funktion | Zweck |
|---|---|
| `vf-linienzug-modus ()` | Modus 1, frei zeichnend. Liest alle Eingaben ueber `vfl-in-point`/`-string`/`-real`/`-int` - aus der Replay-Queue, falls eine aktiv ist |
| `vf-linienzug-modus2 ()` | Modus 2, Pfad + Zielhoehe (Objektauswahl, eigenes Journal `"linienzug2"`) |
| `vfl-journal-replay-start (forward-journal)` | Journal als Antwort-Queue setzen; danach `vf-linienzug-modus` aufrufen |
| `vsp-journal (spec)` | Spec -> Journal (nil bei Spec-Fehlern, Fehler in `*vsp-fehler*`) |
| `vsp-pruefen (spec)` | alle Spec-Fehler sammeln |
| `vsp-bau-aus-spec (spec)` | eine Kette aus einer Spec bauen (headless, Replay, Ergebnis-Record mit `status`, Block, `prompts`, `glieder_soll`/`glieder_ist`) |
| `vsp-bau-liste (specs)` | mehrere Specs, je mit `vl-catch-all-apply` |
| `vsp-bau-datei (datei)` | Spec-Datei lesen (`vsp-json-laden` + `vsp-gruppieren`) und alle Ketten bauen; das ist `VF_SPEC_BAU` |
| `vsp-headless-an ()` / `vsp-headless-aus ()` | Headless-Rahmen: `*vfl-headless*`, Wizard aus, `*ssg-gui-aus*`, zaehlende Eingabe-Stubs |
Ein Abbruch im Headless-Modus nennt die Stelle (`*vfl-headless-fehler*`),
statt auf eine Live-Eingabe zu warten. Details zum Ablauf und zu den
Journal-Regeln: [variofoerderer.md](variofoerderer.md), Abschnitte 5-8b.
---
## 4. Gefaellestrecke (`Gefaellestrecke.lsp`)
### `gf-rebuild (deltaL winkel hz-winkel as-seite es-seite startpunkt as-winkel es-winkel geruest-einzelmodul geruest-typ)`
Der bequemste skriptfaehige Einstieg fuer Modus 1/2: setzt die AS-/ES-Masse,
berechnet die Staustrecke
`L_stau = (deltaL - aus-dx - ein-dx - separator_breite * cos(w)) / cos(w)`
und ruft `gefaellestrecke-einfuegen`. Ohne Zusammenfassung und Rueckfrage
(eigentlich fuer `GEFAELLESTRECKE_EDIT` gedacht).
| Parameter | Bedeutung |
|---|---|
| `deltaL` | horizontale Gesamtlaenge AS + Staustrecke + Separator + ES |
| `winkel` | Neigung der Staustrecke in Grad (Default im Dialog 3.0) |
| `hz-winkel` | Fahrtrichtung |
| `as-seite`, `es-seite` | `"links"`/`"rechts"` |
| `startpunkt` | **KS_EIN des AS-Elements**, Z = Einbauhoehe oben |
| `as-winkel`, `es-winkel` | `"90"`/`"30"` als STRING (nil = `"90"`) |
| `geruest-einzelmodul`, `geruest-typ` | wie beim VF |
Rueckgabe: `(ename deltaH deltaL)` oder nil (Staustrecke <= 0.1 mm -> `alert`).
### `gefaellestrecke-einfuegen (L_stau winkel startpunkt as-seite es-seite hz deltaL-total as-winkel es-winkel geruest-einzelmodul geruest-typ)`
Eigentlicher Bau: AS-Element, skalierte Staustrecke, Separator, ES-Element,
Block `GF_n` mit Attributen, XDATA `SSG_GF_EDIT` und ID. Erwartet die
fertige Staustreckenlaenge `L_stau` und passend gesetzte AS-/ES-Masse
(`vf-set-as-masse`/`vf-set-es-masse`). Rueckgabe wie `gf-rebuild`.
### Weitere
| Funktion | Zweck |
|---|---|
| `gf-modus12-abschluss (... dialog-bestaetigt ...)` | Abschluss Modus 1/2 mit Zusammenfassung; fragt ohne `dialog-bestaetigt` = T per Konsole nach |
| `gf-init-bibliothek ()` | AS-/ES-Masse fuer die GF lesen |
| `gf-linienzug-modus ()` | Modus 3, interaktiv (Auswahl vorhandener LINE/ARC) |
| `gf-linienzug-einfuegen (segmente grade startframe)` | Bau-Kern von Modus 3, erwartet die von `gf-analysiere-kette` aufbereiteten Segmente |
**Falle `*lib-initialized*`**: `gefaellestrecke-einfuegen` initialisiert die
GF-Masse nur, wenn `*lib-initialized*` nil ist - dasselbe Flag setzt
`init-bibliothek` des VarioFoerderers. Wer in einem Lauf erst VF und dann GF
baut, muss `gf-init-bibliothek` einmal selbst erzwingen (so
`mubea:ensure-gf-init` in `tests/test_mubea.lsp`), sonst rechnet die GF mit
den Vario-Massen und landet auf falscher Hoehe.
---
## 5. Einzelbloecke: Separator, Scanner, BTMT, Eingang/Ausgang
| Funktion | Zweck |
|---|---|
| `ils-insert-sensor (fname)` | Befehls-Kern Separator/Scanner: fuegt in einer Schleife ein, Punkt per `getpoint`, Drehung per `pause` - **nicht skriptfaehig** |
| `ils-insert-station (rohname)` | dasselbe fuer BTMT-Beladung, SC_Entladung, Eingang, Ausgang; setzt zusaetzlich den Layer aus dem `LAYER`-Attribut |
| `ssg-ils-block-laden (blockname)` | Blockdefinition `data/ils/<blockname>_<DIM>.dwg` einmal je Zeichnung laden; Rueckgabe: effektiver Blockname mit Suffix oder nil |
| `ssg-ils-block-datei (blockname)` | nur den Dateipfad aufloesen (3D-Fallback) |
| `ssg-block-layer-vorgabe` | `LAYER`-Attribut eines eingefuegten Blocks als Ziel-Layer anwenden |
| `ssg-id-generate (ent)` | eindeutige `ID` vergeben (nur wenn der Block ein ID-Attribut hat) |
Skriptfaehig bauen (Muster aus `hundm05:bau-sensor`):
```lisp
(setq eff (ssg-ils-block-laden "Scanner")) ; nicht per (and ...) verketten!
(command "_.INSERT" eff (list x y z) "" "" rotation)
(while (and (> (getvar "CMDACTIVE") 0) (< n 5)) (command "") (setq n (1+ n)))
(ssg-id-generate (entlast))
```
`ATTREQ`/`ATTDIA` vorher auf 0 setzen. Restliche Prompts gezaehlt mit Enter
beantworten, nicht ungebremst: eine Rueckfrage, die Enter ablehnt, haelt
`CMDACTIVE` sonst dauerhaft > 0.
---
## 6. Omniflo (`OmniModulInsert.lsp`)
| Funktion | Zweck |
|---|---|
| `omni:insert-dxf (sivasnr-str hoehe drehung)` | `%DXFM_OMNIFLO%/<sivasnr>.dxf` einfuegen, `HOEHE`/`DREHUNG` setzen, Layer. **Einfuegepunkt per Maus** (`pause`); Rueckgabe: Einfuegepunkt oder nil |
| `omni:insert-from-entry (dlg-result)` | Dialog-Ergebnis von Bogen/Weiche -> `omni:insert-dxf` |
| `omni:make-gerade (blockname pt pt2 srcAttribs textHeight textGap textEnt)` | **skriptfaehig**: Aluprofil-Gerade `"AP60"`/`"AP110"`/`"APG110"` von `pt` nach `pt2` als Compound-Block mit Text. `srcAttribs` per `omni:read-src-attribs`, `textEnt` nil. Kein `ssg-start` - Aufrufer setzt OSMODE/ATTREQ/ATTDIA = 0. Rueckgabe: Entity |
| `omni:insert-block (blockname laengemax)` | Befehls-Kern der Geraden (fragt `pt`/`pt2` per `getpoint`) |
| `omni:ladeschleifen-dialog (profiltyp init-hoehe)` | Dialog Ladeschleife, danach `omni:insert-dxf` |
Skriptfaehig fuer Boegen/Weichen: `_.INSERT` der DXF direkt mit Punkt
`(x y hoehe)` und Drehung, danach `ssg-attrib-set-on` mit `HOEHE`/`DREHUNG`
(`omni:test-insert` in `tests/test_omniflo.lsp`). Die festen TEF-/Zubehoer-
Befehle (`OMNI_TEF_*`, `OMNI_STOPPER` ...) rufen `omni:insert-dxf` mit fester
Sivas-Nummer. `OMNI_TV_*` und `OMNI_APBW_*` sind Platzhalter ohne Bau-Logik.
---
## 7. TEF-Foerderer-Linie (`TEFInsert.lsp`)
| Funktion | Zweck |
|---|---|
| `c:TEF_FOERDERER_LINIE` | Start-/Endpunkt abfragen, Linie zeichnen, 1000-mm-TEF-Geraden (`0_B10030.dxf`) aneinanderreihen; das letzte Stueck wird zurueckversetzt, damit der Foerderer genau am Linienende endet |
| `tefl-insert-element (start richtung-einheit s hz winkel)` | ein Element an Position `s` (mm ab `start`) entlang der Linie, Rz(hz)*Ry(winkel) |
| `tefl-ensure-block-loaded (dxf-pfad)` | Blockdefinition einmal laden |
---
## 8. Geruest (`GeruestInsert.lsp`)
| Funktion | Zweck |
|---|---|
| `geruest-einfuegen (bg wahl)` | Befehls-Kern Saeulen/Rohrabhaenger/Wandbefestigung: baut aus der Dialog-Auswahl `wahl` = `(variante-index oben unten laenge farbe)` die Werte (ARTINR, BEZEICHNUNG, TEILEART, LAENGE, TEILEFARBE), fragt dann den Punkt per `getpoint` |
| `geruest-block-bauen (bg variante werte pt teile-dwgs)` | **skriptfaehiger Kern**: Dummy-DWG + Teile-DWGs bei `pt`, Block `GR_<id>_<ts>`. `bg` = Baugruppe aus `geruest.json`, `werte` = Attribut-Alist, `teile-dwgs` aus `geruest-teile-dwgs` |
| `geruest-traeger-einfuegen (bg wahl)` | Befehls-Kern Traeger: Schleife Startpunkt -> Endpunkt oder Laenge |
| `geruest-traeger-block-bauen (bg layer netto strebe strebe-pfad muffe-pfad werte pt winkel)` | **skriptfaehiger Kern** Traeger: LINE (0,0,0)-(netto,0,0), Streben, Muffe, Block bei `pt` mit `winkel` (Radiant). Rueckgabe: `(blockname . entity)` |
| `geruest-traeger-laenge`, `-start`, `-streben`, `-pruefen` | reine Berechnung (Netto-Laenge nach Abzuegen, Startpunkt, Strebenverteilung, min/max) - in `tests/test_unit.lsp` getestet |
| `geruest-traeger-beschriften (blockEnt)` | Beschriftungstext aus dem fertigen Block |
| `geruest-block-abschliessen (bg attribs werte lastEnt pt rot)` | gemeinsamer Schluss aller Geruest-Bloecke (ATTDEFs, Block bilden, einfuegen, ID) |
Fuer Geruest gibt es noch keinen JSON-Treiber.
---
## 9. Einfuegeprimitiven (`ssg_ks_insert.lsp`, `vf_etage.lsp`)
Grundbausteine, auf denen VF, GF und Linienzug aufsetzen. Alle legen **KS_EIN**
des Blocks (nicht den Block-Ursprung) auf den Startpunkt und geben den
Weltpunkt von **KS_AUS** zurueck - damit lassen sich Bausteine verketten.
| Funktion | Zweck |
|---|---|
| `ensure-block-loaded (name)` | Block einmal ins Dokument laden |
| `extract-ks-from-block (block-obj)` | KS_EIN/KS_AUS eines eingefuegten Blocks (VLA-Objekt) lesen, Cache `*ks-cache*` je Blockname |
| `insert-block-by-ks (blockname einfuegepunkt hz)` | Block nur um Z gedreht (AS/ES-Elemente, Stationen) |
| `insert-inclined-scaled-block (blockname startpunkt laenge winkel hz)` | Block in X auf `laenge` skaliert und um `winkel` geneigt, Rz(hz)*Ry(winkel) (Staustrecken) |
| `insert-rotated-block-with-ks (blockname startpunkt winkel block-dx block-dz hz)` | Block gedreht, `block-dx`/`block-dz` nur als Fallback ohne KS_AUS (Boegen) |
| `insert-hz-scaled-block-by-ks (blockname startpunkt laenge hz-winkel vert-winkel)` | waagrechter, auf `laenge` skalierter Block (`Staustrecke_SP_1000_mm`, Massstab `laenge/1000`); Kandidat fuer die noch fehlende waagrechte Foerderstrecke. Bricht bei fehlender Blockdatei mit `(exit)` ab - vorher mit `ssg-ils-block-laden` pruefen |
| `ssg-rot-matrix-zy (chz shz cv sv)` | 4x4-Rotationsmatrix Rz(hz)*Ry(vert) aus Cosinus/Sinus beider Winkel (`ssg_core.lsp`) |
---
## 10. Gemeinsame Regeln fuer eigene Treiber
- Systemvariablen ueber `ssg-start`/`ssg-end` sichern; `OSMODE` 0,
`ATTREQ` 0, `ATTDIA` 0 setzen, sonst fragt `_.INSERT` nach Attributen.
- Module vorher laden: `(ssg-ensure "KreiselInsert")`, `"VarioFoerderer"`,
`"Gefaellestrecke"`, `"SSG_LIB_Commands"`.
- Die Dimension folgt `ssg-ils-dim-aktuell`; fuer einen festen Lauf
`*ssg-ils-dim*` (bzw. `*vsp-dim-override*` beim Spec-Bau) setzen und danach
zuruecksetzen.
- Rueckgaben nicht mit `and`/`or` verketten - die liefern in AutoLISP nur
T/nil (siehe `CLAUDE.md`, Konventionen).
- Interaktive GUI abschalten: `ssg-gui-aus` bzw. `vsp-headless-an`.
- Vorbilder: `tests/test_mubea.lsp` (Kreisel, VF Standard/Etage, GF,
Einzelbloecke), `tests/test_hundm05.lsp` (Spec-Ketten, Kreisel,
Einzelbloecke), `tests/test_omniflo_strecke.lsp` (Omniflo).
@@ -1,6 +1,9 @@
# TODO/Plan: VF-Linienzug ohne GUI/Konsole aufrufbar machen
**Stand:** 2026-09-02 · **Status:** Stufe 0 fertig (im CAD noch ungetestet)
**Stand:** 2026-09-02, Fortschrittsnotizen bis 2026-09-18 ·
**Status:** Stufe 0 fertig und CAD-verifiziert; Stufe 1 (Modus 1) im CAD
verifiziert, `TEST_HUNDM05` aktiv in `tests/alltests.json`; Stufe 2
Schritte 0-4 + 7-Assertion fertig, 5/6/8/9/10 offen, 11 zurueckgestellt.
**Herkunft:** Planungslauf (Plan-Modus) vom 2026-09-02, hier eingecheckt zur Nachverfolgung.
## Fortschritt
@@ -12,7 +15,7 @@
| P1 | `vfl-meldung` statt `alert` in den Bau-Pfaden | **erledigt** |
| P2 | `*vfl-headless*`: leere Replay-Queue wird zum Fehler | **erledigt** |
| P3 | Kleinkram (`*vfl-meldungen*`-Reset, `vfl-view-refresh`) | **erledigt** |
| S1 | Stufe 1: `Lisp/vf_spec.lsp` (Spec -> Journal -> Replay) | **Modus 1 fertig**, im CAD ungetestet |
| S1 | Stufe 1: `Lisp/vf_spec.lsp` (Spec -> Journal -> Replay) | **Modus 1 fertig, im CAD verifiziert** (`TEST_HUNDM05` aktiv in `tests/alltests.json`) |
| S2 | Stufe 2: echte Funktionstrennung | **Schritte 0-4 + 7-Assertion fertig**, 5/6/8/9/10 offen, 11 zurueckgestellt |
| PY | `lib/vf_journal_export.py`: Grammatik vervollstaendigen | **erledigt** |
@@ -79,11 +82,11 @@ Block ist (danach entstehen noch Beschriftungstexte). Behoben:
- `vfl-meldung` verkraftet jetzt `txt` = nil (fehlender i18n-Schluessel
wuerde `strcat` genau dann abbrechen, wenn schon etwas schiefging).
**Noch offen** (braucht BricsCAD): `TEST_HUNDM05` muss 5x
`"status": "executed"` mit `prompts` 0 liefern, und eine interaktive
Gegenprobe (`FOERDERANLAGE` -> Linienzug Modus 1, Doppelklick-Edit,
`SSG_DIM_SWITCH`) muss unveraendert aussehen. Erst danach kann in
`tests/alltests.json` das `"disabled": true` der hundm05-Zeile weg.
**Erledigt**: `TEST_HUNDM05` liefert 5x `"status": "executed"` mit `prompts`
0; die interaktive Gegenprobe (`FOERDERANLAGE` -> Linienzug Modus 1,
Doppelklick-Edit, `SSG_DIM_SWITCH`) ist unveraendert. Das `"disabled": true`
der hundm05-Zeile in `tests/alltests.json` ist weg, der Test laeuft aktiv
mit.
**Bewusst nicht umgestellt**: `vfl-konvertiere-ent` (Batch-2D/3D) laeuft
weiter ohne `*vfl-headless*` - eine Live-Rueckfrage ist dort bisher gewolltes
+18 -11
View File
@@ -70,7 +70,7 @@ Die JSON-Dateien liefern die IDs (Sivasnr) und Metadaten zur Filterung. Die DXF-
### --boegen
Alle Eintraege aus `omniflo_boegen.json` (27 Items, KurvenWinkel 22.5/45/67.5/90/180).
Alle Eintraege aus `omniflo_boegen.json` (29 Items, KurvenWinkel 22.5/45/67.5/90/180).
**Kriterium:** Schnittpunkt der Tangenten am Anfangs- und Endpunkt der Bogenkurve. Bei 180-Grad-Boegen wird der Mittelpunkt zwischen Start und Ende verwendet.
@@ -103,19 +103,21 @@ Einzel-, Doppel- und Dreiwegeweichen mit KurvenWinkel 0, ohne Sternweiche (8 Ite
### --delta
Deltaweichen (1 Item).
Deltaweichen (7 Items).
**Kriterium:** Mittelpunkt der laengsten horizontalen Linie.
### --dreifachweiche
Dreifachweichen (6 Items).
Dreifachweichen (aktuell 0 Items in `omniflo_weichen.json` - Schalter und
Filterkriterium existieren weiter in `lib/omniflo_utils.py` fuer den Fall,
dass wieder Dreifachweichen-Daten gepflegt werden).
**Kriterium:** Mittelpunkt der laengsten horizontalen Linie.
### --sternweiche
Sternweiche (1 Item).
Sternweiche (2 Items).
**Kriterium:** Zentrum, berechnet als Mittelpunkt der laengsten horizontalen Linie (entspricht dem Schnittpunkt der horizontalen und vertikalen Mittelachse).
@@ -135,21 +137,24 @@ Hier die Weichen
## Abdeckung
Alle 107 Items (27 Boegen + 80 Weichen) sind exklusiv genau einem Schalter zugeordnet. Keine Ueberlappungen, keine Luecken.
Alle 110 Items (29 Boegen + 81 Weichen, Stand aktuelle `data/json/omniflo_*.json`)
sind exklusiv genau einem Schalter zugeordnet. Keine Ueberlappungen, keine
Luecken. Die Zahlen je Schalter verschieben sich mit der Datenbasis; bei
Zweifel per `SWITCH_FILTERS` (`lib/omniflo_utils.py`) nachrechnen.
## Uebersicht aller Schalter
| Schalter | Items | WeichenTyp | KurvenWinkel | Einfuegepunkt-Kriterium |
| --- | --- | --- | --- | --- |
| `--boegen` | 27 | - | 22.5, 45, 67.5, 90, 180 | Tangentenschnittpunkt am Bogen (180: Mittelpunkt) |
| `--boegen` | 29 | - | 22.5, 45, 67.5, 90, 180 | Tangentenschnittpunkt am Bogen (180: Mittelpunkt) |
| `--weichen45` | 32 | Einzel-, Doppel-, Dreiwegeweiche | 45 | Tangente oberer Bogenpunkt x laengste Vertikale |
| `--weichen90` | 24 | Einzel-, Doppel-, Dreiwegeweiche | 90 | Tangente oberer Bogenpunkt x laengste Vertikale |
| `--weichenkoerper` | 8 | Einzel-, Doppel-, Dreiwegeweiche | 22.5 | Laengste Diagonale x laengste Vertikale |
| `--weichen-parallel` | 8 | Einzel-, Doppel-, Dreiwegeweiche | 0 | Laengste Diagonale x laengste Vertikale |
| `--dreifachweiche` | 6 | Dreifachweiche | 90 | Mittelpunkt laengste Horizontale |
| `--delta` | 1 | Deltaweiche | 90 | Mittelpunkt laengste Horizontale |
| `--sternweiche` | 1 | Sternweiche | 0 | Zentrum (Mittelpunkt laengste Horizontale) |
| **Gesamt** | **107** | | | |
| `--dreifachweiche` | 0 | Dreifachweiche | 90 | Mittelpunkt laengste Horizontale |
| `--delta` | 7 | Deltaweiche | 90 | Mittelpunkt laengste Horizontale |
| `--sternweiche` | 2 | Sternweiche | 0 | Zentrum (Mittelpunkt laengste Horizontale) |
| **Gesamt** | **110** | | | |
## Umgebungsvariablen
@@ -169,9 +174,11 @@ Setzt Koordinatensystem-Bloecke (K1, K2, K3, K4) in Omniflo DXF-Dateien. Jeder B
## Aufruf
```
python lib/set_koords.py [--schalter] [--number SIVASNR] [--force]
bin\set_coords.bat [--schalter] [--number SIVASNR] [--force]
```
Das Batch-Skript ruft `setenv.bat` auf und startet `lib/set_koords.py` mit den uebergebenen Argumenten.
## Datenquellen
| Pfad | Inhalt |
+91 -28
View File
@@ -185,12 +185,18 @@ Winkelberechnung befuellt, da seine Optionsliste von Dialog 1 abhaengt.
| Verteilung Staustrecken | `verteilung` | Dropdown | Gleichmaessig (L_GF1=L_GF2) / Vorne Minimum, hinten Rest / Hinten Minimum, vorne Rest / Eigene Werte | Gleichmaessig |
| L_GF1 vorne (manuell) | `lgf1_manuell` | Zahl (mm) | nur aktiv bei Verteilung "Eigene Werte" | L_GF / 2 |
Vorgelagert (Konsole, vor Dialog 1): Eingabemodus-Frage "3D-Linie" vs. "Werte
manuell" — nur bei Wahl "2" oeffnen sich obige Dialoge, sonst laeuft der
komplette [Legacy-Konsolen-Pfad](#8-legacy-konsolen-pfad). Direkt vor Dialog 1
wird zusaetzlich der Startpunkt (X/Y) per Punktwahl gewaehlt
(`vfs-standard-dialog-ablauf`, `Lisp/vf_standard.lsp:1069`); die Z-Hoehe kommt
aus dem Feld "Einfuegehoehe".
Vorgelagert: Eingabemodus-Frage "3D-Linie" vs. "Werte manuell" per DCL-Dialog
(`vfc_eingabemodus`, `vfc-dialog-eingabemodus-waehlen` in `Lisp/vf_core.lsp`;
Radio-Buttons wie `vfc_typ`, Rueckfall auf die alte Konsolenfrage bei
abgeschalteter GUI oder `DXFM_LANG=en_GB`). **Beide** Antworten fuehren zu
Dialog 1/2 oben: bei "3D-Linie" wird zuerst die Linie gewaehlt
(`vfc-3dlinie-erfassen`, Objektauswahl bleibt Zeichnung/Konsole — eine Linie
laesst sich nicht durch ein Formularfeld ersetzen) und deltaL/deltaH/hz/
Einfuegehoehe gehen als Prefill in Dialog 1; bei "Werte manuell" wird nur der
Startpunkt per Punktwahl-Dialog (`vfc-dialog-startpunkt-waehlen`) gewaehlt und
Dialog 1 startet ohne Geometrie-Prefill. Der
[Legacy-Konsolen-Pfad](#8-legacy-konsolen-pfad) existiert nur noch als
Rueckfall, wenn keiner der beiden Dialoge gezeigt werden kann/darf.
---
@@ -236,13 +242,62 @@ Das Winkel/Seite-Paar (`aus_winkel`/`aus_seite`, `ein_winkel`/`ein_seite`)
taucht identisch auch im Linienzug als AS-/ES-Element-Baustein auf (siehe
Abschnitt 5.2).
Zusaetzlich als Legacy-Konsole vorhanden (kein Dialog):
**Modus 2** — Startpunkt/Endpunkt waehlen (`GEFAELLESTRECKE_3DLINIE`): 2x
Punktwahl + Gefaellewinkel (Zahl, aus DeltaH automatisch vorgeschlagen).
Legacy-Konsole, kein Dialog.
- **Modus 2** — Startpunkt/Endpunkt waehlen: 2x Punktwahl + Gefaellewinkel
(Zahl, aus DeltaH automatisch vorgeschlagen).
- **Modus 3** — Bestehenden Linienzug (Linien/Boegen) auswaehlen: Objektauswahl,
Winkel wird aus der Geometrie vorgeschlagen und kann per j/n bestaetigt oder
ueberschrieben werden.
**Modus 3** — Bestehenden Linienzug (Linien/Boegen) auswaehlen
(`GEFAELLESTRECKE_LINIENZUG`): Objektauswahl (`ssget` LINE/ARC) und
Start-/Endpunktwahl bleiben Zeichnung/Konsole. AUS-/EIN-Element (Winkel
90/30 + Seite links/rechts) laufen danach ueber EINEN Dialog
(`gefaellestrecke_linienzug`, `gf-dialog-linienzug-aus-ein` in
`Lisp/Gefaellestrecke.lsp`) — muss vor der automatischen Segmentlaengen-
/Winkelberechnung laufen, die von der AS-/ES-Masse abhaengt. Danach zeigt
ein zweiter Dialog (`gf-dialog-linienzug-winkel`) den automatisch
berechneten Vorschlagswinkel ueberschreibbar zusammen mit einer kurzen
Segment-Zusammenfassung; dessen OK ersetzt zugleich die SPAETERE finale
Einfuegen-Bestaetigung (keine doppelte Rueckfrage nach der rein
automatischen AS/ES-Korrekturschleife). Rueckfall auf die alten
Konsolenfragen (inkl. der finalen Einfuegen-Bestaetigung), wenn einer der
beiden Dialoge nicht gezeigt werden kann/darf (GUI aus); ein bewusster
Dialog-Abbruch ('ABBRUCH) bricht dagegen den ganzen Befehl ab, OHNE auf die
Konsole zurueckzufallen.
**Beispiel Modus 3 — Gefaellestrecke aus einem gezeichneten Linienzug:**
1. Vorab eine Kette aus LINE-/ARC-Objekten entlang der gewuenschten Trasse
zeichnen (Geraden + Rundungen, hier ein abgerundeter Linienzug):
![GF aus Linienzug - Ausgangslinie](images/gf-linienzug1.png)
2. `GEFAELLESTRECKE_LINIENZUG` aufrufen, die Objekte auswaehlen sowie Start-
und Endpunkt der Kette anklicken. Danach AS-/EIN-Element (Winkel/Seite)
im ersten Dialog waehlen; der zweite Dialog zeigt den automatisch aus
der Geometrie berechneten Gefaellewinkel-Vorschlag (hier 3°, AS/ES-Felder
nur noch zur Kontrolle, nicht mehr editierbar):
![GF aus Linienzug - Dialog mit Vorschlagswinkel](images/gf-linienzug2.png)
3. Nach OK baut der Befehl die Gefaellestrecke direkt entlang der
Original-Linie (AUS-Element, Gefaellebogen an jeder Rundung,
Staustrecke, EIN-Element) — die urspruengliche Linie bleibt zur
Kontrolle in der Zeichnung stehen:
![GF aus Linienzug - fertige Strecke neben der Ausgangslinie](images/gf-linienzug3.png)
**Bearbeiten (`c:GEFAELLESTRECKE_EDIT`):** Doppelklick auf einen per
Linienzug gebauten `GF_n`-Block (TEILEART `"Streckengruppe"`, enthaelt
mindestens einen Bogen) dispatcht auf `gf-linienzug-rebuild` statt auf den
einfachen Gefaellestrecke-Dialog — der kennt keine Segmentliste/Boegen und
wuerde beim Neuaufbau die Bogengeometrie verlieren. Die Segmentliste
(Typ/Fahrtrichtung/Laenge/Winkel/Seite je Segment, bereits laengenfertig)
UND der Baustartpunkt stehen als eigene XDATA (App `SSG_GF_LZ`,
`gf-lz-xdata-schreiben`/`-lesen`, variable Laenge + Chunking wie die
Sepliste-XDATA in `ssg_ks_insert.lsp`) auf dem Block — ohne sie bleibt eine
Streckengruppe wie zuvor nicht editierbar (Meldung "Nur einfache
Gefaellestrecken..."). Der Edit-Ablauf nutzt dieselben zwei Dialoge wie das
Bauen (`gf-dialog-linienzug-aus-ein`/`-winkel`), diesmal mit den aktuellen
Attributen (`WINKEL_AS`/`SEITE_AS`/`WINKEL_ES`/`SEITE_ES`) vorbelegt statt
mit Defaults — AS-/ES-Element und Gefaellewinkel bleiben damit nachtraeglich
aenderbar, die Segmentlaengen/-form (Geraden, Boegen) selbst nicht (dafuer
muss die Kette per `GEFAELLESTRECKE_LINIENZUG` neu gebaut werden). Baut am
selben Startpunkt neu und loescht den alten Block erst NACH erfolgreichem
Neuaufbau.
---
@@ -377,6 +432,18 @@ interaktive Linienzug-Ablauf weiter (Abschnitt 5).
Einzige Eingabe — Rest laeuft automatisch (Attribute aggregiert, Luecken
werden gemeldet).
**VARIOFOERDERER_NACHRUESTEN / VF_NACHRUESTEN**
| Feld | Steuerelement | Werte |
|---|---|---|
| VF_n-Bloecke | Objektauswahl (`ssget`) | Altbestand ohne `SSG_VF_EDIT`-Marker |
| Baurichtung hz je Fund | Dialog `vfs_nachruesten_hz` (Zahl, Grad) | Vorgabe = zuletzt eingegebener Wert; Rueckfall auf Konsole nur, wenn der Dialog nicht gezeigt werden kann/darf |
Typ (Standard/Etage) wird automatisch aus den Attributen erkannt
(`GF_Bogen_R/L_60` -> Etage). Nur die Baurichtung ist nicht rekonstruierbar
und wird je unmarkiertem Fund abgefragt; "Abbrechen" im Dialog uebernimmt
fuer diesen Fund den Vorgabewert, ohne die ganze Schleife abzubrechen.
**VF_SEKTION_RESTORE — lose Kette aus der Zeichnung wiederherstellen**
| Feld | Steuerelement | Werte |
@@ -419,9 +486,11 @@ Wiederherstellungs-Daten gehoeren ausschliesslich in die XDATA der Zeichnung.
## 8. Legacy-Konsolen-Pfad
Wird bei Standard/Etage durchlaufen, wenn auf die Eingabemodus-Frage *nicht*
"2" getippt wird (Enter/leer faellt ebenfalls hierher zurueck) — also aktuell
noch der Vorgabe-Pfad. Zwei Untermodi:
Reiner Rueckfall fuer Standard/Etage: greift nur noch, wenn der Dialog
`vfc_eingabemodus` nicht gezeigt werden kann/darf (GUI abgeschaltet,
`DXFM_LANG=en_GB`) — im Normalfall (GUI an, Deutsch) laufen beide
Eingabemodi inzwischen ueber den Dialog (Abschnitt 2, "Vorgelagert"). Zwei
Untermodi:
**3D-Linie auswaehlen**
@@ -448,7 +517,7 @@ Optionen, bei "Eigene Werte" zusaetzlich L_GF1 als Zahl) -> Bestaetigung
## 8b. Nicht-interaktiver Betrieb (Headless)
Fuer Tests, Batch-Nachbau und den geplanten Spec-Bau (Fahrplan:
`doc/TODO-plan-vf-interactive.md`) muss eine Kette **ohne** Dialog und ohne
`doc/todo/plan-vf-interactive.md`) muss eine Kette **ohne** Dialog und ohne
Konsolenfrage laufen. Drei Schalter greifen dabei ineinander:
| Schalter | Datei | Wirkung |
@@ -585,19 +654,13 @@ eine bereits genannte, kleinere Nummer (z.B. 34 -> 35 -> 34) sind Schleifen
|---|---|---|---|
| 1 | Befehl waehlen | FOERDERANLAGE / GEFAELLESTRECKE | 2, 40 |
| 2 | Anlagen-Typ | Standard / Etage / Linienzug | 3, 3, 30 |
| 3 | Eingabemodus (nur Standard/Etage) | Konsole / Dialog | 4, 10 |
| 4 | Startpunkt waehlen | Punktwahl | 5 |
| 3 | Eingabemodus (nur Standard/Etage) | Dialog `vfc_eingabemodus`: 3D-Linie / Werte manuell | 11, 4 |
| 4 | Startpunkt waehlen | Punktwahl-Dialog | 5 |
| 5 | Dialog "Basis" | DeltaL, DeltaH, Auf/Ab, Einfuegehoehe, Fahrtrichtung, Seite, Motorseite, 2D/3D, Geruest | 6 |
| 6 | Winkelberechnung (automatisch) | - | 7 |
| 7 | Dialog "Winkel/Verteilung" | Winkel, Verteilung, ggf. L_GF1 | 8 |
| 8 | Bau (automatisch) | - | ENDE |
| 10 | Eingabemodus Konsole | 3D-Linie / Werte | 11, 12 |
| 11 | 3D-Linie waehlen | Objektwahl -> DeltaL/DeltaH/Fahrtrichtung automatisch | 13 |
| 12 | Werte eingeben | DeltaL, DeltaH, Auf/Ab, Startpunkt, Fahrtrichtung | 13 |
| 13 | Seite waehlen | rechts/links | 14 |
| 14 | Winkel waehlen | automatisch bei 1 Treffer, sonst Liste | 16 |
| 16 | Staustrecken-Verteilung | 4 Optionen, ggf. L_GF1 manuell | 17 |
| 17 | Bestaetigung "Einfuegen?" | Ja/Nein | 8 |
| 11 | 3D-Linie waehlen | Objektwahl (Zeichnung) -> DeltaL/DeltaH/Fahrtrichtung automatisch, Prefill fuer Dialog 5 | 5 |
| 30 | Linienzug-Modus | Manuell / Pfad+Zielhoehe / Vorwaerts-Nachbau | 31, 50, 55 |
| 31 | Startpunkt + Starthoehe | Punktwahl + Zahl | 32 |
| 32 | AS-Element setzen? | Ja/Nein | 33, 34 |
@@ -645,9 +708,9 @@ eine bereits genannte, kleinere Nummer (z.B. 34 -> 35 -> 34) sind Schleifen
### Beispiel-Abfolgen
- Standard, Dialog-Pfad: `1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8`
- Standard, Legacy-Konsole mit 3D-Linie: `1 -> 2 -> 3 -> 10 -> 11 -> 13 -> 14 -> 16 -> 17 -> 8`
- Etage, Dialog-Pfad: `1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8`
- Standard, Werte manuell: `1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8`
- Standard, aus 3D-Linie: `1 -> 2 -> 3 -> 11 -> 5 -> 6 -> 7 -> 8`
- Etage, Werte manuell: `1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8`
- Linienzug — AS-Element, GF, Auf/Ab-VF mit Zwischenkurve, Kettenende:
`1 -> 2 -> 30 -> 31 -> 32 -> 33 -> 34 -> 36 -> 41 -> 34 -> 37 -> 42 -> 46 -> 42 -> 45`
- Linienzug — horizontaler Anfang direkt bis Kettenende:
+53 -47
View File
@@ -10,9 +10,8 @@ aufrufbar in BricsCAD ueber `TEST_LINIENZUG_STUFE2` (siehe
diesen Testlauf jederzeit wiederholen.
Fuer die Architektur-Details (Frame-Kette, Journal/XDATA, Wizard-Dialoge)
siehe `doc/variofoerderer.md` und `doc/VarioFoerderer_Linienzug_Prinzipien.md`.
Diese Anleitung konzentriert sich auf die Bedienung und die typischen
Stolperfallen.
siehe `doc/variofoerderer.md`. Diese Anleitung konzentriert sich auf die
Bedienung und die typischen Stolperfallen.
## 1. Was ist Modus 1?
@@ -58,43 +57,48 @@ ist der interessante Teil (siehe Abschnitt 4, Stufe 1/Stufe 2).
Diese Tabelle zitiert die tatsaechlichen Konsolen-Fragen aus dem Testfall
(Kommentar-Spalte = `kommentar`-Feld im JSON) und erklaert, was jede Frage
bedeutet.
bedeutet. Die Datei hat aktuell 62 Eingabe-Eintraege (ohne das Kopf-Objekt);
mehrere Eintraege pro Zeile sind zu einem Schritt zusammengefasst, wo eine
Antwort mehrere JSON-Eintraege verbraucht (z.B. eine Vario-Kurve = Winkel +
Seite + Variante = 3 Eintraege).
| # | Frage (sinngemaess) | Antwort im Beispiel | Bedeutung |
| # (JSON-Eintraege) | Frage (sinngemaess) | Antwort im Beispiel | Bedeutung |
|---|---|---|---|
| 1 | Startpunkt der Kette | Klick (X/Y) | Beliebiger Punkt in der Zeichnung |
| 2 | Hoehe (Z) Startpunkt | 2154 | Absolute Einbauhoehe des Kettenanfangs |
| 3 | AS-Element setzen? | Ja | Umlenkstation am Anfang - "AS" = Ausgangs-/Anfangs-Element |
| 4 | AS-Element Winkel | 90 Grad | Baugroesse des Umlenkstations-Blocks (90 oder 30 Grad Kurvenradius) |
| 5 | AS-Seite | links | Auf welcher Seite die Umlenkstation seitlich ausschwenkt |
| 6 | Naechstes Element | Horizontal-VF | Kettenanfang-Menue hat 6 Optionen (GF-Bogen, Vario-Kurve, Linie-GF, Linie-VF, Horizontal-VF, Linienende) |
| 7 | Endpunkt Horizontal-VF | Klick | Laenge/Richtung der ersten VF-Einheit |
| 8 | Ziel-Hoehe Eingang GF1 | 1980 | Hoehe, auf die der Eingangs-GF-Anteil der VF-Einheit einregelt |
| 9 | Ist der Endpunkt der Foerderer? | Nein | Innerhalb der VF-Einheit: "geht die Kette hier zu Ende?" |
| 10-13 | Naechstes im VarioFoerderer -> Vario-Kurve 90 rechts innen | - | Grundriss-Schwenk INNERHALB der laufenden VF-Einheit |
| 14 | Ist der Endpunkt der Foerderer? | Nein | s.o. |
| 15-16 | Horizontaler Foerderer, Endpunkt | Klick | Weiteres gerades VF-Sub-Segment |
| 17 | Ist der Endpunkt der Foerderer? | Nein | s.o. |
| 18-21 | Vario-Kurve 90 rechts innen | - | Zweiter Grundriss-Schwenk |
| 22 | Ist der Endpunkt der Foerderer? | Ja, nur Motorstation | Schliesst die 1. VF-Einheit ab (Motorstation, kein ES) |
| 23 | Ist das Kettenende (ES-Element)? | Nein, weiterbauen | Nach der Motorstation: geht die Kette weiter? |
| 24 | Zusaetzlichen Separator hier? | Nein | Optionaler Separator direkt an der Motorstation |
| 25 | Naechstes Element | Neue Linie: GF | Jetzt folgt ein reines Gefaellestrecke-Element (kein VF) |
| 26 | Laenge bestimmen ueber | Endpunkt waehlen | Alternativ: Zielhoehe zuerst festlegen (siehe `vfl-gf-laenge-modus`) |
| 27 | Endpunkt Gefaellestrecke | Klick | Bestimmt deltaL der GF-Geraden |
| 28-29 | Separator VOR / NACH? | Ja / Ja | GF-Stuecke werden ueber Separatoren mechanisch begrenzt |
| 30-31 | Gefaelle festlegen -> Neigungswinkel | 3 Grad | Direkter Winkel (Alternative: Zielhoehe -> Winkel wird berechnet) |
| 32 | Ist das Kettenende? | Nein, weiterbauen | 3-Optionen-Menue: Ja+ES / Ja ohne ES / Nein |
| 33 | Naechstes Element | Horizontal-VF (2. Einheit) | Neue VF-Einheit beginnt direkt am GF-Ausgang (Separator als Eingang) |
| 34-49 | (wie oben: Vario-Kurven, Auf/Ab-Foerderer 27 Grad) | - | s.o. |
| 50 | Ist der Endpunkt der Foerderer? | Ja, Motorstation + Kettenende | Startet den automatischen Kettenende-Abschluss |
| 51-53 | ES-Element setzen? / Winkel / Seite | Ja / 90 / links | Ausgangs-Element, spiegelbildlich zum AS-Element |
| 54 | Endpunkt Kettenende | Klick | Letzter gewuenschter Punkt der Kette |
| 55 | Ziel-Hoehe Kettenende | 2154 | Muss wieder exakt die Starthoehe sein |
| 56 | (automatisch, keine Eingabe) | - | Stufe-1/Stufe-2-Loeser rechnet, siehe Abschnitt 4 |
| 57 | GF2=86mm unter Mindestlaenge - trotzdem bauen? | Ja | Sicherheitsfrage, siehe Abschnitt 4 |
| 6 | Naechstes Element | Neue VF mit horizontalem Anfang | Kettenanfang-Menue hat 6 Optionen (GF-Bogen, Vario-Kurve, Linie-GF, Linie-VF, Horizontal-VF, Linienende) |
| 7 | Endpunkt der Linie | Klick | Laenge/Richtung der ersten VF-Einheit |
| 8 | Ziel-Hoehe fuer den horizontalen VF-Anfang | 1980 | Hoehe, auf die der Eingangs-GF-Anteil der VF-Einheit einregelt |
| 9-10 | Zusaetzlichen Separator VOR/NACH dem horizontalen Stueck? | Nein / Nein | Optionale Separatoren direkt am VF-Einlauf |
| 11 | Ist der Endpunkt der Foerderer? | Nein | Innerhalb der VF-Einheit: "geht die Kette hier zu Ende?" |
| 12-15 | Naechstes im VarioFoerderer -> Vario-Kurve 90 rechts innen | - | Grundriss-Schwenk INNERHALB der laufenden VF-Einheit |
| 16 | Ist der Endpunkt der Foerderer? | Nein | s.o. |
| 17-18 | Horizontaler Foerderer, Endpunkt | Klick | Weiteres gerades VF-Sub-Segment |
| 19-20 | Zusaetzlichen Separator VOR/NACH? | Nein / Nein | s.o. |
| 21 | Ist der Endpunkt der Foerderer? | Nein | s.o. |
| 22-25 | Vario-Kurve 90 rechts innen | - | Zweiter Grundriss-Schwenk |
| 26 | Ist der Endpunkt der Foerderer? | Ja, nur Motorstation | Schliesst die 1. VF-Einheit ab (Motorstation, kein ES) |
| 27 | Ist das Kettenende (ES-Element)? | Nein, weiterbauen | Nach der Motorstation: geht die Kette weiter? |
| 28 | Zusaetzlichen Separator hier? | Nein | Optionaler Separator direkt an der Motorstation |
| 29 | Naechstes Element | Neue Linie: GF | Jetzt folgt ein reines Gefaellestrecke-Element (kein VF) |
| 30 | Laenge bestimmen ueber | Endpunkt waehlen | Alternativ: Zielhoehe zuerst festlegen (siehe `vfl-gf-laenge-modus`) |
| 31 | Ist das Kettenende? | Nein, weiterbauen | 3-Optionen-Menue: Ja+ES / Ja ohne ES / Nein - kommt VOR der Gefaelle-/Laengenberechnung |
| 32 | Endpunkt Gefaellestrecke | Klick | Bestimmt deltaL der GF-Geraden |
| 33-34 | Separator VOR / NACH? | Ja / Ja | GF-Stuecke werden ueber Separatoren mechanisch begrenzt |
| 35-36 | Gefaelle festlegen -> Neigungswinkel | 3 Grad | Direkter Winkel (Alternative: Zielhoehe -> Winkel wird berechnet) |
| 37 | Naechstes Element | Neue VF mit horizontalem Anfang (2. Einheit) | Neue VF-Einheit beginnt direkt am GF-Ausgang (Separator als Eingang) |
| 38-55 | (wie oben: Separatoren, Vario-Kurven, Auf/Ab-Foerderer 27 Grad) | - | s.o.; Auf/Ab-Foerderer nutzt Index 8 der gueltigen Winkeltabelle-Kandidaten = 27 Grad |
| 56 | Ist der Endpunkt der Foerderer? | Ja, Motorstation + Kettenende | Startet den automatischen Kettenende-Abschluss |
| 57-59 | ES-Element setzen? / Winkel / Seite | Ja / 90 / links | Ausgangs-Element, spiegelbildlich zum AS-Element |
| 60 | Endpunkt Kettenende | Klick | Letzter gewuenschter Punkt der Kette |
| 61 | Ziel-Hoehe Kettenende | 2154 | Muss wieder exakt die Starthoehe sein |
| 62 | GF2=319mm unter Mindestlaenge (400mm) - trotzdem bauen? | Ja | Sicherheitsfrage, siehe Abschnitt 4 - Stufe-1/Stufe-2-Loeser rechnet dazwischen automatisch |
**Wichtig zu Frage 9/14/17 ("Ist der Endpunkt der Foerderer?"):** Diese Frage
**Wichtig zu "Ist der Endpunkt der Foerderer?"** (Eintraege 11/16/21/26 usw.):
Diese Frage
kommt IMMER, wenn Sie innerhalb einer laufenden VF-Einheit einen Punkt
gepickt haben. "Nein" heisst: der gepickte Punkt ist nur eine
Zwischen-Etappe, es geht in derselben VF-Einheit weiter (Vario-Kurve,
@@ -103,7 +107,7 @@ Motorstation - optional zusaetzlich mit ES-Element (echtes Kettenende).
## 4. Stufe 1 / Stufe 2 - wie die letzte Strecke berechnet wird
Am Kettenende (Frage 55/56) ist die Aufgabe: von der aktuellen Position/
Am Kettenende (Eintrag 61/62) ist die Aufgabe: von der aktuellen Position/
Hoehe zur gewuenschten Ziel-Hoehe kommen, UND dabei die feste Baugruppe
Motorstation + Separator (+ ES-Element, falls gewaehlt) unterbringen. Das
Programm versucht das in zwei Stufen (`vfl-winkel-stufe-entscheidung`,
@@ -112,25 +116,25 @@ Programm versucht das in zwei Stufen (`vfl-winkel-stufe-entscheidung`,
- **Stufe 1 - Winkeltabelle:** Es probiert der Reihe nach die festen
Vario-Kurven-Winkel 3/6/9/12/15/18/21/27/33/39/45/51 Grad durch
(`berechne-alle-winkel`) und prueft, ob einer davon eine PASSENDE,
positive VF-Laenge ergibt. Das ist der Normalfall (siehe die Zeilen
"34-49" in der Tabelle: der Auf/Ab-Foerderer in der 2. VF-Einheit findet
positive VF-Laenge ergibt. Das ist der Normalfall (siehe die Zeile
"38-55" in der Tabelle: der Auf/Ab-Foerderer in der 2. VF-Einheit findet
so einen passenden Winkel, Auswahl-Index 8 = 27 Grad).
- **Stufe 2 - Horizontale Mitte + GF-Ausgleich:** Wenn KEIN Tabellenwinkel
passt (wie im Beispiel: alle 12 Kandidaten ergeben eine negative
VF-Laenge, die Reststrecke ist einfach zu kurz fuer einen echten
passt (wie im Beispiel am Kettenende: alle 12 Kandidaten ergeben eine
negative VF-Laenge, die Reststrecke ist einfach zu kurz fuer einen echten
Vertikalbogen), rechnet `berechne-horizontale-mitte` eine andere Loesung:
ein HORIZONTALES VF-Stueck (winkel=0) plus eine kurze Gefaellestrecke
(GF2), die exakt den fehlenden Hoehenunterschied ausgleicht. Im Beispiel:
GF2=86mm, VF=286mm.
GF2=319mm, L_VF=48mm.
Die Formel dahinter ist simpel und lohnt sich zu verinnerlichen: bei einem
FESTEN Neigungswinkel von 3 Grad braucht ein Hoehenausgleich von `H`
Millimetern eine GF-Laenge von `H / tan(3 Grad) ~= H * 19`. Ein winziger
Hoehenrest von z.B. 49mm braucht demnach bereits ~935mm GF-Laenge - siehe
Abschnitt 5.a. GF2 im Beispiel (86mm) ist kuerzer als die uebliche
Mindestlaenge (400mm, `*vfl-gf-min-laenge*`) - deshalb die Rueckfrage in
Schritt 57 ("trotzdem mit 86mm bauen?"). "Ja" baut trotzdem exakt mit dem
berechneten Wert; "Nein" wuerde den bis dahin gebauten Teil verwerfen (siehe
Millimetern eine GF-Laenge von `H / tan(3 Grad) ~= H * 19`. Ein Hoehenrest
von z.B. 17mm braucht demnach bereits ~320mm GF-Laenge - siehe Abschnitt
5.a. GF2 im Beispiel (319mm) liegt knapp unter der uebliche Mindestlaenge
(400mm, `*vfl-gf-min-laenge*`) - deshalb die Rueckfrage im letzten Eintrag
("trotzdem mit 319mm bauen?"). "Ja" baut trotzdem exakt mit dem berechneten
Wert; "Nein" wuerde den bis dahin gebauten Teil verwerfen (siehe
`vfl-loesche-seit`/`vfl-modus-abbruch-sichern`).
**Merksatz:** Stufe 1 sucht einen "sauberen" Standard-Winkel; Stufe 2 ist
@@ -170,9 +174,11 @@ Fallback ausloest.
Ein AS- oder ES-Element mit 90 Grad Bauform dreht die Fahrtrichtung nicht
einfach "auf der Stelle" - sein Block hat eine reale Baugroesse mit einem
seitlichen (quer zur Fahrtrichtung liegenden) Versatz. Im Standard-Testfall
(`linienzug_tests.json`) betraegt dieser Versatz ca. 637mm (`dY`), im
Stufe-2-Testfall ca. 638mm (`dX`, da die Fahrtrichtung dort anders liegt).
seitlichen (quer zur Fahrtrichtung liegenden) Versatz. Sowohl im Standard-
Testfall (`linienzug_tests.json`) als auch im Stufe-2-Testfall
(`linienzug_tests_stufe2.json`) betraegt dieser Versatz ca. 638mm (dort als
`erwartung_dx_mm` dokumentiert, da die Fahrtrichtung am Kettenende auf der
Y-Achse liegt und sich der Versatz dadurch in X statt in Y zeigt).
**Das ist kein Baufehler** - es ist die tatsaechliche Geometrie des
90-Grad-ES/AS-Blocks. Ein "Ist-Ziel-Report" mit einer Restabweichung von
ca. 638mm quer zur letzten Fahrtrichtung, aber ~0mm in Laengs-/Hoehenrichtung,
+61 -38
View File
@@ -245,6 +245,8 @@
"vfl-m3-abweichung": "\n Abweichung: dX=%1 dY=%2 dZ=%3 mm",
"vfl-m3-laengs-quer": "\n Laengs KS_AUS-Achse: %1 mm | Quer zur Achse (soll ~0): %2 mm",
"vfl-m3-achse-hinweis": "\n (dZ=Ziel-Hoehe; Quer zur KS_AUS-Achse ~0 => Endpunkt liegt auf der Achse)",
"vfl-m3-ziel-soll-es-korrigiert": "\n Soll (ES-korrigiert): X=%1 Y=%2 Z=%3 (Ziel + bekannter ES-Laengsversatz)",
"vfl-m3-abweichung-es-korrigiert": "\n Abweichung (ES-korrigiert): dX=%1 dY=%2 dZ=%3 mm",
"gf-fehler-block-fehlt": "\n FEHLER: Block '%1' fehlt",
"gf-fehler-block-fehlt-ausruf": "\n FEHLER: Block '%1' fehlt!",
"gf-fehler-blockdatei-fehlt": "\n FEHLER: Block-Datei nicht gefunden: %1",
@@ -330,7 +332,6 @@
"vfc-delta-l-h-richtung": "\n %1L=%2 mm %1H=%3 mm Fahrtrichtung=%4%5",
"vfc-endpunkt-xyz": "\n KS_AUS: X=%1 Y=%2 Z=%3",
"vfc-endpunkt-xyz-dxdz": "\n KS_AUS: X=%1 Y=%2 Z=%3 (dx=%4 dz=%5)",
"vfc-fahrtrichtung-ergebnis": "\n>>> Fahrtrichtung: %1%2",
"vfc-fehler-block-datei-fehlt": "\n FEHLER: Block-Datei nicht gefunden: %1",
"vfc-fehler-block-nicht-in-bibliothek": "\n FEHLER: Block '%1' nicht in Bibliothek",
"vfc-fehler-block-nicht-in-bibliothek-abgebrochen": "\n FEHLER: Block '%1' nicht in Bibliothek - abgebrochen",
@@ -500,32 +501,18 @@
"vfc-alert-keine-gueltige-linie": "Keine gueltige Linie ausgewaehlt!",
"vfc-bitte-3dlinie-foerderstrecke": "\nBitte 3D-Linie fuer die Foerderstrecke auswaehlen:",
"vfc-bks-weltkoordinaten": "\n BKS auf Weltkoordinaten gesetzt.",
"vfc-dlg-startpunkt-kopf": "Startpunkt der Anlage waehlen (X/Y):",
"vfc-eingabemodus-3dlinie": "\n 1 - 3D-Linie auswaehlen (Start- und Endpunkt mit Hoehe)",
"vfc-eingabemodus-header": "\n\nEingabemodus waehlen:",
"vfc-eingabemodus-werte": "\n 2 - Werte manuell eingeben",
"vfc-fahrtrichtung-0": "\n 1 - 0%1 (X-Achse +, Ost)",
"vfc-fahrtrichtung-180": "\n 3 - 180%1 (X-Achse -, West)",
"vfc-fahrtrichtung-270": "\n 4 - 270%1 (Y-Achse -, Sued)",
"vfc-fahrtrichtung-90": "\n 2 - 90%1 (Y-Achse +, Nord)",
"vfc-fahrtrichtung-header": "\n\nFahrtrichtung waehlen:",
"vfc-fehler-keine-linie": "\n FEHLER: Keine Linie oder Polylinie ausgewaehlt!",
"vfc-foerderrichtung-ab": "\n Foerderrichtung: AB",
"vfc-foerderrichtung-auf": "Auf",
"vfc-foerderrichtung-menu": "\nFoerderrichtung:\n 1 - AUF\n 2 - AB",
"vfc-gf-verteilung-header": "\n\nVerteilung der Gefaellestrecken (vorne/hinten):",
"vfc-gf-verteilung-1": "\n 1 - Gleichmaessig (L_GF1 = L_GF2 = L_GF/2)",
"vfc-gf-verteilung-2": "\n 2 - Vorne Minimum, hinten Rest",
"vfc-gf-verteilung-3": "\n 3 - Hinten Minimum, vorne Rest",
"vfc-gf-verteilung-4": "\n 4 - Eigene Werte eingeben",
"vfc-kein-objekt-gewaehlt": "\n Kein Objekt gewaehlt.",
"vfc-label-von-bis": ": von %1mm bis %2mm, ",
"vfc-linie-polylinie-waehlen": "\n >> 3D-Linie oder Polylinie waehlen: ",
"vfc-modus-3dlinie-fallback": "Linie",
"vfc-modus-3dlinie-header": "\n\n>>> MODUS: 3D-Linie auswaehlen <<<",
"vfc-modus-werteingabe-header": "\n\n>>> MODUS: Manuelle Werteingabe <<<",
"vfc-objekt-block-waehlen": "\n >> Objekt (Block) waehlen: ",
"vfc-prompt-delta-h": "\n%1H - Hoehenunterschied (mm): ",
"vfc-prompt-delta-l": "\n%1L - Horizontale Distanz (mm): ",
"vfc-prompt-startpunkt-aus": "\nStartpunkt fuer AUS_Element waehlen: ",
"vfc-prompt-wahl-1-2-ohne-default": "\nIhre Wahl (1/2): ",
"vfc-status-ok": " OK",
@@ -540,25 +527,7 @@
"vfc-prompt-wahl-1-n": "\nIhre Wahl (1-%1) [1]: ",
"vfc-typ-gewaehlt": "\n>>> Typ: %1",
"vfc-naechste-vf-nummer": "\n>>> Naechste VF-Nummer: VF%1",
"vfc-seite-header": "\n\nSeite waehlen:",
"vfc-seite-rechts": "\n 1 - Rechts",
"vfc-seite-links": "\n 2 - Links",
"vfc-seite-gewaehlt": "\n>>> Seite: %1",
"vfc-hinweis-horizontal-moeglich": "\n\n>>> Hinweis: Ein horizontale Variofoerderer ( 0%1) ist bei diesem %2L/%2H zusaetzlich moeglich!",
"vfc-alert-kein-winkel": "Kein passender Winkel gefunden!\n%1L=%2 mm, %1H=%3 mm, Richtung=%4",
"vfc-einzige-variante-horizontal": "\n\n>>> Einzige gueltige Variante: Horizontale Variofoerderer",
"vfc-einziger-winkel": "\n\n>>> Einziger gueltiger Winkel: %1%2",
"vfc-mehrere-winkel-header": "\n\nMehrere gueltige Winkel verfuegbar. Bitte waehlen:",
"vfc-winkel-option-horizontal": "\n %1 - Horizontale Variofoerderer (0%2) (L_GF=%3 mm, L_VF=%4 mm)",
"vfc-winkel-option": "\n %1 - %2%3 (L_GF=%4 mm, L_VF=%5 mm)",
"vfc-prompt-winkel-waehlen": "Winkel waehlen (1-%1) [1]: ",
"vfc-zus-horizontal": "\n>>> Horizontale Variofoerderer L_GF: %1 mm L_VF: %2 mm",
"vfc-zus-winkel": "\n>>> Winkel: %1%2 L_GF: %3 mm L_VF: %4 mm",
"vfc-prompt-lgf1-vorne": "\nL_GF1 vorne (mm) [%1]: ",
"vfc-lgf2-hinten": "\n L_GF2 hinten: %1 mm",
"vfc-zus-lgf": "\n>>> L_GF1=%1 mm L_GF2=%2 mm",
"vfc-einfuegen-frage": "\n\nMoechten Sie die Foerderanlage einfuegen?",
"vfc-einfuegen-optionen": "\n 1 - Ja, Module einfuegen\n 2 - Nein, abbrechen",
"vfc-vorgang-abgebrochen": "\nVorgang abgebrochen.",
"vfs-dlg-richtung-auf": "Auf",
"vfs-dlg-richtung-ab": "Ab",
@@ -808,6 +777,7 @@
"gf-status-deltah-3dpunkte": "\n %1H aus 3D-Punkten: %2 mm",
"gf-status-sortiere-segmente": "\n Sortiere Segmente ...",
"gf-alert-keine-kette": "Keine verbundene Kette gefunden!",
"gf-alert-lz-edit-kein-dialog": "Bearbeiten einer Streckengruppe (Linienzug) braucht die GUI - bitte GUI einschalten (ssg-gui-an) und erneut versuchen.",
"gf-status-segmente-gefunden": " %1 Segmente gefunden.",
"gf-status-segment-analyse-header": "\n\n--- Segment-Analyse (Laengen nach Kuerzung) ---",
"gf-status-segment-linie": "\n %1. Linie L=%2 mm hz=%3%4",
@@ -846,6 +816,7 @@
"gf-dlg-richtung-270": "270%1 (Y-, Sued)",
"gf-dlg-links": "Links",
"gf-dlg-rechts": "Rechts",
"gf-dlg-linienzug-vorlauf": "Linienzug ausgewaehlt - Winkel wird nach Bestaetigung berechnet.",
"gf-status-gf-block-erstellt": "\n>>> GF-Block erstellt: %1 (%2)",
"gf-status-schritt1-aus": "\n\n1/4: %1 Fahrtrichtung=%2%3 KS_EIN-hz=%4%5 v=%6%7",
"gf-status-schritt2-staustrecke": "\n\n2/4: Staustrecke L=%1 mm hz=%2%3 v=%4%5",
@@ -946,13 +917,11 @@
"vfc-linienzug-modus-1": "\n 1 - Manuelle Eingabe (Punkte klicken)",
"vfc-linienzug-modus-2": "\n 2 - 3D-Objekte + Ziel-Hoehe (Randwert-Solver, fertig)",
"vfc-linienzug-modus-3": "\n 3 - 3D-Objekte stueckweise (Vorwaerts-Nachbau, in Arbeit)",
"vfc-linienzug-modus-4": "\n 4 - QC Linie mit GF (automatische Auf-Ab-Berechnung)",
"vfc-linienzug-modus-5": "\n 5 - QC Linie mit GF und U-Form",
"prompt-wahl-1-5": "\nIhre Wahl (1/2/3/4/5) [1]: ",
"prompt-wahl-1-3": "\nIhre Wahl (1/2/3) [1]: ",
"vfl-qc-uform-nicht-implementiert": "\nFEHLER: 'QC Linie mit GF und U-Form' ist noch nicht implementiert - bitte Option 4 oder einen anderen Modus waehlen.",
"vfc-typ-standard-beschreibung": "Standard VarioFoerderer (AS/ES 90 Grad, horizontal versetzt)",
"vfc-typ-etage-beschreibung": "Etage VarioFoerderer (AS/ES 30 Grad, direkt uebereinander)",
"vfc-typ-linienzug-beschreibung": "3D-Linienzug (gemischte GF/VF-Kette; Modus 1 manuell / Modus 2 Ziel-Hoehe fertig / Modus 3 stueckweise in Arbeit)",
"vfc-typ-linienzug-beschreibung": "Streckengruppe (gemischte GF/VF-Kette; Modus 1 manuell / Modus 2 Ziel-Hoehe fertig / Modus 3 stueckweise in Arbeit)",
"vfs-schritt6-horizontal": "\n\n6/11: Horizontale Zwischenstrecke (0 Grad, L=%1 mm)",
"vfs-schritt6-steigung": "\n\n6/11: Steigungsstrecke (%1 Grad, L=%2 mm)",
"vfs-schritt6-gefaelle": "\n\n6/11: Gefaellestrecke (%1 Grad, L=%2 mm)",
@@ -1042,5 +1011,59 @@
"gr-tr-beschr-ergebnis": "\n%1 Traeger beschriftet (davon %2 ohne bekannte Variante), %3 nicht beschriftbar, %4 verwaiste Beschriftungen entfernt.",
"gr-tr-beschr-keine": "\nKeine Rohr-Geruest-Traeger in der Zeichnung.",
"gr-tr-strebe-rand": "Traeger %1 mm: Der Randabstand der Querstreben betraegt %2 mm und liegt ausserhalb des erlaubten Bereichs %3 bis %4 mm (Strebenabstand %5 mm, %6 Streben). Der Traeger wird trotzdem eingefuegt."
"in-yesno-keys": "Ja Nein",
"in-keys-bereich": "Alle Auswahl",
"in-keys-modus": "Teil Gesamt",
"bt-prompt-muster": "\nBlockname oder Muster (z.B. GR_*): ",
"bt-kein-block": "\nDas gewaehlte Objekt ist keine Blockeinfuegung.",
"bt-prompt-waehlen-count": "\nBlock waehlen [Name/Muster] <alle Bloecke>: ",
"bt-count-keine": "\nKeine Einfuegungen von %1 gefunden.",
"bt-count-keine-alle": "\nKeine Blockeinfuegungen im aktuellen Layout.",
"bt-count-ergebnis": "\n%1 Einfuegung(en) von %2.",
"bt-count-zeile": "\n %1: %2",
"bt-count-summe": "\nGesamt: %1 Einfuegung(en) in %2 Block(s).",
"bt-prompt-waehlen-delete": "\nZu loeschenden Block waehlen [Name/Muster]: ",
"bt-delete-kein-muster": "\nKein Block gewaehlt - nichts geloescht.",
"bt-delete-alle-gesperrt": "\nAlle %1 Einfuegung(en) liegen auf gesperrten Layern - nichts geloescht.",
"bt-delete-frage": "%1 Einfuegung(en) von %2 loeschen?",
"bt-delete-titel": "Bloecke loeschen",
"bt-delete-ergebnis": "\n%1 Einfuegung(en) geloescht.",
"bt-delete-gesperrt": "\n%1 Einfuegung(en) auf gesperrten Layern blieben stehen.",
"bt-abgebrochen": "\nAbgebrochen - nichts geaendert.",
"bt-attr-bereich": "\nBereich",
"bt-attr-muster": "\nBlockname-Muster",
"bt-attr-auswahl": "\nBloecke waehlen: ",
"bt-attr-keine-bloecke": "\nKeine passenden Blockeinfuegungen gefunden.",
"bt-attr-tag": "\nAttribut-Tag (Muster)",
"bt-attr-suche": "\nSuchen nach",
"bt-attr-ersatz": "\nErsetzen durch",
"bt-attr-modus": "\nErsetzen als",
"bt-attr-nichts": "\nKein Attributwert enthaelt den Suchtext.",
"bt-attr-frage": "%1 Attributwert(e) in %2 Block(s) aendern?",
"bt-attr-titel": "Attribute ersetzen",
"bt-attr-ergebnis": "\n%1 Attributwert(e) geaendert.",
"tt-bereich": "\nBereich",
"tt-auswahl": "\nObjekte waehlen: ",
"tt-keine-objekte": "\nKeine passenden Objekte gefunden.",
"tt-suche": "\nSuchen nach",
"tt-ersatz": "\nErsetzen durch",
"tt-modus": "\nErsetzen als",
"tt-nichts": "\nKein Text und kein Attributwert enthaelt den Suchtext.",
"tt-frage": "%1 Text(e) und %2 Attributwert(e) aendern?",
"tt-ersetzen-titel": "Text ersetzen",
"tt-ergebnis": "\n%1 Text(e) und %2 Attributwert(e) geaendert.",
"tt-abgebrochen": "\nAbgebrochen - nichts geaendert.",
"tt-parallel-titel": "Text parallel beschriften",
"tt-hoehe": "\nTexthoehe",
"tt-abstand": "\nAbstand zur Linie",
"tt-parallel-waehlen": "\nLinie, Polylinie oder Bogen waehlen (Enter = Ende): ",
"tt-parallel-keine-kurve": "\nWinkel am gewaehlten Objekt nicht ermittelbar.",
"tt-text": "\nText",
"tt-parallel-fehler": "\nText konnte nicht erzeugt werden.",
"tt-hoehe-titel": "Texthoehe aendern",
"tt-geaendert": "\n%1 Text(e) geaendert.",
"tt-stil": "\nTextstil",
"tt-stil-fehlt": "\nTextstil %1 existiert nicht in der Zeichnung.",
"tt-stil-titel": "Textstil aendern"
}
}
+61 -38
View File
@@ -245,6 +245,8 @@
"vfl-m3-abweichung": "\n Deviation: dX=%1 dY=%2 dZ=%3 mm",
"vfl-m3-laengs-quer": "\n Along KS_AUS axis: %1 mm | across axis (should be ~0): %2 mm",
"vfl-m3-achse-hinweis": "\n (dZ=target height; across KS_AUS axis ~0 => end point lies on the axis)",
"vfl-m3-ziel-soll-es-korrigiert": "\n Target (ES-corrected): X=%1 Y=%2 Z=%3 (target + known ES lateral offset)",
"vfl-m3-abweichung-es-korrigiert": "\n Deviation (ES-corrected): dX=%1 dY=%2 dZ=%3 mm",
"gf-fehler-block-fehlt": "\n ERROR: block '%1' missing",
"gf-fehler-block-fehlt-ausruf": "\n ERROR: block '%1' missing!",
"gf-fehler-blockdatei-fehlt": "\n ERROR: block file not found: %1",
@@ -330,7 +332,6 @@
"vfc-delta-l-h-richtung": "\n %1L=%2 mm %1H=%3 mm Travel direction=%4%5",
"vfc-endpunkt-xyz": "\n KS_AUS: X=%1 Y=%2 Z=%3",
"vfc-endpunkt-xyz-dxdz": "\n KS_AUS: X=%1 Y=%2 Z=%3 (dx=%4 dz=%5)",
"vfc-fahrtrichtung-ergebnis": "\n>>> Travel direction: %1%2",
"vfc-fehler-block-datei-fehlt": "\n ERROR: block file not found: %1",
"vfc-fehler-block-nicht-in-bibliothek": "\n ERROR: block '%1' not in library",
"vfc-fehler-block-nicht-in-bibliothek-abgebrochen": "\n ERROR: block '%1' not in library - cancelled",
@@ -500,32 +501,18 @@
"vfc-alert-keine-gueltige-linie": "No valid line selected!",
"vfc-bitte-3dlinie-foerderstrecke": "\nPlease select a 3D line for the conveyor section:",
"vfc-bks-weltkoordinaten": "\n UCS set to world coordinates.",
"vfc-dlg-startpunkt-kopf": "Select start point of the system (X/Y):",
"vfc-eingabemodus-3dlinie": "\n 1 - Select 3D line (start and end point with height)",
"vfc-eingabemodus-header": "\n\nSelect input mode:",
"vfc-eingabemodus-werte": "\n 2 - Enter values manually",
"vfc-fahrtrichtung-0": "\n 1 - 0%1 (X axis +, East)",
"vfc-fahrtrichtung-180": "\n 3 - 180%1 (X axis -, West)",
"vfc-fahrtrichtung-270": "\n 4 - 270%1 (Y axis -, South)",
"vfc-fahrtrichtung-90": "\n 2 - 90%1 (Y axis +, North)",
"vfc-fahrtrichtung-header": "\n\nSelect travel direction:",
"vfc-fehler-keine-linie": "\n ERROR: No line or polyline selected!",
"vfc-foerderrichtung-ab": "\n Conveying direction: DOWN",
"vfc-foerderrichtung-auf": "Up",
"vfc-foerderrichtung-menu": "\nConveying direction:\n 1 - UP\n 2 - DOWN",
"vfc-gf-verteilung-header": "\n\nDistribution of slope sections (front/rear):",
"vfc-gf-verteilung-1": "\n 1 - Even (L_GF1 = L_GF2 = L_GF/2)",
"vfc-gf-verteilung-2": "\n 2 - Front minimum, rear remainder",
"vfc-gf-verteilung-3": "\n 3 - Rear minimum, front remainder",
"vfc-gf-verteilung-4": "\n 4 - Enter custom values",
"vfc-kein-objekt-gewaehlt": "\n No object selected.",
"vfc-label-von-bis": ": from %1mm to %2mm, ",
"vfc-linie-polylinie-waehlen": "\n >> Select 3D line or polyline: ",
"vfc-modus-3dlinie-fallback": "Line",
"vfc-modus-3dlinie-header": "\n\n>>> MODE: Select 3D line <<<",
"vfc-modus-werteingabe-header": "\n\n>>> MODE: Manual value entry <<<",
"vfc-objekt-block-waehlen": "\n >> Select object (block): ",
"vfc-prompt-delta-h": "\n%1H - height difference (mm): ",
"vfc-prompt-delta-l": "\n%1L - horizontal distance (mm): ",
"vfc-prompt-startpunkt-aus": "\nSelect start point for AUS_Element: ",
"vfc-prompt-wahl-1-2-ohne-default": "\nYour choice (1/2): ",
"vfc-status-ok": " OK",
@@ -540,25 +527,7 @@
"vfc-prompt-wahl-1-n": "\nYour choice (1-%1) [1]: ",
"vfc-typ-gewaehlt": "\n>>> Type: %1",
"vfc-naechste-vf-nummer": "\n>>> Next VF number: VF%1",
"vfc-seite-header": "\n\nSelect side:",
"vfc-seite-rechts": "\n 1 - Right",
"vfc-seite-links": "\n 2 - Left",
"vfc-seite-gewaehlt": "\n>>> Side: %1",
"vfc-hinweis-horizontal-moeglich": "\n\n>>> Note: a horizontal VarioFoerderer ( 0%1) is additionally possible for this %2L/%2H!",
"vfc-alert-kein-winkel": "No suitable angle found!\n%1L=%2 mm, %1H=%3 mm, direction=%4",
"vfc-einzige-variante-horizontal": "\n\n>>> Only valid variant: horizontal VarioFoerderer",
"vfc-einziger-winkel": "\n\n>>> Only valid angle: %1%2",
"vfc-mehrere-winkel-header": "\n\nSeveral valid angles available. Please choose:",
"vfc-winkel-option-horizontal": "\n %1 - Horizontal VarioFoerderer (0%2) (L_GF=%3 mm, L_VF=%4 mm)",
"vfc-winkel-option": "\n %1 - %2%3 (L_GF=%4 mm, L_VF=%5 mm)",
"vfc-prompt-winkel-waehlen": "Select angle (1-%1) [1]: ",
"vfc-zus-horizontal": "\n>>> Horizontal VarioFoerderer L_GF: %1 mm L_VF: %2 mm",
"vfc-zus-winkel": "\n>>> Angle: %1%2 L_GF: %3 mm L_VF: %4 mm",
"vfc-prompt-lgf1-vorne": "\nL_GF1 front (mm) [%1]: ",
"vfc-lgf2-hinten": "\n L_GF2 rear: %1 mm",
"vfc-zus-lgf": "\n>>> L_GF1=%1 mm L_GF2=%2 mm",
"vfc-einfuegen-frage": "\n\nDo you want to insert the conveyor system?",
"vfc-einfuegen-optionen": "\n 1 - Yes, insert modules\n 2 - No, cancel",
"vfc-vorgang-abgebrochen": "\nProcess cancelled.",
"vfs-dlg-richtung-auf": "Up",
"vfs-dlg-richtung-ab": "Down",
@@ -808,6 +777,7 @@
"gf-status-deltah-3dpunkte": "\n %1H from 3D points: %2 mm",
"gf-status-sortiere-segmente": "\n Sorting segments ...",
"gf-alert-keine-kette": "No connected chain found!",
"gf-alert-lz-edit-kein-dialog": "Editing a chain group (path-built) requires the GUI - please enable the GUI (ssg-gui-an) and try again.",
"gf-status-segmente-gefunden": " %1 segments found.",
"gf-status-segment-analyse-header": "\n\n--- Segment analysis (lengths after trimming) ---",
"gf-status-segment-linie": "\n %1. Line L=%2 mm hz=%3%4",
@@ -846,6 +816,7 @@
"gf-dlg-richtung-270": "270%1 (Y-, South)",
"gf-dlg-links": "Left",
"gf-dlg-rechts": "Right",
"gf-dlg-linienzug-vorlauf": "Path selected - angle will be calculated after confirmation.",
"gf-status-gf-block-erstellt": "\n>>> GF block created: %1 (%2)",
"gf-status-schritt1-aus": "\n\n1/4: %1 travel dir=%2%3 KS_EIN-hz=%4%5 v=%6%7",
"gf-status-schritt2-staustrecke": "\n\n2/4: Buffer section L=%1 mm hz=%2%3 v=%4%5",
@@ -946,13 +917,11 @@
"vfc-linienzug-modus-1": "\n 1 - Manual entry (click points)",
"vfc-linienzug-modus-2": "\n 2 - 3D objects + target height (boundary-value solver, finished)",
"vfc-linienzug-modus-3": "\n 3 - 3D objects step by step (forward reconstruction, work in progress)",
"vfc-linienzug-modus-4": "\n 4 - QC line with GF (automatic up/down calculation)",
"vfc-linienzug-modus-5": "\n 5 - QC line with GF and U-shape",
"prompt-wahl-1-5": "\nYour choice (1/2/3/4/5) [1]: ",
"prompt-wahl-1-3": "\nYour choice (1/2/3) [1]: ",
"vfl-qc-uform-nicht-implementiert": "\nERROR: 'QC line with GF and U-shape' is not yet implemented - please choose option 4 or a different mode.",
"vfc-typ-standard-beschreibung": "Standard VarioFoerderer (AS/ES 90 degrees, offset horizontally)",
"vfc-typ-etage-beschreibung": "Etage VarioFoerderer (AS/ES 30 degrees, directly stacked)",
"vfc-typ-linienzug-beschreibung": "3D line path (mixed GF/VF chain; mode 1 manual / mode 2 target height finished / mode 3 step by step work in progress)",
"vfc-typ-linienzug-beschreibung": "Route group (mixed GF/VF chain; mode 1 manual / mode 2 target height finished / mode 3 step by step work in progress)",
"vfs-schritt6-horizontal": "\n\n6/11: Horizontal intermediate section (0 deg, L=%1 mm)",
"vfs-schritt6-steigung": "\n\n6/11: Incline section (%1 deg, L=%2 mm)",
"vfs-schritt6-gefaelle": "\n\n6/11: Slope section (%1 deg, L=%2 mm)",
@@ -1042,5 +1011,59 @@
"gr-tr-beschr-ergebnis": "\n%1 beam(s) labelled (%2 without known variant), %3 not labellable, %4 orphaned label(s) removed.",
"gr-tr-beschr-keine": "\nNo pipe scaffold beams in the drawing.",
"gr-tr-strebe-rand": "Beam %1 mm: the edge distance of the cross braces is %2 mm, outside the allowed range %3 to %4 mm (brace spacing %5 mm, %6 braces). The beam is inserted anyway."
"in-yesno-keys": "Yes No",
"in-keys-bereich": "All Selection",
"in-keys-modus": "Part Whole",
"bt-prompt-muster": "\nBlock name or pattern (e.g. GR_*): ",
"bt-kein-block": "\nThe selected object is not a block reference.",
"bt-prompt-waehlen-count": "\nSelect block [Name/pattern] <all blocks>: ",
"bt-count-keine": "\nNo references of %1 found.",
"bt-count-keine-alle": "\nNo block references in the current layout.",
"bt-count-ergebnis": "\n%1 reference(s) of %2.",
"bt-count-zeile": "\n %1: %2",
"bt-count-summe": "\nTotal: %1 reference(s) in %2 block(s).",
"bt-prompt-waehlen-delete": "\nSelect block to delete [Name/pattern]: ",
"bt-delete-kein-muster": "\nNo block selected - nothing deleted.",
"bt-delete-alle-gesperrt": "\nAll %1 reference(s) are on locked layers - nothing deleted.",
"bt-delete-frage": "Delete %1 reference(s) of %2?",
"bt-delete-titel": "Delete blocks",
"bt-delete-ergebnis": "\n%1 reference(s) deleted.",
"bt-delete-gesperrt": "\n%1 reference(s) on locked layers were kept.",
"bt-abgebrochen": "\nCancelled - nothing changed.",
"bt-attr-bereich": "\nScope",
"bt-attr-muster": "\nBlock name pattern",
"bt-attr-auswahl": "\nSelect blocks: ",
"bt-attr-keine-bloecke": "\nNo matching block references found.",
"bt-attr-tag": "\nAttribute tag (pattern)",
"bt-attr-suche": "\nFind",
"bt-attr-ersatz": "\nReplace with",
"bt-attr-modus": "\nReplace as",
"bt-attr-nichts": "\nNo attribute value contains the search text.",
"bt-attr-frage": "Change %1 attribute value(s) in %2 block(s)?",
"bt-attr-titel": "Replace attributes",
"bt-attr-ergebnis": "\n%1 attribute value(s) changed.",
"tt-bereich": "\nScope",
"tt-auswahl": "\nSelect objects: ",
"tt-keine-objekte": "\nNo matching objects found.",
"tt-suche": "\nFind",
"tt-ersatz": "\nReplace with",
"tt-modus": "\nReplace as",
"tt-nichts": "\nNo text or attribute value contains the search text.",
"tt-frage": "Change %1 text(s) and %2 attribute value(s)?",
"tt-ersetzen-titel": "Replace text",
"tt-ergebnis": "\n%1 text(s) and %2 attribute value(s) changed.",
"tt-abgebrochen": "\nCancelled - nothing changed.",
"tt-parallel-titel": "Label parallel to line",
"tt-hoehe": "\nText height",
"tt-abstand": "\nDistance to line",
"tt-parallel-waehlen": "\nSelect line, polyline or arc (Enter = finish): ",
"tt-parallel-keine-kurve": "\nCannot determine the angle on the selected object.",
"tt-text": "\nText",
"tt-parallel-fehler": "\nText could not be created.",
"tt-hoehe-titel": "Change text height",
"tt-geaendert": "\n%1 text(s) changed.",
"tt-stil": "\nText style",
"tt-stil-fehlt": "\nText style %1 does not exist in the drawing.",
"tt-stil-titel": "Change text style"
}
}
+413
View File
@@ -0,0 +1,413 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
dxf_anlage_export.py - Eine mit unseren Makros GEBAUTE (und von Hand
nachbearbeitete) Anlage aus der Zeichnung zurueck in Nachbau-Testdaten
schreiben.
Gegenstueck zu lib/dxf_scan_components.py: der Scanner liest FREMDE
Zeichnungen (Rohbloecke, Linien) und muss vieles raten. Hier stehen unsere
Wrapper-Bloecke in der Zeichnung, und jeder traegt seine Bau-Parameter
selbst - als Attribute und XDATA, genau die Werte, die auch der jeweilige
Edit-Befehl (Doppelklick) zum Neuaufbau liest. Typischer Ablauf: Scanner-
Vorlage nachbauen, in BricsCAD von Hand korrigieren/ergaenzen, Zeichnung als
DXF speichern und mit diesem Skript die Testdaten aktualisieren.
Je Wrapper (Felder wie in tests/testdata/object_data.md bzw. mubea.json):
KREISEL_n -> Kreisel ("function": "insert", x/y/z = Einfuegepunkt,
abstand = Mittenabstand AN8-SP8 aus der Blockdefinition,
rotation, typ = KREISELART, drehrichtung = DREHRICHTUNG)
GF_n -> Gefaellestrecke Modus 1 (XDATA SSG_GF_EDIT wie
gf-xdata-lesen + SEITE_AS/SEITE_ES wie GEFAELLESTRECKE_EDIT).
Endet die Strecke auf der Kette eines Kreisels, wird statt
des gebauten Winkels dessen Hoehe als hoehe_ende_mm
uebernommen - der Treiber rechnet den Winkel daraus neu.
VF_n "standard"/"etage"
-> VarioFoerderer im mubea-Schema (Parameter wie
vfs-edit-basis-lesen: Einfuegepunkt, hz aus XDATA, DELTA_L/
DELTA_H/ANTRIEBFAHRTRICHTUNG/SEITE_AS/MOTORSEITE, dazu
VF_WINKEL und L_GF1 aus L_GF_m)
VF_n "linienzug"
-> das Eingabe-Journal UNVERAENDERT ("typ":
"linienzug_journal"). Bewusst KEINE Spec: der Bau-Dialog ist
neuer als die Spec-Grammatik (vf_linienzug_grammatik.py,
vf_spec.lsp), eine Uebersetzung wuerde desynchronisieren.
Der Treiber spielt das Journal per vsp-bau-journal ab.
sonstige Bloecke (Separator, Scanner, ...)
-> Einzel-Insert ("function": "insert", "block" ohne
_2D/_3D-Suffix, damit die Dimension der Sitzung gilt)
Nicht uebernommen (gemeldet): "linienzug2" (Modus 2 - Journal verweist auf
Pfad-Objekte der Zeichnung per Handle) und Bloecke ohne Bau-Parameter.
Aufruf:
python dxf_anlage_export.py <dxf> <output.json> [--projekt NAME]
Beispiel (Dematic/Arvato, Nachbau-Daten fuer TEST_DEMATIC_ARVATO):
python lib/dxf_anlage_export.py C:/develop/sps_skel/data/Dematic_TST.dxf \\
tests/testdata/dematic_arvato.json --projekt Arvato
Bewusst OHNE ezdxf: reine Gruppencode-Lesung (vf_journal_export.gruppen),
ASCII-DXF.
"""
import argparse
import collections
import json
import math
import os
import re
import sys
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from vf_journal_export import TRENNER, gruppen # noqa: E402
from dxf_scan_components import arrays_einzeilig, kreisel_anschluss # noqa: E402
import testdata_schema as sch # noqa: E402
PREFIX = "[dxf_anlage_export]"
RUND = 2
# Kreisel-Durchmesser (Radmitte bis Kette), wie component_defaults.json.
KREISEL_RADIUS = 400.0
# Bis zu diesem Abstand (mm) gilt ein GF-Ende als auf der Kette eines
# Kreisels (der GF-Bau legt AS-/ES-Ursprung genau auf die Kette).
GF_KREISEL_TOL = 50.0
DIM_SUFFIX = re.compile(r"_(2D|3D)$")
# ============================================================
# DXF lesen
# ============================================================
def _float(v):
try:
return float(v)
except (TypeError, ValueError):
return 0.0
def lese_zeichnung(dxf_pfad):
"""Modelspace-INSERTs (mit Attributen und XDATA je App) und die INSERTs
jeder Blockdefinition.
Rueckgabe: (inserts, block_inhalt)
inserts - Liste {name, handle, p, rot, attribs, xdata}; xdata ist
app -> Liste der 1000er-Werte in Reihenfolge
block_inhalt - blockname -> Liste {name, p} der direkt enthaltenen
INSERTs (fuer den Kreisel-Mittenabstand)
"""
paare = gruppen(dxf_pfad)
inserts = []
block_inhalt = {}
section = None
block = None
i, n = 0, len(paare)
while i < n:
code, wert = paare[i]
if code != "0":
i += 1
continue
if wert == "SECTION" and i + 1 < n:
section = paare[i + 1][1].strip()
elif wert == "ENDSEC":
section = None
elif wert == "BLOCK":
j = i + 1
while j < n and paare[j][0] != "0":
if paare[j][0] == "2":
block = paare[j][1]
break
j += 1
elif wert == "ENDBLK":
block = None
elif wert == "INSERT" and section in ("ENTITIES", "BLOCKS"):
e = {"name": None, "handle": None, "p": [0.0, 0.0, 0.0],
"rot": 0.0, "attribs": {}, "xdata": {}, "ps": 0}
app = None
j = i + 1
while j < n and paare[j][0] != "0":
c, v = paare[j]
if c == "2" and e["name"] is None:
e["name"] = v
elif c == "5" and e["handle"] is None:
e["handle"] = v
elif c in ("10", "20", "30") and app is None:
e["p"][{"10": 0, "20": 1, "30": 2}[c]] = _float(v)
elif c == "50":
e["rot"] = _float(v)
elif c == "67":
e["ps"] = int(_float(v))
elif c == "1001":
app = v
e["xdata"][app] = []
elif c == "1000" and app:
e["xdata"][app].append(v)
j += 1
# Attribute: ATTRIB-Entities bis SEQEND (Wert Code 1, Tag Code 2)
while j < n and paare[j] == ("0", "ATTRIB"):
k = j + 1
tag = val = None
while k < n and paare[k][0] != "0":
if paare[k][0] == "2" and tag is None:
tag = paare[k][1]
elif paare[k][0] == "1" and val is None:
val = paare[k][1]
k += 1
if tag:
e["attribs"][tag] = val if val is not None else ""
j = k
if section == "ENTITIES":
if e["ps"] != 1:
inserts.append(e)
elif block:
block_inhalt.setdefault(block, []).append(
{"name": e["name"], "p": e["p"]})
i = j
continue
i += 1
return inserts, block_inhalt
# ============================================================
# Wrapper -> Eintraege
# ============================================================
def _nummer(name):
m = re.search(r"_(\d+)", name)
return int(m.group(1)) if m else 0
def _r(v):
return round(float(v), RUND) + 0.0
def _richtung(hz):
rad = math.radians(hz)
return (math.cos(rad), math.sin(rad))
def kreisel_eintrag(e, block_inhalt, projekt):
"""Kreisel wie hundm05:bau-kreisel ihn erwartet."""
a = e["attribs"]
abstand = _float(a.get("ABSTAND"))
quelle = "Attribut ABSTAND (ganze mm)"
# Genauer aus der Blockdefinition: Mittenabstand der beiden Stationen
stationen = [s for s in block_inhalt.get(e["name"], [])
if s["name"] and s["name"].upper().startswith(("AN8", "SP8"))]
an = [s for s in stationen if s["name"].upper().startswith("AN8")]
sp = [s for s in stationen if s["name"].upper().startswith("SP8")]
if an and sp:
abstand = math.hypot(sp[0]["p"][0] - an[0]["p"][0],
sp[0]["p"][1] - an[0]["p"][1])
quelle = "Blockdefinition (AN8 -> SP8)"
nr = int(_float(a.get("NUMMER"))) or _nummer(e["name"])
return collections.OrderedDict([
(sch.F_ID, "Kreisel_%s_%02d" % (projekt, nr)),
(sch.F_FUNCTION, sch.FUNC_INSERT),
(sch.F_X, _r(e["p"][0])), (sch.F_Y, _r(e["p"][1])), (sch.F_Z, _r(e["p"][2])),
(sch.F_ABSTAND, _r(abstand)),
(sch.F_ROTATION, _r(e["rot"])),
(sch.F_TYP, a.get("KREISELART") or sch.TYP_STANDARD),
# Umlaufsinn: bestimmt die Reihenfolge im Kreisel-Umlauf und damit den
# TRO-Fluss - ohne ihn kam jeder Nachbau als UZS heraus (Dematic 1/4:
# GUZ). hundm05:bau-kreisel reicht ihn an kreisel-insert-script weiter.
(sch.F_DREHRICHTUNG, a.get("DREHRICHTUNG") or sch.DREHRICHTUNG_UZS),
(sch.F_COMMENT, "aus Zeichnung: %s (ID %s), abstand aus %s"
% (e["name"], a.get("ID", "?"), quelle)),
])
def kreisel_geo(kreisel):
"""kreisel_geo-Form (siehe dxf_scan_components.kreisel_anschluss) aus
einem Kreisel-Eintrag: Achse ab AN8-Radmitte = Einfuegepunkt + Radius."""
u = _richtung(kreisel["rotation"])
return {"id": kreisel["id"],
"a": (kreisel["x"] + KREISEL_RADIUS * u[0],
kreisel["y"] + KREISEL_RADIUS * u[1]),
"u": u, "laenge": kreisel["abstand"], "r": KREISEL_RADIUS,
"z": kreisel["z"]}
def kreisel_an_punkt(p, richtung, geo):
"""Kreisel, auf dessen Kette p liegt (oder None)."""
ans = kreisel_anschluss(p, richtung, geo)
if ans and abs(ans[2]) <= GF_KREISEL_TOL:
return ans[0]
return None
def gf_eintrag(e, geo, projekt, hinweise):
"""Gefaellestrecke Modus 1 - Felder wie GEFAELLESTRECKE_EDIT sie liest."""
a = e["attribs"]
xd = e["xdata"].get("SSG_GF_EDIT")
if not xd or len(xd) < 6:
hinweise.append("%s ohne SSG_GF_EDIT-XDATA - uebersprungen" % e["name"])
return None
hz, winkel = _float(xd[0]), _float(xd[1])
z_start, deltaL = _float(xd[4]), _float(xd[5])
start = (e["p"][0], e["p"][1])
r = _richtung(hz)
ende = (start[0] + deltaL * r[0], start[1] + deltaL * r[1])
eintrag = collections.OrderedDict([
(sch.F_TEST_ID, "GF_%s_%02d" % (projekt, _nummer(e["name"]))),
(sch.F_MODUS, sch.GF_MODUS_WERTEINGABE),
(sch.F_DELTAL_MM, _r(deltaL)),
(sch.F_HZ_GRAD, _r(hz)),
(sch.F_START_MM, [_r(start[0]), _r(start[1]), _r(z_start)]),
(sch.F_AS_SEITE, a.get("SEITE_AS") or sch.SEITE_LINKS),
(sch.F_ES_SEITE, a.get("SEITE_ES") or sch.SEITE_LINKS),
(sch.F_AS_WINKEL, xd[2] or sch.SCHLEUS_WINKEL_90),
(sch.F_ES_WINKEL, xd[3] or sch.SCHLEUS_WINKEL_90),
])
k_start = kreisel_an_punkt(start, r, geo)
k_ende = kreisel_an_punkt(ende, (-r[0], -r[1]), geo)
if k_start:
eintrag["kreisel_start"] = k_start["id"]
if k_ende:
eintrag["kreisel_ende"] = k_ende["id"]
eintrag["hoehe_ende_mm"] = k_ende["z"]
kommentar = ("Endhoehe = Hoehe von %s (%.1f), Winkel rechnet der "
"Treiber neu; gebaut war %.4f Grad -> HOEHE_BIS %s"
% (k_ende["id"], k_ende["z"], winkel,
a.get("HOEHE_BIS_mm", "?")))
else:
eintrag["winkel_grad"] = round(winkel, 4)
kommentar = "kein Kreisel am Ende - gebauter Winkel uebernommen"
eintrag[sch.F_COMMENT] = "aus Zeichnung: %s (ID %s); %s" % (
e["name"], a.get("ID", "?"), kommentar)
return eintrag
def vf_standard_eintrag(e, projekt, typ):
"""VarioFoerderer im mubea-Schema (mubea:vario-bauen)."""
a = e["attribs"]
xd = e["xdata"].get("SSG_VF_EDIT") or []
l_gf = [t for t in (a.get("L_GF_m") or "").split(",") if t.strip()]
eintrag = collections.OrderedDict([
(sch.F_TEST_ID, "VF_%s_%02d" % (projekt, _nummer(e["name"]))),
(sch.F_VF_TYP, typ),
(sch.F_RICHTUNG, a.get("ANTRIEBFAHRTRICHTUNG") or sch.RICHTUNG_AUF),
(sch.F_DELTA_L, _r(_float(a.get("DELTA_L_mm")))),
(sch.F_DELTA_H, _r(_float(a.get("DELTA_H_mm")))),
(sch.F_WINKEL, int(_float(a.get("VF_WINKEL")))),
(sch.F_L_GF1, _r(1000.0 * _float(l_gf[0])) if l_gf else 0.0),
(sch.F_SEITE, a.get("SEITE_AS") or sch.SEITE_RECHTS),
(sch.F_MOTORSEITE, (a.get("MOTORSEITE") or sch.SEITE_RECHTS).split(",")[0]),
(sch.F_HZ, _r(_float(xd[1]) if len(xd) > 1 else 0.0)),
(sch.F_X, _r(e["p"][0])), (sch.F_Y, _r(e["p"][1])), (sch.F_Z, _r(e["p"][2])),
(sch.F_COMMENT, "aus Zeichnung: %s (ID %s), Hoehe %s -> %s; deltaL/"
"deltaH aus den (ganzzahligen) Attributen"
% (e["name"], a.get("ID", "?"), a.get("HOEHE_VON_mm", "?"),
a.get("HOEHE_BIS_mm", "?"))),
])
return eintrag
def vf_journal_eintrag(e, projekt, nr):
"""Linienzug: Journal unveraendert (Tokens 'ART:wert')."""
a = e["attribs"]
roh = "".join(e["xdata"]["SSG_VF_EDIT"][1:])
tokens = [t for t in roh.split(TRENNER) if t]
return collections.OrderedDict([
(sch.F_TEST_ID, "VF_%s_LZ_%02d" % (projekt, nr)),
(sch.F_VF_TYP, "linienzug_journal"),
("journal", tokens),
(sch.F_COMMENT, "aus Zeichnung: %s (ID %s), %d Eingaben, Hoehe %s -> %s; "
"wird 1:1 abgespielt (vsp-bau-journal)"
% (e["name"], a.get("ID", "?"), len(tokens),
a.get("HOEHE_VON_mm", "?"), a.get("HOEHE_BIS_mm", "?"))),
])
def einzel_eintrag(e):
a = e["attribs"]
info = ", ".join("%s %s" % (k, a[k]) for k in ("ID", "ZUORDNUNG", "ARTINR")
if a.get(k))
return collections.OrderedDict([
(sch.F_FUNCTION, sch.FUNC_INSERT),
(sch.F_BLOCK, DIM_SUFFIX.sub("", e["name"])),
(sch.F_X, _r(e["p"][0])), (sch.F_Y, _r(e["p"][1])), (sch.F_Z, _r(e["p"][2])),
(sch.F_ROTATION, _r(e["rot"])),
(sch.F_COMMENT, "aus Zeichnung: %s%s" % (e["name"],
(" (%s)" % info) if info else "")),
])
def baue_eintraege(inserts, block_inhalt, projekt):
"""Reihenfolge wie mubea.json: Kreisel, VF, GF, Einzelbloecke - die VF
vor den GF, weil gf-init-bibliothek globale Elementmasse umsetzt."""
kreisel, vf, lz, gf, einzel, hinweise = [], [], [], [], [], []
for e in sorted(inserts, key=lambda e: (e["name"] or "", e["p"][0], e["p"][1])):
name = e["name"] or ""
if name.startswith("KREISEL_"):
kreisel.append(kreisel_eintrag(e, block_inhalt, projekt))
geo = [kreisel_geo(k) for k in kreisel]
for e in inserts:
name = e["name"] or ""
if name.startswith("KREISEL_"):
continue
if name.startswith("GF_"):
g = gf_eintrag(e, geo, projekt, hinweise)
if g:
gf.append(g)
elif name.startswith("VF_"):
xd = e["xdata"].get("SSG_VF_EDIT")
marker = xd[0] if xd else None
if marker in ("standard", "etage"):
vf.append(vf_standard_eintrag(e, projekt, marker))
elif marker == "linienzug":
lz.append(vf_journal_eintrag(e, projekt, len(lz) + 1))
else:
hinweise.append("%s: Marker %r nicht nachbaubar - uebersprungen"
% (name, marker))
elif name.startswith("*") or name.startswith("ZZ_"):
continue # anonyme Bloecke, Export-Marker
else:
einzel.append(einzel_eintrag(e))
gf.sort(key=lambda g: g["test_id"])
vf.sort(key=lambda v: v["test_id"])
kreisel.sort(key=lambda k: k["id"])
return kreisel + vf + lz + gf + einzel, hinweise
def main():
p = argparse.ArgumentParser(
description="Gebaute Anlage (Wrapper-Bloecke) aus einer Zeichnung in "
"Nachbau-Testdaten schreiben.")
p.add_argument("dxf", help="Zeichnung (ASCII-DXF)")
p.add_argument("output", help="Ziel-JSON")
p.add_argument("--projekt", help="Kennung in den IDs (Default: Dateiname)")
args = p.parse_args()
if not os.path.isfile(args.dxf):
print("%s FEHLER: DXF nicht gefunden: %s" % (PREFIX, args.dxf))
sys.exit(1)
projekt = args.projekt or os.path.splitext(os.path.basename(args.dxf))[0]
print("%s lese %s ..." % (PREFIX, args.dxf))
inserts, block_inhalt = lese_zeichnung(args.dxf)
eintraege, hinweise = baue_eintraege(inserts, block_inhalt, projekt)
zaehler = collections.Counter(
"Kreisel" if sch.F_ABSTAND in e else
"GF" if sch.F_MODUS in e else
"VF Linienzug" if e.get(sch.F_VF_TYP) == "linienzug_journal" else
"VF %s" % e[sch.F_VF_TYP] if sch.F_VF_TYP in e and sch.F_TEST_ID in e else
e.get(sch.F_BLOCK, "?") for e in eintraege)
for k, v in sorted(zaehler.items()):
print("%s %-22s %d" % (PREFIX, k, v))
for h in hinweise:
print("%s ! %s" % (PREFIX, h))
with open(args.output, "w", encoding="utf-8") as fh:
fh.write(arrays_einzeilig(json.dumps(eintraege, ensure_ascii=False,
indent=2)))
fh.write("\n")
print("%s %d Eintraege geschrieben -> %s"
% (PREFIX, len(eintraege), args.output))
if __name__ == "__main__":
main()
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -5,7 +5,7 @@ dxf_vf_abbild.py - Abbild der VF_/GF_-Wrapperbloecke einer Testzeichnung:
Attribute und Bausteinliste je Kette.
Zweck: Regressionsnetz fuer Umbauten am Bau-Ablauf. Nach jedem Schritt der
Funktionstrennung (doc/TODO-plan-vf-interactive.md, Stufe 2) muss die
Funktionstrennung (doc/todo/plan-vf-interactive.md, Stufe 2) muss die
gebaute Geometrie unveraendert sein - "unveraendert" heisst hier: gleiche
Attribute (inklusive der reihenfolgeabhaengigen Komma-Listen L_VF_m/L_GF_m/
GF_WINKEL, die in der Zeichnung unsichtbar, im Sivas-Export aber falsch
+30
View File
@@ -1287,6 +1287,11 @@ def compute_kreisel_umlauf(items, tolerance_mm, durchmesser_mm=800.0,
punkte_je_kreisel = {tid: [] for tid in kreisel}
# Ein-/Auslaufpunkt je Strecke (K1 = KS_EIN des AS, K2 = KS_AUS des ES),
# fuer AS/ES, deren Marker-Box keinen Kreisel trifft (siehe unten).
strecken_kos = {it.get("teileid", ""): _asel_kos_xy(it)
for it in items if it.get("teileart", "") in GF_VF_TEILEARTEN}
for item in items:
if item.get("teileart", "") not in KREISEL_UMLAUF_TEILEARTEN:
continue
@@ -1305,6 +1310,31 @@ def compute_kreisel_umlauf(items, tolerance_mm, durchmesser_mm=800.0,
(teileid, bbox.get("cx", 0.0), bbox.get("cy", 0.0)))
matched_tid = tid
break
# Rueckfall fuer AS/ES: der ZZ_ASES_MARKER sitzt auf dem EINFUEGEPUNKT
# des Elements, der Kreisel beruehrt aber dessen Ein-/Auslauf (KS_EIN/
# KS_AUS). Ein 90-Grad-Element hat den Einlauf ~610 mm seitlich - laeuft
# die Strecke quer vom Kreisel weg, liegt dieser Versatz entlang der
# Kette und der Marker trotzdem darauf; laeuft sie PARALLEL zum
# Kreisel, liegt er quer dazu und der Marker ~560 mm daneben (Dematic/
# Arvato VF_5 an Kreisel1: Marker 557 mm, Einlauf 52 mm von der Kette,
# Review 2026-10-08). Nur wenn die Marker-Box nichts trifft - bereits
# zugeordnete AS/ES behalten Position und Reihenfolge.
if matched_tid is None and item.get("teileart", "") in (
AUSSCHLEUS_TEILEART, EINSCHLEUS_TEILEART):
k1_xy, k2_xy = strecken_kos.get(item.get("_zuordnung", ""), (None, None))
pt = k1_xy if item.get("teileart", "") == AUSSCHLEUS_TEILEART else k2_xy
if pt is not None:
pt_bounds = _bounds({"cx": pt[0], "cy": pt[1], "dx": 0.0, "dy": 0.0},
half_tol)
for tid, kb in kreisel_bounds.items():
if _overlaps(pt_bounds, kb):
punkte_je_kreisel[tid].append((teileid, pt[0], pt[1]))
matched_tid = tid
if dbg:
dbg(f" Umlauf-Kandidat {teileid!r}: Marker-Box ohne "
f"Kreisel, Ein-/Auslauf ({pt[0]:.0f},{pt[1]:.0f}) "
f"liegt auf Kreisel {tid}")
break
if dbg:
if matched_tid is not None:
dbg(f" Umlauf-Kandidat {teileid!r} ({item.get('teileart', '')!r}) "
+3 -3
View File
@@ -907,9 +907,9 @@ def format_csv_line(item, details=None):
def details_mit_bezeichnung(details, merkmalstamm):
"""Kopie von details, bei der jeder Merkmalnummer-Key durch seine
Klartext-Bezeichnung aus dem Merkmalstamm ersetzt wird (Wert bleibt
unveraendert). Keys, die keine reine Zahl sind (aktuell nur beim
Eckrad, siehe build_eckrad_details - dort noch beschreibende
Klartext-Keys statt Merkmalnummern), bleiben unveraendert."""
unveraendert). Keys, die keine reine Zahl sind, bleiben unveraendert
(aktuell kein Normalfall mehr - alle Sektionen in cfg/sivas.cfg nutzen
echte Merkmalnummern)."""
neu = {}
for key, value in details.items():
if key.isdigit():
+79
View File
@@ -0,0 +1,79 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
testdata_schema.py - Feldnamen und feste Werte der JSON-Testdaten-Schemas aus
doc/json-input-lisp.md, als einzige Quelle fuer alle Erzeuger.
Bisher standen dieselben Feldnamen ("function", "abstand", "deltaL_mm",
"as_seite", ...) als lose String-Literale unabhaengig in dxf_scan_components.py
(fremde Zeichnungen) UND dxf_anlage_export.py (eigene, mit unseren Makros
gebaute Zeichnungen) - ein Tippfehler oder eine Schema-Aenderung in nur einer
der beiden Dateien waere nicht aufgefallen. Dieses Modul buendelt sie an
einer Stelle; die LISP-Treiber (tests/test_*.lsp) lesen die JSON-Keys direkt
als Strings und sind davon nicht betroffen.
Nur Feldnamen/feste Werte, KEINE Validierung oder Default-Logik - die bleibt
bewusst in den jeweiligen Erzeugern, deren Kontext (fremde vs. eigene
Zeichnung) unterschiedliche Fallbacks braucht.
"""
# --- Gemeinsame Felder ---
F_FUNCTION = "function"
F_ID = "id"
F_TEST_ID = "test_id"
F_BLOCK = "block"
F_X = "x"
F_Y = "y"
F_Z = "z"
F_ROTATION = "rotation"
F_COMMENT = "comment"
FUNC_INSERT = "insert"
FUNC_CONNECT = "connect"
# --- Abschnitt 1 (json-input-lisp.md): Kreisel ---
F_ABSTAND = "abstand"
F_TYP = "typ"
F_DREHRICHTUNG = "drehrichtung"
TYP_STANDARD = "STANDARD"
TYP_PIN = "PIN"
DREHRICHTUNG_UZS = "UZS"
DREHRICHTUNG_GUZ = "GUZ"
# --- Abschnitt 3: VarioFoerderer Standard und Etage ---
F_VF_TYP = "typ"
F_RICHTUNG = "richtung"
F_DELTA_L = "deltaL"
F_DELTA_H = "deltaH"
F_WINKEL = "winkel"
F_L_GF1 = "L_GF1"
F_GF_VERTEILUNG = "gf_verteilung"
F_SEITE = "seite"
F_MOTORSEITE = "motorseite"
F_HZ = "hz"
VF_TYP_STANDARD = "standard"
VF_TYP_ETAGE = "etage"
RICHTUNG_AUF = "Auf"
RICHTUNG_AB = "Ab"
SEITE_LINKS = "links"
SEITE_RECHTS = "rechts"
# --- Abschnitt 4.1: Gefaellestrecke Modus 1 ---
F_MODUS = "modus"
F_DELTAL_MM = "deltaL_mm"
F_WINKEL_GRAD = "winkel_grad"
F_HZ_GRAD = "hz_grad"
F_START_MM = "start_mm"
F_AS_SEITE = "as_seite"
F_ES_SEITE = "es_seite"
F_AS_WINKEL = "as_winkel"
F_ES_WINKEL = "es_winkel"
GF_MODUS_WERTEINGABE = 1
GF_MODUS_RICHTUNG_AUS_PUNKTEN = 2
GF_MODUS_LINIENZUG = 3
SCHLEUS_WINKEL_90 = "90"
SCHLEUS_WINKEL_30 = "30"
+1 -1
View File
@@ -7,7 +7,7 @@ uebersetzen und zurueck.
Eine Spec beschreibt eine Kette in Domaenenwerten ("links", "winkel",
"aussen", ja/nein) statt in Menue-Codes und Journal-Tokens: lesbar,
schreibbar und damit die Eingabeform fuer den nicht-interaktiven Bau
(Lisp/vf_spec.lsp, siehe doc/TODO-plan-vf-interactive.md Stufe 1).
(Lisp/vf_spec.lsp, siehe doc/todo/plan-vf-interactive.md Stufe 1).
Zwei Richtungen, die einander pruefen:
+218 -53
View File
@@ -92,10 +92,22 @@
<Command>^C^C(ssg-ensure "VarioFoerderer") EtageVarioFoerderer3D</Command>
</Macro>
</MenuMacro>
<MenuMacro UID="MM_00024">
<MenuMacro UID="MM_00191">
<Macro>
<Name>3D-Linienzug</Name>
<Command>^C^C(ssg-ensure "VarioFoerderer") LinienzugVarioFoerderer</Command>
<Name>Werte manuell</Name>
<Command>^C^C(ssg-ensure "VarioFoerderer") LinienzugVarioFoerdererManuell</Command>
</Macro>
</MenuMacro>
<MenuMacro UID="MM_00192">
<Macro>
<Name>aus 3D Linie mit Zielhoehe</Name>
<Command>^C^C(ssg-ensure "VarioFoerderer") LinienzugVarioFoerdererZielhoehe</Command>
</Macro>
</MenuMacro>
<MenuMacro UID="MM_00193">
<Macro>
<Name>3D Objekte stueckweise (in Arbeit)</Name>
<Command>^C^C(ssg-ensure "VarioFoerderer") LinienzugVarioFoerdererStueckweise</Command>
</Macro>
</MenuMacro>
<MenuMacro UID="MM_00025">
@@ -128,6 +140,18 @@
<Command>^C^C(ssg-ensure "Gefaellestrecke") GEFAELLESTRECKE_LINIENZUG</Command>
</Macro>
</MenuMacro>
<MenuMacro UID="MM_00188">
<Macro>
<Name>QC Linie mit GF (automatische Auf-Ab-Berechnung)</Name>
<Command>^C^C(ssg-ensure "VarioFoerderer") QcLinieMitGf</Command>
</Macro>
</MenuMacro>
<MenuMacro UID="MM_00189">
<Macro>
<Name>QC Linie mit GF und U-Form</Name>
<Command>^C^C(ssg-ensure "VarioFoerderer") QcLinieMitGfUForm</Command>
</Macro>
</MenuMacro>
<MenuMacro UID="MM_00033">
<Macro>
<Name>90</Name>
@@ -669,114 +693,168 @@
</Macro>
</MenuMacro>
<MenuMacro UID="MM_00145">
<Macro>
<Name>Bloecke zaehlen</Name>
<Command>^C^C(ssg-ensure "ssg_blocktools") SSG_BLOCK_COUNT</Command>
</Macro>
</MenuMacro>
<MenuMacro UID="MM_00146">
<Macro>
<Name>Bloecke loeschen</Name>
<Command>^C^C(ssg-ensure "ssg_blocktools") SSG_BLOCK_DELETE</Command>
</Macro>
</MenuMacro>
<MenuMacro UID="MM_00147">
<Macro>
<Name>Attribute ersetzen</Name>
<Command>^C^C(ssg-ensure "ssg_blocktools") SSG_ATTR_ERSETZEN</Command>
</Macro>
</MenuMacro>
<MenuMacro UID="MM_00149">
<Macro>
<Name>Text ersetzen</Name>
<Command>^C^C(ssg-ensure "ssg_texttools") SSG_TEXT_ERSETZEN</Command>
</Macro>
</MenuMacro>
<MenuMacro UID="MM_00150">
<Macro>
<Name>Text parallel beschriften</Name>
<Command>^C^C(ssg-ensure "ssg_texttools") SSG_TEXT_PARALLEL</Command>
</Macro>
</MenuMacro>
<MenuMacro UID="MM_00151">
<Macro>
<Name>Texthoehe aendern</Name>
<Command>^C^C(ssg-ensure "ssg_texttools") SSG_TEXT_HOEHE</Command>
</Macro>
</MenuMacro>
<MenuMacro UID="MM_00152">
<Macro>
<Name>Textstil aendern</Name>
<Command>^C^C(ssg-ensure "ssg_texttools") SSG_TEXT_STIL</Command>
</Macro>
</MenuMacro>
<MenuMacro UID="MM_00154">
<Macro>
<Name>alle Tests ausfuehren und exportieren</Name>
<Command>^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_run_all.lsp")) (c:SSG_RUN_ALL_TESTS_EXPORT)</Command>
</Macro>
</MenuMacro>
<MenuMacro UID="MM_00146">
<MenuMacro UID="MM_00155">
<Macro>
<Name>Tests ausfuehren und stehen lassen</Name>
<Command>^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_run_all.lsp")) (c:SSG_RUN_ALL_TESTS_OFFEN)</Command>
</Macro>
</MenuMacro>
<MenuMacro UID="MM_00147">
<MenuMacro UID="MM_00156">
<Macro>
<Name>Export CSV/Sivas ALL</Name>
<Command>^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_export_all.lsp")) (c:TEST_EXPORT_ALL)</Command>
</Macro>
</MenuMacro>
<MenuMacro UID="MM_00149">
<MenuMacro UID="MM_00158">
<Macro>
<Name>Kreisel</Name>
<Command>^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_kreisel.lsp")) (c:TEST_KREISEL)</Command>
</Macro>
</MenuMacro>
<MenuMacro UID="MM_00150">
<MenuMacro UID="MM_00159">
<Macro>
<Name>Foerderer</Name>
<Command>^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_foerderer.lsp")) (c:TEST_FOERDERER)</Command>
</Macro>
</MenuMacro>
<MenuMacro UID="MM_00151">
<MenuMacro UID="MM_00160">
<Macro>
<Name>Foerderer-Linienzug</Name>
<Command>^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_linienzug.lsp")) (c:TEST_LINIENZUG) (c:TEST_LINIENZUG_STUFE2)</Command>
</Macro>
</MenuMacro>
<MenuMacro UID="MM_00152">
<MenuMacro UID="MM_00161">
<Macro>
<Name>Omniflo</Name>
<Command>^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_omniflo.lsp")) (c:TEST_OMNIFLO)</Command>
</Macro>
</MenuMacro>
<MenuMacro UID="MM_00153">
<MenuMacro UID="MM_00162">
<Macro>
<Name>Omniflo Strecke</Name>
<Command>^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_omniflo_strecke.lsp")) (c:TEST_OMNIFLO_STRECKE)</Command>
</Macro>
</MenuMacro>
<MenuMacro UID="MM_00154">
<MenuMacro UID="MM_00163">
<Macro>
<Name>Gefaellestrecke</Name>
<Command>^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_gefaellestrecke.lsp")) (c:TEST_GEFAELLESTRECKE)</Command>
</Macro>
</MenuMacro>
<MenuMacro UID="MM_00155">
<MenuMacro UID="MM_00164">
<Macro>
<Name>Mubea Gesamtmodell</Name>
<Command>^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_mubea.lsp")) (c:TEST_MUBEA)</Command>
</Macro>
</MenuMacro>
<MenuMacro UID="MM_00156">
<MenuMacro UID="MM_00165">
<Macro>
<Name>HundM05 Kreisel-Abschnitt</Name>
<Command>^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_hundm05.lsp")) (c:TEST_HUNDM05)</Command>
</Macro>
</MenuMacro>
<MenuMacro UID="MM_00157">
<MenuMacro UID="MM_00166">
<Macro>
<Name>Dematic/Arvato Flowpuffer (Vorlage)</Name>
<Command>^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_dematic_arvato.lsp")) (c:TEST_DEMATIC_ARVATO)</Command>
</Macro>
</MenuMacro>
<MenuMacro UID="MM_00167">
<Macro>
<Name>ILS 3.0 Showroom (Vorlage)</Name>
<Command>^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_showroom_ils.lsp")) (c:TEST_SHOWROOM_ILS)</Command>
</Macro>
</MenuMacro>
<MenuMacro UID="MM_00168">
<Macro>
<Name>KS 2D/3D pruefen (CSV)</Name>
<Command>^C^C(load (strcat (getenv "DXFMAKRO") "/Lisp/ks_pruefung.lsp")) KS_PRUEFEN</Command>
</Macro>
</MenuMacro>
<MenuMacro UID="MM_00169">
<MenuMacro UID="MM_00180">
<Macro>
<Name>Kreisel bearbeiten</Name>
<Command>(ssg-ensure "KreiselInsert") KreiselEdit</Command>
</Macro>
</MenuMacro>
<MenuMacro UID="MM_00170">
<MenuMacro UID="MM_00181">
<Macro>
<Name>Omniflo Element bearbeiten</Name>
<Command>(ssg-ensure "OmniModulInsert") OMNI_EDIT</Command>
</Macro>
</MenuMacro>
<MenuMacro UID="MM_00171">
<MenuMacro UID="MM_00182">
<Macro>
<Name>Gefaellestrecke bearbeiten</Name>
<Command>(ssg-ensure "Gefaellestrecke") GEFAELLESTRECKE_EDIT</Command>
</Macro>
</MenuMacro>
<MenuMacro UID="MM_00172">
<MenuMacro UID="MM_00183">
<Macro>
<Name>VarioFoerderer bearbeiten</Name>
<Command>(ssg-ensure "VarioFoerderer") VARIOFOERDERER_EDIT</Command>
</Macro>
</MenuMacro>
<MenuMacro UID="MM_00173">
<MenuMacro UID="MM_00184">
<Macro>
<Name>TRO-Marker bearbeiten</Name>
<Command>(ssg-ensure "Tro_Edit") TRO_EDIT</Command>
</Macro>
</MenuMacro>
<MenuMacro UID="MM_00174">
<MenuMacro UID="MM_00185">
<Macro>
<Name>Verbindung bearbeiten</Name>
<Command>(ssg-ensure "Connection_Edit") CONNECTION_EDIT</Command>
</Macro>
</MenuMacro>
<MenuMacro UID="MM_00176">
<MenuMacro UID="MM_00187">
<Macro>
<Name>SSG Bearbeiten (Auto)</Name>
<Command>(ssg-ensure "SSG_LIB_Commands") SSG_BLOCKEDIT</Command>
@@ -798,6 +876,7 @@
<PopMenuRef pUID="PM_00134"/>
<PopMenuRef pUID="PM_00137"/>
<PopMenuRef pUID="PM_00144"/>
<PopMenuRef pUID="PM_00153"/>
</PopMenu>
<PopMenu UID="PM_00005">
<Name>ILS</Name>
@@ -865,12 +944,7 @@
<Name>Foerderer</Name>
<PopMenuRef pUID="PM_00018"/>
<PopMenuRef pUID="PM_00021"/>
<PopMenuItem>
<NameRef>3D-Linienzug</NameRef>
<MenuItem>
<MacroRef MenuMacroID="MM_00024"/>
</MenuItem>
</PopMenuItem>
<PopMenuRef pUID="PM_00190"/>
<PopMenuItem>
<NameRef>Vario_Kette_Merge</NameRef>
<MenuItem>
@@ -914,6 +988,27 @@
</MenuItem>
</PopMenuItem>
</PopMenu>
<PopMenu UID="PM_00190">
<Name>Streckengruppe</Name>
<PopMenuItem>
<NameRef>Werte manuell</NameRef>
<MenuItem>
<MacroRef MenuMacroID="MM_00191"/>
</MenuItem>
</PopMenuItem>
<PopMenuItem>
<NameRef>aus 3D Linie mit Zielhoehe</NameRef>
<MenuItem>
<MacroRef MenuMacroID="MM_00192"/>
</MenuItem>
</PopMenuItem>
<PopMenuItem>
<NameRef>3D Objekte stueckweise (in Arbeit)</NameRef>
<MenuItem>
<MacroRef MenuMacroID="MM_00193"/>
</MenuItem>
</PopMenuItem>
</PopMenu>
<PopMenu UID="PM_00027">
<Name>Gefaellestrecke</Name>
<PopMenuItem>
@@ -934,6 +1029,18 @@
<MacroRef MenuMacroID="MM_00030"/>
</MenuItem>
</PopMenuItem>
<PopMenuItem>
<NameRef>QC Linie mit GF (automatische Auf-Ab-Berechnung)</NameRef>
<MenuItem>
<MacroRef MenuMacroID="MM_00188"/>
</MenuItem>
</PopMenuItem>
<PopMenuItem>
<NameRef>QC Linie mit GF und U-Form</NameRef>
<MenuItem>
<MacroRef MenuMacroID="MM_00189"/>
</MenuItem>
</PopMenuItem>
</PopMenu>
<PopMenu UID="PM_00031">
<Name>Omniflo</Name>
@@ -1559,125 +1666,183 @@
</PopMenuItem>
</PopMenu>
<PopMenu UID="PM_00144">
<Name>Tests</Name>
<Name>Werkzeuge</Name>
<PopMenuItem>
<NameRef>alle Tests ausfuehren und exportieren</NameRef>
<NameRef>Bloecke zaehlen</NameRef>
<MenuItem>
<MacroRef MenuMacroID="MM_00145"/>
</MenuItem>
</PopMenuItem>
<PopMenuItem>
<NameRef>Tests ausfuehren und stehen lassen</NameRef>
<NameRef>Bloecke loeschen</NameRef>
<MenuItem>
<MacroRef MenuMacroID="MM_00146"/>
</MenuItem>
</PopMenuItem>
<PopMenuItem>
<NameRef>Export CSV/Sivas ALL</NameRef>
<NameRef>Attribute ersetzen</NameRef>
<MenuItem>
<MacroRef MenuMacroID="MM_00147"/>
</MenuItem>
</PopMenuItem>
<PopMenuItem IsSeparator="true"/>
<PopMenuItem>
<NameRef>Kreisel</NameRef>
<NameRef>Text ersetzen</NameRef>
<MenuItem>
<MacroRef MenuMacroID="MM_00149"/>
</MenuItem>
</PopMenuItem>
<PopMenuItem>
<NameRef>Foerderer</NameRef>
<NameRef>Text parallel beschriften</NameRef>
<MenuItem>
<MacroRef MenuMacroID="MM_00150"/>
</MenuItem>
</PopMenuItem>
<PopMenuItem>
<NameRef>Foerderer-Linienzug</NameRef>
<NameRef>Texthoehe aendern</NameRef>
<MenuItem>
<MacroRef MenuMacroID="MM_00151"/>
</MenuItem>
</PopMenuItem>
<PopMenuItem>
<NameRef>Omniflo</NameRef>
<NameRef>Textstil aendern</NameRef>
<MenuItem>
<MacroRef MenuMacroID="MM_00152"/>
</MenuItem>
</PopMenuItem>
</PopMenu>
<PopMenu UID="PM_00153">
<Name>Tests</Name>
<PopMenuItem>
<NameRef>Omniflo Strecke</NameRef>
<MenuItem>
<MacroRef MenuMacroID="MM_00153"/>
</MenuItem>
</PopMenuItem>
<PopMenuItem>
<NameRef>Gefaellestrecke</NameRef>
<NameRef>alle Tests ausfuehren und exportieren</NameRef>
<MenuItem>
<MacroRef MenuMacroID="MM_00154"/>
</MenuItem>
</PopMenuItem>
<PopMenuItem>
<NameRef>Mubea Gesamtmodell</NameRef>
<NameRef>Tests ausfuehren und stehen lassen</NameRef>
<MenuItem>
<MacroRef MenuMacroID="MM_00155"/>
</MenuItem>
</PopMenuItem>
<PopMenuItem>
<NameRef>HundM05 Kreisel-Abschnitt</NameRef>
<NameRef>Export CSV/Sivas ALL</NameRef>
<MenuItem>
<MacroRef MenuMacroID="MM_00156"/>
</MenuItem>
</PopMenuItem>
<PopMenuItem IsSeparator="true"/>
<PopMenuItem>
<NameRef>Kreisel</NameRef>
<MenuItem>
<MacroRef MenuMacroID="MM_00158"/>
</MenuItem>
</PopMenuItem>
<PopMenuItem>
<NameRef>Foerderer</NameRef>
<MenuItem>
<MacroRef MenuMacroID="MM_00159"/>
</MenuItem>
</PopMenuItem>
<PopMenuItem>
<NameRef>Foerderer-Linienzug</NameRef>
<MenuItem>
<MacroRef MenuMacroID="MM_00160"/>
</MenuItem>
</PopMenuItem>
<PopMenuItem>
<NameRef>Omniflo</NameRef>
<MenuItem>
<MacroRef MenuMacroID="MM_00161"/>
</MenuItem>
</PopMenuItem>
<PopMenuItem>
<NameRef>Omniflo Strecke</NameRef>
<MenuItem>
<MacroRef MenuMacroID="MM_00162"/>
</MenuItem>
</PopMenuItem>
<PopMenuItem>
<NameRef>Gefaellestrecke</NameRef>
<MenuItem>
<MacroRef MenuMacroID="MM_00163"/>
</MenuItem>
</PopMenuItem>
<PopMenuItem>
<NameRef>Mubea Gesamtmodell</NameRef>
<MenuItem>
<MacroRef MenuMacroID="MM_00164"/>
</MenuItem>
</PopMenuItem>
<PopMenuItem>
<NameRef>HundM05 Kreisel-Abschnitt</NameRef>
<MenuItem>
<MacroRef MenuMacroID="MM_00165"/>
</MenuItem>
</PopMenuItem>
<PopMenuItem>
<NameRef>Dematic/Arvato Flowpuffer (Vorlage)</NameRef>
<MenuItem>
<MacroRef MenuMacroID="MM_00166"/>
</MenuItem>
</PopMenuItem>
<PopMenuItem>
<NameRef>ILS 3.0 Showroom (Vorlage)</NameRef>
<MenuItem>
<MacroRef MenuMacroID="MM_00167"/>
</MenuItem>
</PopMenuItem>
<PopMenuItem>
<NameRef>KS 2D/3D pruefen (CSV)</NameRef>
<MenuItem>
<MacroRef MenuMacroID="MM_00157"/>
<MacroRef MenuMacroID="MM_00168"/>
</MenuItem>
</PopMenuItem>
</PopMenu>
<PopMenu UID="PM_00168">
<PopMenu UID="PM_00179">
<Alias>POP501</Alias>
<Name>SSG_LIB Edit Context</Name>
<PopMenuItem>
<NameRef>Kreisel bearbeiten</NameRef>
<MenuItem>
<MacroRef MenuMacroID="MM_00169"/>
<MacroRef MenuMacroID="MM_00180"/>
</MenuItem>
</PopMenuItem>
<PopMenuItem>
<NameRef>Omniflo Element bearbeiten</NameRef>
<MenuItem>
<MacroRef MenuMacroID="MM_00170"/>
<MacroRef MenuMacroID="MM_00181"/>
</MenuItem>
</PopMenuItem>
<PopMenuItem>
<NameRef>Gefaellestrecke bearbeiten</NameRef>
<MenuItem>
<MacroRef MenuMacroID="MM_00171"/>
<MacroRef MenuMacroID="MM_00182"/>
</MenuItem>
</PopMenuItem>
<PopMenuItem>
<NameRef>VarioFoerderer bearbeiten</NameRef>
<MenuItem>
<MacroRef MenuMacroID="MM_00172"/>
<MacroRef MenuMacroID="MM_00183"/>
</MenuItem>
</PopMenuItem>
<PopMenuItem>
<NameRef>TRO-Marker bearbeiten</NameRef>
<MenuItem>
<MacroRef MenuMacroID="MM_00173"/>
<MacroRef MenuMacroID="MM_00184"/>
</MenuItem>
</PopMenuItem>
<PopMenuItem>
<NameRef>Verbindung bearbeiten</NameRef>
<MenuItem>
<MacroRef MenuMacroID="MM_00174"/>
<MacroRef MenuMacroID="MM_00185"/>
</MenuItem>
</PopMenuItem>
<PopMenuItem IsSeparator="true"/>
<PopMenuItem>
<NameRef>SSG Bearbeiten (Auto)</NameRef>
<MenuItem>
<MacroRef MenuMacroID="MM_00176"/>
<MacroRef MenuMacroID="MM_00187"/>
</MenuItem>
</PopMenuItem>
</PopMenu>
+6 -1
View File
@@ -2,7 +2,7 @@
;; SSG_LIB.mnl - Automatisch geladen beim MENULOAD von SSG_LIB.mnu
;;
;; Definiert den Lazy-Loader (ssg-ensure) und laedt alle Module.
;; Kern-Module: ssg_core, ssg_lang, ssg_dbg, ssg_dialog, ssg_layer, ssg_id
;; Kern-Module: ssg_core, ssg_lang, ssg_dbg, ssg_dialog, ssg_layer, ssg_id, ssg_input
;; Feature-Module: KreiselInsert, Gefaellestrecke, VarioFoerderer, ...
;; ============================================================
@@ -144,6 +144,8 @@
(ssg-ensure "ssg_dialog")
(ssg-ensure "ssg_layer")
(ssg-ensure "ssg_id")
;; Generische Eingabe-Wrapper (ssg-in-*), von den Werkzeug-Modulen genutzt
(ssg-ensure "ssg_input")
;; Gemeinsame KS-Extraktion + Block-Einfuegeprimitiven (von Gefaellestrecke
;; UND VarioFoerderer genutzt) - MUSS vor beiden geladen sein.
(ssg-ensure "ssg_ks_insert")
@@ -159,6 +161,9 @@
;; Tro_Edit wird nicht vorgeladen - der Dispatcher SSG_BLOCKEDIT und die
;; Menuemakros holen es per (ssg-ensure "Tro_Edit") bei Bedarf nach.
(ssg-ensure "SSG_LIB_Commands")
;; Werkzeuge (Reihenfolge: ssg_texttools nutzt ssg_blocktools)
(ssg-ensure "ssg_blocktools")
(ssg-ensure "ssg_texttools")
;; Menue einhaengen
(menucmd "P13=+SSG_LIB.POP1")
+18 -2
View File
@@ -21,13 +21,18 @@
[->Etage]
[Werte manuell]^C^C(ssg-ensure "VarioFoerderer") EtageVarioFoerderer
[<-aus 3D-Linie]^C^C(ssg-ensure "VarioFoerderer") EtageVarioFoerderer3D
[3D-Linienzug]^C^C(ssg-ensure "VarioFoerderer") LinienzugVarioFoerderer
[->Streckengruppe]
[Werte manuell]^C^C(ssg-ensure "VarioFoerderer") LinienzugVarioFoerdererManuell
[aus 3D Linie mit Zielhoehe]^C^C(ssg-ensure "VarioFoerderer") LinienzugVarioFoerdererZielhoehe
[<-3D Objekte stueckweise (in Arbeit)]^C^C(ssg-ensure "VarioFoerderer") LinienzugVarioFoerdererStueckweise
[Vario_Kette_Merge]^C^C(ssg-ensure "VarioFoerderer") Vario_Kette_Merge
[<-VarioFoerderer nachruesten (Marker)]^C^C(ssg-ensure "VarioFoerderer") VARIOFOERDERER_NACHRUESTEN
[->Gefaellestrecke]
[einfach]^C^C(ssg-ensure "Gefaellestrecke") GEFAELLESTRECKE_EINFACH
[aus 3D-Linie]^C^C(ssg-ensure "Gefaellestrecke") GEFAELLESTRECKE_3DLINIE
[<-<-aus Linienzug (LINE + ARC)]^C^C(ssg-ensure "Gefaellestrecke") GEFAELLESTRECKE_LINIENZUG
[aus Linienzug (LINE + ARC)]^C^C(ssg-ensure "Gefaellestrecke") GEFAELLESTRECKE_LINIENZUG
[QC Linie mit GF (automatische Auf-Ab-Berechnung)]^C^C(ssg-ensure "VarioFoerderer") QcLinieMitGf
[<-QC Linie mit GF und U-Form]^C^C(ssg-ensure "VarioFoerderer") QcLinieMitGfUForm
[->Omniflo]
[->Boegen APB110]
[90]^C^C(ssg-ensure "OmniModulInsert") OMNI_APB_630_90
@@ -141,6 +146,15 @@
[Sprache]^C^C(ssg-ensure "SSG_LIB_Commands") SSG_SPRACHE
[Planquadrate an/aus]^C^C(ssg-ensure "DrawPlanquadrate") PLANQUADRATE_TOGGLE
[<-CSV-Export]^C^C(ssg-ensure "export") CSV_EXPORT_KONFIG
[->Werkzeuge]
[Bloecke zaehlen]^C^C(ssg-ensure "ssg_blocktools") SSG_BLOCK_COUNT
[Bloecke loeschen]^C^C(ssg-ensure "ssg_blocktools") SSG_BLOCK_DELETE
[Attribute ersetzen]^C^C(ssg-ensure "ssg_blocktools") SSG_ATTR_ERSETZEN
[--]
[Text ersetzen]^C^C(ssg-ensure "ssg_texttools") SSG_TEXT_ERSETZEN
[Text parallel beschriften]^C^C(ssg-ensure "ssg_texttools") SSG_TEXT_PARALLEL
[Texthoehe aendern]^C^C(ssg-ensure "ssg_texttools") SSG_TEXT_HOEHE
[<-Textstil aendern]^C^C(ssg-ensure "ssg_texttools") SSG_TEXT_STIL
[->Tests]
[alle Tests ausfuehren und exportieren]^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_run_all.lsp")) (c:SSG_RUN_ALL_TESTS_EXPORT)
[Tests ausfuehren und stehen lassen]^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_run_all.lsp")) (c:SSG_RUN_ALL_TESTS_OFFEN)
@@ -154,6 +168,8 @@
[Gefaellestrecke]^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_gefaellestrecke.lsp")) (c:TEST_GEFAELLESTRECKE)
[Mubea Gesamtmodell]^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_mubea.lsp")) (c:TEST_MUBEA)
[HundM05 Kreisel-Abschnitt]^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_hundm05.lsp")) (c:TEST_HUNDM05)
[Dematic/Arvato Flowpuffer (Vorlage)]^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_dematic_arvato.lsp")) (c:TEST_DEMATIC_ARVATO)
[ILS 3.0 Showroom (Vorlage)]^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_showroom_ils.lsp")) (c:TEST_SHOWROOM_ILS)
[<-KS 2D/3D pruefen (CSV)]^C^C(load (strcat (getenv "DXFMAKRO") "/Lisp/ks_pruefung.lsp")) KS_PRUEFEN
***DOUBLECLICK
+3 -1
View File
@@ -10,5 +10,7 @@
{ "name": "gefaellestrecke", "save": "dwg", "module": "Gefaellestrecke" },
{ "name": "mubea", "save": "dxf", "module": "KreiselInsert" },
{ "name": "hundm05", "save": "dxf", "module": "VarioFoerderer" },
{ "name": "hm_recformat", "save": "dxf", "module": "VarioFoerderer", "disabled": true }
{ "name": "dematic_arvato", "save": "dxf", "module": "VarioFoerderer", "disabled": true },
{ "name": "hm_recformat", "save": "dxf", "module": "VarioFoerderer", "disabled": true },
{ "name": "showroom_ils", "save": "dxf", "module": "VarioFoerderer", "disabled": true }
]
+417
View File
@@ -0,0 +1,417 @@
;; ============================================================
;; test_dematic_arvato.lsp - Nachbau des Abschnitts Flowpuffer/Kreisel der
;; Anlage Dematic/Arvato.
;;
;; Datenquelle: tests/testdata/dematic_arvato.json. Entstehung in zwei
;; Stufen:
;; 1. Vorlage aus der Fremdzeichnung (Scanner, raet vieles):
;; python lib/dxf_scan_components.py \
;; C:/develop/sps_skel/data/Dematic_arvato_reduced.dxf data \
;; tests/testdata/dematic_arvato.json --projekt Arvato \
;; --fenster -2534 -4549 49466 29451 --ohne-hoehen \
;; --kreisel-hoehe 35860.37 12519.72 2437 \
;; --kreisel-hoehe 36661.24 24878.8 1826
;; 2. Vorlage mit diesem Treiber bauen, in BricsCAD von Hand korrigieren
;; und ergaenzen (VF-Ketten, Hoehen, Sensoren aufgeraeumt), als DXF
;; speichern und daraus die Testdaten neu schreiben - AKTUELLER STAND:
;; python lib/dxf_anlage_export.py \
;; C:/develop/sps_skel/data/Dematic_TST.dxf \
;; tests/testdata/dematic_arvato.json --projekt Arvato
;;
;; Eintragsarten:
;; "function": "insert" ohne "block" -> Kreisel (hundm05:bau-kreisel ->
;; kreisel-insert-script; x/y = Einfuegepunkt,
;; abstand = Mittenabstand AN8-SP8)
;; "function": "insert" + "block" -> Einzelblock (hundm05:bau-sensor)
;; "typ": "standard"/"etage" + "test_id"
;; -> VarioFoerderer ueber mubea:vario-bauen
;; (mubea-Schema: deltaL, deltaH, richtung,
;; winkel, L_GF1, seite, hz, x/y/z), optional
;; "motorseite"
;; "typ": "linienzug_journal"
;; -> Linienzug-Kette: das aufgezeichnete Eingabe-
;; Journal (SSG_VF_EDIT) wird 1:1 abgespielt
;; (vsp-bau-journal) - keine Spec, weil der
;; Dialog neuer ist als die Spec-Grammatik
;; "modus": 1 -> Gefaellestrecke ueber mubea:gf-bauen
;; (start_mm + deltaL_mm, kein Endpunkt). Mit
;; hoehe_ende_mm (Hoehe des Kreisels am Ende)
;; rechnet dematic_arvato:gf-geometrie Winkel
;; und Staustreckenlaenge (gf-bauen-exakt),
;; sonst gilt winkel_grad.
;; "typ": "gerade" -> waagrechter Foerderer aus der Scanner-Vorlage -
;; kein Bau-Pfad, wird gemeldet und uebersprungen
;;
;; Reihenfolge wie mubea.json (VF vor GF): gf-init-bibliothek setzt die
;; globalen AS/ES-Masse um, siehe mubea:ensure-gf-init.
;;
;; Keine eigene Bau-Logik: hundm05:bau-kreisel/-sensor aus
;; tests/test_hundm05.lsp und mubea:gf-bauen/-vario-bauen aus
;; tests/test_mubea.lsp werden mitgeladen (beide Dateien definieren nur
;; Funktionen), Linienzug-Ketten laufen ueber vsp-bau-journal (vf_spec.lsp).
;;
;; Aufruf in BricsCAD:
;; (load (strcat (getenv "DXFMAKRO") "/tests/test_dematic_arvato.lsp"))
;; TEST_DEMATIC_ARVATO
;; ============================================================
(if (not (boundp '*dematic-arvato-records*)) (setq *dematic-arvato-records* nil))
;; Module und die Bau-Funktionen aus test_hundm05.lsp beim LADEN dieser Datei
;; holen, nicht erst in c:TEST_DEMATIC_ARVATO: in BricsCAD werden per load
;; definierte Funktionen erst nach Rueckkehr zum Top-Level sichtbar (siehe
;; tests/test_unit.scr).
(ssg-ensure "KreiselInsert")
(ssg-ensure "VarioFoerderer")
(ssg-ensure "SSG_LIB_Commands")
(ssg-ensure "Gefaellestrecke")
(if (null (car (atoms-family 1 '("HUNDM05:BAU-SENSOR"))))
(load (strcat (getenv "DXFMAKRO") "/tests/test_hundm05.lsp")))
(if (null (car (atoms-family 1 '("MUBEA:VARIO-BAUEN"))))
(load (strcat (getenv "DXFMAKRO") "/tests/test_mubea.lsp")))
(defun dematic_arvato:datei ()
(strcat (getenv "DXFMAKRO") "/tests/testdata/dematic_arvato.json"))
;; Record um den gebauten Block ergaenzen (oder als Abbruch markieren).
(defun dematic_arvato:rec-block (rec ent fehlertext / ed)
(if (and ent (= (type ent) 'ENAME))
(progn
(setq ed (entget ent))
(princ (strcat " -> Block " (cdr (assoc 2 ed))))
(setq rec (vsp-set rec "block_name" (cdr (assoc 2 ed))))
(setq rec (vsp-set rec "block_handle" (cdr (assoc 5 ed))))
(setq rec (vsp-set rec "insert_point" (cdr (assoc 10 ed))))
(setq rec (vsp-set rec "attribs" (ssg-attrib-read ent)))
(vsp-set rec "status" "executed"))
(progn
(princ (strcat " FEHLER: " fehlertext))
(vsp-set (vsp-set rec "status" "abbruch") "fehler_text" fehlertext))))
;; Foerderer "gerade": noch kein Bau-Pfad - nur melden.
(defun dematic_arvato:gerade-melden (obj / tid rec)
(setq tid (ssg-val obj "test_id"))
(princ (strcat "\n [GERADE] " (if tid tid "?")
" uebersprungen - waagrechter Foerderer noch nicht unterstuetzt"))
(setq rec (vsp-rec-neu (if tid tid "(ohne id)")))
(setq rec (vsp-set rec "kind" "gerade"))
(vsp-set (vsp-set rec "status" "uebersprungen") "fehler_text"
"kein Bau-Pfad fuer typ gerade"))
;; ES-Element bei Einlaufneigung w (Grad, bergab) in Fahrtrichtung hz
;; vermessen: horizontale Laenge entlang hz und Abfall von KS_EIN bis KS_AUS.
;; Wie gf-messe-dz-block (Gefaellestrecke.lsp), liefert aber zusaetzlich die
;; Laenge - beide aendern sich mit der Neigung (90-Grad-ES flach ~436 mm
;; lang, bei 43 Grad nur noch ~292 mm).
;; Rueckgabe: (dx dz), dz positiv = nach unten.
(defun dematic_arvato:es-mass (blockname hz w / rad-h rad-v frame-aus ent-vor ent-nach p)
(setq rad-h (* hz (/ pi 180.0))
rad-v (* w (/ pi 180.0)))
(setq ent-vor (entlast))
(setq frame-aus
(insert-block-ks-to-ks blockname
(make-frame-from-dir '(0 0 0)
(list (* (cos rad-h) (cos rad-v)) (* (sin rad-h) (cos rad-v))
(- (sin rad-v))))))
(setq ent-nach (entlast))
(if (and ent-nach (not (eq ent-nach ent-vor))) (entdel ent-nach))
(setq p (car frame-aus))
(list (+ (* (car p) (cos rad-h)) (* (cadr p) (sin rad-h)))
(- 0.0 (caddr p))))
;; Winkel UND Staustreckenlaenge einer GF (Modus 1) aus Start- und Endhoehe,
;; so dass der ES-Auslauf genau auf Hoehe UND Kette des unteren Kreisels
;; liegt. deltaL reicht von AS-KS_EIN bis ES-KS_AUS (horizontal).
;;
;; H = deltaL - aus-dx - es_dx(w) horizontale Laenge der Schraege
;; tan(w) = (dH - aus-dz - es_dz(w)) / H Schraege = Staustrecke + Separator
;; L_stau = H / cos(w) - 300
;;
;; es_dx/es_dz werden beim aktuellen Winkel gemessen (dematic_arvato:es-mass)
;; und iteriert; das AS liegt flach, aus-dx/aus-dz sind fest.
;;
;; Warum nicht mubea:gf-bauen / gf-winkel-berechnen:
;; - gf-winkel-berechnen rechnet asin(dH / L), also mit SCHRAEGER Laenge
;; (Modus 3); Modus 1 haelt aber die horizontale Laenge fest. Bei 2-3 Grad
;; (Dematic) gleich, bei den steilen Showroom-GF (1860 mm auf 2405 mm)
;; ~50 statt ~43 Grad - die GF endete weit unter dem Kreisel.
;; - mubea:gf-bauen zieht die FLACH gemessene ES-Laenge ein-dx ab. Bei 43
;; Grad ist das ES horizontal ~144 mm kuerzer, die GF hoerte so 144 mm
;; vor der Kette des unteren Kreisels auf (Hoehe stimmte).
;; VORZEICHEN: vf-set-as-masse misst aus-dz als KS_AUS.z - KS_EIN.z
;; (negativ) - darum der Betrag (Dematic: sonst HOEHE_BIS 1568 statt 1826).
;; Rueckgabe: (winkel L_stau)
(defun dematic_arvato:gf-geometrie (deltaL hz as-seite es-seite as-winkel es-winkel
z-start z-ende / es-block dH es H winkel vorher
iter dx-as dz-as)
(mubea:ensure-gf-init)
(vf-set-as-masse as-winkel as-seite)
(vf-set-es-masse es-winkel es-seite)
(setq es-block (strcat "ES_Element_" es-winkel "_" es-seite)
dx-as (float aus-dx)
dz-as (abs (float aus-dz))
dH (- z-start z-ende)
es (list (float ein-dx) (abs (float ein-dz)))
vorher -999.0
iter 0)
(setq H (- deltaL dx-as (car es))
winkel (* (atan (- dH dz-as (cadr es)) H) (/ 180.0 pi)))
(while (and (< iter 8) (> (abs (- winkel vorher)) 0.0005))
(setq vorher winkel
es (dematic_arvato:es-mass es-block hz winkel)
H (- deltaL dx-as (car es))
winkel (* (atan (- dH dz-as (cadr es)) H) (/ 180.0 pi))
iter (1+ iter)))
(vf-set-as-masse "90" as-seite)
(vf-set-es-masse "90" es-seite)
(list winkel (- (/ H (cos (* winkel (/ pi 180.0)))) 300.0)))
;; GF mit vorgegebener Staustreckenlaenge einfuegen (wie mubea:gf-bauen, aber
;; L_stau kommt aus dematic_arvato:gf-geometrie statt aus der flachen
;; ES-Laenge).
(defun dematic_arvato:gf-bauen-exakt (tid start-mm deltaL hz as-seite es-seite
as-winkel es-winkel winkel L_stau / ent)
(mubea:ensure-gf-init)
;; Element-Masse der Variante wie in mubea:gf-bauen, danach zurueck auf 90
(vf-set-as-masse as-winkel as-seite)
(vf-set-es-masse es-winkel es-seite)
(princ (strcat "\n [GF] " tid " -> Start=(" (rtos (car start-mm) 2 0)
"," (rtos (cadr start-mm) 2 0) "," (rtos (caddr start-mm) 2 0)
") hz=" (rtos hz 2 0) " deltaL=" (rtos deltaL 2 0)
" winkel=" (rtos winkel 2 3) " L_stau=" (rtos L_stau 2 1)))
(setq ent (car (gefaellestrecke-einfuegen
L_stau winkel start-mm as-seite es-seite hz
deltaL as-winkel es-winkel "0" "Schoenenberger Geruest")))
(vf-set-as-masse "90" as-seite)
(vf-set-es-masse "90" es-seite)
ent)
;; Gefaellestrecke (Modus 1) bauen - Felder wie mubea:build-gf, ohne dessen
;; anzahl/delta-Vervielfaeltigung (jede GF steht einzeln in der Datei).
;; Mit "hoehe_ende_mm" (Hoehe des Kreisels am Ende) wird der Winkel daraus
;; gerechnet, sonst gilt "winkel_grad" (Default 3.0).
(defun dematic_arvato:bau-gf (obj / tid start deltaL hz winkel z-ende geo
as-seite es-seite as-winkel es-winkel rec)
(setq tid (ssg-val obj "test_id")
start (ssg-val obj "start_mm")
deltaL (ssg-val obj "deltaL_mm")
hz (ssg-val obj "hz_grad")
winkel (ssg-val obj "winkel_grad")
z-ende (ssg-val obj "hoehe_ende_mm")
as-seite (cond ((ssg-val obj "as_seite")) ("links"))
es-seite (cond ((ssg-val obj "es_seite")) ("links"))
as-winkel (cond ((ssg-val obj "as_winkel")) ("90"))
es-winkel (cond ((ssg-val obj "es_winkel")) ("90")))
(setq rec (vsp-rec-neu (if tid tid "(ohne id)")))
(setq rec (vsp-set rec "kind" "gefaellestrecke"))
(setq rec (vsp-set rec "dimension" (vsp-dim-text)))
(cond
((not (and (= (type start) 'LIST) (= (length start) 3)
(numberp deltaL) (numberp hz)))
(princ (strcat "\n [GF] " (if tid tid "?")
" - FEHLER: start_mm, deltaL_mm und hz_grad muessen gesetzt sein"))
(vsp-set (vsp-set rec "status" "spec-fehler") "fehler_text"
"start_mm, deltaL_mm oder hz_grad fehlt bzw. ist ungueltig"))
((and (numberp z-ende) (>= z-ende (caddr start)))
(princ (strcat "\n [GF] " (if tid tid "?")
" - FEHLER: hoehe_ende_mm liegt nicht unter der Starthoehe"))
(vsp-set (vsp-set rec "status" "spec-fehler") "fehler_text"
"hoehe_ende_mm >= start_mm.z - kein Gefaelle"))
(T
;; Mit Endhoehe: Winkel + Staustreckenlaenge exakt (gf-geometrie),
;; sonst fester Winkel ueber mubea:gf-bauen.
(setq geo (if (numberp z-ende)
(dematic_arvato:gf-geometrie (float deltaL) (float hz)
as-seite es-seite as-winkel es-winkel
(float (caddr start)) (float z-ende))))
(setq winkel
(cond
(geo (car geo))
((numberp winkel) (float winkel))
(T 3.0)))
;; Winkel und Soll-Endhoehe als Meldung (das Record-Schema aus vf_spec
;; kennt dafuer kein Feld); die Ist-Endhoehe steht in attribs HOEHE_BIS.
(setq rec (vsp-set rec "meldungen"
(list (strcat "winkel_grad " (rtos winkel 2 3)
(if (numberp z-ende)
(strcat " aus Hoehe " (rtos (caddr start) 2 1)
" -> " (rtos z-ende 2 1))
"")))))
(setq rec
(dematic_arvato:rec-block rec
(if geo
(dematic_arvato:gf-bauen-exakt tid (mapcar 'float start) (float deltaL)
(float hz) as-seite es-seite as-winkel
es-winkel winkel (cadr geo))
(mubea:gf-bauen tid (mapcar 'float start) (float deltaL) (float hz)
as-seite es-seite as-winkel es-winkel winkel))
"gefaellestrecke-einfuegen lieferte keinen GF-Block"))
;; Ist-Endhoehe gegen den Kreisel am Ende pruefen
(dematic_arvato:gf-endhoehe-pruefen rec z-ende))))
;; HOEHE_BIS_mm des gebauten GF-Blocks mit der Soll-Endhoehe vergleichen;
;; mehr als 5 mm daneben -> status "warnung" + Meldung (die GF trifft den
;; unteren Kreisel nicht).
(defun dematic_arvato:gf-endhoehe-pruefen (rec z-ende / ist diff)
(setq ist (cdr (assoc "HOEHE_BIS_mm" (ssg-val rec "attribs"))))
(cond
((not (and (numberp z-ende) ist (= (ssg-val rec "status") "executed"))) rec)
(T
(setq diff (- (atof ist) z-ende))
(setq rec (vsp-set rec "meldungen"
(append (ssg-val rec "meldungen")
(list (strcat "HOEHE_BIS " ist " (Soll "
(rtos z-ende 2 0) ", Abweichung "
(rtos diff 2 0) " mm)")))))
(if (> (abs diff) 5.0)
(progn
(princ (strcat "\n WARNUNG: GF endet bei " ist " statt "
(rtos z-ende 2 0)))
(vsp-set rec "status" "warnung"))
rec))))
;; VarioFoerderer "standard"/"etage" - mubea-Schema, Bau ueber
;; mubea:vario-bauen. "motorseite" wirkt wie im Edit-Dialog ueber den
;; Override *vf-motorseite* (vf-block-erstellen liest ihn).
(defun dematic_arvato:bau-vf (obj / tid typ rec ent)
(setq tid (ssg-val obj "test_id")
typ (cond ((ssg-val obj "typ")) ("standard")))
(setq rec (vsp-rec-neu (if tid tid "(ohne id)")))
(setq rec (vsp-set rec "kind" "vario"))
(setq rec (vsp-set rec "dimension" (vsp-dim-text)))
(setq *vf-motorseite* (ssg-val obj "motorseite"))
(setq ent
(vl-catch-all-apply 'mubea:vario-bauen
(list tid typ (ssg-val obj "richtung")
(float (ssg-val obj "deltaL")) (float (ssg-val obj "deltaH"))
(ssg-val obj "winkel") (float (cond ((ssg-val obj "L_GF1")) (0.0)))
(ssg-val obj "seite") (ssg-val obj "hz")
(list (float (ssg-val obj "x")) (float (ssg-val obj "y"))
(float (ssg-val obj "z"))))))
(setq *vf-motorseite* nil)
(if (vl-catch-all-error-p ent)
(vsp-set (vsp-set rec "status" "abbruch") "fehler_text"
(vl-catch-all-error-message ent))
(dematic_arvato:rec-block rec ent
"kein VF-Block (deltaL beim gewuenschten Winkel nicht loesbar?)")))
;; Linienzug-Kette: aufgezeichnetes Journal ("ART:wert"-Tokens, wie in der
;; SSG_VF_EDIT-XDATA) 1:1 abspielen. Headless-Rahmen wie vsp-bau-datei; er
;; MUSS auch nach einem Fehler zurueck, sonst bleiben getstring/getpoint der
;; Sitzung ersetzt.
(defun dematic_arvato:bau-journal (obj / tid journal res)
(setq tid (cond ((ssg-val obj "test_id")) ("(ohne id)")))
(setq journal (mapcar 'vfl-string->entry (ssg-val obj "journal")))
(vsp-headless-an)
(setq res (vl-catch-all-apply 'vsp-bau-journal
(list tid journal nil
(if journal nil (list "Feld \"journal\" fehlt oder ist leer")))))
(vsp-headless-aus)
(if (vl-catch-all-error-p res)
(vsp-set (vsp-set (vsp-rec-neu tid) "status" "abbruch") "fehler_text"
(vl-catch-all-error-message res))
res))
(defun dematic_arvato:bau-eintrag (obj / kind res typ)
(setq typ (ssg-val obj "typ"))
(cond
((ssg-val obj "modus")
(setq kind "gefaellestrecke")
(setq res (vl-catch-all-apply 'dematic_arvato:bau-gf (list obj))))
((= typ "linienzug_journal")
(setq kind "linienzug")
(setq res (dematic_arvato:bau-journal obj)))
((and (member typ '("standard" "etage")) (ssg-val obj "test_id"))
(setq kind "vario")
(setq res (dematic_arvato:bau-vf obj)))
((and (= (ssg-val obj "function") "insert") (ssg-val obj "block"))
(setq kind "sensor")
(setq res (vl-catch-all-apply 'hundm05:bau-sensor (list obj))))
((= (ssg-val obj "function") "insert")
(setq kind "kreisel")
(setq res (vl-catch-all-apply 'hundm05:bau-kreisel (list obj))))
((= typ "gerade")
(setq kind "gerade")
(setq res (dematic_arvato:gerade-melden obj)))
(T
(setq kind "unbekannt")
(princ "\n WARNUNG: unbekannter Eintrag uebersprungen")
(setq res (vsp-set (vsp-rec-neu "(unbekannt)") "status" "uebersprungen"))))
(if (vl-catch-all-error-p res)
(progn
(princ (strcat "\n [" (strcase kind) "] Ausnahme: "
(vl-catch-all-error-message res)))
(vsp-set (vsp-set (vsp-set (vsp-rec-neu (cond ((ssg-val obj "id"))
((ssg-val obj "test_id"))
((ssg-val obj "block"))
("?")))
"kind" kind) "status" "abbruch")
"fehler_text" (vl-catch-all-error-message res)))
res))
;; Alle Eintraege einer Nachbau-Datei bauen und die Records zurueckgeben
;; (nil bei Fehler vor dem Bau). Gemeinsamer Lauf fuer jeden Treiber mit
;; diesem Eintragsschema - auch tests/test_showroom_ils.lsp.
;; befehl = Name fuer Meldungen/ssg-start, titel = Kopfzeile, datei = JSON
(defun dematic_arvato:bau-datei (befehl titel datei / daten out records zaehler st)
(princ "\n\n================================================================")
(princ (strcat "\n " befehl " - " titel))
(princ (strcat "\n " datei))
(princ "\n================================================================")
(cond
((null (car (atoms-family 1 '("VSP-BAU-JOURNAL"))))
(princ (strcat "\n[" befehl "] FEHLER: vf_spec.lsp nicht geladen"
" (VarioFoerderer laden)."))
nil)
((null (findfile datei))
(princ (strcat "\n[" befehl "] FEHLER: " datei " nicht gefunden!"))
nil)
(T
(setq daten (ssg-json-laden datei))
(princ (strcat "\n " (itoa (length daten)) " Eintraege geladen"))
(ssg-start befehl '(("OSMODE") ("CECOLOR") ("ATTREQ") ("ATTDIA")))
(setvar "OSMODE" 0)
(setvar "ATTREQ" 0)
(setvar "ATTDIA" 0)
;; Vario-Bibliothek (Bogen-/AS-/ES-Masse) wie C:TEST_MUBEA, und die
;; GF-Elementmasse in jeder Zeichnung neu ermitteln.
(if (vsp-lib-noetig-p) (init-bibliothek))
(setq *mubea-gf-init-done* nil)
(setq out '())
(foreach obj daten
(setq out (cons (dematic_arvato:bau-eintrag obj) out)))
(ssg-end)
(setq records (reverse out))
;; Zusammenfassung je Status
(setq zaehler '())
(foreach r records
(setq st (cond ((ssg-val r "status")) ("?")))
(if (assoc st zaehler)
(setq zaehler (subst (cons st (1+ (cdr (assoc st zaehler))))
(assoc st zaehler) zaehler))
(setq zaehler (cons (cons st 1) zaehler))))
(princ "\n================================================================")
(foreach z (reverse zaehler)
(princ (strcat "\n " (car z) ": " (itoa (cdr z)))))
(princ "\n================================================================")
(command "_.ZOOM" "_E")
records)))
(defun c:TEST_DEMATIC_ARVATO ()
(setq *dematic-arvato-records*
(dematic_arvato:bau-datei "TEST_DEMATIC_ARVATO" "Abschnitt Flowpuffer/Kreisel"
(dematic_arvato:datei)))
(princ))
;; Ergebnis-Export (Konvention <name>:export-results fuer test_run_all.lsp)
(defun dematic_arvato:export-results (out-dir / pfad)
(if (null *dematic-arvato-records*)
(princ "\n Keine Dematic/Arvato-Ergebnisse vorhanden.")
(progn
(vl-mkdir out-dir)
(setq pfad (strcat out-dir "/dematic_arvato_results.json"))
(vsp-results-schreiben *dematic-arvato-records* pfad)))
(princ))
(princ "\nTEST_DEMATIC_ARVATO geladen. Aufruf: TEST_DEMATIC_ARVATO")
(princ)
+147
View File
@@ -0,0 +1,147 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
test_dxf_anlage_export.py - Gebaute Anlage -> Nachbau-Testdaten
(lib/dxf_anlage_export.py). Laeuft ohne BricsCAD und ohne DXF: die
Wrapper-Daten sind die Werte aus Dematic_TST.dxf, von Hand nachgestellt
(Form wie lese_zeichnung sie liefert).
1. Kreisel: abstand exakt aus der Blockdefinition (AN8 -> SP8), nicht aus
dem ganzzahligen ABSTAND-Attribut.
2. GF auf zwei Kreiselketten: Endhoehe = Hoehe des Kreisels am Ende,
der (falsch) gebaute Winkel wird NICHT uebernommen.
3. GF ohne Kreisel am Ende: gebauter Winkel bleibt.
4. VF "standard": Parameter wie vfs-edit-basis-lesen, L_GF1 aus L_GF_m.
5. VF "linienzug": Journal unveraendert als Token-Liste.
6. Einzelblock: _2D/_3D-Suffix entfaellt.
"""
import os
import sys
import pytest
sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)),
"..", "lib"))
import dxf_anlage_export as dae # noqa: E402
def _insert(name, p, rot=0.0, attribs=None, xdata=None):
return {"name": name, "handle": "1", "p": list(p), "rot": rot,
"attribs": attribs or {}, "xdata": xdata or {}, "ps": 0}
KREISEL_OBEN = _insert("KREISEL_2_STANDARD_33044", (35860.37, 12519.72, 2437.0),
180.0, {"ID": "0002", "NUMMER": "2", "ABSTAND": "33044",
"KREISELART": "STANDARD"})
KREISEL_UNTEN = _insert("KREISEL_3_STANDARD_33470", (36661.24, 24878.8, 1826.0),
180.0, {"ID": "0003", "NUMMER": "3", "ABSTAND": "33470",
"KREISELART": "STANDARD"})
BLOCK_INHALT = {
"KREISEL_2_STANDARD_33044": [{"name": "AN8_3D", "p": [400.0, 0.0, 0.0]},
{"name": "SP8_3D", "p": [33444.28, 0.0, 0.0]}],
"KREISEL_3_STANDARD_33470": [{"name": "AN8_3D", "p": [400.0, 0.0, 0.0]},
{"name": "SP8_3D", "p": [33870.18, 0.0, 0.0]}],
}
def _geo():
return [dae.kreisel_geo(dae.kreisel_eintrag(k, BLOCK_INHALT, "T"))
for k in (KREISEL_OBEN, KREISEL_UNTEN)]
def test_kreisel_abstand_aus_blockdefinition():
k = dae.kreisel_eintrag(KREISEL_OBEN, BLOCK_INHALT, "T")
assert k["id"] == "Kreisel_T_02"
assert k["abstand"] == pytest.approx(33044.28, abs=0.01)
assert (k["x"], k["y"], k["z"], k["rotation"]) == (35860.37, 12519.72, 2437.0, 180.0)
ohne_block = dae.kreisel_eintrag(KREISEL_OBEN, {}, "T")
assert ohne_block["abstand"] == 33044.0
assert k["drehrichtung"] == "UZS" # Attribut fehlt -> Vorgabe
def test_kreisel_drehrichtung_aus_attribut():
guz = _insert("KREISEL_4_STANDARD_3619", (42563.78, 1703.66, 2177.0), 90.0,
{"NUMMER": "4", "DREHRICHTUNG": "GUZ"})
assert dae.kreisel_eintrag(guz, {}, "T")["drehrichtung"] == "GUZ"
def test_gf_zwischen_zwei_kreiseln_bekommt_endhoehe():
gf = _insert("GF_1", (5833.56, 12919.72, 2437.0), 0.0,
{"ID": "0005", "SEITE_AS": "links", "SEITE_ES": "links",
"HOEHE_BIS_mm": "1568"},
{"SSG_GF_EDIT": ["90", "3.7929", "90", "90", "2437", "11559.08"]})
hinweise = []
e = dae.gf_eintrag(gf, _geo(), "T", hinweise)
assert e["test_id"] == "GF_T_01"
assert e["start_mm"] == [5833.56, 12919.72, 2437.0]
assert e["deltaL_mm"] == 11559.08 and e["hz_grad"] == 90.0
assert (e["kreisel_start"], e["kreisel_ende"]) == ("Kreisel_T_02", "Kreisel_T_03")
assert e["hoehe_ende_mm"] == 1826.0
assert "winkel_grad" not in e
assert hinweise == []
def test_gf_ohne_kreisel_behaelt_gebauten_winkel():
gf = _insert("GF_7", (0.0, 0.0, 1000.0), 0.0, {},
{"SSG_GF_EDIT": ["0", "3", "90", "30", "1000", "5000"]})
e = dae.gf_eintrag(gf, _geo(), "T", [])
assert e["winkel_grad"] == 3.0
assert "hoehe_ende_mm" not in e and "kreisel_ende" not in e
assert e["es_winkel"] == "30"
def test_gf_ohne_xdata_wird_gemeldet():
hinweise = []
assert dae.gf_eintrag(_insert("GF_9", (0, 0, 0)), [], "T", hinweise) is None
assert "SSG_GF_EDIT" in hinweise[0]
def test_vf_standard():
vf = _insert("VF_2", (3314.07, 24478.8, 1826.0), 0.0,
{"ID": "0082", "DELTA_L_mm": "11559", "DELTA_H_mm": "611",
"ANTRIEBFAHRTRICHTUNG": "Auf", "SEITE_AS": "links",
"MOTORSEITE": "rechts", "VF_WINKEL": "15",
"L_GF_m": "1.907,1.907"},
{"SSG_VF_EDIT": ["standard", "270"]})
e = dae.vf_standard_eintrag(vf, "T", "standard")
assert e["test_id"] == "VF_T_02"
assert (e["richtung"], e["deltaL"], e["deltaH"], e["winkel"]) == ("Auf", 11559.0, 611.0, 15)
assert e["L_GF1"] == 1907.0 and e["hz"] == 270.0
assert (e["seite"], e["motorseite"]) == ("links", "rechts")
assert (e["x"], e["y"], e["z"]) == (3314.07, 24478.8, 1826.0)
def test_vf_linienzug_journal_unveraendert():
roh = ["linienzug", "PT:42161.679193,2448.319538,0^JREAL:2177^JSTR:1^JSTR:9",
"0^JSTEP:Linie-VF^JDL:9370.410886"]
vf = _insert("VF_26", (42161.68, 2448.32, 2177.0), 0.0, {"ID": "0184"},
{"SSG_VF_EDIT": roh})
e = dae.vf_journal_eintrag(vf, "T", 1)
assert e["typ"] == "linienzug_journal" and e["test_id"] == "VF_T_LZ_01"
# Chunk-Grenze mitten im Token ("STR:9" + "0") wird korrekt zusammengesetzt
assert e["journal"] == ["PT:42161.679193,2448.319538,0", "REAL:2177", "STR:1",
"STR:90", "STEP:Linie-VF", "DL:9370.410886"]
def test_einzelblock_ohne_dimensionssuffix():
e = dae.einzel_eintrag(_insert("Separator_SP_3D", (3038.72, 12119.73, 2473.0),
0.0, {"ID": "0043", "ZUORDNUNG": "0002"}))
assert e["block"] == "Separator_SP"
assert e["function"] == "insert" and e["z"] == 2473.0
assert "ID 0043" in e["comment"]
def test_reihenfolge_vf_vor_gf():
inserts = [
_insert("GF_1", (5833.56, 12919.72, 2437.0), 0.0, {},
{"SSG_GF_EDIT": ["90", "3", "90", "90", "2437", "11559.08"]}),
_insert("Scanner_3D", (1, 2, 3)),
_insert("VF_2", (0, 0, 0), 0.0, {}, {"SSG_VF_EDIT": ["standard", "0"]}),
KREISEL_OBEN, KREISEL_UNTEN,
_insert("*U12", (0, 0, 0)),
]
eintraege, _ = dae.baue_eintraege(inserts, BLOCK_INHALT, "T")
art = ["K" if "abstand" in e else "GF" if "modus" in e else
"VF" if "typ" in e else e["block"] for e in eintraege]
assert art == ["K", "K", "VF", "GF", "Scanner"]
+288
View File
@@ -0,0 +1,288 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
test_dxf_scan_gf.py - Gefaellestrecken aus Staustrecken-Linien
(gf_eintraege_aus_linien in lib/dxf_scan_components.py). Laeuft ohne
BricsCAD und ohne DXF: die Linien und Ausschleuselemente sind die
gemessenen Werte aus Dematic_arvato_reduced.dxf, von Hand nachgestellt.
1. Fallende Linie mit AS am oberen Ende -> GF, AS wird verbraucht.
2. Der Nachbar-AS der Linie daneben (800 mm Raster, auf der anderen Seite
naeher dran) wird NICHT gegriffen - die Seite aus dem Blocknamen
entscheidet, nicht der kleinste Abstand.
3. Rueckwaerts gezeichnete GF (tiefes Ende zuerst) -> Start bleibt oben.
4. AS am UNTEREN Ende -> Steigfoerderer, keine GF, AS bleibt unverbraucht.
5. Waagrechte Linie -> keine GF.
6. Anschluss an die Kreisel: Start/Ende werden auf die Ketten geschoben,
deltaL reicht von Kette zu Kette; Hoehen kommen von den Kreiseln.
7. Separator auf der Achse wird verbraucht, einer daneben nicht.
8. hoehen_entfernen laesst nur Anwender-Hoehen stehen.
"""
import os
import sys
import pytest
sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)),
"..", "lib"))
import dxf_scan_components as dsc # noqa: E402
AS_LINKS = "Ausschleuselement links 200000217 Draufsicht"
def _as(x, y, z=3191.63, block=AS_LINKS):
return {"familie": "schleuselement", "block": block,
"x": x, "y": y, "z": z, "rot": 270.0}
def _linie(a, b, layer="6-SP"):
return {"layer": layer, "a": list(a), "b": list(b)}
@pytest.fixture(autouse=True)
def _projekt(monkeypatch):
monkeypatch.setattr(dsc, "PROJEKT", "Test")
# Die beiden Kreisel am GF-Feld (Radmitten AN8 -> SP8, r = 400), wie
# baue_eintraege sie als kreisel_geo anlegt. Ketten: oben y = 12919.72,
# unten y = 24478.8.
def _kreisel_oben(z=2437.0):
return {"id": "K_oben", "a": (35460.37, 12519.72), "u": (-1.0, 0.0),
"laenge": 33044.28, "r": 400.0, "z_anwender": z}
def _kreisel_unten(z=1826.0):
return {"id": "K_unten", "a": (36261.24, 24878.8), "u": (-1.0, 0.0),
"laenge": 33470.18, "r": 400.0, "z_anwender": z}
def test_gf_mit_as_am_oberen_ende():
linie = _linie((5833.56, 13348.38, 3191.63), (5833.44, 24002.54, 2821.63))
as_eigen = _as(5367.10, 14505.61)
eintraege, belegt, hinweise = dsc.gf_eintraege_aus_linien([linie], [as_eigen])
assert len(eintraege) == 1
gf = eintraege[0]
assert gf["test_id"] == "GF_Test_01"
assert gf["modus"] == 1
# ohne Kreisel: Linienende bleibt stehen, Hoehe unbekannt -> Platzhalter
assert gf["start_mm"] == [5833.56, 13348.38, 0.0]
assert gf["deltaL_mm"] == pytest.approx(10654.16, abs=0.01)
assert gf["hz_grad"] == 90.0
assert gf["winkel_grad"] == 3.0
assert gf["hoehe_unbekannt"] is True
assert (gf["as_seite"], gf["as_winkel"]) == ("links", "90")
assert belegt == {id(as_eigen)}
assert len(hinweise) == 2 and all("kein Kreisel" in h for h in hinweise)
def test_anschluss_an_beide_kreisel_mit_hoehen():
linie = _linie((5833.56, 13348.38, 3191.63), (5833.44, 24002.54, 2821.63))
eintraege, _, hinweise = dsc.gf_eintraege_aus_linien(
[linie], [_as(5367.10, 14505.61)], [_kreisel_oben(), _kreisel_unten()])
gf = eintraege[0]
assert gf["start_mm"][1] == pytest.approx(12919.72, abs=0.01)
assert gf["start_mm"][2] == 2437.0
assert gf["hoehe_ende_mm"] == 1826.0
assert gf["hoehe_quelle"] == "Anwender"
assert "winkel_grad" not in gf # rechnet der LISP-Treiber
assert gf["deltaL_mm"] == pytest.approx(24478.8 - 12919.72, abs=0.05)
assert (gf["kreisel_start"], gf["kreisel_ende"]) == ("K_oben", "K_unten")
assert hinweise == []
def test_kreisel_ohne_hoehe_gibt_platzhalter():
linie = _linie((5833.56, 13348.38, 3191.63), (5833.44, 24002.54, 2821.63))
eintraege, _, _ = dsc.gf_eintraege_aus_linien(
[linie], [], [_kreisel_oben(z=None), _kreisel_unten()])
assert eintraege[0]["kreisel_start"] == "K_oben"
assert "hoehe_ende_mm" not in eintraege[0]
assert eintraege[0]["winkel_grad"] == 3.0
def test_separator_auf_achse_wird_verbraucht():
linie = _linie((5833.56, 13348.38, 3191.63), (5833.44, 24002.54, 2821.63))
sep_achse = {"familie": "sensor", "block": "S-SP", "x": 5834.0, "y": 23810.0}
sep_daneben = {"familie": "sensor", "block": "S-SP", "x": 6734.0, "y": 23810.0}
scanner = {"familie": "sensor", "block": "Scanner", "x": 5834.0, "y": 20000.0}
_, belegt, _ = dsc.gf_eintraege_aus_linien(
[linie], [], [_kreisel_oben(), _kreisel_unten()],
[sep_achse, sep_daneben, scanner])
assert belegt == {id(sep_achse)}
def test_hoehen_entfernen_laesst_anwender_hoehen_stehen():
eintraege = [
{"id": "K1", "x": 0, "y": 0, "z": 2437.0, "hoehe_quelle": "Anwender"},
{"block": "S-SP", "x": 0, "y": 0, "z": 2821.63, "comment": ""},
{"test_id": "G", "typ": "gerade", "startpunkt": [0, 0, 5.0],
"endpunkt": [1, 0, 5.0]},
]
assert dsc.hoehen_entfernen(eintraege) == 2
assert eintraege[0]["z"] == 2437.0
assert eintraege[1]["z"] == 0.0 and eintraege[1]["hoehe_unbekannt"] is True
assert eintraege[2]["startpunkt"][2] == 0.0 and eintraege[2]["endpunkt"][2] == 0.0
def test_nachbar_as_auf_falscher_seite_wird_nicht_gegriffen():
# Linie bei x=5834; ihr AS 467 mm links, der AS der Nachbarlinie
# (x=6734) 433 mm RECHTS - also naeher, aber auf der falschen Seite.
linie = _linie((5833.56, 13348.38, 3191.63), (5833.44, 24002.54, 2821.63))
as_eigen = _as(5367.10, 14505.61)
as_nachbar = _as(6267.10, 14505.61)
_, belegt, _ = dsc.gf_eintraege_aus_linien([linie], [as_nachbar, as_eigen])
assert belegt == {id(as_eigen)}
def test_rueckwaerts_gezeichnete_gf_startet_oben():
linie = _linie((5833.44, 24002.54, 2821.63), (5833.56, 13348.38, 3191.63))
eintraege, _, _ = dsc.gf_eintraege_aus_linien([linie], [_as(5367.10, 14505.61)])
assert eintraege[0]["start_mm"][:2] == [5833.56, 13348.38]
assert eintraege[0]["hz_grad"] == 90.0
def test_as_am_unteren_ende_ist_steigfoerderer():
# Gemessen: Linie x=2801 von 2822 hinauf auf 3192, AS am tiefen Ende.
linie = _linie((2801.42, 24043.0, 2821.63), (2801.42, 13389.0, 3191.63))
as_unten = _as(3267.48, 22892.92, z=2821.63)
eintraege, belegt, hinweise = dsc.gf_eintraege_aus_linien([linie], [as_unten])
assert eintraege == []
assert belegt == set()
assert len(hinweise) == 1 and "Steigfoerderer" in hinweise[0]
def test_waagrechte_linie_ist_keine_gf():
linie = _linie((36661.0, 10279.0, 2821.63), (36661.0, 24879.0, 2821.63))
eintraege, belegt, hinweise = dsc.gf_eintraege_aus_linien([linie], [])
assert eintraege == []
assert belegt == set()
assert any("waagrechte" in h for h in hinweise)
def test_ohne_as_defaults_und_hinweis():
linie = _linie((0.0, 0.0, 1000.0), (5000.0, 0.0, 800.0))
eintraege, _, hinweise = dsc.gf_eintraege_aus_linien([linie], [])
assert eintraege[0]["hz_grad"] == 0.0
assert eintraege[0]["as_seite"] == dsc.DEFAULT_SEITE
assert any("ohne Ausschleuselement" in h for h in hinweise)
# --- Showroom_ILS_3_0.dxf: flacher 2D-Plan, Werte dort gemessen -------------
def _station(x, y):
return {"x": x, "y": y}
def test_kreisel_paare_zwei_kreisel_auf_einer_achse():
# x=26998: AN8 y=3466 / SP8 y=12499 und AN8 y=13299 / SP8 y=16299. Die
# Luecke SP8(12499)-AN8(13299) = 800 ist das kuerzeste Paar - ohne
# Tausch-Nachbesserung kamen 800 + 12833 statt 9033 + 3000 heraus.
an = [_station(26998.0, 3466.4), _station(26998.0, 13298.9)]
sp = [_station(26998.0, 16298.9), _station(26998.0, 12498.9)]
paare, an_rest, sp_rest = dsc.kreisel_paare_bilden(an, sp)
assert an_rest == [] and sp_rest == []
abstaende = sorted(round(p[2], 1) for p in paare)
assert abstaende == [3000.0, 9032.5]
def test_zerstueckelte_linie_wird_vereint():
# GF bei x=34006 in vier Stuecken, das Separatorstueck 0,3 mm daneben
stuecke = [
_linie((34005.93, 13893.90, 0.0), (34005.93, 14193.90, 0.0)),
_linie((34005.93, 15043.90, 0.0), (34005.93, 15593.90, 0.0)),
_linie((34006.24, 14744.31, 0.0), (34006.24, 15044.31, 0.0)),
_linie((34005.93, 14193.90, 0.0), (34005.93, 14743.90, 0.0)),
]
vereint = dsc.linien_zusammenfassen(stuecke)
assert len(vereint) == 1
ys = sorted([vereint[0]["a"][1], vereint[0]["b"][1]])
assert ys == pytest.approx([13893.90, 15593.90], abs=0.01)
def test_parallele_nachbarlinie_wird_nicht_vereint():
linien = [_linie((0.0, 0.0, 0.0), (0.0, 1000.0, 0.0)),
_linie((800.0, 1000.0, 0.0), (800.0, 2000.0, 0.0))]
assert len(dsc.linien_zusammenfassen(linien)) == 2
def _kreisel_d():
# Schleife oben (Kette unten y=15898.9), Radmitten per --kreisel-achse
return {"id": "K_D", "a": (27797.93, 16298.9), "u": (1.0, 0.0),
"laenge": 8908.0, "r": 400.0, "z_anwender": None}
def _kreisel_e():
# Schleife Mitte (Kette oben y=13493.9)
return {"id": "K_E", "a": (28772.93, 13093.9), "u": (1.0, 0.0),
"laenge": 6533.0, "r": 400.0, "z_anwender": None}
def test_flacher_plan_richtung_und_seiten_aus_as_es():
# Waagrechte Linie; AE-D sitzt 305 mm VOR dem oberen Ende auf der
# Kreisel-Kette, 180 mm links der Fahrtrichtung (Fahrt -y, links = +x).
# EE-R am unteren Ende 212 mm rechts davon.
linie = _linie((30455.93, 13893.9, 0.0), (30455.93, 15593.9, 0.0))
ae = {"familie": "schleuselement", "block": "AE-D",
"x": 30636.27, "y": 15898.9, "z": 0.0, "rot": 270.0}
ee = {"familie": "schleuselement", "block": "EE-R",
"x": 30243.76, "y": 13493.9, "z": 0.0, "rot": 90.0}
eintraege, belegt, _ = dsc.gf_eintraege_aus_linien(
[linie], [ae], [_kreisel_d(), _kreisel_e()], es_liste=[ee], flach=True)
assert len(eintraege) == 1
gf = eintraege[0]
assert gf["hz_grad"] == 270.0
assert gf["start_mm"][:2] == [30455.93, 15898.9]
assert gf["deltaL_mm"] == pytest.approx(2405.0, abs=0.01)
assert (gf["as_seite"], gf["es_seite"]) == ("links", "rechts")
assert (gf["kreisel_start"], gf["kreisel_ende"]) == ("K_D", "K_E")
assert belegt == {id(ae), id(ee)}
def test_flacher_plan_ohne_flach_schalter_keine_gf():
linie = _linie((30455.93, 13893.9, 0.0), (30455.93, 15593.9, 0.0))
ae = {"familie": "schleuselement", "block": "AE-D",
"x": 30636.27, "y": 15898.9, "z": 0.0, "rot": 270.0}
eintraege, _, _ = dsc.gf_eintraege_aus_linien([linie], [ae])
assert eintraege == []
def test_flacher_plan_ohne_as_keine_gf():
# Staulinie am Kreisel B (x=36348) - kein AS an einem Ende
linie = _linie((36347.6, 11313.9, 0.0), (36347.6, 14913.9, 0.0))
eintraege, _, hinweise = dsc.gf_eintraege_aus_linien([linie], [], flach=True)
assert eintraege == []
assert any("waagrechte" in h for h in hinweise)
def test_kurznamen_ae_ee():
assert dsc.familie_von("AE-D") == "schleuselement"
assert dsc.familie_von("EE-R") == "schleuselement"
assert dsc.mappe_block("AE-D")[0].startswith("AS_Element_90_")
assert dsc.mappe_block("EE-R")[0].startswith("ES_Element_90_")
def test_sensor_bekommt_hoehe_des_kreisels():
# Kreisel_Showroom_03: Einfuegepunkt (37105.93, 9888.9), rotation 180,
# Ketten y=9488.9/10288.9. Separator auf der Kette, Scanner 280 mm
# innerhalb, ein Teil 1000 mm daneben bleibt unberuehrt.
kreisel = {"id": "K3", "x": 37105.93, "y": 9888.9, "z": 1700.0,
"abstand": 7200.0, "rotation": 180.0, "hoehe_quelle": "Anwender"}
sep = {"function": "insert", "block": "S-LP", "x": 30343.39, "y": 9488.9,
"z": 0.0, "hoehe_unbekannt": True, "comment": ""}
scan = {"function": "insert", "block": "Scanner", "x": 35905.93,
"y": 10008.9, "z": 0.0, "comment": ""}
weit = {"function": "insert", "block": "S-LP", "x": 33000.0, "y": 11300.0,
"z": 0.0, "comment": ""}
assert dsc.sensor_hoehen_von_kreiseln([kreisel, sep, scan, weit]) == 2
assert sep["z"] == 1700.0 and "hoehe_unbekannt" not in sep
assert scan["z"] == 1700.0
assert weit["z"] == 0.0
def test_sensor_ohne_anwender_hoehe_bleibt():
kreisel = {"id": "K", "x": 0.0, "y": 0.0, "z": 0.0, "abstand": 5000.0,
"rotation": 0.0}
sep = {"function": "insert", "block": "S-LP", "x": 1000.0, "y": 400.0,
"z": 0.0, "comment": ""}
assert dsc.sensor_hoehen_von_kreiseln([kreisel, sep]) == 0
+53
View File
@@ -485,3 +485,56 @@ class TestAsEsImKreiselUmlauf:
keys = [p[0] for p in umlauf["0001"]]
assert "0057" not in keys, (
"ES-Item weit ausserhalb der Kreiselbox wurde faelschlich erkannt")
def _trans(x, y, z=0.0):
"""Gegenstueck zu _decode_trans_xy (csv:trans-encode in export.lsp): drei
vorzeichenbehaftete 24-Bit-Fixed-Point-Werte (Faktor 10), je 4 Zeichen."""
from export_neighbors import _B64_CHARS
text = ""
for v in (x, y, z):
n = int(round(v * 10.0)) & 0xFFFFFF
text += "".join(_B64_CHARS[(n >> s) & 63] for s in (18, 12, 6, 0))
return text
def _strecke(teileid, k1_xy, k2_xy):
return {"teileart": "ILS 2.0 Strecke", "teileid": teileid,
"k1": _trans(*k1_xy), "k2": _trans(*k2_xy)}
class TestAsEsUeberEinlaufpunkt:
"""Dematic/Arvato VF_5 an Kreisel1 (Review 2026-10-08): die Strecke laeuft
PARALLEL zum Kreisel, der 90-Grad-Einlauf (KS_EIN) liegt darum quer zur
Kette - Marker (Einfuegepunkt) 557 mm neben der Kette, Einlauf nur 52 mm
davor. Kreisel entlang +Y, rechte Kette bei x = +400."""
def _kreisel_y(self):
return _kreisel("0001", 0.0, 0.0, 90.0, abstand=3619.0)
def test_marker_daneben_einlauf_auf_der_kette(self):
items = [self._kreisel_y(),
_separator("0043", 400.0, 1500.0),
_ases("ILS Ausschleuselement", "0071", 957.0, 2283.0, "0009"),
_strecke("0009", (348.0, 2283.0), (348.0, 9000.0))]
umlauf = compute_kreisel_umlauf(
items, tolerance_mm=200.0, durchmesser_mm=DURCHMESSER_MM)
punkte = {p[0]: p for p in umlauf["0001"]}
assert "0071" in punkte, "AS ueber den Einlaufpunkt nicht im Umlauf"
# nach dem Einlauf einsortiert, nicht nach dem Marker
assert len(umlauf["0001"]) == 2
def test_ohne_einlaufpunkt_bleibt_es_bei_der_marker_box(self):
items = [self._kreisel_y(),
_ases("ILS Ausschleuselement", "0071", 957.0, 2283.0, "0009")]
umlauf = compute_kreisel_umlauf(
items, tolerance_mm=200.0, durchmesser_mm=DURCHMESSER_MM)
assert "0071" not in [p[0] for p in umlauf["0001"]]
def test_einlauf_weit_weg_wird_nicht_zugeordnet(self):
items = [self._kreisel_y(),
_ases("ILS Ausschleuselement", "0071", 957.0, 2283.0, "0009"),
_strecke("0009", (5000.0, 2283.0), (9000.0, 2283.0))]
umlauf = compute_kreisel_umlauf(
items, tolerance_mm=200.0, durchmesser_mm=DURCHMESSER_MM)
assert "0071" not in [p[0] for p in umlauf["0001"]]
+1 -1
View File
@@ -10,7 +10,7 @@
;; roh aus der XDATA einer echten Zeichnung. Damit ist dies der einzige Test,
;; der belegt, dass ein BESTEHENDER VF_n-Block weiter abspielbar bleibt -
;; also dass Doppelklick-Editieren und 2D/3D-Konvertierung an Altbestand
;; funktionieren (Invariante I1 in doc/TODO-plan-vf-interactive.md). Ein
;; funktionieren (Invariante I1 in doc/todo/plan-vf-interactive.md). Ein
;; spec-gebautes Journal kann das nicht zeigen, es kommt aus dem Uebersetzer.
;;
;; Darum in tests/alltests.json auf "disabled": true - er baut dieselbe
+9 -4
View File
@@ -78,14 +78,15 @@
;; Rueckgabe: Ergebnis-Record in derselben Form wie die Ketten, damit
;; vsp-results-schreiben beide in EINE Datei schreibt (unterschieden ueber
;; das Feld "kind").
(defun hundm05:bau-kreisel (obj / id x y z abstand rotation typ pt ent ed rec)
(defun hundm05:bau-kreisel (obj / id x y z abstand rotation typ drehrichtung pt ent ed rec)
(setq id (ssg-val obj "id"))
(setq x (ssg-val obj "x")
y (ssg-val obj "y")
z (ssg-val obj "z")
abstand (ssg-val obj "abstand")
rotation (ssg-val obj "rotation")
typ (ssg-val obj "typ"))
typ (ssg-val obj "typ")
drehrichtung (ssg-val obj "drehrichtung"))
(if (numberp x) (setq x (float x)))
(if (numberp y) (setq y (float y)))
(if (numberp z) (setq z (float z)))
@@ -106,9 +107,9 @@
(princ (strcat "\n [KREISEL] " id " -> (" (rtos x 2 0) ", "
(rtos y 2 0) ", " (rtos (if z z 0.0) 2 0) ") A="
(rtos abstand 2 0) " R=" (rtos (if rotation rotation 0.0) 2 1)
" " typ))
" " typ (if drehrichtung (strcat " " drehrichtung) "")))
(setq ent (kreisel-insert-script pt abstand
(if rotation rotation 0.0) typ z))
(if rotation rotation 0.0) typ z drehrichtung))
(if ent
(progn
(setq ed (entget ent))
@@ -138,6 +139,10 @@
(defun hundm05:bau-sensor (obj / id blockname x y z rotation pt eff n vorher ent ed attribs rec)
(setq id (ssg-val obj "id"))
(setq blockname (ssg-val obj "block"))
;; Eintraege aus lib/dxf_scan_components.py haben kein "id" - die
;; Meldungen unten setzen id per strcat zusammen und brachen dann mit
;; "bad argument type <NIL>" ab.
(if (null id) (setq id (cond (blockname) ("(ohne id)"))))
(setq x (ssg-val obj "x")
y (ssg-val obj "y")
z (ssg-val obj "z")
+6 -4
View File
@@ -52,8 +52,8 @@
;; --- Einzelnen Insert-Testfall ausfuehren ---
(defun kreisel:run-insert-test (eintrag / id x y z abstand rotation typ
pt blockEnt ed attribs block-name
block-handle insert-point)
drehrichtung pt blockEnt ed attribs
block-name block-handle insert-point)
(setq id (ssg-val eintrag "id"))
(setq x (ssg-val eintrag "x"))
(setq y (ssg-val eintrag "y"))
@@ -61,6 +61,7 @@
(setq abstand (ssg-val eintrag "abstand"))
(setq rotation (ssg-val eintrag "rotation"))
(setq typ (ssg-val eintrag "typ"))
(setq drehrichtung (ssg-val eintrag "drehrichtung"))
(if (numberp x) (setq x (float x)))
(if (numberp y) (setq y (float y)))
@@ -71,9 +72,10 @@
(setq pt (list x y z))
(princ (strcat "\n [INSERT] " id " -> (" (rtos x 2 0) ", " (rtos y 2 0)
", " (rtos z 2 0) ") A=" (rtos abstand 2 0)
" R=" (rtos rotation 2 1) " " typ))
" R=" (rtos rotation 2 1) " " typ
(if drehrichtung (strcat " " drehrichtung) "")))
(setq blockEnt (kreisel-insert-script pt abstand rotation typ z))
(setq blockEnt (kreisel-insert-script pt abstand rotation typ z drehrichtung))
(if blockEnt
(progn
+34 -16
View File
@@ -119,19 +119,20 @@
;; ============================================================
;; --- Kreisel (wie test_kreisel: kreisel-insert-script) ---
(defun mubea:build-kreisel (e / id x y z abstand rotation typ pt ent)
(setq id (ssg-val e "id")
x (float (ssg-val e "x"))
y (float (ssg-val e "y"))
z (float (ssg-val e "z"))
abstand (float (ssg-val e "abstand"))
rotation (float (ssg-val e "rotation"))
typ (ssg-val e "typ"))
(defun mubea:build-kreisel (e / id x y z abstand rotation typ drehrichtung pt ent)
(setq id (ssg-val e "id")
x (float (ssg-val e "x"))
y (float (ssg-val e "y"))
z (float (ssg-val e "z"))
abstand (float (ssg-val e "abstand"))
rotation (float (ssg-val e "rotation"))
typ (ssg-val e "typ")
drehrichtung (ssg-val e "drehrichtung"))
(if (null typ) (setq typ "STANDARD"))
(setq pt (list x y z))
(princ (strcat "\n [KREISEL] " id " -> (" (rtos x 2 0) "," (rtos y 2 0)
"," (rtos z 2 0) ") A=" (rtos abstand 2 0) " R=" (rtos rotation 2 1)))
(setq ent (kreisel-insert-script pt abstand rotation typ z))
(setq ent (kreisel-insert-script pt abstand rotation typ z drehrichtung))
(mubea:ent-json id "kreisel" ent)
)
@@ -146,8 +147,18 @@
;; gueltigen Winkel zu nehmen. L_GF1 aus JSON ist der Vorlauf-Zielwert;
;; L_GF2 (Nachlauf) ist der Rest (L_GF_gesamt - L_GF1).
(defun mubea:build-vario-one (tid typ richtung deltaL deltaH winkel-soll gf1-ziel seite hz
startpunkt / ergebnis winkel-treffer best-winkel L_GF L_VF
gf1 gf2 hoehe-bis lastEnt ent vf-nummer)
startpunkt)
(mubea:ent-json tid "vario"
(mubea:vario-bauen tid typ richtung deltaL deltaH winkel-soll gf1-ziel seite hz
startpunkt)))
;; Der eigentliche Bau ohne Ergebnis-Format - auch von
;; tests/test_dematic_arvato.lsp genutzt (dort mit vsp-Records).
;; Rueckgabe: Entity des VF_n-Blocks oder nil (auch, wenn deltaL beim
;; gewuenschten Winkel nicht loesbar ist).
(defun mubea:vario-bauen (tid typ richtung deltaL deltaH winkel-soll gf1-ziel seite hz
startpunkt / ergebnis winkel-treffer best-winkel L_GF L_VF
gf1 gf2 hoehe-bis lastEnt ent vf-nummer)
(if (or (null seite) (= seite "")) (setq seite "links"))
(if (or (null typ) (= typ "")) (setq typ "standard"))
(if (null hz) (setq hz 0.0) (setq hz (float hz)))
@@ -207,12 +218,12 @@
;; Linienzug/Altbestand bleiben unmarkiert.
(if (and ent (= (type ent) 'ENAME) (member typ '("standard" "etage")))
(vf-edit-xdata-schreiben ent typ hz))
(mubea:ent-json tid "vario" ent))
(if (and ent (= (type ent) 'ENAME)) ent nil))
(progn
(princ (strcat "\n FEHLER: deltaL=" (rtos deltaL 2 0)
" bei Winkel " (if winkel-soll (rtos winkel-soll 2 0) "auto")
" nicht loesbar (kein gueltiges L_GF/L_VF)."))
(mubea:result-json tid "vario" "failed" nil nil nil nil)))
nil))
)
;; --- Vario(s) aus einem Template-Eintrag bauen ---
@@ -290,8 +301,15 @@
;; sep_x = 300 * cos(v), v = Element-Winkel (winkel_grad, Default 3 Grad)
;; Die Zielhoehe ergibt sich aus L_stau/Winkel (kein Ziel-Hoehen-Parameter).
;; Rueckgabe: Ergebnis-JSON-String.
(defun mubea:build-gf-one (tid start-mm deltaL hz as-seite es-seite as-winkel es-winkel winkel /
rad sep-x test-L_stau ent)
(defun mubea:build-gf-one (tid start-mm deltaL hz as-seite es-seite as-winkel es-winkel winkel)
(mubea:ent-json tid "gefaellestrecke"
(mubea:gf-bauen tid start-mm deltaL hz as-seite es-seite as-winkel es-winkel winkel)))
;; Der eigentliche Bau ohne Ergebnis-Format - auch von
;; tests/test_dematic_arvato.lsp genutzt (dort mit vsp-Records).
;; Rueckgabe: Entity des GF_n-Blocks oder nil.
(defun mubea:gf-bauen (tid start-mm deltaL hz as-seite es-seite as-winkel es-winkel winkel /
rad sep-x test-L_stau ent)
(mubea:ensure-gf-init)
;; Element-Masse fuer die gewaehlte AS/ES-Variante setzen, damit aus-dx/ein-dx
;; zur Variante (90/30 Grad) passen. Danach wieder auf 90 zuruecksetzen.
@@ -312,7 +330,7 @@
deltaL as-winkel es-winkel "0" "Schoenenberger Geruest")))
(vf-set-as-masse "90" as-seite)
(vf-set-es-masse "90" es-seite)
(mubea:ent-json tid "gefaellestrecke" ent)
ent
)
;; --- Gefaellestrecke(n) aus einem Template-Eintrag bauen ---
+77
View File
@@ -0,0 +1,77 @@
;; ============================================================
;; test_showroom_ils.lsp - Nachbau des ILS-3.0-Showrooms.
;;
;; Datenquelle: tests/testdata/showroom_ils.json. Entstehung in zwei Stufen:
;; 1. Scanner auf der Fremdzeichnung (flacher 2D-Plan, Hoehen vom Anwender):
;; python lib/dxf_scan_components.py \
;; C:/develop/sps_skel/data/Showroom_ILS_3_0.dxf data \
;; tests/testdata/showroom_ils.json --projekt Showroom \
;; --flach --ohne-hoehen \
;; --kreisel-achse 27797.93 16298.90 36705.93 16298.90 \
;; --kreisel-achse 35305.93 13093.90 28772.93 13093.90 \
;; --kreisel-hoehe 26997.93 3066.4 2226.4 \
;; --kreisel-hoehe 26997.93 12898.9 2226.4 \
;; --kreisel-hoehe 37105.93 9888.9 1700 \
;; --kreisel-hoehe 27397.93 16298.9 2226.4 \
;; --kreisel-hoehe 35705.93 13093.9 1970
;; 2. VON HAND (geht bei Stufe 1 verloren - danach neu eintragen):
;; Kreisel_Showroom_04 (vertikal, rechts) samt Separator/Scanner bei
;; y=14979 entfernt, dafuer VF_Showroom_01 (VarioFoerderer standard,
;; Auf von Kreisel_Showroom_03 zu Kreisel_Showroom_05) eingetragen.
;; Showroom_BTMT_BEL_01 (Kreisel_Showroom_03) und Showroom_BTMT_ENT_01
;; (Kreisel_Showroom_01) aus der gebauten Zeichnung uebernommen
;; (results/export_raw.json, EXPORTCSV vom 2026-10-07).
;;
;; Inhalt: 5 Kreisel, 1 VarioFoerderer, 11 Gefaellestrecken (Modus 1),
;; Separatoren/Scanner, BTMT Be- und Entladung.
;; - Ebenen: oben 2226.4 (Kreisel 01/02/05), Mitte 1970 (06), unten 1700 (03)
;; - in der gebauten Zeichnung KREISEL_1/2/4, KREISEL_5, KREISEL_3.
;; - Kreisel_Showroom_05/06 sind Schleifen ohne AN8/SP8 im Plan (an beiden
;; Enden Weichenboegen) - per --kreisel-achse als STANDARD-Kreisel
;; angenaehert (Radmitten = Mittelpunkte der PIN-Kreise). Die AN8-Seite
;; ist NICHT beliebig: der Export legt Bahn L links von AN8->SP8, der
;; Materialfluss setzt den Bahnwechsel ans AN8-Ende. Kreisel_Showroom_06
;; (UZS) hat AN8 darum im OSTEN, sonst wird Bahn L zur Sackgasse.
;; - Weichen (WB-*/WM-*/WL-*/WR-*) werden bewusst NICHT nachgebaut.
;; - GF: den Winkel
;; und die Staustreckenlaenge rechnet dematic_arvato:gf-geometrie aus
;; hoehe_ende_mm (ES-Masse bei der Neigung gemessen), und
;; dematic_arvato:gf-endhoehe-pruefen meldet "warnung", wenn eine GF
;; den unteren Kreisel um mehr als 5 mm verfehlt.
;;
;; Keine eigene Bau-Logik: Eintragsschema und Lauf wie TEST_DEMATIC_ARVATO
;; (dematic_arvato:bau-datei aus tests/test_dematic_arvato.lsp).
;;
;; Aufruf in BricsCAD:
;; (load (strcat (getenv "DXFMAKRO") "/tests/test_showroom_ils.lsp"))
;; TEST_SHOWROOM_ILS
;; ============================================================
(if (not (boundp '*showroom-ils-records*)) (setq *showroom-ils-records* nil))
;; Beim LADEN holen (siehe test_dematic_arvato.lsp: per load definierte
;; Funktionen sind erst nach Rueckkehr zum Top-Level sichtbar).
(if (null (car (atoms-family 1 '("DEMATIC_ARVATO:BAU-DATEI"))))
(load (strcat (getenv "DXFMAKRO") "/tests/test_dematic_arvato.lsp")))
(defun showroom_ils:datei ()
(strcat (getenv "DXFMAKRO") "/tests/testdata/showroom_ils.json"))
(defun c:TEST_SHOWROOM_ILS ()
(setq *showroom-ils-records*
(dematic_arvato:bau-datei "TEST_SHOWROOM_ILS" "ILS 3.0 Showroom"
(showroom_ils:datei)))
(princ))
;; Ergebnis-Export (Konvention <name>:export-results fuer test_run_all.lsp)
(defun showroom_ils:export-results (out-dir / pfad)
(if (null *showroom-ils-records*)
(princ "\n Keine Showroom-Ergebnisse vorhanden.")
(progn
(vl-mkdir out-dir)
(setq pfad (strcat out-dir "/showroom_ils_results.json"))
(vsp-results-schreiben *showroom-ils-records* pfad)))
(princ))
(princ "\nTEST_SHOWROOM_ILS geladen. Aufruf: TEST_SHOWROOM_ILS")
(princ)
+73 -1
View File
@@ -1601,6 +1601,77 @@
(strcat "harter Fehler: " (vl-catch-all-error-message res))))
)
;; ------------------------------------------------------------
;; TESTS: ssg_input / ssg_blocktools / ssg_texttools - reine Funktionen
;; (die interaktiven Befehle SSG_BLOCK_*, SSG_ATTR_ERSETZEN, SSG_TEXT_*
;; brauchen eine Zeichnung und sind hier NICHT abgedeckt)
;; ------------------------------------------------------------
(defun tu-tests-werkzeuge ( / _e)
(princ "\n[ssg_input / ssg_blocktools / ssg_texttools]")
(if (not (and (car (atoms-family 1 '("SSG-IN-DEFAULT")))
(car (atoms-family 1 '("SSG-BT-WERT-NEU")))
(car (atoms-family 1 '("SSG-TT-LESBARER-WINKEL")))))
(tu-record nil "werkzeuge/geladen"
"ssg_input/ssg_blocktools/ssg_texttools nicht geladen (ssg_load.lsp)")
(progn
;; --- ssg_input ---
(tu-eqf "ssg-in-default/vorgabe" 5.0 (ssg-in-default nil 5.0))
(tu-eqf "ssg-in-default/eingabe" 3.0 (ssg-in-default 3.0 5.0))
(tu-nil "ssg-in-default/beides-nil" (ssg-in-default nil nil))
(tu-eq "ssg-in-fmt-real/ganz" "5" (ssg-in-fmt-real 5.0))
(tu-eq "ssg-in-fmt-real/halb" "2.5" (ssg-in-fmt-real 2.5))
(tu-eq "ssg-in-fmt-real/null" "0" (ssg-in-fmt-real 0.0))
(tu-eq "ssg-in-fmt-real/hundert" "100" (ssg-in-fmt-real 100.0))
(tu-eq "ssg-in-fmt-real/bruch" "0.125" (ssg-in-fmt-real 0.125))
(tu-eq "ssg-in-fmt-real/negativ" "-1.5" (ssg-in-fmt-real -1.5))
(tu-eq "ssg-in-fmt-pt/3d" "1,2.5,0" (ssg-in-fmt-pt '(1.0 2.5 0.0)))
(tu-eq "ssg-in-fmt-pt/2d" "1,2,0" (ssg-in-fmt-pt '(1.0 2.0)))
(tu-eq "ssg-in-prompt/mit-vorgabe" "\nHoehe <5>: " (ssg-in-prompt "\nHoehe" "5"))
(tu-eq "ssg-in-prompt/ohne" "\nHoehe: " (ssg-in-prompt "\nHoehe" nil))
(tu-eq "ssg-in-first-word" "Ja" (ssg-in-first-word "Ja Nein"))
(tu-eq "ssg-in-first-word/ein-wort" "Ja" (ssg-in-first-word "Ja"))
(tu-eq "ssg-in-second-word" "Nein" (ssg-in-second-word "Ja Nein"))
(tu-eq "ssg-in-second-word/ein-wort" "" (ssg-in-second-word "Ja"))
;; --- ssg_blocktools ---
(tu-true "ssg-bt-name-passt-p/muster" (ssg-bt-name-passt-p "GR_TR_1" "gr_*"))
(tu-nil "ssg-bt-name-passt-p/kein" (ssg-bt-name-passt-p "GR_TR_1" "XX*"))
(tu-true "ssg-bt-name-passt-p/nil" (ssg-bt-name-passt-p "ABC" nil))
(tu-true "ssg-bt-name-passt-p/leer" (ssg-bt-name-passt-p "ABC" ""))
(tu-true "ssg-bt-name-passt-p/escape-ja" (ssg-bt-name-passt-p "A.B" "A`.B"))
(tu-nil "ssg-bt-name-passt-p/escape-nein" (ssg-bt-name-passt-p "AxB" "A`.B"))
(tu-eq "ssg-bt-muster-escape" "A`.B`#1" (ssg-bt-muster-escape "A.B#1"))
(tu-eq "ssg-bt-muster-anzeige" "A.B#1" (ssg-bt-muster-anzeige "A`.B`#1"))
(tu-eq "ssg-bt-zaehle-namen"
'(("Alpha" . 1) ("Beta" . 1) ("Zeta" . 3))
(ssg-bt-zaehle-namen '("Zeta" "Alpha" "Zeta" "Beta" "Zeta")))
(tu-nil "ssg-bt-zaehle-namen/leer" (ssg-bt-zaehle-namen nil))
(tu-eq "ssg-bt-wert-neu/teil" "ABC_1" (ssg-bt-wert-neu "ABC-1" "-" "_" T))
(tu-eq "ssg-bt-wert-neu/mehrfach" "a.b.c" (ssg-bt-wert-neu "a-b-c" "-" "." T))
(tu-eq "ssg-bt-wert-neu/loeschen" "AC" (ssg-bt-wert-neu "ABC" "B" "" T))
(tu-nil "ssg-bt-wert-neu/kein-treffer" (ssg-bt-wert-neu "ABC" "X" "y" T))
(tu-eq "ssg-bt-wert-neu/gesamt-ja" "X" (ssg-bt-wert-neu "ABC" "ABC" "X" nil))
(tu-nil "ssg-bt-wert-neu/gesamt-nein" (ssg-bt-wert-neu "ABCD" "ABC" "X" nil))
(tu-nil "ssg-bt-wert-neu/leere-suche" (ssg-bt-wert-neu "ABC" "" "X" T))
(tu-nil "ssg-bt-wert-neu/gross-klein" (ssg-bt-wert-neu "abc" "ABC" "X" T))
;; --- ssg_texttools ---
(tu-eqf "ssg-tt-lesbarer-winkel/0" 0.0 (ssg-tt-lesbarer-winkel 0.0))
(tu-eqf "ssg-tt-lesbarer-winkel/45" (/ pi 4.0) (ssg-tt-lesbarer-winkel (/ pi 4.0)))
(tu-eqf "ssg-tt-lesbarer-winkel/90" (/ pi 2.0) (ssg-tt-lesbarer-winkel (/ pi 2.0)))
(tu-eqf "ssg-tt-lesbarer-winkel/135" (* 1.75 pi) (ssg-tt-lesbarer-winkel (* 0.75 pi)))
(tu-eqf "ssg-tt-lesbarer-winkel/180" 0.0 (ssg-tt-lesbarer-winkel pi))
(tu-eqf "ssg-tt-lesbarer-winkel/270" (/ pi 2.0) (ssg-tt-lesbarer-winkel (* 1.5 pi)))
(tu-eqf "ssg-tt-lesbarer-winkel/-45" (* 1.75 pi) (ssg-tt-lesbarer-winkel (- (/ pi 4.0))))
(tu-eqf "ssg-tt-lesbarer-winkel/360" 0.0 (ssg-tt-lesbarer-winkel (* 2.0 pi)))
(tu-eqf "ssg-tt-versetzt/x" '(5.0 0.0 0.0) (ssg-tt-versetzt '(0.0 0.0 0.0) 0.0 5.0))
(tu-eqf "ssg-tt-versetzt/y" '(0.0 2.0 0.0) (ssg-tt-versetzt '(0.0 0.0 0.0) (/ pi 2.0) 2.0))
(tu-eqf "ssg-tt-versetzt/2d" '(1.0 4.0 0.0) (ssg-tt-versetzt '(1.0 1.0) (/ pi 2.0) 3.0))
)
)
)
(defun c:TEST_UNIT ( / out-dir report)
(tu-reset)
(princ "\n================================================================")
@@ -1610,7 +1681,8 @@
(foreach fn '("tu-tests-core" "tu-tests-lang" "tu-tests-id" "tu-tests-vfcore"
"tu-tests-export" "tu-tests-gf" "tu-tests-omni" "tu-tests-kreisel"
"tu-tests-sepliste" "tu-tests-json" "tu-tests-geruest"
"tu-tests-sepscan" "tu-tests-vfl-segs" "tu-tests-vfl-abbruch")
"tu-tests-sepscan" "tu-tests-vfl-segs" "tu-tests-vfl-abbruch"
"tu-tests-werkzeuge")
(tu-run-block fn))
(princ "\n\n----------------------------------------------------------------")
+1 -1
View File
@@ -7,7 +7,7 @@ HundM-Ketten.
Warum zusaetzlich zu tests/test_hundm05.py: der Ergebnis-Record sagt
"executed, kein Prompt, Journal aufgegangen" - er sagt NICHT, ob dieselbe
Geometrie herauskam wie vorher. Genau das ist bei der Funktionstrennung in
Stufe 2 (doc/TODO-plan-vf-interactive.md) das Risiko: die Reihenfolge der
Stufe 2 (doc/todo/plan-vf-interactive.md) das Risiko: die Reihenfolge der
dL-Subtraktionen und der vfl-acc-*-Aufrufe IST Geometrie, und eine falsche
Reihenfolge faellt in der Zeichnung nicht auf - nur im Sivas-Export.
+1 -1
View File
@@ -11,7 +11,7 @@ einem selten erreichten Zweig ein neues (alert ...) oder ein rohes
(getreal ...) hinzufuegt. Genau das haelt dieser Test fest: die Fundstellen
sind eingecheckt, jede neue muss hier bewusst eingetragen werden.
Hintergrund und Fahrplan: doc/TODO-plan-vf-interactive.md,
Hintergrund und Fahrplan: doc/todo/plan-vf-interactive.md,
Mechanik: doc/variofoerderer.md Abschnitt 8b.
"""
+774
View File
@@ -0,0 +1,774 @@
[
{
"id": "Kreisel_Arvato_01",
"function": "insert",
"x": 19204.0,
"y": 1703.66,
"z": 2177.0,
"abstand": 3619.14,
"rotation": 90.0,
"typ": "STANDARD",
"drehrichtung": "GUZ",
"comment": "aus Zeichnung: KREISEL_1_STANDARD_3619 (ID 0056), abstand aus Blockdefinition (AN8 -> SP8)"
},
{
"id": "Kreisel_Arvato_02",
"function": "insert",
"x": 35860.37,
"y": 12519.72,
"z": 2437.0,
"abstand": 33044.28,
"rotation": 180.0,
"typ": "STANDARD",
"drehrichtung": "UZS",
"comment": "aus Zeichnung: KREISEL_2_STANDARD_33044 (ID 0002), abstand aus Blockdefinition (AN8 -> SP8)"
},
{
"id": "Kreisel_Arvato_03",
"function": "insert",
"x": 36661.24,
"y": 24878.8,
"z": 1826.0,
"abstand": 33470.18,
"rotation": 180.0,
"typ": "STANDARD",
"drehrichtung": "UZS",
"comment": "aus Zeichnung: KREISEL_3_STANDARD_33470 (ID 0003), abstand aus Blockdefinition (AN8 -> SP8)"
},
{
"id": "Kreisel_Arvato_04",
"function": "insert",
"x": 42563.78,
"y": 1703.66,
"z": 2177.0,
"abstand": 3619.14,
"rotation": 90.0,
"typ": "STANDARD",
"drehrichtung": "GUZ",
"comment": "aus Zeichnung: KREISEL_4_STANDARD_3619 (ID 0055), abstand aus Blockdefinition (AN8 -> SP8)"
},
{
"test_id": "VF_Arvato_01",
"typ": "standard",
"richtung": "Auf",
"deltaL": 11559.0,
"deltaH": 611.0,
"winkel": 15,
"L_GF1": 1907.0,
"seite": "links",
"motorseite": "rechts",
"hz": 270.0,
"x": 3314.07,
"y": 24478.8,
"z": 1826.0,
"comment": "aus Zeichnung: VF_1 (ID 0005), Hoehe 0 -> 611; deltaL/deltaH aus den (ganzzahligen) Attributen"
},
{
"test_id": "VF_Arvato_02",
"typ": "standard",
"richtung": "Auf",
"deltaL": 11559.0,
"deltaH": 611.0,
"winkel": 15,
"L_GF1": 1907.0,
"seite": "links",
"motorseite": "rechts",
"hz": 270.0,
"x": 15285.06,
"y": 24478.8,
"z": 1826.0,
"comment": "aus Zeichnung: VF_2 (ID 0006), Hoehe 0 -> 611; deltaL/deltaH aus den (ganzzahligen) Attributen"
},
{
"test_id": "VF_Arvato_03",
"typ": "standard",
"richtung": "Auf",
"deltaL": 11559.0,
"deltaH": 611.0,
"winkel": 15,
"L_GF1": 1907.0,
"seite": "links",
"motorseite": "rechts",
"hz": 270.0,
"x": 23843.05,
"y": 24478.8,
"z": 1826.0,
"comment": "aus Zeichnung: VF_3 (ID 0007), Hoehe 0 -> 611; deltaL/deltaH aus den (ganzzahligen) Attributen"
},
{
"test_id": "VF_Arvato_04",
"typ": "standard",
"richtung": "Auf",
"deltaL": 22559.0,
"deltaH": 0.0,
"winkel": 12,
"L_GF1": 6852.0,
"seite": "rechts",
"motorseite": "rechts",
"hz": 180.0,
"x": 42163.78,
"y": 4017.06,
"z": 2177.0,
"comment": "aus Zeichnung: VF_4 (ID 0008), Hoehe 0 -> 0; deltaL/deltaH aus den (ganzzahligen) Attributen"
},
{
"test_id": "VF_Arvato_05",
"typ": "standard",
"richtung": "Auf",
"deltaL": 6852.0,
"deltaH": 260.0,
"winkel": 18,
"L_GF1": 767.0,
"seite": "links",
"motorseite": "rechts",
"hz": 90.0,
"x": 19551.49,
"y": 5265.19,
"z": 2177.0,
"comment": "aus Zeichnung: VF_5 (ID 0009), Hoehe 0 -> 260; deltaL/deltaH aus den (ganzzahligen) Attributen"
},
{
"test_id": "VF_Arvato_LZ_01",
"typ": "linienzug_journal",
"journal": [
"PT:42161.679193,2448.319538,0",
"REAL:2177",
"STR:1",
"STR:90",
"STR:2",
"STEP:Linie-VF",
"STR:4",
"DL:9370.410886",
"REAL:-180",
"STR:1",
"REAL:2800",
"INT:1",
"STR:2",
"STR:2",
"STR:2",
"STEP:Linie-GF",
"STR:2",
"STR:1",
"STR:3",
"DL:6187.72996",
"STR:1",
"STR:2",
"STR:2",
"REAL:3",
"STEP:Linie-VF",
"STR:3",
"DL:4572.938729",
"STR:2",
"INT:1",
"STR:3",
"STR:1",
"STEP:ES",
"STR:90",
"STR:1",
"DL:2872.479403",
"REAL:2100",
"STR:3",
"STR:1",
"STEP:ES",
"STR:90",
"STR:2",
"DL:2857.418974",
"REAL:2000",
"STR:3",
"STR:1",
"STEP:ES",
"STR:90",
"STR:2",
"DL:2850.93244",
"REAL:2177",
"INT:2",
"STR:2"
],
"comment": "aus Zeichnung: VF_6 (ID 0010), 52 Eingaben, Hoehe 2177 -> 2174; wird 1:1 abgespielt (vsp-bau-journal)"
},
{
"test_id": "GF_Arvato_01",
"modus": 1,
"deltaL_mm": 11559.08,
"hz_grad": 90.0,
"start_mm": [5833.56, 12919.72, 2437.0],
"as_seite": "links",
"es_seite": "links",
"as_winkel": "90",
"es_winkel": "90",
"kreisel_start": "Kreisel_Arvato_02",
"kreisel_ende": "Kreisel_Arvato_03",
"hoehe_ende_mm": 1826.0,
"comment": "aus Zeichnung: GF_1 (ID 0011); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 2.4700 Grad -> HOEHE_BIS 1825"
},
{
"test_id": "GF_Arvato_02",
"modus": 1,
"deltaL_mm": 11559.08,
"hz_grad": 90.0,
"start_mm": [6733.56, 12919.72, 2437.0],
"as_seite": "links",
"es_seite": "links",
"as_winkel": "90",
"es_winkel": "90",
"kreisel_start": "Kreisel_Arvato_02",
"kreisel_ende": "Kreisel_Arvato_03",
"hoehe_ende_mm": 1826.0,
"comment": "aus Zeichnung: GF_2 (ID 0012); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 2.4700 Grad -> HOEHE_BIS 1825"
},
{
"test_id": "GF_Arvato_03",
"modus": 1,
"deltaL_mm": 11559.08,
"hz_grad": 90.0,
"start_mm": [7533.56, 12919.72, 2437.0],
"as_seite": "links",
"es_seite": "links",
"as_winkel": "90",
"es_winkel": "90",
"kreisel_start": "Kreisel_Arvato_02",
"kreisel_ende": "Kreisel_Arvato_03",
"hoehe_ende_mm": 1826.0,
"comment": "aus Zeichnung: GF_3 (ID 0013); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 2.4700 Grad -> HOEHE_BIS 1825"
},
{
"test_id": "GF_Arvato_04",
"modus": 1,
"deltaL_mm": 11559.08,
"hz_grad": 90.0,
"start_mm": [8333.56, 12919.72, 2437.0],
"as_seite": "links",
"es_seite": "links",
"as_winkel": "90",
"es_winkel": "90",
"kreisel_start": "Kreisel_Arvato_02",
"kreisel_ende": "Kreisel_Arvato_03",
"hoehe_ende_mm": 1826.0,
"comment": "aus Zeichnung: GF_4 (ID 0014); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 2.4700 Grad -> HOEHE_BIS 1825"
},
{
"test_id": "GF_Arvato_05",
"modus": 1,
"deltaL_mm": 11559.08,
"hz_grad": 90.0,
"start_mm": [9383.57, 12919.72, 2437.0],
"as_seite": "links",
"es_seite": "links",
"as_winkel": "90",
"es_winkel": "90",
"kreisel_start": "Kreisel_Arvato_02",
"kreisel_ende": "Kreisel_Arvato_03",
"hoehe_ende_mm": 1826.0,
"comment": "aus Zeichnung: GF_5 (ID 0015); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 2.4700 Grad -> HOEHE_BIS 1825"
},
{
"test_id": "GF_Arvato_06",
"modus": 1,
"deltaL_mm": 11559.08,
"hz_grad": 90.0,
"start_mm": [10183.57, 12919.72, 2437.0],
"as_seite": "links",
"es_seite": "links",
"as_winkel": "90",
"es_winkel": "90",
"kreisel_start": "Kreisel_Arvato_02",
"kreisel_ende": "Kreisel_Arvato_03",
"hoehe_ende_mm": 1826.0,
"comment": "aus Zeichnung: GF_6 (ID 0016); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 2.4700 Grad -> HOEHE_BIS 1825"
},
{
"test_id": "GF_Arvato_07",
"modus": 1,
"deltaL_mm": 11559.08,
"hz_grad": 90.0,
"start_mm": [10983.57, 12919.72, 2437.0],
"as_seite": "links",
"es_seite": "links",
"as_winkel": "90",
"es_winkel": "90",
"kreisel_start": "Kreisel_Arvato_02",
"kreisel_ende": "Kreisel_Arvato_03",
"hoehe_ende_mm": 1826.0,
"comment": "aus Zeichnung: GF_7 (ID 0017); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 2.4700 Grad -> HOEHE_BIS 1825"
},
{
"test_id": "GF_Arvato_08",
"modus": 1,
"deltaL_mm": 11559.08,
"hz_grad": 90.0,
"start_mm": [12323.57, 12919.72, 2437.0],
"as_seite": "links",
"es_seite": "links",
"as_winkel": "90",
"es_winkel": "90",
"kreisel_start": "Kreisel_Arvato_02",
"kreisel_ende": "Kreisel_Arvato_03",
"hoehe_ende_mm": 1826.0,
"comment": "aus Zeichnung: GF_8 (ID 0018); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 2.4700 Grad -> HOEHE_BIS 1825"
},
{
"test_id": "GF_Arvato_09",
"modus": 1,
"deltaL_mm": 11559.08,
"hz_grad": 90.0,
"start_mm": [13123.57, 12919.72, 2437.0],
"as_seite": "links",
"es_seite": "links",
"as_winkel": "90",
"es_winkel": "90",
"kreisel_start": "Kreisel_Arvato_02",
"kreisel_ende": "Kreisel_Arvato_03",
"hoehe_ende_mm": 1826.0,
"comment": "aus Zeichnung: GF_9 (ID 0019); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 2.4700 Grad -> HOEHE_BIS 1825"
},
{
"test_id": "GF_Arvato_10",
"modus": 1,
"deltaL_mm": 11559.08,
"hz_grad": 90.0,
"start_mm": [13923.57, 12919.72, 2437.0],
"as_seite": "links",
"es_seite": "links",
"as_winkel": "90",
"es_winkel": "90",
"kreisel_start": "Kreisel_Arvato_02",
"kreisel_ende": "Kreisel_Arvato_03",
"hoehe_ende_mm": 1826.0,
"comment": "aus Zeichnung: GF_10 (ID 0020); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 2.4700 Grad -> HOEHE_BIS 1825"
},
{
"test_id": "GF_Arvato_11",
"modus": 1,
"deltaL_mm": 11559.08,
"hz_grad": 90.0,
"start_mm": [16733.57, 12919.72, 2437.0],
"as_seite": "links",
"es_seite": "links",
"as_winkel": "90",
"es_winkel": "90",
"kreisel_start": "Kreisel_Arvato_02",
"kreisel_ende": "Kreisel_Arvato_03",
"hoehe_ende_mm": 1826.0,
"comment": "aus Zeichnung: GF_11 (ID 0021); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 2.4700 Grad -> HOEHE_BIS 1825"
},
{
"test_id": "GF_Arvato_12",
"modus": 1,
"deltaL_mm": 11559.08,
"hz_grad": 90.0,
"start_mm": [17533.57, 12919.72, 2437.0],
"as_seite": "links",
"es_seite": "links",
"as_winkel": "90",
"es_winkel": "90",
"kreisel_start": "Kreisel_Arvato_02",
"kreisel_ende": "Kreisel_Arvato_03",
"hoehe_ende_mm": 1826.0,
"comment": "aus Zeichnung: GF_12 (ID 0022); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 2.4700 Grad -> HOEHE_BIS 1825"
},
{
"test_id": "GF_Arvato_13",
"modus": 1,
"deltaL_mm": 11559.08,
"hz_grad": 90.0,
"start_mm": [18333.57, 12919.72, 2437.0],
"as_seite": "links",
"es_seite": "links",
"as_winkel": "90",
"es_winkel": "90",
"kreisel_start": "Kreisel_Arvato_02",
"kreisel_ende": "Kreisel_Arvato_03",
"hoehe_ende_mm": 1826.0,
"comment": "aus Zeichnung: GF_13 (ID 0023); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 2.4700 Grad -> HOEHE_BIS 1825"
},
{
"test_id": "GF_Arvato_14",
"modus": 1,
"deltaL_mm": 11559.08,
"hz_grad": 90.0,
"start_mm": [19381.07, 12919.72, 2437.0],
"as_seite": "links",
"es_seite": "links",
"as_winkel": "90",
"es_winkel": "90",
"kreisel_start": "Kreisel_Arvato_02",
"kreisel_ende": "Kreisel_Arvato_03",
"hoehe_ende_mm": 1826.0,
"comment": "aus Zeichnung: GF_14 (ID 0024); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 2.4700 Grad -> HOEHE_BIS 1825"
},
{
"test_id": "GF_Arvato_15",
"modus": 1,
"deltaL_mm": 11559.08,
"hz_grad": 90.0,
"start_mm": [20281.07, 12919.72, 2437.0],
"as_seite": "links",
"es_seite": "links",
"as_winkel": "90",
"es_winkel": "90",
"kreisel_start": "Kreisel_Arvato_02",
"kreisel_ende": "Kreisel_Arvato_03",
"hoehe_ende_mm": 1826.0,
"comment": "aus Zeichnung: GF_15 (ID 0025); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 2.4700 Grad -> HOEHE_BIS 1825"
},
{
"test_id": "GF_Arvato_16",
"modus": 1,
"deltaL_mm": 11559.08,
"hz_grad": 90.0,
"start_mm": [21081.07, 12919.72, 2437.0],
"as_seite": "links",
"es_seite": "links",
"as_winkel": "90",
"es_winkel": "90",
"kreisel_start": "Kreisel_Arvato_02",
"kreisel_ende": "Kreisel_Arvato_03",
"hoehe_ende_mm": 1826.0,
"comment": "aus Zeichnung: GF_16 (ID 0026); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 2.4700 Grad -> HOEHE_BIS 1825"
},
{
"test_id": "GF_Arvato_17",
"modus": 1,
"deltaL_mm": 11559.08,
"hz_grad": 90.0,
"start_mm": [21881.07, 12919.72, 2437.0],
"as_seite": "links",
"es_seite": "links",
"as_winkel": "90",
"es_winkel": "90",
"kreisel_start": "Kreisel_Arvato_02",
"kreisel_ende": "Kreisel_Arvato_03",
"hoehe_ende_mm": 1826.0,
"comment": "aus Zeichnung: GF_17 (ID 0027); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 2.4700 Grad -> HOEHE_BIS 1825"
},
{
"test_id": "GF_Arvato_18",
"modus": 1,
"deltaL_mm": 11559.08,
"hz_grad": 90.0,
"start_mm": [25541.07, 12919.72, 2437.0],
"as_seite": "links",
"es_seite": "links",
"as_winkel": "90",
"es_winkel": "90",
"kreisel_start": "Kreisel_Arvato_02",
"kreisel_ende": "Kreisel_Arvato_03",
"hoehe_ende_mm": 1826.0,
"comment": "aus Zeichnung: GF_18 (ID 0028); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 2.4700 Grad -> HOEHE_BIS 1825"
},
{
"test_id": "GF_Arvato_19",
"modus": 1,
"deltaL_mm": 11559.08,
"hz_grad": 90.0,
"start_mm": [26341.07, 12919.72, 2437.0],
"as_seite": "links",
"es_seite": "links",
"as_winkel": "90",
"es_winkel": "90",
"kreisel_start": "Kreisel_Arvato_02",
"kreisel_ende": "Kreisel_Arvato_03",
"hoehe_ende_mm": 1826.0,
"comment": "aus Zeichnung: GF_19 (ID 0029); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 2.4700 Grad -> HOEHE_BIS 1825"
},
{
"test_id": "GF_Arvato_20",
"modus": 1,
"deltaL_mm": 11559.08,
"hz_grad": 90.0,
"start_mm": [27841.06, 12919.72, 2437.0],
"as_seite": "links",
"es_seite": "links",
"as_winkel": "90",
"es_winkel": "90",
"kreisel_start": "Kreisel_Arvato_02",
"kreisel_ende": "Kreisel_Arvato_03",
"hoehe_ende_mm": 1826.0,
"comment": "aus Zeichnung: GF_20 (ID 0030); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 2.4700 Grad -> HOEHE_BIS 1825"
},
{
"test_id": "GF_Arvato_21",
"modus": 1,
"deltaL_mm": 11559.08,
"hz_grad": 90.0,
"start_mm": [28741.06, 12919.72, 2437.0],
"as_seite": "links",
"es_seite": "links",
"as_winkel": "90",
"es_winkel": "90",
"kreisel_start": "Kreisel_Arvato_02",
"kreisel_ende": "Kreisel_Arvato_03",
"hoehe_ende_mm": 1826.0,
"comment": "aus Zeichnung: GF_21 (ID 0031); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 2.4700 Grad -> HOEHE_BIS 1825"
},
{
"test_id": "GF_Arvato_22",
"modus": 1,
"deltaL_mm": 11559.08,
"hz_grad": 90.0,
"start_mm": [29541.06, 12919.72, 2437.0],
"as_seite": "links",
"es_seite": "links",
"as_winkel": "90",
"es_winkel": "90",
"kreisel_start": "Kreisel_Arvato_02",
"kreisel_ende": "Kreisel_Arvato_03",
"hoehe_ende_mm": 1826.0,
"comment": "aus Zeichnung: GF_22 (ID 0032); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 2.4700 Grad -> HOEHE_BIS 1825"
},
{
"test_id": "GF_Arvato_23",
"modus": 1,
"deltaL_mm": 11559.08,
"hz_grad": 90.0,
"start_mm": [30341.06, 12919.72, 2437.0],
"as_seite": "links",
"es_seite": "links",
"as_winkel": "90",
"es_winkel": "90",
"kreisel_start": "Kreisel_Arvato_02",
"kreisel_ende": "Kreisel_Arvato_03",
"hoehe_ende_mm": 1826.0,
"comment": "aus Zeichnung: GF_23 (ID 0033); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 2.4700 Grad -> HOEHE_BIS 1825"
},
{
"test_id": "GF_Arvato_24",
"modus": 1,
"deltaL_mm": 11559.08,
"hz_grad": 90.0,
"start_mm": [31891.06, 12919.72, 2437.0],
"as_seite": "links",
"es_seite": "links",
"as_winkel": "90",
"es_winkel": "90",
"kreisel_start": "Kreisel_Arvato_02",
"kreisel_ende": "Kreisel_Arvato_03",
"hoehe_ende_mm": 1826.0,
"comment": "aus Zeichnung: GF_24 (ID 0034); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 2.4700 Grad -> HOEHE_BIS 1825"
},
{
"test_id": "GF_Arvato_25",
"modus": 1,
"deltaL_mm": 11559.08,
"hz_grad": 90.0,
"start_mm": [32791.06, 12919.72, 2437.0],
"as_seite": "links",
"es_seite": "links",
"as_winkel": "90",
"es_winkel": "90",
"kreisel_start": "Kreisel_Arvato_02",
"kreisel_ende": "Kreisel_Arvato_03",
"hoehe_ende_mm": 1826.0,
"comment": "aus Zeichnung: GF_25 (ID 0035); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 2.4700 Grad -> HOEHE_BIS 1825"
},
{
"test_id": "GF_Arvato_26",
"modus": 1,
"deltaL_mm": 11559.08,
"hz_grad": 90.0,
"start_mm": [33591.06, 12919.72, 2437.0],
"as_seite": "links",
"es_seite": "links",
"as_winkel": "90",
"es_winkel": "90",
"kreisel_start": "Kreisel_Arvato_02",
"kreisel_ende": "Kreisel_Arvato_03",
"hoehe_ende_mm": 1826.0,
"comment": "aus Zeichnung: GF_26 (ID 0036); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 2.4700 Grad -> HOEHE_BIS 1825"
},
{
"test_id": "GF_Arvato_27",
"modus": 1,
"deltaL_mm": 11559.08,
"hz_grad": 90.0,
"start_mm": [34391.06, 12919.72, 2437.0],
"as_seite": "links",
"es_seite": "links",
"as_winkel": "90",
"es_winkel": "90",
"kreisel_start": "Kreisel_Arvato_02",
"kreisel_ende": "Kreisel_Arvato_03",
"hoehe_ende_mm": 1826.0,
"comment": "aus Zeichnung: GF_27 (ID 0037); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 2.4700 Grad -> HOEHE_BIS 1825"
},
{
"function": "insert",
"block": "Separator_SP",
"x": 3038.72,
"y": 12119.73,
"z": 2473.0,
"rotation": 0.0,
"comment": "aus Zeichnung: Separator_SP_3D (ID 0038, ZUORDNUNG 0002, ARTINR 200000077)"
},
{
"function": "insert",
"block": "Separator_SP",
"x": 3482.38,
"y": 24478.8,
"z": 1826.0,
"rotation": 0.0,
"comment": "aus Zeichnung: Separator_SP_3D (ID 0039, ZUORDNUNG 0003, ARTINR 200000077)"
},
{
"function": "insert",
"block": "Separator_SP",
"x": 5094.1,
"y": 12919.72,
"z": 2473.0,
"rotation": 180.0,
"comment": "aus Zeichnung: Separator_SP_3D (ID 0040, ZUORDNUNG 0002, ARTINR 200000077)"
},
{
"function": "insert",
"block": "Separator_SP",
"x": 15412.41,
"y": 24478.8,
"z": 1826.0,
"rotation": 0.0,
"comment": "aus Zeichnung: Separator_SP_3D (ID 0041, ZUORDNUNG 0003, ARTINR 200000077)"
},
{
"function": "insert",
"block": "Separator_SP",
"x": 15994.1,
"y": 12919.78,
"z": 2473.0,
"rotation": 180.0,
"comment": "aus Zeichnung: Separator_SP_3D (ID 0042, ZUORDNUNG 0002, ARTINR 200000077)"
},
{
"function": "insert",
"block": "Separator_SP",
"x": 19604.0,
"y": 5042.22,
"z": 2177.0,
"rotation": 270.0,
"comment": "aus Zeichnung: Separator_SP_3D (ID 0043, ZUORDNUNG 0056, ARTINR 200000077)"
},
{
"function": "insert",
"block": "Separator_SP",
"x": 24002.04,
"y": 24478.8,
"z": 1826.0,
"rotation": 0.0,
"comment": "aus Zeichnung: Separator_SP_3D (ID 0044, ZUORDNUNG 0003, ARTINR 200000077)"
},
{
"function": "insert",
"block": "Separator_SP",
"x": 24794.1,
"y": 12919.82,
"z": 2473.0,
"rotation": 180.0,
"comment": "aus Zeichnung: Separator_SP_3D (ID 0045, ZUORDNUNG 0002, ARTINR 200000077)"
},
{
"function": "insert",
"block": "Separator_SP",
"x": 35050.37,
"y": 12919.72,
"z": 2437.0,
"rotation": 180.0,
"comment": "aus Zeichnung: Separator_SP_3D (ID 0046, ZUORDNUNG 0002, ARTINR 200000077)"
},
{
"function": "insert",
"block": "Separator_SP",
"x": 35182.77,
"y": 25278.8,
"z": 1826.0,
"rotation": 180.0,
"comment": "aus Zeichnung: Separator_SP_3D (ID 0047, ZUORDNUNG 0003, ARTINR 200000077)"
},
{
"function": "insert",
"block": "Separator_SP",
"x": 42163.99,
"y": 4269.52,
"z": 2177.0,
"rotation": 90.0,
"comment": "aus Zeichnung: Separator_SP_3D (ID 0048, ZUORDNUNG 0055, ARTINR 200000077)"
},
{
"function": "insert",
"block": "Scanner",
"x": 3632.63,
"y": 24865.38,
"z": 1826.0,
"rotation": 90.0,
"comment": "aus Zeichnung: Scanner_3D (ID 0049, ZUORDNUNG 0003, ARTINR 829534306)"
},
{
"function": "insert",
"block": "Scanner",
"x": 4943.86,
"y": 13306.31,
"z": 2473.0,
"rotation": 90.0,
"comment": "aus Zeichnung: Scanner_3D (ID 0050, ZUORDNUNG 0011, ARTINR 829534306)"
},
{
"function": "insert",
"block": "Scanner",
"x": 15562.65,
"y": 24865.38,
"z": 1826.0,
"rotation": 90.0,
"comment": "aus Zeichnung: Scanner_3D (ID 0051, ZUORDNUNG 0003, ARTINR 829534306)"
},
{
"function": "insert",
"block": "Scanner",
"x": 15843.86,
"y": 13306.36,
"z": 2473.0,
"rotation": 90.0,
"comment": "aus Zeichnung: Scanner_3D (ID 0052, ZUORDNUNG 0002, ARTINR 829534306)"
},
{
"function": "insert",
"block": "Scanner",
"x": 24152.28,
"y": 24865.38,
"z": 1826.0,
"rotation": 90.0,
"comment": "aus Zeichnung: Scanner_3D (ID 0059, ZUORDNUNG 0003, ARTINR 829534306)"
},
{
"function": "insert",
"block": "Scanner",
"x": 24643.86,
"y": 13306.4,
"z": 2473.0,
"rotation": 90.0,
"comment": "aus Zeichnung: Scanner_3D (ID 0054, ZUORDNUNG 0028, ARTINR 829534306)"
},
{
"function": "insert",
"block": "BTMT-Beladung",
"x": 42163.78,
"y": 4978.68,
"z": 2177.0,
"rotation": 270.0,
"comment": "aus Zeichnung: BTMT-Beladung_3D (ID 0057, ARTINR 829662012)"
},
{
"function": "insert",
"block": "SC_Entladung",
"x": 35609.45,
"y": 25278.8,
"z": 1826.0,
"rotation": 0.0,
"comment": "aus Zeichnung: SC_Entladung_3D (ID 0058, ARTINR 400100156)"
},
{
"function": "insert",
"block": "Scanner",
"x": 42163.78,
"y": 4224.88,
"z": 2177.0,
"rotation": 180.0,
"comment": "aus Zeichnung: Scanner_3D (ID 0053, ZUORDNUNG 0055, ARTINR 829534306)"
}
]
+413
View File
@@ -0,0 +1,413 @@
[
{
"id": "Kreisel_Showroom_01",
"function": "insert",
"x": 26997.93,
"y": 3066.4,
"z": 2226.4,
"abstand": 9032.5,
"rotation": 90.0,
"typ": "STANDARD",
"darstellung": "2D",
"drehrichtung": "GUZ",
"comment": "aus DXF: Radmitte AN8 (Layer 1ANTR-800) (26997.93, 3466.40) -> SP8 (Layer 1SP-800) (26997.93, 12498.90), Mittenabstand 9032.50, rotation 90.00 Grad; x/y = AN8-Mitte minus Radius. ACHTUNG hoehe=11039.9 ist NICHT belegt: AN8/SP8 sind flache 2D-Symbole auf Z=0 und nur 0 3D-Nachbarn in 3000 mm - zu wenige fuer eine belegbare Hoehe. Hoehe 2226.4 vom Anwender.",
"hoehe_quelle": "Anwender"
},
{
"id": "Kreisel_Showroom_02",
"function": "insert",
"x": 26997.93,
"y": 12898.9,
"z": 2226.4,
"abstand": 3000.0,
"rotation": 90.0,
"typ": "STANDARD",
"darstellung": "2D",
"drehrichtung": "UZS",
"comment": "aus DXF: Radmitte AN8 (Layer 1ANTR-800) (26997.93, 13298.90) -> SP8 (Layer 1SP-800) (26997.93, 16298.90), Mittenabstand 3000.00, rotation 90.00 Grad; x/y = AN8-Mitte minus Radius. ACHTUNG hoehe=11039.9 ist NICHT belegt: AN8/SP8 sind flache 2D-Symbole auf Z=0 und nur 0 3D-Nachbarn in 3000 mm - zu wenige fuer eine belegbare Hoehe. Hoehe 2226.4 vom Anwender.",
"hoehe_quelle": "Anwender"
},
{
"id": "Kreisel_Showroom_03",
"function": "insert",
"x": 37105.93,
"y": 9888.9,
"z": 1700.0,
"abstand": 7200.0,
"rotation": 180.0,
"typ": "STANDARD",
"darstellung": "2D",
"drehrichtung": "GUZ",
"comment": "aus DXF: Radmitte AN8 (Layer 1ANTR-800) (36705.93, 9888.90) -> SP8 (Layer 1SP-800) (29505.93, 9888.90), Mittenabstand 7200.00, rotation 180.00 Grad; x/y = AN8-Mitte minus Radius. ACHTUNG hoehe=11039.9 ist NICHT belegt: AN8/SP8 sind flache 2D-Symbole auf Z=0 und nur 0 3D-Nachbarn in 3000 mm - zu wenige fuer eine belegbare Hoehe. Hoehe 1700.0 vom Anwender.",
"hoehe_quelle": "Anwender"
},
{
"id": "Kreisel_Showroom_05",
"function": "insert",
"x": 27397.93,
"y": 16298.9,
"z": 2226.4,
"abstand": 8908.0,
"rotation": 0.0,
"typ": "STANDARD",
"darstellung": "2D",
"drehrichtung": "GUZ",
"comment": "aus DXF: Radmitte (manuell AN8) (Layer --kreisel-achse) (27797.93, 16298.90) -> (manuell SP8) (Layer --kreisel-achse) (36705.93, 16298.90), Mittenabstand 8908.00, rotation 0.00 Grad; x/y = AN8-Mitte minus Radius. ACHTUNG hoehe=0.0 ist NICHT belegt: AN8/SP8 sind flache 2D-Symbole auf Z=0 und nur 0 3D-Nachbarn in 3000 mm - zu wenige fuer eine belegbare Hoehe. Hoehe 2226.4 vom Anwender.",
"hoehe_quelle": "Anwender"
},
{
"id": "Kreisel_Showroom_06",
"function": "insert",
"x": 35705.93,
"y": 13093.9,
"z": 1970.0,
"abstand": 6533.0,
"rotation": 180.0,
"typ": "STANDARD",
"darstellung": "2D",
"drehrichtung": "UZS",
"comment": "aus DXF: Schleife ohne AN8/SP8, Radmitten der Enden (35305.93, 13093.90) -> (28772.93, 13093.90) aus den PIN-Kreisen (--kreisel-achse), Mittenabstand 6533.00, rotation 180 - AN8-Seite bewusst OSTEN: der Export (export_neighbors.kreisel_half_bboxes) legt Bahn L links von AN8->SP8, und material_flow/tro_flow setzen den Bahnwechsel R->L (UZS) ans AN8-Ende. Mit AN8 im Westen lagen die Zulaeufe von Kreisel_Showroom_05 auf L und die Ablaeufe nach Kreisel_Showroom_03 auf R - Bahn 0005-L wurde zur Sackgasse. Hoehe 1970 vom Anwender.",
"hoehe_quelle": "Anwender"
},
{
"test_id": "VF_Showroom_01",
"typ": "standard",
"richtung": "Auf",
"deltaL": 5610.0,
"deltaH": 526.4,
"seite": "links",
"hz": 90.0,
"x": 36305.93,
"y": 10288.9,
"z": 1700.0,
"comment": "von Hand: ersetzt Kreisel_Showroom_04 (vertikaler Kreisel AN8 (36706, 10689) -> SP8 (36706, 15499)) samt dessen Separator/Scanner bei y=14979. AS auf der oberen Kette von Kreisel_Showroom_03 (y=10288.9, Hoehe 1700) auf dem linken Strang des alten Kreisels (x=36306), Steigung +Y bis zur unteren Kette von Kreisel_Showroom_05 (y=15898.9, Hoehe 2226.4): deltaL 15898.9 - 10288.9 = 5610, deltaH 2226.4 - 1700 = 526.4. seite noch offen (links als Vorgabe), winkel waehlt der Solver."
},
{
"test_id": "GF_Showroom_01",
"modus": 1,
"deltaL_mm": 2405.0,
"hz_grad": 270.0,
"start_mm": [30455.93, 15898.9, 2226.4],
"as_seite": "links",
"es_seite": "rechts",
"as_winkel": "90",
"es_winkel": "90",
"kreisel_start": "Kreisel_Showroom_05",
"kreisel_ende": "Kreisel_Showroom_06",
"hoehe_ende_mm": 1970.0,
"hoehe_quelle": "Anwender",
"comment": "aus DXF: LINE auf Layer '6-SP' (30455.93, 15593.90) -> (30455.93, 13893.90), Laenge XY 1700.00; am oberen Ende um 305.0 mm bis zur Kette von Kreisel_Showroom_05 verlaengert; am unteren Ende um 400.0 mm bis zur Kette von Kreisel_Showroom_06 verlaengert; Hoehen vom Anwender (Kreisel Kreisel_Showroom_05 / Kreisel_Showroom_06), den Winkel rechnet der Treiber; as_seite links aus der Lage zur Fahrtrichtung; AS aus Block 'AE-D' bei (30636.27, 15898.90) -> AS_Element_90_links, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90; Separator auf der Achse entfernt (die GF baut ihren eigenen): S-SP bei (30456, 13994), S-SP bei (30456, 14807); es_seite rechts aus der Lage zur Fahrtrichtung; ES aus Block 'EE-R' bei (30243.76, 13493.90) -> ES_Element_90_rechts, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90."
},
{
"test_id": "GF_Showroom_02",
"modus": 1,
"deltaL_mm": 2405.0,
"hz_grad": 270.0,
"start_mm": [31255.93, 12693.9, 1970.0],
"as_seite": "rechts",
"es_seite": "links",
"as_winkel": "90",
"es_winkel": "90",
"kreisel_start": "Kreisel_Showroom_06",
"kreisel_ende": "Kreisel_Showroom_03",
"hoehe_ende_mm": 1700.0,
"hoehe_quelle": "Anwender",
"comment": "aus DXF: LINE auf Layer '6-SP' (31255.93, 12388.90) -> (31255.93, 10688.90), Laenge XY 1700.00; am oberen Ende um 305.0 mm bis zur Kette von Kreisel_Showroom_06 verlaengert; am unteren Ende um 400.0 mm bis zur Kette von Kreisel_Showroom_03 verlaengert; Hoehen vom Anwender (Kreisel Kreisel_Showroom_06 / Kreisel_Showroom_03), den Winkel rechnet der Treiber; as_seite rechts aus der Lage zur Fahrtrichtung; AS aus Block 'AE-D' bei (31075.60, 12693.90) -> AS_Element_90_rechts, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90; Separator auf der Achse entfernt (die GF baut ihren eigenen): S-SP bei (31256, 10789), S-SP bei (31256, 11602); es_seite links aus der Lage zur Fahrtrichtung; ES aus Block 'EE-R' bei (31468.11, 10288.90) -> ES_Element_90_links, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90."
},
{
"test_id": "GF_Showroom_03",
"modus": 1,
"deltaL_mm": 2405.0,
"hz_grad": 270.0,
"start_mm": [31255.93, 15898.9, 2226.4],
"as_seite": "links",
"es_seite": "rechts",
"as_winkel": "90",
"es_winkel": "90",
"kreisel_start": "Kreisel_Showroom_05",
"kreisel_ende": "Kreisel_Showroom_06",
"hoehe_ende_mm": 1970.0,
"hoehe_quelle": "Anwender",
"comment": "aus DXF: LINE auf Layer '6-SP' (31255.93, 15593.90) -> (31255.93, 13893.90), Laenge XY 1700.00; am oberen Ende um 305.0 mm bis zur Kette von Kreisel_Showroom_05 verlaengert; am unteren Ende um 400.0 mm bis zur Kette von Kreisel_Showroom_06 verlaengert; Hoehen vom Anwender (Kreisel Kreisel_Showroom_05 / Kreisel_Showroom_06), den Winkel rechnet der Treiber; as_seite links aus der Lage zur Fahrtrichtung; AS aus Block 'AE-D' bei (31436.27, 15898.90) -> AS_Element_90_links, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90; Separator auf der Achse entfernt (die GF baut ihren eigenen): S-SP bei (31256, 13994), S-SP bei (31256, 14807); es_seite rechts aus der Lage zur Fahrtrichtung; ES aus Block 'EE-R' bei (31043.76, 13493.90) -> ES_Element_90_rechts, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90."
},
{
"test_id": "GF_Showroom_04",
"modus": 1,
"deltaL_mm": 2405.0,
"hz_grad": 270.0,
"start_mm": [32055.93, 12693.9, 1970.0],
"as_seite": "rechts",
"es_seite": "links",
"as_winkel": "90",
"es_winkel": "90",
"kreisel_start": "Kreisel_Showroom_06",
"kreisel_ende": "Kreisel_Showroom_03",
"hoehe_ende_mm": 1700.0,
"hoehe_quelle": "Anwender",
"comment": "aus DXF: LINE auf Layer '6-SP' (32055.93, 12388.90) -> (32055.93, 10688.90), Laenge XY 1700.00; am oberen Ende um 305.0 mm bis zur Kette von Kreisel_Showroom_06 verlaengert; am unteren Ende um 400.0 mm bis zur Kette von Kreisel_Showroom_03 verlaengert; Hoehen vom Anwender (Kreisel Kreisel_Showroom_06 / Kreisel_Showroom_03), den Winkel rechnet der Treiber; as_seite rechts aus der Lage zur Fahrtrichtung; AS aus Block 'AE-D' bei (31875.60, 12693.90) -> AS_Element_90_rechts, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90; Separator auf der Achse entfernt (die GF baut ihren eigenen): S-SP bei (32056, 10789), S-SP bei (32056, 11602); es_seite links aus der Lage zur Fahrtrichtung; ES aus Block 'EE-R' bei (32268.11, 10288.90) -> ES_Element_90_links, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90."
},
{
"test_id": "GF_Showroom_05",
"modus": 1,
"deltaL_mm": 2405.0,
"hz_grad": 270.0,
"start_mm": [32055.93, 15898.9, 2226.4],
"as_seite": "links",
"es_seite": "rechts",
"as_winkel": "90",
"es_winkel": "90",
"kreisel_start": "Kreisel_Showroom_05",
"kreisel_ende": "Kreisel_Showroom_06",
"hoehe_ende_mm": 1970.0,
"hoehe_quelle": "Anwender",
"comment": "aus DXF: LINE auf Layer '6-SP' (32055.93, 15593.90) -> (32055.93, 13893.90), Laenge XY 1700.00; am oberen Ende um 305.0 mm bis zur Kette von Kreisel_Showroom_05 verlaengert; am unteren Ende um 400.0 mm bis zur Kette von Kreisel_Showroom_06 verlaengert; Hoehen vom Anwender (Kreisel Kreisel_Showroom_05 / Kreisel_Showroom_06), den Winkel rechnet der Treiber; as_seite links aus der Lage zur Fahrtrichtung; AS aus Block 'AE-D' bei (32236.27, 15898.90) -> AS_Element_90_links, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90; Separator auf der Achse entfernt (die GF baut ihren eigenen): S-SP bei (32056, 13994), S-SP bei (32056, 14807); es_seite rechts aus der Lage zur Fahrtrichtung; ES aus Block 'EE-R' bei (31843.76, 13493.90) -> ES_Element_90_rechts, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90."
},
{
"test_id": "GF_Showroom_06",
"modus": 1,
"deltaL_mm": 2405.0,
"hz_grad": 270.0,
"start_mm": [33205.93, 12693.9, 1970.0],
"as_seite": "rechts",
"es_seite": "links",
"as_winkel": "90",
"es_winkel": "90",
"kreisel_start": "Kreisel_Showroom_06",
"kreisel_ende": "Kreisel_Showroom_03",
"hoehe_ende_mm": 1700.0,
"hoehe_quelle": "Anwender",
"comment": "aus DXF: LINE auf Layer '6-SP' (33205.93, 12388.90) -> (33205.93, 10688.90), Laenge XY 1700.00; am oberen Ende um 305.0 mm bis zur Kette von Kreisel_Showroom_06 verlaengert; am unteren Ende um 400.0 mm bis zur Kette von Kreisel_Showroom_03 verlaengert; Hoehen vom Anwender (Kreisel Kreisel_Showroom_06 / Kreisel_Showroom_03), den Winkel rechnet der Treiber; as_seite rechts aus der Lage zur Fahrtrichtung; AS aus Block 'AE-D' bei (33025.60, 12693.90) -> AS_Element_90_rechts, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90; Separator auf der Achse entfernt (die GF baut ihren eigenen): S-SP bei (33206, 10789), S-SP bei (33206, 11602); es_seite links aus der Lage zur Fahrtrichtung; ES aus Block 'EE-R' bei (33418.11, 10288.90) -> ES_Element_90_links, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90."
},
{
"test_id": "GF_Showroom_07",
"modus": 1,
"deltaL_mm": 2405.0,
"hz_grad": 270.0,
"start_mm": [33205.93, 15898.9, 2226.4],
"as_seite": "links",
"es_seite": "rechts",
"as_winkel": "90",
"es_winkel": "90",
"kreisel_start": "Kreisel_Showroom_05",
"kreisel_ende": "Kreisel_Showroom_06",
"hoehe_ende_mm": 1970.0,
"hoehe_quelle": "Anwender",
"comment": "aus DXF: LINE auf Layer '6-SP' (33205.93, 15593.90) -> (33205.93, 13893.90), Laenge XY 1700.00; am oberen Ende um 305.0 mm bis zur Kette von Kreisel_Showroom_05 verlaengert; am unteren Ende um 400.0 mm bis zur Kette von Kreisel_Showroom_06 verlaengert; Hoehen vom Anwender (Kreisel Kreisel_Showroom_05 / Kreisel_Showroom_06), den Winkel rechnet der Treiber; as_seite links aus der Lage zur Fahrtrichtung; AS aus Block 'AE-D' bei (33386.27, 15898.90) -> AS_Element_90_links, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90; Separator auf der Achse entfernt (die GF baut ihren eigenen): S-SP bei (33206, 13994), S-SP bei (33206, 14807); es_seite rechts aus der Lage zur Fahrtrichtung; ES aus Block 'EE-R' bei (32993.76, 13493.90) -> ES_Element_90_rechts, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90."
},
{
"test_id": "GF_Showroom_08",
"modus": 1,
"deltaL_mm": 2405.0,
"hz_grad": 270.0,
"start_mm": [34005.93, 12693.9, 1970.0],
"as_seite": "rechts",
"es_seite": "links",
"as_winkel": "90",
"es_winkel": "90",
"kreisel_start": "Kreisel_Showroom_06",
"kreisel_ende": "Kreisel_Showroom_03",
"hoehe_ende_mm": 1700.0,
"hoehe_quelle": "Anwender",
"comment": "aus DXF: LINE auf Layer '6-SP' (34005.93, 12388.90) -> (34005.93, 10688.90), Laenge XY 1700.00; am oberen Ende um 305.0 mm bis zur Kette von Kreisel_Showroom_06 verlaengert; am unteren Ende um 400.0 mm bis zur Kette von Kreisel_Showroom_03 verlaengert; Hoehen vom Anwender (Kreisel Kreisel_Showroom_06 / Kreisel_Showroom_03), den Winkel rechnet der Treiber; as_seite rechts aus der Lage zur Fahrtrichtung; AS aus Block 'AE-D' bei (33825.60, 12693.90) -> AS_Element_90_rechts, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90; Separator auf der Achse entfernt (die GF baut ihren eigenen): S-SP bei (34006, 10789), S-SP bei (34006, 11602); es_seite links aus der Lage zur Fahrtrichtung; ES aus Block 'EE-R' bei (34218.11, 10288.90) -> ES_Element_90_links, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90."
},
{
"test_id": "GF_Showroom_09",
"modus": 1,
"deltaL_mm": 2405.0,
"hz_grad": 270.0,
"start_mm": [34005.93, 15898.9, 2226.4],
"as_seite": "links",
"es_seite": "rechts",
"as_winkel": "90",
"es_winkel": "90",
"kreisel_start": "Kreisel_Showroom_05",
"kreisel_ende": "Kreisel_Showroom_06",
"hoehe_ende_mm": 1970.0,
"hoehe_quelle": "Anwender",
"comment": "aus DXF: LINE auf Layer '6-SP' (34005.93, 15593.90) -> (34005.93, 13893.90), Laenge XY 1700.00; am oberen Ende um 305.0 mm bis zur Kette von Kreisel_Showroom_05 verlaengert; am unteren Ende um 400.0 mm bis zur Kette von Kreisel_Showroom_06 verlaengert; Hoehen vom Anwender (Kreisel Kreisel_Showroom_05 / Kreisel_Showroom_06), den Winkel rechnet der Treiber; as_seite links aus der Lage zur Fahrtrichtung; AS aus Block 'AE-D' bei (34186.27, 15898.90) -> AS_Element_90_links, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90; Separator auf der Achse entfernt (die GF baut ihren eigenen): S-SP bei (34006, 13994), S-SP bei (34006, 14807); es_seite rechts aus der Lage zur Fahrtrichtung; ES aus Block 'EE-R' bei (33793.76, 13493.90) -> ES_Element_90_rechts, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90."
},
{
"test_id": "GF_Showroom_10",
"modus": 1,
"deltaL_mm": 2405.0,
"hz_grad": 270.0,
"start_mm": [34805.93, 12693.9, 1970.0],
"as_seite": "rechts",
"es_seite": "links",
"as_winkel": "90",
"es_winkel": "90",
"kreisel_start": "Kreisel_Showroom_06",
"kreisel_ende": "Kreisel_Showroom_03",
"hoehe_ende_mm": 1700.0,
"hoehe_quelle": "Anwender",
"comment": "aus DXF: LINE auf Layer '6-SP' (34805.93, 12388.90) -> (34805.93, 10688.90), Laenge XY 1700.00; am oberen Ende um 305.0 mm bis zur Kette von Kreisel_Showroom_06 verlaengert; am unteren Ende um 400.0 mm bis zur Kette von Kreisel_Showroom_03 verlaengert; Hoehen vom Anwender (Kreisel Kreisel_Showroom_06 / Kreisel_Showroom_03), den Winkel rechnet der Treiber; as_seite rechts aus der Lage zur Fahrtrichtung; AS aus Block 'AE-D' bei (34625.60, 12693.90) -> AS_Element_90_rechts, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90; Separator auf der Achse entfernt (die GF baut ihren eigenen): S-SP bei (34806, 10789), S-SP bei (34806, 11602); es_seite links aus der Lage zur Fahrtrichtung; ES aus Block 'EE-R' bei (35018.11, 10288.90) -> ES_Element_90_links, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90."
},
{
"test_id": "GF_Showroom_11",
"modus": 1,
"deltaL_mm": 2405.0,
"hz_grad": 270.0,
"start_mm": [34805.93, 15898.9, 2226.4],
"as_seite": "links",
"es_seite": "rechts",
"as_winkel": "90",
"es_winkel": "90",
"kreisel_start": "Kreisel_Showroom_05",
"kreisel_ende": "Kreisel_Showroom_06",
"hoehe_ende_mm": 1970.0,
"hoehe_quelle": "Anwender",
"comment": "aus DXF: LINE auf Layer '6-SP' (34805.93, 15593.90) -> (34805.93, 13893.90), Laenge XY 1700.00; am oberen Ende um 305.0 mm bis zur Kette von Kreisel_Showroom_05 verlaengert; am unteren Ende um 400.0 mm bis zur Kette von Kreisel_Showroom_06 verlaengert; Hoehen vom Anwender (Kreisel Kreisel_Showroom_05 / Kreisel_Showroom_06), den Winkel rechnet der Treiber; as_seite links aus der Lage zur Fahrtrichtung; AS aus Block 'AE-D' bei (34986.27, 15898.90) -> AS_Element_90_links, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90; Separator auf der Achse entfernt (die GF baut ihren eigenen): S-SP bei (34806, 13994), S-SP bei (34806, 14807); es_seite rechts aus der Lage zur Fahrtrichtung; ES aus Block 'EE-R' bei (34593.76, 13493.90) -> ES_Element_90_rechts, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90."
},
{
"function": "insert",
"block": "S-LP",
"x": 26597.93,
"y": 11973.9,
"z": 2226.4,
"rotation": 270.0,
"darstellung": "2D",
"comment": "aus DXF: Block 'S-LP', Layer '5SEP-LP'; Block 'S-LP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt) [Hoehe entfernt: --ohne-hoehen] Hoehe 2226.4 von Kreisel_Showroom_01 (liegt auf dessen Kette).",
"hoehe_quelle": "Anwender"
},
{
"function": "insert",
"block": "S-LP",
"x": 26597.93,
"y": 13982.92,
"z": 2226.4,
"rotation": 90.0,
"darstellung": "2D",
"comment": "aus DXF: Block 'S-LP', Layer 'TGW_HB_2OG-AM_5'; Block 'S-LP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt) [Hoehe entfernt: --ohne-hoehen] Hoehe 2226.4 von Kreisel_Showroom_02 (liegt auf dessen Kette).",
"hoehe_quelle": "Anwender"
},
{
"function": "insert",
"block": "S-LP",
"x": 27397.93,
"y": 5450.07,
"z": 2226.4,
"rotation": 90.0,
"darstellung": "2D",
"comment": "aus DXF: Block 'S-LP', Layer 'TGW_HB_2OG-AM_5'; Block 'S-LP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt) [Hoehe entfernt: --ohne-hoehen] Hoehe 2226.4 von Kreisel_Showroom_01 (liegt auf dessen Kette).",
"hoehe_quelle": "Anwender"
},
{
"function": "insert",
"block": "S-LP",
"x": 27397.93,
"y": 15773.9,
"z": 2226.4,
"rotation": 270.0,
"darstellung": "2D",
"comment": "aus DXF: Block 'S-LP', Layer '5SEP-LP'; Block 'S-LP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt) [Hoehe entfernt: --ohne-hoehen] Hoehe 2226.4 von Kreisel_Showroom_02 (liegt auf dessen Kette).",
"hoehe_quelle": "Anwender"
},
{
"function": "insert",
"block": "S-LP",
"x": 29397.93,
"y": 13493.9,
"z": 1970.0,
"rotation": 0.0,
"darstellung": "2D",
"comment": "aus DXF: Block 'S-LP', Layer '5SEP-LP'; Block 'S-LP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt) [Hoehe entfernt: --ohne-hoehen] Hoehe 1970 von Kreisel_Showroom_06 (liegt auf dessen Kette).",
"hoehe_quelle": "Anwender"
},
{
"function": "insert",
"block": "S-LP",
"x": 30343.39,
"y": 9488.9,
"z": 1700.0,
"rotation": 0.0,
"darstellung": "2D",
"comment": "aus DXF: Block 'S-LP', Layer '5SEP-LP'; Block 'S-LP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt) [Hoehe entfernt: --ohne-hoehen] Hoehe 1700.0 von Kreisel_Showroom_03 (liegt auf dessen Kette).",
"hoehe_quelle": "Anwender"
},
{
"function": "insert",
"block": "S-LP",
"x": 32083.74,
"y": 9488.9,
"z": 1700.0,
"rotation": 0.0,
"darstellung": "2D",
"comment": "aus DXF: Block 'S-LP', Layer '5SEP-LP'; Block 'S-LP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt) [Hoehe entfernt: --ohne-hoehen] Hoehe 1700.0 von Kreisel_Showroom_03 (liegt auf dessen Kette).",
"hoehe_quelle": "Anwender"
},
{
"function": "insert",
"block": "S-LP",
"x": 35905.93,
"y": 10288.9,
"z": 1700.0,
"rotation": 180.0,
"darstellung": "2D",
"comment": "aus DXF: Block 'S-LP', Layer '5SEP-LP'; Block 'S-LP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt) [Hoehe entfernt: --ohne-hoehen] Hoehe 1700.0 von Kreisel_Showroom_03 (liegt auf dessen Kette).",
"hoehe_quelle": "Anwender"
},
{
"function": "insert",
"block": "Scanner",
"x": 29398.73,
"y": 13176.71,
"z": 1970.0,
"rotation": 270.0,
"darstellung": "2D",
"comment": "aus DXF: Block 'SCAN', Layer 'ZZSCANNER', auf Makro-Block 'Scanner' abgebildet; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt) [Hoehe entfernt: --ohne-hoehen] Hoehe 1970 von Kreisel_Showroom_06 (liegt auf dessen Kette).",
"hoehe_quelle": "Anwender"
},
{
"function": "insert",
"block": "Scanner",
"x": 30343.39,
"y": 9208.9,
"z": 1700.0,
"rotation": 270.0,
"darstellung": "2D",
"comment": "aus DXF: Block 'SCAN', Layer 'ZZSCANNER', auf Makro-Block 'Scanner' abgebildet; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt) [Hoehe entfernt: --ohne-hoehen] Hoehe 1700.0 von Kreisel_Showroom_03 (liegt auf dessen Kette).",
"hoehe_quelle": "Anwender"
},
{
"function": "insert",
"block": "Scanner",
"x": 32083.74,
"y": 9208.9,
"z": 1700.0,
"rotation": 270.0,
"darstellung": "2D",
"comment": "aus DXF: Block 'SCAN', Layer 'ZZSCANNER', auf Makro-Block 'Scanner' abgebildet; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt) [Hoehe entfernt: --ohne-hoehen] Hoehe 1700.0 von Kreisel_Showroom_03 (liegt auf dessen Kette).",
"hoehe_quelle": "Anwender"
},
{
"function": "insert",
"block": "Scanner",
"x": 35905.93,
"y": 10008.9,
"z": 1700.0,
"rotation": 270.0,
"darstellung": "2D",
"comment": "aus DXF: Block 'SCAN', Layer 'ZZSCANNER', auf Makro-Block 'Scanner' abgebildet; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt) [Hoehe entfernt: --ohne-hoehen] Hoehe 1700.0 von Kreisel_Showroom_03 (liegt auf dessen Kette).",
"hoehe_quelle": "Anwender"
},
{
"id": "Showroom_BTMT_BEL_01",
"comment": "BTMT Beladung auf Kreisel_Showroom_03 (Hoehe 1700) - von Hand in der gebauten Showroom-Zeichnung ergaenzt, Einfuegepunkt/Drehung aus results/export_raw.json (EXPORTCSV vom 2026-10-07, Block BTMT-Beladung_3D, ID 0040)",
"function": "insert",
"block": "BTMT-Beladung",
"x": 29877.99,
"y": 9478.98,
"z": 1690.08,
"rotation": 180.0
},
{
"id": "Showroom_BTMT_ENT_01",
"comment": "BTMT Entladung auf Kreisel_Showroom_01 (Hoehe 2226.4) - von Hand in der gebauten Showroom-Zeichnung ergaenzt, Einfuegepunkt/Drehung aus results/export_raw.json (EXPORTCSV vom 2026-10-07, Block SC_Entladung_3D, ID 0041)",
"function": "insert",
"block": "SC_Entladung",
"x": 27397.93,
"y": 4555.45,
"z": 2226.4,
"rotation": 270.0
}
]