Merge remote-tracking branch 'origin/master'

This commit is contained in:
Yuelin Wang
2026-09-18 17:47:53 +02:00
39 changed files with 3487 additions and 824 deletions
+435 -165
View File
@@ -2013,6 +2013,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.
@@ -2020,6 +2073,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
@@ -2031,6 +2086,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))
@@ -2048,6 +2104,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
@@ -2086,6 +2143,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.
@@ -2133,7 +2205,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))
@@ -2306,6 +2378,47 @@
;; sich um einen frischen Bau oder einen Editier-Neuaufbau handelte (kein
;; Sonderfall mehr noetig). Aufgerufen aus dem *error*-Handler von
;; vf-linienzug-modus.
;; Den scharfen Abbruch-Wickel-Handler als *error* installieren - gemeinsam
;; fuer alle drei Linienzug-Modi (frueher 3x wortgleich ausgeschrieben, nur der
;; Marker-String "linienzug"/"linienzug2"/"linienzug3" unterschied sich).
;;
;; Der Handler faengt jeden Abbruch (ESC / (exit) / Laufzeitfehler) ab, wickelt
;; die bis dahin gebaute Teil-Geometrie per vfl-modus-abbruch-sichern zu einem
;; VF_n-Block mit dem vollen Journal (Marker als XDATA) und stellt *error*
;; wieder her. Details/Begruendung (dynamic scoping, *ssg-ils-dim*-Reset,
;; ssg-end) siehe die ausfuehrlichen Kommentare an der frueheren Aufrufstelle
;; in vf-linienzug-modus.
;;
;; VERTRAG (dynamic scoping): Der Aufrufer MUSS als Locals gebunden haben und
;; VOR diesem Aufruf gesetzt haben: old-error (Ruecksprung-*error*), lastEnt,
;; vfl-nummer, anzahl-gf, anzahl-vf, startpunkt, frame, as-seite, es-seite,
;; dbg-an. Sie werden vom Handler-Lambda zur ABBRUCHZEIT dynamisch aufgeloest -
;; also gegen den dann noch aktiven Modus-Frame, nicht gegen diesen Konstruktor
;; (der ist beim Abbruch laengst zurueckgekehrt). marker wird dagegen ZUR
;; INSTALL-ZEIT als String-Literal in den Lambda eingebacken (list-Konstruktion),
;; damit der Handler ihn ohne globalen Zwischenzustand selbst traegt.
(defun vfl-abbruch-handler-installieren (marker)
;; *error* auf eine LAMBDA-LISTE setzen, in die der marker als String-Literal
;; eingebaut ist (list-Konstruktion). AutoLISP ruft *error* als Funktion auf,
;; egal ob (lambda ...) oder (function (lambda ...)) - die reine Lambda-Liste
;; genuegt und vermeidet eval/function-Feinheiten. Alle uebrigen Symbole
;; (old-error, lastEnt, ...) bleiben ungequotet-frei und werden zur Aufrufzeit
;; dynamisch aufgeloest.
(setq *error*
(list 'lambda '(msg)
'(setq *error* old-error)
'(setq *ssg-ils-dim* nil)
(list 'vfl-modus-abbruch-sichern 'lastEnt 'vfl-nummer 'anzahl-gf 'anzahl-vf
'startpunkt 'frame 'as-seite 'es-seite marker)
'(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)))
*error*)
(defun vfl-modus-abbruch-sichern (lastEnt vfl-nummer anzahl-gf anzahl-vf
startpunkt frame as-seite es-seite marker /
e cnt vfl-ins wickel-erg grund fwd n trunc)
@@ -5943,6 +6056,60 @@
(vf-set-es-masse winkel seite)
seite)
;; AS-Winkel (30/90) + Seite abfragen. Gemeinsame Schale fuer die frueher
;; wortgleich in vf-linienzug-modus/-modus2/-modus3 UND vfl-qc-linie-mit-gf
;; ausgeschriebene AS-Praeambel (Winkel-Frage 30/90, Seiten-Frage links/rechts,
;; vf-set-as-masse) - Gegenstueck zu vfl-frage-es-seite. Setzt *vfl-as-winkel*
;; und die AS-Masse (aus-dx/dz) fuer die Variante. Rueckgabe: Seite (links/rechts).
;;
;; seiten-headerkey ist der EINZIGE Unterschied zwischen den Aufrufstellen
;; (modus1: "vfl-aus-seite-header", modus2: "gf-seite-aus-header") und daher
;; Parameter. Die je Modus unterschiedliche VORANGEHENDE Wizard-Vorbereitung
;; (vflw-gruppe-as-impl "AS setzen?" bzw. vflw-gruppe-winkel-seite-impl) bleibt
;; bewusst an der Aufrufstelle - die abzudeckende Winkel/Seite-Frage selbst ist
;; ueberall identisch. vf-frage-element-winkel/vflw-wahl zeigen den Wizard-
;; Winkeldialog bei aktivem Wizard-Modus schon selbst.
(defun vfl-frage-as-winkel-seite (seiten-headerkey / antwort as-seite)
(princ (ssg-text "vf-winkel-aus-header"))
(princ (ssg-text "vf-winkel-90"))
(princ (ssg-text "vf-winkel-30"))
(setq *vfl-as-winkel*
(vfl-in-value "STR"
(function (lambda () (vf-frage-element-winkel "vf-winkel-aus-header"))))) ; 30/90 vor Seite
(princ (ssg-text seiten-headerkey))
(princ (ssg-text "gf-seite-links"))
(princ (ssg-text "gf-seite-rechts"))
(setq antwort (vfl-menu (ssg-text "prompt-wahl-1-2")
(list (ssg-text "gf-seite-links") (ssg-text "gf-seite-rechts")) 1
seiten-headerkey))
(setq as-seite (if (= antwort "2") "rechts" "links"))
(vf-set-as-masse *vfl-as-winkel* as-seite) ; Masse fuer Variante
as-seite)
;; ES-Winkel (30/90) + Seite abfragen - MARKER-FREIE Schale fuer die Modi 2/3,
;; die das ES-Element als eigene Praeambel (Start/Ziel bereits fest) abfragen
;; und ihr eigenes Journal-/Masse-Schema fuehren. Unterscheidet sich bewusst
;; von vfl-frage-es-seite (Modus 1), das zusaetzlich einen Journal-Marker "ES"
;; setzt und ueber vfl-es-masse-setzen laeuft - das ist Teil des Modus-1-
;; Kettenglied-Replays und darf hier NICHT feuern. Setzt *vfl-es-winkel* und
;; die ES-Masse (ein-dx/dz). Rueckgabe: Seite (links/rechts).
(defun vfl-frage-es-winkel-seite (seiten-headerkey / antwort es-seite)
(princ (ssg-text "vf-winkel-ein-header"))
(princ (ssg-text "vf-winkel-90"))
(princ (ssg-text "vf-winkel-30"))
(setq *vfl-es-winkel*
(vfl-in-value "STR"
(function (lambda () (vf-frage-element-winkel "vf-winkel-ein-header"))))) ; 30/90 vor Seite
(princ (ssg-text seiten-headerkey))
(princ (ssg-text "gf-seite-links"))
(princ (ssg-text "gf-seite-rechts"))
(setq antwort (vfl-menu (ssg-text "prompt-wahl-1-2")
(list (ssg-text "gf-seite-links") (ssg-text "gf-seite-rechts")) 1
seiten-headerkey))
(setq es-seite (if (= antwort "2") "rechts" "links"))
(vf-set-es-masse *vfl-es-winkel* es-seite) ; Masse fuer Variante
es-seite)
;; dialog-schon-gezeigt: T, wenn Winkel+Seite BEREITS ueber einen vorherigen
;; kombinierten Dialog (vflw-gruppe-as-impl, "ES-Element setzen?" + Winkel +
;; Seite in einem Bildschirm) abgefragt und in die Pending-Queue gelegt
@@ -6317,32 +6484,11 @@
(setq lastEnt (vf-lastent-ohne-attribute))
(setq anzahl-gf 0 anzahl-vf 0 frame nil)
(setq old-error *error*)
;; Abbruch-Handler: zuerst *error* zuruecksetzen (kein rekursiver
;; Wiedereintritt bei einem Fehler waehrend des Wickelns), dann wickeln.
;; Laeuft der Aufruf innerhalb einer ssg-start-Sitzung (Editier-Pfad via
;; c:VARIOFOERDERER_EDIT -> vfl-edit-ent), wird diese mit ssg-end sauber
;; geschlossen (Undo-Gruppe, gesicherte Systemvariablen, *error* aus dem
;; Sitzungs-Frame) - sonst bliebe die von ssg-start geoeffnete Undo-Gruppe
;; offen.
;; *ssg-ils-dim*: der Editier-/Konverter-Pfad setzt vor dem Replay einen
;; Dimensions-Override und raeumt ihn NACH der Rueckkehr wieder ab. Bei einem
;; Abbruch kehrt der Aufruf nie dorthin zurueck (der Handler beendet den
;; Befehl), daher MUSS der Override hier zurueckgesetzt werden - sonst bliebe
;; er fuer den Rest der Sitzung stehen und alle folgenden Einfuegungen liefen
;; in der falschen Dimension.
(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 "linienzug")
(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))))
;; Scharfen Abbruch-Wickel-Handler installieren (gemeinsam fuer alle drei
;; Modi, siehe vfl-abbruch-handler-installieren). old-error/lastEnt/vfl-nummer/
;; anzahl-gf/anzahl-vf/startpunkt/frame/as-seite/es-seite/dbg-an sind hier als
;; Locals gebunden und werden vom Handler zur Abbruchzeit dynamisch gesehen.
(vfl-abbruch-handler-installieren "linienzug")
(if (vfl-wizard-aktiv)
(vl-catch-all-apply 'vflw-gruppe-punkt-hoehe-impl
@@ -6390,22 +6536,7 @@
;; tragen, wenn diesmal kein AS gewaehlt wird.
(setq *vfl-as-winkel* nil *vfl-es-winkel* nil)
(if as-vorhanden
(progn
(princ (ssg-text "vf-winkel-aus-header"))
(princ (ssg-text "vf-winkel-90"))
(princ (ssg-text "vf-winkel-30"))
(setq *vfl-as-winkel*
(vfl-in-value "STR"
(function (lambda () (vf-frage-element-winkel "vf-winkel-aus-header"))))) ; 30/90 vor Seite
(princ (ssg-text "vfl-aus-seite-header"))
(princ (ssg-text "gf-seite-links"))
(princ (ssg-text "gf-seite-rechts"))
(setq antwort (vfl-menu (ssg-text "prompt-wahl-1-2")
(list (ssg-text "gf-seite-links") (ssg-text "gf-seite-rechts")) 1
"vfl-aus-seite-header"))
(setq as-seite (if (= antwort "2") "rechts" "links"))
(vf-set-as-masse *vfl-as-winkel* as-seite) ; Masse fuer Variante
)
(setq as-seite (vfl-frage-as-winkel-seite "vfl-aus-seite-header"))
)
;; ES-Seite wird erst am Kettenende abgefragt (siehe vfl-frage-es-seite),
;; da das ES-Element erst dort eingefuegt wird.
@@ -8183,22 +8314,29 @@
;; 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"))
journal)
(member marker '("linienzug" "linienzug2" "linienzug3"))
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
(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
@@ -8224,8 +8362,17 @@
;; 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")
;; 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
(setq glieder (vfl-journal-glieder journal))
(setq n (length glieder))
@@ -8281,15 +8428,27 @@
;; 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
;; 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
;; 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.
@@ -8300,12 +8459,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
@@ -8701,14 +8865,115 @@
(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))
;; 2D-Laenge eines Pfad-Objekts: LINE = Abstand Start-Endpunkt, ARC = Sehne
;; (Abstand Start-Endpunkt, dasselbe Mass wie gf-analysiere-kette es fuer die
;; Segmentlaenge nutzt). Nicht-LINE/ARC liefern 0.0 (werden dadurch als "zu
;; kurz" ausgewertet und verworfen). Rein lesend, ohne Nebeneffekt.
(defun vfl-obj-2d-laenge (obj / objname sp ep)
(setq objname (vla-get-ObjectName obj))
(if (or (= objname "AcDbLine") (= objname "AcDbArc"))
(progn
(setq sp (vlax-safearray->list (vlax-variant-value (vla-get-StartPoint obj))))
(setq ep (vlax-safearray->list (vlax-variant-value (vla-get-EndPoint obj))))
(gf-abstand-2d sp ep))
0.0))
;; Aus einer Objektliste alle Elemente unter *vfk-pfad-min-segmentlaenge*
;; herauswerfen (Geister-/Artefakt-Segmente, z.B. von einer Rechteck-Auswahl
;; miterfasste Mini-Objekte). Rueckgabe: (behalten-liste . verworfen-anzahl).
;; Reine Filterung, keine Meldung - der Aufrufer entscheidet ueber die Warnung.
(defun vfl-filter-mini-objekte (obj-liste / behalten verworfen)
(setq behalten '() verworfen 0)
(foreach obj obj-liste
(if (< (vfl-obj-2d-laenge obj) *vfk-pfad-min-segmentlaenge*)
(setq verworfen (1+ verworfen))
(setq behalten (cons obj behalten))))
(cons (reverse behalten) verworfen))
;; 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 filter-erg verworfen)
(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))
;; Geister-/Mini-Objekte VOR der Sortierung ausfiltern: ein von einer
;; Rechteck-Auswahl miterfasstes winziges Segment (unter
;; *vfk-pfad-min-segmentlaenge*) wuerde sonst per Nearest-Neighbor
;; stumm in die Kette gehaengt und ein Geister-Bauteil erzeugen (realer
;; Bug: 14-mm-Bogen am Kettenende). Verworfene mit Grund melden.
(setq filter-erg (vfl-filter-mini-objekte obj-liste))
(setq obj-liste (car filter-erg) verworfen (cdr filter-erg))
(if (> verworfen 0)
(vfl-meldung (ssg-textf "vfl-m3-mini-objekte-verworfen"
(list (itoa verworfen) (rtos *vfk-pfad-min-segmentlaenge* 2 0)))))
(setq kette (if obj-liste (gf-sortiere-objekte obj-liste startpunkt) nil))
(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=========================================")
@@ -8720,34 +8985,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
@@ -8784,24 +9055,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)))
@@ -8811,7 +9083,19 @@
(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)
;; Scharfen Abbruch-Wickel-Handler installieren (gemeinsam, siehe
;; vfl-abbruch-handler-installieren).
(vfl-abbruch-handler-installieren "linienzug3")
(setq n (length segmente))
;; erste/letzte "Linie" fuer die Trimmung bestimmen
(setq first-line -1 last-line -1 i 0)
(while (< i n)
@@ -8830,13 +9114,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)
@@ -8949,12 +9239,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"))
@@ -9199,7 +9498,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
@@ -9264,11 +9563,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)
@@ -9292,22 +9594,7 @@
;; Globals pro Lauf zuruecksetzen (siehe Kommentar in vf-linienzug-modus).
(setq *vfl-as-winkel* nil *vfl-es-winkel* nil)
(if as-vorhanden
(progn
(princ (ssg-text "vf-winkel-aus-header"))
(princ (ssg-text "vf-winkel-90"))
(princ (ssg-text "vf-winkel-30"))
(setq *vfl-as-winkel*
(vfl-in-value "STR"
(function (lambda () (vf-frage-element-winkel "vf-winkel-aus-header"))))) ; 30/90 vor Seite
(princ (ssg-text "gf-seite-aus-header"))
(princ (ssg-text "gf-seite-links"))
(princ (ssg-text "gf-seite-rechts"))
(setq antwort (vfl-menu (ssg-text "prompt-wahl-1-2")
(list (ssg-text "gf-seite-links") (ssg-text "gf-seite-rechts")) 1
"gf-seite-aus-header"))
(setq as-seite (if (= antwort "2") "rechts" "links"))
(vf-set-as-masse *vfl-as-winkel* as-seite) ; Masse fuer Variante
)
(setq as-seite (vfl-frage-as-winkel-seite "gf-seite-aus-header"))
)
;; --- 3. Endpunkt + Z + ES-Seite (NEU in Modus 3) ---
@@ -9330,34 +9617,19 @@
"vfl-es-setzen-frage"))
(setq es-vorhanden (/= antwort "2"))
(if es-vorhanden
(progn
(princ (ssg-text "vf-winkel-ein-header"))
(princ (ssg-text "vf-winkel-90"))
(princ (ssg-text "vf-winkel-30"))
(setq *vfl-es-winkel*
(vfl-in-value "STR"
(function (lambda () (vf-frage-element-winkel "vf-winkel-ein-header"))))) ; 30/90 vor Seite
(princ (ssg-text "gf-seite-ein-header"))
(princ (ssg-text "gf-seite-links"))
(princ (ssg-text "gf-seite-rechts"))
(setq antwort (vfl-menu (ssg-text "prompt-wahl-1-2")
(list (ssg-text "gf-seite-links") (ssg-text "gf-seite-rechts")) 1
"gf-seite-ein-header"))
(setq es-seite (if (= antwort "2") "rechts" "links"))
(vf-set-es-masse *vfl-es-winkel* es-seite) ; Masse fuer Variante
)
(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
@@ -9365,13 +9637,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)))
@@ -9470,9 +9747,14 @@
(if (/= vf-count 1)
(progn
;; Konsolen-Diagnose (fuer den Log / dbg-Nachvollzug) ...
(princ (ssg-textf "vfl-m3-vf-laeufe" (list (itoa vf-count))))
(princ (ssg-text "vfl-m3-vf-lauf-noetig"))
(princ (ssg-text "vfl-m3-vf-lauf-m3b"))
;; ... UND als sichtbare Meldung, damit die Abweisung nicht in der
;; Konsole untergeht (vfl-meldung zeigt bei erlaubter GUI ein alert,
;; headless nur princ - blockiert also einen Batch-Lauf nicht).
(vfl-meldung (ssg-textf "vfl-m3-vf-lauf-alert" (list (itoa vf-count))))
(exit)))
;; Traeger-Stueck = laengste VF-Gerade im Lauf (traegt die ganze Hoehe).
(setq carrier-idx -1 i vf-start)
@@ -9626,22 +9908,10 @@
;; dbg-Hook selbst) und uebernehmen das dbgclose gleich mit, sonst wuerde
;; bei einem Abbruch ab hier doppelt geschlossen.
(setq old-error dbg-old-error)
;; *ssg-ils-dim* hier zuruecksetzen - Begruendung siehe gleichlautende Stelle
;; im Handler von vf-linienzug-modus (Abbruch kehrt nie zum Aufrufer zurueck,
;; der den Override abraeumen wuerde).
(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 "linienzug2")
(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))))
;; Scharfen Abbruch-Wickel-Handler installieren (loest den fruehen dbg-Hook ab,
;; Ruecksprungziel bleibt dbg-old-error via old-error). Gemeinsam fuer alle
;; Modi - siehe vfl-abbruch-handler-installieren.
(vfl-abbruch-handler-installieren "linienzug2")
;; erste/letzte Gerade fuer AS/ES-Trimmung bestimmen
(setq first-line -1 last-line -1 i 0)
(while (< i n)