[FIX] VF-Linienzug: Abbruch beim Editieren brach den VF-Block auf

Die interaktiven Editier-Pfade riefen den Neuaufbau ueber
vl-catch-all-apply auf. Der alte Block ist dort per entdel schon
entfernt, und der Catch faengt einen Abbruch (ESC -> (exit)) VOR
*error* ab - der Abbruch-Wickler vfl-modus-abbruch-sichern kam damit
nie zum Zug. Ergebnis: die komplette Kette blieb als lose Einzelteile
ohne VF_n-Block liegen und war nicht mehr per Doppelklick editierbar.

- vfl-edit-ent (Sektions-Zweig) und vfl-edit-ent2 rufen
  vf-linienzug-modus/-modus2 jetzt DIREKT auf. Nur der
  nicht-interaktive Batch-Konverter vfl-konvertiere-ent behaelt den
  Catch (die Batch-Schleife muss weiterlaufen) und meldet den
  betroffenen Block statt still zu scheitern.
- Beide Abbruch-Handler setzen *ssg-ils-dim* zurueck. Das tat bisher
  nur der Aufrufer, der nach einem Abbruch nicht mehr erreicht wird -
  der Dim-Override blieb fuer die restliche Sitzung stehen.

Wiederherstellung aus der Zeichnung (Sektions-XDATA):

- vfl-segment-xdata-sichern schrieb nur die Slice des LETZTEN Glieds
  einer Schleifen-Iteration. Eine VF-Einheit mit eingebetteten
  Vario-Kurven verlor dadurch ihre eigenen Eingaben. Jetzt wird der
  komplette Journal-Abschnitt der Iteration geschrieben, indiziert mit
  dem ersten Glied-Index darin (neu: vfl-journal-ab-glied,
  vfl-steps-zaehlen). Ein Glied ohne Geometrie verbraucht seinen
  Abschnitt nicht mehr - er wandert in den naechsten Record, der
  Entities bekommt.
- Neue XDATA-App SSG_VF_EDIT_PRE haelt die Praeambel (Startpunkt,
  Starthoehe, AS ja/nein + Winkel/Seite) auf den Entities der ersten
  Iteration. Ohne sie fehlte der Kopf des Journals in jeder Sektion.
- Neuer Befehl VF_SEKTION_RESTORE: Auswahl der losen Geometrie ->
  Sektionen lueckenlos ab Glied 1 zusammensetzen -> stummer Replay ->
  interaktiv weiterbauen. Die alte Geometrie wird erst NACH
  erfolgreichem Neuaufbau geloescht, ein Abbruch laesst sie samt XDATA
  stehen (Versuch wiederholbar). Altbestand ohne Praeambel-XDATA wird
  danach gefragt.

Die .dbg-Dateien bleiben reine Ausgabe und werden von keinem Befehl
gelesen - Wiederherstellungs-Daten gehoeren in die XDATA der Zeichnung.

