Files
dxfmakros/Lisp
m.stangl 3698c8982c Sepliste-XDATA fuer Separator/AS/ES-Reihenfolge + Unit-Tests, makunbound-Fix
Sammelt beim Bau von VF_n/GF_n-Ketten die Baureihenfolge der Separator-/
AS-/ES-Sub-Bloecke vor dem Block-Sweep und schreibt sie als XDATA auf den
fertigen Wrapper (ssg_ks_insert.lsp); export.lsp liest sie fuer das neue
"sepliste"-Feld im CSV-Export, export_neighbors.py nutzt es als Fallback
zur BBox-Kollisionspruefung. Dazu Unit-Tests fuer die reinen Serialisierungs-
funktionen (Chunking, Roundtrip) in test_unit.lsp.

Ausserdem: makunbound (existiert nicht in BricsCAD-AutoLISP) aus
test_run_all.lsp entfernt - verursachte Laufzeitfehler bei
SSG_RUN_ALL_TESTS_EXPORT/_OFFEN.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-09 20:36:42 +02:00
..
2026-09-07 15:38:39 +02:00
2026-09-07 15:38:39 +02:00

Lisp AutoLISP-Bibliotheken (SSG_LIB)

AutoLISP-Routinen für BricsCAD Pro zur automatisierten Erstellung von Förderanlagen-Layouts. Destilliert aus den historischen ACADSST-Makros (Schönenberger Systeme GmbH) und erweitert für die SSG_LIB-Befehle.


Menue einrichten und Module laden

Module werden automatisch ueber SSG_LIB.mnl geladen, sobald das Menue einmalig in BricsCAD registriert wurde:

Einmalige Einrichtung (BricsCAD-Kommandozeile):

_MENULOAD   →  menu/SSG_LIB.mnu auswaehlen

BricsCAD laedt daraufhin automatisch SSG_LIB.mnl, welches alle Module per ssg-ensure initialisiert (Kern: ssg_core/lang/dbg/dialog/layer, dann alle Feature-Module). Details: siehe ../CLAUDE.md Abschnitt "Lademechanismus".

Manuell laden (Notfall / Entwicklung):

(load (strcat (getenv "DXFMAKRO") "/Lisp/ssg_load.lsp"))

ssg_load.lsp laedt alle Module in der richtigen Reihenfolge ohne Menueabhaengigkeit.


Status: noch offene Menueintraege (im Menue ausgegraut)

Die folgenden Menueintraege rufen aktuell nur eine Dummy-Funktion auf (Meldung [DUMMY], keine Geometrie). Sie sind in menu/SSG_LIB.mnu mit ~ ausgegraut und werden erst bei echter Implementierung wieder aktiviert. Der ~-Marker steht am Label-Anfang, bei Submenue-Schliessern hinter dem <- ([<-~Label]).

Menuebereich Eintraege Definiert in
ILS ▸ Foerderer Durch TEF angetriebene Strecke; Kurven 90/60/30 links/rechts angetrieben Aussen + Innen (12) SSG_LIB_Commands.lsp
ILS ▸ Gefaellestrecke Kurven 90/60/30 links/rechts Gefaellestrecke (6) SSG_LIB_Commands.lsp
Omniflo ▸ TEF Elemente UmlenkR/L, AntriebL/R, TEF Gerade, KettenFoerderer (6) OmniModulInsert.lsp
Omniflo ▸ Verbinder alle OMNI_TV_* (18) OmniModulInsert.lsp
Omniflo ▸ Boegen fuer Weichen alle OMNI_APBW_* (14) OmniModulInsert.lsp

Aktiv (implementiert) sind u.a.: Kreisel, Eckrad, VarioFoerderer, EtageVarioFoerderer, Gefaellestrecke, BTMT Be-/Entladung, Scanner/Separator, Omniflo Boegen (APB), Aluprofil-Geraden (AP), alle Weichen (W90/W45/WP/WK/WKomb), Export (Sivas/CSV) und die Tests.


Dateien

ssg_core.lsp Kernbibliothek

Grundfunktionen für Umgebungssicherung, Benutzerinteraktion, Layer, Blöcke, Attribute und JSON-Konfiguration. Muss als erstes geladen werden.

Umgebungssicherung:

Funktion Beschreibung
ssg-start titel vars Systemvariablen sichern, CMDECHO aus, Undo-Gruppe öffnen
ssg-end Systemvariablen wiederherstellen, Undo-Gruppe schließen
ssg-errhan em Fehlerhandler räumt auf und ruft ssg-end auf

Benutzer-Abfragen:

Funktion Beschreibung
ssg-ques text defa Ja/Nein-Abfrage; defa=T → Default Ja, nil → Default Nein
ssg-emsg text Fehlermeldung mit optionalem Signalton (ssg-bell)

Layer-Hilfsfunktionen:

Funktion Beschreibung
ssg-get-layer text Layer eines angeklickten Objektes ermitteln
ssg-layer-ss name typ Auswahlsatz aller Objekte eines Layers (optional nach Typ filtern)
ssg-make-layer name farbe aktiv Layer anlegen (falls nicht vorhanden) und optional aktivieren
ssg-ss-foreach ss func Iteration über Auswahlsatz func für jeden Entity-Name
ssg-ss-redraw ss modus Auswahlsatz hervorheben (3), invertieren (4) oder normal (0)
ssg-ss-add src dest Auswahlsatz src zu dest hinzufügen (in-place, mit Highlight)

