Files
dxfmakros/doc/lisp_methods.md
T

18 KiB

LISP-Routinen zum Bau einzelner Einheiten

Uebersicht ueber die LISP-Funktionen, die eine Einheit (Kreisel, Eckrad, VarioFoerderer, Gefaellestrecke, Omniflo-Element, Geruest, Einzelblock) erzeugen, mit Signatur, Parametern, Rueckgabe und Voraussetzungen.

Zu jedem Element steht der interaktive Befehl (was der Anwender aufruft) und der skriptfaehige Kern (ohne getpoint/Dialog, aus Code oder JSON aufrufbar). Das JSON-Format, mit dem die Testtreiber diese Kerne aufrufen, steht in json-input-lisp.md; alle Befehle in kommandos.md.

Einheiten: mm und Grad. hz = Fahrtrichtung in der XY-Ebene, 0 = +X, 90 = +Y. Punkte sind Listen (x y z) in Weltkoordinaten.


0. Uebersicht

Einheit Befehl Skriptfaehiger Kern Ergebnis-Block Modul
Kreisel KreiselInsert, KreiselConnect, KreiselQuick kreisel-insert-script, kreisel-connect-script KREISEL_n KreiselInsert.lsp
Eckrad ILS_Eckrad ils-eckrad-insert ECKRAD_n KreiselInsert.lsp
VF Standard StandardVarioFoerderer, FOERDERANLAGE berechne-standard + variofoerderer-einfuegen + vf-block-erstellen VF_n vf_standard.lsp, vf_core.lsp
VF Etage EtageVarioFoerderer berechne-etage + etage-foerderanlage-einfuegen + vf-block-erstellen VF_n vf_etage.lsp, vf_core.lsp
VF Linienzug LinienzugVarioFoerderer vsp-bau-aus-spec (Spec) bzw. vfl-journal-replay-start + vf-linienzug-modus VF_n vf_linienzug.lsp, vf_spec.lsp
Gefaellestrecke GEFAELLESTRECKE_EINFACH/_3DLINIE gf-rebuild bzw. gefaellestrecke-einfuegen GF_n Gefaellestrecke.lsp
Gefaellestrecke Linienzug GEFAELLESTRECKE_LINIENZUG - (nur interaktiv; Kern gf-linienzug-einfuegen braucht analysierte Segmente) GF_n Gefaellestrecke.lsp
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

1. Kreisel und Eckrad (KreiselInsert.lsp)

kreisel-insert-script (pt abstand rotation typ hoehe)

Kreisel an einem freien Punkt. Ruft draw-module auf.

Parameter Bedeutung
pt Einfuegepunkt: aeusserster Punkt der AN-Seite auf der Achse (einen Radius = 400 mm vor der Mitte des Antriebsrads)
abstand Mittenabstand Antriebsrad - Spannrad
rotation Drehung der Achse AN -> SP in Grad
typ "STANDARD" oder "PIN" (nil = "STANDARD") -> Attribut KREISELART
hoehe Einbauhoehe; nil = Z von pt, sonst *kreisel-default-hoehe*

Rueckgabe: Entity des KREISEL_n-Blocks oder nil. Setzt ssg-start/ssg-end selbst.

kreisel-connect-script (ptStart ptEnd typ hoehe)

Kreisel zwischen zwei aeussersten Punkten (AN-Seite, SP-Seite). Berechnet abstand = Distanz - *kreisel-durchmesser* (800) und rotation aus den Punkten. Rueckgabe wie oben.

draw-module (basePoint abstand rotation attribs)

Gemeinsamer Bau-Kern beider Funktionen: setzt Antriebs- und Spannstation, Tangenten, Beschriftung, fasst alles zu KREISEL_n zusammen, schreibt die Attribute (attribs = Alist, wird mit *kreisel-attrib-defs* gemischt). Direkt nur aufrufen, wenn zusaetzliche Attribute gesetzt werden muessen.

ils-eckrad-insert (pt rotation attribs)

Eckrad als Compound-Block ECKRAD_n.

Parameter Bedeutung
pt Radmitte (x y hoehe)
rotation Drehung in Grad
attribs Alist mit Ueberschreibungen, z.B. (("GERUEST_EINZELMODUL" . "1") ("GERUEST_TYP" . "Schoenenberger Geruest")); nil = Defaults

