From 8ccec9dea70e24aa1bfc8c3602e5ccbe833dc13b Mon Sep 17 00:00:00 2001 From: Michael Stangl Date: Fri, 18 Sep 2026 16:44:10 +0200 Subject: [PATCH] VF-Linienzug Modus 2 auf SEGS umstellen (behebt Doppelklick-Desync) Modus 2 journalisiert die Segment-Essenz (SEGS) statt der Objekt-Handles (OBJS) - identische Umstellung wie Modus 3. Damit ist der Block selbst- enthalten und der Doppelklick-Neubau unabhaengig von den Original-LINE/ARC. Behebt den beobachteten Modus-2-Desync (Winkel wurde beim Neuaufbau interaktiv nachgefragt + Abweichung, weil der OBJS-Replay an den - ggf. verschobenen - Pfad-Objekten hing). - vfl-in-selection + obj-liste im Modus-2-Ablauf durch vfl-in-segmente ersetzt (Live: ssget -> gf-sortiere-objekte -> gf-analysiere-kette -> Eck-Vorpruefung -> SEGS; Replay: fertige Essenz aus dem Journal). Objektauswahl steht jetzt NACH der Startpunkt-Praeambel (vfl-in-segmente braucht den startpunkt). - segmente9 (9-Feld-Essenz) eingefuehrt, 5-Feld-segmente daraus abgeleitet; seg-ent -> nil (kein Live-Highlight mehr, wie Modus 3). - Marker bleibt "linienzug2". HARTER SCHNITT fuer Altbestand: alte OBJS-"linienzug2"-Bloecke (ohne SEGS) werden beim Doppelklick klar abgewiesen (neuer Text vfl-edit-m2-obsolet, de/en) statt mit falschen Daten in den Bau zu laufen; der Batch-Konverter ueberspringt sie. Erkennung: vfl-journal-hat-segs-p. Tests: 3 file-freie Unit-Tests fuer vfl-journal-hat-segs-p (SEGS erkannt, OBJS/leer nicht). 243/243 LISP-Unit-Tests gruen in BricsCAD; test-neutral gegen HEAD (11=11 Python-Failures); lang-Paritaet geprueft. End-to-end (Neubau + deckungsgleicher Doppelklick) wie bei Modus 3 interaktiv zu bestaetigen. Co-Authored-By: Claude Opus 4.8 (1M context) --- Lisp/vf_linienzug.lsp | 73 +++++++++++++++++++++++++++++-------------- lang/de_DE.json | 1 + lang/en_GB.json | 1 + tests/test_unit.lsp | 16 ++++++++++ 4 files changed, 68 insertions(+), 23 deletions(-) diff --git a/Lisp/vf_linienzug.lsp b/Lisp/vf_linienzug.lsp index 6db3ff6..291a57a 100644 --- a/Lisp/vf_linienzug.lsp +++ b/Lisp/vf_linienzug.lsp @@ -8285,7 +8285,12 @@ (setq marker (car xd) journal (cdr xd)) (if (and (wcmatch bname "VF_*") (member marker '("linienzug" "linienzug2" "linienzug3")) - journal) + journal + ;; Alte OBJS-"linienzug2"-Bloecke (ohne SEGS) NICHT konvertieren - + ;; ihr Replay ist mit dem SEGS-Umbau nicht mehr fahrbar (harter + ;; Schnitt, wie im Doppelklick-Pfad vfl-edit-ent). Sie ueberspringen + ;; (nil zurueck), damit die Batch-Schleife sauber weiterlaeuft. + (or (/= marker "linienzug2") (vfl-journal-hat-segs-p journal))) (progn (setq *ssg-ils-dim* ziel-dim) ; Zieldim erzwingen (entdel ent) ; alten Block weg @@ -8320,7 +8325,14 @@ ;; gelesen; der Override greift beim anschliessenden Replay/Weiterbau. (setq dim (ssg-dim-xdata-lesen ent)) (cond - ((= marker "linienzug2") (vfl-edit-ent2 ent journal)) + ((= marker "linienzug2") + ;; Harter Schnitt: nur SEGS-Bloecke (neue Fassung) sind per Doppelklick + ;; neu aufbaubar. Alte OBJS-Bloecke (Objekt-Handles statt Segment-Essenz) + ;; wuerden im Replay falsche Daten in den Bau geben - klar abweisen statt + ;; zu crashen. + (if (vfl-journal-hat-segs-p journal) + (vfl-edit-ent2 ent journal) + (alert (ssg-text "vfl-edit-m2-obsolet")))) ((= marker "linienzug3") (vfl-edit-ent3 ent journal)) (t (progn @@ -8381,6 +8393,13 @@ (setq *ssg-ils-dim* nil)))))) (princ)) +;; T, wenn das Journal einen SEGS-Eintrag traegt (Modus 2 NEU / Modus 3 - die +;; Kette ist per Segment-Essenz selbst-enthalten). Alte Modus-2-Bloecke tragen +;; hier stattdessen einen OBJS-Eintrag (Objekt-Handles) - fuer die ist der +;; SEGS-Replay nicht mehr fahrbar (harter Schnitt, siehe vfl-edit-ent). +(defun vfl-journal-hat-segs-p (journal) + (and (vl-some (function (lambda (e) (equal (car e) "SEGS"))) journal) t)) + ;; Modus-2/3-Block per Doppelklick zuruecksetzen: voller Reset - die komplette ;; gespeicherte Eingabe wird 1:1 stumm abgespielt, identischer Neuaufbau. Kein ;; Sektions-Dialog; der Nutzer kann den neu entstandenen Block danach ganz @@ -9384,7 +9403,7 @@ 100.0)))) (defun vf-linienzug-modus2 ( / ss k obj-liste startpunkt start-hoehe as-seite - endpunkt end-hoehe es-seite kette segmente n i seg + endpunkt end-hoehe es-seite kette segmente segmente9 n i seg seg-ent typ hz laenge bwinkel bseite antwort winkel klass plan e ecke-bad vf-start vf-ende dz z-front @@ -9448,11 +9467,14 @@ (vfl-gf-abhaengigkeit-sicherstellen "vfl-m3-alert-gf-modul") - ;; --- 1. Pfad-Objekte waehlen --- - (princ (ssg-text "vfl-m3-pfad-waehlen")) - (setq ss (vfl-in-selection '((0 . "LINE,ARC")))) - (if (null ss) (progn (princ (ssg-text "vfl-m3-keine-objekte")) (exit))) - (setq obj-liste (mapcar 'vlax-ename->vla-object ss)) + ;; --- 1./4. Pfad-Objekte + Segment-Essenz: siehe Schritt 4 unten. --- + ;; Auswahl UND Ableitung laufen zusammen in vfl-in-segmente (Live: ssget -> + ;; gf-sortiere-objekte -> gf-analysiere-kette -> Eck-Vorpruefung -> SEGS; + ;; Replay: fertige Essenz aus dem Journal). Persistiert die Segment-Essenz + ;; statt der Objekt-Handles - der Block ist damit selbst-enthalten und der + ;; Doppelklick-Neubau unabhaengig von den Original-LINE/ARC (behebt den + ;; frueheren OBJS-Replay-Drift). Da vfl-in-segmente den startpunkt fuer die + ;; Sortierung braucht, steht die Auswahl NACH der Startpunkt-Praeambel. ;; --- 2. Startpunkt + Z + AS-Seite --- (if (vfl-wizard-aktiv) @@ -9502,16 +9524,16 @@ (setq es-seite (vfl-frage-es-winkel-seite "gf-seite-ein-header")) ) - ;; --- 4. Sortieren + Analysieren + Eck-Vorpruefung --- - (setq kette (gf-sortiere-objekte obj-liste startpunkt)) - (if (null kette) - (progn (princ (ssg-text "vfl-m3-fehler-nicht-sortierbar")) (exit))) - (setq segmente (gf-analysiere-kette kette)) - (setq ecke-bad (vfl2-pruefe-eckwinkel kette *vfk-eckwinkel-toleranz*)) - (if ecke-bad - (progn - (vfl-meldung (ssg-textf "vfl-m3-alert-eckwinkel" (list (rtos ecke-bad 2 1)))) - (exit))) + ;; --- 4. Pfad waehlen + Sortieren + Analysieren + Eck-Vorpruefung --- + ;; vfl-in-segmente kapselt Live + Replay und persistiert die Segment-Essenz + ;; (SEGS) statt der Objekt-Handles - siehe Schritt 1 oben und Modus 3. + (princ (ssg-text "vfl-m3-pfad-waehlen")) + (setq segmente9 (vfl-in-segmente '((0 . "LINE,ARC")) startpunkt *vfk-eckwinkel-toleranz*)) + (if (null segmente9) (progn (princ (ssg-text "vfl-m3-keine-objekte")) (exit))) + ;; segmente = 5-Feld-Bausicht (typ hz laenge bwinkel bseite) aus der 9-Feld- + ;; Essenz - die Klassifizierungs-Schleife unten arbeitet unveraendert damit. + (setq segmente (mapcar (function (lambda (s) (list (nth 0 s) (nth 1 s) (nth 2 s) (nth 3 s) (nth 4 s)))) + segmente9)) ;; --- 5. Klassifizierung (Phase A: nur speichern, nichts bauen) --- ;; Plan-Eintrag Gerade: ("Linie" hz laenge klass winkel) klass=GF/VF @@ -9519,13 +9541,18 @@ (setq n (length segmente) i 0 plan '()) (while (< i n) (setq seg (nth i segmente) typ (car seg) hz (cadr seg) laenge (caddr seg)) - (setq seg-ent (car (nth i kette))) ; echte LINE/ARC-Entity dieses Segments + ;; seg-ent: KEINE Live-Entity mehr - Modus 2 baut jetzt aus der Segment- + ;; Essenz (SEGS), nicht aus durchgereichten LINE/ARC (siehe Modus 3). Damit + ;; entfaellt das kosmetische Pfad-Segment-Highlight (vfl-seg-highlight ist + ;; nil-sicher). Bewusst: die Essenz macht Bau/Replay unabhaengig von den + ;; Original-Objekten, ein Highlight haette beim Doppelklick-Neubau ohnehin + ;; keine Entity mehr. + (setq seg-ent nil) ;; Wizard: alle Fragen dieses Segments in EINEM Dialog erfassen (die ;; unveraenderten vfl-menu/vfl-in-*-Aufrufe unten konsumieren die Antworten - ;; aus *vflw-pending*). Segment vorher in der Zeichnung hervorheben. Der - ;; nach-kurve-Fall stellt keine Frage (auto-VF) -> kein Dialog. Ebenso - ;; nach-vf bei einem Bogen: Vario-Kurve ist dann erzwungen (eine VF- - ;; Einheit kann nicht in einen GF-Bogen auslaufen), auch kein Dialog. + ;; aus *vflw-pending*). Der nach-kurve-Fall stellt keine Frage (auto-VF) -> + ;; kein Dialog. Ebenso nach-vf bei einem Bogen: Vario-Kurve ist dann + ;; erzwungen (eine VF-Einheit kann nicht in einen GF-Bogen auslaufen). (if (and (vfl-wizard-aktiv) (not (and (= typ "Linie") nach-kurve)) (not (and (= typ "Bogen") nach-vf))) diff --git a/lang/de_DE.json b/lang/de_DE.json index 8683a14..3b7cc44 100644 --- a/lang/de_DE.json +++ b/lang/de_DE.json @@ -111,6 +111,7 @@ "vfl-glied-vario": "Vario-Kurve (horizontale Kurve im VF)", "vfl-glied-offen": "(offen)", "vfl-edit-kein-journal": "Dieser Linienzug-Block traegt kein Eingabe-Journal (Altbestand) und kann nicht schrittweise editiert werden.", + "vfl-edit-m2-obsolet": "Dieser Modus-2-Block wurde mit dem alten Objekt-Referenz-Journal gebaut und kann nicht mehr per Doppelklick neu aufgebaut werden. Bitte die Kette mit Modus 2 neu erzeugen (die neue Fassung speichert die Segment-Daten direkt am Block).", "vfl-edit-kette-header": "\n\nLinienzug mit %1 Glied(ern):", "vfl-edit-abgespielt": "\n>>> %1 Glied(er) werden abgespielt, %2 zurueckgenommen - danach interaktiv weiter.", "vfl-edit2-reset-info": "\n>>> Linienzug (Modus 2) wird mit den gespeicherten Angaben identisch neu aufgebaut...", diff --git a/lang/en_GB.json b/lang/en_GB.json index c728e93..903c455 100644 --- a/lang/en_GB.json +++ b/lang/en_GB.json @@ -111,6 +111,7 @@ "vfl-glied-vario": "Vario curve (horizontal curve in VF)", "vfl-glied-offen": "(open)", "vfl-edit-kein-journal": "This chain block carries no input journal (legacy) and cannot be edited step by step.", + "vfl-edit-m2-obsolet": "This mode-2 block was built with the old object-reference journal and can no longer be rebuilt by double-click. Please recreate the chain with mode 2 (the new version stores the segment data directly on the block).", "vfl-edit-kette-header": "\n\nChain with %1 segment(s):", "vfl-edit-abgespielt": "\n>>> %1 segment(s) replayed, %2 undone - then continue interactively.", "vfl-edit2-reset-info": "\n>>> Rebuilding this Modus-2 chain identically from the saved inputs...", diff --git a/tests/test_unit.lsp b/tests/test_unit.lsp index 7877ad1..29249df 100644 --- a/tests/test_unit.lsp +++ b/tests/test_unit.lsp @@ -900,6 +900,22 @@ ;; erwarteten Trenner und KEIN Newline (sonst zerrisse der Record-Trenner) (tu-nil "vfl-segs/kein-newline" (vl-string-search "\n" (vfl-segs->string _segs))) + + ;; vfl-journal-hat-segs-p: unterscheidet neue SEGS-Ketten von alten + ;; OBJS-"linienzug2"-Bloecken (harter Schnitt beim Doppelklick). + (if (atoms-family 1 '("VFL-JOURNAL-HAT-SEGS-P")) + (progn + ;; SEGS-Journal (Modus 2 neu / Modus 3): erkannt + (tu-true "vfl-hat-segs/mit-segs" + (vfl-journal-hat-segs-p + (list (cons "PT" '(0.0 0.0 0.0)) (cons "SEGS" _segs)))) + ;; Altes OBJS-Journal (Objekt-Handles): NICHT als SEGS erkannt + (tu-nil "vfl-hat-segs/nur-objs" + (vfl-journal-hat-segs-p + (list (cons "PT" '(0.0 0.0 0.0)) (cons "OBJS" '("A1" "A2"))))) + ;; Leeres Journal: nil + (tu-nil "vfl-hat-segs/leer" (vfl-journal-hat-segs-p '()))) + (tu-record nil "vfl-hat-segs/modul" "VFL-JOURNAL-HAT-SEGS-P fehlt")) ) ) )