Ziel-Layer je Baugruppe (cfg/layer.cfg):

Für Baugruppen, die ein Makro aus Einzelteilen zusammenbaut (KREISEL_n, ECKRAD_n, VF_n, GF_n) und für die selbst gezeichnete Hilfsgeometrie (Kreisel-Tangenten, PIN-Linien, Beschriftungstexte) gibt es keine Blockdatei in data/ und damit kein LAYER-Attribut ihr Ziel-Layer und die Layerfarbe kommen aus cfg/layer.cfg. Nur eingefügte Blöcke nehmen dagegen ihr LAYER-Attribut als Vorgabe. Alle Funktionen liefern nil, wenn nichts konfiguriert ist; der Layer bleibt dann unangetastet (kein Fehler bei fehlender cfg/layer.cfg).

Funktion Beschreibung
ssg-layer-cfg-load cfg/layer.cfg einmalig (lazy) einlesen, Rückgabe ini-Alist oder nil
ssg-layer-cfg-reset Ladezustand verwerfen (cfg in laufender Sitzung neu einlesen, Tests)
ssg-layer-cfg-eintrag ini sektion key Reine Aufl./Zerlegung "Layername, Farbe"(layer . farbe); Farbe fehlt → "7"
ssg-layer-eintrag key Ziel-Layer einer Baugruppe: [ils_<Dimension>][allgemein]nil
ssg-layer-anlegen key aktiv Layer der Baugruppe mit cfg-Farbe anlegen, optional aktivieren; Rückgabe Layername
ssg-layer-setzen ent key Blockreferenz auf den Ziel-Layer ihrer Baugruppe legen (Layer wird angelegt)
ssg-layer-farbe-fuer-name name Farbe zu einem Layernamen (Abschnitt [farben], sonst passender Baugruppen-Wert, sonst "7")
ssg-block-layer-vorgabe ent blockname attribs Layer einer nur eingefügten Referenz aus der Block-Vorgabe: LAYER-Attribut → ssg-ils-block-ebene → nichts

Die Farbe greift nur bei der Neuanlage eines Layers ssg-make-layer lässt bestehende Layer unverändert. Layer, die eine Blockdatei aus data/ils selbst mitbringt (z. B. ILS_SP), legt BricsCAD bereits beim Einfügen des Blocks mit der Farbe aus der DWG an; dort wirkt die cfg-Farbe nicht, der Layername des Wrappers aber schon.

Block-Operationen:

Funktion Beschreibung
ssg-timestamp Zeitstempel als YYYYMMDDHHMMSS-String erzeugen
ssg-make-blockname pt Eindeutigen Blocknamen aus Einfügepunkt + Zeitstempel erzeugen
ssg-insert-block layer farbe pfad pt xs ys rot Layer anlegen und Block einfügen
ssg-make-block pt rotation ss Auswahlsatz als Block definieren und gleich einfügen

ILS-Blockdateien laden (2D/3D):

Funktion Beschreibung
ssg-ils-dim-aktuell Gültige Dimension: *ssg-ils-dim*DXFM_DIM"3D"
ssg-ils-blockname[-dim] roh [dim] Effektiver Blockname mit Suffix _2D/_3D
ssg-ils-block-datei[-dim] roh [dim] Pfad zu data/ils/<blockname>.dwg (3D-Fallback)
ssg-ils-block-laden[-dim] roh [dim] Blockdefinition sicherstellen; Rückgabe = effektiver Name
ssg-block-refresh-reset roh Redefine-Sperre lösen (nil = alle Blöcke) → DWG wird neu gelesen

Jede Block-DWG wird einmal pro Zeichnung aus der Datei neu definiert (Redefine); danach greift eine Sperre (*ssg-block-refreshed*, siehe ssg-block-refreshed-p/ -set). Ohne sie las jede einzelne Element-Einfügung die DWG erneut von der Platte und regenerierte alle bereits platzierten Referenzen bei den großen 3D-Blöcken (AS_Element_90_links_3D ~52 MB) waren Tests wie TEST_MUBEA dadurch minutenlang beschäftigt. Wurde eine Block-DWG während der laufenden Sitzung geändert, hebt ssg-block-refresh-reset die Sperre auf.

Attribut-Operationen:

Funktion Beschreibung
ssg-attrib-set tag wert ersetzen Ein Attribut der letzten Einfügung setzen oder anfügen
ssg-attrib-set-many alist Mehrere Attribute der letzten Einfügung auf einmal setzen
ssg-attrib-set-on ent alist Attribute eines bestimmten INSERT-Entity setzen (nicht entlast)
ssg-attrib-read ent Alle Attribute eines INSERT-Entity als Assoziationsliste lesen
ssg-attrib-read-dwg pfad Block temporär einfügen, ATTRIBs lesen, Block wieder löschen
ssg-attrib-defaults defs Default-Attribute aus Definitionsliste ((TAG DEFAULT) ...) erzeugen
ssg-attrib-merge given defs Übergebene Attribute mit Defaults zusammenführen
ssg-attrib-make-defs defs hoehe Unsichtbare ATTDEF-Entities erzeugen (für Block-Definition)
ssg-attrib-alist-to-defs alist Assoziationsliste (TAG . Wert) in ATTDEF-Definitionsliste umwandeln
ssg-attrib-by-handle handle tag wert ersetzen Attribut eines Blocks anhand seines Entity-Handles suchen und ändern