c:ILS_Eckrad berechnet die Radmitte aus Beruehrpunkt + Radius in Richtung des zweiten Klicks. Rueckgabe: Entity des Blocks.


2. VarioFoerderer Standard und Etage (vf_core.lsp, vf_standard.lsp, vf_etage.lsp)

Ablauf in drei Schritten: loesen (Winkel und Teillaengen aus den Gesamtmassen), einfuegen (Bausteine verketten), Block bilden (VF_n mit Attributen). Der Dialog-Ablauf vf-dialog-ablauf / vf-dialog-berechnen-einfuegen macht dasselbe, oeffnet aber Dialog 2 und ist darum nicht skriptfaehig.

Vorbereitung

Funktion Zweck
init-bibliothek () Bogen-, AS-/ES- und Stationsmasse aus den Bloecken lesen. Setzt *lib-initialized*. Wird von berechne-standard aufgerufen
init-bibliothek-etage () dasselbe fuer Etage, aufgerufen von berechne-etage
vf-set-as-masse (winkel seite) / vf-set-es-masse (winkel seite) AS-/ES-Masse (aus-dx/aus-dz, ein-dx/ein-dz) fuer die Variante "90"/"30" + "links"/"rechts" setzen

Loesen

Funktion Rueckgabe
berechne-standard (deltaL deltaH richtung seite) (best-winkel L_GF L_VF ergebnis-liste)
berechne-alle-winkel (deltaL deltaH richtung feste-hz schon-flach) wie oben; feste-hz nil = 1600 mm feste Horizontale, schon-flach nil
berechne-etage (deltaL deltaH richtung seite) wie oben, Etage-Geometrie (setzt die Gefaellebogen-Masse je seite)
vf-winkel-solve (...) gemeinsamer L_GF/L_VF-Solve beider Typen (intern)
  • richtung = "Auf"/"Ab", deltaH als Betrag.
  • ergebnis-liste = je Kandidatenwinkel (winkel L_GF L_VF gueltig). Kandidaten aus vario.bogen_winkel (3 ... 51). Einen bestimmten Winkel erzwingen: Eintrag mit diesem winkel aus der Liste nehmen und gueltig, L_GF > 0, L_VF > 0 pruefen (so mubea:build-vario-one).
  • L_GF wird danach auf Vorlauf L_GF1 und Nachlauf L_GF2 aufgeteilt (gleichmaessig / vorne / hinten / manuell, foerderer:split-gf).

Einfuegen

(variofoerderer-einfuegen      deltaL deltaH richtung best-winkel L_GF1 L_GF2 L_VF startpunkt seite hz)
(etage-foerderanlage-einfuegen deltaL deltaH richtung best-winkel L_GF1 L_GF2 L_VF startpunkt seite hz)

Identische Signatur (Registry-Vertrag *vf-typ-registry*). startpunkt = Lage von KS_EIN des AS-Elements, Z = Einbauhoehe am Anfang. seite = "links"/"rechts". Rueckgabe: Endpunkt (KS_AUS des ES-Elements). variofoerderer-einfuegen ist aus Teilen zusammengesetzt (vfs-as-teil, VF-Eingang/Koerper, vfs-es-teil), die auch der Linienzug nutzt.

Block bilden

(setq lastEnt (ssg-lastent-ohne-attribute))   ; VOR dem Einfuegen merken
...einfuegen...
(vf-block-erstellen anlage-typ seite (vf-next-number) n-scanner
                    hoehe-von hoehe-bis deltaH deltaL L_VF L_GF1 L_GF2
                    richtung best-winkel startpunkt lastEnt hz
                    geruest-einzelmodul geruest-typ)
(vf-edit-xdata-schreiben ent anlage-typ hz)   ; editierbar per Doppelklick
  • anlage-typ = "standard"/"etage"; hoehe-bis = +deltaH bei "Auf", -deltaH bei "Ab"; geruest-einzelmodul "0"/"1" (nil = "1"), geruest-typ einer aus *ssg-geruest-optionen*.
  • Sammelt alle Objekte seit lastEnt zum Block VF_n, setzt Layer, Attribute, ID (ssg-id-generate) und Dimension. Rueckgabe: Entity des Blocks.
  • lastEnt immer mit ssg-lastent-ohne-attribute holen, nicht mit (entlast) (siehe CLAUDE.md, ssg_core).
  • Blocknummer immer ueber vf-next-number: eine feste Nummer fuehrt bei der zweiten Anlage zu einer Rueckfrage von _.-BLOCK und einem haengenden Befehl.

