refactor: Segment-Antworten als Werte, Modus-Dispatch im Spec-Pfad, Python liest Modus 2/3

Drei herausgeloeste Teile aus doc/todo/spec-modus2-3.md. Der Rest (volle
Spec-Grammatik fuer Modus 2/3, Schritte 3-5 und 7) bleibt bewusst liegen:
Modus-2/3-Journale sind durch ihren SEGS-Eintrag bereits selbst-enthalten
und ohne Zeichnung abspielbar, der Mehrwert einer Spec ist dort also klein.

1. lib/vf_journal_export.py trennt nach Marker. Modus 1 laeuft wie bisher
   durch die Grammatik; "linienzug2"/"linienzug3" werden als Rohtokens
   ausgegeben, im Format, das tests/test_linienzug.lsp einliest. Vorher lief
   die Modus-1-Grammatik auch ueber sie (der startswith-Filter laesst sie
   durch) und brach mit "Token 6: STEP erwartet" ab. Gegen die echte
   Zeichnung geprueft: die Ausgabe ist identisch mit der bisher von Hand
   erzeugten Testdatei.

2. vsp-bau-journal waehlt die Bau-Funktion jetzt anhand des Journals
   (vsp-bau-fn-fuer-journal): kein SEGS = Modus 1, SEGS + Formatmarke
   "m2v2" = Modus 2, SEGS ohne = Modus 3. Bewusst abgeleitet statt als
   zusaetzliches Argument - die Funktion hat zwei Aufrufer, und AutoLISP
   verlangt exakte Argumentzahl. Die Ableitung kann der Datenlage auch nicht
   widersprechen, weil sie genau das Journal liest, das abgespielt wird.

3. Die Segment-Klassifizierung in Modus 2 journalisiert WERTE statt
   Menue-Ziffern: Geradentyp "gf"/"vf", Bogentyp "gf-bogen"/"vario-kurve",
   Variante "aussen"/"innen". Konsole UND Wizard-Dialoge legen dieselben
   Werte ab. Damit deutet ein Umsortieren der Optionen keine gespeicherte
   Kette mehr um - dasselbe Risiko, das beim Lauf-Anfang (833a4b6) real
   wurde. Bestandsketten laufen ueber Alt-Tabellen weiter, ein unbekannter
   Wert bricht mit Segmentnummer ab statt zu raten.

   Statt dreier fast gleicher Normalisierer gibt es einen gemeinsamen
   vfl-wert-norm; vfl-m2-anfang-norm delegiert jetzt dorthin.

   Nebeneffekt: Bogentyp und Variante benutzten BEIDE "1"/"2" und waren im
   Journal nicht zu unterscheiden - deshalb brauchte es die Formatmarke zur
   Erkennung von Alt-Journalen. Mit eigenen Wertevorraeten ist das erledigt;
   ein Test prueft, dass die Mengen disjunkt bleiben.

