die DWG sind bereinigt. Die bisherige positionsbasierte Block-Einfügung (Punkt + Winkel) wurde durch eine vollständige 3D-Frame-Kettung über KS_EIN/KS_AUS-Koordinatensysteme ersetzt, sodass beliebige räumliche Orientierungen korrekt durch die gesamte VarioFoerderer- und Gefaellestrecke-Anlage propagiert werden.

This commit is contained in:
2026-06-30 12:29:33 +02:00
parent 4a9d29f243
commit 0bee5ad8d0
22 changed files with 327 additions and 36 deletions
+67 -30
View File
@@ -332,6 +332,22 @@
)
)
;; --- KS-Rahmen aus Fahrtrichtungsvektor (Fallback wenn vf_core nicht geladen) ---
(if (null (car (atoms-family 1 '("MAKE-FRAME-FROM-DIR"))))
(defun make-frame-from-dir (P xu-unit / hlen yu zu)
(setq hlen (sqrt (+ (* (car xu-unit)(car xu-unit))
(* (cadr xu-unit)(cadr xu-unit)))))
(setq yu
(if (> hlen 1e-6)
(list (/ (- (cadr xu-unit)) hlen) (/ (car xu-unit) hlen) 0.0)
'(1.0 0.0 0.0)))
(setq zu
(list (- (* (cadr xu-unit)(caddr yu)) (* (caddr xu-unit)(cadr yu)))
(- (* (caddr xu-unit)(car yu)) (* (car xu-unit)(caddr yu)))
(- (* (car xu-unit)(cadr yu)) (* (cadr xu-unit)(car yu)))))
(list P xu-unit yu zu))
)
;; --- Linie/Polylinie-Endpunkte lesen ---
(if (null (car (atoms-family 1 '("GET-LINE-START-END-POINTS"))))
(defun get-line-start-end-points (msg / ent obj obj-name sp ep)
@@ -775,20 +791,19 @@
)
;; Alle Segmente des Linienzugs einfuegen.
;; segmente: Ergebnis von gf-analysiere-kette
;; grade: Gefaellewinkel in Grad
;; startpunkt: 3D-Einfuegepunkt des ersten Blocks
;;
;; Reihenfolge bei Bogen:
;; ... Staustrecke (Linie) → Separator am Ende der Linie → Gefaellebogen ...
(defun gf-linienzug-einfuegen (segmente grade startpunkt /
aktuell i n seg naechstes
typ hz laenge bwinkel bseite blockname)
(setq aktuell startpunkt)
;; segmente : Ergebnis von gf-analysiere-kette
;; grade : Gefaellewinkel in Grad
;; startframe : Vollstaendiger Rahmen (P xu yu zu) am Kettenanfang
;; Rueckgabe : Vollstaendiger Rahmen (P xu yu zu) am Kettenende
(defun gf-linienzug-einfuegen (segmente grade startframe /
aktuell-frame i n seg naechstes
typ hz laenge bwinkel bseite blockname
rad-h rad-v xu-incl endpunkt)
(setq aktuell-frame startframe)
(setq n (length segmente))
(setq i 0)
(while (< i n)
(setq seg (nth i segmente))
(setq seg (nth i segmente))
(setq naechstes (if (< (1+ i) n) (nth (1+ i) segmente) nil))
(setq typ (car seg))
(setq hz (cadr seg))
@@ -801,9 +816,16 @@
": Staustrecke L=" (rtos laenge 2 1) " mm"
" hz=" (rtos hz 2 1) grad-zeichen
" v=" (rtos grade 2 2) grad-zeichen))
(setq aktuell
(setq endpunkt
(gf-insert-hz-incl-scaled
"Staustrecke_SP_1000_mm" aktuell laenge hz grade))
"Staustrecke_SP_1000_mm" (car aktuell-frame) laenge hz grade))
;; Ausgangsrahmen: geneigte Fahrtrichtung
(setq rad-h (* (float hz) (/ pi 180.0)))
(setq rad-v (* (float grade) (/ pi 180.0)))
(setq xu-incl (list (* (cos rad-h)(cos rad-v))
(* (sin rad-h)(cos rad-v))
(- (sin rad-v))))
(setq aktuell-frame (make-frame-from-dir endpunkt xu-incl))
;; Separator am Ende dieser Linie, falls naechstes Segment ein Bogen ist
(if (and naechstes (= (car naechstes) "Bogen"))
(progn
@@ -811,20 +833,20 @@
": Separator 300mm (vor Bogen)"
" hz=" (rtos hz 2 1) grad-zeichen
" v=" (rtos grade 2 2) grad-zeichen))
(setq aktuell
(setq endpunkt
(gf-insert-hz-with-ks
"Staustrecke_Separator_SP_300_mm" aktuell hz grade 300 0))
"Staustrecke_Separator_SP_300_mm" (car aktuell-frame) hz grade 300 0))
(setq aktuell-frame (make-frame-from-dir endpunkt xu-incl))
)
)
)
((= typ "Bogen")
(setq blockname (gf-bogen-blockname bwinkel bseite))
;; Gefaellebogen (nur Hz-Rotation, Block hat eigene 3D-Geometrie)
(princ (strcat "\n\n" (itoa (1+ i)) "/" (itoa n)
": " blockname
" hz=" (rtos hz 2 1) grad-zeichen))
(setq aktuell
(gf-insert-gefaellebogen-by-ks blockname aktuell hz))
;; Gefaellebogen: KS_EIN an aktuellem Rahmen ausrichten (volle 3D-Rotation)
(setq aktuell-frame (insert-block-ks-to-ks blockname aktuell-frame))
)
)
(setq i (1+ i))
@@ -832,8 +854,7 @@
(princ "\n\n=========================================")
(princ "\n>>> Linienzug-Gefaellestrecke eingefuegt! <<<")
(princ "\n=========================================")
aktuell
)
aktuell-frame)
;; Listenelement an Position idx durch val ersetzen.
(defun gf-replace-nth (lst idx val / i result)
@@ -873,10 +894,12 @@
entry-hz exit-hz
first-idx last-idx neu-l
chz shz as-target
aktuell-pt nach-aus-pt
aktuell-pt aktuell-frame nach-aus-pt
gf-nummer last-ent
L-gf-str delta-l-gf laengen-liste first-l l-item
bL90 bL60 bL30 bR90 bR60 bR30 n-bogen-gf)
bL90 bL60 bL30 bR90 bR60 bR30 n-bogen-gf
rad-h-as rad-v-as xu-entry
sep-endpunkt rad-h-es rad-v-es xu-exit sep-frame)
(princ "\n\n>>> MODUS 3: Linienzug auswaehlen <<<")
(princ "\nBitte alle Linien (LINE) und Boegen (ARC) des Pfades auswaehlen,")
(princ "\ndann ENTER druecken:")
@@ -1068,19 +1091,33 @@
(setq aktuell-pt (gf-insert-gefaellebogen-by-ks as-block as-target entry-hz))
(setq nach-aus-pt aktuell-pt)
;; Linienzug mit Gefaellebogen und Separatoren (gekuerzte Laengen)
(setq aktuell-pt (gf-linienzug-einfuegen segmente grade aktuell-pt))
;; Eingangsrahmen nach AS-Element: Position + geneigte Fahrtrichtung
(setq rad-h-as (* (float entry-hz) (/ pi 180.0)))
(setq rad-v-as (* (float grade) (/ pi 180.0)))
(setq xu-entry (list (* (cos rad-h-as)(cos rad-v-as))
(* (sin rad-h-as)(cos rad-v-as))
(- (sin rad-v-as))))
(setq aktuell-frame (make-frame-from-dir aktuell-pt xu-entry))
;; Linienzug mit Gefaellebogen und Separatoren (Frame-basiert)
(setq aktuell-frame (gf-linienzug-einfuegen segmente grade aktuell-frame))
;; Separator vor EIN-Element
(princ "\n>>> Separator vor EIN-Element")
(setq aktuell-pt
(setq sep-endpunkt
(gf-insert-hz-with-ks "Staustrecke_Separator_SP_300_mm"
aktuell-pt exit-hz grade 300 0))
(car aktuell-frame) exit-hz grade 300 0))
;; Ausgangsrahmen nach Separator fuer ES-Element
(setq rad-h-es (* (float exit-hz) (/ pi 180.0)))
(setq rad-v-es (* (float grade) (/ pi 180.0)))
(setq xu-exit (list (* (cos rad-h-es)(cos rad-v-es))
(* (sin rad-h-es)(cos rad-v-es))
(- (sin rad-v-es))))
(setq sep-frame (make-frame-from-dir sep-endpunkt xu-exit))
;; EIN-Element mit Austrittsrichtung ausrichten (Rz um exit-hz)
(princ (strcat "\n>>> EIN-Element: " es-block
" (hz=" (rtos exit-hz 2 1) grad-zeichen ")"))
(gf-insert-gefaellebogen-by-ks es-block aktuell-pt exit-hz)
;; EIN-Element: KS_EIN an vollstaendigem Rahmen ausrichten (KS-zu-KS)
(princ (strcat "\n>>> EIN-Element: " es-block))
(insert-block-ks-to-ks es-block sep-frame)
;; --- GF_N-Block erstellen ---
+6 -6
View File
@@ -19,8 +19,9 @@
;; DXFM_DIM sicher lesen (type-Guard gegen nicht-String Rueckgabewerte)
(setq *ki-dxfm-dim* (getenv "DXFM_DIM"))
(if (not (= (type *ki-dxfm-dim*) 'STR)) (setq *ki-dxfm-dim* "3D"))
;; Block-Pfad: primaer aus DXFMAKRO + DXFM_DIM, dann *ssg-lisp-pfad*-Heuristik
(setq block-pfad
;; Modul-eigener Block-Pfad (nicht in globalem block-pfad speichern,
;; da GF/VF stets 3D-Pfad benoetigen, KI aber DXFM_DIM-abhaengig)
(setq *block-path*
(cond
((and (getenv "DXFMAKRO") (= (type (getenv "DXFMAKRO")) 'STR))
(strcat (vl-string-right-trim "/" (vl-string-translate "\\" "/" (getenv "DXFMAKRO")))
@@ -34,7 +35,6 @@
nil)
)
)
(setq *block-path* block-pfad)
;; ssg_core laden falls noch nicht geschehen (Schutz bei direktem Laden ohne ssg-ensure)
(if (null (car (atoms-family 1 '("SSG-CFG-OR"))))
@@ -401,10 +401,10 @@
)
;; AN8 Kreis (Antriebsstation) bei (radius, 0)
(command "_.INSERT" (strcat block-pfad "AN8.dwg") (list radius 0.0 0.0) 1 1 0)
(command "_.INSERT" (strcat *block-path* "AN8.dwg") (list radius 0.0 0.0) 1 1 0)
;; SP8 Kreis (Spannstation) bei (radius+abstand, 0)
(command "_.INSERT" (strcat block-pfad "SP8.dwg") (list (+ radius abstand) 0.0 0.0) 1 1 0)
(command "_.INSERT" (strcat *block-path* "SP8.dwg") (list (+ radius abstand) 0.0 0.0) 1 1 0)
;; Tangenten auf Layer S_LP
(ssg-make-layer "S_LP" "7" T)
@@ -1288,6 +1288,6 @@
(princ "\n>>> KREISELINSERT v7.0 geladen <<<")
(princ "\n>>> Befehle: KreiselInsert, KreiselConnect, KreiselRedraw,")
(princ "\n KreiselEdit, KreiselQuick, KreiselParams, ILS_Eckrad")
(if block-pfad (princ (strcat "\n Block-Pfad: " block-pfad)))
(if *block-path* (princ (strcat "\n Block-Pfad: " *block-path*)))
(princ "\n=========================================")
(princ)
+146
View File
@@ -156,6 +156,81 @@
(cadr item))))
ks-rel))
;; ============================================================
;; 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))))))
;; 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))
;; Rueckgabe: (P xu yu zu) - Ursprung + 3 normierte Einheitsvektoren
(defun ks-frame-extract (ks-raw / origin x-end y-end z-end)
(setq origin (car ks-raw)
x-end (cadr ks-raw)
y-end (caddr ks-raw)
z-end (cadddr ks-raw))
(list origin
(vec3-normalize (list (- (car x-end)(car origin))
(- (cadr x-end)(cadr origin))
(- (caddr x-end)(caddr origin))))
(vec3-normalize (list (- (car y-end)(car origin))
(- (cadr y-end)(cadr origin))
(- (caddr y-end)(caddr origin))))
(vec3-normalize (list (- (car z-end)(car origin))
(- (cadr z-end)(cadr origin))
(- (caddr z-end)(caddr origin))))))
;; KS-Rahmen aus normiertem Fahrtrichtungsvektor mit horizontaler Senkrechtachse
;; Rueckgabe: (P xu yu zu)
;; Konvention: yu = horizontal senkrecht zu xu (links der Fahrtrichtung)
;; zu = xu x yu (senkrecht zur Gurtoberflaeche, nach oben)
(defun make-frame-from-dir (P xu-unit / hlen yu zu)
(setq hlen (sqrt (+ (* (car xu-unit)(car xu-unit))
(* (cadr xu-unit)(cadr xu-unit)))))
(setq yu
(if (> hlen 1e-6)
(list (/ (- (cadr xu-unit)) hlen)
(/ (car xu-unit) hlen)
0.0)
'(1.0 0.0 0.0)))
(setq zu (vec3-cross xu-unit yu))
(list P xu-unit yu zu))
;; ============================================================
;; TEIL 5: KS_EIN/KS_AUS EXTRAKTION
;; ============================================================
@@ -395,6 +470,77 @@
)
)
;; Fuegt Block ein und richtet KS_EIN am Ziel-Rahmen aus (volle 3D-Rotation).
;; target-frame : (P xt yt zt) - Ziel-Rahmen, z.B. KS_AUS des Vorgaenger-Elements
;; Rueckgabe : (P xu yu zu) - KS_AUS-Rahmen des eingefuegten Blocks
(defun insert-block-ks-to-ks (blockname target-frame /
block-obj ks-data ks-ein-raw ks-aus-raw
f-ein f-aus P-t xt yt zt
P-ein xe ye ze P-aus xu-aus yu-aus zu-aus
R R-Pein R-Paus tx ty tz T4
P-out xu-out yu-out zu-out)
(ensure-block-loaded blockname)
(if (not (tblsearch "BLOCK" blockname))
(progn
(princ (strcat "\n FEHLER: Block '" blockname "' nicht in Bibliothek"))
(exit)))
;; Ziel-Rahmen auspacken
(setq P-t (car target-frame)
xt (cadr target-frame)
yt (caddr target-frame)
zt (cadddr target-frame))
;; Block am Ursprung einfuegen (Rotation=0, Massstab=1)
(setq block-obj (vla-InsertBlock modelspace
(vlax-3D-point '(0 0 0))
blockname 1.0 1.0 1.0 0))
;; KS_EIN und KS_AUS extrahieren (nutzt Cache nach erstem Aufruf)
(setq ks-data (extract-ks-from-block block-obj))
(setq ks-ein-raw (cadr (assoc "KS_EIN" ks-data)))
(setq ks-aus-raw (cadr (assoc "KS_AUS" ks-data)))
(if (not (and ks-ein-raw ks-aus-raw))
(progn
(princ (strcat "\n FEHLER: KS_EIN/KS_AUS fehlen in '" blockname "'"))
(vla-Delete block-obj)
(exit)))
;; Normierte Rahmen (P xu yu zu) aus rohen KS-Daten berechnen
(setq f-ein (ks-frame-extract ks-ein-raw)
f-aus (ks-frame-extract ks-aus-raw))
(setq P-ein (car f-ein)
xe (cadr f-ein)
ye (caddr f-ein)
ze (cadddr f-ein))
(setq P-aus (car f-aus)
xu-aus (cadr f-aus)
yu-aus (caddr f-aus)
zu-aus (cadddr f-aus))
;; Rotationsmatrix: R * xe = xt, R * ye = yt, R * ze = zt
(setq R (mat3-from-frames xt yt zt xe ye ze))
;; Translation: t = P_target - R * P_ein
(setq R-Pein (mat3-mul-vec3 R P-ein))
(setq tx (- (car P-t) (car R-Pein))
ty (- (cadr P-t) (cadr R-Pein))
tz (- (caddr P-t) (caddr R-Pein)))
;; 4x4-Transformationsmatrix aufbauen und auf Block anwenden
(setq T4 (vlax-tmatrix
(list (list (car (car R)) (cadr (car R)) (caddr (car R)) tx)
(list (car (cadr R)) (cadr (cadr R)) (caddr (cadr R)) ty)
(list (car (caddr R)) (cadr (caddr R)) (caddr (caddr R)) tz)
(list 0.0 0.0 0.0 1.0))))
(vla-TransformBy block-obj T4)
;; Ausgabe-Rahmen fuer KS_AUS mathematisch berechnen (kein Re-Extrahieren noetig)
(setq R-Paus (mat3-mul-vec3 R P-aus))
(setq P-out (list (+ (car R-Paus) tx)
(+ (cadr R-Paus) ty)
(+ (caddr R-Paus) tz)))
(setq xu-out (mat3-mul-vec3 R xu-aus)
yu-out (mat3-mul-vec3 R yu-aus)
zu-out (mat3-mul-vec3 R zu-aus))
(princ (strcat "\n '" blockname "' eingefuegt"
"\n KS_AUS: X=" (rtos (car P-out) 2 2)
" Y=" (rtos (cadr P-out) 2 2)
" Z=" (rtos (caddr P-out) 2 2)))
(list P-out xu-out yu-out zu-out))
(defun insert-inclined-scaled-block (blockname startpunkt laenge winkel /
rad matrix block-obj endpunkt scale)
(if (<= laenge 0.1)
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+108
View File
@@ -0,0 +1,108 @@
# KS-Frame-Architektur — Aufbaulogik
## Kernidee
Jeder 3D-Block enthaelt eingebettete **KS_EIN**- und **KS_AUS**-Teilbloecke
(Koordinatensystem-Marker). Statt Winkel und Position manuell zu berechnen,
wird die Kette der Bloecke rein mathematisch verknuepft:
```
KS_AUS(n) ──► KS_EIN(n+1) ──► Block(n+1) eingefuegt ──► KS_AUS(n+1) ──► ...
```
Jeder **Frame** = `(P xu yu zu)` — Ursprung + 3 normierte Einheitsvektoren
(Fahrtrichtung, links-senkrecht, hoch).
---
## Schritt 1 — Mathematisches Fundament (`vf_core.lsp`)
Reine Hilfsfunktionen ohne Seiteneffekte:
| Funktion | Eingabe → Ausgabe |
|---|---|
| `ks-frame-extract` | Rohdaten `(origin x-end y-end z-end)` → normierter Frame `(P xu yu zu)` |
| `vec3-normalize` | Vektor → Einheitsvektor |
| `vec3-cross` | (a, b) → Kreuzprodukt |
| `mat3-mul-vec3` | 3×3-Matrix × Vektor |
| `mat3-from-frames` | `(xt yt zt, xe ye ze)` → Rotationsmatrix R mit `R*xe=xt` |
| `make-frame-from-dir` | Punkt + Richtungsvektor → vollstaendiger Frame (yu=links-horizontal, zu=hoch) |
---
## Schritt 2 — Kernfunktion `insert-block-ks-to-ks` (`vf_core.lsp`)
```lisp
(insert-block-ks-to-ks blockname target-frame) KS_AUS-frame
```
Ablauf intern:
1. Block bei `(0 0 0)` einfuegen (Rohzustand)
2. KS_EIN und KS_AUS aus Block extrahieren
3. Rotationsmatrix berechnen: `R = mat3-from-frames(xt yt zt, xe ye ze)`
4. Translation: `t = P_target R × P_EIN`
5. 4×4-Transformationsmatrix `T4` aufbauen und auf Block anwenden via `vla-TransformBy`
6. KS_AUS-Frame mathematisch mitrotieren (kein zweites Extrahieren noetig)
Das ist die einzige Funktion, die alle spaetere Module brauchen.
---
## Schritt 3 — Gefaellestrecke Modus 3 (`Gefaellestrecke.lsp`)
Ersetzt die alte positions-basierte Einfuegung durch Frame-Kettung:
**Vorher**: `aktuell-pt` (nur 2D-Punkt) + manuelle Winkelrechnung
**Nachher**: `aktuell-frame` (vollstaendiger 3D-Frame) propagiert durch die
gesamte Streckenkette
- Linie-Segment: `make-frame-from-dir(endpunkt, xu-incl)` → neuer Frame
- Bogen-Segment: `insert-block-ks-to-ks(blockname, aktuell-frame)` → gibt
direkt den Folge-Frame zurueck
---
## Schritt 4 — VarioFoerderer (`vf_standard.lsp` / `vf_etage.lsp`)
Gleiche Umstellung wie Schritt 3, aber fuer gerade Foerderstrecken:
- `insert-block-by-ks` und `insert-rotated-block-with-ks` → ersetzt durch
`insert-block-ks-to-ks`
- `variofoerderer-einfuegen` und `vf-etage-einfuegen`: `startpunkt``startframe`
---
## Warum diese Reihenfolge?
```
Schritt 1: Fundament legen (keine Abhaengigkeiten)
Schritt 2: Kernfunktion auf Fundament aufsetzen
Schritt 3: Gefaellestrecke zuerst — komplexer (3D-Neigung + Boegen)
Schritt 4: VarioFoerderer — einfacher (nur ebene Kurven)
```
---
## Zusammenfassung in einem Satz
Die bisherige positionsbasierte Block-Einfuegung (Punkt + Winkel) wurde
durch eine vollstaendige **3D-Frame-Kettung ueber
KS_EIN/KS_AUS-Koordinatensysteme** ersetzt, sodass beliebige raeumliche
Orientierungen korrekt durch die gesamte VarioFoerderer- und
Gefaellestrecke-Anlage propagiert werden.
---
## Betroffene Dateien
| Datei | Aenderung |
|---|---|
| `Lisp/vf_core.lsp` | Schritt 1 + 2: neue Hilfsfunktionen und `insert-block-ks-to-ks` |
| `Lisp/Gefaellestrecke.lsp` | Schritt 3: Modus-3-Kette auf Frame-Basis umgestellt |
| `Lisp/vf_standard.lsp` | Schritt 4: VarioFoerderer auf Frame-Basis umgestellt |
| `Lisp/vf_etage.lsp` | Schritt 4: Etagen-VarioFoerderer auf Frame-Basis umgestellt |
| `Lisp/KreiselInsert.lsp` | Bugfix: `block-pfad`-Kontamination behoben (2D/3D-Konflikt) |