3. VF-Linienzug (vf_linienzug.lsp, vf_spec.lsp)

Ketten mit Vario-Kurven, GF-Boegen und mehreren VF-Einheiten. Der Bau-Ablauf ist ein Frage-Antwort-Assistent; jede Eingabe wird journalisiert und als XDATA am VF_n-Block gespeichert. Nicht-interaktiv baut man ihn, indem man ein Journal abspielt.

Funktion Zweck
vf-linienzug-modus () Modus 1, frei zeichnend. Liest alle Eingaben ueber vfl-in-point/-string/-real/-int - aus der Replay-Queue, falls eine aktiv ist
vf-linienzug-modus2 () Modus 2, Pfad + Zielhoehe (Objektauswahl, eigenes Journal "linienzug2")
vfl-journal-replay-start (forward-journal) Journal als Antwort-Queue setzen; danach vf-linienzug-modus aufrufen
vsp-journal (spec) Spec -> Journal (nil bei Spec-Fehlern, Fehler in *vsp-fehler*)
vsp-pruefen (spec) alle Spec-Fehler sammeln
vsp-bau-aus-spec (spec) eine Kette aus einer Spec bauen (headless, Replay, Ergebnis-Record mit status, Block, prompts, glieder_soll/glieder_ist)
vsp-bau-liste (specs) mehrere Specs, je mit vl-catch-all-apply
vsp-bau-datei (datei) Spec-Datei lesen (vsp-json-laden + vsp-gruppieren) und alle Ketten bauen; das ist VF_SPEC_BAU
vsp-headless-an () / vsp-headless-aus () Headless-Rahmen: *vfl-headless*, Wizard aus, *ssg-gui-aus*, zaehlende Eingabe-Stubs

Ein Abbruch im Headless-Modus nennt die Stelle (*vfl-headless-fehler*), statt auf eine Live-Eingabe zu warten. Details zum Ablauf und zu den Journal-Regeln: variofoerderer.md, Abschnitte 5-8b.


4. Gefaellestrecke (Gefaellestrecke.lsp)

gf-rebuild (deltaL winkel hz-winkel as-seite es-seite startpunkt as-winkel es-winkel geruest-einzelmodul geruest-typ)

Der bequemste skriptfaehige Einstieg fuer Modus 1/2: setzt die AS-/ES-Masse, berechnet die Staustrecke L_stau = (deltaL - aus-dx - ein-dx - separator_breite * cos(w)) / cos(w) und ruft gefaellestrecke-einfuegen. Ohne Zusammenfassung und Rueckfrage (eigentlich fuer GEFAELLESTRECKE_EDIT gedacht).

Parameter Bedeutung
deltaL horizontale Gesamtlaenge AS + Staustrecke + Separator + ES
winkel Neigung der Staustrecke in Grad (Default im Dialog 3.0)
hz-winkel Fahrtrichtung
as-seite, es-seite "links"/"rechts"
startpunkt KS_EIN des AS-Elements, Z = Einbauhoehe oben
as-winkel, es-winkel "90"/"30" als STRING (nil = "90")
geruest-einzelmodul, geruest-typ wie beim VF

Rueckgabe: (ename deltaH deltaL) oder nil (Staustrecke <= 0.1 mm -> alert).

gefaellestrecke-einfuegen (L_stau winkel startpunkt as-seite es-seite hz deltaL-total as-winkel es-winkel geruest-einzelmodul geruest-typ)

Eigentlicher Bau: AS-Element, skalierte Staustrecke, Separator, ES-Element, Block GF_n mit Attributen, XDATA SSG_GF_EDIT und ID. Erwartet die fertige Staustreckenlaenge L_stau und passend gesetzte AS-/ES-Masse (vf-set-as-masse/vf-set-es-masse). Rueckgabe wie gf-rebuild.

Weitere

