From 5bb6bb82417decf722650a55fe48610dd9e0cc9c Mon Sep 17 00:00:00 2001 From: Yuelin Wang Date: Tue, 21 Jul 2026 14:05:13 +0200 Subject: [PATCH] fix: Z-Versatz bei GF/VF behoben (OSMODE=0 im Wrap ssg-block-wrap-welt); gepickte Hoehe als Einfuegehoehe im GF-Dialog --- Lisp/Gefaellestrecke.lsp | 71 +++++++++++++++++++++++++++++++--------- Lisp/ssg_core.lsp | 46 ++++++++++++++++++++++++++ Lisp/vf_core.lsp | 11 +++---- Lisp/vf_linienzug.lsp | 11 +++---- 4 files changed, 111 insertions(+), 28 deletions(-) diff --git a/Lisp/Gefaellestrecke.lsp b/Lisp/Gefaellestrecke.lsp index 99b641f..355700f 100644 --- a/Lisp/Gefaellestrecke.lsp +++ b/Lisp/Gefaellestrecke.lsp @@ -1438,7 +1438,7 @@ startpunkt last-ent nach-aus-pt entry-hz L-first-seg es-seite / gf-bname gf-ss ent gf-insert typ-str anzahl-gf - gf-winkel-str i) + gf-winkel-str i gf-g10z gf-korr-dz gf-osmode-alt) ;; Beschriftung: Mitte der ersten Geraden, 400mm senkrecht versetzt (gf-make-label gf-nummer hoehe-von hoehe-bis deltaH deltaL L-gf-str winkel n-separator nach-aus-pt entry-hz L-first-seg) @@ -1479,15 +1479,26 @@ (ssadd ent gf-ss) (setq ent (entnext ent)) ) - ;; Block definieren und einfuegen (ATTREQ/ATTDIA=0: keine interaktive Abfrage) - (setvar "ATTREQ" 0) - (setvar "ATTDIA" 0) - (command "_.-BLOCK" gf-bname startpunkt gf-ss "") - (command "_.INSERT" gf-bname startpunkt 1.0 1.0 0.0) - (setvar "ATTREQ" 1) + ;; Block definieren und einfuegen. ssg-block-wrap-welt schaltet dabei den + ;; Objektfang (OSMODE=0), die Elevation (0) und das BKS (Welt) sauber ab - + ;; sonst wird der uebergebene Einfuegepunkt umgefangen bzw. der OCS-Skew der + ;; gekippten Elemente schlaegt durch (Ursache des Z-Versatz-Bugs). + (ssg-block-wrap-welt gf-bname startpunkt gf-ss) ;; Attribute auf das eingefuegte INSERT-Objekt setzen (volle Werteliste; ;; nicht vorhandene Tags ignoriert ssg-attrib-set-on -> reduzierter Satz ok). (setq gf-insert (entlast)) + ;; Kette wurde bei Z=0 gebaut; der OSMODE=0-Wrap loest den OCS-Skew der + ;; gekippten Elemente sauber zur logischen Position (Z=0) auf. Den fertigen + ;; GF_n-Block daher nur noch senkrecht auf die Zielhoehe heben (OSMODE=0, + ;; sonst faengt _.MOVE die Punkte auf Objekte um). gf-g10z faengt einen + ;; evtl. Rest-Z im Einfuegepunkt ab. + (setq gf-g10z (cadddr (assoc 10 (entget gf-insert)))) + (setq gf-korr-dz (- hoehe-von gf-g10z)) + (setq gf-osmode-alt (getvar "OSMODE")) + (setvar "OSMODE" 0) + (if (> (abs gf-korr-dz) 1e-6) + (command "_.MOVE" gf-insert "" (list 0.0 0.0 0.0) (list 0.0 0.0 gf-korr-dz))) + (setvar "OSMODE" gf-osmode-alt) (ssg-attrib-set-on gf-insert (list (cons "Bezeichnung" gf-bname) @@ -1533,9 +1544,22 @@ ein-hz rad-ein xu-ein startframe aktuell-frame stau-endpunkt sep-endpunkt sep-frame - gf-deltaH L-gf-str nach-aus-pt gf-insert) + gf-deltaH L-gf-str nach-aus-pt gf-insert + ziel-hoehe alt-elev) (if (null as-winkel) (setq as-winkel "90")) (if (null es-winkel) (setq es-winkel "90")) + ;; Gesamte Operation mit ELEVATION=0 fahren. Fing man den Startpunkt auf + ;; einen hohen Punkt, kann ELEVATION != 0 sein und veraendert, wie die + ;; gekippten Elemente gezeichnet werden (OCS-Skew wird sonst inkonsistent + ;; absorbiert -> Rest-Versatz). Mit ELEVATION=0 ist der Skew immer 31.945. + (setq alt-elev (getvar "ELEVATION")) + (setvar "ELEVATION" 0.0) + ;; Gepickte Zielhoehe merken und die Kette intern bei Z=0 aufbauen. Das + ;; entkoppelt den (hoehenunabhaengigen) OCS-Skew der gekippten Elemente von + ;; der Zielhoehe: Elemente immer bei 0 platzieren, den fertigen (nicht + ;; gekippten) GF_n-Block danach in gf-block-erstellen auf ziel-hoehe heben. + (setq ziel-hoehe (caddr startpunkt)) + (setq startpunkt (list (car startpunkt) (cadr startpunkt) 0.0)) (setq as-block (strcat "AS_Element_" as-winkel "_" as-seite)) (setq es-block (strcat "ES_Element_" es-winkel "_" es-seite)) (if (not *lib-initialized*) (gf-init-bibliothek)) @@ -1601,8 +1625,11 @@ (setq gf-insert (gf-block-erstellen "standard" as-seite gf-nummer - (caddr startpunkt) - (caddr endpunkt) + ;; hoehe-von = Zielhoehe; hoehe-bis = Zielhoehe + (relative Endhoehe der + ;; bei Z=0 gebauten Kette). So sind die Hoehen-Attribute korrekt, obwohl + ;; die Kette intern bei 0 liegt (der GF_n-Block wird spaeter angehoben). + ziel-hoehe + (+ ziel-hoehe (caddr endpunkt)) gf-deltaH (float deltaL-total) L-gf-str @@ -1616,11 +1643,13 @@ ;; auf das GF_N-INSERT schreiben, damit GEFAELLESTRECKE_EDIT die Strecke ;; verlustfrei nachbauen kann. Nicht Teil des Sivas-Attributsatzes. (gf-xdata-schreiben gf-insert hz winkel as-winkel es-winkel - (caddr startpunkt) deltaL-total) + ziel-hoehe deltaL-total) (princ "\n\n=========================================") (princ (ssg-text "gf-status-erfolgreich-eingefuegt")) (princ "\n=========================================") + ;; ELEVATION wiederherstellen (Nutzer-Umgebung nicht dauerhaft veraendern). + (setvar "ELEVATION" alt-elev) ;; Rueckgabe: (ename echtes-deltaH echtes-deltaL) - volle Fliesskomma- ;; Genauigkeit, unabhaengig von der auf ganze mm gerundeten HOEHE_VON/ ;; HOEHE_BIS-Attribut-Darstellung im GF_N-Block. @@ -1640,7 +1669,7 @@ ;; Rueckgabe: (deltaL winkel hz-winkel as-seite es-seite einfuegehoehe ;; as-winkel es-winkel) ;; oder nil bei Abbruch / fehlendem Dialog. -(defun gf-dialog-eingabe ( prefill / dcl-pfad dat ergebnis +(defun gf-dialog-eingabe ( prefill hoehe-vorbelegung / dcl-pfad dat ergebnis dlg-deltal dlg-hoehe dlg-winkel dlg-richtung dlg-aus dlg-ein dlg-aus-winkel dlg-ein-winkel @@ -1658,8 +1687,12 @@ (set_tile "deltal" (if prefill (rtos (cdr (assoc "deltaL" prefill)) 2 0) (rtos (ssg-cfg-or "gefaelle" "default_delta_l" 5000.0) 2 0))) + ;; Einfuegehoehe: 1) explizite Vorbelegung (gepickte Punkthoehe, Modus 1), + ;; 2) prefill (Edit), 3) Default "0". (set_tile "einfuegehoehe" - (if prefill (rtos (cdr (assoc "einfuegehoehe" prefill)) 2 1) "0")) + (cond (hoehe-vorbelegung (rtos hoehe-vorbelegung 2 1)) + (prefill (rtos (cdr (assoc "einfuegehoehe" prefill)) 2 1)) + (t "0"))) (set_tile "winkel" (if prefill (rtos (cdr (assoc "winkel" prefill)) 2 1) (rtos (ssg-cfg-or "gefaelle" "default_winkel" 3.0) 2 1))) @@ -1966,12 +1999,14 @@ ;; Modus 1: Manuelle Eingabe via DCL-Dialog (t (princ (ssg-text "gf-modus1-header")) - ;; Startpunkt (X/Y) in der Zeichnung waehlen; Z kommt aus dem Dialog + ;; Startpunkt (X/Y/Z) in der Zeichnung waehlen. Faengt man einen Punkt mit + ;; Hoehe (z.B. Basispunkt Z=12000), wird diese als Einfuegehoehe in den + ;; Dialog vorbelegt - der Nutzer kann sie dort bestaetigen oder aendern. (setq startpunkt-fuer-einfuegen (getpoint (ssg-text "gf-prompt-startpunkt-aus"))) (if (null startpunkt-fuer-einfuegen) (setq startpunkt-fuer-einfuegen '(0 0 0))) - (setq dlg-werte (gf-dialog-eingabe nil)) + (setq dlg-werte (gf-dialog-eingabe nil (caddr startpunkt-fuer-einfuegen))) (if (null dlg-werte) (princ (ssg-text "gf-status-abgebrochen")) (progn @@ -1982,7 +2017,11 @@ es-seite (nth 4 dlg-werte) gf-as-winkel (nth 6 dlg-werte) gf-es-winkel (nth 7 dlg-werte)) - ;; Einfuegehoehe (Z) aus Dialog auf gewaehlten Startpunkt anwenden + ;; Einfuegehoehe = Dialogwert (nth 5), der mit der gepickten Hoehe + ;; vorbelegt wurde. So gewinnt die gepickte Hoehe standardmaessig, + ;; bleibt aber im Dialog editierbar. Nur diese Z-Hoehe zaehlt (X/Y + ;; vom gefangenen Punkt) -> geht als ziel-hoehe in die Attribute und + ;; als finale Hoehe in den GF_n-Move (gf-block-erstellen). (setq startpunkt-fuer-einfuegen (list (car startpunkt-fuer-einfuegen) (cadr startpunkt-fuer-einfuegen) diff --git a/Lisp/ssg_core.lsp b/Lisp/ssg_core.lsp index df84901..03c945f 100644 --- a/Lisp/ssg_core.lsp +++ b/Lisp/ssg_core.lsp @@ -73,6 +73,52 @@ ) +;; ------------------------------------------------------------ +;; BLOCK-WRAP MIT GARANTIERT WELTPARALLELEM BKS +;; ------------------------------------------------------------ +;; Fasst die Entities in ss zu einem Block bname zusammen und fuegt ihn am +;; Welt-Punkt basispkt-welt wieder ein. Setzt das BKS dazu temporaer hart +;; auf Welt und stellt es danach wieder her. +;; +;; Hintergrund (31.95mm-Z-Versatz-Bug): (command "_.-BLOCK"/"_.INSERT" ...) +;; rechnet Punktargumente im AKTUELLEN BKS. Bei einem vom Welt-KS +;; abweichenden BKS ging der korrekt via (trans ...) umgerechnete Z-Wert +;; beim _.-BLOCK -> _.INSERT-Rundlauf verloren, sodass der fertige Block +;; um die BKS-Hoehe (z.B. 31.95mm) in Z verschoben wurde - obwohl die +;; ELEVATION-Systemvariable 0 war. Bei BKS=Welt liegen Objekte, Basispunkt +;; und Einfuegepunkt alle bei WCS-Z ohne jede Umrechnungs-Mehrdeutigkeit; +;; ein bei WCS-Z=0 platziertes Element bleibt garantiert bei Z=0. +;; +;; Rueckgabe: das eingefuegte INSERT-Objekt (entlast). +(defun ssg-block-wrap-welt (bname basispkt-welt ss / alt-attreq alt-attdia alt-elev alt-osmode) + (setq alt-attreq (getvar "ATTREQ") + alt-attdia (getvar "ATTDIA") + alt-elev (getvar "ELEVATION") + alt-osmode (getvar "OSMODE")) + (setvar "ATTREQ" 0) + (setvar "ATTDIA" 0) + ;; OSMODE=0: laufenden Objektfang abschalten. Sonst kann _.INSERT den + ;; explizit uebergebenen Einfuegepunkt (X,Y,0) auf ein an derselben X/Y-Stelle + ;; liegendes Objekt umfangen - z.B. den gefangenen Basispunkt bei Z=12000 -> + ;; der Block landet auf 12000 statt 0 (12000er-Bug). + (setvar "OSMODE" 0) + ;; ELEVATION=0: sonst kann _.INSERT die Z-Hoehe aus der aktuellen Elevation + ;; statt aus dem uebergebenen Punkt ziehen. + (setvar "ELEVATION" 0.0) + ;; BKS temporaer auf Welt; _Previous stellt danach das vorige BKS wieder her. + (command "_.UCS" "_World") + ;; basispkt-welt ist ein Welt-Punkt; bei BKS=Welt ist er zugleich BKS-Punkt. + (command "_.-BLOCK" bname basispkt-welt ss "") + (command "_.INSERT" bname basispkt-welt 1.0 1.0 0.0) + (command "_.UCS" "_Previous") + (setvar "OSMODE" alt-osmode) + (setvar "ELEVATION" alt-elev) + (setvar "ATTREQ" alt-attreq) + (setvar "ATTDIA" alt-attdia) + (entlast) +) + + ;; ------------------------------------------------------------ ;; BENUTZER-ABFRAGEN ;; ------------------------------------------------------------ diff --git a/Lisp/vf_core.lsp b/Lisp/vf_core.lsp index 3e59657..bd23b43 100644 --- a/Lisp/vf_core.lsp +++ b/Lisp/vf_core.lsp @@ -1104,12 +1104,11 @@ (setq vf-bname (strcat "VF_" (itoa vf-nummer))) (if (> (sslength vf-ss) 0) (progn - (setvar "ATTREQ" 0) - (setvar "ATTDIA" 0) - (command "_.-BLOCK" vf-bname startpunkt vf-ss "") - (command "_.INSERT" vf-bname startpunkt 1.0 1.0 0.0) - (setvar "ATTREQ" 1) - (setq vf-insert (entlast)) + ;; Block definieren und einfuegen mit garantiert weltparallelem BKS. + ;; startpunkt ist ein Welt-Punkt; ssg-block-wrap-welt setzt das BKS + ;; temporaer auf Welt (verhindert den 31.95mm-Z-Versatz bei + ;; abweichendem BKS) und stellt es danach wieder her. + (setq vf-insert (ssg-block-wrap-welt vf-bname startpunkt vf-ss)) (setq montagehoehe-m (/ (+ hoehe-von hoehe-bis) 2000.0)) ;; L_GF_m: kommagetrennte Segmentlaengen in Metern (vorne,hinten), ;; analog L_GF_m in Gefaellestrecke.lsp. diff --git a/Lisp/vf_linienzug.lsp b/Lisp/vf_linienzug.lsp index 0829dd0..72da806 100644 --- a/Lisp/vf_linienzug.lsp +++ b/Lisp/vf_linienzug.lsp @@ -821,12 +821,11 @@ (ssadd ent vfl-ss) (setq ent (entnext ent)) ) - (setvar "ATTREQ" 0) - (setvar "ATTDIA" 0) - (command "_.-BLOCK" vfl-bname startpunkt vfl-ss "") - (command "_.INSERT" vfl-bname startpunkt 1.0 1.0 0.0) - (setvar "ATTREQ" 1) - (setq vfl-insert (entlast)) + ;; Block definieren und einfuegen mit garantiert weltparallelem BKS. + ;; startpunkt ist ein Welt-Punkt; ssg-block-wrap-welt setzt das BKS + ;; temporaer auf Welt (verhindert den 31.95mm-Z-Versatz bei abweichendem + ;; BKS, siehe Kommentar dort) und stellt es danach wieder her. + (setq vfl-insert (ssg-block-wrap-welt vfl-bname startpunkt vfl-ss)) ;; Werte (volle Liste; nicht vorhandene Tags ignoriert ssg-attrib-set-on) (ssg-attrib-set-on vfl-insert (list