diff --git a/Lisp/Gefaellestrecke.lsp b/Lisp/Gefaellestrecke.lsp index f8626f5..8219b5b 100644 --- a/Lisp/Gefaellestrecke.lsp +++ b/Lisp/Gefaellestrecke.lsp @@ -767,6 +767,9 @@ ;; 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")) @@ -776,6 +779,9 @@ (vf-set-as-masse gf-as-winkel as-seite) ;; 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")) @@ -1735,6 +1741,9 @@ (setq winkel (float winkel)) ;; AUS-Element: 30/90 + Seite + (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")) @@ -1743,6 +1752,9 @@ (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")) diff --git a/Lisp/vf_core.lsp b/Lisp/vf_core.lsp index f0ceaff..ed7bbc6 100644 --- a/Lisp/vf_core.lsp +++ b/Lisp/vf_core.lsp @@ -621,9 +621,14 @@ ;; "vf-winkel-ein-header"). Rueckgabe: "30" oder "90" (Default 90). ;; Wizard: nutzt vflw-wahl (dcl/vf_linienzug_wizard.dcl, definiert in ;; vf_linienzug.lsp) falls dieses Modul geladen und *vfl-wizard-mode* aktiv -;; ist - sonst (oder bei jedem Fehler) unveraendert die Konsolen-Fragen -;; (princ + getstring, de/en ueber ssg-text). Gemeinsam genutzt von -;; Gefaellestrecke.lsp UND vf_linienzug.lsp. +;; ist - sonst (oder bei jedem Fehler) unveraendert die Konsolen-Frage +;; (getstring, de/en ueber ssg-text). Gemeinsam genutzt von Gefaellestrecke.lsp +;; UND vf_linienzug.lsp. Druckt selbst KEINE Kopfzeile/Optionstexte mehr (das +;; macht immer der AUFRUFER, unconditional, VOR diesem Aufruf) - sonst fehlt +;; die Kopfzeile in der Konsole genau dann, wenn ein vfl-in-value-Wrapper den +;; Wert bereits aus der Pending-Queue/dem Journal-Replay liest und diese +;; Funktion dadurch gar nicht erst aufgerufen wird (Inkonsistenz Dialog vs. +;; Konsole, siehe Aufrufer in vf_linienzug.lsp/Gefaellestrecke.lsp). (defun vf-frage-element-winkel (headerkey / antwort) ;; Wizard-Dialog nur, wenn Wizard-Modus aktiv, vflw-wahl geladen UND die GUI ;; global nicht abgeschaltet ist (Tests: (ssg-gui-aus)) - sonst Konsole/getstring. @@ -638,12 +643,7 @@ (if (or (vl-catch-all-error-p antwort) (null antwort) (= antwort "")) (setq antwort "1")) ) - (progn - (princ (ssg-text headerkey)) - (princ (ssg-text "vf-winkel-90")) - (princ (ssg-text "vf-winkel-30")) - (setq antwort (getstring (ssg-text "prompt-wahl-1-2"))) - ) + (setq antwort (getstring (ssg-text "prompt-wahl-1-2"))) ) (if (= antwort "2") "30" "90")) @@ -967,7 +967,7 @@ (setq horizontal-info nil) (if (and horizontal-p (= richtung "Ab")) (progn - (setq horizontal-info (berechne-horizontale-mitte deltaL deltaH "Ab")) + (setq horizontal-info (berechne-horizontale-mitte deltaL deltaH "Ab" nil)) (if (and horizontal-info (caddr horizontal-info)) (setq ergebnis-liste (append ergebnis-liste (list (list 0 (car horizontal-info) (cadr horizontal-info) T)))) @@ -1067,6 +1067,94 @@ ) ) +;; ============================================================ +;; TEIL 11b: DIALOG-AUSWAHL FUER TYP/LINIENZUG-MODUS (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- +;; 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 +;; 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 +;; geblieben). Rueckgabe jeweils: Ergebnis bei OK, 'ABBRUCH bei Cancel, nil +;; wenn der Dialog gar nicht erst gezeigt werden konnte/durfte. +;; "Zurueck" hat an dieser allerersten Frage der ganzen Anlage nichts, wohin es +;; zurueckspringen koennte - wird daher lokal aufgeloest: der Dialog wird +;; einfach erneut gezeigt (kein Sonderfall fuer den Aufrufer noetig). +(defun vfc-dialog-typ-waehlen ( / dcl-pfad dat gtyp ergebnis fertig) + (if (and (or (not (car (atoms-family 1 '("SSG-GUI-P")))) (ssg-gui-p)) + (= *ssg-lang* "de_DE") + (equal (mapcar 'car *vf-typ-registry*) '("standard" "etage" "linienzug"))) + (progn + (setq fertig nil) + (while (not fertig) + (setq fertig t) + (setq dcl-pfad (strcat (getenv "DXFM_DCL") "/variofoerderer.dcl")) + (setq dat (load_dialog dcl-pfad)) + (if (not (new_dialog "vfc_typ" dat)) + (progn (if (and dat (>= dat 0)) (unload_dialog dat)) (setq ergebnis nil)) + (progn + (set_tile "typ_standard" "1") + (action_tile "accept" + "(setq gtyp (cond ((= (get_tile \"typ_etage\") \"1\") \"etage\") + ((= (get_tile \"typ_linienzug\") \"1\") \"linienzug\") + (t \"standard\"))) + (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) (setq ergebnis gtyp)) + ((= ergebnis 2) (setq fertig nil)) ;; Zurueck: Dialog erneut zeigen + (t (setq ergebnis 'ABBRUCH)) + ) + ) + ) + ) + ergebnis + ) + nil + ) +) + +;; "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) + (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)) + (progn (if (and dat (>= dat 0)) (unload_dialog dat)) nil) + (progn + (set_tile "modus_1" "1") + (action_tile "accept" + "(setq gmodus (cond ((= (get_tile \"modus_2\") \"1\") 2) + ((= (get_tile \"modus_3\") \"1\") 3) + (t 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) + ) + ) + ) + ) + nil + ) +) + ;; ============================================================ ;; TEIL 12: DISPATCHER c:VarioFoerderer ;; ============================================================ @@ -1077,7 +1165,7 @@ 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) + staustrecke-basis vf-insert dlg-typ dlg-modus zurueck-zu-typ) (princ "\n=========================================") (princ (ssg-text "vfc-banner-titel")) @@ -1091,53 +1179,82 @@ ) ) - (if (and *vf-vorauswahl-typ* (assoc *vf-vorauswahl-typ* *vf-typ-registry*)) - (progn - (setq typ-eintr (assoc *vf-vorauswahl-typ* *vf-typ-registry*)) - (princ (ssg-textf "vfc-typ-vorgewaehlt" (list *vf-vorauswahl-typ*))) - (setq *vf-vorauswahl-typ* nil) - ) - (progn - (setq *vf-vorauswahl-typ* nil) - (princ (ssg-text "vfc-anlagen-typ-header")) - (setq idx 1) - (foreach eintr *vf-typ-registry* - (princ (ssg-textf "vfc-typ-option" (list idx (nth 3 eintr)))) - (setq idx (1+ idx)) + ;; Aeussere Schleife nur wegen "Zurueck" bei der Linienzug-Modus-Frage + ;; (springt zurueck zur Anlagen-Typ-Frage) - fuer Standard/Etage bleibt + ;; zurueck-zu-typ immer nil, die Schleife laeuft dann genau einmal. + (setq zurueck-zu-typ t) + (while zurueck-zu-typ + (setq zurueck-zu-typ nil) + (if (and *vf-vorauswahl-typ* (assoc *vf-vorauswahl-typ* *vf-typ-registry*)) + (progn + (setq typ-eintr (assoc *vf-vorauswahl-typ* *vf-typ-registry*)) + (princ (ssg-textf "vfc-typ-vorgewaehlt" (list *vf-vorauswahl-typ*))) + (setq *vf-vorauswahl-typ* nil) + ) + (progn + (setq *vf-vorauswahl-typ* nil) + (setq dlg-typ (vfc-dialog-typ-waehlen)) + (cond + ((eq dlg-typ 'ABBRUCH) (exit)) + (dlg-typ (setq typ-eintr (assoc dlg-typ *vf-typ-registry*))) + (t + ;; Dialog nicht verfuegbar/nicht erlaubt (GUI aus, andere Sprache, + ;; abweichende Registry) - alte Konsolen-Liste unveraendert. + (princ (ssg-text "vfc-anlagen-typ-header")) + (setq idx 1) + (foreach eintr *vf-typ-registry* + (princ (ssg-textf "vfc-typ-option" (list idx (nth 3 eintr)))) + (setq idx (1+ idx)) + ) + (setq wahl (getint (ssg-textf "vfc-prompt-wahl-1-n" + (list (length *vf-typ-registry*))))) + (if (or (null wahl) (< wahl 1) (> wahl (length *vf-typ-registry*))) + (setq wahl 1)) + (setq typ-eintr (nth (1- wahl) *vf-typ-registry*)) + ) + ) ) - (setq wahl (getint (ssg-textf "vfc-prompt-wahl-1-n" - (list (length *vf-typ-registry*))))) - (if (or (null wahl) (< wahl 1) (> wahl (length *vf-typ-registry*))) - (setq wahl 1)) - (setq typ-eintr (nth (1- wahl) *vf-typ-registry*)) ) - ) - (setq anlage-typ (nth 0 typ-eintr)) - (setq berechne-fn (nth 1 typ-eintr)) - (setq einfuege-fn (nth 2 typ-eintr)) - (princ (ssg-textf "vfc-typ-gewaehlt" (list anlage-typ))) + (setq anlage-typ (nth 0 typ-eintr)) + (setq berechne-fn (nth 1 typ-eintr)) + (setq einfuege-fn (nth 2 typ-eintr)) + (princ (ssg-textf "vfc-typ-gewaehlt" (list anlage-typ))) - ;; Sonderfall "linienzug": eigener Befehlsablauf (interaktive Mehrsegment- - ;; 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. - (if (= anlage-typ "linienzug") - (progn - (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")) - (setq wahl (getint (ssg-text "prompt-wahl-1-2-3"))) - ;; Konsolen-Nummer -> interne Funktion: - ;; 2 = fertiger Ziel-Hoehe-Modus (intern vf-linienzug-modus2) - ;; 3 = alter Vorwaerts-Nachbau (intern vf-linienzug-modus3, wird umgebaut) - ;; 1/Default = frische manuelle Eingabe (Journal vorher zuruecksetzen). Ein - ;; abgebrochener Bau bleibt als VF_n-Block stehen und wird per Doppelklick - ;; fortgesetzt/editiert (vfl-edit-ent), kein separater Menuepunkt noetig. - (cond ((= wahl 2) (vf-linienzug-modus2)) - ((= wahl 3) (vf-linienzug-modus3)) - (t (vfl-journal-reset) (vf-linienzug-modus))) - (exit) + ;; Sonderfall "linienzug": eigener Befehlsablauf (interaktive Mehrsegment- + ;; 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. + (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")) + (setq wahl (getint (ssg-text "prompt-wahl-1-2-3"))) + ) + ) + (if (not zurueck-zu-typ) + (progn + ;; Konsolen-Nummer -> interne Funktion: + ;; 2 = fertiger Ziel-Hoehe-Modus (intern vf-linienzug-modus2) + ;; 3 = alter Vorwaerts-Nachbau (intern vf-linienzug-modus3, wird umgebaut) + ;; 1/Default = frische manuelle Eingabe (Journal vorher zuruecksetzen). Ein + ;; abgebrochener Bau bleibt als VF_n-Block stehen und wird per Doppelklick + ;; fortgesetzt/editiert (vfl-edit-ent), kein separater Menuepunkt noetig. + (cond ((= wahl 2) (vf-linienzug-modus2)) + ((= wahl 3) (vf-linienzug-modus3)) + (t (vfl-journal-reset) (vf-linienzug-modus))) + (exit) + ) + ) + ) ) ) @@ -1198,7 +1315,7 @@ ;; 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")) + (setq horizontal-info (berechne-horizontale-mitte deltaL deltaH "Ab" nil)) (if (and horizontal-info (caddr horizontal-info)) (progn (setq ergebnis-liste diff --git a/Lisp/vf_konstanten.lsp b/Lisp/vf_konstanten.lsp index dba406c..9ee5599 100644 --- a/Lisp/vf_konstanten.lsp +++ b/Lisp/vf_konstanten.lsp @@ -271,6 +271,11 @@ ;; Wert geometrisch herleiten laesst statt empirisch fixiert zu bleiben. (if (null *vfk-bruecke-korrektur*) (setq *vfk-bruecke-korrektur* 10.48)) +;; Konstruktions-Obergrenze (mm) fuer die Gesamtlaenge eines zusammen- +;; haengenden VF-Laufs (Modus 2, vf-linienzug-modus2) - reiner Hinweis beim +;; Ueberschreiten, kein Abbruch. Aktiv referenziert. +(if (null *vfk-vf-laenge-max*) (setq *vfk-vf-laenge-max* 25000.0)) + (setq *vfk-konstanten-geladen* t) (princ "\nvf_konstanten geladen.") (princ) diff --git a/Lisp/vf_linienzug.lsp b/Lisp/vf_linienzug.lsp index 6af508a..abd8b7d 100644 --- a/Lisp/vf_linienzug.lsp +++ b/Lisp/vf_linienzug.lsp @@ -77,7 +77,12 @@ *vfl-acc-gfbogen* '() ; Alist ("L_90".n ...) GF-Boegen *vfl-acc-variokurve* '() ; Alist ("A_90".n ...) Vario-Kurven *vfl-ziel-punkt* nil ; Soll-ES-Punkt fuer Option-3-Ist-Ziel-Report - *vfl-acc-separator* 0)) ; Anzahl eingefuegter Separatoren (300 mm) + *vfl-acc-separator* 0 ; Anzahl eingefuegter Separatoren (300 mm) + ;; "Zurueck"/"Abbrechen"-Button (siehe vfl-in-value/vfl-modus-abbruch- + ;; sichern): nil (normal) / "zurueck" (letztes Glied verwerfen und neu + ;; fragen) / "abbrechen" (Bau hier stoppen, Baustand bleibt stehen). + *vfl-wizard-abbruch-grund* nil + *vfl-abbruch-letztes-ent* nil)) ;; Alist-Zaehler erhoehen / lesen (defun vfl-inc-count (al key / e) @@ -500,11 +505,14 @@ (set_tile "kopf" (vflw-clean prompt)) (action_tile "accept" "(setq dlg-wert (get_tile \"wert\")) (done_dialog 1)") (action_tile "cancel" "(done_dialog 0)") + (action_tile "back" "(done_dialog 2)") (setq ergebnis (start_dialog)) (unload_dialog dat) - (if (and (= ergebnis 1) dlg-wert (> (strlen dlg-wert) 0)) - (atof dlg-wert) - nil)))) + (cond + ((and (= ergebnis 1) dlg-wert (> (strlen dlg-wert) 0)) (atof dlg-wert)) + ((= ergebnis 2) (setq *vfl-wizard-abbruch-grund* "zurueck") nil) + ((= ergebnis 0) (setq *vfl-wizard-abbruch-grund* "abbrechen") nil) + (t nil))))) (defun vflw-zahl (prompt / r) (setq r (vl-catch-all-apply 'vflw-zahl-impl (list prompt))) (if (vl-catch-all-error-p r) (getreal prompt) r)) @@ -527,9 +535,13 @@ (set_tile "opts" (itoa (max 0 (1- (if default-idx default-idx 1))))) (action_tile "accept" "(setq dlg-opt (get_tile \"opts\")) (done_dialog 1)") (action_tile "cancel" "(done_dialog 0)") + (action_tile "back" "(done_dialog 2)") (setq ergebnis (start_dialog)) (unload_dialog dat) - (if (= ergebnis 1) (itoa (1+ (atoi dlg-opt))) "")))) + (cond + ((= ergebnis 1) (itoa (1+ (atoi dlg-opt)))) + ((= ergebnis 2) (setq *vfl-wizard-abbruch-grund* "zurueck") "") + (t (setq *vfl-wizard-abbruch-grund* "abbrechen") ""))))) (defun vflw-wahl (prompt optionen default-idx / r) (setq r (vl-catch-all-apply 'vflw-wahl-impl (list prompt optionen default-idx))) (if (vl-catch-all-error-p r) "" r)) @@ -572,6 +584,8 @@ (action_tile "pick" "(done_dialog 2)") (action_tile "accept" "(setq gwert (get_tile \"wert\")) (done_dialog 1)") (action_tile "cancel" "(done_dialog 0)") + ;; Code 3 statt 2 - 2 ist hier schon durch "Punkt waehlen..." belegt. + (action_tile "back" "(done_dialog 3)") (setq ergebnis (start_dialog)) (unload_dialog dat) (cond @@ -585,7 +599,8 @@ (setq fertig t) (if (and gpunkt gwert (> (strlen gwert) 0)) (vflw-pending-push-all (list gpunkt (atof gwert))))) - (t (setq fertig t))) + ((= ergebnis 3) (setq fertig t) (setq *vfl-wizard-abbruch-grund* "zurueck")) + (t (setq fertig t) (setq *vfl-wizard-abbruch-grund* "abbrechen"))) ) ) ) @@ -607,35 +622,35 @@ (progn (set_tile "kopf" (vflw-clean (ssg-text kopf-key))) (set_tile "setzen" "1") - (start_list "winkel") - (add_list (vflw-clean (ssg-text "vf-winkel-90"))) - (add_list (vflw-clean (ssg-text "vf-winkel-30"))) - (end_list) - (set_tile "winkel" "0") - (start_list "seite") - (add_list (vflw-clean (ssg-text "gf-seite-links"))) - (add_list (vflw-clean (ssg-text "gf-seite-rechts"))) - (end_list) - (set_tile "seite" "0") + (set_tile "winkel_90" "1") + (set_tile "seite_links" "1") (action_tile "setzen" - "(mode_tile \"winkel\" (if (= (get_tile \"setzen\") \"1\") 0 1)) - (mode_tile \"seite\" (if (= (get_tile \"setzen\") \"1\") 0 1))") + "(mode_tile \"winkel_90\" (if (= (get_tile \"setzen\") \"1\") 0 1)) + (mode_tile \"winkel_30\" (if (= (get_tile \"setzen\") \"1\") 0 1)) + (mode_tile \"seite_links\" (if (= (get_tile \"setzen\") \"1\") 0 1)) + (mode_tile \"seite_rechts\" (if (= (get_tile \"setzen\") \"1\") 0 1))") (action_tile "accept" "(setq gsetzen (get_tile \"setzen\")) - (setq gwinkel (get_tile \"winkel\")) - (setq gseite (get_tile \"seite\")) + (setq gwinkel (if (= (get_tile \"winkel_30\") \"1\") \"30\" \"90\")) + (setq gseite (if (= (get_tile \"seite_rechts\") \"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) - (if (= ergebnis 1) - (if (= gsetzen "1") - ;; Winkel-Slot wird von vfl-in-value (AS-Winkel, ueber - ;; vf-frage-element-winkel) konsumiert - der erwartet direkt - ;; "30"/"90", NICHT den Auswahl-Index wie beim Seite-Slot. - (vflw-pending-push-all - (list "1" (if (= gwinkel "1") "30" "90") (if (= gseite "1") "2" "1"))) - (vflw-pending-push-all (list "2")))))) + (cond + ((= ergebnis 1) + (if (= gsetzen "1") + ;; Winkel-Slot wird von vfl-in-value (AS-Winkel, ueber + ;; vf-frage-element-winkel) konsumiert - der erwartet direkt + ;; "30"/"90", NICHT den Auswahl-Index wie beim Seite-Slot. + (vflw-pending-push-all (list "1" gwinkel gseite)) + (vflw-pending-push-all (list "2")))) + ((= ergebnis 2) (setq *vfl-wizard-abbruch-grund* "zurueck")) + (t (setq *vfl-wizard-abbruch-grund* "abbrechen")) + ) + ) + ) (princ)) ;; ------------------------------------------------------------ @@ -647,33 +662,57 @@ ;; wird IMMER als echter Wert in die Pending-Queue geschrieben (nie als Index), ;; damit Journal/Log selbsterklaerend sind. GF-Bogen legt Zahlen ab (vom ;; vfl-menu-winkel/vfl-in-value als "INT" journalisiert), ES Strings "90"/"30". -(defun vflw-gruppe-winkel-seite-impl (kopf-key winkel-optionen winkel-werte / dat dcl-pfad ergebnis gwinkel gseite) +;; winkel-werte enthaelt entweder (30 60 90) als ZAHLEN [GF-Bogen, INT- +;; Journal] oder ("90" "30") als STRINGS [ES, STR-Journal] - das bestimmt +;; sowohl welche Radio-Buttons waehlbar sind (nicht enthaltene Winkel werden +;; per mode_tile gesperrt), den Default (erster Eintrag der Liste, wie +;; bisher Index 0) ALS AUCH den TYP des in die Pending-Queue geschriebenen +;; Werts - der muss exakt zu winkel-werte passen, sonst schlaegt der +;; nachgelagerte Typ-Check (vfl-in-value "INT" bzw. "STR") fehl. +(defun vflw-gruppe-winkel-seite-impl (kopf-key winkel-optionen winkel-werte / + dat dcl-pfad ergebnis gwinkel-grad gseite) (setq dat (load_dialog (vflw-dcl-pfad))) (if (not (new_dialog "vflw_winkel_seite" dat)) (if (and dat (>= dat 0)) (unload_dialog dat)) (progn (set_tile "kopf" (vflw-clean (ssg-text kopf-key))) - (start_list "winkel") - (foreach o winkel-optionen (add_list (vflw-clean o))) - (end_list) - (set_tile "winkel" "0") - (start_list "seite") - (add_list (vflw-clean (ssg-text "gf-seite-links"))) - (add_list (vflw-clean (ssg-text "gf-seite-rechts"))) - (end_list) - (set_tile "seite" "0") + (if (not (vfl-winkel-in-liste-p 30 winkel-werte)) (mode_tile "winkel_30" 1)) + (if (not (vfl-winkel-in-liste-p 60 winkel-werte)) (mode_tile "winkel_60" 1)) + (if (not (vfl-winkel-in-liste-p 90 winkel-werte)) (mode_tile "winkel_90" 1)) + (set_tile (strcat "winkel_" (itoa (vfl-winkel-als-zahl (car winkel-werte)))) "1") + (set_tile "seite_links" "1") (action_tile "accept" - "(setq gwinkel (get_tile \"winkel\")) (setq gseite (get_tile \"seite\")) (done_dialog 1)") + "(setq gwinkel-grad (cond ((= (get_tile \"winkel_30\") \"1\") 30) + ((= (get_tile \"winkel_60\") \"1\") 60) + (t 90))) + (setq gseite (if (= (get_tile \"seite_rechts\") \"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) - (if (= ergebnis 1) - (vflw-pending-push-all - (list - (nth (atoi gwinkel) winkel-werte) - (if (= gseite "1") "2" "1")))))) + (cond + ((= ergebnis 1) + ;; Original-Eintrag aus winkel-werte uebernehmen (nicht den nackten + ;; Grad-Wert) - erhaelt den Typ (INT fuer GF-Bogen, STR fuer ES). + (vflw-pending-push-all + (list (car (vl-remove-if-not + (function (lambda (w) (= (vfl-winkel-als-zahl w) gwinkel-grad))) + winkel-werte)) + gseite))) + ((= ergebnis 2) (setq *vfl-wizard-abbruch-grund* "zurueck")) + (t (setq *vfl-wizard-abbruch-grund* "abbrechen")) + ) + ) + ) (princ)) +;; Hilfsfunktionen fuer winkel-werte-Listen, die je nach Aufrufer Zahlen +;; (GF-Bogen) oder Strings (ES) enthalten koennen (siehe oben). +(defun vfl-winkel-als-zahl (w) (if (numberp w) w (atoi w))) +(defun vfl-winkel-in-liste-p (grad liste) + (vl-some (function (lambda (w) (= (vfl-winkel-als-zahl w) grad))) liste)) + ;; ------------------------------------------------------------ ;; Gruppe "Vario-Kurve": Winkel(90/60/30) + Seite + Variante(aussen/innen). ;; Reihenfolge/Journal: vfl-menu-winkel (Winkel als ECHTER Wert 90/60/30, als @@ -685,37 +724,27 @@ (if (and dat (>= dat 0)) (unload_dialog dat)) (progn (set_tile "kopf" (vflw-clean (ssg-text "vfl-variokurve-winkel-header"))) - ;; Winkel-Reihenfolge vereinheitlicht auf 30/60/90 (wie GF-Bogen); - ;; Default 90 -> Listenposition 2. - (start_list "winkel") - (add_list (vflw-clean (ssg-text "vfl-opt3-30grad"))) - (add_list (vflw-clean (ssg-text "vfl-opt2-60grad"))) - (add_list (vflw-clean (ssg-text "vfl-opt1-90grad"))) - (end_list) - (set_tile "winkel" "2") - (start_list "seite") - (add_list (vflw-clean (ssg-text "gf-seite-links"))) - (add_list (vflw-clean (ssg-text "gf-seite-rechts"))) - (end_list) - (set_tile "seite" "0") - (start_list "variante") - (add_list (vflw-clean (ssg-text "vfl-variante-aussen"))) - (add_list (vflw-clean (ssg-text "vfl-variante-innen"))) - (end_list) - (set_tile "variante" "1") + (set_tile "winkel_90" "1") + (set_tile "seite_links" "1") + (set_tile "variante_innen" "1") (action_tile "accept" - "(setq gwinkel (get_tile \"winkel\")) - (setq gseite (get_tile \"seite\")) - (setq gvariante (get_tile \"variante\")) + "(setq gwinkel (cond ((= (get_tile \"winkel_30\") \"1\") 30) + ((= (get_tile \"winkel_60\") \"1\") 60) + (t 90))) + (setq gseite (if (= (get_tile \"seite_rechts\") \"1\") \"2\" \"1\")) + (setq gvariante (if (= (get_tile \"variante_innen\") \"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) - (if (= ergebnis 1) - (vflw-pending-push-all - (list (nth (atoi gwinkel) *vfk-gf-bogen-winkel*) - (if (= gseite "1") "2" "1") - (if (= gvariante "1") "2" "1")))))) + (cond + ((= ergebnis 1) (vflw-pending-push-all (list gwinkel gseite gvariante))) + ((= ergebnis 2) (setq *vfl-wizard-abbruch-grund* "zurueck")) + (t (setq *vfl-wizard-abbruch-grund* "abbrechen")) + ) + ) + ) (princ)) ;; ------------------------------------------------------------ @@ -727,38 +756,89 @@ ;; vfl-in-abstand) - dessen Z-Konzept existiert nicht mehr, "Hoehe" hier ist ;; ein eigener, unabhaengiger Zahlenwert. Original-Reihenfolge/-Journal ab hier: ;; vfl-in-string (Modus), danach vfl-in-real (Winkel ODER Hoehe). -(defun vflw-gruppe-gefaelle-impl (hoehe-default / dat dcl-pfad ergebnis gmodus gwert winkel-default) +;; nur-winkel: T fuer den "Zielhoehe zuerst festlegen"-Zweig von "Neue Linie: +;; GF" (Zielhoehe ist dort BEREITS fix, deltaL wird erst aus Winkel+Hoehe +;; berechnet) - "Gegebene Hoehe" ergibt dann keinen Sinn mehr und wird per +;; mode_tile gesperrt, der Hinweistext zeigt stattdessen, dass deltaL +;; berechnet wird. Konsumiert an der Aufrufstelle in diesem Fall NUR per +;; vfl-in-real (kein vorheriges vfl-in-string fuer den Modus mehr noetig) - +;; es wird daher auch nur der Winkelwert gepusht, kein Modus-String. +(defun vflw-gruppe-gefaelle-impl (hoehe-default nur-winkel / dat dcl-pfad ergebnis gmodus gwert winkel-default) (setq winkel-default (ssg-cfg-or "vario" "gefaelle_winkel" 3)) (setq dat (load_dialog (vflw-dcl-pfad))) (if (not (new_dialog "vflw_gefaelle" dat)) (if (and dat (>= dat 0)) (unload_dialog dat)) (progn (set_tile "kopf" (vflw-clean (ssg-text "vfl-gefaelle-festlegen-header"))) - (start_list "modus") - (add_list (vflw-clean (ssg-text "vfl-gefaelle-opt-hoehe"))) - (add_list (vflw-clean (ssg-text "vfl-gefaelle-opt-winkel"))) - (end_list) - (set_tile "modus" "0") - (set_tile "wlabel" "Zielhoehe (Z, mm):") - (set_tile "wert" (rtos hoehe-default 2 1)) + (set_tile "modus_winkel" "1") + (set_tile "wlabel" "Neigungswinkel (Grad):") + (set_tile "wert" (rtos (float winkel-default) 2 1)) + (if nur-winkel + (progn + (mode_tile "modus_hoehe" 1) + (set_tile "hinweis" (ssg-text "vfl-gf-hinweis-laenge-berechnet")) + ) + ) ;; Wertfeld MUSS beim Moduswechsel mit umschalten - sonst steht dort ;; nach dem Wechsel noch der Wert des vorherigen Modus (Hoehe/Winkel ;; sind nicht dieselbe Groesse, ein stehengebliebener Hoehenwert waere ;; als Neigungswinkel unsinnig). - (action_tile "modus" - "(if (= (get_tile \"modus\") \"0\") - (progn (set_tile \"wlabel\" \"Zielhoehe (Z, mm):\") - (set_tile \"wert\" (rtos hoehe-default 2 1))) - (progn (set_tile \"wlabel\" \"Neigungswinkel (Grad):\") - (set_tile \"wert\" (rtos (float winkel-default) 2 1))))") + (action_tile "modus_hoehe" + "(set_tile \"wlabel\" \"Zielhoehe (Z, mm):\") + (set_tile \"wert\" (rtos hoehe-default 2 1))") + (action_tile "modus_winkel" + "(set_tile \"wlabel\" \"Neigungswinkel (Grad):\") + (set_tile \"wert\" (rtos (float winkel-default) 2 1))") (action_tile "accept" - "(setq gmodus (get_tile \"modus\")) (setq gwert (get_tile \"wert\")) (done_dialog 1)") + ;; Winkel ist jetzt Option 1 (Default), Hoehe Option 2 - siehe + ;; wahl=\"Linie-GF\" in vf-linienzug-modus. + "(setq gmodus (if (= (get_tile \"modus_hoehe\") \"1\") \"2\" \"1\")) + (setq gwert (get_tile \"wert\")) (done_dialog 1)") (action_tile "cancel" "(done_dialog 0)") + (action_tile "back" "(done_dialog 2)") (setq ergebnis (start_dialog)) (unload_dialog dat) - (if (= ergebnis 1) - (vflw-pending-push-all - (list (if (= gmodus "1") "2" "1") (atof gwert)))))) + (cond + ((= ergebnis 1) + (if nur-winkel + (vflw-pending-push-all (list (atof gwert))) + (vflw-pending-push-all (list gmodus (atof gwert))))) + ((= ergebnis 2) (setq *vfl-wizard-abbruch-grund* "zurueck")) + (t (setq *vfl-wizard-abbruch-grund* "abbrechen")) + ) + ) + ) + (princ)) + +;; ------------------------------------------------------------ +;; "Wie soll die Laenge dieser Gefaellestrecke bestimmt werden?" (Neue Linie: +;; GF) - Endpunkt waehlen (Laenge ergibt sich, heutiges Verhalten) ODER +;; Zielhoehe zuerst festlegen (Laenge wird aus Zielhoehe+Winkel berechnet). +;; Nur an der Aufrufstelle gezeigt, wenn bereits ein Frame existiert (siehe +;; vf-linienzug-modus, wahl="Linie-GF"). Pusht "1" (Endpunkt), "2" +;; (Zielhoehe) oder "3" (steigende GF, Sonderfall). +(defun vflw-gruppe-gf-laenge-modus-impl ( / dat ergebnis gwahl) + (setq dat (load_dialog (vflw-dcl-pfad))) + (if (not (new_dialog "vflw_gf_laenge_modus" dat)) + (if (and dat (>= dat 0)) (unload_dialog dat)) + (progn + (set_tile "kopf" (vflw-clean (ssg-text "vfl-gf-laenge-modus-header"))) + (action_tile "accept" + "(setq gwahl (cond ((= (get_tile \"modus_hoehe\") \"1\") \"2\") + ((= (get_tile \"modus_steigend\") \"1\") \"3\") + (t \"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) (vflw-pending-push-all (list gwahl))) + ((= ergebnis 2) (setq *vfl-wizard-abbruch-grund* "zurueck")) + (t (setq *vfl-wizard-abbruch-grund* "abbrechen")) + ) + ) + ) (princ)) ;; ------------------------------------------------------------ @@ -800,51 +880,434 @@ (set_tile "wert" (rtos vorbelegt 2 1)) (action_tile "accept" "(setq dlg-wert (get_tile \"wert\")) (done_dialog 1)") (action_tile "cancel" "(done_dialog 0)") + (action_tile "back" "(done_dialog 2)") (setq ergebnis (start_dialog)) (unload_dialog dat) - (if (and (= ergebnis 1) dlg-wert (> (strlen dlg-wert) 0)) - (vflw-pending-push-all (list (atof dlg-wert)))))) + (cond + ((and (= ergebnis 1) dlg-wert (> (strlen dlg-wert) 0)) + (vflw-pending-push-all (list (atof dlg-wert)))) + ((= ergebnis 2) (setq *vfl-wizard-abbruch-grund* "zurueck")) + ((= ergebnis 0) (setq *vfl-wizard-abbruch-grund* "abbrechen")) + ) + ) + ) (princ)) ;; ------------------------------------------------------------ -;; Gruppe "Horizontales Stueck": Separator VOR + Separator NACH + -;; Foerderer-Ende (3 Optionen). Original-Reihenfolge/-Journal (alle in -;; vfl-baue-horizontal-koerper): vfl-in-string (Sep-vor), vfl-in-string -;; (Sep-nach), [nur im Ziel-Modus] vfl-in-string (Ist-Ende). Der Endpunkt -;; wird an der Aufrufstelle bereits separat ueber vfl-neue-linie-messen -;; gemessen - kein Punkt-Button hier (analog Gefaelle-/Ziel-Hoehe-Gruppe). -;; mit-ende: T, wenn (im Ziel-Modus) zusaetzlich die Ist-Ende-Frage -;; mitgestellt werden soll (siehe vfl-baue-horizontal-koerper). -(defun vflw-gruppe-horizontal-impl (mit-ende / dat dcl-pfad ergebnis gsepvor gsepnach gende) +;; Gruppe "Separator VOR/NACH bei GF" (Neue Linie: GF): beide Ja/Nein-Fragen +;; in einem Bildschirm. Reihenfolge/Journal: vfl-in-string (Sep-VOR), dann +;; vfl-in-string (Sep-NACH) - siehe wahl="Linie-GF" in vf-linienzug-modus. +(defun vflw-gruppe-sep-gf-impl ( / dat ergebnis gsepvor gsepnach) (setq dat (load_dialog (vflw-dcl-pfad))) - (if (not (new_dialog "vflw_horizontal" dat)) + (if (not (new_dialog "vflw_sep_gf" dat)) (if (and dat (>= dat 0)) (unload_dialog dat)) (progn - (set_tile "kopf" "Horizontales Stueck") + (set_tile "kopf" "Separator an dieser Gefaellestrecke") (set_tile "sepvor" "0") (set_tile "sepnach" "0") - (start_list "istende") - (add_list (vflw-clean (ssg-text "vfl-ja-nur-motorstation"))) - (add_list (vflw-clean (ssg-text "vfl-nein-weiterbauen"))) - (add_list (vflw-clean (ssg-text "vfl-ja-motorstation-kettenende"))) - (end_list) - (set_tile "istende" "1") - (mode_tile "istende" (if mit-ende 0 1)) (action_tile "accept" - "(setq gsepvor (get_tile \"sepvor\")) - (setq gsepnach (get_tile \"sepnach\")) - (setq gende (get_tile \"istende\")) - (done_dialog 1)") + "(setq gsepvor (get_tile \"sepvor\")) (setq gsepnach (get_tile \"sepnach\")) (done_dialog 1)") (action_tile "cancel" "(done_dialog 0)") + (action_tile "back" "(done_dialog 2)") (setq ergebnis (start_dialog)) (unload_dialog dat) - (if (= ergebnis 1) - (vflw-pending-push-all - (append - (list (if (= gsepvor "1") "1" "2") (if (= gsepnach "1") "1" "2")) - (if mit-ende (list (itoa (1+ (atoi gende)))) nil)))))) + (cond + ((= ergebnis 1) + (vflw-pending-push-all + (list (if (= gsepvor "1") "1" "2") (if (= gsepnach "1") "1" "2")))) + ((= ergebnis 2) (setq *vfl-wizard-abbruch-grund* "zurueck")) + (t (setq *vfl-wizard-abbruch-grund* "abbrechen")) + ) + ) + ) (princ)) +;; Text in maximal max-zeilen Zeilen von je hoechstens max-len Zeichen +;; umbrechen (an Wortgrenzen; bereits vorhandene "\n" bleiben als Zeilenumbruch +;; erhalten) - fuer DCL-text-Tiles, die selbst NICHT automatisch umbrechen +;; (einzeiliges Tile, laengerer Text wird sonst stillschweigend abgeschnitten - +;; siehe vflw-gruppe-ja-nein-impl). Ueberzaehlige Zeilen werden auf eine "..."- +;; Zeile gekuerzt statt verworfen, damit sichtbar bleibt, dass Text fehlt. +(defun vflw-umbruch-zeilen (text max-len max-zeilen / roh-zeilen zeilen woerter aktuelle i gekuerzt) + (setq roh-zeilen (vfl-kette-split text "\n")) + (setq zeilen '()) + (foreach roh roh-zeilen + (setq woerter (vfl-kette-split roh " ") aktuelle nil) + (foreach wort woerter + (cond + ((= wort "")) + ((null aktuelle) (setq aktuelle wort)) + ((<= (+ (strlen aktuelle) 1 (strlen wort)) max-len) + (setq aktuelle (strcat aktuelle " " wort))) + (t (setq zeilen (append zeilen (list aktuelle))) + (setq aktuelle wort)))) + (setq zeilen (append zeilen (list (if aktuelle aktuelle ""))))) + (if (> (length zeilen) max-zeilen) + (progn + (setq gekuerzt '() i 0) + (repeat (1- max-zeilen) + (setq gekuerzt (append gekuerzt (list (nth i zeilen))) i (1+ i))) + (setq zeilen (append gekuerzt (list "..."))))) + zeilen) + +;; ------------------------------------------------------------ +;; Generische Ja/Nein-Rueckfrage (2 Radio-Buttons, dynamischer Kopftext ueber +;; MEHRERE Zeilen - siehe vflw-umbruch-zeilen, ein einzelnes text-Tile schneidet +;; laengere Hinweise sonst ab) - wiederverwendet ueberall dort, wo bisher eine +;; einzelne Ja/Nein-Frage auf den generischen Dropdown (vflw_wahl) +;; zurueckgefallen waere, z.B. "trotzdem mit Mindestlaenge bauen?" +;; (Zu-kurz-Nachfrage in vfl-baue-horizontal-koerper). +(defun vflw-gruppe-ja-nein-impl (kopf-txt / dat ergebnis gwahl zeilen zeile i dlg-name max-zeilen) + ;; Zeilenzahl VOR new_dialog ermitteln - waehlt eine von drei Groessen- + ;; varianten (1/3/6 Kopf-Zeilen), damit kurze Hinweise nicht mit leeren + ;; Zeilen aufgeblaeht werden (siehe Kommentar bei den vflw_ja_nein_*- + ;; Dialogen im DCL). + (setq zeilen (vflw-umbruch-zeilen (vflw-clean kopf-txt) 70 6)) + (cond + ((<= (length zeilen) 1) (setq dlg-name "vflw_ja_nein_1" max-zeilen 1)) + ((<= (length zeilen) 3) (setq dlg-name "vflw_ja_nein_3" max-zeilen 3)) + (t (setq dlg-name "vflw_ja_nein_6" max-zeilen 6))) + (setq dat (load_dialog (vflw-dcl-pfad))) + (if (not (new_dialog dlg-name dat)) + (if (and dat (>= dat 0)) (unload_dialog dat)) + (progn + (setq i 1) + (foreach zeile zeilen + (set_tile (strcat "kopf" (itoa i)) zeile) + (setq i (1+ i))) + (while (<= i max-zeilen) (set_tile (strcat "kopf" (itoa i)) "") (setq i (1+ i))) + (set_tile "wahl_ja" "1") + (action_tile "accept" "(setq gwahl (get_tile \"wahl_nein\")) (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) + ;; Konsolen-Echo: im Wizard-Modus kommt die Antwort aus dem Dialog, + ;; nicht aus einer getippten Konsolen-Eingabe - ohne dieses Echo + ;; steht im (Debug-)Log/Konsolen-Log nirgends, was hier gewaehlt + ;; wurde (siehe Fehlerbericht 2026-09-11). + (princ (ssg-textf "vfl-wizard-antwort-echo" + (list (ssg-text (if (= gwahl "1") "vfl-antwort-nein" "vfl-antwort-ja"))))) + (vflw-pending-push-all (list (if (= gwahl "1") "2" "1")))) + ((= ergebnis 2) (setq *vfl-wizard-abbruch-grund* "zurueck")) + (t (setq *vfl-wizard-abbruch-grund* "abbrechen")) + ) + ) + ) + (princ)) + +;; Generische Auf/Ab-Richtungsfrage (2 Radio-Buttons, dynamischer Kopftext) - +;; wiederverwendet fuer Punkt 7 (Kletter-Teilstrecke ohne Zielhoehe, sowohl +;; "Naechstes im VF" als auch "Neue Linie: Ab/Auf VF" mit reduziertem +;; Eingang). +(defun vflw-gruppe-richtung-impl (kopf-txt / dat ergebnis grichtung) + (setq dat (load_dialog (vflw-dcl-pfad))) + (if (not (new_dialog "vflw_richtung" dat)) + (if (and dat (>= dat 0)) (unload_dialog dat)) + (progn + (set_tile "kopf" (vflw-clean kopf-txt)) + (set_tile "richtung_auf" "1") + (action_tile "accept" "(setq grichtung (get_tile \"richtung_ab\")) (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) (vflw-pending-push-all (list (if (= grichtung "1") "2" "1")))) + ((= ergebnis 2) (setq *vfl-wizard-abbruch-grund* "zurueck")) + (t (setq *vfl-wizard-abbruch-grund* "abbrechen")) + ) + ) + ) + (princ)) + +;; Startpunkt-Typ (kein eindeutiger GF-/VF-Baustein per KS_AUS-Scan erkannt, +;; siehe vfl-eingang-modus-bestimmen): EINE flache 3-Optionen-Frage (direkt +;; Umlenkstation / GF-Stueck+Umlenkstation / ohne Umlenkstation) statt +;; verschachtelter Zwei-Schritt-Abfrage. +(defun vflw-gruppe-startpunkt-typ-impl ( / dat ergebnis gwahl) + (setq dat (load_dialog (vflw-dcl-pfad))) + (if (not (new_dialog "vflw_startpunkt_typ" dat)) + (if (and dat (>= dat 0)) (unload_dialog dat)) + (progn + (set_tile "kopf" (vflw-clean (ssg-textf "vfl-frage-startpunkt-typ" (list (rtos *vfl-gf-min-laenge* 2 0))))) + (set_tile "eingang_direkt" "1") + (action_tile "accept" + "(setq gwahl (cond ((= (get_tile \"eingang_stumpf\") \"1\") \"2\") + ((= (get_tile \"eingang_ohne\") \"1\") \"3\") + (t \"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) (vflw-pending-push-all (list gwahl))) + ((= ergebnis 2) (setq *vfl-wizard-abbruch-grund* "zurueck")) + (t (setq *vfl-wizard-abbruch-grund* "abbrechen")) + ) + ) + ) + (princ)) + +;; "Ist das Kettenende?" (2-Optionen-Variante: Ja-Separator+ES / Nein- +;; weiterbauen) - vfl-vf-einheit-abschluss. +(defun vflw-gruppe-ist-kettenende-2opt-impl ( / dat ergebnis gwahl) + (setq dat (load_dialog (vflw-dcl-pfad))) + (if (not (new_dialog "vflw_ist_kettenende_2opt" dat)) + (if (and dat (>= dat 0)) (unload_dialog dat)) + (progn + (set_tile "kopf" (vflw-clean (ssg-text "vfl-ist-kettenende-frage"))) + (action_tile "accept" "(setq gwahl (get_tile \"wahl_ja\")) (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) (vflw-pending-push-all (list (if (= gwahl "1") "1" "2")))) + ((= ergebnis 2) (setq *vfl-wizard-abbruch-grund* "zurueck")) + (t (setq *vfl-wizard-abbruch-grund* "abbrechen")) + ) + ) + ) + (princ)) + +;; GF-Verteilung (Haelfte Einlauf+Ausgang / alles Einlauf) - kopf-txt dynamisch, +;; wiederverwendet fuer Modus 1 (vfl-vf-einheit-abschluss) UND Modus 3 +;; (Segment-Loop br-gf-mode). Die beiden Aufrufer kodieren die Antwort +;; UNTERSCHIEDLICH (Modus 1: "1"=Haelfte/"2"=Einlauf; Modus 3: "2"=Haelfte/ +;; "1"=Einlauf) - haelfte-code/einlauf-code legen das je Aufrufer fest. +(defun vflw-gruppe-gf-verteilung-impl (kopf-txt haelfte-code einlauf-code / dat ergebnis gwahl) + (setq dat (load_dialog (vflw-dcl-pfad))) + (if (not (new_dialog "vflw_gf_verteilung" dat)) + (if (and dat (>= dat 0)) (unload_dialog dat)) + (progn + (set_tile "kopf" (vflw-clean kopf-txt)) + (action_tile "accept" "(setq gwahl (get_tile \"wahl_haelfte\")) (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) (vflw-pending-push-all (list (if (= gwahl "1") haelfte-code einlauf-code)))) + ((= ergebnis 2) (setq *vfl-wizard-abbruch-grund* "zurueck")) + (t (setq *vfl-wizard-abbruch-grund* "abbrechen")) + ) + ) + ) + (princ)) + +;; "Naechstes im VF" (innerhalb einer laufenden VF-Einheit weiterbauen): +;; Horizontaler Foerderer / Vario-Kurve / Auf-Ab-Foerderer. +(defun vflw-gruppe-naechstes-im-vf-impl ( / dat ergebnis gwahl) + (setq dat (load_dialog (vflw-dcl-pfad))) + (if (not (new_dialog "vflw_naechstes_im_vf" dat)) + (if (and dat (>= dat 0)) (unload_dialog dat)) + (progn + (set_tile "kopf" (vflw-clean (ssg-text "vfl-naechstes-element-vf"))) + (action_tile "accept" + "(setq gwahl (cond ((= (get_tile \"wahl_horizontal\") \"1\") \"1\") + ((= (get_tile \"wahl_variokurve\") \"1\") \"2\") + (t \"3\"))) + (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) (vflw-pending-push-all (list gwahl))) + ((= ergebnis 2) (setq *vfl-wizard-abbruch-grund* "zurueck")) + (t (setq *vfl-wizard-abbruch-grund* "abbrechen")) + ) + ) + ) + (princ)) + +;; Feste Zuordnung Standard-Winkel -> Radio-Tile-Key, gemeinsam genutzt von +;; vflw-gruppe-winkel-hoehen-impl und vflw-gruppe-winkel-wahl-impl (beide +;; Dialoge nutzen dieselben 12 Slots w_3..w_51). +(setq *vflw-winkel-tile-keys* + '((3 . "w_3") (6 . "w_6") (9 . "w_9") (12 . "w_12") (15 . "w_15") (18 . "w_18") + (21 . "w_21") (27 . "w_27") (33 . "w_33") (39 . "w_39") (45 . "w_45") (51 . "w_51"))) + +;; Punkt-7-Winkel/Hoehen-Tabelle (vfl-waehle-winkel-hoehen-tabelle): optionen +;; = ALLE konfigurierten Winkel (winkel dH-oder-nil L_VF-oder-nil gueltig), +;; gueltige = die daraus gefilterten baubaren. Fuer JEDEN der 12 Radio-Slots +;; wird das Text-Tile daneben befuellt: baubar -> Endhoehe, nicht baubar -> +;; Grund (wie die Konsolen-Zeile) - und NUR die baubaren werden per mode_tile +;; freigeschaltet. Pusht die POSITION (1-basiert) des gewaehlten Winkels +;; INNERHALB von gueltige, identisch zu dem, was vfl-menu-int an dieser +;; Aufrufstelle sonst liefern wuerde. +(defun vflw-gruppe-winkel-hoehen-impl (optionen gueltige start-z / dat ergebnis e gwinkel + tk htk zeile idx gefunden) + (setq dat (load_dialog (vflw-dcl-pfad))) + (if (not (new_dialog "vflw_winkel_hoehen" dat)) + (if (and dat (>= dat 0)) (unload_dialog dat)) + (progn + (set_tile "kopf" (vflw-clean (ssg-text "vfl-winkel-hoehen-header"))) + (foreach e optionen + (setq tk (cdr (assoc (car e) *vflw-winkel-tile-keys*))) + (if tk + (progn + (setq htk (strcat "h_" (substr tk 3))) + (if (nth 3 e) + (progn + (set_tile htk (ssg-textf "vfl-winkel-hoehen-zeile-tile" (list (rtos (+ start-z (nth 1 e)) 2 0)))) + (mode_tile tk 0) + ) + (progn + (set_tile htk (ssg-text "vfl-winkel-zeile-tile-ungueltig")) + (mode_tile tk 1) + ) + ) + ) + ) + ) + (setq gefunden nil) + (foreach e gueltige + (setq tk (cdr (assoc (car e) *vflw-winkel-tile-keys*))) + (if (and tk (not gefunden)) (progn (set_tile tk "1") (setq gefunden t))) + ) + (action_tile "accept" + "(setq gwinkel (cond + ((= (get_tile \"w_3\") \"1\") 3) ((= (get_tile \"w_6\") \"1\") 6) + ((= (get_tile \"w_9\") \"1\") 9) ((= (get_tile \"w_12\") \"1\") 12) + ((= (get_tile \"w_15\") \"1\") 15) ((= (get_tile \"w_18\") \"1\") 18) + ((= (get_tile \"w_21\") \"1\") 21) ((= (get_tile \"w_27\") \"1\") 27) + ((= (get_tile \"w_33\") \"1\") 33) ((= (get_tile \"w_39\") \"1\") 39) + ((= (get_tile \"w_45\") \"1\") 45) (t 51))) + (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) + (setq idx 1 zeile nil) + (foreach e gueltige + (if (= (car e) gwinkel) (setq zeile idx)) + (setq idx (1+ idx))) + (if zeile (vflw-pending-push-all (list zeile)))) + ((= ergebnis 2) (setq *vfl-wizard-abbruch-grund* "zurueck")) + (t (setq *vfl-wizard-abbruch-grund* "abbrechen")) + ) + ) + ) + (princ)) + +;; Winkel-Wahl aus berechne-alle-winkel (Zielhoehe-basierter Solve): +;; ergebnis-liste = ALLE konfigurierten Winkel (winkel L_GF L_VF gueltig), +;; gueltige = die daraus gefilterten baubaren (Filter komplexer als nur der +;; gueltig-Flag - siehe vfl-waehle-winkel: zusaetzlich L_GF/L_VF > 0 - +;; deshalb hier NICHT (nth 3 e) pruefen, sondern per gueltige-winkel-Liste +;; abgleichen). Fuer JEDEN der 12 Radio-Slots wird das Text-Tile daneben +;; befuellt: baubar -> L_GF+L_VF, nicht baubar -> "nicht baubar" - und NUR +;; die baubaren werden per mode_tile freigeschaltet. Pusht die POSITION +;; (1-basiert) des gewaehlten Winkels INNERHALB von gueltige. +(defun vflw-gruppe-winkel-wahl-impl (ergebnis-liste gueltige / dat ergebnis e gwinkel idx + tk htk zeile gefunden gueltige-winkel) + (setq gueltige-winkel (mapcar 'car gueltige)) + (setq dat (load_dialog (vflw-dcl-pfad))) + (if (not (new_dialog "vflw_winkel_wahl" dat)) + (if (and dat (>= dat 0)) (unload_dialog dat)) + (progn + (set_tile "kopf" (vflw-clean (ssg-text "vfl-mehrere-winkel-header"))) + (foreach e ergebnis-liste + (setq tk (cdr (assoc (car e) *vflw-winkel-tile-keys*))) + (if tk + (progn + (setq htk (strcat "h_" (substr tk 3))) + (if (member (car e) gueltige-winkel) + (progn + (set_tile htk (ssg-textf "vfl-winkel-wahl-zeile-tile" (list (rtos (cadr e) 2 1) (rtos (caddr e) 2 1)))) + (mode_tile tk 0) + ) + (progn + (set_tile htk (ssg-text "vfl-winkel-zeile-tile-ungueltig")) + (mode_tile tk 1) + ) + ) + ) + ) + ) + (setq gefunden nil) + (foreach e gueltige + (setq tk (cdr (assoc (car e) *vflw-winkel-tile-keys*))) + (if (and tk (not gefunden)) (progn (set_tile tk "1") (setq gefunden t))) + ) + (action_tile "accept" + "(setq gwinkel (cond + ((= (get_tile \"w_3\") \"1\") 3) ((= (get_tile \"w_6\") \"1\") 6) + ((= (get_tile \"w_9\") \"1\") 9) ((= (get_tile \"w_12\") \"1\") 12) + ((= (get_tile \"w_15\") \"1\") 15) ((= (get_tile \"w_18\") \"1\") 18) + ((= (get_tile \"w_21\") \"1\") 21) ((= (get_tile \"w_27\") \"1\") 27) + ((= (get_tile \"w_33\") \"1\") 33) ((= (get_tile \"w_39\") \"1\") 39) + ((= (get_tile \"w_45\") \"1\") 45) (t 51))) + (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) + (setq idx 1 zeile nil) + (foreach e gueltige + (if (= (car e) gwinkel) (setq zeile idx)) + (setq idx (1+ idx))) + (if zeile (vflw-pending-push-all (list zeile)))) + ((= ergebnis 2) (setq *vfl-wizard-abbruch-grund* "zurueck")) + (t (setq *vfl-wizard-abbruch-grund* "abbrechen")) + ) + ) + ) + (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 +;; 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 +;; (wahl_gfbogen usw.), waehrend die Umrechnung auf die richtige Positions- +;; Nummer hier im Callback passiert (kettenanfang: 1:1: 1-6; sonst: Slot 2 +;; entfaellt, alles ab Slot 3 ruecktr um 1 nach vorn). +(defun vflw-gruppe-naechstes-element-impl (kettenanfang / 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)) + (progn + (set_tile "kopf" (vflw-clean (ssg-text "vfl-naechstes-element-header"))) + (set_tile "wahl_liniegf" "1") + (if (not kettenanfang) (mode_tile "wahl_variokurve" 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 "cancel" "(done_dialog 0)") + (action_tile "back" "(done_dialog 2)") + (setq ergebnis (start_dialog)) + (unload_dialog dat) + (cond + ((= ergebnis 1) + (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")) + (t (setq *vfl-wizard-abbruch-grund* "abbrechen")) + ) + ) + ) + (princ)) + +;; ------------------------------------------------------------ ;; ============================================================ ;; TEIL 0b-4b: SEGMENT-GRUPPEN-DIALOGE (Modus 2 + Modus 3) ;; ============================================================ @@ -876,30 +1339,34 @@ ;; Original-Reihenfolge/-Journal im Loop: vfl-menu (Typ), dann bei GF ;; vfl-in-real (Neigung). Bei VF wird KEIN Neigungswert gefragt -> nur "2" ;; in die Pending-Queue. neigung-default: Vorbelegung Neigungsfeld (Grad). -(defun vflw-seg-linie-m2-impl (kopf-txt neigung-default / dat ergebnis gtyp gwert) +(defun vflw-seg-linie-m2-impl (kopf-txt neigung-default / dat ergebnis gtyp gwert gsepvor gsepnach) (setq dat (load_dialog (vflw-dcl-pfad))) (if (not (new_dialog "vflw_seg_linie_m2" dat)) (if (and dat (>= dat 0)) (unload_dialog dat)) (progn (set_tile "kopf" (vflw-clean kopf-txt)) - (start_list "typ") - (add_list (vflw-clean "GF (Neigungswinkel)")) - (add_list (vflw-clean "VF (Bruecke)")) - (end_list) - (set_tile "typ" "0") + (set_tile "typ_gf" "1") (set_tile "wert" (rtos (float neigung-default) 2 1)) - ;; Neigungsfeld nur bei GF (Index 0) aktiv. - (action_tile "typ" - "(mode_tile \"wert\" (if (= (get_tile \"typ\") \"0\") 0 1))") + ;; Neigungsfeld + Separator-Toggles nur bei GF aktiv. + (action_tile "typ_gf" + "(mode_tile \"wert\" 0) (mode_tile \"sep_vor\" 0) (mode_tile \"sep_nach\" 0)") + (action_tile "typ_vf" + "(mode_tile \"wert\" 1) (mode_tile \"sep_vor\" 1) (mode_tile \"sep_nach\" 1)") (action_tile "accept" - "(setq gtyp (get_tile \"typ\")) (setq gwert (get_tile \"wert\")) (done_dialog 1)") + "(setq gtyp (if (= (get_tile \"typ_gf\") \"1\") \"0\" \"1\")) + (setq gwert (get_tile \"wert\")) + (setq gsepvor (get_tile \"sep_vor\")) + (setq gsepnach (get_tile \"sep_nach\")) + (done_dialog 1)") (action_tile "cancel" "(done_dialog 0)") (setq ergebnis (start_dialog)) (unload_dialog dat) (if (= ergebnis 1) (if (= gtyp "0") - (vflw-pending-push-all (list "1" (atof gwert))) ; GF + Neigung - (vflw-pending-push-all (list "2")))))) ; VF (keine Neigung) + ;; GF + Neigung + Separator VOR/NACH (Ja/Nein je "1"/"0") + (vflw-pending-push-all + (list "1" (atof gwert) (if (= gsepvor "1") "1" "2") (if (= gsepnach "1") "1" "2"))) + (vflw-pending-push-all (list "2")))))) ; VF (keine Neigung/Separator) (princ)) ;; --- Modus 3, Segment "Gerade": Typ (GF/VF-Ab/VF-Auf/VF-Hor) + Wert --- @@ -913,33 +1380,33 @@ (if (and dat (>= dat 0)) (unload_dialog dat)) (progn (set_tile "kopf" (vflw-clean kopf-txt)) - (start_list "typ") - (add_list (vflw-clean "GF (Neigungswinkel)")) - (add_list (vflw-clean "VF-Ab")) - (add_list (vflw-clean "VF-Auf")) - (add_list (vflw-clean "VF-Horizontal")) - (end_list) - (set_tile "typ" "0") + (set_tile "typ_gf" "1") (set_tile "wlabel" "GF-Neigung (Grad):") (set_tile "wert" (rtos (float neigung-default) 2 1)) ;; Feld/Beschriftung schaltet mit dem Typ um: GF->Neigung, VF-Ab/Auf-> ;; Vario-Winkel, VF-Hor->deaktiviert. Werte-Defaults liegen als lokale ;; Variablen vor und werden im Callback (dynamic scope) gelesen. - (action_tile "typ" - "(cond - ((= (get_tile \"typ\") \"0\") - (set_tile \"wlabel\" \"GF-Neigung (Grad):\") - (set_tile \"wert\" (rtos (float neigung-default) 2 1)) - (mode_tile \"wert\" 0)) - ((= (get_tile \"typ\") \"3\") - (set_tile \"wlabel\" \"(kein Wert)\") - (mode_tile \"wert\" 1)) - (t - (set_tile \"wlabel\" \"Vario-Winkel (Grad):\") - (set_tile \"wert\" (rtos (float vario-default) 2 1)) - (mode_tile \"wert\" 0)))") + (action_tile "typ_gf" + "(set_tile \"wlabel\" \"GF-Neigung (Grad):\") + (set_tile \"wert\" (rtos (float neigung-default) 2 1)) + (mode_tile \"wert\" 0)") + (action_tile "typ_vfab" + "(set_tile \"wlabel\" \"Vario-Winkel (Grad):\") + (set_tile \"wert\" (rtos (float vario-default) 2 1)) + (mode_tile \"wert\" 0)") + (action_tile "typ_vfauf" + "(set_tile \"wlabel\" \"Vario-Winkel (Grad):\") + (set_tile \"wert\" (rtos (float vario-default) 2 1)) + (mode_tile \"wert\" 0)") + (action_tile "typ_vfhor" + "(set_tile \"wlabel\" \"(kein Wert)\") + (mode_tile \"wert\" 1)") (action_tile "accept" - "(setq gtyp (get_tile \"typ\")) (setq gwert (get_tile \"wert\")) (done_dialog 1)") + "(setq gtyp (cond ((= (get_tile \"typ_gf\") \"1\") \"0\") + ((= (get_tile \"typ_vfab\") \"1\") \"1\") + ((= (get_tile \"typ_vfauf\") \"1\") \"2\") + (t \"3\"))) + (setq gwert (get_tile \"wert\")) (done_dialog 1)") (action_tile "cancel" "(done_dialog 0)") (setq ergebnis (start_dialog)) (unload_dialog dat) @@ -964,29 +1431,43 @@ ;; Variante-Antwort nicht und sie wuerde ins naechste Segment lecken). Bei ;; nil wird die Vario-Kurve-Option deaktiviert und bei versehentlicher Wahl ;; als GF-Bogen ("1") behandelt (der Aufrufer weist Vario dort ohnehin ab). +;; Dritter Zustand 'ERZWUNGEN (Modus 2: Bogen folgt direkt auf eine als VF +;; klassifizierte Gerade - die VF-Einheit MUSS mit einer Vario-Kurve +;; weitergehen, siehe nach-vf in vf-linienzug-modus2): GF-Bogen-Option +;; deaktiviert, Vario-Kurve vorbelegt+aktiv, nur noch Aussen/Innen waehlbar. (defun vflw-seg-bogen-impl (kopf-txt vario-erlaubt / dat ergebnis gtyp gvariante) (setq dat (load_dialog (vflw-dcl-pfad))) (if (not (new_dialog "vflw_seg_bogen" dat)) (if (and dat (>= dat 0)) (unload_dialog dat)) (progn (set_tile "kopf" (vflw-clean kopf-txt)) - (start_list "typ") - (add_list (vflw-clean "GF-Bogen")) - (add_list (vflw-clean (if vario-erlaubt "Vario-Kurve" "Vario-Kurve (nur im VF-Lauf)"))) - (end_list) - (set_tile "typ" "0") - (start_list "variante") - (add_list (vflw-clean (ssg-text "vfl-variante-aussen"))) - (add_list (vflw-clean (ssg-text "vfl-variante-innen"))) - (end_list) - (set_tile "variante" "0") - (mode_tile "variante" 1) ; Variante erst bei Vario-Kurve aktiv - ;; Variante-Feld nur aktivieren, wenn Vario gewaehlt UND erlaubt. - (if vario-erlaubt - (action_tile "typ" - "(mode_tile \"variante\" (if (= (get_tile \"typ\") \"1\") 0 1))")) + (if (eq vario-erlaubt 'ERZWUNGEN) + (progn + (set_tile "typ_vario" "1") + (mode_tile "typ_gfbogen" 1) ; GF-Bogen gesperrt - Vario ist Pflicht + (mode_tile "variante_aussen" 0) ; Variante sofort aktiv + (mode_tile "variante_innen" 0)) + (progn + (set_tile "typ_gfbogen" "1") + (set_tile "variante_aussen" "1") + (mode_tile "variante_aussen" 1) ; Variante erst bei Vario-Kurve aktiv + (mode_tile "variante_innen" 1) + ;; Vario-Kurve-Option selbst nur anklickbar, wenn erlaubt (Modus 3 + ;; ausserhalb eines offenen VF-Laufs: deaktiviert - ihr Label kann + ;; hier NICHT auf "(nur im VF-Lauf)" umbeschriftet werden, radio_button- + ;; Labels sind fest, siehe DCL-Kommentar). + (if (not vario-erlaubt) (mode_tile "typ_vario" 1)) + ;; Variante-Feld nur aktivieren, wenn Vario gewaehlt UND erlaubt. + (if vario-erlaubt + (progn + (action_tile "typ_gfbogen" + "(mode_tile \"variante_aussen\" 1) (mode_tile \"variante_innen\" 1)") + (action_tile "typ_vario" + "(mode_tile \"variante_aussen\" 0) (mode_tile \"variante_innen\" 0)"))))) (action_tile "accept" - "(setq gtyp (get_tile \"typ\")) (setq gvariante (get_tile \"variante\")) (done_dialog 1)") + "(setq gtyp (if (= (get_tile \"typ_vario\") \"1\") \"1\" \"0\")) + (setq gvariante (if (= (get_tile \"variante_innen\") \"1\") \"1\" \"0\")) + (done_dialog 1)") (action_tile "cancel" "(done_dialog 0)") (setq ergebnis (start_dialog)) (unload_dialog dat) @@ -998,6 +1479,50 @@ (vflw-pending-push-all (list "1")))))) (princ)) +;; --- Modus 2: Lauf-Abschluss (NUR wenn der VF-Lauf das Pfadende ist) --- +;; "1"=ohne Motorstation (offenes Ende) / "2"=Motorstation setzen (kein ES) / +;; "3"=Motorstation + ES-Element (Kettenende). Plain ok_cancel wie alle +;; anderen Modus-2-Segment-Dialoge - kein Zurueck/Abbrechen-Mechanismus. +(defun vflw-m2-lauf-abschluss-impl (kopf-txt / dat ergebnis gwahl) + (setq dat (load_dialog (vflw-dcl-pfad))) + (if (not (new_dialog "vflw_m2_lauf_abschluss" dat)) + (if (and dat (>= dat 0)) (unload_dialog dat)) + (progn + (set_tile "kopf" (vflw-clean kopf-txt)) + (set_tile "abschluss_motor" "1") + (action_tile "accept" + "(setq gwahl (cond ((= (get_tile \"abschluss_offen\") \"1\") \"1\") + ((= (get_tile \"abschluss_motor_es\") \"1\") \"3\") + (t \"2\"))) + (done_dialog 1)") + (action_tile "cancel" "(done_dialog 0)") + (setq ergebnis (start_dialog)) + (unload_dialog dat) + (if (= ergebnis 1) (vflw-pending-push-all (list gwahl))))) + (princ)) + +;; --- Modus 2: Lauf-Anfang (NUR wenn der VF-Lauf der Pfadanfang ist) --- +;; "1"=ohne Umlenkstation (offener Anfang) / "2"=Umlenkstation direkt (kein +;; GF1/Separator) / "3"=Umlenkstation mit GF1+Separator (heutiges Standard- +;; verhalten). Plain ok_cancel, analog vflw-m2-lauf-abschluss-impl. +(defun vflw-m2-lauf-anfang-impl (kopf-txt / dat ergebnis gwahl) + (setq dat (load_dialog (vflw-dcl-pfad))) + (if (not (new_dialog "vflw_m2_lauf_anfang" dat)) + (if (and dat (>= dat 0)) (unload_dialog dat)) + (progn + (set_tile "kopf" (vflw-clean kopf-txt)) + (set_tile "anfang_umlenk_gf1" "1") + (action_tile "accept" + "(setq gwahl (cond ((= (get_tile \"anfang_offen\") \"1\") \"1\") + ((= (get_tile \"anfang_umlenk\") \"1\") \"2\") + (t \"3\"))) + (done_dialog 1)") + (action_tile "cancel" "(done_dialog 0)") + (setq ergebnis (start_dialog)) + (unload_dialog dat) + (if (= ergebnis 1) (vflw-pending-push-all (list gwahl))))) + (princ)) + ;; ============================================================ ;; TEIL 0b-3: GRUPPEN-DIALOGE (PENDING-QUEUE) ;; ============================================================ @@ -1176,6 +1701,16 @@ ;; Gueltigkeit strenger geprueft werden muss (z.B. vfl-in-string: "" ist ein ;; gueltiger String), siehe vfl-in-value-p. (defun vfl-in-value (kind livefn / popped v) + ;; Zentraler Abbruch-Trigger fuer den "Zurueck"/"Abbrechen"-Button (siehe + ;; vfl-modus-abbruch-sichern): EIN Check hier deckt vfl-in-point/-string/ + ;; -real/-int/vfl-menu/-menu-int komplett ab, statt jede Aufrufstelle im + ;; Bau-Ablauf einzeln pruefen zu muessen. Laeuft AUSSERHALB von vl-catch- + ;; all-apply (das umschliesst nur den vorgelagerten Gruppen-Dialog-Aufruf), + ;; (exit) erreicht also zuverlaessig den scharf geschalteten *error*-Handler. + (if *vfl-wizard-abbruch-grund* + (progn + (dbgmsg (strcat "ABBRUCH-TRIGGER: *vfl-wizard-abbruch-grund*=" *vfl-wizard-abbruch-grund* " -> (exit)")) + (exit))) (setq popped (if *vfl-replay-queue* (vfl-replay-pop) nil)) (if popped (setq v (car popped)) @@ -1187,6 +1722,11 @@ ;; Variante mit explizitem Gueltig-Praedikat (fuer vfl-in-string: "" ist gueltig). (defun vfl-in-value-p (kind gueltig-p livefn / popped v) + ;; Siehe Kommentar in vfl-in-value - derselbe zentrale Abbruch-Trigger. + (if *vfl-wizard-abbruch-grund* + (progn + (dbgmsg (strcat "ABBRUCH-TRIGGER: *vfl-wizard-abbruch-grund*=" *vfl-wizard-abbruch-grund* " -> (exit)")) + (exit))) (setq popped (if *vfl-replay-queue* (vfl-replay-pop) nil)) (if popped (setq v (car popped)) @@ -1433,12 +1973,22 @@ ;; vf-linienzug-modus. (defun vfl-modus-abbruch-sichern (lastEnt vfl-nummer anzahl-gf anzahl-vf startpunkt frame as-seite es-seite marker / - e cnt vfl-ins wickel-erg) + e cnt vfl-ins wickel-erg grund fwd n trunc) + ;; Abbruch-Grund VOR dem Wickeln merken (das Flag wird unten evtl. schon + ;; fuer den "Zurueck"-Neuaufruf zurueckgesetzt) UND immer konsumieren, damit + ;; kein "Zurueck"/"Abbrechen" aus diesem Lauf in einen etwaigen naechsten + ;; durchsickert (siehe auch Reset am Kopf von vf-linienzug-modus). + (setq grund *vfl-wizard-abbruch-grund*) + (setq *vfl-wizard-abbruch-grund* nil) + (dbgmsg (strcat "ABBRUCH-SICHERN erreicht: grund=" (if grund grund "nil(ESC/Fehler)"))) (setq cnt 0 e (if lastEnt (entnext lastEnt) (entnext))) (while e (setq cnt (1+ cnt)) (setq e (entnext e))) (cond ((or (= cnt 0) (null frame)) - (princ (ssg-text "vfl-abbruch-nichts-gebaut"))) + (princ (ssg-text "vfl-abbruch-nichts-gebaut")) + ;; "Zurueck" ohne jede gebaute Geometrie (z.B. ganz am Anfang) - nichts + ;; zu verwerfen, einfach denselben Lauf frisch neu starten. + (if (= grund "zurueck") (vl-catch-all-apply 'vf-linienzug-modus))) (t ;; vfl-block-erstellen nutzt intern (command "_.UCS" ...) fuer den ;; BKS-Wechsel (ssg-block-wrap-welt) - im *error*-Handler-Kontext @@ -1456,7 +2006,24 @@ (if (vl-catch-all-error-p wickel-erg) (princ (ssg-textf "vfl-abbruch-wickeln-fehler" (list (vl-catch-all-error-message wickel-erg)))) - (princ (ssg-textf "vfl-abbruch-gesichert" (list (itoa cnt))))) + (progn + (princ (ssg-textf "vfl-abbruch-gesichert" (list (itoa cnt)))) + (setq *vfl-abbruch-letztes-ent* vfl-ins) + ;; "Zurueck": letztes (angefangenes) Glied verwerfen und automatisch + ;; genau das tun, was der Sektions-Reset-Zweig von vfl-edit-ent sonst + ;; ueber den Auswahl-Dialog macht - nur ohne den Dialog, Ziel-Sektion + ;; ist immer "ein Glied weniger als jetzt vorhanden". + (if (and (= grund "zurueck") vfl-ins) + (progn + (setq fwd (reverse *vfl-journal*)) + (setq n (length (vfl-journal-glieder fwd))) + (setq trunc (vfl-journal-truncate fwd (max 0 (1- n)))) + (princ (ssg-text "vfl-zurueck-glied-verworfen")) + (entdel vfl-ins) + (vfl-journal-replay-start trunc) + (vl-catch-all-apply 'vf-linienzug-modus))) + ) + ) ) ) (princ)) @@ -1543,6 +2110,95 @@ ;; TEIL 1: SEGMENT-ENTSCHEIDUNG (GF oder VF) ;; ============================================================ +;; Punkt 7: Kletter-Teilstrecke OHNE Zielhoehe (kommt die Kette bereits flach +;; an, gibt es keinen sinnvollen Zielpunkt zum Anpeilen). Fuer jeden +;; konfigurierten Bogenwinkel wird L_VF direkt aus deltaL geloest (reiner +;; VF-Koerper, kein GF-Anteil) und die daraus folgende Hoehenaenderung +;; mitberechnet. Rotationskonvention 1:1 aus vfs-vf-koerper/berechne-alle- +;; winkel uebernommen (Eintritt immer @3 Grad, Austritt @(3-w) Auf / @(w+3) +;; Ab) - hier OHNE Uebergangs-Kompensation fuer "schon-flach", weil deltaL an +;; dieser Aufrufstelle bereits NACH einer evtl. noetigen vfl-nach-3grad- +;; Wandlung gemessen wird (die Kette steht zu diesem Zeitpunkt also schon auf +;; der 3-Grad-Basis). WICHTIG: "ungueltig" bedeutet hier NICHT wie bei +;; berechne-alle-winkel "trifft die vorgegebene Zielhoehe nicht" (es gibt hier +;; gar keine Zielhoehe - die Hoehe folgt erst aus dem gewaehlten Winkel!), +;; sondern reinen Platzbedarf: der Bogen-Fussabdruck (waechst mit dem Winkel) +;; allein passt schon nicht in die gewaehlte Strecke deltaL, es bliebe kein +;; oder ein negatives L_VF fuer die Geradstrecke uebrig. Rueckgabe: Liste von +;; (winkel deltaH-oder-nil L_VF-oder-nil gueltig), aufsteigend nach winkel, +;; EIN Eintrag pro konfiguriertem Winkel (auch ungueltige, fuer die +;; Diagnose-Tabelle in vfl-waehle-winkel-hoehen-tabelle). +(defun vfl-winkel-hoehen-optionen (deltaL richtung / winkel-list rad3 w + mass1 mass2 r2 winkel-eff radEff + bx1 bz1 bx2 bz2 L_VF dH gueltig ergebnisse) + (setq winkel-list (ssg-cfg-or "vario" "bogen_winkel" + '(3 6 9 12 15 18 21 27 33 39 45 51))) + (setq rad3 (* *vfk-gefaelle-winkel* (/ pi 180.0))) + (setq ergebnisse '()) + (foreach w winkel-list + (if (= richtung "Auf") + (setq mass1 (get-bogen-mass bogen-auf w) mass2 (get-bogen-mass bogen-ab w) + r2 (* (float (- *vfk-gefaelle-winkel* w)) (/ pi 180.0)) + winkel-eff (- w *vfk-gefaelle-winkel*)) + (setq mass1 (get-bogen-mass bogen-ab w) mass2 (get-bogen-mass bogen-auf w) + r2 (* (float (+ w *vfk-gefaelle-winkel*)) (/ pi 180.0)) + winkel-eff (+ w *vfk-gefaelle-winkel*))) + (setq dH nil L_VF nil gueltig nil) + (if (and mass1 mass2) + (progn + (setq bx1 (+ (* (car mass1) (cos rad3)) (* (caddr mass1) (sin rad3)))) + (setq bz1 (+ (* (- (car mass1)) (sin rad3)) (* (caddr mass1) (cos rad3)))) + (setq bx2 (+ (* (car mass2) (cos r2)) (* (caddr mass2) (sin r2)))) + (setq bz2 (+ (* (- (car mass2)) (sin r2)) (* (caddr mass2) (cos r2)))) + (setq radEff (* (float winkel-eff) (/ pi 180.0))) + (setq L_VF (/ (- deltaL bx1 bx2) (cos radEff))) + (if (> L_VF *vfk-restlaenge-min-clamp*) + (progn + (setq dH (+ bz1 bz2 (* L_VF (sin radEff)))) + (setq gueltig t) + ) + ) + ) + ) + (setq ergebnisse (append ergebnisse (list (list w dH L_VF gueltig)))) + ) + ergebnisse) + +;; UI zu vfl-winkel-hoehen-optionen: ALLE konfigurierten Winkel als Tabelle +;; zeigen (gueltige mit resultierender Endhoehe, ungueltige mit Hinweis +;; "Bogen passt nicht in die gewaehlte Strecke" - analog zur GUELTIG/ +;; UNGUELTIG-Diagnose von berechne-alle-winkel), dann aus den GUELTIGEN +;; waehlen lassen. start-z = aktuelle Z-Koordinate (fuer die Anzeige der +;; absoluten Ende-Hoehe). Rueckgabe: (winkel dH L_VF gueltig) oder nil, wenn +;; kein einziger Winkel bei dieser Streckenlaenge baubar ist. +(defun vfl-waehle-winkel-hoehen-tabelle (deltaL richtung start-z / + optionen gueltige idx labels e antwort) + (setq optionen (vfl-winkel-hoehen-optionen deltaL richtung)) + (princ (ssg-text "vfl-winkel-hoehen-header")) + (foreach e optionen + (if (nth 3 e) + (princ (ssg-textf "vfl-winkel-hoehen-zeile" (list (car e) (rtos (+ start-z (nth 1 e)) 2 0)))) + (princ (ssg-textf "vfl-winkel-hoehen-zeile-ungueltig" (list (car e)))) + ) + ) + (setq gueltige (vl-remove-if-not (function (lambda (e) (nth 3 e))) optionen)) + (cond + ((null gueltige) nil) + ((= (length gueltige) 1) (car gueltige)) + (t + (setq idx 1 labels '()) + (foreach e gueltige + (setq labels (append labels + (list (ssg-textf "vfl-winkel-hoehen-option" + (list idx (car e) (rtos (+ start-z (nth 1 e)) 2 0)))))) + (setq idx (1+ idx))) + (if (vfl-wizard-aktiv) + (vl-catch-all-apply 'vflw-gruppe-winkel-hoehen-impl (list optionen gueltige start-z))) + (setq antwort (vfl-menu-int (ssg-textf "vfl-prompt-wahl-bis-n" (list (length gueltige))) + labels 1 "vfl-winkel-hoehen-header")) + (if (or (null antwort) (< antwort 1) (> antwort (length gueltige))) (setq antwort 1)) + (nth (1- antwort) gueltige)))) + ;; Aus der Ergebnisliste von berechne-alle-winkel die GUELTIGEN Winkel filtern ;; und - bei mehreren - den Nutzer waehlen lassen. Rueckgabe: (winkel L_GF L_VF) ;; oder nil, wenn kein gueltiger Winkel existiert. @@ -1565,80 +2221,34 @@ (setq labels (append labels (list (ssg-textf "vfl-winkel-option" (list idx (car e) (rtos (cadr e) 2 1) (rtos (caddr e) 2 1)))))) (setq idx (1+ idx))) + (if (vfl-wizard-aktiv) + (vl-catch-all-apply 'vflw-gruppe-winkel-wahl-impl (list ergebnis-liste gueltige))) (setq antwort (vfl-menu-int (ssg-textf "vfl-prompt-wahl-bis-n" (list (length gueltige))) labels 1 "vfl-mehrere-winkel-header")) (if (or (null antwort) (< antwort 1) (> antwort (length gueltige))) (setq antwort 1)) (setq e (nth (1- antwort) gueltige)) (list (nth 0 e) (nth 1 e) (nth 2 e))))) -;; berechne-alle-winkel ausfuehren (mit Linienzug-FESTE_HORIZONTAL = 1300) und -;; den Winkel waehlen lassen. Rueckgabe: (winkel L_GF L_VF) oder nil. -;; aus-dx/aus-dz temporaer nullen: an jeder Aufrufstelle (ueber vfl-vf- -;; entscheidung) ist ein evtl. vorhandenes AS-Element bereits real eingefuegt -;; und deltaL bereits aus dessen echtem KS_AUS neu berechnet (vfl-projiziere- -;; distanz) - der Platzbedarf ist also schon "verbraucht" und darf nicht -;; nochmal in berechne-alle-winkel abgezogen werden (sonst fehlt am Ende -;; systematisch genau dieser Betrag, aus-dx typischerweise mehrere hundert mm). -;; ein-dx/ein-dz bleiben unangetastet: das ES-Element ist an dieser Stelle noch -;; nicht gebaut (folgt erst nach der "Kettenende?"-Frage) - konsistent mit -;; vfl-body-zerlegung, die ebenfalls nur aus-dx/aus-dz nullt. -(defun vfl-vf-winkel (deltaL deltaH richtung / save-ausdx save-ausdz res) - (setq save-ausdx aus-dx save-ausdz aus-dz) - (setq aus-dx 0.0 aus-dz 0.0) - (setq res - (vfl-waehle-winkel - (nth 3 (berechne-alle-winkel deltaL deltaH richtung *vfl-feste-horizontal*)))) - (setq aus-dx save-ausdx aus-dz save-ausdz) - res) - ;; Rueckgabe: (typ winkel L_GF L_VF) - erzwingt IMMER eine VF-Einheit (nie GF), ;; genutzt sowohl von vfl-segment-entscheidung (automatische Zweig-Auswahl) als ;; auch direkt vom expliziten "Ab/Auf VF"-Menuepunkt in Modus 1 (vf-linienzug-modus). ;; typ="VF": winkel = best-winkel (0 = Horizontale Mitte), L_GF/L_VF wie ;; berechne-alle-winkel bzw. berechne-horizontale-mitte ;; typ=nil : keine VF-Einheit fuer dieses deltaL/deltaH geometrisch moeglich -(defun vfl-vf-entscheidung (deltaL deltaH richtung / - winkel-natuerlich wahl horizontal-info) - (if (or (not *lib-initialized*) (null bogen-auf)) (init-bibliothek)) - (cond - ;; Zu kurz fuer eine VF-Einheit: Umlenkstation (500 mm) + Motorstation - ;; (500 mm) belegen zusammen 1000 mm deltaL. - ((< deltaL *vfk-vf-mindestlaenge*) (list nil nil nil nil)) - - ;; Segment ohne messbare Hoehenaenderung: kein sinnvolles VF - ((< deltaH 1.0) (list nil nil nil nil)) - - ;; Steigend: bei mehreren gueltigen Winkeln waehlt der Nutzer (vfl-vf-winkel). - ((= richtung "Auf") - (setq wahl (vfl-vf-winkel deltaL deltaH "Auf")) - (if wahl - (list "VF" (nth 0 wahl) (nth 1 wahl) (nth 2 wahl)) - (list nil nil nil nil))) - - ;; Fallend: natuerlichen Neigungswinkel bestimmen (atan der Schraege). - ;; steiler als 3 Grad -> absteigender VarioFoerderer (VF-ab) - ;; sonst -> VF (Horizontale Mitte oder diskreter Winkel) - (t - (setq winkel-natuerlich (* (atan (/ deltaH deltaL)) (/ 180.0 pi))) - (if (> winkel-natuerlich *vfk-gefaelle-winkel*) - (progn - (setq wahl (vfl-vf-winkel deltaL deltaH "Ab")) - (if wahl - (list "VF" (nth 0 wahl) (nth 1 wahl) (nth 2 wahl)) - (list nil nil nil nil))) - (progn - (setq horizontal-info (berechne-horizontale-mitte deltaL deltaH "Ab")) - (if (and horizontal-info (caddr horizontal-info)) - (list "VF" 0 (car horizontal-info) (cadr horizontal-info)) - (progn - (setq wahl (vfl-vf-winkel deltaL deltaH "Ab")) - (if wahl - (list "VF" (nth 0 wahl) (nth 1 wahl) (nth 2 wahl)) - (list nil nil nil nil))))) - ) - ) - ) -) +;; Duenner Wrapper um die mit vfl-body-zerlegung geteilte Stufe-1/Stufe-2- +;; Entscheidung (vfl-winkel-stufe-entscheidung) - eigene Mindestlaenge +;; (*vfk-vf-mindestlaenge*=1000, Umlenkstation+Motorstation), Budget +;; *vfl-feste-horizontal*=1300 (Umlenkstation+Separator+Motorstation, 1 +;; Separator/Einlaufseite - der Eingang dieser FRISCHEN VF-Einheit ist hier +;; noch nicht gebaut, im Gegensatz zum Kettenende-Fall). schon-flach immer +;; nil: der Frame kommt hier immer frisch von der Umlenkstation bei 3 Grad. +;; deltaH<1.0 wird NICHT mehr sofort abgelehnt (das war die alte Luecke - +;; vfl-winkel-stufe-entscheidung versucht dafuer jetzt auch Stufe 2 rein +;; horizontal, wie beim Kettenende-Fall). +(defun vfl-vf-entscheidung (deltaL deltaH richtung) + (if (< deltaL *vfk-vf-mindestlaenge*) + (list nil nil nil nil) + (vfl-winkel-stufe-entscheidung deltaL deltaH richtung nil *vfl-feste-horizontal*))) ;; Stumme Variante von berechne-alle-winkel: NUR die Machbarkeits-Pruefung ;; (mind. ein Winkel mit L_GF>=0 und L_VF>=0), OHNE die Diagnosetabelle auf @@ -1709,8 +2319,9 @@ ;; T, wenn fuer deltaL/deltaH/richtung MINDESTENS ein gueltiger Winkel bzw. ;; die horizontale Mitte existiert - sonst nil. Nutzt dieselbe Fallunter- ;; scheidung wie vfl-vf-entscheidung, aber ohne Nutzer-Interaktion (fuer die -;; Sondierung in vfl-vf-min-deltah). aus-dx/aus-dz werden wie in vfl-vf-winkel -;; temporaer genullt (AS-Footprint an dieser Stelle bereits verbraucht) - +;; Sondierung in vfl-vf-min-deltah). aus-dx/aus-dz werden (wie in +;; vfl-winkel-stufe-entscheidung) temporaer genullt (AS-Footprint an dieser +;; Stelle bereits verbraucht) - ;; sonst wuerde die Sondierung ein zu kleines Budget sehen und einen ;; eigentlich baubaren Wert faelschlich als "nicht baubar" verwerfen. (defun vfl-vf-machbar-p (deltaL deltaH richtung / horizontal-info save-ausdx save-ausdz ergebnis) @@ -1725,7 +2336,7 @@ (setq aus-dx save-ausdx aus-dz save-ausdz) ergebnis) (t - (setq horizontal-info (berechne-horizontale-mitte deltaL deltaH "Ab")) + (setq horizontal-info (berechne-horizontale-mitte deltaL deltaH "Ab" nil)) (if (and horizontal-info (caddr horizontal-info)) t (progn @@ -1815,12 +2426,12 @@ (cond ((< deltaL *vfk-kettenende-mindestlaenge*) nil) ((< deltaH 1.0) - (setq horizontal-info (berechne-horizontale-mitte deltaL deltaH "Ab")) + (setq horizontal-info (berechne-horizontale-mitte deltaL deltaH "Ab" nil)) (and horizontal-info (caddr horizontal-info) t)) ((= richtung "Auf") (vfl-winkel-machbar-p deltaL deltaH "Auf" *vfk-feste-horizontal-kettenende*)) (t - (setq horizontal-info (berechne-horizontale-mitte deltaL deltaH "Ab")) + (setq horizontal-info (berechne-horizontale-mitte deltaL deltaH "Ab" nil)) (if (and horizontal-info (caddr horizontal-info)) t (vfl-winkel-machbar-p deltaL deltaH "Ab" *vfk-feste-horizontal-kettenende*))) @@ -1874,20 +2485,27 @@ (list nil nil nil nil) (list "GF" *vfk-gefaelle-winkel* nil nil))) - ;; Segment ohne messbare Hoehenaenderung: weder Gefaelle noch sinnvolles VF - ((< deltaH 1.0) (list nil nil nil nil)) - ;; Steigend: Gefaelle kann nicht steigen -> nur VF moeglich. ((= richtung "Auf") (vfl-vf-entscheidung deltaL deltaH richtung)) ;; Fallend: natuerlichen Neigungswinkel bestimmen (atan der Schraege). ;; Eine reine Gefaellestrecke ist nie steiler als 3 Grad, daher: - ;; ~3 Grad (Toleranzband) -> reine GF (fest 3 Grad) + ;; ~3 Grad (Toleranzband) -> reine GF, am NATUERLICHEN Winkel gebaut ;; sonst -> VF (vfl-vf-entscheidung) + ;; WICHTIG: winkel-natuerlich (nicht der feste *vfk-gefaelle-winkel*) wird + ;; zurueckgegeben - vfl-insert-gf-segment (der tatsaechliche Bauaufruf, + ;; siehe Aufrufer) baut GENAU bei diesem Winkel ueber die volle deltaL, + ;; trifft deltaH damit per Definition exakt. Der feste 3-Grad-Wert wuerde + ;; hier - anders als beim Kettenende-Abschluss (vfl-winkel-stufe- + ;; entscheidung/vfl-body-abschluss, wo GF2 ohnehin IMMER fest bei 3 Grad + ;; gebaut wird und ein abweichender Rueckgabewinkel wirkungslos waere) - + ;; einen echten Hoehenfehler erzeugen, sobald der natuerliche Winkel nur + ;; NAHE (Toleranz *vfl-gf-winkel-toleranz*=0.5 Grad), aber nicht EXAKT 3 + ;; Grad ist. (t (setq winkel-natuerlich (* (atan (/ deltaH deltaL)) (/ 180.0 pi))) (if (<= (abs (- winkel-natuerlich *vfk-gefaelle-winkel*)) *vfl-gf-winkel-toleranz*) - (list "GF" *vfk-gefaelle-winkel* nil nil) + (list "GF" winkel-natuerlich nil nil) (vfl-vf-entscheidung deltaL deltaH richtung)) ) ) @@ -2024,6 +2642,20 @@ (vfl-journal-record "REAL" hz-aktuell)) (if deltaL (cons deltaL hz-aktuell) nil)) +;; NUR die Fahrtrichtung picken (kein deltaL) - fuer "Linie-GF"/Zweig B +;; ("Zielhoehe zuerst festlegen") am ECHTEN Kettenanfang, wo noch kein +;; Vorgaenger-Frame existiert, aus dem die Richtung uebernommen werden +;; koennte. Der Klick-ABSTAND wird bewusst ignoriert (die Laenge kommt dort +;; aus Zielhoehe+Winkel, nicht aus dem Klick) - nur die gesnappte Richtung +;; wird verwendet. Laeuft ueber vfl-in-value (wie alle anderen vfl-in-*- +;; Wrapper): Replay/Pending-Queue/Abbruch-Trigger/Journal (als "REAL") +;; funktionieren dadurch automatisch mit. +(defun vfl-in-richtung (p-akt prompt) + (vfl-in-value "REAL" + (function (lambda ( / p2) + (setq p2 (vfl-getpoint p-akt prompt)) + (if p2 (vfl-hz-snappen-absolut (vfl-planar-hz p-akt p2)) nil))))) + ;; Rueckgabe: (deltaL hz) oder nil bei Abbruch. Foerderer-Maximallaenge 25 m: ;; bei Ueberschreitung wird die Eingabe abgelehnt und der Endpunkt erneut ;; abgefragt. @@ -2136,6 +2768,75 @@ (vfl-frame-3grad pt hz)) frame)) +;; Genereller Uebergang zwischen zwei Basis-Neigungen (0/+3/-3 Grad, +;; Vorzeichenkonvention wie frame->hz-winkel: positiv=fallend, negativ= +;; steigend). Die Bibliothek kennt nur einen 3-Grad-Bogen gegenueber FLACH +;; (0 Grad) - ein Wechsel zwischen der fallenden (+3) und der steigenden (-3) +;; Basis braucht daher IMMER zwei Boegen ueber 0 als Zwischenhalt. "auf"- +;; Boegen senken die Neigung numerisch (Richtung steigend), "ab"-Boegen +;; erhoehen sie (Richtung fallend) - siehe vfl-nach-3grad/vfl-baue- +;; horizontal-koerper, deren Uebergaenge hier verallgemeinert werden. Ist +;; kein Uebergang noetig (Start-/Zielbasis identisch), no-op. +;; Rueckgabe: (neuer-frame fussabdruck-summe) - fussabdruck-summe (mm, auf hz +;; projiziert) muss der Aufrufer von der geplanten Restlaenge/Zielstrecke +;; abziehen. +(defun vfl-bogen-uebergang (frame ziel-winkel / t0 basis-ziel hz pt m summe vor-pt) + (setq hz (car (frame->hz-winkel frame))) + (setq t0 (cadr (frame->hz-winkel frame))) + (setq t0 (cond ((< (abs t0) *vfk-frame-flach-toleranz*) 0) + ((< t0 0) (- (fix *vfk-gefaelle-winkel*))) + (t (fix *vfk-gefaelle-winkel*)))) + (setq basis-ziel (cond ((< (abs ziel-winkel) *vfl-gf-winkel-toleranz*) 0) + ((< ziel-winkel 0) (- (fix *vfk-gefaelle-winkel*))) + (t (fix *vfk-gefaelle-winkel*)))) + (setq summe 0.0) + (if (/= t0 basis-ziel) + (progn + ;; Schritt 1: t0 -> 0 (falls t0 noch nicht flach ist). + (if (/= t0 0) + (progn + (setq vor-pt (car frame)) + (if (> t0 0) + (progn + (setq m (get-bogen-mass bogen-auf (fix *vfk-gefaelle-winkel*))) + (princ (ssg-text "vfl-bogen-auf3-uebergang")) + (setq pt (insert-rotated-block-with-ks "Vario_Bogen_auf_3_TEF_rechts" vor-pt + (fix *vfk-gefaelle-winkel*) (car m) (caddr m) hz))) + (progn + (setq m (get-bogen-mass bogen-ab (fix *vfk-gefaelle-winkel*))) + (princ (ssg-text "vfl-bogen-ab3-uebergang")) + (setq pt (insert-rotated-block-with-ks "Vario_Bogen_ab_3_TEF_rechts" vor-pt + (- (fix *vfk-gefaelle-winkel*)) (car m) (caddr m) hz))) + ) + (setq summe (+ summe (vfl-projiziere-distanz vor-pt pt hz))) + (setq frame (make-frame-from-dir pt (hz-winkel->xu hz 0))) + ) + ) + ;; Schritt 2: 0 -> basis-ziel (falls das Ziel nicht flach ist). + (if (/= basis-ziel 0) + (progn + (setq vor-pt (car frame)) + (if (> basis-ziel 0) + (progn + (setq m (get-bogen-mass bogen-ab (fix *vfk-gefaelle-winkel*))) + (princ (ssg-text "vfl-bogen-ab3-uebergang")) + (setq pt (insert-rotated-block-with-ks "Vario_Bogen_ab_3_TEF_rechts" vor-pt + 0 (car m) (caddr m) hz))) + (progn + (setq m (get-bogen-mass bogen-auf (fix *vfk-gefaelle-winkel*))) + (princ (ssg-text "vfl-bogen-auf3-uebergang")) + (setq pt (insert-rotated-block-with-ks "Vario_Bogen_auf_3_TEF_rechts" vor-pt + 0 (car m) (caddr m) hz))) + ) + (setq summe (+ summe (vfl-projiziere-distanz vor-pt pt hz))) + (setq frame (make-frame-from-dir pt (hz-winkel->xu hz basis-ziel))) + ) + ) + ) + ) + (list frame summe) +) + ;; Horizontales Sub-Segment bauen. Die flache Zone (0 Grad) wird NICHT mehr ;; automatisch mit ab_3 auf die 3-Grad-Basis zurueckgefuehrt - das Stueck ENDET ;; FLACH. Der ab_3-Uebergang kommt erst, wenn ein 3-Grad-Element folgt @@ -2143,13 +2844,20 @@ ;; NICHT flach ist (sonst bleibt die laufende flache Zone erhalten). Separatoren ;; VOR/NACH liegen in der 0-Grad-Ebene. Rueckgabe: neuer Frame (flach, 0 Grad). ;; ziel-modus=T: dL ist die GESAMT-Zielstrecke ab pt (der Nutzer hat einen -;; Endpunkt gepickt, den die Kette exakt treffen soll). In diesem Fall werden -;; ALLE Fragen, die die spaeter tatsaechlich gebaute Laenge beeinflussen -;; (Separator VOR/NACH, UND "Ist der Endpunkt der Foerderer?"), VOR der -;; Laengenberechnung gestellt - erst wenn wirklich alle Informationen da sind, -;; wird dL final berechnet und die horizontale Strecke gebaut. Das verhindert, -;; dass die Kette am Ende ueber den gepickten Punkt hinausragt, nur weil -;; nachtraeglich noch ein Separator oder eine Motorstation dazukommt. +;; Endpunkt gepickt, den die Kette exakt treffen soll). In diesem Fall wird +;; "Ist der Endpunkt der Foerderer?" VOR der Laengenberechnung gestellt - +;; erst wenn die Antwort feststeht, wird dL final berechnet und die +;; horizontale Strecke gebaut. Das verhindert, dass die Kette am Ende ueber +;; den gepickten Punkt hinausragt, nur weil nachtraeglich noch eine +;; Motorstation dazukommt. +;; KEIN Separator VOR/NACH mehr innerhalb dieses Sub-Segments: ein +;; Separator ist mechanisch nur zwischen zwei GF-Segmenten, zwischen GF und +;; Umlenkstation, oder zwischen Motorstation und GF gueltig - NICHT +;; innerhalb einer laufenden, angetriebenen VF-Einheit (die Sub-Segmente +;; haengen nur ueber Vertikalboegen zusammen, keine echte Trennstelle). Der +;; Separator an der Motorstation wird stattdessen dort gefragt/gebaut, wo er +;; hingehoert: vfl-sep-an-stelle-frage in vfl-vf-einheit-abschluss beim +;; Weiterbauen, automatisch vor dem ES-Element beim Kettenende. ;; gf2-laenge: die (schon feststehende) GF2-Laenge aus der GF-Verteilungs- ;; Frage (L_GF2-bau in vfl-vf-einheit) - wird bei Antwort "1" (nur Motor- ;; station) MIT reserviert, da vfs-vf-exit sie direkt danach anbaut. Bei @@ -2160,17 +2868,121 @@ ;; (vfl-vf-einheit) muss die Frage dann NICHT erneut stellen. Bei ziel-modus= ;; nil (Default/mid-chain-Fortsetzung): unveraendertes Verhalten, Rueckgabe ;; nur frame. -(defun vfl-baue-horizontal-koerper (frame hz dL ziel-modus gf2-laenge / - pt m1 sep-vor pt-vor-bogen sep-nach ist-ende-antwort) - (setq pt (car frame)) +;; Alle seit checkpoint (Ergebnis von (entlast), NIL falls Zeichnung vorher leer +;; war) neu erzeugten Entities wieder loeschen - Gegenteil von +;; vfl-modus-abbruch-sichern (das wickelt statt zu loeschen). Genutzt, wenn ein +;; Baustein (z.B. VF-Einheit-Eingang) sich im Nachhinein als sinnlos erweist +;; (zu kurz, Nutzer verzichtet auf "trotzdem bauen") - erst alle enames +;; sammeln, dann loeschen (entdel veraendert waehrend der Iteration die +;; Datenbank-Reihenfolge, siehe SSG_LIB_Commands.lsp). +(defun vfl-loesche-seit (checkpoint / e liste) + (setq liste '()) + (setq e (if checkpoint (entnext checkpoint) (entnext))) + (while e (setq liste (cons e liste)) (setq e (entnext e))) + (foreach e liste (entdel e)) +) + +;; Frage "Ist der Endpunkt der Foerderer?" - eigene Funktion, weil +;; vfl-baue-horizontal-koerper sie unter Umstaenden zweimal stellen muss +;; (Erstfrage + Nachfrage, wenn die Reststrecke sich nachtraeglich als zu +;; kurz herausstellt und die Erstantwort dadurch ungueltig werden kann). Im +;; Wizard-Modus zeigt sie SELBST den Dialog (vflw_horizontal, radio-basiert) +;; und legt die Antwort in die Pending-Queue - so bekommt auch die Nachfrage +;; (kein separater Gruppen-Dialog-Aufruf an der Aufrufstelle) ein echtes +;; Auswahlfenster statt des generischen Dropdowns. +(defun vfl-frage-ist-endpunkt ( / dat ergebnis gende) + (princ (ssg-text "vfl-ist-endpunkt-frage")) + (princ (ssg-text "vfl-ja-nur-motorstation")) + (princ (ssg-text "vfl-nein-weiterbauen")) + (princ (ssg-text "vfl-ja-motorstation-kettenende")) (if (vfl-wizard-aktiv) - (vl-catch-all-apply 'vflw-gruppe-horizontal-impl (list ziel-modus))) - (princ (ssg-text "vfl-sep-vor-frage")) - (princ (ssg-text "vfl-ja")) - (princ (ssg-text "vfl-nein")) - (setq sep-vor (= (vfl-menu (ssg-text "vfl-prompt-wahl-1-2-def2") - (list (ssg-text "vfl-ja") (ssg-text "vfl-nein")) 2 "vfl-sep-vor-frage") "1")) - (if (and ziel-modus sep-vor) (setq dL (max *vfk-restlaenge-min-clamp* (- dL *vfk-separator-laenge*)))) + (progn + (setq dat (load_dialog (vflw-dcl-pfad))) + (if (not (new_dialog "vflw_horizontal" dat)) + (if (and dat (>= dat 0)) (unload_dialog dat)) + (progn + (set_tile "kopf" (vflw-clean (ssg-text "vfl-ist-endpunkt-frage"))) + (set_tile "istende_1" "1") + (action_tile "accept" + "(setq gende (cond ((= (get_tile \"istende_0\") \"1\") \"0\") + ((= (get_tile \"istende_2\") \"1\") \"2\") + (t \"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) (vflw-pending-push-all (list (itoa (1+ (atoi gende)))))) + ((= ergebnis 2) (setq *vfl-wizard-abbruch-grund* "zurueck")) + (t (setq *vfl-wizard-abbruch-grund* "abbrechen")) + ) + ) + ) + ) + ) + (vfl-menu (ssg-text "vfl-prompt-wahl-1-3-def2") + (list (ssg-text "vfl-ja-nur-motorstation") + (ssg-text "vfl-nein-weiterbauen") + (ssg-text "vfl-ja-motorstation-kettenende")) 2 + "vfl-ist-endpunkt-frage")) + +;; Frage "Ist das das Kettenende?" (Linie-GF-Segment-Schleife) - eigene +;; Funktion, da an zwei identischen Stellen genutzt (mit/ohne vorherigen +;; Separator-Einbau). Im Wizard-Modus zeigt sie SELBST den Dialog +;; (vflw_kettenende, radio-basiert) und legt die Antwort in die Pending- +;; Queue - analog zu vfl-frage-ist-endpunkt. +(defun vfl-frage-ist-kettenende ( / dat ergebnis gwahl) + (princ (ssg-text "vfl-ist-kettenende-header")) + (princ (ssg-text "vfl-kettenende-opt-ja-es")) + (princ (ssg-text "vfl-kettenende-opt-ja-ohne-es")) + (princ (ssg-text "vfl-kettenende-opt-nein")) + (if (vfl-wizard-aktiv) + (progn + (setq dat (load_dialog (vflw-dcl-pfad))) + (if (not (new_dialog "vflw_kettenende" dat)) + (if (and dat (>= dat 0)) (unload_dialog dat)) + (progn + (set_tile "kopf" (vflw-clean (ssg-text "vfl-ist-kettenende-header"))) + (action_tile "accept" + "(setq gwahl (cond ((= (get_tile \"wahl_ja_es\") \"1\") \"1\") + ((= (get_tile \"wahl_ja_ohne_es\") \"1\") \"2\") + (t \"3\"))) + (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) (vflw-pending-push-all (list gwahl))) + ((= ergebnis 2) (setq *vfl-wizard-abbruch-grund* "zurueck")) + (t (setq *vfl-wizard-abbruch-grund* "abbrechen")) + ) + ) + ) + ) + ) + (vfl-menu (ssg-text "vfl-prompt-wahl-1-3-def3") + (list (ssg-text "vfl-kettenende-opt-ja-es") + (ssg-text "vfl-kettenende-opt-ja-ohne-es") + (ssg-text "vfl-kettenende-opt-nein")) 3 + "vfl-ist-kettenende-header")) + +;; checkpoint: (entlast) von VOR dem Eingangsaufbau (GF1+Separator+ +;; Umlenkstation) der aufrufenden VF-Einheit, oder nil bei einer Fortsetzung +;; einer bereits laufenden VF-Einheit (dort bleibt bei Abbruch die bisherige +;; Kette stehen). Bei checkpoint<>nil wird vor jedem (exit) dieser Funktion +;; der seither eingefuegte Eingang wieder geloescht (vfl-loesche-seit) - eine +;; VF-Einheit mit nur einer Umlenkstation und nichts dahinter ist kein +;; sinnvolles Teilergebnis. +(defun vfl-baue-horizontal-koerper (frame hz dL ziel-modus gf2-laenge checkpoint / + pt m1 pt-vor-bogen ist-ende-antwort dL-neu + antwort-zu-kurz) + (setq pt (car frame)) + ;; Im Ziel-Modus: "Ist der Endpunkt der Foerderer?" abfragen, BEVOR die + ;; endgueltige Laenge feststeht (Dialog wird bei Bedarf von + ;; vfl-frage-ist-endpunkt selbst gezeigt). + (if ziel-modus (setq ist-ende-antwort (vfl-frage-ist-endpunkt))) ;; auf_3-Eintritt nur, wenn noch NICHT flach (sonst flache Zone fortsetzen). ;; dL ist die gewuenschte Reststrecke AB HIER (pt) - der reale Bogen- ;; Fussabdruck (gemessen, nicht aus der Tabellen-Masse geschaetzt - die @@ -2183,48 +2995,73 @@ (princ (ssg-text "vfl-bogen-auf3-uebergang")) (setq pt (insert-rotated-block-with-ks "Vario_Bogen_auf_3_TEF_rechts" pt (ssg-cfg-or "vario" "gefaelle_winkel" 3) (car m1) (caddr m1) hz)) - (setq dL (max *vfk-restlaenge-min-clamp* (- dL (vfl-projiziere-distanz pt-vor-bogen pt hz)))))) - ;; Separator NACH abfragen (noch nicht bauen) - im Ziel-Modus VOR der - ;; Laengenberechnung, damit der Fussabdruck feststeht. - (princ (ssg-text "vfl-sep-nach-frage")) - (princ (ssg-text "vfl-ja")) - (princ (ssg-text "vfl-nein")) - (setq sep-nach (= (vfl-menu (ssg-text "vfl-prompt-wahl-1-2-def2") - (list (ssg-text "vfl-ja") (ssg-text "vfl-nein")) 2 "vfl-sep-nach-frage") "1")) - (if (and ziel-modus sep-nach) (setq dL (max *vfk-restlaenge-min-clamp* (- dL *vfk-separator-laenge*)))) - ;; Im Ziel-Modus: "Ist der Endpunkt der Foerderer?" JETZT abfragen (statt - ;; erst danach in der Aufruferschleife) - der Ausgangs-Fussabdruck - ;; (Vario_Bogen_ab_3 + Motorstation) wird nur reserviert, wenn tatsaechlich - ;; sofort geschlossen wird (Antwort 1 oder 3). - (if ziel-modus - (progn - (princ (ssg-text "vfl-ist-endpunkt-frage")) - (princ (ssg-text "vfl-ja-nur-motorstation")) - (princ (ssg-text "vfl-nein-weiterbauen")) - (princ (ssg-text "vfl-ja-motorstation-kettenende")) - (setq ist-ende-antwort (vfl-menu (ssg-text "vfl-prompt-wahl-1-3-def2") - (list (ssg-text "vfl-ja-nur-motorstation") - (ssg-text "vfl-nein-weiterbauen") - (ssg-text "vfl-ja-motorstation-kettenende")) 2 - "vfl-ist-endpunkt-frage")) - (cond - ((= ist-ende-antwort "1") - (setq dL (max *vfk-restlaenge-min-clamp* (- dL (car (get-bogen-mass bogen-ab (fix *vfk-gefaelle-winkel*))) *vfk-stations-laenge* - (* (if gf2-laenge gf2-laenge 0.0) - (cos (* *vfk-gefaelle-winkel* (/ pi 180.0)))))))) - ((= ist-ende-antwort "3") - (setq dL (max *vfk-restlaenge-min-clamp* (- dL (car (get-bogen-mass bogen-ab (fix *vfk-gefaelle-winkel*))) *vfk-stations-laenge*)))) + (setq dL-neu (- dL (vfl-projiziere-distanz pt-vor-bogen pt hz))) + (if (< dL-neu *vfk-restlaenge-min-clamp*) + (progn + ;; Nicht sofort abbrechen: Hinweis mit den echten Zahlen zeigen und + ;; fragen, ob mit der Mindestlaenge trotzdem weitergebaut werden + ;; soll (gleiches Bauteil "Staustrecke_SP_1000_mm" wie im Normalfall, + ;; nur auf *vfk-restlaenge-min-clamp* geklemmt statt geplant lang - + ;; der Kettenpunkt landet dann entsprechend weiter als angeklickt). + (princ (ssg-textf "vfl-hinweis-horizontal-fussabdruck-zu-kurz" + (list (rtos dL 2 0) (rtos dL-neu 2 0) (rtos *vfk-restlaenge-min-clamp* 2 0)))) + (princ (ssg-text "vfl-ja")) + (princ (ssg-text "vfl-nein")) + (if (vfl-wizard-aktiv) + (vl-catch-all-apply 'vflw-gruppe-ja-nein-impl + (list (ssg-textf "vfl-hinweis-horizontal-fussabdruck-zu-kurz" + (list (rtos dL 2 0) (rtos dL-neu 2 0) (rtos *vfk-restlaenge-min-clamp* 2 0)))))) + (setq antwort-zu-kurz (vfl-menu (ssg-text "prompt-wahl-1-2") + (list (ssg-text "vfl-ja") (ssg-text "vfl-nein")) 2 + "vfl-hinweis-horizontal-fussabdruck-zu-kurz")) + (if (= antwort-zu-kurz "1") + (progn + (setq dL-neu *vfk-restlaenge-min-clamp*) + ;; Die Erstantwort auf "Ist der Endpunkt der Foerderer?" bezog + ;; sich auf die urspruenglich geplante (laengere) Reststrecke - + ;; nach dem Klemmen auf das Minimum ggf. nicht mehr sinnvoll + ;; (z.B. reicht es dann erst recht nicht mehr fuer Motorstation + ;; +Bogen) - deshalb hier neu erfragen. + (if ziel-modus (setq ist-ende-antwort (vfl-frage-ist-endpunkt))) + ) + (progn + (if checkpoint (vfl-loesche-seit checkpoint)) + (princ (ssg-textf "vfl-fehler-horizontal-fussabdruck-zu-kurz" (list (rtos dL-neu 2 0)))) + (exit) + ) + ) + ) ) + (setq dL dL-neu))) + ;; Ausgangs-Fussabdruck (Vario_Bogen_ab_3 + Motorstation [+ GF2]) nur + ;; reservieren, wenn tatsaechlich sofort mit Motorstation geschlossen wird + ;; (Antwort 1 oder 3) - die Frage selbst ist oben schon beantwortet. + (if ziel-modus + (cond + ((= ist-ende-antwort "1") + (setq dL-neu (- dL (car (get-bogen-mass bogen-ab (fix *vfk-gefaelle-winkel*))) *vfk-stations-laenge* + (* (if gf2-laenge gf2-laenge 0.0) + (cos (* *vfk-gefaelle-winkel* (/ pi 180.0)))))) + (if (< dL-neu *vfk-restlaenge-min-clamp*) + (progn + (if checkpoint (vfl-loesche-seit checkpoint)) + (princ (ssg-textf "vfl-fehler-horizontal-fussabdruck-zu-kurz" (list (rtos dL-neu 2 0)))) + (exit))) + (setq dL dL-neu)) + ((= ist-ende-antwort "3") + (setq dL-neu (- dL (car (get-bogen-mass bogen-ab (fix *vfk-gefaelle-winkel*))) *vfk-stations-laenge*)) + (if (< dL-neu *vfk-restlaenge-min-clamp*) + (progn + (if checkpoint (vfl-loesche-seit checkpoint)) + (princ (ssg-textf "vfl-fehler-horizontal-fussabdruck-zu-kurz" (list (rtos dL-neu 2 0)))) + (exit))) + (setq dL dL-neu)) ) ) - ;; optionaler Separator VOR - in der horizontalen Ebene (0 Grad) - (if sep-vor (setq pt (vfl-sep-hz pt hz))) - ;; horizontale Zwischenstrecke (0 Grad) + ;; horizontale Zwischenstrecke (0 Grad) - KEIN Separator mehr davor/danach. (princ (ssg-textf "vfl-horizontale-zwischenstrecke" (list (rtos dL 2 2)))) (setq pt (insert-inclined-scaled-block "Staustrecke_SP_1000_mm" pt dL 0 hz)) (vfl-acc-vf-seg "horizontal" 0 dL) - ;; optionaler Separator NACH (jetzt tatsaechlich bauen) - (if sep-nach (setq pt (vfl-sep-hz pt hz))) ;; KEIN ab_3 mehr -> das Stueck ENDET FLACH (0 Grad) (setq frame (make-frame-from-dir pt (hz-winkel->xu hz 0.0))) (if ziel-modus (list frame ist-ende-antwort) frame) @@ -2245,52 +3082,249 @@ ;; das horizontale Stueck ausgeglichen). ;; Die Hoehe kommt also aus VF-Winkel/horizontal + GF2, die ueberschuessige ;; Laenge aus dem horizontalen VF - genau die zweistufige Logik. +;; schon-flach: T => die Kette kommt bereits flach (0 Grad) an (letztes +;; Sub-Segment war horizontal, kein ab_3 wurde dafuer gebraucht) - wird an +;; berechne-horizontale-mitte weitergereicht, damit ein evtl. dort +;; entschiedenes horizontales Mittelstueck OHNE ueberfluessigen Eintritts- +;; bogen (auf_3) budgetiert wird. Der Aufrufer (vfl-body-abschluss) baut in +;; diesem Fall das Mittelstueck dann auch tatsaechlich ohne auf_3. ;; Rueckgabe: (typ winkel L_GF2 L_VF) - typ "GF"/"VF"/nil (wie ;; vfl-segment-entscheidung; L_GF2 varriert, Mindestwert siehe vfl-body-abschluss). -(defun vfl-body-zerlegung (deltaL deltaH richtung / - save-ausdx save-ausdz save-feste - winkel-natuerlich wahl horizontal-info res) +;; +;; Diagnose-Ausgabe fuer den Stufe-2-Versuch (horizontales VF + GF, siehe +;; berechne-horizontale-mitte): zeigt GF_total/L_VF auch dann, wenn das +;; Ergebnis ungueltig ist (negativ) - hilft zu erkennen, WARUM Stufe 2 +;; scheitert (z.B. wenn die feste 3-Grad-Neigung der Motor-/Separator-/ES- +;; Stationen allein schon mehr Hoehe abbaut, als das Ziel verlangt - dann +;; wuerde GF_total negativ, was physisch nicht baubar ist). +;; schon-flach: derselbe Wert, der auch an berechne-horizontale-mitte +;; uebergeben wurde - bestimmt hier NUR die Anzeige (ob bogen-x1/z1 als 0 +;; oder als tatsaechlicher Eintrittsbogen-Fussabdruck gezeigt werden), damit +;; sichtbar wird, dass im Kettenende-Fall (Aufrufer vfl-body-zerlegung) NUR +;; der Austrittsbogen (bogen-x2/z2, 0->3 Grad vor Motorstation) zwingend +;; gebraucht wird, waehrend aus-dx/aus-dz (Einlauf-AS-Element) bereits vom +;; Aufrufer auf 0 gesetzt sind (siehe dortiger Kommentar). Rekonstruiert die +;; Bogen-Fussabdruecke separat (dupliziert bewusst die paar Zeilen aus +;; berechne-horizontale-mitte statt deren Rueckgabe zu erweitern - die +;; Funktion ist Standard/Etage-uebergreifend, eine Signaturaenderung dort +;; haette einen groesseren Blast-Radius als hier lokal in vf_linienzug.lsp +;; nochmal auszurechnen). +;; Zeigt ZUSAETZLICH, sobald das Ergebnis ungueltig ist, zwei Mindestwerte, +;; die die beiden moeglichen Ursachen trennen (siehe Nutzer-Anfrage): +;; Variante 1 (kein gerader VF-Anteil, L_VF=0): GF wird exakt auf die +;; VERLANGTE Zielhoehe dimensioniert (GF_total aus horizontal-info) - die +;; dafuer noetige Mindest-Streckenlaenge ist fixed-x + GF_total*cos(rad3). +;; Ist GF_total selbst schon negativ, ist diese Variante gar NICHT ueber die +;; Laenge loesbar (auch bei unendlich viel Laenge nicht) - dann wird +;; stattdessen die Hoehen-Diskrepanz gemeldet: schon OHNE GF-Bogen aendert +;; sich die Hoehe um mindestens minh mm. +;; Variante 2 (kein GF-Bogen, GF_total=0, Rest als gerader VF-Anteil - VF +;; aendert die Hoehe nicht): die resultierende Hoehenaenderung ist dann fix +;; minh mm, UNABHAENGIG von der Streckenlaenge. Ist aber selbst der reine +;; feste Fussabdruck (fixed-x, ohne VF UND ohne GF) schon laenger als die +;; verfuegbare Strecke, ist auch diese Variante nicht ueber die Hoehe +;; loesbar - dann wird stattdessen die Laengen-Diskrepanz gemeldet. +;; Ausgabe wird NICHT sofort geprinct, sondern in *vfl-stufe2-diagnose-text* +;; gesammelt: der Aufrufer (vfl-body-zerlegung) leert die Variable bei jedem +;; Aufruf zuerst, vfl-body-abschluss haengt den gesammelten Text (falls +;; vorhanden) NACH der endgueltigen FEHLER-Meldung an. Grund: Stufe 2 ist nur +;; ein (evtl. scheiternder) ERSTER Versuch, danach folgt oft noch Stufe 1 +;; (Winkel-Suche) - stuende die Stufe-2-Diagnose weiterhin sofort im Log, +;; wuerde sie sich zwischen ">>> Kettenende-Modus" und die Stufe-1-Winkel- +;; tabelle schieben, obwohl sie inhaltlich zur (evtl. erst ganz am Ende +;; sichtbaren) FEHLER-Zeile gehoert. Gelingt Stufe 1 danach doch noch, bleibt +;; der gesammelte Text ungenutzt (kein "typ=nil" in vfl-body-abschluss) - so +;; wird ein erfolgreicher Log nicht mit Details eines verworfenen Zwischen- +;; versuchs zugemuellt. +(defun vfl-diag-add (txt) + (setq *vfl-stufe2-diagnose-text* + (strcat (if *vfl-stufe2-diagnose-text* *vfl-stufe2-diagnose-text* "") txt))) + +(defun vfl-stufe2-diagnose (deltaL deltaH horizontal-info schon-flach / + rad3 mass1 mass2 bogen-x1 bogen-z1 bogen-x2 bogen-z2 + gf-total gueltig fixed-x k-term minh minl-mitgf + fest-planar fest-hoehe) + (vfl-diag-add (ssg-textf "vfl-stufe2-diagnose" + (list (rtos deltaL 2 0) (rtos deltaH 2 0) + (if horizontal-info (rtos (car horizontal-info) 2 1) "?") + (if horizontal-info (rtos (cadr horizontal-info) 2 1) "?") + (if (and horizontal-info (caddr horizontal-info)) "GUELTIG" "UNGUELTIG")))) + (setq rad3 (* *vfk-gefaelle-winkel* (/ pi 180.0))) + (setq mass2 (get-bogen-mass bogen-ab (fix *vfk-gefaelle-winkel*))) + (setq bogen-x2 (car mass2) bogen-z2 (caddr mass2)) + (if schon-flach + (setq bogen-x1 0.0 bogen-z1 0.0) + (progn + (setq mass1 (get-bogen-mass bogen-auf (fix *vfk-gefaelle-winkel*))) + (setq bogen-x1 (+ (* (car mass1) (cos rad3)) (* (caddr mass1) (sin rad3)))) + (setq bogen-z1 (+ (* (- (car mass1)) (sin rad3)) (* (caddr mass1) (cos rad3)))) + ) + ) + (vfl-diag-add (ssg-textf "vfl-stufe2-diagnose-details" + (list (if schon-flach "JA" "NEIN") + (rtos aus-dx 2 1) + (rtos ein-dx 2 1) (rtos ein-dz 2 1) + (rtos bogen-x1 2 1) (rtos bogen-z1 2 1) + (rtos bogen-x2 2 1) (rtos bogen-z2 2 1) + (rtos FESTE_HORIZONTAL 2 1)))) + ;; Explizite Anzeige: wieviel Laenge/Hoehe der feste "Schwanz" (Stationen + + ;; Separator + ES, OHNE die optionalen Uebergangsboegen) allein beansprucht - + ;; direkte Antwort auf "was braucht Motorstation+Separator+ES". Das Label + ;; haengt vom Budget-Kontext ab: FESTE_HORIZONTAL=800 (Kettenende, nur + ;; Motor+Separator - der Eingang/Umlenkstation ist zu diesem Zeitpunkt schon + ;; gebaut) vs. 1300 (frischer VF-Einheit-Eingang, zusaetzlich Umlenkstation - + ;; siehe *vfk-feste-horizontal-kettenende*/-linienzug in vf_konstanten.lsp). + (setq fest-planar (+ ein-dx (* FESTE_HORIZONTAL (cos rad3)))) + (setq fest-hoehe (+ ein-dz (- (* FESTE_HORIZONTAL (sin rad3))))) + (vfl-diag-add (ssg-textf + (if (<= (abs (- FESTE_HORIZONTAL *vfk-feste-horizontal-kettenende*)) 0.5) + "vfl-stufe2-fest-kettenende" + "vfl-stufe2-fest-eingang") + (list (rtos fest-planar 2 0) (rtos fest-hoehe 2 0)))) + (setq gueltig (and horizontal-info (caddr horizontal-info))) + ;; *vfl-stufe2-minl-vorschlag*/*vfl-stufe2-minh-vorschlag*: kurze Zahlenwerte + ;; (kein Text) fuer die knappe Alert-Zusammenfassung in vfl-body-abschluss - + ;; minh ist immer definiert (reine Funktion der festen Geometrie), minl nur, + ;; wenn Variante 1 (GF nach Zielhoehe) ueberhaupt eine nicht-negative GF + ;; ergibt - siehe Kommentar oben. + (setq *vfl-stufe2-minl-vorschlag* nil *vfl-stufe2-minh-vorschlag* nil) + (if (not gueltig) + (progn + (setq gf-total (if horizontal-info (car horizontal-info) nil)) + (setq fixed-x (+ aus-dx ein-dx bogen-x1 bogen-x2 (* FESTE_HORIZONTAL (cos rad3)))) + (setq k-term (+ aus-dz ein-dz (- (* FESTE_HORIZONTAL (sin rad3))) bogen-z1 bogen-z2)) + (setq minh (- k-term)) + (setq *vfl-stufe2-minh-vorschlag* minh) + ;; Variante 1: Mindest-Streckenlaenge (L_VF=0, GF nach Zielhoehe) + (if (and gf-total (>= gf-total 0)) + (progn + (setq minl-mitgf (+ fixed-x (* gf-total (cos rad3)))) + (setq *vfl-stufe2-minl-vorschlag* minl-mitgf) + (vfl-diag-add (ssg-textf "vfl-stufe2-minl" (list (rtos minl-mitgf 2 0) (rtos deltaL 2 0))))) + (vfl-diag-add (ssg-textf "vfl-stufe2-minl-unmoeglich" (list (rtos minh 2 0) (rtos deltaH 2 0)))) + ) + ;; Variante 2: Mindest-Hoehenaenderung (GF=0, Rest als gerader VF-Anteil) + (if (>= deltaL fixed-x) + (vfl-diag-add (ssg-textf "vfl-stufe2-minh" (list (rtos minh 2 0) (rtos deltaH 2 0)))) + (vfl-diag-add (ssg-textf "vfl-stufe2-minh-unmoeglich" (list (rtos fixed-x 2 0) (rtos deltaL 2 0)))) + ) + ) + ) + (princ)) + +;; Vereinheitlichte Stufe-1(Winkel-Tabelle)/Stufe-2(horizontal+GF)-Entscheidung. +;; Genutzt von ZWEI Aufrufern mit unterschiedlichem Fest-Budget: +;; - vfl-body-zerlegung (Kettenende innerhalb einer laufenden VF-Einheit): +;; feste-hz=*vfk-feste-horizontal-kettenende* (800, nur Motor+Separator - +;; der Eingang ist zu diesem Zeitpunkt schon gebaut). +;; - vfl-vf-entscheidung ("Neue Linie: Ab/Auf VF"/"BIS Kettenende", Eingang +;; einer FRISCHEN VF-Einheit): feste-hz=*vfl-feste-horizontal* (1300, +;; Umlenkstation+Separator+Motorstation). +;; schon-flach: nur fuer den Kettenende-Fortsetzungsfall relevant (Frame kann +;; dort schon flach sein, siehe vfl-baue-horizontal-koerper) - am Eingang +;; einer frischen VF-Einheit immer nil (Frame kommt frisch von der +;; Umlenkstation bei 3 Grad). +;; Rueckgabe: (typ winkel L_GF L_VF), typ="GF"/"VF"/nil (winkel=0 bei "VF" +;; heisst horizontales Stufe-2-Ergebnis). KEINE eigene Mindestlaengen-Pruefung +;; - die bleibt Sache der Aufrufer (unterschiedliche Schwellwerte: 800/1000). +(defun vfl-winkel-stufe-entscheidung (deltaL deltaH richtung schon-flach feste-hz / + save-ausdx save-ausdz save-feste + winkel-natuerlich wahl horizontal-info res) (if (or (not *lib-initialized*) (null bogen-auf)) (init-bibliothek)) - ;; Budget-Globals temporaer auf den Mid-Body-Fall umbiegen (mit Restore). + ;; Gesammelten Stufe-2-Diagnosetext + Alert-Vorschlagswerte aus einem evtl. + ;; vorherigen Aufruf verwerfen - der Aufrufer haengt/zeigt sie nur an, wenn + ;; DIESER Aufruf scheitert (typ=nil). + (setq *vfl-stufe2-diagnose-text* nil) + (setq *vfl-stufe2-minl-vorschlag* nil *vfl-stufe2-minh-vorschlag* nil) + ;; Budget-Globals temporaer auf das Aufrufer-Budget umbiegen (mit Restore). (setq save-ausdx aus-dx save-ausdz aus-dz save-feste FESTE_HORIZONTAL) - (setq aus-dx 0.0 aus-dz 0.0 FESTE_HORIZONTAL *vfk-feste-horizontal-kettenende*) + (setq aus-dx 0.0 aus-dz 0.0 FESTE_HORIZONTAL feste-hz) (setq res (cond - ;; kuerzer als Motor(500)+Separator(300): kein Abschluss baubar - ((< deltaL *vfk-kettenende-mindestlaenge*) (list nil nil nil nil)) ;; praktisch flach: horizontales VF + GF2 ((< deltaH 1.0) - (setq horizontal-info (berechne-horizontale-mitte deltaL deltaH "Ab")) + (setq horizontal-info (berechne-horizontale-mitte deltaL deltaH "Ab" schon-flach)) + (vfl-stufe2-diagnose deltaL deltaH horizontal-info schon-flach) (if (and horizontal-info (caddr horizontal-info)) (list "VF" 0 (car horizontal-info) (cadr horizontal-info)) (list nil nil nil nil))) - ;; steigend: nur gewinkeltes VF + GF2 moeglich + ;; steigend: Stufe 1 (gewinkeltes VF) zuerst; scheitert das, Stufe 2 + ;; (horizontales VF + GF2) als Fallback. GF2 wird dabei GENAUSO gebaut + ;; wie im "Ab"-Fall (vfs-vf-exit, fest +3 Grad, gleiche Neigung wie + ;; Motorstation/Umlenkstation/Separator) - KEIN Vorzeichenwechsel, keine + ;; Bau-Aenderung noetig. Das Ausgleichsprinzip: Motorstation+GF2 senken + ;; IMMER ab; wird bei knapper Laenge weniger/kein GF2 verbaut (kuerzer + ;; als das volle Laengenbudget), sinkt die Kette insgesamt weniger stark + ;; ab und die dadurch freiwerdende Laenge wird mit einem horizontalen + ;; VF-Stueck (0 Grad, keine weitere Hoehenaenderung) aufgefuellt statt + ;; mit mehr GF2 - der Uebergangsbogen (ab_3, bereits in berechne- + ;; horizontale-mitte eingerechnet) bleibt dabei unveraendert. ((= richtung "Auf") - (setq wahl (vfl-waehle-winkel (nth 3 (berechne-alle-winkel deltaL deltaH "Auf" *vfk-feste-horizontal-kettenende*)))) - (if wahl (list "VF" (nth 0 wahl) (nth 1 wahl) (nth 2 wahl)) (list nil nil nil nil))) + (princ (ssg-text "vfl-stufe1-start")) + (setq wahl (vfl-waehle-winkel (nth 3 (berechne-alle-winkel deltaL deltaH "Auf" feste-hz)))) + (if wahl + (list "VF" (nth 0 wahl) (nth 1 wahl) (nth 2 wahl)) + (progn + (setq horizontal-info (berechne-horizontale-mitte deltaL deltaH "Auf" schon-flach)) + (vfl-stufe2-diagnose deltaL deltaH horizontal-info schon-flach) + (if (and horizontal-info (caddr horizontal-info)) + (list "VF" 0 (car horizontal-info) (cadr horizontal-info)) + (list nil nil nil nil))))) ;; fallend: natuerlichen Neigungswinkel gegen die 3-Grad-Eigenneigung pruefen (t (setq winkel-natuerlich (* (atan (/ deltaH deltaL)) (/ 180.0 pi))) (cond - ;; ~3 Grad -> reine GF2 (kein Koerper, GF2 traegt Laenge + 3-Grad-Absenkung) - ((<= (abs (- winkel-natuerlich *vfk-gefaelle-winkel*)) *vfl-gf-winkel-toleranz*) - (list "GF" *vfk-gefaelle-winkel* nil nil)) - ;; steiler als 3 Grad -> Stufe 1: gewinkeltes VF + GF2 (GF2 variiert mit Winkel) + ;; KEIN "~3 Grad -> reine GF2 ohne Rechnung"-Kurzschluss mehr - frueher + ;; hier: (list "GF" *vfk-gefaelle-winkel* nil nil) - L_GF/L_VF blieben + ;; nil und vfl-body-abschluss musste GF2 dann selbst aus deltaL ALLEIN + ;; herleiten - deltaH wurde dabei NIE geprueft, der Austrittsbogen + ;; (bogen-x2) NIE abgezogen. Ergebnis: ein REALER Hoehenfehler (in + ;; einem Livetest 2026-09-10 z.B. dZ=-40.5mm), sobald der natuerliche + ;; Winkel nicht EXAKT 3,000 Grad war (nur nahe dran, per Toleranz + ;; *vfl-gf-winkel-toleranz*=0.5 Grad). Stufe 1 (Tabellenwinkel 3 Grad + ;; ist selbst ein Tabelleneintrag) loest deltaL UND deltaH exakt + ;; simultan (vf-winkel-solve) und deckt den ~3-Grad-Fall daher + ;; automatisch und PRAEZISE mit ab - kein separater Zweig noetig. + ;; steiler als 3 Grad -> Stufe 1: gewinkeltes VF + GF2 (GF2 variiert mit + ;; Winkel) zuerst; scheitert das (z.B. bei knapper Streckenlaenge - + ;; "steiler als 3 Grad" heisst nur, dass der NATUERLICHE Winkel ueber + ;; 3 Grad liegt, nicht dass die Tabelle bei JEDEM Winkel passt), Stufe + ;; 2 (horizontales VF + GF2) als Fallback, analog zur "flacher"- + ;; Verzweigung unten und zum "Auf"-Fallback oben. ((> winkel-natuerlich *vfk-gefaelle-winkel*) - (setq wahl (vfl-waehle-winkel (nth 3 (berechne-alle-winkel deltaL deltaH "Ab" *vfk-feste-horizontal-kettenende*)))) - (if wahl (list "VF" (nth 0 wahl) (nth 1 wahl) (nth 2 wahl)) (list nil nil nil nil))) + (princ (ssg-text "vfl-stufe1-start")) + (setq wahl (vfl-waehle-winkel (nth 3 (berechne-alle-winkel deltaL deltaH "Ab" feste-hz)))) + (if wahl + (list "VF" (nth 0 wahl) (nth 1 wahl) (nth 2 wahl)) + (progn + (setq horizontal-info (berechne-horizontale-mitte deltaL deltaH "Ab" schon-flach)) + (vfl-stufe2-diagnose deltaL deltaH horizontal-info schon-flach) + (if (and horizontal-info (caddr horizontal-info)) + (list "VF" 0 (car horizontal-info) (cadr horizontal-info)) + (list nil nil nil nil))))) ;; flacher als 3 Grad -> Stufe 2: horizontales VF + GF2 (t - (setq horizontal-info (berechne-horizontale-mitte deltaL deltaH "Ab")) + (setq horizontal-info (berechne-horizontale-mitte deltaL deltaH "Ab" schon-flach)) + (vfl-stufe2-diagnose deltaL deltaH horizontal-info schon-flach) (if (and horizontal-info (caddr horizontal-info)) (list "VF" 0 (car horizontal-info) (cadr horizontal-info)) (progn - (setq wahl (vfl-waehle-winkel (nth 3 (berechne-alle-winkel deltaL deltaH "Ab" *vfk-feste-horizontal-kettenende*)))) + (vfl-diag-add (ssg-text "vfl-stufe2-ungueltig")) + (princ (ssg-text "vfl-stufe1-start")) + (setq wahl (vfl-waehle-winkel (nth 3 (berechne-alle-winkel deltaL deltaH "Ab" feste-hz)))) (if wahl (list "VF" (nth 0 wahl) (nth 1 wahl) (nth 2 wahl)) (list nil nil nil nil))))))))) ;; Budget-Globals zuruecksetzen (setq aus-dx save-ausdx aus-dz save-ausdz FESTE_HORIZONTAL save-feste) res) +;; Duenner Wrapper: eigene Mindestlaenge (kuerzer als Motor+Separator = kein +;; Abschluss baubar), sonst delegiert an vfl-winkel-stufe-entscheidung mit dem +;; Kettenende-Budget. +(defun vfl-body-zerlegung (deltaL deltaH richtung schon-flach) + (if (< deltaL *vfk-kettenende-mindestlaenge*) + (list nil nil nil nil) + (vfl-winkel-stufe-entscheidung deltaL deltaH richtung schon-flach *vfk-feste-horizontal-kettenende*))) + ;; Fragt Zielpunkt (XY) + Zielhoehe (Z) ab, zerlegt den Rest (vfl-body- ;; zerlegung, Standard-Logik) und baut den Koerper VOR dem Motor: gewinkeltes ;; VF (winkel>0) oder horizontales VF (winkel=0). GF2 (variiert mit dem Winkel, @@ -2301,11 +3335,15 @@ ;; Rueckgabe: (frame anzahl-koerper letzt-hz gf2-laenge) oder nil. (defun vfl-body-abschluss (frame letzt-hz p-umlenk / linie-mess dL hzn hn dH richtn rad3 dec typ w lgf lvf - gf2 cnt p0 tx ty + gf2 cnt p0 tx ty schon-flach antwort-gf2 hoehe-vorschlaege hoehe-ab hoehe-auf hoehe-fallback) - ;; Der Abschluss-Koerper (vfs-vf-koerper) und der Motor gehen von 3-Grad-Basis - ;; aus - eine gerade laufende flache Zone hier mit ab_3 abschliessen. - (setq frame (vfl-nach-3grad frame)) + ;; Schon-flach VOR jeder Konvertierung feststellen - NICHT mehr blind auf + ;; 3 Grad zwingen, bevor feststeht, ob die Zerlegung ohnehin ein + ;; horizontales Mittelstueck ergibt (dann waere die Konvertierung + der + ;; Wiedereintritt in die flache Zone via vfs-vf-koerper ein ueberfluessiges + ;; auf_3/ab_3-Bogenpaar - siehe Kommentar bei vfl-body-zerlegung). Die + ;; Positions-Messung selbst funktioniert unabhaengig von der Neigung. + (setq schon-flach (vfl-frame-flach-p frame)) (setq linie-mess (vfl-neue-linie-messen (car frame) letzt-hz)) (if (null linie-mess) (progn (princ (ssg-text "vfl-abgebrochen-kein-ziel")) nil) @@ -2335,11 +3373,48 @@ (setq rad3 (* (float (ssg-cfg-or "vario" "gefaelle_winkel" 3)) (/ pi 180.0))) (princ (ssg-textf "vfl-kettenende-modus-ziel" (list (rtos dL 2 0) (rtos dH 2 0) richtn))) - (setq dec (vfl-body-zerlegung dL dH richtn)) + (setq dec (vfl-body-zerlegung dL dH richtn schon-flach)) (setq typ (nth 0 dec) w (nth 1 dec) lgf (nth 2 dec) lvf (nth 3 dec)) (if (null typ) (progn - (princ (ssg-text "vfl-fehler-rest-nicht-baubar")) + ;; Klare Rueckmeldung statt nur "nicht baubar": die tatsaechlich + ;; gewaehlte Zielhoehe + Strecke nennen, UND (falls vorhanden) die + ;; bereits VOR der Hoehe-Abfrage berechneten baubaren Vorschlaege + ;; (hoehe-ab/hoehe-auf, siehe vfl-body-hoehe-vorschlaege oben) + ;; hier NOCHMAL zeigen - der Nutzer sieht sie sonst nur einmal vor + ;; der Eingabe und muss beim Fehler wieder hochscrollen. + (if (or hoehe-ab hoehe-auf) + (princ (ssg-textf "vfl-fehler-rest-nicht-baubar-mit-vorschlag" + (list (rtos hn 2 0) (rtos dL 2 0) (rtos dH 2 0) richtn + (cond + ((and hoehe-ab hoehe-auf) + (ssg-textf "vfl-vorschlag-ab-auf" + (list (rtos hoehe-ab 2 0) (rtos hoehe-auf 2 0)))) + (hoehe-ab (ssg-textf "vfl-vorschlag-nur-ab" (list (rtos hoehe-ab 2 0)))) + (t (ssg-textf "vfl-vorschlag-nur-auf" (list (rtos hoehe-auf 2 0)))))))) + (princ (ssg-textf "vfl-fehler-rest-nicht-baubar-ohne-vorschlag" + (list (rtos hn 2 0) (rtos dL 2 0) (rtos dH 2 0) richtn)))) + ;; Gesammelte Stufe-2-Diagnose (siehe vfl-stufe2-diagnose/vfl-diag-add) + ;; erst HIER, NACH der eigentlichen FEHLER-Zeile zeigen - sie gehoert + ;; inhaltlich zur Begruendung, warum nichts gebaut werden konnte, und + ;; wuerde weiter oben (vor der Stufe-1-Tabelle) den Lesefluss stoeren. + (if *vfl-stufe2-diagnose-text* (princ *vfl-stufe2-diagnose-text*)) + ;; Kurze 2-Punkte-Zusammenfassung zusaetzlich als Alert-Popup (nicht + ;; nur im Konsolen-Log) - Punkt 2 nur, wenn Stufe 2 ueberhaupt + ;; versucht wurde (siehe *vfl-stufe2-min*-vorschlag*, von + ;; vfl-stufe2-diagnose gesetzt). + (alert + (strcat + (ssg-textf "vfl-alert-kettenende-p1" (list (rtos dL 2 0) (rtos dH 2 0) richtn)) + (cond + ((and *vfl-stufe2-minl-vorschlag* *vfl-stufe2-minh-vorschlag*) + (ssg-textf "vfl-alert-kettenende-p2-beide" + (list (rtos *vfl-stufe2-minl-vorschlag* 2 0) (rtos *vfl-stufe2-minh-vorschlag* 2 0)))) + (*vfl-stufe2-minh-vorschlag* + (ssg-textf "vfl-alert-kettenende-p2-nur-minh" (list (rtos *vfl-stufe2-minh-vorschlag* 2 0)))) + (*vfl-stufe2-minl-vorschlag* + (ssg-textf "vfl-alert-kettenende-p2-nur-minl" (list (rtos *vfl-stufe2-minl-vorschlag* 2 0)))) + (t "")))) (dbgmsg (strcat "GEOMETRIE FEHLGESCHLAGEN: Kettenende-Abschluss nicht baubar (dL=" (rtos dL 2 0) " dH=" (rtos dH 2 0) " richtung=" richtn ")")) nil) @@ -2358,11 +3433,32 @@ (setq cnt 0) ;; Koerper VOR dem Motor: winkel 0 = horizontales VF, sonst gewinkeltes VF. ;; typ "GF" -> kein Koerper (Rest laeuft komplett ueber GF2). - (if (and (= typ "VF") lvf (> lvf 1.0)) - (progn - (setq frame (vfl-frame-3grad (vfs-vf-koerper (car frame) richtn w lvf hzn) hzn)) - (vfl-acc-vf-seg richtn w lvf) - (setq cnt (1+ cnt)))) + (cond + ;; Schon flach + horizontales Mittelstueck: OHNE vfs-vf-koerper + ;; (das wuerde unbedingt auf_3+ab_3 einbauen) direkt als reine + ;; Verlaengerung der bereits flachen Zone bauen - kein + ;; ueberfluessiges Bogenpaar. Frame bleibt flach; der spaeter + ;; ohnehin noetige Uebergang auf 3 Grad vor der Motorstation + ;; (Ausgang weiter unten in vfl-vf-einheit) erledigt den einzigen + ;; wirklich noetigen Bogen. + ((and schon-flach (= typ "VF") (= w 0) lvf (> lvf 1.0)) + (setq frame (make-frame-from-dir + (insert-inclined-scaled-block "Staustrecke_SP_1000_mm" (car frame) lvf 0 hzn) + (hz-winkel->xu hzn 0.0))) + (vfl-acc-vf-seg "horizontal" 0 lvf) + (setq cnt (1+ cnt))) + ;; Normalfall: gewinkelter ODER horizontaler Koerper - vfs-vf-koerper + ;; braucht dafuer zwingend eine 3-Grad-Basis als Eingang (bracktet + ;; selbst korrekt mit auf_3/ab_3 bzw. den Winkel-Boegen). War der + ;; Frame noch flach (schon-flach, aber ein echter Winkel w<>0 + ;; noetig), wird hier genau EINMAL konvertiert - kein Vorgriff + ;; mehr am Funktionsanfang, daher kein doppeltes Bogenpaar. + ((and (= typ "VF") lvf (> lvf 1.0)) + (setq frame (vfl-nach-3grad frame)) + (setq frame (vfl-frame-3grad (vfs-vf-koerper (car frame) richtn w lvf hzn) hzn)) + (vfl-acc-vf-seg richtn w lvf) + (setq cnt (1+ cnt))) + ) (setq letzt-hz hzn) (vfl-20m-check p-umlenk (car frame)) ;; GF2-Laenge (hinter dem Motor): aus der Zerlegung (variiert mit Winkel), @@ -2372,11 +3468,27 @@ ((= typ "GF") (max 0.0 (- (/ (- dL (abs (if ein-dx ein-dx *vfk-as-es-fallback-dx*))) (cos rad3)) *vfk-feste-horizontal-kettenende*))) (t 0.0))) + ;; Nicht mehr stillschweigend auffuellen (fuehrte zu einer teils + ;; grossen Zielpunkt-Abweichung, siehe Ist-Ziel-Report) - stattdessen + ;; fragen: mit dem exakt berechneten (kleineren) Wert bauen (trifft + ;; den Zielpunkt exakt, Default) ODER auf die uebliche Mindestlaenge + ;; auffuellen (Zielpunkt verschiebt sich entsprechend weiter). Ein + ;; berechneter Wert unter 400mm ist geometrisch genauso baubar wie + ;; jeder andere (vfs-vf-exit skaliert den Block auf jede Laenge >0). (if (and (> gf2 0.0) (< gf2 *vfl-gf-min-laenge*)) (progn - (princ (ssg-textf "vfl-hinweis-gf2-minimum" + (princ (ssg-textf "vfl-frage-gf2-minimum" (list (rtos gf2 2 0) (rtos *vfl-gf-min-laenge* 2 0)))) - (setq gf2 *vfl-gf-min-laenge*))) + (princ (ssg-text "vfl-ja")) + (princ (ssg-text "vfl-nein")) + (if (vfl-wizard-aktiv) + (vl-catch-all-apply 'vflw-gruppe-ja-nein-impl + (list (ssg-textf "vfl-frage-gf2-minimum" + (list (rtos gf2 2 0) (rtos *vfl-gf-min-laenge* 2 0)))))) + (setq antwort-gf2 (vfl-menu (ssg-text "prompt-wahl-1-2") + (list (ssg-text "vfl-ja") (ssg-text "vfl-nein")) 1 + "vfl-frage-gf2-minimum")) + (if (= antwort-gf2 "2") (setq gf2 *vfl-gf-min-laenge*)))) (dbgmsg (strcat "GEOMETRIE ERFOLG: Kettenende-Abschluss gebaut (cnt=" (itoa cnt) " gf2=" (rtos gf2 2 0) "), neue Position=" (dbg-tostring (car frame)))) (list frame cnt hzn gf2) @@ -2386,29 +3498,64 @@ ) ) +;; eingang-modus steuert den VF-Eingang je nach VORHERIGEM Kettenglied +;; (letzter-typ in vf-linienzug-modus) - keine blinde GF1+Separator-Zugabe +;; mehr, wenn das vorherige Glied das schon erledigt hat: +;; nil => Standard: GF1 (mind. *vfl-gf-min-laenge*) + Separator + +;; Umlenkstation (Kettenanfang/AS, oder vorheriges Glied VF). +;; "gf" => vorheriges Glied ist ein GF-Segment OHNE eigenen +;; Separator: kein GF1-Stumpf, nur Separator + Umlenkstation. +;; "separator" => vorheriges Glied ist bereits ein Separator: nur noch +;; Umlenkstation (weder GF1 noch ein zweiter Separator). +;; "keine" => vorheriges Glied ist bereits Teil einer virtuellen VF-Kette +;; OHNE eigene Umlenkstation (z.B. Vario-Kurve als allererstes +;; Kettenglied) - eine zweite Umlenkstation waere mechanisch +;; sinnlos: KEIN GF1, KEIN Separator, KEINE Umlenkstation, der +;; Koerper knuepft direkt am uebergebenen frame an. ;; Rueckgabe: (frame anzahl-koerper ziel-ende) -(defun vfl-vf-einheit (frame hz1 richtung1 winkel1 L_GF1 L_VF1 gf-am-ausgang / +(defun vfl-vf-einheit (frame hz1 richtung1 winkel1 L_GF1 L_VF1 gf-am-ausgang eingang-modus / p-umlenk vf-count antwort L_GF-eff L_GF1-bau L_GF2-bau linie-mess dL dH hn hzn richtn ent typ w lgf lvf letzt-hz fertig ziel-ende ziel-gf2 res3 gf2-eff entry-start res-h vor-antwort es-gewuenscht es-antwort save-eindx save-eindz - hoehe-vorschlaege hoehe-ab hoehe-auf hoehe-fallback) + hoehe-vorschlaege hoehe-ab hoehe-auf hoehe-fallback restlaenge + schon-flach winkel-hoehen-erg entry-checkpoint es-seite) ;; Vorbelegung: ES gewuenscht (Default) - nur bei "3 - Kettenende definieren" ;; wird explizit gefragt und ggf. auf nil gesetzt (siehe dort). (setq es-gewuenscht t) - ;; Gesamte Staustrecke (mind. *vfl-gf-min-laenge*) auf Einlauf/Ausgang verteilen. - (setq L_GF-eff (max L_GF1 *vfl-gf-min-laenge*)) + ;; Gesamte Staustrecke (mind. *vfl-gf-min-laenge*) auf Einlauf/Ausgang + ;; verteilen - AUSSER eingang-modus "gf"/"separator": dort ist kein + ;; GF1-Stumpf noetig (siehe Kommentar oben). + (if (member eingang-modus '("gf" "separator" "keine")) + (setq L_GF-eff 0.0) + (setq L_GF-eff (max L_GF1 *vfl-gf-min-laenge*))) (if gf-am-ausgang (setq L_GF1-bau (/ L_GF-eff 2.0) L_GF2-bau (/ L_GF-eff 2.0)) ; halbe/halbe (setq L_GF1-bau L_GF-eff L_GF2-bau 0.0)) ; alles am Einlauf - ;; --- Eingang: GF1 + Separator + Umlenkstation --- + ;; --- Eingang: [GF1] + [Separator] + Umlenkstation --- + ;; Checkpoint VOR dem Eingangs-Aufbau: falls die horizontale Zwischenstrecke + ;; (unten, winkel1=0) sich als zu kurz erweist und der Nutzer "trotzdem + ;; bauen?" verneint, soll NICHT nur die Fehlermeldung kommen, sondern auch + ;; der bereits eingefuegte Eingang (GF1+Separator+Umlenkstation+ggf. + ;; Uebergangsbogen) wieder entfernt werden - eine VF-Einheit mit nur einer + ;; Umlenkstation und nichts dahinter ist kein sinnvolles Teilergebnis (siehe + ;; vfl-loesche-seit, uebergeben an vfl-baue-horizontal-koerper). + (setq entry-checkpoint (entlast)) (setq entry-start (car frame)) - (setq frame (vfl-frame-3grad (vfs-vf-entry (car frame) L_GF1-bau hz1) hz1)) - (if (> L_GF1-bau 0.1) - (vfl-acc-gf-seg L_GF1-bau (ssg-cfg-or "vario" "gefaelle_winkel" 3))) - (setq *vfl-acc-separator* (1+ *vfl-acc-separator*)) ; Einlauf-Separator (in vfs-vf-entry) - (setq p-umlenk (car frame)) + (if (equal eingang-modus "keine") + (setq p-umlenk (car frame)) + (progn + (setq frame (vfl-frame-3grad + (vfs-vf-entry (car frame) L_GF1-bau hz1 (equal eingang-modus "separator")) + hz1)) + (if (> L_GF1-bau 0.1) + (vfl-acc-gf-seg L_GF1-bau (ssg-cfg-or "vario" "gefaelle_winkel" 3))) + (if (not (equal eingang-modus "separator")) + (setq *vfl-acc-separator* (1+ *vfl-acc-separator*))) ; Einlauf-Separator (in vfs-vf-entry) + (setq p-umlenk (car frame)) + ) + ) ;; --- Erstes Koerper-Sub-Segment --- ;; winkel1=0 => horizontaler Anfang (Option 3): mit Separator-vor/nach-Abfrage. @@ -2420,21 +3567,34 @@ ;; 2) der Fussabdruck fuer einen MOEGLICHEN sofortigen Abschluss direkt ;; nach diesem Stueck: Vario_Bogen_ab_3 (Ausgangs-Uebergang zurueck auf ;; 3 Grad, Tabellen-Mass wie in vfl-nach-3grad) + Motorstation (500mm). - ;; Falls die Kette hier NICHT sofort endet, wird dieser Fussabdruck - ;; trotzdem reserviert - konsistent mit dem "Kettenende"-Verhalten an - ;; anderer Stelle (lieber vorsichtig reservieren als ueberschiessen). + ;; Dieser Ausgangs-Fussabdruck wird NUR reserviert, wenn "Ist der + ;; Endpunkt der Foerderer?" (in vfl-baue-horizontal-koerper) mit + ;; "Ja" beantwortet wird - beim Weiterbauen faellt er weg, siehe dort. (if (= (fix winkel1) 0) (progn + ;; Reale (gemessene) Restlaenge nach Abzug des Eingangs (GF1+Separator+ + ;; Umlenkstation) - NICHT hier schon auf *vfk-restlaenge-min-clamp* + ;; pruefen: das Umlenkstation-Austritts-Frame ist 3 Grad geneigt, der + ;; noch fehlende 3-Grad-Uebergangsbogen (Vario_Bogen_auf_3) frisst + ;; hiervon nochmal etwas ab - die verlaessliche Pruefung (inkl. Hinweis+ + ;; Nachfrage bei zu kurzer Reststrecke) passiert bereits INNERHALB von + ;; vfl-baue-horizontal-koerper, direkt nach dem Bogen-Einbau. Eine + ;; Pruefung hier waere zu frueh (Bogen-Fussabdruck noch nicht + ;; beruecksichtigt) und wuerde genau diese Nachfrage verhindern. + (setq restlaenge (- L_VF1 (vfl-projiziere-distanz entry-start p-umlenk hz1))) ;; ziel-modus=T: Separator VOR/NACH + "Ist der Endpunkt der Foerderer?" ;; werden INNERHALB von vfl-baue-horizontal-koerper VOR der Laengen- ;; berechnung gestellt (siehe dortiger Kommentar) - die Antwort kommt ;; hier zurueck, damit die Schleife unten sie nicht nochmal erfragt. - (setq res-h (vfl-baue-horizontal-koerper frame hz1 - (max *vfk-restlaenge-min-clamp* (- L_VF1 (vfl-projiziere-distanz entry-start p-umlenk hz1))) - t L_GF2-bau)) + (setq res-h (vfl-baue-horizontal-koerper frame hz1 restlaenge t L_GF2-bau entry-checkpoint)) (setq frame (car res-h) vor-antwort (cadr res-h)) ) (progn + ;; vfs-vf-koerper braucht die 3-Grad-Basis als Eintritt - im Normalfall + ;; liefert die Umlenkstation die bereits (vfl-nach-3grad ist dann No-op); + ;; bei eingang-modus "keine" kann frame noch flach sein (z.B. direkt + ;; nach einer Vario-Kurve) und muss hier erst konvertiert werden. + (setq frame (vfl-nach-3grad frame)) (setq frame (vfl-frame-3grad (vfs-vf-koerper (car frame) richtung1 winkel1 L_VF1 hz1) hz1)) (vfl-acc-vf-seg richtung1 winkel1 L_VF1) ) @@ -2450,35 +3610,37 @@ ;; erneut fragen - sonst normal abfragen. (if vor-antwort (setq antwort vor-antwort vor-antwort nil) - (progn - (princ (ssg-text "vfl-ist-endpunkt-frage")) - (princ (ssg-text "vfl-ja-nur-motorstation")) - (princ (ssg-text "vfl-nein-weiterbauen")) - (princ (ssg-text "vfl-ja-motorstation-kettenende")) - (setq antwort (vfl-menu (ssg-text "vfl-prompt-wahl-1-3-def2") - (list (ssg-text "vfl-ja-nur-motorstation") - (ssg-text "vfl-nein-weiterbauen") - (ssg-text "vfl-ja-motorstation-kettenende")) 2 - "vfl-ist-endpunkt-frage")) - ) + (setq antwort (vfl-frage-ist-endpunkt)) ) (if (= antwort "1") (setq fertig t) (if (= antwort "3") ;; --- Option 3: Kettenende exakt am Zielpunkt (nur EIN Motor) --- (progn - ;; ES-Element hier gewuenscht? Falls nein, ein-dx/ein-dz waehrend der - ;; Zerlegung (vfl-body-abschluss -> vfl-body-zerlegung -> berechne- - ;; alle-winkel) temporaer nullen, damit KEIN ES-Fussabdruck reserviert - ;; wird - die Kette endet dann direkt am Zielpunkt ohne Separator+ES. + ;; ES-Element hier gewuenscht (+ falls ja: Winkel/Seite) - kombinierter + ;; Dialog wie AS-Element (vflw-gruppe-as-impl, dieselbe Mechanik wie in + ;; vf-linienzug-modus2). Winkel/Seite werden JETZT (nicht erst spaeter + ;; in vfl-vf-einheit-abschluss) erfragt, weil sie den tatsaechlichen + ;; ES-Fussabdruck (ein-dx/ein-dz, per vf-set-es-masse INNERHALB von + ;; vfl-frage-es-seite gesetzt) bestimmen - der muss VOR vfl-body- + ;; abschluss feststehen, sonst rechnet die Streckenzerlegung mit dem + ;; falschen (alten) Fussabdruck und die Kette trifft den Zielpunkt + ;; nicht exakt. Falls nein: ein-dx/ein-dz waehrend der Zerlegung + ;; temporaer nullen, damit KEIN ES-Fussabdruck reserviert wird - die + ;; Kette endet dann direkt am Zielpunkt ohne Separator+ES. (princ (ssg-text "vfl-es-setzen-frage")) (princ (ssg-text "vfl-ja")) (princ (ssg-text "vfl-es-nein-zielpunkt")) + (if (vfl-wizard-aktiv) + (vl-catch-all-apply 'vflw-gruppe-as-impl (list "vfl-es-setzen-frage"))) (setq es-antwort (vfl-menu (ssg-text "prompt-wahl-1-2") (list (ssg-text "vfl-ja") (ssg-text "vfl-es-nein-zielpunkt")) 1 "vfl-es-setzen-frage")) (setq es-gewuenscht (/= es-antwort "2")) - (if (not es-gewuenscht) + (if es-gewuenscht + ;; dialog-schon-gezeigt=T: Winkel+Seite kamen bereits aus dem + ;; kombinierten vflw-gruppe-as-impl-Dialog oben (mit). + (setq es-seite (vfl-frage-es-seite t)) (progn (setq save-eindx ein-dx save-eindz ein-dz) (setq ein-dx 0.0 ein-dz 0.0))) (setq res3 (vfl-body-abschluss frame letzt-hz p-umlenk)) @@ -2496,6 +3658,8 @@ (princ (ssg-text "vfl-opt-horizontaler-foerderer")) (princ (ssg-text "vfl-opt-vario-kurve")) (princ (ssg-text "vfl-opt-auf-ab-foerderer")) + (if (vfl-wizard-aktiv) + (vl-catch-all-apply 'vflw-gruppe-naechstes-im-vf-impl nil)) (setq antwort (vfl-menu (ssg-text "vfl-prompt-wahl-1-3-def3") (list (ssg-text "vfl-opt-horizontaler-foerderer") (ssg-text "vfl-opt-vario-kurve") @@ -2510,68 +3674,118 @@ ;; --- Horizontaler Foerderer (folgt der aktuellen Fahrtrichtung) --- ((= antwort "1") (setq linie-mess (vfl-neue-linie-messen (car frame) letzt-hz)) - (if linie-mess + ;; Punkt-Pick abgebrochen (ESC): bisher fiel dies still durch (kein + ;; (exit)) und die Schleife fragte einfach erneut "Naechstes + ;; Element" - vom Nutzer als "Abbrechen wirkt nicht" gemeldet. + (if (null linie-mess) (progn (princ (ssg-text "vfl-abgebrochen")) (exit))) + (setq dL (car linie-mess) hzn (cadr linie-mess)) + (if (> dL 1.0) (progn - (setq dL (car linie-mess) hzn (cadr linie-mess)) - (if (> dL 1.0) - (progn - ;; ziel-modus=T: Separator VOR/NACH + "Ist der Endpunkt der - ;; Foerderer?" werden VOR der Laengenberechnung gestellt - ;; (siehe vfl-baue-horizontal-koerper) - Antwort kommt hier - ;; zurueck und wird in der naechsten Schleifen-Runde - ;; verwendet, statt erneut zu fragen. - (setq res-h (vfl-baue-horizontal-koerper frame hzn dL t L_GF2-bau)) - (setq frame (car res-h) vor-antwort (cadr res-h)) - (setq vf-count (1+ vf-count) letzt-hz hzn) - (vfl-20m-check p-umlenk (car frame)) - ) - (princ (ssg-text "vfl-linie-zu-kurz-uebersprungen")) - ) + ;; ziel-modus=T: Separator VOR/NACH + "Ist der Endpunkt der + ;; Foerderer?" werden VOR der Laengenberechnung gestellt + ;; (siehe vfl-baue-horizontal-koerper) - Antwort kommt hier + ;; zurueck und wird in der naechsten Schleifen-Runde + ;; verwendet, statt erneut zu fragen. + ;; kein Checkpoint (nil): dies ist eine Fortsetzung einer + ;; bereits laufenden VF-Einheit, nicht deren Eingang - bei + ;; "trotzdem bauen?"=Nein bleibt die bisherige Kette stehen + ;; (normaler Abbruch/Wickeln, kein Rueckbau). + (setq res-h (vfl-baue-horizontal-koerper frame hzn dL t L_GF2-bau nil)) + (setq frame (car res-h) vor-antwort (cadr res-h)) + (setq vf-count (1+ vf-count) letzt-hz hzn) + (vfl-20m-check p-umlenk (car frame)) ) + (princ (ssg-text "vfl-linie-zu-kurz-uebersprungen")) ) ) ;; --- Auf/Ab-Foerderer (folgt der aktuellen Fahrtrichtung) --- (t + ;; Punkt 7: kommt die Kette hier bereits FLACH an (z.B. nach + ;; Horizontal-VF/Vario-Kurve), gibt es keine sinnvolle Zielhoehe zum + ;; Anpeilen - Auf/Ab wird dann direkt erfragt und aus einer + ;; Winkel/Hoehe-Tabelle gewaehlt (vfl-waehle-winkel-hoehen-tabelle), + ;; statt eine Zielhoehe abzufragen. schon-flach MUSS vor der + ;; vfl-nach-3grad-Wandlung ermittelt werden. + (setq schon-flach (vfl-frame-flach-p frame)) ;; gewinkeltes VF braucht 3-Grad-Basis -> flache Zone ggf. mit ab_3 beenden (setq frame (vfl-nach-3grad frame)) (setq linie-mess (vfl-neue-linie-messen (car frame) letzt-hz)) + ;; Punkt-Pick abgebrochen (ESC): bisher fiel dies still durch (kein + ;; (exit)) und die Schleife fragte einfach erneut "Naechstes + ;; Element" - vom Nutzer als "Abbrechen wirkt nicht" gemeldet. + (if (null linie-mess) (progn (princ (ssg-text "vfl-abgebrochen")) (exit))) (if linie-mess (progn (setq dL (car linie-mess) hzn (cadr linie-mess)) (if (> dL 1.0) - (progn - ;; NUR-VF-Vorschlaege (nicht vfl-segment-hoehe-vorschlaege): - ;; dieser Zweig setzt eine bestehende VF-Kette fort und lehnt - ;; ein hier zurueckkommendes typ="GF" explizit ab (siehe - ;; "vfl-segment-gf-nicht-erlaubt" unten) - der GF-Vorschlag - ;; (3-Grad-Formel) waere hier also gerade NICHT baubar. - (setq hoehe-vorschlaege (vfl-vf-hoehe-vorschlaege (caddr (car frame)) dL)) - (setq hoehe-ab (nth 0 hoehe-vorschlaege) hoehe-auf (nth 1 hoehe-vorschlaege)) - (setq hoehe-fallback (if hoehe-ab hoehe-ab (caddr (car frame)))) - (vfl-hoehe-hinweis-falls-noetig hoehe-ab hoehe-auf) - (if (vfl-wizard-aktiv) - (vl-catch-all-apply 'vflw-gruppe-ziel-hoehe-impl - (list (list hoehe-ab hoehe-auf (caddr (car frame)))))) - (setq hn (vfl-in-real - (if (and hoehe-ab hoehe-auf) - (ssg-textf "vfl-prompt-hoehe-endpunkt-2" - (list (rtos hoehe-ab 2 1) (rtos hoehe-auf 2 1))) - (ssg-textf "vfl-prompt-hoehe-endpunkt" - (list (rtos hoehe-fallback 2 1)))))) - (if (null hn) (setq hn hoehe-fallback)) - (setq dH (- hn (caddr (car frame)))) - (setq richtn (if (>= dH 0.0) "Auf" "Ab")) - (setq dH (abs dH)) - (setq ent (vfl-segment-entscheidung dL dH richtn)) - (setq typ (nth 0 ent) w (nth 1 ent) lgf (nth 2 ent) lvf (nth 3 ent)) - (if (and typ (= typ "VF")) - (progn - (setq frame (vfl-frame-3grad (vfs-vf-koerper (car frame) richtn w lvf hzn) hzn)) - (setq vf-count (1+ vf-count) letzt-hz hzn) - (vfl-acc-vf-seg richtn w lvf) - (vfl-20m-check p-umlenk (car frame)) + (if schon-flach + (progn + (princ (ssg-text "vfl-frage-auf-ab-richtung")) + (princ (ssg-text "vfl-opt-richtung-auf")) + (princ (ssg-text "vfl-opt-richtung-ab")) + (if (vfl-wizard-aktiv) + (vl-catch-all-apply 'vflw-gruppe-richtung-impl + (list (ssg-text "vfl-frage-auf-ab-richtung")))) + (setq antwort (vfl-menu (ssg-text "vfl-prompt-wahl-1-2") + (list (ssg-text "vfl-opt-richtung-auf") + (ssg-text "vfl-opt-richtung-ab")) 1 + "vfl-frage-auf-ab-richtung")) + (setq richtn (if (= antwort "2") "Ab" "Auf")) + (setq winkel-hoehen-erg + (vfl-waehle-winkel-hoehen-tabelle dL richtn (caddr (car frame)))) + (if winkel-hoehen-erg + (progn + (setq w (nth 0 winkel-hoehen-erg) lvf (nth 2 winkel-hoehen-erg)) + ;; Ist-Ziel-Vergleich: vorhergesagte Endhoehe sichern, um + ;; nach dem echten Bau (vfs-vf-koerper, unabhaengig + ;; verifiziert) auf Abweichung zu pruefen - Sicherheitsnetz + ;; fuer die neue Formel, ohne die reale Geometrie zu beeinflussen. + (setq hn (+ (caddr (car frame)) (nth 1 winkel-hoehen-erg))) + (setq frame (vfl-frame-3grad (vfs-vf-koerper (car frame) richtn w lvf hzn) hzn)) + (setq vf-count (1+ vf-count) letzt-hz hzn) + (vfl-acc-vf-seg richtn w lvf) + (vfl-20m-check p-umlenk (car frame)) + (if (> (abs (- (caddr (car frame)) hn)) 5.0) + (princ (ssg-textf "vfl-winkel-hoehen-abweichung" + (list (rtos hn 2 0) (rtos (caddr (car frame)) 2 0))))) + ) + (princ (ssg-text "vfl-linie-zu-kurz-simple")) + ) + ) + (progn + ;; NUR-VF-Vorschlaege (nicht vfl-segment-hoehe-vorschlaege): + ;; dieser Zweig setzt eine bestehende VF-Kette fort und lehnt + ;; ein hier zurueckkommendes typ="GF" explizit ab (siehe + ;; "vfl-segment-gf-nicht-erlaubt" unten) - der GF-Vorschlag + ;; (3-Grad-Formel) waere hier also gerade NICHT baubar. + (setq hoehe-vorschlaege (vfl-vf-hoehe-vorschlaege (caddr (car frame)) dL)) + (setq hoehe-ab (nth 0 hoehe-vorschlaege) hoehe-auf (nth 1 hoehe-vorschlaege)) + (setq hoehe-fallback (if hoehe-ab hoehe-ab (caddr (car frame)))) + (vfl-hoehe-hinweis-falls-noetig hoehe-ab hoehe-auf) + (if (vfl-wizard-aktiv) + (vl-catch-all-apply 'vflw-gruppe-ziel-hoehe-impl + (list (list hoehe-ab hoehe-auf (caddr (car frame)))))) + (setq hn (vfl-in-real + (if (and hoehe-ab hoehe-auf) + (ssg-textf "vfl-prompt-hoehe-endpunkt-2" + (list (rtos hoehe-ab 2 1) (rtos hoehe-auf 2 1))) + (ssg-textf "vfl-prompt-hoehe-endpunkt" + (list (rtos hoehe-fallback 2 1)))))) + (if (null hn) (setq hn hoehe-fallback)) + (setq dH (- hn (caddr (car frame)))) + (setq richtn (if (>= dH 0.0) "Auf" "Ab")) + (setq dH (abs dH)) + (setq ent (vfl-segment-entscheidung dL dH richtn)) + (setq typ (nth 0 ent) w (nth 1 ent) lgf (nth 2 ent) lvf (nth 3 ent)) + (if (and typ (= typ "VF")) + (progn + (setq frame (vfl-frame-3grad (vfs-vf-koerper (car frame) richtn w lvf hzn) hzn)) + (setq vf-count (1+ vf-count) letzt-hz hzn) + (vfl-acc-vf-seg richtn w lvf) + (vfl-20m-check p-umlenk (car frame)) + ) + (princ (ssg-text "vfl-segment-gf-nicht-erlaubt")) ) - (princ (ssg-text "vfl-segment-gf-nicht-erlaubt")) ) ) (princ (ssg-text "vfl-linie-zu-kurz-simple")) @@ -2601,7 +3815,7 @@ (vfs-vf-exit (car frame) gf2-eff letzt-hz nil) letzt-hz)) (if (> gf2-eff 0.1) (vfl-acc-gf-seg gf2-eff (ssg-cfg-or "vario" "gefaelle_winkel" 3))) - (list frame vf-count ziel-ende es-gewuenscht) + (list frame vf-count ziel-ende es-gewuenscht es-seite) ) ;; Rundet einen Winkel (Grad) auf das naechste 30-Grad-Vielfache DES WELT- @@ -2716,11 +3930,25 @@ (setq *vfl-acc-variokurve* (vfl-inc-count *vfl-acc-variokurve* (strcat (if (= kvariante "aussen") "A" "I") "_" (itoa kwinkel)))) - ;; Vario-Kurve ist ein HORIZONTALER Richtungswechsel (KEINE Neigung). - ;; Der aktuelle Frame traegt die 3-Grad-Basisneigung - fuer die Kurve wird er - ;; daher auf 0 Grad abgeflacht (Position + Fahrtrichtung bleiben erhalten). - (setq hz (car (frame->hz-winkel frame))) - (setq flach-frame (make-frame-from-dir (car frame) (hz-winkel->xu hz 0.0))) + ;; Vario-Kurve ist ein HORIZONTALER Richtungswechsel (KEINE Neigung). Ist der + ;; Frame bereits flach (z.B. direkt nach einem AS-Element oder GF-Bogen als + ;; allererstem Kettenglied), wird NICHT per make-frame-from-dir neu + ;; aufgebaut - das wuerde die REALE (aus dem Vorgaenger-Block gemessene) + ;; yu/zu-Rollung verwerfen und durch die rein rechnerische Konvention + ;; ersetzen, was bei realen Bloecken zu einem KS-Versatz/Drehfehler fuehren + ;; kann (dieselbe Fehlerklasse, die weiter unten fuer die AUSGANGS-Korrektur + ;; bereits empirisch gefunden und dort durch die rollungserhaltende + ;; vfl-frame-um-z-drehen ersetzt wurde - hier war die Eingangsseite noch + ;; nicht angepasst). Nur bei einer TATSAECHLICH geneigten 3-Grad-Basis + ;; (mitten in einer VF-Einheit) wird abgeflacht - dort gibt es keine reale + ;; Rollung zu erhalten, die Rekonstruktion ist unbedenklich. + (if (vfl-frame-flach-p frame) + (setq flach-frame frame) + (progn + (setq hz (car (frame->hz-winkel frame))) + (setq flach-frame (make-frame-from-dir (car frame) (hz-winkel->xu hz 0.0))) + ) + ) (setq neuer-frame (insert-block-ks-to-ks blockname flach-frame)) ;; Auf den absoluten 30-Grad-Raster snappen (siehe vfl-hz-snappen-absolut) - ;; gleiche Zeichnungsungenauigkeit wie bei GF-Bogen moeglich. Reine Z-Drehung @@ -2804,6 +4032,191 @@ (caddr startpunkt) nil "KS_EIN") ) +;; KS_AUS-Ursprung UND -Richtung (hz-Winkel in Grad) eines platzierten Blocks - +;; Massstab-bereinigte Kopie wie vfl-kette-ks-ursprung (Explode auf einer +;; skalierungsneutralen Kopie, dann geloescht), zusaetzlich mit der KS_AUS- +;; Achsrichtung: die Laengen-Streckung (XScaleFactor) verschiebt nur den +;; KS_AUS-URSPRUNG entlang der Blocklaenge (gegenueber KS_EIN), die +;; Achsrichtung des kleinen KS_AUS-Unterblocks selbst bleibt davon unberuehrt +;; (an der skalierungsneutralen Kopie unverfaelscht messbar). Rueckgabe: +;; (punkt . hz) oder nil (kein KS_AUS gefunden). +(defun vfl-kette-ks-aus-richtung (block-obj / sx copyobj ksdata kez kaz-raw kax-raw kaz hz) + (setq sx (vla-get-XScaleFactor block-obj)) + (setq copyobj (vla-Copy block-obj)) + (vla-put-XScaleFactor copyobj 1.0) + (vla-put-YScaleFactor copyobj 1.0) + (vla-put-ZScaleFactor copyobj 1.0) + (setq ksdata (extract-ks-from-block-raw copyobj)) + (if (not (vlax-erased-p copyobj)) (vl-catch-all-apply 'vla-Delete (list copyobj))) + (setq kez (if (assoc "KS_EIN" ksdata) (car (cadr (assoc "KS_EIN" ksdata))) nil)) + (setq kaz-raw (if (assoc "KS_AUS" ksdata) (car (cadr (assoc "KS_AUS" ksdata))) nil)) + (setq kax-raw (if (assoc "KS_AUS" ksdata) (cadr (cadr (assoc "KS_AUS" ksdata))) nil)) + (if (and kez kaz-raw kax-raw) + (progn + (setq kaz + (if (/= sx 1.0) + (list (+ (car kez) (* sx (- (car kaz-raw) (car kez)))) + (+ (cadr kez) (* sx (- (cadr kaz-raw) (cadr kez)))) + (+ (caddr kez) (* sx (- (caddr kaz-raw) (caddr kez))))) + kaz-raw)) + (setq hz (/ (* (atan (- (cadr kax-raw) (cadr kaz-raw)) (- (car kax-raw) (car kaz-raw))) 180.0) pi)) + (cons kaz hz) + ) + nil + ) +) + +;; Sucht am gegebenen Punkt (Toleranz 1mm) einen KS_AUS eines vorhandenen +;; Vario-Kette-Bausteins der Zeichnung (lose Teile UND VF_n-Wrapper - gleicher +;; Scan wie vfl-kette-sammle-alle/Vario_Kette_Merge) und liefert dessen +;; Richtung (hz in Grad). Genutzt fuer den Kettenanfang bei GF-Bogen/Vario- +;; Kurve OHNE AS-Element: setzt der Nutzer den Startpunkt exakt auf den KS_AUS +;; eines bestehenden Bausteins (z.B. Fortsetzung einer schon gebauten Kette), +;; soll die neue Kurve dessen Richtung uebernehmen statt der Welt-X-Achse. +;; Rueckgabe: (hz . typ) oder nil, wenn kein KS_AUS in Toleranz gefunden +;; wurde. typ ist das vfl-kette-typ-Ergebnis des GEFUNDENEN Bausteins (bei +;; einem Wrapper-Kind dessen EIGENER Blockname, nicht "WRAPPER") - Basis fuer +;; vfl-kette-typ-familie (GF/VF/uneindeutig), genutzt von +;; vfl-keine-umlenkstation-p. +(defun vfl-ks-aus-hz-an-punkt (pt / tol ss i ename bname typ obj kinder kind + erg bester-d d hz-treffer typ-treffer kind-bname kind-typ) + (setq tol 1.0) + (setq bester-d nil hz-treffer nil typ-treffer nil) + (setq ss (ssget "X" '((0 . "INSERT")))) + (if ss + (progn + (setq i 0) + (while (< i (sslength ss)) + (setq ename (ssname ss i)) + (setq bname (cdr (assoc 2 (entget ename)))) + (setq typ (vfl-kette-typ bname)) + (cond + ((= typ "WRAPPER") + (setq obj (vlax-ename->vla-object ename)) + (setq kinder (vlax-invoke obj 'Explode)) + (foreach kind kinder + (if (and (not (vlax-erased-p kind)) + (= (vla-get-ObjectName kind) "AcDbBlockReference")) + (progn + (setq kind-bname (vla-get-Name kind)) + (setq kind-typ (vfl-kette-typ kind-bname)) + (setq erg (vfl-kette-ks-aus-richtung kind)) + (if erg + (progn + (setq d (distance pt (car erg))) + (if (and (< d tol) (or (null bester-d) (< d bester-d))) + (setq bester-d d hz-treffer (cdr erg) typ-treffer kind-typ)) + ) + ) + ) + ) + ) + (foreach kind kinder (if (not (vlax-erased-p kind)) (vla-Delete kind))) + ) + ((/= typ "UNBEKANNT") + (setq obj (vlax-ename->vla-object ename)) + (setq erg (vfl-kette-ks-aus-richtung obj)) + (if erg + (progn + (setq d (distance pt (car erg))) + (if (and (< d tol) (or (null bester-d) (< d bester-d))) + (setq bester-d d hz-treffer (cdr erg) typ-treffer typ)) + ) + ) + ) + ) + (setq i (1+ i)) + ) + ) + ) + (if hz-treffer (cons hz-treffer typ-treffer) nil) +) + +;; Grobe GF-/VF-Familie-Klassifikation eines vfl-kette-typ-Ergebnisses fuer die +;; Umlenkstations-Entscheidung am echten Kettenanfang (siehe +;; vfl-eingang-modus-bestimmen): AS/ES/STRECKE/SEP werden von BEIDEN Familien +;; genutzt (eine GF-Gerade UND das horizontale VF-Mittelstueck sind derselbe +;; Block "Staustrecke_SP_1000_mm") und bleiben daher absichtlich uneindeutig +;; (nil) - der Scan kann ein reines GF-Geraden-Ende grundsaetzlich NICHT vom +;; Ende eines VF-Horizontalstuecks unterscheiden. +(defun vfl-kette-typ-familie (typ) + (cond + ((member typ '("WRAPPER" "KURVE" "UMLENK" "MOTOR" "BOGENAUF" "BOGENAB")) "VF") + ((member typ '("GFBOGEN")) "GF") + (t nil) + ) +) + +;; Eingang-Modus + L_GF-Stumpf fuer eine neue VF-Einheit bestimmen - EINE +;; gemeinsame Entscheidung fuer "Neue VF mit horizontalem Anfang" UND "Neue +;; Linie: Ab/Auf VF" (Punkt 5). Reihenfolge: +;; Fall 1 - letzter-typ="Separator"/"GF" (session-lokal bekannt, reduzierter +;; aber vorhandener Eingang - kein GF1-Stumpf, ggf. kein neuer Separator). +;; Fall 2 - letzter-typ="Vario-Kurve": die hat keine eigene Umlenkstation/ +;; keinen Abschluss - eine zweite waere mechanisch sinnlos -> KEINE +;; Umlenkstation. +;; Fall 3 - echter Kettenanfang OHNE AS-Element (kettenanfang UND NICHT +;; as-vorhanden): am Startpunkt wird per KS_AUS-Scan (vfl-ks-aus-hz-an- +;; punkt) nachgesehen, was dort schon steht: +;; - eindeutig VF-Familie erkannt -> KEINE Umlenkstation. +;; - eindeutig GF-Familie (GF-Bogen) erkannt -> voller Eingang. +;; - NICHTS Eindeutiges (auch bei einer reinen GF-Geraden/VF-Horizontal- +;; stueck, die per Blockname nicht unterscheidbar sind - siehe +;; vfl-kette-typ-familie) -> der automatische Scan kann hier prinzipiell +;; nicht entscheiden, also EINE flache 3-Optionen-Frage an den Nutzer: +;; Option Eins - direkt Umlenkstation (kein GF-Stumpf); Option Zwei - GF- +;; Stumpf+Umlenkstation; Option Drei - ohne Umlenkstation (VF-Fortsetzung). +;; Bewusst NICHT verschachtelt (erst VF/GF, dann ggf. nachfragen) - ist +;; der Vorgaenger bereits SICHER bekannt (Fall 1/letzter-typ), gibt es +;; ohnehin keine Frage; hier ist die Lage grundsaetzlich unklar, daher +;; gleich alle drei Ergebnisse gleichwertig anbieten. +;; Fall 4 - sonst voller Eingang (GF1+Separator+Umlenkstation). +;; WICHTIG fuer den Aufrufer: bei ALLEN reduzierten Faellen (Separator/GF/ +;; Vario-Kurve/keine) ist L_GF danach 0.0 (vfl-vf-einheit zerlegt L_GF-eff +;; dann ohnehin auf 0.0) - es gibt also KEINE frei waehlbare GF-Laenge mehr, +;; mit der ein 2-Unbekannten-Solve (Zielhoehe -> L_GF+L_VF, wie +;; vfl-vf-entscheidung) eine beliebige Zielhoehe treffen koennte. In allen +;; reduzierten Faellen muss der Aufrufer daher die Punkt-7-Winkel/Hoehen- +;; Tabelle (vfl-waehle-winkel-hoehen-tabelle) statt einer Zielhoehe-Abfrage +;; nutzen - nur bei vollem Eingang (nil) bleibt die klassische Zielhoehe- +;; Abfrage sinnvoll (L_GF dort frei, kann exakt auf die Zielhoehe hinsolvet +;; werden). Rueckgabe: (lgf . eingang-modus). +(defun vfl-eingang-modus-bestimmen (letzter-typ kettenanfang as-vorhanden p-aktuell / + erg familie antwort) + (cond + ((equal letzter-typ "Separator") (cons 0.0 "separator")) + ((equal letzter-typ "GF") (cons 0.0 "gf")) + ((equal letzter-typ "Vario-Kurve") (cons 0.0 "keine")) + ((and kettenanfang (not as-vorhanden)) + (setq erg (vfl-ks-aus-hz-an-punkt p-aktuell)) + (setq familie (if erg (vfl-kette-typ-familie (cdr erg)) nil)) + (cond + ((equal familie "VF") (cons 0.0 "keine")) + ((equal familie "GF") (cons *vfl-gf-min-laenge* nil)) + (t + (princ (ssg-textf "vfl-frage-startpunkt-typ" (list (rtos *vfl-gf-min-laenge* 2 0)))) + (princ (ssg-text "vfl-opt-eingang-direkt")) + (princ (ssg-textf "vfl-opt-eingang-mit-stumpf" (list (rtos *vfl-gf-min-laenge* 2 0)))) + (princ (ssg-text "vfl-opt-eingang-ohne-umlenk")) + (if (vfl-wizard-aktiv) + (vl-catch-all-apply 'vflw-gruppe-startpunkt-typ-impl nil)) + (setq antwort (vfl-menu (ssg-text "vfl-prompt-wahl-1-3-def1") + (list (ssg-text "vfl-opt-eingang-direkt") + (ssg-textf "vfl-opt-eingang-mit-stumpf" (list (rtos *vfl-gf-min-laenge* 2 0))) + (ssg-text "vfl-opt-eingang-ohne-umlenk")) 1 + "vfl-frage-startpunkt-typ")) + (cond + ((= antwort "2") (cons *vfl-gf-min-laenge* nil)) + ((= antwort "3") (cons 0.0 "keine")) + (t (cons 0.0 "gf")) + ) + ) + ) + ) + (t (cons *vfl-gf-min-laenge* nil)) + ) +) + ;; Kettenanfang-Baustein: falls as-vorhanden, AS-Element einfuegen und die ;; GF/VF-Restlaenge um den tatsaechlichen AS-Fussabdruck kuerzen. Falls NICHT ;; as-vorhanden (Nutzer hat "Kein AS-Element" gewaehlt), beginnt die Kette @@ -2846,13 +4259,22 @@ ;; sodass diese als Glied-Inhalt darauf folgen. Beim Replay wird der Marker in ;; vfl-replay-pop automatisch uebersprungen; die beiden STR-Werte poppen danach ;; regulaer. -(defun vfl-frage-es-seite ( / antwort es-seite) +;; dialog-schon-gezeigt: T, wenn Winkel+Seite BEREITS ueber einen vorherigen +;; kombinierten Dialog (vflw-gruppe-as-impl, "ES-Element setzen?" + Winkel + +;; Seite in einem Bildschirm) abgefragt und in die Pending-Queue gelegt +;; wurden - dann NICHT nochmal den eigenen Winkel+Seite-Dialog zeigen (sonst +;; doppelter Dialog), nur die bereits wartenden Werte konsumieren. Sonst +;; (normaler Fall) nil - eigener Dialog wie bisher. +(defun vfl-frage-es-seite (dialog-schon-gezeigt / antwort es-seite) (vfl-journal-mark "ES") - (if (vfl-wizard-aktiv) + (if (and (vfl-wizard-aktiv) (not dialog-schon-gezeigt)) (vl-catch-all-apply 'vflw-gruppe-winkel-seite-impl (list "vf-winkel-ein-header" (list (ssg-text "vf-winkel-90") (ssg-text "vf-winkel-30")) (list "90" "30")))) + (princ (ssg-text "vf-winkel-ein-header")) + (princ (ssg-text "vf-winkel-90")) + (princ (ssg-text "vf-winkel-30")) (setq *vfl-es-winkel* (vfl-in-value "STR" (function (lambda () (vf-frage-element-winkel "vf-winkel-ein-header"))))) ; 30/90 vor Seite @@ -3001,19 +4423,33 @@ ;; winkel1=0 => horizontaler Anfangs-Koerper (Option "Neue horizontal VF"). ;; auto-ende: T => keine Kettenende-Frage, es wird direkt Separator + ES ;; gesetzt (Option "Neue Linie BIS Kettenende"). +;; gf-verteilung-fest: nil => Verteilung wie bisher interaktiv erfragen. +;; "1"/"2" => Frage UEBERSPRINGEN, direkt mit dieser Antwort weiterbauen - +;; fuer den horizontalen Anfangs-Koerper: L_GF ist dort nur der +;; strukturelle Mindest-Eingang (kein frei waehlbarer Staustrecke-Puffer), +;; die Frage waere fuer den Nutzer bedeutungslos. Das Ausgangs-Ende regelt +;; dort stattdessen ausschliesslich die mit/ohne-Motorstation-Frage in +;; vfl-baue-horizontal-koerper. +;; eingang-modus: nil/"gf"/"separator" - siehe vfl-vf-einheit, wird nur +;; durchgereicht (vom Aufrufer aus letzter-typ abgeleitet). ;; Rueckgabe: (frame anzahl-koerper ende-flag es-seite-oder-nil). -(defun vfl-vf-einheit-abschluss (frame hz richtung winkel L_GF L_VF auto-ende / - antwort res es-s ende es-gewuenscht) +(defun vfl-vf-einheit-abschluss (frame hz richtung winkel L_GF L_VF auto-ende gf-verteilung-fest eingang-modus / + antwort res es-s ende es-gewuenscht es-seite-vorab) ;; GF-Verteilung: halbe Staustrecke am Ausgang (GF2) oder alles am Einlauf. - (princ (ssg-text "vfl-gf-verteilung-header")) - (princ (ssg-text "vfl-gf-verteilung-haelfte")) - (princ (ssg-text "vfl-gf-verteilung-ganz-einlauf")) - (setq antwort (vfl-menu (ssg-text "vfl-prompt-wahl-1-2-def2") - (list (ssg-text "vfl-gf-verteilung-haelfte") - (ssg-text "vfl-gf-verteilung-ganz-einlauf")) 2 - "vfl-gf-verteilung-header")) - (setq res (vfl-vf-einheit frame hz richtung winkel L_GF L_VF (= antwort "1"))) - (setq frame (nth 0 res) es-gewuenscht (nth 3 res)) + (if gf-verteilung-fest + (setq antwort gf-verteilung-fest) + (progn + (princ (ssg-text "vfl-gf-verteilung-header")) + (princ (ssg-text "vfl-gf-verteilung-haelfte")) + (princ (ssg-text "vfl-gf-verteilung-ganz-einlauf")) + (if (vfl-wizard-aktiv) + (vl-catch-all-apply 'vflw-gruppe-gf-verteilung-impl (list (ssg-text "vfl-gf-verteilung-header") "1" "2"))) + (setq antwort (vfl-menu (ssg-text "vfl-prompt-wahl-1-2-def2") + (list (ssg-text "vfl-gf-verteilung-haelfte") + (ssg-text "vfl-gf-verteilung-ganz-einlauf")) 2 + "vfl-gf-verteilung-header")))) + (setq res (vfl-vf-einheit frame hz richtung winkel L_GF L_VF (= antwort "1") eingang-modus)) + (setq frame (nth 0 res) es-gewuenscht (nth 3 res) es-seite-vorab (nth 4 res)) ;; Kettenende? Bei auto-ende (Kettenende-Modus) ohne Frage direkt ES setzen. ;; ziel-ende (Option 3 IN der VF-Einheit) OHNE ES-Wunsch (dort abgefragt, ;; siehe vfl-vf-einheit): Kette endet direkt hier, kein Separator+ES, keine @@ -3028,6 +4464,8 @@ (princ (ssg-text "vfl-ist-kettenende-frage")) (princ (ssg-text "vfl-ja-separator-es")) (princ (ssg-text "vfl-nein-weiterbauen")) + (if (vfl-wizard-aktiv) + (vl-catch-all-apply 'vflw-gruppe-ist-kettenende-2opt-impl nil)) (setq antwort (vfl-menu (ssg-text "vfl-prompt-wahl-1-2-def2") (list (ssg-text "vfl-ja-separator-es") (ssg-text "vfl-nein-weiterbauen")) 2 @@ -3060,7 +4498,11 @@ ) ) ((= antwort "1") - (setq es-s (vfl-frage-es-seite)) + ;; War die ES-Seite (+Winkel) schon in vfl-vf-einheit erfragt (Option 3, + ;; ziel-ende - dort VOR vfl-body-abschluss noetig, siehe dortiger + ;; Kommentar), hier NICHT erneut fragen (waere doppelt journalisiert und + ;; ein-dx/ein-dz wurden dort schon fuer die Zerlegung genutzt). + (setq es-s (if es-seite-vorab es-seite-vorab (vfl-frage-es-seite nil))) (setq frame (vfl-insert-es-element "VF" frame (car (frame->hz-winkel frame)) 0.0 (caddr (car frame)) es-s)) @@ -3089,6 +4531,8 @@ (princ (ssg-text "vfl-sep-an-stelle-frage")) (princ (ssg-text "vfl-ja")) (princ (ssg-text "vfl-nein")) + (if (vfl-wizard-aktiv) + (vl-catch-all-apply 'vflw-gruppe-ja-nein-impl (list (ssg-text "vfl-sep-an-stelle-frage")))) (setq antwort (vfl-menu (ssg-text "vfl-prompt-wahl-1-2-def2") (list (ssg-text "vfl-ja") (ssg-text "vfl-nein")) 2 "vfl-sep-an-stelle-frage")) @@ -3106,9 +4550,21 @@ entscheidung typ winkel L_GF L_VF vf-einheit-res frame letzter-typ fertig linie-ende-modus rad3 anzahl-gf anzahl-vf vfl-nummer lastEnt seg-lastEnt - gf-max-winkel gf-ok kettenanfang + gf-max-winkel gf-ok kettenanfang gf-laenge-modus as-vorhanden erg old-error vfl-ins dbg-an - hoehe-vorschlaege hoehe-ab hoehe-auf hoehe-fallback) + hoehe-vorschlaege hoehe-ab hoehe-auf hoehe-fallback + sep-vor-gf sep-nach-gf sep-anzahl + vf-eingang-lgf vf-eingang-modus winkel-hoehen-erg eingang-laenge + bogen-mass fest-drop fest-laenge eingang-fertig + gf-steigend-modus erg-bogen) + ;; "Zurueck"/"Abbrechen"-Flag ganz am Anfang zuruecksetzen (auch schon vor + ;; der ersten Praeambel-Frage) - sonst wuerde ein von einem VORHERIGEN Lauf + ;; 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). Wird ausserdem in vfl-acc-reset erneut + ;; zurueckgesetzt (spaeter im Ablauf) sowie unmittelbar vor jedem "Zurueck"- + ;; Neuaufruf in vfl-modus-abbruch-sichern. + (setq *vfl-wizard-abbruch-grund* nil) (princ "\n\n=========================================") (princ (ssg-text "vfl-modus1-header")) (princ "\n=========================================") @@ -3207,6 +4663,9 @@ (setq *vfl-as-winkel* nil *vfl-es-winkel* nil) (if as-vorhanden (progn + (princ (ssg-text "vf-winkel-aus-header")) + (princ (ssg-text "vf-winkel-90")) + (princ (ssg-text "vf-winkel-30")) (setq *vfl-as-winkel* (vfl-in-value "STR" (function (lambda () (vf-frage-element-winkel "vf-winkel-aus-header"))))) ; 30/90 vor Seite @@ -3254,6 +4713,8 @@ ;; Ketten eines vorherigen INSERTs konsistent uebersprungen werden. (setq seg-lastEnt (vf-lastent-ohne-attribute)) (vfl-journal-mark "?") + (if (vfl-wizard-aktiv) + (vl-catch-all-apply 'vflw-gruppe-naechstes-element-impl (list (null frame)))) (if frame (progn (princ (ssg-text "vfl-menu-gf-bogen-1")) @@ -3275,20 +4736,26 @@ (t "Linie-GF"))) ; "2" oder leer ) (progn - (princ (ssg-text "vfl-menu-linie-gf-1")) - (princ (ssg-text "vfl-menu-linie-vf-2")) - (princ (ssg-text "vfl-menu-horizontal-vf-3")) - (princ (ssg-text "vfl-menu-linie-ende-4")) - (setq antwort (vfl-menu (ssg-text "vfl-prompt-wahl-1-4-def1") - (list (ssg-text "vfl-menu-linie-gf-1") - (ssg-text "vfl-menu-linie-vf-2") - (ssg-text "vfl-menu-horizontal-vf-3") - (ssg-text "vfl-menu-linie-ende-4")) 1 + (princ (ssg-text "vfl-menu-gf-bogen-ka-1")) + (princ (ssg-text "vfl-menu-variokurve-ka-2")) + (princ (ssg-text "vfl-menu-linie-gf-ka-3")) + (princ (ssg-text "vfl-menu-linie-vf-ka-4")) + (princ (ssg-text "vfl-menu-horizontal-vf-ka-5")) + (princ (ssg-text "vfl-menu-linie-ende-ka-6")) + (setq antwort (vfl-menu (ssg-text "vfl-prompt-wahl-1-6-def3") + (list (ssg-text "vfl-menu-gf-bogen-ka-1") + (ssg-text "vfl-menu-variokurve-ka-2") + (ssg-text "vfl-menu-linie-gf-ka-3") + (ssg-text "vfl-menu-linie-vf-ka-4") + (ssg-text "vfl-menu-horizontal-vf-ka-5") + (ssg-text "vfl-menu-linie-ende-ka-6")) 3 "vfl-naechstes-element-header")) - (setq wahl (cond ((= antwort "2") "Linie-VF") - ((= antwort "3") "Horizontal-VF") - ((= antwort "4") (setq linie-ende-modus t) "Linie") - (t "Linie-GF"))) ; "1" oder leer + (setq wahl (cond ((= antwort "1") "GF-Bogen") + ((= antwort "2") "Vario-Kurve") + ((= antwort "4") "Linie-VF") + ((= antwort "5") "Horizontal-VF") + ((= antwort "6") (setq linie-ende-modus t) "Linie") + (t "Linie-GF"))) ; "3" oder leer ) ) ;; Segmenttyp steht fest -> Glied-Label nachtragen (fuer die Edit-Liste). @@ -3297,10 +4764,49 @@ (progn (cond ((= wahl "GF-Bogen") + ;; Als ALLERERSTES Kettenglied (frame=nil) braucht eine Kurve technisch + ;; eine Referenzrichtung, von der aus Winkel+Seite (im Dialog von + ;; vfl-insert-gf-bogen abgefragt) gemessen werden - eine zusaetzliche + ;; Punktwahl nur zur Richtungsbestimmung ist ueberfluessig (kein + ;; eigenes Segment, keine Laenge wird dabei gemessen). Liegt der + ;; gewaehlte Startpunkt exakt auf dem KS_AUS eines bestehenden Vario- + ;; Kette-Bausteins (Fortsetzung einer schon gebauten Kette), wird + ;; dessen Richtung uebernommen; sonst Standard Welt-0 Grad/+X-Achse. + ;; Das AS-Element wird ganz normal ueber vfl-kettenanfang-baustein + ;; eingefuegt (deltaL dabei irrelevant, da hier kein Segment gebaut + ;; wird - Wert wird verworfen). + (if (null frame) + (progn + (setq hz-neu (car (vfl-ks-aus-hz-an-punkt p-aktuell))) + (if (null hz-neu) (setq hz-neu 0.0)) + (setq erg (vfl-kettenanfang-baustein p-aktuell hz-neu 0.0 as-seite as-vorhanden)) + (setq frame (nth 0 erg)) + ) + ) (setq frame (vfl-insert-gf-bogen frame)) (setq p-aktuell (car frame)) ) + ((= wahl "Vario-Kurve") + ;; Gleiche Kettenanfang-Behandlung wie GF-Bogen oben (KS_AUS- + ;; Richtungsuebernahme bei Fortsetzung, sonst Welt-0 Grad). + (if (null frame) + (progn + (setq hz-neu (car (vfl-ks-aus-hz-an-punkt p-aktuell))) + (if (null hz-neu) (setq hz-neu 0.0)) + (setq erg (vfl-kettenanfang-baustein p-aktuell hz-neu 0.0 as-seite as-vorhanden)) + (setq frame (nth 0 erg)) + ) + ) + (setq frame (vfl-insert-vario-kurve frame)) + (setq p-aktuell (car frame)) + ;; letzter-typ merken: eine Vario-Kurve hat KEINE eigene Umlenkstation + ;; und ist mechanisch Teil einer VF-Kette - ein direkt folgendes + ;; "Neue Linie: Ab/Auf VF" darf daher keine zweite Umlenkstation bauen + ;; (siehe Sonderfall in wahl="Linie-VF" unten). + (setq letzter-typ "Vario-Kurve") + ) + ;; --- Neue horizontal VF: VF-Einheit mit horizontalem Anfangs-Koerper --- ((= wahl "Horizontal-VF") (setq linie-mess (vfl-neue-linie-messen p-aktuell @@ -3317,172 +4823,240 @@ (setq frame (nth 0 erg) deltaL (nth 1 erg) p-aktuell (car frame)) ) ) - (if (< deltaL *vfk-vf-mindestlaenge*) + ;; KEINE pauschale "Umlenk+Motor"-Mindestlaenge mehr hier: der noetige + ;; Fussabdruck haengt davon ab, ob gleich eine Motorstation folgt oder + ;; weitergebaut wird - genau das fragt vfl-baue-horizontal-koerper + ;; ("Ist der Endpunkt der Foerderer?") und rechnet mit dem REAL + ;; gemessenen Fussabdruck (siehe vfl-vf-einheit). Hier bleibt nur der + ;; Degenerationsschutz wie bei "Neue Linie: GF". + (if (< deltaL 1.0) (progn - (princ (ssg-text "vfl-fehler-horizontal-vf-kurz")) + (princ (ssg-text "vfl-fehler-linie-zu-kurz")) (if dbg-an (dbgmsg (strcat "GEOMETRIE FEHLGESCHLAGEN: Horizontal-VF zu kurz (deltaL=" (rtos deltaL 2 0) ")")))) (progn - ;; VF-Einheit mit horizontalem ersten Koerper (winkel=0, L_VF=deltaL, - ;; L_GF = Mindestlaenge fuer den Einlauf-Anschluss). - (if dbg-an - (dbgmsg (strcat "GEOMETRIE: vfl-vf-einheit-abschluss horizontal (deltaL=" (rtos deltaL 2 0) - " L_GF=" (rtos *vfl-gf-min-laenge* 2 0) " L_VF=" (rtos deltaL 2 0) ")"))) - (setq vf-einheit-res - (vfl-vf-einheit-abschluss frame hz-neu "Ab" 0 *vfl-gf-min-laenge* deltaL nil)) - (setq frame (nth 0 vf-einheit-res)) - (setq anzahl-vf (+ anzahl-vf (nth 1 vf-einheit-res))) - (if (nth 2 vf-einheit-res) (setq fertig t)) - (if (nth 3 vf-einheit-res) (setq es-seite (nth 3 vf-einheit-res))) - (setq letzter-typ "VF") - (setq p-aktuell (car frame)) - (if dbg-an - (dbgmsg (strcat "GEOMETRIE ERFOLG: Horizontal-VF-Einheit gebaut, neue Position=" - (dbg-tostring p-aktuell)))) + ;; Eingang haengt vom VORHERIGEN Kettenglied ab (letzter-typ) bzw. + ;; am echten Kettenanfang vom KS_AUS-Scan - siehe + ;; vfl-eingang-modus-bestimmen (gemeinsam mit "Neue Linie: Ab/Auf + ;; VF", Punkt 5). + (setq erg (vfl-eingang-modus-bestimmen letzter-typ kettenanfang as-vorhanden p-aktuell)) + (setq vf-eingang-lgf (car erg) vf-eingang-modus (cdr erg)) + ;; NEU: bei einem vollen Neuaufbau des Eingangs (modus=nil, GF1 wird + ;; frisch gebaut) wird GF1 nicht mehr pauschal auf *vfl-gf-min-laenge* + ;; gesetzt, sondern aus einer abgefragten Zielhoehe berechnet - der + ;; Rest bleibt wie bisher horizontal. Bei den anderen Eingangs-Modi + ;; ("separator"/"gf"/"keine" - Fortsetzung nach einem Vorglied) wird + ;; ohnehin kein neues GF1 gebaut, daher unveraendert. + (if (null vf-eingang-modus) + (progn + (if (or (not *lib-initialized*) (null bogen-auf)) (init-bibliothek)) + (setq rad3 (* *vfk-gefaelle-winkel* (/ pi 180.0))) + (setq bogen-mass (get-bogen-mass bogen-auf (fix *vfk-gefaelle-winkel*))) + ;; Hoehen- bzw. Laengenanteil der FIXEN Elemente (Separator + + ;; Umlenkstation + Uebergangsbogen), OHNE GF1 - empirisch + ;; bestaetigt: jedes Element traegt Schraeglaenge*sin(3 Grad) an + ;; Hoehe bei, der Uebergangsbogen einen festen, winkelunabhaengigen + ;; dx/dz-Fussabdruck aus der Bogen-Tabelle. + (setq fest-drop (+ (* *vfk-separator-laenge* (sin rad3)) + (* *vfk-stations-laenge* (sin rad3)) + (caddr bogen-mass))) + (setq fest-laenge (+ *vfk-separator-laenge* *vfk-stations-laenge* (car bogen-mass))) + (setq eingang-fertig nil) + (while (not eingang-fertig) + (setq eingang-fertig t) + (if (vfl-wizard-aktiv) + (vl-catch-all-apply 'vflw-gruppe-ziel-hoehe-impl + (list (- (caddr p-aktuell) fest-drop)))) + (setq hoehe-neu + (vfl-in-real (ssg-textf "vfl-prompt-hoehe-eingang-gf1" + (list (rtos (- (caddr p-aktuell) fest-drop) 2 1))))) + (if (null hoehe-neu) (setq hoehe-neu (- (caddr p-aktuell) fest-drop))) + (setq deltaH (- (caddr p-aktuell) hoehe-neu)) + (cond + ((<= deltaH 0.0) + (alert (ssg-text "vfl-alert-eingang-kann-nicht-steigen")) + (setq vf-eingang-lgf nil)) + ((< deltaH fest-drop) + (alert (ssg-textf "vfl-alert-eingang-hoehe-zu-klein" (list (rtos fest-drop 2 0)))) + (setq eingang-fertig nil)) + (t + (setq vf-eingang-lgf (/ (- deltaH fest-drop) (sin rad3))) + (if (> (+ vf-eingang-lgf fest-laenge) deltaL) + (progn + (alert (ssg-textf "vfl-alert-eingang-hoehe-zu-gross" + (list (rtos (- (caddr p-aktuell) fest-drop + (* (- deltaL fest-laenge) (sin rad3))) 2 0)))) + (setq vf-eingang-lgf nil)) + ) + ) + ) + ) + ) + ) + ;; VF-Einheit mit horizontalem ersten Koerper (winkel=0, L_VF=deltaL) - + ;; nur bauen, wenn vf-eingang-lgf gueltig ist (s.o.). Ist es nil (Abbruch + ;; wegen unpassender Zielhoehe), wird NICHTS gebaut - die aeussere + ;; Schleife zeigt danach automatisch wieder "Naechstes Element waehlen". + (if vf-eingang-lgf + (progn + (if dbg-an + (dbgmsg (strcat "GEOMETRIE: vfl-vf-einheit-abschluss horizontal (deltaL=" (rtos deltaL 2 0) + " L_GF=" (rtos vf-eingang-lgf 2 0) " L_VF=" (rtos deltaL 2 0) + " eingang-modus=" (if vf-eingang-modus vf-eingang-modus "voll") ")"))) + ;; GF-Verteilungsfrage entfaellt hier ("2" = alles am Einlauf, + ;; kein GF2 fest vorgegeben): L_GF ist nur der strukturelle + ;; Mindest-Eingang, das Ausgangs-Ende regelt allein die + ;; mit/ohne-Motorstation-Frage (siehe vfl-baue-horizontal-koerper). + (setq vf-einheit-res + (vfl-vf-einheit-abschluss frame hz-neu "Ab" 0 vf-eingang-lgf deltaL nil "2" vf-eingang-modus)) + (setq frame (nth 0 vf-einheit-res)) + (setq anzahl-vf (+ anzahl-vf (nth 1 vf-einheit-res))) + (if (nth 2 vf-einheit-res) (setq fertig t)) + (if (nth 3 vf-einheit-res) (setq es-seite (nth 3 vf-einheit-res))) + (setq letzter-typ "VF") + (setq p-aktuell (car frame)) + (if dbg-an + (dbgmsg (strcat "GEOMETRIE ERFOLG: Horizontal-VF-Einheit gebaut, neue Position=" + (dbg-tostring p-aktuell)))) + ) + ) ) ) ) ;; --- Neue Linie: GF (Nutzer legt den Typ explizit fest) --- ((= wahl "Linie-GF") - ;; Fahrtrichtung folgt dem vorherigen Element (Frame); nur das erste - ;; Segment (frame=nil) definiert die Richtung frei. - (setq linie-mess (vfl-neue-linie-messen p-aktuell - (if frame (car (frame->hz-winkel frame)) nil))) - (if (null linie-mess) (progn (princ (ssg-text "vfl-abgebrochen")) (exit))) - (setq deltaL (car linie-mess) hz-neu (cadr linie-mess)) (setq kettenanfang (null frame)) (setq gf-max-winkel (float (ssg-cfg-or "vario" "gefaelle_winkel" 3))) - (if (< deltaL 1.0) - (princ (ssg-text "vfl-fehler-linie-zu-kurz")) + ;; NEU: Vorfrage "Wie soll die Laenge bestimmt werden?" - IMMER gezeigt + ;; (auch am Kettenanfang: dort wird bei "Zielhoehe festlegen" die + ;; Richtung ueber einen eigenen, reinen Richtungs-Pick bestimmt statt + ;; ueber den sonst richtungsbestimmenden Endpunkt-Klick - siehe unten). + ;; gf-laenge-modus="2" => Zielhoehe zuerst (Zweig B unten), "3" => + ;; steigende GF (Sonderfall, Zweig C unten, eigenstaendig, KEIN + ;; Separator), sonst (Default "1") Endpunkt waehlen (Zweig A, + ;; unveraendertes heutiges Verhalten). + (setq gf-laenge-modus "1") + (if (vfl-wizard-aktiv) (vl-catch-all-apply 'vflw-gruppe-gf-laenge-modus-impl nil)) + (princ (ssg-text "vfl-gf-laenge-modus-header")) + (princ (ssg-text "vfl-gf-laenge-modus-opt-endpunkt")) + (princ (ssg-text "vfl-gf-laenge-modus-opt-hoehe")) + (princ (ssg-text "vfl-gf-laenge-modus-opt-steigend")) + (setq gf-laenge-modus (vfl-menu (ssg-text "prompt-wahl-1-2") + (list (ssg-text "vfl-gf-laenge-modus-opt-endpunkt") + (ssg-text "vfl-gf-laenge-modus-opt-hoehe") + (ssg-text "vfl-gf-laenge-modus-opt-steigend")) 1 + "vfl-gf-laenge-modus-header")) + (setq gf-ok nil) + (cond + ((= gf-laenge-modus "3") (progn - ;; Kettenanfang: AS-Element (falls gewuenscht) SOFORT einfuegen - ;; (Richtung hz-neu jetzt bekannt) und die GF-Restlaenge aus dem - ;; TATSAECHLICHEN KS_AUS nachrechnen (siehe vfl-kettenanfang- - ;; baustein). Keine Fussabdruck-Schaetzung mehr: sowohl KS_EIN- als - ;; auch Ursprung-basierte Vorab-Messung ignorieren die Dreh­teller- - ;; Rotation, die insert-block-mixed-to-ks beim echten Einfuegen - ;; anwendet, und liefern daher einen falschen Wert (empirisch - ;; bestaetigt: ~210mm Schaetzung vs. tatsaechlich ~420mm noetiger - ;; Versatz). - (if kettenanfang + ;; --- Zweig C: Steigende GF (Sonderfall, bis 3 Grad) - eigene, + ;; von Zweig A/B unabhaengige Kopie: KEIN Separator (gilt laut + ;; Vorgabe nur fuer die normale fallende 3-Grad-GF), dafuer + ;; innerhalb dieses Zweigs nochmal dieselbe Wahl (Endpunkt vs. + ;; Zielhoehe) mit Ziel-Richtung "Auf" statt "Ab". Der noetige + ;; Uebergangsbogen (falls die Vorgaenger-Neigung nicht schon zur + ;; steigenden Basis passt) wird zentral im gemeinsamen Abschluss + ;; unten ueber vfl-bogen-uebergang eingefuegt. + (setq sep-vor-gf nil sep-nach-gf nil) + ;; KEIN vflw-gruppe-gf-laenge-modus-impl hier: dessen Dialog zeigt + ;; alle 3 Optionen (inkl. "steigend" erneut) - fuer diese innere + ;; Frage sind nur Endpunkt/Zielhoehe gueltig. vfl-menu nutzt im + ;; Wizard-Modus automatisch den generischen Auswahl-Fallback. + (princ (ssg-text "vfl-gf-laenge-modus-header")) + (princ (ssg-text "vfl-gf-laenge-modus-opt-endpunkt")) + (princ (ssg-text "vfl-gf-laenge-modus-opt-hoehe")) + (setq gf-steigend-modus (vfl-menu (ssg-text "prompt-wahl-1-2") + (list (ssg-text "vfl-gf-laenge-modus-opt-endpunkt") + (ssg-text "vfl-gf-laenge-modus-opt-hoehe")) 1 + "vfl-gf-laenge-modus-header")) + (if (= gf-steigend-modus "2") (progn - (setq erg (vfl-kettenanfang-baustein p-aktuell hz-neu deltaL as-seite as-vorhanden)) - (setq frame (nth 0 erg) deltaL (nth 1 erg) p-aktuell (car frame)) - ) - ) - ;; Nach dem AS-Einfuegen kann die reale Restlaenge (aus dem - ;; tatsaechlichen KS_AUS neu gemessen) kleiner als der urspruenglich - ;; gepickte Rohwert sein - bei einem knapp gepickten Punkt sogar - ;; NEGATIV (das AS-Element allein braucht bereits mehr Platz als bis - ;; zum Klickpunkt vorhanden war). Ohne diese zweite Pruefung wuerde - ;; vfl-insert-gf-segment mit negativem deltaL "erfolgreich" eine - ;; entartete/unsichtbare GF-Strecke bauen (leerer Sprung zwischen AS - ;; und dem naechsten Element) statt den Nutzer erneut picken zu - ;; lassen - siehe vfl-fehler-linie-zu-kurz oben (dieselbe Meldung). - ;; Sofortiger Abbruch DIESES Zweigs (kein Weiterfragen nach Winkel/ - ;; Hoehe fuer ein Segment, das ohnehin nicht gebaut werden kann) - - ;; gf-ok wird unten sonst mehrfach ueberschrieben. - (if (< deltaL 1.0) - (princ (ssg-text "vfl-fehler-linie-zu-kurz")) - (progn - (setq gf-ok t) - (if (vfl-wizard-aktiv) - (vl-catch-all-apply 'vflw-gruppe-gefaelle-impl - (list (vfl-gf-hoehe-vorschlag (caddr p-aktuell))))) - (princ (ssg-text "vfl-gefaelle-festlegen-header")) - (princ (ssg-text "vfl-gefaelle-opt-hoehe")) - (princ (ssg-text "vfl-gefaelle-opt-winkel")) - (setq antwort (vfl-menu (ssg-text "prompt-wahl-1-2") - (list (ssg-text "vfl-gefaelle-opt-hoehe") - (ssg-text "vfl-gefaelle-opt-winkel")) 1 - "vfl-gefaelle-festlegen-header")) - (if (= antwort "2") + ;; --- Zweig C2: Zielhoehe zuerst (steigend) --- + (if kettenanfang (progn - ;; Winkel direkt vorgeben - deltaH ergibt sich aus deltaL*tan(winkel). + (setq hz-neu (vfl-in-richtung p-aktuell (ssg-text "vfl-prompt-richtung-waehlen"))) + (if (null hz-neu) (progn (princ (ssg-text "vfl-abgebrochen")) (exit))) + (setq erg (vfl-kettenanfang-baustein p-aktuell hz-neu 1.0e9 as-seite as-vorhanden)) + (setq frame (nth 0 erg) p-aktuell (car frame)) + ) + (setq hz-neu (car (frame->hz-winkel frame))) + ) + (setq gf-ok t) + (setq hoehe-neu + (vfl-in-real (ssg-textf "vfl-prompt-hoehe-linienendpunkt" + (list (rtos (caddr p-aktuell) 2 1))))) + (if (null hoehe-neu) (setq hoehe-neu (caddr p-aktuell))) + (setq deltaH (- hoehe-neu (caddr p-aktuell))) + (if (< deltaH 0.0) + (progn + (alert (ssg-text "vfl-alert-gf-steigend-falsche-richtung")) + (setq gf-ok nil)) + (progn + ;; KEIN vflw-gruppe-gefaelle-impl hier (im Gegensatz zu + ;; Zweig B): dessen DCL-Dialog ist fest auf den normalen + ;; Wortlaut/Wertebereich (0 < Winkel) zugeschnitten. Der + ;; generische vfl-in-real-Fallback (vflw_zahl) zeigt den + ;; hier uebergebenen Steigend-Prompt korrekt an. + (princ (ssg-text "vfl-gefaelle-festlegen-header")) (setq winkel - (vfl-in-real (ssg-textf "vfl-prompt-neigungswinkel" (list (rtos gf-max-winkel 2 1))))) + (vfl-in-real (ssg-textf "vfl-prompt-neigungswinkel-steigend" (list (rtos gf-max-winkel 2 1))))) (if (null winkel) (setq winkel gf-max-winkel)) - (if (or (<= winkel 0.0) (> winkel gf-max-winkel)) + (if (or (< winkel 0.0) (> winkel gf-max-winkel)) (progn - (alert (ssg-textf "vfl-alert-winkel-ungueltig" + (alert (ssg-textf "vfl-alert-winkel-ungueltig-steigend" (list (rtos winkel 2 1) (rtos gf-max-winkel 2 1)))) (setq gf-ok nil)) - (progn - (setq richtung "Ab") - (setq deltaH (* deltaL (/ (sin (* winkel (/ pi 180.0))) - (cos (* winkel (/ pi 180.0)))))) - ) - ) - ) - (progn - ;; Gegebene Hoehe - wie bisher, aber Winkel wird daraus abgeleitet - ;; und gegen den GF-Maximalwinkel geprueft (GF kann nicht steigen). - ;; p-aktuell ist ab hier immer der reale Referenzpunkt (bei - ;; Kettenanfang das echte KS_AUS des AS-Elements). Vorschlag/ - ;; Enter-Default = vfl-gf-hoehe-vorschlag (siehe dort), NICHT - ;; die unveraenderte Ist-Hoehe - sonst waere deltaH=0 und die - ;; GF-Pruefung wiese den Wert als "kann nicht steigen" ab. - (setq hoehe-neu - (vfl-in-real (ssg-textf "vfl-prompt-hoehe-linienendpunkt" - (list (rtos (vfl-gf-hoehe-vorschlag (caddr p-aktuell)) 2 1))))) - (if (null hoehe-neu) (setq hoehe-neu (vfl-gf-hoehe-vorschlag (caddr p-aktuell)))) - (setq deltaH (- hoehe-neu (caddr p-aktuell))) - (setq richtung (if (>= deltaH 0.0) "Auf" "Ab")) - (setq deltaH (abs deltaH)) - (cond - ((= richtung "Auf") - (alert (ssg-text "vfl-alert-gf-kann-nicht-steigen")) - (if dbg-an - (dbgmsg (strcat "GEOMETRIE FEHLGESCHLAGEN: Linie-GF kann nicht steigen" - " (deltaL=" (rtos deltaL 2 0) " deltaH=" (rtos deltaH 2 0) ")"))) - (setq gf-ok nil)) - (t - (setq winkel (* (atan (/ deltaH deltaL)) (/ 180.0 pi))) - (if (> winkel gf-max-winkel) - (progn - (alert (ssg-textf "vfl-alert-gefaelle-zu-steil" - (list (rtos winkel 2 1) (rtos gf-max-winkel 2 1)))) - (if dbg-an - (dbgmsg (strcat "GEOMETRIE FEHLGESCHLAGEN: Linie-GF zu steil (deltaL=" - (rtos deltaL 2 0) " deltaH=" (rtos deltaH 2 0) - " winkel=" (rtos winkel 2 1) " max=" (rtos gf-max-winkel 2 1) ")"))) - (setq gf-ok nil)) - ) + (if (and (< winkel 1.0e-6) (> deltaH 1.0e-6)) + (progn + (alert (ssg-textf "vfl-alert-winkel-ungueltig-steigend" + (list (rtos winkel 2 1) (rtos gf-max-winkel 2 1)))) + (setq gf-ok nil)) + (progn + (setq deltaL + (if (< winkel 1.0e-6) 0.0 + (/ deltaH (/ (sin (* winkel (/ pi 180.0))) (cos (* winkel (/ pi 180.0))))))) + (if (< deltaL 1.0) + (progn (princ (ssg-text "vfl-fehler-linie-zu-kurz")) (setq gf-ok nil))) + (setq winkel (- winkel)) + ) ) ) ) ) - (if gf-ok + ) + (progn + ;; --- Zweig C1: Endpunkt waehlen (steigend) --- + (setq linie-mess (vfl-neue-linie-messen p-aktuell + (if frame (car (frame->hz-winkel frame)) nil))) + (if (null linie-mess) (progn (princ (ssg-text "vfl-abgebrochen")) (exit))) + (setq deltaL (car linie-mess) hz-neu (cadr linie-mess)) + (if (< deltaL 1.0) + (princ (ssg-text "vfl-fehler-linie-zu-kurz")) (progn - (if dbg-an - (dbgmsg (strcat "GEOMETRIE: vfl-insert-gf-segment (deltaL=" (rtos deltaL 2 0) - " hz=" (rtos hz-neu 2 1) " winkel=" (rtos winkel 2 1) ")"))) - (setq frame (vfl-insert-gf-segment (car frame) hz-neu deltaL winkel)) - (setq anzahl-gf (1+ anzahl-gf)) - (vfl-acc-gf-seg (/ deltaL (cos (* (float winkel) (/ pi 180.0)))) winkel) - (setq letzter-typ "GF") - (setq p-aktuell (car frame)) - (if dbg-an - (dbgmsg (strcat "GEOMETRIE ERFOLG: GF-Segment gebaut, neue Position=" - (dbg-tostring p-aktuell)))) - (princ (ssg-text "vfl-ist-kettenende-header")) - (princ (ssg-text "vfl-kettenende-opt-ja-es")) - (princ (ssg-text "vfl-kettenende-opt-ja-ohne-es")) - (princ (ssg-text "vfl-kettenende-opt-nein")) - (setq antwort (vfl-menu (ssg-text "vfl-prompt-wahl-1-3-def3") - (list (ssg-text "vfl-kettenende-opt-ja-es") - (ssg-text "vfl-kettenende-opt-ja-ohne-es") - (ssg-text "vfl-kettenende-opt-nein")) 3 - "vfl-ist-kettenende-header")) - (cond - ((= antwort "1") - (setq es-seite (vfl-frage-es-seite)) - (setq frame (vfl-insert-es-element "GF" frame hz-neu winkel - (caddr (car frame)) es-seite)) - (setq fertig t)) - ((= antwort "2") (setq fertig t)) + (if kettenanfang + (progn + (setq erg (vfl-kettenanfang-baustein p-aktuell hz-neu deltaL as-seite as-vorhanden)) + (setq frame (nth 0 erg) deltaL (nth 1 erg) p-aktuell (car frame)) + ) + ) + (if (< deltaL 1.0) + (princ (ssg-text "vfl-fehler-linie-zu-kurz")) + (progn + (setq gf-ok t) + (setq winkel + (vfl-in-real (ssg-textf "vfl-prompt-neigungswinkel-steigend" (list (rtos gf-max-winkel 2 1))))) + (if (null winkel) (setq winkel gf-max-winkel)) + (if (or (< winkel 0.0) (> winkel gf-max-winkel)) + (progn + (alert (ssg-textf "vfl-alert-winkel-ungueltig-steigend" + (list (rtos winkel 2 1) (rtos gf-max-winkel 2 1)))) + (setq gf-ok nil)) + (setq winkel (- winkel)) + ) + ) ) ) ) @@ -3490,6 +5064,315 @@ ) ) ) + ((= gf-laenge-modus "2") + (progn + ;; --- Zweig B: Zielhoehe zuerst festlegen, Laenge wird berechnet --- + (if kettenanfang + (progn + ;; Echter Kettenanfang: keine Vorgaenger-Richtung vorhanden - + ;; eigener Richtungs-Pick (Abstand wird ignoriert, siehe + ;; vfl-in-richtung), danach AS-Element (falls gewuenscht) SOFORT + ;; einfuegen (braucht die jetzt bekannte Richtung). Keine feste + ;; Laengen-Budget-Pruefung noetig - Zweig B hat kein deltaL, das + ;; hier schon existieren muesste. + (setq hz-neu (vfl-in-richtung p-aktuell (ssg-text "vfl-prompt-richtung-waehlen"))) + (if (null hz-neu) (progn (princ (ssg-text "vfl-abgebrochen")) (exit))) + (setq erg (vfl-kettenanfang-baustein p-aktuell hz-neu 1.0e9 as-seite as-vorhanden)) + (setq frame (nth 0 erg) p-aktuell (car frame)) + ) + ;; Sonst: Richtung vom Vorgaenger-Frame uebernehmen - kein Pick. + (setq hz-neu (car (frame->hz-winkel frame))) + ) + (setq rad3 (* gf-max-winkel (/ pi 180.0))) + ;; Separator VOR/NACH wie in Zweig A abfragen - hier aber NICHT von + ;; einer festen Laenge abziehen (die gibt es noch nicht), sondern + ;; ihr Hoehenanteil wird unten von der Zielhoehe abgezogen. + (if (vfl-wizard-aktiv) + (vl-catch-all-apply 'vflw-gruppe-sep-gf-impl nil)) + (princ (ssg-text "vfl-sep-vor-gf-frage")) + (princ (ssg-text "vfl-ja")) + (princ (ssg-text "vfl-nein")) + (setq sep-vor-gf (= (vfl-menu (ssg-text "vfl-prompt-wahl-1-2-def2") + (list (ssg-text "vfl-ja") (ssg-text "vfl-nein")) 2 + "vfl-sep-vor-gf-frage") "1")) + (princ (ssg-text "vfl-sep-nach-gf-frage")) + (princ (ssg-text "vfl-ja")) + (princ (ssg-text "vfl-nein")) + (setq sep-nach-gf (= (vfl-menu (ssg-text "vfl-prompt-wahl-1-2-def2") + (list (ssg-text "vfl-ja") (ssg-text "vfl-nein")) 2 + "vfl-sep-nach-gf-frage") "1")) + (setq sep-anzahl (+ (if sep-vor-gf 1 0) (if sep-nach-gf 1 0))) + (setq gf-ok t) + (setq hoehe-neu + (vfl-in-real (ssg-textf "vfl-prompt-hoehe-linienendpunkt" + (list (rtos (vfl-gf-hoehe-vorschlag (caddr p-aktuell)) 2 1))))) + (if (null hoehe-neu) (setq hoehe-neu (vfl-gf-hoehe-vorschlag (caddr p-aktuell)))) + (setq deltaH (- hoehe-neu (caddr p-aktuell))) + (setq richtung (if (>= deltaH 0.0) "Auf" "Ab")) + (setq deltaH (abs deltaH)) + (if (= richtung "Auf") + (progn + (alert (ssg-text "vfl-alert-gf-kann-nicht-steigen")) + (if dbg-an + (dbgmsg (strcat "GEOMETRIE FEHLGESCHLAGEN: Linie-GF (Zielhoehe zuerst) kann nicht steigen" + " (deltaH=" (rtos deltaH 2 0) ")"))) + (setq gf-ok nil)) + (progn + ;; Hoehenanteil der Separatoren vorab abziehen (Reihenfolge + ;; hier umgekehrt zu Zweig A: Hoehe zuerst, Winkel/Laenge + ;; danach - siehe Kommentar oben). + (if (> sep-anzahl 0) + (setq deltaH (max 0.0 (- deltaH (* sep-anzahl *vfk-separator-laenge* (sin rad3)))))) + (if (vfl-wizard-aktiv) + (vl-catch-all-apply 'vflw-gruppe-gefaelle-impl + (list (vfl-gf-hoehe-vorschlag (caddr p-aktuell)) t))) + (princ (ssg-text "vfl-gefaelle-festlegen-header")) + (setq winkel + (vfl-in-real (ssg-textf "vfl-prompt-neigungswinkel-laenge-berechnet" (list (rtos gf-max-winkel 2 1))))) + (if (null winkel) (setq winkel gf-max-winkel)) + (if (or (<= winkel 0.0) (> winkel gf-max-winkel)) + (progn + (alert (ssg-textf "vfl-alert-winkel-ungueltig" + (list (rtos winkel 2 1) (rtos gf-max-winkel 2 1)))) + (setq gf-ok nil)) + (progn + (setq deltaL (/ deltaH (/ (sin (* winkel (/ pi 180.0))) (cos (* winkel (/ pi 180.0)))))) + (if (< deltaL 1.0) + (progn (princ (ssg-text "vfl-fehler-linie-zu-kurz")) (setq gf-ok nil))) + ) + ) + ) + ) + ) + ) + (t + (progn + ;; --- Zweig A: Endpunkt waehlen (heutiges Verhalten, unveraendert) --- + ;; Fahrtrichtung folgt dem vorherigen Element (Frame); nur das + ;; erste Segment (frame=nil) definiert die Richtung frei. + (setq linie-mess (vfl-neue-linie-messen p-aktuell + (if frame (car (frame->hz-winkel frame)) nil))) + (if (null linie-mess) (progn (princ (ssg-text "vfl-abgebrochen")) (exit))) + (setq deltaL (car linie-mess) hz-neu (cadr linie-mess)) + (if (< deltaL 1.0) + (princ (ssg-text "vfl-fehler-linie-zu-kurz")) + (progn + ;; Kettenanfang: AS-Element (falls gewuenscht) SOFORT einfuegen + ;; (Richtung hz-neu jetzt bekannt) und die GF-Restlaenge aus dem + ;; TATSAECHLICHEN KS_AUS nachrechnen (siehe vfl-kettenanfang- + ;; baustein). Keine Fussabdruck-Schaetzung mehr: sowohl KS_EIN- als + ;; auch Ursprung-basierte Vorab-Messung ignorieren die Dreh­teller- + ;; Rotation, die insert-block-mixed-to-ks beim echten Einfuegen + ;; anwendet, und liefern daher einen falschen Wert (empirisch + ;; bestaetigt: ~210mm Schaetzung vs. tatsaechlich ~420mm noetiger + ;; Versatz). + (if kettenanfang + (progn + (setq erg (vfl-kettenanfang-baustein p-aktuell hz-neu deltaL as-seite as-vorhanden)) + (setq frame (nth 0 erg) deltaL (nth 1 erg) p-aktuell (car frame)) + ) + ) + ;; Nach dem AS-Einfuegen kann die reale Restlaenge (aus dem + ;; tatsaechlichen KS_AUS neu gemessen) kleiner als der urspruenglich + ;; gepickte Rohwert sein - bei einem knapp gepickten Punkt sogar + ;; NEGATIV (das AS-Element allein braucht bereits mehr Platz als bis + ;; zum Klickpunkt vorhanden war). Ohne diese zweite Pruefung wuerde + ;; vfl-insert-gf-segment mit negativem deltaL "erfolgreich" eine + ;; entartete/unsichtbare GF-Strecke bauen (leerer Sprung zwischen AS + ;; und dem naechsten Element) statt den Nutzer erneut picken zu + ;; lassen - siehe vfl-fehler-linie-zu-kurz oben (dieselbe Meldung). + ;; Sofortiger Abbruch DIESES Zweigs (kein Weiterfragen nach Winkel/ + ;; Hoehe fuer ein Segment, das ohnehin nicht gebaut werden kann) - + ;; gf-ok wird unten sonst mehrfach ueberschrieben. + (if (< deltaL 1.0) + (princ (ssg-text "vfl-fehler-linie-zu-kurz")) + (progn + (setq gf-ok t) + ;; Separator VOR/NACH JETZT fragen, BEVOR Hoehe/Winkel berechnet + ;; wird - gueltige Trennstellen GF-GF bzw. GF-Umlenkstation. + ;; Beide Laengen (genaehert mit dem Referenzwinkel gf-max-winkel, + ;; da der tatsaechliche GF-Winkel erst danach feststeht - siehe + ;; analoge Naeherung im Kettenende-Modus/wahl="Linie") werden + ;; SOFORT vom 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)) + (princ (ssg-text "vfl-sep-vor-gf-frage")) + (princ (ssg-text "vfl-ja")) + (princ (ssg-text "vfl-nein")) + (setq sep-vor-gf (= (vfl-menu (ssg-text "vfl-prompt-wahl-1-2-def2") + (list (ssg-text "vfl-ja") (ssg-text "vfl-nein")) 2 + "vfl-sep-vor-gf-frage") "1")) + (princ (ssg-text "vfl-sep-nach-gf-frage")) + (princ (ssg-text "vfl-ja")) + (princ (ssg-text "vfl-nein")) + (setq sep-nach-gf (= (vfl-menu (ssg-text "vfl-prompt-wahl-1-2-def2") + (list (ssg-text "vfl-ja") (ssg-text "vfl-nein")) 2 + "vfl-sep-nach-gf-frage") "1")) + (setq sep-anzahl (+ (if sep-vor-gf 1 0) (if sep-nach-gf 1 0))) + (if (> sep-anzahl 0) + (setq deltaL (- deltaL (* sep-anzahl *vfk-separator-laenge* (cos rad3))))) + (if (< deltaL 1.0) + (progn (princ (ssg-text "vfl-fehler-linie-zu-kurz")) (setq gf-ok nil))) + (if gf-ok + (progn + (if (vfl-wizard-aktiv) + (vl-catch-all-apply 'vflw-gruppe-gefaelle-impl + (list (vfl-gf-hoehe-vorschlag (caddr p-aktuell)) nil))) + (princ (ssg-text "vfl-gefaelle-festlegen-header")) + (princ (ssg-text "vfl-gefaelle-opt-winkel")) + (princ (ssg-text "vfl-gefaelle-opt-hoehe")) + (setq antwort (vfl-menu (ssg-text "prompt-wahl-1-2") + (list (ssg-text "vfl-gefaelle-opt-winkel") + (ssg-text "vfl-gefaelle-opt-hoehe")) 1 + "vfl-gefaelle-festlegen-header")) + (if (= antwort "1") + (progn + ;; Winkel direkt vorgeben - deltaH ergibt sich aus deltaL*tan(winkel). + ;; deltaL ist hier schon um Separator VOR/NACH reduziert. + (setq winkel + (vfl-in-real (ssg-textf "vfl-prompt-neigungswinkel" (list (rtos gf-max-winkel 2 1))))) + (if (null winkel) (setq winkel gf-max-winkel)) + (if (or (<= winkel 0.0) (> winkel gf-max-winkel)) + (progn + (alert (ssg-textf "vfl-alert-winkel-ungueltig" + (list (rtos winkel 2 1) (rtos gf-max-winkel 2 1)))) + (setq gf-ok nil)) + (progn + (setq richtung "Ab") + (setq deltaH (* deltaL (/ (sin (* winkel (/ pi 180.0))) + (cos (* winkel (/ pi 180.0)))))) + ) + ) + ) + (progn + ;; Gegebene Hoehe - wie bisher, aber Winkel wird daraus abgeleitet + ;; und gegen den GF-Maximalwinkel geprueft (GF kann nicht steigen). + ;; p-aktuell ist ab hier immer der reale Referenzpunkt (bei + ;; Kettenanfang das echte KS_AUS des AS-Elements). Vorschlag/ + ;; Enter-Default = vfl-gf-hoehe-vorschlag (siehe dort), NICHT + ;; die unveraenderte Ist-Hoehe - sonst waere deltaH=0 und die + ;; GF-Pruefung wiese den Wert als "kann nicht steigen" ab. + (setq hoehe-neu + (vfl-in-real (ssg-textf "vfl-prompt-hoehe-linienendpunkt" + (list (rtos (vfl-gf-hoehe-vorschlag (caddr p-aktuell)) 2 1))))) + (if (null hoehe-neu) (setq hoehe-neu (vfl-gf-hoehe-vorschlag (caddr p-aktuell)))) + (setq deltaH (- hoehe-neu (caddr p-aktuell))) + (setq richtung (if (>= deltaH 0.0) "Auf" "Ab")) + (setq deltaH (abs deltaH)) + ;; Hoehenanteil der Separator(en) (genaehert auf rad3, + ;; siehe Laengen-Abzug oben) ebenfalls abziehen, sonst + ;; wuerde die Kette am Ende leicht unter/ueber die + ;; gegebene Zielhoehe hinausschiessen. + (if (> sep-anzahl 0) + (setq deltaH (max 0.0 (- deltaH (* sep-anzahl *vfk-separator-laenge* (sin rad3)))))) + (cond + ((= richtung "Auf") + (alert (ssg-text "vfl-alert-gf-kann-nicht-steigen")) + (if dbg-an + (dbgmsg (strcat "GEOMETRIE FEHLGESCHLAGEN: Linie-GF kann nicht steigen" + " (deltaL=" (rtos deltaL 2 0) " deltaH=" (rtos deltaH 2 0) ")"))) + (setq gf-ok nil)) + (t + (setq winkel (* (atan (/ deltaH deltaL)) (/ 180.0 pi))) + (if (> winkel gf-max-winkel) + (progn + (alert (ssg-textf "vfl-alert-gefaelle-zu-steil" + (list (rtos winkel 2 1) (rtos gf-max-winkel 2 1)))) + (if dbg-an + (dbgmsg (strcat "GEOMETRIE FEHLGESCHLAGEN: Linie-GF zu steil (deltaL=" + (rtos deltaL 2 0) " deltaH=" (rtos deltaH 2 0) + " winkel=" (rtos winkel 2 1) " max=" (rtos gf-max-winkel 2 1) ")"))) + (setq gf-ok nil)) + ) + ) + ) + ) + ) + ) + ) + ) + ) + ) + ) + ) + ) + ) + ;; --- Gemeinsamer Abschluss fuer BEIDE Zweige/Zweig C (unveraendert bzw. + ;; per vfl-bogen-uebergang um den Steigend-Sonderfall erweitert) --- + (if gf-ok + (progn + ;; Uebergangsbogen(n) einfuegen, falls die aktuelle Frame-Neigung + ;; nicht zur Ziel-Neigung dieser Linie passt: noetig fuer den + ;; Steigend-Sonderfall (Zweig C, winkel < 0) UND falls der + ;; VORGAENGER eine steigende GF war und jetzt normal (Zweig A/B) + ;; weitergebaut wird. Im unveraenderten Normalfall (Vorgaenger- + ;; Neigung bereits 0/+3, Ziel +3 wie bisher) ist die Bedingung + ;; falsch - kein Verhaltensunterschied zu vorher. + (if (or (< winkel 0.0) (< (cadr (frame->hz-winkel frame)) (- *vfl-gf-winkel-toleranz*))) + (progn + (setq erg-bogen (vfl-bogen-uebergang frame winkel)) + (setq frame (car erg-bogen)) + (setq deltaL (- deltaL (cadr erg-bogen))) + (if (< deltaL 1.0) + (progn (princ (ssg-text "vfl-fehler-linie-zu-kurz")) (setq gf-ok nil))) + ) + ) + (if gf-ok + (progn + ;; Separator VOR (Antwort aus der Vorab-Frage oben) - VOR + ;; dem GF-Segment selbst einfuegen, am GF-Winkel (analog + ;; vfl-insert-es-element bei typ="GF"). + (if sep-vor-gf + (progn + (setq frame (make-frame-from-dir + (gf-insert-hz-with-ks "Staustrecke_Separator_SP_300_mm" + (car frame) hz-neu winkel *vfk-separator-laenge* 0) + (hz-winkel->xu hz-neu winkel))) + (setq *vfl-acc-separator* (1+ *vfl-acc-separator*)) + ) + ) + (if dbg-an + (dbgmsg (strcat "GEOMETRIE: vfl-insert-gf-segment (deltaL=" (rtos deltaL 2 0) + " hz=" (rtos hz-neu 2 1) " winkel=" (rtos winkel 2 1) ")"))) + (setq frame (vfl-insert-gf-segment (car frame) hz-neu deltaL winkel)) + (setq anzahl-gf (1+ anzahl-gf)) + (vfl-acc-gf-seg (/ deltaL (cos (* (float winkel) (/ pi 180.0)))) winkel) + (setq letzter-typ "GF") + (setq p-aktuell (car frame)) + (if dbg-an + (dbgmsg (strcat "GEOMETRIE ERFOLG: GF-Segment gebaut, neue Position=" + (dbg-tostring p-aktuell)))) + ;; Separator NACH (Antwort aus der Vorab-Frage oben) - + ;; DIREKT nach dem GF-Segment einfuegen, noch VOR der + ;; Kettenende-Frage (letzter-typ dadurch "Separator", nicht + ;; mehr "GF" - relevant fuer den naechsten VF-Einheit- + ;; Eingang). + (if sep-nach-gf + (progn + (setq frame (make-frame-from-dir + (gf-insert-hz-with-ks "Staustrecke_Separator_SP_300_mm" + (car frame) hz-neu winkel *vfk-separator-laenge* 0) + (hz-winkel->xu hz-neu winkel))) + (setq *vfl-acc-separator* (1+ *vfl-acc-separator*)) + (setq letzter-typ "Separator") + (setq p-aktuell (car frame)) + ) + ) + (setq antwort (vfl-frage-ist-kettenende)) + (cond + ((= antwort "1") + (setq es-seite (vfl-frage-es-seite nil)) + (setq frame (vfl-insert-es-element "GF" frame hz-neu winkel + (caddr (car frame)) es-seite)) + (setq fertig t)) + ((= antwort "2") (setq fertig t)) + ) + ) + ) + ) + ) ) ;; --- Neue Linie: Ab/Auf VF (Nutzer legt den Typ explizit fest) --- @@ -3510,6 +5393,83 @@ ) (if (< deltaL *vfk-vf-mindestlaenge*) (princ (ssg-text "vfl-fehler-vf-kurz")) + (progn + ;; Eingang haengt vom VORHERIGEN Kettenglied ab (letzter-typ) bzw. + ;; am echten Kettenanfang vom KS_AUS-Scan - siehe + ;; vfl-eingang-modus-bestimmen (gemeinsam mit "Neue VF mit + ;; horizontalem Anfang", Punkt 5). + (setq erg (vfl-eingang-modus-bestimmen letzter-typ kettenanfang as-vorhanden p-aktuell)) + (setq L_GF (car erg) vf-eingang-modus (cdr erg)) + (if vf-eingang-modus + ;; Reduzierter Eingang (Separator/GF/keine): L_GF ist danach immer + ;; 0.0 (vfl-vf-einheit zerlegt L_GF-eff sowieso auf 0.0) - keine + ;; frei waehlbare GF-Laenge mehr, mit der ein 2-Unbekannten-Solve + ;; (vfl-vf-entscheidung) eine beliebige Zielhoehe treffen koennte. + ;; Daher wie Punkt 7 direkt Richtung+Winkel/Hoehen-Tabelle statt + ;; Zielhoehe-Abfrage (siehe vfl-eingang-modus-bestimmen). + (progn + (princ (ssg-text "vfl-frage-auf-ab-richtung")) + (princ (ssg-text "vfl-opt-richtung-auf")) + (princ (ssg-text "vfl-opt-richtung-ab")) + (if (vfl-wizard-aktiv) + (vl-catch-all-apply 'vflw-gruppe-richtung-impl + (list (ssg-text "vfl-frage-auf-ab-richtung")))) + (setq antwort (vfl-menu (ssg-text "vfl-prompt-wahl-1-2") + (list (ssg-text "vfl-opt-richtung-auf") + (ssg-text "vfl-opt-richtung-ab")) 1 + "vfl-frage-auf-ab-richtung")) + (setq richtung (if (= antwort "2") "Ab" "Auf")) + ;; Anders als bei "keine" (Vario-Kurve/Blank-Scan, dort wird + ;; NICHTS gebaut) wird bei "gf"/"separator" tatsaechlich noch + ;; Separator+Umlenkstation (bzw. nur Umlenkstation) eingefuegt, + ;; BEVOR der Kletter-Koerper beginnt - das verbraucht reale + ;; Laenge/Hoehe (beide auf 3-Grad-Basis), die hier VOR dem + ;; Tabellen-Aufruf abgezogen werden muss, sonst waere die Tabelle + ;; zu optimistisch (laenger/hoeher als tatsaechlich baubar). + (setq eingang-laenge + (cond + ((equal vf-eingang-modus "gf") (+ *vfk-separator-laenge* *vfk-stations-laenge*)) + ((equal vf-eingang-modus "separator") *vfk-stations-laenge*) + (t 0.0))) + (setq winkel-hoehen-erg + (vfl-waehle-winkel-hoehen-tabelle + (- deltaL (* eingang-laenge (cos (* *vfk-gefaelle-winkel* (/ pi 180.0))))) + richtung + (- (caddr p-aktuell) (* eingang-laenge (sin (* *vfk-gefaelle-winkel* (/ pi 180.0))))))) + (if (null winkel-hoehen-erg) + (princ (ssg-text "vfl-linie-zu-kurz-simple")) + (progn + (setq winkel (nth 0 winkel-hoehen-erg) L_VF (nth 2 winkel-hoehen-erg)) + (if dbg-an + (dbgmsg (strcat "GEOMETRIE: vfl-vf-einheit-abschluss reduzierter Eingang (deltaL=" + (rtos deltaL 2 0) " richtung=" richtung + " winkel=" (rtos (float winkel) 2 1) + " L_VF=" (rtos L_VF 2 0) + " eingang-modus=" vf-eingang-modus ")"))) + (setq vf-einheit-res + (vfl-vf-einheit-abschluss frame hz-neu richtung winkel L_GF L_VF nil "2" vf-eingang-modus)) + (setq frame (nth 0 vf-einheit-res)) + (setq anzahl-vf (+ anzahl-vf (nth 1 vf-einheit-res))) + (if (nth 2 vf-einheit-res) (setq fertig t)) + (if (nth 3 vf-einheit-res) (setq es-seite (nth 3 vf-einheit-res))) + (setq letzter-typ "VF") + (setq p-aktuell (car frame)) + ;; KEIN Ist-Ziel-Vergleich mehr gegen hoehe-neu hier: hoehe-neu + ;; sagt nur das Ergebnis DIESES einen Kletter-Segments voraus, + ;; aber vfl-vf-einheit-abschluss kann intern beliebig viele + ;; weitere Glieder anhaengen (Vario-Kurve, Kettenende-Zerlegung + ;; mit eigener Hoehenaenderung), BEVOR es hier zurueckkehrt - + ;; der Vergleich war dadurch nach jedem "weiterbauen" spaeter + ;; systematisch falsch (verglich Kletter-Vorhersage mit der + ;; Hoehe NACH allen Folgegliedern). Der echte Ist-Ziel-Vergleich + ;; (Kettenende-Fall) sitzt bereits korrekt in + ;; vfl-vf-einheit-abschluss selbst (*vfl-ziel-punkt*). + (if dbg-an + (dbgmsg (strcat "GEOMETRIE ERFOLG: VF-Einheit reduzierter Eingang gebaut, neue Position=" + (dbg-tostring p-aktuell)))) + ) + ) + ) (progn (setq hoehe-vorschlaege (vfl-vf-hoehe-vorschlaege (caddr p-aktuell) deltaL)) (setq hoehe-ab (nth 0 hoehe-vorschlaege) hoehe-auf (nth 1 hoehe-vorschlaege)) @@ -3535,6 +5495,21 @@ (progn (alert (ssg-textf "vfl-alert-vf-nicht-baubar" (list (rtos deltaL 2 0) (rtos deltaH 2 0) richtung))) + ;; Gesammelte Stufe-2-Diagnose (falls versucht) + kompaktes + ;; 2-Punkte-Alert mit Mindestwerten - analog vfl-body-abschluss. + (if *vfl-stufe2-diagnose-text* (princ *vfl-stufe2-diagnose-text*)) + (alert + (strcat + (ssg-textf "vfl-alert-vf-entscheidung-p1" (list (rtos deltaL 2 0) (rtos deltaH 2 0) richtung)) + (cond + ((and *vfl-stufe2-minl-vorschlag* *vfl-stufe2-minh-vorschlag*) + (ssg-textf "vfl-alert-vf-entscheidung-p2-beide" + (list (rtos *vfl-stufe2-minl-vorschlag* 2 0) (rtos *vfl-stufe2-minh-vorschlag* 2 0)))) + (*vfl-stufe2-minh-vorschlag* + (ssg-textf "vfl-alert-vf-entscheidung-p2-nur-minh" (list (rtos *vfl-stufe2-minh-vorschlag* 2 0)))) + (*vfl-stufe2-minl-vorschlag* + (ssg-textf "vfl-alert-vf-entscheidung-p2-nur-minl" (list (rtos *vfl-stufe2-minl-vorschlag* 2 0)))) + (t "")))) (if dbg-an (dbgmsg (strcat "GEOMETRIE FEHLGESCHLAGEN: Linie-VF nicht baubar (deltaL=" (rtos deltaL 2 0) " deltaH=" (rtos deltaH 2 0) @@ -3546,7 +5521,7 @@ " winkel=" (rtos (float winkel) 2 1) " L_GF=" (rtos L_GF 2 0) " L_VF=" (rtos L_VF 2 0) ")"))) (setq vf-einheit-res - (vfl-vf-einheit-abschluss frame hz-neu richtung winkel L_GF L_VF nil)) + (vfl-vf-einheit-abschluss frame hz-neu richtung winkel L_GF L_VF nil nil nil)) (setq frame (nth 0 vf-einheit-res)) (setq anzahl-vf (+ anzahl-vf (nth 1 vf-einheit-res))) (if (nth 2 vf-einheit-res) (setq fertig t)) @@ -3559,6 +5534,8 @@ ) ) ) + ) + ) ) ) @@ -3657,6 +5634,21 @@ (progn (alert (ssg-textf "vfl-alert-segment-nicht-baubar" (list (rtos deltaL 2 0) (rtos deltaH 2 0) richtung))) + ;; Gesammelte Stufe-2-Diagnose (falls versucht) + kompaktes + ;; 2-Punkte-Alert mit Mindestwerten - analog vfl-body-abschluss. + (if *vfl-stufe2-diagnose-text* (princ *vfl-stufe2-diagnose-text*)) + (alert + (strcat + (ssg-textf "vfl-alert-vf-entscheidung-p1" (list (rtos deltaL 2 0) (rtos deltaH 2 0) richtung)) + (cond + ((and *vfl-stufe2-minl-vorschlag* *vfl-stufe2-minh-vorschlag*) + (ssg-textf "vfl-alert-vf-entscheidung-p2-beide" + (list (rtos *vfl-stufe2-minl-vorschlag* 2 0) (rtos *vfl-stufe2-minh-vorschlag* 2 0)))) + (*vfl-stufe2-minh-vorschlag* + (ssg-textf "vfl-alert-vf-entscheidung-p2-nur-minh" (list (rtos *vfl-stufe2-minh-vorschlag* 2 0)))) + (*vfl-stufe2-minl-vorschlag* + (ssg-textf "vfl-alert-vf-entscheidung-p2-nur-minl" (list (rtos *vfl-stufe2-minl-vorschlag* 2 0)))) + (t "")))) (if dbg-an (dbgmsg (strcat "GEOMETRIE FEHLGESCHLAGEN: Linie (automatisch) nicht baubar" " (deltaL=" (rtos deltaL 2 0) " deltaH=" (rtos deltaH 2 0) @@ -3681,21 +5673,11 @@ ;; Sonst nachfragen, ob die Kette hier endet. (if linie-ende-modus (setq antwort "1") - (progn - (princ (ssg-text "vfl-ist-kettenende-header")) - (princ (ssg-text "vfl-kettenende-opt-ja-es")) - (princ (ssg-text "vfl-kettenende-opt-ja-ohne-es")) - (princ (ssg-text "vfl-kettenende-opt-nein")) - (setq antwort (vfl-menu (ssg-text "vfl-prompt-wahl-1-3-def3") - (list (ssg-text "vfl-kettenende-opt-ja-es") - (ssg-text "vfl-kettenende-opt-ja-ohne-es") - (ssg-text "vfl-kettenende-opt-nein")) 3 - "vfl-ist-kettenende-header")) - ) + (setq antwort (vfl-frage-ist-kettenende)) ) (cond ((= antwort "1") - (setq es-seite (vfl-frage-es-seite)) + (setq es-seite (vfl-frage-es-seite nil)) (setq frame (vfl-insert-es-element "GF" frame hz-neu winkel (caddr (car frame)) es-seite)) (setq fertig t)) @@ -3713,7 +5695,7 @@ " linie-ende-modus=" (if linie-ende-modus "T" "nil") ")"))) (setq vf-einheit-res (vfl-vf-einheit-abschluss frame hz-neu richtung winkel L_GF L_VF - linie-ende-modus)) + linie-ende-modus nil nil)) (setq frame (nth 0 vf-einheit-res)) (setq anzahl-vf (+ anzahl-vf (nth 1 vf-einheit-res))) (if (nth 2 vf-einheit-res) (setq fertig t)) @@ -3854,35 +5836,26 @@ (alert (ssg-textf "vfl-edit-dialog-fehlt" (list dcl-pfad))) nil) (progn (set_tile "kopf" (ssg-text "vfl-gf-bogen-winkel-header")) - (start_list "winkel") - (add_list (ssg-text "vfl-winkel-30")) - (add_list (ssg-text "vfl-winkel-60")) - (add_list (ssg-text "vfl-winkel-90")) - (end_list) - ;; Winkel 30/60/90 -> Listenposition 0/1/2 - (set_tile "winkel" (itoa (- (length *vfk-gf-bogen-winkel*) - (length (member vor-winkel *vfk-gf-bogen-winkel*))))) - (start_list "seite") - (add_list (ssg-text "gf-seite-links")) - (add_list (ssg-text "gf-seite-rechts")) - (end_list) - (set_tile "seite" (if (= vor-seite-code "2") "1" "0")) + (set_tile (strcat "winkel_" (itoa vor-winkel)) "1") + (set_tile (if (= vor-seite-code "2") "seite_rechts" "seite_links") "1") (action_tile "accept" - "(setq gwinkel (get_tile \"winkel\")) (setq gseite (get_tile \"seite\")) (done_dialog 1)") + "(setq gwinkel (cond ((= (get_tile \"winkel_30\") \"1\") 30) + ((= (get_tile \"winkel_60\") \"1\") 60) + (t 90))) + (setq gseite (if (= (get_tile \"seite_rechts\") \"1\") \"2\" \"1\")) + (done_dialog 1)") (action_tile "cancel" "(done_dialog 0)") (setq ergebnis (start_dialog)) (unload_dialog dat) (if (= ergebnis 1) - (list (nth (atoi gwinkel) *vfk-gf-bogen-winkel*) ; Listenposition 0/1/2 -> 30/60/90 - (if (= gseite "1") "2" "1")) ; Liste 0=links/1=rechts -> code "1"/"2" + (list gwinkel gseite) nil)))) ;; Pre-fill-faehiger Winkel+Seite+Variante-Dialog fuer die Vario-Kurve (nutzt -;; das bestehende vflw_variokurve-Tile mit Vorbelegung). Wizard-Optionsreihen- -;; folge: Winkel (30 60 90), Seite (links rechts), Variante (aussen innen) - -;; genau wie vflw-gruppe-variokurve-impl. vor-* sind die aktuellen Werte: -;; vor-winkel echter Wert 30/60/90, vor-seite-code/vor-variante-code je "1"/"2". -;; Rueckgabe: (winkel seite-code variante-code) oder nil bei Abbruch. +;; das bestehende vflw_variokurve-Tile mit Vorbelegung). vor-* sind die +;; aktuellen Werte: vor-winkel echter Wert 30/60/90, vor-seite-code/ +;; vor-variante-code je "1"/"2". Rueckgabe: (winkel seite-code variante-code) +;; oder nil bei Abbruch. (defun vfl-glied-vario-dialog (vor-winkel vor-seite-code vor-variante-code / dat dcl-pfad ergebnis gwinkel gseite gvariante) (setq dcl-pfad (strcat (getenv "DXFM_DCL") "/vf_linienzug_wizard.dcl")) @@ -3892,38 +5865,25 @@ (alert (ssg-textf "vfl-edit-dialog-fehlt" (list dcl-pfad))) nil) (progn (set_tile "kopf" (ssg-text "vfl-variokurve-winkel-header")) - (start_list "winkel") - (add_list (ssg-text "vfl-opt3-30grad")) - (add_list (ssg-text "vfl-opt2-60grad")) - (add_list (ssg-text "vfl-opt1-90grad")) - (end_list) - ;; Winkel 30/60/90 -> Listenposition 0/1/2 - (set_tile "winkel" (itoa (- (length *vfk-gf-bogen-winkel*) - (length (member vor-winkel *vfk-gf-bogen-winkel*))))) - (start_list "seite") - (add_list (ssg-text "gf-seite-links")) - (add_list (ssg-text "gf-seite-rechts")) - (end_list) - (set_tile "seite" (if (= vor-seite-code "2") "1" "0")) - (start_list "variante") - (add_list (ssg-text "vfl-variante-aussen")) - (add_list (ssg-text "vfl-variante-innen")) - (end_list) - (set_tile "variante" (if (= vor-variante-code "2") "1" "0")) + (set_tile (strcat "winkel_" (itoa vor-winkel)) "1") + (set_tile (if (= vor-seite-code "2") "seite_rechts" "seite_links") "1") + (set_tile (if (= vor-variante-code "2") "variante_innen" "variante_aussen") "1") (action_tile "accept" - "(setq gwinkel (get_tile \"winkel\")) (setq gseite (get_tile \"seite\")) (setq gvariante (get_tile \"variante\")) (done_dialog 1)") + "(setq gwinkel (cond ((= (get_tile \"winkel_30\") \"1\") 30) + ((= (get_tile \"winkel_60\") \"1\") 60) + (t 90))) + (setq gseite (if (= (get_tile \"seite_rechts\") \"1\") \"2\" \"1\")) + (setq gvariante (if (= (get_tile \"variante_innen\") \"1\") \"2\" \"1\")) + (done_dialog 1)") (action_tile "cancel" "(done_dialog 0)") (setq ergebnis (start_dialog)) (unload_dialog dat) (if (= ergebnis 1) - (list (nth (atoi gwinkel) *vfk-gf-bogen-winkel*) ; Listenposition 0/1/2 -> 30/60/90 - (if (= gseite "1") "2" "1") ; Liste 0=links/1=rechts -> "1"/"2" - (if (= gvariante "1") "2" "1")) ; Liste 0=aussen/1=innen -> "1"/"2" + (list gwinkel gseite gvariante) nil)))) ;; Pre-fill-faehiger Winkel+Seite-Dialog fuer AS/ES-Element: nur ZWEI -;; Winkel-Optionen (90/30, in genau dieser Listen-Reihenfolge - wie -;; vf-frage-element-winkel/vflw-gruppe-winkel-seite-impl), Winkel als STRING +;; Winkel-Optionen (90/30 - "winkel_60" wird gesperrt), Winkel als STRING ;; "90"/"30" (nicht Index). kopf-key waehlt die Kopfzeile (AS: vf-winkel-aus- ;; header, ES: vf-winkel-ein-header). Rueckgabe: (winkel-str seite-code) oder ;; nil bei Abbruch. seite-code "1"=links / "2"=rechts. @@ -3935,25 +5895,19 @@ (progn (if (and dat (>= dat 0)) (unload_dialog dat)) (alert (ssg-textf "vfl-edit-dialog-fehlt" (list dcl-pfad))) nil) (progn + (mode_tile "winkel_60" 1) (set_tile "kopf" (ssg-text kopf-key)) - (start_list "winkel") - (add_list (ssg-text "vf-winkel-90")) - (add_list (ssg-text "vf-winkel-30")) - (end_list) - (set_tile "winkel" (if (= vor-winkel-str "30") "1" "0")) ; Liste 0=90/1=30 - (start_list "seite") - (add_list (ssg-text "gf-seite-links")) - (add_list (ssg-text "gf-seite-rechts")) - (end_list) - (set_tile "seite" (if (= vor-seite-code "2") "1" "0")) + (set_tile (if (= vor-winkel-str "30") "winkel_30" "winkel_90") "1") + (set_tile (if (= vor-seite-code "2") "seite_rechts" "seite_links") "1") (action_tile "accept" - "(setq gwinkel (get_tile \"winkel\")) (setq gseite (get_tile \"seite\")) (done_dialog 1)") + "(setq gwinkel (if (= (get_tile \"winkel_30\") \"1\") \"30\" \"90\")) + (setq gseite (if (= (get_tile \"seite_rechts\") \"1\") \"2\" \"1\")) + (done_dialog 1)") (action_tile "cancel" "(done_dialog 0)") (setq ergebnis (start_dialog)) (unload_dialog dat) (if (= ergebnis 1) - (list (if (= gwinkel "1") "30" "90") ; Liste 0=90/1=30 -> "90"/"30" - (if (= gseite "1") "2" "1")) ; Liste 0=links/1=rechts -> "1"/"2" + (list gwinkel gseite) nil)))) ;; --- AS-/ES-Element (Winkel 30/90 + Seite links/rechts) --- @@ -4499,7 +6453,7 @@ ;; VF-Einheit OEFFNEN (Modus 2): GF1 (Basis-Staustrecke) + Separator + ;; Umlenkstation. Rueckgabe: Frame nach der Umlenkstation (Beginn reiner VF). (defun vfl2-vf-open (frame hz / f) - (setq f (vfl-frame-3grad (vfs-vf-entry (car frame) *vfl-gf-min-laenge* hz) hz)) + (setq f (vfl-frame-3grad (vfs-vf-entry (car frame) *vfl-gf-min-laenge* hz nil) hz)) (if (> *vfl-gf-min-laenge* 0.1) (vfl-acc-gf-seg *vfl-gf-min-laenge* (ssg-cfg-or "vario" "gefaelle_winkel" 3))) f) @@ -4593,6 +6547,9 @@ (list "vf-winkel-aus-header" (list (ssg-text "vf-winkel-90") (ssg-text "vf-winkel-30")) (list "90" "30")))) + (princ (ssg-text "vf-winkel-aus-header")) + (princ (ssg-text "vf-winkel-90")) + (princ (ssg-text "vf-winkel-30")) (setq *vfl-as-winkel* (vfl-in-value "STR" (function (lambda () (vf-frage-element-winkel "vf-winkel-aus-header"))))) ; 30/90 vor Seite @@ -4757,7 +6714,7 @@ (if (null frame) (progn (princ (ssg-text "vfl-m3-nichts-gebaut")) (exit))) ;; vfl-frage-es-seite nutzt intern bereits vfl-in-value/vfl-menu - wird also ;; automatisch mitgeloggt, kein manueller dbgmsg noetig. - (setq es-seite (vfl-frage-es-seite)) + (setq es-seite (vfl-frage-es-seite nil)) (if (= run-typ "VF") (progn (setq frame (vfl2-vf-close frame (car (frame->hz-winkel frame)))) @@ -5007,13 +6964,15 @@ member carrier-idx kv-variante seg-hz letzt-koerper-hz vf-first-line vf-last-line climber-span mid-hor z-aftermotor gf2-drop gf2-planar br-lvf this-lvf - nach-kurve n-climb n-hor target-climb winkel-list + nach-kurve nach-vf sep-vor-gf sep-nach-gf n-climb n-hor target-climb winkel-list fdz fdx wslope lvf planar-len ang-diff best-diff w climb-thresh longest-idx climbers nonclimber-len nonclimber-cnt nkurve kurve-chords run-span - hor-koerper-len hor-pairs flat-p fill-len wahl3 + 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 gf-total br-gf-mode br-gf2-exp filler-A-len filler-a-done + m2-lauf-antwort m2-offenes-ende + m2-front-antwort m2-offener-anfang m2-kein-gf1-vorne entry-fixed as-vorhanden es-vorhanden dbg-an dbg-old-error) (princ "\n\n=========================================") (princ (ssg-text "vfl-m3-titel")) @@ -5076,6 +7035,9 @@ (setq *vfl-as-winkel* nil *vfl-es-winkel* nil) (if as-vorhanden (progn + (princ (ssg-text "vf-winkel-aus-header")) + (princ (ssg-text "vf-winkel-90")) + (princ (ssg-text "vf-winkel-30")) (setq *vfl-as-winkel* (vfl-in-value "STR" (function (lambda () (vf-frage-element-winkel "vf-winkel-aus-header"))))) ; 30/90 vor Seite @@ -5111,6 +7073,9 @@ (setq es-vorhanden (/= antwort "2")) (if es-vorhanden (progn + (princ (ssg-text "vf-winkel-ein-header")) + (princ (ssg-text "vf-winkel-90")) + (princ (ssg-text "vf-winkel-30")) (setq *vfl-es-winkel* (vfl-in-value "STR" (function (lambda () (vf-frage-element-winkel "vf-winkel-ein-header"))))) ; 30/90 vor Seite @@ -5137,8 +7102,12 @@ (exit))) ;; --- 5. Klassifizierung (Phase A: nur speichern, nichts bauen) --- - ;; Plan-Eintrag Gerade: ("Linie" hz laenge klass winkel) klass=GF/VF + ;; Plan-Eintrag Gerade: ("Linie" hz laenge klass winkel [sep-vor sep-nach]) + ;; klass=GF/VF; sep-vor/sep-nach nur bei GF gesetzt (T/nil). ;; Plan-Eintrag Bogen : ("Bogen" hz chord bwinkel bseite klass) + ;; nach-vf: T sobald die letzte Gerade als VF klassifiziert wurde - der + ;; naechste Bogen MUSS dann Vario-Kurve sein (VF-Einheit kann nicht in + ;; einen GF-Bogen auslaufen), siehe vflw-seg-bogen-impl 'ERZWUNGEN. (setq n (length segmente) i 0 plan '()) (while (< i n) (setq seg (nth i segmente) typ (car seg) hz (cadr seg) laenge (caddr seg)) @@ -5158,7 +7127,7 @@ (vflw-seg-bogen-impl (vfl-seg-kopf (1+ i) n (strcat "Eck/Bogen " (itoa (nth 3 seg)) " Grad " (nth 4 seg))) - T)) ; Modus 2: Vario-Kurve immer erlaubt + (if nach-vf 'ERZWUNGEN T))) ; nach VF-Gerade: Vario-Kurve Pflicht (vfl-seg-highlight seg-ent nil))) (cond ((= typ "Linie") @@ -5170,28 +7139,47 @@ (nach-kurve (princ (ssg-text "vfl-m3-auto-vf")) (setq plan (cons (list "Linie" hz laenge "VF" nil) plan)) - (setq nach-kurve nil)) + (setq nach-kurve nil nach-vf t)) (t (princ (ssg-text "vfl-m3-typ-gerade")) (setq antwort (vfl-menu (ssg-text "prompt-wahl-1-2") (list "GF (Neigungswinkel)" "VF (Bruecke)") 1 "vfl-m3-typ-gerade")) (if (= antwort "2") - (setq plan (cons (list "Linie" hz laenge "VF" nil) plan)) + (progn + (setq plan (cons (list "Linie" hz laenge "VF" nil) plan)) + (setq nach-vf t)) (progn (setq winkel (vfl-in-real (ssg-text "vfl-m3-prompt-gf-neigung"))) (if (null winkel) (setq winkel *vfk-gefaelle-winkel*)) (if (> winkel *vfk-gefaelle-winkel*) (progn (princ (ssg-text "vfl-m3-hinweis-gf-max")) (setq winkel *vfk-gefaelle-winkel*))) - (setq plan (cons (list "Linie" hz laenge "GF" winkel) plan))))))) + ;; Separator VOR/NACH diesem GF-Stueck (analog Modus 1) - die + ;; Planlaenge bleibt hier UNVERAENDERT (reale Pfadlaenge, fuer + ;; die Anker-Vorschau/vfl3-seg-dz/-dback noetig); die Trennung + ;; in GF-Koerper+Separator passiert erst beim Bauen (Phase B). + (princ (ssg-text "vfl-sep-vor-gf-frage")) + (setq sep-vor-gf (= (vfl-menu (ssg-text "vfl-prompt-wahl-1-2-def2") + (list (ssg-text "vfl-ja") (ssg-text "vfl-nein")) 2 + "vfl-sep-vor-gf-frage") "1")) + (princ (ssg-text "vfl-sep-nach-gf-frage")) + (setq sep-nach-gf (= (vfl-menu (ssg-text "vfl-prompt-wahl-1-2-def2") + (list (ssg-text "vfl-ja") (ssg-text "vfl-nein")) 2 + "vfl-sep-nach-gf-frage") "1")) + (setq plan (cons (list "Linie" hz laenge "GF" winkel sep-vor-gf sep-nach-gf) plan)) + (setq nach-vf nil)))))) ((= typ "Bogen") (setq bwinkel (nth 3 seg) bseite (nth 4 seg)) (princ (ssg-textf "vfl-m3-seg-bogen" (list (itoa (1+ i)) (itoa n) (itoa bwinkel) bseite))) - (princ (ssg-text "vfl-m3-typ-bogen")) - (setq antwort (vfl-menu (ssg-text "prompt-wahl-1-2") - (list "GF-Bogen" "Vario-Kurve") 1 - "vfl-m3-typ-bogen")) + (if nach-vf + (setq antwort "2") ; nach VF-Gerade: Vario-Kurve erzwungen, keine Typ-Frage + (progn + (princ (ssg-text "vfl-m3-typ-bogen")) + (setq antwort (vfl-menu (ssg-text "prompt-wahl-1-2") + (list "GF-Bogen" "Vario-Kurve") 1 + "vfl-m3-typ-bogen")))) + (setq nach-vf nil) (if (= antwort "2") (progn (princ (ssg-text "vfl-m3-variante-frage")) @@ -5290,6 +7278,58 @@ (princ (ssg-text "vfl-m3-anker-hinweis")) (princ "\n=========================================") + ;; --- Lauf-Anfang waehlen, NUR wenn der VF-Lauf der Pfadanfang ist (kein + ;; Front-Lauf davor) - sonst bleibt die Steuerung komplett unveraendert (AS- + ;; Element aus der Upfront-Frage, Umlenkstation+GF1+Separator immer gebaut). + ;; Muss VOR der Phase-B2-Fussabdruck-Berechnung (entry-fixed) feststehen. + (setq m2-offener-anfang nil m2-kein-gf1-vorne nil) + (if (= vf-start 0) + (progn + (princ (ssg-text "vfl-m3-lauf-anfang-header")) + (princ (ssg-text "vfl-m3-lauf-anfang-opt-offen")) + (princ (ssg-text "vfl-m3-lauf-anfang-opt-umlenk")) + (princ (ssg-text "vfl-m3-lauf-anfang-opt-umlenk-gf1")) + (if (vfl-wizard-aktiv) + (vl-catch-all-apply 'vflw-m2-lauf-anfang-impl (list "vfl-m3-lauf-anfang-header"))) + (setq m2-front-antwort (vfl-menu (ssg-text "vfl-prompt-wahl-1-3-def3") + (list (ssg-text "vfl-m3-lauf-anfang-opt-offen") + (ssg-text "vfl-m3-lauf-anfang-opt-umlenk") + (ssg-text "vfl-m3-lauf-anfang-opt-umlenk-gf1")) 3 + "vfl-m3-lauf-anfang-header")) + (cond + ((= m2-front-antwort "1") + (setq as-vorhanden nil m2-offener-anfang t) + (princ (ssg-text "vfl-m3-lauf-anfang-offen-hinweis"))) + ((= m2-front-antwort "2") (setq m2-kein-gf1-vorne t))))) + + ;; --- Lauf-Abschluss waehlen, NUR wenn der VF-Lauf das Pfadende ist (kein + ;; Back-Lauf danach) - sonst bleibt die Steuerung komplett unveraendert + ;; (es-vorhanden aus der Upfront-Frage, Motorstation immer gebaut). "Ohne + ;; Motorstation" muss VOR der Phase-B2-Zielhoehen-Berechnung feststehen, + ;; da sie die Separator/ES-Naeherung in vfl3-dback wieder aufhebt. + (setq m2-offenes-ende nil) + (if (= vf-ende (1- n)) + (progn + (princ (ssg-text "vfl-m3-lauf-abschluss-header")) + (princ (ssg-text "vfl-m3-lauf-abschluss-opt-offen")) + (princ (ssg-text "vfl-m3-lauf-abschluss-opt-motor")) + (princ (ssg-text "vfl-m3-lauf-abschluss-opt-motor-es")) + (if (vfl-wizard-aktiv) + (vl-catch-all-apply 'vflw-m2-lauf-abschluss-impl (list "vfl-m3-lauf-abschluss-header"))) + (setq m2-lauf-antwort (vfl-menu (ssg-text "vfl-prompt-wahl-1-3-def2") + (list (ssg-text "vfl-m3-lauf-abschluss-opt-offen") + (ssg-text "vfl-m3-lauf-abschluss-opt-motor") + (ssg-text "vfl-m3-lauf-abschluss-opt-motor-es")) 2 + "vfl-m3-lauf-abschluss-header")) + (cond + ((= m2-lauf-antwort "1") + (setq es-vorhanden nil m2-offenes-ende t) + (princ (ssg-text "vfl-m3-lauf-abschluss-offen-hinweis"))) + ((= m2-lauf-antwort "3") + (setq es-vorhanden t) + (if (null es-seite) (setq es-seite (vfl-frage-es-seite nil)))) + (t (setq es-vorhanden nil))))) + ;; ================= PHASE B: BAUEN (messen statt schaetzen) ================= ;; VF-Lauf darf mehrsegmentig sein (VF-Geraden + Vario-Kurven, EINE VF-Einheit). ;; Nummerierung + Akkumulatoren + AS/ES-Fussabdruecke. Ohne AS-Element (aus- @@ -5336,7 +7376,7 @@ (setq seg (nth i plan) typ (car seg) hz (cadr seg)) (cond ((= typ "Linie") - (setq winkel (nth 4 seg)) + (setq winkel (nth 4 seg) sep-vor-gf (nth 5 seg) sep-nach-gf (nth 6 seg)) ;; AS zuerst platzieren (falls gewuenscht), damit der echte KS_AUS bekannt ;; ist. Ohne AS-Element beginnt die Kette direkt am Startpunkt (flach) - ;; die nachfolgende Fussabdruck-Trimmung wird dann automatisch zu 0, da @@ -5352,10 +7392,30 @@ (setq deltaL (- deltaL (+ (* (- (car (car frame)) (car startpunkt)) (cos (* hz (/ pi 180.0)))) (* (- (cadr (car frame)) (cadr startpunkt)) (sin (* hz (/ pi 180.0)))))))) + ;; Separator(en) VOR/NACH aus der Klassifizierung (Punkt 1): die reale + ;; Planlaenge (deltaL, oben aus dem gemessenen Pfad) bleibt fuer die + ;; Anker-Vorschau unangetastet - erst HIER, beim tatsaechlichen Bauen, + ;; wird der GF-Koerper um die Separator-Laenge(n) verkuerzt. + (if sep-vor-gf (setq deltaL (- deltaL *vfk-separator-laenge*))) + (if sep-nach-gf (setq deltaL (- deltaL *vfk-separator-laenge*))) (setq deltaL (max *vfk-restlaenge-min-clamp* deltaL)) + (if sep-vor-gf + (progn + (setq frame (make-frame-from-dir + (gf-insert-hz-with-ks "Staustrecke_Separator_SP_300_mm" + (car frame) hz winkel *vfk-separator-laenge* 0) + (hz-winkel->xu hz winkel))) + (setq *vfl-acc-separator* (1+ *vfl-acc-separator*)))) (setq frame (vfl-insert-gf-segment (car frame) hz deltaL winkel)) (vfl-acc-gf-seg (/ deltaL (cos (* winkel (/ pi 180.0)))) winkel) - (setq anzahl-gf (1+ anzahl-gf) letzt-winkel winkel)) + (setq anzahl-gf (1+ anzahl-gf) letzt-winkel winkel) + (if sep-nach-gf + (progn + (setq frame (make-frame-from-dir + (gf-insert-hz-with-ks "Staustrecke_Separator_SP_300_mm" + (car frame) hz winkel *vfk-separator-laenge* 0) + (hz-winkel->xu hz winkel))) + (setq *vfl-acc-separator* (1+ *vfl-acc-separator*))))) ((= typ "Bogen") (setq bwinkel (nth 3 seg) bseite (nth 4 seg) klass (nth 5 seg)) (if (= klass "GF-Bogen") @@ -5378,6 +7438,10 @@ ;; --- B2: Back-Abstieg -> Junction; Kletterer + Horizontal-Mitte bestimmen --- (setq z-junction (+ (float end-hoehe) (vfl3-dback plan (1+ vf-ende) n last-line ein))) + ;; Offenes Ende (kein Motor/Separator/ES danach): vfl3-dback's Tail-Naeherung + ;; (reserviert IMMER einen Separator+ES-Fussabdruck) ist hier falsch - die + ;; Zielhoehe fuer den Loeser ist exakt end-hoehe. + (if m2-offenes-ende (setq z-junction (float end-hoehe))) (setq dH-bruecke (- z-front z-junction)) ;; Modell: EIN Vario mit Horizontal-Mitte. Nur VF-Geraden, die LANG GENUG sind ;; (Vertikalboegen brauchen viel Platz), tragen die Hoehe (Kletterer, gleicher @@ -5408,6 +7472,11 @@ ;; (ein auf_3 rein, ein ab_3 raus), unabhaengig von der Zahl der Fueller/Kurven. (setq hor-pairs (if (or (> nkurve 0) (> nonclimber-cnt 0)) 1 0)) (setq run-span (+ climber-span nonclimber-len kurve-chords)) + ;; Laengen-Obergrenze fuer eine angetriebene VF-Einheit (Konstruktions- + ;; grenze, siehe *vfk-vf-laenge-max*) - nur Hinweis, kein Abbruch. + (if (> run-span *vfk-vf-laenge-max*) + (alert (ssg-textf "vfl-m3-alert-vf-zu-lang" + (list (rtos (/ run-span 1000.0) 2 1) (rtos (/ *vfk-vf-laenge-max* 1000.0) 2 1))))) (setq br-gf1 *vfl-gf-min-laenge*) ; feste kleine GF1 (setq br-richtn (if (< dH-bruecke 0) "Auf" "Ab")) (setq target-climb (- z-junction z-front)) ; noetige Netto-Hoehe (Auf>0) @@ -5421,32 +7490,76 @@ (list (rtos target-climb 2 1) (itoa n-climb) (itoa nkurve) (itoa nonclimber-cnt)))) ;; feste-Horizontal + Hoehen-Anpassung fuer den Solver: ;; - Mit flacher Zone: Motor sitzt am Kettenende (nicht im Kletter-Segment) -> - ;; feste = 800 (Umlenk+Sep). berechne rechnet Motor-/Uebergangs-Abstieg NICHT, - ;; daher Kletterhoehe um diese Abstiege anpassen (GF2 bleibt ~0). - ;; - Ohne flache Zone (Einzel-Bruecke): feste = 1300 (inkl. Motor), keine Anpassung. + ;; feste = entry-fixed (Umlenk+Sep, ODER weniger bei Lauf-Anfang-Wahl). + ;; berechne rechnet Motor-/Uebergangs-Abstieg NICHT, daher Kletterhoehe + ;; um diese Abstiege anpassen (GF2 bleibt ~0) - ausser bei offenem Ende. + ;; - Ohne flache Zone (Einzel-Bruecke): feste = entry-fixed + Motor (0 bei + ;; offenem Ende), keine Hoehen-Anpassung. (setq rad3v (* *vfk-gefaelle-winkel* (/ pi 180.0))) + ;; Eingangs-Fussabdruck haengt von der Lauf-Anfang-Wahl ab (siehe oben) - + ;; Default (beide Flags nil) ergibt exakt die bisherigen 800/1300. + (setq entry-fixed + (cond (m2-offener-anfang 0.0) + (m2-kein-gf1-vorne *vfk-stations-laenge*) + (t (+ *vfk-stations-laenge* *vfk-separator-laenge*)))) (if (> hor-pairs 0) - (setq feste-vf *vfk-feste-horizontal-kettenende* + (setq feste-vf entry-fixed dH-adj (- dH-bruecke (+ (* *vfk-stations-laenge* (sin rad3v)) *vfk-bruecke-korrektur*))) ; Motor + auf_3/ab_3 - (setq feste-vf *vfk-feste-horizontal-linienzug* dH-adj dH-bruecke)) + (setq feste-vf (+ entry-fixed (if m2-offenes-ende 0.0 *vfk-stations-laenge*)) dH-adj dH-bruecke)) + ;; Offenes Ende (m2-offenes-ende): kein Motor wird gebaut, die obige + ;; Motor-Abstiegs-Korrektur darf dann NICHT abgezogen werden - der Solver + ;; soll die volle dH-bruecke exakt treffen (Ziel = z-junction = end-hoehe). + (if m2-offenes-ende (setq dH-adj dH-bruecke)) (setq wahl3 (vfl3-waehle-winkel climber-span dH-adj feste-vf)) (if (null wahl3) - (progn (princ (ssg-text "vfl-m3-kein-winkel")) - (princ) (exit))) - (setq br-winkel (car wahl3) gf-total (cadr wahl3) br-lvf (caddr wahl3) br-richtn (cadddr wahl3)) - ;; GF-Verteilung: 1 = alles am Einlauf (GF1); 2 = 1/2 GF1 + 1/2 GF2. Bei 1/2/1/2 - ;; wird der im Kletter-Segment durch das halbe GF1 frei werdende Platz mit einem - ;; horizontalen Fueller-A gefuellt; GF2 (~1/2 L_GF) sitzt hinter dem Motor, der - ;; ES-Laengen-Abschluss zieht seinen Fussabdruck ab (Fueller-B wird kuerzer). + (progn + ;; Stufe 2: KEIN Tabellenwinkel passt (der/die Kletterer sind bei JEDER + ;; Neigung zu kurz fuer Umlenkstation+2 Vertikalboegen) - ganzer Lauf wird + ;; flach gebaut, wie die bereits vorhandenen "kurzen" VF-Geraden (Zeile + ;; unten, "kurze VF-Gerade -> horizontaler Fueller"). Die komplette + ;; Hoehe wandert in GF1 (reine Kompensation, wie beim reinen-GF-Fall in + ;; Modus 1 - darf legitim (nahe) 0 sein, siehe Nutzer-Klarstellung). + (princ (ssg-text "vfl-m3-kletter-zu-kurz-flach")) + (setq nonclimber-len (+ nonclimber-len climber-span) + nonclimber-cnt (+ nonclimber-cnt n-climb)) + (setq climbers '() n-climb 0 climber-span 0.0) + ;; hor-pairs war ggf. 0 (reine Einzel-Bruecke ohne Kurve/Fueller) - jetzt + ;; gibt es garantiert mindestens einen Fueller (den ex-Kletterer), also + ;; feste-vf/dH-adj auf die flache-Zone-Variante nachziehen. + (if (<= hor-pairs 0) + (progn + (setq hor-pairs 1) + (setq feste-vf entry-fixed + dH-adj (- dH-bruecke (+ (* *vfk-stations-laenge* (sin rad3v)) *vfk-bruecke-korrektur*))))) + (if m2-offenes-ende (setq dH-adj dH-bruecke)) + (setq br-winkel (fix *vfk-gefaelle-winkel*) br-lvf 0.0 + br-richtn (if (< dH-adj 0) "Auf" "Ab") + gf-total (/ (abs dH-adj) (/ (sin rad3v) (cos rad3v)))) + (princ (ssg-textf "vfl-m3-kletter-flach-gf" (list (rtos gf-total 2 0))))) + (setq br-winkel (car wahl3) gf-total (cadr wahl3) br-lvf (caddr wahl3) br-richtn (cadddr wahl3))) + ;; GF-Verteilung: 1 = alles am Einlauf (GF1); 2 = 1/2 GF1 + 1/2 GF2; 3 = alles + ;; am Auslauf (GF2) - erzwungen (kein GF1-Platz), wenn der Lauf-Anfang ohne + ;; GF1 gewaehlt wurde (offener Anfang ODER Umlenkstation direkt). Bei 1/2/1/2 + ;; wird der im Kletter-Segment durch das halbe GF1 frei werdende Platz mit + ;; einem horizontalen Fueller-A gefuellt; GF2 (~1/2 L_GF) sitzt hinter dem + ;; Motor, der ES-Laengen-Abschluss zieht seinen Fussabdruck ab (Fueller-B + ;; wird kuerzer). (princ (ssg-text "vfl-m3-gf-verteilung")) - (setq br-gf-mode - (if (= (vfl-menu (ssg-text "prompt-wahl-1-2") - (list "Alles am Einlauf (GF1)" "1/2 GF1 + 1/2 GF2") 1 - "vfl-m3-gf-verteilung") "2") 2 1)) - (if (= br-gf-mode 2) - (setq br-gf1 (/ gf-total 2.0) br-gf2-exp (/ gf-total 2.0) - filler-A-len (* (/ gf-total 2.0) (cos rad3v))) - (setq br-gf1 gf-total br-gf2-exp 0.0 filler-A-len 0.0)) + (if (or m2-offener-anfang m2-kein-gf1-vorne) + (progn + (setq br-gf-mode 3 br-gf1 0.0 br-gf2-exp gf-total filler-A-len 0.0) + (princ (ssg-text "vfl-m3-gf-verteilung-alles-auslauf"))) + (progn + (if (vfl-wizard-aktiv) + (vl-catch-all-apply 'vflw-gruppe-gf-verteilung-impl (list (ssg-text "vfl-m3-gf-verteilung") "2" "1"))) + (setq br-gf-mode + (if (= (vfl-menu (ssg-text "prompt-wahl-1-2") + (list "Alles am Einlauf (GF1)" "1/2 GF1 + 1/2 GF2") 1 + "vfl-m3-gf-verteilung") "2") 2 1)) + (if (= br-gf-mode 2) + (setq br-gf1 (/ gf-total 2.0) br-gf2-exp (/ gf-total 2.0) + filler-A-len (* (/ gf-total 2.0) (cos rad3v))) + (setq br-gf1 gf-total br-gf2-exp 0.0 filler-A-len 0.0)))) (setq filler-a-done nil) (princ (ssg-textf "vfl-m3-vario-ergebnis" (list (itoa br-winkel) @@ -5454,8 +7567,9 @@ (ssg-text "vfl-m3-richtung-ab-kurz")) (rtos br-lvf 2 0) (rtos gf-total 2 0) - (if (= br-gf-mode 2) (ssg-text "vfl-m3-vert-halb") - (ssg-text "vfl-m3-vert-ganz"))))) + (cond ((= br-gf-mode 2) (ssg-text "vfl-m3-vert-halb")) + ((= br-gf-mode 3) (ssg-text "vfl-m3-vert-auslauf")) + (t (ssg-text "vfl-m3-vert-ganz")))))) ;; --- B3: Standard-Vario (Klettern, 3-Grad-Basis) + flache Zone (0 Grad) --- ;; Die flache Zone (Vario-Kurve + horizontaler Fueller) haengt EINMAL ueber auf_3 @@ -5463,8 +7577,13 @@ ;; verbunden (keine Zwischen-Boegen). Der horizontale Fueller gleicht die ;; Restlaenge aus (letztes Stueck vor dem Motor getrimmt). (setq pt (car frame) letzt-koerper-hz (cadr (nth vf-start plan)) flat-p nil) - (setq pt (vfs-vf-entry pt br-gf1 letzt-koerper-hz)) ; GF1 + Separator + Umlenk (3 Grad) - (vfl-acc-gf-seg br-gf1 3) + ;; Lauf-Anfang: offener Anfang ueberspringt Umlenkstation komplett; sonst + ;; GF1 (0, wenn m2-kein-gf1-vorne oder GF-Verteilung das so ergab) + ggf. + ;; Separator (uebersprungen bei m2-kein-gf1-vorne) + Umlenk (3 Grad). + (if (not m2-offener-anfang) + (progn + (setq pt (vfs-vf-entry pt br-gf1 letzt-koerper-hz m2-kein-gf1-vorne)) + (vfl-acc-gf-seg br-gf1 3))) (setq i vf-start) (while (<= i vf-ende) (setq seg (nth i plan) seg-hz (cadr seg)) @@ -5478,6 +7597,7 @@ (setq anzahl-vf (1+ anzahl-vf) letzt-koerper-hz seg-hz)) ;; --- kurze VF-Gerade -> horizontaler Fueller (0 Grad) --- ((= (car seg) "Linie") + (setq flat-zone-erste (not flat-p)) (if (not flat-p) (progn (setq pt (vfl3-flach-ein pt letzt-koerper-hz)) (setq flat-p t) ;; Fueller-A: der im Kletter-Segment durch 1/2 GF1 frei werdende Platz @@ -5506,6 +7626,15 @@ ) ) (setq fill-len (caddr seg))) + ;; Kritische Fueller-Position (direkt nach Umlenkstation ODER direkt vor + ;; Motorstation) zu kurz fuer den geforderten Wert - statt still zu + ;; klemmen, den Nutzer warnen (Zielhoehe/-position wird dann nicht exakt + ;; erreicht, siehe vfl-m3-warnung-gf2-negativ fuer die Hoehen-Seite). + (if (and (< fill-len *vfk-restlaenge-min-clamp*) (or flat-zone-erste (= i vf-ende))) + (alert (ssg-textf + (if flat-zone-erste "vfl-m3-warnung-fueller-eingang-zu-kurz" + "vfl-m3-warnung-fueller-ausgang-zu-kurz") + (list (rtos fill-len 2 0) (rtos *vfk-restlaenge-min-clamp* 2 0))))) (setq fill-len (max *vfk-restlaenge-min-clamp* fill-len)) (setq pt (insert-inclined-scaled-block "Staustrecke_SP_1000_mm" pt fill-len 0 seg-hz)) (vfl-acc-vf-seg "horizontal" 0 fill-len) (setq anzahl-vf (1+ anzahl-vf)) @@ -5527,24 +7656,30 @@ (setq pt (car frame)) (if (< i vf-ende) (setq letzt-koerper-hz (cadr (nth (1+ i) plan)))))) (setq i (1+ i))) - (if flat-p (progn (setq pt (vfl3-flach-aus pt letzt-koerper-hz)) (setq flat-p nil))) ; zurueck 3 Grad - ;; Motorstation (ohne GF2) - (setq pt (vfs-vf-exit pt 0.0 letzt-koerper-hz nil)) - (setq *vfl-acc-motorseite* (append *vfl-acc-motorseite* (list "rechts"))) - ;; GF2 = gemessener exakter Hoehen-Ausgleich (Abstieg bis zur Junction) - (setq z-aftermotor (caddr pt)) - (setq gf2-drop (- z-aftermotor z-junction)) - (if (< gf2-drop 0.0) + (if m2-offenes-ende + ;; Bewusst offenes Ende (kein Motor/Separator/ES) - Lauf bleibt flach + ;; (0 Grad) genau dort stehen, wo die Bau-Schleife endete; KEIN + ;; Rueck-Uebergang auf 3 Grad, KEINE Motorstation/GF2. + (setq frame (make-frame-from-dir pt (hz-winkel->xu letzt-koerper-hz 0.0))) (progn - (princ (ssg-textf "vfl-m3-warnung-gf2-negativ" (list (rtos (- gf2-drop) 2 1)))) - (setq gf2-drop 0.0))) - (setq gf2-planar (/ gf2-drop (/ (sin (* *vfk-gefaelle-winkel* (/ pi 180.0))) (cos (* *vfk-gefaelle-winkel* (/ pi 180.0)))))) - (if (> gf2-planar 0.1) - (progn - (princ (ssg-textf "vfl-m3-gf2-ausgleich" (list (rtos gf2-planar 2 1)))) - (setq frame (vfl-insert-gf-segment pt letzt-koerper-hz gf2-planar (fix *vfk-gefaelle-winkel*))) - (vfl-acc-gf-seg (/ gf2-planar (cos (* *vfk-gefaelle-winkel* (/ pi 180.0)))) (fix *vfk-gefaelle-winkel*))) - (setq frame (vfl-frame-3grad pt letzt-koerper-hz))) + (if flat-p (progn (setq pt (vfl3-flach-aus pt letzt-koerper-hz)) (setq flat-p nil))) ; zurueck 3 Grad + ;; Motorstation (ohne GF2) + (setq pt (vfs-vf-exit pt 0.0 letzt-koerper-hz nil)) + (setq *vfl-acc-motorseite* (append *vfl-acc-motorseite* (list "rechts"))) + ;; GF2 = gemessener exakter Hoehen-Ausgleich (Abstieg bis zur Junction) + (setq z-aftermotor (caddr pt)) + (setq gf2-drop (- z-aftermotor z-junction)) + (if (< gf2-drop 0.0) + (progn + (alert (ssg-textf "vfl-m3-warnung-gf2-negativ" (list (rtos (- gf2-drop) 2 1)))) + (setq gf2-drop 0.0))) + (setq gf2-planar (/ gf2-drop (/ (sin (* *vfk-gefaelle-winkel* (/ pi 180.0))) (cos (* *vfk-gefaelle-winkel* (/ pi 180.0)))))) + (if (> gf2-planar 0.1) + (progn + (princ (ssg-textf "vfl-m3-gf2-ausgleich" (list (rtos gf2-planar 2 1)))) + (setq frame (vfl-insert-gf-segment pt letzt-koerper-hz gf2-planar (fix *vfk-gefaelle-winkel*))) + (vfl-acc-gf-seg (/ gf2-planar (cos (* *vfk-gefaelle-winkel* (/ pi 180.0)))) (fix *vfk-gefaelle-winkel*))) + (setq frame (vfl-frame-3grad pt letzt-koerper-hz))))) (setq hz letzt-koerper-hz) ;; --- B4: BACK-Lauf bauen (Segmente vf-ende+1 .. n-1) --- @@ -5553,15 +7688,33 @@ (setq seg (nth i plan) typ (car seg) hz (cadr seg)) (cond ((= typ "Linie") - (setq winkel (nth 4 seg) deltaL (caddr seg)) + (setq winkel (nth 4 seg) deltaL (caddr seg) + sep-vor-gf (nth 5 seg) sep-nach-gf (nth 6 seg)) ;; Footprint fuer Separator(300)+ES nur reservieren, wenn ES-Element ;; gewuenscht ist (ein=0 sonst, siehe oben) - ohne ES entfaellt auch ;; der abschliessende Separator. (if (= i last-line) (setq deltaL (- deltaL (if es-vorhanden *vfk-separator-laenge* 0.0) ein))) + ;; Separator(en) VOR/NACH aus der Klassifizierung (Punkt 1, wie B1). + (if sep-vor-gf (setq deltaL (- deltaL *vfk-separator-laenge*))) + (if sep-nach-gf (setq deltaL (- deltaL *vfk-separator-laenge*))) (setq deltaL (max *vfk-restlaenge-min-clamp* deltaL)) + (if sep-vor-gf + (progn + (setq frame (make-frame-from-dir + (gf-insert-hz-with-ks "Staustrecke_Separator_SP_300_mm" + (car frame) hz winkel *vfk-separator-laenge* 0) + (hz-winkel->xu hz winkel))) + (setq *vfl-acc-separator* (1+ *vfl-acc-separator*)))) (setq frame (vfl-insert-gf-segment (car frame) hz deltaL winkel)) (vfl-acc-gf-seg (/ deltaL (cos (* winkel (/ pi 180.0)))) winkel) - (setq anzahl-gf (1+ anzahl-gf) letzt-winkel winkel)) + (setq anzahl-gf (1+ anzahl-gf) letzt-winkel winkel) + (if sep-nach-gf + (progn + (setq frame (make-frame-from-dir + (gf-insert-hz-with-ks "Staustrecke_Separator_SP_300_mm" + (car frame) hz winkel *vfk-separator-laenge* 0) + (hz-winkel->xu hz winkel))) + (setq *vfl-acc-separator* (1+ *vfl-acc-separator*))))) ((= typ "Bogen") (setq bwinkel (nth 3 seg) bseite (nth 4 seg) klass (nth 5 seg)) (if (= klass "GF-Bogen") diff --git a/Lisp/vf_standard.lsp b/Lisp/vf_standard.lsp index d5a8ec5..b903ed0 100644 --- a/Lisp/vf_standard.lsp +++ b/Lisp/vf_standard.lsp @@ -337,20 +337,32 @@ ;; erreichbar (im Rahmen von deltaL), GF1+GF2 werden einfach laenger. ;; - "Auf": wirkt der gewuenschten Steigung entgegen -> nur fuer SEHR ;; KLEINE deltaH ueberhaupt gueltig (wenige cm). +;; schon-flach: T => KEIN Bogen1 (auf_3) am Eintritt - der Aufrufer ist +;; bereits flach (0 Grad) angekommen und wird KEINEN Uebergangsbogen bauen +;; (vermeidet ein ueberfluessiges auf_3/ab_3-Paar, wenn eine bereits flache +;; Kette ohnehin ein horizontales Mittelstueck braucht - siehe +;; vfl-body-abschluss). Default nil (unveraendertes Verhalten fuer alle +;; anderen Aufrufer, die immer von der 3-Grad-Basis starten). ;; Rueckgabe: (GF_total L_VF gueltig) oder nil falls Boegen nicht messbar. -(defun berechne-horizontale-mitte (deltaL deltaH richtung / +(defun berechne-horizontale-mitte (deltaL deltaH richtung schon-flach / mass1 mass2 rad3 bogen-x1 bogen-z1 bogen-x2 bogen-z2 deltaH-signiert A-hz B-hz GF_total L_VF-hz gueltig) - (setq mass1 (get-bogen-mass bogen-auf (fix *vfk-gefaelle-winkel*))) + (setq mass1 (if schon-flach t (get-bogen-mass bogen-auf (fix *vfk-gefaelle-winkel*)))) (setq mass2 (get-bogen-mass bogen-ab (fix *vfk-gefaelle-winkel*))) (if (or (null mass1) (null mass2)) nil (progn (setq rad3 (* *vfk-gefaelle-winkel* (/ pi 180.0))) - ;; Bogen1 (immer auf_3): Eintritt bei 3 Grad (von Umlenkstation), biegt auf 0 Grad - (setq bogen-x1 (+ (* (car mass1) (cos rad3)) (* (caddr mass1) (sin rad3)))) - (setq bogen-z1 (+ (* (- (car mass1)) (sin rad3)) (* (caddr mass1) (cos rad3)))) + ;; Bogen1 (immer auf_3): Eintritt bei 3 Grad (von Umlenkstation), biegt + ;; auf 0 Grad - entfaellt bei schon-flach (kein Eintrittsbogen noetig). + (if schon-flach + (setq bogen-x1 0.0 bogen-z1 0.0) + (progn + (setq bogen-x1 (+ (* (car mass1) (cos rad3)) (* (caddr mass1) (sin rad3)))) + (setq bogen-z1 (+ (* (- (car mass1)) (sin rad3)) (* (caddr mass1) (cos rad3)))) + ) + ) ;; Bogen2 (immer ab_3): Eintritt bei 0 Grad (von der horizontalen Mitte), biegt auf 3 Grad (setq bogen-x2 (car mass2)) (setq bogen-z2 (caddr mass2)) @@ -412,7 +424,11 @@ ;; Beginnt eine reine VF-Einheit: bringt die Kette von der (3-Grad-geneigten) ;; AS-Seite ueber GF1 + Separator bis zur Umlenkstation. Wird pro VF-Einheit ;; GENAU EINMAL aufgerufen (auch wenn danach mehrere Sub-Segmente folgen). -(defun vfs-vf-entry (aktueller-punkt L_GF1 hz) +;; ohne-separator: T => der Separator entfaellt (das vorherige Kettenglied +;; IST bereits ein Separator, siehe letzter-typ in vf-linienzug-modus - eine +;; gueltige Trennstelle braucht nur einen Separator, nicht zwei hintereinander). +;; L_GF1 sollte in diesem Fall vom Aufrufer bereits auf 0 gesetzt sein. +(defun vfs-vf-entry (aktueller-punkt L_GF1 hz ohne-separator) (if (null hz) (setq hz 0.0)) (setq hz (float hz)) ;; 1. Gefaellestrecke GF1 (verbindet AS-Neigung mit Umlenkstation) @@ -425,13 +441,17 @@ ) (princ (ssg-text "vfs-vf-eingang-gf1-skip")) ) - ;; 2. Separator (am GF1-Ende / vor Umlenkstation) - (princ (ssg-text "vfs-vf-eingang-separator")) - (setq aktueller-punkt - (insert-rotated-block-with-ks "Staustrecke_Separator_SP_300_mm" aktueller-punkt - (ssg-cfg-or "vario" "gefaelle_winkel" 3) - (ssg-cfg-or "vario" "separator_block_dx" 300) - (ssg-cfg-or "vario" "separator_block_dz" 0) hz)) + ;; 2. Separator (am GF1-Ende / vor Umlenkstation) - entfaellt bei ohne-separator + (if (not ohne-separator) + (progn + (princ (ssg-text "vfs-vf-eingang-separator")) + (setq aktueller-punkt + (insert-rotated-block-with-ks "Staustrecke_Separator_SP_300_mm" aktueller-punkt + (ssg-cfg-or "vario" "gefaelle_winkel" 3) + (ssg-cfg-or "vario" "separator_block_dx" 300) + (ssg-cfg-or "vario" "separator_block_dz" 0) hz)) + ) + ) ;; 3. Umlenkstation (princ (ssg-text "vfs-vf-eingang-umlenk")) (setq aktueller-punkt @@ -604,7 +624,7 @@ (defun vfs-mitte-teil (aktueller-punkt richtung best-winkel L_GF1 L_GF2 L_VF hz) (if (null hz) (setq hz 0.0)) (setq hz (float hz)) - (setq aktueller-punkt (vfs-vf-entry aktueller-punkt L_GF1 hz)) + (setq aktueller-punkt (vfs-vf-entry aktueller-punkt L_GF1 hz nil)) (setq aktueller-punkt (vfs-vf-koerper aktueller-punkt richtung best-winkel L_VF hz)) (setq aktueller-punkt (vfs-vf-exit aktueller-punkt L_GF2 hz t)) aktueller-punkt diff --git a/dcl/variofoerderer.dcl b/dcl/variofoerderer.dcl index d525479..7b33694 100644 --- a/dcl/variofoerderer.dcl +++ b/dcl/variofoerderer.dcl @@ -1,16 +1,98 @@ // ============================================================ -// variofoerderer.dcl - Standard-VarioFoerderer Parameter-Eingabe -// Zwei Dialoge fuer den Standardfall (anlage-typ "standard") von -// c:VarioFoerderer, ersetzen die interaktive Werteingabe (Modus -// "Werteingabe") aus vf-eingabe-abfragen / vf_core.lsp: -// Dialog 1 (variofoerderer_basis): deltaL, deltaH, Foerderrichtung, -// Einfuegehoehe, Fahrtrichtung, Seite. -// Dialog 2 (variofoerderer_winkel): Winkel (dynamisch berechnete -// gueltige Varianten), Verteilung der Gefaellestrecken vorne/hinten. -// Die 3D-Linie-Eingabe (Modus "3D-Linie") und andere Anlagen-Typen -// (Etage, Linienzug) bleiben interaktiv (Kommandozeile). +// variofoerderer.dcl - VarioFoerderer Parameter-Eingabe +// 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). // ============================================================ +// Anlagen-Typ waehlen (Standard/Etage/Linienzug). Radio-Buttons statt +// Dropdown - alle Optionen sofort sichtbar. WICHTIG: Labels sind hier FEST +// einprogrammiert (Deutsch) und NICHT wie bei popup_list zur Laufzeit aus +// ssg-text befuellbar (set_tile kann das Label eines radio_button nicht +// setzen, nur den Zustand - siehe auch dcl/vfl_edit_modus.dcl). Bei +// aktivem Englisch (DXFM_LANG=en_GB) faellt vfc-dialog-typ-waehlen in +// vf_core.lsp automatisch auf die alte, vollstaendig uebersetzte +// Konsolen-Liste zurueck (siehe dortiger Kommentar). +vfc_typ : dialog { + label = "VarioFoerderer - Anlagen-Typ"; + + : boxed_radio_column { + label = "Anlagen-Typ waehlen:"; + key = "typ"; + + : radio_button { + key = "typ_standard"; + label = "Standard VarioFoerderer (AS/ES 90 Grad, horizontal versetzt)"; + value = "1"; + } + : radio_button { + key = "typ_etage"; + label = "Etage VarioFoerderer (AS/ES 30 Grad, direkt uebereinander)"; + } + : radio_button { + key = "typ_linienzug"; + label = "3D-Linienzug (gemischte GF/VF-Kette)"; + } + } + + // 3-Button-Zeile wie im Linienzug-Wizard (dcl/vf_linienzug_wizard.dcl): + // Zurueck(2)/Ok Weiter(1)/Abbrechen(0). "Zurueck" hat hier nichts, wohin es + // zurueckspringen koennte (erste Frage der gesamten Anlage) - vf_core.lsp + // zeigt in diesem Fall einfach denselben Dialog erneut. + : 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; } + } +} + +// 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"; + + : boxed_radio_column { + label = "Linienzug-Modus waehlen:"; + key = "modus"; + + : radio_button { + key = "modus_1"; + label = "Manuelle Eingabe (Punkte klicken)"; + 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)"; + } + } + + // "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; } + } +} + variofoerderer_basis : dialog { label = "VarioFoerderer (Standard) - Eingabe"; diff --git a/dcl/vf_linienzug_wizard.dcl b/dcl/vf_linienzug_wizard.dcl index 38fe15e..c7bac0b 100644 --- a/dcl/vf_linienzug_wizard.dcl +++ b/dcl/vf_linienzug_wizard.dcl @@ -31,7 +31,14 @@ vflw_zahl : dialog { } } - ok_cancel; + : 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; } + } } // Mehrfachauswahl (ersetzt eine princ-Menue-Liste + getstring/getint). @@ -55,7 +62,14 @@ vflw_wahl : dialog { } } - ok_cancel; + : 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; } + } } // ============================================================ @@ -112,14 +126,24 @@ vflw_punkt_zahl : dialog { } } - ok_cancel; + // "back" nutzt hier done_dialog 3 statt 2 - Code 2 ist bereits durch den + // "Punkt waehlen..."-Button oben belegt (siehe vflw-gruppe-punkt-hoehe-impl). + : 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; } + } } // AS-/ES-Element (Kettenanfang bzw. -ende): Ja/Nein-Toggle + Winkel + Seite // in einem Bildschirm - "kopf" traegt die konkrete Frage (AS oder ES), // "setzen" bleibt bewusst generisch beschriftet, damit derselbe Dialog fuer // beide Faelle passt. Winkel/Seite werden deaktiviert, solange der Toggle -// aus ist. +// aus ist. Radio-Buttons statt Dropdown, Labels daher fest auf Deutsch +// (siehe Kommentar bei vfc_typ in variofoerderer.dcl). vflw_as : dialog { label = "VarioFoerderer Assistent"; @@ -133,24 +157,34 @@ vflw_as : dialog { key = "setzen"; label = "Ja, setzen"; } - : popup_list { - key = "winkel"; + : boxed_radio_column { label = "Winkel:"; - width = 20; + key = "winkel"; + : radio_button { key = "winkel_90"; label = "90 Grad"; value = "1"; } + : radio_button { key = "winkel_30"; label = "30 Grad"; } } - : popup_list { - key = "seite"; + : boxed_radio_column { label = "Seite:"; - width = 20; + key = "seite"; + : radio_button { key = "seite_links"; label = "Links"; value = "1"; } + : radio_button { key = "seite_rechts"; label = "Rechts"; } } } - ok_cancel; + : 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; } + } } -// Winkel + Seite. Wiederverwendet fuer GF-Bogen (3 Winkel-Optionen) UND -// ES-Element am Kettenende (2 Winkel-Optionen) - die Optionsliste wird pro -// Aufruf zur Laufzeit befuellt, die Feld-Anzahl ist in beiden Faellen gleich. +// Winkel + Seite. Wiederverwendet fuer GF-Bogen (3 Winkel-Optionen: 30/60/90) +// UND ES-Element am Kettenende (2 Winkel-Optionen: 90/30 - dort wird +// "winkel_60" per mode_tile deaktiviert, siehe vflw-gruppe-winkel-seite-impl/ +// vfl-glied-as-es-dialog). Radio-Buttons statt Dropdown, Labels fest deutsch. vflw_winkel_seite : dialog { label = "VarioFoerderer Assistent"; @@ -160,22 +194,33 @@ vflw_winkel_seite : dialog { label = ""; width = 60; } - : popup_list { - key = "winkel"; + : boxed_radio_column { label = "Winkel:"; - width = 20; + key = "winkel"; + : radio_button { key = "winkel_30"; label = "30 Grad"; } + : radio_button { key = "winkel_60"; label = "60 Grad"; } + : radio_button { key = "winkel_90"; label = "90 Grad"; value = "1"; } } - : popup_list { - key = "seite"; + : boxed_radio_column { label = "Seite:"; - width = 20; + key = "seite"; + : radio_button { key = "seite_links"; label = "Links"; value = "1"; } + : radio_button { key = "seite_rechts"; label = "Rechts"; } } } - ok_cancel; + : 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; } + } } // Vario-Kurve: Winkel + Seite + Variante (aussen/innen) in einem Bildschirm. +// Radio-Buttons statt Dropdown, Labels fest deutsch. vflw_variokurve : dialog { label = "VarioFoerderer Assistent"; @@ -185,30 +230,41 @@ vflw_variokurve : dialog { label = ""; width = 60; } - : popup_list { - key = "winkel"; + : boxed_radio_column { label = "Winkel:"; - width = 20; + key = "winkel"; + : radio_button { key = "winkel_30"; label = "30 Grad"; } + : radio_button { key = "winkel_60"; label = "60 Grad"; } + : radio_button { key = "winkel_90"; label = "90 Grad"; value = "1"; } } - : popup_list { - key = "seite"; + : boxed_radio_column { label = "Seite:"; - width = 20; + key = "seite"; + : radio_button { key = "seite_links"; label = "Links"; value = "1"; } + : radio_button { key = "seite_rechts"; label = "Rechts"; } } - : popup_list { - key = "variante"; + : boxed_radio_column { label = "Variante:"; - width = 20; + key = "variante"; + : radio_button { key = "variante_aussen"; label = "Aussen"; value = "1"; } + : radio_button { key = "variante_innen"; label = "Innen"; } } } - ok_cancel; + : 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; } + } } // Gefaelle festlegen (Linie GF): Modus (Hoehe/Winkel) + EIN Wertfeld, dessen // Beschriftung sich je nach Modus umschaltet (Action-Tile auf "modus", siehe // vflw-gruppe-gefaelle-impl in vf_linienzug.lsp). Kein Punkt-Feld - siehe -// Kopfkommentar oben. +// Kopfkommentar oben. Radio-Buttons statt Dropdown, Labels fest deutsch. vflw_gefaelle : dialog { label = "VarioFoerderer Assistent"; @@ -218,10 +274,11 @@ vflw_gefaelle : dialog { label = ""; width = 60; } - : popup_list { - key = "modus"; + : boxed_radio_column { label = "Eingabe als:"; - width = 40; + key = "modus"; + : radio_button { key = "modus_winkel"; label = "Neigungswinkel eingeben"; value = "1"; } + : radio_button { key = "modus_hoehe"; label = "Gegebene Hoehe (Zielhoehe)"; } } : text { key = "wlabel"; @@ -232,15 +289,64 @@ vflw_gefaelle : dialog { label = ""; edit_width = 10; } + // Nur befuellt/sichtbar relevant, wenn vflw-gruppe-gefaelle-impl mit + // nur-winkel=T aufgerufen wird (Zweig "Zielhoehe zuerst festlegen" bei + // "Neue Linie: GF") - zeigt dann den Hinweis, dass deltaL daraus + // berechnet wird, statt der sonst hier stehenden Hoehe-Option. + : text { + key = "hinweis"; + label = ""; + } } - ok_cancel; + : 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; } + } } -// Horizontales Stueck: Separator-vor + Separator-nach + "Foerderer-Ende?" -// (3 Optionen) in einem Bildschirm. Kein Punkt-Feld - siehe Kopfkommentar -// oben. -vflw_horizontal : dialog { +// "Wie soll die Laenge dieser Gefaellestrecke bestimmt werden?" (Neue Linie: +// GF) - Endpunkt-Pick (heutiges Verhalten) ODER Zielhoehe zuerst festlegen +// (Laenge wird dann aus Zielhoehe+Winkel berechnet, siehe +// vflw-gruppe-gf-laenge-modus-impl). Nur gezeigt, wenn bereits ein Frame +// existiert (Kettenanfang braucht weiterhin zwingend den Pick fuer die +// Richtung). Radio-Buttons statt Dropdown, Labels fest deutsch. +vflw_gf_laenge_modus : dialog { + label = "VarioFoerderer Assistent"; + + : column { + : text { + key = "kopf"; + label = ""; + width = 60; + } + : boxed_radio_column { + key = "modus"; + label = ""; + : radio_button { key = "modus_endpunkt"; label = "Endpunkt waehlen (Laenge ergibt sich)"; value = "1"; } + : radio_button { key = "modus_hoehe"; label = "Zielhoehe festlegen (Laenge wird berechnet)"; } + : radio_button { key = "modus_steigend"; label = "Steigende GF (Sonderfall, bis 3 Grad)"; } + } + } + + : 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; } + } +} + +// Separator VOR/NACH bei "Neue Linie: GF": beide Ja/Nein-Fragen in einem +// Bildschirm (Toggles, da echte Ja/Nein-Fragen - kein Radio-Cluster noetig). +// Siehe vflw-gruppe-sep-gf-impl in vf_linienzug.lsp. +vflw_sep_gf : dialog { label = "VarioFoerderer Assistent"; : column { @@ -251,20 +357,502 @@ vflw_horizontal : dialog { } : toggle { key = "sepvor"; - label = "Separator VOR dem Stueck"; + label = "Separator VOR dieser Gefaellestrecke"; } : toggle { key = "sepnach"; - label = "Separator NACH dem Stueck"; - } - : popup_list { - key = "istende"; - label = "Foerderer-Ende:"; - width = 45; + label = "Separator NACH dieser Gefaellestrecke"; } } - ok_cancel; + : 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; } + } +} + +// Horizontales Stueck: nur noch "Foerderer-Ende?" (3 Optionen) - kein +// Separator mehr (siehe vfl-baue-horizontal-koerper). Kein Punkt-Feld - +// siehe Kopfkommentar oben. Radio-Buttons statt Dropdown, Labels daher fest +// auf Deutsch (siehe Kommentar bei vfc_typ in variofoerderer.dcl). +vflw_horizontal : dialog { + label = "VarioFoerderer Assistent"; + + : column { + : text { + key = "kopf"; + label = ""; + width = 60; + } + : boxed_radio_column { + label = "Foerderer-Ende:"; + key = "istende"; + + : radio_button { + key = "istende_0"; + label = "Ja (nur Motorstation setzen)"; + value = "1"; + } + : radio_button { + key = "istende_1"; + label = "Nein (weiterbauen)"; + } + : radio_button { + key = "istende_2"; + label = "Ja (Motorstation setzen, Kettenende definieren)"; + } + } + } + + : 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; } + } +} + +// "Naechstes Element waehlen" - Hauptmenue des Linienzug-Aufbaus (Modus 1). +// IMMER alle 6 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). +vflw_naechstes_element : dialog { + label = "VarioFoerderer Assistent"; + + : column { + : text { + key = "kopf"; + label = ""; + width = 60; + } + : boxed_radio_column { + 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_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 + // (unveraendert, is_cancel -> ESC/Leertaste wirkt weiterhin), 1=Weiter + // (unveraendert, is_default), NEU 2=Zurueck (verwirft das zuletzt gebaute + // Kettenglied und fragt es neu ab, siehe vflw-gruppe-naechstes-element-impl/ + // vfl-modus-abbruch-sichern). + : 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; } + } +} + +// "Ist das das Kettenende?" (Linie-GF-Segment-Schleife) - 3 feste Optionen. +// Radio-Buttons statt Dropdown, Labels fest deutsch. +vflw_kettenende : dialog { + label = "VarioFoerderer Assistent"; + + : column { + : text { + key = "kopf"; + label = ""; + width = 60; + } + : boxed_radio_column { + key = "wahl"; + label = ""; + : radio_button { key = "wahl_ja_es"; label = "Ja (ES-Element setzen)"; } + : radio_button { key = "wahl_ja_ohne_es"; label = "Ja (ohne ES-Element setzen)"; } + : radio_button { key = "wahl_nein"; label = "Nein (weiterbauen)"; value = "1"; } + } + } + + : 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; } + } +} + +// "Ist das Kettenende?" (2-Optionen-Variante - Ja/Nein statt der 3-Optionen- +// Variante vflw_kettenende oben). Radio-Buttons statt Dropdown, Labels fest +// deutsch. +vflw_ist_kettenende_2opt : dialog { + label = "VarioFoerderer Assistent"; + + : column { + : text { + key = "kopf"; + label = ""; + width = 60; + } + : boxed_radio_column { + key = "wahl"; + label = ""; + : radio_button { key = "wahl_ja"; label = "Ja (Separator + ES-Element setzen)"; } + : radio_button { key = "wahl_nein"; label = "Nein (weiterbauen)"; value = "1"; } + } + } + + : 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; } + } +} + +// GF-Verteilung (halbe Staustrecke am Ausgang GF2 oder alles am Einlauf +// GF1) - wiederverwendet fuer Modus 1 (vfl-vf-einheit-abschluss) UND Modus 3 +// (Segment-Loop, br-gf-mode). Radio-Buttons statt Dropdown, Labels fest +// deutsch. +vflw_gf_verteilung : dialog { + label = "VarioFoerderer Assistent"; + + : column { + : text { + key = "kopf"; + label = ""; + width = 60; + } + : boxed_radio_column { + key = "wahl"; + label = ""; + : radio_button { key = "wahl_haelfte"; label = "Haelfte am Einlauf (GF1) + Haelfte am Ausgang (GF2)"; } + : radio_button { key = "wahl_einlauf"; label = "Alles am Einlauf (GF1), kein GF2"; value = "1"; } + } + } + + : 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; } + } +} + +// "Naechstes im VF" (innerhalb einer laufenden VF-Einheit weiterbauen): +// Horizontaler Foerderer / Vario-Kurve / Auf-Ab-Foerderer. Radio-Buttons +// statt Dropdown, Labels fest deutsch. +vflw_naechstes_im_vf : dialog { + label = "VarioFoerderer Assistent"; + + : column { + : text { + key = "kopf"; + label = ""; + width = 60; + } + : boxed_radio_column { + key = "wahl"; + label = ""; + : radio_button { key = "wahl_horizontal"; label = "Horizontaler Foerderer (Linie ohne Hoehendifferenz)"; } + : radio_button { key = "wahl_variokurve"; label = "Vario-Kurve (30/60/90 Grad)"; } + : radio_button { key = "wahl_aufab"; label = "Auf/Ab-Foerderer (Linie mit Hoehendifferenz)"; value = "1"; } + } + } + + : 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; } + } +} + +// Punkt-7-Winkel/Hoehen-Tabelle (vfl-waehle-winkel-hoehen-tabelle): 12 feste +// Radio-Slots (einer je Standard-Winkel 3-51 Grad), nicht baubare per +// mode_tile deaktiviert. WICHTIG: die radio_button-Tiles muessen DIREKTE +// Kinder eines radio_column/radio_row/boxed_radio_column-Clusters sein - eine +// Verschachtelung ueber : row {} INNERHALB des Clusters (fruehere Version) +// hebt die gegenseitige Ausschliesslichkeit auf (per Test bestaetigt: mehrere +// Radios gleichzeitig waehlbar, keins abwaehlbar)! Die Endhoehe steht daher +// NICHT im selben row-Tile, sondern in einer PARALLELEN Text-Spalte rechts +// daneben (eigene column AUSSERHALB des Radio-Clusters, per aeusserem : row +// nebeneinandergestellt, gleiche Zeilenreihenfolge) - dynamisch befuellt via +// vflw-gruppe-winkel-hoehen-impl (zeigt auch bei nicht baubaren Winkeln den +// Grund, siehe dortige Kommentare). +vflw_winkel_hoehen : dialog { + label = "VarioFoerderer Assistent"; + + : column { + : text { + key = "kopf"; + label = ""; + width = 60; + } + : text { label = "Winkel waehlen:"; } + : row { + : radio_column { + key = "wahl"; + : radio_button { key = "w_3"; label = "3 Grad"; } + : radio_button { key = "w_6"; label = "6 Grad"; } + : radio_button { key = "w_9"; label = "9 Grad"; } + : radio_button { key = "w_12"; label = "12 Grad"; } + : radio_button { key = "w_15"; label = "15 Grad"; } + : radio_button { key = "w_18"; label = "18 Grad"; } + : radio_button { key = "w_21"; label = "21 Grad"; } + : radio_button { key = "w_27"; label = "27 Grad"; } + : radio_button { key = "w_33"; label = "33 Grad"; } + : radio_button { key = "w_39"; label = "39 Grad"; } + : radio_button { key = "w_45"; label = "45 Grad"; } + : radio_button { key = "w_51"; label = "51 Grad"; } + } + : column { + : text { key = "h_3"; label = ""; width = 48; } + : text { key = "h_6"; label = ""; width = 48; } + : text { key = "h_9"; label = ""; width = 48; } + : text { key = "h_12"; label = ""; width = 48; } + : text { key = "h_15"; label = ""; width = 48; } + : text { key = "h_18"; label = ""; width = 48; } + : text { key = "h_21"; label = ""; width = 48; } + : text { key = "h_27"; label = ""; width = 48; } + : text { key = "h_33"; label = ""; width = 48; } + : text { key = "h_39"; label = ""; width = 48; } + : text { key = "h_45"; label = ""; width = 48; } + : text { key = "h_51"; label = ""; width = 48; } + } + } + } + + : 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; } + } +} + +// Winkel-Wahl aus berechne-alle-winkel (Zielhoehe-basierter Solve, mehrere +// gueltige Winkel): wie vflw_winkel_hoehen (radio_column direkt, Text-Spalte +// parallel daneben), aber die Text-Spalte zeigt L_GF+L_VF statt Endhoehe +// (dynamisch befuellt, siehe vflw-gruppe-winkel-wahl-impl). +vflw_winkel_wahl : dialog { + label = "VarioFoerderer Assistent"; + + : column { + : text { + key = "kopf"; + label = ""; + width = 60; + } + : text { label = "Winkel waehlen:"; } + : row { + : radio_column { + key = "wahl"; + : radio_button { key = "w_3"; label = "3 Grad"; } + : radio_button { key = "w_6"; label = "6 Grad"; } + : radio_button { key = "w_9"; label = "9 Grad"; } + : radio_button { key = "w_12"; label = "12 Grad"; } + : radio_button { key = "w_15"; label = "15 Grad"; } + : radio_button { key = "w_18"; label = "18 Grad"; } + : radio_button { key = "w_21"; label = "21 Grad"; } + : radio_button { key = "w_27"; label = "27 Grad"; } + : radio_button { key = "w_33"; label = "33 Grad"; } + : radio_button { key = "w_39"; label = "39 Grad"; } + : radio_button { key = "w_45"; label = "45 Grad"; } + : radio_button { key = "w_51"; label = "51 Grad"; } + } + : column { + : text { key = "h_3"; label = ""; width = 48; } + : text { key = "h_6"; label = ""; width = 48; } + : text { key = "h_9"; label = ""; width = 48; } + : text { key = "h_12"; label = ""; width = 48; } + : text { key = "h_15"; label = ""; width = 48; } + : text { key = "h_18"; label = ""; width = 48; } + : text { key = "h_21"; label = ""; width = 48; } + : text { key = "h_27"; label = ""; width = 48; } + : text { key = "h_33"; label = ""; width = 48; } + : text { key = "h_39"; label = ""; width = 48; } + : text { key = "h_45"; label = ""; width = 48; } + : text { key = "h_51"; label = ""; width = 48; } + } + } + } + + : 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; } + } +} + +// Generische Ja/Nein-Rueckfrage (2 Radio-Buttons, dynamischer Kopftext) - +// wiederverwendet z.B. fuer "trotzdem mit Mindestlaenge bauen?" (Zu-kurz- +// Nachfrage in vfl-baue-horizontal-koerper). Radio-Buttons statt Dropdown, +// Labels fest deutsch (nur "kopf" wird je Aufruf per set_tile befuellt). +// Drei Groessenvarianten (1/3/6 Kopf-Zeilen) statt EINER Variante mit immer 6 +// Zeilen: DCL kann Tiles nicht dynamisch ausblenden/schrumpfen - ein leeres +// text-Tile belegt trotzdem seine volle Zeilenhoehe (grosse Luecke bei kurzen +// Hinweisen wie "Zusaetzlichen Separator einfuegen?"). vflw-gruppe-ja-nein-impl +// waehlt anhand der per vflw-umbruch-zeilen ermittelten Zeilenzahl die +// passende Variante (1/3/6). Alle drei teilen dieselben Tile-Keys "kopf1".."kopfN" +// plus "wahl"/"wahl_ja"/"wahl_nein"/"back"/"accept"/"cancel" - der Aufrufer +// muss dadurch NICHT zwischen ihnen unterscheiden, ausser bei new_dialog/ +// set_tile fuer die (in der kleineren Variante gar nicht vorhandenen) hoeheren +// kopfN-Tiles. +vflw_ja_nein_1 : dialog { + label = "VarioFoerderer Assistent"; + : column { + : text { key = "kopf1"; label = ""; width = 70; } + : boxed_radio_column { + key = "wahl"; + label = ""; + : radio_button { key = "wahl_ja"; label = "Ja"; value = "1"; } + : radio_button { key = "wahl_nein"; label = "Nein"; } + } + } + : 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; } + } +} + +vflw_ja_nein_3 : dialog { + label = "VarioFoerderer Assistent"; + : column { + : text { key = "kopf1"; label = ""; width = 70; } + : text { key = "kopf2"; label = ""; width = 70; } + : text { key = "kopf3"; label = ""; width = 70; } + : boxed_radio_column { + key = "wahl"; + label = ""; + : radio_button { key = "wahl_ja"; label = "Ja"; value = "1"; } + : radio_button { key = "wahl_nein"; label = "Nein"; } + } + } + : 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; } + } +} + +vflw_ja_nein_6 : dialog { + label = "VarioFoerderer Assistent"; + : column { + : text { key = "kopf1"; label = ""; width = 70; } + : text { key = "kopf2"; label = ""; width = 70; } + : text { key = "kopf3"; label = ""; width = 70; } + : text { key = "kopf4"; label = ""; width = 70; } + : text { key = "kopf5"; label = ""; width = 70; } + : text { key = "kopf6"; label = ""; width = 70; } + : boxed_radio_column { + key = "wahl"; + label = ""; + : radio_button { key = "wahl_ja"; label = "Ja"; value = "1"; } + : radio_button { key = "wahl_nein"; label = "Nein"; } + } + } + : 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; } + } +} + +// Generische Auf/Ab-Richtungsfrage (2 Radio-Buttons, dynamischer Kopftext) - +// wiederverwendet fuer Punkt 7 (Kletter-Teilstrecke ohne Zielhoehe, sowohl +// "Naechstes im VF" als auch "Neue Linie: Ab/Auf VF" mit reduziertem +// Eingang). Radio-Buttons statt Dropdown, Labels fest deutsch. +vflw_richtung : dialog { + label = "VarioFoerderer Assistent"; + + : column { + : text { + key = "kopf"; + label = ""; + width = 60; + } + : boxed_radio_column { + key = "richtung"; + label = ""; + : radio_button { key = "richtung_auf"; label = "Auf"; value = "1"; } + : radio_button { key = "richtung_ab"; label = "Ab"; } + } + } + + : 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-Typ (kein eindeutiger GF-/VF-Baustein per KS_AUS-Scan erkannt, +// siehe vfl-eingang-modus-bestimmen): EINE flache 3-Optionen-Frage statt +// verschachtelter Zwei-Schritt-Abfrage - ist der Vorgaenger unklar, sind alle +// drei Ergebnisse gleichwertig direkt waehlbar. Radio-Buttons statt Dropdown, +// Labels fest deutsch (GF-Stumpf-Laenge als Default-Wert 400mm statisch im +// Label, siehe *vfl-gf-min-laenge*). +vflw_startpunkt_typ : dialog { + label = "VarioFoerderer Assistent"; + + : column { + : text { + key = "kopf"; + label = ""; + width = 60; + } + : boxed_radio_column { + label = "Eingang:"; + key = "eingang"; + : radio_button { key = "eingang_direkt"; label = "Direkt Umlenkstation (kein GF-Stueck)"; value = "1"; } + : radio_button { key = "eingang_stumpf"; label = "GF-Stueck (min. 400mm) + Umlenkstation"; } + : radio_button { key = "eingang_ohne"; label = "Ohne Umlenkstation (VF-Fortsetzung)"; } + } + } + + : 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; } + } } // ============================================================ @@ -278,6 +866,7 @@ vflw_horizontal : dialog { // Modus 2, Segment "Gerade": Typ (GF/VF) + [nur bei GF aktiv] GF-Neigung. // Das Neigungsfeld wird per action_tile auf "typ" aktiviert/deaktiviert. +// Radio-Buttons statt Dropdown, Labels fest deutsch. vflw_seg_linie_m2 : dialog { label = "VarioFoerderer Assistent"; @@ -287,10 +876,11 @@ vflw_seg_linie_m2 : dialog { label = ""; width = 60; } - : popup_list { - key = "typ"; + : boxed_radio_column { label = "Typ:"; - width = 40; + key = "typ"; + : radio_button { key = "typ_gf"; label = "GF (Neigungswinkel)"; value = "1"; } + : radio_button { key = "typ_vf"; label = "VF (Bruecke)"; } } : text { key = "wlabel"; @@ -301,6 +891,11 @@ vflw_seg_linie_m2 : dialog { label = ""; edit_width = 10; } + : boxed_column { + label = "Separator (nur bei GF):"; + : toggle { key = "sep_vor"; label = "Separator VOR diesem GF-Stueck"; } + : toggle { key = "sep_nach"; label = "Separator NACH diesem GF-Stueck"; } + } } ok_cancel; @@ -309,7 +904,8 @@ vflw_seg_linie_m2 : dialog { // Modus 3, Segment "Gerade": Typ (GF / VF-Ab / VF-Auf / VF-Horizontal) + EIN // Wertfeld, dessen Beschriftung mit dem Typ umschaltet (GF -> Neigung, // VF-Ab/Auf -> Vario-Winkel, VF-Horizontal -> Feld deaktiviert). Umschaltung -// per action_tile auf "typ" (siehe vflw-seg-linie-m3-impl). +// per action_tile auf "typ" (siehe vflw-seg-linie-m3-impl). Radio-Buttons +// statt Dropdown, Labels fest deutsch. vflw_seg_linie_m3 : dialog { label = "VarioFoerderer Assistent"; @@ -319,10 +915,13 @@ vflw_seg_linie_m3 : dialog { label = ""; width = 60; } - : popup_list { - key = "typ"; + : boxed_radio_column { label = "Typ:"; - width = 45; + key = "typ"; + : radio_button { key = "typ_gf"; label = "GF (Neigungswinkel)"; value = "1"; } + : radio_button { key = "typ_vfab"; label = "VF-Ab"; } + : radio_button { key = "typ_vfauf"; label = "VF-Auf"; } + : radio_button { key = "typ_vfhor"; label = "VF-Horizontal"; } } : text { key = "wlabel"; @@ -340,7 +939,9 @@ vflw_seg_linie_m3 : dialog { // Segment "Eck/Bogen" (Modus 2 + Modus 3 identisch): Typ (GF-Bogen / // Vario-Kurve) + [nur bei Vario-Kurve aktiv] Variante (aussen/innen). Die -// Variante-Liste wird per action_tile auf "typ" aktiviert/deaktiviert. +// Variante-Gruppe wird per action_tile auf "typ" aktiviert/deaktiviert, die +// Vario-Kurve-Option selbst ggf. ueber "vario-erlaubt" (mode_tile), siehe +// vflw-seg-bogen-impl. Radio-Buttons statt Dropdown, Labels fest deutsch. vflw_seg_bogen : dialog { label = "VarioFoerderer Assistent"; @@ -350,15 +951,65 @@ vflw_seg_bogen : dialog { label = ""; width = 60; } - : popup_list { - key = "typ"; + : boxed_radio_column { label = "Typ:"; - width = 40; + key = "typ"; + : radio_button { key = "typ_gfbogen"; label = "GF-Bogen"; value = "1"; } + : radio_button { key = "typ_vario"; label = "Vario-Kurve"; } } - : popup_list { - key = "variante"; + : boxed_radio_column { label = "Variante:"; - width = 30; + key = "variante"; + : radio_button { key = "variante_aussen"; label = "Aussen"; value = "1"; } + : radio_button { key = "variante_innen"; label = "Innen"; } + } + } + + ok_cancel; +} + +// Modus 2: Lauf-Abschluss, NUR wenn der VF-Lauf das Ende des gewaehlten Pfads +// ist (kein Back-Lauf danach) - siehe vflw-m2-lauf-abschluss-impl. Radio- +// Buttons, Labels fest deutsch. +vflw_m2_lauf_abschluss : dialog { + label = "VarioFoerderer Assistent"; + + : column { + : text { + key = "kopf"; + label = ""; + width = 60; + } + : boxed_radio_column { + label = "Lauf beenden mit:"; + key = "abschluss"; + : radio_button { key = "abschluss_offen"; label = "Ohne Motorstation (offenes Ende, spaeter fortsetzen)"; } + : radio_button { key = "abschluss_motor"; label = "Motorstation setzen"; value = "1"; } + : radio_button { key = "abschluss_motor_es"; label = "Motorstation + ES-Element setzen (Kettenende)"; } + } + } + + ok_cancel; +} + +// Modus 2: Lauf-Anfang, NUR wenn der VF-Lauf der Anfang des gewaehlten Pfads +// ist (kein Front-Lauf davor) - siehe vflw-m2-lauf-anfang-impl. Radio-Buttons, +// Labels fest deutsch. +vflw_m2_lauf_anfang : dialog { + label = "VarioFoerderer Assistent"; + + : column { + : text { + key = "kopf"; + label = ""; + width = 60; + } + : boxed_radio_column { + label = "Lauf beginnen mit:"; + key = "anfang"; + : radio_button { key = "anfang_offen"; label = "Ohne Umlenkstation (offener Anfang, spaeter fortsetzen)"; } + : radio_button { key = "anfang_umlenk"; label = "Umlenkstation direkt (kein GF1/Separator)"; } + : radio_button { key = "anfang_umlenk_gf1"; label = "Umlenkstation mit GF1 + Separator"; value = "1"; } } } diff --git a/doc/vf_linienzug_modus1_anleitung.md b/doc/vf_linienzug_modus1_anleitung.md new file mode 100644 index 0000000..371b0ba --- /dev/null +++ b/doc/vf_linienzug_modus1_anleitung.md @@ -0,0 +1,194 @@ +# VF-Linienzug Modus 1 - Anleitung anhand eines realen Beispiels + +Diese Anleitung erklaert Modus 1 des VF-Linienzugs ("Manuelle Eingabe", +`vf-linienzug-modus` in `Lisp/vf_linienzug.lsp`) nicht abstrakt, sondern +Schritt fuer Schritt anhand eines echten, in BricsCAD gebauten und +verifizierten Beispiels. Dasselbe Beispiel ist als automatisierter +Regressionstest hinterlegt: `tests/testdata/linienzug_tests_stufe2.json`, +aufrufbar in BricsCAD ueber `TEST_LINIENZUG_STUFE2` (siehe +`tests/test_linienzug.lsp`). Wer die Zahlen selbst nachvollziehen will, kann +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. + +## 1. Was ist Modus 1? + +Modus 1 baut eine VF-Linienzug-Kette **interaktiv, Element fuer Element**: +Sie klicken/geben nacheinander Punkte, Laengen, Winkel und Ja/Nein- +Entscheidungen ein, und jede Antwort erzeugt sofort ein Stueck Geometrie +(Umlenkstation, Gefaellestrecke, VF-Einheit, Vario-Kurve, ...). Das +unterscheidet Modus 1 von: + +- **Modus 2** (Ziel-Hoehe-Modus): Sie zeichnen vorher einen Pfad (LINE/ARC- + Kette) und eine Zielhoehe, das Programm loest die Kette automatisch. +- **Modus 3** (Vorwaerts-Nachbau): rekonstruiert eine Kette aus einer + bestehenden Zeichnung (Legacy, wird umgebaut). + +**Aufruf:** Befehl `FOERDERANLAGE` (bzw. `VarioFoerderer`) -> Anlagen-Typ +"Linienzug" waehlen -> Modus "1" (Manuelle Eingabe). + +Jede Eingabe wird in einem Journal mitgeschrieben und als XDATA auf den +fertigen `VF_n`-Block geschrieben. Ein Abbruch (ESC) loescht dadurch nichts - +die bis dahin gebaute Teilkette bleibt als Block stehen und ist per +Doppelklick weiter bearbeitbar. + +## 2. Das Beispiel im Ueberblick + +Die Kette aus `linienzug_tests_stufe2.json` sieht so aus (Grundriss, von +oben betrachtet): + +``` +Start (Z=2154) --AS 90 links--> Horizontal-VF --Vario 90 rechts innen--> + --Horizontal-VF--> --Vario 90 rechts innen--> Linie-GF (3 Grad, Separator + vor+nach) --> Horizontal-VF --Vario 30 rechts innen--> Auf 27 Grad + --Vario 30 links aussen--> Kettenende (Motorstation + ES 90 links) +``` + +Kurz gesagt: die Kette startet auf Z=2154, macht zwei 90-Grad-Schwenks im +Grundriss, faellt ueber ein eigenstaendiges GF-Stueck (3 Grad) etwas ab, +steigt dann in einer zweiten VF-Einheit um 27 Grad wieder an, und muss am +Ende exakt auf die Starthoehe (2154mm) zurueckkommen. Genau dieser letzte +Schritt - der Rest-Hoehenausgleich passt zu keinem der Standard-Winkel mehr - +ist der interessante Teil (siehe Abschnitt 4, Stufe 1/Stufe 2). + +## 3. Die Fragen der Reihe nach + +Diese Tabelle zitiert die tatsaechlichen Konsolen-Fragen aus dem Testfall +(Kommentar-Spalte = `kommentar`-Feld im JSON) und erklaert, was jede Frage +bedeutet. + +| # | 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 | + +**Wichtig zu Frage 9/14/17 ("Ist der Endpunkt der Foerderer?"):** 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, +weiteres gerades Stueck, Auf/Ab). "Ja" beendet die VF-Einheit mit einer +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/ +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`, +`Lisp/vf_linienzug.lsp`): + +- **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 + 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 + 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. + +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 +`vfl-loesche-seit`/`vfl-modus-abbruch-sichern`). + +**Merksatz:** Stufe 1 sucht einen "sauberen" Standard-Winkel; Stufe 2 ist +der Rettungsanker, wenn dafuer schlicht nicht genug Platz ist - er tauscht +einen Vertikalbogen gegen "flach + minimaler GF-Ausgleich". + +## 5. Typische Stolperfallen + +### a) Gefaellestrecke (GF) ist "laengenhungrig" bei 3 Grad + +3 Grad ist ein SEHR flacher Winkel. `tan(3 Grad) ~= 0.0524`, also braucht +jeder Millimeter Hoehenunterschied ungefaehr **19mm** Laenge: + +``` +Laenge = Hoehendifferenz / tan(3 Grad) ~= Hoehendifferenz * 19 +``` + +Wer nur wenige mm bis cm Hoehenunterschied ausgleichen will, bekommt damit +schnell GF-Laengen im halben bis ganzen Meterbereich. Das ist die haeufigste +Ursache fuer "die Reststrecke ist zu kurz"-Meldungen und fuer den +Stufe-2-Fallback aus Abschnitt 4. Falls eine GF partout nicht passt: entweder +mehr Grundriss-Laenge einplanen, oder pruefen, ob ein Vertikalbogen +(Vario-Kurve mit groesserem Winkel, siehe Stufe 1) die bessere Wahl ist. + +### b) Motorstation + Separator + ES-Element haben einen FESTEN Fussabdruck + +Am Kettenende ist nicht die ganze gepickte Reststrecke frei verfuegbar - +ein fester Anteil ist fuer Motorstation und Separator reserviert +(`*vfk-feste-horizontal-kettenende*` = 800mm = 500mm Motorstation + 300mm +Separator), und falls zusaetzlich ein ES-Element gewaehlt wird, kommt dessen +eigener Fussabdruck (abhaengig von 30/90 Grad Bauform) noch oben drauf. Wer +diese festen 800mm (+ ES) nicht einplant, landet schnell bei einer negativen +"freien" Reststrecke - genau der Fall, der in Abschnitt 4 den Stufe-2- +Fallback ausloest. + +### c) Seitlicher Versatz bei 90-Grad-AS/ES-Elementen ist NORMAL + +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). +**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, +ist ein KORREKTES Ergebnis, keine Abweichung, die weiter untersucht werden +muss. + +## 6. Nachvollziehen / Nachbauen + +- Live in BricsCAD: `FOERDERANLAGE` -> Linienzug -> Modus 1, und die + Eingaben aus der Tabelle in Abschnitt 3 der Reihe nach eintippen/klicken. +- Automatisiert (ohne Klicks): Befehl `TEST_LINIENZUG_STUFE2` (nach Laden + von `tests/test_linienzug.lsp`) spielt exakt dieselbe Sequenz aus + `tests/testdata/linienzug_tests_stufe2.json` ab und meldet das + Ist-Ziel-Ergebnis in der Konsole. +- Debug-Log: mit `dbgopen`/dem zentralen Debug-Schalter (siehe + `Lisp/ssg_dbg.lsp`) lassen sich alle `GEOMETRIE:`/`GEOMETRIE ERFOLG:`- + Zeilen in eine `.dbg`-Datei im Log-Verzeichnis mitschreiben - hilfreich, + um genau wie in diesem Beispiel eine reale Sitzung nachtraeglich in + einen Testfall zu verwandeln. diff --git a/lang/de_DE.json b/lang/de_DE.json index 6c2392e..0eacde9 100644 --- a/lang/de_DE.json +++ b/lang/de_DE.json @@ -2,6 +2,7 @@ "texts": { "vfl-alert-gf-modul-fehlt": "Gefaellestrecke-Modul nicht geladen!\nDer Linienzug-Typ benoetigt Gefaellestrecke.lsp\n(GF-Segmente und GF-Boegen). Bitte Menue laden.", "vfl-prompt-startpunkt-kette": "\n\nStartpunkt der Kette waehlen: ", + "vfl-prompt-richtung-waehlen": "\n\nFahrtrichtung waehlen (Punkt in gewuenschter Richtung klicken - der Abstand wird ignoriert): ", "vfl-prompt-hoehe-startpunkt-kette": "\nHoehe (Z) des Startpunkts [%1]: ", "vfl-abgebrochen": "\nAbgebrochen.", "vfl-as-setzen-frage": "\n\nAS-Element setzen?", @@ -19,24 +20,53 @@ "vfl-menu-horizontal-vf-3": "\n 3 - Neue VF mit horizontalem Anfang (Horizontal-Stueck)", "vfl-menu-linie-ende-4": "\n 4 - Neue Linie BIS Kettenende (danach Separator + ES-Element)", "vfl-prompt-wahl-1-4-def1": "\nIhre Wahl (1-4) [1]: ", - "vfl-fehler-horizontal-vf-kurz": "\nFEHLER: Horizontaler VF braucht >= 1000 mm (Umlenk + Motor) - laenger zeichnen.", + "vfl-menu-gf-bogen-ka-1": "\n 1 - GF-Bogen (horizontale Kurve)", + "vfl-menu-variokurve-ka-2": "\n 2 - Vario-Kurve (horizontale Kurve, 30/60/90 Grad)", + "vfl-menu-linie-gf-ka-3": "\n 3 - Neue Linie: GF (Gefaellestrecke)", + "vfl-menu-linie-vf-ka-4": "\n 4 - Neue Linie: Ab/Auf VF (VarioFoerderer-Einheit)", + "vfl-menu-horizontal-vf-ka-5": "\n 5 - Neue VF mit horizontalem Anfang (Horizontal-Stueck)", + "vfl-menu-linie-ende-ka-6": "\n 6 - Neue Linie BIS Kettenende (danach Separator + ES-Element)", + "vfl-prompt-wahl-1-6-def3": "\nIhre Wahl (1-6) [3]: ", + "vfl-fehler-horizontal-fussabdruck-zu-kurz": "\nFEHLER: Fussabdruck passt nicht in die gewaehlte Strecke (Rest waere nur %1 mm) - kuerzer/weniger Zusatzelemente waehlen oder laenger zeichnen.", + "vfl-hinweis-horizontal-fussabdruck-zu-kurz": "\n\nHinweis: gewaehlte Reststrecke war %1 mm, nach dem 3-Grad-Uebergangsbogen blieben nur %2 mm (Minimum: %3 mm). Trotzdem mit der Mindestlaenge weiterbauen (Kettenpunkt landet dann entsprechend weiter als angeklickt)?", "vfl-fehler-linie-zu-kurz": "\nFEHLER: Linie zu kurz (oder entgegen der Fahrtrichtung) - bitte erneut waehlen.", "vfl-fehler-vf-kurz": "\nFEHLER: VarioFoerderer braucht >= 1000 mm (Umlenk + Motor) - laenger zeichnen oder \"GF\" waehlen.", "vfl-gefaelle-festlegen-header": "\nGefaelle festlegen:", - "vfl-gefaelle-opt-hoehe": "\n 1 - Gegebene Hoehe (Zielhoehe)", - "vfl-gefaelle-opt-winkel": "\n 2 - Neigungswinkel eingeben", + "vfl-gefaelle-opt-hoehe": "\n 2 - Gegebene Hoehe (Zielhoehe)", + "vfl-gefaelle-opt-winkel": "\n 1 - Neigungswinkel eingeben", "vfl-prompt-neigungswinkel": "\nNeigungswinkel (Grad, 0 < Winkel <= %1) [%1]: ", + "vfl-prompt-neigungswinkel-laenge-berechnet": "\nNeigungswinkel (Grad, 0 < Winkel <= %1) [%1] (deltaL wird berechnet und eingefuegt): ", + "vfl-gf-hinweis-laenge-berechnet": "(deltaL wird berechnet und eingefuegt)", + "vfl-gf-laenge-modus-header": "\nWie soll die Laenge dieser Gefaellestrecke bestimmt werden?", + "vfl-gf-laenge-modus-opt-endpunkt": "\n 1 - Endpunkt waehlen (Laenge ergibt sich)", + "vfl-gf-laenge-modus-opt-hoehe": "\n 2 - Zielhoehe festlegen (Laenge wird berechnet)", + "vfl-gf-laenge-modus-opt-steigend": "\n 3 - Steigende GF (Sonderfall, bis 3 Grad)", + "vfl-prompt-neigungswinkel-steigend": "\nSteigungswinkel (Grad, 0 <= Winkel <= %1, 0 = flach) [%1]: ", + "vfl-alert-winkel-ungueltig-steigend": "Steigungswinkel ungueltig: %1 Grad. Erlaubt: 0 <= Winkel <= %2 Grad.", + "vfl-alert-gf-steigend-falsche-richtung": "Steigende Gefaellestrecke: die gewaehlte Zielhoehe liegt unter der aktuellen Hoehe - bitte hoehere Zielhoehe waehlen oder den normalen (fallenden) Modus benutzen.", "vfl-alert-winkel-ungueltig": "Neigungswinkel ungueltig: %1 Grad. Erlaubt: 0 < Winkel <= %2 Grad.", "vfl-prompt-hoehe-linienendpunkt": "\nHoehe (Z) des Linienendpunkts [%1]: ", "vfl-prompt-hoehe-linienendpunkt-2": "\nHoehe (Z) des Linienendpunkts (Ab: %1 | Auf: %2) [%1]: ", "vfl-hinweis-hoehe-vorschlag-fehlt": "\n(Hinweis: In diese Richtung ist bei dieser Segmentlaenge kein baubarer Vorschlag gefunden - bitte Wert manuell pruefen.)", "vfl-alert-gf-kann-nicht-steigen": "Gefaellestrecke (GF) kann nicht steigen - bitte tiefere Zielhoehe waehlen oder Ab/Auf VF benutzen.", "vfl-alert-gefaelle-zu-steil": "Gefaelle zu steil fuer GF: %1 Grad (erlaubt max %2 Grad).\nBitte kleinere Hoehendifferenz waehlen oder Ab/Auf VF benutzen.", + "vfl-prompt-hoehe-eingang-gf1": "\nZielhoehe (Z) am Uebergang zur horizontalen Strecke [%1]: ", + "vfl-alert-eingang-kann-nicht-steigen": "Diese VF-Einheit (horizontaler Anfang) kann nicht steigen - bitte 'Neue Linie: Ab/Auf VF' verwenden.", + "vfl-alert-eingang-hoehe-zu-klein": "Zielhoehe zu klein: mindestens %1 mm Hoehenabsenkung noetig (Separator+Umlenkstation+Uebergangsbogen allein erreichen schon so viel). Bitte tiefere Zielhoehe eingeben.", + "vfl-alert-eingang-hoehe-zu-gross": "Zielhoehe zu weit entfernt fuer diese Streckenlaenge - maximal erreichbare Zielhoehe waere ca. %1 mm. Bitte 'Neue Linie: Ab/Auf VF' verwenden.", "vfl-ist-kettenende-header": "\nIst das das Kettenende?", "vfl-kettenende-opt-ja-es": "\n 1 - Ja (ES-Element setzen)", "vfl-kettenende-opt-ja-ohne-es": "\n 2 - Ja (ohne ES-Element setzen)", "vfl-kettenende-opt-nein": "\n 3 - Nein (weiterbauen)", "vfl-alert-vf-nicht-baubar": "VF-Einheit geometrisch nicht baubar!\ndeltaL=%1 mm, deltaH=%2 mm, Richtung=%3\nBitte anderen Endpunkt/Hoehe waehlen.", + "vfl-alert-kettenende-p1": "1. Ziel △L=%1 mm, △H=%2 mm (%3): Auf/Ab-Foerderer (Winkel-Tabelle) nicht baubar.", + "vfl-alert-kettenende-p2-beide": "\n\n2. Horizontal+GF nicht baubar - noetig waeren mindestens △L=%1 mm ODER mindestens △H=%2 mm.", + "vfl-alert-kettenende-p2-nur-minh": "\n\n2. Horizontal+GF nicht baubar - noetig waere mindestens △H=%1 mm Hoehenaenderung.", + "vfl-alert-kettenende-p2-nur-minl": "\n\n2. Horizontal+GF nicht baubar - noetig waere mindestens △L=%1 mm Streckenlaenge.", + "vfl-alert-vf-entscheidung-p1": "1. Ziel △L=%1 mm, △H=%2 mm (%3): Winkel-Tabelle nicht baubar.", + "vfl-alert-vf-entscheidung-p2-beide": "\n\n2. Mindestens noetig waeren: △L=%1 mm ODER △H=%2 mm.", + "vfl-alert-vf-entscheidung-p2-nur-minh": "\n\n2. Mindestens noetig waere: △H=%1 mm Hoehenaenderung.", + "vfl-alert-vf-entscheidung-p2-nur-minl": "\n\n2. Mindestens noetig waere: △L=%1 mm Streckenlaenge.", "vfl-alert-segment-nicht-baubar": "Segment geometrisch nicht baubar!\ndeltaL=%1 mm, deltaH=%2 mm, Richtung=%3\nBitte anderen Endpunkt/Hoehe waehlen.", "vfl-info-kurzes-segment": "\n>>> Kurzes Segment (deltaL=%1 mm < 1000): automatisch 3-Grad-Gefaellestrecke (keine Hoehenabfrage, deltaH=%2 mm).", "vfl-info-kettenende-footprint": "\n>>> Kettenende-Modus: Footprint fuer Separator + ES reserviert -> baubar deltaL=%1 mm, deltaH=%2 mm.", @@ -69,9 +99,14 @@ "vfc-block-eingefuegt-xyzref-ksaus": "\n '%1' eingefuegt (XY:%2 Z:%3)\n KS_AUS: X=%4 Y=%5 Z=%6", "vfl-ja": "\n 1 - Ja", "vfl-nein": "\n 2 - Nein", + "vfl-antwort-ja": "Ja", + "vfl-antwort-nein": "Nein", + "vfl-wizard-antwort-echo": "\n -> Auswahl im Dialog: %1", "vfl-sep-vor-frage": "\n\nZusaetzlichen Separator VOR dem horizontalen Stueck?", "vfl-sep-nach-frage": "\n\nZusaetzlichen Separator NACH dem horizontalen Stueck?", "vfl-sep-an-stelle-frage": "\n\nZusaetzlichen Separator an dieser Stelle einfuegen?", + "vfl-sep-vor-gf-frage": "\n\nSeparator VOR dieser Gefaellestrecke einfuegen?", + "vfl-sep-nach-gf-frage": "\n\nSeparator NACH dieser Gefaellestrecke einfuegen?", "vf-winkel-aus-header": "\n\nAUS-Element (AS_Element) - Winkel waehlen:", "vf-winkel-ein-header": "\n\nEIN-Element (ES_Element) - Winkel waehlen:", "vf-winkel-90": "\n 1 - 90 Grad", @@ -137,6 +172,17 @@ "vfl-m3-warnung-zu-steil": "\n WARNUNG: ~Neigung > 51 Grad -> zu steil fuer Vario (Magnitude infeasibel).", "vfl-m3-vario-bereich-ok": "\n -> innerhalb Vario-Bereich (3..51 Grad), grobe Orientierung.", "vfl-m3-anker-hinweis": "\n (Anker oben = grobe Vorschau; exakte Werte werden beim Bau GEMESSEN)", + "vfl-m3-lauf-abschluss-header": "\n\nDer VF-Lauf ist das Ende des gewaehlten Pfads. Lauf beenden mit:", + "vfl-m3-lauf-abschluss-opt-offen": "\n 1 - Ohne Motorstation (offenes Ende, spaeter fortsetzen/verschmelzen)", + "vfl-m3-lauf-abschluss-opt-motor": "\n 2 - Motorstation setzen (kein ES-Element)", + "vfl-m3-lauf-abschluss-opt-motor-es": "\n 3 - Motorstation + ES-Element setzen (Kettenende)", + "vfl-m3-lauf-abschluss-offen-hinweis": "\n Lauf bleibt bewusst offen - keine Motorstation/Separator/ES gebaut, spaeter fortsetzen oder per Vario_Kette_Merge verbinden.", + "vfl-m3-lauf-anfang-header": "\n\nDer VF-Lauf ist der Anfang des gewaehlten Pfads. Lauf beginnen mit:", + "vfl-m3-lauf-anfang-opt-offen": "\n 1 - Ohne Umlenkstation (offener Anfang, spaeter fortsetzen/verschmelzen)", + "vfl-m3-lauf-anfang-opt-umlenk": "\n 2 - Umlenkstation direkt (kein GF1/Separator)", + "vfl-m3-lauf-anfang-opt-umlenk-gf1": "\n 3 - Umlenkstation mit GF1 + Separator", + "vfl-m3-lauf-anfang-offen-hinweis": "\n Anfang bleibt bewusst offen - keine Umlenkstation/GF1/Separator gebaut, spaeter fortsetzen oder per Vario_Kette_Merge verbinden.", + "vfl-m3-alert-vf-zu-lang": "VF-Lauf ist %1 m lang (Grenze %2 m) - bitte neu planen (z.B. Zwischen-Motorstation einfuegen).", "vfl-m3-phase-b1": "\n\n>>> Phase B1: Front-Lauf (AS + GF) bauen ...", "vfl-m3-alert-beginnt-bogen": "Kette beginnt mit einem Bogen - bitte erst eine Gerade.", "vfl-m3-kurve-front-uebersprungen": "\n >>> [M3a] Vario-Kurve im Front-Lauf - uebersprungen.", @@ -145,9 +191,15 @@ "vfl-m3-junction-exakt": "\n Junction (exakt): %1 mm", "vfl-m3-kletter-info": "\n Kletterhoehe %1 mm | Kletterer %2 | Kurven %3 | kurze VF %4", "vfl-m3-kein-winkel": "\n KEIN passender Vario-Winkel -> infeasibel (Front bereits gebaut).", + "vfl-m3-kletter-zu-kurz-flach": "\n Kein Kletter-Winkel passt (Segment zu kurz) -> Lauf wird komplett flach gebaut, Hoehe wandert in GF1.", + "vfl-m3-kletter-flach-gf": "\n Flache Zone: GF-Kompensation (GF1) = %1 mm", + "vfl-m3-warnung-fueller-eingang-zu-kurz": "\n WARNUNG: Fueller direkt nach der Umlenkstation zu kurz (%1 mm < Minimum %2 mm) - nur Minimalabstand gebaut, Zielposition nicht exakt erreicht.", + "vfl-m3-warnung-fueller-ausgang-zu-kurz": "\n WARNUNG: Fueller direkt vor der Motorstation zu kurz (%1 mm < Minimum %2 mm) - nur Minimalabstand gebaut, Zielposition nicht exakt erreicht.", "vfl-m3-gf-verteilung": "\n\n GF-Verteilung: 1 - alles am Einlauf (GF1) 2 - 1/2 GF1 + 1/2 GF2", + "vfl-m3-gf-verteilung-alles-auslauf": "\n Kein GF1-Platz am Einlauf gewaehlt - komplette Kompensation wandert nach GF2 (Auslauf).", "vfl-m3-vert-halb": "1/2 GF1 + 1/2 GF2", "vfl-m3-vert-ganz": "alles GF1", + "vfl-m3-vert-auslauf": "alles GF2 (Auslauf)", "vfl-m3-vario-ergebnis": "\n -> Vario %1 (%2), L_VF %3 mm, GF gesamt %4 mm, Verteilung %5 (GF2-Rest = Mess-Feinkorrektur)", "vfl-m3-warnung-gf2-negativ": "\n WARNUNG: Koerper klettert zu wenig - GF2<0 (fehlen %1 mm). Winkel zu flach; dZ nicht exakt.", "vfl-m3-gf2-ausgleich": "\n GF2 (gemessener Ausgleich): L=%1 mm", @@ -285,15 +337,46 @@ "vfl-20m-hinweis": "\n >>> HINWEIS: Foerderer laenger als 20 m (%1 m) - Motorstation empfohlen!", "vfl-block-erstellt": "\n>>> Block '%1' (%2) erstellt und eingefuegt.", "vfl-fehler-rest-nicht-baubar": "\n FEHLER: Rest nicht baubar (zu steil/zu kurz fuer Schwanz Motor+GF2+Separator+ES). Bitte weiter zeichnen oder flacher planen.", + "vfl-fehler-rest-nicht-baubar-mit-vorschlag": "\n FEHLER: Bei Zielhoehe %1 mm (Strecke dL=%2 mm, Hoehendifferenz dH=%3 mm, %4) nicht baubar (zu steil/zu kurz fuer Schwanz Motor+GF2+Separator+ES). Baubare Zielhoehe waere ungefaehr:%5", + "vfl-fehler-rest-nicht-baubar-ohne-vorschlag": "\n FEHLER: Bei Zielhoehe %1 mm (Strecke dL=%2 mm, Hoehendifferenz dH=%3 mm, %4) nicht baubar - bei dieser Streckenlaenge wurde auch keine alternative Zielhoehe gefunden. Bitte laenger zeichnen oder flacher planen.", + "vfl-vorschlag-ab-auf": " Ab %1 mm oder Auf %2 mm", + "vfl-vorschlag-nur-ab": " Ab %1 mm (Auf ist bei dieser Streckenlaenge nicht baubar)", + "vfl-vorschlag-nur-auf": " Auf %1 mm (Ab ist bei dieser Streckenlaenge nicht baubar)", + "vfl-stufe1-start": "\n\n[Diagnose Stufe 1 - VF-Winkel-Suche]", + "vfl-stufe2-diagnose": "\n\n[Diagnose Stufe 2 - horizontal+GF] deltaL=%1 mm deltaH=%2 mm -> GF_total=%3 mm L_VF=%4 mm (%5)", + "vfl-stufe2-diagnose-details": "\n [Details] schon-flach=%1 | aus-dx=%2 mm (Einlauf, sollte 0 sein) | ein-dx=%3 mm ein-dz=%4 mm (ES-Element) | bogen-x1=%5 mm bogen-z1=%6 mm (Eintrittsbogen 3->0 Grad, nur falls nicht schon-flach) | bogen-x2=%7 mm bogen-z2=%8 mm (Austrittsbogen 0->3 Grad, immer) | FESTE_HORIZONTAL=%9 mm (Separator+Motorstation)", + "vfl-stufe2-fest-kettenende": "\n Motorstation+Separator+ES benoetigen: Laenge=%1 mm, Hoehenabsenkung=%2 mm (fest, unabhaengig vom Winkel)", + "vfl-stufe2-fest-eingang": "\n Umlenkstation+Separator+Motorstation+ES benoetigen: Laenge=%1 mm, Hoehenabsenkung=%2 mm (fest, unabhaengig vom Winkel)", + "vfl-stufe2-minl": "\n [Mindestwert 1] Ohne geraden VF-Anteil (GF nach Zielhoehe dimensioniert): mindestens %1 mm Streckenlaenge noetig (vorhanden: %2 mm)", + "vfl-stufe2-minl-unmoeglich": "\n [Mindestwert 1] Nicht per Streckenlaenge loesbar: schon ohne GF-Bogen aendert sich die Hoehe um %1 mm - die Zielhoehe verlangt aber nur %2 mm (zu wenig Hoehenunterschied fuer die feste Neigung)", + "vfl-stufe2-minh": "\n [Mindestwert 2] Ohne GF-Bogen (Rest als gerader VF-Anteil, der die Hoehe nicht aendert): mindestens %1 mm Hoehenaenderung noetig (vorhanden: %2 mm)", + "vfl-stufe2-minh-unmoeglich": "\n [Mindestwert 2] Nicht per Zielhoehe loesbar: schon ohne geraden VF-Anteil und ohne GF-Bogen betraegt der feste Fussabdruck %1 mm - die Strecke bietet aber nur %2 mm", + "vfl-stufe2-ungueltig": "\n Stufe 2 (horizontal+GF) war ungueltig - es wurde stattdessen Stufe 1 (VF-Winkel-Suche) versucht (siehe Tabelle oben).", "vfl-fuege-block-ein": "\n Fuege %1 ein ...", - "vfl-hinweis-gf2-minimum": "\n HINWEIS: berechnetes GF2=%1 mm < Minimum %2 mm -> auf Minimum angehoben (ES endet dadurch etwas weiter; siehe Ist-Ziel-Report).", + "vfl-frage-gf2-minimum": "\n Berechnetes GF2=%1 mm liegt unter der ueblichen Mindestlaenge (%2 mm).\n Ja = mit den exakt berechneten %1 mm bauen (Zielpunkt wird exakt getroffen).\n Nein = auf %2 mm auffuellen (Zielpunkt verschiebt sich entsprechend weiter).", "vfl-horizontale-zwischenstrecke": "\n\nHorizontale Zwischenstrecke (0 Grad, L=%1 mm)", "vfl-kettenende-modus-ziel": "\n>>> Kettenende-Modus: Ziel dL=%1 mm, dH=%2 mm (%3). GF2 variiert mit dem Winkel.", "vfl-prompt-hoehe-endpunkt": "\nHoehe (Z) des Endpunkts [%1]: ", "vfl-prompt-hoehe-endpunkt-2": "\nHoehe (Z) des Endpunkts (Ab: %1 | Auf: %2) [%1]: ", "vfl-prompt-hoehe-kettenende": "\nHoehe (Z) des Kettenendes (ES-Element) [%1]: ", "vfl-prompt-hoehe-kettenende-2": "\nHoehe (Z) des Kettenendes (ES-Element) (Ab: %1 | Auf: %2) [%1]: ", + "vfl-prompt-wahl-1-2": "\nIhre Wahl (1-2) [1]: ", "vfl-prompt-wahl-bis-n": "\nIhre Wahl (1-%1) [1]: ", + "vfl-frage-auf-ab-richtung": "\n\nKette kommt flach an - keine Zielhoehe verfuegbar. Richtung waehlen:", + "vfl-frage-startpunkt-typ": "\n\nAm Startpunkt konnte kein eindeutiger GF-/VF-Baustein erkannt werden (GF-Stueck und VF-Horizontalstueck sehen baulich identisch aus). Wie soll der Eingang gebaut werden?", + "vfl-opt-eingang-direkt": "\n 1 - Direkt Umlenkstation bauen (kein GF-Stueck)", + "vfl-opt-eingang-mit-stumpf": "\n 2 - GF (%1 mm) + Umlenkstation", + "vfl-opt-eingang-ohne-umlenk": "\n 3 - Ohne Umlenkstation (VF-Fortsetzung)", + "vfl-opt-richtung-auf": "\n 1 - Auf", + "vfl-opt-richtung-ab": "\n 2 - Ab", + "vfl-winkel-hoehen-header": "\n\nVerfuegbare Winkel und die damit erreichte Endhoehe - bitte waehlen:", + "vfl-winkel-hoehen-option": "\n %1 - %2 Grad (Endhoehe: %3 mm)", + "vfl-winkel-hoehen-zeile": "\n %1 Grad - Endhoehe: %2 mm", + "vfl-winkel-hoehen-zeile-tile": "Endhoehe: %1 mm", + "vfl-winkel-wahl-zeile-tile": "L_GF=%1 mm L_VF=%2 mm", + "vfl-winkel-zeile-tile-ungueltig": "nicht baubar (Bogen passt nicht in die gewaehlte Strecke)", + "vfl-winkel-hoehen-zeile-ungueltig": "\n %1 Grad - nicht baubar (Bogen passt nicht in die gewaehlte Strecke)", + "vfl-winkel-hoehen-abweichung": "\n [Hinweis] Ist-Ziel-Vergleich: vorhergesagte Endhoehe %1 mm, tatsaechlich erreicht %2 mm.", "vfl-segment-gf-nicht-erlaubt": "\n Segment waere GF (zu steil) oder nicht baubar - innerhalb einer VF-Einheit nicht erlaubt.\n Bitte flacher/steigend zeichnen oder Foerderer beenden.", "vfl-winkel-option": "\n %1 - %2 Grad (L_GF=%3 mm L_VF=%4 mm)", "vfs-as90-mass": "\n AS_90: dx=%1 dz=%2", @@ -767,6 +850,7 @@ "vfl-abbruch-gesichert": "\n>>> Linienzug abgebrochen: %1 Objekt(e) als Block gesichert (per Doppelklick editierbar/fortsetzbar).", "vfl-abbruch-nichts-gebaut": "\n>>> Abgebrochen - es wurde noch keine Geometrie erzeugt.", "vfl-abbruch-wickeln-fehler": "\n>>> FEHLER beim Sichern der Teil-Geometrie als Block: %1", + "vfl-zurueck-glied-verworfen": "\n>>> Zurueck: letztes Kettenglied wird verworfen - bitte neu beantworten.", "vfl-edit-dialog-fehlt": "Dialog nicht gefunden: %1", "vfl-edit-abgebrochen": "\nEditieren abgebrochen - keine Aenderung.", "vfl-dlg-kopf-sektionen": "Sektionen: %1", diff --git a/lang/en_GB.json b/lang/en_GB.json index 82d7fc0..8b37da1 100644 --- a/lang/en_GB.json +++ b/lang/en_GB.json @@ -2,6 +2,7 @@ "texts": { "vfl-alert-gf-modul-fehlt": "Slope-section module not loaded!\nThe chain type requires Gefaellestrecke.lsp\n(GF segments and GF arcs). Please load the menu.", "vfl-prompt-startpunkt-kette": "\n\nSelect chain start point: ", + "vfl-prompt-richtung-waehlen": "\n\nChoose direction (click a point in the desired direction - the distance is ignored): ", "vfl-prompt-hoehe-startpunkt-kette": "\nHeight (Z) of the start point [%1]: ", "vfl-abgebrochen": "\nCancelled.", "vfl-as-setzen-frage": "\n\nPlace AS element?", @@ -19,24 +20,53 @@ "vfl-menu-horizontal-vf-3": "\n 3 - New VF with horizontal start (horizontal piece)", "vfl-menu-linie-ende-4": "\n 4 - New line TO chain end (then separator + ES element)", "vfl-prompt-wahl-1-4-def1": "\nYour choice (1-4) [1]: ", - "vfl-fehler-horizontal-vf-kurz": "\nERROR: Horizontal VF needs >= 1000 mm (deflection + motor) - draw it longer.", + "vfl-menu-gf-bogen-ka-1": "\n 1 - GF arc (horizontal curve)", + "vfl-menu-variokurve-ka-2": "\n 2 - Vario curve (horizontal curve, 30/60/90 degrees)", + "vfl-menu-linie-gf-ka-3": "\n 3 - New line: GF (gravity section)", + "vfl-menu-linie-vf-ka-4": "\n 4 - New line: down/up VF (VarioFoerderer unit)", + "vfl-menu-horizontal-vf-ka-5": "\n 5 - New VF with horizontal start (horizontal piece)", + "vfl-menu-linie-ende-ka-6": "\n 6 - New line TO chain end (then separator + ES element)", + "vfl-prompt-wahl-1-6-def3": "\nYour choice (1-6) [3]: ", + "vfl-fehler-horizontal-fussabdruck-zu-kurz": "\nERROR: Footprint does not fit into the chosen distance (remainder would be only %1 mm) - choose fewer/shorter extras or draw it longer.", + "vfl-hinweis-horizontal-fussabdruck-zu-kurz": "\n\nNote: the chosen remaining length was %1 mm, after the 3-degree transition bend only %2 mm remained (minimum: %3 mm). Continue building with the minimum length anyway (the chain point will then end up further along than clicked)?", "vfl-fehler-linie-zu-kurz": "\nERROR: Line too short (or against travel direction) - please pick again.", "vfl-fehler-vf-kurz": "\nERROR: VarioFoerderer needs >= 1000 mm (deflection + motor) - draw it longer or choose \"GF\".", "vfl-gefaelle-festlegen-header": "\nDefine slope:", - "vfl-gefaelle-opt-hoehe": "\n 1 - Given height (target height)", - "vfl-gefaelle-opt-winkel": "\n 2 - Enter incline angle", + "vfl-gefaelle-opt-hoehe": "\n 2 - Given height (target height)", + "vfl-gefaelle-opt-winkel": "\n 1 - Enter incline angle", "vfl-prompt-neigungswinkel": "\nIncline angle (degrees, 0 < angle <= %1) [%1]: ", + "vfl-prompt-neigungswinkel-laenge-berechnet": "\nIncline angle (degrees, 0 < angle <= %1) [%1] (deltaL will be calculated and inserted): ", + "vfl-gf-hinweis-laenge-berechnet": "(deltaL will be calculated and inserted)", + "vfl-gf-laenge-modus-header": "\nHow should the length of this gravity section be determined?", + "vfl-gf-laenge-modus-opt-endpunkt": "\n 1 - Pick end point (length results from it)", + "vfl-gf-laenge-modus-opt-hoehe": "\n 2 - Set target height (length will be calculated)", + "vfl-gf-laenge-modus-opt-steigend": "\n 3 - Rising GF (special case, up to 3 degrees)", + "vfl-prompt-neigungswinkel-steigend": "\nRising angle (degrees, 0 <= angle <= %1, 0 = level) [%1]: ", + "vfl-alert-winkel-ungueltig-steigend": "Rising angle invalid: %1 degrees. Allowed: 0 <= angle <= %2 degrees.", + "vfl-alert-gf-steigend-falsche-richtung": "Rising gravity conveyor: the chosen target height is below the current height - please choose a higher target height or use the normal (falling) mode.", "vfl-alert-winkel-ungueltig": "Incline angle invalid: %1 degrees. Allowed: 0 < angle <= %2 degrees.", "vfl-prompt-hoehe-linienendpunkt": "\nHeight (Z) of the line end point [%1]: ", "vfl-prompt-hoehe-linienendpunkt-2": "\nHeight (Z) of the line end point (down: %1 | up: %2) [%1]: ", "vfl-hinweis-hoehe-vorschlag-fehlt": "\n(Note: no buildable suggestion found for that direction at this segment length - please check the value manually.)", "vfl-alert-gf-kann-nicht-steigen": "Gravity section (GF) cannot rise - please pick a lower target height or use down/up VF.", "vfl-alert-gefaelle-zu-steil": "Slope too steep for GF: %1 degrees (max allowed %2 degrees).\nPlease pick a smaller height difference or use down/up VF.", + "vfl-prompt-hoehe-eingang-gf1": "\nTarget height (Z) at the transition to the horizontal section [%1]: ", + "vfl-alert-eingang-kann-nicht-steigen": "This VF unit (horizontal start) cannot rise - please use 'New line: up/down VF' instead.", + "vfl-alert-eingang-hoehe-zu-klein": "Target height too small: at least %1 mm of drop is needed (separator+deflection station+transition bend alone already reach that much). Please enter a lower target height.", + "vfl-alert-eingang-hoehe-zu-gross": "Target height too far away for this distance - the maximum reachable target height would be about %1 mm. Please use 'New line: up/down VF' instead.", "vfl-ist-kettenende-header": "\nIs this the chain end?", "vfl-kettenende-opt-ja-es": "\n 1 - Yes (place ES element)", "vfl-kettenende-opt-ja-ohne-es": "\n 2 - Yes (without placing ES element)", "vfl-kettenende-opt-nein": "\n 3 - No (keep building)", "vfl-alert-vf-nicht-baubar": "VF unit geometrically not buildable!\ndeltaL=%1 mm, deltaH=%2 mm, direction=%3\nPlease pick another end point/height.", + "vfl-alert-kettenende-p1": "1. Target ΔL=%1 mm, ΔH=%2 mm (%3): angled Vario (angle table) not buildable.", + "vfl-alert-kettenende-p2-beide": "\n\n2. Horizontal+GF not buildable - would need at least ΔL=%1 mm OR at least ΔH=%2 mm.", + "vfl-alert-kettenende-p2-nur-minh": "\n\n2. Horizontal+GF not buildable - would need at least ΔH=%1 mm of height change.", + "vfl-alert-kettenende-p2-nur-minl": "\n\n2. Horizontal+GF not buildable - would need at least ΔL=%1 mm of distance.", + "vfl-alert-vf-entscheidung-p1": "1. Target ΔL=%1 mm, ΔH=%2 mm (%3): angle table not buildable.", + "vfl-alert-vf-entscheidung-p2-beide": "\n\n2. At least needed: ΔL=%1 mm OR ΔH=%2 mm.", + "vfl-alert-vf-entscheidung-p2-nur-minh": "\n\n2. At least needed: ΔH=%1 mm of height change.", + "vfl-alert-vf-entscheidung-p2-nur-minl": "\n\n2. At least needed: ΔL=%1 mm of distance.", "vfl-alert-segment-nicht-baubar": "Segment geometrically not buildable!\ndeltaL=%1 mm, deltaH=%2 mm, direction=%3\nPlease pick another end point/height.", "vfl-info-kurzes-segment": "\n>>> Short segment (deltaL=%1 mm < 1000): automatic 3-degree gravity section (no height query, deltaH=%2 mm).", "vfl-info-kettenende-footprint": "\n>>> Chain-end mode: footprint for separator + ES reserved -> buildable deltaL=%1 mm, deltaH=%2 mm.", @@ -69,9 +99,14 @@ "vfc-block-eingefuegt-xyzref-ksaus": "\n '%1' inserted (XY:%2 Z:%3)\n KS_AUS: X=%4 Y=%5 Z=%6", "vfl-ja": "\n 1 - Yes", "vfl-nein": "\n 2 - No", + "vfl-antwort-ja": "Yes", + "vfl-antwort-nein": "No", + "vfl-wizard-antwort-echo": "\n -> Dialog selection: %1", "vfl-sep-vor-frage": "\n\nInsert additional separator BEFORE the horizontal section?", "vfl-sep-nach-frage": "\n\nInsert additional separator AFTER the horizontal section?", "vfl-sep-an-stelle-frage": "\n\nInsert additional separator at this point?", + "vfl-sep-vor-gf-frage": "\n\nInsert separator BEFORE this slope section (GF)?", + "vfl-sep-nach-gf-frage": "\n\nInsert separator AFTER this slope section (GF)?", "vf-winkel-aus-header": "\n\nOutput element (AS_Element) - choose angle:", "vf-winkel-ein-header": "\n\nInput element (ES_Element) - choose angle:", "vf-winkel-90": "\n 1 - 90 deg", @@ -137,6 +172,17 @@ "vfl-m3-warnung-zu-steil": "\n WARNING: ~slope > 51 deg -> too steep for Vario (magnitude infeasible).", "vfl-m3-vario-bereich-ok": "\n -> within Vario range (3..51 deg), rough orientation.", "vfl-m3-anker-hinweis": "\n (anchors above = rough preview; exact values are MEASURED during build)", + "vfl-m3-lauf-abschluss-header": "\n\nThe VF run is the end of the selected path. End the run with:", + "vfl-m3-lauf-abschluss-opt-offen": "\n 1 - No motor station (open end, continue/merge later)", + "vfl-m3-lauf-abschluss-opt-motor": "\n 2 - Set motor station (no ES element)", + "vfl-m3-lauf-abschluss-opt-motor-es": "\n 3 - Motor station + ES element (chain end)", + "vfl-m3-lauf-abschluss-offen-hinweis": "\n Run deliberately left open - no motor station/separator/ES built; continue later or join with Vario_Kette_Merge.", + "vfl-m3-lauf-anfang-header": "\n\nThe VF run is the start of the selected path. Start the run with:", + "vfl-m3-lauf-anfang-opt-offen": "\n 1 - No reversing station (open start, continue/merge later)", + "vfl-m3-lauf-anfang-opt-umlenk": "\n 2 - Reversing station directly (no GF1/separator)", + "vfl-m3-lauf-anfang-opt-umlenk-gf1": "\n 3 - Reversing station with GF1 + separator", + "vfl-m3-lauf-anfang-offen-hinweis": "\n Start deliberately left open - no reversing station/GF1/separator built; continue later or join with Vario_Kette_Merge.", + "vfl-m3-alert-vf-zu-lang": "VF run is %1 m long (limit %2 m) - please re-plan (e.g. insert an intermediate motor station).", "vfl-m3-phase-b1": "\n\n>>> Phase B1: building front run (AS + GF) ...", "vfl-m3-alert-beginnt-bogen": "Chain starts with an arc - please begin with a straight.", "vfl-m3-kurve-front-uebersprungen": "\n >>> [M3a] Vario curve in front run - skipped.", @@ -145,9 +191,15 @@ "vfl-m3-junction-exakt": "\n Junction (exact): %1 mm", "vfl-m3-kletter-info": "\n Climb height %1 mm | climbers %2 | curves %3 | short VF %4", "vfl-m3-kein-winkel": "\n NO matching Vario angle -> infeasible (front already built).", + "vfl-m3-kletter-zu-kurz-flach": "\n No climb angle fits (segment too short) -> run is built entirely flat, height is absorbed by GF1.", + "vfl-m3-kletter-flach-gf": "\n Flat zone: GF compensation (GF1) = %1 mm", + "vfl-m3-warnung-fueller-eingang-zu-kurz": "\n WARNING: filler right after the reversing station is too short (%1 mm < minimum %2 mm) - only the minimum clearance was built, target position not reached exactly.", + "vfl-m3-warnung-fueller-ausgang-zu-kurz": "\n WARNING: filler right before the motor station is too short (%1 mm < minimum %2 mm) - only the minimum clearance was built, target position not reached exactly.", "vfl-m3-gf-verteilung": "\n\n GF distribution: 1 - all at inlet (GF1) 2 - 1/2 GF1 + 1/2 GF2", + "vfl-m3-gf-verteilung-alles-auslauf": "\n No GF1 room at the inlet chosen - full compensation moves to GF2 (outlet).", "vfl-m3-vert-halb": "1/2 GF1 + 1/2 GF2", "vfl-m3-vert-ganz": "all GF1", + "vfl-m3-vert-auslauf": "all GF2 (outlet)", "vfl-m3-vario-ergebnis": "\n -> Vario %1 (%2), L_VF %3 mm, GF total %4 mm, distribution %5 (GF2 remainder = measured fine correction)", "vfl-m3-warnung-gf2-negativ": "\n WARNING: body climbs too little - GF2<0 (missing %1 mm). Angle too shallow; dZ not exact.", "vfl-m3-gf2-ausgleich": "\n GF2 (measured compensation): L=%1 mm", @@ -285,15 +337,46 @@ "vfl-20m-hinweis": "\n >>> NOTE: conveyor longer than 20 m (%1 m) - motor station recommended!", "vfl-block-erstellt": "\n>>> Block '%1' (%2) created and inserted.", "vfl-fehler-rest-nicht-baubar": "\n ERROR: remainder cannot be built (too steep/too short for tail motor+GF2+separator+ES). Please continue drawing or plan flatter.", + "vfl-fehler-rest-nicht-baubar-mit-vorschlag": "\n ERROR: not buildable at target height %1 mm (distance dL=%2 mm, height difference dH=%3 mm, %4) - too steep/too short for tail motor+GF2+separator+ES. An approximately buildable target height would be:%5", + "vfl-fehler-rest-nicht-baubar-ohne-vorschlag": "\n ERROR: not buildable at target height %1 mm (distance dL=%2 mm, height difference dH=%3 mm, %4) - no alternative target height was found for this distance either. Please draw a longer distance or plan flatter.", + "vfl-vorschlag-ab-auf": " down to %1 mm or up to %2 mm", + "vfl-vorschlag-nur-ab": " down to %1 mm (up is not buildable at this distance)", + "vfl-vorschlag-nur-auf": " up to %1 mm (down is not buildable at this distance)", + "vfl-stufe1-start": "\n\n[Diagnosis stage 1 - VF angle search]", + "vfl-stufe2-diagnose": "\n\n[Diagnosis stage 2 - horizontal+GF] deltaL=%1 mm deltaH=%2 mm -> GF_total=%3 mm L_VF=%4 mm (%5)", + "vfl-stufe2-diagnose-details": "\n [Details] already-flat=%1 | aus-dx=%2 mm (entry, should be 0) | ein-dx=%3 mm ein-dz=%4 mm (ES element) | bogen-x1=%5 mm bogen-z1=%6 mm (entry bend 3->0 deg, only if not already-flat) | bogen-x2=%7 mm bogen-z2=%8 mm (exit bend 0->3 deg, always) | FESTE_HORIZONTAL=%9 mm (separator+motor station)", + "vfl-stufe2-fest-kettenende": "\n Motor station+separator+ES require: length=%1 mm, height drop=%2 mm (fixed, independent of angle)", + "vfl-stufe2-fest-eingang": "\n Reversing station+separator+motor station+ES require: length=%1 mm, height drop=%2 mm (fixed, independent of angle)", + "vfl-stufe2-minl": "\n [Minimum 1] Without a straight VF section (GF sized to the target height): at least %1 mm of distance needed (available: %2 mm)", + "vfl-stufe2-minl-unmoeglich": "\n [Minimum 1] Not solvable via distance: even without a GF bend the height already changes by %1 mm - the target only calls for %2 mm (not enough height difference for the fixed incline)", + "vfl-stufe2-minh": "\n [Minimum 2] Without a GF bend (remainder as a straight VF section, which does not change height): at least %1 mm of height change needed (available: %2 mm)", + "vfl-stufe2-minh-unmoeglich": "\n [Minimum 2] Not solvable via target height: even without a straight VF section and without a GF bend, the fixed footprint is already %1 mm - the distance only offers %2 mm", + "vfl-stufe2-ungueltig": "\n Stage 2 (horizontal+GF) was invalid - stage 1 (VF angle search) was tried instead (see table above).", "vfl-fuege-block-ein": "\n Inserting %1 ...", - "vfl-hinweis-gf2-minimum": "\n NOTE: calculated GF2=%1 mm < minimum %2 mm -> raised to minimum (ES therefore ends a bit further on; see actual-vs-target report).", + "vfl-frage-gf2-minimum": "\n Calculated GF2=%1 mm is below the usual minimum length (%2 mm).\n Yes = build with the exact calculated %1 mm (hits the target point exactly).\n No = pad up to %2 mm (target point shifts further accordingly).", "vfl-horizontale-zwischenstrecke": "\n\nHorizontal intermediate section (0 deg, L=%1 mm)", "vfl-kettenende-modus-ziel": "\n>>> Chain-end mode: target dL=%1 mm, dH=%2 mm (%3). GF2 varies with the angle.", "vfl-prompt-hoehe-endpunkt": "\nHeight (Z) of the end point [%1]: ", "vfl-prompt-hoehe-endpunkt-2": "\nHeight (Z) of the end point (down: %1 | up: %2) [%1]: ", "vfl-prompt-hoehe-kettenende": "\nHeight (Z) of the chain end (ES element) [%1]: ", "vfl-prompt-hoehe-kettenende-2": "\nHeight (Z) of the chain end (ES element) (down: %1 | up: %2) [%1]: ", + "vfl-prompt-wahl-1-2": "\nYour choice (1-2) [1]: ", "vfl-prompt-wahl-bis-n": "\nYour choice (1-%1) [1]: ", + "vfl-frage-auf-ab-richtung": "\n\nChain arrives flat - no target height available. Choose direction:", + "vfl-frage-startpunkt-typ": "\n\nNo clear GF/VF component was recognized at the starting point (a GF stretch and a VF horizontal stretch look structurally identical). How should the entry be built?", + "vfl-opt-eingang-direkt": "\n 1 - Build idler station directly (no GF stretch)", + "vfl-opt-eingang-mit-stumpf": "\n 2 - GF (%1 mm) + idler station", + "vfl-opt-eingang-ohne-umlenk": "\n 3 - No idler station (VF continuation)", + "vfl-opt-richtung-auf": "\n 1 - Up", + "vfl-opt-richtung-ab": "\n 2 - Down", + "vfl-winkel-hoehen-header": "\n\nAvailable angles and the resulting end height - please choose:", + "vfl-winkel-hoehen-option": "\n %1 - %2 deg (end height: %3 mm)", + "vfl-winkel-hoehen-zeile": "\n %1 deg - end height: %2 mm", + "vfl-winkel-hoehen-zeile-tile": "end height: %1 mm", + "vfl-winkel-wahl-zeile-tile": "L_GF=%1 mm L_VF=%2 mm", + "vfl-winkel-zeile-tile-ungueltig": "not buildable (bend does not fit into the chosen distance)", + "vfl-winkel-hoehen-zeile-ungueltig": "\n %1 deg - not buildable (bend does not fit into the chosen distance)", + "vfl-winkel-hoehen-abweichung": "\n [Note] Target-vs-actual check: predicted end height %1 mm, actually reached %2 mm.", "vfl-segment-gf-nicht-erlaubt": "\n Segment would be GF (too steep) or not buildable - not allowed within a VF unit.\n Please draw flatter/rising or end the conveyor.", "vfl-winkel-option": "\n %1 - %2 deg (L_GF=%3 mm L_VF=%4 mm)", "vfs-as90-mass": "\n AS_90: dx=%1 dz=%2", @@ -767,6 +850,7 @@ "vfl-abbruch-gesichert": "\n>>> Chain cancelled: %1 object(s) saved as a block (editable/resumable via double-click).", "vfl-abbruch-nichts-gebaut": "\n>>> Cancelled - no geometry was created yet.", "vfl-abbruch-wickeln-fehler": "\n>>> ERROR saving the partial geometry as a block: %1", + "vfl-zurueck-glied-verworfen": "\n>>> Back: discarding the last chain element - please answer it again.", "vfl-edit-dialog-fehlt": "Dialog not found: %1", "vfl-edit-abgebrochen": "\nEdit cancelled - no change.", "vfl-dlg-kopf-sektionen": "Sections: %1", diff --git a/tests/test_linienzug.lsp b/tests/test_linienzug.lsp index b101960..5d269df 100644 --- a/tests/test_linienzug.lsp +++ b/tests/test_linienzug.lsp @@ -33,7 +33,10 @@ ;; ;; Aufruf in BricsCAD: ;; (load (strcat (getenv "DXFMAKRO") "/tests/test_linienzug.lsp")) -;; TEST_LINIENZUG +;; TEST_LINIENZUG (Standard-Szenario, linienzug_tests.json, in +;; alltests.json/SSG_RUN_ALL_TESTS registriert) +;; TEST_LINIENZUG_STUFE2 (Stufe-2-Fallback-Regressionstest Kettenende, +;; linienzug_tests_stufe2.json, manueller Aufruf) ;; ============================================================ ;; Naechste Skript-Antwort liefern (FIFO). Bei leerer Queue Warnung + "". @@ -126,8 +129,17 @@ ) ) -(defun c:TEST_LINIENZUG ( / json-datei daten meta schritte-anz rest-anz status - old-vgp old-gs old-gi old-gr err) +;; --- Gemeinsamer Replay-Kern, von allen c:TEST_LINIENZUG*-Befehlen genutzt --- +;; befehl-anzeige: nur fuer die Konsolen-Ueberschrift/ssg-start (String). +;; test-id: Bezeichner fuer das *linienzug-test-results*-JSON (run-all- +;; Konvention, siehe linienzug:export-results). +;; Rueckgabe: (status schritte-anz rest-anz) - status ist "OK"/"ABWEICHUNG"/ +;; "FEHLER". Setzt zusaetzlich *linienzug-test-results* (letzter Aufruf +;; gewinnt - identisch zum bisherigen Verhalten von c:TEST_LINIENZUG, das +;; ebenfalls nur einen einzigen Testfall pro Lauf kennt). +(defun tlz-run-datei (json-datei test-id befehl-anzeige / + daten meta schritte-anz rest-anz status + old-vgp old-gs old-gi old-gr err) (if (or (not *lib-initialized*) (null bogen-auf)) (init-bibliothek)) (if (null (car (atoms-family 1 '("VF-LINIENZUG-MODUS")))) (progn @@ -138,12 +150,10 @@ ) (princ "\n================================================================") - (princ "\n TEST_LINIENZUG - VF-Linienzug Replay-Test") + (princ (strcat "\n " befehl-anzeige " - VF-Linienzug Replay-Test")) (princ "\n================================================================") ;; --- Eingabe-Skript aus JSON laden --- - (setq json-datei - (strcat (getenv "DXFMAKRO") "\\tests\\testdata\\linienzug_tests.json")) (setq daten (ssg-load-json json-datei)) (if (null daten) (progn @@ -158,7 +168,7 @@ (princ (strcat "\n Eingabe-Schritte: " (itoa schritte-anz))) (if meta (princ (strcat "\n Szenario: " (ssg-val meta "beschreibung")))) - (ssg-start "TEST_LINIENZUG" '(("OSMODE") ("ATTREQ") ("ATTDIA"))) + (ssg-start befehl-anzeige '(("OSMODE") ("ATTREQ") ("ATTDIA"))) (setvar "OSMODE" 0) (setvar "ATTREQ" 0) (setvar "ATTDIA" 0) @@ -192,11 +202,11 @@ (if (vl-catch-all-error-p err) (progn (setq status "FEHLER") - (princ (strcat "\n TEST_LINIENZUG: FEHLER -> " + (princ (strcat "\n " befehl-anzeige ": FEHLER -> " (vl-catch-all-error-message err)))) (progn (setq status (if (= rest-anz 0) "OK" "ABWEICHUNG")) - (princ "\n TEST_LINIENZUG: Kette gebaut.") + (princ (strcat "\n " befehl-anzeige ": Kette gebaut.")) (if (> rest-anz 0) (princ (strcat "\n WARNUNG: " (itoa rest-anz) " Skript-Eintraege NICHT verbraucht (Ablauf weicht ab).")) @@ -214,12 +224,34 @@ ;; --- Ergebnis fuer run-all als JSON-String ablegen --- (setq *linienzug-test-results* (strcat " {\n" - " \"test_id\": \"LZ_Standard\",\n" + " \"test_id\": \"" test-id "\",\n" " \"status\": \"" status "\",\n" " \"schritte_gesamt\": " (itoa schritte-anz) ",\n" " \"schritte_offen\": " (itoa rest-anz) "\n" " }")) (ssg-end) + (list status schritte-anz rest-anz) +) + +(defun c:TEST_LINIENZUG ( / json-datei) + (setq json-datei + (strcat (getenv "DXFMAKRO") "\\tests\\testdata\\linienzug_tests.json")) + (tlz-run-datei json-datei "LZ_Standard" "TEST_LINIENZUG") + (princ) +) + +;; Zweiter Testfall (Regressionstest, in dieser Session neu aufgenommen): +;; Stufe-2-Fallback beim Kettenende (typ=VF winkel=0, horizontales VF + GF- +;; Ausgleich), siehe Beschreibung/Kommentare in linienzug_tests_stufe2.json. +;; Eigenstaendiger Befehl statt zweitem Array-Eintrag in linienzug_tests.json, +;; damit LZ_Standard unangetastet bleibt (jede JSON-Datei bleibt ein +;; einzelnes Szenario, wie von tlz-daten->queue/-meta erwartet). NICHT in +;; tests/alltests.json registriert - manueller Einzelaufruf, bei Bedarf +;; spaeter dort ergaenzen. +(defun c:TEST_LINIENZUG_STUFE2 ( / json-datei) + (setq json-datei + (strcat (getenv "DXFMAKRO") "\\tests\\testdata\\linienzug_tests_stufe2.json")) + (tlz-run-datei json-datei "LZ_Stufe2_Kettenende" "TEST_LINIENZUG_STUFE2") (princ) ) diff --git a/tests/testdata/linienzug_tests.json b/tests/testdata/linienzug_tests.json index 67c4d73..bf530ba 100644 --- a/tests/testdata/linienzug_tests.json +++ b/tests/testdata/linienzug_tests.json @@ -1,6 +1,6 @@ [ { - "beschreibung": "Standard-Linienzug (Modus 1): Start Z4500 AS rechts -> Neue Linie Ab Z1800 45deg (GF am Einlauf) -> Horizontal 900 mit Separator VOR+NACH -> Vario-Kurve 90 links aussen -> Horizontal 250 -> Vario-Kurve 90 links aussen -> Kettenende (Option 3) Z4500 45deg ES rechts", + "beschreibung": "Standard-Linienzug (Modus 1): Start Z4500 AS rechts -> Neue Linie Ab Z1800 45deg (GF am Einlauf) -> Horizontal 900 -> Vario-Kurve 90 links aussen -> Horizontal 250 -> Vario-Kurve 90 links aussen -> Kettenende (Option 3) Z4500 45deg ES rechts", "erwartung_dx_mm": 0, "erwartung_dy_mm": 637, "erwartung_dz_mm": 0, @@ -33,8 +33,8 @@ }, { "typ": "string", - "wert": "2", - "kommentar": "getstring Naechstes Element (2 = Neue Linie: Ab/Auf VF - Gefaelle hier 26 Grad > GF-Maximalwinkel, daher NICHT Option 1/GF)" + "wert": "4", + "kommentar": "getstring Naechstes Element (4 = Neue Linie: Ab/Auf VF - Kettenanfang-Menue hat seit GF-Bogen/Vario-Kurve-Erweiterung 6 statt 4 Optionen, Linie-VF ist jetzt Option 4 statt 2; Gefaelle hier 26 Grad > GF-Maximalwinkel, daher NICHT Option 3/GF)" }, { "typ": "point_rel", @@ -73,20 +73,10 @@ "hz": 0, "kommentar": "getpoint Horizontal-Endpunkt (dL=900, hz=0)" }, - { - "typ": "string", - "wert": "1", - "kommentar": "getstring Separator VOR? (Ja)" - }, - { - "typ": "string", - "wert": "1", - "kommentar": "getstring Separator NACH? (Ja)" - }, { "typ": "string", "wert": "2", - "kommentar": "getstring Ist Endpunkt? (Nein)" + "kommentar": "getstring Ist Endpunkt? (Nein) - kein Separator mehr innerhalb der VF-Einheit (5-Punkte-Umbau)" }, { "typ": "string", @@ -124,16 +114,6 @@ "hz": 90, "kommentar": "getpoint Horizontal-Endpunkt (dL=250, hz=90)" }, - { - "typ": "string", - "wert": "2", - "kommentar": "getstring Separator VOR? (Nein)" - }, - { - "typ": "string", - "wert": "2", - "kommentar": "getstring Separator NACH? (Nein)" - }, { "typ": "string", "wert": "2", diff --git a/tests/testdata/linienzug_tests_stufe2.json b/tests/testdata/linienzug_tests_stufe2.json new file mode 100644 index 0000000..57dcd62 --- /dev/null +++ b/tests/testdata/linienzug_tests_stufe2.json @@ -0,0 +1,295 @@ +[ + { + "beschreibung": "Stufe-2-Fallback-Regressionstest (Kettenende): Start Z2154 AS 90 Grad links -> Horizontal-VF (2x Vario-Kurve 90 rechts innen) -> Linie-GF 3 Grad (Sep vor+nach) -> Horizontal-VF (Vario-Kurve 30 rechts innen -> Auf 27 Grad -> Vario-Kurve 30 links aussen) -> Kettenende ueber 'Ist der Endpunkt der Foerderer?'-Option 3 mit ES 90 Grad links; GF2 (86mm) liegt unter der Mindestlaenge (400mm), Stufe 1 (Winkeltabelle) scheitert komplett (alle Kandidaten negative Laenge) -> Stufe 2 (vfl-winkel-stufe-entscheidung) liefert typ=VF winkel=0 (horizontales VF + GF-Ausgleich). Reproduziert den in dieser Session gefixten Bug (Stufe-2-Fallback griff im Kettenende-Zweig 'Ab, steiler als 3 Grad' bisher nicht, wenn Stufe 1 scheiterte) - erster erfolgreicher Stufe-2-Bau der Session, live in BricsCAD verifiziert.", + "erwartung_dx_mm": 638, + "erwartung_dy_mm": 0, + "erwartung_dz_mm": 0, + "erwartung_hinweis": "dX~638 = seitlicher Fussabdruck ES_Element_90 quer zur letzten Fahrtrichtung (Bauform des 90-Grad-ES-Elements, kein Baufehler). Kernzweck des Testfalls: Stufe-2-Fallback beim Kettenende (typ=VF winkel=0 im Kettenende-Abschluss, GF2=86mm unter Mindestlaenge -> 'trotzdem mit 86mm bauen?'=Ja)." + }, + { + "typ": "point_abs", + "wert": [24377.817458, -10300, 2067], + "kommentar": "getpoint Startpunkt der Kette (Rohwert aus dem realen BricsCAD-Testlauf)" + }, + { + "typ": "real", + "wert": 2154.0, + "kommentar": "getreal Hoehe (Z) Startpunkt" + }, + { + "typ": "string", + "wert": "1", + "kommentar": "getstring AS-Element setzen? (Ja)" + }, + { + "typ": "string", + "wert": "1", + "kommentar": "getstring AS-Element Winkel - Menu-Index 1=90 Grad/2=30 Grad (vf-frage-element-winkel mappt den rohen Index auf den Winkel-STRING '90'/'30'; im Debug-Journal erscheint bereits der gemappte Wert '90', die Konsolen-/Mock-Eingabe selbst bleibt der Index)" + }, + { + "typ": "string", + "wert": "1", + "kommentar": "getstring AS-Seite (links)" + }, + { + "typ": "string", + "wert": "5", + "kommentar": "getstring Naechstes Element (Kettenanfang-Menue, 6 Optionen: 5 = Horizontal-VF)" + }, + { + "typ": "point_rel", + "dL": 6082.461, + "hz": 90, + "kommentar": "getpoint Endpunkt Horizontal-VF (freie Richtung am Kettenanfang, hz-vorgabe=nil - hz=90 ist die vom Code gesnappte Richtung, direkt aus dem Debug-Journal (REAL-Eintrag unmittelbar nach dem DL-Eintrag) uebernommen; dieser REAL-Eintrag ist ein reiner Journal-Nebeneffekt von vfl-in-abstand und KEIN eigener Eingabe-Schritt, siehe Lisp/vf_linienzug.lsp vfl-in-abstand" + }, + { + "typ": "real", + "wert": 1980.0, + "kommentar": "getreal Ziel-Hoehe Eingang GF1 (eingang-modus=voll/nil, vollstaendiger Neuaufbau des VF-Eingangs)" + }, + { + "typ": "string", + "wert": "2", + "kommentar": "getstring Ist der Endpunkt der Foerderer? (Nein) - erste Frage innerhalb vfl-baue-horizontal-koerper (ziel-modus)" + }, + { + "typ": "string", + "wert": "2", + "kommentar": "getstring Naechstes im VarioFoerderer (Vario-Kurve)" + }, + { + "typ": "int", + "wert": 90, + "kommentar": "getint Vario-Kurve Winkel (90 Grad, roher Winkelwert - KEIN Auswahl-Index, siehe vfl-menu-winkel)" + }, + { + "typ": "string", + "wert": "2", + "kommentar": "getstring Vario-Kurve Seite (rechts)" + }, + { + "typ": "string", + "wert": "2", + "kommentar": "getstring Vario-Kurve Variante (innen)" + }, + { + "typ": "string", + "wert": "2", + "kommentar": "getstring Ist der Endpunkt der Foerderer? (Nein)" + }, + { + "typ": "string", + "wert": "1", + "kommentar": "getstring Naechstes im VarioFoerderer (Horizontaler Foerderer)" + }, + { + "typ": "point_rel", + "dL": 1300, + "hz": 0, + "kommentar": "getpoint Horizontal-Endpunkt innerhalb der VF-Einheit. hz=0 ANNAHME (NICHT direkt im Debug-/Konsolen-Auszug als 'hz=' ausgewiesen, sondern aus der Turn-Arithmetik hergeleitet: Start-hz=90, davor bereits eine 90-Grad-rechts-Vario-Kurve (-90) -> 90-90=0; dieselbe Turn-Konvention [rechts=-Winkel/links=+Winkel] ist an ZWEI anderen Stellen dieses Testfalls unabhaengig durch explizite 'hz='-Werte im Konsolen-Auszug bestaetigt, siehe die Vario_Bogen_ab_3/ab_27-Eintraege). BITTE in BricsCAD live gegenpruefen (einzige nicht direkt beleg-bestaetigte hz-Rekonstruktion dieses Testfalls)." + }, + { + "typ": "string", + "wert": "2", + "kommentar": "getstring Ist der Endpunkt der Foerderer? (Nein) - innerhalb vfl-baue-horizontal-koerper (ziel-modus)" + }, + { + "typ": "string", + "wert": "2", + "kommentar": "getstring Naechstes im VarioFoerderer (Vario-Kurve)" + }, + { + "typ": "int", + "wert": 90, + "kommentar": "getint Vario-Kurve Winkel (90 Grad)" + }, + { + "typ": "string", + "wert": "2", + "kommentar": "getstring Vario-Kurve Seite (rechts)" + }, + { + "typ": "string", + "wert": "2", + "kommentar": "getstring Vario-Kurve Variante (innen)" + }, + { + "typ": "string", + "wert": "1", + "kommentar": "getstring Ist der Endpunkt der Foerderer? (Ja, nur Motorstation) - schliesst die 1. Horizontal-VF-Einheit ab" + }, + { + "typ": "string", + "wert": "2", + "kommentar": "getstring Ist das Kettenende (ES-Element)? (Nein, weiterbauen) - vfl-vf-einheit-abschluss" + }, + { + "typ": "string", + "wert": "2", + "kommentar": "getstring Zusaetzlichen Separator an dieser Stelle einfuegen? (Nein)" + }, + { + "typ": "string", + "wert": "2", + "kommentar": "getstring Naechstes Element (Hauptmenue, 5 Optionen, Frame vorhanden: 2 = Neue Linie: GF)" + }, + { + "typ": "string", + "wert": "1", + "kommentar": "getstring Wie soll die Laenge dieser Gefaellestrecke bestimmt werden? (1 = Endpunkt waehlen)" + }, + { + "typ": "point_rel", + "dL": 978.394396, + "hz": -90, + "kommentar": "getpoint Endpunkt Gefaellestrecke. hz=-90 DIREKT aus dem Debug-Journal bestaetigt (GEOMETRIE-Zeile 'vfl-insert-gf-segment (deltaL=379 hz=-90 winkel=3)')" + }, + { + "typ": "string", + "wert": "1", + "kommentar": "getstring Separator VOR dieser Gefaellestrecke einfuegen? (Ja)" + }, + { + "typ": "string", + "wert": "1", + "kommentar": "getstring Separator NACH dieser Gefaellestrecke einfuegen? (Ja)" + }, + { + "typ": "string", + "wert": "1", + "kommentar": "getstring Gefaelle festlegen (1 = Neigungswinkel eingeben)" + }, + { + "typ": "real", + "wert": 3.0, + "kommentar": "getreal Neigungswinkel (3 Grad)" + }, + { + "typ": "string", + "wert": "3", + "kommentar": "getstring Ist das Kettenende? (3 = Nein, weiterbauen - 3-Optionen-Menue: 1=Ja+ES, 2=Ja ohne ES, 3=Nein)" + }, + { + "typ": "string", + "wert": "4", + "kommentar": "getstring Naechstes Element (5 Optionen: 4 = Neue VF mit horizontalem Anfang/Horizontal-VF)" + }, + { + "typ": "point_rel", + "dL": 888.101488, + "hz": -90, + "kommentar": "getpoint Endpunkt Horizontal-VF (2. Einheit). hz=-90 unveraendert gegenueber dem vorigen GF-Segment (keine Richtungsaenderung dazwischen); eingang-modus=separator (letztes Glied war der Separator NACH der Gefaellestrecke) -> KEINE Ziel-Hoehe-Frage fuer GF1 (im Unterschied zur 1. Horizontal-VF-Einheit)" + }, + { + "typ": "string", + "wert": "2", + "kommentar": "getstring Ist der Endpunkt der Foerderer? (Nein) - innerhalb vfl-baue-horizontal-koerper (ziel-modus)" + }, + { + "typ": "string", + "wert": "2", + "kommentar": "getstring Naechstes im VarioFoerderer (Vario-Kurve)" + }, + { + "typ": "int", + "wert": 30, + "kommentar": "getint Vario-Kurve Winkel (30 Grad)" + }, + { + "typ": "string", + "wert": "2", + "kommentar": "getstring Vario-Kurve Seite (rechts)" + }, + { + "typ": "string", + "wert": "2", + "kommentar": "getstring Vario-Kurve Variante (innen)" + }, + { + "typ": "string", + "wert": "2", + "kommentar": "getstring Ist der Endpunkt der Foerderer? (Nein)" + }, + { + "typ": "string", + "wert": "3", + "kommentar": "getstring Naechstes im VarioFoerderer (Auf/Ab-Foerderer)" + }, + { + "typ": "point_rel", + "dL": 1614.972606, + "hz": -120, + "kommentar": "getpoint Endpunkt Auf/Ab-Foerderer. hz=-120 DIREKT bestaetigt (Konsolen-Auszug zeigt fuer den anschliessenden Vario_Bogen_ab_3_TEF_rechts explizit 'hz=-120 Grad' bei derselben Fahrtrichtung)" + }, + { + "typ": "string", + "wert": "1", + "kommentar": "getstring Kette kommt flach an - Richtung waehlen (1 = Auf)" + }, + { + "typ": "int", + "wert": 8, + "kommentar": "getint Winkel-/Hoehen-Tabelle: Auswahl-Index (NICHT der Winkel selbst) unter den GUELTIGEN Kandidaten - gueltig sind hier 3/6/9/12/15/18/21/27 Grad (8 Werte), Index 8 = letzter gueltiger Kandidat = 27 Grad (siehe Konsolen-Auszug '5/11: Vario_Bogen_auf_27_TEF_rechts')" + }, + { + "typ": "string", + "wert": "2", + "kommentar": "getstring Ist der Endpunkt der Foerderer? (Nein)" + }, + { + "typ": "string", + "wert": "2", + "kommentar": "getstring Naechstes im VarioFoerderer (Vario-Kurve)" + }, + { + "typ": "int", + "wert": 30, + "kommentar": "getint Vario-Kurve Winkel (30 Grad)" + }, + { + "typ": "string", + "wert": "1", + "kommentar": "getstring Vario-Kurve Seite (links)" + }, + { + "typ": "string", + "wert": "1", + "kommentar": "getstring Vario-Kurve Variante (aussen) - Konsolen-Auszug bestaetigt 'Vario_Kurve_links_30_TEF_aussen'" + }, + { + "typ": "string", + "wert": "3", + "kommentar": "getstring Ist der Endpunkt der Foerderer? (3 = Ja, Motorstation setzen + Kettenende definieren) - startet den Stufe-1/Stufe-2-Kettenende-Zweig (vfl-body-abschluss/vfl-body-zerlegung)" + }, + { + "typ": "string", + "wert": "1", + "kommentar": "getstring ES-Element setzen? (Ja)" + }, + { + "typ": "string", + "wert": "1", + "kommentar": "getstring ES-Element Winkel - Menu-Index 1=90 Grad/2=30 Grad (wie AS-Winkel oben, gleiches Mapping ueber vf-frage-element-winkel)" + }, + { + "typ": "string", + "wert": "1", + "kommentar": "getstring ES-Seite (links)" + }, + { + "typ": "point_rel", + "dL": 1802.808856, + "hz": -90, + "kommentar": "getpoint Endpunkt Kettenende (vfl-body-abschluss). hz=-90 DIREKT bestaetigt: die im Debug-Log erreichte Position (25544.710135 -8783.275914 2270.287821) hat exakt dieselbe X- und Z-Koordinate wie die KS_AUS-Position der vorigen Vario-Kurve (25544.71 / 2270.29 lt. Konsolen-Auszug) - nur Y aendert sich, das ist ausschliesslich mit hz=-90 (reine Y-Richtung) vereinbar" + }, + { + "typ": "real", + "wert": 2154.0, + "kommentar": "getreal Ziel-Hoehe Kettenende. Ab hier laeuft vfl-body-zerlegung AUTOMATISCH: Stufe 1 (Winkeltabelle 3/6/9/.../51 Grad) scheitert komplett (alle Kandidaten ergeben negative L_VF), Stufe 2 (vfl-winkel-stufe-entscheidung/berechne-horizontale-mitte) liefert typ=VF winkel=0 L_GF=86 L_VF=286 - KEINE weitere Eingabe fuer diese Entscheidung noetig" + }, + { + "typ": "string", + "wert": "1", + "kommentar": "getstring Berechnetes GF2=86mm liegt unter der ueblichen Mindestlaenge (400mm) - trotzdem mit den exakt berechneten 86mm bauen? (Ja) - schliesst die Kette ab (VF_n mit GF=1 VF=5)" + } +]