diff --git a/Lisp/export.lsp b/Lisp/export.lsp index 423e978..fd59c30 100644 --- a/Lisp/export.lsp +++ b/Lisp/export.lsp @@ -630,9 +630,9 @@ ;; Kopie gesetzt werden kann (csv:sep-proxies-zuordnung-setzen). Die ;; proxy-enames dienen ausserdem csv:sep-proxies-loeschen nach dem Export. (defun csv:sep-proxies-erzeugen ( / ms ss-all i ename ed bname nested pt rotation - psx psy psz c si rec nested-ent nested-bname - local-pt nested-rot lx ly lz world-pt - block-obj proxy-liste) + extrusion0 R0 psx psy psz rec nested-ent nested-bname + local-pt R-nested R-final scaled-pt rot-pt world-pt + T4 block-obj xform-fehler proxy-liste) (setq ss-all (ssget "X" (list (cons 0 "INSERT")))) (if ss-all (progn @@ -649,25 +649,43 @@ (if nested (progn (setq pt (cdr (assoc 10 ed))) + (if (null (caddr pt)) (setq pt (list (car pt) (cadr pt) 0.0))) (setq rotation (cond ((cdr (assoc 50 ed))) (0.0))) + ;; Extrusion des Wrapper-INSERTs selbst beruecksichtigen statt + ;; reine Z-Drehung anzunehmen - GF_n/VF_n stehen zwar bisher immer + ;; flach (Extrusion (0 0 1)), aber mat3-from-normal-rotation + ;; reduziert sich dafuer ohnehin exakt auf Rz(rotation), kostet + ;; also nichts und macht den Code robust falls sich das aendert. + (setq extrusion0 (cond ((cdr (assoc 210 ed))) ('(0.0 0.0 1.0)))) + (setq R0 (mat3-from-normal-rotation extrusion0 rotation)) (setq psx (cond ((cdr (assoc 41 ed))) (1.0))) (setq psy (cond ((cdr (assoc 42 ed))) (1.0))) (setq psz (cond ((cdr (assoc 43 ed))) (1.0))) - (setq c (cos rotation) si (sin rotation)) (foreach rec nested (setq nested-ent (nth 0 rec)) (setq local-pt (nth 1 rec)) - (setq nested-rot (nth 2 rec)) + (setq R-nested (nth 2 rec)) (setq nested-bname (cdr (assoc 2 (entget nested-ent)))) - (setq lx (* psx (car local-pt)) - ly (* psy (cadr local-pt)) - lz (* psz (caddr local-pt))) - (setq world-pt - (list (+ (car pt) (- (* lx c) (* ly si))) - (+ (cadr pt) (+ (* lx si) (* ly c))) - (+ (cond ((caddr pt)) (0.0)) lz))) - ;; Rotation fuer vla-InsertBlock in RADIANT (ActiveX-Konvention, - ;; anders als der Grad-Winkel von "command _.INSERT"). + (setq scaled-pt (list (* psx (car local-pt)) + (* psy (cadr local-pt)) + (* psz (caddr local-pt)))) + (setq rot-pt (mat3-mul-vec3 R0 scaled-pt)) + (setq world-pt (list (+ (car pt) (car rot-pt)) + (+ (cadr pt) (cadr rot-pt)) + (+ (caddr pt) (caddr rot-pt)))) + (setq R-final (mat3-mul-mat3 R0 R-nested)) + ;; Volle 3D-Orientierung statt bisher nur eines Z-Drehwinkels: + ;; ein einzelner Skalar-Drehwinkel kann eine Kippung ausserhalb + ;; der XY-Ebene (Gefaellestrecke-/VF-Neigung) gar nicht + ;; darstellen. Deshalb - wie insert-block-ks-to-ks (vf_core.lsp) + ;; - am Ursprung mit Rotation=0 einfuegen und die komplette + ;; Lage (Drehung UND Verschiebung) in EINER vla-TransformBy + ;; anwenden, statt Rotation als vla-InsertBlock-Parameter. + (setq T4 (vlax-tmatrix + (list (list (car (car R-final)) (cadr (car R-final)) (caddr (car R-final)) (car world-pt)) + (list (car (cadr R-final)) (cadr (cadr R-final)) (caddr (cadr R-final)) (cadr world-pt)) + (list (car (caddr R-final)) (cadr (caddr R-final)) (caddr (caddr R-final)) (caddr world-pt)) + (list 0.0 0.0 0.0 1.0)))) ;; Gekapselt, weil hier - anders als beim frueheren festen ;; 1.0/1.0/1.0 - die tatsaechlichen Skalierungsfaktoren ;; durchgereicht werden: ein einzelner Sonderfall (entartete @@ -676,17 +694,29 @@ ;; eine Kopie ausfallen lassen - mit Meldung, welcher Block. (setq block-obj (vl-catch-all-apply 'vla-InsertBlock - (list ms (vlax-3D-point world-pt) nested-bname + (list ms (vlax-3D-point '(0.0 0.0 0.0)) nested-bname (csv:skalierung-oder-eins (* psx (nth 3 rec))) (csv:skalierung-oder-eins (* psy (nth 4 rec))) (csv:skalierung-oder-eins (* psz (nth 5 rec))) - (+ rotation nested-rot)))) - (if (vl-catch-all-error-p block-obj) - (princ (ssg-textf "exp-sep-proxy-fehler" - (list nested-bname bname - (vl-catch-all-error-message block-obj)))) - (setq proxy-liste - (cons (cons (vlax-vla-object->ename block-obj) ename) proxy-liste)) + 0.0))) + (cond + ((vl-catch-all-error-p block-obj) + (princ (ssg-textf "exp-sep-proxy-fehler" + (list nested-bname bname + (vl-catch-all-error-message block-obj))))) + (t + (setq xform-fehler (vl-catch-all-apply 'vla-TransformBy (list block-obj T4))) + (if (vl-catch-all-error-p xform-fehler) + (progn + (princ (ssg-textf "exp-sep-proxy-fehler" + (list nested-bname bname + (vl-catch-all-error-message xform-fehler)))) + (vl-catch-all-apply 'vla-Delete (list block-obj)) + ) + (setq proxy-liste + (cons (cons (vlax-vla-object->ename block-obj) ename) proxy-liste)) + ) + ) ) ) ) diff --git a/Lisp/ssg_core.lsp b/Lisp/ssg_core.lsp index 702738f..28746c3 100644 --- a/Lisp/ssg_core.lsp +++ b/Lisp/ssg_core.lsp @@ -201,6 +201,112 @@ ) +;; ------------------------------------------------------------ +;; 3x3-VEKTOR-/MATRIXHELFER (allgemein, dependency-frei) +;; ------------------------------------------------------------ +;; Hier statt in vf_core.lsp, weil ssg-collect-nested-inserts-rel (weiter +;; unten in diesem Modul) sie ebenfalls braucht und dieses Modul IMMER vor +;; jedem Feature-Modul (inkl. vf_core.lsp) geladen ist - siehe MNL-Ladeliste. +;; vf_core.lsp (insert-block-ks-to-ks/insert-block-mixed-to-ks) nutzt +;; dieselben Definitionen unveraendert weiter. + +;; Vektorkreuzprodukt a x b +(defun vec3-cross (a b) + (list (- (* (cadr a)(caddr b)) (* (caddr a)(cadr b))) + (- (* (caddr a)(car b)) (* (car a)(caddr b))) + (- (* (car a)(cadr b)) (* (cadr a)(car b))))) + +;; Vektor auf Einheitslaenge normieren +(defun vec3-normalize (v / len) + (setq len (vec-length v)) + (if (> len 1e-10) + (list (/ (car v) len) (/ (cadr v) len) (/ (caddr v) len)) + '(1.0 0.0 0.0))) + +;; 3x3-Rotationsmatrix (Zeilenliste) mal 3D-Vektor +(defun mat3-mul-vec3 (R v / r0 r1 r2) + (setq r0 (car R) r1 (cadr R) r2 (caddr R)) + (list (+ (* (car r0)(car v)) (* (cadr r0)(cadr v)) (* (caddr r0)(caddr v))) + (+ (* (car r1)(car v)) (* (cadr r1)(cadr v)) (* (caddr r1)(caddr v))) + (+ (* (car r2)(car v)) (* (cadr r2)(cadr v)) (* (caddr r2)(caddr v))))) + +;; Rotationsmatrix R sodass: R*xe=xt, R*ye=yt, R*ze=zt +;; (xt yt zt) = Ziel-Achsen; (xe ye ze) = Quell-Achsen (je normierte Einheitsvektoren) +;; Formel: R = M_target * M_source^T +;; R[i][j] = xt[i]*xe[j] + yt[i]*ye[j] + zt[i]*ze[j] +(defun mat3-from-frames (xt yt zt xe ye ze) + (list + (list (+ (* (car xt)(car xe)) (* (car yt)(car ye)) (* (car zt)(car ze))) + (+ (* (car xt)(cadr xe)) (* (car yt)(cadr ye)) (* (car zt)(cadr ze))) + (+ (* (car xt)(caddr xe)) (* (car yt)(caddr ye)) (* (car zt)(caddr ze)))) + (list (+ (* (cadr xt)(car xe)) (* (cadr yt)(car ye)) (* (cadr zt)(car ze))) + (+ (* (cadr xt)(cadr xe)) (* (cadr yt)(cadr ye)) (* (cadr zt)(cadr ze))) + (+ (* (cadr xt)(caddr xe)) (* (cadr yt)(caddr ye)) (* (cadr zt)(caddr ze)))) + (list (+ (* (caddr xt)(car xe)) (* (caddr yt)(car ye)) (* (caddr zt)(car ze))) + (+ (* (caddr xt)(cadr xe)) (* (caddr yt)(cadr ye)) (* (caddr zt)(cadr ze))) + (+ (* (caddr xt)(caddr xe)) (* (caddr yt)(caddr ye)) (* (caddr zt)(caddr ze)))))) + +;; --- 3x3-Matrizenprodukt A*B (beide als Zeilenlisten wie mat3-from-frames) --- +;; Spalten von B einzeln mit A multiplizieren (mat3-mul-vec3), Ergebnis-Matrix +;; aus den 3 Ergebnis-Spalten wieder ueber mat3-from-frames zusammensetzen +;; (mit Einheitsvektoren als Quell-Achsen baut das eine Matrix AUS Spalten - +;; siehe mat3-from-normal-rotation, das denselben Trick nutzt). +(defun mat3-mul-mat3 (A B / b-col0 b-col1 b-col2) + (setq b-col0 (list (caar B) (car (cadr B)) (car (caddr B)))) + (setq b-col1 (list (cadar B) (cadr (cadr B)) (cadr (caddr B)))) + (setq b-col2 (list (caddar B) (caddr (cadr B)) (caddr (caddr B)))) + (mat3-from-frames + (mat3-mul-vec3 A b-col0) (mat3-mul-vec3 A b-col1) (mat3-mul-vec3 A b-col2) + '(1.0 0.0 0.0) '(0.0 1.0 0.0) '(0.0 0.0 1.0)) +) + +;; --- OCS-Basis (Arbitrary Axis Algorithm) aus einer Extrusionsrichtung --- +;; normal = Extrusionsvektor (DXF-Gruppe 210/220/230, Laenge beliebig). +;; Rueckgabe: (ax ay az) - normierte OCS-Achsen, az = normiertes normal. +;; Standardalgorithmus (Autodesk "Arbitrary Axis Algorithm"): Referenzachse +;; ist Welt-Y, wenn normal nahe der Welt-Z-Achse liegt, sonst Welt-Z - damit +;; bleibt ax*ay*az immer ein wohldefiniertes, rechtshaendiges Dreibein, auch +;; wenn normal selbst (fast) mit der jeweiligen Referenzachse zusammenfaellt. +(defun mat3-ocs-basis (normal / n wy-ref ax ay) + (setq n (vec3-normalize normal)) + (setq wy-ref + (if (and (< (abs (car n)) (/ 1.0 64.0)) (< (abs (cadr n)) (/ 1.0 64.0))) + '(0.0 1.0 0.0) + '(0.0 0.0 1.0))) + (setq ax (vec3-normalize (vec3-cross wy-ref n))) + (setq ay (vec3-normalize (vec3-cross n ax))) + (list ax ay n) +) + +;; --- OCS-Basis als 3x3-Matrix (Spalten = ax ay az aus mat3-ocs-basis) --- +;; Rechnet einen OCS-lokalen Punkt/Vektor (z.B. die rohe INSERT-Gruppe 10 +;; eines gekippten Elements) in echte lokale Koordinaten der Elternebene um: +;; (mat3-mul-vec3 (mat3-ocs-matrix normal) ocs-punkt). +(defun mat3-ocs-matrix (normal / basis) + (setq basis (mat3-ocs-basis normal)) + (mat3-from-frames (car basis) (cadr basis) (caddr basis) + '(1.0 0.0 0.0) '(0.0 1.0 0.0) '(0.0 0.0 1.0)) +) + +;; --- Reine Z-Drehungsmatrix Rz(winkel), winkel in Radiant --- +(defun mat3-rz (winkel / c s) + (setq c (cos winkel) s (sin winkel)) + (mat3-from-frames (list c s 0.0) (list (- s) c 0.0) '(0.0 0.0 1.0) + '(1.0 0.0 0.0) '(0.0 1.0 0.0) '(0.0 0.0 1.0)) +) + +;; --- Volle 3x3-Rotationsmatrix aus Extrusion + Drehwinkel (DXF-Gruppen 210/50) --- +;; normal = Extrusionsvektor, rotation = Drehwinkel in Radiant. +;; = OCS-Basis(normal) * Rz(rotation): erst die eigene Z-Drehung IN der +;; (evtl. gekippten) OCS-Ebene, dann diese Ebene selbst in die Elternebene +;; kippen. Fuer normal=(0 0 1) ist mat3-ocs-matrix die Einheitsmatrix, das +;; Ergebnis reduziert sich also exakt auf Rz(rotation) - fuer bereits flache +;; Elemente aendert sich damit nichts am bisherigen Verhalten. +(defun mat3-from-normal-rotation (normal rotation) + (mat3-mul-mat3 (mat3-ocs-matrix normal) (mat3-rz rotation)) +) + + ;; ------------------------------------------------------------ ;; BENUTZER-ABFRAGEN ;; ------------------------------------------------------------ @@ -960,13 +1066,14 @@ ;; steckt. ;; ;; Rueckgabe: Liste von Treffer-Records, oder nil. Ein Record ist -;; (ename (x y z) rot-rad sx sy sz) +;; (ename (x y z) R sx sy sz) ;; mit der Platzierung des Treffers RELATIV zur abgefragten Blockdefinition ;; bname - ueber alle Verschachtelungsebenen hinweg aufsummiert (Position, -;; Z-Drehung und Skalierung). Der Aufrufer muss also nur noch die Platzierung -;; des top-level INSERT daraufrechnen. Der rohe Einfuegepunkt aus -;; (entget ename) ist bei mehr als einer Ebene NICHT verwendbar - er gilt nur -;; innerhalb der unmittelbaren Zwischen-Blockdefinition. +;; volle 3D-Rotationsmatrix R und Skalierung). Der Aufrufer muss also nur +;; noch die Platzierung des top-level INSERT daraufrechnen. Der rohe +;; Einfuegepunkt aus (entget ename) ist bei mehr als einer Ebene NICHT +;; verwendbar - er gilt nur innerhalb der unmittelbaren Zwischen- +;; Blockdefinition. ;; ;; Kein Selection-Set: die Entities sind nicht Space-resident und damit fuer ;; ssadd nicht sicher verwendbar. Sie bleiben ueber entget normal lesbar @@ -974,30 +1081,47 @@ ;; eigene Bounding-Box (vla-getboundingbox) liefert fuer sie keine sinnvollen ;; Weltkoordinaten. (defun ssg-collect-nested-inserts (bname pattern) - (ssg-collect-nested-inserts-rel bname pattern '(0.0 0.0 0.0) 0.0 1.0 1.0 1.0) + (ssg-collect-nested-inserts-rel bname pattern '(0.0 0.0 0.0) + '((1.0 0.0 0.0) (0.0 1.0 0.0) (0.0 0.0 1.0)) + 1.0 1.0 1.0) ) ;; --- Rekursions-Rumpf mit mitgefuehrter Platzierung --- -;; basis-pt/basis-rot/bsx/bsy/bsz = Platzierung der gerade durchsuchten +;; basis-pt/basis-R/bsx/bsy/bsz = Platzierung der gerade durchsuchten ;; Blockdefinition im Koordinatensystem des URSPRUENGLICH abgefragten Blocks. ;; Auf jeder Ebene wird der Einfuegepunkt des Sub-INSERT erst mit der -;; Skalierung, dann mit der Drehung der Ebene darueber verrechnet und +;; Skalierung, dann mit der Rotation der Ebene darueber verrechnet und ;; aufaddiert - genau das fehlte frueher: die Rekursion gab die Entities ;; tieferer Ebenen mit ihrer ROH-Position aus der jeweiligen Zwischen- ;; Blockdefinition zurueck. Zwei Separatoren, die in zwei verschieden ;; platzierten Zwischenbloecken an derselben lokalen Stelle sitzen, landeten ;; dadurch auf exakt derselben Weltposition (und damit beim falschen Carrier). ;; -;; Modellannahme wie im uebrigen Export (csv:local-to-world): reine -;; Z-Drehung, keine OCS-/Extrusionsrichtung. Fuer die Wrapper-Ketten -;; VF_n/GF_n/KREISEL_n trifft das zu. -(defun ssg-collect-nested-inserts-rel (bname pattern basis-pt basis-rot bsx bsy bsz +;; basis-R ist eine VOLLE 3x3-Rotationsmatrix (mat3-* oben in diesem Modul), +;; keine reine Z-Drehung mehr: ein Sub-INSERT, dessen Extrusionsrichtung +;; (DXF-Gruppe 210) von der Welt-Z-Achse abweicht - z.B. die um den +;; Gefaellewinkel gekippte Staustrecke/Separator-Kette in +;; Gefaellestrecke.lsp/vf_standard.lsp (ssg-rot-matrix-zy, Rz(hz)*Ry(-vert)) +;; - hat seinen eigenen Einfuegepunkt (Gruppe 10) NICHT in den gewoehnlichen +;; lokalen XYZ-Koordinaten der Elterndefinition, sondern relativ zu SEINER +;; EIGENEN, gekippten OCS-Ebene (Arbitrary Axis Algorithm). Die fruehere +;; reine Z-Drehung ignorierte das komplett und lieferte fuer gekippte Ketten +;; einen falschen, von der tatsaechlichen Fahrtrichtung unabhaengigen +;; ("eingefrorenen") Weltpunkt. mat3-ocs-matrix wandelt die rohe OCS-lokale +;; Gruppe-10 in echte lokale Koordinaten um, bevor sie mit der Eltern- +;; Rotation weiterverrechnet wird; mat3-from-normal-rotation liefert die +;; volle 3D-Orientierung des Sub-INSERTs selbst (fuer die naechste +;; Rekursionsebene bzw. den Treffer-Record). Fuer Extrusion=(0 0 1) (der +;; Normalfall, z.B. Kreisel/Eckrad) reduziert sich beides exakt auf die alte +;; reine Z-Drehung - unveraendertes Verhalten dort. +(defun ssg-collect-nested-inserts-rel (bname pattern basis-pt basis-R bsx bsy bsz / blk-tbl sub-ent sub-ed sub-bname loc-pt - rot sx sy sz c si lx ly lz wx wy wz result) + extrusion rot sx sy sz ocs-mat loc-pt-real + scaled-pt rot-pt R-local R-world world-pt + result) (setq blk-tbl (tblsearch "BLOCK" bname)) (if blk-tbl (progn - (setq c (cos basis-rot) si (sin basis-rot)) (setq sub-ent (entnext (cdr (assoc -2 blk-tbl)))) (while sub-ent (setq sub-ed (entget sub-ent)) @@ -1005,23 +1129,36 @@ (progn (setq sub-bname (cdr (assoc 2 sub-ed))) (setq loc-pt (cdr (assoc 10 sub-ed))) + (if (null (caddr loc-pt)) + (setq loc-pt (list (car loc-pt) (cadr loc-pt) 0.0))) (setq rot (cond ((cdr (assoc 50 sub-ed))) (0.0))) + (setq extrusion (cond ((cdr (assoc 210 sub-ed))) ('(0.0 0.0 1.0)))) (setq sx (cond ((cdr (assoc 41 sub-ed))) (1.0))) (setq sy (cond ((cdr (assoc 42 sub-ed))) (1.0))) (setq sz (cond ((cdr (assoc 43 sub-ed))) (1.0))) - (setq lx (* bsx (car loc-pt)) - ly (* bsy (cadr loc-pt)) - lz (* bsz (cond ((caddr loc-pt)) (0.0)))) - (setq wx (+ (car basis-pt) (- (* lx c) (* ly si))) - wy (+ (cadr basis-pt) (+ (* lx si) (* ly c))) - wz (+ (caddr basis-pt) lz)) + ;; Gruppe-10 ist OCS-lokal (relativ zu diesem Sub-INSERTs EIGENER + ;; Extrusion) - erst in echte lokale Koordinaten der aktuell + ;; durchsuchten Blockdefinition umrechnen, dann skalieren, dann + ;; mit der Eltern-Matrix in Weltkoordinaten drehen/verschieben. + (setq ocs-mat (mat3-ocs-matrix extrusion)) + (setq loc-pt-real (mat3-mul-vec3 ocs-mat loc-pt)) + (setq scaled-pt (list (* bsx (car loc-pt-real)) + (* bsy (cadr loc-pt-real)) + (* bsz (caddr loc-pt-real)))) + (setq rot-pt (mat3-mul-vec3 basis-R scaled-pt)) + (setq world-pt (list (+ (car basis-pt) (car rot-pt)) + (+ (cadr basis-pt) (cadr rot-pt)) + (+ (caddr basis-pt) (caddr rot-pt)))) + ;; Volle 3D-Orientierung dieses Sub-INSERTs in Weltkoordinaten. + (setq R-local (mat3-from-normal-rotation extrusion rot)) + (setq R-world (mat3-mul-mat3 basis-R R-local)) (if (wcmatch sub-bname pattern) - (setq result (cons (list sub-ent (list wx wy wz) (+ basis-rot rot) + (setq result (cons (list sub-ent world-pt R-world (* bsx sx) (* bsy sy) (* bsz sz)) result)) (setq result (append result (ssg-collect-nested-inserts-rel sub-bname pattern - (list wx wy wz) (+ basis-rot rot) + world-pt R-world (* bsx sx) (* bsy sy) (* bsz sz)))) ) ) diff --git a/Lisp/vf_core.lsp b/Lisp/vf_core.lsp index e478ef6..fb0fcd2 100644 --- a/Lisp/vf_core.lsp +++ b/Lisp/vf_core.lsp @@ -119,42 +119,15 @@ ;; ============================================================ ;; TEIL 4b: KS-FRAME MATHEMATIK ;; ============================================================ - -;; Vektorkreuzprodukt a x b -(defun vec3-cross (a b) - (list (- (* (cadr a)(caddr b)) (* (caddr a)(cadr b))) - (- (* (caddr a)(car b)) (* (car a)(caddr b))) - (- (* (car a)(cadr b)) (* (cadr a)(car b))))) - -;; Vektor auf Einheitslaenge normieren -(defun vec3-normalize (v / len) - (setq len (vec-length v)) - (if (> len 1e-10) - (list (/ (car v) len) (/ (cadr v) len) (/ (caddr v) len)) - '(1.0 0.0 0.0))) - -;; 3x3-Rotationsmatrix (Zeilenliste) mal 3D-Vektor -(defun mat3-mul-vec3 (R v / r0 r1 r2) - (setq r0 (car R) r1 (cadr R) r2 (caddr R)) - (list (+ (* (car r0)(car v)) (* (cadr r0)(cadr v)) (* (caddr r0)(caddr v))) - (+ (* (car r1)(car v)) (* (cadr r1)(cadr v)) (* (caddr r1)(caddr v))) - (+ (* (car r2)(car v)) (* (cadr r2)(cadr v)) (* (caddr r2)(caddr v))))) - -;; Rotationsmatrix R sodass: R*xe=xt, R*ye=yt, R*ze=zt -;; (xt yt zt) = Ziel-Achsen; (xe ye ze) = Quell-Achsen (je normierte Einheitsvektoren) -;; Formel: R = M_target * M_source^T -;; R[i][j] = xt[i]*xe[j] + yt[i]*ye[j] + zt[i]*ze[j] -(defun mat3-from-frames (xt yt zt xe ye ze) - (list - (list (+ (* (car xt)(car xe)) (* (car yt)(car ye)) (* (car zt)(car ze))) - (+ (* (car xt)(cadr xe)) (* (car yt)(cadr ye)) (* (car zt)(cadr ze))) - (+ (* (car xt)(caddr xe)) (* (car yt)(caddr ye)) (* (car zt)(caddr ze)))) - (list (+ (* (cadr xt)(car xe)) (* (cadr yt)(car ye)) (* (cadr zt)(car ze))) - (+ (* (cadr xt)(cadr xe)) (* (cadr yt)(cadr ye)) (* (cadr zt)(cadr ze))) - (+ (* (cadr xt)(caddr xe)) (* (cadr yt)(caddr ye)) (* (cadr zt)(caddr ze)))) - (list (+ (* (caddr xt)(car xe)) (* (caddr yt)(car ye)) (* (caddr zt)(car ze))) - (+ (* (caddr xt)(cadr xe)) (* (caddr yt)(cadr ye)) (* (caddr zt)(cadr ze))) - (+ (* (caddr xt)(caddr xe)) (* (caddr yt)(caddr ye)) (* (caddr zt)(caddr ze)))))) +;; vec3-cross/vec3-normalize/mat3-mul-vec3/mat3-from-frames (und die +;; OCS-/Extrusions-Helfer mat3-mul-mat3/mat3-ocs-basis/mat3-ocs-matrix/ +;; mat3-rz/mat3-from-normal-rotation) sitzen in ssg_core.lsp, nicht hier: +;; ssg-collect-nested-inserts-rel (Export-Zuordnung verpackter Separatoren) +;; braucht sie ebenfalls und ist ein CORE-Modul, das IMMER vor vf_core.lsp +;; geladen ist - vf_core.lsp selbst ist nur ein Feature-Modul (nicht jede +;; Zeichnung laedt VarioFoerderer). Damit beide Seiten dieselbe, einzige +;; Definition nutzen, wohnen die allgemeinen Vektor-/Matrix-Helfer im immer +;; geladenen Core (wie ssg-rot-matrix-zy schon dort wohnt) statt hier. ;; Normierter KS-Rahmen aus rohen KS-Daten (origin x-end y-end z-end) ;; Eingabe: Teilliste aus extract-ks-from-block-raw, z.B. (cadr (assoc "KS_EIN" ks-data))