Drei zusammenhaengende Korrekturen am GF-Zweig mit ES-Element (Modus 1). 1) ES-Fussabdruck wurde massiv unterschaetzt (333.65 mm zu lang) Reserviert wurde (abs ein-dx) - die Block-X-Komponente aus vf-element-masse. Ein Element wird aber so gedreht eingebaut, dass sein KS_EIN auf der Fahrtrichtung liegt; beim drehenden ES_Element_30 (ein-ang=120 Grad) landet dadurch ein Teil der Block-Y-Komponente auf der Fahrtachse. Real verbraucht es laengs 576.2 mm statt der reservierten 242.6 mm - die Kette ragte um die Differenz ueber den gepickten Endpunkt hinaus (Nutzer-Befund 2026-10-09). Warum das lange unentdeckt blieb: beim ES_Element_90 ist ein-ang=0, dort ist (abs ein-dx) ZUFAELLIG richtig. Der frueher bestaetigende 90-Grad-Test konnte den Fehler strukturell nicht finden (Nutzer-Hinweis). Neu in vf_core.lsp: vf-element-laengs / vf-element-quer (hz-unabhaengige Projektion auf bzw. quer zur Fahrtrichtung), vf-set-es-masse setzt zusaetzlich ein-laengs / ein-quer. In vf_linienzug.lsp liest vfl-es-laengs den Wert mit Rueckfallkette; ein bewusst genulltes ein-dx gewinnt dabei, damit die rund zwei Dutzend Null-/Restore-Stellen keinen Doppelabzug bekommen. In BricsCAD bestaetigt: Separator+ES verbrauchen 875.83 mm gegen 875.79 mm Soll (0.04 mm), Hoehe 151.23 gegen 151.20 mm. 2) Endpunkt per Ziellinie statt per Klick Steht die Fahrtrichtung durch den Vorgaenger fest, ist die Laenge nicht mehr frei: die (um den ES-Querversatz seitlich versetzte) Bahn des ES-KS_AUS trifft eine Ziellinie in genau einem Punkt. Ein Klick kann den nur annaehern. Neue Frage mit zwei gleichwertigen Optionen (Radio-Buttons im Wizard-Modus): Ziellinie durch ZWEI PUNKTE zeichnen - Schnittpunkt wird gerechnet - oder wie bisher einen Punkt waehlen. REIN PLANAR: die Hoehe kommt weiterhin aus dem Gefaellewinkel, die Ziellinie bestimmt nur X/Y (Nutzer-Praezisierung). Beide Wege schreiben denselben einzelnen "DL"-Journaleintrag - Replay, Doppelklick-Edit und 2D/3D-Konvertierung muessen von Ziellinien nichts wissen. Die Bindung an die Linie besteht nur beim Bauen: wird die Linie spaeter verschoben, folgt die Kette NICHT. Abwaertskompatibilitaet: die neue Frage erzeugt einen zusaetzlichen Journaleintrag, den aeltere Ketten nicht haben. vfl-replay-peek-art sieht beim Replay nach, was tatsaechlich ansteht; steht dort ein "DL", ist es ein Altbestand und die Frage entfaellt - sonst haette sie den Laengenwert als Antwort verschluckt (Queue-Desync). 3) Bedienung: Achsenzwang und ruhige Ansicht vfl-getpoint-achse zwingt den Cursor beim Picken auf die Anschlussachse (SNAPANG + ORTHOMODE, kein BKS-Wechsel - getpoint liefert daher unveraenderte Koordinaten). Nur die horizontale Richtung wird erzwungen, die Hoehe bleibt frei. vfl-view-refresh zoomte vor JEDER Laengeneingabe hart auf _Extents - die Ansicht sprang bei grossen Anlagen nach jedem Klick weg. Jetzt wird nur noch eingegriffen, wenn der Baupunkt aus dem sichtbaren Ausschnitt laeuft, und dann per _ZOOM _Center unter Beibehaltung der Zoomstufe. 13 neue Unit-Tests (etage-laengs/-quer, vfl-es-laengs, vfl-kreuz2, vfl-laenge-bis-ziellinie inkl. Realfall aus dem BricsCAD-Log), Suite 533/533 gruen. lang-Paritaet geprueft. Offen und bewusst nicht angefasst: vfl-winkel-machbar-p nutzt aus-dx/ein-dx ebenfalls als Laengsmass und hat damit denselben Fehler (AS_30: 276 mm, ES_30: 334 mm). Der saubere Fix fuellt ein-dx/aus-dx an der Quelle mit dem Laengswert - das beruehrt rund 87 Fundstellen samt ihrer Null-/Restore- Konvention und gehoert separat getestet. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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-Reihenfolge (muss vor den Feature-Modulen
stehen): ssg_core, ssg_lang, ssg_dbg, ssg_dialog, ssg_layer, ssg_id,
ssg_ks_insert (Letzteres wird von Gefaellestrecke UND VarioFoerderer genutzt).
Details: siehe ../CLAUDE.md Abschnitt "Lademechanismus".
Manuell laden (Notfall / Entwicklung, z.B. fuer .scr-Testskripte):
(load (strcat (getenv "DXFMAKRO") "/Lisp/ssg_load.lsp"))
ssg_load.lsp ist der Headless-Loader (genutzt von tests/test_unit.scr u.ae.)
und laedt dieselbe Kern-Reihenfolge wie SSG_LIB.mnl, 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 |
|---|---|---|
| Omniflo ▸ Anbaugruppen | OMNI_KettenFoerderer |
OmniModulInsert.lsp |
| Omniflo ▸ Verbinder | alle OMNI_TV_* (18) |
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 |
| Geruest | GERUEST (Gattertraeger-Platzhalter, derselbe Befehl wie Saeulen/Rohrabhaenger/Wandbefestigung) |
GeruestInsert.lsp |
OMNI_TEF_* (UmlenkR/L, AntriebL/R, TEF Gerade) sind entgegen frueherem Stand
implementiert (echtes omni:insert-dxf), nur OMNI_KettenFoerderer ist
weiterhin Dummy.
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 (W90/W45/WP/WK/WKomb)/Ladeschleifen, Export (Sivas/CSV), Werkzeuge (Block-/ Text-Tools, Planquadrate) 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/plan/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
FOERDERANLAGE → linienzug 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 2–3) |
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_input.lsp – Generische Eingabe-Wrapper
Abfragen mit Vorgabewert (<..> im Prompt, Enter = Vorgabe). Steht neben den VF-spezifischen vfl-in-* (vf_linienzug.lsp); diese bleiben unveraendert. Kein Journal, aber ein optionaler Hook. ESC bricht wie ueblich ueber *error* ab.
| Funktion | Beschreibung |
|---|---|
ssg-in-real text default |
Reelle Zahl (getreal), Vorgabe ohne ueberfluessige Nullen angezeigt |
ssg-in-int text default |
Ganzzahl (getint) |
ssg-in-string text default |
String mit Leerzeichen; Enter ohne Eingabe liefert die Vorgabe (ohne Vorgabe nil) |
ssg-in-point text default base |
Punkt, base = Gummiband-Basispunkt oder nil |
ssg-in-dist text default base |
Abstand (getdist) |
ssg-in-keyword text schluessel default |
Schluesselwort im initget-Format, z.B. "Alle Auswahl" |
ssg-in-yesno text default |
Ja/Nein, T = Ja; default T = Enter bedeutet Ja. Woerter aus ssg-text "in-yesno-keys" |
ssg-in-default wert default, ssg-in-fmt-real, ssg-in-fmt-pt, ssg-in-prompt, ssg-in-first-word, ssg-in-second-word |
Reine Hilfsfunktionen (in tests/test_unit.lsp getestet) |
Hook (z.B. fuer ein Eingabe-Journal): (setq *ssg-in-hook* 'meine-funktion) mit (defun meine-funktion (art prompt wert) ...); art ist "REAL", "INT", "STRING", "POINT", "DIST", "KEYWORD" oder "YESNO". Ein Hook, der einen Fehler wirft, wird abgeschaltet.
ssg_id.lsp – Eindeutige Block-IDs
Jedes exportierbare Element bekommt ein Attribut ID mit einer eindeutigen,
vierstelligen Nummer. Kern-Modul (nach ssg_layer, vor ssg_ks_insert).
| Befehl / Funktion | Beschreibung |
|---|---|
c:IDGENERATE |
Weist dem zuletzt eingefuegten Block eine neue ID zu |
c:IDSCHECK |
Prueft alle Bloecke auf doppelte IDs und korrigiert sie |
ssg-id-format n |
Zahl als 4-stelligen String formatieren (1 → "0001") |
ssg-id-max |
Hoechste bereits vergebene ID in der Zeichnung |
ssg-id-generate ent |
Neue ID erzeugen und auf den Block setzen |
ssg-id-check-all |
Zeichnungsweit auf Doubletten pruefen und korrigieren |
ssg-id-collect-blocks |
Alle ID-faehigen INSERT-Entities sammeln (gleiche Muster wie csv:collect-export-blocks, inkl. Separator/Scanner/BTMT) |
ssg_ks_insert.lsp – KS-Extraktion und Block-Einfuegeprimitiven
Gemeinsame Basis fuer VarioFoerderer (vf_core.lsp) UND Gefaellestrecke –
frueher in beiden Modulen dupliziert, jetzt einzige Quelle. Muss laut MNL vor
Gefaellestrecke/vf_core geladen sein; Kern-Modul.
| Funktion | Beschreibung |
|---|---|
vec-length v |
Laenge eines 3er-Vektors |
ks-line-axis laenge |
Achsenkennung (X/Y/Z) aus Linienlaenge der KS-Hilfslinie |
ks-normalize-name nm |
Historische KS-Blocknamen (KSYS_EIN/-AUS) auf KS_EIN/KS_AUS normalisieren |
ks-relativize / ks-absolutize |
KS-Punkte zwischen relativem und Welt-Koordinatensystem umrechnen |
ensure-block-loaded name |
Block aus der Bibliothek einmalig ins aktive Dokument laden |
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-inclined-scaled-block / insert-rotated-block-with-ks |
Geneigten/rotierten Block mit KS-Offset einfuegen (Rz*Ry) |
ssg_blocktools.lsp – Block-Werkzeuge
Ursprung: ACADSST TOOLS.LSP (BLKANZAHL, BLKENTF), DINGEN2 (g-bli), ssg.lsp (suchen-aendern). Arbeitet im aktuellen Layout-Reiter. Blocknamen werden ueber den wirksamen Namen verglichen (dynamische Bloecke); Muster mit wcmatch (*, ?, #, ohne Gross-/Kleinschreibung).
| Befehl | Beschreibung |
|---|---|
SSG_BLOCK_COUNT |
Block anklicken, Name fuer ein Muster, oder Enter fuer eine Statistik aller Bloecke |
SSG_BLOCK_DELETE |
Alle Einfuegungen eines Blocks/Musters loeschen; Rueckfrage (Vorgabe Nein), Einfuegungen auf gesperrten Layern bleiben stehen; eine Undo-Gruppe |
SSG_ATTR_ERSETZEN |
Attributwerte suchen/ersetzen: Bereich (Alle mit Blockname-Muster / Auswahl), Tag-Muster, Suchtext, Ersatz, Modus Teil (Teilstring) oder Gesamt (ganzer Wert). Zeigt vorab die Anzahl und fragt nach |
| Funktion | Beschreibung |
|---|---|
ssg-bt-inserts muster |
Entity-Liste aller Einfuegungen im Layout (optional nach Muster) |
ssg-bt-statistik muster |
((NAME . ANZAHL) ...) alphabetisch |
ssg-bt-attr-ersetzen-ent ent tag suche ersatz teil-p probe-p |
Attribute EINER Einfuegung ersetzen bzw. nur zaehlen (probe-p); Rueckgabe Anzahl |
ssg-bt-attr-ersetzen-liste ents tag suche ersatz teil-p probe-p |
Dasselbe fuer eine Entity-Liste |
ssg-bt-wert-neu wert suche ersatz teil-p |
Reiner Kern: neuer Wert oder nil (unveraendert); beachtet Gross-/Kleinschreibung |
ssg-bt-name-passt-p, ssg-bt-zaehle-namen, ssg-bt-muster-escape |
Reine Hilfsfunktionen (getestet) |
ssg_texttools.lsp – Text-Werkzeuge
Ursprung: ACADSST CHGTEXT.LSP, PARTEXT.LSP, ALTHOEHE.LSP, ALTSTIL.LSP. Laden nach ssg_blocktools (nutzt ssg-bt-wert-neu und ssg-bt-attr-ersetzen-liste). Arbeitet in der XY-Ebene des Welt-KS.
| Befehl | Beschreibung |
|---|---|
SSG_TEXT_ERSETZEN |
Suchen/Ersetzen in TEXT, MTEXT und Block-Attributen; Bereich Alle (Layout) oder Auswahl; Vorschau mit Anzahl, Rueckfrage |
SSG_TEXT_PARALLEL |
Linie/Polylinie/Bogen anklicken, Text wird parallel (lesbar, nie auf dem Kopf) mit Abstand gesetzt; Hoehe, Abstand und letzter Text werden fuer die Sitzung gemerkt; Enter beendet |
SSG_TEXT_HOEHE |
Texthoehe gewaehlter TEXT/MTEXT aendern |
SSG_TEXT_STIL |
Textstil gewaehlter TEXT/MTEXT aendern (Stil muss existieren) |
Reine Kerne (getestet): ssg-tt-lesbarer-winkel (Winkel 90 Grad bis 270 Grad um 180 Grad drehen, Ergebnis in [0, 2 pi)), ssg-tt-versetzt.
Nicht uebernommen aus Walz: Export/Import von Texten (besser per Python/ezdxf), KREISTXT, TXTBOXED, CHTEXT/ASCTEXT/PTEXT (Autodesk 1990, durch BricsCAD-Standard ersetzt).
ssg_load.lsp – Laderoutine
Headless-Loader fuer .scr-Testskripte (z.B. tests/test_unit.scr). Laedt alle
Kern- und Feature-Module in derselben Reihenfolge wie SSG_LIB.mnl, ohne
Menueabhaengigkeit. 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 (Wrapper)
Kompatibilitäts-Wrapper, der vf_core.lsp lädt (Plugin-Dispatcher-Architektur
über *vf-typ-registry*; lädt seinerseits vf_konstanten.lsp, vf_standard.lsp,
vf_etage.lsp, vf_linienzug.lsp, danach vf_spec.lsp). Parametrischer Generator
für ILS Vario-Förderanlagen (Typen Standard/Etage/Linienzug). Liest Block-Geometrie
aus einer DWG-Bibliothek (DXFM_BLOCKS) über die Primitiven aus ssg_ks_insert.lsp.
Alle Konstanten (Abstände, Winkel, Skalierung) werden über ssg-cfg-or
(component_defaults.json, Sektion vario) bzw. die zentralen *vfk-*-Konstanten
aus vf_konstanten.lsp gelesen.
Befehl: c:FOERDERANLAGE / c:VarioFoerderer – wählt zuerst den Anlagen-Typ (Standard/Etage/Linienzug):
- Typ „standard“ und „etage“ + Werteingabe: laufen über denselben,
typ-parametrisierten Dialog-Ablauf (
vf-dialog-ablaufinvf_core.lsp;vfs-standard-dialog-ablauf/vfe-etage-dialog-ablaufsind nur noch duenne Wrapper darauf) mit den Dialogenvfs-dialog-eingabe-basis/vfs-dialog-winkel-verteilung(dcl/variofoerderer.dcl): Dialog 1 erfasst deltaL, Förderrichtung, Einfügehöhe/deltaH, Fahrtrichtung und Seite/Motorseite; Dialog 2 lässt Winkel und L_GF-Verteilung (vorne/hinten) wählen. Startpunkt (X/Y) wird vorher in der Zeichnung gepickt. - Typ „standard“/„etage“ + 3D-Linie laufen ueber denselben Basis-Dialog statt rein interaktiv auf der Konsole.
- Typ „linienzug“ (Streckengruppe,
vf-linienzug-modusinvf_linienzug.lsp) hat drei Modi (manuell/Wizard, 3D-Objekte+Zielhoehe, Vorwaerts-Nachbau) und zeichnet jede Eingabe in einem Journal auf (XDATASSG_VF_EDITamVF_n-Block); Standard laeuft per Default ueber DCL-Dialoge (VF_WIZARD_AN/VF_WIZARD_AUSschalten um). Details, Journal-Format, Headless-Modus (*vfl-headless*) und Spec-basierter Bau ohne Dialog (vf_spec.lsp,VF_SPEC_BAU): siehe../doc/variofoerderer.mdund../CLAUDE.md.
Bearbeiten (c:VARIOFOERDERER_EDIT): Doppelklick auf einen VF_n-Block – bzw.
Rechtsklick-Kontextmenü/SSG_BLOCKEDIT – dispatcht per XDATA-Marker
("standard"/"etage"/"linienzug") in den passenden Neuaufbau-Zweig
(vfe-edit-ent fuer Etage, vfl-edit-ent fuer Linienzug) und öffnet dieselben
Dialoge, vorbelegt mit den aktuellen Parametern; der Block wird am selben
Startpunkt neu aufgebaut (neue VF_n-Nummer). Altbestand-Blöcke ohne
Marker werden mit einer Meldung abgewiesen, statt sie zu verändern. Winkel und
L_GF1 werden aus den Sivas-Attributen (VF_WINKEL, L_GF_m) vorbelegt.
Die Block-Einfuege-Primitiven (ensure-block-loaded, insert-block-by-ks,
insert-inclined-scaled-block, insert-rotated-block-with-ks u.a.) sind seit
der Konsolidierung zentral in ssg_ks_insert.lsp
definiert (von vf_core.lsp, Gefaellestrecke.lsp und TEFInsert.lsp genutzt).
Weitere interne Helfer: init-bibliothek (Block-Bibliothek aus DWG laden),
get-line-start-end-points ename, punkt-differenz p1 p2.
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.dcleingeben (Δ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).
TEFInsert.lsp – TEF-Geradenstuecke entlang einer Linie
Befehl: c:TEF_FOERDERER_LINIE. Zeichnet eine Linie zwischen zwei gewaehlten
Punkten und reiht darauf 1000-mm-TEF-Geradenelemente (0_B10030 aus
DXFM_OMNIFLO) aneinander; ist die Linienlaenge kein exaktes Vielfaches,
wird ein zusaetzliches, zurueckverschobenes Element eingefuegt, sodass der
Foerderer exakt am Linienende endet (keine Luecke, kein abgeschnittenes
Element). Die Linie darf geneigt sein (3D) – Elemente werden dann analog zu
vf_core.lsp/ssg_ks_insert.lsp (Rz*Ry-Rotation) gekippt eingefuegt. Nicht
zu verwechseln mit den einzelnen OMNI_TEF_*-Befehlen in OmniModulInsert.lsp.
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). Die verpackten AS-/ES-Schleuselemente derselben Kette bekommen stattdessen einen DAUERHAFTEN Marker (csv:asmark-aktualisieren, siehe unten); beide Wege teilen sich die Platzierungsrechnung (csv:nested-welt-records + csv:block-einfuegen-welt). Reihenfolge ist wesentlich: erst ssg-id-check-all (Wrapper-IDs endgueltig), dann die Kopien/Marker (ZUORDNUNG direkt beim Erzeugen), dann csv:ketten-verarbeiten (IDs in Kettenfolge, Separator-Typ, sepliste-Stellvertreter), dann ein zweites ssg-id-check-all (Restnummerierung) |
csv:asmark-aktualisieren |
AS-/ES-Kettenenden sichtbar machen: setzt an jedes verpackte AS_Element*/ES_Element* einer VF_n/GF_n-Kette ein kleines Rechteck (Block ZZ_ASES_MARKER, Groesse aus cfg/export.cfg [Marker], Layer aus cfg/layer.cfg ases_marker), das nach dem Export stehen bleibt. Unsichtbare Attribute ID/ZUORDNUNG/TYP/LFDNR/ELEMENT/ARTINR; die ID fuellt ssg-id-check-all und der naechste Export uebernimmt sie, ein AS/ES behaelt seine TeileId also ueber Laeufe hinweg. Baut bei jedem Export alle Marker neu auf (Wiederfinden ueber ZUORDNUNG+TYP+LFDNR) und entfernt verwaiste |
csv:ketten-verarbeiten sep-proxies element-proxies asmarks |
Je VF_n/GF_n aus DERSELBEN KS-geordneten Kette (csv:kette-von, einmal je Lauf berechnet): Einheiten-Proxies (group_vf_gf), IDs in Kettenfolge, Separator-Typ VF/GF (csv:kette-sep-typen -> *cs-sep-typ-by-handle*) und der Stellvertreter jedes sepliste-Eintrags (*csv-sepliste-id-by-handle*, Key = Wrapper-Handle; csv:block-to-json liest dessen ID beim Schreiben als Feld id) |
csv:sepliste-kette-paare eintraege typen |
Zuordnung sepliste-Eintrag -> Kettenbaustein ueber die Reihenfolge je Typ (k-tes AS/SEP/ES der sepliste = k-tes der KS-Kette), ohne die (teils gespiegelten) sepliste-Koordinaten. Reine Rechenfunktion, getestet in tests/test_unit.lsp |
csv:element-familien |
EINZIGE Tabelle Familie -> Blockmuster (pattern_nested_* aus cfg/export.cfg) fuer Suche (csv:pattern-nested-element) UND Klassifizierung (csv:element-teileart, darauf aufbauend csv:kette-typ) |
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:EXPORTCSV → lib/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):
- LISP-Unit-Tests (
tests/test_unit.lsp) – prüfen reine Standardfunktionen direkt in AutoLISP, ohne Zeichnung. - 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_streckeundtest_mubea(Gesamtmodell: Kreisel + Vario + Gefällestrecken + Separatoren austests/testdata/mubea.jsonin einer Zeichnung; überSSG_RUN_ALL_TESTSbzw. 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, Parameter per DCL-Dialog (eckrad_edit.dcl; ohne GUI Konsolen-Rueckfall) |
c:EckradEdit |
Eckrad ueber DCL-Dialog bearbeiten (Bezeichnung, Hoehe, Drehung, Drehrichtung, Geruest; kein Abstand/Typ), Neuaufbau mit gleicher Nummer |
c:KREISEL_WEICHEN |
Beruehrpunkte (= ILS-Weichen) aller Kreisel/Eckraeder gleicher Hoehe ermitteln: Rad/Rad und Rad/Laufprofil auf der freien Radseite, Toleranz toleranz_beruehrung/toleranz_hoehe (component_defaults.json). Ueberschneidungen und Seite-an-Seite-Kreisel werden als Kollision gemeldet. Konsolenliste + Kreis-Marker (Layer kreisel_weiche/kreisel_kollision), ein neuer Lauf ersetzt die Marker. Derselbe Kern (kreisel-bp-ermitteln) liefert beim Export kreisel_weichen.json fuer export_csv.py/export_sivas.py |
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 |
| 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_KettenFoerderer |
Dummy (noch nicht implementiert, im Menue ausgegraut); OMNI_STOPPER/OMNI_SCANNER/OMNI_BUERSTENBREMSE sind implementiert |
| 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 |
Daneben zeichnet TEFInsert.lsp (TEF_FOERDERER_LINIE) eine
Kette von TEF-Geradenelementen (1000 mm) entlang einer frei gewaehlten Linie –
nicht zu verwechseln mit den einzelnen OMNI_TEF_*-Befehlen oben.
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_DIM → 3D, 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.
Eingang-/Ausgang-Symbol: ILS_EINGANG_INSERT/ILS_AUSGANG_INSERT nutzen
dieselbe ils-insert-station-Routine wie BTMT Be-/Entladung (frei platzierbar,
Blöcke Eingang_<DIM>.dwg/Ausgang_<DIM>.dwg in data/ils).
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 |
FOERDERANLAGEist nicht hier definiert – dieser Befehl ist inVarioFoerderer.lspimplementiert.
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 (Reihenfolge wichtig: GR_* vor dem Omniflo-Zweig, da Geruest-Bloecke ebenfalls ein TEILEART-Attribut tragen):
| Blockmuster | Aktion |
|---|---|
KREISEL_* |
KreiselEdit |
ECKRAD_* |
EckradEdit |
GF_* |
GEFAELLESTRECKE_EDIT |
VF_* |
VARIOFOERDERER_EDIT |
GR_* |
Geruest – BEDIT (kein eigener Edit-Pfad; siehe GeruestInsert.lsp) |
TRO_* |
TRO_EDIT |
| Omniflo (TEILEART-Attribut, AP110*, numerisch) | OMNI_EDIT |
| Sonstige | BEDIT (Block-Editor) |
GeruestInsert.lsp – Geruest-Baugruppen
Rohr-Geruest-Baugruppen (Saeulen, Rohrabhaenger, Wandbefestigung, Rohr-Geruest-Traeger)
aus data/json/geruest.json bzw.
data/json/geruest_traeger.json konfigurieren
und einfuegen. Die Dialogdefinition wird zur Laufzeit erzeugt
(geruest-dcl-schreiben, temporaere DCL-Datei) – es gibt keine feste
dcl/geruest.dcl, weil je Anbauteil ein eigenes Mengenfeld gebraucht wird.
Ausfuehrliche Beschreibung (Konfigurationen, Attribut-Schema, Querstreben/Muffe,
Traeger-Beschriftung): siehe ../CLAUDE.md Abschnitt "AutoLISP-Module".
| Befehl | Beschreibung |
|---|---|
c:GERUEST |
Dialog ohne Vorgabe-Bereich (Dropdown Rohrabhaenger/Saeulen/Wandbefestigung) |
c:GERUEST_SAEULEN / c:GERUEST_ROHRABHAENGER / c:GERUEST_WANDBEFESTIGUNG |
Dialog mit vorgewaehltem Bereich (derselbe Dialog wie GERUEST) |
c:GERUEST_TRAEGER |
Eigener fester Dialog (dcl/geruest_traeger.dcl): Rohr-Geruest-Traeger mit Linien-Logik (Start-/Endpunkt oder Laenge, Laengenabzuege, Querstreben/Muffe-Verteilung) |
c:GERUEST_TRAEGER_BESCHRIFTEN |
Alle Traeger der Zeichnung neu beschriften (eigenes TEXT-Objekt, verknuepft per XDATA SSG_GR_BESCHR) |
Block-Praefix GR_<id>_<timestamp> – nicht kosmetisch: SSG_BLOCKEDIT muss
GR_* vor dem Omniflo-Zweig abfangen, da Geruest-Bloecke ebenfalls ein
TEILEART-Attribut tragen. Export-Pattern pattern_geruest = GR_* (cfg/export.cfg).
Tro_Edit.lsp – TRO-Marker
TRO-Marker (Block TRO_SYM_<Typ>) fuer sps_skel/lib/tro_annotate.py.
| Befehl | Beschreibung |
|---|---|
c:TRO_INSERT |
Bestehende Blockdefinition an gewaehltem Punkt einfuegen, setzt ID/TYPE; bricht ab, wenn der Typ noch keine Blockdefinition in der Zeichnung hat (entsteht nur ueber tro_annotate.py) |
c:TRO_EDIT |
ID/TYPE eines bestehenden Markers per Dialog aendern |
Typliste kommt aus tro_types.lsp (von
tro_annotate.py --emit-lisp nach DXFM_LISP geschrieben). SSG_BLOCKEDIT
leitet Blocknamen TRO_* zu TRO_EDIT.
Connection_Edit.lsp – Verbindungen (SPS)
Verbindungslinien zwischen zwei Punkten/Bausteinen fuer SPS-Dokumentation.
| Befehl | Beschreibung |
|---|---|
c:CONNECTION_INSERT |
Verbindung zwischen zwei Punkten einfuegen (Laenge/Winkel/Mitte werden berechnet) |
c:CONNECTION_EDIT |
Bestehende Verbindung bearbeiten |
DrawPlanquadrate.lsp – Planquadrat-Raster
Zeichnet auf Z=0 ein Planquadrat-Linienraster (senkrecht/waagerecht) im
Abstand/Zaehlschema der aktiven [Planquadrate]-Konfiguration aus
cfg/export.cfg – dieselbe Quelle wie lib/export_planquadrat.py fuer den
CSV-Export. Bereich und Ursprung kommen aus der Bounding-Box derselben
Blockmenge wie EXPORTCSV (csv:collect-export-blocks), nicht aus dem reinen
Einfuegepunkt oder den Zeichnungs-Extents. Lazy geladen ueber
(ssg-ensure "DrawPlanquadrate"), nicht Teil der Core-Ladereihenfolge.
| Befehl | Beschreibung |
|---|---|
c:DRAW_PLANQUADRATE |
Raster neu aufbauen (entfernt zuerst einen evtl. vorhandenen Block) |
c:DELETE_PLANQUADRATE |
Raster-Block entfernen |
c:PLANQUADRATE_TOGGLE |
Dispatcht auf Zeichnen bzw. Loeschen, je nachdem ob der Block existiert |
Das fertige Raster (Linien + Zaehl-Texte) wird zu einem einzigen Block
ZZ_PLANQUADRATE bei (0,0,0) zusammengefasst; Layer aus cfg/layer.cfg.