b8e8d0b0a0
Neues Modul KettenFoerderer.lsp: baut aus KF_UM_<winkel>, KF_LAENGE und KF_AN_<winkel> (je KS_AUS auf KS_EIN) plus der Draufsicht KF_2D einen Block KF_<n>. Die Bausteine werden aufgerichtet eingebaut (Rz*Rx(90)*Rz), die Hoehe laeuft in Z; KF_2D liegt deckungsgleich mit der Kette. Der Einbauwinkel jedes Folgebausteins wird aus der Richtung des KS_AUS seines Vorgaengers gemessen, KF_LAENGE ueber die Einbauhoehe skaliert. - Dialog (DCL-Vorlage, Typ als Radiobuttons), Hoehe per Zahl oder aus zwei Punkten, Doppelklick auf KF_n oeffnet KF_EDIT mit Neuaufbau - eigenstaendiges Attribut-Schema, Auswahllisten mit Sivas-Optionstexten in data/json/kettenfoerderer.json - Sivas-Export: Merkmale 350, 353-357, 359-361, 391, baugleiche Foerderer werden zu einer Zeile zusammengefasst (Artikelnummer 6120) - ssg_ks_insert.lsp: neue Primitiven ks-xy-winkel, ks-block-messen, insert-block-ks-skaliert und insert-block-ks-matrix (freie 3x3-Rotation); ensure-block-loaded nimmt Bloecke ohne Dimensionssuffix unveraendert - Menueeintrag KettenFoerderer aktiviert, toter Dummy OMNI_KettenFoerderer entfernt; KF_* im Export-Pattern, in der ID-Vergabe und im Dispatcher SSG_BLOCKEDIT (vor dem Omniflo-Zweig) - Unit-Tests tu-tests-kf fuer die reinen Rechenkerne; Modul wird in der MNL vorgeladen, dbg-Schalter kf-zeit zur Laufzeitmessung Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
908 lines
40 KiB
Common Lisp
908 lines
40 KiB
Common Lisp
;; ============================================================
|
|
;; SSG_KS_INSERT.LSP - Gemeinsame KS-Extraktion + Block-Einfuegeprimitiven
|
|
;; ============================================================
|
|
;; Frueher doppelt gepflegt in vf_core.lsp (unbedingt) UND Gefaellestrecke.lsp
|
|
;; (geguardet als "Fallback wenn vf_core nicht geladen"). Da vf_core im MNL-Fluss
|
|
;; immer nach Gefaellestrecke laedt, gewann bisher STILLSCHWEIGEND die
|
|
;; vf_core-Version - die Gefaellestrecke-Fallbacks waren de facto tot und wichen
|
|
;; zudem leicht ab (Layer-Setzung, hz-Guard, Null-Check, Meldungs-Keys). Diese
|
|
;; Datei ist jetzt die EINZIGE Quelle (kanonische vf_core-Variante); beide
|
|
;; Cluster laden sie ueber die MNL VOR Gefaellestrecke/vf_core.
|
|
;;
|
|
;; Abhaengigkeiten (aus ssg_core, daher zuerst laden): ssg-ils-block-laden,
|
|
;; ssg-ils-blockname, ssg-ils-block-auf-ebene, ssg-rot-matrix-zy, ssg-text/-textf.
|
|
;; ============================================================
|
|
|
|
(vl-load-com)
|
|
|
|
;; Cache fuer extract-ks-from-block (Blockname -> relative KS-Punkte). Guard,
|
|
;; damit ein Neu-Laden dieser Datei den Cache nicht verwirft.
|
|
(if (not (boundp '*ks-cache*)) (setq *ks-cache* nil))
|
|
|
|
;; ------------------------------------------------------------
|
|
;; KS-MATHEMATIK (Basis)
|
|
;; ------------------------------------------------------------
|
|
(defun vec-length (v)
|
|
(sqrt (+ (* (car v) (car v)) (* (cadr v) (cadr v)) (* (caddr v) (caddr v)))))
|
|
|
|
;; Achsenkennung aus Linienlaenge fuer die KS-Extraktion (X=1 bzw. 100, Y=2, Z=3).
|
|
(defun ks-line-axis (len)
|
|
(cond
|
|
((and (> len 0.5) (< len 1.5)) "X")
|
|
((and (> len 99) (< len 101)) "X")
|
|
((and (> len 1.5) (< len 2.5)) "Y")
|
|
((and (> len 2.5) (< len 3.5)) "Z")
|
|
(t nil)))
|
|
|
|
;; Normalisiert die verschiedenen KS-Blocknamen auf "KS_EIN"/"KS_AUS".
|
|
;; Standard ist KS_EIN/KS_AUS; historische Bestandsbloecke koennen noch
|
|
;; KSYS_EIN/KSYS_AUS fuehren. Rueckgabe nil, wenn kein KS-Block.
|
|
(defun ks-normalize-name (nm)
|
|
(cond
|
|
((or (= nm "KS_EIN") (= nm "KSYS_EIN")) "KS_EIN")
|
|
((or (= nm "KS_AUS") (= nm "KSYS_AUS")) "KS_AUS")
|
|
(t nil)))
|
|
|
|
(defun ks-relativize (ks-data base-pt)
|
|
(mapcar '(lambda (item)
|
|
(list (car item)
|
|
(mapcar '(lambda (pt)
|
|
(list (- (car pt) (car base-pt))
|
|
(- (cadr pt) (cadr base-pt))
|
|
(- (caddr pt) (caddr base-pt))))
|
|
(cadr item))))
|
|
ks-data))
|
|
|
|
(defun ks-absolutize (ks-rel base-pt)
|
|
(mapcar '(lambda (item)
|
|
(list (car item)
|
|
(mapcar '(lambda (pt)
|
|
(list (+ (car pt) (car base-pt))
|
|
(+ (cadr pt) (cadr base-pt))
|
|
(+ (caddr pt) (caddr base-pt))))
|
|
(cadr item))))
|
|
ks-rel))
|
|
|
|
;; ------------------------------------------------------------
|
|
;; BLOCK-LADER
|
|
;; ------------------------------------------------------------
|
|
;; Zentraler Loader (flache Ablage). Laedt den Block in der AKTUELLEN Dimension
|
|
;; (ssg-ils-dim-aktuell: *ssg-ils-dim*-Override -> DXFM_DIM) mit automatischem
|
|
;; 3D-Fallback, sodass 2D- und 3D-Aufbau gleichermassen funktionieren. Laedt den
|
|
;; Block unter seinem effektiven, dim-suffigierten Namen und GIBT DIESEN ZURUECK,
|
|
;; damit Aufrufer ihn zum Einfuegen (vla-InsertBlock/tblsearch) verwenden.
|
|
;; Meldung nur bei Fehlschlag.
|
|
;; Sonderfall Bloecke OHNE Dimensionssuffix (data/omniflo/<Dim>/, z.B. die
|
|
;; Kettenfoerderer-Bausteine): ssg-ils-blockname wuerde "KF_UM_26" zu
|
|
;; "KF_UM_26_2D" machen - das ist die Konvention der FLACHEN Ablage data/ils,
|
|
;; die Omniflo-Ordner arbeiten stattdessen mit getrennten Verzeichnissen und
|
|
;; unsuffigierten Namen. Liegt die Definition unter dem Rohnamen bereits in
|
|
;; der Zeichnung und gibt es KEINE suffigierte Variante, wird der Rohname
|
|
;; unveraendert verwendet. Die Bedingung ist bewusst eng gefasst (BEIDE Teile
|
|
;; muessen zutreffen), damit die Dim-Aufloesung fuer alle data/ils-Bloecke
|
|
;; unberuehrt bleibt: dort existiert die suffigierte Variante, sobald der
|
|
;; Block geladen ist, und der erste Zweig greift nie.
|
|
;; Realer Fehler, den das behebt: die KS-Messung eines KF-Bausteins lief ins
|
|
;; Leere und meldete "KS_EIN/KS_AUS fehlt", obwohl beide KS im Block vorhanden
|
|
;; waren - gesucht wurde nur ein Blockname, den es nicht gibt.
|
|
(defun ensure-block-loaded (blockname / eff)
|
|
(setq eff (ssg-ils-blockname blockname))
|
|
(if (and (not (tblsearch "BLOCK" eff))
|
|
(tblsearch "BLOCK" blockname))
|
|
blockname
|
|
(progn
|
|
(if (not (ssg-ils-block-laden blockname))
|
|
(princ (ssg-textf "vfc-fehler-block-datei-fehlt" (list blockname)))
|
|
)
|
|
eff
|
|
)
|
|
)
|
|
)
|
|
|
|
;; ------------------------------------------------------------
|
|
;; KS-EXTRAKTION (mit Cache *ks-cache*)
|
|
;; ------------------------------------------------------------
|
|
(defun extract-ks-from-block-raw (block-obj / sub-entities sub-obj ks-results
|
|
ks-ref inner-entities inner-obj origin x-end y-end z-end
|
|
line-start line-end axis line-len line-vec)
|
|
(setq ks-results '())
|
|
(setq sub-entities (vlax-invoke block-obj 'Explode))
|
|
(foreach sub-obj sub-entities
|
|
(setq ks-ref
|
|
(if (and (not (vlax-erased-p sub-obj))
|
|
(= (vla-get-ObjectName sub-obj) "AcDbBlockReference"))
|
|
(ks-normalize-name (vla-get-Name sub-obj))
|
|
nil))
|
|
(if ks-ref
|
|
(progn
|
|
(setq inner-entities (vlax-invoke sub-obj 'Explode))
|
|
(setq origin nil x-end nil y-end nil z-end nil)
|
|
(foreach inner-obj inner-entities
|
|
(if (and (not (vlax-erased-p inner-obj))
|
|
(= (vla-get-ObjectName inner-obj) "AcDbLine"))
|
|
(progn
|
|
(setq line-start (vlax-safearray->list
|
|
(vlax-variant-value (vla-get-StartPoint inner-obj))))
|
|
(setq line-end (vlax-safearray->list
|
|
(vlax-variant-value (vla-get-EndPoint inner-obj))))
|
|
(setq line-vec (list (- (car line-end) (car line-start))
|
|
(- (cadr line-end) (cadr line-start))
|
|
(- (caddr line-end) (caddr line-start))))
|
|
(setq line-len (vec-length line-vec))
|
|
(setq axis (ks-line-axis line-len))
|
|
(if (null origin) (setq origin line-start))
|
|
(cond
|
|
((= axis "X") (setq x-end line-end))
|
|
((= axis "Y") (setq y-end line-end))
|
|
((= axis "Z") (setq z-end line-end))
|
|
)
|
|
)
|
|
)
|
|
(if (not (vlax-erased-p inner-obj)) (vla-Delete inner-obj))
|
|
)
|
|
(if (and origin x-end y-end z-end)
|
|
(setq ks-results (cons (list ks-ref (list origin x-end y-end z-end)) ks-results))
|
|
)
|
|
)
|
|
)
|
|
)
|
|
(foreach sub-obj sub-entities
|
|
(if (not (vlax-erased-p sub-obj)) (vla-Delete sub-obj))
|
|
)
|
|
ks-results
|
|
)
|
|
|
|
(defun extract-ks-from-block (block-obj / blockname insert-pt cached result ks-rel)
|
|
(setq blockname (vla-get-Name block-obj))
|
|
(setq insert-pt (vlax-safearray->list
|
|
(vlax-variant-value (vla-get-InsertionPoint block-obj))))
|
|
(setq cached (assoc blockname *ks-cache*))
|
|
(if cached
|
|
(ks-absolutize (cdr cached) insert-pt)
|
|
(progn
|
|
(setq result (extract-ks-from-block-raw block-obj))
|
|
(if result
|
|
(progn
|
|
(setq ks-rel (ks-relativize result insert-pt))
|
|
(setq *ks-cache* (cons (cons blockname ks-rel) *ks-cache*))
|
|
)
|
|
)
|
|
result
|
|
)
|
|
)
|
|
)
|
|
|
|
;; ------------------------------------------------------------
|
|
;; EINFUEGEPRIMITIVEN
|
|
;; ------------------------------------------------------------
|
|
|
|
;; --- Block per KS_EIN/KS_AUS einfuegen (nur horizontale Rz-Rotation) ---
|
|
;; KS_EIN (nicht der Block-Ursprung) kommt auf einfuegepunkt zu liegen.
|
|
;; Rueckgabe: Weltpunkt von KS_AUS (fuer Verkettung), sonst einfuegepunkt.
|
|
(defun insert-block-by-ks (blockname einfuegepunkt hz / block-obj temp-obj ks-data ks-ein ks-aus
|
|
rad-h chv shv ein-x ein-y ein-z dx-loc dy-loc dz-loc offset ausgang)
|
|
(if (or (null einfuegepunkt) (not (listp einfuegepunkt)))
|
|
(progn
|
|
(princ (ssg-textf "vfc-fehler-ungueltiger-einfuegepunkt" (list blockname)))
|
|
(exit)
|
|
)
|
|
)
|
|
(setq blockname (ensure-block-loaded blockname))
|
|
(if (not (tblsearch "BLOCK" blockname))
|
|
(progn
|
|
(princ (ssg-textf "vfc-fehler-block-nicht-in-bibliothek-abgebrochen" (list blockname)))
|
|
(exit)
|
|
)
|
|
)
|
|
(princ (ssg-textf "vfc-fuege-block-ein-hz" (list blockname (rtos (float hz) 2 1) (chr 176))))
|
|
(setq rad-h (* (float hz) (/ pi 180.0)))
|
|
(setq chv (cos rad-h) shv (sin rad-h))
|
|
;; KS_EIN/KS_AUS ueber eigenes Temp-Objekt am Ursprung ermitteln (nicht am
|
|
;; spaeter tatsaechlich platzierten block-obj - extract-ks-from-block
|
|
;; exploded das uebergebene Objekt intern), siehe insert-block-ks-to-ks.
|
|
(setq temp-obj (vla-InsertBlock modelspace
|
|
(vlax-3D-point '(0 0 0))
|
|
blockname 1.0 1.0 1.0 0))
|
|
(setq ks-data (extract-ks-from-block temp-obj))
|
|
(if (not (vlax-erased-p temp-obj)) (vla-Delete temp-obj))
|
|
(setq ks-ein (cadr (assoc "KS_EIN" ks-data)))
|
|
(setq ks-aus (cadr (assoc "KS_AUS" ks-data)))
|
|
;; Block am Ursprung einfuegen (nicht direkt am einfuegepunkt), damit die
|
|
;; Rz-Rotation um den Block-Ursprung dreht, nicht um die Weltachse.
|
|
(setq block-obj (vla-InsertBlock modelspace
|
|
(vlax-3D-point '(0 0 0))
|
|
blockname 1.0 1.0 1.0 0))
|
|
(ssg-ils-block-auf-ebene block-obj blockname)
|
|
(if (> (abs hz) 0.0001)
|
|
(vla-TransformBy block-obj (vlax-tmatrix
|
|
(list (list chv (- shv) 0 0)
|
|
(list shv chv 0 0)
|
|
(list 0 0 1 0)
|
|
(list 0 0 0 1))))
|
|
)
|
|
(if (and ks-ein ks-aus)
|
|
(progn
|
|
(setq ein-x (car (car ks-ein)) ein-y (cadr (car ks-ein)) ein-z (caddr (car ks-ein)))
|
|
;; Block-Ursprung so verschieben, dass das ROTIERTE KS_EIN exakt auf
|
|
;; einfuegepunkt zu liegen kommt: Ursprung = einfuegepunkt - Rz(hz)*ks_ein_lokal
|
|
(setq offset (list
|
|
(- (car einfuegepunkt) (- (* chv ein-x) (* shv ein-y)))
|
|
(- (cadr einfuegepunkt) (+ (* shv ein-x) (* chv ein-y)))
|
|
(- (caddr einfuegepunkt) ein-z)))
|
|
(vla-Move block-obj
|
|
(vlax-3D-point '(0 0 0))
|
|
(vlax-3D-point offset))
|
|
;; KS_AUS = einfuegepunkt + Rz(hz)*(ks_aus_lokal - ks_ein_lokal)
|
|
(setq dx-loc (- (car (car ks-aus)) ein-x))
|
|
(setq dy-loc (- (cadr (car ks-aus)) ein-y))
|
|
(setq dz-loc (- (caddr (car ks-aus)) ein-z))
|
|
(setq ausgang (list
|
|
(+ (car einfuegepunkt) (- (* chv dx-loc) (* shv dy-loc)))
|
|
(+ (cadr einfuegepunkt) (+ (* shv dx-loc) (* chv dy-loc)))
|
|
(+ (caddr einfuegepunkt) dz-loc)))
|
|
(ssg-sepliste-dbg
|
|
(strcat "insert-block-by-ks " blockname
|
|
" hz=" (rtos (float hz) 2 2)
|
|
" einfuegepunkt=" (ssg-sepliste-dbg-pt einfuegepunkt)
|
|
" ks_ein_lokal=" (ssg-sepliste-dbg-pt (car ks-ein))
|
|
" ks_aus_lokal=" (ssg-sepliste-dbg-pt (car ks-aus))
|
|
" offset(=Gruppencode 10)=" (ssg-sepliste-dbg-pt offset)
|
|
" ausgang=" (ssg-sepliste-dbg-pt ausgang)))
|
|
(princ (ssg-textf "vfc-ks-aus-xyz"
|
|
(list (rtos (car ausgang) 2 2) (rtos (cadr ausgang) 2 2) (rtos (caddr ausgang) 2 2))))
|
|
ausgang
|
|
)
|
|
(progn
|
|
(princ (ssg-text "vfc-warnung-ks-nicht-gefunden"))
|
|
einfuegepunkt
|
|
)
|
|
)
|
|
)
|
|
|
|
;; --- Skalierter geneigter Block (Staustrecke, Richtung X), Rz(hz)*Ry(winkel) ---
|
|
(defun insert-inclined-scaled-block (blockname startpunkt laenge winkel hz /
|
|
rad-v rad-h chv shv cvv svv scale block-obj matrix endpunkt)
|
|
(if (<= laenge 0.1)
|
|
(progn
|
|
(princ (ssg-textf "vfc-laenge-uebersprungen" (list (rtos laenge 2 2))))
|
|
startpunkt
|
|
)
|
|
(progn
|
|
(setq blockname (ensure-block-loaded blockname))
|
|
(if (not (tblsearch "BLOCK" blockname))
|
|
(progn
|
|
(princ (ssg-textf "vfc-fehler-block-nicht-in-bibliothek-abgebrochen" (list blockname)))
|
|
(exit)
|
|
)
|
|
)
|
|
(princ (ssg-textf "vfc-fuege-ein-lwhz"
|
|
(list blockname (rtos laenge 2 2) (itoa (fix winkel)) (chr 176) (rtos (float hz) 2 1) (chr 176))))
|
|
(setq scale (/ laenge (ssg-cfg-or "vario" "skalierung_basis" 1000.0)))
|
|
(setq rad-v (* (float winkel) (/ pi 180.0)))
|
|
(setq rad-h (* (float hz) (/ pi 180.0)))
|
|
(setq chv (cos rad-h) shv (sin rad-h) cvv (cos rad-v) svv (sin rad-v))
|
|
(setq block-obj (vla-InsertBlock modelspace
|
|
(vlax-3D-point '(0 0 0))
|
|
blockname scale 1.0 1.0 0))
|
|
(ssg-ils-block-auf-ebene block-obj blockname)
|
|
(setq matrix (ssg-rot-matrix-zy chv shv cvv svv))
|
|
(vla-TransformBy block-obj (vlax-tmatrix matrix))
|
|
(vla-Move block-obj
|
|
(vlax-3D-point '(0 0 0))
|
|
(vlax-3D-point startpunkt))
|
|
(setq endpunkt (list
|
|
(+ (car startpunkt) (* laenge chv cvv))
|
|
(+ (cadr startpunkt) (* laenge shv cvv))
|
|
(+ (caddr startpunkt) (* laenge (- svv)))))
|
|
(ssg-sepliste-dbg
|
|
(strcat "insert-inclined-scaled-block " blockname
|
|
" laenge=" (rtos laenge 2 2) " winkel=" (rtos (float winkel) 2 2)
|
|
" hz=" (rtos (float hz) 2 2) " scale=" (rtos scale 2 4)
|
|
" startpunkt(=Gruppencode 10)=" (ssg-sepliste-dbg-pt startpunkt)
|
|
" endpunkt=" (ssg-sepliste-dbg-pt endpunkt)))
|
|
(princ (ssg-textf "vfc-endpunkt-xyz"
|
|
(list (rtos (car endpunkt) 2 2) (rtos (cadr endpunkt) 2 2) (rtos (caddr endpunkt) 2 2))))
|
|
endpunkt
|
|
)
|
|
)
|
|
)
|
|
|
|
;; --- Rotierter Block mit manuellem dx/dz-Fallback, Rz(hz)*Ry(winkel) ---
|
|
;; block-dx/block-dz: Fallback-Laenge (aus Config), nur verwendet falls
|
|
;; KS_EIN/KS_AUS am Block nicht extrahiert werden koennen. Ist KS_AUS
|
|
;; vorhanden, wird der ECHTE gemessene Versatz KS_AUS-KS_EIN verwendet -
|
|
;; das schuetzt vor veralteten Config-Zahlen. KS_EIN (nicht der Block-Ursprung)
|
|
;; kommt auf startpunkt zu liegen.
|
|
(defun insert-rotated-block-with-ks (blockname startpunkt winkel block-dx block-dz hz /
|
|
rad-v rad-h chv shv cvv svv matrix block-obj temp-obj ks-data
|
|
ks-ein-raw ks-aus-raw
|
|
ein-x ein-y ein-z aus-x aus-y aus-z
|
|
dx dz ins-pt endpunkt)
|
|
(if (or (null startpunkt) (not (listp startpunkt)))
|
|
(progn
|
|
(princ (ssg-textf "vfc-fehler-ungueltiger-einfuegepunkt" (list blockname)))
|
|
startpunkt
|
|
)
|
|
(progn
|
|
(setq blockname (ensure-block-loaded blockname))
|
|
(if (not (tblsearch "BLOCK" blockname))
|
|
(progn
|
|
(princ (ssg-textf "vfc-fehler-block-nicht-in-bibliothek-abgebrochen" (list blockname)))
|
|
(exit)
|
|
)
|
|
)
|
|
(princ (ssg-textf "vfc-fuege-block-ein-rotation-hz"
|
|
(list blockname (itoa (fix winkel)) (chr 176) (rtos (float hz) 2 1) (chr 176))))
|
|
(setq rad-v (* winkel (/ pi 180.0)))
|
|
(setq rad-h (* (float hz) (/ pi 180.0)))
|
|
(setq chv (cos rad-h) shv (sin rad-h) cvv (cos rad-v) svv (sin rad-v))
|
|
;; Lokale KS_EIN/KS_AUS-Position ueber EIGENES Temp-Objekt ermitteln.
|
|
(setq temp-obj (vla-InsertBlock modelspace
|
|
(vlax-3D-point '(0 0 0))
|
|
blockname 1.0 1.0 1.0 0))
|
|
(setq ks-data (extract-ks-from-block temp-obj))
|
|
(if (not (vlax-erased-p temp-obj)) (vla-Delete temp-obj))
|
|
(setq ks-ein-raw (cadr (assoc "KS_EIN" ks-data)))
|
|
(setq ks-aus-raw (cadr (assoc "KS_AUS" ks-data)))
|
|
(setq ein-x 0.0 ein-y 0.0 ein-z 0.0)
|
|
(if ks-ein-raw
|
|
(setq ein-x (car (car ks-ein-raw))
|
|
ein-y (cadr (car ks-ein-raw))
|
|
ein-z (caddr (car ks-ein-raw)))
|
|
)
|
|
;; Echten Versatz KS_AUS-KS_EIN verwenden, sofern messbar.
|
|
(setq dx block-dx dz block-dz)
|
|
(if ks-aus-raw
|
|
(progn
|
|
(setq aus-x (car (car ks-aus-raw))
|
|
aus-y (cadr (car ks-aus-raw))
|
|
aus-z (caddr (car ks-aus-raw)))
|
|
(setq dx (- aus-x ein-x) dz (- aus-z ein-z))
|
|
)
|
|
)
|
|
(setq block-obj (vla-InsertBlock modelspace
|
|
(vlax-3D-point '(0 0 0))
|
|
blockname 1.0 1.0 1.0 0))
|
|
(ssg-ils-block-auf-ebene block-obj blockname)
|
|
(setq matrix (ssg-rot-matrix-zy chv shv cvv svv))
|
|
(vla-TransformBy block-obj (vlax-tmatrix matrix))
|
|
;; Block-Ursprung so verschieben, dass das ROTIERTE KS_EIN exakt auf
|
|
;; startpunkt liegt: Ursprung = startpunkt - Rz(hz)*Ry(winkel)*ks_ein_lokal
|
|
(setq ins-pt (list
|
|
(- (car startpunkt) (+ (* ein-x chv cvv) (* ein-y (- shv)) (* ein-z chv svv)))
|
|
(- (cadr startpunkt) (+ (* ein-x shv cvv) (* ein-y chv) (* ein-z shv svv)))
|
|
(- (caddr startpunkt) (+ (* ein-x (- svv)) (* ein-z cvv)))))
|
|
(vla-Move block-obj
|
|
(vlax-3D-point '(0 0 0))
|
|
(vlax-3D-point ins-pt))
|
|
;; KS_AUS-Weltpunkt = startpunkt + Rz(hz)*Ry(winkel)*(dx 0 dz)
|
|
(setq endpunkt (list
|
|
(+ (car startpunkt) (+ (* dx chv cvv) (* dz chv svv)))
|
|
(+ (cadr startpunkt) (+ (* dx shv cvv) (* dz shv svv)))
|
|
(+ (caddr startpunkt) (+ (* dx (- svv)) (* dz cvv)))))
|
|
(ssg-sepliste-dbg
|
|
(strcat "insert-rotated-block-with-ks " blockname
|
|
" winkel=" (rtos (float winkel) 2 2) " hz=" (rtos (float hz) 2 2)
|
|
" startpunkt=" (ssg-sepliste-dbg-pt startpunkt)
|
|
" ks_ein_lokal=" (ssg-sepliste-dbg-pt (list ein-x ein-y ein-z))
|
|
" ks_aus_lokal=" (if ks-aus-raw
|
|
(ssg-sepliste-dbg-pt (list aus-x aus-y aus-z))
|
|
"nil (Fallback dx/dz aus cfg)")
|
|
" dx=" (rtos dx 2 2) " dz=" (rtos dz 2 2)
|
|
" ins-pt(=Gruppencode 10)=" (ssg-sepliste-dbg-pt ins-pt)
|
|
" endpunkt=" (ssg-sepliste-dbg-pt endpunkt)))
|
|
(princ (ssg-textf "vfc-endpunkt-xyz-dxdz"
|
|
(list (rtos (car endpunkt) 2 2) (rtos (cadr endpunkt) 2 2) (rtos (caddr endpunkt) 2 2)
|
|
(rtos dx 2 1) (rtos dz 2 1))))
|
|
endpunkt
|
|
)
|
|
)
|
|
)
|
|
|
|
;; ------------------------------------------------------------
|
|
;; KS-ORIENTIERUNG + SKALIERTE KS-EINFUEGUNG
|
|
;; ------------------------------------------------------------
|
|
;; Ergaenzt fuer den Kettenfoerderer (KettenFoerderer.lsp): dort ist die
|
|
;; Neigung KEIN freier Parameter, sondern steckt fest in der Geometrie der
|
|
;; Blockvarianten (KF_UM_26 gegen KF_UM_30). Der Einbauwinkel eines
|
|
;; Folgebausteins ergibt sich darum aus der RICHTUNG des KS_AUS seines
|
|
;; Vorgaengers. Dafuer reicht der bisher allein ausgewertete KS-URSPRUNG
|
|
;; nicht - die X-Achse des KS muss mit gelesen werden. extract-ks-from-block
|
|
;; liefert sie als (origin x-end y-end z-end) bereits mit, sie wurde bislang
|
|
;; nur von keinem Aufrufer genutzt.
|
|
|
|
;; Winkel der X-Achse eines KS-Eintrags in der XY-Ebene, in Grad (-180..180).
|
|
;; ks-eintrag = (origin x-end y-end z-end), also genau der cadr-Teil eines
|
|
;; extract-ks-from-block-Ergebnisses. Rueckgabe nil, wenn die X-Achse keine
|
|
;; XY-Laenge hat (senkrecht stehendes KS) oder der Eintrag unbrauchbar ist.
|
|
(defun ks-xy-winkel (ks-eintrag / org xend dx dy)
|
|
(if (and ks-eintrag (listp ks-eintrag) (>= (length ks-eintrag) 2)
|
|
(listp (car ks-eintrag)) (listp (cadr ks-eintrag)))
|
|
(progn
|
|
(setq org (car ks-eintrag) xend (cadr ks-eintrag))
|
|
(setq dx (- (car xend) (car org))
|
|
dy (- (cadr xend) (cadr org)))
|
|
(if (< (+ (* dx dx) (* dy dy)) 1e-12)
|
|
nil
|
|
(/ (* 180.0 (atan dy dx)) pi)))
|
|
nil))
|
|
|
|
;; Winkel auf -180..180 Grad normalisieren. Reiner Rechenkern.
|
|
(defun ks-winkel-normalisieren (w)
|
|
(if (null w)
|
|
nil
|
|
(progn
|
|
(setq w (float w))
|
|
(while (> w 180.0) (setq w (- w 360.0)))
|
|
(while (<= w -180.0) (setq w (+ w 360.0)))
|
|
w)))
|
|
|
|
;; Lokalen KS_AUS-KS_EIN-Versatz eines Blocks als (dx dy dz) liefern.
|
|
;; ks-data = Ergebnis von extract-ks-from-block/ks-block-messen.
|
|
;; Rueckgabe nil, wenn eines der beiden KS fehlt.
|
|
(defun ks-versatz (ks-data / ein aus)
|
|
(setq ein (cadr (assoc "KS_EIN" ks-data))
|
|
aus (cadr (assoc "KS_AUS" ks-data)))
|
|
(if (and ein aus)
|
|
(list (- (car (car aus)) (car (car ein)))
|
|
(- (cadr (car aus)) (cadr (car ein)))
|
|
(- (caddr (car aus)) (caddr (car ein))))
|
|
nil))
|
|
|
|
;; Misst KS_EIN/KS_AUS eines Blocks, ohne eine bleibende Einfuegung zu
|
|
;; hinterlassen: der Block wird bei Massstab 1 am Ursprung eingefuegt,
|
|
;; vermessen und wieder geloescht. extract-ks-from-block cached das Ergebnis
|
|
;; je Blockname, der zweite Aufruf kostet also nichts mehr.
|
|
;; Rueckgabe wie extract-ks-from-block (Blockkoordinaten), sonst nil.
|
|
(defun ks-block-messen (blockname / eff temp-obj daten)
|
|
(setq eff (ensure-block-loaded blockname))
|
|
(if (tblsearch "BLOCK" eff)
|
|
(progn
|
|
(setq temp-obj (vla-InsertBlock modelspace
|
|
(vlax-3D-point '(0 0 0)) eff 1.0 1.0 1.0 0))
|
|
(setq daten (extract-ks-from-block temp-obj))
|
|
(if (not (vlax-erased-p temp-obj)) (vla-Delete temp-obj))
|
|
daten)
|
|
nil))
|
|
|
|
;; --- Block per KS_EIN/KS_AUS einfuegen, in X SKALIERT (nur Rz-Rotation) ---
|
|
;; Wie insert-block-by-ks, zusaetzlich mit X-Massstab skala - fuer laengen-
|
|
;; variable Zwischenstuecke (Kettenfoerderer KF_LAENGE, dieselbe Rolle wie
|
|
;; die Staustrecke beim VarioFoerderer). Die lokalen KS-Punkte werden VOR der
|
|
;; Rotation in X mitskaliert; nur so liegt KS_EIN exakt auf einfuegepunkt und
|
|
;; der zurueckgegebene KS_AUS traegt den skalierten Versatz.
|
|
;; Rueckgabe: Weltpunkt von KS_AUS (fuer die Verkettung), sonst einfuegepunkt.
|
|
(defun insert-block-ks-skaliert (blockname einfuegepunkt hz skala /
|
|
block-obj ks-data ks-ein ks-aus rad-h chv shv
|
|
ein-x ein-y ein-z aus-x dx-loc dy-loc dz-loc
|
|
offset ausgang)
|
|
(if (or (null einfuegepunkt) (not (listp einfuegepunkt)))
|
|
(progn
|
|
(princ (ssg-textf "vfc-fehler-ungueltiger-einfuegepunkt" (list blockname)))
|
|
(exit))
|
|
)
|
|
(if (or (null skala) (<= skala 0.0)) (setq skala 1.0))
|
|
(setq blockname (ensure-block-loaded blockname))
|
|
(if (not (tblsearch "BLOCK" blockname))
|
|
(progn
|
|
(princ (ssg-textf "vfc-fehler-block-nicht-in-bibliothek-abgebrochen" (list blockname)))
|
|
(exit))
|
|
)
|
|
(princ (ssg-textf "vfc-fuege-block-ein-hz" (list blockname (rtos (float hz) 2 1) (chr 176))))
|
|
(setq rad-h (* (float hz) (/ pi 180.0)))
|
|
(setq chv (cos rad-h) shv (sin rad-h))
|
|
;; KS am UNSKALIERTEN Block messen (der Cache arbeitet je Blockname), die
|
|
;; lokalen Punkte danach selbst in X skalieren.
|
|
(setq ks-data (ks-block-messen blockname))
|
|
(setq ks-ein (cadr (assoc "KS_EIN" ks-data)))
|
|
(setq ks-aus (cadr (assoc "KS_AUS" ks-data)))
|
|
(setq block-obj (vla-InsertBlock modelspace
|
|
(vlax-3D-point '(0 0 0))
|
|
blockname skala 1.0 1.0 0))
|
|
(ssg-ils-block-auf-ebene block-obj blockname)
|
|
(if (> (abs hz) 0.0001)
|
|
(vla-TransformBy block-obj (vlax-tmatrix
|
|
(list (list chv (- shv) 0 0)
|
|
(list shv chv 0 0)
|
|
(list 0 0 1 0)
|
|
(list 0 0 0 1))))
|
|
)
|
|
(if (and ks-ein ks-aus)
|
|
(progn
|
|
(setq ein-x (* skala (car (car ks-ein)))
|
|
ein-y (cadr (car ks-ein))
|
|
ein-z (caddr (car ks-ein)))
|
|
(setq aus-x (* skala (car (car ks-aus))))
|
|
(setq offset (list
|
|
(- (car einfuegepunkt) (- (* chv ein-x) (* shv ein-y)))
|
|
(- (cadr einfuegepunkt) (+ (* shv ein-x) (* chv ein-y)))
|
|
(- (caddr einfuegepunkt) ein-z)))
|
|
(vla-Move block-obj
|
|
(vlax-3D-point '(0 0 0))
|
|
(vlax-3D-point offset))
|
|
(setq dx-loc (- aus-x ein-x))
|
|
(setq dy-loc (- (cadr (car ks-aus)) ein-y))
|
|
(setq dz-loc (- (caddr (car ks-aus)) ein-z))
|
|
(setq ausgang (list
|
|
(+ (car einfuegepunkt) (- (* chv dx-loc) (* shv dy-loc)))
|
|
(+ (cadr einfuegepunkt) (+ (* shv dx-loc) (* chv dy-loc)))
|
|
(+ (caddr einfuegepunkt) dz-loc)))
|
|
(ssg-sepliste-dbg
|
|
(strcat "insert-block-ks-skaliert " blockname
|
|
" hz=" (rtos (float hz) 2 2) " skala=" (rtos (float skala) 2 4)
|
|
" einfuegepunkt=" (ssg-sepliste-dbg-pt einfuegepunkt)
|
|
" offset(=Gruppencode 10)=" (ssg-sepliste-dbg-pt offset)
|
|
" ausgang=" (ssg-sepliste-dbg-pt ausgang)))
|
|
(princ (ssg-textf "vfc-ks-aus-xyz"
|
|
(list (rtos (car ausgang) 2 2) (rtos (cadr ausgang) 2 2) (rtos (caddr ausgang) 2 2))))
|
|
ausgang
|
|
)
|
|
(progn
|
|
(princ (ssg-text "vfc-warnung-ks-nicht-gefunden"))
|
|
einfuegepunkt
|
|
)
|
|
)
|
|
)
|
|
|
|
;; ------------------------------------------------------------
|
|
;; FREI ROTIERTE KS-EINFUEGUNG (beliebige 3x3-Matrix)
|
|
;; ------------------------------------------------------------
|
|
;; Verallgemeinerung von insert-block-by-ks/insert-block-ks-skaliert: statt
|
|
;; einer festen Rz- bzw. Rz*Ry-Drehung nimmt sie eine FERTIGE 3x3-Rotations-
|
|
;; matrix entgegen. Noetig geworden fuer AUFRECHT eingebaute Baugruppen: der
|
|
;; Kettenfoerderer ist in der XY-Ebene gezeichnet (X = Fahrtrichtung,
|
|
;; Y = Hoehe), soll aber im Modell stehen - seine Hoehe muss also nach Z. Das
|
|
;; ist eine Drehung um X, die weder insert-block-by-ks (nur Rz) noch
|
|
;; ssg-rot-matrix-zy (Rz*Ry) erzeugen kann.
|
|
;;
|
|
;; Bewusst matrixbasiert statt mit einem weiteren Winkelparameter: die
|
|
;; Aufrichtung ist nur EIN Anwendungsfall, und jeder weitere haette eine
|
|
;; weitere Spezialfunktion gebraucht. Den Aufrufern bleibt freigestellt,
|
|
;; welche Drehungen sie kombinieren (beim Kettenfoerderer
|
|
;; Rz(basis) * Rx(90) * Rz(eigen), siehe kf-matrix-aufrecht).
|
|
|
|
;; Elementare Rotationsmatrizen (3x3, Winkel in GRAD).
|
|
(defun ks-rot-x (grad / r c s)
|
|
(setq r (* (float grad) (/ pi 180.0)) c (cos r) s (sin r))
|
|
(list (list 1.0 0.0 0.0)
|
|
(list 0.0 c (- s))
|
|
(list 0.0 s c )))
|
|
|
|
(defun ks-rot-y (grad / r c s)
|
|
(setq r (* (float grad) (/ pi 180.0)) c (cos r) s (sin r))
|
|
(list (list c 0.0 s )
|
|
(list 0.0 1.0 0.0)
|
|
(list (- s) 0.0 c )))
|
|
|
|
(defun ks-rot-z (grad / r c s)
|
|
(setq r (* (float grad) (/ pi 180.0)) c (cos r) s (sin r))
|
|
(list (list c (- s) 0.0)
|
|
(list s c 0.0)
|
|
(list 0.0 0.0 1.0)))
|
|
|
|
;; 3x3-Rotation in die 4x4-Form bringen, die vla-TransformBy erwartet.
|
|
(defun ks-mat3->mat4 (R)
|
|
(list (append (car R) '(0.0))
|
|
(append (cadr R) '(0.0))
|
|
(append (caddr R) '(0.0))
|
|
'(0.0 0.0 0.0 1.0)))
|
|
|
|
;; --- Block per KS_EIN/KS_AUS einfuegen, frei rotiert und in X skaliert ---
|
|
;; blockname Rohname (wird ueber ensure-block-loaded aufgeloest)
|
|
;; einfuegepunkt Weltpunkt, auf den KS_EIN zu liegen kommt
|
|
;; R 3x3-Rotationsmatrix (Blockkoordinaten -> Welt)
|
|
;; skala X-Massstab (1.0 = unskaliert)
|
|
;; Rueckgabe: Weltpunkt von KS_AUS (fuer die Verkettung), sonst einfuegepunkt.
|
|
;;
|
|
;; Reihenfolge wie bei den uebrigen Primitiven: am Ursprung einfuegen,
|
|
;; skalieren, drehen, dann so verschieben, dass das GEDREHTE KS_EIN exakt auf
|
|
;; einfuegepunkt liegt. Die lokalen KS-Punkte werden dabei zuerst in X
|
|
;; mitskaliert - sonst zeigt der zurueckgegebene KS_AUS am skalierten Block
|
|
;; vorbei.
|
|
(defun insert-block-ks-matrix (blockname einfuegepunkt R skala /
|
|
block-obj ks-data ks-ein ks-aus
|
|
ein-lok aus-lok ein-welt aus-welt offset ausgang)
|
|
(if (or (null einfuegepunkt) (not (listp einfuegepunkt)))
|
|
(progn
|
|
(princ (ssg-textf "vfc-fehler-ungueltiger-einfuegepunkt" (list blockname)))
|
|
(exit))
|
|
)
|
|
(if (or (null skala) (<= skala 0.0)) (setq skala 1.0))
|
|
(setq blockname (ensure-block-loaded blockname))
|
|
(if (not (tblsearch "BLOCK" blockname))
|
|
(progn
|
|
(princ (ssg-textf "vfc-fehler-block-nicht-in-bibliothek-abgebrochen" (list blockname)))
|
|
(exit))
|
|
)
|
|
(setq ks-data (ks-block-messen blockname))
|
|
(setq ks-ein (cadr (assoc "KS_EIN" ks-data)))
|
|
(setq ks-aus (cadr (assoc "KS_AUS" ks-data)))
|
|
(setq block-obj (vla-InsertBlock modelspace
|
|
(vlax-3D-point '(0 0 0))
|
|
blockname skala 1.0 1.0 0))
|
|
(ssg-ils-block-auf-ebene block-obj blockname)
|
|
(vla-TransformBy block-obj (vlax-tmatrix (ks-mat3->mat4 R)))
|
|
(if (and ks-ein ks-aus)
|
|
(progn
|
|
;; lokale KS-Punkte, in X mitskaliert
|
|
(setq ein-lok (list (* skala (car (car ks-ein)))
|
|
(cadr (car ks-ein))
|
|
(caddr (car ks-ein))))
|
|
(setq aus-lok (list (* skala (car (car ks-aus)))
|
|
(cadr (car ks-aus))
|
|
(caddr (car ks-aus))))
|
|
(setq ein-welt (mat3-mul-vec3 R ein-lok))
|
|
(setq aus-welt (mat3-mul-vec3 R aus-lok))
|
|
(setq offset (list (- (car einfuegepunkt) (car ein-welt))
|
|
(- (cadr einfuegepunkt) (cadr ein-welt))
|
|
(- (caddr einfuegepunkt) (caddr ein-welt))))
|
|
(vla-Move block-obj
|
|
(vlax-3D-point '(0 0 0))
|
|
(vlax-3D-point offset))
|
|
(setq ausgang (list (+ (car einfuegepunkt) (- (car aus-welt) (car ein-welt)))
|
|
(+ (cadr einfuegepunkt) (- (cadr aus-welt) (cadr ein-welt)))
|
|
(+ (caddr einfuegepunkt) (- (caddr aus-welt) (caddr ein-welt)))))
|
|
(ssg-sepliste-dbg
|
|
(strcat "insert-block-ks-matrix " blockname
|
|
" skala=" (rtos (float skala) 2 4)
|
|
" einfuegepunkt=" (ssg-sepliste-dbg-pt einfuegepunkt)
|
|
" ks_ein_welt=" (ssg-sepliste-dbg-pt ein-welt)
|
|
" ks_aus_welt=" (ssg-sepliste-dbg-pt aus-welt)
|
|
" ausgang=" (ssg-sepliste-dbg-pt ausgang)))
|
|
ausgang
|
|
)
|
|
(progn
|
|
(princ (ssg-text "vfc-warnung-ks-nicht-gefunden"))
|
|
einfuegepunkt
|
|
)
|
|
)
|
|
)
|
|
|
|
;; ------------------------------------------------------------
|
|
;; SEPLISTE: Separator-/AS-/ES-Reihenfolge als XDATA am fertigen Wrapper
|
|
;; ------------------------------------------------------------
|
|
;; Sammelt beim Bau einer VF_n/GF_n-Kette die Weltposition + Baureihenfolge
|
|
;; aller "Staustrecke_Separator_SP_300_mm"/"AS_Element_*"/"ES_Element_*"-
|
|
;; Sub-Bloecke, BEVOR der abschliessende _.-BLOCK-Sweep (ssg-block-wrap-welt)
|
|
;; sie in die Wrapper-Blockdefinition einsaugt und ihre Modellraum-Existenz
|
|
;; damit beendet. Genutzt von vf-block-erstellen (vf_core.lsp),
|
|
;; vfl-block-erstellen (vf_linienzug.lsp) und gf-block-erstellen
|
|
;; (Gefaellestrecke.lsp) - an allen drei Stellen identisch aufgerufen, daher
|
|
;; hier zentral (vgl. Projektregel "Wiederverwendung vor Neuschaffung").
|
|
;;
|
|
;; Traegt bewusst KEINE ssg-id-generate-ID (kein ID-ATTDEF an diesen
|
|
;; Bloecken, Sinn/Zweck rein interne Geometrie-Traeger) - jeder Eintrag
|
|
;; bekommt nur eine laufende Nummer innerhalb der Liste. Der Export bildet
|
|
;; daraus bei Bedarf eigene, global fortlaufende TeileIds.
|
|
|
|
;; --- Diagnose-Protokoll (Schalter "vf-sepliste", siehe ssg_dbg.lsp) ---------
|
|
;; TEMPORAER fuer die Fehlersuche "gespiegelte Sepliste-Koordinate (lfdnr=2)" -
|
|
;; nach Abschluss mitsamt Schalter wieder entfernen.
|
|
;; Der Schalter ist in ssg_dbg.lsp mit Default 1 vorregistriert, das Protokoll
|
|
;; laeuft also nach einem BricsCAD-Neustart ohne weiteres Zutun. Es genuegt,
|
|
;; EINE VF-/GF-Kette zu bauen - das Protokoll landet in
|
|
;; DXFM_LOG/vf_sepliste.dbg. Protokolliert wird der komplette Weg der
|
|
;; Sepliste-Koordinaten: je Einfuegeprimitive der Startpunkt, die am Block
|
|
;; gemessenen KS_EIN/KS_AUS-Lokalpunkte, der daraus berechnete
|
|
;; Block-Einfuegepunkt (ins-pt = genau der Wert, den die Sepliste spaeter als
|
|
;; Gruppencode 10 einsammelt) und der Folgepunkt - sowie am Ende die
|
|
;; entnext-Wanderung von ssg-sepliste-sammeln mit JEDEM gefundenen INSERT.
|
|
;; Hintergrund: im Export tauchen Sepliste-Koordinaten auf, die nicht zur
|
|
;; sichtbaren Geometrie passen (x exakt negiert) - die Herkunft dieses Werts
|
|
;; ist ohne Laufzeit-Protokoll nicht zu klaeren.
|
|
;;
|
|
;; Nutzt NUR die Schalterverwaltung aus ssg_dbg.lsp, aber BEWUSST einen eigenen
|
|
;; Dateihandle statt dbgopen/dbgmsg: ssg_dbg fuehrt mit *dbg-path* genau EINE
|
|
;; global offene Datei. Der Linienzug-Bau (vfl-modus1, Schalter per Default EIN)
|
|
;; oeffnet seine vfl_modus1.dbg und haelt *dbg-path* damit besetzt - die
|
|
;; Sepliste-Zeilen waeren sonst stillschweigend dort gelandet statt in einer
|
|
;; eigenen Datei. Genau dieser Bau ist aber der zu protokollierende Vorgang.
|
|
(if (not (boundp '*ssg-sepliste-dbg-pfad*)) (setq *ssg-sepliste-dbg-pfad* nil))
|
|
|
|
;; Legt die Datei beim ERSTEN Aufruf je Sitzung an (leert sie dabei) und
|
|
;; liefert den Pfad; danach nur noch den gemerkten Pfad. nil = Schalter aus.
|
|
(defun ssg-sepliste-dbg-oeffnen ( / dir fh)
|
|
(if (and (car (atoms-family 1 '("DBG-SCHALTER-P")))
|
|
(dbg-schalter-p "vf-sepliste"))
|
|
(progn
|
|
(if (null *ssg-sepliste-dbg-pfad*)
|
|
(progn
|
|
(setq dir (getenv "DXFM_LOG"))
|
|
(if (or (null dir) (= dir "")) (setq dir "."))
|
|
(if (and (/= (substr dir (strlen dir) 1) "\\")
|
|
(/= (substr dir (strlen dir) 1) "/"))
|
|
(setq dir (strcat dir "\\")))
|
|
(setq *ssg-sepliste-dbg-pfad* (strcat dir "vf_sepliste.dbg"))
|
|
(setq fh (open *ssg-sepliste-dbg-pfad* "w"))
|
|
(if fh
|
|
(progn
|
|
(write-line "=== vf-sepliste Diagnose ===" fh)
|
|
(close fh)
|
|
(princ (strcat "\n[DBG] vf-sepliste-Protokoll: " *ssg-sepliste-dbg-pfad*)))
|
|
(progn
|
|
(princ (strcat "\n[DBG] FEHLER: " *ssg-sepliste-dbg-pfad*
|
|
" nicht schreibbar"))
|
|
(setq *ssg-sepliste-dbg-pfad* nil)))))
|
|
*ssg-sepliste-dbg-pfad*)
|
|
nil))
|
|
|
|
;; Eine Zeile anhaengen (kein Puffer - ein Bau erzeugt nur wenige hundert
|
|
;; Zeilen, dafuer geht keine Zeile verloren, wenn der Bau abbricht).
|
|
(defun ssg-sepliste-dbg (msg / pfad fh)
|
|
(if (setq pfad (ssg-sepliste-dbg-oeffnen))
|
|
(progn
|
|
(setq fh (open pfad "a"))
|
|
(if fh (progn (write-line msg fh) (close fh)))))
|
|
(princ))
|
|
|
|
;; Punkt (x y z) kompakt als "(x, y, z)" - nil-sicher.
|
|
(defun ssg-sepliste-dbg-pt (pt)
|
|
(if (and pt (listp pt))
|
|
(strcat "(" (rtos (car pt) 2 2) ", " (rtos (cadr pt) 2 2) ", "
|
|
(rtos (cond ((caddr pt)) (0.0)) 2 2) ")")
|
|
"nil"))
|
|
|
|
;; Einfaches Chunking eines Strings in Stuecke <= n Zeichen (DXF-Limit einer
|
|
;; 1000-Gruppe ist 255 Byte) - eigenstaendige Kopie statt vfl-chunk-string
|
|
;; (vf_linienzug.lsp), da diese Datei laut Lademechanismus VOR vf_linienzug
|
|
;; geladen wird und dessen Funktionen hier noch nicht existieren.
|
|
(defun ssg-sepliste-chunk-string (s n / out len)
|
|
(setq out '())
|
|
(while (> (setq len (strlen s)) n)
|
|
(setq out (cons (substr s 1 n) out))
|
|
(setq s (substr s (1+ n))))
|
|
(if (> (strlen s) 0) (setq out (cons s out)))
|
|
(reverse out))
|
|
|
|
;; Sammelt alle seit lastEnt neu erzeugten Separator-/AS-/ES-Entities in
|
|
;; Baureihenfolge (identische entnext-Wanderung wie die Auswahlsatz-Sammlung
|
|
;; der Aufrufer, nur mit wcmatch-Filter). Rueckgabe: Liste von
|
|
;; (typ lfdnr x y), typ = "SEP"/"AS"/"ES", lfdnr 1-basiert in Baureihenfolge.
|
|
(defun ssg-sepliste-sammeln (lastEnt / ent ed bname typ lfdnr pt liste)
|
|
(ssg-sepliste-dbg "=== ssg-sepliste-sammeln: entnext-Wanderung ab lastEnt ===")
|
|
(setq liste '() lfdnr 0)
|
|
(setq ent (if lastEnt (entnext lastEnt) (entnext)))
|
|
(while ent
|
|
(setq ed (entget ent))
|
|
(if (= (cdr (assoc 0 ed)) "INSERT")
|
|
(progn
|
|
(setq bname (cdr (assoc 2 ed)))
|
|
(setq typ (cond
|
|
((wcmatch bname "Staustrecke_Separator_SP_300_mm*") "SEP")
|
|
((wcmatch bname "AS_Element_*") "AS")
|
|
((wcmatch bname "ES_Element_*") "ES")
|
|
(t nil)))
|
|
(setq pt (cdr (assoc 10 ed)))
|
|
;; JEDEN INSERT protokollieren (auch die nicht klassifizierten) - nur so
|
|
;; laesst sich im .dbg nachvollziehen, welches Entity einen auffaelligen
|
|
;; Einfuegepunkt liefert und in welcher Reihenfolge es entstand.
|
|
(ssg-sepliste-dbg
|
|
(strcat "INSERT " bname
|
|
" handle=" (cond ((cdr (assoc 5 ed))) ("-"))
|
|
" typ=" (cond (typ) ("-"))
|
|
" pt=" (ssg-sepliste-dbg-pt pt)))
|
|
(if typ
|
|
(progn
|
|
(setq lfdnr (1+ lfdnr))
|
|
(setq liste (cons (list typ lfdnr (car pt) (cadr pt)) liste))
|
|
)
|
|
)
|
|
)
|
|
)
|
|
(setq ent (entnext ent))
|
|
)
|
|
(setq liste (reverse liste))
|
|
(ssg-sepliste-dbg (strcat "Ergebnis: " (itoa (length liste)) " Sepliste-Eintraege"))
|
|
(foreach e liste
|
|
(ssg-sepliste-dbg
|
|
(strcat " " (nth 0 e) " lfdnr=" (itoa (nth 1 e))
|
|
" x=" (rtos (nth 2 e) 2 2) " y=" (rtos (nth 3 e) 2 2))))
|
|
liste
|
|
)
|
|
|
|
;; Koordinate mit GENAU 2 Nachkommastellen formatieren - bewusst OHNE rtos.
|
|
;; rtos haengt an den Zeichnungs-Systemvariablen DIMZIN (Nullunterdrueckung),
|
|
;; LUPREC und LUNITS: bei dem hier verbreiteten DIMZIN=8 wuerde rtos die
|
|
;; abschliessenden Nullen wegwerfen (10.00 -> 10), und dieselben Koordinaten
|
|
;; serialisierten je nach Zeichnungsprofil unterschiedlich. Die Sepliste
|
|
;; landet als XDATA/Journal PERSISTENT am Block - die Serialisierung muss
|
|
;; darum reproduzierbar und profilunabhaengig sein. Rundung kaufmaennisch,
|
|
;; mit Uebertrag (9.999 -> 10.00), Vorzeichen bleibt erhalten.
|
|
(defun ssg-sepliste-fmt-koord (x / neg i f s)
|
|
(setq neg (< x 0.0) x (abs x))
|
|
(setq i (fix x))
|
|
(setq f (fix (+ 0.5 (* 100.0 (- x i)))))
|
|
(if (>= f 100) (progn (setq i (1+ i)) (setq f (- f 100))))
|
|
(setq s (strcat (itoa i) "."
|
|
(if (< f 10) (strcat "0" (itoa f)) (itoa f))))
|
|
(if neg (strcat "-" s) s)
|
|
)
|
|
|
|
;; Serialisiert die Sepliste zu "TYP:LFDNR:X:Y,TYP:LFDNR:X:Y,...".
|
|
(defun ssg-sepliste->string (liste / eintrag out first)
|
|
(setq out "" first t)
|
|
(foreach eintrag liste
|
|
(setq eintrag
|
|
(strcat (nth 0 eintrag) ":" (itoa (nth 1 eintrag)) ":"
|
|
(ssg-sepliste-fmt-koord (nth 2 eintrag)) ":"
|
|
(ssg-sepliste-fmt-koord (nth 3 eintrag))))
|
|
(if first (progn (setq out eintrag) (setq first nil))
|
|
(setq out (strcat out "," eintrag)))
|
|
)
|
|
out
|
|
)
|
|
|
|
;; Gegenstueck zu ssg-sepliste->string - Rueckgabe Liste von (typ lfdnr x y).
|
|
(defun ssg-sepliste-string->liste (s / out teile eintraege feld)
|
|
(setq out '())
|
|
(if (> (strlen s) 0)
|
|
(progn
|
|
(setq eintraege '() teile "")
|
|
(foreach c (ssg-sepliste-explode-chars s)
|
|
(if (= c ",")
|
|
(progn (setq eintraege (cons teile eintraege)) (setq teile ""))
|
|
(setq teile (strcat teile c))
|
|
)
|
|
)
|
|
(setq eintraege (reverse (cons teile eintraege)))
|
|
(foreach eintrag eintraege
|
|
(setq feld (ssg-sepliste-split-feld eintrag ":"))
|
|
(if (= (length feld) 4)
|
|
(setq out (cons (list (nth 0 feld) (atoi (nth 1 feld))
|
|
(atof (nth 2 feld)) (atof (nth 3 feld))) out))
|
|
)
|
|
)
|
|
)
|
|
)
|
|
(reverse out)
|
|
)
|
|
(defun ssg-sepliste-explode-chars (s / i n out)
|
|
(setq out '() i 1 n (strlen s))
|
|
(while (<= i n) (setq out (cons (substr s i 1) out)) (setq i (1+ i)))
|
|
(reverse out)
|
|
)
|
|
(defun ssg-sepliste-split-feld (s sep / pos out)
|
|
(setq out '())
|
|
(while (setq pos (vl-string-search sep s))
|
|
(setq out (cons (substr s 1 pos) out))
|
|
(setq s (substr s (+ pos 1 (strlen sep)))))
|
|
(reverse (cons s out))
|
|
)
|
|
|
|
;; Schreibt die Sepliste als XDATA (App app-name, z.B. "SSG_VF_SEP"/
|
|
;; "SSG_GF_SEP") auf den fertigen Wrapper-Block ent. Layout der 1000-Gruppen:
|
|
;; [0]="sepliste" (Marker), [1..]=serialisierte Liste in 250-Byte-Chunks
|
|
;; (DXF-Limit 255 Byte je 1000-Gruppe) - identisches Muster wie
|
|
;; vfl-journal-xdata-schreiben (vf_linienzug.lsp).
|
|
(defun ssg-sepliste-xdata-schreiben (ent app-name liste / chunks appentry)
|
|
(if (and ent liste)
|
|
(progn
|
|
(regapp app-name)
|
|
(setq chunks (ssg-sepliste-chunk-string (ssg-sepliste->string liste) 250))
|
|
(setq appentry
|
|
(cons app-name
|
|
(cons (cons 1000 "sepliste")
|
|
(mapcar (function (lambda (c) (cons 1000 c))) chunks))))
|
|
(entmod (append (entget ent) (list (list -3 appentry))))
|
|
)
|
|
)
|
|
ent
|
|
)
|
|
|
|
;; Liest die Sepliste-XDATA. Rueckgabe: Liste von (typ lfdnr x y), oder nil
|
|
;; (kein/unbekanntes Sepliste-XDATA am Entity).
|
|
(defun ssg-sepliste-xdata-lesen (ent app-name / xd app-data werte)
|
|
(setq xd (entget ent (list app-name)))
|
|
(setq app-data (cdr (assoc -3 xd)))
|
|
(if app-data
|
|
(progn
|
|
(setq werte (mapcar 'cdr (cdr (car app-data))))
|
|
(if (and werte (= (car werte) "sepliste"))
|
|
(ssg-sepliste-string->liste (apply 'strcat (cdr werte)))
|
|
nil))
|
|
nil
|
|
)
|
|
)
|
|
|
|
(princ)
|