From 143a4e79994791d28a751f50cb39bf47325bfa37 Mon Sep 17 00:00:00 2001 From: Yuelin Wang Date: Wed, 16 Sep 2026 09:08:59 +0200 Subject: [PATCH] =?UTF-8?q?fix:=20Ab/Auf=20VF=20Kettenende=20nutzt=20erste?= =?UTF-8?q?n=20Winkel-Solve=20statt=20fehleranfaelliger=20zweiter=20Loesun?= =?UTF-8?q?g=EF=BC=8Cfix:=20fehlende=20Separator-Reservierung=20vor=20ES-E?= =?UTF-8?q?lement=20im=20Kettenende-Solve=20ergaenzt=20=EF=BC=8CStufe=203?= =?UTF-8?q?=20(Winkel+Horizontal-Fuellstueck)=20fuer=20VF-Linienzug=20Modu?= =?UTF-8?q?s=201=20ergaenzt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Lisp/vf_linienzug.lsp | 675 +++++++++++++++++++++++++------- Lisp/vf_standard.lsp | 168 +++++++- cfg/Merkmalsstamm_in_Sivas.xlsx | Bin 0 -> 66824 bytes lang/de_DE.json | 7 + lang/en_GB.json | 7 + 5 files changed, 690 insertions(+), 167 deletions(-) create mode 100644 cfg/Merkmalsstamm_in_Sivas.xlsx diff --git a/Lisp/vf_linienzug.lsp b/Lisp/vf_linienzug.lsp index 4d7b2b4..d131868 100644 --- a/Lisp/vf_linienzug.lsp +++ b/Lisp/vf_linienzug.lsp @@ -1055,20 +1055,24 @@ ;; faelschlich eine hier moegliche Punktwahl suggerieren wuerde). ;; hoehe-default: entweder eine Zahl (aktuelle Kettenhoehe, alte Vorbelegung - ;; die bei direkter Uebernahme immer als deltaH=0 abgelehnt wird), ODER eine -;; Liste (hoehe-ab hoehe-auf) mit zwei baubaren Vorschlaegen (siehe -;; vfl-vf-hoehe-vorschlaege/vfl-segment-hoehe-vorschlaege) - dann zeigt der -;; Kopftext beide Richtungen, vorbelegt wird die Ab-Variante (haeufigerer -;; Fall, siehe vfl-segment-entscheidung). Ist hoehe-ab nil (kein baubarer -;; Wert in der sondierten Zone gefunden), faellt die Vorbelegung auf die -;; unveraenderte Kettenhoehe zurueck (altes Verhalten) plus Warnhinweis. +;; Liste (hoehe-ab hoehe-auf hoehe-kette [hoehe-pick]) mit zwei baubaren +;; Vorschlaegen (siehe vfl-vf-hoehe-vorschlaege/vfl-segment-hoehe-vorschlaege) +;; - dann zeigt der Kopftext beide Richtungen. Vorbelegt wird, in dieser +;; Reihenfolge: hoehe-pick (die tatsaechliche Z-Hoehe des zuvor per Objektfang +;; gepickten Endpunkts, siehe *vfl-letzter-pick-z*/vfl-hoehe-endpunkt-abfragen +;; - der Nutzer hat damit meist schon die gewuenschte Zielhoehe angeklickt), +;; sonst die Ab-Variante (haeufigerer Fall, siehe vfl-segment-entscheidung). +;; Ist weder hoehe-pick noch hoehe-ab vorhanden, faellt die Vorbelegung auf +;; die unveraenderte Kettenhoehe zurueck (altes Verhalten) plus Warnhinweis. (defun vflw-gruppe-ziel-hoehe-impl (hoehe-default / dat dcl-pfad ergebnis dlg-wert - zwei-werte hoehe-ab hoehe-auf hoehe-kette vorbelegt) + zwei-werte hoehe-ab hoehe-auf hoehe-kette + hoehe-pick vorbelegt) (setq zwei-werte (listp hoehe-default)) (if zwei-werte (progn (setq hoehe-ab (nth 0 hoehe-default) hoehe-auf (nth 1 hoehe-default)) - (setq hoehe-kette (nth 2 hoehe-default)) - (setq vorbelegt (if hoehe-ab hoehe-ab hoehe-kette))) + (setq hoehe-kette (nth 2 hoehe-default) hoehe-pick (nth 3 hoehe-default)) + (setq vorbelegt (cond (hoehe-pick hoehe-pick) (hoehe-ab hoehe-ab) (t hoehe-kette)))) (setq vorbelegt hoehe-default)) (setq dat (load_dialog (vflw-dcl-pfad))) (if (not (new_dialog "vflw_zahl" dat)) @@ -1076,10 +1080,14 @@ (progn (set_tile "kopf" (vflw-clean - (if (and zwei-werte 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 vorbelegt 2 1)))))) + (cond + ((and zwei-werte hoehe-ab hoehe-auf hoehe-pick) + (ssg-textf "vfl-prompt-hoehe-endpunkt-3" + (list (rtos hoehe-ab 2 1) (rtos hoehe-auf 2 1) (rtos hoehe-pick 2 1)))) + ((and zwei-werte hoehe-ab hoehe-auf) + (ssg-textf "vfl-prompt-hoehe-endpunkt-2" + (list (rtos hoehe-ab 2 1) (rtos hoehe-auf 2 1)))) + (t (ssg-textf "vfl-prompt-hoehe-endpunkt" (list (rtos vorbelegt 2 1))))))) (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)") @@ -2789,6 +2797,45 @@ (princ) ) +;; Gemeinsame Frage-Schale "Zielhoehe nach Endpunkt-Pick" - buendelt das an +;; mehreren Stellen (vfl-body-abschluss/Kettenende, VF-Fortsetzung Auf/Ab, +;; Horizontal-VF-Eingang, "Linie" GF-Familie) fast identisch wiederholte +;; Muster (Wizard-Dialog + Konsolen-Fallback + leere Eingabe -> Vorschlag). +;; *vfl-letzter-pick-z* (von vfl-in-abstand gesetzt, siehe dort) hat Vorrang +;; vor dem rein rechnerischen Ab-Vorschlag: wurde der Endpunkt per Objektfang +;; auf einem echten 3D-Punkt (z.B. einem vorhandenen Block) gepickt, ist genau +;; diese Hoehe die vom Nutzer gemeinte Zielhoehe - nicht der naechstgelegene +;; nur rechnerisch baubare Wert. Der Vorschlag bleibt im Eingabefeld/Dialog +;; jederzeit ueberschreibbar; der final gewaehlte Wert (hn) fliesst dabei +;; UNVERAENDERT in den Bau ein (siehe Aufrufer) - eine manuelle Korrektur wird +;; also korrekt weiterverrechnet, nicht verworfen. +;; schluessel-basis waehlt die passenden lang-Keys ("endpunkt"/"kettenende"/ +;; "linienendpunkt", siehe lang/de_DE.json) - vor dem Anlegen weiterer +;; Varianten immer erst pruefen, ob eine der drei bestehenden passt. +;; Rueckgabe: die gewaehlte Zielhoehe, NIE nil (leere Eingabe -> Vorschlag). +(defun vfl-hoehe-endpunkt-abfragen (hoehe-ab hoehe-auf ist-hoehe schluessel-basis / hoehe-fallback hn) + (setq hoehe-fallback + (cond (*vfl-letzter-pick-z* *vfl-letzter-pick-z*) (hoehe-ab hoehe-ab) (t ist-hoehe))) + (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 ist-hoehe *vfl-letzter-pick-z*)))) + (setq hn + (vfl-in-real + (cond + ((and hoehe-ab hoehe-auf *vfl-letzter-pick-z*) + (ssg-textf (strcat "vfl-prompt-hoehe-" schluessel-basis "-3") + (list (rtos hoehe-ab 2 1) (rtos hoehe-auf 2 1) (rtos *vfl-letzter-pick-z* 2 1)))) + ((and hoehe-ab hoehe-auf) + (ssg-textf (strcat "vfl-prompt-hoehe-" schluessel-basis "-2") + (list (rtos hoehe-ab 2 1) (rtos hoehe-auf 2 1)))) + (t + (ssg-textf (strcat "vfl-prompt-hoehe-" schluessel-basis) + (list (rtos hoehe-fallback 2 1))))))) + (if (null hn) (setq hn hoehe-fallback)) + hn +) + ;; Konsolen-Echo nach Endpunkt-Pick + Zielhoehe-Eingabe: zeigt den absoluten ;; Endpunkt (X/Y, aus p-aktuell + deltaL entlang hz-neu zurueckgerechnet - nur ;; deltaL/hz werden journalisiert, siehe vfl-in-abstand) sowie die eingegebene @@ -3032,6 +3079,10 @@ ;; ohnehin immer die des Vorgaengers, ein Journal-Eintrag dafuer waere ;; redundant. Rueckgabe: (deltaL . hz) oder nil bei Abbruch/leerer Eingabe. (defun vfl-in-abstand (p-akt hz-vorgabe prompt / p2 rad ux uy deltaL hz-aktuell popped) + ;; *vfl-letzter-pick-z* IMMER zuerst zuruecksetzen (auch im Replay-Zweig, + ;; siehe unten) - ein Wert aus einem fruehreren Live-Pick derselben Sitzung + ;; darf niemals in einen Replay-/Headless-Nachbau durchsickern. + (setq *vfl-letzter-pick-z* nil) ;; Zentraler Abbruch-Trigger (siehe Kommentar in vfl-in-value): vfl-in-abstand ;; hat eine EIGENE Pending-/Replay-Logik und laeuft NICHT ueber vfl-in-value/ ;; -value-p - ohne diesen Check wuerde ein per Wizard-Dialog gesetztes @@ -3075,6 +3126,20 @@ ;; journalisiert. (setq popped (vflw-pending-pop)) (setq p2 (if popped (car popped) (vfl-getpoint p-akt prompt))) + ;; *vfl-letzter-pick-z*: die Z-Hoehe DIESES Picks, fuer eine unmittelbar + ;; nachfolgende Zielhoehe-Frage (siehe vfl-hoehe-endpunkt-abfragen) als + ;; Vorschlag verfuegbar machen - vorher bei JEDEM Endpunkt-Pick + ;; ersatzlos verworfen (nur X/Y gingen in deltaL ein), obwohl gerade ein + ;; Snap auf einen vorhandenen 3D-Block (Objektfang) die vom Nutzer + ;; gemeinte Zielhoehe meist schon exakt liefert. Nur uebernehmen, wenn + ;; die Z-Koordinate spuerbar von der aktuellen Konstruktionsebene + ;; (ELEVATION) abweicht - sonst ist es nur ein flacher Freihand-Klick + ;; ohne echte 3D-Information, kein echter Objektfang. Analog zu + ;; *vfl-stufe2-minl-vorschlag* ein transientes globales Vorschlags-Feld, + ;; nicht Teil des Rueckgabewerts (der bleibt unveraendert deltaL/hz); + ;; oben bereits auf nil zurueckgesetzt. + (if (and p2 (> (abs (- (caddr p2) (getvar "ELEVATION"))) 0.01)) + (setq *vfl-letzter-pick-z* (caddr p2))) (if (null p2) (setq deltaL nil) (progn @@ -3162,6 +3227,50 @@ (+ (* (- (car ziel-punkt) (car neu-basis)) (cos rad)) (* (- (cadr ziel-punkt) (cadr neu-basis)) (sin rad)))) +;; Fahrtrichtung + Vorlauflaenge FUER EIN DREHENDES AS-/ES-ELEMENT so +;; korrigieren, dass dessen KS_AUS exakt den absoluten Zielpunkt trifft - real +;; gemessener Bug: die bisherige Reservierung zog nur den Laengsanteil +;; (ein-dx/aus-dx, hz-unabhaengig IMMER exakt der Laengsanteil des rohen +;; Block-Fussabdrucks) vom Budget ab, nie den Queranteil (ein-dy/aus-dy), der +;; bei jedem Winkel <>0 Grad entsteht (0 bei 0 Grad, maximal bei 90 Grad) - +;; die Kette landete dadurch seitlich exakt um raw-dy versetzt neben dem Ziel +;; (BricsCAD-bestaetigt: Modus 1 UND Modus 2, ES_Element_90, ca. 638mm Versatz, +;; Hoehe und Laengsrichtung dabei beide exakt getroffen). +;; Herleitung: Sei D = ziel - start (2D), raw-dx/raw-dy der ROHE, ungedrehte +;; Fussabdruck (vf-element-masse, KS_AUS-KS_EIN bei Rotation 0). Bei +;; Einfuegewinkel hz gilt IMMER (Rotationsinvariante: die Projektion eines +;; gedrehten Vektors auf seine eigene Drehachse aendert sich durch die Drehung +;; nicht): Laengsanteil (entlang hz) = raw-dx, Queranteil (quer zu hz) = +;; raw-dy - unabhaengig vom konkreten hz. Mit L = Vorlauflaenge + raw-dx +;; (effektive Gesamt-Laengsstrecke inkl. Element-Vorschub) folgt daraus ein +;; rechtwinkliges Dreieck: |D|^2 = L^2 + raw-dy^2 (D, L-Anteil und raw-dy- +;; Anteil bilden ein orthonormales Paar), also L = sqrt(|D|^2 - raw-dy^2), und +;; die gesuchte Richtung hz' = Winkel von D MINUS dem Winkel, den raw-dy quer +;; dazu beitraegt (atan2(raw-dy, L)). +;; Rueckgabe: (hz-korrigiert L) - L ist die korrigierte RAW-Distanz zum +;; Zielpunkt entlang hz-korrigiert (Laengsanteil von D), NICHT bereits um +;; raw-dx reduziert - genau wie das bisherige deltaL (vfl-neue-linie-messen/ +;; vfl-projiziere-distanz) wird sie unveraendert an die bestehenden Solver +;; (vfl-body-zerlegung/vfl-vf-entscheidung -> berechne-alle-winkel) weiter- +;; gereicht, die raw-dx (ein-dx/aus-dx) SELBST intern abziehen (siehe deren +;; A-Formel) - hier zusaetzlich abzuziehen waere eine Doppel-Reservierung. +;; nil, wenn |D| < |raw-dy| (Ziel liegt naeher als der reine Seitenversatz - +;; geometrisch unerreichbar, unabhaengig von jeder Winkelwahl). +(defun vfl-richtung-mit-drehendem-fussabdruck (start ziel raw-dx raw-dy / + dx dy dsq l hz-ziel hz-korr) + (setq dx (- (car ziel) (car start)) dy (- (cadr ziel) (cadr start))) + (setq dsq (- (+ (* dx dx) (* dy dy)) (* raw-dy raw-dy))) + (if (< dsq 0.0) + nil + (progn + (setq l (sqrt dsq)) + (setq hz-ziel (* (atan dy dx) (/ 180.0 pi))) + (setq hz-korr (- hz-ziel (* (atan raw-dy l) (/ 180.0 pi)))) + (list hz-korr l) + ) + ) +) + ;; Rahmen am Ende eines vfs-*-Bausteins: die Bausteine (Entry/Koerper/Exit) ;; enden IMMER auf der 3-Grad-Basisneigung (siehe Prinzipien-Dok Abschnitt 6). (defun vfl-frame-3grad (punkt hz) @@ -4427,6 +4536,33 @@ "vfl-ist-kettenende-header")) antwort) +;; Frage-Schale "ES-Element setzen?" (+ falls ja: Winkel/Seite) - ausgelagert +;; aus vfl-vf-einheit (Option 3 "Kettenende"), damit sie auch VOR einem +;; Winkel-Solve aufgerufen werden kann: der tatsaechliche ES-Fussabdruck +;; (ein-dx/ein-dz, per vfl-es-masse-setzen INNERHALB von vfl-frage-es-seite +;; gesetzt) muss dafuer VOR dem Solve feststehen, sonst waehlt dieser einen zu +;; flachen/langen Winkel und der spaeter noetige Schwanz (Motorstation+ +;; Separator+ES) passt nicht mehr in die Reststrecke (siehe vfl-vf-einheit, +;; vorab-antwort-Parameter). Bei "Nein" werden ein-dx/ein-dz genullt (kein +;; ES-Fussabdruck reserviert) und der alte Wert als 3./4. Rueckgabewert +;; mitgegeben - der Aufrufer muss ihn nach getaner Zerlegung wiederherstellen. +;; Rueckgabe: (es-gewuenscht es-seite save-eindx save-eindz). +(defun vfl-es-element-abfragen ( / es-antwort es-gewuenscht es-seite save-eindx save-eindz) + (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 es-gewuenscht + (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))) + (list es-gewuenscht es-seite save-eindx save-eindz)) + ;; --- Horizontaler Koerper: Frage-Schale (Name unveraendert) --- ;; Fragt Separator vor/nach und - im Ziel-Modus - "Ist der Endpunkt der ;; Foerderer?", danach baut vfl-hor-koerper-bauen. Keine der drei Fragen @@ -4563,6 +4699,71 @@ ) (princ)) +;; Stufe-3-Zusatzfrage: Position des horizontalen Fuellstuecks (vor ODER nach +;; dem S-Bogen) - wird NUR gestellt, wenn Stufe 3 tatsaechlich einen Treffer +;; liefert (seltener Fallback, siehe vfl-winkel-stufe-entscheidung). Generischer +;; vflw_wahl-Popup-Dialog ueber vfl-menu (Muster wie die AUS-Element-Seite- +;; Frage) - keine neue DCL-Sonderloesung noetig. Selbstbeschreibender String +;; "vor"/"nach" statt roher Index-Antwort (Projektkonvention). +(defun vfl-frage-stufe3-position (/ antwort) + (princ (ssg-text "vfl-frage-stufe3-position")) + (princ (ssg-text "vfl-opt-stufe3-vor")) + (princ (ssg-text "vfl-opt-stufe3-nach")) + (setq antwort (vfl-menu (ssg-text "prompt-wahl-1-2") + (list (ssg-text "vfl-opt-stufe3-vor") + (ssg-text "vfl-opt-stufe3-nach")) 1 + "vfl-frage-stufe3-position")) + (if (= antwort "2") "nach" "vor")) + +;; Gemeinsamer Bau-Helfer fuer EINEN VF-Koerper, optional MIT zusaetzlichem +;; horizontalem Fuellstueck (Stufe 3, siehe vfl-winkel-stufe-entscheidung/ +;; vfl-stufe3-winkel-horizontal in vf_standard.lsp). Ersetzt den bis dahin an +;; zwei Stellen identisch duplizierten Aufruf (vfl-body-abschluss-bauen UND +;; vfl-vf-einheit): (vfl-frame-3grad (vfs-vf-koerper ... hzn) hzn) + +;; vfl-acc-vf-seg + Zaehler-Erhoehung. +;; L_hor/position nil oder L_hor<=0: unveraendertes Verhalten (ein einzelner +;; vfs-vf-koerper-Aufruf) - reiner Drop-in-Ersatz fuer Stufe 1/2, KEINE +;; Verhaltensaenderung dort. +;; Sonst: zwei vfs-vf-koerper-Aufrufe (S-Bogen bei winkel/L_VF, Fuellstueck +;; bei winkel=0/L_hor - baut sein eigenes auf_3/ab_3-Uebergangsbogenpaar +;; SELBST, siehe vfs-vf-koerper best-winkel=0-Sonderfall in vf_standard.lsp), +;; Reihenfolge nach position ("vor"/"nach" dem S-Bogen, vom Anwender gewaehlt). +;; Frame wird zwischen den Teilschritten jedesmal per vfl-frame-3grad neu +;; aufgebaut, jedes Teilstueck einzeln journalisiert (vfl-acc-vf-seg) - sonst +;; fehlt es im Export/Report. +;; vfl-nach-3grad (falls noetig) bleibt Sache des AUFRUFERS, wie bisher. +;; Rueckgabe: (list frame cnt-erhoehung), cnt-erhoehung = Anzahl eingefuegter +;; Koerper (1 ohne Fuellstueck, 2 mit). +(defun vfl-baue-vf-koerper-mit-fuellstueck (frame richtn winkel L_VF L_hor position hzn / cnt) + (setq cnt 0) + (if (and L_hor (> L_hor 1.0) position) + (if (= position "vor") + (progn + (setq frame (vfl-frame-3grad (vfs-vf-koerper (car frame) richtn 0 L_hor hzn) hzn)) + (vfl-acc-vf-seg "horizontal" 0 L_hor) + (setq cnt (1+ cnt)) + (setq frame (vfl-frame-3grad (vfs-vf-koerper (car frame) richtn winkel L_VF hzn) hzn)) + (vfl-acc-vf-seg richtn winkel L_VF) + (setq cnt (1+ cnt)) + ) + (progn + (setq frame (vfl-frame-3grad (vfs-vf-koerper (car frame) richtn winkel L_VF hzn) hzn)) + (vfl-acc-vf-seg richtn winkel L_VF) + (setq cnt (1+ cnt)) + (setq frame (vfl-frame-3grad (vfs-vf-koerper (car frame) richtn 0 L_hor hzn) hzn)) + (vfl-acc-vf-seg "horizontal" 0 L_hor) + (setq cnt (1+ cnt)) + ) + ) + (progn + (setq frame (vfl-frame-3grad (vfs-vf-koerper (car frame) richtn winkel L_VF hzn) hzn)) + (vfl-acc-vf-seg richtn winkel L_VF) + (setq cnt (1+ cnt)) + ) + ) + (list frame cnt) +) + ;; 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 @@ -4579,12 +4780,17 @@ ;; 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). +;; Rueckgabe: (typ winkel L_GF L_VF) bzw. bei einem Stufe-3-Treffer (typ +;; winkel L_GF L_VF L_hor position), typ="GF"/"VF"/nil (winkel=0 bei "VF" +;; heisst horizontales Stufe-2-Ergebnis). L_hor/position sind nur bei Stufe 3 +;; belegt (siehe vfl-stufe3-winkel-horizontal, vf_standard.lsp) - fehlende +;; Listenelemente liefern ueber (nth ...) automatisch nil, alle Konsumenten +;; lesen ausschliesslich per nth. 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) + winkel-natuerlich wahl horizontal-info + stufe3-erg res) (if (or (not *lib-initialized*) (null bogen-auf)) (init-bibliothek)) ;; Gesammelten Stufe-2-Diagnosetext + Alert-Vorschlagswerte aus einem evtl. ;; vorherigen Aufruf verwerfen - der Aufrufer haengt/zeigt sie nur an, wenn @@ -4624,7 +4830,18 @@ (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))))) + (progn + ;; Stufe 1 UND Stufe 2 gescheitert: Stufe 3 (steiler Tabellen- + ;; winkel + horizontales Fuellstueck, vfl-stufe3-winkel- + ;; horizontal in vf_standard.lsp) als letzter Fallback vor der + ;; Ablehnung. Position (vor/nach dem S-Bogen) fragt der + ;; Anwender NUR, wenn Stufe 3 tatsaechlich einen Treffer liefert. + (princ (ssg-text "vfl-stufe3-start")) + (setq stufe3-erg (vfl-stufe3-winkel-horizontal deltaL deltaH "Auf" feste-hz schon-flach)) + (if (nth 4 stufe3-erg) + (list "VF" (nth 0 stufe3-erg) (nth 1 stufe3-erg) (nth 2 stufe3-erg) + (nth 3 stufe3-erg) (vfl-frage-stufe3-position)) + (list nil nil nil nil))))))) ;; fallend: natuerlichen Neigungswinkel gegen die 3-Grad-Eigenneigung pruefen (t (setq winkel-natuerlich (* (atan (/ deltaH deltaL)) (/ 180.0 pi))) @@ -4704,7 +4921,8 @@ ;; ein-dx/ein-dz um den Aufruf herum nullt (kein ES-Fussabdruck reservieren); ;; letzt-hz wurde nur einer wirkungslosen Zuweisung zugefuehrt (siehe unten). (defun vfl-body-abschluss-bauen (frame p-umlenk dL hzn hn schon-flach es-gewuenscht / - dH richtn rad3 dec typ w lgf lvf gf2 cnt + dH richtn rad3 dec typ w lgf lvf lhor position + bau-erg gf2 cnt p0 tx ty letzt-hz antwort-gf2) (setq dH (- hn (caddr (car frame)))) (setq richtn (if (>= dH 0.0) "Auf" "Ab")) @@ -4713,7 +4931,8 @@ (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 schon-flach es-gewuenscht)) - (setq typ (nth 0 dec) w (nth 1 dec) lgf (nth 2 dec) lvf (nth 3 dec)) + (setq typ (nth 0 dec) w (nth 1 dec) lgf (nth 2 dec) lvf (nth 3 dec) + lhor (nth 4 dec) position (nth 5 dec)) (if (null typ) (progn (princ (ssg-text "vfl-fehler-rest-nicht-baubar")) @@ -4768,9 +4987,8 @@ ;; flachen Fall ab (siehe berechne-alle-winkel/entry-dx/entry-dz). ((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 bau-erg (vfl-baue-vf-koerper-mit-fuellstueck frame richtn w lvf lhor position hzn)) + (setq frame (car bau-erg) cnt (+ cnt (cadr bau-erg)))) ) ;; ohne Wirkung: letzt-hz ist lokal und wird nicht mehr gelesen - ;; die Fahrtrichtung verlaesst die Funktion ueber die Rueckgabe. @@ -4816,9 +5034,18 @@ ;; die gemessene Laenge und die aktuelle Kettenhoehe. Darum in dieser ;; Reihenfolge: flache Zone abschliessen -> Laenge messen -> Vorschlaege ;; berechnen -> Zielhoehe fragen -> bauen. -(defun vfl-body-abschluss (frame letzt-hz p-umlenk es-gewuenscht / +;; vorab-ziel-punkt (optional, Default nil): der ABSOLUTE Zielpunkt (Liste +;; x y z) steht bereits fest - z.B. weil er schon VOR dem Winkel-Solve der +;; VF-Einheit gepickt wurde (siehe vfl-vf-einheit, vorab-antwort="3"). Dann +;; NICHT nochmal per vfl-neue-linie-messen/vfl-hoehe-endpunkt-abfragen fragen +;; (der sonst noetige, fehleranfaellige zweite Klick auf denselben Punkt - +;; Nutzer-Wunsch), sondern Restlaenge/-hoehe direkt aus der aktuellen +;; Frame-Position zu diesem Punkt herleiten (vfl-projiziere-distanz, dieselbe +;; Technik wie bei der AS-Restlaengen-Korrektur). letzt-hz bleibt dabei die +;; Fahrtrichtung (unveraendert seit dem urspruenglichen Pick). +(defun vfl-body-abschluss (frame letzt-hz p-umlenk es-gewuenscht vorab-ziel-punkt / linie-mess dL hzn hn schon-flach ergebnis dH richtn - hoehe-vorschlaege hoehe-ab hoehe-auf hoehe-fallback) + hoehe-vorschlaege hoehe-ab hoehe-auf gueltig) ;; 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 @@ -4826,29 +5053,41 @@ ;; auf_3/ab_3-Bogenpaar - siehe Kommentar bei vfl-winkel-stufe-entscheidung). ;; 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) + (setq gueltig t) + (if vorab-ziel-punkt + (setq dL (vfl-projiziere-distanz (car frame) vorab-ziel-punkt letzt-hz) + hzn letzt-hz + hn (caddr vorab-ziel-punkt)) + (progn + (setq linie-mess (vfl-neue-linie-messen (car frame) letzt-hz)) + (if (null linie-mess) + (setq gueltig nil) + (progn + (setq dL (car linie-mess) hzn (cadr linie-mess)) + ;; Baubare Vorschlaege (Ab/Auf) statt der unveraenderten Kettenhoehe + ;; als Default - sonst waere dH=0 ("Auf", da (>= 0.0 0.0)) und der + ;; Rest wird von vfl-body-zerlegung sofort als "nicht baubar" + ;; abgelehnt (kleineres Budget als vfl-vf-entscheidung: nur + ;; Motor+Separator, 800mm statt 1300mm) - siehe + ;; vfl-body-hoehe-vorschlaege/vfl-body-machbar-p. + (setq hoehe-vorschlaege (vfl-body-hoehe-vorschlaege (caddr (car frame)) dL es-gewuenscht schon-flach)) + (setq hoehe-ab (nth 0 hoehe-vorschlaege) hoehe-auf (nth 1 hoehe-vorschlaege)) + (setq hn (vfl-hoehe-endpunkt-abfragen hoehe-ab hoehe-auf (caddr (car frame)) "kettenende")) + ) + ) + ) + ) + ;; Nutzer-Entscheidung (2026-09-15): dL/hzn bleiben unveraendert entlang der + ;; urspruenglich gemessenen/vorgegebenen Fahrtrichtung - KEINE Drehung mehr, + ;; um den seitlichen Fussabdruck eines drehenden ES-Elements (ein-dy) + ;; auszugleichen (siehe vfl-richtung-mit-drehendem-fussabdruck, jetzt nicht + ;; mehr hier verwendet). Ein drehendes ES-Element (30/90 Grad) landet + ;; dadurch mit einem natuerlichen, unvermeidbaren seitlichen Versatz neben + ;; dem Zielpunkt - erwartetes Verhalten (Hauptstrang bleibt gerade), keine + ;; zu behebende Abweichung. + (if (not gueltig) (progn (princ (ssg-text "vfl-abgebrochen-kein-ziel")) nil) (progn - (setq dL (car linie-mess) hzn (cadr linie-mess)) - ;; Baubare Vorschlaege (Ab/Auf) statt der unveraenderten Kettenhoehe als - ;; Default - sonst waere dH=0 ("Auf", da (>= 0.0 0.0)) und der Rest wird - ;; von vfl-body-zerlegung sofort als "nicht baubar" abgelehnt (kleineres - ;; Budget als vfl-vf-entscheidung: nur Motor+Separator, 800mm statt - ;; 1300mm) - siehe vfl-body-hoehe-vorschlaege/vfl-body-machbar-p. - (setq hoehe-vorschlaege (vfl-body-hoehe-vorschlaege (caddr (car frame)) dL es-gewuenscht schon-flach)) - (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-kettenende-2" - (list (rtos hoehe-ab 2 1) (rtos hoehe-auf 2 1))) - (ssg-textf "vfl-prompt-hoehe-kettenende" (list (rtos hoehe-fallback 2 1)))))) - (if (null hn) (setq hn hoehe-fallback)) (setq ergebnis (vfl-body-abschluss-bauen frame p-umlenk dL hzn hn schon-flach es-gewuenscht)) ;; Klare Rueckmeldung statt nur der einfachen Bau-Fehlermeldung (die ;; steht schon in vfl-body-abschluss-bauen): die tatsaechlich gewaehlte @@ -4931,12 +5170,30 @@ frame) ;; Rueckgabe: (frame anzahl-koerper ziel-ende) -(defun vfl-vf-einheit (frame hz1 richtung1 winkel1 L_GF1 L_VF1 gf-am-ausgang eingang-modus / +;; vorab-antwort/vorab-es-gewuenscht/vorab-es-seite (optional, Default nil): +;; wurde "Ist der Endpunkt der Foerderer?" (+ ggf. "ES-Element setzen?") vom +;; Aufrufer bereits VOR diesem Aufruf gestellt (siehe vf-linienzug-modus, +;; "Linie-VF"-Zweig) - dann NICHT in der Fortsetzungsschleife nochmal fragen, +;; sondern die Antwort direkt fuer die ERSTE Runde uebernehmen. Nur fuer den +;; geneigten Erstkoerper relevant (winkel1<>0) - der horizontale Fall +;; (winkel1=0) hat sein eigenes vor-antwort ueber vfl-baue-horizontal-koerper. +;; vorab-ziel-punkt (nur bei vorab-antwort="3" relevant): der bereits VOR dem +;; Winkel-Solve absolut gepickte Zielpunkt (x y z) - wird 1:1 an +;; vfl-body-abschluss durchgereicht, damit dort NICHT nochmal ein zweiter +;; Endpunkt abgefragt wird (Nutzer-Wunsch: "der zweite Klick ist unnoetig"). +;; L_hor1/L_hor1-position: nur bei einem Stufe-3-Treffer fuer das ERSTE +;; Koerper-Sub-Segment belegt (siehe vfl-vf-einheit-abschluss), sonst nil. +;; Die interne "weiterbauen"-Fortsetzung (ent aus vfl-segment-entscheidung, +;; s.u.) hat ihr EIGENES, unabhaengiges lhor/position - andere Entscheidung, +;; anderer Solve-Aufruf. +(defun vfl-vf-einheit (frame hz1 richtung1 winkel1 L_GF1 L_VF1 L_hor1 L_hor1-position + gf-am-ausgang eingang-modus + vorab-antwort vorab-es-gewuenscht vorab-es-seite vorab-ziel-punkt / 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 + linie-mess dL dH hn hzn richtn ent typ w lgf lvf lhor position bau-erg 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 + res-h vor-antwort es-gewuenscht erg-es save-eindx save-eindz + hoehe-vorschlaege hoehe-ab hoehe-auf schon-flach winkel-hoehen-erg es-seite) ;; Vorbelegung: ES gewuenscht (Default) - nur bei "3 - Kettenende definieren" ;; wird explizit gefragt und ggf. auf nil gesetzt (siehe dort). @@ -4989,7 +5246,7 @@ (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 frame (car res-h) vor-antwort (cadr res-h)) + (setq frame (car res-h) vor-antwort (cadr res-h) vf-count 1) ) (progn ;; vfs-vf-koerper braucht die 3-Grad-Basis als Eintritt - im Normalfall @@ -4997,11 +5254,12 @@ ;; 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) + (setq bau-erg (vfl-baue-vf-koerper-mit-fuellstueck frame richtung1 winkel1 L_VF1 L_hor1 L_hor1-position hz1)) + (setq frame (car bau-erg) vf-count (cadr bau-erg)) + (setq vor-antwort vorab-antwort) ) ) - (setq vf-count 1 letzt-hz hz1) + (setq letzt-hz hz1) (vfl-20m-check p-umlenk (car frame)) ;; --- Fortsetzungs-Schleife bis Foerderer-Ende --- @@ -5030,31 +5288,37 @@ ;; 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 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 es-gewuenscht)) - (if (not es-gewuenscht) - (setq ein-dx save-eindx ein-dz save-eindz)) - (if res3 - (setq frame (nth 0 res3) - vf-count (+ vf-count (nth 1 res3)) - letzt-hz (nth 2 res3) - ziel-gf2 (nth 3 res3) - ziel-ende t - fertig t))) + ;; War das schon VOR dem Winkel-Solve entschieden (vorab-antwort="3", + ;; siehe Funktionskopf) - dann NICHT nochmal fragen (waere doppelt + ;; journalisiert), ein-dx/ein-dz NICHT anfassen (stehen bereits korrekt, + ;; der Aufrufer hat sie vor dem Solve gesetzt) UND vfl-body-abschluss + ;; GAR NICHT mehr aufrufen: die schon VOR diesem Solve bekannte + ;; Fahrtrichtungs-Korrektur (vfl-richtung-mit-drehendem-fussabdruck im + ;; Aufrufer) macht den ersten Winkel-Solve bereits vollstaendig ES- + ;; bewusst (laengs UND quer) - die dabei schon berechnete GF2-Laenge + ;; (L_GF2-bau, aus der GF-Verteilungs-Frage) trifft den Zielpunkt daher + ;; bereits exakt. Eine zweite, unabhaengige Loesung (vfl-body-abschluss) + ;; war nur noetig, SOLANGE der erste Solve das ES-Element noch nicht + ;; kannte - real beobachteter Bug: genau diese zweite, unabhaengige + ;; Loesung konnte scheitern (z.B. "kein passender Winkel"), obwohl die + ;; ERSTE Wahl bereits eine vollstaendig gueltige Gesamtloesung war. + (if (equal vorab-antwort "3") + (setq es-gewuenscht vorab-es-gewuenscht es-seite vorab-es-seite + ziel-gf2 L_GF2-bau ziel-ende t fertig t) + (progn + (setq erg-es (vfl-es-element-abfragen)) + (setq es-gewuenscht (nth 0 erg-es) es-seite (nth 1 erg-es) + save-eindx (nth 2 erg-es) save-eindz (nth 3 erg-es)) + (setq res3 (vfl-body-abschluss frame letzt-hz p-umlenk es-gewuenscht nil)) + (if (not es-gewuenscht) (setq ein-dx save-eindx ein-dz save-eindz)) + (if res3 + (setq frame (nth 0 res3) + vf-count (+ vf-count (nth 1 res3)) + letzt-hz (nth 2 res3) + ziel-gf2 (nth 3 res3) + ziel-ende t + fertig t)))) + ) (progn (princ (ssg-text "vfl-naechstes-element-vf")) (princ (ssg-text "vfl-opt-horizontaler-foerderer")) @@ -5155,28 +5419,18 @@ ;; (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 hn (vfl-hoehe-endpunkt-abfragen hoehe-ab hoehe-auf (caddr (car frame)) "endpunkt")) (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)) + (setq typ (nth 0 ent) w (nth 1 ent) lgf (nth 2 ent) lvf (nth 3 ent) + lhor (nth 4 ent) position (nth 5 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) + (setq bau-erg (vfl-baue-vf-koerper-mit-fuellstueck frame richtn w lvf lhor position hzn)) + (setq frame (car bau-erg)) + (setq vf-count (+ vf-count (cadr bau-erg)) letzt-hz hzn) (vfl-20m-check p-umlenk (car frame)) ) (princ (ssg-text "vfl-segment-gf-nicht-erlaubt")) @@ -5869,7 +6123,15 @@ (setq *vfl-ziel-punkt* nil))) (princ)) -(defun vfl-vf-einheit-abschluss (frame hz richtung winkel L_GF L_VF auto-ende gf-verteilung-fest eingang-modus / +;; vorab-antwort/vorab-es-gewuenscht/vorab-es-seite/vorab-ziel-punkt: siehe +;; vfl-vf-einheit (Default nil - unveraendertes Verhalten fuer alle Aufrufer, +;; die diese Vorab-Entscheidung nicht kennen). +;; L_hor/L_hor-position: nur bei einem Stufe-3-Treffer belegt (siehe +;; vfl-winkel-stufe-entscheidung/vfl-stufe3-winkel-horizontal), sonst nil - +;; unveraendertes Verhalten fuer alle anderen Aufrufer. +(defun vfl-vf-einheit-abschluss (frame hz richtung winkel L_GF L_VF L_hor L_hor-position + auto-ende gf-verteilung-fest eingang-modus + vorab-antwort vorab-es-gewuenscht vorab-es-seite vorab-ziel-punkt / antwort res es-s ende es-gewuenscht es-seite-vorab) ;; GF-Verteilung: halbe Staustrecke am Ausgang (GF2) oder alles am Einlauf. ;; gf-verteilung-fest: Aufrufer erzwingt die Antwort (z.B. "2", wenn L_GF @@ -5886,7 +6148,8 @@ (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 res (vfl-vf-einheit frame hz richtung winkel L_GF L_VF L_hor L_hor-position (= antwort "1") eingang-modus + vorab-antwort vorab-es-gewuenscht vorab-es-seite vorab-ziel-punkt)) (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, @@ -5951,19 +6214,22 @@ ;; ============================================================ (defun vf-linienzug-modus ( / startpunkt start-hoehe as-seite es-seite antwort wahl p-aktuell linie-mess hoehe-neu hoehe-bis deltaL deltaH richtung hz-neu - entscheidung typ winkel L_GF L_VF vf-einheit-res + entscheidung typ winkel L_GF L_VF lhor stufe3-position 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 as-vorhanden erg old-error vfl-ins dbg-an - hoehe-vorschlaege hoehe-ab hoehe-auf hoehe-fallback + hoehe-vorschlaege hoehe-ab hoehe-auf gf-laenge-modus gf-steigend-modus sep-vor-gf sep-nach-gf sep-anzahl erg-bogen vf-eingang-lgf vf-eingang-modus eingang-laenge winkel-hoehen-erg bogen-mass fest-drop fest-laenge eingang-fertig linie-ende-familie linie-ende-untermodus res3 save-eindx save-eindz es-gewuenscht - startpunkt-familie gf-kettenende-antwort) + startpunkt-familie gf-kettenende-antwort + vorab-antwort vorab-es-gewuenscht vorab-es-seite + save-eindx-vorab save-eindz-vorab erg-es vorab-ziel-punkt + rad3-sep sep-eindx-add sep-eindz-add) ;; "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-*- @@ -6375,7 +6641,8 @@ ;; 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)) + (vfl-vf-einheit-abschluss frame hz-neu "Ab" 0 vf-eingang-lgf deltaL nil nil nil "2" vf-eingang-modus + nil 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)) @@ -6955,7 +7222,8 @@ " 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)) + (vfl-vf-einheit-abschluss frame hz-neu richtung winkel L_GF L_VF nil nil nil "2" vf-eingang-modus + nil 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)) @@ -6969,27 +7237,80 @@ ) ) (progn + ;; Erst fragen, ob DIESER Endpunkt schon das Kettenende ist (+ + ;; falls ja: ES-Element setzen), DANN erst Zielhoehe/Winkel + ;; berechnen - analog zu vfl-baue-horizontal-koerper (horizontaler + ;; Erstkoerper). Vorher wurde die Frage erst NACH dem Bau des + ;; ersten (Winkel-)Segments gestellt (in der Fortsetzungsschleife + ;; von vfl-vf-einheit) - dann war ein evtl. noetiger ES- + ;; Fussabdruck (Motorstation+Separator+ES) beim Winkel-Solve noch + ;; nicht reserviert, der gewaehlte Winkel konnte zu viel Strecke + ;; verbrauchen und der zwingend zweite, separate Endpunkt-Pick + ;; fuer den "Schwanz" schlug dann mangels Reststrecke fehl (Nutzer- + ;; Ruecksprache). ein-dx/ein-dz (ES-Fussabdruck) wirken bereits + ;; automatisch in vfl-vf-hoehe-vorschlaege/vfl-vf-entscheidung + ;; (ueber vfl-winkel-machbar-p) - hier muss nur die Reihenfolge + ;; stimmen. + (setq vorab-antwort (vfl-frage-ist-endpunkt)) + (setq vorab-es-gewuenscht nil vorab-es-seite nil + save-eindx-vorab nil save-eindz-vorab nil) + (setq sep-eindx-add 0.0 sep-eindz-add 0.0) + (if (= vorab-antwort "3") + (progn + (setq erg-es (vfl-es-element-abfragen)) + (setq vorab-es-gewuenscht (nth 0 erg-es) vorab-es-seite (nth 1 erg-es) + save-eindx-vorab (nth 2 erg-es) save-eindz-vorab (nth 3 erg-es)) + ;; vfl-insert-es-element baut IMMER einen eigenen Separator + ;; (300mm, 3 Grad) VOR dem ES-Block - das ist NICHT Teil des + ;; ueber vf-set-es-masse gemessenen ein-dx/ein-dz (die messen + ;; nur den ES-Block selbst, siehe Bibliotheks-Init-Log + ;; "ES_90: dx=436 dz=-65"). Fuer den Solve zusaetzlich + ;; reservieren, sonst fehlt genau dieser Fussabdruck im + ;; Ergebnis - real gemessener Bug (BricsCAD-Test): dX=-299.6mm + ;; dZ=-15.7mm, exakt der Separator-Fussabdruck bei 3 Grad + ;; (300*cos3=299.6, 300*sin3=15.7). Nach dem Solve/Bau wieder + ;; abgezogen (siehe Restaurierung unten), damit ein-dx/ein-dz + ;; danach wieder den reinen ES-Block-Fussabdruck zeigen. + (if vorab-es-gewuenscht + (progn + (setq rad3-sep (* (float (ssg-cfg-or "vario" "gefaelle_winkel" 3)) (/ pi 180.0))) + (setq sep-eindx-add (* *vfk-separator-laenge* (cos rad3-sep)) + sep-eindz-add (* *vfk-separator-laenge* (sin rad3-sep))) + (setq ein-dx (+ ein-dx sep-eindx-add) + ein-dz (- ein-dz sep-eindz-add)))))) (setq hoehe-vorschlaege (vfl-vf-hoehe-vorschlaege (caddr p-aktuell) deltaL)) (setq hoehe-ab (nth 0 hoehe-vorschlaege) hoehe-auf (nth 1 hoehe-vorschlaege)) - (setq hoehe-fallback (if hoehe-ab hoehe-ab (caddr p-aktuell))) - (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 p-aktuell))))) - (setq hoehe-neu - (vfl-in-real - (if (and hoehe-ab hoehe-auf) - (ssg-textf "vfl-prompt-hoehe-linienendpunkt-2" - (list (rtos hoehe-ab 2 1) (rtos hoehe-auf 2 1))) - (ssg-textf "vfl-prompt-hoehe-linienendpunkt" (list (rtos hoehe-fallback 2 1)))))) - (if (null hoehe-neu) (setq hoehe-neu hoehe-fallback)) + (setq hoehe-neu (vfl-hoehe-endpunkt-abfragen hoehe-ab hoehe-auf (caddr p-aktuell) "linienendpunkt")) (setq deltaH (- hoehe-neu (caddr p-aktuell))) (setq richtung (if (>= deltaH 0.0) "Auf" "Ab")) (setq deltaH (abs deltaH)) (vfl-echo-endpunkt-hoehe p-aktuell deltaL hz-neu hoehe-neu deltaH richtung) + ;; Absoluter Zielpunkt dieses (einzigen) Picks - nur bei "3" + ;; gebraucht: wird bis nach vfl-vf-einheit durchgereicht, damit + ;; vfl-body-abschluss NICHT nochmal denselben Punkt abfragt + ;; (siehe vfl-vf-einheit/vfl-body-abschluss, vorab-ziel-punkt). + (setq vorab-ziel-punkt + (if (= vorab-antwort "3") + (list (+ (car p-aktuell) (* deltaL (cos (* (float hz-neu) (/ pi 180.0))))) + (+ (cadr p-aktuell) (* deltaL (sin (* (float hz-neu) (/ pi 180.0))))) + hoehe-neu) + nil)) + ;; Nutzer-Entscheidung (2026-09-15): der Hauptstrang (GF1/Klettern/ + ;; GF2/Motorstation) behaelt IMMER die urspruenglich gepickte + ;; Fahrtrichtung (hz-neu/deltaL bleiben unveraendert) - KEINE + ;; Vorab-Drehung mehr, um den seitlichen ES-Versatz (ein-dy) + ;; auszugleichen. Ein drehendes ES-Element (30/90 Grad) landet + ;; dadurch mit einem natuerlichen, unvermeidbaren seitlichen + ;; Versatz neben dem urspruenglich gepickten Punkt - das ist + ;; erwartetes Verhalten (Prinzip: Hauptstrang bleibt gerade, ES + ;; faellt "natuerlich" dorthin, wohin sein eigener Fussabdruck + ;; fuehrt), keine zu behebende Abweichung. ein-dx/ein-dz (Laengs/ + ;; Hoehe) werden weiterhin ganz normal ueber vfl-winkel-machbar-p + ;; reserviert (siehe vfl-vf-entscheidung). (setq entscheidung (vfl-vf-entscheidung deltaL deltaH richtung)) (setq typ (nth 0 entscheidung) winkel (nth 1 entscheidung) - L_GF (nth 2 entscheidung) L_VF (nth 3 entscheidung)) + L_GF (nth 2 entscheidung) L_VF (nth 3 entscheidung) + lhor (nth 4 entscheidung) stufe3-position (nth 5 entscheidung)) (if (null typ) (progn (vfl-meldung (ssg-textf "vfl-alert-vf-nicht-baubar" @@ -7020,7 +7341,9 @@ " 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 nil nil)) + (vfl-vf-einheit-abschluss frame hz-neu richtung winkel L_GF L_VF lhor stufe3-position nil nil nil + vorab-antwort vorab-es-gewuenscht vorab-es-seite + vorab-ziel-punkt)) (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)) @@ -7032,6 +7355,18 @@ (dbg-tostring p-aktuell)))) ) ) + ;; ein-dx/ein-dz (ES-Fussabdruck) nach diesem gesamten Aufruf + ;; wiederherstellen - sowohl im Erfolgs- als auch im "nicht + ;; baubar"-Fehlerfall, sonst wuerde eine genullte/aufaddierte + ;; ES-Groesse in eine spaetere, unabhaengige ES-Entscheidung an + ;; anderer Stelle in dieser Kette durchsickern: bei "ES nein" auf + ;; den Zustand VOR der Frage zuruecksetzen, bei "ES ja" die oben + ;; addierte Separator-Reservierung wieder abziehen (ein-dx/ein-dz + ;; zeigen danach wieder den reinen ES-Block-Fussabdruck). + (if (= vorab-antwort "3") + (if vorab-es-gewuenscht + (setq ein-dx (- ein-dx sep-eindx-add) ein-dz (+ ein-dz sep-eindz-add)) + (setq ein-dx save-eindx-vorab ein-dz save-eindz-vorab))) ) ) ) @@ -7097,7 +7432,7 @@ (if es-gewuenscht (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 (car (frame->hz-winkel frame)) (car frame) es-gewuenscht)) + (setq res3 (vfl-body-abschluss frame (car (frame->hz-winkel frame)) (car frame) es-gewuenscht nil)) (if (not es-gewuenscht) (setq ein-dx save-eindx ein-dz save-eindz)) (if (null res3) (if dbg-an @@ -7168,22 +7503,30 @@ (progn (setq hoehe-vorschlaege (vfl-segment-hoehe-vorschlaege (caddr p-aktuell) deltaL)) (setq hoehe-ab (nth 0 hoehe-vorschlaege) hoehe-auf (nth 1 hoehe-vorschlaege)) - (setq hoehe-fallback (if hoehe-ab hoehe-ab (caddr p-aktuell))) - (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 p-aktuell))))) - (setq hoehe-neu - (vfl-in-real - (if (and hoehe-ab hoehe-auf) - (ssg-textf "vfl-prompt-hoehe-linienendpunkt-2" - (list (rtos hoehe-ab 2 1) (rtos hoehe-auf 2 1))) - (ssg-textf "vfl-prompt-hoehe-linienendpunkt" (list (rtos hoehe-fallback 2 1)))))) - (if (null hoehe-neu) (setq hoehe-neu hoehe-fallback)) + (setq hoehe-neu (vfl-hoehe-endpunkt-abfragen hoehe-ab hoehe-auf (caddr p-aktuell) "linienendpunkt")) (setq deltaH (- hoehe-neu (caddr p-aktuell))) (setq richtung (if (>= deltaH 0.0) "Auf" "Ab")) (setq deltaH (abs deltaH)) (vfl-echo-endpunkt-hoehe p-aktuell deltaL hz-neu hoehe-neu deltaH richtung) + ;; Kettenende-Modus (Option 6, "Neue Linie BIS Kettenende"): + ;; ES-Element wird HIER IMMER gebaut (das verspricht schon + ;; der Menuetext) - Winkel/Seite deshalb JETZT erfragen + ;; (vfl-frage-es-seite, setzt ein-dx/ein-dz via + ;; vf-set-es-masse), BEVOR die Fussabdruck-Reservierung + ;; unten laeuft - vorher liefen beide mit veralteten/ + ;; zufaelligen ein-dx/ein-dz (die echte Frage kam bisher + ;; erst spaeter, redundant, INNERHALB von vfl-vf-einheit - + ;; Nutzer-Ruecksprache: derselbe Fehler wie bei "Neue + ;; Linie: Ab/Auf VF", hier nur eine Stufe frueher versteckt). + ;; vorab-ziel-punkt (der bereits gepickte Zielpunkt) wird bis + ;; zu vfl-vf-einheit durchgereicht, damit fuer den "Auf"-Fall + ;; (VF-Einheit noetig) KEIN zweiter Klick mehr noetig ist. + (setq vorab-antwort "3" vorab-es-gewuenscht t) + (setq vorab-es-seite (vfl-frage-es-seite nil)) + (setq vorab-ziel-punkt + (list (+ (car p-aktuell) (* deltaL (cos (* (float hz-neu) (/ pi 180.0))))) + (+ (cadr p-aktuell) (* deltaL (sin (* (float hz-neu) (/ pi 180.0))))) + hoehe-neu)) ;; Kettenende-Modus (Option 4): Der abgefragte Endpunkt (XY+Z) ;; ist das exakte Ende der Kette NACH Separator + ES-Element. ;; Deren Footprint (Separator 300 mm bei ~3 Grad + ES-Element @@ -7202,6 +7545,23 @@ (list (rtos deltaL 2 0) (rtos deltaH 2 0)))) ) ) + ;; ein-dx/ein-dz waehrend der Typ-/Winkel-Entscheidung + ;; (vfl-vf-entscheidung/vfl-segment-entscheidung, nur im + ;; "Auf"-Fall relevant) temporaer nullen: der ES-Fussabdruck + ;; wurde oben BEREITS von deltaL/deltaH abgezogen - eine + ;; zweite Reservierung INNERHALB des Solvers waere doppelt + ;; (analog zu vfl-vf-winkel, das aus-dx/aus-dz aus demselben + ;; Grund temporaer nullt). Nach der Entscheidung sofort + ;; wiederhergestellt - der spaetere Bau (vfl-vf-einheit) + ;; braucht die echten Werte nicht mehr (er nutzt L_GF2-bau + ;; direkt), aber andere Stellen in dieser Kette schon. + (setq save-eindx-vorab ein-dx save-eindz-vorab ein-dz) + (setq ein-dx 0.0 ein-dz 0.0) + ;; Aus einer fruehren Schleifen-Iteration stehengebliebene + ;; Stufe-3-Werte NICHT versehentlich fuer dieses Segment + ;; wiederverwenden - nur die beiden entscheidung-Zweige + ;; unten setzen sie ggf. neu. + (setq lhor nil stufe3-position nil) (if (equal linie-ende-familie "GF") (progn ;; --- Startpunkt als GF-Familie erkannt --- @@ -7219,7 +7579,24 @@ (setq *vfl-stufe2-diagnose-text* nil) (setq *vfl-stufe2-minl-vorschlag* nil *vfl-stufe2-minh-vorschlag* nil) (if (= richtung "Auf") - (setq typ nil) + ;; Steigend: wie im "nicht eindeutig"-Zweig + ;; (vfl-segment-entscheidung) NICHT sofort + ;; aufgeben - eine bestehende GF-Kette darf + ;; durchaus in eine frische VF-Einheit (eigene + ;; Umlenk-/Motorstation) uebergehen. Direkt + ;; vfl-vf-entscheidung aufrufen (identisch zu dem, + ;; was vfl-segment-entscheidung fuer "Auf" ohnehin + ;; getan haette) - der gemeinsame Baubereich unten + ;; (typ="GF" vs. sonst) baut ein typ="VF"-Ergebnis + ;; bereits unveraendert ueber vfl-vf-einheit- + ;; abschluss (mit eigener Umlenkstation), genau wie + ;; bei "Neue Linie: Ab/Auf VF". Realer Bug-Fall: + ;; vorher wurde hier IMMER typ=nil gesetzt, obwohl + ;; ein baubarer VF-Weg existierte (Nutzer-Meldung). + (setq entscheidung (vfl-vf-entscheidung deltaL deltaH richtung) + typ (nth 0 entscheidung) winkel (nth 1 entscheidung) + L_GF (nth 2 entscheidung) L_VF (nth 3 entscheidung) + lhor (nth 4 entscheidung) stufe3-position (nth 5 entscheidung)) (progn (princ (ssg-text "vfl-gf-laenge-modus-header")) (princ (ssg-text "vfl-gf-laenge-modus-opt-endpunkt")) @@ -7252,10 +7629,13 @@ (progn (setq entscheidung (vfl-segment-entscheidung deltaL deltaH richtung)) (setq typ (nth 0 entscheidung) winkel (nth 1 entscheidung) - L_GF (nth 2 entscheidung) L_VF (nth 3 entscheidung))) + L_GF (nth 2 entscheidung) L_VF (nth 3 entscheidung) + lhor (nth 4 entscheidung) stufe3-position (nth 5 entscheidung))) ) ) ) + ;; ein-dx/ein-dz wiederherstellen (siehe Nullung oben). + (setq ein-dx save-eindx-vorab ein-dz save-eindz-vorab) (if (null typ) (progn @@ -7296,24 +7676,23 @@ (if dbg-an (dbgmsg (strcat "GEOMETRIE ERFOLG: GF-Segment gebaut, neue Position=" (dbg-tostring p-aktuell)))) - ;; Kettenende-Modus (Option 4): ohne Frage direkt ES setzen. - ;; Sonst nachfragen, ob die Kette hier endet. - (if linie-ende-modus - (setq antwort "1") - (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)) - ) + ;; Kettenende-Modus (Option 6): ES-Element direkt setzen, + ;; Winkel/Seite wurden bereits VOR dem Solve erfragt + ;; (vorab-es-seite) - kein "Ist Kettenende?" noetig, + ;; linie-ende-modus ist in diesem "Linie"-Zweig immer T. + (setq es-seite vorab-es-seite) + (setq frame (vfl-insert-es-element "GF" frame hz-neu winkel + (caddr (car frame)) es-seite)) + (setq fertig t) ) (progn ;; --- VarioFoerderer-Einheit (Umlenk..Motor, mehrsegmentig) --- ;; linie-ende-modus=T -> direkt Kettenende (Separator + ES). + ;; vorab-antwort/-es-gewuenscht/-es-seite/-ziel-punkt (oben + ;; VOR dem Solve erfragt/berechnet) werden durchgereicht, + ;; damit vfl-vf-einheit weder "Ist der Endpunkt?" nochmal + ;; fragt noch einen zweiten Klick braucht (Nutzer-Wunsch, + ;; identischer Fix wie bei "Neue Linie: Ab/Auf VF"). (if dbg-an (dbgmsg (strcat "GEOMETRIE: vfl-vf-einheit-abschluss (deltaL=" (rtos deltaL 2 0) " deltaH=" (rtos deltaH 2 0) " richtung=" richtung @@ -7321,8 +7700,10 @@ " L_GF=" (rtos L_GF 2 0) " L_VF=" (rtos L_VF 2 0) " 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 nil nil)) + (vfl-vf-einheit-abschluss frame hz-neu richtung winkel L_GF L_VF lhor stufe3-position + linie-ende-modus nil nil + vorab-antwort vorab-es-gewuenscht vorab-es-seite + vorab-ziel-punkt)) (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)) diff --git a/Lisp/vf_standard.lsp b/Lisp/vf_standard.lsp index 80f8aec..484bfdc 100644 --- a/Lisp/vf_standard.lsp +++ b/Lisp/vf_standard.lsp @@ -214,6 +214,44 @@ ;; ============================================================ ;; TEIL 4: WINKELBERECHNUNG ;; ============================================================ +;; Laengen-/Hoehenbilanz (A/B) fuer EINEN Kandidatenwinkel des S-Bogens - +;; die Vektorzerlegung, die vf-winkel-solve danach nach L_GF/L_VF aufloest. +;; Ausgelagert aus berechne-alle-winkel (frueher inline dupliziert), damit +;; vfl-stufe3-winkel-horizontal (vf_linienzug.lsp - fixiert L_GF statt es zu +;; loesen) dieselbe Bilanz ohne Code-Duplikation nutzen kann. +;; mass1/mass2: (get-bogen-mass bogen-auf/-ab winkel), vom Aufrufer schon +;; richtungsabhaengig zugeordnet (Auf: mass1=auf, mass2=ab; Ab: umgekehrt). +;; entry-dx/entry-dz: Fussabdruck eines evtl. vorgeschalteten Uebergangsbogens +;; (schon-flach-Fall), sonst 0.0. Rueckgabe: (list A B), oder nil wenn +;; mass1/mass2 fehlen (Bogen bei diesem Winkel nicht verfuegbar). +(defun vf-winkel-AB (winkel richtung mass1 mass2 deltaL deltaH feste-hz + entry-dx entry-dz abs-dz-AUS abs-dz-EIN sin3 cos3 / + rad5 rad7 bogen-x1 bogen-z1 bogen-x2 bogen-z2 A B) + (if (or (null mass1) (null mass2)) + nil + (progn + (setq rad5 (* *vfk-gefaelle-winkel* (/ pi 180.0))) + (setq rad7 (* (float (if (= richtung "Auf") (- *vfk-gefaelle-winkel* winkel) (+ winkel *vfk-gefaelle-winkel*))) + (/ pi 180.0))) + (setq bogen-x1 (+ (* (car mass1) (cos rad5)) (* (caddr mass1) (sin rad5)))) + (setq bogen-z1 (+ (* (- (car mass1)) (sin rad5)) (* (caddr mass1) (cos rad5)))) + (setq bogen-x2 (+ (* (car mass2) (cos rad7)) (* (caddr mass2) (sin rad7)))) + (setq bogen-z2 (+ (* (- (car mass2)) (sin rad7)) (* (caddr mass2) (cos rad7)))) + (setq A (- deltaL aus-dx ein-dx bogen-x1 bogen-x2 + (* feste-hz cos3) entry-dx)) + (if (= richtung "Auf") + (setq B (+ deltaH abs-dz-AUS abs-dz-EIN (abs entry-dz) + (- bogen-z1) (- bogen-z2) + (* feste-hz sin3))) + (setq B (+ (- deltaH abs-dz-AUS abs-dz-EIN (abs entry-dz) + (* feste-hz sin3)) + bogen-z1 bogen-z2)) + ) + (list A B) + ) + ) +) + ;; feste-hz: horizontales Budget der festen Elemente (Umlenk+Motor+Separatoren). ;; nil => Standardwert FESTE_HORIZONTAL (1600, Standard-VF mit 2 Separatoren). ;; Der Linienzug uebergibt 1300 (nur 1 Separator am Einlauf, siehe vf_linienzug). @@ -229,9 +267,9 @@ ;; Aufrufer, die immer von der 3-Grad-Basis starten). (defun berechne-alle-winkel (deltaL deltaH richtung feste-hz schon-flach / winkel-list ergebnis-liste A B cos3 sin3 - bogen-x1 bogen-z1 bogen-x2 bogen-z2 + ab-erg abs-dz-AUS abs-dz-EIN L_GF L_VF cosα sinα - winkel-eff cosEff sinEff rad5 rad7 + winkel-eff cosEff sinEff winkel mass1 mass2 gueltig entry-mass entry-dx entry-dz best-winkel best-L_GF best-L_VF) @@ -272,31 +310,17 @@ (setq mass2 (get-bogen-mass bogen-auf winkel)) ) ) - (if (or (null mass1) (null mass2)) + (setq ab-erg (vf-winkel-AB winkel richtung mass1 mass2 deltaL deltaH feste-hz + entry-dx entry-dz abs-dz-AUS abs-dz-EIN sin3 cos3)) + (if (null ab-erg) (setq ergebnis-liste (cons (list winkel nil nil nil) ergebnis-liste)) (progn - (setq rad5 (* *vfk-gefaelle-winkel* (/ pi 180.0))) - (setq rad7 (* (float (if (= richtung "Auf") (- *vfk-gefaelle-winkel* winkel) (+ winkel *vfk-gefaelle-winkel*))) - (/ pi 180.0))) - (setq bogen-x1 (+ (* (car mass1) (cos rad5)) (* (caddr mass1) (sin rad5)))) - (setq bogen-z1 (+ (* (- (car mass1)) (sin rad5)) (* (caddr mass1) (cos rad5)))) - (setq bogen-x2 (+ (* (car mass2) (cos rad7)) (* (caddr mass2) (sin rad7)))) - (setq bogen-z2 (+ (* (- (car mass2)) (sin rad7)) (* (caddr mass2) (cos rad7)))) + (setq A (car ab-erg) B (cadr ab-erg)) (setq cosα (cos (* winkel (/ pi 180.0))) sinα (sin (* winkel (/ pi 180.0)))) - (setq A (- deltaL aus-dx ein-dx bogen-x1 bogen-x2 - (* feste-hz cos3) entry-dx)) (setq winkel-eff (if (= richtung "Auf") (- winkel *vfk-gefaelle-winkel*) (+ winkel *vfk-gefaelle-winkel*))) (setq cosEff (cos (* winkel-eff (/ pi 180.0))) sinEff (sin (* winkel-eff (/ pi 180.0)))) - (if (= richtung "Auf") - (setq B (+ deltaH abs-dz-AUS abs-dz-EIN (abs entry-dz) - (- bogen-z1) (- bogen-z2) - (* feste-hz sin3))) - (setq B (+ (- deltaH abs-dz-AUS abs-dz-EIN (abs entry-dz) - (* feste-hz sin3)) - bogen-z1 bogen-z2)) - ) (setq ergebnis-liste (cons (vf-winkel-solve winkel richtung A B sinα cosEff sinEff sin3 cos3) ergebnis-liste)) @@ -398,6 +422,110 @@ ) ) +;; Stufe 3 (Fallback fuer vfl-winkel-stufe-entscheidung, vf_linienzug.lsp): +;; gewinkelter S-Bogen (Tabellenwinkel) UND horizontales Fuellstueck +;; kombiniert, wenn WEDER Stufe 1 (reiner Tabellenwinkel) NOCH Stufe 2 +;; (berechne-horizontale-mitte, reine Horizontale) eine gueltige Loesung +;; liefern. GF wird FIX auf *vfl-gf-min-laenge* gesetzt (Konvention wie die +;; "climber"-Randbedingung in Modus 2/3) statt wie in Stufe 1 simultan +;; geloest - aus der Hoehenbilanz bleibt dann genau L_VF, aus der +;; Laengenbilanz der Rest als L_hor (horizontales Fuellstueck vor ODER nach +;; dem S-Bogen - Position waehlt der Anwender, siehe vfl-winkel-stufe- +;; entscheidung). +;; +;; Herleitung: vf-winkel-solve loest fuer einen Kandidatenwinkel implizit +;; das 2x2-System (durch Ruecksubstitution der dortigen Cramer-Loesung +;; rekonstruiert, winkel-eff=winkel-*vfk-gefaelle-winkel* fuer "Auf"): +;; cos3*L_GF + cosEff*L_VF = A (Laengenbilanz) +;; -sin3*L_GF + sinEff*L_VF = B (Hoehenbilanz) +;; Mit L_GF fix ergibt die Hoehenbilanz L_VF, die Laengenbilanz danach L_hor. +;; +;; Das Fuellstueck braucht sein EIGENES 3-Grad-Uebergangsbogenpaar (auf_3+ +;; ab_3, wie in berechne-horizontale-mitte) - dieser Fussabdruck ist NICHT +;; gratis und wird hier VORAB von A/B abgezogen, sonst wiederholt sich der +;; reale dZ-Fehler aus der Historie (siehe Kommentar bei vfl-winkel-stufe- +;; entscheidung, vf_linienzug.lsp). +;; +;; Absichtlich eng gehalten (kein Blackbox-Rateversuch): +;; - Nur "Auf" implementiert. "Ab" faellt laut bestehendem Kommentar bei +;; vfl-winkel-stufe-entscheidung fast immer schon unter Stufe 2 - ohne +;; einen konkreten Bedarfsfall bleibt der "Ab"-Zweig hier ein +;; dokumentiertes TODO statt einer ungetesteten Vermutung. +;; - schon-flach NICHT unterstuetzt: welcher der beiden Uebergangsboegen +;; (Fuellstueck oder S-Bogen) dabei entfallen wuerde, haengt von der - +;; zum Zeitpunkt der Berechnung noch unbekannten - Position (vor/nach) +;; ab. Stufe 3 liefert in diesem Fall bewusst KEIN Ergebnis statt eine +;; der beiden Moeglichkeiten zu raten. +;; +;; Rueckgabe: (list winkel L_GF L_VF L_hor gueltig) beim ersten (flachsten) +;; Kandidatenwinkel mit L_VF>=0 UND L_hor>=0, sonst (list nil nil nil nil nil). +(defun vfl-stufe3-winkel-horizontal (deltaL deltaH richtung feste-hz schon-flach / + winkel-list mass-f1 mass-f2 sin3 cos3 + bogen-x1f bogen-z1f bogen-x2f bogen-z2f + A-frei B-frei mass1 mass2 ab-erg A B + winkel-eff sinEff cosEff gf-min + L_GF L_VF L_hor winkel treffer) + (if (or (/= richtung "Auf") schon-flach) + (list nil nil nil nil nil) + (progn + (setq gf-min (if (and (boundp '*vfl-gf-min-laenge*) *vfl-gf-min-laenge*) + *vfl-gf-min-laenge* 400.0)) + (setq sin3 (sin (* *vfk-gefaelle-winkel* (/ pi 180.0))) + cos3 (cos (* *vfk-gefaelle-winkel* (/ pi 180.0)))) + (setq mass-f1 (get-bogen-mass bogen-auf (fix *vfk-gefaelle-winkel*))) + (setq mass-f2 (get-bogen-mass bogen-ab (fix *vfk-gefaelle-winkel*))) + (if (or (null mass-f1) (null mass-f2)) + (list nil nil nil nil nil) + (progn + ;; Fuellstueck-Uebergangsboegen (unabhaengig vom Kandidatenwinkel): + ;; Bogen1 (auf_3, Eintritt bei 3 Grad, wie in berechne-horizontale- + ;; mitte), Bogen2 (ab_3, Eintritt bei 0 Grad - keine Rotation noetig). + (setq bogen-x1f (+ (* (car mass-f1) cos3) (* (caddr mass-f1) sin3))) + (setq bogen-z1f (+ (* (- (car mass-f1)) sin3) (* (caddr mass-f1) cos3))) + (setq bogen-x2f (car mass-f2)) + (setq bogen-z2f (caddr mass-f2)) + (setq winkel-list (ssg-cfg-or "vario" "bogen_winkel" + '(3 6 9 12 15 18 21 27 33 39 45 51))) + (setq L_GF gf-min treffer nil) + (foreach winkel winkel-list + (if (not treffer) + (progn + (setq mass1 (get-bogen-mass bogen-auf winkel)) + (setq mass2 (get-bogen-mass bogen-ab winkel)) + (setq ab-erg (vf-winkel-AB winkel richtung mass1 mass2 deltaL deltaH + feste-hz 0.0 0.0 (abs aus-dz) (abs ein-dz) sin3 cos3)) + (if ab-erg + (progn + (setq A (car ab-erg) B (cadr ab-erg)) + ;; Fuellstueck-Fussabdruck vorab abziehen - siehe + ;; Kopfkommentar (NICHT gratis). + (setq A-frei (- A bogen-x1f bogen-x2f)) + (setq B-frei (- B bogen-z1f bogen-z2f)) + (setq winkel-eff (- winkel *vfk-gefaelle-winkel*)) + (setq sinEff (sin (* winkel-eff (/ pi 180.0))) + cosEff (cos (* winkel-eff (/ pi 180.0)))) + (if (> (abs sinEff) 0.0001) + (progn + (setq L_VF (/ (+ B-frei (* sin3 L_GF)) sinEff)) + (setq L_hor (- A-frei (* cos3 L_GF) (* cosEff L_VF))) + (if (and (numberp L_VF) (numberp L_hor) + (>= L_VF 0.0) (>= L_hor 0.0)) + (setq treffer (list winkel L_GF L_VF L_hor T)) + ) + ) + ) + ) + ) + ) + ) + ) + (if treffer treffer (list nil nil nil nil nil)) + ) + ) + ) + ) +) + ;; ============================================================ ;; TEIL 5: BERECHNE-WRAPPER (Schnittstelle fuer Registry) ;; ============================================================ diff --git a/cfg/Merkmalsstamm_in_Sivas.xlsx b/cfg/Merkmalsstamm_in_Sivas.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..ad4c3ba60b9326957db9d777ae3f74529d82bc28 GIT binary patch literal 66824 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 literal 0 HcmV?d00001 diff --git a/lang/de_DE.json b/lang/de_DE.json index dca1407..87e74ca 100644 --- a/lang/de_DE.json +++ b/lang/de_DE.json @@ -46,6 +46,7 @@ "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-prompt-hoehe-linienendpunkt-3": "\nHoehe (Z) des Linienendpunkts (Ab: %1 | Auf: %2 | gepickt: %3) [%3]: ", "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.", @@ -389,6 +390,10 @@ "vfl-stufe2-minh": "\n [Fixwert ohne GF-Bogen] Rest als gerader VF-Anteil (hoehenneutral): diese Aufteilung ergibt IMMER genau %1 mm Hoehenaenderung, unabhaengig von der Laenge - Zielhoehe verlangt aber %2 mm, passt also nur bei exakter Uebereinstimmung", "vfl-stufe2-minh-unmoeglich": "\n [Fixwert ohne GF-Bogen] 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-stufe3-start": "\n\n[Diagnose Stufe 3 - Winkel + horizontales Fuellstueck] Stufe 1 und Stufe 2 gescheitert, versuche Kombination aus steilem S-Bogen und horizontalem Reststueck ...", + "vfl-frage-stufe3-position": "\n\nDie Strecke braucht einen S-Bogen KOMBINIERT mit einem geraden horizontalen Stueck. Wo soll das horizontale Stueck sitzen?", + "vfl-opt-stufe3-vor": "\n 1 - Horizontales Stueck VOR dem S-Bogen", + "vfl-opt-stufe3-nach": "\n 2 - Horizontales Stueck NACH dem S-Bogen", "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-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-fuege-block-ein": "\n Fuege %1 ein ...", @@ -398,8 +403,10 @@ "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-endpunkt-3": "\nHoehe (Z) des Endpunkts (Ab: %1 | Auf: %2 | gepickt: %3) [%3]: ", "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-hoehe-kettenende-3": "\nHoehe (Z) des Kettenendes (ES-Element) (Ab: %1 | Auf: %2 | gepickt: %3) [%3]: ", "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-opt-richtung-auf": "\n 1 - Auf", diff --git a/lang/en_GB.json b/lang/en_GB.json index 67a507e..7c6797b 100644 --- a/lang/en_GB.json +++ b/lang/en_GB.json @@ -46,6 +46,7 @@ "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-prompt-hoehe-linienendpunkt-3": "\nHeight (Z) of the line end point (down: %1 | up: %2 | picked: %3) [%3]: ", "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.", @@ -390,6 +391,10 @@ "vfl-stufe2-minh": "\n [Fixed value without GF bend] Remainder as a straight VF section (height-neutral): this split ALWAYS results in exactly %1 mm of height change, regardless of length - but the target height calls for %2 mm, so this only fits on an exact match", "vfl-stufe2-minh-unmoeglich": "\n [Fixed value without GF bend] 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-stufe3-start": "\n\n[Diagnosis stage 3 - angle + horizontal filler] Stage 1 and stage 2 failed, trying a combination of a steep S-bend and a horizontal remainder piece ...", + "vfl-frage-stufe3-position": "\n\nThe section needs an S-bend COMBINED with a straight horizontal piece. Where should the horizontal piece go?", + "vfl-opt-stufe3-vor": "\n 1 - Horizontal piece BEFORE the S-bend", + "vfl-opt-stufe3-nach": "\n 2 - Horizontal piece AFTER the S-bend", "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-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).", @@ -398,8 +403,10 @@ "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-endpunkt-3": "\nHeight (Z) of the end point (down: %1 | up: %2 | picked: %3) [%3]: ", "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-hoehe-kettenende-3": "\nHeight (Z) of the chain end (ES element) (down: %1 | up: %2 | picked: %3) [%3]: ", "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-opt-richtung-auf": "\n 1 - Up",