Dialog-Hilfsfunktionen:

Funktion Beschreibung
ssg-dialog-run dcl id init-fn accept-fn Generischer DCL-Dialog: laden, initialisieren, starten, entladen

Zoom-Hilfsfunktionen:

Funktion Beschreibung
ssg-zoom-save Aktuelle View-Größe merken
ssg-zoom-restore Auf gemerkte View-Größe zurückschalten (nur wenn verändert)

JSON-Konfigurationssystem:

Liest data/json/component_defaults.json beim Laden über ssg-load-config. Die Config wird in der globalen Variable *ssg-config* gehalten.

Funktion Beschreibung
ssg-load-config Config aus $DXFM_DATA/json/component_defaults.json laden
ssg-cfg section key Wert aus Config lesen, nil wenn nicht vorhanden
ssg-cfg-or section key default Wert aus Config lesen, default als Fallback

Interne Parser-Funktionen (nicht direkt aufrufen): ssg-read-file-lines, ssg-cfg-trim, ssg-cfg-split-comma, ssg-cfg-parse-value, ssg-cfg-parse-array, ssg-cfg-parse-kv, ssg-cfg-parse-nested


ssg_lang.lsp Sprachumschaltung (Deutsch/Englisch)

Zentrale Textverwaltung fuer benutzersichtbare Meldungen. Kern-Modul, wird direkt nach ssg_core geladen. Wird schrittweise auf weitere Module ausgerollt (siehe doc/translate.md).

Funktion Beschreibung
ssg-text key Liefert Text zu key in *ssg-lang*, Fallback de_DE, dann Key selbst
ssg-textf key werte Wie ssg-text, ersetzt Platzhalter %1 %2 ... durch werte (Liste)

Sprache umschalten: Befehl SSG_SPRACHE (Menue → Konfiguration → Sprache) setzt *ssg-lang* live und persistiert via (setenv "DXFM_LANG" ...). Default ohne DXFM_LANG ist "de_DE".


ssg_dbg.lsp Debug-Logging

Dateibasiertes Debug-Log mit gepuffertem Schreiben. dbgf/dbg/dbgmsg puffern im Speicher, dbgreturn flusht auf die Platte (open/append/close).

