VF-Linienzug Modus 3 editierbar: Segment-Essenz statt Objekt-Handles

Modus 3 (Vorwaerts-Nachbau) hat jetzt dieselbe XDATA-Editierbarkeit +
Doppelklick-Neubau wie Modus 1/2. Statt der Pfad-Objekt-Handles wird die
abgeleitete Segment-ESSENZ journalisiert (neuer Journal-Typ SEGS): der VF_n-
Block ist damit selbst-enthalten, der Neubau unabhaengig davon, ob die
urspruenglichen LINE/ARC noch existieren - robuster als der OBJS-Weg von Modus 2.

Journal-Kern (vf_linienzug.lsp):
- Neuer Typ SEGS: Segmentliste (typ hz laenge bwinkel bseite spx spy epx epy)
  serialisiert als ";"-getrennte Segmente, Felder per "|". Eingebunden in
  vfl-entry->string / vfl-string->entry / vfl-entry->json.
- vfl-in-segmente: Live (ssget -> gf-sortiere-objekte -> gf-analysiere-kette ->
  Eck-Vorpruefung -> 9-Feld-Essenz) ODER Replay (Essenz direkt aus SEGS-Journal).
  Ersetzt vfl-in-selection im Modus-3-Ablauf.
- vfl-kette->segmente9 fuehrt Bau-Segmente + Start/Endpunkte zusammen; Soll-Ende
  kommt jetzt aus der Essenz statt aus den Original-Entities.

Modus-3-Umbau:
- Abbruch-Wickler + vfl-journal-xdata-schreiben mit Marker "linienzug3" (analog
  Modus 2). Kopf-Kommentar/Fehler-Handler-Variablen an Modus 2 angeglichen.
- Kein Live-Segment-Highlight mehr (Essenz-Bau reicht keine Entity mehr durch) -
  bewusst, im Code dokumentiert.

Doppelklick/Batch:
- vfl-edit-ent2 zu vfl-edit-ent-voll parametrisiert; vfl-edit-ent3 ruft
  vf-linienzug-modus3. vfl-edit-ent / vfl-konvertiere-ent / vfl-journal-xdata-
  lesen dispatchen "linienzug3".

Tests:
- 8 file-freie SEGS-Roundtrip-Unit-Tests (tests/test_unit.lsp, tu-tests-vfl-segs);
  234/234 LISP-Unit-Tests gruen in BricsCAD.
- vfl-in-segmente im statischen Headless-Waechter registriert.
- Verifiziert an einer echten linienzug3-Kette (results/test.dwg): SEGS-Journal
  korrekt geschrieben, Doppelklick-Neubau geometrisch deckungsgleich zum Original.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Michael Stangl