Geprueft: TEST_UNIT 883/883 (17 neue Tests). TEST_LINIENZUG_MODUS2 beide
Varianten OK - und zwar mit den AUFGEZEICHNETEN Journalen, die bei den
Segment-Fragen noch die alten Ziffern tragen. Genau darum wurden sie nicht
auf die neuen Werte umgeschrieben: sie sind der Nachweis der
Abwaertskompatibilitaet.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-10-27 12:09:05 +01:00
parent e3c7fb0d25
commit 4a19ac0ae0
6 changed files with 230 additions and 30 deletions
+75 -26
View File
@@ -1984,10 +1984,12 @@
(unload_dialog dat)
(if (= ergebnis 1)
(if (= gtyp "0")
;; GF + Neigung + Separator VOR/NACH (Ja/Nein je "1"/"0")
;; GF + Neigung + Separator VOR/NACH (Ja/Nein je "1"/"0").
;; Der Typ geht als WERT in die Queue (*vfl-m2-linie-werte*), die
;; Separator-Antworten bleiben Ja/Nein-Ziffern wie ueberall sonst.
(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)
(list "gf" (atof gwert) (if (= gsepvor "1") "1" "2") (if (= gsepnach "1") "1" "2")))
(vflw-pending-push-all (list "vf")))))) ; VF (keine Neigung/Separator)
(princ))
;; --- Modus 3, Segment "Gerade": Typ (GF/VF-Ab/VF-Auf/VF-Hor) + Wert ---
@@ -2090,10 +2092,12 @@
(unload_dialog dat)
(if (= ergebnis 1)
(if (and (= gtyp "1") vario-erlaubt)
;; Vario-Kurve: "2" + Variante ("1"=aussen / "2"=innen; Index+1)
(vflw-pending-push-all (list "2" (itoa (1+ (atoi gvariante)))))
;; GF-Bogen (oder Vario unzulaessig): "1" (keine Variante)
(vflw-pending-push-all (list "1"))))))
;; Vario-Kurve + Variante, beide als WERT (*vfl-m2-bogen-werte* /
;; *vfl-m2-variante-werte*) statt als Menue-Index.
(vflw-pending-push-all
(list "vario-kurve" (if (= gvariante "1") "innen" "aussen")))
;; GF-Bogen (oder Vario unzulaessig): keine Variante
(vflw-pending-push-all (list "gf-bogen"))))))
(princ))
;; ============================================================
@@ -5337,12 +5341,36 @@
;; nil heisst fuer den Aufrufer: ABBRECHEN. Ein Rueckfall auf eine geratene
;; Anfangsvariante waere genau der lautlose Fehlaufbau, den die Wertumstellung
;; verhindern soll - lieber ein harter Abbruch mit Fundstelle.
(defun vfl-m2-anfang-norm (wert / tr)
;; Allgemeiner Normalisierer fuer selbstbeschreibende Antwortwerte.
;; werte = heutige Werte in Optionsreihenfolge, alt = Alist Alt-Ziffer -> Wert
;; (nur fuer Bestandsketten). Rueckgabe nil = UNBEKANNT; der Aufrufer bricht
;; dann ab, statt eine Variante zu raten - ein geratener Wert waere ein
;; lautloser Fehlaufbau. Alt-Ziffern und neue Werte sind disjunkt, die
;; Zuordnung also eindeutig.
(defun vfl-wert-norm (wert werte alt / tr)
(cond
((not (and wert (= (type wert) 'STR))) nil)
((member wert *vfl-m2-anfang-werte*) wert)
((setq tr (assoc wert *vfl-m2-anfang-alt*)) (cdr tr))
(t nil)))
((not (and wert (= (type wert) 'STR))) nil)
((member wert werte) wert)
((setq tr (assoc wert alt)) (cdr tr))
(t nil)))
(defun vfl-m2-anfang-norm (wert)
(vfl-wert-norm wert *vfl-m2-anfang-werte* *vfl-m2-anfang-alt*))
;; --- Segment-Klassifizierung (Modus 2): Werte statt Menue-Ziffern ---
;; Dieselbe Begruendung wie beim Lauf-Anfang: die Ziffer haengt an der
;; Position im Menue, der Wert an seiner Bedeutung. Ein Umsortieren der
;; Optionen deutete sonst jede gespeicherte Kette still um.
;; Zusatznutzen hier: Typ und Variante benutzten BEIDE "1"/"2" und waren im
;; Journal nicht auseinanderzuhalten (siehe Kommentar bei m2-format-neu) -
;; mit eigenen Wertevorraeten ist das erledigt.
;; Alt -> Neu (nur fuer Bestandsketten), jeweils die alte Optionsreihenfolge.
(setq *vfl-m2-linie-werte* '("gf" "vf"))
(setq *vfl-m2-linie-alt* '(("1" . "gf") ("2" . "vf")))
(setq *vfl-m2-bogen-werte* '("gf-bogen" "vario-kurve"))
(setq *vfl-m2-bogen-alt* '(("1" . "gf-bogen") ("2" . "vario-kurve")))
(setq *vfl-m2-variante-werte* '("aussen" "innen"))
(setq *vfl-m2-variante-alt* '(("1" . "aussen") ("2" . "innen")))
;; Punkt um eine Strecke ENTGEGEN der Fahrtrichtung zurueckversetzen.
;; laenge-planar = horizontale (Grundriss-)Laenge, winkel = Gefaelle in Grad
@@ -11663,10 +11691,17 @@
(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 antwort
(vfl-wert-norm
(vfl-menu-strwert (ssg-text "prompt-wahl-1-2")
(list "GF (Neigungswinkel)" "VF (Bruecke)")
*vfl-m2-linie-werte* 1 "vfl-m3-typ-gerade")
*vfl-m2-linie-werte* *vfl-m2-linie-alt*))
(if (null antwort)
(progn (vfl-meldung (ssg-textf "vfl-m2-segwert-unbekannt"
(list (itoa (1+ i)) (vfl-replay-kette-text))))
(exit)))
(if (= antwort "vf")
(progn
(setq plan (cons (list "Linie" hz laenge "VF" nil) plan))
(setq nach-vf t))
@@ -11719,21 +11754,35 @@
;; Plan-Phase (m2-format-neu) - am WERT der naechsten Antwort ginge es
;; nicht, denn Typ und Variante benutzen beide "1"/"2".
(if (and nach-vf (not m2-format-neu))
(setq antwort "2") ; Alt-Journal: Vario-Kurve war erzwungen
(setq antwort "vario-kurve") ; Alt-Journal: Vario-Kurve war erzwungen
(progn
(princ (ssg-text "vfl-m3-typ-bogen"))
(setq antwort (vfl-menu (ssg-text "prompt-wahl-1-2")
(list "GF-Bogen" "Vario-Kurve")
(if nach-vf 2 1)
"vfl-m3-typ-bogen"))))
(setq antwort
(vfl-wert-norm
(vfl-menu-strwert (ssg-text "prompt-wahl-1-2")
(list "GF-Bogen" "Vario-Kurve")
*vfl-m2-bogen-werte* (if nach-vf 2 1) "vfl-m3-typ-bogen")
*vfl-m2-bogen-werte* *vfl-m2-bogen-alt*))
(if (null antwort)
(progn (vfl-meldung (ssg-textf "vfl-m2-segwert-unbekannt"
(list (itoa (1+ i)) (vfl-replay-kette-text))))
(exit)))))
(setq nach-vf nil)
(if (= antwort "2")
(if (= antwort "vario-kurve")
(progn
(princ (ssg-text "vfl-m3-variante-frage"))
(setq kv-variante (if (= (vfl-menu (ssg-text "vfl-prompt-wahl-1-2-def2")
(list (ssg-text "vfl-variante-aussen") (ssg-text "vfl-variante-innen")) 2
"vfl-m3-variante-frage")
"1") "aussen" "innen"))
;; Die Variante IST schon ein Domaenenwert ("aussen"/"innen") - sie
;; wandert jetzt unveraendert ins Journal, statt als Index "1"/"2".
(setq kv-variante
(vfl-wert-norm
(vfl-menu-strwert (ssg-text "vfl-prompt-wahl-1-2-def2")
(list (ssg-text "vfl-variante-aussen") (ssg-text "vfl-variante-innen"))
*vfl-m2-variante-werte* 2 "vfl-m3-variante-frage")
*vfl-m2-variante-werte* *vfl-m2-variante-alt*))
(if (null kv-variante)
(progn (vfl-meldung (ssg-textf "vfl-m2-segwert-unbekannt"
(list (itoa (1+ i)) (vfl-replay-kette-text))))
(exit)))
(setq plan (cons (list "Bogen" hz laenge bwinkel bseite "Vario-Kurve" kv-variante) plan))
(setq nach-kurve t)) ; naechste Gerade automatisch VF
(progn
+24 -1
View File
@@ -936,6 +936,29 @@
;; sid = Kennung im Record, dim = "2D"/"3D" oder nil (Sitzung),
;; fehler = Liste der Spec-Fehler (bei nil-Journal die Begruendung).
;; Erwartet den Headless-Rahmen (vsp-headless-an) beim Aufrufer.
;; Bau-Funktion AUS DEM JOURNAL ableiten (Rueckgabe: Funktions-Symbol).
;; Bewusst abgeleitet statt als zusaetzliches Argument: vsp-bau-journal hat
;; zwei Aufrufer, und AutoLISP verlangt exakte Argumentzahl - eine erweiterte
;; Signatur muesste jeden davon nachziehen (siehe CLAUDE.md). Die Ableitung
;; kann der Datenlage ausserdem nicht widersprechen, weil sie GENAU das
;; Journal liest, das gleich abgespielt wird.
;;
;; Unterscheidung:
;; kein SEGS -> Modus 1 (Fragenfluss, Menue-Codes)
;; SEGS + STR "m2v2" -> Modus 2 (die Formatmarke schreibt nur
;; vf-linienzug-modus2, vfl-m2-formatmarke)
;; SEGS ohne "m2v2" -> Modus 3
;; Ein Fehlgriff faellt sofort auf: der Ergebnis-Record meldet dann offene
;; Eingaben bzw. glieder_soll <> glieder_ist.
(defun vsp-bau-fn-fuer-journal (journal)
(cond
((not (vfl-journal-hat-segs-p journal)) 'vf-linienzug-modus)
((vl-some (function (lambda (e)
(and (equal (car e) "STR") (equal (cdr e) "m2v2"))))
journal)
'vf-linienzug-modus2)
(t 'vf-linienzug-modus3)))
(defun vsp-bau-journal (sid journal dim fehler / rec vor-ent alt-error err
offen hl meld ist-glieder soll-glieder diff
ist-journal jdiff ent ed)
@@ -975,7 +998,7 @@
(setq alt-error *error*)
(vfl-journal-reset)
(vfl-journal-replay-start journal)
(setq err (vl-catch-all-apply 'vf-linienzug-modus '()))
(setq err (vl-catch-all-apply (vsp-bau-fn-fuer-journal journal) '()))
(setq offen (vsp-queue-rest))
;; Diagnose VOR dem Reset sichern (vfl-journal-reset loescht sie).
(setq ist-journal (reverse *vfl-journal*))