Funktion Beschreibung
dbgopen filename envvar Debug-Datei öffnen (Verzeichnis via Umgebungsvariable, z.B. "DXFM_LOG")
dbgclose Puffer schreiben und Datei schließen
dbgon Debug-Ausgabe aktivieren
dbgoff Debug-Ausgabe deaktivieren (verhindert Dateianlage wenn vor dbgopen)
dbgf funcname Funktionseintritt loggen, Einrückung erhöhen
dbgreturn retval Funktionsaustritt loggen, Puffer flushen, Rückgabewert durchreichen
dbg varname Variable oder Wert loggen: (dbg 'x) oder (dbg wert)
dbgmsg text Freitext-Nachricht loggen
dbgp text Alias für dbgmsg
dbgflush Puffer sofort schreiben (ohne dbgreturn, z.B. in Startup-Code)

Beispiel:

(dbgopen "test.dbg" "DXFM_LOG")
(dbgf "meine-funktion")
(dbg 'x)
(dbgreturn ergebnis)   ; schreibt Puffer auf Platte
(dbgclose)

Zentrale Debug-Schalter (default je nach Schalter)

Damit dbg*-Aufrufe dauerhaft im Code stehen bleiben können, ohne im Normalbetrieb ungeplant .dbg-Dateien zu erzeugen, gibt es eine zentrale Schalter-Sammlung (*dbg-schalter*, Symbol → 0/1). Eine Routine öffnet ihre Debug-Datei nur, wenn ihr Schalter eingeschaltet ist. Unbekannte/neue Schalter gelten implizit als 0/aus; die VF-Linienzug-Schalter unten sind bewusst mit Default 1/an vorregistriert (siehe Tabelle).

Funktion Beschreibung
dbg-schalter-on name Schalter name einschalten (1)
dbg-schalter-off name Schalter name ausschalten (0)
dbg-schalter-p name T wenn eingeschaltet, sonst nil
dbg-schalter-open name filename envvar Öffnet die Datei nur wenn Schalter=1; gibt T/nil zurück
dbg-schalter-liste Alle bekannten Schalter + Zustand ausgeben

Bekannte Schalter:

Schalter Default Modul Loggt nach
"vfl-modus1" AN (1) Linienzug Modus 1 (manuelle Eingabe, vf-linienzug-modus) DXFM_LOG/vfl_modus1.dbg
"vfl-modus2" AN (1) Linienzug Modus 2 (3D-Objekte + Ziel-Höhe, vf-linienzug-modus2) DXFM_LOG/vfl_modus2.dbg
"vfl-modus3" AN (1) Linienzug Modus 3 (Vorwärts-Nachbau, vf-linienzug-modus3) DXFM_LOG/vfl_modus3.dbg

Alle drei Modi loggen automatisch jede interaktive Eingabe, weil sie durchgehend über die gemeinsamen Wrapper vfl-in-point/-string/-real/ -int/-value/-selection gehen, die zentral in vfl-journal-record protokolliert werden keine einzelne Aufrufstelle im Bau-Ablauf musste dafür angefasst werden. Da der Default AN ist, wird bei jedem Aufruf von FOERDERANLAGElinienzug ohne weiteres Zutun mitgeloggt; bei Bedarf einzeln abschaltbar mit (dbg-schalter-off "vfl-modus1") usw.

;; Standardmaessig bereits an - nur zur Kontrolle:
(dbg-schalter-liste)
;; ... FOERDERANLAGE -> linienzug -> Modus 1/2/3 durchspielen ...
;; -> Datei DXFM_LOG/vfl_modus<N>.dbg enthält Session + alle Eingaben
(dbg-schalter-off "vfl-modus1")   ; bei Bedarf einzeln abschalten

Muster in einer Routine:

(setq dbg-an (dbg-schalter-open "vfl-modus3" "vfl_modus3.dbg" "DXFM_LOG"))
(if dbg-an (dbgmsg "FRAGE: ..."))
;; ... get* ...
(if dbg-an (progn (dbgmsg "ANTWORT:") (dbg 'wert) (dbgflush)))
;; am Ende:
(if dbg-an (progn (dbgreturn ergebnis) (dbgclose)))

ssg_dialog.lsp Dialog-Pattern für Modul-Einfüge-Makros

Kapselt das wiederkehrende DCL-Muster: Dialog mit Vorschaubild, Radio-Auswahl, Block einfügen, Attribute setzen. Setzt ssg_core.lsp voraus.

Funktion Beschreibung
ssg-dia-show-slide tile lib name Vorschau-Slide im image-Tile anzeigen (Hintergrundfarbe aus Config: infrastruktur/dialog_preview_bg_color)
ssg-dia-update-preview tile idx lib liste Vorschau anhand Index-String aus Radio-/List-Tile aktualisieren
ssg-modul-dialog dcl id sel-tile start-val prev-tile lib slides extra-init extra-read Vollständiger Modul-Dialog: lädt DCL, setzt Tiles, verknüpft Vorschau, liefert gewählten Index
ssg-insert-modul layer farbe pfad attribs rotation Standardsequenz: Layer anlegen → Punkt abfragen → Block einfügen → Attribute setzen

Die Datei enthält außerdem ein auskommentiertes Template für neue c:BEFEHL-Definitionen nach dem SSG-Muster.


ssg_layer.lsp Interaktive Layer-Verwaltung

Benutzerfreundliche BricsCAD-Befehle für Layer-Operationen. Alle Befehle sichern die Umgebung über ssg-start/ssg-end. Setzt ssg_core.lsp voraus.

Hilfsfunktionen:

Funktion Beschreibung
ssg-layer-list-all Alle Layernamen als Liste
ssg-layer-info-all Alle Layer als Assoziationslisten (Name, Farbe, Linientyp, Flags)
ssg-layer-visible-p name Sichtbarkeitsstatus prüfen (T = sichtbar)
ssg-layer-safe-p name gruppe Prüfen ob Layer ausgeschaltet werden darf (nicht aktiver Layer)
ssg-layer-group name Gruppen-Kennung aus Layernamen extrahieren (Position 23)
ssg-layer-rename-group name neu Neuen Layernamen mit geänderter Gruppen-Kennung berechnen
ssg-layer-group-move alt neu Alle Objekte einer Layergruppe auf neue Gruppen-Kennung verschieben

BricsCAD-Befehle:

Befehl Beschreibung
c:SSG-LayerSet Layer des angeklickten Objektes als aktiven Layer setzen
c:SSG-LayerInfo Layer des angeklickten Objektes anzeigen
c:SSG-LayerMove Auswahlsatz auf Layer eines anderen Objektes verschieben
c:SSG-LayerCopy Auswahlsatz kopieren und Kopie auf Ziel-Layer legen
c:SSG-LayerMoveType Alle Objekte des gleichen Typs auf dem gleichen Layer verschieben
c:SSG-LayerOff Layer durch Anklicken ausschalten (Schleife bis Enter)
c:SSG-LayerFreeze Layer durch Anklicken einfrieren (Schleife bis Enter)
c:SSG-FreezeAll Alle Layer außer einem einfrieren
c:SSG-ThawAll Alle Layer auftauen
c:SSG-LayerOnAll Alle ausgeschalteten Layer einschalten
c:SSG-LayerDelete Layer mit Sicherheitsabfrage löschen (Objekte + Layer)

ssg_load.lsp Laderoutine

Lädt alle Module in der richtigen Reihenfolge. Ermittelt den Pfad automatisch über findfile. Ruft direkt nach ssg_core.lsp die Funktion ssg-load-config auf, damit die JSON-Konfiguration für alle nachfolgenden Module verfügbar ist.


VarioFoerderer.lsp Vario-Förderer

Kompatibilitäts-Wrapper, der vf_core.lsp lädt (Plugin-Dispatcher-Architektur; lädt seinerseits vf_standard.lsp, vf_etage.lsp, vf_linienzug.lsp). Parametrischer Generator für ILS Vario-Förderanlagen. Liest Block-Geometrie aus einer DWG-Bibliothek (DXFM_BLOCKS). Alle Konstanten (Abstände, Winkel, Skalierung) werden via ssg-cfg-or aus component_defaults.json (Sektion vario) gelesen.

Befehl: c:FOERDERANLAGE / c:VarioFoerderer wählt zuerst den Anlagen-Typ (Standard/Etage/Linienzug):

  • Typ „standard“ + Werteingabe: läuft über den DCL-Dialog dcl/variofoerderer.dcl (zwei Dialoge, vfs-standard-dialog-ablauf in vf_standard.lsp): Dialog 1 (vfs-dialog-eingabe-basis) erfasst deltaL, deltaH, Förderrichtung (Auf/Ab), Einfügehöhe, Fahrtrichtung und Seite; anschließend berechnet berechne-standard die gültigen Winkel-Varianten, und Dialog 2 (vfs-dialog-winkel-verteilung) lässt Winkel und L_GF-Verteilung (vorne/hinten) wählen. Startpunkt (X/Y) wird wie bei der Gefällestrecke vorher in der Zeichnung gepickt.
  • Typ „standard“ + 3D-Linie, sowie Typ „etage“ und „linienzug“ bleiben vollständig interaktiv (Kommandozeile), unverändert gegenüber dem bisherigen Ablauf.

Bearbeiten (c:VARIOFOERDERER_EDIT): Doppelklick auf einen VF_n-Block bzw. Rechtsklick-Kontextmenü/SSG_BLOCKEDIT öffnet dieselben Dialoge, vorbelegt mit den aktuellen Parametern, und baut die Strecke bei OK am selben Startpunkt neu auf (neue VF_n-Nummer). Da VF_n-Blöcke auch von Etage- und Linienzug-Anlagen erzeugt werden (deren komplexere Geometrie ein einfacher Neuaufbau zerstören würde), markiert vfs-xdata-schreiben nur per Standard-Dialog erstellte Blöcke mit XDATA (App SSG_VF_EDIT, Fahrtrichtung hz); Blöcke ohne diese Markierung weist c:VARIOFOERDERER_EDIT mit einer Meldung ab, statt sie zu verändern. Winkel und L_GF1 werden aus den Sivas-Attributen (VF_WINKEL, L_GF_m) vorbelegt (Verteilung stets als „Eigene Werte“ mit dem exakten aktuellen L_GF1).

Wichtige interne Funktionen (werden auch von Gefaellestrecke.lsp genutzt):

Funktion Beschreibung
init-bibliothek Block-Bibliothek aus DWG laden und Geometriedaten extrahieren
ensure-block-loaded name Block aus Bibliothek in aktives Dokument laden (einmalig)
insert-block-by-ks name ks-nr pt Block anhand Koordinatensystem-Punkt einfügen
insert-inclined-scaled-block name laenge winkel pt Geneigten, skalierten Block einfügen
insert-rotated-block-with-ks name rot pt Rotierten Block mit KS-Offset einfügen
get-line-start-end-points ename Start- und Endpunkt einer LINE-Entity ermitteln
punkt-differenz p1 p2 Differenzvektor zweier Punkte

Gefaellestrecke.lsp Gefällestrecken-Generator

Erzeugt eine einfache Förderanlage mit festem Gefällewinkel: AUS-Element → Staustrecke (skaliert) → Separator → EIN-Element

Setzt VarioFoerderer.lsp voraus (nutzt dessen init-bibliothek, insert-block-by-ks und weitere Hilfsfunktionen). Alle Defaults (default_delta_l, default_winkel, separator_breite) kommen aus Config-Sektion gefaelle.

Befehl: c:GEFAELLESTRECKE

Drei Modi:

  • Modus 1: Startpunkt (X/Y) picken, restliche Parameter über den DCL-Dialog dcl/gefaellestrecke.dcl eingeben (ΔL, Einfügehöhe Z, Gefällewinkel, Fahrtrichtung, AUS-/EIN-Element je Winkel 30/90 und Seite links/rechts). Die Einfügehöhe aus dem Dialog setzt die Z-Koordinate des Startpunkts.
  • Modus 2: Bestehende 3D-Linie wählen (ΔL und Fahrtrichtung werden daraus berechnet), restliche Parameter interaktiv über die Kommandozeile.
  • Modus 3: Linienzug aus LINE-/ARC-Objekten; ARC-Segmente werden durch Gefällebogen-Blöcke ersetzt, Winkel aus ΔH und Geometrie berechnet.

Dialog-Hilfsfunktionen: gf-dialog-eingabe (lädt/liest den DCL-Dialog, liefert (deltaL winkel hz-winkel as-seite es-seite einfuegehoehe as-winkel es-winkel dim geruest-einzelmodul geruest-typ) oder nil bei Abbruch) und gf-modus12-abschluss (gemeinsamer Abschluss für Modus 1+2: setzt die Element-Masse per vf-set-as-masse/vf-set-es-masse, berechnet die Staustreckenlänge, zeigt die Zusammenfassung und ruft gefaellestrecke-einfuegen).

Die AUS-/EIN-Element-Varianten (30/90 Grad, links/rechts) liegen als DWG-Blöcke AS_Element_<30|90>_<links|rechts> bzw. ES_Element_… flach in data/ils/ (Dimension im Dateinamen als Suffix _2D/_3D, aufgelöst über ssg-ils-block-datei); ihre Maße werden direkt aus dem Block gemessen (vf-element-masse), es gibt dafür keine JSON-Tabelle.

Bearbeiten (c:GEFAELLESTRECKE_EDIT): Doppelklick auf einen Gefällestrecken-Block (GF_n) bzw. Rechtsklick-Kontextmenü/SSG_BLOCKEDIT öffnet denselben DCL-Dialog, vorbelegt mit den aktuellen Parametern, und baut die Strecke bei OK am selben Startpunkt neu auf. Damit Fahrtrichtung und Element-Winkel (30/90) verlustfrei rekonstruiert werden, schreibt gefaellestrecke-einfuegen diese beim Erstellen als XDATA (App SSG_GF_EDIT, Helfer gf-xdata-schreiben/gf-xdata-lesen) auf das GF_n-INSERT bewusst nicht in den Sivas-Attributsatz, damit der Export unverändert bleibt. Ältere Blöcke ohne XDATA werden aus den Attributen vorbelegt (Fahrtrichtung 0°, Element-Winkel 90° als Vorgabe). Der Neuaufbau läuft über gf-rebuild (nicht-interaktiv, ohne Konsolen-Rückfrage).


export.lsp Export-Funktionen

Sammelt INSERT-Blöcke aus der Zeichnung und exportiert sie als JSON oder ruft Python-Skripte für den Sivas-Export auf.

Befehl / Funktion Beschreibung
c:EXPORTSIVAS Alle Blöcke als JSON sammeln und export_sivas.py aufrufen (Sivas-CSV)
c:EXPORTCSV Alle Blöcke als JSON sammeln und export_csv.py aufrufen (einfache Item-Liste, inkl. Omniflo Bogen/Weiche/Gerade und abschließender "Omniflo Sum"-Zeile)
csv:collect-export-blocks Alle INSERT-Blöcke der Zeichnung als JSON-Array sammeln
csv:run-export py-skript json-datei output-csv Python-Skript mit gesammelten Daten aufrufen; legt vorher fuer in VF_n/GF_n/KREISEL_n verpackte Separator_SP_2D/_3D-Sub-INSERTs (Sensor-Symbol; siehe ssg-collect-nested-inserts in ssg_core.lsp - NICHT der interne Staustrecke_Separator_SP-Trennsteg) je eine echte, temporaere Kopie an derselben Stelle an (csv:sep-proxies-erzeugen, Position/Drehung/Skalierung ueber alle Verschachtelungsebenen hinweg identisch zum Vorbild - kein kosmetischer Versatz mehr, der die geometrische Sensor-Zuordnung verfaelschen wuerde), damit sie ganz normal ueber ssg-id-check-all/csv:collect-export-blocks erfasst werden, und entfernt sie danach wieder (csv:sep-proxies-loeschen). Reihenfolge ist wesentlich: erst alle Kopien aus allen Wrappern erzeugen, dann ssg-id-check-all (vergibt IDs oberhalb des globalen Maximums), dann csv:sep-proxies-zuordnung-setzen
csv:sep-proxies-zuordnung-setzen proxy-liste ZUORDNUNG jeder Separator-Kopie auf die ID ihres Wrapper-Blocks setzen (ein in VF_n mit ID 0010 verpackter Separator erhaelt ZUORDNUNG 0010) und die Zuordnung ueber *cs-sep-fix-by-handle* fuer cs-zuordnung-lauf festnageln - fuer verpackte Separatoren ist der Carrier bekannt und wird nicht per Boundingbox geraten. Muss NACH ssg-id-check-all laufen, da ein frisch gebauter Wrapper vorher noch keine ID hat
csv:read-attribs ename Attribute eines INSERT als JSON-Objekt lesen
c:OMNI_UPDATE_ATTRIBS HOEHE/DREHUNG aller Omniflo-Elemente aus der Zeichnung aktualisieren

Der Omniflo-CSV-Export (Bogen/Weiche/Gerade, inkl. Merkmale-Aufbau und Sum-Zeile) läuft seit Entfernung von c:OMNI_EXPORT ausschließlich über c:EXPORTCSVlib/export_csv.py (build_bogen_merkmale, build_weiche_merkmale, build_gerade_merkmale, build_omni_sum_merkmale).

Ausgabeordner: c:EXPORTSIVAS/c:EXPORTCSV schreiben immer nach DXFM_RESULTS. TEST_EXPORT_ALL (siehe tests/test_export_all.lsp) leitet waehrend des Testlaufs stattdessen nach DXFM_TESTOUT um, über die reine Lisp-Sitzungsvariable *export-test-override* (wird von csv:run-export zusaetzlich zu DXFM_RESULTS abgefragt und danach garantiert wieder auf nil zurueckgesetzt, auch bei einem Fehler, ueber vl-catch-all-apply).

Wichtig: Der Umweg über *export-test-override* ist bewusst gewaehlt und kein (setenv "DXFM_RESULTS" ...). In BricsCAD/AutoCAD schreibt (setenv ...) nicht nur in den Windows-Prozess, sondern dauerhaft in die Profil-Registry der Anwendung der Wert überlebt damit jeden Neustart und jedes setenv.bat, bis er erneut per (setenv) überschrieben wird. Ein einziger (setenv "DXFM_RESULTS" ...)-Aufruf (z. B. ein frueherer, unvollstaendiger Testlauf) würde DXFM_RESULTS für alle künftigen Sitzungen unwiderruflich auf den Testordner umbiegen. Falls das bereits passiert ist, hilft nur ein manuelles (setenv "DXFM_RESULTS" "<richtiger Pfad>") in BricsCAD, um den Profil-Wert zu korrigieren.


tests.lsp Testbefehle

Testbefehle für die Python-Integration. Export-Funktionen wurden in export.lsp ausgelagert.

Befehl Beschreibung
c:CALLPYTHON testpycall.py via _.SHELL aufrufen und Rückgabe einlesen (Integrationstest LISP↔Python)

Tests

Zwei Test-Ebenen, beide gesteuert über bin\run_tests.bat (Details und Verzeichnisstruktur: ../tests/README.md):

  1. LISP-Unit-Tests (tests/test_unit.lsp) prüfen reine Standardfunktionen direkt in AutoLISP, ohne Zeichnung.
  2. Zeichnungsbasierte Integrationstests (tests/test_*.lsp + tests/test_*.py) erzeugen Blöcke in BricsCAD und validieren das Ergebnis anschließend mit pytest/ezdxf. Module: test_kreisel, test_foerderer, test_linienzug, test_gefaellestrecke, test_omniflo, test_omniflo_strecke und test_mubea (Gesamtmodell: Kreisel + Vario + Gefällestrecken + Separatoren aus tests/testdata/mubea.json in einer Zeichnung; über SSG_RUN_ALL_TESTS bzw. Menü „Tests → Mubea Gesamtmodell").

Welche JSON-Angaben pro Element-Typ nötig sind (abgeleitet aus den Produktions-Routinen, nicht aus den Test-Wrappern), dokumentiert ../tests/testdata/object_data.md inkl. der Unterscheidung scriptbar vs. nur-interaktiv.

LISP-Unit-Tests (test_unit.lsp)

Testen reine Hilfsfunktionen solche, die nur aus ihren Argumenten ein Ergebnis berechnen und keine Zeichnungsdatenbank, Auswahlsätze, Dialoge oder Blockdateien brauchen (String-, Zahl-, Vektor-, Listen- und Alist-Helfer). Abgedeckt werden Funktionen aus ssg_core, ssg_lang, ssg_id, vf_core, export, Gefaellestrecke, OmniModulInsert und KreiselInsert.

Aufruf über die Kommandozeile (startet BricsCAD headless):

bin\run_tests.bat --lisp

run_tests.bat --lisp löscht das alte Ergebnis, startet BricsCAD mit tests/test_unit.scr (lädt ssg_load.lsp + test_unit.lsp, ruft TEST_UNIT auf und beendet BricsCAD), gibt danach tests/output/unit_results.txt aus und liefert Exit-Code 1, wenn ein Test fehlschlägt oder kein Report entsteht.

Aufruf direkt in BricsCAD (SSG_LIB geladen):

(load (strcat (getenv "DXFMAKRO") "/tests/test_unit.lsp"))
TEST_UNIT

Aufbau eines Testfalls. test_unit.lsp enthält ein Mini-Framework: jeder Testfall ruft eine Funktion auf und vergleicht das Ergebnis gegen einen erwarteten Wert. Die Assertion-Helfer zählen Treffer/Fehler mit und schreiben je eine PASS/FAIL-Zeile:

Helfer Vergleich
tu-eq name erwartet ist exakt (equal) Strings, Ganzzahlen, Listen davon
tu-eqf name erwartet ist numerisch mit Toleranz 1e-6 Fliesskomma, auch verschachtelte Listen
tu-true name ist Ergebnis ist nicht nil
tu-nil name ist Ergebnis ist nil

Beispiel Formatierung einer ID und ein Vektor-Kreuzprodukt:

(tu-eq  "ssg-id-format/1"      "0001"          (ssg-id-format 1))
(tu-eqf "vec3-cross/x-cross-y" '(0.0 0.0 1.0)  (vec3-cross '(1.0 0.0 0.0) '(0.0 1.0 0.0)))

Die Testfälle sind in tu-tests-<modul>-Funktionen gruppiert; c:TEST_UNIT ruft alle nacheinander auf, gibt eine Zusammenfassung (Gesamt / PASS / FAIL) aus und schreibt den Report unit_results.txt mit einer abschließenden Zeile RESULT: OK bzw. RESULT: FAIL (die run_tests.bat auswertet).

Neuen Testfall ergänzen: in der passenden tu-tests-<modul>-Funktion eine tu-eq/tu-eqf/tu-true/tu-nil-Zeile hinzufügen. Für ein neues Modul eine eigene tu-tests-<modul>-Funktion anlegen und in c:TEST_UNIT aufrufen. Getestet werden sollten nur Funktionen ohne Zeichnungs-/Dialog-Umfeld alles mit ssget/entget/entmake/command/vla-*/entsel/DCL gehört in die zeichnungsbasierten Integrationstests.


KreiselInsert.lsp ILS Kreisel und Eckrad

AutoLISP-Implementierung fuer ILS Kreisel und Eckrad. Enthaelt alle Befehle fuer Einfuegen, Verbinden, Neuzeichnen und Bearbeiten.

Befehl Beschreibung
c:KreiselInsert Kreisel-Block an Punkt einfuegen (mit Dialog fuer Parameter)
c:KreiselConnect Zwei Punkte waehlen, Kreisel dazwischen einfuegen
c:KreiselRedraw Bestehenden Kreisel mit neuen Parametern neu zeichnen
c:KreiselQuick Schnelleinfuegung mit Standardwerten
c:KreiselEdit Kreisel-Attribute ueber DCL-Dialog bearbeiten
c:KreiselParams Aktuelle Kreisel-Parameter anzeigen
c:KreiselLabelSetup Schriftart, Hoehe und Farbe fuer Kreisel-Beschriftung konfigurieren
c:KreiselLabelPos Label-Offset (dx/dy) setzen
c:KreiselLabelHoehe Label-Hoehe aendern
c:ILS_Eckrad Eckrad an Tangentenpunkt einfuegen

OmniModulInsert.lsp Omniflo-Komponenten

AutoLISP-Implementierung fuer alle Omniflo-Komponenten: Boegen, Weichen, Verbinder, Transferwagen. Liest JSON-Daten aus omniflo_boegen.json und omniflo_weichen.json. Alle Konstanten via ssg-cfg-or aus Config.

Befehlsgruppe Befehle Beschreibung
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
TEF ⚠️ OMNI_TEF_UmlenkR/L, OMNI_TEF_AntriebL/R, OMNI_TEF_Gerade, OMNI_KettenFoerderer Dummy (noch nicht implementiert, im Menue ausgegraut)
Transferwagen ⚠️ OMNI_TV_* 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

SSG_LIB_Commands.lsp BTMT, Sensoren, Dummy-Befehle, Konfiguration und SSG_BLOCKEDIT

Sammeldatei fuer Menue-Befehle: teils Platzhalter fuer noch nicht implementierte Eintraege, teils bereits echte Funktionalitaet (BTMT Be-/Entladung, Sensoren, Konfiguration, Doppelklick-Dispatcher). Alle noch offenen Dummy-Menueintraege sind in menu/SSG_LIB.mnu mit ~ ausgegraut (siehe Abschnitt "Status: noch offene Menueintraege").

Sensoren einfuegen (real, ueber ils-insert-sensor → wiederholtes _.INSERT mit interaktivem Einfuegepunkt/Rotation, Blockdatei via ssg-ils-block-datei):

Befehl Block Beschreibung
ILS_SCANNER_INSERT Scanner Scanner wiederholt einfuegen (ENTER/ESC beendet)
ILS_SEPARATOR_INSERT Separator_SP Separator wiederholt einfuegen (Menue „Separator einfuegen")

BTMT Be-/Entladestation einfuegen (real, ueber ils-insert-station):

Befehl ROH-Block Datei (3D) Beschreibung
ILS_BTMT_Beladung BTMT-Beladung BTMT-Beladung_3D.dwg Beladestation wiederholt einfuegen (ENTER/ESC beendet)
ILS_BTMT_Entladung SC_Entladung SC_Entladung_3D.dwg Entladestation wiederholt einfuegen (ENTER/ESC beendet)

Ablauf je Einfuegung: Einfuegepunkt abfragen → _.INSERT mit interaktiver Drehung (pause) → Layer aus dem LAYER-Attribut bzw. der eigenen Ebene der Blockdefinition setzen (ils-block-layer-setzen, gleiche Konvention wie omni:insert-dxf/tefl-insert-element) → ssg-id-generate, falls der Block ein ID-Attribut fuehrt.

Die Blockdefinition kommt aus ssg-ils-block-laden (aktuelle Dimension *ssg-ils-dim*DXFM_DIM3D, DWG wird nur einmal pro Zeichnung gelesen); eingefuegt wird der zurueckgegebene dim-suffigierte Blockname. Fehlt die Datei der gewuenschten Dimension, greift der 3D-Fallback mit Warnung aktuell fuer BTMT-Beladung_2D.dwg; sobald diese Datei in data/ils/ liegt, wird sie im 2D-Modus ohne Codeaenderung verwendet (SC_Entladung_2D.dwg existiert bereits).

Beide Stationen werden ueber pattern_btmt_beladung/pattern_btmt_entladung (cfg/export.cfg) von ssg-id-collect-blocks (ssg_id.lsp) UND von csv:collect-export-blocks (export.lsp) erfasst und erscheinen im Sivas-/ CSV-Export als eigene TeileArt-Zeilen ("ILS 2.0 BTMT Beladung"/"ILS 2.0 BTMT Entladung" bzw. "BT - Beladung ..."/"Abwurf fuer Klammerbuegel ..."); im Sivas-Export zusaetzlich in den Summenzaehlern "Anzahl aller BTBeladung"/ "Anzahl aller Abwurfstationen" der ILS-Automation-Zeile.

Registrierte Dummy-Befehle:

Gruppe Befehle
ILS Zusatzmodule ILS_ETF_Etagenfoerderer
ILS Kurven angetrieben Aussen ILS_K90LA, ILS_K90RA, ILS_K60LA, ILS_K60RA, ILS_K30LA, ILS_K30RA
ILS Kurven angetrieben Innen ILS_K90LI, ILS_K90RI, ILS_K60LI, ILS_K60RI, ILS_K30LI, ILS_K30RI
ILS Gefaellestrecken-Kurven ILS_Gefaellestrecke

FOERDERANLAGE ist nicht hier definiert dieser Befehl ist in VarioFoerderer.lsp implementiert.

Konfigurationsbefehle (Menue → Konfiguration):

Befehl Beschreibung
SSG_DIM_SWITCH Schaltet zwischen 2D/3D-Bloecken um (setzt DXFM_DIM, DXFM_BLOCKS, DXFM_OMNIFLO)
SSG_SPRACHE Oeffnet Dialog sprache.dcl, setzt *ssg-lang* und persistiert via DXFM_LANG (siehe ssg_lang.lsp)

SSG_BLOCKEDIT Doppelklick/Kontextmenue-Dispatcher:

Erkennt den Blocktyp des selektierten INSERT-Blocks und ruft den passenden Bearbeitungsbefehl auf:

Blockmuster Aktion
KREISEL_* KreiselEdit
ECKRAD_* BEDIT (Block-Editor)
Omniflo (TEILEART-Attribut, AP110*, numerisch) OMNI_EDIT
Sonstige BEDIT (Block-Editor)