Funktion Zweck
gf-modus12-abschluss (... dialog-bestaetigt ...) Abschluss Modus 1/2 mit Zusammenfassung; fragt ohne dialog-bestaetigt = T per Konsole nach
gf-init-bibliothek () AS-/ES-Masse fuer die GF lesen
gf-linienzug-modus () Modus 3, interaktiv (Auswahl vorhandener LINE/ARC)
gf-linienzug-einfuegen (segmente grade startframe) Bau-Kern von Modus 3, erwartet die von gf-analysiere-kette aufbereiteten Segmente

Falle *lib-initialized*: gefaellestrecke-einfuegen initialisiert die GF-Masse nur, wenn *lib-initialized* nil ist - dasselbe Flag setzt init-bibliothek des VarioFoerderers. Wer in einem Lauf erst VF und dann GF baut, muss gf-init-bibliothek einmal selbst erzwingen (so mubea:ensure-gf-init in tests/test_mubea.lsp), sonst rechnet die GF mit den Vario-Massen und landet auf falscher Hoehe.


5. Einzelbloecke: Separator, Scanner, BTMT, Eingang/Ausgang

Funktion Zweck
ils-insert-sensor (fname) Befehls-Kern Separator/Scanner: fuegt in einer Schleife ein, Punkt per getpoint, Drehung per pause - nicht skriptfaehig
ils-insert-station (rohname) dasselbe fuer BTMT-Beladung, SC_Entladung, Eingang, Ausgang; setzt zusaetzlich den Layer aus dem LAYER-Attribut
ssg-ils-block-laden (blockname) Blockdefinition data/ils/<blockname>_<DIM>.dwg einmal je Zeichnung laden; Rueckgabe: effektiver Blockname mit Suffix oder nil
ssg-ils-block-datei (blockname) nur den Dateipfad aufloesen (3D-Fallback)
ssg-block-layer-vorgabe LAYER-Attribut eines eingefuegten Blocks als Ziel-Layer anwenden
ssg-id-generate (ent) eindeutige ID vergeben (nur wenn der Block ein ID-Attribut hat)

Skriptfaehig bauen (Muster aus hundm05:bau-sensor):

(setq eff (ssg-ils-block-laden "Scanner"))          ; nicht per (and ...) verketten!
(command "_.INSERT" eff (list x y z) "" "" rotation)
(while (and (> (getvar "CMDACTIVE") 0) (< n 5)) (command "") (setq n (1+ n)))
(ssg-id-generate (entlast))

ATTREQ/ATTDIA vorher auf 0 setzen. Restliche Prompts gezaehlt mit Enter beantworten, nicht ungebremst: eine Rueckfrage, die Enter ablehnt, haelt CMDACTIVE sonst dauerhaft > 0.


6. Omniflo (OmniModulInsert.lsp)

Funktion Zweck
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 (x y hoehe) und Drehung, danach ssg-attrib-set-on mit HOEHE/DREHUNG (omni:test-insert in tests/test_omniflo.lsp). Die festen TEF-/Zubehoer- Befehle (OMNI_TEF_*, OMNI_STOPPER ...) rufen omni:insert-dxf mit fester Sivas-Nummer. OMNI_TV_* und OMNI_APBW_* sind Platzhalter ohne Bau-Logik.


7. TEF-Foerderer-Linie (TEFInsert.lsp)

Funktion Zweck
c:TEF_FOERDERER_LINIE Start-/Endpunkt abfragen, Linie zeichnen, 1000-mm-TEF-Geraden (0_B10030.dxf) aneinanderreihen; das letzte Stueck wird zurueckversetzt, damit der Foerderer genau am Linienende endet
tefl-insert-element (start richtung-einheit s hz winkel) ein Element an Position s (mm ab start) entlang der Linie, Rz(hz)*Ry(winkel)
tefl-ensure-block-loaded (dxf-pfad) Blockdefinition einmal laden

8. Geruest (GeruestInsert.lsp)

