[FIX] Omniflo TEF einfügen entlang Gerade funktioniert wieder; Omniflo Gerade ist aus dem Menü entfernt worden, da entweder über das Menü Fahrstrecke oder nur als Linie gezeichnet wird

This commit is contained in:
Simon Hensch committed 2026-11-03 07:40:01 +01:00
1 parent afc5dce13a
commit 98106a6af4
17 files changed
+59 -548

No files matched your search

+2 -2
View File
@@ -78,7 +78,7 @@ Die `start_briscad.bat` ruft `setenv.bat` auf und startet BricsCAD.
| VarioFoerderer | `VarioFoerderer` | FOERDERANLAGE, VARIOFOERDERER_EDIT, Vario_Kette_Merge |
| Gefaellestrecke | `Gefaellestrecke` | GEFAELLESTRECKE, GEFAELLESTRECKE_EDIT |
| Kettenfoerderer | `KettenFoerderer` | KETTENFOERDERER (Menue: Omniflo -> KettenFoerderer), KF_EDIT (Doppelklick auf KF_n). KF_KS_PRUEFEN ist ein reiner Diagnosebefehl und bewusst NICHT im Menue |
| Omniflo (komplett) | `OmniModulInsert` + `GeruestInsert` | OMNI_APB_*, OMNI_W*_*, OMNI_AP*, OMNI_TEF_*, OMNI_TV_*, OMNI_LADESCHLEIFE_*, OMNI_EDIT; OMNI_FAHRSTRECKE / OMNI_FAHRSTRECKE_BESCHRIFTEN (GeruestInsert, Linien-Logik wie GERUEST_TRAEGER) |
| Omniflo (komplett) | `OmniModulInsert` + `GeruestInsert` | OMNI_APB_*, OMNI_W*_*, OMNI_TEF_*, OMNI_TV_*, OMNI_LADESCHLEIFE_*, OMNI_EDIT; OMNI_FAHRSTRECKE / OMNI_FAHRSTRECKE_BESCHRIFTEN (GeruestInsert, Linien-Logik wie GERUEST_TRAEGER) |
| Geruest | `GeruestInsert` | GERUEST_SAEULEN, GERUEST_ROHRABHAENGER, GERUEST_WANDBEFESTIGUNG (je eigener Dialog aus der Vorlage geruest.dcl, keine Umschaltung), GERUEST_TRAEGER (eigener Dialog), GERUEST_TRAEGER_BESCHRIFTEN (Untermenue Geruest -> Funktionen -> Traeger beschriften; alle Traeger der Zeichnung neu beschriften); Gattertraeger noch Platzhalter auf GERUEST (zeigt nur einen Hinweis) |
| Connections | `Connection_Edit` + `SSG_LIB_Commands` | CONNECTION_INSERT, CONNECTION_EDIT, ILS_EINGANG_INSERT, ILS_AUSGANG_INSERT |
| Lager | `LagerInsert` + `LagerPruefung` | LG_GESCHOSS, LG_GESCHOSS_AKTIV, LG_GESCHOSS_KOPIEREN, LG_BEREICH, LG_REIHE, LG_GANG, LG_EDIT, LG_REGALE, LAGER_HAND_YAML, LAGER_EXPORT, LG_REGELN |
@@ -114,7 +114,7 @@ Detaillierte Dokumentation aller Funktionen und Befehle: siehe `Lisp/README.md`.
| `vf_spec.lsp` (von vf_core.lsp NACH vf_linienzug.lsp geladen) | VF_SPEC_BAU | Linienzug-Ketten aus **Eingabedaten** bauen, ohne Dialog und ohne Konsolenfrage (Stufe 1 aus `doc/todo/plan-vf-interactive.md`). Eine **Spec** beschreibt eine Kette in Domaenenwerten (`"links"`, `"winkel"`, `"aussen"`, ja/nein) statt in Menue-Codes; `vsp-journal` uebersetzt sie in ein Eingabe-Journal, `vsp-bau-aus-spec` spielt es per `vfl-journal-replay-start` durch den UNVERAENDERTEN `vf-linienzug-modus` (Replay-Kern `vsp-bau-journal` - nimmt auch ein unveraendert uebernommenes, aufgezeichnetes Journal, z.B. aus `dxf_anlage_export.py`). Damit traegt der fertige Block dasselbe `SSG_VF_EDIT`-Journal wie eine handgebaute Kette und bleibt per Doppelklick editier- und 2D/3D-konvertierbar - kein Journal-Konsument muss etwas von Specs wissen. Wichtige Regeln, die der Uebersetzer kennt: der Menue-Code haengt am Frame (erste Sektion 4 Optionen ohne GF-Bogen, danach 5), `hz` steht nur beim ERSTEN Segment im Journal, und `erst-hor` unterscheidet den horizontalen Erstkoerper einer VF-Einheit (Separator-/Endpunktfragen vorab) vom gewinkelten (keine Frage). Fehlerverhalten: fail fast - `vsp-pruefen` sammelt ALLE Spec-Fehler, gebaut wird dann nichts (nichts wird geraten). Ergebnis-Record je Kette mit `status` (`executed`/`warnung`/`desync`/`abbruch`/`spec-fehler`), Block/Handle/Einfuegepunkt/Attributen, `prompts` (muss 0 sein), `glieder_soll` vs. `glieder_ist` (Desync-Detektor, der auch bei aufgehender Queue greift) und den gesammelten `meldungen`. Headless-Rahmen `vsp-headless-an`/`-aus` (Save/Restore von `*vfl-headless*`, `*vfl-wizard-mode*`, `*ssg-gui-aus*` + zaehlende Eingabe-Stubs). Spec-Datei flach als JSON (`ssg-load-json` liest zeilenweise), erzeugt von `lib/vf_spec_export.py`. Gegenstueck/Referenz in Python: derselbe Emitter, gegen die 5 echten HundM-Ketten rundlaufgeprueft |
| `Gefaellestrecke.lsp` | GEFAELLESTRECKE, GEFAELLESTRECKE_EDIT | Gefaelle-Foerderanlage (AUS -> Staustrecke skaliert -> Separator -> EIN); Modus 1 per DCL-Dialog (Einfuegehoehe, Element-Winkel 30/90); Doppelklick auf GF_n-Block ruft GEFAELLESTRECKE_EDIT (Dialog vorbelegt, Neuaufbau; die Einfuegehoehe kommt aus der aktuellen Z des Einfuegepunkts statt aus XDATA/HOEHE_VON_mm, damit ein in Z verschobener Block per OK direkt auf der neuen Hoehe neu entsteht - gleiches gilt fuer die 2D/3D-Umschaltung `gf-konvertiere-ent`; der GF-Linienzug-Rebuild nutzt weiter die absoluten Segmentpunkte aus XDATA) |
| `export.lsp` | EXPORTSIVAS, EXPORTCSV, OMNI_UPDATE_ATTRIBS, CSV_EXPORT_KONFIG | JSON-Sammlung und Python-Export (Omniflo-Merkmale/Sum-Zeile via lib/export_csv.py). **Gefrorene Layer**: `csv:collect-export-blocks` laesst Bloecke auf gefrorenen Layern aus (ausgeschaltete Layer zaehlen NICHT), Schalter `*csv-gefrorene-ausschliessen*` (Standard an, Toggle im Dialog CSV_EXPORT_KONFIG). Die Hilfsobjekte eines gefrorenen VF_n/GF_n (Separator-/Element-Kopien, Einheiten-/AS-ES-Marker) liegen auf eigenen Layern und werden darum ueber `*csv-ausschluss-enames*` mit ausgelassen (gesetzt in `csv:export-vorbereiten` per `csv:hilfskopien-ausschluss`); erzeugt und nummeriert werden sie trotzdem, damit IDs stabil bleiben. DrawPlanquadrate nutzt dieselbe Sammlung und folgt dem Filter. **Hoehen-Neuberechnung**: erster Schritt von `csv:export-vorbereiten` ist `csv:hoehen-aktualisieren` - in Z verschobene `KREISEL_*`/`ECKRAD_*`/`VF_*`/`GF_*` bekommen ihre Hoehen-Attribute aus der Einfuege-Z neu (reiner Kern `csv:hoehen-werte`, getestet; Formeln/Rundung wie beim Bau: Kreisel HOEHE + MONTAGEHOEHE_m=z/1000, Eckrad HOEHE, GF/VF HOEHE_VON_mm=(fix z), MONTAGEHOEHE_m GF=z/1000 bzw. VF=(VON+BIS)/2000). HOEHE_BIS_mm = VON - (VON_alt - BIS_alt), bewusst NICHT z - DELTA_H_mm (ohne Vorzeichen -> steigende VF falsch, separat abgeschnitten -> 1 mm Abweichung); DELTA_H_mm nur Rueckfall. Nicht verschobene Bloecke (Attribut passt zu z) bleiben unangetastet, damit Bau-Werte und Hand-Korrekturen (z.B. Buehnen-Abzug aus HOEHEN_CHECK) bit-genau erhalten bleiben |
| `OmniModulInsert.lsp` | OMNI_LOAD, OMNI_APB_*, OMNI_W*_*, OMNI_AP60/AP110, OMNI_TEF_*, OMNI_TV_*, OMNI_APBW_*, OMNI_LADESCHLEIFE_AP110, OMNI_EDIT | Omniflo-Komponenten: Boegen, Weichen, Verbinder (`OMNI_TV_*`: DWGs dimensionsunabhaengig in `data/omniflo/Verbinder`, `omni:insert-verbinder` -> gemeinsamer Einfuegekern `omni:insert-datei`, den auch `omni:insert-dxf` nutzt; im Export ueber `pattern_verbinder` = `VB_*, TV_*` gesammelt (`csv:collect-export-blocks`, `ssg-id-collect-blocks`), Sivas-Zeilen ueber TEILEART/ARTINR wie alle Omniflo-Teile), Transferwagen, Ladeschleifen (`data/json/omniflo_ladeschleifen.json`, per `ssg-json-laden`, da die Beschreibungen Kommas enthalten; Blockdatei darf `.dwg` statt `.dxf` sein), Edit-Dialog |
| `OmniModulInsert.lsp` | OMNI_LOAD, OMNI_APB_*, OMNI_W*_*, OMNI_TEF_*, OMNI_TV_*, OMNI_APBW_*, OMNI_LADESCHLEIFE_AP110, OMNI_EDIT | Omniflo-Komponenten: Boegen, Weichen, Verbinder (`OMNI_TV_*`: DWGs dimensionsunabhaengig in `data/omniflo/Verbinder`, `omni:insert-verbinder` -> gemeinsamer Einfuegekern `omni:insert-datei`, den auch `omni:insert-dxf` nutzt; im Export ueber `pattern_verbinder` = `VB_*, TV_*` gesammelt (`csv:collect-export-blocks`, `ssg-id-collect-blocks`), Sivas-Zeilen ueber TEILEART/ARTINR wie alle Omniflo-Teile), Transferwagen, Ladeschleifen (`data/json/omniflo_ladeschleifen.json`, per `ssg-json-laden`, da die Beschreibungen Kommas enthalten; Blockdatei darf `.dwg` statt `.dxf` sein), Edit-Dialog |
| `SSG_LIB_Commands.lsp` | ILS_BTMT_Beladung, ILS_BTMT_Entladung, ILS_SCANNER_INSERT, ILS_SEPARATOR_INSERT, ILS_EINGANG_INSERT, ILS_AUSGANG_INSERT, SSG_BLOCKEDIT, SSG_DIM_SWITCH, SSG_SPRACHE | BTMT Be-/Entladung (`ils-insert-station`: wiederholtes Einfuegen von `BTMT-Beladung` bzw. `SC_Entladung`, Drehung interaktiv, Layer aus `LAYER`-Attribut, Dimension via `ssg-ils-block-laden`) + Sensoren (`ils-insert-sensor`) + Eingang-/Ausgang-Symbol (frei platzierbar wie BTMT Be-/Entladung, ueber `ils-insert-station` mit den Rohnamen `Eingang`/`Ausgang`, Bloecke `Eingang_<DIM>.dwg`/`Ausgang_<DIM>.dwg` in data/ils) + Doppelklick/Kontextmenue-Dispatcher + Konfiguration (2D/3D, Sprache) |
| `Tro_Edit.lsp` | TRO_INSERT, TRO_EDIT | TRO-Marker (Block `TRO_SYM_<Typ>`) fuer sps_skel (lib/tro_annotate.py): TRO_INSERT fuegt eine bestehende Blockdefinition an einem gewaehlten Punkt ein und setzt ID/TYPE (bricht ab, wenn der Typ noch keine Blockdefinition in der Zeichnung hat - die entsteht nur ueber tro_annotate.py); TRO_EDIT aendert ID/TYPE eines bestehenden Markers per Dialog. Typliste aus `tro_types.lsp` (von `tro_annotate.py --emit-lisp` nach DXFM_LISP geschrieben). Der Dispatcher SSG_BLOCKEDIT leitet Blocknamen `TRO_*` zu TRO_EDIT. |
| `Connection_Edit.lsp` | CONNECTION_INSERT, CONNECTION_EDIT | Verbindung zwischen zwei TRO-Markern als Block `CONNECTION_ARROW` (Pfeilmitte); Beziehung ueber die INTERNEN IDs der TROs (`FROM_ID`/`TO_ID`, sichtbar `FROM_TRO`/`TO_TRO`, `KIND` flow/colocated), damit Umbenennen/Verschieben die Zuordnung nicht bricht. Dialog `connection_edit.dcl`; SSG_BLOCKEDIT leitet `CONNECTION_*` hierher (vor dem TRO-Zweig) |
-257
View File
@@ -481,263 +481,6 @@
(princ)
)
;; --- Omniflo / Aluprofil Gerade ---
;; Aluprofil-Fahrstrecke einfuegen.
;;
;; Ablauf:
;; 1. Quell-Block (.dwg) temporaer einfuegen, Attribute lesen, loeschen
;; 2. Nutzer waehlt Einfuegepunkt -> Text "blockname" wird horizontal platziert
;; 3. Nutzer klickt Endpunkt -> Linie definiert Fahrstreckenlaenge und Richtung
;; 4. Laenge wird gegen laengemax geprueft (Fehlermeldung bei Ueberschreitung)
;; 5. Compound-Block aus Linie + ATTDEFs (mit Quell-Werten) wird erzeugt
;; Blockname: blockname_YYYYMMDDHHMMSS
;; 6. Text wird gedreht, oberhalb der Linie positioniert, Inhalt aktualisiert
;; z.B. "APG110 L=2879"
;;
;; blockname = Profiltyp (z.B. "AP60", "AP110", "APG110")
;; laengemax = Maximale Fahrstreckenlaenge in mm
;; --- Quell-Attribute einer Aluprofil-.dwg lesen (mit ID-Feld) ---
;; blockname = Profiltyp (z.B. "AP60", "AP110", "APG110")
;;
;; Seit dem ILS-Flach-Refactor tragen die Quell-Bloecke das Dimensionssuffix
;; _2D/_3D und liegen flach unter data/ils/ (z.B. AP60_3D.dwg). Die Aufloesung
;; laeuft daher ueber den zentralen Resolver ssg-ils-block-datei (mit
;; automatischem 3D-Fallback) statt ueber *block-path* + Name. Nur wenn der
;; Resolver nichts findet, wird als Rueckfall der alte Pfad (*block-path* +
;; Name ohne Suffix) versucht.
;; Rueckgabe: Attribut-Alist (mit angehaengtem leeren "ID"-Feld) oder nil,
;; wenn keine Quell-.dwg gefunden wird bzw. sie keine Attribute hat.
(defun omni:read-src-attribs (blockname / datei srcAttribs)
(if (car (atoms-family 1 '("SSG-ILS-BLOCK-DATEI")))
(setq datei (ssg-ils-block-datei blockname))
)
(if (and (null datei) (boundp '*block-path*) *block-path*)
(setq datei (strcat *block-path* blockname ".dwg"))
)
(if datei
(progn
(setq srcAttribs (ssg-attrib-read-dwg datei))
(if (and srcAttribs (not (assoc "ID" srcAttribs)))
(setq srcAttribs (append srcAttribs (list (cons "ID" ""))))
)
)
)
srcAttribs
)
;; --- Aluprofil-Gerade non-interaktiv aus zwei Punkten erzeugen ---
;;
;; Skriptfaehiger Kern von omni:insert-block: baut aus zwei bekannten
;; Punkten (Anfang pt, Ende pt2) den Compound-Block (Linie + ATTDEFs) und
;; fuegt ihn ein. Fuehrt KEINE Nutzerabfrage und KEIN ssg-start/ssg-end aus -
;; der Aufrufer sichert die Umgebung und setzt OSMODE/ATTREQ/ATTDIA=0.
;;
;; blockname = Profiltyp (z.B. "AP110")
;; pt / pt2 = Anfangs-/Endpunkt (Liste x y [z])
;; srcAttribs = Quell-Attribute (Alist) oder nil (dann Block ohne ATTDEFs)
;; textHeight / textGap = Textparameter
;; textEnt = optionaler, bereits erzeugter Vorschau-Text (Tag 1 = blockname);
;; nil -> wird hier erzeugt
;; Rueckgabe: Entity-Name des eingefuegten INSERT-Blocks oder nil.
(defun omni:make-gerade (blockname pt pt2 srcAttribs textHeight textGap textEnt /
laenge laengeStr dx dy angle angleDeg
perpX perpY textPt ed lastEnt ss e bname blockEnt
attribs attribDefs)
(setq laenge (distance (list (car pt) (cadr pt))
(list (car pt2) (cadr pt2))))
(setq laengeStr (rtos laenge 2 0))
(setq dx (- (car pt2) (car pt))
dy (- (cadr pt2) (cadr pt)))
(setq angle (atan dy dx))
(setq angleDeg (* (/ 180.0 pi) angle))
;; 1. Vorschau-Text erzeugen, falls nicht vom Aufrufer uebergeben
(if (null textEnt)
(progn
(entmake (list '(0 . "TEXT")
(cons 8 (getvar "CLAYER"))
(cons 10 (list (car pt) (cadr pt)
(if (caddr pt) (caddr pt) 0.0)))
(cons 40 textHeight)
(cons 1 blockname)
'(50 . 0.0)))
(setq textEnt (entlast))
)
)
(setq lastEnt textEnt)
;; 2. Compound-Block: Linie bei (0,0)..(laenge,0) + ATTDEFs aus Quell-Attributen
(command "_.LINE" (list 0.0 0.0) (list laenge 0.0) "")
(setq attribDefs (ssg-attrib-alist-to-defs srcAttribs))
(ssg-attrib-make-defs attribDefs 50.0)
;; Neue Entities einsammeln (alles nach textEnt)
(setq ss (ssadd))
(setq e (entnext lastEnt))
(while e (ssadd e ss) (setq e (entnext e)))
;; Block mit eindeutigem Zeitstempel-Namen erzeugen. ssg-timestamp hat nur
;; Sekundenaufloesung - bei mehreren Aufrufen innerhalb derselben Sekunde
;; (z.B. Streckenzug-Schleife) kollidiert der Name; dann einen laufenden
;; Zaehler anhaengen, bis der Name frei ist. (Fruehere Variante haengte
;; (itoa (fix (* CDATE 1000000))) an - das sprengt den 32-Bit-INT-Bereich
;; von itoa und brach mit einem Lisp-Fehler ab.)
(setq bname (strcat blockname "_" (ssg-timestamp)))
(if (tblsearch "BLOCK" bname)
(progn
(if (null *omni-gerade-block-counter*) (setq *omni-gerade-block-counter* 0))
(while (tblsearch "BLOCK" bname)
(setq *omni-gerade-block-counter* (1+ *omni-gerade-block-counter*))
(setq bname (strcat blockname "_" (ssg-timestamp) "_"
(itoa *omni-gerade-block-counter*)))
)
)
)
;; Objektfang aus: sonst kann _.INSERT den Einfuegepunkt pt auf ein Objekt
;; umfangen (z.B. den Text bei pt) und die Hoehe verfaelschen.
(setvar "OSMODE" 0)
(command "_.-BLOCK" bname (list 0.0 0.0 0.0) ss "")
;; Block einfuegen (ATTREQ/ATTDIA bereits auf 0)
(command "_.INSERT" bname pt 1 1 angleDeg)
(setq blockEnt (entlast))
;; 3. Attribute setzen: Quell-Werte + LAENGE/A aktualisieren
(setq attribs srcAttribs)
(if (assoc "LAENGE" attribs)
(setq attribs (subst (cons "LAENGE" laengeStr)
(assoc "LAENGE" attribs) attribs))
(setq attribs (cons (cons "LAENGE" laengeStr) attribs))
)
(if (assoc "A" attribs)
(setq attribs (subst (cons "A" laengeStr)
(assoc "A" attribs) attribs))
(setq attribs (cons (cons "A" laengeStr) attribs))
)
(ssg-attrib-set-on blockEnt attribs)
;; Layer aus dem LAYER-Attribut setzen - dieselbe Vorgabe-Konvention wie in
;; omni:insert-dxf und c:OMNI_EDIT. Die Quell-Attribute (srcAttribs) tragen
;; den Layer bereits, er wurde hier bisher nur nicht angewendet.
(ssg-block-layer-vorgabe blockEnt bname attribs)
;; 4. Text oberhalb der Linie positionieren, um Linienwinkel drehen,
;; Inhalt mit Laenge ergaenzen
(setq perpX (* (- (sin angle)) textGap)
perpY (* (cos angle) textGap))
(setq textPt (list (+ (car pt) perpX)
(+ (cadr pt) perpY)
(if (caddr pt) (caddr pt) 0.0)))
(setq ed (entget textEnt))
(setq ed (subst (cons 10 textPt) (assoc 10 ed) ed))
(if (assoc 50 ed)
(setq ed (subst (cons 50 angle) (assoc 50 ed) ed))
(setq ed (append ed (list (cons 50 angle))))
)
(setq ed (subst (cons 1 (strcat blockname " L=" laengeStr))
(assoc 1 ed) ed))
(entmod ed)
(entupd textEnt)
;; 5. Eindeutige ID zuweisen
(if (and blockEnt (atoms-family 1 '("ssg-id-generate")))
(ssg-id-generate blockEnt)
)
(princ (ssg-textf "omni-insert-block-eingefuegt" (list bname laengeStr)))
blockEnt
)
;; Aluprofil-Fahrstrecke interaktiv einfuegen (siehe Ablaufbeschreibung oben).
;; Fragt Einfuege- und Endpunkt ab und delegiert die Blockerzeugung an
;; omni:make-gerade.
(defun omni:insert-block (blockname laengemax /
pt pt2 laenge textEnt textHeight textGap srcAttribs ok)
(setq textHeight (ssg-cfg-or "omniflo" "text_height" 100.0))
(setq textGap (ssg-cfg-or "omniflo" "text_gap" 20.0))
;; 0. Attribute aus der Quell-.dwg lesen (vor ssg-start, da eigene INSERT/ERASE)
(setq srcAttribs (omni:read-src-attribs blockname))
(if (null srcAttribs)
(progn (princ (ssg-text "omni-insert-keine-attribute")) nil)
(progn
;; LAENGEMAX aus Quell-Attribut lesen (falls vorhanden), sonst Parameter
(if (and (assoc "LAENGEMAX" srcAttribs)
(> (strlen (cdr (assoc "LAENGEMAX" srcAttribs))) 0))
(setq laengemax (atof (cdr (assoc "LAENGEMAX" srcAttribs))))
)
(setq pt (getpoint (ssg-text "omni-prompt-einfuegepunkt")))
(if (null pt)
(progn (princ (ssg-text "omni-abbruch-omni")) nil)
(progn
(ssg-start "OMNI Aluprofil" '(("OSMODE") ("ATTREQ") ("ATTDIA")))
;; ATTREQ/ATTDIA auf 0 setzen (werden durch ssg-end wiederhergestellt)
(setvar "ATTREQ" 0)
(setvar "ATTDIA" 0)
;; Vorschau-Text horizontal am Einfuegepunkt (waehrend Endpunktwahl)
(entmake (list '(0 . "TEXT")
(cons 8 (getvar "CLAYER"))
(cons 10 (list (car pt) (cadr pt)
(if (caddr pt) (caddr pt) 0.0)))
(cons 40 textHeight)
(cons 1 blockname)
'(50 . 0.0)))
(setq textEnt (entlast))
;; Endpunkt fuer Fahrstrecke abfragen (Schleife bei Ueberschreitung)
(setq ok nil)
(while (not ok)
(setq pt2 (getpoint pt (ssg-text "omni-prompt-endpunkt-fahrstrecke")))
(if (null pt2)
(progn
;; Abbruch: Vorschau-Text loeschen
(command "_.ERASE" textEnt "")
(princ (ssg-text "omni-abbruch-omni"))
(setq ok T pt nil)
)
(progn
(setq laenge (distance (list (car pt) (cadr pt))
(list (car pt2) (cadr pt2))))
(if (> laenge laengemax)
(alert (ssg-textf "omni-laenge-ueberschritten"
(list (rtos laenge 2 0) (rtos laengemax 2 0))))
(progn
(omni:make-gerade blockname pt pt2 srcAttribs
textHeight textGap textEnt)
(setq ok T)
)
)
)
)
)
(ssg-end)
pt
)
)
)
)
)
(defun c:OMNI_AP60 ()
(omni:insert-block "AP60" (ssg-cfg-or "omniflo" "laengemax_ap60" 7000.0))
(princ)
)
(defun c:OMNI_AP110 ()
(omni:insert-block "AP110" (ssg-cfg-or "omniflo" "laengemax_ap110" 6000.0))
(princ)
)
(defun c:OMNI_APG110 ()
(omni:insert-block "APG110" (ssg-cfg-or "omniflo" "laengemax_apg110" 6000.0))
(princ)
)
;; ============================================================
;; OMNIFLO WEICHEN-DIALOG
;; Generischer Dialog fuer Weichen-Auswahl nach Winkel/Typ
+1 -2
View File
@@ -48,7 +48,7 @@ ebenfalls aktiv (Modul `KettenFoerderer.lsp`, Beschreibung in `CLAUDE.md`).
Aktiv (implementiert) sind u.a.: Kreisel, Eckrad, VarioFoerderer (Standard/Etage/
Linienzug), Gefaellestrecke, Geruest (Saeulen/Rohrabhaenger/Wandbefestigung/
Rohr-Geruest-Traeger), TRO-Marker, Connections, BTMT Be-/Entladung, Scanner/
Separator, Omniflo Boegen (APB)/TEF-Elemente/Aluprofil-Geraden (AP)/alle Weichen
Separator, Omniflo Boegen (APB)/TEF-Elemente/alle Weichen
(W90/W45/WP/WK/WKomb)/Ladeschleifen/Schwenkschienen/Fahrstrecke, Kettenfoerderer,
Export (Sivas/CSV), Werkzeuge (Block-/Text-Tools, Faehnchen + Stueckliste,
DIN-Formate, Planquadrate) und die Tests. Die frueheren Dummy-Befehle fuer ILS-Kurven
@@ -703,7 +703,6 @@ AutoLISP-Implementierung fuer alle Omniflo-Komponenten: Boegen, Weichen, Verbind
| Daten | `OMNI_LOAD`, `OMNI_INFO_BOGEN`, `OMNI_INFO_WEICHE` | JSON-Daten laden und abfragen |
| Boegen | `OMNI_APB_630_90`, `OMNI_APB_550_675`, `OMNI_APB_630_45`, `OMNI_APB_550_225`, `OMNI_APB_650_180` | Omniflo-Boegen ueber DCL-Dialog einfuegen |
| Weichen | `OMNI_W90_*`, `OMNI_W45_*`, `OMNI_WP_*`, `OMNI_WK_*`, `OMNI_WKomb_*` | Omniflo-Weichen (Einfach/Doppel/Dreiwege, Delta, Stern) |
| 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 |
| 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_STOPPER`, `OMNI_SCANNER`, `OMNI_BUERSTENBREMSE` | Implementiert |
+20 -5
View File
@@ -3,7 +3,8 @@
;;
;; Zeichnet eine Linie zwischen zwei vom Benutzer gewaehlten Punkten
;; und reiht darauf 1000 mm lange TEF-Geradenelemente
;; (data/omniflo/<DIM>/0_B10030.dxf, $INSBASE=Ursprung=Anfang des
;; (data/omniflo/<DIM>/0_B10030.dxf - Dimensionsrueckfall wie bei
;; omni:insert-dxf, $INSBASE=Ursprung=Anfang des
;; Elements, Ende bei lokal X=1000) aneinander.
;;
;; Ist die Linienlaenge kein exaktes Vielfaches von 1000 mm, wird fuer
@@ -34,13 +35,27 @@
(if (null *tefl-blockname*) (setq *tefl-blockname* "0_B10030"))
;; ------------------------------------------------------------
;; Pfad zur Element-DXF ermitteln (DXFM_OMNIFLO, wie omni:insert-dxf
;; in OmniModulInsert.lsp).
;; Pfad zur Element-DXF ermitteln - ueber denselben Resolver wie
;; omni:insert-dxf (omni:omniflo-datei-finden, OmniModulInsert.lsp): .dxf
;; bzw. .dwg im aktuellen Dimensionsordner, sonst Rueckfall auf den anderen
;; (2D<->3D). Das Element liegt derzeit nur in data/omniflo/2D/, ein
;; fester Pfad in DXFM_OMNIFLO (= .../3D) fand es deshalb nicht.
;; Rueckgabe: vorhandener Dateipfad; ohne Fund der erwartete .dxf-Pfad (fuer
;; die Fehlermeldung); nil nur, wenn DXFM_OMNIFLO fehlt.
;; ------------------------------------------------------------
(defun tefl-dxf-pfad ( / omniflo-pfad)
(defun tefl-dxf-pfad ( / omniflo-pfad gefunden)
(setq omniflo-pfad (getenv "DXFM_OMNIFLO"))
(if omniflo-pfad
(strcat (vl-string-translate "\\" "/" omniflo-pfad) "/" *tefl-blockname* ".dxf")
(progn
(if (null (car (atoms-family 1 '("OMNI:OMNIFLO-DATEI-FINDEN"))))
(ssg-ensure "OmniModulInsert")
)
(setq gefunden (omni:omniflo-datei-finden *tefl-blockname* omniflo-pfad))
(if gefunden
gefunden
(strcat (vl-string-translate "\\" "/" omniflo-pfad) "/" *tefl-blockname* ".dxf")
)
)
)
)
+1 -1
View File
@@ -29,7 +29,7 @@ SSG_LIB
│ └── QC Linie mit GF (auch U-Form) → QcLinieMitGf / QcLinieMitGfUForm
├── Omniflo
│ ├── Fahrstrecke / Fahrstrecken beschriften → OMNI_FAHRSTRECKE / OMNI_FAHRSTRECKE_BESCHRIFTEN
│ ├── Boegen APB110 / APB60, Aluprofil Gerade (AP60/AP110/APG110)
│ ├── Boegen APB110 / APB60
│ ├── Weichen (90/45/Parallel/22.5, Delta, Star)
│ ├── TEF Elemente (inkl. TEF Gerade auf Linie → TEF_FOERDERER_LINIE)
│ ├── Anbaugruppen (Stopper, Scanner, Buerstenbremse)
-3
View File
@@ -25,9 +25,6 @@
"text_gap": 20.0,
"default_hoehe": "2000",
"default_drehung": "0",
"laengemax_ap60": 7000.0,
"laengemax_ap110": 6000.0,
"laengemax_apg110": 6000.0,
"default_gerade_laenge": "2000",
"bogen_winkel": [180, 90, 67.5, 45, 22.5],
"weichen_winkel_90": 90,
+1 -14
View File
@@ -34,7 +34,6 @@ Literale - gleiches Schema, noch nicht auf das gemeinsame Modul umgestellt.
| [VF-Linienzug-Kette (Spec)](#5-vf-linienzug-kette-spec) | Kopf mit `spec_id`, danach `glied`/`sub` | `vsp-bau-aus-spec` (Replay durch `vf-linienzug-modus`) | `start_punkt` = Kettenanfang | `hundm05.json` |
| [VF-Linienzug (Journal)](#6-vf-linienzug-eingabe-journal) | Kopf mit `test_id`, danach `typ` = `point_abs`/`real`/`string`/... | `vfl-journal-replay-start` + `vf-linienzug-modus` | erstes `point_abs` | `linienzug_tests.json`, `hm_recformat.json` |
| [Omniflo Bogen/Weiche](#71-bogen-und-weiche) | `"type": "bogen"` / `"weiche"` + `sivasnr` | `_.INSERT` der `<sivasnr>.dxf` (Kern `omni:insert-dxf` fragt den Punkt interaktiv) | `x`,`y`, Z = `hoehe` | `omniflo_tests.json`, `omniflo_strecke_tests.json` |
| [Omniflo Gerade](#72-aluprofil-gerade) | `"type": "gerade"` + `profil` | `omni:make-gerade` | `x`,`y` -> `x_ende`,`y_ende`, Z = `hoehe` | `omniflo_strecke_tests.json` |
| [Waagrechte Foerderstrecke](#8-waagrechte-foerderstrecke-gerade---noch-ohne-bau-pfad) | `"typ": "gerade"` + `startpunkt` | **kein Bau-Pfad** (wird gemeldet und uebersprungen) | `startpunkt`, `endpunkt` | `dematic_arvato.json` |
Nicht aus JSON baubar (es gibt keine Testdaten und keinen Treiber): Eckrad,
@@ -380,18 +379,6 @@ Sivas-Nummern: `data/json/omniflo_boegen.json`, `omniflo_weichen.json`.
Treiber: `omni:test-insert` (`test_omniflo.lsp`), `omnistr:insert-bogen`
(`test_omniflo_strecke.lsp`).
### 7.2 Aluprofil-Gerade
```json
{ "seq": 1, "type": "gerade", "profil": "AP110", "laenge": 1000.0,
"x": 2000.0, "y": 0.0, "x_ende": 3000.0, "y_ende": 0.0,
"drehung": 0.0, "hoehe": 2000, "id": "0003" }
```
`profil` = `"AP60"`, `"AP110"` oder `"APG110"`. Die Gerade laeuft von
(`x`,`y`) nach (`x_ende`,`y_ende`) auf Z = `hoehe`; Laenge und Drehung folgen
aus den Punkten (`laenge` ist nur Doku). Gebaut mit `omni:make-gerade`.
---
## 8. Waagrechte Foerderstrecke (`gerade`) - noch ohne Bau-Pfad
@@ -418,7 +405,7 @@ ueberspringt sie. Passende Primitive waere `insert-hz-scaled-block-by-ks`
| `foerderer_tests.json` | Kopf `y_abstand` + 17 VF Standard | `TEST_FOERDERER` |
| `gefaellestrecke_tests.json` | Kopf + GF Modus 1/2/3 | `TEST_GEFAELLESTRECKE` |
| `omniflo_tests.json` | 27 Boegen, 80 Weichen | `TEST_OMNIFLO` |
| `omniflo_strecke_tests.json` | Streckenzug aus Geraden und Boegen | `TEST_OMNIFLO_STRECKE` |
| `omniflo_strecke_tests.json` | Streckenzug aus Boegen und Weiche | `TEST_OMNIFLO_STRECKE` |
| `linienzug_tests.json` / `_stufe2.json` | Eingabe-Journal je einer Kette | `TEST_LINIENZUG` / `TEST_LINIENZUG_STUFE2` |
| `hm_recformat.json` | 5 HundM-Ketten als Journal | `TEST_HM_RECFORMAT` |
| `hundm05.json` | 5 HundM-Ketten als Spec + Kreisel, Separatoren, Scanner, BTMT | `TEST_HUNDM05`, `VF_SPEC_BAU` |
-1
View File
@@ -91,7 +91,6 @@ Gross-/Kleinschreibung spielt an der Kommandozeile keine Rolle.
| `OMNI_LOAD` | Omniflo-Komponentendaten laden |
| `OMNI_INFO_BOGEN` / `OMNI_INFO_WEICHE` | Daten eines Bogens / einer Weiche anzeigen |
| `OMNI_APB60_90`, `OMNI_APB_630_90`, `OMNI_APB_630_45`, `OMNI_APB_550_675`, `OMNI_APB_550_225`, `OMNI_APB_650_180` | Boegen einfuegen (Dialog `omniflo_boegen.dcl`) |
| `OMNI_AP60`, `OMNI_AP110`, `OMNI_APG110` | Gerade Profile einfuegen |
| `OMNI_W90_Einfach`/`_Doppel`/`_Dreiwege` | Weichen 90 Grad (Dialog `omniflo_weichen.dcl`) |
| `OMNI_W45_Einfach`/`_Doppel`/`_Dreiwege` | Weichen 45 Grad |
| `OMNI_WP_Einfach`/`_Doppel`/`_Dreiwege` | Parallelweichen |
-3
View File
@@ -29,7 +29,6 @@ Einheiten: mm und Grad. `hz` = Fahrtrichtung in der XY-Ebene, 0 = +X,
| Separator, Scanner | `ILS_SEPARATOR_INSERT`, `ILS_SCANNER_INSERT` | - (Schleife mit `getpoint`); Kern: `ssg-ils-block-laden` + `_.INSERT` | Einzelblock | `SSG_LIB_Commands.lsp`, `ssg_core.lsp` |
| BTMT, Eingang/Ausgang | `ILS_BTMT_*`, `ILS_EINGANG_INSERT`/`ILS_AUSGANG_INSERT` | wie Separator | Einzelblock | `SSG_LIB_Commands.lsp` |
| Omniflo Bogen/Weiche/TEF | `OMNI_APB_*`, `OMNI_W*_*`, `OMNI_TEF_*` ... | `_.INSERT` der `<sivasnr>.dxf` (Kern `omni:insert-dxf` fragt den Punkt) | Einzelblock | `OmniModulInsert.lsp` |
| Omniflo Gerade | `OMNI_AP60`/`AP110`/`APG110` | `omni:make-gerade` | Compound-Block | `OmniModulInsert.lsp` |
| TEF-Foerderer-Linie | `TEF_FOERDERER_LINIE` | `tefl-insert-element` (ein Element) | Einzelbloecke | `TEFInsert.lsp` |
| Geruest (Saeule, Rohrabhaenger, Wandbefestigung) | `GERUEST`, `GERUEST_SAEULEN` ... | `geruest-block-bauen` | `GR_<id>_<ts>` | `GeruestInsert.lsp` |
| Geruest-Traeger | `GERUEST_TRAEGER` | `geruest-traeger-block-bauen` | `GR_<id>_<ts>` | `GeruestInsert.lsp` |
@@ -256,8 +255,6 @@ beantworten, nicht ungebremst: eine Rueckfrage, die Enter ablehnt, haelt
|---|---|
| `omni:insert-dxf (sivasnr-str hoehe drehung)` | `%DXFM_OMNIFLO%/<sivasnr>.dxf` einfuegen, `HOEHE`/`DREHUNG` setzen, Layer. **Einfuegepunkt per Maus** (`pause`); Rueckgabe: Einfuegepunkt oder nil |
| `omni:insert-from-entry (dlg-result)` | Dialog-Ergebnis von Bogen/Weiche -> `omni:insert-dxf` |
| `omni:make-gerade (blockname pt pt2 srcAttribs textHeight textGap textEnt)` | **skriptfaehig**: Aluprofil-Gerade `"AP60"`/`"AP110"`/`"APG110"` von `pt` nach `pt2` als Compound-Block mit Text. `srcAttribs` per `omni:read-src-attribs`, `textEnt` nil. Kein `ssg-start` - Aufrufer setzt OSMODE/ATTREQ/ATTDIA = 0. Rueckgabe: Entity |
| `omni:insert-block (blockname laengemax)` | Befehls-Kern der Geraden (fragt `pt`/`pt2` per `getpoint`) |
| `omni:ladeschleifen-dialog (profiltyp init-hoehe)` | Dialog Ladeschleife, danach `omni:insert-dxf` |
Skriptfaehig fuer Boegen/Weichen: `_.INSERT` der DXF direkt mit Punkt
-6
View File
@@ -362,8 +362,6 @@
"omni-edit-dxf-nicht-gefunden": "DXF nicht gefunden: %1",
"omni-einfuegen-info": "\n[OMNI] Einfuegen: %1 (%2)",
"omni-fehler-dxf-nicht-gefunden": "\n[OMNI] FEHLER: DXF nicht gefunden: %1",
"omni-insert-block-eingefuegt": "\n[OMNI] %1 eingefuegt. Laenge=%2 mm",
"omni-laenge-ueberschritten": "Die gewuenschte Fahrstreckenlaenge von %1 mm ueberschreitet die Maximallaenge von %2 mm des Fahrstreckenprofils.\nBitte neu definieren!",
"omni-weiche-info-breite": "\n Breite: %1",
"omni-weiche-info-kurvenrichtung": "\n KurvenRichtung: %1",
"omni-weiche-info-kurvenwinkel": "\n KurvenWinkel: %1",
@@ -537,7 +535,6 @@
"omni-abbruch-ladeschleife": "\n[LADESCHLEIFE] Abgebrochen.",
"omni-ladeschleife-dialog-ladefehler": "Ladeschleifen-Dialog konnte nicht geladen werden.",
"omni-ladeschleife-keine-gefunden": "Keine Ladeschleifen%1 gefunden.",
"omni-abbruch-omni": "\n[OMNI] Abgebrochen.",
"omni-abbruch-weiche": "\n[WEICHE] Abgebrochen.",
"omni-bogen-dialog-ladefehler": "Bogen-Dialog konnte nicht geladen werden.",
"omni-edit-kein-block": "Kein Block ausgewaehlt!",
@@ -547,10 +544,7 @@
"omni-fehler-dxfm-omniflo": "\n[OMNI] FEHLER: DXFM_OMNIFLO nicht gesetzt!",
"omni-info-bogen-prompt": "\nSivasId des Bogens eingeben: ",
"omni-info-weiche-prompt": "\nSivasId der Weiche eingeben: ",
"omni-insert-keine-attribute": "\n[OMNI] Keine Attribute im Quell-Block gefunden.",
"omni-prompt-drehwinkel": "\nDrehwinkel angeben: ",
"omni-prompt-einfuegepunkt": "\nEinfuegepunkt waehlen: ",
"omni-prompt-endpunkt-fahrstrecke": "\nEndpunkt der Fahrstrecke waehlen: ",
"omni-weiche-dialog-ladefehler": "Weichen-Dialog konnte nicht geladen werden.",
"prompt-wahl-1-2-3-4": "\nIhre Wahl (1/2/3/4) [1]: ",
"vfc-alert-keine-gueltige-linie": "Keine gueltige Linie ausgewaehlt!",
-6
View File
@@ -362,8 +362,6 @@
"omni-edit-dxf-nicht-gefunden": "DXF not found: %1",
"omni-einfuegen-info": "\n[OMNI] Inserting: %1 (%2)",
"omni-fehler-dxf-nicht-gefunden": "\n[OMNI] ERROR: DXF not found: %1",
"omni-insert-block-eingefuegt": "\n[OMNI] %1 inserted. Length=%2 mm",
"omni-laenge-ueberschritten": "The requested travel path length of %1 mm exceeds the maximum length of %2 mm of the travel path profile.\nPlease redefine!",
"omni-weiche-info-breite": "\n Width: %1",
"omni-weiche-info-kurvenrichtung": "\n Curve direction:%1",
"omni-weiche-info-kurvenwinkel": "\n Curve angle: %1",
@@ -537,7 +535,6 @@
"omni-abbruch-ladeschleife": "\n[LOADING LOOP] Cancelled.",
"omni-ladeschleife-dialog-ladefehler": "Loading loop dialog could not be loaded.",
"omni-ladeschleife-keine-gefunden": "No loading loops%1 found.",
"omni-abbruch-omni": "\n[OMNI] Cancelled.",
"omni-abbruch-weiche": "\n[SWITCH] Cancelled.",
"omni-bogen-dialog-ladefehler": "Arc dialog could not be loaded.",
"omni-edit-kein-block": "No block selected!",
@@ -547,10 +544,7 @@
"omni-fehler-dxfm-omniflo": "\n[OMNI] ERROR: DXFM_OMNIFLO not set!",
"omni-info-bogen-prompt": "\nEnter Sivas ID of the arc: ",
"omni-info-weiche-prompt": "\nEnter Sivas ID of the switch: ",
"omni-insert-keine-attribute": "\n[OMNI] No attributes found on source block.",
"omni-prompt-drehwinkel": "\nSpecify rotation angle: ",
"omni-prompt-einfuegepunkt": "\nSelect insertion point: ",
"omni-prompt-endpunkt-fahrstrecke": "\nSelect end point of the travel path: ",
"omni-weiche-dialog-ladefehler": "Switch dialog could not be loaded.",
"prompt-wahl-1-2-3-4": "\nYour choice (1/2/3/4) [1]: ",
"vfc-alert-keine-gueltige-linie": "No valid line selected!",
-40
View File
@@ -212,24 +212,6 @@
<Command>^C^C(ssg-ensure "OmniModulInsert") OMNI_APB60_90</Command>
</Macro>
</MenuMacro>
<MenuMacro UID="MM_00052">
<Macro>
<Name>AP 60</Name>
<Command>^C^C(ssg-ensure "OmniModulInsert") OMNI_AP60</Command>
</Macro>
</MenuMacro>
<MenuMacro UID="MM_00053">
<Macro>
<Name>AP 110</Name>
<Command>^C^C(ssg-ensure "OmniModulInsert") OMNI_AP110</Command>
</Macro>
</MenuMacro>
<MenuMacro UID="MM_00054">
<Macro>
<Name>APG 110</Name>
<Command>^C^C(ssg-ensure "OmniModulInsert") OMNI_APG110</Command>
</Macro>
</MenuMacro>
<MenuMacro UID="MM_00056">
<Macro>
<Name>Einfach 90</Name>
@@ -1211,7 +1193,6 @@
<PopMenuItem IsSeparator="true"/>
<PopMenuRef pUID="PM_00043"/>
<PopMenuRef pUID="PM_00049"/>
<PopMenuRef pUID="PM_00051"/>
<PopMenuRef pUID="PM_00055"/>
<PopMenuRef pUID="PM_00075"/>
<PopMenuRef pUID="PM_00084"/>
@@ -1279,27 +1260,6 @@
</MenuItem>
</PopMenuItem>
</PopMenu>
<PopMenu UID="PM_00051">
<Name>Aluprofil Gerade</Name>
<PopMenuItem>
<NameRef>AP 60</NameRef>
<MenuItem>
<MacroRef MenuMacroID="MM_00052"/>
</MenuItem>
</PopMenuItem>
<PopMenuItem>
<NameRef>AP 110</NameRef>
<MenuItem>
<MacroRef MenuMacroID="MM_00053"/>
</MenuItem>
</PopMenuItem>
<PopMenuItem>
<NameRef>APG 110</NameRef>
<MenuItem>
<MacroRef MenuMacroID="MM_00054"/>
</MenuItem>
</PopMenuItem>
</PopMenu>
<PopMenu UID="PM_00055">
<Name>Weichen</Name>
<PopMenuItem>
-4
View File
@@ -48,10 +48,6 @@
[<-180 ]^C^C(ssg-ensure "OmniModulInsert") OMNI_APB_650_180
[->Boegen APB60]
[<-90]^C^C(ssg-ensure "OmniModulInsert") OMNI_APB60_90
[->Aluprofil Gerade]
[AP 60]^C^C(ssg-ensure "OmniModulInsert") OMNI_AP60
[AP 110]^C^C(ssg-ensure "OmniModulInsert") OMNI_AP110
[<-APG 110]^C^C(ssg-ensure "OmniModulInsert") OMNI_APG110
[->Weichen]
[Einfach 90]^C^C(ssg-ensure "OmniModulInsert") OMNI_W90_Einfach
[Doppel 90]^C^C(ssg-ensure "OmniModulInsert") OMNI_W90_Doppel
+3 -4
View File
@@ -338,7 +338,7 @@ tests/
testdata/
kreisel_tests.json # Testfall-Definitionen fuer Kreisel
omniflo_tests.json # Testfall-Definitionen fuer Omniflo
omniflo_strecke_tests.json # Streckenzug: 4 Geraden + 2 Boegen + 1 Weiche (7 Elemente)
omniflo_strecke_tests.json # Streckenzug: 2 Boegen + 1 Weiche (3 Elemente)
hm_recformat.json # Aufzeichnung: rohes Journal der 5 Ketten
hundm05.json # daraus abgeleitete Spec (wird erweitert)
foerderer_tests.json / mubea.json / ...
@@ -707,14 +707,13 @@ def <modul>_ref_dxf():
### test_omniflo_strecke.py
Streckenzug **4 Geraden -> 180-Grad-Kurve (4x 45-Grad-Bogen) -> 4 Geraden**.
Streckenzug aus **2 Boegen + 1 Weiche**.
Die Geometrie wird ohne BricsCAD direkt aus `omniflo_strecke_tests.json` geprueft.
| Klasse | Prueft |
|---|---|
| `TestStreckeStruktur` | 4+4+4 = 12 Elemente, Reihenfolge der Gruppen, Typen |
| `TestStreckeStruktur` | 3 Elemente, Gruppenverteilung, Typen |
| `TestStreckeKatalog` | Bogen-SivasNummern existieren in `omniflo_boegen.json` (Radius/Winkel) |
| `TestStreckeGeometrie` | Lueckenlose Verkettung, Kurvensumme 180 Grad, gemeinsamer Bogen-Mittelpunkt |
| `TestStreckeResults` | omniflo_strecke_results.json aus BricsCAD: Elemente vollstaendig, Status OK |
## Umgebungsvariablen
+14 -81
View File
@@ -3,20 +3,12 @@
;;
;; Baut aus tests/testdata/omniflo_strecke_tests.json einen verketteten
;; Streckenzug auf:
;; 4 Geraden -> 180-Grad-Kurve (4x 45-Grad-Bogen) -> 4 Geraden
;; 2 Boegen + 1 Weiche
;;
;; Jedes Element traegt bereits seine absolute Platzierung (x, y, drehung)
;; sowie Endpunkt (x_ende, y_ende). Die Elemente sind lueckenlos verkettet
;; (Ende[i] = Anfang[i+1]), sodass eine durchgehende U-foermige Strecke
;; entsteht.
;; Jedes Element traegt bereits seine absolute Platzierung (x, y, drehung).
;;
;; - Boegen (type "bogen"): DXF aus DXFM_OMNIFLO an (x,y) mit Drehung
;; einfuegen (wie test_omniflo.lsp).
;; - Geraden (type "gerade"): echter Aluprofil-Block ueber den skript-
;; faehigen Kern omni:make-gerade (aus OmniModulInsert.lsp). Fehlt die
;; Quell-.dwg (kein AP110.dwg im Blockpfad), werden Ersatz-Attribute
;; verwendet, sodass dennoch ein Compound-Block (Linie + ATTDEFs) statt
;; einer nackten Linie entsteht.
;; - Boegen/Weichen (type "bogen"): DXF aus DXFM_OMNIFLO an (x,y) mit
;; Drehung einfuegen (wie test_omniflo.lsp).
;;
;; Ergebnisse -> tests/output/omniflo_strecke_results.json
;; (via omniflo_strecke:export-results, aufgerufen von SSG_RUN_ALL_TESTS
@@ -90,54 +82,6 @@
)
;; --- Gerade non-interaktiv als echten Aluprofil-Block erzeugen ---
;; Nutzt den skriptfaehigen Kern omni:make-gerade aus OmniModulInsert.lsp.
;; profil = Profiltyp (z.B. "AP110")
;; pt-anf = Anfangspunkt, pt-end = Endpunkt (bestimmen Laenge + Drehung)
;; hoehe-str / drehung-str = Attributwerte HOEHE/DREHUNG
;; Rueckgabe: Block-Entity oder nil.
(defun omnistr:build-gerade (profil pt-anf pt-end hoehe-str drehung-str /
srcAttribs textHeight textGap blockEnt)
(dbgf "omnistr:build-gerade")
(dbgmsg (strcat "profil=" (if profil profil "nil")
" hoehe=" (if hoehe-str hoehe-str "nil")
" drehung=" (if drehung-str drehung-str "nil")))
(dbgreturn
(if (null (car (atoms-family 1 '("OMNI:MAKE-GERADE"))))
(progn
;; Precondition-Fehler (Modul nicht geladen): bleibt im Fenster sichtbar
(princ "\n[TEST_OMNIFLO_STRECKE] FEHLER: omni:make-gerade nicht geladen (OmniModulInsert.lsp)!")
nil
)
(progn
(setq textHeight (ssg-cfg-or "omniflo" "text_height" 100.0))
(setq textGap (ssg-cfg-or "omniflo" "text_gap" 20.0))
;; Quell-Attribute lesen; falls keine .dwg vorhanden, Ersatz erzeugen
(setq srcAttribs (omni:read-src-attribs profil))
(if (null srcAttribs)
(progn
(dbgmsg (strcat "keine Quell-.dwg fuer " profil " - Ersatz-Attribute"))
(setq srcAttribs (list (cons "PROFILTYP" profil)
(cons "HOEHE" (if hoehe-str hoehe-str "2000"))
(cons "ID" "")))
)
)
(setvar "ATTREQ" 0)
(setvar "ATTDIA" 0)
(setq blockEnt (omni:make-gerade profil pt-anf pt-end
srcAttribs textHeight textGap nil))
(if (and blockEnt (= (cdr (assoc 0 (entget blockEnt))) "INSERT"))
(ssg-attrib-set-on blockEnt
(list (cons "HOEHE" (if hoehe-str hoehe-str "2000"))
(cons "DREHUNG" (if drehung-str drehung-str "0"))))
)
blockEnt
)
)
)
)
;; --- Ergebnis eines Streckenelements als JSON-String erzeugen ---
(defun omnistr:test-result-json (test-id seq typ description status / )
(strcat " {\n"
@@ -184,9 +128,9 @@
;; Liest omniflo_strecke_tests.json und baut den Streckenzug auf.
;; ============================================================
(defun c:TEST_OMNIFLO_STRECKE (/ tests-json-pfad elemente
idx eintrag typ sivasnr profil hoehe-str drehung-str
description x-val y-val xe-val ye-val seq
insert-pt pt-end anzahl-ok anzahl-fehler
idx eintrag typ sivasnr hoehe-str drehung-str
description x-val y-val seq
insert-pt anzahl-ok anzahl-fehler
results-list ergebnis)
(ssg-start "TEST_OMNIFLO_STRECKE"
@@ -245,22 +189,15 @@
(if (null drehung-str) (setq drehung-str "0"))
(if (numberp drehung-str) (setq drehung-str (rtos drehung-str 2 4)))
;; Anfangs- und Endpunkt lesen
(setq x-val (ssg-val eintrag "x")
y-val (ssg-val eintrag "y")
xe-val (ssg-val eintrag "x_ende")
ye-val (ssg-val eintrag "y_ende"))
(if (null x-val) (setq x-val 0.0))
(if (null y-val) (setq y-val 0.0))
(if (null xe-val) (setq xe-val x-val))
(if (null ye-val) (setq ye-val y-val))
(if (not (numberp x-val)) (setq x-val (atof x-val)))
(if (not (numberp y-val)) (setq y-val (atof y-val)))
(if (not (numberp xe-val)) (setq xe-val (atof xe-val)))
(if (not (numberp ye-val)) (setq ye-val (atof ye-val)))
;; Einfuegepunkt lesen
(setq x-val (ssg-val eintrag "x")
y-val (ssg-val eintrag "y"))
(if (null x-val) (setq x-val 0.0))
(if (null y-val) (setq y-val 0.0))
(if (not (numberp x-val)) (setq x-val (atof x-val)))
(if (not (numberp y-val)) (setq y-val (atof y-val)))
(setq insert-pt (list x-val y-val (atof hoehe-str)))
(setq pt-end (list xe-val ye-val (atof hoehe-str)))
(dbgmsg (strcat (itoa seq) ". " (if typ typ "?") ": "
(if description description "")
@@ -273,10 +210,6 @@
((= typ "bogen")
(setq sivasnr (ssg-val eintrag "sivasnr"))
(omnistr:insert-bogen sivasnr insert-pt hoehe-str drehung-str))
((= typ "gerade")
(setq profil (ssg-val eintrag "profil"))
(if (null profil) (setq profil "AP110"))
(omnistr:build-gerade profil insert-pt pt-end hoehe-str drehung-str))
(T
(dbgmsg (strcat "WARNUNG: unbekannter Typ '"
(if typ typ "nil") "'"))
+15 -57
View File
@@ -4,28 +4,25 @@
test_omniflo_strecke.py - Validiert den Omniflo-Streckenzug.
Testfall (tests/testdata/omniflo_strecke_tests.json), aktuelles Datenmodell:
7 Elemente: 2x gerade_unten (Fahrtrichtung 0 Grad), 2x gerade_oben
(Fahrtrichtung 180 Grad), 2x bogen (echte Omniflo-Boegen), 1x weiche.
3 Elemente: 2x bogen (echte Omniflo-Boegen), 1x weiche.
Prueft (ohne BricsCAD):
1. Struktur: 7 Elemente in der richtigen Gruppen-/Typ-Verteilung, seq lueckenlos
1. Struktur: 3 Elemente in der richtigen Gruppen-/Typ-Verteilung, seq lueckenlos
2. Katalog: die Bogen-SivasNummern (gruppe "bogen") existieren in
data/json/omniflo_boegen.json mit passendem Radius/Kurvenwinkel; die
Weichen-SivasNummer in data/json/omniflo_weichen.json
3. Geometrie: die Geraden haben eine zur Laenge passende Distanz Anfang->Ende
und behalten ihre Fahrtrichtung (drehung).
Hinweis: Boegen/Weichen tragen im aktuellen Testdaten-Modell KEINE Endpunkte
(x_ende/y_ende = null) und keine Mittelpunkte - die frueheren Halbkreis-/
Verkettungs-Tests (drehung_ende, x_mitte, kurve_180, 12 Elemente) bezogen sich
auf ein anderes, nicht mehr vorhandenes Modell und wurden entfernt.
auf ein anderes, nicht mehr vorhandenes Modell und wurden entfernt. Die
Aluprofil-Geraden (AP60/AP110/APG110) wurden samt Menue und Befehlen entfernt.
Optional (nach BricsCAD-Lauf c:TEST_OMNIFLO_STRECKE):
4. Integrationstest gegen tests/output/omniflo_strecke_results.json
3. Integrationstest gegen tests/output/omniflo_strecke_results.json
"""
import json
import math
import os
import pytest
@@ -103,8 +100,8 @@ def weichen_lookup():
class TestStreckeStruktur:
def test_gesamtzahl(self, strecke):
"""4 Geraden + 2 Boegen + 1 Weiche = 7 Elemente."""
assert len(strecke) == 7, f"Erwartet 7 Elemente, erhalten {len(strecke)}"
"""2 Boegen + 1 Weiche = 3 Elemente."""
assert len(strecke) == 3, f"Erwartet 3 Elemente, erhalten {len(strecke)}"
def test_seq_lueckenlos(self, strecke):
"""seq muss lueckenlos bei 1 beginnend aufsteigen."""
@@ -112,33 +109,18 @@ class TestStreckeStruktur:
assert el["seq"] == i + 1, f"Element {i}: seq={el['seq']}, erwartet {i + 1}"
def test_gruppen_verteilung(self, strecke):
"""Erwartete Gruppen-Verteilung: 2x gerade_unten, 2x gerade_oben,
2x bogen, 1x weiche."""
"""Erwartete Gruppen-Verteilung: 2x bogen, 1x weiche."""
from collections import Counter
ist = Counter(el["gruppe"] for el in strecke)
erwartet = {"gerade_unten": 2, "gerade_oben": 2, "bogen": 2, "weiche": 1}
assert dict(ist) == erwartet, f"Gruppen-Verteilung abweichend:\n Ist: {dict(ist)}\n Soll: {erwartet}"
erwartet = {"bogen": 2, "weiche": 1}
assert dict(ist) == erwartet, (
f"Gruppen-Verteilung abweichend: Ist {dict(ist)}, Soll {erwartet}")
def test_typen(self, strecke):
"""gerade_* -> type 'gerade', bogen/weiche -> type 'bogen'."""
"""bogen/weiche -> type 'bogen'."""
for el in strecke:
erwartet = "gerade" if el["gruppe"].startswith("gerade") else "bogen"
assert el["type"] == erwartet, (
f"seq {el['seq']}: type={el['type']}, erwartet {erwartet}")
def test_vier_geraden(self, strecke):
"""Vier Geraden gesamt (2 unten + 2 oben)."""
assert sum(1 for el in strecke if el["type"] == "gerade") == 4
def test_geraden_richtungen(self, strecke):
"""gerade_unten faehrt 0 Grad, gerade_oben 180 Grad (Gegenrichtung)."""
for el in strecke:
if el["gruppe"] == "gerade_unten":
assert el["drehung"] == pytest.approx(0.0, abs=_TOL), (
f"seq {el['seq']}: gerade_unten drehung={el['drehung']}, erwartet 0")
elif el["gruppe"] == "gerade_oben":
assert el["drehung"] == pytest.approx(180.0, abs=_TOL), (
f"seq {el['seq']}: gerade_oben drehung={el['drehung']}, erwartet 180")
assert el["type"] == "bogen", (
f"seq {el['seq']}: type={el['type']}, erwartet bogen")
# ---------------------------------------------------------------------------
@@ -174,31 +156,7 @@ class TestStreckeKatalog:
# ---------------------------------------------------------------------------
# 3. Geometrie der Geraden
# ---------------------------------------------------------------------------
class TestStreckeGeometrie:
def test_geraden_laenge(self, strecke):
"""Die euklidische Distanz Anfang->Ende entspricht der Laenge."""
for el in strecke:
if el["type"] != "gerade":
continue
dist = math.hypot(el["x_ende"] - el["x"], el["y_ende"] - el["y"])
assert dist == pytest.approx(el["laenge"], abs=0.5), (
f"seq {el['seq']}: Distanz {dist:.2f} != Laenge {el['laenge']}")
def test_geraden_haben_endpunkt(self, strecke):
"""Geraden tragen einen Endpunkt (x_ende/y_ende gesetzt)."""
for el in strecke:
if el["type"] != "gerade":
continue
assert el.get("x_ende") is not None and el.get("y_ende") is not None, (
f"seq {el['seq']}: Gerade ohne Endpunkt")
# ---------------------------------------------------------------------------
# 4. Integrationstest gegen BricsCAD-Ergebnis (optional)
# 3. Integrationstest gegen BricsCAD-Ergebnis (optional)
# ---------------------------------------------------------------------------
class TestStreckeResults:
+2 -62
View File
@@ -1,66 +1,6 @@
[
{
"seq": 1,
"gruppe": "gerade_unten",
"type": "gerade",
"profil": "AP110",
"laenge": 1000.0,
"x": 2000.0,
"y": 0.0,
"drehung": 0.0,
"x_ende": 3000.0,
"y_ende": 0.0,
"hoehe": 2000,
"id": "0003",
"description": "Gerade AP110 L=1000"
},
{
"seq": 2,
"gruppe": "gerade_unten",
"type": "gerade",
"profil": "AP110",
"laenge": 1000.0,
"x": 3000.0,
"y": 0.0,
"drehung": 0.0,
"x_ende": 4000.0,
"y_ende": 0.0,
"hoehe": 2000,
"id": "0004",
"description": "Gerade AP110 L=1000"
},
{
"seq": 3,
"gruppe": "gerade_oben",
"type": "gerade",
"profil": "AP110",
"laenge": 1000.0,
"x": 4000.0,
"y": 990.34,
"drehung": 180.0,
"x_ende": 3000.0,
"y_ende": 990.34,
"hoehe": 2000,
"id": "0005",
"description": "Gerade AP110 L=1000"
},
{
"seq": 4,
"gruppe": "gerade_oben",
"type": "gerade",
"profil": "AP110",
"laenge": 1000.0,
"x": 3000.0,
"y": 990.34,
"drehung": 180.0,
"x_ende": 2000.0,
"y_ende": 990.34,
"hoehe": 2000,
"id": "0006",
"description": "Gerade AP110 L=1000"
},
{
"seq": 5,
"gruppe": "bogen",
"type": "bogen",
"sivasnr": "821104022",
@@ -74,7 +14,7 @@
"description": "APB 110 R 400/90 - 500/500"
},
{
"seq": 6,
"seq": 2,
"gruppe": "bogen",
"type": "bogen",
"sivasnr": "821104022",
@@ -88,7 +28,7 @@
"description": "APB 110 R 400/90 - 500/500"
},
{
"seq": 7,
"seq": 3,
"gruppe": "weiche",
"type": "bogen",
"sivasnr": "834372100",