diff --git a/CLAUDE.md b/CLAUDE.md index 48dbdc5..d893b14 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -70,7 +70,7 @@ Die `start_briscad.bat` ruft `setenv.bat` auf und startet BricsCAD. | Menue-Bereich | Modul | Befehle | |---|---|---| -| Kreisel-Module | `KreiselInsert` | KreiselInsert, KreiselConnect, KreiselEdit, ILS_Eckrad | +| Kreisel-Module | `KreiselInsert` | KreiselInsert, KreiselConnect, KreiselEdit, ILS_Eckrad, EckradEdit | | TRO | `Tro_Edit` | TRO_INSERT, TRO_EDIT | | Zusatzmodul/Foerderer/Kurven | `SSG_LIB_Commands` | ILS_BTMT_*, ILS_ETF_*, ILS_GK*_* | | VarioFoerderer | `VarioFoerderer` | FOERDERANLAGE, VARIOFOERDERER_EDIT, Vario_Kette_Merge | @@ -81,7 +81,7 @@ Die `start_briscad.bat` ruft `setenv.bat` auf und startet BricsCAD. | Export | `export` | EXPORTSIVAS, EXPORTCSV, CALLPYTHON | | Werkzeuge | `ssg_blocktools`, `ssg_texttools`, `ssg_stueckliste`, `DinFormate` | SSG_BLOCK_COUNT, SSG_BLOCK_DELETE, SSG_ATTR_ERSETZEN, SSG_TEXT_ERSETZEN, SSG_TEXT_PARALLEL, SSG_TEXT_HOEHE, SSG_TEXT_STIL, SSG_FAEHNCHEN_STUECKLISTE, DIN_FORMATE | | Konfiguration | `SSG_LIB_Commands` + `DrawPlanquadrate` | SSG_DIM_SWITCH, SSG_SPRACHE, PLANQUADRATE_TOGGLE (DRAW_PLANQUADRATE/DELETE_PLANQUADRATE) | -| Doppelklick/Kontextmenue | `SSG_LIB_Commands` | SSG_BLOCKEDIT (dispatcht Kreisel->KreiselEdit, Omniflo->OMNI_EDIT, GF_*->GEFAELLESTRECKE_EDIT, VF_*->VARIOFOERDERER_EDIT) | +| Doppelklick/Kontextmenue | `SSG_LIB_Commands` | SSG_BLOCKEDIT (dispatcht Kreisel->KreiselEdit, Eckrad->EckradEdit, Omniflo->OMNI_EDIT, GF_*->GEFAELLESTRECKE_EDIT, VF_*->VARIOFOERDERER_EDIT) | ### Entfernte Legacy-Dateien @@ -105,11 +105,11 @@ Detaillierte Dokumentation aller Funktionen und Befehle: siehe `Lisp/README.md`. | `ssg_blocktools.lsp` | SSG_BLOCK_COUNT, SSG_BLOCK_DELETE, SSG_ATTR_ERSETZEN | Block-Werkzeuge fuer das aktuelle Layout (Ursprung ACADSST `TOOLS.LSP`/`ssg.lsp`): Einfuegungen zaehlen (Pick, wcmatch-Muster oder Statistik aller Bloecke), alle Einfuegungen loeschen (Rueckfrage, gesperrte Layer bleiben), Attributwerte zeichnungsweit/in Auswahl suchen+ersetzen (Vorschau mit Anzahl, Teilstring oder Gesamtwert). Wirksamer Blockname (dynamische Bloecke). Reine Kerne `ssg-bt-name-passt-p`, `ssg-bt-zaehle-namen`, `ssg-bt-wert-neu` in `tests/test_unit.lsp` getestet | | `ssg_texttools.lsp` | SSG_TEXT_ERSETZEN, SSG_TEXT_PARALLEL, SSG_TEXT_HOEHE, SSG_TEXT_STIL | Text-Werkzeuge (Ursprung ACADSST `CHGTEXT`/`PARTEXT`/`ALTHOEHE`/`ALTSTIL`): Suchen/Ersetzen in TEXT, MTEXT und Block-Attributen (nutzt `ssg-bt-*`, daher NACH `ssg_blocktools` laden), Text parallel zu Linie/Polylinie/Bogen (lesbar ausgerichtet, Abstand), Hoehe/Stil aendern. Arbeitet in der XY-Ebene des Welt-KS. Reine Kerne `ssg-tt-lesbarer-winkel`, `ssg-tt-versetzt` getestet | | `ssg_stueckliste.lsp` | SSG_FAEHNCHEN_STUECKLISTE | Positions-Faehnchen + Stuecklistentabelle, komplett AUS DER ZEICHNUNG - es wird keine Datei eingelesen. Der Benutzer waehlt die Elemente aus (`ssg-sl-erkannte-elemente`: `ssget`-Auswahl, Enter ohne Auswahl = alle erkannten im aktuellen Layout; der reine Filter `ssg-sl-elemente-aus-ss` laesst nicht erkannte Objekte still wegfallen, man darf also grosszuegig ein Fenster aufziehen). `ssg-sl-klasse` klassifiziert Blocknamen (`KREISEL_*`/`ECKRAD_*` -> "ILS Kreisel/Eckrad", `VF_*`/`GF_*` -> "ILS Streckengruppe", `GR_*` -> "Rohrgeruest", `AP60*`/`AP110*`/`AP_110*`/`APG110*` -> je eigene Omniflo-Geraden-Gruppe; wirksamer Blockname ueber `ssg-bt-effname`, also auch dynamische Bloecke). Jedes einzelne Element bekommt ein Faehnchen (`ssg-sl-faehnchen`, Rechteck/Kreis/Automation-Rahmen + Text) an der unteren linken Ecke seiner Bounding-Box (aus `csv:get-bbox` - liefert Zentrum+Abmessungen, NICHT Eckpunkte, die Ecke wird im Code daraus berechnet); die Tabelle (`ssg-sl-tabelle-zeichnen`) gruppiert GROB je Elementklasse (keine Sivas-Artikelaufloesung wie `export_sivas.py`) zu einer Zeile mit Anzahl + Laengensumme aus dem `LAENGE`-Attribut (`ssg-sl-gruppieren`/reiner Kern `ssg-sl-gruppieren-werte`), mehrere gleichartige Elemente tragen daher dieselbe Positionsnummer. **Bewusst KEIN Datei-Import wie bei Walz/Bihler**: dort vergab ein externes System die Positionsnummern und lieferte sie als Datei zurueck, die das CAD nur abzeichnete - bei Walz (`MENU/POSITION.LSP`) eine `.pos`/`.zei` aus einem Clipper-Warenwirtschaftssystem mit Koordinaten-Zuordnung, bei Bihler ITB (`Walz_und_Bihler/SBCADBib/ITB-Module_ori.lsp`, `c:bea_pos`) eine `.pos` mit Zuordnung ueber den Entity-Handle. Diese Umwege sind hier nicht nachgebaut (Entscheidung 2026-10): Nummern und Mengen entstehen in dieser Funktion, die Stuecklisten-AUSGABE liefern EXPORTSIVAS/EXPORTCSV aus denselben Block-Attributen. Der alte `c:stueckl` (Laengen-Summierung ueber hartcodierte Walz-Profillayer wie `L-2`=ST, `A-7`=AP110) hat ebenfalls kein Aequivalent im dxfmakros-Datenmodell (Block-Attribute statt Linien-Layer). Braucht `csv:get-bbox`/`csv:get-attrib` aus `export.lsp` und `ssg-bt-effname` aus `ssg_blocktools.lsp` - muss daher NACH beiden geladen werden (siehe `ssg-ensure`-Reihenfolge in `SSG_LIB.mnl`/`ssg_load.lsp`). Reine Kerne `ssg-sl-klasse`, `ssg-sl-gruppieren-werte` in `tests/test_unit.lsp` getestet | -| `KreiselInsert.lsp` | KreiselInsert, KreiselConnect, KreiselRedraw, KreiselQuick, KreiselEdit, KreiselParams, KreiselLabelSetup, KreiselLabelPos, KreiselLabelHoehe, ILS_Eckrad | ILS Kreisel und Eckrad komplett in AutoLISP | +| `KreiselInsert.lsp` | KreiselInsert, KreiselConnect, KreiselRedraw, KreiselQuick, KreiselEdit, KreiselParams, KreiselLabelSetup, KreiselLabelPos, KreiselLabelHoehe, ILS_Eckrad, EckradEdit | ILS Kreisel und Eckrad komplett in AutoLISP. Eckrad: eigener Dialog `eckrad_edit.dcl` (`eckrad-dialog`, reiner Kern `eckrad-dialog-werte` getestet) beim Einfuegen (ILS_Eckrad, ohne GUI Konsolen-Rueckfall) und per Doppelklick (EckradEdit); kein Abstand/Typ, Drehung als freier Winkel statt fester Kreisel-Ausrichtung. `ils-eckrad-insert` behaelt eine vorhandene NUMMER (Edit -> gleicher Blockname `ECKRAD_n`). Kreiselname: `draw-module` setzt `Bezeichnung` nur noch bei leerem Wert auf die Vorgabe `KreiselN` (eigener Name aus KreiselEdit bleibt erhalten); Beschriftung `kreisel-label-text` = `KREISEL n: _` (ohne Namen bzw. bei Vorgabename wie bisher `KREISEL n: _`); da die Beschriftung als TEXT in der wiederverwendeten Blockdefinition `KREISEL_n_TYP_ABSTAND` steckt, setzt `kreisel-label-aktualisieren` sie dort per `entmod` neu (wirkt auf alle Referenzen der Definition) | | `VarioFoerderer.lsp` (Wrapper fuer `vf_core.lsp`/`vf_standard.lsp`/`vf_etage.lsp`/`vf_linienzug.lsp`) | FOERDERANLAGE, VARIOFOERDERER_EDIT, VARIOFOERDERER_NACHRUESTEN, Vario_Kette_Merge, VF_SEKTION_RESTORE, VF_WIZARD_AN, VF_WIZARD_AUS | Vario-Foerderanlagen Generator (Typen Standard/Etage/Linienzug); Standard- UND Etage-Typ: Werteingabe per DCL-Dialog, inkl. der vorgelagerten Eingabemodus-Wahl 3D-Linie/Werte manuell (`vfc_eingabemodus`, `vfc-dialog-eingabemodus-waehlen`) - beide Modi laufen seitdem in denselben Basis-/Winkel-Dialog, der Konsolen-Pfad ist nur noch Rueckfall bei abgeschalteter GUI/anderer Sprache. Der Dialog-Ablauf ist zentral in vf_core (`vf-dialog-ablauf`/`vf-dialog-berechnen-einfuegen`, parametrisiert ueber Typ-Registry `*vf-typ-registry*` + Flag `horizontal-p`); `vfs-standard-dialog-ablauf`/`vfe-etage-dialog-ablauf` sind nur noch duenne Wrapper darauf. Beide nutzen dieselben Dialoge `vfs-dialog-eingabe-basis`/`vfs-dialog-winkel-verteilung` und den gemeinsamen L_GF/L_VF-Solve `vf-winkel-solve` (vf_core; berechne-alle-winkel/berechne-winkel-etage teilen ihn); Doppelklick auf VF_n-Block ruft VARIOFOERDERER_EDIT, das per SSG_VF_EDIT-XDATA-Marker ("standard"/"etage"/"linienzug") in den passenden Neuaufbau-Zweig dispatcht (`vfe-edit-ent` fuer Etage, `vfl-edit-ent` fuer Linienzug); Altbestand-Bloecke ohne Marker werden abgewiesen. Linienzug (Modus 1, `vf-linienzug-modus`) zeichnet jede interaktive Eingabe in einem Journal auf (`vfl-in-point`/`-string`/`-real`/`-int`) und schreibt es als XDATA auf den fertigen `VF_n`-Block; ein Abbruch (ESC) loescht dadurch nichts mehr, sondern wickelt die bis dahin gebaute Teil-Geometrie ebenso zu einem Block (`vfl-modus-abbruch-sichern`) - sie bleibt stehen und ist sofort per Doppelklick weiter editierbar/fortsetzbar. Der komplette Linienzug-Hauptstrang (Menue-Fragen von AS-Element bis Kettenende, inkl. GF-Bogen/Vario-Kurve/VF-Einheit-Fortsetzung) laeuft per Default ueber DCL-Dialoge statt Konsole (`*vfl-wizard-mode*`, Befehle VF_WIZARD_AN/VF_WIZARD_AUS): `vfl-in-string`/`-int`/`-real` zeigen bei aktivem Wizard-Modus generische Dialoge aus `dcl/vf_linienzug_wizard.dcl` (Zahl-Eingabe bzw. Mehrfachauswahl aus `vfl-menu`/`vfl-menu-int`) statt `getstring`/`getint`/`getreal` aufzurufen; die ORIGINALEN Konsolen-Fragen (princ + get*, de/en ueber ssg-text) bleiben unveraendert im Code (Fallback bei Fehlern via `vl-catch-all-apply`, siehe `doc/variofoerderer.md`). `vfl-edit-ent` liest das Journal, zeigt die Sektionen ueber einen DCL-Dialog (`vfl-dlg-position`, `dcl/vfl_edit.dcl`) an, kuerzt bei Bedarf auf eine gewaehlte Sektion (stummer Replay der behaltenen Eingaben, umgeht den Wizard-Zweig komplett) und baut danach interaktiv weiter. Linienzug Modus 2 (Pfad+Zielhoehe-Solver, `vf-linienzug-modus2`) nutzt dieselben Wrapper PLUS die neue Objektauswahl-Wrapper-Funktion `vfl-in-selection` (Pfad-Objekte als stabile Entity-Handles journalisiert, neue Journal-Art `"OBJS"`) und schreibt sein Journal unter dem eigenen XDATA-Marker `"linienzug2"`; Doppelklick baut hier NICHT abschnittsweise, sondern per vollem Reset 1:1 aus dem Journal neu auf (`vfl-edit-ent2`, dispatcht aus `vfl-edit-ent` per Marker) - Modus 3 (Vorwaerts-Nachbau) bleibt bewusst reine Konsole (im Code selbst als Legacy/"wird umgebaut" markiert). `Vario_Kette_Merge` (in vf_linienzug.lsp) fuehrt mehrere einzeln gebaute VF_n-Bloecke ab einem gewaehlten Start-Baustein ueber die reale KS_AUS->KS_EIN-Nachbarschaft zu einem Gesamt-Block zusammen (aggregierte Attribute, Luecken-Erkennung). Die interaktiven Editier-Pfade (`vfl-edit-ent` Sektions-Zweig, `vfl-edit-ent2`) rufen den Neuaufbau BEWUSST direkt auf, NICHT ueber `vl-catch-all-apply`: der alte Block ist beim Neuaufbau schon per `entdel` weg, und ein Catch faengt den Abbruch VOR `*error*` ab - der Abbruch-Wickler `vfl-modus-abbruch-sichern` kaeme nie zum Zug und die ganze Kette bliebe als lose Einzelteile ohne Block liegen (Fehlerbild "VF-Block aufgebrochen"). Nur der nicht-interaktive Batch-Konverter `vfl-konvertiere-ent` behaelt den Catch (die Batch-Schleife muss weiterlaufen) und meldet den betroffenen Block. Die Abbruch-Handler setzen zusaetzlich `*ssg-ils-dim*` zurueck, weil der Aufrufer, der das sonst tut, nach einem Abbruch nicht mehr erreicht wird. Recovery-Pfad fuer bereits aufgebrochene Ketten: `VF_SEKTION_RESTORE` (vf_linienzug.lsp) setzt das Ketten-Journal aus der XDATA der losen Objekte zusammen - `SSG_VF_EDIT_SEG` traegt pro Entity den Journal-Abschnitt DER ITERATION, in der es entstand (indiziert mit dem ersten Glied-Index darin; eine VF-Einheit mit eingebetteten Vario-Kurven erzeugt mehrere Glieder in einer Iteration), `SSG_VF_EDIT_PRE` auf den Entities des ersten Gliedes die Praeambel (Startpunkt/Starthoehe/AS). Die `.dbg`-Dateien sind reine AUSGABE und werden von keinem Befehl gelesen (dbgopen legt sie bei jedem Lauf neu an) - Wiederherstellungs-Daten gehoeren in die XDATA. `vf_konstanten.lsp` (von vf_core.lsp vor den drei Submodulen geladen) sammelt alle Laengen-/Winkel-/Toleranz-Magic-Numbers aus dem VarioFoerderer-Cluster als dokumentierte `*vfk-*`-Konstanten. Die Migration ist abgeschlossen: vf_core/vf_standard/vf_etage/vf_linienzug referenzieren durchgaengig die zentralen Konstanten statt roher Literale (Winkel, Stations-/Separator-Laengen, Mindestlaengen, AS/ES-Fallback-Versaetze, Text-/Label-Masse) - Ausnahmen sind in `vf_konstanten.lsp` selbst dokumentiert (Werte mit fuehrender Config-Anbindung via `ssg-cfg-or`, itoa-/Integer-Kontexte, Blocknamen-Strings, die 2000.0-mm/m-Umrechnung). `*vfk-gf-bogen-winkel*` (30/60/90, GF-Bogen + Vario-Kurve) und `*vfk-as-es-winkel*` ("30"/"90", AS/ES; bewusst STRING, da 2-wertig und im Journal als STR gefuehrt) sind Beispiele; vf_linienzug hat fuer beide einen Fallback, falls vf_konstanten nicht geladen wurde. **Nicht-interaktiver Betrieb**: `*vfl-headless*` (+ `vfl-headless-p`/`-abbruch`/`-notausgang`, Diagnose `*vfl-headless-fehler*`, optionaler Antwort-Hook `*vfl-headless-antwort-fn*`) verbietet jede Live-Eingabe - eine erschoepfte Replay-Queue ist damit ein harter Abbruch MIT Fundstelle (Art der Eingabe, Glied- und Eingabe-Nummer) statt eines stillen Rueckfalls auf `getpoint`/`getreal`; eingebaut in `vfl-in-value`/`-value-p`/`-selection`/`-abstand`. Die Bau-Pfade melden abgewiesene Sektionen ueber `vfl-meldung` (sammelt nach `*vfl-meldungen*` + `dbgmsg`, `alert` nur bei erlaubter GUI, sonst `princ`) statt per blockierendem `alert`; reine Interaktiv-Alerts (fehlendes DCL, "nicht editierbar", "kein Journal") bleiben `alert`. Genutzt von `tests/test_hm_recformat.lsp` (Replay der echten Aufzeichnungen) und von `vf_spec.lsp`; Fahrplan in `doc/todo/plan-vf-interactive.md`. Details/Entscheidungsbaum: `doc/variofoerderer.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) | -| `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 | +| `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 | | `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. | @@ -123,6 +123,7 @@ Detaillierte Dokumentation aller Funktionen und Befehle: siehe `Lisp/README.md`. | Datei | Verwendet von | |---|---| | `kreisel_edit.dcl` | KreiselEdit (KreiselInsert.lsp) | +| `eckrad_edit.dcl` | ILS_Eckrad + EckradEdit (KreiselInsert.lsp, `eckrad-dialog`) | | `gefaellestrecke.dcl` | GEFAELLESTRECKE Modus 1 (Gefaellestrecke.lsp, `gf-dialog-eingabe`) | | `variofoerderer.dcl` | FOERDERANLAGE Standardfall + Werteingabe (vf_standard.lsp, `vfs-dialog-eingabe-basis`/`vfs-dialog-winkel-verteilung`) | | `omniflo_boegen.dcl` | OMNI_APB_* (OmniModulInsert.lsp) | diff --git a/Lisp/Gefaellestrecke.lsp b/Lisp/Gefaellestrecke.lsp index c03d27e..7a003cb 100644 --- a/Lisp/Gefaellestrecke.lsp +++ b/Lisp/Gefaellestrecke.lsp @@ -2496,6 +2496,8 @@ es-winkel (nth 3 xd) z-start (atof (nth 4 xd)) deltaL (atof (nth 5 xd))) + ;; aktuelle Z statt XDATA (Block evtl. in Z verschoben) + (if (caddr startpunkt) (setq z-start (caddr startpunkt))) (setq as-seite (cond ((cdr (assoc "SEITE_AS" attribs))) ("links"))) (setq es-seite (cond ((cdr (assoc "SEITE_ES" attribs))) ("links"))) ;; bestehende Geruest-Einstellungen erhalten @@ -2599,6 +2601,10 @@ z-start (atof (cond ((cdr (assoc "HOEHE_VON_mm" attribs))) ("0"))) deltaL (atof (cond ((cdr (assoc "DELTA_L_mm" attribs))) ("0")))) ) + ;; Einfuegehoehe = aktuelle Z des Einfuegepunkts (= Kettenstart). XDATA und + ;; HOEHE_VON_mm sind veraltet, wenn der Block in Z verschoben wurde - OK im + ;; Dialog baut dann direkt auf der neuen Hoehe neu auf (wie Kreisel/Eckrad). + (if (caddr startpunkt) (setq z-start (caddr startpunkt))) (setq prefill (list (cons "deltaL" deltaL) @@ -2616,7 +2622,10 @@ ;; AS-Seite + untere Hoehe fuer den optionalen parallelen VF-Bau (setq as-seite (cond ((cdr (assoc "SEITE_AS" attribs))) ("links"))) - (setq hoehe-bis (atof (cond ((cdr (assoc "HOEHE_BIS_mm" attribs))) ("0")))) + ;; um dieselbe Z-Verschiebung korrigiert: BIS = Z - (VON_alt - BIS_alt) + (setq hoehe-bis (- z-start + (- (atof (cond ((cdr (assoc "HOEHE_VON_mm" attribs))) ("0"))) + (atof (cond ((cdr (assoc "HOEHE_BIS_mm" attribs))) ("0")))))) ;; 2. Argument (hoehe-vorbelegung) explizit nil: BricsCAD verlangt die exakte ;; Argumentzahl (setzt fehlende NICHT automatisch auf nil). Im Edit kommt die diff --git a/Lisp/KreiselInsert.lsp b/Lisp/KreiselInsert.lsp index 7625716..1039e58 100644 --- a/Lisp/KreiselInsert.lsp +++ b/Lisp/KreiselInsert.lsp @@ -193,10 +193,35 @@ (dbgreturn result) ) +;; Beschriftungstext (reiner Kern, in tests/test_unit.lsp getestet): +;; "KREISEL 1: Pufferkreisel PIN_4000" - mit eigenem Namen +;; "KREISEL 1: PIN_4000" - Name leer oder Vorgabe "Kreisel1" +(defun kreisel-label-text (nummer name kreiselart abstand) + (strcat "KREISEL " (itoa nummer) ": " + (if (or (null name) (= name "") (= name (strcat "Kreisel" (itoa nummer)))) + "" + (strcat name " ")) + kreiselart "_" (rtos abstand 2 0)) +) + +;; Beschriftung in einer BESTEHENDEN Blockdefinition auf textStr setzen. +;; draw-module verwendet eine vorhandene Definition KREISEL_n_TYP_ABSTAND +;; wieder (Edit/Redraw) - ein geaenderter Name kaeme sonst nie in die +;; Beschriftung. Wirkt auf alle Referenzen dieser Definition. +(defun kreisel-label-aktualisieren (bname textStr / e ed) + (setq e (tblobjname "BLOCK" bname)) + (while (setq e (entnext e)) + (setq ed (entget e)) + (if (and (= (cdr (assoc 0 ed)) "TEXT") + (/= (cdr (assoc 1 ed)) textStr)) + (entmod (subst (cons 1 textStr) (assoc 1 ed) ed)) + ) + ) +) + ;; Beschriftungstext erzeugen -(defun kreisel-make-label (nummer abstand kreiselart / textStr insertPoint radius mitteX mitteY textHoehe lay) - ;; Text: "KREISEL 1: PIN_4000" - (setq textStr (strcat "KREISEL " (itoa nummer) ": " kreiselart "_" (rtos abstand 2 0))) +(defun kreisel-make-label (nummer abstand kreiselart name / textStr insertPoint radius mitteX mitteY textHoehe lay) + (setq textStr (kreisel-label-text nummer name kreiselart abstand)) ;; Geometrie berechnen (setq radius (/ *kreisel-durchmesser* 2.0)) @@ -344,9 +369,11 @@ ) ) - ;; Bezeichnung automatisch setzen: "KreiselN" - (setq attribs (subst (cons "Bezeichnung" (strcat "Kreisel" (itoa kreisel-nummer))) - (assoc "Bezeichnung" attribs) attribs)) + ;; Bezeichnung: eigener Name (KreiselEdit) bleibt erhalten, sonst Vorgabe "KreiselN" + (if (member (cdr (assoc "Bezeichnung" attribs)) '(nil "")) + (setq attribs (subst (cons "Bezeichnung" (strcat "Kreisel" (itoa kreisel-nummer))) + (assoc "Bezeichnung" attribs) attribs)) + ) ;; --- HÖHE BESTIMMEN --- ;; Priorität 1: Aus basePoint (wenn 3D Punkt mit Z > 0) @@ -445,7 +472,8 @@ ) ;; BESCHRIFTUNG einfügen (vor Block-Erzeugung, damit sie im Block ist) - (kreisel-make-label kreisel-nummer abstand (if is-pin "PIN" "STANDARD") ) + (kreisel-make-label kreisel-nummer abstand (if is-pin "PIN" "STANDARD") + (cdr (assoc "Bezeichnung" attribs))) ;; Unsichtbare Attribut-Definitionen erzeugen (ssg-attrib-make-defs *kreisel-attrib-defs* 50.0) @@ -472,7 +500,13 @@ (princ (ssg-textf "kreisel-neue-blockdef" (list bname))) ) - (princ (ssg-textf "kreisel-bestehende-blockdef" (list bname))) + (progn + (princ (ssg-textf "kreisel-bestehende-blockdef" (list bname))) + ;; Beschriftung der wiederverwendeten Definition an den Namen anpassen + (kreisel-label-aktualisieren bname + (kreisel-label-text kreisel-nummer (cdr (assoc "Bezeichnung" attribs)) + (if is-pin "PIN" "STANDARD") abstand)) + ) ) ;; --- Block am Zielpunkt einfuegen (ohne Attribut-Dialog) --- @@ -1071,7 +1105,7 @@ ;; 4. Hoehe aus Z-Koordinate oder manuell ;; -------------------------------------------- (defun c:ILS_Eckrad ( / ptTangent ptDir dx dy dist ux uy radius - centerPt rotation hoehe + centerPt rotation hoehe hoehe-aus-z attribs ergebnis geruest-einzelmodul geruest-typ) (dbgf "c:ILS_Eckrad") @@ -1114,30 +1148,205 @@ (setq rotation (* (/ 180.0 pi) (atan dy dx))) (dbg 'rotation) - ;; 4. Hoehe bestimmen - (if (and (> (length ptTangent) 2) (caddr ptTangent) (> (caddr ptTangent) 0)) + ;; 4. Hoehe vorbelegen: aus Z des Beruehrpunkts, sonst Default + (setq hoehe-aus-z (and (> (length ptTangent) 2) (caddr ptTangent) (> (caddr ptTangent) 0))) + (if hoehe-aus-z (progn (setq hoehe (caddr ptTangent)) (princ (ssg-textf "kreisel-hoehe-aus-3dpunkt" (list (rtos hoehe 2 0)))) ) - (progn - (setq hoehe (getreal (ssg-textf "kreisel-prompt-hoehe-z" (list (rtos *eckrad-default-hoehe* 2 0))))) - (if (null hoehe) (setq hoehe *eckrad-default-hoehe*)) - ) + (setq hoehe *eckrad-default-hoehe*) ) (dbg 'hoehe) - ;; 5. Geruest fuer Einzelmodul + Geruestoption abfragen - (setq geruest-einzelmodul (if (ssg-ques (ssg-text "kreisel-eckrad-geruest-frage") T) "1" "0")) - (setq geruest-typ (ssg-ask-geruest-typ)) + (if (ssg-gui-p) + ;; 5a. Dialog: Bezeichnung, Hoehe, Drehung, Drehrichtung, Geruest + (progn + (setq attribs (ssg-attrib-merge (list (cons "HOEHE" (rtos hoehe 2 0))) + *eckrad-attrib-defs*)) + (setq ergebnis (eckrad-dialog attribs rotation)) + (if (null ergebnis) + (progn (princ (ssg-text "kreisel-abgebrochen")) (dbgreturn nil) (exit)) + ) + (setq attribs (car ergebnis) + rotation (cdr ergebnis) + hoehe (atof (cdr (assoc "HOEHE" attribs)))) + ) + ;; 5b. Ohne GUI (Tests): Konsolenabfrage wie bisher + (progn + (if (not hoehe-aus-z) + (progn + (setq hoehe (getreal (ssg-textf "kreisel-prompt-hoehe-z" (list (rtos *eckrad-default-hoehe* 2 0))))) + (if (null hoehe) (setq hoehe *eckrad-default-hoehe*)) + ) + ) + (setq geruest-einzelmodul (if (ssg-ques (ssg-text "kreisel-eckrad-geruest-frage") T) "1" "0")) + (setq geruest-typ (ssg-ask-geruest-typ)) + (setq attribs (list (cons "GERUEST_EINZELMODUL" geruest-einzelmodul) + (cons "GERUEST_TYP" geruest-typ))) + ) + ) ;; 6. Einfuegen (centerPt ist der Kreismittelpunkt) - (ils-eckrad-insert (list (car centerPt) (cadr centerPt) hoehe) rotation - (list (cons "GERUEST_EINZELMODUL" geruest-einzelmodul) - (cons "GERUEST_TYP" geruest-typ))) + (ils-eckrad-insert (list (car centerPt) (cadr centerPt) hoehe) rotation attribs) (dbgreturn nil) ) + +;; -------------------------------------------- +;; eckrad-dialog-werte: Dialogeingaben -> (attribs . rotation) +;; Reiner Kern (ohne DCL/Zeichnung, in tests/test_unit.lsp getestet). +;; Parameter: +;; attribs - bisherige Attribut-alist ((TAG . WERT) ...) +;; name - Bezeichnung (String) +;; hoehe-str - Hoehe in mm (String aus edit_box) +;; drehung-str - Drehung in Grad (String aus edit_box) +;; drehr-idx - popup_list-Index Drehrichtung ("0"=UZS, "1"=GUZ) +;; einzelmodul - toggle-Wert "0"/"1" +;; geruest-idx - popup_list-Index in *ssg-geruest-optionen* (String) +;; Rueckgabe: (attribs-neu . rotation) oder nil bei ungueltiger Zahl. +;; Drehung wird auf [0, 360) normiert. +;; -------------------------------------------- +(defun eckrad-dialog-werte (attribs name hoehe-str drehung-str drehr-idx + einzelmodul geruest-idx / hoehe drehung neu) + (setq hoehe (distof hoehe-str 2) + drehung (distof drehung-str 2)) + (if (and hoehe drehung) + (progn + (setq drehung (rem (+ (rem drehung 360.0) 360.0) 360.0)) + (setq neu (list (cons "Bezeichnung" name) + (cons "HOEHE" (rtos hoehe 2 0)) + (cons "DREHUNG" (rtos drehung 2 1)) + (cons "DREHRICHTUNG" (if (= drehr-idx "1") "GUZ" "UZS")) + (cons "GERUEST_EINZELMODUL" (if (= einzelmodul "1") "1" "0")) + (cons "GERUEST_TYP" (ssg-geruest-idx-to-typ (atoi geruest-idx))))) + ;; Neue Werte ueber die bestehenden legen (attribs als Default-Schema) + (cons (ssg-attrib-merge neu (mapcar '(lambda (p) (list (car p) (cdr p))) attribs)) + drehung) + ) + ) +) + +;; -------------------------------------------- +;; eckrad-dialog: DCL-Dialog fuer Einfuegen und Bearbeiten +;; Parameter: +;; attribs - Attribut-alist zur Vorbelegung (mit *eckrad-attrib-defs* gemergt) +;; rotation - aktuelle Drehung in Grad +;; Rueckgabe: (attribs-neu . rotation-neu) oder nil (Abbruch/DCL fehlt) +;; -------------------------------------------- +(defun eckrad-dialog (attribs rotation / dcl-pfad dat eckrad-dlg-ergebnis) + (setq attribs (ssg-attrib-merge attribs *eckrad-attrib-defs*)) + (setq dcl-pfad (strcat (getenv "DXFM_DCL") "/eckrad_edit.dcl")) + (setq dat (load_dialog dcl-pfad)) + (if (or (< dat 0) (not (new_dialog "eckrad_edit" dat))) + (progn + (if (>= dat 0) (unload_dialog dat)) + (alert (ssg-textf "kreisel-edit-dialog-fehlt" (list dcl-pfad))) + nil + ) + (progn + (set_tile "name" (cdr (assoc "Bezeichnung" attribs))) + (set_tile "hoehe" (cdr (assoc "HOEHE" attribs))) + (set_tile "drehung" (rtos rotation 2 1)) + + (start_list "drehrichtung") + (add_list "UZS") + (add_list "GUZ") + (end_list) + (set_tile "drehrichtung" (if (equal (cdr (assoc "DREHRICHTUNG" attribs)) "GUZ") "1" "0")) + + (set_tile "geruest_einzelmodul" + (if (equal (cdr (assoc "GERUEST_EINZELMODUL" attribs)) "1") "1" "0")) + + (start_list "geruest_typ") + (foreach opt *ssg-geruest-optionen* (add_list opt)) + (end_list) + (set_tile "geruest_typ" (itoa (ssg-geruest-typ-to-idx (cdr (assoc "GERUEST_TYP" attribs))))) + + ;; OK nur bei gueltigen Zahlen, sonst Fehlerzeile und Dialog bleibt offen + (action_tile "accept" + (strcat + "(setq eckrad-dlg-ergebnis (eckrad-dialog-werte attribs" + " (get_tile \"name\") (get_tile \"hoehe\") (get_tile \"drehung\")" + " (get_tile \"drehrichtung\") (get_tile \"geruest_einzelmodul\")" + " (get_tile \"geruest_typ\")))" + "(if eckrad-dlg-ergebnis (done_dialog 1)" + " (set_tile \"error\" (ssg-text \"kreisel-eckrad-ungueltige-zahl\")))" + ) + ) + (action_tile "cancel" "(setq eckrad-dlg-ergebnis nil) (done_dialog 0)") + + (start_dialog) + (unload_dialog dat) + eckrad-dlg-ergebnis + ) + ) +) + +;; ----------------------------------------------- +;; EckradEdit: Bestehendes Eckrad per Dialog bearbeiten +;; (Doppelklick auf ECKRAD_n ueber SSG_BLOCKEDIT) +;; +;; Ablauf: +;; 1. Eckrad-Block auswaehlen (oder vorselektiert) +;; 2. Dialog mit aktuellen Werten oeffnen +;; 3. Bei OK: Block loeschen und mit gleicher Nummer neu einfuegen +;; ----------------------------------------------- +(defun c:EckradEdit ( / ss sel ent ed attribs basePoint rotation ergebnis) + + ;; Implied Selection VOR ssg-start pruefen (ssg-start hebt Selektion auf) + (setq ss (ssget "I")) + (if (and ss (= (sslength ss) 1) + (= (cdr (assoc 0 (entget (ssname ss 0)))) "INSERT")) + (setq ent (ssname ss 0)) + ) + + (ssg-start (ssg-text "kreisel-start-eckrad-edit") '(("OSMODE") ("CECOLOR") ("ATTREQ") ("ATTDIA"))) + (setvar "OSMODE" 0) + + (if (null ent) + (progn + (setq sel (entsel (ssg-text "kreisel-prompt-eckrad-auswaehlen"))) + (if sel (setq ent (car sel))) + ) + ) + (if (null ent) (progn (ssg-end) (exit))) + + (setq ed (entget ent)) + (if (or (/= (cdr (assoc 0 ed)) "INSERT") + (not (wcmatch (strcase (cdr (assoc 2 ed))) "ECKRAD_*"))) + (progn (ssg-emsg (ssg-text "kreisel-emsg-kein-eckrad-block")) (ssg-end) (exit)) + ) + + ;; Bestehende Werte auslesen, fehlende mit Defaults auffuellen + (setq attribs (ssg-attrib-merge (ssg-attrib-read ent) *eckrad-attrib-defs*)) + (setq basePoint (cdr (assoc 10 ed))) + (setq rotation (* (/ 180.0 pi) (cdr (assoc 50 ed)))) + + ;; HOEHE immer aus Z-Koordinate des Einfuegepunkts + (setq attribs (subst (cons "HOEHE" (rtos (if (caddr basePoint) (caddr basePoint) 0.0) 2 0)) + (assoc "HOEHE" attribs) attribs)) + + (setq ergebnis (eckrad-dialog attribs rotation)) + (if ergebnis + (progn + (setq attribs (car ergebnis) + rotation (cdr ergebnis)) + (command "_.ERASE" ent "") + (ils-eckrad-insert (list (car basePoint) (cadr basePoint) + (atof (cdr (assoc "HOEHE" attribs)))) + rotation attribs) + (princ (ssg-textf "kreisel-eckrad-edit-aktualisiert" + (list (cdr (assoc "Bezeichnung" attribs)) + (cdr (assoc "HOEHE" attribs)) + (rtos rotation 2 1)))) + ) + (princ (ssg-text "kreisel-abgebrochen")) + ) + + (ssg-end) +) + ;; -------------------------------------------- ;; ils-eckrad-insert: Erzeugt Eckrad als Compound-Block mit Attributen ;; Parameter: @@ -1182,10 +1391,16 @@ (dbg 'z-hoehe) (dbg 'block-hoehe) - ;; Automatische Nummer vergeben - (setq eckrad-nummer (eckrad-next-number)) - (setq attribs (subst (cons "NUMMER" (itoa eckrad-nummer)) - (assoc "NUMMER" attribs) attribs)) + ;; NUMMER: Bestehende beibehalten (EckradEdit), sonst neue vergeben - + ;; so behaelt ein bearbeitetes Eckrad seinen Blocknamen ECKRAD_n + (setq eckrad-nummer (atoi (cdr (assoc "NUMMER" attribs)))) + (if (<= eckrad-nummer 0) + (progn + (setq eckrad-nummer (eckrad-next-number)) + (setq attribs (subst (cons "NUMMER" (itoa eckrad-nummer)) + (assoc "NUMMER" attribs) attribs)) + ) + ) (dbg 'eckrad-nummer) ;; Blockname: ECKRAD_1, ECKRAD_2, ... diff --git a/Lisp/README.md b/Lisp/README.md index 48c6d1f..41a89f2 100644 --- a/Lisp/README.md +++ b/Lisp/README.md @@ -684,7 +684,8 @@ AutoLISP-Implementierung fuer ILS Kreisel und Eckrad. Enthaelt alle Befehle fuer | `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 | +| `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 | --- @@ -784,7 +785,7 @@ Erkennt den Blocktyp des selektierten INSERT-Blocks und ruft den passenden Bearb | Blockmuster | Aktion | | --- | --- | | `KREISEL_*` | `KreiselEdit` | -| `ECKRAD_*` | `BEDIT` (Block-Editor) | +| `ECKRAD_*` | `EckradEdit` | | `GF_*` | `GEFAELLESTRECKE_EDIT` | | `VF_*` | `VARIOFOERDERER_EDIT` | | `GR_*` | Geruest – `BEDIT` (kein eigener Edit-Pfad; siehe `GeruestInsert.lsp`) | diff --git a/Lisp/SSG_LIB_Commands.lsp b/Lisp/SSG_LIB_Commands.lsp index 9b23e73..943e707 100644 --- a/Lisp/SSG_LIB_Commands.lsp +++ b/Lisp/SSG_LIB_Commands.lsp @@ -345,10 +345,10 @@ (c:KreiselEdit) ) - ;; Eckrad-Bloecke -> BEDIT (kein eigener Edit-Dialog in LISP) + ;; Eckrad-Bloecke -> EckradEdit ((wcmatch bname "ECKRAD_*") (princ (ssg-textf "cmd-eckrad-bearbeiten" (list bname))) - (command "_.BEDIT" bname) + (c:EckradEdit) ) ;; Gefaellestrecke-Bloecke (GF_n) -> GEFAELLESTRECKE_EDIT (DCL-Dialog) diff --git a/Lisp/count_sep_scan.lsp b/Lisp/count_sep_scan.lsp index 588f867..747fe75 100644 --- a/Lisp/count_sep_scan.lsp +++ b/Lisp/count_sep_scan.lsp @@ -139,15 +139,18 @@ ;;; dieselben Muster wie csv:collect-export-blocks/export_csv.py. ;;; ------------------------------------------------------------ -;; --- Ist nm ein Kreisel/Eckrad-, VarioFoerderer- oder Gefaellestrecke- +;; --- Ist nm ein Kreisel-, VarioFoerderer- oder Gefaellestrecke- ;; Compound-Block? Alle drei fuehren einheitlich die Attribute -;; ANZAHL_SCANNER/ANZAHL_SEPARATOR. --- +;; ANZAHL_SCANNER/ANZAHL_SEPARATOR. Das Eckrad faellt zwar unter +;; pattern_kreisel, hat diese Attribute aber nicht und zaehlt bewusst +;; KEINE Sensoren (Entscheidung 2026-10) - darum ausgenommen; sonst +;; "FEHLER beim Schreiben der Anzahl-Attribute an ECKRAD_n". --- (defun cs-carrier-p (nm / up) (setq up (strcase nm)) - (or (wcmatch up (export:pattern "pattern_kreisel" "KR_*,KREISEL_*,ECKRAD_*")) - (wcmatch up (export:pattern "pattern_variofoerderer" "VF_*")) - (wcmatch up (export:pattern "pattern_gefaellestrecke" "GF_*")) - ) + (and (not (wcmatch up (export:pattern "pattern_eckrad" "ECKRAD_*"))) + (or (wcmatch up (export:pattern "pattern_kreisel" "KR_*,KREISEL_*,ECKRAD_*")) + (wcmatch up (export:pattern "pattern_variofoerderer" "VF_*")) + (wcmatch up (export:pattern "pattern_gefaellestrecke" "GF_*")))) ) ;;; ------------------------------------------------------------ diff --git a/Lisp/export.lsp b/Lisp/export.lsp index 85e316b..93e8200 100644 --- a/Lisp/export.lsp +++ b/Lisp/export.lsp @@ -2493,6 +2493,77 @@ ;; Sammelt relevante Bloecke, schreibt JSON, ruft Python auf. ;; label = Anzeigename (z.B. "EXPORTCSV") ;; --- Export-Vorbereitung: Zeichnungszustand fuer den Export herrichten --- +;; --- Hoehen-Attribute aus der Z-Koordinate neu berechnen --- +;; Reiner Kern (in tests/test_unit.lsp getestet). Wird ein Kreisel/Eckrad/VF_n/ +;; GF_n nachtraeglich in Z verschoben, sind seine Hoehen-Attribute veraltet. +;; Rechnet dieselben Formeln/Rundungen wie beim Bau: +;; KREISEL: HOEHE = (rtos z 2 0), MONTAGEHOEHE_m = (rtos z/1000 2 3) (draw-module) +;; ECKRAD : HOEHE = (rtos z 2 0) (ils-eckrad-insert) +;; GF : VON = (fix z), MONTAGEHOEHE_m = (rtos z/1000 2 3) (gf-block-erstellen) +;; VF : VON = (fix z), MONTAGEHOEHE_m = (rtos (VON+BIS)/2000 2 3) (vf_core/vf_linienzug) +;; GF/VF : BIS = VON - (VON_alt - BIS_alt). NICHT z - DELTA_H_mm: DELTA_H_mm +;; ist ohne Vorzeichen (steigende VF!) und separat abgeschnitten. +;; DELTA_H_mm nur als Rueckfall, wenn VON/BIS fehlen. +;; art = "KREISEL"/"ECKRAD"/"GF"/"VF", z = Einfuege-Z (VF/GF: Kettenstart), +;; attribs = bisherige Attribut-alist. +;; Rueckgabe: alist der neuen Werte, oder nil, wenn der Block nicht verschoben +;; wurde (Attribut passt noch zu z) - dann bleibt er bit-genau beim Bau-Wert. +(defun csv:hoehen-werte (art z attribs / alt von von-alt bis-alt diff bis) + (cond + ((member art '("KREISEL" "ECKRAD")) + (setq alt (cdr (assoc "HOEHE" attribs))) + (if (not (and alt (/= alt "") (equal (atof alt) (atof (rtos z 2 0)) 1e-6))) + (if (= art "KREISEL") + (list (cons "HOEHE" (rtos z 2 0)) + (cons "MONTAGEHOEHE_m" (rtos (/ z 1000.0) 2 3))) + (list (cons "HOEHE" (rtos z 2 0)))))) + ((member art '("GF" "VF")) + (setq von (fix z) + von-alt (cdr (assoc "HOEHE_VON_mm" attribs)) + bis-alt (cdr (assoc "HOEHE_BIS_mm" attribs))) + (if (not (and von-alt (/= von-alt "") (= (atoi von-alt) von))) + (progn + (setq diff (if (and von-alt (/= von-alt "") bis-alt (/= bis-alt "")) + (- (atoi von-alt) (atoi bis-alt)) + (atoi (cond ((cdr (assoc "DELTA_H_mm" attribs))) ("0"))))) + (setq bis (- von diff)) + (list (cons "HOEHE_VON_mm" (itoa von)) + (cons "HOEHE_BIS_mm" (itoa bis)) + (cons "MONTAGEHOEHE_m" + (if (= art "GF") + (rtos (/ z 1000.0) 2 3) + (rtos (/ (+ von bis) 2000.0) 2 3))))))) + ) +) + +;; Hoehen-Attribute aller Kreisel/Eckrad/VF_n/GF_n pruefen und bei in Z +;; verschobenen Bloecken neu setzen (csv:hoehen-werte). Laeuft als erster +;; Schritt von csv:export-vorbereiten, gilt also fuer EXPORTSIVAS und EXPORTCSV. +(defun csv:hoehen-aktualisieren ( / ss i ent ed bname art werte n) + (setq n 0) + (if (setq ss (ssget "_X" '((0 . "INSERT") (2 . "KREISEL_*,ECKRAD_*,VF_*,GF_*")))) + (progn + (setq i 0) + (while (setq ent (ssname ss i)) + (setq ed (entget ent) + bname (strcase (cdr (assoc 2 ed)))) + (setq art (cond ((wcmatch bname "KREISEL_*") "KREISEL") + ((wcmatch bname "ECKRAD_*") "ECKRAD") + ((wcmatch bname "GF_*") "GF") + ((wcmatch bname "VF_*") "VF"))) + (setq werte (csv:hoehen-werte art (cadddr (assoc 10 ed)) (ssg-attrib-read ent))) + (if werte + (progn + (ssg-attrib-set-on ent werte) + (setq n (1+ n)))) + (setq i (1+ i)) + ) + ) + ) + (if (> n 0) (princ (ssg-textf "exp-hoehen-aktualisiert" (list n)))) + n +) + ;; Aus csv:run-export ausgelagert: alle Schritte, die VOR dem Sammeln/Schreiben ;; den Zeichnungszustand herrichten - IDs sicherstellen, Stellvertreter der ;; verpackten Kettenbausteine erzeugen und nummerieren, Omniflo-Attribute @@ -2522,6 +2593,9 @@ (setq *csv-res-sammlung* nil) (setq *csv-ketten* nil) (setq *csv-sepliste-id-by-handle* nil) + ;; 0. Hoehen-Attribute in Z verschobener Kreisel/Eckrad/VF/GF nachziehen, + ;; damit Sivas- und Raw-Export die aktuelle Hoehe sehen. + (csv:hoehen-aktualisieren) ;; 1. IDs aller Bloecke sicherstellen und Duplikate korrigieren - hier nur ;; fuer die dauerhaften Bloecke, Stellvertreter gibt es noch keine. (princ (ssg-textf "exp-check-ids" (list label))) diff --git a/cfg/sivas.cfg b/cfg/sivas.cfg index 8a19a35..7e4a203 100644 --- a/cfg/sivas.cfg +++ b/cfg/sivas.cfg @@ -64,13 +64,16 @@ # Code (bedingte Umbenennung bzw. Umrechnung mm->m). [eckrad] -# Dieselben Sivas-Merkmalnummern wie bei Kreisel (siehe oben), aus -# Merkmalsstamm_in_Sivas.xlsx: 3992 "Geruest fuer Einzelmodul", 3993 -# "Geruestoption fuer Einzelmodul". "ist_eins" liefert ein ECHTES bool -# (True/False), NICHT "Ja"/"Nein" wie ja_nein bei Kreisel/Gefaellestrecke - -# json.dumps schreibt dann true/false ohne Anfuehrungszeichen (bisheriges -# Verhalten von build_eckrad_details). -3992= GERUEST_EINZELMODUL : 0 | ist_eins +# Am Kreisel ausgerichtet, aber nur Merkmale, fuer die das Eckrad-Objekt ein +# Attribut hat (*eckrad-attrib-defs*); Merkmalnummern aus +# Merkmalsstamm_in_Sivas.xlsx. Hoehe: beim Eckrad 2950 "Anlagenhoehe in +# Meter" (NICHT 2952 "Kreiselhoehe" wie beim Kreisel), Wert aus HOEHE (mm), +# da das Eckrad kein MONTAGEHOEHE_m traegt. 3381 "Eckrad - zu +# fertigende Menge" steht wie 3511 beim Kreisel fest auf 1 (reale Stueckzahl +# in der Anzahl-Spalte). Separatoren (3382/3383) hat das Eckrad nicht. +2950= HOEHE : 0 | mm_zu_m +3381= : 1 +3992= GERUEST_EINZELMODUL : 0 | ja_nein 3993= GERUEST_TYP : Schoenenberger Geruest | geruest_typ_anzeige [geruest] diff --git a/data/omniflo/3D/BTMT-Beladung.dwg b/data/omniflo/3D/BTMT-Beladung.dwg deleted file mode 100644 index ae43b05..0000000 Binary files a/data/omniflo/3D/BTMT-Beladung.dwg and /dev/null differ diff --git a/lang/de_DE.json b/lang/de_DE.json index 948709b..0e87048 100644 --- a/lang/de_DE.json +++ b/lang/de_DE.json @@ -469,6 +469,11 @@ "kreisel-quick-fertig": "\nSchnell Einfuegen fertig.", "kreisel-start-connect": "Kreisel Smart Connect", "kreisel-start-eckrad": "Eckrad einfuegen", + "kreisel-start-eckrad-edit": "Eckrad bearbeiten", + "kreisel-prompt-eckrad-auswaehlen": "\nEckrad-Block auswaehlen: ", + "kreisel-emsg-kein-eckrad-block": "Kein Eckrad-Block! (Blockname ECKRAD_* erwartet)", + "kreisel-eckrad-ungueltige-zahl": "Hoehe und Drehung muessen Zahlen sein.", + "kreisel-eckrad-edit-aktualisiert": "\nEckrad aktualisiert: Name=%1 Hoehe=%2 Rotation=%3", "kreisel-start-edit": "Kreisel bearbeiten", "kreisel-start-insert": "Kreisel Modul einfuegen", "kreisel-start-quick": "Kreisel Schnell Einfuegen", @@ -674,6 +679,7 @@ "plq-geloescht": "\n[DELETE_PLANQUADRATE] Planquadrat-Raster entfernt (%1 Einfuegung(en)).", "plq-nichts-zu-loeschen": "\n[DELETE_PLANQUADRATE] Kein Planquadrat-Raster in der Zeichnung vorhanden.", "exp-check-ids": "\n[%1] Pruefe und vergebe IDs...", + "exp-hoehen-aktualisiert": "\nHoehen-Attribute von %1 verschobenen Bloecken aus der Z-Koordinate neu gesetzt.", "exp-sep-proxy-fehler": "\n[EXPORT] WARNUNG: Kopie von '%1' aus Block '%2' fehlgeschlagen (%3) - dieses Element fehlt im Export.", "exp-sep-zuordnung": "\n[%1] verpackte Separator-Kopie(n): ZUORDNUNG aus der ID des Wrapper-Blocks gesetzt.", "exp-sep-zuordnung-ohne-id": "\n[%1] verpackte Separator-Kopie(n) ohne Wrapper-ID - ZUORDNUNG wird geometrisch bestimmt.", diff --git a/lang/en_GB.json b/lang/en_GB.json index ce4950c..9208ce6 100644 --- a/lang/en_GB.json +++ b/lang/en_GB.json @@ -469,6 +469,11 @@ "kreisel-quick-fertig": "\nQuick insert done.", "kreisel-start-connect": "Kreisel Smart Connect", "kreisel-start-eckrad": "Insert Eckrad", + "kreisel-start-eckrad-edit": "Edit Eckrad", + "kreisel-prompt-eckrad-auswaehlen": "\nSelect Eckrad block: ", + "kreisel-emsg-kein-eckrad-block": "Not an Eckrad block! (block name ECKRAD_* expected)", + "kreisel-eckrad-ungueltige-zahl": "Height and rotation must be numbers.", + "kreisel-eckrad-edit-aktualisiert": "\nEckrad updated: Name=%1 Height=%2 Rotation=%3", "kreisel-start-edit": "Edit Kreisel", "kreisel-start-insert": "Insert Kreisel module", "kreisel-start-quick": "Kreisel quick insert", @@ -674,6 +679,7 @@ "plq-geloescht": "\n[DELETE_PLANQUADRATE] Planquadrat grid removed (%1 insertion(s)).", "plq-nichts-zu-loeschen": "\n[DELETE_PLANQUADRATE] No Planquadrat grid found in the drawing.", "exp-check-ids": "\n[%1] Checking and assigning IDs...", + "exp-hoehen-aktualisiert": "\nHeight attributes of %1 moved blocks reset from their Z coordinate.", "exp-sep-proxy-fehler": "\n[EXPORT] WARNING: copying '%1' out of block '%2' failed (%3) - this element is missing from the export.", "exp-sep-zuordnung": "\n[%1] packed separator copy/copies: ZUORDNUNG set from the wrapper block ID.", "exp-sep-zuordnung-ohne-id": "\n[%1] packed separator copy/copies without a wrapper ID - ZUORDNUNG determined geometrically.", diff --git a/lib/export_sivas.py b/lib/export_sivas.py index e62012f..3dd2ac5 100644 --- a/lib/export_sivas.py +++ b/lib/export_sivas.py @@ -113,17 +113,17 @@ def ja_nein(flag_1_0): return "Ja" if flag_1_0 == "1" else "Nein" -def ist_eins(flag_1_0): - """Wandelt ein "0"/"1"-Attribut in ein echtes bool um (True/False im - JSON, NICHT "Ja"/"Nein" wie ja_nein - siehe build_eckrad_details).""" - return flag_1_0 == "1" +def mm_zu_m(wert_mm): + """Wandelt ein mm-Attribut (z.B. Eckrad-HOEHE) in Meter um, gerundet wie + 3512 beim Kreisel ("2000" -> "2.0").""" + return str(round(safe_float(wert_mm, 0.0) / 1000.0, 3)) # --- Transform-Namen, wie sie in cfg/sivas.cfg hinter "|" stehen koennen --- TRANSFORMS = { "ja_nein": ja_nein, "geruest_typ_anzeige": geruest_typ_anzeige, - "ist_eins": ist_eins, + "mm_zu_m": mm_zu_m, } @@ -157,13 +157,15 @@ def build_gefaellestrecke_details(block, anzahl=1): def kreisel_signature(block): """ - Schluessel zur Gruppierung gleichartiger Kreisel: Kreiselart, Abstand, - Anzahl der Separatoren, Anzahl der Scanner, Anzahl der Rampen sowie - Geruest fuer Einzelmodul/Geruestoption entscheiden, ob Kreisel in - derselben Sivas-Zeile summiert werden. + Schluessel zur Gruppierung gleichartiger Kreisel: Montagehoehe (Merkmal + 2952), Kreiselart, Abstand, Anzahl der Separatoren, Anzahl der Scanner, + Anzahl der Rampen sowie Geruest fuer Einzelmodul/Geruestoption + entscheiden, ob Kreisel in derselben Sivas-Zeile summiert werden. + Die Hoehe wird numerisch verglichen ("4.820" == "4.82"). """ attribs = block.get("attribs", {}) return ( + round(safe_float(attribs.get("MONTAGEHOEHE_m", "0"), 0.0), 3), attribs.get("KREISELART", "STANDARD"), attribs.get("ABSTAND", "2300"), attribs.get("ANZAHL_SEPARATOR", attribs.get("N_SEPARATOREN", "2")), @@ -176,12 +178,13 @@ def kreisel_signature(block): def eckrad_signature(block): """ - Schluessel zur Gruppierung gleichartiger Eckraeder: Geruest fuer - Einzelmodul/Geruestoption entscheiden, ob Eckraeder in derselben - Sivas-Zeile summiert werden. + Schluessel zur Gruppierung gleichartiger Eckraeder: Hoehe (Merkmal 2950) + und Geruest fuer Einzelmodul/Geruestoption entscheiden, ob Eckraeder in + derselben Sivas-Zeile summiert werden. """ attribs = block.get("attribs", {}) return ( + mm_zu_m(attribs.get("HOEHE", "0")), attribs.get("GERUEST_EINZELMODUL", "0"), attribs.get("GERUEST_TYP", "Schoenenberger Geruest"), ) @@ -315,8 +318,8 @@ def build_kreisel_details(block): def build_eckrad_details(block): - """Merkmale-Dict fuer ein ILS Eckrad. Vollstaendig aus cfg/sivas.cfg - [eckrad] (keine berechneten Werte).""" + """Merkmale-Dict fuer eine Gruppe gleichartiger ILS Eckraeder. + Vollstaendig aus cfg/sivas.cfg [eckrad] (2950 per Transform mm_zu_m).""" attribs = block.get("attribs", {}) return sivas_mapping.anwenden(SIVAS_MAPPING_ECKRAD, attribs, TRANSFORMS) diff --git a/lib/sivas_mapping.py b/lib/sivas_mapping.py index 2a6aa81..d1480be 100644 --- a/lib/sivas_mapping.py +++ b/lib/sivas_mapping.py @@ -109,9 +109,7 @@ def anwenden(section_mapping, attribs, transforms): Rueckgabe: dict merkmal -> wert. Ohne Transform wird der Rohwert zu str() gewandelt (bisheriges Verhalten der build_*_details-Funktionen: alles Merkmalnummer-Werte sind Strings). Ein Transform liefert seinen - Rueckgabewert UNVERAENDERT (z.B. build_eckrad_details erwartet fuer - "Geruest fuer Einzelmodul" ein echtes bool, kein "True"/"False"-String - - json.dumps schreibt dann true/false statt eines Strings). + Rueckgabewert UNVERAENDERT (er ist selbst fuer den Typ verantwortlich). """ ergebnis = {} for merkmal, (attribut, alt_attribut, default, transform) in section_mapping.items(): diff --git a/menu/SSG_LIB.mnu b/menu/SSG_LIB.mnu index 023d66a..ead1030 100644 --- a/menu/SSG_LIB.mnu +++ b/menu/SSG_LIB.mnu @@ -7,7 +7,8 @@ [Einfuegen]^C^C(ssg-ensure "KreiselInsert") KreiselInsert [Verbinden]^C^C(ssg-ensure "KreiselInsert") KreiselConnect [Bearbeiten]^C^C(ssg-ensure "KreiselInsert") KreiselEdit -[<-Eckrad]^C^C(ssg-ensure "KreiselInsert") ILS_Eckrad +[Eckrad]^C^C(ssg-ensure "KreiselInsert") ILS_Eckrad +[<-Eckrad bearbeiten]^C^C(ssg-ensure "KreiselInsert") EckradEdit [->Zusatzmodul] [BTMT-Beladung]^C^C(ssg-ensure "SSG_LIB_Commands") ILS_BTMT_Beladung [BTMT-Entladung]^C^C(ssg-ensure "SSG_LIB_Commands") ILS_BTMT_Entladung @@ -196,6 +197,7 @@ ***POP501 [SSG_LIB Edit Context] [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 diff --git a/tests/test_unit.lsp b/tests/test_unit.lsp index 892fb75..0b17433 100644 --- a/tests/test_unit.lsp +++ b/tests/test_unit.lsp @@ -617,6 +617,46 @@ ) +;; ------------------------------------------------------------ +;; TESTS: export.lsp - Hoehen-Attribute aus Z neu berechnen +;; ------------------------------------------------------------ +(defun tu-tests-hoehen ( / _w) + (princ "\n[export/hoehen]") + + ;; Nicht verschoben -> nil (Block bleibt beim Bau-Wert) + (tu-nil "csv:hoehen-werte/kreisel-unveraendert" + (csv:hoehen-werte "KREISEL" 2000.0 '(("HOEHE" . "2000") ("MONTAGEHOEHE_m" . "1.800")))) + (tu-nil "csv:hoehen-werte/vf-unveraendert" + (csv:hoehen-werte "VF" 2000.0 '(("HOEHE_VON_mm" . "2000") ("HOEHE_BIS_mm" . "1876")))) + + ;; Kreisel / Eckrad verschoben + (setq _w (csv:hoehen-werte "KREISEL" 2500.0 '(("HOEHE" . "2000")))) + (tu-eq "csv:hoehen-werte/kreisel-hoehe" "2500" (cdr (assoc "HOEHE" _w))) + (tu-eqf "csv:hoehen-werte/kreisel-montage" 2.5 (atof (cdr (assoc "MONTAGEHOEHE_m" _w)))) + (setq _w (csv:hoehen-werte "ECKRAD" 1500.0 '(("HOEHE" . "2000")))) + (tu-eq "csv:hoehen-werte/eckrad-hoehe" "1500" (cdr (assoc "HOEHE" _w))) + (tu-nil "csv:hoehen-werte/eckrad-ohne-montage" (assoc "MONTAGEHOEHE_m" _w)) + + ;; GF abwaerts: Differenz 124 bleibt, MONTAGE = VON/1000 + (setq _w (csv:hoehen-werte "GF" 2500.0 + '(("HOEHE_VON_mm" . "2000") ("HOEHE_BIS_mm" . "1876") ("DELTA_H_mm" . "123")))) + (tu-eq "csv:hoehen-werte/gf-von" "2500" (cdr (assoc "HOEHE_VON_mm" _w))) + (tu-eq "csv:hoehen-werte/gf-bis" "2376" (cdr (assoc "HOEHE_BIS_mm" _w))) + (tu-eqf "csv:hoehen-werte/gf-montage" 2.5 (atof (cdr (assoc "MONTAGEHOEHE_m" _w)))) + + ;; VF steigend ("Auf"): BIS liegt ueber VON, DELTA_H_mm ohne Vorzeichen + (setq _w (csv:hoehen-werte "VF" 1000.0 + '(("HOEHE_VON_mm" . "2000") ("HOEHE_BIS_mm" . "2400") ("DELTA_H_mm" . "400")))) + (tu-eq "csv:hoehen-werte/vf-auf-von" "1000" (cdr (assoc "HOEHE_VON_mm" _w))) + (tu-eq "csv:hoehen-werte/vf-auf-bis" "1400" (cdr (assoc "HOEHE_BIS_mm" _w))) + (tu-eqf "csv:hoehen-werte/vf-auf-montage" 1.2 (atof (cdr (assoc "MONTAGEHOEHE_m" _w)))) + + ;; VF ohne VON/BIS -> Rueckfall z - DELTA_H_mm + (setq _w (csv:hoehen-werte "VF" 3000.0 '(("DELTA_H_mm" . "500")))) + (tu-eq "csv:hoehen-werte/vf-rueckfall-bis" "2500" (cdr (assoc "HOEHE_BIS_mm" _w))) +) + + ;; ------------------------------------------------------------ ;; TESTS: Gefaellestrecke.lsp - Geometrie-/Listen-Helfer ;; ------------------------------------------------------------ @@ -671,7 +711,7 @@ ;; ------------------------------------------------------------ ;; TESTS: KreiselInsert.lsp - Geometrie-Helfer ;; ------------------------------------------------------------ -(defun tu-tests-kreisel () +(defun tu-tests-kreisel ( / _e) (princ "\n[KreiselInsert]") ;; Projektion eines Punktes auf eine Gerade @@ -689,6 +729,30 @@ (tu-eqf "kreisel-idx-to-rotation/2" 90.0 (kreisel-idx-to-rotation 2)) (tu-eq "kreisel-rotation-to-idx/90" 2 (kreisel-rotation-to-idx 90.0)) (tu-eq "kreisel-rotation-to-idx/180" 1 (kreisel-rotation-to-idx 180.0)) + + ;; Beschriftung mit/ohne eigenen Namen + (tu-eq "kreisel-label-text/name" + "KREISEL 3: Puffer STANDARD_2300" (kreisel-label-text 3 "Puffer" "STANDARD" 2300.0)) + (tu-eq "kreisel-label-text/vorgabe-name" + "KREISEL 3: PIN_4000" (kreisel-label-text 3 "Kreisel3" "PIN" 4000.0)) + (tu-eq "kreisel-label-text/leer" + "KREISEL 3: PIN_4000" (kreisel-label-text 3 "" "PIN" 4000.0)) + + ;; Eckrad-Dialog: Eingaben -> (attribs . rotation) + (setq _e (eckrad-dialog-werte '(("NUMMER" . "3") ("HOEHE" . "0") ("DREHRICHTUNG" . "UZS")) + "Eck3" "2500" "-90" "1" "0" "1")) + (tu-eqf "eckrad-dialog-werte/rotation-normiert" 270.0 (cdr _e)) + (tu-eq "eckrad-dialog-werte/hoehe" "2500" (cdr (assoc "HOEHE" (car _e)))) + (tu-eq "eckrad-dialog-werte/nummer-bleibt" "3" (cdr (assoc "NUMMER" (car _e)))) + (tu-eq "eckrad-dialog-werte/name" "Eck3" (cdr (assoc "Bezeichnung" (car _e)))) + (tu-eq "eckrad-dialog-werte/guz" "GUZ" (cdr (assoc "DREHRICHTUNG" (car _e)))) + (tu-eq "eckrad-dialog-werte/einzelmodul" "0" (cdr (assoc "GERUEST_EINZELMODUL" (car _e)))) + (tu-eq "eckrad-dialog-werte/geruest-typ" (nth 1 *ssg-geruest-optionen*) + (cdr (assoc "GERUEST_TYP" (car _e)))) + (tu-nil "eckrad-dialog-werte/hoehe-ungueltig" + (eckrad-dialog-werte nil "" "abc" "0" "0" "1" "2")) + (tu-nil "eckrad-dialog-werte/drehung-leer" + (eckrad-dialog-werte nil "" "2000" "" "0" "1" "2")) ) @@ -1982,7 +2046,7 @@ (foreach fn '("tu-tests-core" "tu-tests-lang" "tu-tests-id" "tu-tests-vfcore" "tu-tests-etage" - "tu-tests-export" "tu-tests-gf" "tu-tests-omni" "tu-tests-kreisel" + "tu-tests-export" "tu-tests-hoehen" "tu-tests-gf" "tu-tests-omni" "tu-tests-kreisel" "tu-tests-sepliste" "tu-tests-json" "tu-tests-geruest" "tu-tests-sepscan" "tu-tests-vfl-segs" "tu-tests-vfl-abbruch" "tu-tests-werkzeuge")