2026-09-18 15:55:47 +02:00
co-authored by Claude Opus 4.8
parent bc4b25d251
commit 3cce1ec457
3 changed files with 301 additions and 54 deletions
+249 -53
View File
@@ -1995,6 +1995,59 @@
(setq s (substr s (+ pos 1 (strlen sep)))))
(reverse (cons s out)))
;; --- SEGS: Segment-Essenz einer Modus-3-Kette (selbst-enthalten) ---
;; Ein SEGS-Wert ist die AUS DEN PFAD-OBJEKTEN ABGELEITETE Zahlenliste, die der
;; Modus-3-Bau ohnehin allein verwendet (gf-analysiere-kette + Start/Endpunkte
;; aus gf-sortiere-objekte). Sie ersetzt im Journal die frueheren OBJS-Handles:
;; dadurch ist die Kette im XDATA vollstaendig beschrieben und beim Doppelklick-
;; Replay unabhaengig davon, ob die urspruenglichen LINE/ARC noch existieren
;; (robuster als der OBJS-Weg von Modus 2). Siehe doc/variofoerderer.md.
;;
;; Ein Segment ist eine 9er-Liste, die die "Bau-Essenz" und die fuer die
;; AS-Trimmung/das Soll-Ende noetigen absoluten Punkte zusammenfuehrt:
;; (typ hz laenge bwinkel bseite spx spy epx epy)
;; typ "Linie"/"Bogen" (delimiter-frei, daher unquotiert serialisiert)
;; hz Eintritts-Horizontalwinkel (Grad)
;; laenge 2D-Laenge / Sehnenmass (mm)
;; bwinkel Bogenwinkel (0 bei Linie)
;; bseite "links"/"rechts"
;; spx spy Startpunkt (XY, mm) des Segments \ aus gf-sortiere-objekte,
;; epx epy Endpunkt (XY, mm) des Segments / fuer Trimmung + Soll-Ende
;;
;; Serialisierung: Segmente per ";" getrennt, Felder je Segment per "|". Beide
;; Trenner sind kollisionsfrei - die einzigen String-Felder (typ/bseite) sind
;; feste Schluesselwoerter ohne ";" oder "|", alle uebrigen Felder sind Zahlen
;; (rtos-Mode-2, wie PT/REAL). Ein leeres SEGS ("") ist eine leere Liste.
(defun vfl-seg->string (seg)
(vfl-strjoin
(list (nth 0 seg) ; typ (String)
(rtos (float (nth 1 seg)) 2 6) ; hz
(rtos (float (nth 2 seg)) 2 6) ; laenge
(rtos (float (nth 3 seg)) 2 6) ; bwinkel
(nth 4 seg) ; bseite (String)
(rtos (float (nth 5 seg)) 2 6) ; spx
(rtos (float (nth 6 seg)) 2 6) ; spy
(rtos (float (nth 7 seg)) 2 6) ; epx
(rtos (float (nth 8 seg)) 2 6)) ; epy
"|"))
(defun vfl-string->seg (s / f)
(setq f (vfl-strsplit s "|"))
(list (nth 0 f) ; typ
(atof (nth 1 f)) ; hz
(atof (nth 2 f)) ; laenge
(fix (atof (nth 3 f))) ; bwinkel (Ganzzahl, wie gf-analysiere-kette)
(nth 4 f) ; bseite
(atof (nth 5 f)) ; spx
(atof (nth 6 f)) ; spy
(atof (nth 7 f)) ; epx
(atof (nth 8 f)))) ; epy
(defun vfl-segs->string (segs)
(vfl-strjoin (mapcar 'vfl-seg->string segs) ";"))
(defun vfl-string->segs (s)
(if (= (strlen s) 0)
'()
(mapcar 'vfl-string->seg (vfl-strsplit s ";"))))
;; --- Serialisierung (tagged, selbstbeschreibend) ---
;; Zeilenformat "kind:payload", Eintraege per "\n" verkettet. getstring/getreal
;; liefern nie ein Newline, daher ist "\n" ein sicherer Record-Trenner.
@@ -2002,6 +2055,8 @@
;; Entity-Handles (Hex-Strings, kollidieren nie mit dem Komma-Trenner).
;; Handles bleiben - anders als Enames - ueber Sitzungen/Undo hinweg stabil
;; und sind damit die richtige Persistenzform fuer ssget-Ergebnisse.
;; "SEGS" (Segment-Essenz, Modus 3): Payload = ";"-getrennte Segmente, Felder
;; per "|" (siehe vfl-segs->string oben).
(defun vfl-entry->string (e / k v)
(setq k (car e) v (cdr e))
(cond
@@ -2013,6 +2068,7 @@
((= k "STR") (strcat "STR:" v))
((= k "STEP") (strcat "STEP:" v))
((= k "OBJS") (strcat "OBJS:" (vfl-strjoin v ",")))
((= k "SEGS") (strcat "SEGS:" (vfl-segs->string v)))
(t "NIL:")))
(defun vfl-string->entry (ln / p kind pay c)
(setq p (vl-string-search ":" ln))
@@ -2030,6 +2086,7 @@
((= kind "STR") (cons "STR" pay))
((= kind "STEP") (cons "STEP" pay))
((= kind "OBJS") (cons "OBJS" (if (> (strlen pay) 0) (vfl-strsplit pay ",") nil)))
((= kind "SEGS") (cons "SEGS" (vfl-string->segs pay)))
(t (cons "NIL" nil))))))
;; forward-journal ist bereits in Bau-Reihenfolge (nicht die umgekehrte
;; *vfl-journal*-Rohform) - gemeinsame Serialisierung fuer Ketten- UND
@@ -2068,6 +2125,21 @@
((= k "OBJS") (strcat "[" (vfl-strjoin
(mapcar (function (lambda (h) (strcat "\"" (vfl-json-escape h) "\"")))
v) ",") "]"))
((= k "SEGS") (strcat "["
(vfl-strjoin
(mapcar
(function (lambda (seg)
(strcat "[\"" (vfl-json-escape (nth 0 seg)) "\","
(vfl-json-num (float (nth 1 seg))) ","
(vfl-json-num (float (nth 2 seg))) ","
(vfl-json-num (float (nth 3 seg))) ",\""
(vfl-json-escape (nth 4 seg)) "\","
(vfl-json-num (float (nth 5 seg))) ","
(vfl-json-num (float (nth 6 seg))) ","
(vfl-json-num (float (nth 7 seg))) ","
(vfl-json-num (float (nth 8 seg))) "]")))
v) ",")
"]"))
(t "null"))
"}"))
;; forward-journal (Bau-Reihenfolge) als kompakter JSON-Array-String.
@@ -2115,7 +2187,7 @@
;; Rueckgabe: (marker . journal) oder nil (kein/unbekanntes Journal).
(defun vfl-journal-xdata-lesen (ent / xd)
(setq xd (vfs-xdata-lesen ent))
(if (and xd (member (car xd) '("linienzug" "linienzug2")))
(if (and xd (member (car xd) '("linienzug" "linienzug2" "linienzug3")))
(cons (car xd) (vfl-string->journal (apply 'strcat (cdr xd))))
nil))
@@ -8184,22 +8256,24 @@
;; und der Override sicher zurueckgesetzt wird. Rueckgabe: T bei Erfolg, sonst nil.
;; Bekannte Grenze (nur Modus 2): das Replay von vfl-in-selection braucht die
;; Original-Pfadobjekte; wurden sie geloescht, schlaegt der Konverter fuer diesen
;; Block sauber fehl (sichtbar am nicht erhoehten Batch-Zaehler).
;; Block sauber fehl (sichtbar am nicht erhoehten Batch-Zaehler). Modus 3
;; ("linienzug3") hat diese Grenze NICHT: es replayt die Segment-Essenz (SEGS)
;; aus dem Journal, nicht die Objekt-Handles - unabhaengig von den Original-LINE/ARC.
(defun vfl-konvertiere-ent (ent ziel-dim / bname xd marker journal ok)
(setq bname (cdr (assoc 2 (entget ent))))
(setq xd (vfl-journal-xdata-lesen ent)) ; (marker . journal) oder nil
(setq marker (car xd) journal (cdr xd))
(if (and (wcmatch bname "VF_*")
(member marker '("linienzug" "linienzug2"))
(member marker '("linienzug" "linienzug2" "linienzug3"))
journal)
(progn
(setq *ssg-ils-dim* ziel-dim) ; Zieldim erzwingen
(entdel ent) ; alten Block weg
(vfl-journal-replay-start journal) ; volle Queue, KEIN Truncate
(setq ok (vl-catch-all-apply
(if (= marker "linienzug2")
'vf-linienzug-modus2
'vf-linienzug-modus)))
(cond ((= marker "linienzug2") 'vf-linienzug-modus2)
((= marker "linienzug3") 'vf-linienzug-modus3)
(t 'vf-linienzug-modus))))
(setq *ssg-ils-dim* nil) ; Override zuruecksetzen
;; Fehlgeschlagene Konvertierung NICHT stumm verschlucken: der alte Block
;; ist per entdel schon weg, die Teil-Geometrie liegt frei in der
@@ -8225,8 +8299,10 @@
;; Doppelklick kein *ssg-ils-dim*-Override aktiv ist). Wird VOR dem entdel
;; gelesen; der Override greift beim anschliessenden Replay/Weiterbau.
(setq dim (ssg-dim-xdata-lesen ent))
(if (= marker "linienzug2")
(vfl-edit-ent2 ent journal)
(cond
((= marker "linienzug2") (vfl-edit-ent2 ent journal))
((= marker "linienzug3") (vfl-edit-ent3 ent journal))
(t
(progn
(setq glieder (vfl-journal-glieder journal))
(setq n (length glieder))
@@ -8282,15 +8358,20 @@
;; Handler selbst (dort ebenfalls (setq *ssg-ils-dim* nil)), denn
;; die naechste Zeile wird dann nicht mehr erreicht.
(vf-linienzug-modus)
(setq *ssg-ils-dim* nil)))))
(setq *ssg-ils-dim* nil))))))
(princ))
;; Modus-2-Block per Doppelklick zuruecksetzen: voller Reset - die komplette
;; gespeicherte Eingabe (inkl. der gewaehlten Pfad-Objekte, siehe
;; vfl-in-selection) wird 1:1 stumm abgespielt, identischer Neuaufbau. Kein
;; 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
;; normal weiterbearbeiten oder loeschen.
(defun vfl-edit-ent2 (ent journal / dim)
;;
;; bau-fn = die Modus-Bau-Funktion, die das Journal abspielt: 'vf-linienzug-modus2
;; fuer Marker "linienzug2" (Pfad-Objekte per OBJS-Handles) bzw.
;; 'vf-linienzug-modus3 fuer "linienzug3" (Segment-Essenz per SEGS - unabhaengig
;; von den Original-Objekten). Beide Modi haben eine flache Klassifizierungs-
;; Schleife ohne editierbare Einzelglieder, daher derselbe volle Reset.
(defun vfl-edit-ent-voll (ent journal bau-fn / dim)
;; Dimension des Bestandsblocks VOR dem entdel merken und beim Neubau als
;; Override erzwingen (dimensionstreuer Doppelklick-Neubau, sonst globale
;; DXFM_DIM). Danach Override zuruecksetzen.
@@ -8301,12 +8382,17 @@
(vfl-journal-replay-start journal)
;; DIREKTER Aufruf, KEIN vl-catch-all-apply - identische Begruendung wie im
;; Sektions-Zweig von vfl-edit-ent (siehe dortiger Kommentar): der alte Block
;; ist per entdel schon weg, bei einem Abbruch muss der *error*-Handler von
;; vf-linienzug-modus2 die Teil-Geometrie wickeln. Den Dim-Override raeumt im
;; Abbruchfall der Handler ab.
(vf-linienzug-modus2)
;; ist per entdel schon weg, bei einem Abbruch muss der *error*-Handler der
;; Modus-Funktion die Teil-Geometrie wickeln. Den Dim-Override raeumt im
;; Abbruchfall der Handler ab. bau-fn ist ein Funktions-SYMBOL (quoted beim
;; Aufruf) - ueber apply aufrufen, nicht als (bau-fn) (das riefe die Funktion
;; namens "bau-fn" auf, nicht den durchgereichten Wert).
(apply bau-fn nil)
(setq *ssg-ils-dim* nil)
(princ))
;; Rueckwaertskompatibler Wrapper (Modus 2). vfl-edit-ent3 fuer Modus 3.
(defun vfl-edit-ent2 (ent journal) (vfl-edit-ent-voll ent journal 'vf-linienzug-modus2))
(defun vfl-edit-ent3 (ent journal) (vfl-edit-ent-voll ent journal 'vf-linienzug-modus3))
;; ============================================================
;; RECOVERY: Kette aus der Sektions-XDATA der Zeichnung neu aufbauen
@@ -8702,14 +8788,80 @@
(foreach x liste (setq d (abs (- x w))) (if (< d bd) (setq bd d best x)))
best)
;; --- Segment-Essenz einer selektierten Pfad-Kette (Modus 3) --------------
;; Fuehrt die 5-Feld-Bau-Segmente aus gf-analysiere-kette mit den absoluten
;; Start-/Endpunkten aus gf-sortiere-objekte (kette: (ent sp ep umk)) zu der
;; selbstbeschreibenden 9-Feld-Form zusammen, die das SEGS-Journal traegt:
;; (typ hz laenge bwinkel bseite spx spy epx epy)
;; Beide Listen sind gleich lang und in derselben Reihenfolge (segmente wurde
;; genau aus kette abgeleitet). spx/spy/epx/epy sind die planaren XY der
;; Segment-Enden - sie ersetzen den spaeteren direkten kette-Zugriff (AS-
;; Trimmung am ersten Segment, Soll-Ende-Report), sodass der Bau OHNE die
;; Original-Entities auskommt und beim Replay aus dem Journal gespeist wird.
(defun vfl-kette->segmente9 (kette segmente / out i seg item sp ep)
(setq out '() i 0)
(foreach seg segmente
(setq item (nth i kette) sp (cadr item) ep (caddr item))
(setq out (cons (list (nth 0 seg) (nth 1 seg) (nth 2 seg) (nth 3 seg) (nth 4 seg)
(car sp) (cadr sp) (car ep) (cadr ep))
out))
(setq i (1+ i)))
(reverse out))
;; Objektauswahl + Analyse (Live) ODER Segment-Essenz aus dem Journal (Replay).
;; Gegenstueck zu vfl-in-selection, aber persistiert NICHT die Entity-Handles,
;; sondern die abgeleitete 9-Feld-Segmentliste (Journal-Art "SEGS"). Damit ist
;; der Modus-3-Block im XDATA vollstaendig beschrieben und der Doppelklick-Neubau
;; unabhaengig davon, ob die urspruenglichen LINE/ARC noch existieren.
;; Rueckgabe: die 9-Feld-Segmentliste oder nil (Abbruch/leer). filter/startpunkt
;; wie bei der Live-Auswahl; ecke-tol wird nur im Live-Zweig fuer die
;; Eck-Vorpruefung gebraucht (Replay-Daten sind bereits geprueft eingefroren).
(defun vfl-in-segmente (filter startpunkt ecke-tol / popped ss k obj-liste kette segmente ecke-bad segs9)
(setq popped (if *vfl-replay-queue* (vfl-replay-pop) nil))
(if popped
;; --- Replay: fertige Segment-Essenz direkt aus dem Journal ---
(progn
(setq segs9 (car popped))
(if (null segs9)
(if (vfl-headless-p) (vfl-headless-abbruch "SEGS-leer")))
segs9)
;; --- Live: Objekte waehlen, sortieren, analysieren, dann journalisieren ---
(progn
(if (vfl-headless-p) (vfl-headless-abbruch "SEGS"))
(setq ss (ssget filter))
(if (null ss)
(progn (vfl-journal-record "NIL" nil) nil)
(progn
;; Auswahlsatz -> VLA-Objektliste (wie im frueheren vfl-in-selection).
(setq obj-liste '() k 0)
(while (< k (sslength ss))
(setq obj-liste (cons (vlax-ename->vla-object (ssname ss k)) obj-liste))
(setq k (1+ k)))
(setq obj-liste (reverse obj-liste))
(setq kette (gf-sortiere-objekte obj-liste startpunkt))
(if (null kette)
(progn (princ (ssg-text "vfl-m3-fehler-nicht-sortierbar"))
(vfl-journal-record "NIL" nil) nil)
(progn
(setq segmente (gf-analysiere-kette kette))
(setq ecke-bad (vfl2-pruefe-eckwinkel kette ecke-tol))
(if ecke-bad
(progn
(vfl-meldung (ssg-textf "vfl-vwnb-alert-eckwinkel" (list (rtos ecke-bad 2 1))))
(vfl-journal-record "NIL" nil) nil)
(progn
(setq segs9 (vfl-kette->segmente9 kette segmente))
(vfl-journal-record "SEGS" segs9)
segs9)))))))))
(defun vf-linienzug-modus3 ( / ss obj-liste startpunkt start-hoehe as-seite
es-seite kette segmente n i seg seg-ent typ hz laenge
es-seite kette segmente segmente9 n i seg seg-ent typ hz laenge
bwinkel bseite frame antwort winkel deltaL
anzahl-gf anzahl-vf vfl-nummer lastEnt hoehe-bis
ecke-bad first-line last-line letzt-winkel
aus ein soll-ende ist-ende run-typ richtn best-w
kvariante L_VF ent-fp rad3 just-open
dbg-an old-error)
dbg-an old-error dbg-old-error vfl-ins)
(princ "\n\n=========================================")
(princ (ssg-text "vfl-vwnb-titel"))
(princ "\n=========================================")
@@ -8721,34 +8873,40 @@
;; automatisch ueber vfl-journal-record mitgeloggt (siehe dort) - hier nur
;; noch Session-Start/-Ende + Zwischenergebnisse, die NICHT direkt aus einer
;; Nutzereingabe stammen (Analyse-Ergebnis, Segment-Header, Bau-Ergebnis).
;; *vfl-journal*/*vflw-pending* werden dabei nebenbei mitbefuellt, aber von
;; Modus 3 nirgends gelesen/persistiert (kein Replay/XDATA wie bei Modus 1/2
;; - das ist hier bewusst NICHT mit umgebaut, nur das Logging).
;; Der *error*-Handler schliesst die Datei bei Abbruch sauber.
;; *vfl-journal* wird - wie bei Modus 1/2 - als XDATA (Marker "linienzug3")
;; persistiert und ist damit per Doppelklick editierbar (vfl-edit-ent3, voller
;; Reset-Replay). Statt der Objekt-Handles traegt es die Segment-ESSENZ (SEGS,
;; siehe vfl-in-segmente): der Block ist selbst-enthalten und der Neubau
;; unabhaengig von den urspruenglichen LINE/ARC.
;; FRUEHER *error*-Handler: schliesst nur die dbg-Datei sauber, falls waehrend
;; der Pfad-/Praeambel-Phase (noch keine Geometrie) abgebrochen wird. Der
;; eigentliche Abbruch-WICKLER (Teil-Geometrie zu einem VF_n-Block sichern)
;; wird erst nach dem Setup scharf geschaltet (siehe unten), sobald
;; vfl-nummer/lastEnt feststehen - analog Modus 2.
(setq dbg-an (dbg-schalter-open "vfl-modus3" "vfl_modus3.dbg" "DXFM_LOG"))
(if dbg-an
(progn
(dbgf "vf-linienzug-modus3")
(dbgmsg "=== SESSION Modus 3 (Vorwaerts-Nachbau) START ===")
(dbgflush)))
(setq old-error *error*)
(setq dbg-old-error *error*)
(setq *error*
(function (lambda (msg)
(setq *error* old-error)
(setq *error* dbg-old-error)
(if dbg-an
(progn
(dbgmsg (strcat "=== ABBRUCH: " (if msg msg "(exit)") " ==="))
(dbgreturn nil)
(dbgclose)))
(if old-error (old-error msg) (princ)))))
(if dbg-old-error (dbg-old-error msg) (princ)))))
(vfl-gf-abhaengigkeit-sicherstellen "vfl-m3-alert-gf-modul")
;; --- 1. Pfad-Objekte waehlen (LINE/ARC) ---
(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./3. Pfad-Objekte + Segment-Essenz: siehe Schritt 3 unten. ---
;; Auswahl UND Ableitung laufen zusammen in vfl-in-segmente, weil die
;; Sortierung den Startpunkt braucht (Schritt 2) - die Objektauswahl steht
;; daher NACH der Startpunkt-/AS-Praeambel, nicht mehr davor. Journalisiert
;; wird nur noch die abgeleitete Segment-Essenz (SEGS), nicht die Handles.
;; --- 2. Startpunkt (hoehere Seite) + Hoehe + AS-Seite ---
;; Wizard: Startpunkt+Hoehe als EIN Gruppen-Dialog (analog Modus 2). Die
@@ -8785,24 +8943,25 @@
(setq as-seite (if (= (vfl-in-string (ssg-text "prompt-wahl-1-2")) "2") "rechts" "links"))
(vf-set-as-masse *vfl-as-winkel* as-seite) ; Masse fuer Variante
;; --- 3. Sortieren + Analysieren ---
(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))
;; --- 3. Pfad waehlen + Sortieren + Analysieren + Eck-Vorpruefung ---
;; vfl-in-segmente kapselt Live (ssget -> gf-sortiere-objekte ->
;; gf-analysiere-kette -> Eck-Vorpruefung -> 9-Feld-Essenz) UND Replay
;; (fertige Essenz aus dem SEGS-Journal). Persistiert die Segment-Essenz
;; statt der Objekt-Handles - damit ist der Block selbst-enthalten und der
;; Doppelklick-Neubau (vfl-edit-ent3) braucht die Original-LINE/ARC nicht.
(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), abgeleitet aus
;; der 9-Feld-Essenz - der bestehende Bau 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))
(if dbg-an
(progn
(dbgmsg (strcat "ANALYSE: " (itoa (length segmente)) " Segment(e) erkannt"))
(dbg 'segmente)
(dbgflush)))
;; --- 4. Eck-Winkel-Vorpruefung (vor dem Bau) ---
(setq ecke-bad (vfl2-pruefe-eckwinkel kette *vfk-eckwinkel-toleranz*))
(if ecke-bad
(progn
(vfl-meldung (ssg-textf "vfl-vwnb-alert-eckwinkel" (list (rtos ecke-bad 2 1))))
(exit)))
;; --- 5. Setup ---
(setq aus (if aus-dx aus-dx *vfk-as-es-fallback-dx*) ein (if ein-dx ein-dx *vfk-as-es-fallback-dx*))
(setq rad3 (* (float (ssg-cfg-or "vario" "gefaelle_winkel" 3)) (/ pi 180.0)))
@@ -8812,7 +8971,29 @@
(setq vfl-nummer (vf-next-number))
(setq lastEnt (vf-lastent-ohne-attribute))
(vfl-acc-reset)
(setq anzahl-gf 0 anzahl-vf 0 frame nil n (length segmente))
(setq anzahl-gf 0 anzahl-vf 0 frame nil)
;; --- Abbruch-Sicherung ab hier scharf (analog Modus 1/2) ---
;; Ab Schritt 6 kann jederzeit Geometrie entstehen. Der Wickler sichert die
;; bis zum Abbruch gebaute Teil-Geometrie als VF_n-Block mit dem vollen
;; Journal (Marker "linienzug3") - sie bleibt stehen und ist per Doppelklick
;; fortsetz-/editierbar. Loest den fruehen dbg-Hook ab (Ruecksprungziel bleibt
;; dbg-old-error) und uebernimmt das dbgclose. *ssg-ils-dim* zuruecksetzen:
;; Begruendung siehe gleichlautende Stelle in vf-linienzug-modus.
(setq old-error dbg-old-error)
(setq *error*
(function (lambda (msg)
(setq *error* old-error)
(setq *ssg-ils-dim* nil)
(vfl-modus-abbruch-sichern lastEnt vfl-nummer anzahl-gf anzahl-vf
startpunkt frame as-seite es-seite "linienzug3")
(if dbg-an
(progn
(dbgmsg (strcat "=== ABBRUCH: " (if msg msg "(exit)") " ==="))
(dbgreturn nil)
(dbgclose)))
(if (and (boundp '*ssg-start-stack*) *ssg-start-stack*) (ssg-end))
(princ))))
(setq n (length segmente))
;; erste/letzte "Linie" fuer die Trimmung bestimmen
(setq first-line -1 last-line -1 i 0)
(while (< i n)
@@ -8831,13 +9012,19 @@
(setq i 0)
(while (< i n)
(setq seg (nth i segmente) typ (car seg) hz (cadr seg))
(setq seg-ent (car (nth i kette))) ; echte LINE/ARC-Entity dieses Segments
;; seg-ent: KEINE Live-Entity mehr - Modus 3 baut jetzt aus der Segment-
;; Essenz (SEGS), nicht aus durchgereichten LINE/ARC. Damit entfaellt das
;; kosmetische Pfad-Segment-Highlight (vfl-seg-highlight ist nil-sicher).
;; Der Wegfall ist bewusst: die Essenz macht den Bau/Replay unabhaengig von
;; den Original-Objekten, ein Highlight haette beim Doppelklick-Neubau ohnehin
;; keine Entity mehr zum Hervorheben.
(setq seg-ent nil)
;; Wizard: alle Fragen dieses Segments in EINEM Dialog erfassen (die
;; unveraenderten vfl-in-*-Aufrufe unten konsumieren die Antworten aus
;; *vflw-pending*). Segment vorher in der Zeichnung hervorheben. Bei einem
;; Bogen ist Vario-Kurve nur im offenen VF-Lauf erlaubt - deshalb die
;; Variante-Antwort nur mitschicken, wenn run-typ="VF" (sonst konsumiert
;; der Aufrufer sie nicht und sie wuerde ins naechste Segment lecken).
;; *vflw-pending*). Bei einem Bogen ist Vario-Kurve nur im offenen VF-Lauf
;; erlaubt - deshalb die Variante-Antwort nur mitschicken, wenn run-typ="VF"
;; (sonst konsumiert der Aufrufer sie nicht und sie wuerde ins naechste
;; Segment lecken).
(if (vfl-wizard-aktiv)
(progn
(vfl-seg-highlight seg-ent T)
@@ -8950,12 +9137,21 @@
(setq frame (vfl-insert-es-element "GF" frame (car (frame->hz-winkel frame))
(if letzt-winkel letzt-winkel *vfk-gefaelle-winkel*) (caddr (car frame)) es-seite)))
;; --- 8. Block + Ist-Ziel-Report ---
;; --- 8. Block + Journal-XDATA + Ist-Ziel-Report ---
(setq hoehe-bis (caddr (car frame)))
(vfl-block-erstellen vfl-nummer anzahl-gf anzahl-vf (caddr startpunkt) hoehe-bis
(vfl-planar-dist startpunkt (car frame)) as-seite es-seite startpunkt lastEnt)
(setq vfl-ins
(vfl-block-erstellen vfl-nummer anzahl-gf anzahl-vf (caddr startpunkt) hoehe-bis
(vfl-planar-dist startpunkt (car frame)) as-seite es-seite startpunkt lastEnt))
;; Eingabe-Journal am fertigen Block persistieren (Marker "linienzug3") ->
;; spaeter per Doppelklick editierbar (vfl-edit-ent3: voller Reset-Replay wie
;; Modus 2, aus der Segment-Essenz statt aus Objekt-Handles).
(if vfl-ins (vfl-journal-xdata-schreiben vfl-ins "linienzug3"))
(setq soll-ende (caddr (last kette))) ; Endpunkt des letzten gezeichneten Segments
;; Endpunkt des letzten gezeichneten Segments - aus der Segment-Essenz
;; (epx/epy des letzten Segments), nicht mehr aus den Original-Entities.
;; Damit stimmt der Soll-Ende-Report auch beim Doppelklick-Neubau, wenn die
;; urspruenglichen LINE/ARC laengst weg sind.
(setq soll-ende (list (nth 7 (last segmente9)) (nth 8 (last segmente9))))
(setq ist-ende (car frame)) ; ES-KS_AUS
(princ "\n\n=========================================")
(princ (ssg-text "vfl-vwnb-eingefuegt"))