diff --git a/CLAUDE.md b/CLAUDE.md index 64a1533..9438baf 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -110,7 +110,7 @@ Detaillierte Dokumentation aller Funktionen und Befehle: siehe `Lisp/README.md`. | `vf_spec.lsp` (von vf_core.lsp NACH vf_linienzug.lsp geladen) | VF_SPEC_BAU | Linienzug-Ketten aus **Eingabedaten** bauen, ohne Dialog und ohne Konsolenfrage (Stufe 1 aus `doc/todo/plan-vf-interactive.md`). Eine **Spec** beschreibt eine Kette in Domaenenwerten (`"links"`, `"winkel"`, `"aussen"`, ja/nein) statt in Menue-Codes; `vsp-journal` uebersetzt sie in ein Eingabe-Journal, `vsp-bau-aus-spec` spielt es per `vfl-journal-replay-start` durch den UNVERAENDERTEN `vf-linienzug-modus` (Replay-Kern `vsp-bau-journal` - nimmt auch ein unveraendert uebernommenes, aufgezeichnetes Journal, z.B. aus `dxf_anlage_export.py`). Damit traegt der fertige Block dasselbe `SSG_VF_EDIT`-Journal wie eine handgebaute Kette und bleibt per Doppelklick editier- und 2D/3D-konvertierbar - kein Journal-Konsument muss etwas von Specs wissen. Wichtige Regeln, die der Uebersetzer kennt: der Menue-Code haengt am Frame (erste Sektion 4 Optionen ohne GF-Bogen, danach 5), `hz` steht nur beim ERSTEN Segment im Journal, und `erst-hor` unterscheidet den horizontalen Erstkoerper einer VF-Einheit (Separator-/Endpunktfragen vorab) vom gewinkelten (keine Frage). Fehlerverhalten: fail fast - `vsp-pruefen` sammelt ALLE Spec-Fehler, gebaut wird dann nichts (nichts wird geraten). Ergebnis-Record je Kette mit `status` (`executed`/`warnung`/`desync`/`abbruch`/`spec-fehler`), Block/Handle/Einfuegepunkt/Attributen, `prompts` (muss 0 sein), `glieder_soll` vs. `glieder_ist` (Desync-Detektor, der auch bei aufgehender Queue greift) und den gesammelten `meldungen`. Headless-Rahmen `vsp-headless-an`/`-aus` (Save/Restore von `*vfl-headless*`, `*vfl-wizard-mode*`, `*ssg-gui-aus*` + zaehlende Eingabe-Stubs). Spec-Datei flach als JSON (`ssg-load-json` liest zeilenweise), erzeugt von `lib/vf_spec_export.py`. Gegenstueck/Referenz in Python: derselbe Emitter, gegen die 5 echten HundM-Ketten rundlaufgeprueft | | `Gefaellestrecke.lsp` | GEFAELLESTRECKE, GEFAELLESTRECKE_EDIT | Gefaelle-Foerderanlage (AUS -> Staustrecke skaliert -> Separator -> EIN); Modus 1 per DCL-Dialog (Einfuegehoehe, Element-Winkel 30/90); Doppelklick auf GF_n-Block ruft GEFAELLESTRECKE_EDIT (Dialog vorbelegt, Neuaufbau; die Einfuegehoehe kommt aus der aktuellen Z des Einfuegepunkts statt aus XDATA/HOEHE_VON_mm, damit ein in Z verschobener Block per OK direkt auf der neuen Hoehe neu entsteht - gleiches gilt fuer die 2D/3D-Umschaltung `gf-konvertiere-ent`; der GF-Linienzug-Rebuild nutzt weiter die absoluten Segmentpunkte aus XDATA) | | `export.lsp` | EXPORTSIVAS, EXPORTCSV, OMNI_UPDATE_ATTRIBS, CSV_EXPORT_KONFIG | JSON-Sammlung und Python-Export (Omniflo-Merkmale/Sum-Zeile via lib/export_csv.py). **Gefrorene Layer**: `csv:collect-export-blocks` laesst Bloecke auf gefrorenen Layern aus (ausgeschaltete Layer zaehlen NICHT), Schalter `*csv-gefrorene-ausschliessen*` (Standard an, Toggle im Dialog CSV_EXPORT_KONFIG). Die Hilfsobjekte eines gefrorenen VF_n/GF_n (Separator-/Element-Kopien, Einheiten-/AS-ES-Marker) liegen auf eigenen Layern und werden darum ueber `*csv-ausschluss-enames*` mit ausgelassen (gesetzt in `csv:export-vorbereiten` per `csv:hilfskopien-ausschluss`); erzeugt und nummeriert werden sie trotzdem, damit IDs stabil bleiben. DrawPlanquadrate nutzt dieselbe Sammlung und folgt dem Filter. **Hoehen-Neuberechnung**: erster Schritt von `csv:export-vorbereiten` ist `csv:hoehen-aktualisieren` - in Z verschobene `KREISEL_*`/`ECKRAD_*`/`VF_*`/`GF_*` bekommen ihre Hoehen-Attribute aus der Einfuege-Z neu (reiner Kern `csv:hoehen-werte`, getestet; Formeln/Rundung wie beim Bau: Kreisel HOEHE + MONTAGEHOEHE_m=z/1000, Eckrad HOEHE, GF/VF HOEHE_VON_mm=(fix z), MONTAGEHOEHE_m GF=z/1000 bzw. VF=(VON+BIS)/2000). HOEHE_BIS_mm = VON - (VON_alt - BIS_alt), bewusst NICHT z - DELTA_H_mm (ohne Vorzeichen -> steigende VF falsch, separat abgeschnitten -> 1 mm Abweichung); DELTA_H_mm nur Rueckfall. Nicht verschobene Bloecke (Attribut passt zu z) bleiben unangetastet, damit Bau-Werte und Hand-Korrekturen (z.B. Buehnen-Abzug aus HOEHEN_CHECK) bit-genau erhalten bleiben | -| `OmniModulInsert.lsp` | OMNI_LOAD, OMNI_APB_*, OMNI_W*_*, OMNI_AP60/AP110, OMNI_TEF_*, OMNI_TV_*, OMNI_APBW_*, OMNI_LADESCHLEIFE_AP110, OMNI_EDIT | Omniflo-Komponenten: Boegen, Weichen, Verbinder, Transferwagen, Ladeschleifen (`data/json/omniflo_ladeschleifen.json`, per `ssg-json-laden`, da die Beschreibungen Kommas enthalten; Blockdatei darf `.dwg` statt `.dxf` sein), Edit-Dialog | +| `OmniModulInsert.lsp` | OMNI_LOAD, OMNI_APB_*, OMNI_W*_*, OMNI_AP60/AP110, OMNI_TEF_*, OMNI_TV_*, OMNI_APBW_*, OMNI_LADESCHLEIFE_AP110, OMNI_EDIT | Omniflo-Komponenten: Boegen, Weichen, Verbinder (`OMNI_TV_*`: DWGs dimensionsunabhaengig in `data/omniflo/Verbinder`, `omni:insert-verbinder` -> gemeinsamer Einfuegekern `omni:insert-datei`, den auch `omni:insert-dxf` nutzt; im Export ueber `pattern_verbinder` = `VB_*, TV_*` gesammelt (`csv:collect-export-blocks`, `ssg-id-collect-blocks`), Sivas-Zeilen ueber TEILEART/ARTINR wie alle Omniflo-Teile), Transferwagen, Ladeschleifen (`data/json/omniflo_ladeschleifen.json`, per `ssg-json-laden`, da die Beschreibungen Kommas enthalten; Blockdatei darf `.dwg` statt `.dxf` sein), Edit-Dialog | | `SSG_LIB_Commands.lsp` | ILS_BTMT_Beladung, ILS_BTMT_Entladung, ILS_SCANNER_INSERT, ILS_SEPARATOR_INSERT, ILS_EINGANG_INSERT, ILS_AUSGANG_INSERT, ILS_ETF_*, ILS_GK*_*, SSG_BLOCKEDIT, SSG_DIM_SWITCH, SSG_SPRACHE | BTMT Be-/Entladung (`ils-insert-station`: wiederholtes Einfuegen von `BTMT-Beladung` bzw. `SC_Entladung`, Drehung interaktiv, Layer aus `LAYER`-Attribut, Dimension via `ssg-ils-block-laden`) + Sensoren (`ils-insert-sensor`) + Eingang-/Ausgang-Symbol (frei platzierbar wie BTMT Be-/Entladung, ueber `ils-insert-station` mit den Rohnamen `Eingang`/`Ausgang`, Bloecke `Eingang_.dwg`/`Ausgang_.dwg` in data/ils) + Dummy-Befehle fuer Menue + Doppelklick/Kontextmenue-Dispatcher + Konfiguration (2D/3D, Sprache) | | `Tro_Edit.lsp` | TRO_INSERT, TRO_EDIT | TRO-Marker (Block `TRO_SYM_`) fuer sps_skel (lib/tro_annotate.py): TRO_INSERT fuegt eine bestehende Blockdefinition an einem gewaehlten Punkt ein und setzt ID/TYPE (bricht ab, wenn der Typ noch keine Blockdefinition in der Zeichnung hat - die entsteht nur ueber tro_annotate.py); TRO_EDIT aendert ID/TYPE eines bestehenden Markers per Dialog. Typliste aus `tro_types.lsp` (von `tro_annotate.py --emit-lisp` nach DXFM_LISP geschrieben). Der Dispatcher SSG_BLOCKEDIT leitet Blocknamen `TRO_*` zu TRO_EDIT. | | `GeruestInsert.lsp` | GERUEST, GERUEST_SAEULEN, GERUEST_ROHRABHAENGER, GERUEST_WANDBEFESTIGUNG, GERUEST_TRAEGER, GERUEST_TRAEGER_BESCHRIFTEN, OMNI_FAHRSTRECKE, OMNI_FAHRSTRECKE_BESCHRIFTEN | Geruest-Baugruppen aus `data/json/geruest.json` konfigurieren und einfuegen. **Ein Dialog je Bereich**: Rohrabhaenger / Saeulen / Wandbefestigung oeffnen NUR ueber ihren eigenen Menuebefehl (`geruest-starten id`, Dialogtitel aus dem ASCII-Feld `titel`); eine Umschaltung im Dialog gibt es nicht (DCL hat kein Reiter-Tile), `GERUEST` ohne Bereich zeigt nur einen Hinweis. Der Dialogstand beginnt je Aufruf frisch. 1"- und 2"-Saeulen liegen in EINER Baugruppe `Saeulen` mit gemeinsamer Anbauteil-Liste; **`teileart` und `dummy` duerfen je Geometrie-Variante ueberschrieben werden** (`geruest-variante-wert`, Variante gewinnt vor Baugruppe; fuer `dummy` ueber `geruest-dummy-wahl`: fehlt die DWG der Variante, Meldung + Rueckfall auf den Baugruppen-Dummy; ist der Dummy zugleich eine Teile-DWG, wird er per `geruest-ohne-pfad` nicht doppelt eingefuegt) - so liefert `R 1"` weiterhin TEILEART `Geruest Saeule 1 Zoll` und die `R 2"`-Varianten `Geruest Saeule 2 Zoll`, die Groessen bleiben im Export also unterscheidbar. **Das Layout steht als Vorlage in `dcl/geruest.dcl`** (bzw. `dcl/geruest_traeger.dcl`); nur die datenabhaengigen Bloecke - ein `radio_button` je Variante (Key `v`, `geruest-radio-key`/`-index`), Mengenfeld + Ankreuzfeld je Anbauteil - werden zur Laufzeit an Markerzeilen `//@NAME@` eingesetzt (`geruest-dcl-ersetzungen` -> `ssg-dcl-vorlage-fuellen` in ssg_core, Temp-Datei, nach `unload_dialog` geloescht). Grund: DCL kann Tiles weder zur Laufzeit erzeugen noch ausblenden, Radiobutton-Labels lassen sich per `set_tile` nicht aendern, und eine `list_box` kann keine Eingabefelder enthalten. Varianten bewusst als Radiobuttons statt `list_box`: BricsCAD zeichnet die Listenspalte nur halb so breit, und ein `tabs`-Wert passt nur schrift-/skalierungsabhaengig. Inhalt: Basis-Variante aus `geometrie_varianten` (`list_box` mit Einfachauswahl, Hoehe nach Variantenzahl, `geruest-dcl-listenhoehe`), **Winkel Platte** (0/90 Grad, `*geruest-winkel-werte*`): Ausrichtung der Anbauteile zur Basis - die Teile-DWGs aus oben/unten/sonstiges werden um diesen Winkel um Z gedreht in den Block eingefuegt, Basis und Dummy bleiben ungedreht (`geruest-teile-dwgs-rot`; in Konfigurationen als echter Wert `winkel_platte`, kein Block-Attribut), Laenge (gegen `attribute.Laenge` min/max geprueft, Retry-Schleife), Farbe (`attribute.Teilefarbe`, Freitext bei `frei_option`) und **eine Befestigungsspalte** "Befestigung oben und unten" mit allen `anbaugruppen.befestigung` - die Anzahl ist die GESAMTanzahl je Teil (oben und unten zusammen; Tile-Keys `b`/`bm`, Zustand `*geruest-dlg-bef*`). Unter jedem Teil (auch in Sonstiges) zeigt eine Textzeile "Art.-Nr. ..." die Artikelnummer(n) (`geruest-artnr-anzeige`: Einzelteil -> `sivas_id`, Gruppe -> eindeutige Nummern der Teile; DCL kennt keine Schriftgroesse, darum normale Groesse in eigener Zeile). `anbaugruppen` ist ein Objekt mit zwei Listen: `befestigung` (Befestigungsspalte) und `sonstiges` (Teile, die weder oben noch unten sitzen, z.B. die Saeulen-Haltearme) - letztere bekommen eine eigene Zeile darunter (nur wenn nicht leer), in ARTINR/BEZEICHNUNG nach "unten" als "sonstiges" (`geruest-anbau-liste`; ein altes flaches Array gilt als `befestigung`). **Zwei Mengenfelder im JSON, bewusst verschieden benannt**: `stueckzahl` = wie oft ein Teil TATSAECHLICH geschrieben wird (je Variante bzw. je Satz/Anbauteil, fehlt = 1), `anzahl_vorgabe` = NUR die Vorbelegung des Anzahl-Feldes im Dialog (Anbaugruppen, fehlt = 1); ein Anbauteil wird Anzahl x `stueckzahl` mal geschrieben, bei einer Gruppe (`teile`) zaehlt die Anzahl die Saetze (`geruest-stueckzahl`/`geruest-anzahl-vorgabe`). In Konfigurationen (`befestigung`/`sonstiges`, dazu `winkel_platte`) heisst der gespeicherte Dialogwert `anzahl`. Aeltere Konfigurationen mit getrennten `oben`/`unten`-Listen laden weiter: deren Mengen werden zur Gesamtanzahl addiert (`geruest-konfig-befestigung`), Sonstiges-Teile darin still in die Sonstiges-Zeile umgehaengt (`geruest-konfig-sonstiges`); beim naechsten Speichern steht alles im neuen Format. Baugruppen ohne `attribute`-Block (Wandbefestigung) bekommen Laenge/Farbe gesperrt, Baugruppen ohne Anbauteile bekommen gar keine Spalten (ein leerer DCL-Cluster ist unzulaessig). Im generierten Label wird `"` zu `''` ersetzt (`geruest-dcl-label`) - fuenf Artikelnamen enthalten ein Anfuehrungszeichen, das das DCL-Label sonst vorzeitig beendet und die Datei zerstoert. **Konfigurationen**: gepflegte Bibliothek je Baugruppe unter `konfigurationen` in `geruest.json` (schreibgeschuetzt) plus eigene in `cfg/geruest_user.json` (gitignored, `geruest-user-schreiben`; getrennte Datei, damit Benutzerdaten und versionierte Bibliothek nicht kollidieren). Eigene Eintraege sind in der Liste mit `*` markiert und nur diese loeschbar. **Geaenderte Konfiguration**: beim Anwenden wird der Dialogstand als Vergleichsbasis gemerkt (`*geruest-dlg-konfig-basis*`); jede Eingabe vergleicht den aktuellen Record damit (`geruest-dlg-aenderung-pruefen`, Vergleich statt Flag - Zuruecknehmen hebt die Markierung wieder auf) und kennzeichnet den Listeneintrag mit "(geaendert)" plus Statuszeile `kstatus`. Speichern bietet bei einer gewaehlten EIGENEN Konfiguration deren Namen als Vorgabe an (Enter = ueberschreiben, `geruest-konfig-name-vorgabe`); Bibliotheks-Konfigurationen brauchen einen neuen Namen. Konfigurationen verweisen ueber den ANZEIGENAMEN auf Variante und Anbauteile; ein unbekannter Name wird gemeldet und uebersprungen, statt die Konfiguration scheitern zu lassen. Speichern/Loeschen laufen ueber `done_dialog 2`/`3` (Dialog schliessen, Aktion, neu zeigen) - `getstring` funktioniert aus einem `action_tile`-Rueckruf heraus nicht. Der Block wird - wie KREISEL_n/VF_n - SELBST zusammengebaut: Dummy-DWG aus `data/geruest` liefert nur Geometrie, das Attribut-Schema kommt aus `*geruest-attrib-defs*` (ID, ARTINR, LAENGE, BEZEICHNUNG, TEILEART, TEILEFARBE, LAYER) und wird per `ssg-attrib-merge` mit den Dummy-Tags zusammengefuehrt - sonst verschluckt `ssg-attrib-set-on` stillschweigend jeden Tag, den die Dummy-DWG nicht als ATTDEF kennt. **Teile-Geometrie**: jede ausgewaehlte Artikelnummer (Basis/oben/unten inkl. aufgeloester Gruppen), fuer die `data/geruest/.dwg` existiert, wird zusaetzlich einmal bei 0,0,0 mit in den Block eingefuegt (`geruest-teile-dwgs`, dedupliziert, fehlende DWGs still uebergangen) - reine visuelle Rueckmeldung, die Attribut-Logik bleibt davon unberuehrt. **TEILEFARBE** ist eine kommagetrennte Liste parallel zu ARTINR (z.B. `,,RAL7030,,RAL7030`): Teile mit `"farbig": true` in `geruest.json` (je Artikel; eine Gruppe vererbt es an ihre Teile, fehlend = false) bekommen die im Dialog gewaehlte Baugruppenfarbe, alle anderen einen leeren Eintrag. ARTINR und TEILEFARBE entstehen aus demselben Durchlauf (`geruest-teile-paare`/`-paare-n`, `geruest-farbliste`), sind also garantiert gleich lang. `export_sivas.py` schreibt daraus je Artikelnummer das Merkmal `{"108": ""}` in `details` (Nummer aus `cfg/export.cfg` `[Sivas] merkmal_teilefarbe`). Blockname `GR__` (Kollisionszaehler wie in OmniModulInsert). **Das `GR_`-Praefix ist nicht kosmetisch**: `SSG_BLOCKEDIT` haelt JEDEN Block mit TEILEART-Attribut fuer ein Omniflo-Element, deshalb steht in `SSG_LIB_Commands.lsp` ein `GR_*`-Zweig VOR dem Omniflo-Zweig. ARTINR listet jede Sivas-ID so oft, wie Anzahl x `stueckzahl` es vorgeben - erst Basis, dann Befestigung, dann Sonstiges; bei einer benannten Gruppe (`teile`) wird das ganze Set n-mal wiederholt, die Mengen INNERHALB des Sets bleiben dabei erhalten (`geruest-artikelnummern-n`). BEZEICHNUNG nennt Position und Menge je Teil ("Befestigung 4x ...", "sonstiges 1x ...") und verkettet mit `" + "`, NICHT mit Komma - die Artikelbezeichnungen enthalten selbst Kommas ("ROHR R 1\" 33,7 x 2,6"). Zuordnung Menue -> JSON laeuft ueber das ASCII-Feld `id`, weil die aeusseren JSON-Schluessel Umlaute bzw. Anfuehrungszeichen tragen. CSV-/Sivas-Export: `pattern_geruest = GR_*` (cfg/export.cfg), `csv:collect-export-blocks`/`ssg-id-collect-blocks` sammeln GR_-Bloecke wie BTMT eigenstaendig; `*geruest-attrib-defs*` traegt zusaetzlich ein leeres `ID`-ATTDEF (Voraussetzung fuer `ssg-id-check-all`, das nur bestehende ATTRIBs beschreiben kann). ARTINR/BEZEICHNUNG/TEILEART/LAENGE landen in export_csv.py/export_sivas.py in festen Spalten, TEILEFARBE/LAYER (+ ARTINR bei export_csv.py) im Merkmale-/details-JSON. **Attribut-Keys in `geruest.json` sind GROSS** (`LAENGE`, `TEILEFARBE`, ...) = die Block-Attribut-Tags; `ssg-json-get` unterscheidet Gross/Klein. **Rohr-Geruest-Traeger** (`GERUEST_TRAEGER`): Traeger-Baugruppen mit Linien-Logik liegen in einer EIGENEN Datei `data/json/geruest_traeger.json` (gleicher Aufbau wie geruest.json, eigener Lader/Cache `geruest-traeger-daten`, Suche `geruest-baugruppe id daten`; gemeinsamer Lader `geruest-json-laden-cache`) - sie tauchen darum nicht im Bereichs-Dropdown von GERUEST auf; dort kann spaeter auch der Gattertraeger hin. eigener Dialog aus der Vorlage `dcl/geruest_traeger.dcl` (Variante als Radiobuttons, JEDE Variante - auch die mit Muffe - mit eigenem Button, Beschriftung "Name (Artikelnummern)" ueber `geruest-varianten-label`; Varianten mit `"disabled": true` erscheinen in allen drei Geruest-Dialogen ausgegraut und nicht waehlbar (`geruest-variante-gesperrt-p`, `geruest-varianten-sperren` per `mode_tile`; Vorauswahl ueber `geruest-variante-waehlbar`/`-erste-freie-variante`; eine Konfiguration mit gesperrter Variante laesst die Auswahl unveraendert und meldet `gr-konfig-variante-gesperrt`) - bleiben aber in den Daten, damit Konfigurationen und Neubeschriften sie weiter ueber den Namen finden; eine Muffen-Checkbox gab es zwischenzeitlich, sie wurde wieder entfernt, weil die Artikelnummer der Muffen-Variante dann im Dialog nicht sichtbar war; Farbe, je eine Checkbox + Feld fuer `LAENGENABZUGANFANG`/`LAENGENABZUGENDE`, Vorgabe `vorgabe`/`aktiv` aus dem attribute-Block, je Variante ueberschreibbar via `geruest-attr-feld`); danach Einfuege-Schleife bis ESC/Enter: Startpunkt, dann Endpunkt ODER getippte Laenge (+ Richtung). Aktive Abzuege ruecken die Linie beidseitig ein (Strecke 1000, Abzug Anfang 20/Ende 35 -> Start 20 mm hinter dem Klick, Linie 945 mm); `LAENGE` = Netto-Laenge, gegen `LAENGE.min/max` geprueft. KEINE Dummy-DWG: die Geometrie ist eine per `entmake` erzeugte LINE (0,0,0)-(L,0,0) auf dem `layer` der Variante, eingefuegt mit dem Richtungswinkel (ANGBASE/ANGDIR/AUNITS dafuer kurz auf 0). **Querstreben + Muffe** als verschachtelte Dummy-DWGs im selben Block, reine Grafik ohne Export: `querstrebe.dummy` (`data/geruest/dummy_Strebe_30x4.dwg`, Basispunkt Strebenmitte, 30 mm laengs X) an jeder Strebenposition, NUR bei Varianten mit ausdruecklichem `"mit_querstrebe": true` (z.B. nicht beim `Rohr 1"`); fehlt die DWG, Rueckfall auf je eine 25-mm-Querlinie an Strebenanfang/-ende (`laenge`/`querlinie`, Standard 30/25 nur im Code). `muffe.dummy` (`dummy_Muffe_1zoll.dwg`, Basispunkt Muffenmitte) am Linienende, NUR bei Varianten mit ausdruecklichem `"mit_muffe": true` (nicht aus dem Namen geraten; bei "mit 2 Muffen" trotzdem nur eine am Ende); `querstrebe`/`muffe` per Variante ueberschreibbar (`geruest-variante-wert`). Dummys werden ohne Drehung eingefuegt (Traeger laeuft im Block entlang +X), ab dem zweiten Mal per Blockname (`geruest-dummy-einfuegen`). Verteilungs-Konfiguration `querstrebe` (`abstand`/`rand_min`/`rand_max`, Variante vor Baugruppe), Plan `geruest-traeger-streben-plan` -> (rand positionen): der Abstand zwischen zwei Streben ist IMMER genau `abstand`, beide Raender gleich (netto = k*abstand + 2*rand); gewaehlt wird die Strebenzahl, deren Rand am naechsten an `rand_min`..`rand_max` liegt (Gleichstand -> weniger Streben). Mit 500/100..250 geht das nur auf, wenn netto mod 500 = 0 oder in [200, 500) liegt (z.B. 1300 -> 150|500|500|150); sonst (1001..1199, unter 200 mm) liegt der Rand ausserhalb (1100 -> 300|500|300) - `geruest-traeger-rand-pruefen` zeigt dann eine Messagebox (ohne GUI: Konsole), der Traeger wird trotzdem eingefuegt. Schema `*geruest-traeger-attrib-defs*` = `*geruest-attrib-defs*` + die zwei Abzug-Tags; gemeinsamer Block-Schluss mit den anderen Bereichen in `geruest-block-abschliessen`. Reine Berechnung (`geruest-traeger-laenge`/`-start`/`-pruefen`, `geruest-mm-zahl`) in `tests/test_unit.lsp`. **Traeger-Beschriftung** (Checkbox im Dialog, Standard an; z.B. `RT 80/80 L=2650`): EIGENES TEXT-Objekt neben dem Block, abgeleitet NUR aus dem fertigen Block (Einfuegepunkt, DXF 50, Attribute `LAENGE` + `VARIANTE`) - darum nutzen Einfuegen und `GERUEST_TRAEGER_BESCHRIFTEN` dieselbe Funktion `geruest-traeger-beschriften`, und ein von Hand verschobener/gedrehter Traeger wird beim Neubeschriften korrekt erfasst. Verknuepfung Text -> Block per XDATA `SSG_GR_BESCHR` (1005 = Block-Handle): Neubeschriften ersetzt statt verdoppelt, der Sammelbefehl entfernt verwaiste Texte. JSON `beschriftung` (je FELD Variante vor Baugruppe, `geruest-obj-feld`): Inhalt `format` (`%1` Text, `%2` Laenge auf ganze mm) + `text` (fehlt -> Variantenname) und `layer` (je Variante verschieden, darum in JEDER Variante gepflegt - keine Baugruppen-Vorgabe; fehlt er doch, aktueller Layer); Formatierung NUR `stil`/`ausrichtung`/`hoehe` - alles andere regelt der Textstil ausserhalb, es wird kein Stil angelegt (fehlt er: Meldung, aktueller TEXTSTYLE). `ausrichtung` = Codes von TEXT "Ausrichten" (T/M/B + L/C/R), Bezugspunkt auf der Traegerlinie, L/R in LESErichtung. Textwinkel entlang des Traegers, DIN: fuer 90 < w <= 270 Grad um 180 gedreht (`geruest-text-winkel`). **Omniflo-Fahrstrecke** (`OMNI_FAHRSTRECKE`, Daten `data/json/omniflo_fahrstrecke.json`, Vorlage `dcl/fahrstrecke.dcl`): dieselbe Linien-Logik wie der Traeger, Code geteilt - `geruest-linien-starten id daten dcl-datei dlg-name` (Dialog `geruest-traeger-dialog` mit Vorlage + Dialogname als Argument, Einfuegen `geruest-traeger-einfuegen`), Beschriftung `geruest-traeger-beschriften blockEnt bg` mit der Baugruppe als Argument, Sammelbefehle je Typ ueber `geruest-linien-beschriften id daten` (Bloecke `GR__*`; verwaiste Texte werden typunabhaengig entfernt). Unterschiede stehen nur in den Daten: keine Querstreben (kein `mit_querstrebe`), Muffen-Dummy wie beim Traeger ueber den `muffe`-Block der Baugruppe (nur Varianten mit `"mit_muffe": true`), `farbig` nur bei ST/STL, Muffen-Varianten nur fuer ST/STL. Der Dialogstand bleibt je Baugruppe erhalten (`*geruest-tr-id*`; Wechsel Traeger <-> Fahrstrecke setzt ihn zurueck). Meldungstexte `gr-tr-*` nennen den Bauteilnamen aus `titel` als Platzhalter. In der Stueckliste eigene Klasse `fahrstrecke` (`GR_Fahrstrecke_*` vor dem allgemeinen `GR_*`). Noch NICHT enthalten: Edit-Pfad (GERUEST_EDIT) | diff --git a/Lisp/OmniModulInsert.lsp b/Lisp/OmniModulInsert.lsp index 181f136..8be22f0 100644 --- a/Lisp/OmniModulInsert.lsp +++ b/Lisp/OmniModulInsert.lsp @@ -1004,8 +1004,7 @@ ;; hoehe = Hoehe in mm als String (wird als HOEHE-Attribut gesetzt) ;; drehung = Drehwinkel in Grad als String (Block-Rotation) ;; Rueckgabe: Einfuegepunkt oder nil bei Abbruch -(defun omni:insert-dxf (sivasnr-str hoehe drehung / dxf-pfad omniflo-pfad angleDeg - drehung-anzeige blockEnt attribs layer-name ed pt10 zval zdelta) +(defun omni:insert-dxf (sivasnr-str hoehe drehung / dxf-pfad omniflo-pfad) (setq omniflo-pfad (getenv "DXFM_OMNIFLO")) (if (null omniflo-pfad) (progn @@ -1019,94 +1018,102 @@ (princ (ssg-textf "omni-fehler-dxf-nicht-gefunden" (list (strcat omniflo-pfad "/" sivasnr-str ".dxf")))) nil ) - (progn - (ssg-start "OMNI DXF Insert" '(("ATTREQ") ("ATTDIA"))) - (setvar "ATTREQ" 0) - (setvar "ATTDIA" 0) - - ;; Absolute Z-Hoehe fuer den Einfuegepunkt bestimmen - (setq zval (if (and hoehe (/= hoehe "")) (atof hoehe) 0.0)) - - ;; Interaktives Einfuegen mit Live-Vorschau am Mauszeiger: - ;; dxf-pfad -> Block aus Datei definieren/waehlen - ;; 1. 'pause -> Einfuegepunkt; Objekt haengt sichtbar am Cursor und - ;; verschiebt sich mit der Maus (erster Klick positioniert) - ;; "" "" -> X-/Y-Massstab = 1 - ;; Drehung -> aus Dialog fest, sonst 2. 'pause: Objekt dreht sich - ;; beim Ziehen sichtbar mit, zweiter Klick beendet - (if drehung - (progn - (setq angleDeg (atof drehung)) - (setq drehung-anzeige drehung) - (command "_.INSERT" dxf-pfad pause "" "" angleDeg) - ) - (command "_.INSERT" dxf-pfad pause "" "" pause) - ) - ;; INSERT vollstaendig abschliessen (bei Bedarf weitere Eingabe zulassen) - (while (> (getvar "CMDACTIVE") 0) (command pause)) - - (setq blockEnt (entlast)) - - (if (and blockEnt (= (cdr (assoc 0 (entget blockEnt))) "INSERT")) - (progn - (setq ed (entget blockEnt)) - - ;; Tatsaechlich per Maus gesetzte Drehung ermitteln (interaktiv) - (if (null drehung) - (progn - (setq angleDeg (* (cdr (assoc 50 ed)) (/ 180.0 pi))) - (setq drehung-anzeige (rtos angleDeg 2 1)) - ) - ) - - ;; Z-Hoehe absolut anwenden: Block (inkl. Attribute) per MOVE um - ;; die Differenz zum aktuellen Einfuegepunkt-Z verschieben. Osnap - ;; beim interaktiven Einfuegen kann eine abweichende Z-Lage liefern, - ;; daher Differenz statt fixem Wert (vgl. GF-Z-Versatz-Bug). - ;; Explizite Koordinaten unterliegen keinem Objektfang. - (setq pt10 (cdr (assoc 10 ed))) - (setq zdelta (- zval (caddr pt10))) - (if (/= zdelta 0.0) - (command "_.MOVE" blockEnt "" (list 0.0 0.0 0.0) (list 0.0 0.0 zdelta)) - ) - - ;; HOEHE und DREHUNG Attribute setzen - (ssg-attrib-set-on blockEnt - (list (cons "HOEHE" (if hoehe hoehe (ssg-cfg-or "omniflo" "default_hoehe" "2000"))) - (cons "DREHUNG" drehung-anzeige))) - - ;; Layer aus der Block-Vorgabe (LAYER-Attribut) setzen - (setq attribs (ssg-attrib-read blockEnt)) - (setq layer-name (ssg-block-layer-vorgabe blockEnt sivasnr-str attribs)) - ) - ) - - ;; Fallback fuer Anzeige, falls keine Drehung ermittelt wurde - (if (null drehung-anzeige) - (setq drehung-anzeige (rtos (if angleDeg angleDeg 0.0) 2 1)) - ) - - ;; Eindeutige ID zuweisen - (if (and blockEnt (atoms-family 1 '("ssg-id-generate"))) - (ssg-id-generate blockEnt) - ) - - (princ (ssg-textf "omni-dxf-eingefuegt" - (list - sivasnr-str - (if hoehe hoehe (ssg-cfg-or "omniflo" "default_hoehe" "2000")) - drehung-anzeige - (if layer-name (strcat " Layer=" layer-name) "") - ))) - (ssg-end) - ;; Rueckgabe: tatsaechlicher Einfuegepunkt - (if blockEnt (cdr (assoc 10 (entget blockEnt)))) - ) + (omni:insert-datei dxf-pfad sivasnr-str hoehe drehung) ) ) ) ) +;; --- Block-Datei (DXF/DWG) interaktiv einfuegen --- +;; dxf-pfad = vollstaendiger Pfad der Blockdatei (bereits auf Existenz geprueft) +;; name = Anzeigename/Blockname fuer Meldung und Layer-Vorgabe +;; hoehe, drehung wie omni:insert-dxf +;; Rueckgabe: Einfuegepunkt oder nil bei Abbruch +(defun omni:insert-datei (dxf-pfad name hoehe drehung / angleDeg + drehung-anzeige blockEnt attribs layer-name ed pt10 zval zdelta) + (ssg-start "OMNI DXF Insert" '(("ATTREQ") ("ATTDIA"))) + (setvar "ATTREQ" 0) + (setvar "ATTDIA" 0) + + ;; Absolute Z-Hoehe fuer den Einfuegepunkt bestimmen + (setq zval (if (and hoehe (/= hoehe "")) (atof hoehe) 0.0)) + + ;; Interaktives Einfuegen mit Live-Vorschau am Mauszeiger: + ;; dxf-pfad -> Block aus Datei definieren/waehlen + ;; 1. 'pause -> Einfuegepunkt; Objekt haengt sichtbar am Cursor und + ;; verschiebt sich mit der Maus (erster Klick positioniert) + ;; "" "" -> X-/Y-Massstab = 1 + ;; Drehung -> aus Dialog fest, sonst 2. 'pause: Objekt dreht sich + ;; beim Ziehen sichtbar mit, zweiter Klick beendet + (if drehung + (progn + (setq angleDeg (atof drehung)) + (setq drehung-anzeige drehung) + (command "_.INSERT" dxf-pfad pause "" "" angleDeg) + ) + (command "_.INSERT" dxf-pfad pause "" "" pause) + ) + ;; INSERT vollstaendig abschliessen (bei Bedarf weitere Eingabe zulassen) + (while (> (getvar "CMDACTIVE") 0) (command pause)) + + (setq blockEnt (entlast)) + + (if (and blockEnt (= (cdr (assoc 0 (entget blockEnt))) "INSERT")) + (progn + (setq ed (entget blockEnt)) + + ;; Tatsaechlich per Maus gesetzte Drehung ermitteln (interaktiv) + (if (null drehung) + (progn + (setq angleDeg (* (cdr (assoc 50 ed)) (/ 180.0 pi))) + (setq drehung-anzeige (rtos angleDeg 2 1)) + ) + ) + + ;; Z-Hoehe absolut anwenden: Block (inkl. Attribute) per MOVE um + ;; die Differenz zum aktuellen Einfuegepunkt-Z verschieben. Osnap + ;; beim interaktiven Einfuegen kann eine abweichende Z-Lage liefern, + ;; daher Differenz statt fixem Wert (vgl. GF-Z-Versatz-Bug). + ;; Explizite Koordinaten unterliegen keinem Objektfang. + (setq pt10 (cdr (assoc 10 ed))) + (setq zdelta (- zval (caddr pt10))) + (if (/= zdelta 0.0) + (command "_.MOVE" blockEnt "" (list 0.0 0.0 0.0) (list 0.0 0.0 zdelta)) + ) + + ;; HOEHE und DREHUNG Attribute setzen + (ssg-attrib-set-on blockEnt + (list (cons "HOEHE" (if hoehe hoehe (ssg-cfg-or "omniflo" "default_hoehe" "2000"))) + (cons "DREHUNG" drehung-anzeige))) + + ;; Layer aus der Block-Vorgabe (LAYER-Attribut) setzen + (setq attribs (ssg-attrib-read blockEnt)) + (setq layer-name (ssg-block-layer-vorgabe blockEnt name attribs)) + ) + ) + + ;; Fallback fuer Anzeige, falls keine Drehung ermittelt wurde + (if (null drehung-anzeige) + (setq drehung-anzeige (rtos (if angleDeg angleDeg 0.0) 2 1)) + ) + + ;; Eindeutige ID zuweisen + (if (and blockEnt (atoms-family 1 '("ssg-id-generate"))) + (ssg-id-generate blockEnt) + ) + + (princ (ssg-textf "omni-dxf-eingefuegt" + (list + name + (if hoehe hoehe (ssg-cfg-or "omniflo" "default_hoehe" "2000")) + drehung-anzeige + (if layer-name (strcat " Layer=" layer-name) "") + ))) + (ssg-end) + ;; Rueckgabe: tatsaechlicher Einfuegepunkt + (if blockEnt (cdr (assoc 10 (entget blockEnt)))) +) + ;; --- Eintrag aus Dialog-Ergebnis einfuegen --- ;; dlg-result = (eintrag hoehe drehung) aus omni:bogen-dialog / omni:weichen-dialog @@ -1650,76 +1657,106 @@ ) ;; --- Omniflo / Verbinder --- +;; Verbinder-Bloecke liegen dimensionsunabhaengig als DWG in +;; data/omniflo/Verbinder (nicht unter DXFM_OMNIFLO = data/omniflo/). +;; Einfuegen wie die festen TEF-Bauteile ueber omni:insert-datei: Punkt und +;; Drehung interaktiv, Layer aus dem LAYER-Attribut, ID per ssg-id-generate. +;; Befehl -> DWG-Name steht direkt im jeweiligen c:OMNI_TV_*-Befehl. + +;; Pfad der Verbinder-DWG aus Datenverzeichnis + Dateiname (ohne .dwg) +(defun omni:verbinder-pfad (data-pfad datei) + (strcat (vl-string-right-trim "/" (vl-string-translate "\\" "/" data-pfad)) + "/omniflo/Verbinder/" datei ".dwg") +) + +;; Verbinder-DWG interaktiv einfuegen. Rueckgabe: Einfuegepunkt oder nil +(defun omni:insert-verbinder (datei / data-pfad pfad) + (setq data-pfad (getenv "DXFM_DATA")) + (cond + ((null data-pfad) + (princ (ssg-text "omni-fehler-dxfm-data")) + nil) + ((not (findfile (setq pfad (omni:verbinder-pfad data-pfad datei)))) + (princ (ssg-textf "omni-fehler-dxf-nicht-gefunden" (list pfad))) + nil) + (t (omni:insert-datei pfad datei nil nil)) + ) +) + (defun c:OMNI_TV_W_W () - (princ "\n[DUMMY] TV W-W kpl") + (omni:insert-verbinder "TV_W-W_kpl") (princ) ) (defun c:OMNI_TV_W_AP110 () - (princ "\n[DUMMY] TV W-AP110 kpl") + (omni:insert-verbinder "TV_W-AP110_kpl") (princ) ) (defun c:OMNI_TV_W_AP60 () - (princ "\n[DUMMY] TV W-AP60 oben kpl.") + (omni:insert-verbinder "TV_W-AP60_oben") + (princ) +) +(defun c:OMNI_TV_W_AP60_KPL () + (omni:insert-verbinder "TV_W-AP60_kpl") (princ) ) (defun c:OMNI_TV_W_AP110_W () - (princ "\n[DUMMY] TV W-AP110-W kpl") - (princ) -) -(defun c:OMNI_TV_W_AP () - (princ "\n[DUMMY] TV W-AP oben kpl") + (omni:insert-verbinder "TV_W-AP110-W_kpl") (princ) ) (defun c:OMNI_TV_80 () - (princ "\n[DUMMY] TV 80") + (omni:insert-verbinder "TV_80_kpl") (princ) ) (defun c:OMNI_TV_50 () - (princ "\n[DUMMY] TV 50") + (omni:insert-verbinder "TV_50_kpl") (princ) ) (defun c:OMNI_TV_ENDPLATTE () - (princ "\n[DUMMY] Endplatte Al-Profil AP schraubbar") + (omni:insert-verbinder "VB_ENDP_AP") (princ) ) (defun c:OMNI_TV_ANSCHLAG () - (princ "\n[DUMMY] Anschlag AP-Ende fuer Spulenzug") + (omni:insert-verbinder "VB_ENDP_AP_Spulenzug") (princ) ) (defun c:OMNI_TV_A_AP110_AP60 () - (princ "\n[DUMMY] TV-A fuer AP110/AP60 kpl") + (omni:insert-verbinder "TV_AP110-AP60_kpl") (princ) ) (defun c:OMNI_TV_A_AP60_ST () - (princ "\n[DUMMY] TV-A fuer AP60/ST") + (omni:insert-verbinder "TV_AP60-ST_kpl") (princ) ) (defun c:OMNI_TV_A_AP110_ST () - (princ "\n[DUMMY] TV-A fuer AP110/ST kpl") + (omni:insert-verbinder "TV_AP110-ST_kpl") (princ) ) (defun c:OMNI_TV_SW_II_SW_SW () - (princ "\n[DUMMY] TV-SW II fuer SW-SW") + (omni:insert-verbinder "TV_SW-SW") (princ) ) (defun c:OMNI_TV_SW_III_AP110_SW () - (princ "\n[DUMMY] TV-SW III fuer SW-AP110-SW") + (omni:insert-verbinder "TV_SW-AP110-SW") (princ) ) -(defun c:OMNI_TV_SW_III_AP110 () - (princ "\n[DUMMY] TV-SW III fuer SW-AP110") +(defun c:OMNI_TV_W_AP60_KPL () + (omni:insert-verbinder "TV_W-AP60_kpl") + (princ) +) +(defun c:OMNI_TV_SW_I_AP110 () + (omni:insert-verbinder "TV_SW_I_SW-AP110") (princ) ) (defun c:OMNI_TV_SW_IV_AP60 () - (princ "\n[DUMMY] TV-SW IV fuer Anschluss SW-AP60") + (omni:insert-verbinder "TV_SW_IV_SW-AP60") (princ) ) (defun c:OMNI_TV_SW_IV_ST () - (princ "\n[DUMMY] TV-SW IV fuer SW-ST") + (omni:insert-verbinder "TV_SW_IV_SW-ST") (princ) ) (defun c:OMNI_TV_MUFFE () - (princ "\n[DUMMY] Muffe") + (omni:insert-verbinder "VB_Muffe") (princ) ) diff --git a/Lisp/README.md b/Lisp/README.md index 68091b0..fd66a9e 100644 --- a/Lisp/README.md +++ b/Lisp/README.md @@ -39,7 +39,6 @@ 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` | @@ -703,7 +702,7 @@ AutoLISP-Implementierung fuer alle Omniflo-Komponenten: Boegen, Weichen, Verbind | 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 `.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) | +| Verbinder | `OMNI_TV_*` | Verbinder-DWG aus `data/omniflo/Verbinder` (dimensionsunabhaengig, `omni:insert-verbinder` -> `omni:insert-datei`, Punkt + Drehung interaktiv). Zuordnung Befehl -> DWG nach Dateiname, z.B. `OMNI_TV_W_AP60` -> `TV_W-AP60_oben`, `OMNI_TV_ENDPLATTE` -> `VB_ENDP_AP`, `OMNI_TV_W_AP60_KPL` -> `TV_W-AP60_kpl`, `OMNI_TV_ANSCHLAG` -> `VB_ENDP_AP_Spulenzug`, `OMNI_TV_SW_I_AP110` -> `TV_SW_I_SW-AP110`, `OMNI_TV_MUFFE` -> `VB_Muffe`. Alle 18 Eintraege aktiv | | Bogenweichen ⚠️ | `OMNI_APBW_*` | **Dummy** (noch nicht implementiert, im Menue ausgegraut) | | Bearbeiten | `OMNI_EDIT` | Omniflo-Block selektieren und Attribute bearbeiten | diff --git a/Lisp/export.lsp b/Lisp/export.lsp index 197f25b..7c8dff4 100644 --- a/Lisp/export.lsp +++ b/Lisp/export.lsp @@ -2394,6 +2394,9 @@ ;; GeruestInsert.lsp). Wie BTMT eigenstaendig und von keinem anderen ;; Element mitgezaehlt - export_csv.py UND export_sivas.py fuehren sie ;; beide als eigene TeileArt-Zeilen. +;; VB_*/TV_* = Omniflo-Verbinder (siehe pattern_verbinder in +;; cfg/export.cfg, OMNI_TV_* in OmniModulInsert.lsp). export_sivas.py +;; fuehrt sie ueber TEILEART/ARTINR im allgemeinen Omniflo-Zweig. ;; Bloecke auf GEFRORENEN Layern (und die Hilfsobjekte gefrorener VF_n/GF_n) ;; werden ausgelassen, solange *csv-gefrorene-ausschliessen* an ist (Standard, ;; Dialog CSV_EXPORT_KONFIG); ausgeschaltete Layer zaehlen nicht als gefroren. @@ -2445,6 +2448,7 @@ (wcmatch bname (export:pattern "pattern_eingang" "Eingang*")) (wcmatch bname (export:pattern "pattern_ausgang" "Ausgang*")) (wcmatch bname (export:pattern "pattern_geruest" "GR_*")) + (wcmatch bname (export:pattern "pattern_verbinder" "VB_*,TV_*")) (wcmatch bname (export:pattern "pattern_unit_marker" "ZZ_UNIT_MARKER*")) ;; Rein numerische Namen = Omniflo SivasNr (Boegen/Weichen) ;; Rein LISP-intern (Python klassifiziert Omniflo stattdessen diff --git a/Lisp/ssg_id.lsp b/Lisp/ssg_id.lsp index b4a936a..794b98b 100644 --- a/Lisp/ssg_id.lsp +++ b/Lisp/ssg_id.lsp @@ -45,6 +45,8 @@ ;; Spalte (auch auf Kreiseln) bekommen. ;; GR_* (Geruest-Baugruppen, siehe pattern_geruest in cfg/export.cfg) ebenso - ;; das ID-ATTDEF steht seit *geruest-attrib-defs* zur Verfuegung. +;; VB_*/TV_* (Omniflo-Verbinder, siehe pattern_verbinder in +;; cfg/export.cfg) ebenso - fest im Code wie GR_*. ;; Gefaellebogen_* (siehe pattern_nested_bogen in cfg/export.cfg): einer der ;; Bausteine einer GF-Kette, verpackt in VF_n/GF_n; wird beim Export ebenso ;; als temporaere Kopie ausgepackt wie die uebrigen Vario_*/Staustrecke_*- @@ -81,6 +83,7 @@ (wcmatch bname "BTMT-Beladung*,SC_Entladung*") (wcmatch bname "Eingang*,Ausgang*") (wcmatch bname "GR_*") + (wcmatch bname "VB_*,TV_*") (wcmatch bname "#*") ) (ssadd ename ss-out) diff --git a/cfg/export.cfg b/cfg/export.cfg index b3c4909..47f186c 100644 --- a/cfg/export.cfg +++ b/cfg/export.cfg @@ -71,6 +71,11 @@ # Eigenstaendig wie BTMT, kein ANZAHL_*-Attribut an einem Carrier - export_csv.py # UND export_sivas.py fuehren sie als eigene TeileArt-Zeilen. # +# pattern_verbinder: Omniflo-Verbinder (OMNI_TV_*, DWGs in data/omniflo/ +# Verbinder). Nur fuer Lisp's Block-SAMMLUNG und ID-Vergabe - export_sivas.py +# erkennt sie wie alle Omniflo-Teile ueber TEILEART "Omniflo ..." und schreibt +# je Nummer aus ARTINR eine Omniflo-Zeile. +# # pattern_nested_bogen/_streckenelement/_umlenkstation/_motorstation: die # uebrigen Bausteine einer VF_n/GF_n-Kette (Boegen, gerade Foerderer-/ # Gefaellestrecken-Segmente, Umlenk-/Motorstation). Wie pattern_schleuselement @@ -130,6 +135,7 @@ pattern_ks_subblocks= KS_EIN, KS_AUS, K1, K2, K3, K4 pattern_gerade= AP110*, AP_110*, AP60* # Gerüst pattern_geruest= GR_* +pattern_verbinder= VB_*, TV_* [python] # Interpreter fuer die Export-Skripte (lib/export_csv.py, lib/export_sivas.py). diff --git a/data/omniflo/Verbinder/TV_50_kpl.dwg b/data/omniflo/Verbinder/TV_50_kpl.dwg new file mode 100644 index 0000000..fe36410 Binary files /dev/null and b/data/omniflo/Verbinder/TV_50_kpl.dwg differ diff --git a/data/omniflo/Verbinder/TV_80_kpl.dwg b/data/omniflo/Verbinder/TV_80_kpl.dwg new file mode 100644 index 0000000..413581e Binary files /dev/null and b/data/omniflo/Verbinder/TV_80_kpl.dwg differ diff --git a/data/omniflo/Verbinder/TV_AP110-AP60_kpl.dwg b/data/omniflo/Verbinder/TV_AP110-AP60_kpl.dwg new file mode 100644 index 0000000..755a994 Binary files /dev/null and b/data/omniflo/Verbinder/TV_AP110-AP60_kpl.dwg differ diff --git a/data/omniflo/Verbinder/TV_AP110-ST_kpl.dwg b/data/omniflo/Verbinder/TV_AP110-ST_kpl.dwg new file mode 100644 index 0000000..49d8638 Binary files /dev/null and b/data/omniflo/Verbinder/TV_AP110-ST_kpl.dwg differ diff --git a/data/omniflo/Verbinder/TV_AP60-ST_kpl.dwg b/data/omniflo/Verbinder/TV_AP60-ST_kpl.dwg new file mode 100644 index 0000000..17f0695 Binary files /dev/null and b/data/omniflo/Verbinder/TV_AP60-ST_kpl.dwg differ diff --git a/data/omniflo/Verbinder/TV_SW-AP110-SW.dwg b/data/omniflo/Verbinder/TV_SW-AP110-SW.dwg new file mode 100644 index 0000000..bb0415e Binary files /dev/null and b/data/omniflo/Verbinder/TV_SW-AP110-SW.dwg differ diff --git a/data/omniflo/Verbinder/TV_SW-SW.dwg b/data/omniflo/Verbinder/TV_SW-SW.dwg new file mode 100644 index 0000000..8f01eff Binary files /dev/null and b/data/omniflo/Verbinder/TV_SW-SW.dwg differ diff --git a/data/omniflo/Verbinder/TV_SW_IV_SW-AP60.dwg b/data/omniflo/Verbinder/TV_SW_IV_SW-AP60.dwg new file mode 100644 index 0000000..f515a27 Binary files /dev/null and b/data/omniflo/Verbinder/TV_SW_IV_SW-AP60.dwg differ diff --git a/data/omniflo/Verbinder/TV_SW_IV_SW-ST.dwg b/data/omniflo/Verbinder/TV_SW_IV_SW-ST.dwg new file mode 100644 index 0000000..4eaa15f Binary files /dev/null and b/data/omniflo/Verbinder/TV_SW_IV_SW-ST.dwg differ diff --git a/data/omniflo/Verbinder/TV_SW_I_SW-AP110.dwg b/data/omniflo/Verbinder/TV_SW_I_SW-AP110.dwg new file mode 100644 index 0000000..a713d68 Binary files /dev/null and b/data/omniflo/Verbinder/TV_SW_I_SW-AP110.dwg differ diff --git a/data/omniflo/Verbinder/TV_W-AP110-W_kpl.dwg b/data/omniflo/Verbinder/TV_W-AP110-W_kpl.dwg new file mode 100644 index 0000000..9439429 Binary files /dev/null and b/data/omniflo/Verbinder/TV_W-AP110-W_kpl.dwg differ diff --git a/data/omniflo/Verbinder/TV_W-AP110_kpl.dwg b/data/omniflo/Verbinder/TV_W-AP110_kpl.dwg new file mode 100644 index 0000000..7163b12 Binary files /dev/null and b/data/omniflo/Verbinder/TV_W-AP110_kpl.dwg differ diff --git a/data/omniflo/Verbinder/TV_W-AP60_kpl.dwg b/data/omniflo/Verbinder/TV_W-AP60_kpl.dwg new file mode 100644 index 0000000..6efc598 Binary files /dev/null and b/data/omniflo/Verbinder/TV_W-AP60_kpl.dwg differ diff --git a/data/omniflo/Verbinder/TV_W-AP60_oben.dwg b/data/omniflo/Verbinder/TV_W-AP60_oben.dwg new file mode 100644 index 0000000..aaaa219 Binary files /dev/null and b/data/omniflo/Verbinder/TV_W-AP60_oben.dwg differ diff --git a/data/omniflo/Verbinder/TV_W-W_kpl.dwg b/data/omniflo/Verbinder/TV_W-W_kpl.dwg new file mode 100644 index 0000000..cc2f35a Binary files /dev/null and b/data/omniflo/Verbinder/TV_W-W_kpl.dwg differ diff --git a/data/omniflo/Verbinder/VB_ENDP_AP.dwg b/data/omniflo/Verbinder/VB_ENDP_AP.dwg new file mode 100644 index 0000000..ecdced7 Binary files /dev/null and b/data/omniflo/Verbinder/VB_ENDP_AP.dwg differ diff --git a/data/omniflo/Verbinder/VB_ENDP_AP_Spulenzug.dwg b/data/omniflo/Verbinder/VB_ENDP_AP_Spulenzug.dwg new file mode 100644 index 0000000..729a3e0 Binary files /dev/null and b/data/omniflo/Verbinder/VB_ENDP_AP_Spulenzug.dwg differ diff --git a/data/omniflo/Verbinder/VB_Muffe.dwg b/data/omniflo/Verbinder/VB_Muffe.dwg new file mode 100644 index 0000000..140449f Binary files /dev/null and b/data/omniflo/Verbinder/VB_Muffe.dwg differ diff --git a/doc/kommandos.md b/doc/kommandos.md index f4e3513..12230ba 100644 --- a/doc/kommandos.md +++ b/doc/kommandos.md @@ -98,7 +98,7 @@ Gross-/Kleinschreibung spielt an der Kommandozeile keine Rolle. | `OMNI_APBW_R400_45_140`, `OMNI_APBW_R400_675_260`, `OMNI_APBW_R550_45_77`, `OMNI_APBW_R550_45_194`, `OMNI_APBW_R550_225_360`, `OMNI_APBW_R550_225_410A`/`B`/`C`, `OMNI_APBW_R550_675_58`/`_125`/`_208`/`_360`, `OMNI_APBW_R650_90_300`, `OMNI_APBW_R750_90_200` | Boegen fuer Weichen (fest, ohne Dialog) | | `OMNI_TEF_UmlenkL`/`R`, `OMNI_TEF_AntriebL`/`R`, `OMNI_TEF_Gerade` | TEF-Elemente (fest, ohne Drehung) | | `OMNI_STOPPER`, `OMNI_SCANNER`, `OMNI_BUERSTENBREMSE` | Anbaugruppen | -| `OMNI_TV_W_W`, `OMNI_TV_W_AP`, `OMNI_TV_W_AP60`, `OMNI_TV_W_AP110`, `OMNI_TV_W_AP110_W`, `OMNI_TV_50`, `OMNI_TV_80`, `OMNI_TV_ENDPLATTE`, `OMNI_TV_ANSCHLAG`, `OMNI_TV_MUFFE`, `OMNI_TV_A_AP110_AP60`, `OMNI_TV_A_AP60_ST`, `OMNI_TV_A_AP110_ST`, `OMNI_TV_SW_II_SW_SW`, `OMNI_TV_SW_III_AP110`, `OMNI_TV_SW_III_AP110_SW`, `OMNI_TV_SW_IV_AP60`, `OMNI_TV_SW_IV_ST` | Verbinder | +| `OMNI_TV_W_W`, `OMNI_TV_W_AP60`, `OMNI_TV_W_AP60_KPL`, `OMNI_TV_W_AP110`, `OMNI_TV_W_AP110_W`, `OMNI_TV_50`, `OMNI_TV_80`, `OMNI_TV_ENDPLATTE`, `OMNI_TV_ANSCHLAG`, `OMNI_TV_MUFFE`, `OMNI_TV_A_AP110_AP60`, `OMNI_TV_A_AP60_ST`, `OMNI_TV_A_AP110_ST`, `OMNI_TV_SW_II_SW_SW`, `OMNI_TV_SW_I_AP110`, `OMNI_TV_SW_III_AP110_SW`, `OMNI_TV_SW_IV_AP60`, `OMNI_TV_SW_IV_ST` | Verbinder | | `OMNI_LADESCHLEIFE_AP110` | Ladeschleife (Dialog `omniflo_ladeschleifen.dcl`) | | `OMNI_KettenFoerderer` | Platzhalter (noch ohne Funktion) | | `OMNI_EDIT` | Omniflo-Element per Dialog bearbeiten; auch per Doppelklick | diff --git a/menu/SSG_LIB.cui b/menu/SSG_LIB.cui index 4db8efd..85b684e 100644 --- a/menu/SSG_LIB.cui +++ b/menu/SSG_LIB.cui @@ -411,23 +411,23 @@ - - TV W-W kpl - ^C^C(ssg-ensure "OmniModulInsert") OMNI_TV_W_W - - - TV W-AP110 kpl ^C^C(ssg-ensure "OmniModulInsert") OMNI_TV_W_AP110 - + TV W-AP60 oben kpl. ^C^C(ssg-ensure "OmniModulInsert") OMNI_TV_W_AP60 + + + TV W-W kpl + ^C^C(ssg-ensure "OmniModulInsert") OMNI_TV_W_W + + TV W-AP110-W kpl @@ -436,8 +436,8 @@ - TV W-AP oben kpl - ^C^C(ssg-ensure "OmniModulInsert") OMNI_TV_W_AP + TV W-AP60 kpl + ^C^C(ssg-ensure "OmniModulInsert") OMNI_TV_W_AP60_KPL @@ -460,55 +460,55 @@ - Anschlag AP-Ende fuer Spulenzug + Anschlag AP-Ende für Spulenzug ^C^C(ssg-ensure "OmniModulInsert") OMNI_TV_ANSCHLAG - TV-A fuer AP110/AP60 kpl + TV-A für AP110/AP60 kpl ^C^C(ssg-ensure "OmniModulInsert") OMNI_TV_A_AP110_AP60 - TV-A fuer AP60/ST + TV-A für AP60/ST ^C^C(ssg-ensure "OmniModulInsert") OMNI_TV_A_AP60_ST - TV-A fuer AP110/ST kpl + TV-A für AP110/ST kpl ^C^C(ssg-ensure "OmniModulInsert") OMNI_TV_A_AP110_ST - TV-SW II fuer SW-SW + TV-SW II für SW-SW ^C^C(ssg-ensure "OmniModulInsert") OMNI_TV_SW_II_SW_SW - TV-SW III fuer SW-AP110-SW + TV-SW III für SW-AP110-SW ^C^C(ssg-ensure "OmniModulInsert") OMNI_TV_SW_III_AP110_SW - TV-SW III fuer SW-AP110 - ^C^C(ssg-ensure "OmniModulInsert") OMNI_TV_SW_III_AP110 + TV-SW I für SW-AP110 + ^C^C(ssg-ensure "OmniModulInsert") OMNI_TV_SW_I_AP110 - TV-SW IV fuer Anschluss SW-AP60 + TV-SW IV für Anschluss SW-AP60 ^C^C(ssg-ensure "OmniModulInsert") OMNI_TV_SW_IV_AP60 - TV-SW IV fuer SW-ST + TV-SW IV für SW-ST ^C^C(ssg-ensure "OmniModulInsert") OMNI_TV_SW_IV_ST @@ -872,61 +872,61 @@ ^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_showroom_ils.lsp")) (c:TEST_SHOWROOM_ILS) - + Testanlage test_system ^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_test_system.lsp")) (c:TEST_TEST_SYSTEM) - + KS 2D/3D pruefen (CSV) ^C^C(load (strcat (getenv "DXFMAKRO") "/Lisp/ks_pruefung.lsp")) KS_PRUEFEN - + Kreisel bearbeiten (ssg-ensure "KreiselInsert") KreiselEdit - + Eckrad bearbeiten (ssg-ensure "KreiselInsert") EckradEdit - + Omniflo Element bearbeiten (ssg-ensure "OmniModulInsert") OMNI_EDIT - + Gefaellestrecke bearbeiten (ssg-ensure "Gefaellestrecke") GEFAELLESTRECKE_EDIT - + VarioFoerderer bearbeiten (ssg-ensure "VarioFoerderer") VARIOFOERDERER_EDIT - + TRO-Marker bearbeiten (ssg-ensure "Tro_Edit") TRO_EDIT - + Verbindung bearbeiten (ssg-ensure "Connection_Edit") CONNECTION_EDIT - + SSG Bearbeiten (Auto) (ssg-ensure "SSG_LIB_Commands") SSG_BLOCKEDIT @@ -1430,109 +1430,109 @@ Verbinder - ~TV W-W kpl + TV W-AP110 kpl - ~TV W-AP110 kpl + TV W-AP60 oben kpl. - ~TV W-AP60 oben kpl. + TV W-W kpl - ~TV W-AP110-W kpl + TV W-AP110-W kpl - ~TV W-AP oben kpl + TV W-AP60 kpl - ~TV 80 + TV 80 - ~TV 50 + TV 50 - ~Endplatte Al-Profil AP schraubbar + Endplatte Al-Profil AP schraubbar - ~Anschlag AP-Ende fuer Spulenzug + Anschlag AP-Ende für Spulenzug - ~TV-A fuer AP110/AP60 kpl + TV-A für AP110/AP60 kpl - ~TV-A fuer AP60/ST + TV-A für AP60/ST - ~TV-A fuer AP110/ST kpl + TV-A für AP110/ST kpl - ~TV-SW II fuer SW-SW + TV-SW II für SW-SW - ~TV-SW III fuer SW-AP110-SW + TV-SW III für SW-AP110-SW - ~TV-SW III fuer SW-AP110 + TV-SW I für SW-AP110 - ~TV-SW IV fuer Anschluss SW-AP60 + TV-SW IV für Anschluss SW-AP60 - ~TV-SW IV fuer SW-ST + TV-SW IV für SW-ST - ~Muffe + Muffe @@ -1930,66 +1930,66 @@ Testanlage test_system - + KS 2D/3D pruefen (CSV) - + - + POP501 SSG_LIB Edit Context Kreisel bearbeiten - + Eckrad bearbeiten - + Omniflo Element bearbeiten - + Gefaellestrecke bearbeiten - + VarioFoerderer bearbeiten - + TRO-Marker bearbeiten - + Verbindung bearbeiten - + SSG Bearbeiten (Auto) - + diff --git a/menu/SSG_LIB.mnu b/menu/SSG_LIB.mnu index e09f703..5c406bb 100644 --- a/menu/SSG_LIB.mnu +++ b/menu/SSG_LIB.mnu @@ -95,24 +95,24 @@ [~KettenFoerderer]^C^C(ssg-ensure "OmniModulInsert") OMNI_KettenFoerderer [Ladeschleifen]^C^C(ssg-ensure "OmniModulInsert") OMNI_LADESCHLEIFE_AP110 [->Verbinder] -[~TV W-W kpl]^C^C(ssg-ensure "OmniModulInsert") OMNI_TV_W_W -[~TV W-AP110 kpl]^C^C(ssg-ensure "OmniModulInsert") OMNI_TV_W_AP110 -[~TV W-AP60 oben kpl.]^C^C(ssg-ensure "OmniModulInsert") OMNI_TV_W_AP60 -[~TV W-AP110-W kpl]^C^C(ssg-ensure "OmniModulInsert") OMNI_TV_W_AP110_W -[~TV W-AP oben kpl]^C^C(ssg-ensure "OmniModulInsert") OMNI_TV_W_AP -[~TV 80]^C^C(ssg-ensure "OmniModulInsert") OMNI_TV_80 -[~TV 50]^C^C(ssg-ensure "OmniModulInsert") OMNI_TV_50 -[~Endplatte Al-Profil AP schraubbar]^C^C(ssg-ensure "OmniModulInsert") OMNI_TV_ENDPLATTE -[~Anschlag AP-Ende fuer Spulenzug]^C^C(ssg-ensure "OmniModulInsert") OMNI_TV_ANSCHLAG -[~TV-A fuer AP110/AP60 kpl]^C^C(ssg-ensure "OmniModulInsert") OMNI_TV_A_AP110_AP60 -[~TV-A fuer AP60/ST]^C^C(ssg-ensure "OmniModulInsert") OMNI_TV_A_AP60_ST -[~TV-A fuer AP110/ST kpl]^C^C(ssg-ensure "OmniModulInsert") OMNI_TV_A_AP110_ST -[~TV-SW II fuer SW-SW]^C^C(ssg-ensure "OmniModulInsert") OMNI_TV_SW_II_SW_SW -[~TV-SW III fuer SW-AP110-SW]^C^C(ssg-ensure "OmniModulInsert") OMNI_TV_SW_III_AP110_SW -[~TV-SW III fuer SW-AP110]^C^C(ssg-ensure "OmniModulInsert") OMNI_TV_SW_III_AP110 -[~TV-SW IV fuer Anschluss SW-AP60]^C^C(ssg-ensure "OmniModulInsert") OMNI_TV_SW_IV_AP60 -[~TV-SW IV fuer SW-ST]^C^C(ssg-ensure "OmniModulInsert") OMNI_TV_SW_IV_ST -[<-~Muffe]^C^C(ssg-ensure "OmniModulInsert") OMNI_TV_MUFFE +[TV W-AP110 kpl]^C^C(ssg-ensure "OmniModulInsert") OMNI_TV_W_AP110 +[TV W-AP60 oben kpl.]^C^C(ssg-ensure "OmniModulInsert") OMNI_TV_W_AP60 +[TV W-W kpl]^C^C(ssg-ensure "OmniModulInsert") OMNI_TV_W_W +[TV W-AP110-W kpl]^C^C(ssg-ensure "OmniModulInsert") OMNI_TV_W_AP110_W +[TV W-AP60 kpl]^C^C(ssg-ensure "OmniModulInsert") OMNI_TV_W_AP60_KPL +[TV 80]^C^C(ssg-ensure "OmniModulInsert") OMNI_TV_80 +[TV 50]^C^C(ssg-ensure "OmniModulInsert") OMNI_TV_50 +[Endplatte Al-Profil AP schraubbar]^C^C(ssg-ensure "OmniModulInsert") OMNI_TV_ENDPLATTE +[Anschlag AP-Ende für Spulenzug]^C^C(ssg-ensure "OmniModulInsert") OMNI_TV_ANSCHLAG +[TV-A für AP110/AP60 kpl]^C^C(ssg-ensure "OmniModulInsert") OMNI_TV_A_AP110_AP60 +[TV-A für AP60/ST]^C^C(ssg-ensure "OmniModulInsert") OMNI_TV_A_AP60_ST +[TV-A für AP110/ST kpl]^C^C(ssg-ensure "OmniModulInsert") OMNI_TV_A_AP110_ST +[TV-SW II für SW-SW]^C^C(ssg-ensure "OmniModulInsert") OMNI_TV_SW_II_SW_SW +[TV-SW III für SW-AP110-SW]^C^C(ssg-ensure "OmniModulInsert") OMNI_TV_SW_III_AP110_SW +[TV-SW I für SW-AP110]^C^C(ssg-ensure "OmniModulInsert") OMNI_TV_SW_I_AP110 +[TV-SW IV für Anschluss SW-AP60]^C^C(ssg-ensure "OmniModulInsert") OMNI_TV_SW_IV_AP60 +[TV-SW IV für SW-ST]^C^C(ssg-ensure "OmniModulInsert") OMNI_TV_SW_IV_ST +[<-Muffe]^C^C(ssg-ensure "OmniModulInsert") OMNI_TV_MUFFE [->Boegen fuer Weichen] [~APB 110 R400/45 140 nur fuer Delta]^C^C(ssg-ensure "OmniModulInsert") OMNI_APBW_R400_45_140 [~APB 110 R550/45 194 nur fuer Delta]^C^C(ssg-ensure "OmniModulInsert") OMNI_APBW_R550_45_194 diff --git a/tests/test_unit.lsp b/tests/test_unit.lsp index 78a235e..41c6d23 100644 --- a/tests/test_unit.lsp +++ b/tests/test_unit.lsp @@ -794,6 +794,14 @@ (tu-eq "omni:filter/anzahl" 2 (length (omni:filter _lst "KurvenWinkel" 45))) (tu-eq "omni:filter/wert" 100 (cdr (assoc "Sivasnr" (car (omni:filter _lst "KurvenWinkel" 45))))) + + ;; Verbinder-Pfad: Backslashes normalisiert, abschliessender Trenner entfernt + (tu-eq "omni:verbinder-pfad/backslash" + "C:/x/data/omniflo/Verbinder/TV_W-W_kpl.dwg" + (omni:verbinder-pfad "C:\\x\\data" "TV_W-W_kpl")) + (tu-eq "omni:verbinder-pfad/trenner" + "C:/x/data/omniflo/Verbinder/VB_ENDP_AP.dwg" + (omni:verbinder-pfad "C:/x/data/" "VB_ENDP_AP")) )