From cf626d721e70e094b22deafe442cc5daeb5fa0b9 Mon Sep 17 00:00:00 2001 From: Yuelin Wang Date: Tue, 27 Oct 2026 11:42:31 +0100 Subject: [PATCH] test: Linienzug Modus 2 als Journal-Replay, Richtungsfrage in den Modus-1-Skripten Neu: TEST_LINIENZUG_MODUS2 spielt zwei echte Laeufe DERSELBEN Strecke ab - einmal mit der 90-Grad-Ecke als Vario-Kurve (waagerecht, mit flacher Zone), einmal als GF-Bogen (geneigt, ohne flache Zone). Beide muessen quer zur ES-KS_AUS-Achse ~0 und dZ ~0 erreichen; laengs darf um die Ausladung des ES-Elements abweichen (Leitsatz, doc/VarioFoerderer_Linienzug_Prinzipien.md Abschnitt 0). Gemessen am 2026-10-27: beide 0.2 mm quer, dZ 0. Das Paar ist Absicht. Die beiden Varianten laufen durch VERSCHIEDENE Zweige, und erst ihr Vergleich hat die Fehler dieser Woche sichtbar gemacht - der ES-Fussabdruck wurde vom falschen Segment abgezogen, was sich nur in der GF-Bogen-Variante zeigte (878 mm). Einen der beiden zu loeschen nimmt dem Test seinen Wert. Anders als die Modus-1-Faelle braucht Modus 2 KEINE Mocks und KEINEN gezeichneten Pfad: sein Journal traegt einen SEGS-Eintrag mit der kompletten Segment-Essenz, ist also von den Original-Objekten unabhaengig. Der Test spielt daher das echte, mit lib/vf_journal_export.py aus der Zeichnung gelesene Journal ab. Jeder Eintrag fuehrt seine Art mit (PT/STR/REAL/SEGS), womit die Verschiebe-Anfaelligkeit des Mock-Replays entfaellt. Dazu: vf-linienzug-modus2 legt die gemessene Abweichung in *vfl-m2-abweichung* ab (laengs quer dz). Sonst muesste ein Test sie aus der Konsolenausgabe zurueckparsen. Ausserdem behoben: beide Modus-1-Testskripte brachen mit "bad argument type <\"5\"> expected at [cdr]" ab. Commit fb56794 (Rueckwaerts-Bau) hat eine Frage VOR die AS-Praeambel gesetzt. Fuer Journale ist sie abwaertskompatibel, fuer die MOCK-Skripte nicht: der Mock beantwortet jede getstring-Abfrage aus der Queue, eine fehlende Antwort verschiebt also alles Folgende um eine Position. Beide Dateien haben den Eintrag jetzt, mit Begruendung im Kommentar. Menue: Tests -> Foerderer-Linienzug ruft den neuen Fall mit auf. Die kompilierte SSG_LIB.cui ist bewusst NICHT mit committet - ihre Aenderung besteht groesstenteils aus fremden Eintraegen und verschobenen UIDs; BricsCAD erzeugt sie beim naechsten _MENULOAD neu aus der .mnu. Co-Authored-By: Claude Opus 5 --- Lisp/vf_linienzug.lsp | 7 + menu/SSG_LIB.mnu | 2 +- tests/test_linienzug.lsp | 143 ++++++++++++++++++ tests/testdata/linienzug_modus2_gfbogen.json | 119 +++++++++++++++ .../testdata/linienzug_modus2_variokurve.json | 107 +++++++++++++ tests/testdata/linienzug_tests.json | 5 + tests/testdata/linienzug_tests_stufe2.json | 5 + 7 files changed, 387 insertions(+), 1 deletion(-) create mode 100644 tests/testdata/linienzug_modus2_gfbogen.json create mode 100644 tests/testdata/linienzug_modus2_variokurve.json diff --git a/Lisp/vf_linienzug.lsp b/Lisp/vf_linienzug.lsp index 6828ad9..5201c3f 100644 --- a/Lisp/vf_linienzug.lsp +++ b/Lisp/vf_linienzug.lsp @@ -12628,6 +12628,13 @@ (setq quer-wert (+ (* (- (car ist-ende) (car soll-ende)) (- dir-y)) (* (- (cadr ist-ende) (cadr soll-ende)) dir-x))) (princ (ssg-textf "vfl-m3-laengs-quer" (list (rtos laengs-wert 2 1) (rtos quer-wert 2 1)))) + ;; Gemessene Abweichung fuer automatische Tests ablegen (laengs quer dz). + ;; Die Werte sind sonst Lokale dieser Funktion und waeren nur aus der + ;; Konsolenausgabe zu lesen - ein Test muesste sie aus Text zurueckparsen. + ;; Quer und dz sind die Pflichtgroessen (muessen ~0 sein), laengs ist die + ;; zulaessige Ausladung des ES-Elements. + (setq *vfl-m2-abweichung* + (list laengs-wert quer-wert (- (caddr ist-ende) (caddr soll-ende)))) (princ (ssg-text "vfl-m3-achse-hinweis")) ;; Der Querversatz ist KEIN Fehler, sondern die Geometrie des ES-Blocks: ;; das Ausschleuselement wandert beim Schwenken zur Seite. Ihn als diff --git a/menu/SSG_LIB.mnu b/menu/SSG_LIB.mnu index 7bf1be4..50ea18e 100644 --- a/menu/SSG_LIB.mnu +++ b/menu/SSG_LIB.mnu @@ -179,7 +179,7 @@ [--] [Kreisel]^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_kreisel.lsp")) (c:TEST_KREISEL) [Foerderer]^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_foerderer.lsp")) (c:TEST_FOERDERER) -[Foerderer-Linienzug]^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_linienzug.lsp")) (c:TEST_LINIENZUG) (c:TEST_LINIENZUG_STUFE2) +[Foerderer-Linienzug]^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_linienzug.lsp")) (c:TEST_LINIENZUG) (c:TEST_LINIENZUG_STUFE2) (c:TEST_LINIENZUG_MODUS2) [Omniflo]^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_omniflo.lsp")) (c:TEST_OMNIFLO) [Omniflo Strecke]^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_omniflo_strecke.lsp")) (c:TEST_OMNIFLO_STRECKE) [Gefaellestrecke]^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_gefaellestrecke.lsp")) (c:TEST_GEFAELLESTRECKE) diff --git a/tests/test_linienzug.lsp b/tests/test_linienzug.lsp index 06c6d11..1b4f820 100644 --- a/tests/test_linienzug.lsp +++ b/tests/test_linienzug.lsp @@ -264,3 +264,146 @@ (tlz-run-datei json-datei "LZ_Stufe2_Kettenende" "TEST_LINIENZUG_STUFE2") (princ) ) + + +;; ============================================================ +;; MODUS 2 (aus 3D-Linie mit Zielhoehe) - Replay zweier echter Laeufe +;; ============================================================ +;; Anders als die Modus-1-Faelle oben braucht Modus 2 KEINE Mocks und KEINEN +;; gezeichneten Pfad: sein Journal traegt einen SEGS-Eintrag mit der kompletten +;; Segment-Essenz (Typ, Richtung, Laenge, Eckwinkel, Seite, Start/Ende), ist +;; also von den Original-Objekten unabhaengig - dieselbe Eigenschaft, auf der +;; schon vfl-konvertiere-ent beruht (vfl-journal-hat-segs-p). Der Test spielt +;; daher das echte, aus der Zeichnung ausgelesene Journal ab. +;; +;; Die beiden Faelle sind BEWUSST ein Paar: derselbe Pfad, nur die 90-Grad-Ecke +;; einmal als Vario-Kurve (waagerecht) und einmal als GF-Bogen (geneigt). Sie +;; laufen durch verschiedene Zweige - mit und ohne flache Zone - und genau der +;; VERGLEICH hat am 2026-10-26/27 Fehler aufgedeckt, die ein einzelner Lauf +;; nicht gezeigt haette (ES-Fussabdruck am falschen Segment: 878 mm nur in der +;; GF-Bogen-Variante). Einen davon zu loeschen nimmt dem Test seinen Wert. +;; +;; Aufgezeichnet mit lib/vf_journal_export.py aus einem echten BricsCAD-Lauf. +;; Pruefkriterium (Nutzer-Vorgabe 2026-10-26): quer zur ES-KS_AUS-Achse und dZ +;; MUESSEN ~0 sein, laengs DARF abweichen (Ausladung des ES-Elements). + +(setq *tlz-m2-toleranz* 1.0) ; mm; 0.2 ist die Messaufloesung der Blockmasse + +;; Wert als String - eigene Kopie statt hmrec:als-string aus +;; test_hm_recformat.lsp: diese Datei soll fuer sich allein ladbar bleiben. +(defun tlz-m2-str (v) + (cond ((null v) "") + ((= (type v) 'STR) v) + ((= (type v) 'INT) (itoa v)) + ((= (type v) 'REAL) (rtos v 2 6)) + (T (vl-princ-to-string v)))) + +;; Ein JSON-Record -> Journal-Eintrag (kind . wert), nil bei Metadaten-Zeile. +(defun tlz-m2-eintrag->journal (e / art) + (setq art (ssg-val e "art")) + (cond + ((null art) nil) + ((= art "PT") (cons "PT" (list (float (ssg-val e "x")) + (float (ssg-val e "y")) + (float (ssg-val e "z"))))) + ((= art "REAL") (cons "REAL" (float (ssg-val e "wert")))) + ((= art "INT") (cons "INT" (fix (ssg-val e "wert")))) + ;; SEGS traegt im Journal eine LISTE von Segment-Records, nicht den + ;; String - genau diese Umwandlung macht auch der XDATA-Decoder + ;; (vfl-journal-string->entry). Ohne sie bekommt vfl-in-segmente den + ;; Rohstring und der erste mapcar darauf stirbt (real 2026-10-27). + ((= art "SEGS") (cons "SEGS" (vfl-string->segs (tlz-m2-str (ssg-val e "wert"))))) + (T (cons art (tlz-m2-str (ssg-val e "wert")))))) + +;; Einen Modus-2-Fall abspielen. Rueckgabe: (status laengs quer dz offen). +(defun tlz-m2-run (json-datei test-id anzeige / + daten journal meta offen err status abw j + old-headless old-gui quer dz laengs) + (if (or (not *lib-initialized*) (null bogen-auf)) (init-bibliothek)) + (princ (strcat "\n\n--- " anzeige " ---")) + ;; Vorbelegen, damit der Ergebnis-Record auch im Fehlerzweig Zahlen hat - + ;; sonst stirbt das abschliessende rtos an nil (real passiert 2026-10-27). + (setq laengs 0.0 quer 999.0 dz 999.0 offen 0 status "FEHLER") + (setq daten (ssg-load-json json-datei)) + (if (null daten) + (progn (princ (strcat "\n FEHLER: Testdaten fehlen: " json-datei)) + (setq status "FEHLER")) + (progn + (setq meta (car daten)) + (setq journal '()) + (foreach e daten + (setq j (tlz-m2-eintrag->journal e)) + (if j (setq journal (cons j journal)))) + (setq journal (reverse journal)) + (princ (strcat "\n Journal-Eintraege: " (itoa (length journal)))) + (if meta (princ (strcat "\n Szenario: " (ssg-val meta "kurz")))) + + (ssg-start anzeige '(("OSMODE") ("ATTREQ") ("ATTDIA"))) + (setvar "OSMODE" 0) (setvar "ATTREQ" 0) (setvar "ATTDIA" 0) + ;; GUI aus (keine Wizard-Dialoge) UND headless: eine erschoepfte + ;; Replay-Queue ist damit ein harter Abbruch MIT Fundstelle statt eines + ;; stillen Rueckfalls auf eine Live-Abfrage, die im Batch haengen wuerde. + (setq old-gui *ssg-gui-aus* old-headless *vfl-headless*) + (if (car (atoms-family 1 '("SSG-GUI-AUS"))) (ssg-gui-aus)) + (setq *vfl-headless* T *vfl-m2-abweichung* nil) + + (vfl-journal-replay-start journal) + (setq err (vl-catch-all-apply 'vf-linienzug-modus2 '())) + + (setq *vfl-headless* old-headless *ssg-gui-aus* old-gui) + (if (car (atoms-family 1 '("SSG-GUI-AN"))) (if (null old-gui) (ssg-gui-an))) + + (setq offen (length *vfl-replay-queue*)) + (setq abw (if (boundp '*vfl-m2-abweichung*) *vfl-m2-abweichung* nil)) + (setq laengs (if abw (car abw) 0.0) + quer (if abw (cadr abw) 999.0) + dz (if abw (caddr abw) 999.0)) + (cond + ((vl-catch-all-error-p err) + (setq status "FEHLER") + (princ (strcat "\n FEHLER: " (vl-catch-all-error-message err)))) + ((null abw) + (setq status "FEHLER") + (princ "\n FEHLER: keine Abweichung gemessen (Bau nicht beendet).")) + (T + (princ (strcat "\n laengs=" (rtos laengs 2 1) + " quer=" (rtos quer 2 1) + " dZ=" (rtos dz 2 1) " mm")) + (if (> offen 0) + (princ (strcat "\n WARNUNG: " (itoa offen) + " Journal-Eintraege NICHT verbraucht (Ablauf weicht ab)."))) + (setq status + (if (and (<= (abs quer) *tlz-m2-toleranz*) + (<= (abs dz) *tlz-m2-toleranz*) + (= offen 0)) + "OK" "ABWEICHUNG")) + (princ (strcat "\n -> " status + " (Soll: |quer| und |dZ| <= " (rtos *tlz-m2-toleranz* 2 1) + " mm, laengs frei)")))) + (ssg-end))) + (list status laengs quer dz offen)) + +(defun c:TEST_LINIENZUG_MODUS2 ( / basis a b) + ;; Doppelte Backslashes: "\t" waere in AutoLISP ein TABULATOR, der Pfad + ;; wuerde zu "...dxfmakrosestsestdata" (real passiert 2026-10-27). + (setq basis (strcat (getenv "DXFMAKRO") "\\tests\\testdata\\")) + (princ "\n================================================================") + (princ "\n TEST_LINIENZUG_MODUS2 - zwei Varianten DERSELBEN Strecke") + (princ "\n================================================================") + (setq a (tlz-m2-run (strcat basis "linienzug_modus2_variokurve.json") + "LZ_M2_variokurve" "Variante A: Ecke = Vario-Kurve")) + (setq b (tlz-m2-run (strcat basis "linienzug_modus2_gfbogen.json") + "LZ_M2_gfbogen" "Variante B: Ecke = GF-Bogen")) + (princ "\n\n================================================================") + (princ (strcat "\n ERGEBNIS: Variante A " (car a) " | Variante B " (car b))) + (princ "\n================================================================") + ;; Ergebnis fuer run-all (Konvention wie linienzug:export-results) + (setq *linienzug-m2-test-results* + (strcat " { \"test_id\": \"LZ_M2_variokurve\", \"status\": \"" (car a) + "\", \"quer_mm\": " (rtos (caddr a) 2 2) + ", \"dz_mm\": " (rtos (cadddr a) 2 2) " },\n" + " { \"test_id\": \"LZ_M2_gfbogen\", \"status\": \"" (car b) + "\", \"quer_mm\": " (rtos (caddr b) 2 2) + ", \"dz_mm\": " (rtos (cadddr b) 2 2) " }")) + (princ) +) diff --git a/tests/testdata/linienzug_modus2_gfbogen.json b/tests/testdata/linienzug_modus2_gfbogen.json new file mode 100644 index 0000000..e190d01 --- /dev/null +++ b/tests/testdata/linienzug_modus2_gfbogen.json @@ -0,0 +1,119 @@ +[ + { + "beschreibung": "Linienzug Modus 2, Variante B: 90-Grad-Ecke als GF-BOGEN (geneigt eingebaut). Deckt die Neigungs-Projektion der Eck-Korrektur ab (vfl-projiziere-neigung) und den Zweig OHNE flache Zone, in dem der ES-Fussabdruck frueher faelschlich vom VF-Lauf abgezogen wurde (878 mm). Aufgezeichnet 2026-10-27 aus einem echten BricsCAD-Lauf.", + "test_id": "LZ_M2_gfbogen", + "kurz": "Ecke als GF-Bogen", + "erwartung_quer_mm": 0, + "erwartung_dz_mm": 0, + "erwartung_laengs_mm": 105, + "erwartung_hinweis": "quer zur ES-KS_AUS-Achse MUSS ~0 sein und dZ ~0; laengs darf abweichen - das ist die Ausladung des ES-Elements (siehe doc/VarioFoerderer_Linienzug_Prinzipien.md, Abschnitt 0)." + }, + { + "art": "PT", + "x": 6373.07914, + "y": 6047.735576, + "z": 0.0 + }, + { + "art": "REAL", + "wert": 0.0 + }, + { + "art": "STR", + "wert": "1" + }, + { + "art": "STR", + "wert": "90" + }, + { + "art": "STR", + "wert": "1" + }, + { + "art": "PT", + "x": 17373.07914, + "y": -267.387621, + "z": 184.3 + }, + { + "art": "REAL", + "wert": 184.3 + }, + { + "art": "STR", + "wert": "1" + }, + { + "art": "STR", + "wert": "30" + }, + { + "art": "STR", + "wert": "2" + }, + { + "art": "SEGS", + "wert": "Linie|0|9700|0|links|6373.07914|6047.735576|16073.07914|6047.735576;Bogen|0|707.106781|90|rechts|16073.07914|6047.735576|16573.07914|5547.735576;Linie|-90|4295.507955|0|links|16573.07914|5547.735576|16573.07914|1252.227621;Bogen|-90|258.819045|30|links|16573.07914|1252.227621|16640.066438|1002.227621;Linie|-60|1466.025404|0|links|16640.066438|1002.227621|17373.07914|-267.387621" + }, + { + "art": "STR", + "wert": "m2v2" + }, + { + "art": "STR", + "wert": "2" + }, + { + "art": "STR", + "wert": "1" + }, + { + "art": "STR", + "wert": "1" + }, + { + "art": "REAL", + "wert": 3.0 + }, + { + "art": "STR", + "wert": "2" + }, + { + "art": "STR", + "wert": "2" + }, + { + "art": "STR", + "wert": "1" + }, + { + "art": "STR", + "wert": "1" + }, + { + "art": "REAL", + "wert": 3.0 + }, + { + "art": "STR", + "wert": "2" + }, + { + "art": "STR", + "wert": "2" + }, + { + "art": "STR", + "wert": "mit-gf1" + }, + { + "art": "INT", + "wert": 1 + }, + { + "art": "STR", + "wert": "1" + } +] diff --git a/tests/testdata/linienzug_modus2_variokurve.json b/tests/testdata/linienzug_modus2_variokurve.json new file mode 100644 index 0000000..9ee8aed --- /dev/null +++ b/tests/testdata/linienzug_modus2_variokurve.json @@ -0,0 +1,107 @@ +[ + { + "beschreibung": "Linienzug Modus 2, Variante A: 90-Grad-Ecke als VARIO-KURVE (waagerecht eingebaut), Segment 3 dadurch automatisch VF. Deckt die flache Zone ab (Abschluss-Fussabdruck Bogen+Motorstation) und die Eck-Korrektur von 93.8 mm je Nachbargerade. Aufgezeichnet 2026-10-27 aus einem echten BricsCAD-Lauf.", + "test_id": "LZ_M2_variokurve", + "kurz": "Ecke als Vario-Kurve", + "erwartung_quer_mm": 0, + "erwartung_dz_mm": 0, + "erwartung_laengs_mm": 105, + "erwartung_hinweis": "quer zur ES-KS_AUS-Achse MUSS ~0 sein und dZ ~0; laengs darf abweichen - das ist die Ausladung des ES-Elements (siehe doc/VarioFoerderer_Linienzug_Prinzipien.md, Abschnitt 0)." + }, + { + "art": "PT", + "x": 20702.423223, + "y": 6047.735576, + "z": 0.0 + }, + { + "art": "REAL", + "wert": 0.0 + }, + { + "art": "STR", + "wert": "1" + }, + { + "art": "STR", + "wert": "90" + }, + { + "art": "STR", + "wert": "1" + }, + { + "art": "PT", + "x": 31702.423223, + "y": -267.387621, + "z": 184.3 + }, + { + "art": "REAL", + "wert": 184.3 + }, + { + "art": "STR", + "wert": "1" + }, + { + "art": "STR", + "wert": "30" + }, + { + "art": "STR", + "wert": "2" + }, + { + "art": "SEGS", + "wert": "Linie|0|9700|0|links|20702.423223|6047.735576|30402.423223|6047.735576;Bogen|0|707.106781|90|rechts|30402.423223|6047.735576|30902.423223|5547.735576;Linie|-90|4295.507955|0|links|30902.423223|5547.735576|30902.423223|1252.227621;Bogen|-90|258.819045|30|links|30902.423223|1252.227621|30969.410521|1002.227621;Linie|-60|1466.025404|0|links|30969.410521|1002.227621|31702.423223|-267.387621" + }, + { + "art": "STR", + "wert": "m2v2" + }, + { + "art": "STR", + "wert": "2" + }, + { + "art": "STR", + "wert": "2" + }, + { + "art": "STR", + "wert": "1" + }, + { + "art": "STR", + "wert": "1" + }, + { + "art": "STR", + "wert": "1" + }, + { + "art": "REAL", + "wert": 3.0 + }, + { + "art": "STR", + "wert": "2" + }, + { + "art": "STR", + "wert": "2" + }, + { + "art": "STR", + "wert": "mit-gf1" + }, + { + "art": "INT", + "wert": 1 + }, + { + "art": "STR", + "wert": "1" + } +] diff --git a/tests/testdata/linienzug_tests.json b/tests/testdata/linienzug_tests.json index b703f40..cac4547 100644 --- a/tests/testdata/linienzug_tests.json +++ b/tests/testdata/linienzug_tests.json @@ -16,6 +16,11 @@ "wert": 2154.0, "kommentar": "getreal Hoehe (Z) Startpunkt" }, + { + "typ": "string", + "wert": "1", + "kommentar": "getstring Bau-Richtung (1 = vorwaerts) - seit 2026-10-25 (Commit fb56794, Rueckwaerts-Bau). Die Frage steht VOR der AS-Praeambel. Fuer JOURNALE ist sie abwaertskompatibel (fehlt der Eintrag, gilt das Journal als Alt-Format), fuer dieses MOCK-Skript aber nicht: der Mock beantwortet jede getstring-Abfrage aus der Queue, eine fehlende Antwort verschiebt also alles Folgende um eine Position. Sichtbar wurde das als Abbruch in cdr mit dem String 5, weil die Achsen-Punktabfrage dann diesen String zog statt eines Punktes." + }, { "typ": "string", "wert": "1", diff --git a/tests/testdata/linienzug_tests_stufe2.json b/tests/testdata/linienzug_tests_stufe2.json index e834f50..b198676 100644 --- a/tests/testdata/linienzug_tests_stufe2.json +++ b/tests/testdata/linienzug_tests_stufe2.json @@ -16,6 +16,11 @@ "wert": 2154.0, "kommentar": "getreal Hoehe (Z) Startpunkt" }, + { + "typ": "string", + "wert": "1", + "kommentar": "getstring Bau-Richtung (1 = vorwaerts) - seit 2026-10-25 (Commit fb56794, Rueckwaerts-Bau). Siehe gleichlautenden Eintrag in linienzug_tests.json: fuer Journale abwaertskompatibel, fuer dieses Mock-Skript nicht." + }, { "typ": "string", "wert": "1",