feat: Kettenfoerderer (Schraegfoerderer Stahl) als parametrische 3D-Baugruppe

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>
This commit is contained in:
2026-10-23 15:34:27 +02:00
parent fb567949be
commit b8e8d0b0a0
28 changed files with 2207 additions and 21 deletions
+5 -2
View File
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
+6 -4
View File
@@ -1538,10 +1538,12 @@
) )
;; --- Omniflo / KettenFoerderer --- ;; --- Omniflo / KettenFoerderer ---
(defun c:OMNI_KettenFoerderer () ;; Der Platzhalter c:OMNI_KettenFoerderer (reiner Dummy, gab nur "[DUMMY]
(princ "\n[DUMMY] KettenFoerderer") ;; KettenFoerderer" aus und war im Menue ausgegraut) wurde entfernt: der
(princ) ;; Kettenfoerderer ist seit 2026-10-22 als eigene Baugruppe umgesetzt, der
) ;; Menueeintrag zeigt jetzt auf (ssg-ensure "KettenFoerderer") KETTENFOERDERER
;; (Lisp/KettenFoerderer.lsp). Damit war der Dummy toter Code - auf ihn verwies
;; nur noch der Menueeintrag selbst.
;; --- Omniflo / Ladeschleifen --- ;; --- Omniflo / Ladeschleifen ---
+7 -4
View File
@@ -38,14 +38,13 @@ am Label-Anfang, bei Submenue-Schliessern hinter dem `<-` (`[<-~Label]`).
| Menuebereich | Eintraege | Definiert in | | Menuebereich | Eintraege | Definiert in |
| --- | --- | --- | | --- | --- | --- |
| Omniflo ▸ Anbaugruppen | `OMNI_KettenFoerderer` | `OmniModulInsert.lsp` |
| Omniflo ▸ Boegen fuer Weichen | alle `OMNI_APBW_*` (14) | `OmniModulInsert.lsp` | | Omniflo ▸ Boegen fuer Weichen | alle `OMNI_APBW_*` (14) | `OmniModulInsert.lsp` |
| ILS ▸ Zusatzmodule/Kurven | `ILS_ETF_Etagenfoerderer`, `ILS_K{90,60,30}{L,R}{A,I}` (12), `ILS_Gefaellestrecke` | `SSG_LIB_Commands.lsp` | | ILS ▸ Zusatzmodule/Kurven | `ILS_ETF_Etagenfoerderer`, `ILS_K{90,60,30}{L,R}{A,I}` (12), `ILS_Gefaellestrecke` | `SSG_LIB_Commands.lsp` |
| Geruest | `GERUEST` (Gattertraeger-Platzhalter, derselbe Befehl wie Saeulen/Rohrabhaenger/Wandbefestigung) | `GeruestInsert.lsp` | | Geruest | `GERUEST` (Gattertraeger-Platzhalter, derselbe Befehl wie Saeulen/Rohrabhaenger/Wandbefestigung) | `GeruestInsert.lsp` |
`OMNI_TEF_*` (UmlenkR/L, AntriebL/R, TEF Gerade) sind entgegen frueherem Stand `OMNI_TEF_*` (UmlenkR/L, AntriebL/R, TEF Gerade) sind entgegen frueherem Stand
**implementiert** (echtes `omni:insert-dxf`), nur `OMNI_KettenFoerderer` ist **implementiert** (echtes `omni:insert-dxf`). Der Menueeintrag KettenFoerderer ist
weiterhin Dummy. ebenfalls aktiv (Modul `KettenFoerderer.lsp`, Beschreibung in `CLAUDE.md`).
Aktiv (implementiert) sind u.a.: Kreisel, Eckrad, VarioFoerderer (Standard/Etage/ Aktiv (implementiert) sind u.a.: Kreisel, Eckrad, VarioFoerderer (Standard/Etage/
Linienzug), Gefaellestrecke, Geruest (Saeulen/Rohrabhaenger/Wandbefestigung/ Linienzug), Gefaellestrecke, Geruest (Saeulen/Rohrabhaenger/Wandbefestigung/
@@ -383,6 +382,10 @@ Gefaellestrecke/`vf_core` geladen sein; Kern-Modul.
| `extract-ks-from-block[-raw] name` | KS_EIN/KS_AUS-Punkte eines Blocks ermitteln (Cache `*ks-cache*`) | | `extract-ks-from-block[-raw] name` | KS_EIN/KS_AUS-Punkte eines Blocks ermitteln (Cache `*ks-cache*`) |
| `insert-block-by-ks name ks-nr pt` | Block anhand KS-Punkt einfuegen (nur Rz-Rotation) | | `insert-block-by-ks name ks-nr pt` | Block anhand KS-Punkt einfuegen (nur Rz-Rotation) |
| `insert-inclined-scaled-block` / `insert-rotated-block-with-ks` | Geneigten/rotierten Block mit KS-Offset einfuegen (Rz*Ry) | | `insert-inclined-scaled-block` / `insert-rotated-block-with-ks` | Geneigten/rotierten Block mit KS-Offset einfuegen (Rz*Ry) |
| `ks-xy-winkel ks-eintrag` | Richtung der X-Achse eines KS in der XY-Ebene (Grad); `nil` bei senkrechter Achse |
| `ks-block-messen name` / `ks-versatz ks-data` | KS eines Blocks messen, ohne bleibende Einfuegung / Versatz KS_AUS-KS_EIN |
| `insert-block-ks-skaliert name pt hz skala` | Wie `insert-block-by-ks`, zusaetzlich in X skaliert |
| `insert-block-ks-matrix name pt R skala` | Einfuegen mit **freier 3x3-Rotationsmatrix** (`ks-rot-x/-y/-z`), z.B. fuer aufgerichtete Baugruppen |
--- ---
@@ -701,7 +704,7 @@ AutoLISP-Implementierung fuer alle Omniflo-Komponenten: Boegen, Weichen, Verbind
| Geraden | `OMNI_AP60`, `OMNI_AP110`, `OMNI_APG110` | Omniflo-Geradenstuecke | | Geraden | `OMNI_AP60`, `OMNI_AP110`, `OMNI_APG110` | Omniflo-Geradenstuecke |
| Ladeschleifen | `OMNI_LADESCHLEIFE_AP110` | Ladeschleife aus `omniflo_ladeschleifen.json` ueber DCL-Dialog (`dcl/omniflo_ladeschleifen.dcl`) einfuegen; Daten per `ssg-json-laden` (Beschreibungen enthalten Kommas). Blockdatei `<Sivasnr>.dwg` unter `DXFM_OMNIFLO` (`omni:insert-dxf` faellt auf `.dwg` zurueck, wenn keine `.dxf` existiert). Per `OMNI_EDIT` editierbar | | Ladeschleifen | `OMNI_LADESCHLEIFE_AP110` | Ladeschleife aus `omniflo_ladeschleifen.json` ueber DCL-Dialog (`dcl/omniflo_ladeschleifen.dcl`) einfuegen; Daten per `ssg-json-laden` (Beschreibungen enthalten Kommas). Blockdatei `<Sivasnr>.dwg` unter `DXFM_OMNIFLO` (`omni:insert-dxf` faellt auf `.dwg` zurueck, wenn keine `.dxf` existiert). Per `OMNI_EDIT` editierbar |
| TEF Elemente | `OMNI_TEF_UmlenkR/L`, `OMNI_TEF_AntriebL/R`, `OMNI_TEF_Gerade` | Feste TEF-Bauteile ohne Sivas-Auswahl, direkt per `omni:insert-dxf` an gewaehltem Punkt eingefuegt (Dateien unter `DXFM_OMNIFLO`) | | TEF Elemente | `OMNI_TEF_UmlenkR/L`, `OMNI_TEF_AntriebL/R`, `OMNI_TEF_Gerade` | Feste TEF-Bauteile ohne Sivas-Auswahl, direkt per `omni:insert-dxf` an gewaehltem Punkt eingefuegt (Dateien unter `DXFM_OMNIFLO`) |
| Anbaugruppen ⚠️ | `OMNI_KettenFoerderer` | **Dummy** (noch nicht implementiert, im Menue ausgegraut); `OMNI_STOPPER`/`OMNI_SCANNER`/`OMNI_BUERSTENBREMSE` sind implementiert | | Anbaugruppen | `OMNI_STOPPER`, `OMNI_SCANNER`, `OMNI_BUERSTENBREMSE` | Implementiert |
| Verbinder | `OMNI_TV_*` | Verbinder-DWG aus `data/omniflo/Verbinder` (dimensionsunabhaengig, `omni:insert-verbinder` -> `omni:insert-datei`, Punkt + Drehung interaktiv). Zuordnung Befehl -> DWG nach Dateiname, z.B. `OMNI_TV_W_AP60` -> `TV_W-AP60_oben`, `OMNI_TV_ENDPLATTE` -> `VB_ENDP_AP`, `OMNI_TV_W_AP60_KPL` -> `TV_W-AP60_kpl`, `OMNI_TV_ANSCHLAG` -> `VB_ENDP_AP_Spulenzug`, `OMNI_TV_SW_I_AP110` -> `TV_SW_I_SW-AP110`, `OMNI_TV_MUFFE` -> `VB_Muffe`. Alle 18 Eintraege aktiv | | Verbinder | `OMNI_TV_*` | Verbinder-DWG aus `data/omniflo/Verbinder` (dimensionsunabhaengig, `omni:insert-verbinder` -> `omni:insert-datei`, Punkt + Drehung interaktiv). Zuordnung Befehl -> DWG nach Dateiname, z.B. `OMNI_TV_W_AP60` -> `TV_W-AP60_oben`, `OMNI_TV_ENDPLATTE` -> `VB_ENDP_AP`, `OMNI_TV_W_AP60_KPL` -> `TV_W-AP60_kpl`, `OMNI_TV_ANSCHLAG` -> `VB_ENDP_AP_Spulenzug`, `OMNI_TV_SW_I_AP110` -> `TV_SW_I_SW-AP110`, `OMNI_TV_MUFFE` -> `VB_Muffe`. Alle 18 Eintraege aktiv |
| Bogenweichen ⚠️ | `OMNI_APBW_*` | **Dummy** (noch nicht implementiert, im Menue ausgegraut) | | Bogenweichen ⚠️ | `OMNI_APBW_*` | **Dummy** (noch nicht implementiert, im Menue ausgegraut) |
| Bearbeiten | `OMNI_EDIT` | Omniflo-Block selektieren und Attribute bearbeiten | | Bearbeiten | `OMNI_EDIT` | Omniflo-Block selektieren und Attribute bearbeiten |
+18
View File
@@ -408,6 +408,24 @@
(command "_.EATTEDIT") (command "_.EATTEDIT")
) )
;; Kettenfoerderer (KF_n, KettenFoerderer.lsp) -> KF_EDIT (DCL-Dialog mit
;; Neuaufbau an derselben Stelle). MUSS - aus demselben Grund wie GR_* -
;; vor dem Omniflo-Zweig stehen: traegt die Baugruppe ein TEILEART-
;; Attribut, wuerde dort sonst der Omniflo-Elementdialog aufgehen.
((wcmatch bname "KF_*")
(princ (ssg-textf "cmd-kettenfoerderer-bearbeiten" (list bname)))
(if (and (null *ssg-KettenFoerderer-loaded*) (atoms-family 1 '("SSG-ENSURE")))
(ssg-ensure "KettenFoerderer")
)
(if (atoms-family 1 '("C:KF_EDIT"))
(c:KF_EDIT)
(progn
(princ (ssg-textf "tro-edit-modul-fehlt" (list "KettenFoerderer.lsp")))
(command "_.EATTEDIT")
)
)
)
;; Omniflo-Bloecke -> OMNI_EDIT ;; Omniflo-Bloecke -> OMNI_EDIT
;; Erkennung: TEILEART-Attribut vorhanden, AP110-Blockname oder rein numerisch ;; Erkennung: TEILEART-Attribut vorhanden, AP110-Blockname oder rein numerisch
((progn ((progn
+6
View File
@@ -2397,6 +2397,11 @@
;; VB_*/TV_* = Omniflo-Verbinder (siehe pattern_verbinder in ;; VB_*/TV_* = Omniflo-Verbinder (siehe pattern_verbinder in
;; cfg/export.cfg, OMNI_TV_* in OmniModulInsert.lsp). export_sivas.py ;; cfg/export.cfg, OMNI_TV_* in OmniModulInsert.lsp). export_sivas.py
;; fuehrt sie ueber TEILEART/ARTINR im allgemeinen Omniflo-Zweig. ;; fuehrt sie ueber TEILEART/ARTINR im allgemeinen Omniflo-Zweig.
;; KF_* = Kettenfoerderer/Schraegfoerderer Stahl (siehe
;; pattern_kettenfoerderer in cfg/export.cfg, KettenFoerderer.lsp). Wie
;; GR_* eine selbst zusammengebaute Baugruppe mit eigenen Attributen
;; (TEILEART/ARTINR), darum eigenstaendig gesammelt - die drei Bausteine
;; darin werden NICHT einzeln gezaehlt.
;; Bloecke auf GEFRORENEN Layern (und die Hilfsobjekte gefrorener VF_n/GF_n) ;; Bloecke auf GEFRORENEN Layern (und die Hilfsobjekte gefrorener VF_n/GF_n)
;; werden ausgelassen, solange *csv-gefrorene-ausschliessen* an ist (Standard, ;; werden ausgelassen, solange *csv-gefrorene-ausschliessen* an ist (Standard,
;; Dialog CSV_EXPORT_KONFIG); ausgeschaltete Layer zaehlen nicht als gefroren. ;; Dialog CSV_EXPORT_KONFIG); ausgeschaltete Layer zaehlen nicht als gefroren.
@@ -2449,6 +2454,7 @@
(wcmatch bname (export:pattern "pattern_ausgang" "Ausgang*")) (wcmatch bname (export:pattern "pattern_ausgang" "Ausgang*"))
(wcmatch bname (export:pattern "pattern_geruest" "GR_*")) (wcmatch bname (export:pattern "pattern_geruest" "GR_*"))
(wcmatch bname (export:pattern "pattern_verbinder" "VB_*,TV_*")) (wcmatch bname (export:pattern "pattern_verbinder" "VB_*,TV_*"))
(wcmatch bname (export:pattern "pattern_kettenfoerderer" "KF_*"))
(wcmatch bname (export:pattern "pattern_unit_marker" "ZZ_UNIT_MARKER*")) (wcmatch bname (export:pattern "pattern_unit_marker" "ZZ_UNIT_MARKER*"))
;; Rein numerische Namen = Omniflo SivasNr (Boegen/Weichen) ;; Rein numerische Namen = Omniflo SivasNr (Boegen/Weichen)
;; Rein LISP-intern (Python klassifiziert Omniflo stattdessen ;; Rein LISP-intern (Python klassifiziert Omniflo stattdessen
+5 -1
View File
@@ -86,8 +86,12 @@
;; Einheiten-Proxies selbst ab; Separator-/Element- ;; Einheiten-Proxies selbst ab; Separator-/Element-
;; Kopien sammeln sich dagegen an - Zeichnung mit ;; Kopien sammeln sich dagegen an - Zeichnung mit
;; eingeschaltetem Schalter nicht speichern. ;; eingeschaltetem Schalter nicht speichern.
;; kf-zeit - Zwischenzeiten beim Aufruf von KETTENFOERDERER
;; (Daten lesen / Dialogaufbau), siehe kf-zeit in
;; KettenFoerderer.lsp. Standard 0 - nur einschalten,
;; wenn der Dialog spuerbar verzoegert erscheint.
;; ------------------------------------------------------------ ;; ------------------------------------------------------------
(foreach nm '(("vf-sepliste" . 1) ("csv_leave_proxies" . 0)) (foreach nm '(("vf-sepliste" . 1) ("csv_leave_proxies" . 0) ("kf-zeit" . 0))
(if (not (assoc (car nm) *dbg-schalter*)) (if (not (assoc (car nm) *dbg-schalter*))
(setq *dbg-schalter* (cons nm *dbg-schalter*)))) (setq *dbg-schalter* (cons nm *dbg-schalter*))))
+4
View File
@@ -47,6 +47,9 @@
;; das ID-ATTDEF steht seit *geruest-attrib-defs* zur Verfuegung. ;; das ID-ATTDEF steht seit *geruest-attrib-defs* zur Verfuegung.
;; VB_*/TV_* (Omniflo-Verbinder, siehe pattern_verbinder in ;; VB_*/TV_* (Omniflo-Verbinder, siehe pattern_verbinder in
;; cfg/export.cfg) ebenso - fest im Code wie GR_*. ;; cfg/export.cfg) ebenso - fest im Code wie GR_*.
;; KF_* (Kettenfoerderer, siehe pattern_kettenfoerderer in cfg/export.cfg,
;; KettenFoerderer.lsp) ebenso - das ID-ATTDEF kommt aus kf-attrib-defs, das
;; auf dem gemeinsamen Strecken-Schema aufsetzt und darum ID bereits fuehrt.
;; Gefaellebogen_* (siehe pattern_nested_bogen in cfg/export.cfg): einer der ;; Gefaellebogen_* (siehe pattern_nested_bogen in cfg/export.cfg): einer der
;; Bausteine einer GF-Kette, verpackt in VF_n/GF_n; wird beim Export ebenso ;; Bausteine einer GF-Kette, verpackt in VF_n/GF_n; wird beim Export ebenso
;; als temporaere Kopie ausgepackt wie die uebrigen Vario_*/Staustrecke_*- ;; als temporaere Kopie ausgepackt wie die uebrigen Vario_*/Staustrecke_*-
@@ -84,6 +87,7 @@
(wcmatch bname "Eingang*,Ausgang*") (wcmatch bname "Eingang*,Ausgang*")
(wcmatch bname "GR_*") (wcmatch bname "GR_*")
(wcmatch bname "VB_*,TV_*") (wcmatch bname "VB_*,TV_*")
(wcmatch bname "KF_*")
(wcmatch bname "#*") (wcmatch bname "#*")
) )
(ssadd ename ss-out) (ssadd ename ss-out)
+281 -2
View File
@@ -72,11 +72,31 @@
;; Block unter seinem effektiven, dim-suffigierten Namen und GIBT DIESEN ZURUECK, ;; Block unter seinem effektiven, dim-suffigierten Namen und GIBT DIESEN ZURUECK,
;; damit Aufrufer ihn zum Einfuegen (vla-InsertBlock/tblsearch) verwenden. ;; damit Aufrufer ihn zum Einfuegen (vla-InsertBlock/tblsearch) verwenden.
;; Meldung nur bei Fehlschlag. ;; Meldung nur bei Fehlschlag.
(defun ensure-block-loaded (blockname / ) ;; 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)) (if (not (ssg-ils-block-laden blockname))
(princ (ssg-textf "vfc-fehler-block-datei-fehlt" (list blockname))) (princ (ssg-textf "vfc-fehler-block-datei-fehlt" (list blockname)))
) )
(ssg-ils-blockname blockname) eff
)
)
) )
;; ------------------------------------------------------------ ;; ------------------------------------------------------------
@@ -379,6 +399,265 @@
) )
) )
;; ------------------------------------------------------------
;; 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 ;; SEPLISTE: Separator-/AS-/ES-Reihenfolge als XDATA am fertigen Wrapper
;; ------------------------------------------------------------ ;; ------------------------------------------------------------
+10
View File
@@ -76,6 +76,15 @@
# erkennt sie wie alle Omniflo-Teile ueber TEILEART "Omniflo ..." und schreibt # erkennt sie wie alle Omniflo-Teile ueber TEILEART "Omniflo ..." und schreibt
# je Nummer aus ARTINR eine Omniflo-Zeile. # je Nummer aus ARTINR eine Omniflo-Zeile.
# #
# pattern_kettenfoerderer: Kettenfoerderer/Schraegfoerderer Stahl
# (KettenFoerderer.lsp, KF_<n>). Eine selbst zusammengebaute Baugruppe wie
# GR_*, mit eigenen Attributen TEILEART ("Omniflo Kettenfoerderer ...") und
# ARTINR - erkannt wird sie darum im allgemeinen Omniflo-Zweig von
# export_sivas.py. Die drei Bausteine darin (Umlenkstation, skaliertes
# Zwischenstueck, Antriebsstation) werden NICHT einzeln gezaehlt. Die im
# Dialog gewaehlten Verbindungselemente stehen als Attribut
# VERBINDUNGSELEMENTE am Block und landen im Merkmale-/details-JSON.
#
# pattern_nested_bogen/_streckenelement/_umlenkstation/_motorstation: die # pattern_nested_bogen/_streckenelement/_umlenkstation/_motorstation: die
# uebrigen Bausteine einer VF_n/GF_n-Kette (Boegen, gerade Foerderer-/ # uebrigen Bausteine einer VF_n/GF_n-Kette (Boegen, gerade Foerderer-/
# Gefaellestrecken-Segmente, Umlenk-/Motorstation). Wie pattern_schleuselement # Gefaellestrecken-Segmente, Umlenk-/Motorstation). Wie pattern_schleuselement
@@ -136,6 +145,7 @@ pattern_gerade= AP110*, AP_110*, AP60*
# Gerüst # Gerüst
pattern_geruest= GR_* pattern_geruest= GR_*
pattern_verbinder= VB_*, TV_* pattern_verbinder= VB_*, TV_*
pattern_kettenfoerderer= KF_*
[python] [python]
# Interpreter fuer die Export-Skripte (lib/export_csv.py, lib/export_sivas.py). # Interpreter fuer die Export-Skripte (lib/export_csv.py, lib/export_sivas.py).
+7
View File
@@ -168,6 +168,13 @@ gf_beschriftung = GF_Beschriftung, 7
# Lisp/DrawPlanquadrate.lsp (DRAW_PLANQUADRATE). # Lisp/DrawPlanquadrate.lsp (DRAW_PLANQUADRATE).
planquadrate = ZZ_Planquadrate, 8 planquadrate = ZZ_Planquadrate, 8
# Kettenfoerderer (Schraegfoerderer Stahl), aus Umlenkstation + skaliertem
# Zwischenstueck + Antriebsstation zusammengebauter Block KF_n - siehe
# Lisp/KettenFoerderer.lsp (KETTENFOERDERER). Wie VF_n/GF_n eine
# ZUSAMMENGEBAUTE Baugruppe ohne eigene Blockdatei, der Layer muss darum hier
# stehen. Die drei Bausteine darin behalten ihre eigenen Layer.
kettenfoerderer = Omni_Kettenfoerderer, 4
# ============================================================ # ============================================================
# Farben fuer Layer OHNE Baugruppen-Key # Farben fuer Layer OHNE Baugruppen-Key
+46
View File
@@ -105,6 +105,41 @@
[geruest] [geruest]
Farbe= FARBE Farbe= FARBE
[kettenfoerderer]
# Kettenfoerderer / Schraegfoerderer Stahl (KF_n, Lisp/KettenFoerderer.lsp).
# Merkmalnummern laut Merkmalstamm des Schraegfoerderers.
#
# 350 kommt aus FOERDERERTYP (Bauart im Klartext). Der Default greift nur
# bei Altbestands-Bloecken ohne das Attribut.
# 359 kommt aus WINKEL, das den Neigungswinkel als nackte Zahl fuehrt
# ("26"/"30"); die Anzeige-Tabelle [kf_typ_anzeige] weiter unten macht
# daraus den Sivas-Optionstext mit Gradzeichen. Grund fuer die
# Zweiteilung: Block-Attribute bleiben laut Projektkonvention ASCII.
# 353 (Anzahl der gleichen KF) steht ABSICHTLICH NICHT hier: der Wert
# entsteht erst aus der Gruppierung baugleicher Bloecke
# (kettenfoerderer_signature in export_sivas.py) und ist damit kein
# flaches Attribut-Mapping - gleiche Bauart wie 3510/3512 beim Kreisel.
# 356 und 361 nutzen den vorhandenen Transform ja_nein, die Attribute
# fuehren "1"/"0".
# 357 "Antriebsart" ist beim Kettenfoerderer FEST (1.1 kW): im Dialog ein
# Dropdown mit genau einer, zwingend gewaehlten Option - das Attribut gibt es trotzdem, damit der Wert am
# Block steht und nicht nur im Export auftaucht.
# 354 "Farbe Foerderer" und 355 "Antriebsmotor Foerderer" sind ZWEI getrennte
# Merkmale (nicht ein kombinierter Text) - im Dialog darum auch zwei
# Felder, Attribute FARBE und ANTRIEBSMOTOR.
# 354/355/391 tragen bereits den vollen Sivas-Optionstext im Attribut (die
# Auswahllisten in data/json/kettenfoerderer.json liefern ihn so) -
# darum kein Transform.
350= FOERDERERTYP : Schrägförderer Stahl
359= WINKEL : 26 | kf_typ_anzeige
361= STANDARD_STEUERUNG : 0 | ja_nein
354= FARBE : RAL 7035
355= ANTRIEBSMOTOR : Europa 50 Hz
357= ANTRIEBSART : 1.1 kW
356= MOVIMOT : 0 | ja_nein
360= H_EINBAUHOEHE_mm : 0
391= VERBINDUNGSELEMENTE : Nein
[variofoerderer] [variofoerderer]
# Nur die von der Segmentanzahl UNABHAENGIGEN Top-Level-Felder einer VF_N- # Nur die von der Segmentanzahl UNABHAENGIGEN Top-Level-Felder einer VF_N-
# Streckengruppe (siehe build_variofoerderer_details in export_sivas.py). # Streckengruppe (siehe build_variofoerderer_details in export_sivas.py).
@@ -155,6 +190,17 @@ Farbe= FARBE
# zeichen (Attribute selbst bleiben ASCII, siehe CLAUDE.md-Konvention). # zeichen (Attribute selbst bleiben ASCII, siehe CLAUDE.md-Konvention).
Schoenenberger Geruest= Schönenberger-Gerüst Schoenenberger Geruest= Schönenberger-Gerüst
[kf_typ_anzeige]
# Attributwert WINKEL (Neigungswinkel als nackte Zahl) -> Optionswert der
# Sivas-Auswahlliste zu Merkmal 359. Gleiche Bauart wie
# [geruest_typ_anzeige]/[as_es_winkel_anzeige]: steht ein Wert hier NICHT
# drin, wird er unveraendert uebernommen.
#
# >>> Lehnt Sivas den Import ab, ist DIESE Tabelle die einzige Stelle zum
# >>> Nachziehen (z.B. "26 °" mit Leerzeichen) - der Code bleibt unberuehrt.
26= Schrägförderer Stahl 26°
30= Schrägförderer Stahl 30°
[weichen] [weichen]
# ILS 2.0 Weiche (6216): eine Summenzeile, Werte aus den Kreisel-Beruehr- # ILS 2.0 Weiche (6216): eine Summenzeile, Werte aus den Kreisel-Beruehr-
# punkten des LISP-Exports (kreisel_weichen.json). Ein Beruehrpunkt ist eine # punkten des LISP-Exports (kreisel_weichen.json). Ein Beruehrpunkt ist eine
+67
View File
@@ -0,0 +1,67 @@
{
"kettenfoerderer": {
"id": "Kettenfoerderer",
"titel": "Kettenfoerderer (Schraegfoerderer Stahl)",
"layer": "kettenfoerderer",
"teileart": "Schraegfoerderer Stahl",
"foerderertyp": "Schrägförderer Stahl",
"einbauhoehe": { "vorgabe": 1500, "min": 300, "max": 8000 },
"laenge": { "min": 100, "max": 20000 },
"_hinweis_ansicht": "KF_2D liegt DECKUNGSGLEICH mit der Kette (KS_EIN auf KS_EIN der Umlenkung, KS_AUS auf KS_AUS des Antriebs) - die Baugruppe ist EIN Koerper. Den frueheren Versatz (versatz_y) gibt es nicht mehr, seit die Kette aufgerichtet eingebaut wird.",
"ansicht_2d": { "block": "KF_2D" },
"_hinweis_antriebsart": "Merkmal 357 ist beim Kettenfoerderer FEST: die Liste hat genau EINEN Eintrag, der im Dialog als Dropdown erscheint und zwingend gewaehlt ist. Weitere Antriebsarten (z.B. 0.55 kW) waeren einfach eine weitere Zeile.",
"antriebsart": [
{ "name": "1.1 kW", "wert": "1.1 kW" }
],
"farbe": [
{ "name": "RAL 7035", "wert": "RAL 7035" },
{ "name": "RAL 2000", "wert": "RAL 2000" },
{ "name": "RAL 5018", "wert": "RAL 5018" },
{ "name": "Sonderfarbe", "wert": "Sonderfarbe" }
],
"antriebsmotor": [
{ "name": "Europa 50 Hz", "wert": "Europa 50 Hz" }
],
"movimot": [
{ "name": "Nein", "wert": "0" },
{ "name": "Ja", "wert": "1" }
],
"standard_steuerung": [
{ "name": "Nein", "wert": "0" },
{ "name": "Ja", "wert": "1" }
],
"verbindungselemente": [
{ "name": "Verbindungselemente an AP", "wert": "Verbindungselemente an AP" },
{ "name": "Verbindungselemente an ST", "wert": "Verbindungselemente an ST" },
{ "name": "Nein", "wert": "Nein" }
],
"varianten": [
{
"name": "Schraegfoerderer Stahl 26 Grad",
"winkel": 26,
"standard": true,
"block_umlenkung": "KF_UM_26",
"block_laenge": "KF_LAENGE",
"block_antrieb": "KF_AN_26",
"sivas_id": "6120"
},
{
"name": "Schraegfoerderer Stahl 30 Grad",
"winkel": 30,
"block_umlenkung": "KF_UM_30",
"block_laenge": "KF_LAENGE",
"block_antrieb": "KF_AN_30",
"sivas_id": "6120"
}
]
}
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+104
View File
@@ -0,0 +1,104 @@
// ============================================================
// kettenfoerderer.dcl - Kettenfoerderer (Schraegfoerderer Stahl)
// Verwendet von KettenFoerderer.lsp (kf-dialog, Befehl KETTENFOERDERER).
//
// VORLAGE mit Markerzeilen: nur der Varianten-Block ist datenabhaengig und
// wird zur Laufzeit an //@VARIANTEN@ eingesetzt (kf-dcl-ersetzungen ->
// ssg-dcl-vorlage-fuellen in ssg_core, Temp-Datei). Grund: DCL kann
// radio_button-Tiles weder zur Laufzeit erzeugen noch ihre Labels per
// set_tile aendern - gleiches Vorgehen wie geruest_traeger.dcl.
//
// Varianten bewusst als Radiobuttons statt popup_list: es sind nur zwei
// Werte (26/30 Grad), beide sollen ohne Aufklappen sichtbar sein.
// Die Gruppenbeschriftung steht am boxed_row - ein zusaetzliches Label am
// Tile waere doppelt gemoppelt.
//
// Die Beschriftungen folgen dem Sivas-Merkmalstamm, damit Dialog und
// Stueckliste dieselbe Sprache sprechen (Merkmalnummer in Klammern):
// Schraegfoerderer Stahl Typ (359) H - Einbauhoehe Schraegfoerderer (360)
// Farbe Foerderer (354) Antriebsmotor Foerderer (355)
// Antrieb mit Movimot (356) Verbindungselemente (391)
// Farbe und Antriebsmotor sind dabei ZWEI eigenstaendige Merkmale
// (Attribute FARBE und ANTRIEBSMOTOR), nicht ein kombinierter Text.
//
// Kein Geruest-Bereich: der Kettenfoerderer traegt sich selbst.
// ============================================================
kettenfoerderer : dialog {
label = "Kettenfoerderer";
width = 62;
: boxed_radio_row {
key = "variante";
label = "Schraegfoerderer Stahl Typ";
//@VARIANTEN@
}
: boxed_column {
label = "Geometrie";
: row {
: edit_box {
key = "hoehe";
label = "H - Einbauhoehe Schraegfoerderer [ mm ]:";
edit_width = 12;
}
// Zweite Eingabeart: Hoehe aus zwei gewaehlten Punkten messen.
// Der Knopf schliesst den Dialog (done_dialog 2), der Aufrufer pickt
// die Punkte und zeigt ihn mit dem Ergebnis erneut - aus einem
// action_tile heraus laesst sich kein getpoint aufrufen.
: button {
key = "hoehe_messen";
label = "aus 2 Punkten messen";
}
}
}
: boxed_column {
label = "Ausfuehrung";
// Reihenfolge wie im Sivas-Merkmalstamm: 361 vor 354 - Dialog,
// Attributschema und Merkmalstamm bleiben damit in derselben Folge.
: popup_list {
key = "standard_steuerung";
label = "mit Standard Steuerung:";
width = 40;
}
: popup_list {
key = "farbe";
label = "Farbe Foerderer:";
width = 40;
}
: popup_list {
key = "antriebsmotor";
label = "Antriebsmotor Foerderer:";
width = 40;
}
// Antriebsart (Merkmal 357): Dropdown mit genau EINER Option, die immer
// gewaehlt ist - beim Kettenfoerderer ist sie fest 1.1 kW. Als Dropdown
// statt als Textzeile, damit alle Merkmale gleich aussehen; kommt spaeter
// eine zweite Antriebsart dazu, ist es nur eine weitere Zeile in der JSON.
: popup_list {
key = "antriebsart";
label = "Antriebsart 0,55 / 1,1 kW:";
width = 40;
}
: popup_list {
key = "movimot";
label = "Antrieb mit Movimot:";
width = 40;
}
: popup_list {
key = "verbindung";
label = "Verbindungselemente:";
width = 40;
}
}
ok_cancel;
}
+51 -1
View File
@@ -1148,6 +1148,56 @@
"kreisel-bp-kollision": "\n KOLLISION %1: %2 <-> %3 [%4] bei X=%5 Y=%6 Z=%7", "kreisel-bp-kollision": "\n KOLLISION %1: %2 <-> %3 [%4] bei X=%5 Y=%6 Z=%7",
"kreisel-bp-marker": "\n%1 Marker gezeichnet (Layer %2).", "kreisel-bp-marker": "\n%1 Marker gezeichnet (Layer %2).",
"exp-kreisel-weichen": "\n[%1] Kreisel-Weichenpunkte: %2 Beruehrung(en), %3 Kollision(en) -> %4", "exp-kreisel-weichen": "\n[%1] Kreisel-Weichenpunkte: %2 Beruehrung(en), %3 Kollision(en) -> %4",
"exp-kreisel-kollision": "\n[%1] WARNUNG: %2 Kreisel-Kollision(en) - Befehl KREISEL_WEICHEN zeigt sie an." "exp-kreisel-kollision": "\n[%1] WARNUNG: %2 Kreisel-Kollision(en) - Befehl KREISEL_WEICHEN zeigt sie an.",
"kf-fehler-daten-fehlt": "\nFEHLER: Kettenfoerderer-Daten nicht gefunden: %1",
"kf-fehler-daten-leer": "\nFEHLER: Kettenfoerderer-Daten konnten nicht gelesen werden.",
"kf-fehler-block-datei": "\nFEHLER: Blockdatei fuer %1 nicht gefunden (erwartet in data/omniflo/<Dimension>/).",
"kf-fehler-ks-fehlt": "In mindestens einem Baustein fehlt KS_EIN oder KS_AUS - die Kette kann nicht verkettet werden. Befehl KF_KS_PRUEFEN zeigt, welcher Block betroffen ist.",
"kf-fehler-hoehe-zu-klein": "Die Einbauhoehe ist zu klein: Umlenk- und Antriebsstation bringen bereits mehr Hoehe mit, als gefordert ist. Bitte groessere Hoehe waehlen.",
"kf-fehler-laenge-unter-min": "Das Zwischenstueck waere kuerzer als zulaessig. Bitte groessere Einbauhoehe waehlen.",
"kf-fehler-laenge-ueber-max": "Das Zwischenstueck waere laenger als zulaessig. Bitte kleinere Einbauhoehe waehlen.",
"kf-fehler-winkel-null": "Der gemessene Einbauwinkel des Zwischenstuecks ist waagerecht - damit laesst sich keine Hoehe erreichen. Bitte die KS-Lage der Bloecke pruefen (KF_KS_PRUEFEN).",
"kf-fehler-dcl": "Dialogdatei kettenfoerderer.dcl nicht gefunden.",
"kf-prompt-messpunkt-1": "\nErsten Messpunkt waehlen (Hoehenbezug unten): ",
"kf-prompt-messpunkt-2": "\nZweiten Messpunkt waehlen (Hoehenbezug oben): ",
"kf-messung-ergebnis": "\n>>> Gemessen: Hoehendifferenz dZ = %1 mm (zur Kontrolle dY = %2 mm).",
"kf-konsole-hoehe-hinweis": "\n(0 eingeben, um die Hoehe aus zwei Punkten zu messen)",
"kf-2d-gebaut": "\n>>> Draufsicht %1 eingefuegt: Schraeglaenge %2 mm, Neigung %3 Grad.",
"kf-2d-laenge-null": "\nDraufsicht uebersprungen: die Kette hat keine messbare Grundrisslaenge.",
"kf-2d-ks-fehlt": "\nDraufsicht uebersprungen: %1 hat kein messbares KS_EIN/KS_AUS.",
"kf-prompt-startpunkt": "\nEinfuegepunkt waehlen (KS_EIN der Draufsicht; die Seitenansicht entsteht darueber): ",
"kf-prompt-drehung": "\nDrehwinkel der Kette: ",
"kf-abgebrochen": "\nAbgebrochen.",
"kf-fertig": "\n>>> %1 erstellt: Einbauhoehe %2 mm, Zwischenstueck %3 mm.",
"kf-konsole-variante-header": "\n\nSchraegfoerderer Stahl Typ waehlen:",
"kf-konsole-option": "\n %1 - %2",
"kf-konsole-variante-prompt": "\nSchraegfoerderer Stahl Typ",
"kf-konsole-hoehe-prompt": "\nH - Einbauhoehe Schraegfoerderer [mm]",
"kf-konsole-verbindung-header": "\n\nVerbindungselemente waehlen:",
"kf-konsole-verbindung-prompt": "\nVerbindungselemente",
"kf-konsole-farbe-header": "\n\nFarbe Foerderer waehlen:",
"kf-konsole-farbe-prompt": "\nFarbe",
"kf-konsole-antriebsmotor-header": "\n\nAntriebsmotor Foerderer waehlen:",
"kf-konsole-antriebsmotor-prompt": "\nAntriebsmotor Foerderer",
"kf-variante-label": "%1 %2",
"kf-variante-label-standard": "%1 %2 (Standard)",
"kf-konsole-movimot-header": "\n\nAntrieb mit Movimot?",
"kf-konsole-movimot-prompt": "\nAntrieb mit Movimot",
"kf-konsole-steuerung-header": "\n\nMit Standard Steuerung?",
"kf-konsole-steuerung-prompt": "\nMit Standard Steuerung",
"kf-pruef-kopf": "\n\n=== KF_KS_PRUEFEN: KS-Lage der Kettenfoerderer-Bloecke ===",
"kf-pruef-variante": "\n\n--- Variante: %1 ---",
"kf-pruef-block": "\n %1: KS_EIN (%2, %3) Richtung %4 | KS_AUS (%5, %6) Richtung %7",
"kf-pruef-block-fehlt": "\n %1: Blockdatei nicht gefunden.",
"kf-pruef-ks-fehlt": "\n %1: KS unvollstaendig - KS_EIN: %2, KS_AUS: %3",
"kf-pruef-ks-fehlt-kurz": "\n[KF] KS_EIN/KS_AUS nicht lesbar am Baustein: %1 (Befehl KF_KS_PRUEFEN zeigt Einzelheiten)",
"kf-pruef-fehler": "\n Geometrie nicht ermittelbar: %1",
"kf-pruef-geo": "\n Einbauwinkel (Grad): Umlenkung %1, Zwischenstueck %2, Antrieb %3\n Hoehenbeitrag (mm): Umlenkung %4, Antrieb %5\n Zwischenstueck nativ (mm): dx %6, dy %7",
"kf-pruef-ja": "vorhanden",
"kf-pruef-nein": "FEHLT",
"kf-edit-waehlen": "\nKettenfoerderer (KF_n) zum Bearbeiten waehlen: ",
"kf-edit-kein-kf": "Der gewaehlte Block ist kein Kettenfoerderer (KF_n).",
"kf-edit-fertig": "\n>>> %1 neu aufgebaut als %2.",
"cmd-kettenfoerderer-bearbeiten": "\n>>> Kettenfoerderer %1 wird bearbeitet ..."
} }
} }
+51 -1
View File
@@ -1148,6 +1148,56 @@
"kreisel-bp-kollision": "\n COLLISION %1: %2 <-> %3 [%4] at X=%5 Y=%6 Z=%7", "kreisel-bp-kollision": "\n COLLISION %1: %2 <-> %3 [%4] at X=%5 Y=%6 Z=%7",
"kreisel-bp-marker": "\n%1 markers drawn (layer %2).", "kreisel-bp-marker": "\n%1 markers drawn (layer %2).",
"exp-kreisel-weichen": "\n[%1] Kreisel switch points: %2 contact(s), %3 collision(s) -> %4", "exp-kreisel-weichen": "\n[%1] Kreisel switch points: %2 contact(s), %3 collision(s) -> %4",
"exp-kreisel-kollision": "\n[%1] WARNING: %2 Kreisel collision(s) - command KREISEL_WEICHEN shows them." "exp-kreisel-kollision": "\n[%1] WARNING: %2 Kreisel collision(s) - command KREISEL_WEICHEN shows them.",
"kf-fehler-daten-fehlt": "\nERROR: chain conveyor data not found: %1",
"kf-fehler-daten-leer": "\nERROR: chain conveyor data could not be read.",
"kf-fehler-block-datei": "\nERROR: block file for %1 not found (expected in data/omniflo/<dimension>/).",
"kf-fehler-ks-fehlt": "At least one component is missing KS_EIN or KS_AUS - the chain cannot be linked. Command KF_KS_PRUEFEN shows which block is affected.",
"kf-fehler-hoehe-zu-klein": "The installation height is too small: the deflection and drive stations already contribute more height than requested. Please choose a greater height.",
"kf-fehler-laenge-unter-min": "The intermediate section would be shorter than permitted. Please choose a greater installation height.",
"kf-fehler-laenge-ueber-max": "The intermediate section would be longer than permitted. Please choose a smaller installation height.",
"kf-fehler-winkel-null": "The measured installation angle of the intermediate section is horizontal - no height can be gained. Please check the KS positions of the blocks (KF_KS_PRUEFEN).",
"kf-fehler-dcl": "Dialog file kettenfoerderer.dcl not found.",
"kf-prompt-messpunkt-1": "\nSelect first measuring point (lower reference): ",
"kf-prompt-messpunkt-2": "\nSelect second measuring point (upper reference): ",
"kf-messung-ergebnis": "\n>>> Measured: height difference dZ = %1 mm (for reference dY = %2 mm).",
"kf-konsole-hoehe-hinweis": "\n(enter 0 to measure the height from two points)",
"kf-2d-gebaut": "\n>>> Plan view %1 inserted: slope length %2 mm, inclination %3 deg.",
"kf-2d-laenge-null": "\nPlan view skipped: the chain has no measurable plan length.",
"kf-2d-ks-fehlt": "\nPlan view skipped: %1 has no measurable KS_EIN/KS_AUS.",
"kf-prompt-startpunkt": "\nSelect insertion point (KS_EIN of the plan view; the side view is built above it): ",
"kf-prompt-drehung": "\nRotation angle of the chain: ",
"kf-abgebrochen": "\nCancelled.",
"kf-fertig": "\n>>> %1 created: installation height %2 mm, intermediate section %3 mm.",
"kf-konsole-variante-header": "\n\nSelect inclined steel conveyor type:",
"kf-konsole-option": "\n %1 - %2",
"kf-konsole-variante-prompt": "\nInclined steel conveyor type",
"kf-konsole-hoehe-prompt": "\nH - installation height of inclined conveyor [mm]",
"kf-konsole-verbindung-header": "\n\nSelect connecting elements:",
"kf-konsole-verbindung-prompt": "\nConnecting elements",
"kf-konsole-farbe-header": "\n\nSelect conveyor colour:",
"kf-konsole-farbe-prompt": "\nColour",
"kf-konsole-antriebsmotor-header": "\n\nSelect conveyor drive motor:",
"kf-konsole-antriebsmotor-prompt": "\nConveyor drive motor",
"kf-variante-label": "%1 %2",
"kf-variante-label-standard": "%1 %2 (default)",
"kf-konsole-movimot-header": "\n\nDrive with Movimot?",
"kf-konsole-movimot-prompt": "\nDrive with Movimot",
"kf-konsole-steuerung-header": "\n\nWith standard control system?",
"kf-konsole-steuerung-prompt": "\nWith standard control system",
"kf-pruef-kopf": "\n\n=== KF_KS_PRUEFEN: KS positions of the chain conveyor blocks ===",
"kf-pruef-variante": "\n\n--- Variant: %1 ---",
"kf-pruef-block": "\n %1: KS_EIN (%2, %3) direction %4 | KS_AUS (%5, %6) direction %7",
"kf-pruef-block-fehlt": "\n %1: block file not found.",
"kf-pruef-ks-fehlt": "\n %1: KS incomplete - KS_EIN: %2, KS_AUS: %3",
"kf-pruef-ks-fehlt-kurz": "\n[KF] KS_EIN/KS_AUS not readable on component: %1 (command KF_KS_PRUEFEN shows details)",
"kf-pruef-fehler": "\n Geometry could not be determined: %1",
"kf-pruef-geo": "\n Installation angles (deg): deflection %1, intermediate %2, drive %3\n Height contribution (mm): deflection %4, drive %5\n Intermediate section native (mm): dx %6, dy %7",
"kf-pruef-ja": "present",
"kf-pruef-nein": "MISSING",
"kf-edit-waehlen": "\nSelect chain conveyor (KF_n) to edit: ",
"kf-edit-kein-kf": "The selected block is not a chain conveyor (KF_n).",
"kf-edit-fertig": "\n>>> %1 rebuilt as %2.",
"cmd-kettenfoerderer-bearbeiten": "\n>>> Editing chain conveyor %1 ..."
} }
} }
+115
View File
@@ -101,6 +101,18 @@ def get_id(block):
# Sprachdatei, da rein Sivas-seitig. # Sprachdatei, da rein Sivas-seitig.
GERUEST_TYP_ANZEIGE = sivas_mapping.load_flat_mapping("geruest_typ_anzeige") GERUEST_TYP_ANZEIGE = sivas_mapping.load_flat_mapping("geruest_typ_anzeige")
# Kettenfoerderer: Attribut WINKEL fuehrt den Neigungswinkel als nackte Zahl
# ("26"/"30"), Sivas-Merkmal 359 erwartet den Optionstext mit Gradzeichen.
# Gleiche Bauart und derselbe Grund wie GERUEST_TYP_ANZEIGE.
KF_TYP_ANZEIGE = sivas_mapping.load_flat_mapping("kf_typ_anzeige")
# TeileArt-Spalte der Kettenfoerderer-Zeilen. Fester Wert statt Block-Attribut:
# er ist fuer jeden Kettenfoerderer gleich, stuende also an jedem Block nur
# redundant herum. Die Erkennung laeuft ueber den Blocknamen
# (pattern_kettenfoerderer), nicht ueber TEILEART. Ein Block, der das Attribut
# doch mitbringt (Altbestand), hat weiterhin Vorrang.
KF_TEILEART = "Schraegfoerderer Stahl"
SEPARATOR_BEARBEITUNG_ANZEIGE = "ohne HARTCOAT HRC 50 ± 5" SEPARATOR_BEARBEITUNG_ANZEIGE = "ohne HARTCOAT HRC 50 ± 5"
# Sivas-Merkmale "Streckengruppe - Variofoerderer 001..005 - Hoehe in Meter". # Sivas-Merkmale "Streckengruppe - Variofoerderer 001..005 - Hoehe in Meter".
@@ -113,6 +125,12 @@ def geruest_typ_anzeige(wert):
return GERUEST_TYP_ANZEIGE.get(wert, wert) return GERUEST_TYP_ANZEIGE.get(wert, wert)
def kf_typ_anzeige(wert):
"""Wandelt den Kettenfoerderer-Winkel ("26"/"30") in die Sivas-Anzeige
zu Merkmal 359 um ("Schrägförderer Stahl 26°")."""
return KF_TYP_ANZEIGE.get(str(wert).strip(), wert)
def ja_nein(flag_1_0): def ja_nein(flag_1_0):
"""Wandelt ein "0"/"1"-Attribut in die Sivas-Anzeige "Ja"/"Nein" um.""" """Wandelt ein "0"/"1"-Attribut in die Sivas-Anzeige "Ja"/"Nein" um."""
return "Ja" if flag_1_0 == "1" else "Nein" return "Ja" if flag_1_0 == "1" else "Nein"
@@ -191,6 +209,7 @@ def es_seite(wert, attribs):
TRANSFORMS = { TRANSFORMS = {
"ja_nein": ja_nein, "ja_nein": ja_nein,
"geruest_typ_anzeige": geruest_typ_anzeige, "geruest_typ_anzeige": geruest_typ_anzeige,
"kf_typ_anzeige": kf_typ_anzeige,
"mm_zu_m": mm_zu_m, "mm_zu_m": mm_zu_m,
"as_es_vorhanden": as_es_vorhanden, "as_es_vorhanden": as_es_vorhanden,
"as_es_winkel": as_es_winkel, "as_es_winkel": as_es_winkel,
@@ -275,6 +294,42 @@ def eckrad_signature(block):
) )
def kettenfoerderer_signature(block):
"""
Schluessel zur Gruppierung gleichartiger Kettenfoerderer (KF_n): baugleiche
Bloecke landen in EINER Sivas-Zeile, deren Anzahl das Merkmal 353 ("Anzahl
der gleichen Schraegfoerderer") traegt.
In den Schluessel gehoert JEDES Attribut, aus dem ein Merkmal der Zeile
entsteht - sonst verschmelzen zwei unterschiedlich ausgefuehrte Foerderer
zu einer Zeile, und die Merkmale des ERSTEN Blocks gelten fuer beide
(gleiche Ueberlegung wie bei gefaellestrecke_signature/as_es_signatur).
Die Kommentare nennen darum je Attribut die Merkmalnummer; einzige
Ausnahme ist 353, das erst aus der Gruppengroesse entsteht.
Das ist zugleich die Voraussetzung dafuer, dass items_zusammenfassen (fuer
die _zusammengefasst.csv) zwei KF-Zeilen NIE verschmelzen kann: gleiche
Merkmale wuerden schon hier dieselbe Gruppe ergeben. Sonst wuerde dort
"anzahl" addiert, waehrend 353 unveraendert stehen bliebe.
Die Laenge des Zwischenstuecks (L_KF_mm) ist eine FOLGE der Einbauhoehe und
steht darum nicht eigens im Schluessel.
"""
attribs = block.get("attribs", {})
return (
attribs.get("WINKEL", "26"), # 359
attribs.get("STANDARD_STEUERUNG", "0"), # 361
attribs.get("FOERDERERTYP", ""), # 350
attribs.get("H_EINBAUHOEHE_mm", "0"), # 360
attribs.get("FARBE", ""), # 354
attribs.get("ANTRIEBSMOTOR", ""), # 355
attribs.get("ANTRIEBSART", ""), # 357
attribs.get("MOVIMOT", "0"), # 356
attribs.get("VERBINDUNGSELEMENTE", "Nein"), # 391
attribs.get("ARTINR", ""),
)
def gefaellestrecke_signature(block): def gefaellestrecke_signature(block):
""" """
Schluessel zur Gruppierung gleichartiger Gefaellestrecken: Bloecke mit Schluessel zur Gruppierung gleichartiger Gefaellestrecken: Bloecke mit
@@ -404,6 +459,7 @@ SIVAS_MAPPING_KREISEL = sivas_mapping.load_section_mapping("kreisel")
SIVAS_MAPPING_ECKRAD = sivas_mapping.load_section_mapping("eckrad") SIVAS_MAPPING_ECKRAD = sivas_mapping.load_section_mapping("eckrad")
SIVAS_MAPPING_GERUEST = sivas_mapping.load_section_mapping("geruest") SIVAS_MAPPING_GERUEST = sivas_mapping.load_section_mapping("geruest")
SIVAS_MAPPING_WEICHEN = sivas_mapping.load_section_mapping("weichen") SIVAS_MAPPING_WEICHEN = sivas_mapping.load_section_mapping("weichen")
SIVAS_MAPPING_KETTENFOERDERER = sivas_mapping.load_section_mapping("kettenfoerderer")
def build_kreisel_details(block): def build_kreisel_details(block):
@@ -431,6 +487,21 @@ def build_eckrad_details(block):
return sivas_mapping.anwenden(SIVAS_MAPPING_ECKRAD, attribs, TRANSFORMS) return sivas_mapping.anwenden(SIVAS_MAPPING_ECKRAD, attribs, TRANSFORMS)
def build_kettenfoerderer_details(block, anzahl=1):
"""Merkmale-Dict fuer eine Gruppe baugleicher Kettenfoerderer (KF_n,
Lisp/KettenFoerderer.lsp).
350/359/354/356/360/391 kommen flach aus cfg/sivas.cfg [kettenfoerderer].
353 ("Anzahl der gleichen Schraegfoerderer") entsteht erst hier aus der
Gruppengroesse und kann darum nicht im Mapping stehen - gleiche Bauart wie
3510/3512 beim Kreisel.
"""
attribs = block.get("attribs", {})
details = sivas_mapping.anwenden(SIVAS_MAPPING_KETTENFOERDERER, attribs, TRANSFORMS)
details["353"] = str(anzahl)
return details
# def build_geruest_details(block): # def build_geruest_details(block):
#"""Merkmale-Dict fuer eine GR_-Geruest-Baugruppe (siehe pattern_geruest in #"""Merkmale-Dict fuer eine GR_-Geruest-Baugruppe (siehe pattern_geruest in
#cfg/export.cfg, GeruestInsert.lsp *geruest-attrib-defs*). ARTINR/ #cfg/export.cfg, GeruestInsert.lsp *geruest-attrib-defs*). ARTINR/
@@ -549,6 +620,8 @@ def process_blocks(blocks, anzahl_weichen_ils=0):
btmt_beladung_ids = [] # IDs aller BTMT-Beladung*-Bloecke (eine gruppierte Zeile) btmt_beladung_ids = [] # IDs aller BTMT-Beladung*-Bloecke (eine gruppierte Zeile)
btmt_entladung_ids = [] # IDs aller SC_Entladung*-Bloecke (eine gruppierte Zeile) btmt_entladung_ids = [] # IDs aller SC_Entladung*-Bloecke (eine gruppierte Zeile)
geruest_list = [] # Liste von GR_-Geruest-Baugruppenbloecken, je einer Zeile geruest_list = [] # Liste von GR_-Geruest-Baugruppenbloecken, je einer Zeile
# Kettenfoerderer: kettenfoerderer_signature(block) -> {"block", "ids", "anzahl"}
kettenfoerderer_groups = {}
counters = { counters = {
"anzahl_kreisel": 0, "anzahl_kreisel": 0,
@@ -571,6 +644,7 @@ def process_blocks(blocks, anzahl_weichen_ils=0):
"anzahl_btbeladung": 0, "anzahl_btbeladung": 0,
"anzahl_abwurfstationen": 0, "anzahl_abwurfstationen": 0,
"anzahl_geruest": 0, "anzahl_geruest": 0,
"anzahl_kettenfoerderer": 0,
} }
for block in blocks: for block in blocks:
@@ -620,6 +694,22 @@ def process_blocks(blocks, anzahl_weichen_ils=0):
counters["anzahl_geruest"] += 1 counters["anzahl_geruest"] += 1
continue continue
# --- Kettenfoerderer / Schraegfoerderer Stahl (KF_n) ---
# MUSS vor dem allgemeinen Omniflo-Zweig stehen: die KF-Baugruppe
# traegt TEILEART "Omniflo Kettenfoerderer ..." und wuerde dort sonst
# ueber ARTINR aufgeloest - ihre eigenen Merkmale (350/353/354/356/
# 359/360/391) gingen dabei verloren. Anders als das Geruest werden
# BAUGLEICHE Foerderer zu einer Zeile zusammengefasst, weil Merkmal
# 353 genau diese Stueckzahl verlangt.
if matches_any(bname, BLOCKPATTERNS.get("pattern_kettenfoerderer", [])):
sig = kettenfoerderer_signature(block)
if sig not in kettenfoerderer_groups:
kettenfoerderer_groups[sig] = {"block": block, "ids": [], "anzahl": 0}
kettenfoerderer_groups[sig]["anzahl"] += 1
kettenfoerderer_groups[sig]["ids"].append(get_id(block))
counters["anzahl_kettenfoerderer"] += 1
continue
# --- Omniflo Gerade (AP110) --- # --- Omniflo Gerade (AP110) ---
# VOR dem allgemeinen Omniflo-Zweig: Geraden tragen ggf. ebenfalls # VOR dem allgemeinen Omniflo-Zweig: Geraden tragen ggf. ebenfalls
# TEILEART "Omniflo ...", brauchen aber die Laengensumme. # TEILEART "Omniflo ...", brauchen aber die Laengensumme.
@@ -886,6 +976,31 @@ def process_blocks(blocks, anzahl_weichen_ils=0):
}) })
nr += 1 nr += 1
# Kettenfoerderer / Schraegfoerderer Stahl (KF_n) - eine Zeile je Gruppe
# BAUGLEICHER Foerderer, deren Groesse als Merkmal 353 mitgefuehrt wird.
# Die Sivasnr kommt - wie beim Geruest - aus dem ARTINR-Attribut (gepflegt
# als "sivas_id" je Variante in data/json/kettenfoerderer.json); ist dort
# nichts hinterlegt, bleibt die Spalte leer und die Zeile traegt allein
# ihre Merkmale. Die drei Bausteine des Foerderers (Umlenkstation,
# skaliertes Zwischenstueck, Antriebsstation) bekommen KEINE eigenen
# Zeilen - der Schraegfoerderer ist in Sivas EIN Artikel.
for gruppe in kettenfoerderer_groups.values():
block = gruppe["block"]
attribs = block.get("attribs", {})
items.append({
"nr": nr,
"teileart": attribs.get("TEILEART") or attribs.get("FOERDERERTYP") or KF_TEILEART,
"sivasnr": attribs.get("ARTINR", ""),
"sivasnr_quoted": True,
"bezeichnung": attribs.get("Bezeichnung", ""),
"dispgruppe": 20,
"anzahl": gruppe["anzahl"],
"laenge_mm": attribs.get("L_KF_mm", ""),
"ids": gruppe["ids"],
"details": build_kettenfoerderer_details(block, gruppe["anzahl"]),
})
nr += 1
# VarioFoerderer-Compound-Bloecke (VF_N) - je Block eine eigene Zeile mit # VarioFoerderer-Compound-Bloecke (VF_N) - je Block eine eigene Zeile mit
# vollstaendigen Gefaelle-/Angetrieben-Teilgruppen (immer TYP "Streckengruppe"). # vollstaendigen Gefaelle-/Angetrieben-Teilgruppen (immer TYP "Streckengruppe").
for block in vario_list: for block in vario_list:
+2 -2
View File
@@ -401,7 +401,7 @@
<MenuMacro UID="MM_00095"> <MenuMacro UID="MM_00095">
<Macro> <Macro>
<Name>KettenFoerderer</Name> <Name>KettenFoerderer</Name>
<Command>^C^C(ssg-ensure "OmniModulInsert") OMNI_KettenFoerderer</Command> <Command>^C^C(ssg-ensure "KettenFoerderer") KETTENFOERDERER</Command>
</Macro> </Macro>
</MenuMacro> </MenuMacro>
<MenuMacro UID="MM_00096"> <MenuMacro UID="MM_00096">
@@ -1150,7 +1150,7 @@
<PopMenuRef pUID="PM_00084"/> <PopMenuRef pUID="PM_00084"/>
<PopMenuRef pUID="PM_00088"/> <PopMenuRef pUID="PM_00088"/>
<PopMenuItem> <PopMenuItem>
<NameRef>~KettenFoerderer</NameRef> <NameRef>KettenFoerderer</NameRef>
<MenuItem> <MenuItem>
<MacroRef MenuMacroID="MM_00095"/> <MacroRef MenuMacroID="MM_00095"/>
</MenuItem> </MenuItem>
+5
View File
@@ -158,6 +158,11 @@
(ssg-ensure "export") (ssg-ensure "export")
(ssg-ensure "external_call") (ssg-ensure "external_call")
(ssg-ensure "OmniModulInsert") (ssg-ensure "OmniModulInsert")
;; Kettenfoerderer vorladen statt lazy: der erste Menueklick musste sonst
;; das Laden des Moduls mitbezahlen, der Dialog erschien dadurch spuerbar
;; verzoegert. Das Modul ist klein, der Startaufschlag faellt nicht ins
;; Gewicht. (Zum Nachmessen: Schalter "kf-zeit", siehe KettenFoerderer.lsp)
(ssg-ensure "KettenFoerderer")
;; Tro_Edit wird nicht vorgeladen - der Dispatcher SSG_BLOCKEDIT und die ;; Tro_Edit wird nicht vorgeladen - der Dispatcher SSG_BLOCKEDIT und die
;; Menuemakros holen es per (ssg-ensure "Tro_Edit") bei Bedarf nach. ;; Menuemakros holen es per (ssg-ensure "Tro_Edit") bei Bedarf nach.
(ssg-ensure "SSG_LIB_Commands") (ssg-ensure "SSG_LIB_Commands")
+1 -1
View File
@@ -92,7 +92,7 @@
[Schwenkschiene Schiebetür R]^C^C(ssg-ensure "OmniModulInsert") OMNI_SCHW_400_R [Schwenkschiene Schiebetür R]^C^C(ssg-ensure "OmniModulInsert") OMNI_SCHW_400_R
[Schwenkschiene Schiebetür L mit Sensorik]^C^C(ssg-ensure "OmniModulInsert") OMNI_SCHW_400_L_SENSORIK [Schwenkschiene Schiebetür L mit Sensorik]^C^C(ssg-ensure "OmniModulInsert") OMNI_SCHW_400_L_SENSORIK
[<-<-<-Schwenkschiene Schiebetür R mit Sensorik]^C^C(ssg-ensure "OmniModulInsert") OMNI_SCHW_400_R_SENSORIK [<-<-<-Schwenkschiene Schiebetür R mit Sensorik]^C^C(ssg-ensure "OmniModulInsert") OMNI_SCHW_400_R_SENSORIK
[~KettenFoerderer]^C^C(ssg-ensure "OmniModulInsert") OMNI_KettenFoerderer [KettenFoerderer]^C^C(ssg-ensure "KettenFoerderer") KETTENFOERDERER
[Ladeschleifen]^C^C(ssg-ensure "OmniModulInsert") OMNI_LADESCHLEIFE_AP110 [Ladeschleifen]^C^C(ssg-ensure "OmniModulInsert") OMNI_LADESCHLEIFE_AP110
[->Verbinder] [->Verbinder]
[TV W-AP110 kpl]^C^C(ssg-ensure "OmniModulInsert") OMNI_TV_W_AP110 [TV W-AP110 kpl]^C^C(ssg-ensure "OmniModulInsert") OMNI_TV_W_AP110
+253 -1
View File
@@ -2464,7 +2464,7 @@
"tu-tests-export" "tu-tests-hoehen" "tu-tests-gf" "tu-tests-omni" "tu-tests-kreisel" "tu-tests-kreisel-bp" "tu-tests-export" "tu-tests-hoehen" "tu-tests-gf" "tu-tests-omni" "tu-tests-kreisel" "tu-tests-kreisel-bp"
"tu-tests-sepliste" "tu-tests-json" "tu-tests-geruest" "tu-tests-sepliste" "tu-tests-json" "tu-tests-geruest"
"tu-tests-sepscan" "tu-tests-vfl-segs" "tu-tests-vfl-abbruch" "tu-tests-sepscan" "tu-tests-vfl-segs" "tu-tests-vfl-abbruch"
"tu-tests-werkzeuge") "tu-tests-werkzeuge" "tu-tests-kf")
(tu-run-block fn)) (tu-run-block fn))
(princ "\n\n----------------------------------------------------------------") (princ "\n\n----------------------------------------------------------------")
@@ -2487,3 +2487,255 @@
(princ "\ntest_unit.lsp geladen. Befehl: TEST_UNIT") (princ "\ntest_unit.lsp geladen. Befehl: TEST_UNIT")
(princ) (princ)
;; ------------------------------------------------------------
;; TESTS: KettenFoerderer.lsp + ssg_ks_insert.lsp (KS-Orientierung)
;; ------------------------------------------------------------
;; Reine Rechenkerne des Kettenfoerderers: Hoehenbilanz, Massstab,
;; Grenzpruefung, KS-Winkel. Alles ohne Zeichnung und ohne Blockdateien -
;; die zeichnungsabhaengigen Teile (kf-geometrie-messen, kf-kette-bauen)
;; brauchen BricsCAD und bleiben dem Befehl KF_KS_PRUEFEN vorbehalten.
(defun tu-tests-kf ( / _l _s _defs)
(princ "\n[KettenFoerderer]")
(if (not (car (atoms-family 1 '("KF-LAENGE-BERECHNEN"))))
(tu-record nil "KettenFoerderer-Modul geladen"
"KettenFoerderer.lsp nicht geladen - siehe tests/test_unit.scr")
(progn
;; --- ks-winkel-normalisieren: auf -180..180 falten ---
(tu-eqf "ks-winkel-norm/190" -170.0 (ks-winkel-normalisieren 190.0))
(tu-eqf "ks-winkel-norm/-190" 170.0 (ks-winkel-normalisieren -190.0))
(tu-eqf "ks-winkel-norm/26" 26.0 (ks-winkel-normalisieren 26.0))
(tu-eqf "ks-winkel-norm/360" 0.0 (ks-winkel-normalisieren 360.0))
(tu-nil "ks-winkel-norm/nil" (ks-winkel-normalisieren nil))
;; --- ks-xy-winkel: X-Achse eines KS-Eintrags (origin x-end y-end z-end)
(tu-eqf "ks-xy-winkel/entlang-X" 0.0
(ks-xy-winkel '((0.0 0.0 0.0) (1.0 0.0 0.0) (0.0 2.0 0.0) (0.0 0.0 3.0))))
(tu-eqf "ks-xy-winkel/entlang-Y" 90.0
(ks-xy-winkel '((0.0 0.0 0.0) (0.0 1.0 0.0) (-2.0 0.0 0.0) (0.0 0.0 3.0))))
;; versetzter Ursprung: nur die RICHTUNG zaehlt, nicht die Lage
(tu-eqf "ks-xy-winkel/versetzt-45" 45.0
(ks-xy-winkel (list '(100.0 50.0 0.0) '(101.0 51.0 0.0) '(99.0 51.0 0.0) '(100.0 50.0 1.0))))
;; senkrechte X-Achse (keine XY-Laenge) -> nil statt Division durch 0
(tu-nil "ks-xy-winkel/senkrecht"
(ks-xy-winkel '((0.0 0.0 0.0) (0.0 0.0 1.0) (0.0 2.0 0.0) (0.0 0.0 3.0))))
;; --- kf-hz-folge: Folgebaustein an KS_AUS des Vorgaengers ausrichten ---
;; Vorgaenger zeigt 26 Grad, Folgebaustein ist waagerecht gezeichnet (0)
(tu-eqf "kf-hz-folge/26-auf-0" 26.0 (kf-hz-folge 26.0 0.0))
;; Folgebaustein ist selbst schon um 26 Grad gezeichnet -> keine Drehung
(tu-eqf "kf-hz-folge/26-auf-26" 0.0 (kf-hz-folge 26.0 26.0))
;; fehlende Eigenrichtung -> Baustein uebernimmt die Vorgaengerrichtung
(tu-eqf "kf-hz-folge/ohne-beta" 26.0 (kf-hz-folge 26.0 nil))
(tu-nil "kf-hz-folge/ohne-phi" (kf-hz-folge nil 0.0))
;; --- kf-dy-eingebaut: Hoehenbeitrag nach Rz(hz) und X-Massstab ---
;; waagerechter Baustein, waagerecht eingebaut -> kein Hoehengewinn
(tu-eqf "kf-dy/0-grad" 0.0 (kf-dy-eingebaut 1000.0 0.0 0.0 1.0))
;; 1000 mm unter 30 Grad -> 500 mm (sin 30 = 0.5)
(tu-eqf "kf-dy/30-grad" 500.0 (kf-dy-eingebaut 1000.0 0.0 30.0 1.0))
;; derselbe Baustein doppelt skaliert -> doppelter Hoehengewinn
(tu-eqf "kf-dy/30-grad-skaliert-2" 1000.0 (kf-dy-eingebaut 1000.0 0.0 30.0 2.0))
;; senkrecht eingebaut -> die volle Laenge als Hoehe
(tu-eqf "kf-dy/90-grad" 1000.0 (kf-dy-eingebaut 1000.0 0.0 90.0 1.0))
;; --- kf-laenge-berechnen: Hoehenbilanz nach der Laenge aufloesen ---
;; H=1000, Stationen tragen nichts bei, 30 Grad -> L = 1000/sin30 = 2000
(tu-eqf "kf-laenge/30-grad-glatt" 2000.0
(kf-laenge-berechnen 1000.0 0.0 0.0 0.0 30.0))
;; Stationen tragen 100+150 bei -> nur 750 mm bleiben fuer das Stueck
(tu-eqf "kf-laenge/mit-stationen" 1500.0
(kf-laenge-berechnen 1000.0 100.0 150.0 0.0 30.0))
;; Gegenprobe: die errechnete Laenge ergibt wieder genau H
(setq _l (kf-laenge-berechnen 1000.0 100.0 150.0 0.0 30.0))
(tu-eqf "kf-laenge/rundlauf-ergibt-H" 1000.0
(+ 100.0 150.0 (kf-dy-eingebaut _l 0.0 30.0 1.0)))
;; bereits geneigt gezeichnetes Zwischenstueck: dy-nativ wird abgezogen
;; (dy-nativ skaliert NICHT mit, nur X wird skaliert)
(tu-eqf "kf-laenge/mit-dy-nativ" 1800.0
(kf-laenge-berechnen 1000.0 0.0 0.0 (/ 100.0 (cos (/ pi 6.0))) 30.0))
;; waagerecht -> keine Hoehe erreichbar
(tu-nil "kf-laenge/0-grad-unloesbar"
(kf-laenge-berechnen 1000.0 0.0 0.0 0.0 0.0))
;; --- kf-skala-berechnen ---
(tu-eqf "kf-skala/2000-von-1000" 2.0 (kf-skala-berechnen 2000.0 1000.0))
(tu-nil "kf-skala/ohne-nativlaenge" (kf-skala-berechnen 2000.0 0.0))
(tu-nil "kf-skala/ohne-laenge" (kf-skala-berechnen nil 1000.0))
;; --- kf-laenge-pruefen: Grenzen aus der JSON ---
(tu-nil "kf-pruefen/in-ordnung" (kf-laenge-pruefen 2000.0 100.0 20000.0))
(tu-eq "kf-pruefen/zu-kurz" "kf-fehler-laenge-unter-min"
(kf-laenge-pruefen 50.0 100.0 20000.0))
(tu-eq "kf-pruefen/zu-lang" "kf-fehler-laenge-ueber-max"
(kf-laenge-pruefen 99999.0 100.0 20000.0))
;; negative Laenge = Stationen bringen mehr Hoehe mit als gefordert
(tu-eq "kf-pruefen/negativ" "kf-fehler-hoehe-zu-klein"
(kf-laenge-pruefen -10.0 100.0 20000.0))
(tu-eq "kf-pruefen/nil" "kf-fehler-winkel-null"
(kf-laenge-pruefen nil 100.0 20000.0))
;; --- kf-zahl: JSON-Wert als Zahl (Parser liefert Zahl ODER String) ---
(tu-eqf "kf-zahl/int" 26.0 (kf-zahl 26))
(tu-eqf "kf-zahl/real" 26.0 (kf-zahl 26.0))
(tu-eqf "kf-zahl/string" 26.0 (kf-zahl "26"))
(tu-nil "kf-zahl/nil" (kf-zahl nil))
;; --- kf-attrib-defs: VF-Schema + KF-Zusatz, KEIN Tag doppelt ---
(setq _defs (kf-attrib-defs))
(tu-true "kf-attrib-defs/hat-ID" (assoc "ID" _defs))
(tu-true "kf-attrib-defs/hat-FOERDERERTYP" (assoc "FOERDERERTYP" _defs))
(tu-true "kf-attrib-defs/hat-WINKEL" (assoc "WINKEL" _defs))
(tu-true "kf-attrib-defs/hat-STANDARD_STEUERUNG"
(assoc "STANDARD_STEUERUNG" _defs))
;; Reihenfolge wie im Sivas-Merkmalstamm: 361 folgt direkt auf den Typ,
;; STANDARD_STEUERUNG steht also unmittelbar hinter WINKEL
(tu-eq "kf-attrib-defs/361-folgt-auf-winkel" "STANDARD_STEUERUNG"
(car (nth (1+ (kf-tag-index "WINKEL" _defs)) _defs)))
;; FOERDERERTYP ist die BAUART im Klartext, der Winkel steht in WINKEL
(tu-eq "kf-attrib-defs/FOERDERERTYP-ist-bauart" "Schraegfoerderer Stahl"
(cadr (assoc "FOERDERERTYP" _defs)))
(tu-true "kf-attrib-defs/hat-MOVIMOT" (assoc "MOVIMOT" _defs))
;; Farbe und Antriebsmotor sind ZWEI Eigenschaften (Sivas 354 bzw. 355), nicht
;; ein kombiniertes AUSFUEHRUNG-Attribut
(tu-true "kf-attrib-defs/hat-FARBE" (assoc "FARBE" _defs))
(tu-true "kf-attrib-defs/hat-ANTRIEBSMOTOR" (assoc "ANTRIEBSMOTOR" _defs))
(tu-nil "kf-attrib-defs/kein-AUSFUEHRUNG" (assoc "AUSFUEHRUNG" _defs))
;; Der Kettenfoerderer traegt sich selbst - die Geruest-Tags aus dem
;; VF-Schema werden bewusst NICHT mitgefuehrt
(tu-nil "kf-attrib-defs/kein-GERUEST_EINZELMODUL"
(assoc "GERUEST_EINZELMODUL" _defs))
(tu-nil "kf-attrib-defs/kein-GERUEST_TYP" (assoc "GERUEST_TYP" _defs))
;; TYP/ARTINR stehen in BEIDEN Listen - der Zusatz muss gewinnen, und
;; der Tag darf nur EINMAL vorkommen (zwei ATTDEFs gleichen Tags waeren
;; im Block ungueltig, ssg-attrib-set-on traefe nur den ersten).
(tu-eq "kf-attrib-defs/TYP-ueberschrieben" "Kettenfoerderer"
(cadr (assoc "TYP" _defs)))
(setq _s 0)
(foreach _d _defs (if (= (car _d) "TYP") (setq _s (1+ _s))))
(tu-eq "kf-attrib-defs/TYP-nur-einmal" 1 _s)
(setq _s 0)
(foreach _d _defs (if (= (car _d) "ARTINR") (setq _s (1+ _s))))
(tu-eq "kf-attrib-defs/ARTINR-nur-einmal" 1 _s)
;; Der Winkel steht ALLEIN in FOERDERERTYP - kein zweites Winkel-Tag
(tu-nil "kf-attrib-defs/kein-KF_WINKEL" (assoc "KF_WINKEL" _defs))
(tu-nil "kf-attrib-defs/kein-KF_TYP" (assoc "KF_TYP" _defs))
;; Das Schema ist EIGENSTAENDIG, nicht vom VF-Streckenschema geerbt -
;; keines der VF-Tags darf durchschlagen
(tu-nil "kf-attrib-defs/kein-SEITE_AS" (assoc "SEITE_AS" _defs))
(tu-nil "kf-attrib-defs/kein-ANZAHL_VF" (assoc "ANZAHL_VF" _defs))
(tu-nil "kf-attrib-defs/kein-TEILEART" (assoc "TEILEART" _defs))
(tu-eq "kf-attrib-defs/LAYER-ist-F-3" "F-3" (cadr (assoc "LAYER" _defs)))
;; --- kf-variante-finden: ueber den Winkel, auch als String ---
(tu-eq "kf-variante-finden/26" "A"
(cdr (assoc "name"
(kf-variante-finden 26
'((("winkel" . 26) ("name" . "A"))
(("winkel" . 30) ("name" . "B")))))))
(tu-eq "kf-variante-finden/30-als-string" "B"
(cdr (assoc "name"
(kf-variante-finden 30
'((("winkel" . "26") ("name" . "A"))
(("winkel" . "30") ("name" . "B")))))))
(tu-nil "kf-variante-finden/unbekannt"
(kf-variante-finden 45 '((("winkel" . 26) ("name" . "A")))))
;; --- kf-antriebsart (Merkmal 357): Dropdown mit EINER Option ---
;; Der Wert kommt aus dem ERSTEN Listeneintrag - nicht aus dem Code.
(tu-eq "kf-antriebsart/aus-daten" "1.1 kW"
(kf-antriebsart '(("antriebsart" (("name" . "1.1 kW") ("wert" . "1.1 kW"))))))
;; eine zweite Option aendert die Vorgabe NICHT (Index 0 bleibt massgebend)
(tu-eq "kf-antriebsart/erster-eintrag-gewinnt" "1.1 kW"
(kf-antriebsart '(("antriebsart" (("name" . "1.1 kW") ("wert" . "1.1 kW"))
(("name" . "0.55 kW") ("wert" . "0.55 kW"))))))
;; Liste fehlt -> Rueckfall, aber als STRING (nicht T/nil)
(tu-eq "kf-antriebsart/ohne-eintrag" "1.1 kW" (kf-antriebsart '(("titel" . "x"))))
(tu-true "kf-antriebsart/ist-string"
(= (type (kf-antriebsart '(("titel" . "x")))) 'STR))
;; Dezimalpunkt, kein Komma (Nutzervorgabe)
(tu-nil "kf-antriebsart/kein-komma"
(vl-string-search "," (kf-antriebsart '(("titel" . "x")))))
;; --- kf-neigung-aus-punkten: Kern der 3D-Aufrichtung ---
;; Liefert (Schraeglaenge Neigungswinkel) aus Ketten-Start und -Ende.
;; Die Kette wird AUFGERICHTET eingebaut, die Hoehe laeuft also in Z.
;; 3-4-5-Dreieck: 3000 waagerecht, 4000 hoch -> 5000 schraeg
(tu-eqf "kf-neigung/3-4-5-laenge" 5000.0
(car (kf-neigung-aus-punkten '(0.0 0.0 0.0) '(3000.0 0.0 4000.0) 0.0)))
;; 45 Grad: gleiche Betraege waagerecht und hoch
(tu-eqf "kf-neigung/45-grad" 45.0
(cadr (kf-neigung-aus-punkten '(0.0 0.0 0.0) '(1000.0 0.0 1000.0) 0.0)))
;; waagerecht -> Winkel 0, Laenge = Horizontalabstand
(tu-eqf "kf-neigung/waagerecht" '(2000.0 0.0)
(kf-neigung-aus-punkten '(0.0 0.0 0.0) '(2000.0 0.0 0.0) 0.0))
;; Der Horizontalanteil wird auf die KETTENRICHTUNG projiziert, nicht
;; auf die Welt-X-Achse: bei 90 Grad Basisdrehung laeuft die Kette in Y.
;; Ohne Projektion kaeme hier 0 heraus und der Winkel waere 90 statt 45.
(tu-eqf "kf-neigung/gedreht-90" '(1414.213562 45.0)
(kf-neigung-aus-punkten '(0.0 0.0 0.0) '(0.0 1000.0 1000.0) 90.0))
;; fallende Kette -> negativer Winkel
(tu-eqf "kf-neigung/fallend" -45.0
(cadr (kf-neigung-aus-punkten '(0.0 0.0 1000.0) '(1000.0 0.0 0.0) 0.0)))
;; Start = Ende -> nil statt Division durch 0
(tu-nil "kf-neigung/nulllaenge"
(kf-neigung-aus-punkten '(5.0 5.0 5.0) '(5.0 5.0 5.0) 0.0))
;; --- kf-matrix-aufrecht: Y_lokal wird zu Z_welt ---
;; Das ist die Kernaussage der Aufrichtung. Geprueft wird sie an den
;; Bildern der Einheitsvektoren, nicht an den Matrixeintraegen - so
;; bleibt der Test lesbar und unabhaengig von der Schreibweise.
(tu-eqf "kf-matrix/Y-lokal-wird-Z-welt" '(0.0 0.0 1.0)
(mat3-mul-vec3 (kf-matrix-aufrecht 0.0 0.0) '(0.0 1.0 0.0)))
;; Die Fahrtrichtung (X) bleibt bei Basisdrehung 0 die Welt-X-Achse
(tu-eqf "kf-matrix/X-bleibt-X" '(1.0 0.0 0.0)
(mat3-mul-vec3 (kf-matrix-aufrecht 0.0 0.0) '(1.0 0.0 0.0)))
;; Basisdrehung 90 Grad dreht die Fahrtrichtung in die Welt-Y-Achse,
;; die Hoehe bleibt dabei in Z
(tu-eqf "kf-matrix/basis-90-dreht-X-nach-Y" '(0.0 1.0 0.0)
(mat3-mul-vec3 (kf-matrix-aufrecht 90.0 0.0) '(1.0 0.0 0.0)))
(tu-eqf "kf-matrix/basis-90-haelt-Z" '(0.0 0.0 1.0)
(mat3-mul-vec3 (kf-matrix-aufrecht 90.0 0.0) '(0.0 1.0 0.0)))
;; --- Standard-Variante: steht in den DATEN, nicht im Code ---
(tu-true "kf-variante-standard-p/markiert"
(kf-variante-standard-p '(("winkel" . 26) ("standard" . T))))
(tu-nil "kf-variante-standard-p/ohne-feld"
(kf-variante-standard-p '(("winkel" . 30))))
;; Index fuer die Vorauswahl - auch wenn der Standard NICHT der erste ist
(tu-eq "kf-standard-index/zweiter" 1
(kf-standard-index '((("winkel" . 26))
(("winkel" . 30) ("standard" . T)))))
(tu-eq "kf-standard-index/erster" 0
(kf-standard-index '((("winkel" . 26) ("standard" . T))
(("winkel" . 30)))))
;; keine Variante markiert -> erste, statt nil (der Dialog braucht einen Index)
(tu-eq "kf-standard-index/keiner" 0
(kf-standard-index '((("winkel" . 26)) (("winkel" . 30)))))
;; --- kf-punkt-differenzen: zweite Hoehen-Eingabeart (2 Punkte) ---
;; Gemessen wird die Differenz in Z - die Baugruppe steht aufgerichtet im
;; Modell. Zurueckgegeben wird (dz dy): die HOEHE zuerst, dY nur zur
;; Kontrolle (wer in einer Draufsicht pickt, sieht dz = 0).
(tu-eqf "kf-punkt-diff/dz" '(1500.0 0.0)
(kf-punkt-differenzen '(0.0 0.0 0.0) '(2000.0 0.0 1500.0)))
;; Vorzeichen egal - die Reihenfolge der Punkte darf keine Rolle spielen
(tu-eqf "kf-punkt-diff/umgekehrt" '(1500.0 0.0)
(kf-punkt-differenzen '(2000.0 0.0 1500.0) '(0.0 0.0 0.0)))
;; in einer Draufsicht gepickt: dz = 0, dY gross
(tu-eqf "kf-punkt-diff/draufsicht" '(0.0 1200.0)
(kf-punkt-differenzen '(0.0 0.0 0.0) '(3000.0 1200.0 0.0)))
;; Punkte ohne Z (2D-Pick) duerfen nicht abstuerzen: dz ist dann 0
(tu-eqf "kf-punkt-diff/ohne-z" '(0.0 800.0)
(kf-punkt-differenzen '(0.0 0.0) '(100.0 800.0)))
(tu-nil "kf-punkt-diff/nil" (kf-punkt-differenzen nil '(1.0 2.0 3.0)))
;; --- kf-auswahl-wert: "wert" vor "name", Vorgabe bei leerem Index ---
(tu-eq "kf-auswahl-wert/wert" "Nein"
(kf-auswahl-wert '((("name" . "Nein") ("wert" . "Nein"))) 0 "X"))
(tu-eq "kf-auswahl-wert/ausserhalb" "X"
(kf-auswahl-wert '((("name" . "Nein") ("wert" . "Nein"))) 5 "X"))
)
)
)
+1
View File
@@ -10,6 +10,7 @@
; Modul, gehoert dessen load-Zeile HIER dazu (nicht in test_unit.lsp). ; Modul, gehoert dessen load-Zeile HIER dazu (nicht in test_unit.lsp).
(load (strcat (getenv "DXFM_LISP") "/GeruestInsert.lsp") "GeruestInsert.lsp nicht gefunden") (load (strcat (getenv "DXFM_LISP") "/GeruestInsert.lsp") "GeruestInsert.lsp nicht gefunden")
(load (strcat (getenv "DXFM_LISP") "/count_sep_scan.lsp") "count_sep_scan.lsp nicht gefunden") (load (strcat (getenv "DXFM_LISP") "/count_sep_scan.lsp") "count_sep_scan.lsp nicht gefunden")
(load (strcat (getenv "DXFM_LISP") "/KettenFoerderer.lsp") "KettenFoerderer.lsp nicht gefunden")
(load (strcat (getenv "DXFMAKRO") "/tests/test_unit.lsp")) (load (strcat (getenv "DXFMAKRO") "/tests/test_unit.lsp"))
(c:TEST_UNIT) (c:TEST_UNIT)
(command "_.QUIT") (command "_.QUIT")