fix: VF-Familie bei "Neue Linie BIS Kettenende" nutzt vfl-body-abschluss

Ersetzt den direkten vfl-vf-entscheidung-Aufruf (1300mm Budget, setzt
immer eine frische Umlenkstation voraus) durch Wiederverwendung von
vfl-body-abschluss + vfl-vf-ausgang-bauen - denselben Bausteinen, die
bereits "Option 3: Kettenende exakt am Zielpunkt" innerhalb einer
laufenden VF-Einheit nutzt (800mm Budget, keine Umlenkstation, volle
Stufe-1/2-Diagnose inkl. exakter Zielhoehe bleibt erhalten, da kein
GF1-Stumpf noetig ist).

Zusaetzlich: vfl-letzter-typ-familie korrigiert - letzter-typ="VF"
(gerade fertig gebaute VF-Einheit) zaehlt NICHT zur "VF"-Familie fuer
diesen Zweck, nur "Vario-Kurve" hat keine eigene Umlenkstation. Eine
neue VF-Einheit nach einer bereits fertigen braucht weiterhin eine
frische Umlenkstation (faellt jetzt korrekt auf die bisherige
Automatik zurueck).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Yuelin Wang
2026-09-12 01:33:01 +02:00
co-authored by Claude Sonnet 5
parent 38ee74ed3e
commit 0d9ec93623
+115 -60
View File
@@ -3486,12 +3486,16 @@
;; Vereinheitlichte Stufe-1(Winkel-Tabelle)/Stufe-2(horizontal+GF)-Entscheidung. ;; Vereinheitlichte Stufe-1(Winkel-Tabelle)/Stufe-2(horizontal+GF)-Entscheidung.
;; Genutzt von ZWEI Aufrufern mit unterschiedlichem Fest-Budget: ;; Genutzt von ZWEI Aufrufern mit unterschiedlichem Fest-Budget:
;; - vfl-body-zerlegung (Kettenende innerhalb einer laufenden VF-Einheit): ;; - vfl-body-zerlegung (Kettenende innerhalb einer laufenden VF-Einheit
;; ODER "Neue Linie BIS Kettenende" mit als VF-Familie erkanntem
;; Startpunkt, siehe linie-ende-familie/vfl-body-abschluss - beide Faelle
;; brauchen KEINE eigene Umlenkstation):
;; feste-hz=*vfk-feste-horizontal-kettenende* (800, nur Motor+Separator - ;; feste-hz=*vfk-feste-horizontal-kettenende* (800, nur Motor+Separator -
;; der Eingang ist zu diesem Zeitpunkt schon gebaut). ;; der Eingang ist zu diesem Zeitpunkt schon gebaut bzw. entfaellt).
;; - vfl-vf-entscheidung ("Neue Linie: Ab/Auf VF"/"BIS Kettenende", Eingang ;; - vfl-vf-entscheidung ("Neue Linie: Ab/Auf VF" bzw. "BIS Kettenende" mit
;; einer FRISCHEN VF-Einheit): feste-hz=*vfl-feste-horizontal* (1300, ;; NICHT eindeutig zuordenbarem Startpunkt, Eingang einer FRISCHEN
;; Umlenkstation+Separator+Motorstation). ;; VF-Einheit): feste-hz=*vfl-feste-horizontal* (1300, Umlenkstation+
;; Separator+Motorstation).
;; schon-flach: nur fuer den Kettenende-Fortsetzungsfall relevant (Frame kann ;; schon-flach: nur fuer den Kettenende-Fortsetzungsfall relevant (Frame kann
;; dort schon flach sein, siehe vfl-baue-horizontal-koerper) - am Eingang ;; dort schon flach sein, siehe vfl-baue-horizontal-koerper) - am Eingang
;; einer frischen VF-Einheit immer nil (Frame kommt frisch von der ;; einer frischen VF-Einheit immer nil (Frame kommt frisch von der
@@ -4452,9 +4456,16 @@
;; laufende Fortsetzung (kettenanfang=nil) ist der Vorgaengertyp bereits ;; laufende Fortsetzung (kettenanfang=nil) ist der Vorgaengertyp bereits
;; ohne KS_AUS-Scan bekannt. "Separator" zaehlt als GF-Familie (er folgt in ;; ohne KS_AUS-Scan bekannt. "Separator" zaehlt als GF-Familie (er folgt in
;; diesem Ablauf immer auf ein GF-Segment, siehe "Linie-GF"-Zweig). ;; diesem Ablauf immer auf ein GF-Segment, siehe "Linie-GF"-Zweig).
;; WICHTIG: "VF" (eine gerade FERTIG gebaute VF-Einheit, Motorstation schon
;; eingefuegt) zaehlt hier BEWUSST NICHT zur "VF"-Familie - eine neue
;; VF-Einheit direkt danach braucht sehr wohl eine frische Umlenkstation
;; (siehe vfl-eingang-modus-bestimmen: nur "Vario-Kurve" mappt dort auf
;; eingang-modus="keine", "VF" fehlt dort bewusst und faellt auf den
;; Default/volle-Eingang-Fall zurueck). Nur "Vario-Kurve" hat keine eigene
;; Umlenkstation/keinen Abschluss - eine zweite waere mechanisch sinnlos.
(defun vfl-letzter-typ-familie (letzter-typ) (defun vfl-letzter-typ-familie (letzter-typ)
(cond (cond
((member letzter-typ '("VF" "Vario-Kurve")) "VF") ((equal letzter-typ "Vario-Kurve") "VF")
((member letzter-typ '("GF" "Separator")) "GF") ((member letzter-typ '("GF" "Separator")) "GF")
(t nil) (t nil)
) )
@@ -4860,7 +4871,8 @@
sep-anzahl erg-bogen vf-eingang-lgf vf-eingang-modus sep-anzahl erg-bogen vf-eingang-lgf vf-eingang-modus
eingang-laenge winkel-hoehen-erg eingang-laenge winkel-hoehen-erg
bogen-mass fest-drop fest-laenge eingang-fertig bogen-mass fest-drop fest-laenge eingang-fertig
linie-ende-familie linie-ende-untermodus) linie-ende-familie linie-ende-untermodus
res3 save-eindx save-eindz es-gewuenscht)
;; "Zurueck"/"Abbrechen"-Flag ganz am Anfang zuruecksetzen (auch schon vor ;; "Zurueck"/"Abbrechen"-Flag ganz am Anfang zuruecksetzen (auch schon vor
;; der ersten Praeambel-Frage) - sonst wuerde ein von einem VORHERIGEN Lauf ;; der ersten Praeambel-Frage) - sonst wuerde ein von einem VORHERIGEN Lauf
;; noch gesetztes Flag (z.B. nach "Abbrechen") den allerersten vfl-in-*- ;; noch gesetztes Flag (z.B. nach "Abbrechen") den allerersten vfl-in-*-
@@ -5808,36 +5820,90 @@
((= wahl "Linie") ;; --- Neue Linie BIS Kettenende --- ((= wahl "Linie") ;; --- Neue Linie BIS Kettenende ---
;; GF/VF-Entscheidung: wird der Startpunkt eindeutig einer bestehenden ;; GF/VF-Entscheidung: wird der Startpunkt eindeutig einer bestehenden
;; VF- oder GF-Kette zugeordnet (linie-ende-familie, siehe unten), ;; VF- oder GF-Kette zugeordnet (linie-ende-familie), entscheidet DAS
;; entscheidet DAS die Bau-Logik (Stufe-1/2-Diagnose bzw. Endpunkt/ ;; die Bau-Logik - nur wenn nicht eindeutig, greift die automatische
;; Zielhoehe-Wahl) - nur wenn nicht eindeutig, greift weiterhin die ;; Machbarkeits-Entscheidung (vfl-segment-entscheidung).
;; automatische Machbarkeits-Entscheidung (vfl-segment-entscheidung). (setq kettenanfang (null frame))
;; Fahrtrichtung folgt dem vorherigen Element (Frame); nur das erste ;; Startpunkt-Typ erkennen: bei einer laufenden Fortsetzung ist der
;; Segment (frame=nil) definiert die Richtung frei. ;; Vorgaengertyp schon bekannt (letzter-typ); am echten Kettenanfang
;; OHNE AS-Element wird wie bei vfl-eingang-modus-bestimmen per
;; KS_AUS-Scan erkannt (Rueckgabe (hz . typ) - typ wird bei VF-Familie
;; unten fuer die Flach/3-Grad-Unterscheidung gebraucht). Steht schon
;; ein AS-Element (as-vorhanden), ist der Anfang per Definition
;; neutral/nicht zuordenbar.
(setq erg (if (and kettenanfang (not as-vorhanden))
(vfl-ks-aus-hz-an-punkt p-aktuell)
nil))
(setq linie-ende-familie
(if kettenanfang
(if erg (vfl-kette-typ-familie (cdr erg)) nil)
(vfl-letzter-typ-familie letzter-typ)))
(cond
;; --- Startpunkt als VF-Familie erkannt: KEINE eigene Umlenkstation
;; noetig (Vorgaenger Vario-Kurve/Umlenk/Motor/Bogen bzw. laufende
;; VF-Fortsetzung). Strukturell IDENTISCH zu "Option 3: Kettenende
;; exakt am Zielpunkt" INNERHALB einer laufenden VF-Einheit
;; (vfl-vf-einheit): derselbe Stufe-1/Stufe-2-Diagnose-Baustein
;; (vfl-body-abschluss, Budget OHNE Umlenkstation -
;; *vfk-feste-horizontal-kettenende*) + Motorstation/GF2
;; (vfl-vf-ausgang-bauen) + ES-Element - KEIN Rueckfall auf eine
;; reine Winkeltabelle noetig (anders als bei "Neue Linie: Ab/Auf
;; VF" mit reduziertem Eingang): hier gibt es keinen GF1-Stumpf,
;; dessen Wegfall die 2-Unbekannten-Loesung stoeren wuerde - die
;; volle Freiheit (Winkel + GF2) bleibt erhalten, exakte Zielhoehe
;; ist also weiterhin moeglich.
((equal linie-ende-familie "VF")
(if kettenanfang
;; Kettenanfang auf einer bestehenden VF-Kette: Frame
;; konstruieren (Vario-Kurve endet flach, alle anderen VF-Typen
;; auf der 3-Grad-Basis) - der eigentliche Endpunkt-Pick erfolgt
;; gleich INNERHALB von vfl-body-abschluss.
(setq frame (make-frame-from-dir p-aktuell
(hz-winkel->xu (car erg)
(if (equal (cdr erg) "KURVE") 0.0 *vfk-gefaelle-winkel*)))))
;; ES-Element hier gewuenscht (+ falls ja: Winkel/Seite) - wie bei
;; "Option 3" (vfl-vf-einheit) VOR vfl-body-abschluss erfragt, weil
;; der tatsaechliche ES-Fussabdruck (ein-dx/ein-dz) die
;; Streckenzerlegung beeinflusst.
(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 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 (/= 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)))
(setq res3 (vfl-body-abschluss frame (car (frame->hz-winkel frame)) (car frame)))
(if (not es-gewuenscht) (setq ein-dx save-eindx ein-dz save-eindz))
(if (null res3)
(if dbg-an
(dbgmsg "GEOMETRIE FEHLGESCHLAGEN: Linie (VF-Familie, Kettenende) nicht baubar"))
(progn
(setq anzahl-vf (+ anzahl-vf (nth 1 res3)))
(setq frame (vfl-vf-ausgang-bauen (nth 0 res3) (nth 2 res3) (nth 3 res3)))
(if es-gewuenscht
(setq frame (vfl-insert-es-element "VF" frame (car (frame->hz-winkel frame)) 0.0
(caddr (car frame)) es-seite)))
(vfl-ziel-report frame)
(setq letzter-typ "VF" p-aktuell (car frame) fertig t)
(if dbg-an
(dbgmsg (strcat "GEOMETRIE ERFOLG: Linie (VF-Familie, Kettenende) gebaut, neue Position="
(dbg-tostring p-aktuell))))
)
)
)
;; --- Startpunkt als GF-Familie erkannt ODER nicht eindeutig ---
(t
;; 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 (setq linie-mess (vfl-neue-linie-messen p-aktuell
(if frame (car (frame->hz-winkel frame)) nil))) (if frame (car (frame->hz-winkel frame)) nil)))
(if (null linie-mess) (progn (princ (ssg-text "vfl-abgebrochen")) (exit))) (if (null linie-mess) (progn (princ (ssg-text "vfl-abgebrochen")) (exit)))
(setq deltaL (car linie-mess) hz-neu (cadr linie-mess)) (setq deltaL (car linie-mess) hz-neu (cadr linie-mess))
(setq kettenanfang (null frame))
;; Startpunkt-Typ erkennen (VF/GF/nicht eindeutig): bei einer
;; laufenden Fortsetzung ist der Vorgaengertyp schon bekannt
;; (letzter-typ); am echten Kettenanfang OHNE AS-Element wird wie bei
;; vfl-eingang-modus-bestimmen per KS_AUS-Scan erkannt, ob der
;; gepickte Startpunkt auf einer bestehenden VF- oder GF-Kette liegt.
;; Steht schon ein AS-Element (as-vorhanden), ist der Anfang per
;; Definition neutral/nicht zuordenbar - dann bleibt die generische
;; Automatik (vfl-segment-entscheidung) unten aktiv. Genutzt weiter
;; unten, um bei erkannter Familie NICHT die generische Automatik zu
;; fragen, sondern direkt die passende (VF: Stufe-1/2-Diagnose; GF:
;; Endpunkt/Zielhoehe-Wahl wie "Neue Linie: GF") Logik zu verwenden.
(setq linie-ende-familie
(if kettenanfang
(if (not as-vorhanden)
(progn
(setq erg (vfl-ks-aus-hz-an-punkt p-aktuell))
(if erg (vfl-kette-typ-familie (cdr erg)) nil))
nil)
(vfl-letzter-typ-familie letzter-typ)))
(if (< deltaL 1.0) (if (< deltaL 1.0)
(princ (ssg-text "vfl-fehler-linie-zu-kurz")) (princ (ssg-text "vfl-fehler-linie-zu-kurz"))
(progn (progn
@@ -5916,28 +5982,20 @@
(list (rtos deltaL 2 0) (rtos deltaH 2 0)))) (list (rtos deltaL 2 0) (rtos deltaH 2 0))))
) )
) )
(cond (if (equal linie-ende-familie "GF")
;; --- Startpunkt als VF-Familie erkannt --- (progn
;; IMMER ueber die Stufe-1/Stufe-2-Diagnose bauen (auch
;; wenn der natuerliche Winkel zufaellig nahe 3 Grad
;; liegt) - vfl-segment-entscheidung wuerde in dem Fall
;; faelschlich eine reine GF waehlen, obwohl der
;; Vorgaenger eindeutig eine VF-Kette ist.
((equal linie-ende-familie "VF")
(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)))
;; --- Startpunkt als GF-Familie erkannt --- ;; --- Startpunkt als GF-Familie erkannt ---
;; Dieselbe Endpunkt-/Zielhoehe-Wahl wie "Neue Linie: GF" ;; Dieselbe Endpunkt-/Zielhoehe-Wahl wie "Neue
;; (Zweig A/B) statt der generischen Automatik - eine ;; Linie: GF" (Zweig A/B) statt der generischen
;; reine Gefaellestrecke kann nicht steigen. ;; Automatik - eine reine Gefaellestrecke kann
((equal linie-ende-familie "GF") ;; nicht steigen. Stufe-2-Diagnosevariablen
;; Stufe-2-Diagnosevariablen zuruecksetzen: dieser Zweig ;; zuruecksetzen: dieser Zweig ruft
;; ruft vfl-vf-entscheidung NICHT auf, ein evtl. noch ;; vfl-vf-entscheidung NICHT auf, ein evtl. noch
;; von einem frueheren Versuch gesetzter Text/Vorschlag ;; von einem frueheren Versuch gesetzter Text/
;; darf bei einem hier fehlschlagenden GF-Segment nicht ;; Vorschlag darf bei einem hier fehlschlagenden
;; faelschlich mit angezeigt werden (siehe gemeinsamer ;; GF-Segment nicht faelschlich mit angezeigt
;; "typ=nil"-Meldungsblock unten). ;; werden (siehe gemeinsamer "typ=nil"-
;; Meldungsblock unten).
(setq *vfl-stufe2-diagnose-text* nil) (setq *vfl-stufe2-diagnose-text* nil)
(setq *vfl-stufe2-minl-vorschlag* nil *vfl-stufe2-minh-vorschlag* nil) (setq *vfl-stufe2-minl-vorschlag* nil *vfl-stufe2-minh-vorschlag* nil)
(if (= richtung "Auf") (if (= richtung "Auf")
@@ -5954,9 +6012,6 @@
(ssg-text "vfl-gf-laenge-modus-opt-hoehe")) 1 (ssg-text "vfl-gf-laenge-modus-opt-hoehe")) 1
"vfl-gf-laenge-modus-header")) "vfl-gf-laenge-modus-header"))
(if (= linie-ende-untermodus "2") (if (= linie-ende-untermodus "2")
;; Zielhoehe fest, Winkel fix *vfk-gefaelle-winkel*
;; -> Laenge wird daraus berechnet (ersetzt die
;; oben gemessene/reservierte deltaL).
(progn (progn
(setq winkel *vfk-gefaelle-winkel*) (setq winkel *vfk-gefaelle-winkel*)
(setq deltaL (setq deltaL
@@ -5964,8 +6019,6 @@
(if (< deltaL 1.0) (if (< deltaL 1.0)
(setq typ nil) (setq typ nil)
(setq typ "GF" L_GF nil L_VF nil))) (setq typ "GF" L_GF nil L_VF nil)))
;; Endpunkt (deltaL) fest, Winkel aus deltaL +
;; Zielhoehe berechnen.
(progn (progn
(setq winkel (* (atan (/ deltaH deltaL)) (/ 180.0 pi))) (setq winkel (* (atan (/ deltaH deltaL)) (/ 180.0 pi)))
(if (> winkel *vfk-gefaelle-winkel*) (if (> winkel *vfk-gefaelle-winkel*)
@@ -5976,7 +6029,7 @@
) )
) )
;; --- Nicht eindeutig zuordenbar: bisherige Automatik --- ;; --- Nicht eindeutig zuordenbar: bisherige Automatik ---
(t (progn
(setq entscheidung (vfl-segment-entscheidung deltaL deltaH richtung)) (setq entscheidung (vfl-segment-entscheidung deltaL deltaH richtung))
(setq typ (nth 0 entscheidung) winkel (nth 1 entscheidung) (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)))
@@ -6069,6 +6122,8 @@
) )
) )
) )
)
)
;; Segment-XDATA: alle seit seg-lastEnt neu erzeugten Entities dieses ;; Segment-XDATA: alle seit seg-lastEnt neu erzeugten Entities dieses
;; Glieds mit ihrer eigenen Journal-Teilsequenz markieren (rein additiv, ;; Glieds mit ihrer eigenen Journal-Teilsequenz markieren (rein additiv,
;; siehe vfl-segment-xdata-sichern) - muss laufen, WAEHREND die Entities ;; siehe vfl-segment-xdata-sichern) - muss laufen, WAEHREND die Entities