Funktion Zweck
geruest-einfuegen (bg wahl) Befehls-Kern Saeulen/Rohrabhaenger/Wandbefestigung: baut aus der Dialog-Auswahl wahl = (variante-index oben unten laenge farbe) die Werte (ARTINR, BEZEICHNUNG, TEILEART, LAENGE, TEILEFARBE), fragt dann den Punkt per getpoint
geruest-block-bauen (bg variante werte pt teile-dwgs) skriptfaehiger Kern: Dummy-DWG + Teile-DWGs bei pt, Block GR_<id>_<ts>. bg = Baugruppe aus geruest.json, werte = Attribut-Alist, teile-dwgs aus geruest-teile-dwgs
geruest-traeger-einfuegen (bg wahl) Befehls-Kern Traeger: Schleife Startpunkt -> Endpunkt oder Laenge
geruest-traeger-block-bauen (bg layer netto strebe strebe-pfad muffe-pfad werte pt winkel) skriptfaehiger Kern Traeger: LINE (0,0,0)-(netto,0,0), Streben, Muffe, Block bei pt mit winkel (Radiant). Rueckgabe: (blockname . entity)
geruest-traeger-laenge, -start, -streben, -pruefen reine Berechnung (Netto-Laenge nach Abzuegen, Startpunkt, Strebenverteilung, min/max) - in tests/test_unit.lsp getestet
geruest-traeger-beschriften (blockEnt) Beschriftungstext aus dem fertigen Block
geruest-block-abschliessen (bg attribs werte lastEnt pt rot) gemeinsamer Schluss aller Geruest-Bloecke (ATTDEFs, Block bilden, einfuegen, ID)

Fuer Geruest gibt es noch keinen JSON-Treiber.


9. Einfuegeprimitiven (ssg_ks_insert.lsp, vf_etage.lsp)

Grundbausteine, auf denen VF, GF und Linienzug aufsetzen. Alle legen KS_EIN des Blocks (nicht den Block-Ursprung) auf den Startpunkt und geben den Weltpunkt von KS_AUS zurueck - damit lassen sich Bausteine verketten.

Funktion Zweck
ensure-block-loaded (name) Block einmal ins Dokument laden
extract-ks-from-block (block-obj) KS_EIN/KS_AUS eines eingefuegten Blocks (VLA-Objekt) lesen, Cache *ks-cache* je Blockname
insert-block-by-ks (blockname einfuegepunkt hz) Block nur um Z gedreht (AS/ES-Elemente, Stationen)
insert-inclined-scaled-block (blockname startpunkt laenge winkel hz) Block in X auf laenge skaliert und um winkel geneigt, Rz(hz)*Ry(winkel) (Staustrecken)
insert-rotated-block-with-ks (blockname startpunkt winkel block-dx block-dz hz) Block gedreht, block-dx/block-dz nur als Fallback ohne KS_AUS (Boegen)
insert-hz-scaled-block-by-ks (blockname startpunkt laenge hz-winkel vert-winkel) waagrechter, auf laenge skalierter Block (Staustrecke_SP_1000_mm, Massstab laenge/1000); Kandidat fuer die noch fehlende waagrechte Foerderstrecke. Bricht bei fehlender Blockdatei mit (exit) ab - vorher mit ssg-ils-block-laden pruefen
ssg-rot-matrix-zy (chz shz cv sv) 4x4-Rotationsmatrix Rz(hz)*Ry(vert) aus Cosinus/Sinus beider Winkel (ssg_core.lsp)

10. Gemeinsame Regeln fuer eigene Treiber

  • Systemvariablen ueber ssg-start/ssg-end sichern; OSMODE 0, ATTREQ 0, ATTDIA 0 setzen, sonst fragt _.INSERT nach Attributen.
  • Module vorher laden: (ssg-ensure "KreiselInsert"), "VarioFoerderer", "Gefaellestrecke", "SSG_LIB_Commands".
  • Die Dimension folgt ssg-ils-dim-aktuell; fuer einen festen Lauf *ssg-ils-dim* (bzw. *vsp-dim-override* beim Spec-Bau) setzen und danach zuruecksetzen.
  • Rueckgaben nicht mit and/or verketten - die liefern in AutoLISP nur T/nil (siehe CLAUDE.md, Konventionen).
  • Interaktive GUI abschalten: ssg-gui-aus bzw. vsp-headless-an.
  • Vorbilder: tests/test_mubea.lsp (Kreisel, VF Standard/Etage, GF, Einzelbloecke), tests/test_hundm05.lsp (Spec-Ketten, Kreisel, Einzelbloecke), tests/test_omniflo_strecke.lsp (Omniflo).