tests/testdata/vfl_journal_hm05_abbruch.json: Journal der Session vom
2026-08-31 (9 Glieder), gegen das die Slice-/Join-Logik geprueft wurde.
Reine Daten, wird von keinem Befehl gelesen.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-01 15:15:16 +02:00
parent 5e944dd8c2
commit 04a12e5981
6 changed files with 360 additions and 17 deletions
+1 -1
View File
File diff suppressed because one or more lines are too long
+302 -16
View File
@@ -143,8 +143,15 @@
;; "NIL" Abbruch/Default (value nil) "STEP" Glied-Checkpoint (value = Label)
;; *vfl-journal* wird in UMGEKEHRTER Reihenfolge gehalten (neuestes zuerst, cons).
;; *vfl-seg-glied-letzte* = Glied-Stand nach der vorherigen Iteration der
;; Bau-Hauptschleife (fuer die Segment-XDATA, siehe vfl-segment-xdata-sichern).
;; MUSS bei jedem Journal-Start auf 0 stehen, sonst bekaeme das erste Glied
;; eines neuen Baus einen zu hohen Index und die Praeambel wuerde nicht
;; geschrieben.
(if (not (boundp '*vfl-seg-glied-letzte*)) (setq *vfl-seg-glied-letzte* 0))
(defun vfl-journal-reset ()
(setq *vfl-journal* '() *vfl-replay-queue* nil)
(setq *vfl-journal* '() *vfl-replay-queue* nil *vfl-seg-glied-letzte* 0)
(if (boundp '*vflw-pending*) (setq *vflw-pending* nil)))
;; Eintrag anhaengen (vorn, da Reverse-Reihenfolge).
@@ -1287,6 +1294,7 @@
;; forward-journal (Bau-Reihenfolge) als kompakter JSON-Array-String.
(defun vfl-journal->json (forward-journal)
(strcat "[" (vfl-strjoin (mapcar 'vfl-entry->json forward-journal) ",") "]"))
(defun vfl-string->journal (s / out)
(setq out '())
(foreach ln (vfl-strsplit s "\n")
@@ -1365,6 +1373,46 @@
nil))
nil))
;; --- Praeambel-XDATA (eigene App "SSG_VF_EDIT_PRE") -----------------------
;; Die Segment-XDATA (SSG_VF_EDIT_SEG) deckt nur die GLIEDER ab - alles vor
;; dem ersten STEP (Startpunkt, Starthoehe, AS ja/nein + AS-Winkel/-Seite)
;; steht in keiner Slice. Fuer eine vollstaendige Wiederherstellung aus der
;; Zeichnung allein (c:VF_SEKTION_RESTORE) fehlt damit genau der Kopf des
;; Journals. Deshalb wird die Praeambel zusaetzlich als eigene XDATA-App auf
;; die Entities des ERSTEN Gliedes geschrieben - eigene App, weil pro Entity
;; nur ein SSG_VF_EDIT_SEG-Record Platz hat (der gehoert dem Glied).
;; Layout: [0]="linienzug-pre" (Marker), [1..]=Journal-String in 250-Byte-Chunks.
;;
;; Praeambel = alle Journal-Eintraege VOR dem ersten STEP.
(defun vfl-journal-praeambel (forward-journal / out fertig)
(setq out '() fertig nil)
(foreach e forward-journal
(if (and (not fertig) (= (car e) "STEP")) (setq fertig t))
(if (not fertig) (setq out (cons e out))))
(reverse out))
(defun vfl-journal-xdata-schreiben-pre (ent pre-journal / chunks appentry)
(regapp "SSG_VF_EDIT_PRE")
(setq chunks (vfl-chunk-string (vfl-journal-list->string pre-journal) 250))
(setq appentry
(cons "SSG_VF_EDIT_PRE"
(cons (cons 1000 "linienzug-pre")
(mapcar (function (lambda (c) (cons 1000 c))) chunks))))
(entmod (append (entget ent) (list (list -3 appentry))))
ent)
;; Rueckgabe: Praeambel-Journal oder nil (keine/unbekannte Praeambel-XDATA).
(defun vfl-journal-xdata-lesen-pre (ent / xd app-data werte)
(setq xd (entget ent '("SSG_VF_EDIT_PRE")))
(setq app-data (cdr (assoc -3 xd)))
(if app-data
(progn
(setq werte (mapcar 'cdr (cdr (car app-data))))
(if (and werte (= (car werte) "linienzug-pre"))
(vfl-string->journal (apply 'strcat (cdr werte)))
nil))
nil))
;; Wird direkt nach dem Segment-Dispatch-cond in vf-linienzug-modus aufgerufen
;; (per vl-catch-all-apply abgesichert - ein Fehler hier darf den Hauptbau nie
;; abbrechen, rein additive Zusatz-XDATA). seg-lastEnt = Schnappschuss VOR
@@ -1377,13 +1425,31 @@
;; ergaenzt) und schreibt sie auf JEDES seit seg-lastEnt neu erzeugte Entity
;; (entnext-Wanderung, gleiches Muster wie vfl-block-erstellen/
;; vfl-modus-abbruch-sichern).
(defun vfl-segment-xdata-sichern (seg-lastEnt wahl / forward-journal seg-idx seg-journal e cnt slice-label)
(defun vfl-segment-xdata-sichern (seg-lastEnt wahl / forward-journal seg-idx seg-von
seg-journal log-slice e cnt slice-label pre-journal)
(setq forward-journal (reverse *vfl-journal*))
(setq seg-idx (length (vfl-journal-glieder forward-journal)))
;; Erstes Glied DIESER Iteration: eine Iteration kann mehrere Glieder
;; erzeugen (VF-Einheit + eingebettete Vario-Kurven). *vfl-seg-glied-letzte*
;; haelt den Glied-Stand der vorherigen Iteration.
(if (null *vfl-seg-glied-letzte*) (setq *vfl-seg-glied-letzte* 0))
(setq seg-von (1+ *vfl-seg-glied-letzte*))
(setq cnt 0)
(if (> seg-idx 0)
(if (and (> seg-idx 0) (>= seg-idx seg-von))
(progn
(setq seg-journal (vfl-journal-slice forward-journal seg-idx))
;; XDATA: der KOMPLETTE in dieser Iteration entstandene Journal-Abschnitt
;; (Glieder seg-von .. seg-idx), indiziert mit dem ERSTEN Glied-Index.
;; Nur so ist die Kette spaeter luecken- und desync-frei aus der
;; Zeichnung rekonstruierbar (c:VF_SEKTION_RESTORE).
(setq seg-journal (vfl-journal-ab-glied forward-journal seg-von))
;; Fuers Log/die Schema-Validierung weiterhin die Slice des LETZTEN
;; Glieds (unveraendertes Verhalten, siehe Kommentar unten).
(setq log-slice (vfl-journal-slice forward-journal seg-idx))
;; Praeambel (Startpunkt/Starthoehe/AS) bei der ERSTEN Iteration
;; mitschreiben - ohne sie waere die Kette aus der Zeichnung nicht
;; vollstaendig rekonstruierbar (vfl-journal-xdata-schreiben-pre).
;; Danach aendert sich die Praeambel nicht mehr.
(setq pre-journal (if (= seg-von 1) (vfl-journal-praeambel forward-journal) nil))
;; Tatsaechliches Label der geschnittenen Slice (der STEP-Wert am Anfang).
;; Kann von wahl (dem Hauptschleifen-Label) ABWEICHEN: enthaelt die
;; VF-Einheit eine Vario-Kurve, ist DEREN STEP das letzte Glied, seg-idx
@@ -1391,30 +1457,42 @@
;; noch "Horizontal-VF"/"Linie-VF" ist. Fuers Log/die Validierung zaehlt
;; das echte Slice-Label, nicht wahl (sonst falsch etikettiert).
(setq slice-label
(if (and seg-journal (= (car (car seg-journal)) "STEP"))
(cdr (car seg-journal)) wahl))
(if (and log-slice (= (car (car log-slice)) "STEP"))
(cdr (car log-slice)) wahl))
(setq e (if seg-lastEnt (entnext seg-lastEnt) (entnext)))
(while e
(vfl-journal-xdata-schreiben-seg e seg-idx seg-journal)
(vfl-journal-xdata-schreiben-seg e seg-von seg-journal)
(if pre-journal (vfl-journal-xdata-schreiben-pre e pre-journal))
(setq cnt (1+ cnt))
(setq e (entnext e))
)
;; Glied-Stand NUR fortschreiben, wenn wirklich Entities beschrieben
;; wurden. Ein Glied ohne Geometrie (z.B. "VF-Einheit nicht baubar" -
;; Menue-Antwort und Laenge sind journalisiert, gebaut wurde nichts) hat
;; keinen Traeger fuer seine XDATA. Bliebe der Stand trotzdem stehen,
;; waere sein Journal-Abschnitt unauffindbar und die Kette waere ab dort
;; nur noch mit Luecke wiederherstellbar. So wandert der Abschnitt
;; stattdessen in den naechsten Record, der Entities bekommt.
(if (> cnt 0) (setq *vfl-seg-glied-letzte* seg-idx))
;; Diagnose: den tatsaechlichen Segment-Journal-Inhalt als JSON loggen
;; (analog zum Ketten-XDATA-JOURNAL-JSON in vfl-journal-xdata-schreiben)
;; plus die Anzahl der beschriebenen Entities. No-Op ohne offene .dbg.
(dbgmsg (strcat "SEGMENT-XDATA-JSON Glied " (itoa seg-idx) " ("
(if slice-label slice-label "?") ") auf " (itoa cnt) " Entity(s): "
(vfl-journal->json seg-journal)))
(dbgmsg (strcat "SEGMENT-XDATA-JSON Glied " (itoa seg-von)
(if (> seg-idx seg-von) (strcat ".." (itoa seg-idx)) "")
" (" (if slice-label slice-label "?") ") auf " (itoa cnt)
" Entity(s): " (vfl-journal->json seg-journal)))
;; Zusaetzlich benannt loggen (statt roher [INT]/[STR]-Zeilen). Feste
;; Glieder (AS/ES/GF-Bogen/Vario-Kurve) ueber ihr Feld-Schema
;; (GF-Bogen.winkel = 90), die VF-Einheit (Linie-VF/Horizontal-VF, variable
;; Laenge) ueber den Sub-Step-Logger (VF.menue = 4, VF.laenge = ...). Beide
;; validieren, was validierbar ist, und markieren Abweichungen (<!! ...>).
;; Ueber slice-label (echtes Glied), nicht wahl.
;; Bewusst log-slice (genau EIN Glied) - die Schema-Logger erwarten die
;; Slice eines einzelnen Glieds, nicht den Iterations-Abschnitt.
(if (vfl-schema-felder slice-label)
(vfl-schema-log-slice slice-label seg-journal)
(vfl-schema-log-slice slice-label log-slice)
(if (member slice-label '("Linie-VF" "Horizontal-VF"))
(vfl-schema-log-vf slice-label seg-journal)))
(vfl-schema-log-vf slice-label log-slice)))
)
(dbgmsg (strcat "SEGMENT-XDATA: kein Glied vorhanden (" (if wahl wahl "?") ")"))
)
@@ -1465,7 +1543,8 @@
;; zur Lesequelle, *vfl-journal* startet leer und wird bei der erneuten
;; Ausfuehrung neu aufgebaut. Genutzt von vfl-edit-ent und der Wiederaufnahme.
(defun vfl-journal-replay-start (forward-journal)
(setq *vfl-replay-queue* forward-journal *vfl-journal* '())
(setq *vfl-replay-queue* forward-journal *vfl-journal* '()
*vfl-seg-glied-letzte* 0)
(if (boundp '*vflw-pending*) (setq *vflw-pending* nil)))
;; --- Glied-Zerlegung fuer den Editier-Dialog ---
@@ -1507,6 +1586,34 @@
(started (setq out (cons e out))))))
(reverse out))
;; Journal-Eintraege AB dem (from-step-idx)-ten Glied bis zum ENDE des
;; Journals (alle folgenden STEPs inklusive). Gegenstueck zu
;; vfl-journal-slice, das bei genau einem Glied stoppt.
;; Gebraucht fuer die Segment-XDATA: eine Iteration der Bau-Hauptschleife kann
;; MEHRERE Glieder erzeugen (eine VF-Einheit mit eingebetteten Vario-Kurven
;; legt Horizontal-VF/Linie-VF + je Kurve ein eigenes STEP ab). Auf die
;; Entities dieser Iteration muss deshalb der GESAMTE in ihr entstandene
;; Journal-Abschnitt, nicht nur die Slice des letzten Glieds - sonst fehlen
;; die Eingaben der Einheit selbst und die Kette ist aus der Zeichnung nicht
;; mehr vollstaendig rekonstruierbar (c:VF_SEKTION_RESTORE).
(defun vfl-journal-ab-glied (forward-journal from-step-idx / seen out started)
(setq seen 0 out '() started nil)
(foreach e forward-journal
(if started
(setq out (cons e out))
(if (= (car e) "STEP")
(progn
(setq seen (1+ seen))
(if (= seen from-step-idx)
(progn (setq started t) (setq out (cons e out))))))))
(reverse out))
;; Anzahl der Glieder (STEP-Eintraege) in einem Journal-Abschnitt.
(defun vfl-steps-zaehlen (journal / n)
(setq n 0)
(foreach e journal (if (= (car e) "STEP") (setq n (1+ n))))
n)
;; Journal-Eintraege des Glieds (seg-idx) durch (new-seg-journal) ersetzen -
;; alle anderen Glieder (davor UND danach) sowie die Praeambel bleiben
;; unveraendert. Gegenstueck zu vfl-journal-slice (welches genau dieses Glied
@@ -3167,9 +3274,16 @@
;; 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
@@ -4191,7 +4305,18 @@
'vf-linienzug-modus2
'vf-linienzug-modus)))
(setq *ssg-ils-dim* nil) ; Override zuruecksetzen
(if (vl-catch-all-error-p ok) nil T))
;; Fehlgeschlagene Konvertierung NICHT stumm verschlucken: der alte Block
;; ist per entdel schon weg, die Teil-Geometrie liegt frei in der
;; Zeichnung (der *error*-Handler in vf-linienzug-modus kann hier nicht
;; greifen, weil vl-catch-all-apply den Abbruch vorher abfaengt - das ist
;; hier gewollt, damit die Batch-Schleife weiterlaeuft). Meldung mit
;; Blockname, damit der betroffene Block auffindbar bleibt.
(if (vl-catch-all-error-p ok)
(progn
(princ (ssg-textf "vfl-konvert-fehler"
(list bname (vl-catch-all-error-message ok))))
nil)
T))
nil))
(defun vfl-edit-ent (ent / xd marker journal glieder glieder-alle has-as n i pos trunc edit-modus dim)
@@ -4247,7 +4372,20 @@
;; Override auf die Dimension des Bestandsblocks, danach zuruecksetzen.
(if dim (setq *ssg-ils-dim* dim))
(vfl-journal-replay-start trunc)
(vl-catch-all-apply 'vf-linienzug-modus)
;; WICHTIG: DIREKTER Aufruf, KEIN vl-catch-all-apply!
;; Der Neuaufbau ist interaktiv - bricht der Nutzer ihn ab (ESC ->
;; (exit) im Bau-Ablauf), MUSS der *error*-Handler in
;; vf-linienzug-modus laufen und die bis dahin gebaute Teil-Geometrie
;; zu einem VF_n-Block wickeln. Ein vl-catch-all-apply faengt den
;; Abbruch VOR *error* ab: der Handler kaeme nie zum Zug, der alte
;; Block ist durch das entdel oben aber schon weg - die ganze Kette
;; bliebe als loses Einzelteil-Haufen ohne Block in der Zeichnung
;; liegen (nicht mehr per Doppelklick editierbar). Genau das war der
;; Fehler "VF-Block aufgebrochen".
;; Das Abraeumen des Dim-Overrides uebernimmt im Abbruchfall der
;; 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)))))
(princ))
@@ -4265,10 +4403,154 @@
(princ (ssg-text "vfl-edit2-reset-info"))
(if dim (setq *ssg-ils-dim* dim))
(vfl-journal-replay-start journal)
(vl-catch-all-apply 'vf-linienzug-modus2)
;; 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)
(setq *ssg-ils-dim* nil)
(princ))
;; ============================================================
;; RECOVERY: Kette aus der Sektions-XDATA der Zeichnung neu aufbauen
;; ============================================================
;; Wofuer: bleibt eine Linienzug-Kette als LOSE Geometrie ohne VF_n-Block in
;; der Zeichnung liegen (der Block war schon per entdel weg, der Neuaufbau
;; wurde abgebrochen und konnte nicht gewickelt werden), ist sie nicht mehr per
;; Doppelklick editierbar. Die Eingaben sind aber nicht verloren: jedes Entity
;; traegt den Journal-Abschnitt der Iteration, in der es entstand
;; (SSG_VF_EDIT_SEG, indiziert mit dem ERSTEN Glied-Index darin - siehe
;; vfl-segment-xdata-sichern), und die Entities der ersten Iteration
;; zusaetzlich die Praeambel (SSG_VF_EDIT_PRE). Daraus laesst sich das
;; Ketten-Journal zusammensetzen und die Kette identisch neu bauen - diesmal
;; sauber als VF_n-Block mit Ketten-XDATA.
;;
;; Quelle ist AUSSCHLIESSLICH die Zeichnung selbst. Die .dbg-Dateien sind
;; reine Ausgabe und werden hier bewusst NICHT gelesen (sie werden bei jedem
;; Lauf neu angelegt, siehe dbgopen).
;;
;; Ablauf: Geometrie waehlen -> Sektionen sammeln und nach Glied-Index sortieren
;; -> Journal (Praeambel + Glieder 1..k) stumm abspielen -> danach normal
;; weiterbauen. Die alte Geometrie wird erst NACH einem erfolgreichen Neuaufbau
;; geloescht (bricht der Neuaufbau ab, bleibt sie samt ihrer XDATA stehen und
;; der Versuch ist wiederholbar).
;; Praeambel interaktiv erfragen - nur fuer Altbestand ohne SSG_VF_EDIT_PRE
;; (Ketten, die vor der Einfuehrung der Praeambel-XDATA gebaut wurden).
;; Reihenfolge/Arten MUESSEN dem Kopf von vf-linienzug-modus entsprechen:
;; PT (Startpunkt), REAL (Starthoehe), STR (AS ja="1"/nein="2") und bei AS
;; zusaetzlich STR (Winkel "30"/"90") + STR (Seite links="1"/rechts="2").
;; Rueckgabe: Praeambel-Journal oder nil (Abbruch).
(defun vfl-praeambel-erfragen ( / p h as w s out)
(princ (ssg-text "vfl-restore-keine-praeambel"))
(setq p (getpoint (ssg-text "vfl-prompt-startpunkt-kette")))
(if (null p)
nil
(progn
(setq h (getreal (ssg-textf "vfl-prompt-hoehe-startpunkt-kette"
(list (rtos (caddr p) 2 1)))))
(if (null h) (setq h (caddr p)))
(initget "Ja Nein")
(setq as (getkword (ssg-text "vfl-restore-frage-as")))
(if (null as) (setq as "Ja"))
(setq out (list (cons "PT" p) (cons "REAL" h)
(cons "STR" (if (= as "Nein") "2" "1"))))
(if (/= as "Nein")
(progn
;; gleiche Frage wie im Bau-Ablauf (liefert "30"/"90")
(setq w (vf-frage-element-winkel "vf-winkel-aus-header"))
(initget "Links Rechts")
(setq s (getkword (ssg-text "vfl-restore-frage-as-seite")))
(if (null s) (setq s "Links"))
(setq out (append out (list (cons "STR" w)
(cons "STR" (if (= s "Rechts") "2" "1")))))))
out)))
;; Sektionen aus einer Auswahl sammeln. Rueckgabe: Liste (idx . slice),
;; aufsteigend nach idx, jeder Index nur EINMAL (alle Entities eines Gliedes
;; tragen dieselbe Slice).
(defun vfl-sektionen-sammeln (ss / i n ent seg idx out)
(setq out '() i 0 n (sslength ss))
(while (< i n)
(setq ent (ssname ss i))
(setq seg (vfl-journal-xdata-lesen-seg ent))
(if seg
(progn
(setq idx (car seg))
(if (not (assoc idx out)) (setq out (cons (cons idx (cdr seg)) out)))))
(setq i (1+ i)))
(vl-sort out (function (lambda (a b) (< (car a) (car b))))))
;; Praeambel aus der Auswahl lesen (erstes Entity, das eine traegt).
(defun vfl-praeambel-sammeln (ss / i n pre)
(setq i 0 n (sslength ss) pre nil)
(while (and (< i n) (null pre))
(setq pre (vfl-journal-xdata-lesen-pre (ssname ss i)))
(setq i (1+ i)))
pre)
(defun c:VF_SEKTION_RESTORE ( / ss sektionen pre journal teile k erwartet luecke
i n sek e alt-liste)
(princ (ssg-text "vfl-restore-prompt-auswahl"))
(setq ss (ssget))
(cond
((null ss) (princ (ssg-text "vfl-abgebrochen")))
((null (setq sektionen (vfl-sektionen-sammeln ss)))
(princ (ssg-text "vfl-restore-keine-sektionen")))
(t
;; Sektionen aneinanderhaengen, solange sie LUECKENLOS ab Glied 1
;; anschliessen. Ein Sektions-Record ist mit dem Index seines ERSTEN
;; Gliedes abgelegt und kann mehrere Glieder enthalten (VF-Einheit mit
;; Vario-Kurven) - der naechste erwartete Index ist daher
;; erster-Index + Anzahl der Glieder darin, nicht einfach +1.
;; Bei einer Luecke wird nur der Anfang wiederhergestellt: ein fehlendes
;; Glied in der Mitte wuerde alle folgenden an die falsche Position setzen.
(setq teile '() k 0 erwartet 1 luecke nil)
(foreach sek sektionen
(if (and (not luecke) (= (car sek) erwartet))
(progn
(setq teile (cons (cdr sek) teile))
(setq k (+ k (vfl-steps-zaehlen (cdr sek))))
(setq erwartet (1+ k)))
(setq luecke t)))
(if luecke
(princ (ssg-textf "vfl-restore-luecke" (list (itoa erwartet) (itoa k)))))
(if (= k 0)
(princ (ssg-text "vfl-restore-keine-sektionen"))
(progn
;; Praeambel: aus der Zeichnung, sonst erfragen (Altbestand ohne
;; SSG_VF_EDIT_PRE).
(setq pre (vfl-praeambel-sammeln ss))
(if (null pre) (setq pre (vfl-praeambel-erfragen)))
(if (null pre)
(princ (ssg-text "vfl-abgebrochen"))
(progn
(setq journal (apply 'append (cons pre (reverse teile))))
(princ (ssg-textf "vfl-restore-gefunden"
(list (itoa k) (itoa (length journal)))))
;; Enames der alten Geometrie merken - geloescht wird ERST nach
;; einem erfolgreichen Neuaufbau (siehe unten).
(setq alt-liste '() i 0 n (sslength ss))
(while (< i n)
(setq alt-liste (cons (ssname ss i) alt-liste))
(setq i (1+ i)))
;; Neu bauen. DIREKTER Aufruf: bricht der Bau ab, wickelt der
;; *error*-Handler in vf-linienzug-modus den Zwischenstand zu
;; einem Block - und die Zeilen danach (Loeschen) laufen NICHT
;; mehr. Die alte Geometrie samt ihrer Sektions-XDATA bleibt also
;; erhalten und der Versuch ist wiederholbar.
(vfl-journal-replay-start journal)
(vf-linienzug-modus)
;; Erfolg: alte lose Geometrie entfernen. Sie liegt VOR lastEnt und
;; ist deshalb nicht im neuen Block gelandet (vgl.
;; vfl-block-erstellen), wuerde aber deckungsgleich darunter
;; liegenbleiben.
(foreach e alt-liste (if e (entdel e)))
(princ (ssg-textf "vfl-restore-geloescht"
(list (itoa (length alt-liste)))))))))))
(princ))
;; DCL-Dialog nach Doppelklick: Editier-Modus waehlen.
;; n = Anzahl Glieder (nur fuer die Kopfzeile). Vorbelegung "rueck" (das
;; bisherige Verhalten, geringste Ueberraschung). Rueckgabe: "rueck", "glied"
@@ -5310,9 +5592,13 @@
;; 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
+38
View File
@@ -377,6 +377,44 @@ interaktive Linienzug-Ablauf weiter (Abschnitt 5).
Einzige Eingabe — Rest laeuft automatisch (Attribute aggregiert, Luecken
werden gemeldet).
**VF_SEKTION_RESTORE — lose Kette aus der Zeichnung wiederherstellen**
| Feld | Steuerelement | Werte |
|---|---|---|
| Lose Linienzug-Geometrie | Objektauswahl (`ssget`) | die Einzelteile der Kette (Bloecke, Linien, Boegen) |
| Startpunkt / Starthoehe / AS | nur bei Altbestand ohne Praeambel-XDATA | `getpoint` / `getreal` / Ja-Nein + Winkel + Seite |
Wofuer: bleibt eine Kette als **lose Geometrie ohne `VF_n`-Block** liegen (der
Block war beim Editieren schon per `entdel` weg, der Neuaufbau brach ab und
konnte nicht gewickelt werden), ist sie nicht mehr per Doppelklick editierbar.
Die Eingaben stecken aber weiterhin in der Zeichnung:
| XDATA-App | Traeger | Inhalt |
|---|---|---|
| `SSG_VF_EDIT` | `VF_n`-Block | volles Ketten-Journal (Marker `linienzug`/`linienzug2`) |
| `SSG_VF_EDIT_SEG` | jedes Entity | Journal-Abschnitt **der Iteration**, in der es entstand, indiziert mit dem **ersten** Glied-Index darin |
| `SSG_VF_EDIT_PRE` | Entities des ersten Gliedes | Praeambel (Startpunkt, Starthoehe, AS ja/nein + Winkel/Seite) |
`VF_SEKTION_RESTORE` liest die Sektionen der Auswahl, haengt sie
lueckenlos ab Glied 1 aneinander (ein Sektions-Record kann **mehrere** Glieder
enthalten — eine VF-Einheit mit eingebetteten Vario-Kurven legt pro Kurve ein
eigenes STEP ab, der naechste erwartete Index ist daher
`erster Index + Anzahl Glieder im Record`), spielt das Journal stumm ab und
baut danach normal weiter. Die alte Geometrie wird **erst nach erfolgreichem**
Neuaufbau geloescht — bricht der Bau ab, bleibt sie samt XDATA stehen und der
Versuch ist wiederholbar.
Grenzen: nur Modus 1 (Modus 2 schreibt keine Sektions-XDATA); bei einer Luecke
wird nur der lueckenlose Anfang wiederhergestellt und die fehlende Sektion
gemeldet. Ketten, die vor der Umstellung auf Iterations-Abschnitte gebaut
wurden, haben unvollstaendige Sektions-XDATA (eine VF-Einheit hinterliess nur
die Slice ihrer letzten Vario-Kurve) und sind daher nur bis zur ersten Luecke
wiederherstellbar.
Die `.dbg`-Dateien sind **reine Ausgabe** und werden von keinem Befehl
gelesen — sie werden bei jedem Lauf neu angelegt (`dbgopen` oeffnet mit `"w"`).
Wiederherstellungs-Daten gehoeren ausschliesslich in die XDATA der Zeichnung.
---
## 8. Legacy-Konsolen-Pfad
+9
View File
@@ -61,6 +61,15 @@
"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...",
"vfl-konvert-fehler": "\n>>> FEHLER bei der Umwandlung von %1: %2 - der alte Block ist entfernt, die Teil-Geometrie liegt frei in der Zeichnung.",
"vfl-restore-prompt-auswahl": "\nLose Linienzug-Geometrie waehlen (die Sektions-XDATA der Objekte wird ausgelesen):",
"vfl-restore-keine-sektionen": "\n>>> In der Auswahl steckt keine Sektions-XDATA (SSG_VF_EDIT_SEG) - daraus laesst sich keine Kette wiederherstellen.",
"vfl-restore-luecke": "\n>>> WARNUNG: Sektion %1 fehlt in der Auswahl - nur die Glieder 1..%2 werden wiederhergestellt.",
"vfl-restore-gefunden": "\n>>> %1 Sektion(en) gefunden, %2 Journal-Eintraege werden abgespielt.",
"vfl-restore-keine-praeambel": "\n>>> Keine Praeambel-XDATA gefunden (Kette vor deren Einfuehrung gebaut) - Startpunkt, Starthoehe und AS-Element werden jetzt erfragt.",
"vfl-restore-frage-as": "\nAS-Element am Kettenanfang vorhanden? [Ja/Nein] <Ja>: ",
"vfl-restore-frage-as-seite": "\nAS-Element Seite? [Links/Rechts] <Links>: ",
"vfl-restore-geloescht": "\n>>> Neuaufbau fertig - %1 alte lose Entity(s) geloescht.",
"omni-alle-winkel": "alle Winkel",
"omni-grad": " Grad",
"omni-bogen-keine-gefunden": "Keine Boegen fuer %1%2 gefunden.",
+9
View File
@@ -61,6 +61,15 @@
"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...",
"vfl-konvert-fehler": "\n>>> ERROR converting %1: %2 - the old block is gone, the partial geometry is loose in the drawing.",
"vfl-restore-prompt-auswahl": "\nSelect the loose chain geometry (the section XDATA of the objects is read):",
"vfl-restore-keine-sektionen": "\n>>> The selection carries no section XDATA (SSG_VF_EDIT_SEG) - no chain can be restored from it.",
"vfl-restore-luecke": "\n>>> WARNING: section %1 is missing from the selection - only segments 1..%2 will be restored.",
"vfl-restore-gefunden": "\n>>> %1 section(s) found, replaying %2 journal entries.",
"vfl-restore-keine-praeambel": "\n>>> No preamble XDATA found (chain built before it existed) - start point, start height and AS element will be asked now.",
"vfl-restore-frage-as": "\nAS element at the start of the chain? [Ja/Nein] <Ja>: ",
"vfl-restore-frage-as-seite": "\nAS element side? [Links/Rechts] <Links>: ",
"vfl-restore-geloescht": "\n>>> Rebuild finished - %1 old loose entity(s) deleted.",
"omni-alle-winkel": "all angles",
"omni-grad": " deg",
"omni-bogen-keine-gefunden": "No arcs found for %1%2.",
+1
View File
@@ -0,0 +1 @@
[{"kind":"PT","value":[3745.1661,556.39254,2000]},{"kind":"REAL","value":2154},{"kind":"STR","value":"1"},{"kind":"STR","value":"90"},{"kind":"STR","value":"1"},{"kind":"STEP","value":"Linie-GF"},{"kind":"STR","value":"1"},{"kind":"DL","value":1555.085752},{"kind":"REAL","value":90},{"kind":"STR","value":"2"},{"kind":"REAL","value":3},{"kind":"STR","value":"3"},{"kind":"STEP","value":"Horizontal-VF"},{"kind":"STR","value":"4"},{"kind":"DL","value":4299.683981},{"kind":"STR","value":"2"},{"kind":"STR","value":"2"},{"kind":"STR","value":"2"},{"kind":"STR","value":"2"},{"kind":"STR","value":"2"},{"kind":"STEP","value":"Vario-Kurve"},{"kind":"INT","value":90},{"kind":"STR","value":"2"},{"kind":"STR","value":"2"},{"kind":"STR","value":"2"},{"kind":"STR","value":"1"},{"kind":"DL","value":1273.577478},{"kind":"STR","value":"2"},{"kind":"STR","value":"2"},{"kind":"STR","value":"2"},{"kind":"STR","value":"2"},{"kind":"STEP","value":"Vario-Kurve"},{"kind":"INT","value":90},{"kind":"STR","value":"2"},{"kind":"STR","value":"2"},{"kind":"STR","value":"1"},{"kind":"STR","value":"2"},{"kind":"STR","value":"1"},{"kind":"STEP","value":"Linie-GF"},{"kind":"STR","value":"2"},{"kind":"DL","value":959.99952},{"kind":"STR","value":"2"},{"kind":"REAL","value":3},{"kind":"STR","value":"3"},{"kind":"STEP","value":"Linie-VF"},{"kind":"STR","value":"3"},{"kind":"DL","value":3160},{"kind":"REAL","value":2345},{"kind":"STEP","value":"Linie-VF"},{"kind":"STR","value":"3"},{"kind":"DL","value":412.867603},{"kind":"STEP","value":"Linie-VF"},{"kind":"STR","value":"3"},{"kind":"DL","value":1900},{"kind":"REAL","value":2350},{"kind":"STEP","value":"Linie-GF"},{"kind":"STR","value":""}]