Merge remote-tracking branch 'origin/master'
This commit is contained in:
@@ -190,6 +190,10 @@ data/block_libraries/ils_library.dxf
|
||||
# Tool-Caches
|
||||
.skylos/
|
||||
|
||||
# Eigene Geruest-Konfigurationen (vom Dialog GERUEST_* geschrieben).
|
||||
# Benutzerdaten - die gepflegte Bibliothek steht in data/json/geruest.json.
|
||||
cfg/geruest_user.json
|
||||
|
||||
# Grosse Test-Zeichnungen (Arbeitsstaende, gehoeren nicht ins Repo)
|
||||
/tests/test.dwg
|
||||
/tests/test.dxf
|
||||
|
||||
@@ -75,7 +75,7 @@ Die `start_briscad.bat` ruft `setenv.bat` auf und startet BricsCAD.
|
||||
| VarioFoerderer | `VarioFoerderer` | FOERDERANLAGE, VARIOFOERDERER_EDIT, Vario_Kette_Merge |
|
||||
| Gefaellestrecke | `Gefaellestrecke` | GEFAELLESTRECKE, GEFAELLESTRECKE_EDIT |
|
||||
| Omniflo (komplett) | `OmniModulInsert` | OMNI_APB_*, OMNI_W*_*, OMNI_AP*, OMNI_TEF_*, OMNI_TV_*, OMNI_EDIT |
|
||||
| Geruest | `GeruestInsert` | GERUEST_ROHRABHAENGER, GERUEST_SAEULE_2ZOLL, GERUEST_SAEULE_1ZOLL, GERUEST_WANDBEFESTIGUNG |
|
||||
| Geruest | `GeruestInsert` | GERUEST (ein Dialog fuer alle Bereiche) |
|
||||
| Connections | `Connection_Edit` + `SSG_LIB_Commands` | CONNECTION_INSERT, CONNECTION_EDIT, ILS_EINGANG_INSERT, ILS_AUSGANG_INSERT |
|
||||
| Export | `export` | EXPORTSIVAS, EXPORTCSV, CALLPYTHON |
|
||||
| Konfiguration | `SSG_LIB_Commands` + `DrawPlanquadrate` | SSG_DIM_SWITCH, SSG_SPRACHE, PLANQUADRATE_TOGGLE (DRAW_PLANQUADRATE/DELETE_PLANQUADRATE) |
|
||||
@@ -107,7 +107,7 @@ Detaillierte Dokumentation aller Funktionen und Befehle: siehe `Lisp/README.md`.
|
||||
| `OmniModulInsert.lsp` | OMNI_LOAD, OMNI_APB_*, OMNI_W*_*, OMNI_AP60/AP110, OMNI_TEF_*, OMNI_TV_*, OMNI_APBW_*, OMNI_EDIT | Omniflo-Komponenten: Boegen, Weichen, Verbinder, Transferwagen, 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_<DIM>.dwg`/`Ausgang_<DIM>.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_<Typ>`) 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_ROHRABHAENGER, GERUEST_SAEULE_2ZOLL, GERUEST_SAEULE_1ZOLL, GERUEST_WANDBEFESTIGUNG | Geruest-Baugruppen aus `data/json/geruest.json` konfigurieren und einfuegen. Dialog (`dcl/geruest.dcl`): Basis-Variante aus `geometrie_varianten` (Dropdown), Anbauteile aus `anbaugruppen` (`list_box` mit `multiple_select` - im Projekt der erste), Laenge (gegen `attribute.Laenge` min/max geprueft, Retry-Schleife) und Farbe (`attribute.Farbe`, Freitext bei `frei_option`). Baugruppen ohne `attribute`-Block (Wandbefestigung) bekommen Laenge/Farbe gesperrt. 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*` (ARTINR, LAENGE, BEZEICHNUNG, TEILEART, FARBE, 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. Blockname `GR_<id>_<ssg-timestamp>` (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 `menge` es vorgibt (benannte Gruppen mit `teile` werden rekursiv aufgeloest); BEZEICHNUNG 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, FARBE/LAYER (+ ARTINR bei export_csv.py) im Merkmale-/details-JSON. Noch NICHT enthalten: Edit-Pfad (GERUEST_EDIT) |
|
||||
| `GeruestInsert.lsp` | GERUEST | Geruest-Baugruppen aus `data/json/geruest.json` konfigurieren und einfuegen. **Ein Dialog fuer alle Bereiche**: oben ein Dropdown `bereich` (Rohrabhaenger / Saeulen / Wandbefestigung, Reihenfolge = Dateireihenfolge, Anzeigename aus dem ASCII-Feld `titel`). DCL hat **kein Reiter-Tile**, und da sich die Teilezeilen je Bereich unterscheiden, schliesst ein Bereichswechsel den Dialog (`done_dialog 4`) und die Schleife in `c:GERUEST` baut ihn neu auf; der Stand jedes Bereichs bleibt in `*geruest-zustand*` erhalten, ein versehentlicher Wechsel verwirft also nichts. 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) - 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. **Die Dialogdefinition wird zur Laufzeit erzeugt** (`geruest-dcl-schreiben` -> temporaere Datei per `vl-filename-mktemp`, nach `unload_dialog` wieder geloescht) - es gibt KEINE `dcl/geruest.dcl`. Grund: je Anbauteil wird ein eigenes Mengenfeld gebraucht, und eine DCL-Liste (`list_box`) kann keine Eingabefelder enthalten; DCL kann weder Dateien einbinden noch Tiles zur Laufzeit erzeugen. Inhalt: Basis-Variante aus `geometrie_varianten` (Dropdown), Laenge (gegen `attribute.Laenge` min/max geprueft, Retry-Schleife), Farbe (`attribute.Teilefarbe`, Freitext bei `frei_option`) und **zwei Befestigungslisten** ("oben"/"unten"), die BEIDE alle `anbaugruppen` enthalten - dasselbe Teil kann oben, unten oder gleichzeitig an beiden Positionen sitzen, je mit eigener Stueckzahl (vorbelegt aus `menge`). 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. 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. Blockname `GR_<id>_<ssg-timestamp>` (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 die gewaehlte Stueckzahl es vorgibt - erst Basis, dann Befestigung oben, dann unten; 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 ("oben 2x ...") 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. Noch NICHT enthalten: Edit-Pfad (GERUEST_EDIT) |
|
||||
| `menu-inventory.lsp` | MenuInventory | BricsCAD Diagnostik (Menuegruppen, Plugins, Startdateien) |
|
||||
| `DrawPlanquadrate.lsp` | DRAW_PLANQUADRATE, DELETE_PLANQUADRATE, PLANQUADRATE_TOGGLE | Zeichnet auf Z=0 ein Planquadrat-Linienraster (senkrecht/waagerecht), im Abstand/Zaehlschema der aktiven `[Planquadrate]`-Konfiguration aus `cfg/export.cfg` (dieselbe Quelle wie `lib/export_planquadrat.py` fuer den CSV-Export). Bereich kommt NICHT aus den Zeichnungs-Extents, sondern aus derselben Blockmenge wie EXPORTCSV (`csv:collect-export-blocks`, export.lsp; siehe `plq-export-bbox`): Ursprung (Index 1) UND obere Grenze kommen BEIDE aus der tatsaechlichen Bounding-Box jedes Blocks (`csv:get-bbox`, wie `bbox_columns()`/`planquadrat_column()`/`_bbox_min()` in `lib/export_csv.py` bzw. `lib/export_planquadrat.py`), NICHT aus dem reinen Einfuegepunkt - bei einem gedrehten/exzentrisch eingefuegten Block (z.B. ein um 90 Grad gedrehter Kreisel) kann das Bounding-Box-Zentrum weit vom Einfuegepunkt abweichen; Ursprung und Zellzuordnung muessen auf derselben Referenz beruhen, sonst driften sie auseinander (realer Bug, behoben). Reine Hilfsgeometrie (Kreisel-Umfahrungsboegen als eigene Linien, Texte) zaehlt bewusst nicht mit, sonst weicht das Raster vom CSV-Export ab. `x_origin`/`y_origin` ueberschreiben den Ursprung, Fallback auf EXTMIN/EXTMAX falls keine Export-Bloecke vorhanden sind bzw. `csv:get-bbox` fuer einen Block scheitert. Spalten-/Zeilenzahl wird IMMER aufgerundet auf volle Rasterschritte, damit alle senkrechten Linien auf der letzten waagerechten enden und umgekehrt - das Raster bildet immer ein geschlossenes Rechteck. Zaehlung (alphabetisch/numerisch je Achse) als Text am linken/unteren Rand. Das fertige Raster (Linien+Texte) wird per `_.-BLOCK`/`_.INSERT` zu einem einzigen Block `ZZ_PLANQUADRATE` bei (0,0,0) zusammengefasst. Layer aus `cfg/layer.cfg` (`[allgemein]` Key `planquadrate`, Fallback `ZZ_Planquadrate`). DRAW_PLANQUADRATE entfernt vor dem Neuaufbau zuerst einen evtl. vorhandenen Block (`plq-block-entfernen`: INSERTs loeschen + `_-PURGE _B`), DELETE_PLANQUADRATE ruft nur diese Entfernung auf. PLANQUADRATE_TOGGLE ("Planquadrate an/aus", Menue: Konfiguration) prueft per `tblsearch`/`ssget "X"`, ob der Block existiert, und dispatcht auf Zeichnen bzw. Loeschen. Lazy geladen ueber `(ssg-ensure "DrawPlanquadrate")`, nicht in der Core-Ladereihenfolge. Die Planquadrat-SPALTE im CSV-Export (`export_csv.py::planquadrat_column`/`resolve_origins`, `lib/export_planquadrat.py::compute_planquadrat`/`_bbox_min`) rechnet ebenfalls durchgaengig auf Bounding-Box-Basis (nicht nur Einfuegepunkt) und liefert eine SPANNE ("A/1-J/1") statt nur einer Zelle, wenn ein Element mehr als eine Zelle ueberdeckt (Kreisel, lange VF-/GF-Ketten). |
|
||||
|
||||
@@ -123,7 +123,6 @@ Detaillierte Dokumentation aller Funktionen und Befehle: siehe `Lisp/README.md`.
|
||||
| `sprache.dcl` | SSG_SPRACHE (SSG_LIB_Commands.lsp) |
|
||||
| `tro_insert.dcl` | TRO_INSERT (Tro_Edit.lsp) |
|
||||
| `tro_edit.dcl` | TRO_EDIT (Tro_Edit.lsp) |
|
||||
| `geruest.dcl` | Alle GERUEST_*-Befehle (GeruestInsert.lsp, `geruest-dialog`) - ein Dialog fuer alle Baugruppen, Listen zur Laufzeit gefuellt |
|
||||
| `vfl_edit.dcl` | Linienzug-Editieren/Fortsetzen (vf_linienzug.lsp, `vfl-dlg-position`, aufgerufen aus `vfl-edit-ent`) |
|
||||
| `vf_linienzug_wizard.dcl` | Linienzug-Assistent (Modus 1, 2 UND 3): zwei generische Einzel-Dialoge (Zahl-Eingabe, Mehrfachauswahl; `vflw-zahl`/`vflw-wahl`, aufgerufen aus `vfl-in-real`/`vfl-in-string`/`vfl-in-int` bei aktivem `*vfl-wizard-mode*`) PLUS sieben Gruppen-Dialoge, die mehrere immer unmittelbar aufeinanderfolgende Fragen in einem Bildschirm zusammenfassen (Kettenstart, AS-Element, GF-Bogen, ES-Element, Vario-Kurve, Gefaelle festlegen, Ziel-Hoehe, Horizontales Stueck - inkl. Punktwahl-Button mit X/Y/Z-Anzeige; `vflw-gruppe-*-impl` in vf_linienzug.lsp fuellen dafuer vorab eine kleine Pending-Queue `*vflw-pending*`, die einzelnen `vfl-in-*`-Aufrufe bleiben dabei unveraendert) PLUS drei Segment-Gruppen-Dialoge fuer die segmentweise Klassifizierung in Modus 2/3 (`vflw_seg_linie_m2` = Typ+GF-Neigung, `vflw_seg_linie_m3` = 4-fach-Typ+kontextabh. Wertfeld, `vflw_seg_bogen` = Typ+Variante; `vflw-seg-*-impl`). Beide Modi heben vor der Frage das aktuelle Pfad-Segment (LINE/ARC) per `vfl-seg-highlight` (`redraw`) in der Zeichnung hervor und zeigen "Segment i/n ..." im Dialogkopf. Details: `doc/variofoerderer.md` |
|
||||
|
||||
@@ -155,6 +154,8 @@ Werden via `bin/setenv.bat` gesetzt. Wichtigste:
|
||||
- **AutoLISP `(and ...)`/`(or ...)` geben `T`/`nil` zurueck, NICHT den letzten Wert** (anders als Common Lisp/Scheme). Nie einen Nicht-Boolean-Wert (String, Entity, Liste) durch `and`/`or` faedeln - dafuer `if`/`cond` verwenden. Realer Bug-Fall: `(setq eff (and blockname (ssg-ils-block-laden blockname)))` setzte `eff` auf `T` statt auf den Blocknamen-String und liess ein spaeteres `_.INSERT`/`strcat` mit `bad argument type <T>` abstuerzen. Beim Debuggen mysterioeser Typfehler `(setq .* (and`/`(setq .* (or` durchsuchen.
|
||||
- **Werte selbstbeschreibend fuehren, nicht als positionsabhaengige Indizes/Flags** - wenn ein spaeterer Konsument (Journal-Replay, Export, Edit) den Wert interpretiert. Beispiel: Winkel ueberall als ECHTER Wert `30`/`60`/`90` journalisieren, nicht als Auswahl-Index `1`/`2`/`3` - ein als Index missverstandener String `"30"` fuehrte real zum falschen 90-Grad-Bogen (VF-Linienzug). Gleiche Klasse wie die `and`/`or`-Typfalle: der Fehler faellt erst beim entfernten Konsumenten auf.
|
||||
- **Wiederverwendung vor Neuschaffung bei LISP-Routinen**: Neue Funktionen moeglichst als Erweiterung/Ergaenzung bestehender Funktionen anlegen. Bevor eine NEUE Bibliothek (`.lsp`-Datei) geschaffen wird, immer zuerst pruefen, ob es bereits thematisch passende Routinen gibt, in die die Funktionalitaet gehoert (z.B. Einfuege-Primitiven in `ssg_ks_insert.lsp`, Kern-Helfer in `ssg_core.lsp`, Konstanten in `vf_konstanten.lsp`). Erst wenn nichts passt, ein neues Modul.
|
||||
- **Neue LISP-Routinen nach Moeglichkeit in die LISP-Testsuite aufnehmen**: Jede neue LISP-Routine soll moeglichst einen Test bekommen. **Vorrang haben Routinen, die OHNE Zeichnung/Dateien testbar sind** (reine Berechnung, Parser, String-/Listen-Helfer, cfg-/JSON-Aufloesung) - die gehoeren als `tu-*`-Testblock in `tests/test_unit.lsp` (Befehl `TEST_UNIT`), der komplett file- und zeichnungsfrei laeuft. Zeichnungs-/geometrieabhaengige Routinen ueber ein Szenario-Modul (`tests/test_<name>.lsp` + Eintrag in `tests/alltests.json`, ausgefuehrt von `SSG_RUN_ALL_TESTS`) abdecken. Die reinen Berechnungspfade einer solchen Routine trotzdem, wo moeglich, zusaetzlich als file-freien Unit-Test herausziehen.
|
||||
- **Headless-Testlauf**: Die Unit-Tests laufen ohne GUI ueber `bin/run_tests.bat --lisp` - das startet BricsCAD im Batch-Modus (`/nologo /b`) mit `tests/test_unit.scr` und fuehrt `TEST_UNIT` aus. **BricsCAD steht dafuer ueber die Umgebungsvariable `BRICSCAD` zur Verfuegung** (in `bin/setenv.bat` gesetzt, auf die installierte `bricscad.exe` zeigend); `run_tests.bat` bricht mit Hinweis ab, wenn sie fehlt. Ein neuer file-freier Unit-Test ist damit auch ohne interaktive BricsCAD-Sitzung fahrbar. (Python-seitige Tests siehe `.venv` + `pytest tests/`.)
|
||||
- **Regelmaessiges Tote-Code-Review**: Wiederkehrend auf tote/nicht mehr verwendete LISP-Routinen pruefen und aufraeumen - vorzugsweise zu Wochenbeginn, wenn in der betreffenden Woche ohnehin an den LISP-Routinen gearbeitet wird.
|
||||
- **Wiederherstellungs-/Editierdaten gehoeren in XDATA/Journal, nicht in `.dbg`**: Alles, was zum Neuaufbau/Editieren eines Blocks noetig ist (z.B. das VF-Linienzug-Eingabe-Journal `SSG_VF_EDIT`), wird als XDATA am Block gefuehrt. Die `.dbg`-Dateien (`ssg_dbg.lsp`) sind reine AUSGABE, werden von keinem Befehl gelesen und bei jedem Lauf neu angelegt - nie als Datenquelle nutzen.
|
||||
- **Editierbarkeit: festes Schema vs. Sektions-Ruecksprung**: Konstrukte mit FESTER Feldstruktur (feste Anzahl/Typen von Werten, z.B. AS/ES/GF-Bogen/Vario-Kurve im VF-Linienzug) ueber ein deklaratives Schema als einzeln editierbare Records fuehren (Einzel-Glied-Edit per Feld-Splice). Konstrukte mit VARIABLEM Dialog-Fluss (datenabhaengige Feldzahl, z.B. Horizontal-Koerper/Auf-Ab-Foerderer) NICHT per fragilem "n Felder abschneiden"-Splice editieren, sondern per Sektions-Ruecksprung: ab dem gewaehlten Glied zuruecksetzen und live neu aufbauen. Ein fester Splice ueber eine datenabhaengige Feldgrenze ist genau das Muster des Winkel-Index-Bugs.
|
||||
|
||||
+930
-152
File diff suppressed because it is too large
Load Diff
+284
-202
@@ -605,59 +605,20 @@
|
||||
)
|
||||
)
|
||||
|
||||
;;; ============================================================
|
||||
;;; ENGINE - wird sowohl von ZAEHLE_SEP_SCAN als auch automatisch
|
||||
;;; vor jedem CSV-/Sivas-Export aufgerufen (siehe export.lsp,
|
||||
;;; csv:run-export).
|
||||
;;;
|
||||
;;; label = Anzeigepraefix fuer die Konsolenausgabe (z.B. "EXPORTCSV").
|
||||
;;; verbose = T -> zusaetzlich je Carrier eine Detailzeile ausgeben
|
||||
;;; (nur fuer den interaktiven Befehl sinnvoll - der
|
||||
;;; automatische Aufruf aus csv:run-export laesst dies aus,
|
||||
;;; damit die Export-Konsole kompakt bleibt).
|
||||
;;;
|
||||
;;; Setzt als Nebenwirkung:
|
||||
;;; *cs-scanner-ergaenzt* - Liste (scanner-id carrier-id
|
||||
;;; distanz-mm strittig-p
|
||||
;;; zweiter-carrier-id zweite-distanz-mm)
|
||||
;;; je per Abstand (nicht per BBox)
|
||||
;;; zugeordnetem Scanner.
|
||||
;;; *cs-scanner-warnung-by-handle* - Assoc-Liste (handle . warnungstext)
|
||||
;;; fuer strittige Scanner-Zuordnungen,
|
||||
;;; von csv:block-to-json ausgelesen.
|
||||
;;; *cs-korrekturen* - Liste (typ-wort sensor-id alt-id
|
||||
;;; neu-id) je Sensor, dessen gespeicherte
|
||||
;;; ZUORDNUNG nicht zur Geometrie passte
|
||||
;;; und ueberschrieben wurde (Report).
|
||||
;;; ============================================================
|
||||
(defun cs-zuordnung-lauf (label verbose /
|
||||
mss ss i ent ed nm bb cx cy lbl carrier-id
|
||||
carriers grid scanlist seplist sk pt
|
||||
scanCounts sepCounts n-scan-unassigned n-sep-unassigned
|
||||
n-strittig n-zuordnung-fehlt alt
|
||||
s sent spt res mode rec best-d second-rec second-d
|
||||
vorgabe-id vorgabe-rec
|
||||
scanner-id contested handle
|
||||
en nm2 ns nsep newS newP okS okP eintrag)
|
||||
(setq carriers nil scanlist nil seplist nil
|
||||
n-zuordnung-fehlt 0 n-scan-unassigned 0 n-sep-unassigned 0 n-strittig 0)
|
||||
(setq *cs-scanner-ergaenzt* nil)
|
||||
(setq *cs-scanner-warnung-by-handle* nil)
|
||||
(setq *cs-korrekturen* nil)
|
||||
(setq *senstol* (cs-senstol))
|
||||
|
||||
;; Alte Markierungskreise entfernen (Idempotenz - Sensoren, die in
|
||||
;; einem frueheren Lauf unzuordenbar waren, koennen inzwischen einen
|
||||
;; Carrier bekommen haben oder umgekehrt).
|
||||
(setq mss (ssget "_X" (list (cons 0 "CIRCLE") (cons 8 *mark-layer*))))
|
||||
(if mss (command "_.ERASE" mss ""))
|
||||
(vl-catch-all-apply '(lambda () (command "_.REGEN")))
|
||||
|
||||
(princ (ssg-textf "sens-start" (list label)))
|
||||
|
||||
;;; ------------------------------------------------------------
|
||||
;;; Alle INSERTs der Zeichnung in Carrier-, Scanner- und Separator-
|
||||
;;; Listen einsortieren.
|
||||
;;; Rueckgabe: (carriers scanlist seplist)
|
||||
;;; carriers = Liste von Records (ename tagScan tagSep minx miny
|
||||
;;; maxx maxy cx cy id label)
|
||||
;;; scanlist/seplist = Liste von (ename einfuegepunkt)
|
||||
;;; Ein Carrier ohne ermittelbare Bounding-Box wird gemeldet und
|
||||
;;; uebersprungen (kann sonst nicht zugeordnet werden).
|
||||
;;; ------------------------------------------------------------
|
||||
(defun cs-sammle-bloecke ( / ss i ent ed nm bb cx cy lbl carrier-id
|
||||
sk pt carriers scanlist seplist)
|
||||
(setq ss (ssget "_X" '((0 . "INSERT"))))
|
||||
(if (null ss)
|
||||
(princ (ssg-textf "sens-no-inserts" (list label)))
|
||||
(if ss
|
||||
(progn
|
||||
(setq i 0)
|
||||
(while (< i (sslength ss))
|
||||
@@ -693,167 +654,288 @@
|
||||
)
|
||||
(setq i (1+ i))
|
||||
)
|
||||
)
|
||||
)
|
||||
(list carriers scanlist seplist)
|
||||
)
|
||||
|
||||
(setq grid (cs-grid-build carriers))
|
||||
(setq scanCounts nil sepCounts nil)
|
||||
;;; ------------------------------------------------------------
|
||||
;;; Abweichende gespeicherte ZUORDNUNG als Korrektur in
|
||||
;;; *cs-korrekturen* vermerken, BEVOR sie ueberschrieben wird
|
||||
;;; (Selbstheilung eingefrorener/verwaister Zuordnungen). typ-wort
|
||||
;;; ist "Scanner" oder "Separator"; neu-id die geometrisch/vorgegeben
|
||||
;;; ermittelte Carrier-ID.
|
||||
;;; ------------------------------------------------------------
|
||||
(defun cs-korrektur-vermerken (sent typ-wort neu-id / alt)
|
||||
(setq alt (cs-get-att-str sent *zuordnung-tag*))
|
||||
(if (and alt (/= alt "") (/= alt neu-id))
|
||||
(setq *cs-korrekturen*
|
||||
(cons (list typ-wort (cs-get-att-str sent "ID") alt neu-id)
|
||||
*cs-korrekturen*)))
|
||||
)
|
||||
|
||||
;; --- Scanner zuordnen (inkl. Distanz-Fallback + Strittig-Erkennung) ---
|
||||
(foreach s scanlist
|
||||
(setq sent (car s) spt (cadr s))
|
||||
;;; ------------------------------------------------------------
|
||||
;;; Strittige Distanz-Zuordnung eines Scanners protokollieren:
|
||||
;;; Eintrag in *cs-scanner-ergaenzt* (immer) und - bei zu knappem
|
||||
;;; Abstand zum zweitnaechsten Carrier - eine Warnung in
|
||||
;;; *cs-scanner-warnung-by-handle* (von csv:block-to-json gelesen).
|
||||
;;; Rueckgabe: T, wenn die Zuordnung strittig ist.
|
||||
;;; ------------------------------------------------------------
|
||||
(defun cs-scanner-distanz-melden (sent rec best-d second-rec second-d /
|
||||
scanner-id contested handle)
|
||||
(setq scanner-id (cs-get-att-str sent "ID"))
|
||||
(setq contested (and second-rec
|
||||
(<= (- second-d best-d) (cs-strittig-diff-mm))))
|
||||
(setq *cs-scanner-ergaenzt*
|
||||
(cons (list scanner-id (nth 9 rec) (fix (+ best-d 0.5))
|
||||
contested
|
||||
(if contested (nth 9 second-rec) nil)
|
||||
(if contested (fix (+ second-d 0.5)) nil))
|
||||
*cs-scanner-ergaenzt*))
|
||||
(if contested
|
||||
(progn
|
||||
(setq handle (cdr (assoc 5 (entget sent))))
|
||||
(setq *cs-scanner-warnung-by-handle*
|
||||
(cons (cons handle
|
||||
(strcat "Distanz-Zuordnung unsicher: "
|
||||
(nth 9 rec) " (" (itoa (fix (+ best-d 0.5))) "mm) vs. "
|
||||
(nth 9 second-rec) " (" (itoa (fix (+ second-d 0.5))) "mm)"))
|
||||
*cs-scanner-warnung-by-handle*))
|
||||
)
|
||||
)
|
||||
contested
|
||||
)
|
||||
|
||||
;;; ------------------------------------------------------------
|
||||
;;; Scanner den Carriern zuordnen (rein geometrisch: BBox, sonst
|
||||
;;; naechster Carrier). Setzt je zugeordnetem Scanner das ZUORDNUNG-
|
||||
;;; Attribut und fuellt *cs-scanner-ergaenzt*/*cs-scanner-warnung-by-
|
||||
;;; handle* (Distanz-Fallback + Strittig-Report).
|
||||
;;; Rueckgabe: (scanCounts n-scan-unassigned n-strittig n-zuordnung-fehlt)
|
||||
;;; ------------------------------------------------------------
|
||||
(defun cs-scanner-zuordnen (scanlist carriers grid /
|
||||
scanCounts n-scan-unassigned n-strittig
|
||||
n-zuordnung-fehlt s sent spt res mode rec
|
||||
best-d second-rec second-d)
|
||||
(setq scanCounts nil n-scan-unassigned 0 n-strittig 0 n-zuordnung-fehlt 0)
|
||||
(foreach s scanlist
|
||||
(setq sent (car s) spt (cadr s))
|
||||
(setq res (cs-resolve-sensor spt carriers grid))
|
||||
(setq mode (nth 0 res) rec (nth 1 res)
|
||||
best-d (nth 2 res) second-rec (nth 3 res) second-d (nth 4 res))
|
||||
(cond
|
||||
((eq mode 'none)
|
||||
(setq n-scan-unassigned (1+ n-scan-unassigned))
|
||||
(cs-mark-unassigned sent))
|
||||
((null rec) nil) ;; Sicherheitsnetz - tritt bei bbox/distance nicht auf
|
||||
(t
|
||||
(setq scanCounts (cs-bump scanCounts (car rec)))
|
||||
(cs-korrektur-vermerken sent "Scanner" (nth 9 rec))
|
||||
(if (member mode '(bbox distance))
|
||||
(if (not (cs-set-att sent *zuordnung-tag* (nth 9 rec)))
|
||||
(setq n-zuordnung-fehlt (1+ n-zuordnung-fehlt))))
|
||||
(if (eq mode 'distance)
|
||||
(if (cs-scanner-distanz-melden sent rec best-d second-rec second-d)
|
||||
(setq n-strittig (1+ n-strittig))))
|
||||
)
|
||||
)
|
||||
)
|
||||
(setq *cs-scanner-ergaenzt* (reverse *cs-scanner-ergaenzt*))
|
||||
(list scanCounts n-scan-unassigned n-strittig n-zuordnung-fehlt)
|
||||
)
|
||||
|
||||
;;; ------------------------------------------------------------
|
||||
;;; Separatoren den Carriern zuordnen. Wie cs-scanner-zuordnen, aber
|
||||
;;; ohne Strittig-Report; zusaetzlich hat eine festgenagelte Zuordnung
|
||||
;;; (verpackter Separator, *cs-sep-fix-by-handle*) Vorrang vor der
|
||||
;;; Geometrie - nur wenn der genannte Carrier nicht (mehr) existiert,
|
||||
;;; wird geometrisch zugeordnet. Bei mode 'vorgabe wird der geschriebene
|
||||
;;; Wert NICHT als Korrektur gemeldet (er ist die Vorgabe selbst).
|
||||
;;; Rueckgabe: (sepCounts n-sep-unassigned n-zuordnung-fehlt)
|
||||
;;; ------------------------------------------------------------
|
||||
(defun cs-separatoren-zuordnen (seplist carriers grid /
|
||||
sepCounts n-sep-unassigned n-zuordnung-fehlt
|
||||
s sent spt res mode rec vorgabe-id vorgabe-rec)
|
||||
(setq sepCounts nil n-sep-unassigned 0 n-zuordnung-fehlt 0)
|
||||
(foreach s seplist
|
||||
(setq sent (car s) spt (cadr s))
|
||||
(setq vorgabe-id (cdr (assoc (cdr (assoc 5 (entget sent))) *cs-sep-fix-by-handle*)))
|
||||
(setq vorgabe-rec (cs-carrier-by-id vorgabe-id carriers))
|
||||
(if vorgabe-rec
|
||||
(setq mode 'vorgabe rec vorgabe-rec)
|
||||
(progn
|
||||
(setq res (cs-resolve-sensor spt carriers grid))
|
||||
(setq mode (nth 0 res) rec (nth 1 res)
|
||||
best-d (nth 2 res) second-rec (nth 3 res) second-d (nth 4 res))
|
||||
(cond
|
||||
((eq mode 'none)
|
||||
(setq n-scan-unassigned (1+ n-scan-unassigned))
|
||||
(cs-mark-unassigned sent))
|
||||
((null rec) nil) ;; Sicherheitsnetz - tritt bei bbox/distance nicht auf
|
||||
(t
|
||||
(setq scanCounts (cs-bump scanCounts (car rec)))
|
||||
;; Abweichende gespeicherte ZUORDNUNG als Korrektur vermerken,
|
||||
;; bevor sie unten ueberschrieben wird (Selbstheilung eingefrorener
|
||||
;; oder verwaister Zuordnungen).
|
||||
(setq alt (cs-get-att-str sent *zuordnung-tag*))
|
||||
(if (and alt (/= alt "") (/= alt (nth 9 rec)))
|
||||
(setq *cs-korrekturen*
|
||||
(cons (list "Scanner" (cs-get-att-str sent "ID") alt (nth 9 rec))
|
||||
*cs-korrekturen*)))
|
||||
(if (member mode '(bbox distance))
|
||||
(if (not (cs-set-att sent *zuordnung-tag* (nth 9 rec)))
|
||||
(setq n-zuordnung-fehlt (1+ n-zuordnung-fehlt))))
|
||||
(if (eq mode 'distance)
|
||||
(progn
|
||||
(setq scanner-id (cs-get-att-str sent "ID"))
|
||||
(setq contested (and second-rec
|
||||
(<= (- second-d best-d) (cs-strittig-diff-mm))))
|
||||
(setq *cs-scanner-ergaenzt*
|
||||
(cons (list scanner-id (nth 9 rec) (fix (+ best-d 0.5))
|
||||
contested
|
||||
(if contested (nth 9 second-rec) nil)
|
||||
(if contested (fix (+ second-d 0.5)) nil))
|
||||
*cs-scanner-ergaenzt*))
|
||||
(if contested
|
||||
(progn
|
||||
(setq n-strittig (1+ n-strittig))
|
||||
(setq handle (cdr (assoc 5 (entget sent))))
|
||||
(setq *cs-scanner-warnung-by-handle*
|
||||
(cons (cons handle
|
||||
(strcat "Distanz-Zuordnung unsicher: "
|
||||
(nth 9 rec) " (" (itoa (fix (+ best-d 0.5))) "mm) vs. "
|
||||
(nth 9 second-rec) " (" (itoa (fix (+ second-d 0.5))) "mm)"))
|
||||
*cs-scanner-warnung-by-handle*))
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
(setq mode (nth 0 res) rec (nth 1 res))
|
||||
)
|
||||
(setq *cs-scanner-ergaenzt* (reverse *cs-scanner-ergaenzt*))
|
||||
|
||||
;; --- Separatoren zuordnen (gleiche Logik, ohne Strittig-Report -
|
||||
;; der Distanz-Fallback stellt hier nur sicher, dass die
|
||||
;; ANZAHL_SEPARATOR-Summe auch bei Sonderfaellen stimmt). ---
|
||||
(foreach s seplist
|
||||
(setq sent (car s) spt (cadr s))
|
||||
;; Festgenagelte Zuordnung (verpackter Separator, Carrier bekannt -
|
||||
;; siehe *cs-sep-fix-by-handle*) hat Vorrang vor der Geometrie. Nur
|
||||
;; wenn der genannte Carrier gar nicht (mehr) existiert, wird
|
||||
;; geometrisch zugeordnet.
|
||||
(setq vorgabe-id (cdr (assoc (cdr (assoc 5 (entget sent))) *cs-sep-fix-by-handle*)))
|
||||
(setq vorgabe-rec (cs-carrier-by-id vorgabe-id carriers))
|
||||
(if vorgabe-rec
|
||||
(setq mode 'vorgabe rec vorgabe-rec)
|
||||
(progn
|
||||
(setq res (cs-resolve-sensor spt carriers grid))
|
||||
(setq mode (nth 0 res) rec (nth 1 res))
|
||||
)
|
||||
)
|
||||
(cond
|
||||
((eq mode 'none)
|
||||
(setq n-sep-unassigned (1+ n-sep-unassigned))
|
||||
(cs-mark-unassigned sent))
|
||||
((null rec) nil) ;; Sicherheitsnetz - tritt bei bbox/distance nicht auf
|
||||
(t
|
||||
(setq sepCounts (cs-bump sepCounts (car rec)))
|
||||
;; Abweichung nur bei geometrischer Zuordnung als Korrektur melden -
|
||||
;; bei mode 'vorgabe ist der geschriebene Wert die Vorgabe selbst,
|
||||
;; keine Korrektur einer Fehl-Zuordnung.
|
||||
(setq alt (cs-get-att-str sent *zuordnung-tag*))
|
||||
(if (and (not (eq mode 'vorgabe)) alt (/= alt "") (/= alt (nth 9 rec)))
|
||||
(setq *cs-korrekturen*
|
||||
(cons (list "Separator" (cs-get-att-str sent "ID") alt (nth 9 rec))
|
||||
*cs-korrekturen*)))
|
||||
(if (member mode '(vorgabe bbox distance))
|
||||
(if (not (cs-set-att sent *zuordnung-tag* (nth 9 rec)))
|
||||
(setq n-zuordnung-fehlt (1+ n-zuordnung-fehlt))))
|
||||
)
|
||||
)
|
||||
)
|
||||
(cond
|
||||
((eq mode 'none)
|
||||
(setq n-sep-unassigned (1+ n-sep-unassigned))
|
||||
(cs-mark-unassigned sent))
|
||||
((null rec) nil) ;; Sicherheitsnetz - tritt bei bbox/distance nicht auf
|
||||
(t
|
||||
(setq sepCounts (cs-bump sepCounts (car rec)))
|
||||
(if (not (eq mode 'vorgabe))
|
||||
(cs-korrektur-vermerken sent "Separator" (nth 9 rec)))
|
||||
(if (member mode '(vorgabe bbox distance))
|
||||
(if (not (cs-set-att sent *zuordnung-tag* (nth 9 rec)))
|
||||
(setq n-zuordnung-fehlt (1+ n-zuordnung-fehlt))))
|
||||
)
|
||||
)
|
||||
)
|
||||
(list sepCounts n-sep-unassigned n-zuordnung-fehlt)
|
||||
)
|
||||
|
||||
;; --- ANZAHL_SCANNER/ANZAHL_SEPARATOR je Carrier schreiben ---
|
||||
(foreach rec carriers
|
||||
(setq en (car rec))
|
||||
(setq nm2 (cdr (assoc 2 (entget en))))
|
||||
(setq ns (cond ((assoc en scanCounts) (cdr (assoc en scanCounts))) (t 0)))
|
||||
(setq nsep (cond ((assoc en sepCounts) (cdr (assoc en sepCounts))) (t 0)))
|
||||
(setq newS ns)
|
||||
;; ANZAHL_SEPARATOR = nur die tatsaechlich platzierten Separator-
|
||||
;; Symbole (Separator_SP/S-LP), die diesem Carrier zugeordnet sind.
|
||||
;; Der intern in der GF/VF-Kette gezeichnete 300-mm-Block
|
||||
;; Staustrecke_Separator_SP ist nur ein Kettenglied (Foerder-/
|
||||
;; Uebergabestueck), KEIN eigenstaendiger Separator - er wird bewusst
|
||||
;; NICHT mitgezaehlt (Entscheidung: nur platzierte Symbole zaehlen).
|
||||
(setq newP nsep)
|
||||
(setq okS (cs-set-att en (nth 1 rec) (itoa newS)))
|
||||
(setq okP (cs-set-att en (nth 2 rec) (itoa newP)))
|
||||
(if verbose
|
||||
(princ (ssg-textf "sens-carrier-zeile"
|
||||
(list nm2 (nth 9 rec) (itoa newS) (itoa newP)))))
|
||||
(if (not (and okS okP))
|
||||
(princ (ssg-textf "sens-carrier-fehler" (list nm2))))
|
||||
;;; ------------------------------------------------------------
|
||||
;;; ANZAHL_SCANNER/ANZAHL_SEPARATOR je Carrier schreiben.
|
||||
;;; scanCounts/sepCounts = Assoc-Listen (carrier-ename . anzahl).
|
||||
;;; ANZAHL_SEPARATOR = nur die tatsaechlich platzierten Separator-
|
||||
;;; Symbole (Separator_SP/S-LP); der intern in der GF/VF-Kette
|
||||
;;; gezeichnete 300-mm-Block Staustrecke_Separator_SP ist nur ein
|
||||
;;; Kettenglied und wird bewusst NICHT mitgezaehlt.
|
||||
;;; verbose = T -> je Carrier eine Detailzeile ausgeben.
|
||||
;;; ------------------------------------------------------------
|
||||
(defun cs-anzahl-schreiben (carriers scanCounts sepCounts verbose /
|
||||
rec en nm2 ns nsep okS okP)
|
||||
(foreach rec carriers
|
||||
(setq en (car rec))
|
||||
(setq nm2 (cdr (assoc 2 (entget en))))
|
||||
(setq ns (cond ((assoc en scanCounts) (cdr (assoc en scanCounts))) (t 0)))
|
||||
(setq nsep (cond ((assoc en sepCounts) (cdr (assoc en sepCounts))) (t 0)))
|
||||
(setq okS (cs-set-att en (nth 1 rec) (itoa ns)))
|
||||
(setq okP (cs-set-att en (nth 2 rec) (itoa nsep)))
|
||||
(if verbose
|
||||
(princ (ssg-textf "sens-carrier-zeile"
|
||||
(list nm2 (nth 9 rec) (itoa ns) (itoa nsep)))))
|
||||
(if (not (and okS okP))
|
||||
(princ (ssg-textf "sens-carrier-fehler" (list nm2))))
|
||||
)
|
||||
)
|
||||
|
||||
;;; ------------------------------------------------------------
|
||||
;;; Abschliessende Konsolen-Zusammenfassung ausgeben: Gesamtzahlen,
|
||||
;;; per Distanz ergaenzte Scanner (*cs-scanner-ergaenzt*), strittige
|
||||
;;; Zuordnungen, korrigierte ZUORDNUNGen (*cs-korrekturen*) sowie
|
||||
;;; markierte unzuordenbare und fehlgeschlagene Attributschreibungen.
|
||||
;;; ------------------------------------------------------------
|
||||
(defun cs-bericht-ausgeben (label n-carrier n-scan n-scan-unassigned
|
||||
n-sep n-sep-unassigned n-strittig
|
||||
n-zuordnung-fehlt / eintrag)
|
||||
(princ (ssg-textf "sens-summary"
|
||||
(list label (itoa n-carrier)
|
||||
(itoa n-scan) (itoa n-scan-unassigned)
|
||||
(itoa n-sep) (itoa n-sep-unassigned))))
|
||||
|
||||
(if *cs-scanner-ergaenzt*
|
||||
(progn
|
||||
(princ (ssg-textf "sens-ergaenzt-header"
|
||||
(list label (itoa (length *cs-scanner-ergaenzt*)))))
|
||||
(foreach eintrag *cs-scanner-ergaenzt*
|
||||
(princ (ssg-textf "sens-ergaenzt-zeile"
|
||||
(list (nth 0 eintrag) (nth 1 eintrag) (itoa (nth 2 eintrag)))))
|
||||
(if (nth 3 eintrag)
|
||||
(princ (ssg-textf "sens-strittig-suffix"
|
||||
(list (nth 4 eintrag) (itoa (nth 5 eintrag))))))
|
||||
)
|
||||
)
|
||||
)
|
||||
(if (> n-strittig 0)
|
||||
(princ (ssg-textf "sens-strittig-summary" (list label (itoa n-strittig)))))
|
||||
|
||||
;; --- Zusammenfassung ---
|
||||
(princ (ssg-textf "sens-summary"
|
||||
(list label (itoa (length carriers))
|
||||
(itoa (length scanlist)) (itoa n-scan-unassigned)
|
||||
(itoa (length seplist)) (itoa n-sep-unassigned))))
|
||||
;; --- Korrigierte (nicht zur Geometrie passende) ZUORDNUNG melden ---
|
||||
(if *cs-korrekturen*
|
||||
(progn
|
||||
(setq *cs-korrekturen* (reverse *cs-korrekturen*))
|
||||
(princ (ssg-textf "sens-korrektur-header"
|
||||
(list label (itoa (length *cs-korrekturen*)))))
|
||||
(foreach eintrag *cs-korrekturen*
|
||||
(princ (ssg-textf "sens-korrektur-zeile"
|
||||
(list (nth 0 eintrag) (nth 1 eintrag)
|
||||
(nth 2 eintrag) (nth 3 eintrag)))))
|
||||
)
|
||||
)
|
||||
|
||||
(if *cs-scanner-ergaenzt*
|
||||
(progn
|
||||
(princ (ssg-textf "sens-ergaenzt-header"
|
||||
(list label (itoa (length *cs-scanner-ergaenzt*)))))
|
||||
(foreach eintrag *cs-scanner-ergaenzt*
|
||||
(princ (ssg-textf "sens-ergaenzt-zeile"
|
||||
(list (nth 0 eintrag) (nth 1 eintrag) (itoa (nth 2 eintrag)))))
|
||||
(if (nth 3 eintrag)
|
||||
(princ (ssg-textf "sens-strittig-suffix"
|
||||
(list (nth 4 eintrag) (itoa (nth 5 eintrag))))))
|
||||
)
|
||||
)
|
||||
)
|
||||
(if (> n-strittig 0)
|
||||
(princ (ssg-textf "sens-strittig-summary" (list label (itoa n-strittig)))))
|
||||
(if (> (+ n-scan-unassigned n-sep-unassigned) 0)
|
||||
(princ (ssg-textf "sens-unassigned-marked"
|
||||
(list label (itoa (+ n-scan-unassigned n-sep-unassigned)) *mark-layer*))))
|
||||
(if (> n-zuordnung-fehlt 0)
|
||||
(princ (ssg-textf "sens-zuordnung-fehlt" (list label (itoa n-zuordnung-fehlt)))))
|
||||
)
|
||||
|
||||
;; --- Korrigierte (nicht zur Geometrie passende) ZUORDNUNG melden ---
|
||||
(if *cs-korrekturen*
|
||||
(progn
|
||||
(setq *cs-korrekturen* (reverse *cs-korrekturen*))
|
||||
(princ (ssg-textf "sens-korrektur-header"
|
||||
(list label (itoa (length *cs-korrekturen*)))))
|
||||
(foreach eintrag *cs-korrekturen*
|
||||
(princ (ssg-textf "sens-korrektur-zeile"
|
||||
(list (nth 0 eintrag) (nth 1 eintrag)
|
||||
(nth 2 eintrag) (nth 3 eintrag)))))
|
||||
)
|
||||
)
|
||||
;;; ============================================================
|
||||
;;; ENGINE - wird sowohl von ZAEHLE_SEP_SCAN als auch automatisch
|
||||
;;; vor jedem CSV-/Sivas-Export aufgerufen (siehe export.lsp,
|
||||
;;; csv:run-export).
|
||||
;;;
|
||||
;;; label = Anzeigepraefix fuer die Konsolenausgabe (z.B. "EXPORTCSV").
|
||||
;;; verbose = T -> zusaetzlich je Carrier eine Detailzeile ausgeben
|
||||
;;; (nur fuer den interaktiven Befehl sinnvoll - der
|
||||
;;; automatische Aufruf aus csv:run-export laesst dies aus,
|
||||
;;; damit die Export-Konsole kompakt bleibt).
|
||||
;;;
|
||||
;;; Setzt als Nebenwirkung:
|
||||
;;; *cs-scanner-ergaenzt* - Liste (scanner-id carrier-id
|
||||
;;; distanz-mm strittig-p
|
||||
;;; zweiter-carrier-id zweite-distanz-mm)
|
||||
;;; je per Abstand (nicht per BBox)
|
||||
;;; zugeordnetem Scanner.
|
||||
;;; *cs-scanner-warnung-by-handle* - Assoc-Liste (handle . warnungstext)
|
||||
;;; fuer strittige Scanner-Zuordnungen,
|
||||
;;; von csv:block-to-json ausgelesen.
|
||||
;;; *cs-korrekturen* - Liste (typ-wort sensor-id alt-id
|
||||
;;; neu-id) je Sensor, dessen gespeicherte
|
||||
;;; ZUORDNUNG nicht zur Geometrie passte
|
||||
;;; und ueberschrieben wurde (Report).
|
||||
;;; ============================================================
|
||||
(defun cs-zuordnung-lauf (label verbose /
|
||||
mss bloecke carriers scanlist seplist grid
|
||||
scan-res sep-res scanCounts sepCounts
|
||||
n-scan-unassigned n-sep-unassigned
|
||||
n-strittig n-zuordnung-fehlt)
|
||||
(setq *cs-scanner-ergaenzt* nil)
|
||||
(setq *cs-scanner-warnung-by-handle* nil)
|
||||
(setq *cs-korrekturen* nil)
|
||||
(setq *senstol* (cs-senstol))
|
||||
|
||||
(if (> (+ n-scan-unassigned n-sep-unassigned) 0)
|
||||
(princ (ssg-textf "sens-unassigned-marked"
|
||||
(list label (itoa (+ n-scan-unassigned n-sep-unassigned)) *mark-layer*))))
|
||||
(if (> n-zuordnung-fehlt 0)
|
||||
(princ (ssg-textf "sens-zuordnung-fehlt" (list label (itoa n-zuordnung-fehlt)))))
|
||||
;; Alte Markierungskreise entfernen (Idempotenz - Sensoren, die in
|
||||
;; einem frueheren Lauf unzuordenbar waren, koennen inzwischen einen
|
||||
;; Carrier bekommen haben oder umgekehrt).
|
||||
(setq mss (ssget "_X" (list (cons 0 "CIRCLE") (cons 8 *mark-layer*))))
|
||||
(if mss (command "_.ERASE" mss ""))
|
||||
(vl-catch-all-apply '(lambda () (command "_.REGEN")))
|
||||
|
||||
(princ (ssg-textf "sens-start" (list label)))
|
||||
|
||||
;; INSERTs in Carrier/Scanner/Separator einsortieren.
|
||||
(setq bloecke (cs-sammle-bloecke))
|
||||
(setq carriers (nth 0 bloecke)
|
||||
scanlist (nth 1 bloecke)
|
||||
seplist (nth 2 bloecke))
|
||||
(if (and (null carriers) (null scanlist) (null seplist))
|
||||
(princ (ssg-textf "sens-no-inserts" (list label)))
|
||||
(progn
|
||||
(setq grid (cs-grid-build carriers))
|
||||
|
||||
;; Scanner zuordnen (BBox, sonst naechster Carrier; Distanz-Fallback
|
||||
;; + Strittig-Report). Zaehler kommen als Liste zurueck.
|
||||
(setq scan-res (cs-scanner-zuordnen scanlist carriers grid))
|
||||
(setq scanCounts (nth 0 scan-res)
|
||||
n-scan-unassigned (nth 1 scan-res)
|
||||
n-strittig (nth 2 scan-res)
|
||||
n-zuordnung-fehlt (nth 3 scan-res))
|
||||
|
||||
;; Separatoren zuordnen (Vorgabe hat Vorrang vor der Geometrie).
|
||||
(setq sep-res (cs-separatoren-zuordnen seplist carriers grid))
|
||||
(setq sepCounts (nth 0 sep-res)
|
||||
n-sep-unassigned (nth 1 sep-res)
|
||||
n-zuordnung-fehlt (+ n-zuordnung-fehlt (nth 2 sep-res)))
|
||||
|
||||
;; ANZAHL_SCANNER/ANZAHL_SEPARATOR je Carrier schreiben und Bericht.
|
||||
(cs-anzahl-schreiben carriers scanCounts sepCounts verbose)
|
||||
(cs-bericht-ausgeben label (length carriers)
|
||||
(length scanlist) n-scan-unassigned
|
||||
(length seplist) n-sep-unassigned
|
||||
n-strittig n-zuordnung-fehlt)
|
||||
)
|
||||
)
|
||||
(princ)
|
||||
|
||||
+173
-81
@@ -297,43 +297,76 @@
|
||||
)
|
||||
|
||||
;; --- Lokalen Punkt (relativ zum Block-Ursprung) unter Beruecksichtigung der
|
||||
;; Eltern-Rotation (reine Z-Drehung um den Einfuegepunkt) in Weltkoordinaten
|
||||
;; umrechnen. Rueckgabe: (x y z) ---
|
||||
(defun csv:local-to-world (parent-pt parent-rot-rad local-pt / c s lx ly lz pz)
|
||||
(setq c (cos parent-rot-rad) s (sin parent-rot-rad))
|
||||
(setq lx (car local-pt) ly (cadr local-pt))
|
||||
;; VOLLEN 3D-Orientierung des Elternblocks in Weltkoordinaten umrechnen ---
|
||||
;; parent-R = volle 3x3-Rotationsmatrix (mat3-* in ssg_core.lsp), nicht nur
|
||||
;; ein Z-Drehwinkel: ein Elternblock kann selbst eine gekippte Extrusion
|
||||
;; tragen (z.B. ein Separator-Proxy, der aus dem geneigten Abschnitt einer
|
||||
;; VF-/GF-Kette neu zusammengesetzt wurde, siehe csv:block-to-json) - eine
|
||||
;; reine Z-Drehung wuerde dessen Sub-Koordinatensysteme (K1-K4/KS_EIN/
|
||||
;; KS_AUS) an einen falschen, teils gespiegelten Weltpunkt legen. Fuer einen
|
||||
;; flachen Elternblock (Extrusion (0 0 1)) ist parent-R = Rz(rotation) und
|
||||
;; das Ergebnis identisch zur frueheren reinen Z-Drehung. Rueckgabe: (x y z).
|
||||
(defun csv:local-to-world (parent-pt parent-R local-pt / lz pz rot-pt)
|
||||
(setq lz (if (caddr local-pt) (caddr local-pt) 0.0))
|
||||
(setq pz (if (caddr parent-pt) (caddr parent-pt) 0.0))
|
||||
(setq rot-pt (mat3-mul-vec3 parent-R (list (car local-pt) (cadr local-pt) lz)))
|
||||
(list
|
||||
(+ (car parent-pt) (- (* lx c) (* ly s)))
|
||||
(+ (cadr parent-pt) (+ (* lx s) (* ly c)))
|
||||
(+ pz lz)
|
||||
(+ (car parent-pt) (car rot-pt))
|
||||
(+ (cadr parent-pt) (cadr rot-pt))
|
||||
(+ pz (caddr rot-pt))
|
||||
)
|
||||
)
|
||||
|
||||
;; --- K1-K4-Koordinatensysteme eines Blocks als Positions-Strings lesen ---
|
||||
;; ename = Entity-Name des platzierten INSERT (Omniflo Bogen/Weiche/Gerade).
|
||||
;; pt/rot-rad = bereits ermittelte Welt-Position/-Rotation (radiant) des
|
||||
;; Eltern-INSERT (siehe csv:block-to-json), keine erneute Abfrage.
|
||||
;; ename = Entity-Name des platzierten INSERT (Omniflo Bogen/Weiche/Gerade).
|
||||
;; pt/parent-R = bereits ermittelte Welt-Position/volle 3x3-Orientierung des
|
||||
;; Eltern-INSERT (siehe csv:block-to-json), keine erneute Abfrage.
|
||||
;; Sucht in der Block-DEFINITION (wie omni:get-block-hoehe) nach direkten
|
||||
;; Sub-INSERTs "K1".."K4" und rechnet deren lokale Position ueber die
|
||||
;; Eltern-Rotation (reine Z-Drehung) in Weltkoordinaten um. Es wird nur die
|
||||
;; POSITION kodiert (12-Zeichen-String, csv:trans-encode) - keine Rotation.
|
||||
;; Sub-INSERTs "K1".."K4" und rechnet deren lokale Position ueber die volle
|
||||
;; Eltern-Orientierung in Weltkoordinaten um (csv:local-to-world). Es wird
|
||||
;; nur die POSITION kodiert (12-Zeichen-String, csv:trans-encode) - keine
|
||||
;; Rotation.
|
||||
;; Zusaetzlich werden Strecken-Koordinatensysteme KS_EIN->K1 und KS_AUS->K2
|
||||
;; (inkl. der KSYS_-Varianten, siehe ks-normalize-name in vf_core.lsp) gemappt,
|
||||
;; sofern kein echter K1/K2 am Block vorhanden ist (echte K-Bloecke haben
|
||||
;; Vorrang: sie werden vorne angehaengt, csv:k-kos liest per assoc den ersten).
|
||||
;; Rueckgabe: Assoc-Liste (("K1" . "<pos-string>") ("K2" . ...) ...), nur
|
||||
;; fuer tatsaechlich vorhandene K-Bloecke (nicht jedes Element hat alle 4).
|
||||
(defun csv:get-k-kos-strings (ename pt rot-rad / ed bname blk-tbl sub-ent sub-ed
|
||||
sub-bname sub-pt world-pt target is-real result)
|
||||
;;
|
||||
;; Gruppe-10 eines Sub-INSERTs ist OCS-lokal zu SEINER EIGENEN Extrusion
|
||||
;; (Gruppe 210), nicht zwingend zur flachen XY-Ebene der Elterndefinition -
|
||||
;; z.B. KS_AUS von SC_Entladung (BTMT-Entladung), das schraeg in 3D sitzt.
|
||||
;; mat3-ocs-matrix/mat3-mul-vec3 (ssg_core.lsp, Arbitrary Axis Algorithm)
|
||||
;; wandeln das erst in echte lokale Koordinaten um, bevor csv:local-to-world
|
||||
;; mit der Eltern-Rotation weiterrechnet - derselbe Fix wie bereits in
|
||||
;; ssg-collect-nested-inserts-rel (dort ausfuehrlich begruendet). Ohne diese
|
||||
;; Umrechnung landete K2 tief unterhalb statt oberhalb des Elements (realer
|
||||
;; Bug, sichtbar in der Materialfluss-Draufsicht sps_skel/HundM05_bbs.svg).
|
||||
;; Fuer Extrusion=(0 0 1) (Normalfall, z.B. KS_EIN) reduziert sich das exakt
|
||||
;; auf die alte reine Uebernahme - unveraendertes Verhalten dort. Denselben
|
||||
;; Grund hat parent-R als VOLLE Matrix statt eines Z-Drehwinkels: ein
|
||||
;; Elternblock (z.B. ein Separator-Proxy, ueber ssg-collect-nested-inserts
|
||||
;; aus dem geneigten Abschnitt einer VF-/GF-Kette neu zusammengesetzt) kann
|
||||
;; selbst eine gekippte Extrusion tragen - eine reine Z-Drehung des Eltern-
|
||||
;; INSERT legte dessen K1/K2 dann an einen falschen, teils gespiegelten
|
||||
;; Weltpunkt (realer Bug: K1 landete beim Vorzeichen von X/Y gespiegelt weit
|
||||
;; ausserhalb der eigenen Boundingbox, sichtbar als fehlendes K-Kreuz in
|
||||
;; sps_skel/HundM05_bbs.svg trotz gefuelltem K1 in der CSV).
|
||||
(defun csv:get-k-kos-strings (ename pt parent-R / ed bname blk-tbl sub-ent sub-ed
|
||||
sub-bname sub-pt sub-extrusion sub-pt-real world-pt
|
||||
target is-real result)
|
||||
(setq ed (entget ename))
|
||||
(setq bname (cdr (assoc 2 ed)))
|
||||
(setq blk-tbl (tblsearch "BLOCK" bname))
|
||||
(setq result nil)
|
||||
(if blk-tbl
|
||||
(progn
|
||||
(setq sub-ent (entnext (cdr (assoc -2 blk-tbl))))
|
||||
;; (assoc -2) ist bereits das ERSTE Entity der Blockdefinition, NICHT
|
||||
;; der BLOCK-Header - direkt hier starten, kein entnext davor (das
|
||||
;; uebersprang sonst ein K1/KS_EIN, das zufaellig als erstes Entity in
|
||||
;; der Blockdefinition steht - derselbe Bug wie frueher in
|
||||
;; ssg-collect-nested-inserts-rel, siehe dortiger Kommentar).
|
||||
(setq sub-ent (cdr (assoc -2 blk-tbl)))
|
||||
(while sub-ent
|
||||
(setq sub-ed (entget sub-ent))
|
||||
(if (= (cdr (assoc 0 sub-ed)) "INSERT")
|
||||
@@ -352,7 +385,11 @@
|
||||
(if (and target (or is-real (not (assoc target result))))
|
||||
(progn
|
||||
(setq sub-pt (cdr (assoc 10 sub-ed)))
|
||||
(setq world-pt (csv:local-to-world pt rot-rad sub-pt))
|
||||
(if (null (caddr sub-pt))
|
||||
(setq sub-pt (list (car sub-pt) (cadr sub-pt) 0.0)))
|
||||
(setq sub-extrusion (cond ((cdr (assoc 210 sub-ed))) ('(0.0 0.0 1.0))))
|
||||
(setq sub-pt-real (mat3-mul-vec3 (mat3-ocs-matrix sub-extrusion) sub-pt))
|
||||
(setq world-pt (csv:local-to-world pt parent-R sub-pt-real))
|
||||
(setq result (cons
|
||||
(cons target
|
||||
(csv:trans-encode
|
||||
@@ -483,14 +520,17 @@
|
||||
(setq ed (entget ename))
|
||||
(setq bname (cdr (assoc 2 ed)))
|
||||
(setq result nil)
|
||||
;; Beide Enden im Wrapper-Frame holen und in Weltkoordinaten (reine
|
||||
;; Z-Drehung) umrechnen. AS traegt das KS_EIN, ES das KS_AUS - jeweils aus
|
||||
;; dem RICHTIGEN Element (csv:vfgf-ks-loc; beide Elemente fuehren beide
|
||||
;; KS-Typen).
|
||||
;; Beide Enden im Wrapper-Frame holen und in Weltkoordinaten umrechnen.
|
||||
;; VF_n/GF_n-Wrapper stehen an ihrem eigenen top-level INSERT immer flach
|
||||
;; (Extrusion (0 0 1) - siehe csv:sep-proxies-erzeugen), darum genuegt hier
|
||||
;; weiterhin die reine Z-Drehungsmatrix (mat3-rz) statt der vollen
|
||||
;; Elternorientierung, die csv:get-k-kos-strings inzwischen braucht (siehe
|
||||
;; dort). AS traegt das KS_EIN, ES das KS_AUS - jeweils aus dem RICHTIGEN
|
||||
;; Element (csv:vfgf-ks-loc; beide Elemente fuehren beide KS-Typen).
|
||||
(setq as-loc (csv:vfgf-ks-loc bname "AS_ELEMENT*" "KS_EIN,KSYS_EIN"))
|
||||
(setq es-loc (csv:vfgf-ks-loc bname "ES_ELEMENT*" "KS_AUS,KSYS_AUS"))
|
||||
(if as-loc (setq as-world (csv:local-to-world pt rot-rad as-loc)))
|
||||
(if es-loc (setq es-world (csv:local-to-world pt rot-rad es-loc)))
|
||||
(if as-loc (setq as-world (csv:local-to-world pt (mat3-rz rot-rad) as-loc)))
|
||||
(if es-loc (setq es-world (csv:local-to-world pt (mat3-rz rot-rad) es-loc)))
|
||||
;; Eingang/Ausgang festlegen (siehe Richtung im Kopfkommentar).
|
||||
(cond
|
||||
;; GF: Richtung ueber die Hoehe - hoeheres Z = Eingang, tieferes Z = Ausgang.
|
||||
@@ -609,7 +649,8 @@
|
||||
;; "k1".."k4" (KOS-Strings der Koordinatensysteme im Block, siehe
|
||||
;; csv:get-k-kos-strings) werden immer geschrieben, unabhaengig von
|
||||
;; include-bbox -- Kodierung ueber csv:kos-encode (siehe dort).
|
||||
(defun csv:block-to-json (ename include-bbox / ed blk-name layer pt rotation handle attribs bbox bbox-json
|
||||
(defun csv:block-to-json (ename include-bbox / ed blk-name layer pt rotation extrusion R-world
|
||||
handle attribs bbox bbox-json
|
||||
insert-quat insert-kos k-list warnung-json warnung-eintrag
|
||||
zuordnung-fix-json zuordnung-fix-eintrag sepliste-json sepliste-app sepliste
|
||||
sepliste-teile sepliste-first)
|
||||
@@ -620,12 +661,27 @@
|
||||
(setq rotation (cdr (assoc 50 ed)))
|
||||
(setq handle (cdr (assoc 5 ed)))
|
||||
(if (null rotation) (setq rotation 0.0))
|
||||
(if (null (caddr pt)) (setq pt (list (car pt) (cadr pt) 0.0)))
|
||||
;; Gruppe 10 ist OCS-lokal zur EIGENEN Extrusion dieses INSERT (Gruppe
|
||||
;; 210) - fuer die allermeisten Bloecke (0 0 1) = Welt, aber ein Separator-
|
||||
;; Proxy, der ueber ssg-collect-nested-inserts aus dem geneigten Abschnitt
|
||||
;; einer VF-/GF-Kette neu zusammengesetzt wurde (csv:sep-proxies-erzeugen),
|
||||
;; kann eine echt gekippte Extrusion tragen. Erst in echte Weltkoordinaten/
|
||||
;; -orientierung umrechnen (Arbitrary Axis Algorithm, ssg_core.lsp), bevor
|
||||
;; irgendetwas darauf aufbaut - sonst zeigt "x"/"y"/"z" (und darueber K1-K4,
|
||||
;; siehe csv:get-k-kos-strings) einen falschen, teils spiegelverkehrten
|
||||
;; Weltpunkt (realer Bug: Separator :4/6/8/10/12 in HundM05, K1 landete am
|
||||
;; Vorzeichen gespiegelt weit ausserhalb der eigenen Boundingbox). Fuer
|
||||
;; Extrusion=(0 0 1) reduziert sich das exakt auf die alte Uebernahme.
|
||||
(setq extrusion (cond ((cdr (assoc 210 ed))) ('(0.0 0.0 1.0))))
|
||||
(setq pt (mat3-mul-vec3 (mat3-ocs-matrix extrusion) pt))
|
||||
(setq R-world (mat3-from-normal-rotation extrusion rotation))
|
||||
(setq attribs (csv:read-attribs ename))
|
||||
(setq insert-quat (csv:z-angle-to-quat (* (/ rotation pi) 180.0)))
|
||||
(setq insert-kos (csv:kos-encode
|
||||
(car pt) (cadr pt) (if (caddr pt) (caddr pt) 0.0)
|
||||
(nth 0 insert-quat) (nth 1 insert-quat) (nth 2 insert-quat) (nth 3 insert-quat)))
|
||||
(setq k-list (csv:get-k-kos-strings ename pt rotation))
|
||||
(setq k-list (csv:get-k-kos-strings ename pt R-world))
|
||||
;; Omniflo-Geraden fuehren keine echten K-Bloecke - K1/K2 aus der Geometrie
|
||||
;; (Anfang/Ende ueber Laenge + Rotation) synthetisieren, damit sie im Export
|
||||
;; wie echte Anschluss-Koordinatensysteme erscheinen und in der Nachbar-
|
||||
@@ -1088,6 +1144,13 @@
|
||||
;; ils-insert-station in SSG_LIB_Commands.lsp). Anders als Separator/
|
||||
;; Scanner werden sie von KEINEM anderen Element mitgezaehlt - export_csv.py
|
||||
;; UND export_sivas.py fuehren sie beide als eigene TeileArt-Zeilen.
|
||||
;; Eingang*/Ausgang* = Materialfluss-Ein-/Ausgangssymbole (siehe
|
||||
;; pattern_eingang/pattern_ausgang in cfg/export.cfg, ils-insert-station in
|
||||
;; SSG_LIB_Commands.lsp). Wie BTMT eigenstaendig, aber NUR fuer den
|
||||
;; CSV-Export: export_csv.py gibt ihnen eigene TeileArt-Zeilen und traegt
|
||||
;; sie - wie Separator/AS/ES - in die "TrackIds"-Spalte ein (auch auf
|
||||
;; Kreiseln, siehe KREISEL_UMLAUF_TEILEARTEN in lib/export_neighbors.py);
|
||||
;; export_sivas.py schliesst sie bewusst aus.
|
||||
;; GR_* = Geruest-Baugruppen (siehe pattern_geruest in cfg/export.cfg,
|
||||
;; GeruestInsert.lsp). Wie BTMT eigenstaendig und von keinem anderen
|
||||
;; Element mitgezaehlt - export_csv.py UND export_sivas.py fuehren sie
|
||||
@@ -1111,6 +1174,8 @@
|
||||
(wcmatch bname (export:pattern "pattern_scanner" "Scanner*"))
|
||||
(wcmatch bname (export:pattern "pattern_btmt_beladung" "BTMT-Beladung*"))
|
||||
(wcmatch bname (export:pattern "pattern_btmt_entladung" "SC_Entladung*"))
|
||||
(wcmatch bname (export:pattern "pattern_eingang" "Eingang*"))
|
||||
(wcmatch bname (export:pattern "pattern_ausgang" "Ausgang*"))
|
||||
(wcmatch bname (export:pattern "pattern_geruest" "GR_*"))
|
||||
;; Rein numerische Namen = Omniflo SivasNr (Boegen/Weichen)
|
||||
;; Rein LISP-intern (Python klassifiziert Omniflo stattdessen
|
||||
@@ -1157,16 +1222,18 @@
|
||||
;; --- Gemeinsame Export-Funktion ---
|
||||
;; Sammelt relevante Bloecke, schreibt JSON, ruft Python auf.
|
||||
;; label = Anzeigename (z.B. "EXPORTCSV")
|
||||
;; py-name = Python-Skript-Name (z.B. "export_csv.py")
|
||||
;; csv-name = Ergebnis-CSV-Name (z.B. "export.csv")
|
||||
;; include-bbox = T -> Bounding-Box je Block ermitteln und mit exportieren
|
||||
;; (siehe csv:block-to-json); fuer EXPORTSIVAS nil.
|
||||
(defun csv:run-export (label py-name csv-name include-bbox / ss i ename fh out-pfad
|
||||
py-skript ergebnis-pfad py-exe log-pfad rc first-block
|
||||
count out-dir sep-proxies)
|
||||
;; --- Export-Vorbereitung: Zeichnungszustand fuer den Export herrichten ---
|
||||
;; Aus csv:run-export ausgelagert: alle Schritte, die VOR dem Sammeln/Schreiben
|
||||
;; den Zeichnungszustand herrichten - Separator-Proxies einpacken, IDs
|
||||
;; sicherstellen, Proxy-Zuordnung setzen, Omniflo-Attribute (HOEHE/DREHUNG)
|
||||
;; aktualisieren, Separator-/Scanner-Zuordnung pruefen, global regenerieren und
|
||||
;; die bbox-Fehlerdiagnose zuruecksetzen. Rueckgabe: die Liste der erzeugten
|
||||
;; Separator-Proxies (der Aufrufer entfernt sie am Ende wieder). label dient
|
||||
;; nur den Meldungen.
|
||||
(defun csv:export-vorbereiten (label / sep-proxies)
|
||||
;; Verpackte Separator_SP-Symbole (siehe csv:sep-proxies-erzeugen) VOR der
|
||||
;; ID-Vergabe durch temporaere, echte Kopien ersetzen - sie werden am Ende
|
||||
;; dieser Funktion wieder entfernt (csv:sep-proxies-loeschen).
|
||||
;; von csv:run-export wieder entfernt (csv:sep-proxies-loeschen).
|
||||
;;
|
||||
;; HINWEIS: csv:sepliste-proxies-erzeugen (echte Kopien fuer die nur noch in
|
||||
;; der sepliste-XDATA gefuehrten SEP/AS/ES-Eintraege der VF_n/GF_n-Wrapper)
|
||||
@@ -1226,6 +1293,76 @@
|
||||
;; bbox-Fehlerdiagnose fuer diesen Lauf zuruecksetzen (siehe csv:get-bbox).
|
||||
(setq *csv-bbox-fail-count* 0)
|
||||
(setq *csv-bbox-fail-first* nil)
|
||||
sep-proxies)
|
||||
|
||||
;; --- Python-Export-Skript aufrufen und Ergebnis auswerten ---------------
|
||||
;; Aus csv:run-export ausgelagert: das fertige raw-JSON (out-pfad) an das
|
||||
;; Python-Skript py-name uebergeben, synchron ausfuehren und den Exitcode
|
||||
;; auswerten (kein stiller Fehlschlag). Arbeitet ausschliesslich ueber die
|
||||
;; uebergebenen Pfade/Namen und die Umgebung (DXFM_LIB/DXFM_DATA/DXFM_LOG) -
|
||||
;; keine Zeichnungs-/Sammel-Logik mehr, daher gut fuer sich testbar.
|
||||
;; label/out-dir dienen nur den Meldungen bzw. dem Ergebnis-Pfad.
|
||||
(defun csv:python-aufrufen (label out-dir out-pfad py-name csv-name
|
||||
/ py-skript ergebnis-pfad py-exe log-pfad rc)
|
||||
;; Python-Skript aufrufen. DXFM_LIB muss gesetzt sein - fehlt es
|
||||
;; (z.B. weil BricsCAD nicht ueber bin/start_briscad.bat gestartet
|
||||
;; wurde und die Umgebungsvariablen daher nie in diesen Prozess
|
||||
;; vererbt wurden), wuerde das folgende strcat sonst mit einem
|
||||
;; kryptischen Lisp-Fehler ("bad argument type <NIL>") abbrechen.
|
||||
(if (null (getenv "DXFM_LIB"))
|
||||
(princ (ssg-textf "exp-dxfm-lib-missing" (list label)))
|
||||
(progn
|
||||
(setq py-skript (strcat (getenv "DXFM_LIB") "/" py-name))
|
||||
(if (findfile py-skript)
|
||||
(progn
|
||||
(setq ergebnis-pfad (strcat out-dir "/" (export:dwg-praefix) csv-name))
|
||||
(setq py-exe (export:python-exe))
|
||||
(setq log-pfad (strcat (cond ((getenv "DXFM_LOG")) (out-dir))
|
||||
"/export_python.log"))
|
||||
(princ (ssg-textf "exp-python-exe" (list label py-exe)))
|
||||
(princ (ssg-textf "exp-calling-python" (list label)))
|
||||
;; Synchron ausfuehren und Exitcode auswerten - ein stiller
|
||||
;; Fehlschlag (z.B. WindowsApps-Platzhalter statt Interpreter)
|
||||
;; darf nicht mehr als "Export gestartet" durchgehen.
|
||||
(setq rc (export:run-python py-exe py-skript
|
||||
(list out-pfad (getenv "DXFM_DATA") ergebnis-pfad)
|
||||
log-pfad))
|
||||
(cond
|
||||
((null rc)
|
||||
(princ (ssg-textf "exp-python-call-failed" (list label))))
|
||||
((/= rc 0)
|
||||
(princ (ssg-textf "exp-python-error" (list label rc log-pfad)))
|
||||
(export:log-ausgeben log-pfad 12)
|
||||
;; Exitcode 49 (Store-Platzhalter direkt) bzw. 9009 (cmd.exe:
|
||||
;; "Befehl nicht gefunden") = kein brauchbarer Interpreter.
|
||||
;; Gezielter Hinweis, wie er korrekt gesetzt wird.
|
||||
(if (or (= rc 49) (= rc 9009)
|
||||
(export:python-store-stub-p py-exe))
|
||||
(princ (ssg-text "exp-python-store-hint"))
|
||||
))
|
||||
((not (findfile ergebnis-pfad))
|
||||
(princ (ssg-textf "exp-csv-missing" (list label ergebnis-pfad log-pfad)))
|
||||
(export:log-ausgeben log-pfad 12))
|
||||
(t
|
||||
(princ (ssg-textf "exp-export-done" (list label ergebnis-pfad))))
|
||||
)
|
||||
)
|
||||
(princ (ssg-textf "exp-python-not-found" (list label py-skript)))
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
;; py-name = Python-Skript-Name (z.B. "export_csv.py")
|
||||
;; csv-name = Ergebnis-CSV-Name (z.B. "export.csv")
|
||||
;; include-bbox = T -> Bounding-Box je Block ermitteln und mit exportieren
|
||||
;; (siehe csv:block-to-json); fuer EXPORTSIVAS nil.
|
||||
(defun csv:run-export (label py-name csv-name include-bbox / ss i ename fh out-pfad
|
||||
first-block count out-dir sep-proxies)
|
||||
;; Zeichnungszustand fuer den Export herrichten (Proxies, IDs, Zuordnung,
|
||||
;; Attribut-Update, Sep/Scan-Zaehlung, REGENALL, bbox-Reset) - ausgelagert.
|
||||
;; Rueckgabe: die erzeugten Separator-Proxies (unten wieder zu entfernen).
|
||||
(setq sep-proxies (csv:export-vorbereiten label))
|
||||
(princ (ssg-textf "exp-collect-blocks" (list label)))
|
||||
|
||||
(setq ss (csv:collect-export-blocks))
|
||||
@@ -1285,53 +1422,8 @@
|
||||
(list (itoa *csv-bbox-fail-count*)
|
||||
(cond (*csv-bbox-fail-first*) ("?"))))))
|
||||
|
||||
;; Python-Skript aufrufen. DXFM_LIB muss gesetzt sein - fehlt es
|
||||
;; (z.B. weil BricsCAD nicht ueber bin/start_briscad.bat gestartet
|
||||
;; wurde und die Umgebungsvariablen daher nie in diesen Prozess
|
||||
;; vererbt wurden), wuerde das folgende strcat sonst mit einem
|
||||
;; kryptischen Lisp-Fehler ("bad argument type <NIL>") abbrechen.
|
||||
(if (null (getenv "DXFM_LIB"))
|
||||
(princ (ssg-textf "exp-dxfm-lib-missing" (list label)))
|
||||
(progn
|
||||
(setq py-skript (strcat (getenv "DXFM_LIB") "/" py-name))
|
||||
(if (findfile py-skript)
|
||||
(progn
|
||||
(setq ergebnis-pfad (strcat out-dir "/" (export:dwg-praefix) csv-name))
|
||||
(setq py-exe (export:python-exe))
|
||||
(setq log-pfad (strcat (cond ((getenv "DXFM_LOG")) (out-dir))
|
||||
"/export_python.log"))
|
||||
(princ (ssg-textf "exp-python-exe" (list label py-exe)))
|
||||
(princ (ssg-textf "exp-calling-python" (list label)))
|
||||
;; Synchron ausfuehren und Exitcode auswerten - ein stiller
|
||||
;; Fehlschlag (z.B. WindowsApps-Platzhalter statt Interpreter)
|
||||
;; darf nicht mehr als "Export gestartet" durchgehen.
|
||||
(setq rc (export:run-python py-exe py-skript
|
||||
(list out-pfad (getenv "DXFM_DATA") ergebnis-pfad)
|
||||
log-pfad))
|
||||
(cond
|
||||
((null rc)
|
||||
(princ (ssg-textf "exp-python-call-failed" (list label))))
|
||||
((/= rc 0)
|
||||
(princ (ssg-textf "exp-python-error" (list label rc log-pfad)))
|
||||
(export:log-ausgeben log-pfad 12)
|
||||
;; Exitcode 49 (Store-Platzhalter direkt) bzw. 9009 (cmd.exe:
|
||||
;; "Befehl nicht gefunden") = kein brauchbarer Interpreter.
|
||||
;; Gezielter Hinweis, wie er korrekt gesetzt wird.
|
||||
(if (or (= rc 49) (= rc 9009)
|
||||
(export:python-store-stub-p py-exe))
|
||||
(princ (ssg-text "exp-python-store-hint"))
|
||||
))
|
||||
((not (findfile ergebnis-pfad))
|
||||
(princ (ssg-textf "exp-csv-missing" (list label ergebnis-pfad log-pfad)))
|
||||
(export:log-ausgeben log-pfad 12))
|
||||
(t
|
||||
(princ (ssg-textf "exp-export-done" (list label ergebnis-pfad))))
|
||||
)
|
||||
)
|
||||
(princ (ssg-textf "exp-python-not-found" (list label py-skript)))
|
||||
)
|
||||
)
|
||||
)
|
||||
;; Python-Export-Skript aufrufen (ausgelagert, siehe oben).
|
||||
(csv:python-aufrufen label out-dir out-pfad py-name csv-name)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
@@ -0,0 +1,314 @@
|
||||
;; ============================================================
|
||||
;; list_blocks.lsp
|
||||
;; Liest die (Sub-)Block-Definitionen aller DWG-Dateien in
|
||||
;; data/ils aus und schreibt sie als JSON-Report
|
||||
;; "blocks_collected.json" nach data/ils.
|
||||
;;
|
||||
;; Hintergrund: 2D- und 3D-Bloecke (z.B.
|
||||
;; Vario_Bogen_ab_27_TEF_rechts_2D.dwg /
|
||||
;; Vario_Bogen_ab_27_TEF_rechts_3D.dwg)
|
||||
;; enthalten teilweise gleichnamige Sub-Bloecke (z.B.
|
||||
;; "200000317_TEF_Bogen_vertikal_abwaerts__15"). Werden beide
|
||||
;; DWGs in dieselbe Zeichnung eingefuegt, kollidieren diese
|
||||
;; Definitionen (nur eine Referenz gewinnt). Dieses Skript LIEST
|
||||
;; die Bloecke nur aus, damit manuell entschieden werden kann,
|
||||
;; welche spaeter mit "_2D"/"_3D" umbenannt werden.
|
||||
;;
|
||||
;; Ausgabe:
|
||||
;; - JSON data/ils/blocks_collected.json:
|
||||
;; { "<Dateiname ohne .dwg>": { "dim": "2D"|"3D"|"-",
|
||||
;; "blocks": ["Name", ...] }, ... }
|
||||
;; - Konsolen-Report inkl. Kollisionsliste (gleicher Blockname
|
||||
;; kommt sowohl in einer _2D- als auch in einer _3D-Datei vor)
|
||||
;;
|
||||
;; Voraussetzung: DXFM_DATA ist gesetzt (siehe bin/setenv.bat).
|
||||
;;
|
||||
;; Aufruf in BricsCAD:
|
||||
;; (load "C:/.../Lisp/list_blocks.lsp")
|
||||
;; ILS_BLOCK_LIST
|
||||
;; ============================================================
|
||||
|
||||
(vl-load-com)
|
||||
|
||||
;; ------------------------------------------------------------
|
||||
;; Bereits offenes Dokument mit gegebenem Pfad suchen (oder nil)
|
||||
;; ------------------------------------------------------------
|
||||
(defun lb-find-open-doc (dwg-pfad / docs anzahl i doc full treffer)
|
||||
(setq docs (vla-get-Documents (vlax-get-acad-object))
|
||||
anzahl (vla-get-Count docs)
|
||||
i 0
|
||||
treffer nil
|
||||
dwg-pfad (strcase (vl-string-translate "\\" "/" dwg-pfad))
|
||||
)
|
||||
(while (and (< i anzahl) (not treffer))
|
||||
(setq doc (vla-item docs i))
|
||||
(setq full (strcase (vl-string-translate "\\" "/" (vla-get-FullName doc))))
|
||||
(if (= full dwg-pfad) (setq treffer doc))
|
||||
(setq i (1+ i))
|
||||
)
|
||||
treffer
|
||||
)
|
||||
|
||||
;; ------------------------------------------------------------
|
||||
;; String fuer JSON escapen (Anfuehrungszeichen/Backslash)
|
||||
;; ------------------------------------------------------------
|
||||
(defun lb-json-escape (s)
|
||||
(if (null s) (setq s ""))
|
||||
(setq s (vl-string-subst "\\\\" "\\" s))
|
||||
(vl-string-subst "\\\"" "\"" s)
|
||||
)
|
||||
|
||||
;; ------------------------------------------------------------
|
||||
;; Strings mit Trennzeichen verbinden
|
||||
;; ------------------------------------------------------------
|
||||
(defun lb-strjoin (liste sep / erg erste s)
|
||||
(setq erg "" erste T)
|
||||
(foreach s liste
|
||||
(if erste (setq erg s erste nil) (setq erg (strcat erg sep s)))
|
||||
)
|
||||
erg
|
||||
)
|
||||
|
||||
;; ------------------------------------------------------------
|
||||
;; Dimension aus dem Dateinamen ableiten ("2D"/"3D"/"-")
|
||||
;; ------------------------------------------------------------
|
||||
(defun lb-dim-aus-name (basisname / n)
|
||||
(setq n (strcase basisname))
|
||||
(cond
|
||||
((wcmatch n "*_2D") "2D")
|
||||
((wcmatch n "*_3D") "3D")
|
||||
(t "-")
|
||||
)
|
||||
)
|
||||
|
||||
;; ------------------------------------------------------------
|
||||
;; Alle echten (Sub-)Block-Definitionen des aktiven Dokuments
|
||||
;; einsammeln (Symboltabelle BLOCK): keine Layouts (Model/Paper-
|
||||
;; Space, "*..."), keine anonymen Bloecke (Flag 1), keine XRefs
|
||||
;; (Flag 4). Alphabetisch sortiert.
|
||||
;; ------------------------------------------------------------
|
||||
(defun lb-collect-blocks-in-current-doc ( / def name flags ergebnis)
|
||||
(setq ergebnis nil
|
||||
def (tblnext "BLOCK" T)
|
||||
)
|
||||
(while def
|
||||
(setq name (cdr (assoc 2 def))
|
||||
flags (cdr (assoc 70 def))
|
||||
)
|
||||
(if (null flags) (setq flags 0))
|
||||
(if (and name
|
||||
(> (strlen name) 0)
|
||||
(/= (substr name 1 1) "*") ; kein Model/Paper-Space
|
||||
(= (logand flags 1) 0) ; nicht anonym
|
||||
(= (logand flags 4) 0) ; kein XRef
|
||||
)
|
||||
(setq ergebnis (cons name ergebnis))
|
||||
)
|
||||
(setq def (tblnext "BLOCK"))
|
||||
)
|
||||
(vl-sort ergebnis (function (lambda (a b) (< (strcase a) (strcase b)))))
|
||||
)
|
||||
|
||||
;; ------------------------------------------------------------
|
||||
;; Eine DWG-Datei oeffnen (falls noetig), Bloecke einsammeln und
|
||||
;; die Datei wieder schliessen (falls durch diese Funktion geoeffnet).
|
||||
;; Rueckgabe: ('ok . ("Name" ...)) oder ('fehler . meldung)
|
||||
;; ------------------------------------------------------------
|
||||
(defun lb-collect-dwg (dwg-pfad / bereits-offen ergebnis fehler)
|
||||
(setq bereits-offen (lb-find-open-doc dwg-pfad))
|
||||
(setq ergebnis nil)
|
||||
(setq fehler
|
||||
(vl-catch-all-apply
|
||||
(function
|
||||
(lambda ()
|
||||
(if bereits-offen
|
||||
(vlax-put-property (vlax-get-acad-object) 'ActiveDocument bereits-offen)
|
||||
(command "_.OPEN" dwg-pfad)
|
||||
)
|
||||
(setq ergebnis (lb-collect-blocks-in-current-doc))
|
||||
(if (not bereits-offen) (command "_.CLOSE"))
|
||||
)
|
||||
)
|
||||
nil
|
||||
)
|
||||
)
|
||||
(if (vl-catch-all-error-p fehler)
|
||||
(cons 'fehler (vl-catch-all-error-message fehler))
|
||||
(cons 'ok ergebnis)
|
||||
)
|
||||
)
|
||||
|
||||
;; ------------------------------------------------------------
|
||||
;; Liste als JSON-Array-Text formatieren (["a", "b"]), eingerueckt
|
||||
;; ------------------------------------------------------------
|
||||
(defun lb-list-to-json (namen einruecken / innen zeilen)
|
||||
(if (null namen)
|
||||
"[]"
|
||||
(progn
|
||||
(setq innen (strcat einruecken " "))
|
||||
(setq zeilen
|
||||
(mapcar
|
||||
(function (lambda (nm) (strcat innen "\"" (lb-json-escape nm) "\"")))
|
||||
namen
|
||||
)
|
||||
)
|
||||
(strcat "[\n"
|
||||
(car zeilen)
|
||||
(apply 'strcat (mapcar (function (lambda (z) (strcat ",\n" z))) (cdr zeilen)))
|
||||
"\n" einruecken "]"
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
;; ------------------------------------------------------------
|
||||
;; Kollisionen ermitteln: Bloecke, deren Name sowohl in einer
|
||||
;; _2D- als auch in einer _3D-Datei vorkommt.
|
||||
;; eintraege = (("<datei>" "2D"|"3D"|"-" ("blk" ...)) ...)
|
||||
;; Rueckgabe: (("blockname" ("datei-2d" ...) ("datei-3d" ...)) ...)
|
||||
;; ------------------------------------------------------------
|
||||
(defun lb-finde-kollisionen (eintraege / tabelle e datei dim blks blk vorhanden coll)
|
||||
;; tabelle: blockname -> (liste-2d-dateien . liste-3d-dateien)
|
||||
(setq tabelle nil)
|
||||
(foreach e eintraege
|
||||
(setq datei (nth 0 e)
|
||||
dim (nth 1 e)
|
||||
blks (nth 2 e)
|
||||
)
|
||||
(foreach blk blks
|
||||
(setq vorhanden (assoc blk tabelle))
|
||||
(if (not vorhanden)
|
||||
(setq vorhanden (list blk nil nil)
|
||||
tabelle (cons vorhanden tabelle))
|
||||
)
|
||||
(cond
|
||||
((= dim "2D") (setq vorhanden (subst (cons datei (nth 1 vorhanden)) (nth 1 vorhanden) vorhanden)))
|
||||
((= dim "3D") (setq vorhanden (subst (cons datei (nth 2 vorhanden)) (nth 2 vorhanden) vorhanden)))
|
||||
)
|
||||
;; aktualisierten Eintrag zurueckschreiben
|
||||
(setq tabelle (subst vorhanden (assoc blk tabelle) tabelle))
|
||||
)
|
||||
)
|
||||
;; nur Bloecke mit mind. einer 2D- UND einer 3D-Datei
|
||||
(setq coll nil)
|
||||
(foreach e tabelle
|
||||
(if (and (nth 1 e) (nth 2 e))
|
||||
(setq coll (cons e coll))
|
||||
)
|
||||
)
|
||||
(vl-sort coll (function (lambda (a b) (< (strcase (car a)) (strcase (car b))))))
|
||||
)
|
||||
|
||||
;; ------------------------------------------------------------
|
||||
;; Hauptbefehl - verarbeitet DXFM_DATA/ils
|
||||
;; ------------------------------------------------------------
|
||||
(defun c:ILS_BLOCK_LIST ( / data-dir dwg-dir json-pfad dateien datei dwg-pfad basisname
|
||||
dim ergebnis orig-doc anzahl-ok anzahl-fehler fehler-liste
|
||||
eintraege fh erste e kollisionen k)
|
||||
(setq data-dir (getenv "DXFM_DATA"))
|
||||
(if (not data-dir)
|
||||
(progn
|
||||
(alert "DXFM_DATA ist nicht gesetzt.\nBitte zuerst bin/setenv.bat ausfuehren.")
|
||||
(exit)
|
||||
)
|
||||
)
|
||||
(setq data-dir (vl-string-translate "\\" "/" data-dir)
|
||||
dwg-dir (strcat data-dir "/ils")
|
||||
json-pfad (strcat dwg-dir "/blocks_collected.json")
|
||||
)
|
||||
(setq dwg-dir (vl-string-right-trim "/" dwg-dir))
|
||||
|
||||
(if (not (findfile dwg-dir))
|
||||
(progn
|
||||
(princ (strcat "\n[BLOCK-LIST] Verzeichnis nicht gefunden: " dwg-dir))
|
||||
(exit)
|
||||
)
|
||||
)
|
||||
|
||||
(setq dateien (vl-directory-files dwg-dir "*.dwg" 1))
|
||||
(if (not dateien)
|
||||
(progn
|
||||
(princ (strcat "\n[BLOCK-LIST] Keine DWG-Dateien in: " dwg-dir))
|
||||
(exit)
|
||||
)
|
||||
)
|
||||
|
||||
(setq orig-doc (vla-get-ActiveDocument (vlax-get-acad-object))
|
||||
anzahl-ok 0
|
||||
anzahl-fehler 0
|
||||
fehler-liste nil
|
||||
eintraege nil
|
||||
)
|
||||
(foreach datei dateien
|
||||
(setq basisname (vl-filename-base datei)
|
||||
dwg-pfad (strcat dwg-dir "/" datei)
|
||||
dim (lb-dim-aus-name basisname)
|
||||
)
|
||||
(princ (strcat "\n[BLOCK-LIST] Lese " datei " ..."))
|
||||
(setq ergebnis (lb-collect-dwg dwg-pfad))
|
||||
(if (equal (car ergebnis) 'fehler)
|
||||
(progn
|
||||
(princ (strcat "\n[BLOCK-LIST] FEHLER bei " datei ": " (cdr ergebnis)))
|
||||
(setq anzahl-fehler (1+ anzahl-fehler))
|
||||
(setq fehler-liste (cons datei fehler-liste))
|
||||
)
|
||||
(progn
|
||||
(setq eintraege (cons (list basisname dim (cdr ergebnis)) eintraege))
|
||||
(setq anzahl-ok (1+ anzahl-ok))
|
||||
(princ (strcat " " (itoa (length (cdr ergebnis))) " Block(e)."))
|
||||
)
|
||||
)
|
||||
)
|
||||
(vlax-put-property (vlax-get-acad-object) 'ActiveDocument orig-doc)
|
||||
(setq eintraege (reverse eintraege))
|
||||
|
||||
;; JSON schreiben
|
||||
(setq fh (open json-pfad "w"))
|
||||
(if (null fh)
|
||||
(princ (strcat "\n[BLOCK-LIST] FEHLER: Datei kann nicht geschrieben werden: " json-pfad))
|
||||
(progn
|
||||
(write-line "{" fh)
|
||||
(setq erste T)
|
||||
(foreach e eintraege
|
||||
(if (not erste) (write-line "," fh))
|
||||
(write-line (strcat " \"" (lb-json-escape (nth 0 e)) "\": {") fh)
|
||||
(write-line (strcat " \"dim\": \"" (nth 1 e) "\",") fh)
|
||||
(write-line (strcat " \"blocks\": " (lb-list-to-json (nth 2 e) " ")) fh)
|
||||
(write-line " }" fh)
|
||||
(setq erste nil)
|
||||
)
|
||||
(write-line "}" fh)
|
||||
(close fh)
|
||||
(princ (strcat "\n[BLOCK-LIST] " json-pfad " geschrieben ("
|
||||
(itoa anzahl-ok) " Dateien)."))
|
||||
)
|
||||
)
|
||||
|
||||
;; Kollisionen ermitteln und ausgeben
|
||||
(setq kollisionen (lb-finde-kollisionen eintraege))
|
||||
(princ (strcat "\n[BLOCK-LIST] Fertig: " (itoa anzahl-ok) " gelesen, "
|
||||
(itoa anzahl-fehler) " Fehler, "
|
||||
(itoa (length kollisionen)) " Kollision(en) (Blockname in 2D UND 3D)."))
|
||||
(if kollisionen
|
||||
(progn
|
||||
(princ "\n[BLOCK-LIST] --- Kollisionen (Kandidaten fuer _2D/_3D-Umbenennung) ---")
|
||||
(foreach k kollisionen
|
||||
(princ (strcat "\n * " (car k)))
|
||||
(princ (strcat "\n 2D: " (lb-strjoin (reverse (nth 1 k)) ", ")))
|
||||
(princ (strcat "\n 3D: " (lb-strjoin (reverse (nth 2 k)) ", ")))
|
||||
)
|
||||
)
|
||||
)
|
||||
(if fehler-liste
|
||||
(progn
|
||||
(princ "\n[BLOCK-LIST] WARNUNG: Fehler bei:")
|
||||
(foreach datei (reverse fehler-liste)
|
||||
(princ (strcat "\n - " datei))
|
||||
)
|
||||
)
|
||||
)
|
||||
(princ)
|
||||
)
|
||||
|
||||
(princ "\nlist_blocks.lsp geladen. Befehl: ILS_BLOCK_LIST")
|
||||
(princ)
|
||||
@@ -0,0 +1,225 @@
|
||||
;; ============================================================
|
||||
;; purge_blocks.lsp
|
||||
;; Entfernt in allen DWG-Dateien in data/ils die nicht
|
||||
;; verwendeten Block-Definitionen und Layer (-PURGE Blocks/Layer).
|
||||
;;
|
||||
;; Ablauf je DWG:
|
||||
;; - Datei oeffnen (falls noetig)
|
||||
;; - Block- und Layer-Anzahl zaehlen
|
||||
;; - -PURGE Blocks und -PURGE Layer in einer Schleife ausfuehren,
|
||||
;; bis nichts mehr entfernt wird (verschachtelte Bloecke bzw.
|
||||
;; nur von entfernten Bloecken benutzte Layer werden erst nach
|
||||
;; dem ersten Durchlauf frei)
|
||||
;; - nur speichern, wenn sich die Anzahl verringert hat
|
||||
;; - schliessen (falls durch dieses Skript geoeffnet)
|
||||
;;
|
||||
;; Es werden AUSSCHLIESSLICH unbenutzte Bloecke und Layer entfernt.
|
||||
;; Andere Objekttypen (Linientypen, Textstile, ...) bleiben
|
||||
;; unangetastet.
|
||||
;;
|
||||
;; Voraussetzung: DXFM_DATA ist gesetzt (siehe bin/setenv.bat).
|
||||
;;
|
||||
;; Aufruf in BricsCAD:
|
||||
;; (load "C:/.../Lisp/purge_blocks.lsp")
|
||||
;; ILS_BLOCK_PURGE
|
||||
;; ============================================================
|
||||
|
||||
(vl-load-com)
|
||||
|
||||
;; ------------------------------------------------------------
|
||||
;; Bereits offenes Dokument mit gegebenem Pfad suchen (oder nil)
|
||||
;; ------------------------------------------------------------
|
||||
(defun pb-find-open-doc (dwg-pfad / docs anzahl i doc full treffer)
|
||||
(setq docs (vla-get-Documents (vlax-get-acad-object))
|
||||
anzahl (vla-get-Count docs)
|
||||
i 0
|
||||
treffer nil
|
||||
dwg-pfad (strcase (vl-string-translate "\\" "/" dwg-pfad))
|
||||
)
|
||||
(while (and (< i anzahl) (not treffer))
|
||||
(setq doc (vla-item docs i))
|
||||
(setq full (strcase (vl-string-translate "\\" "/" (vla-get-FullName doc))))
|
||||
(if (= full dwg-pfad) (setq treffer doc))
|
||||
(setq i (1+ i))
|
||||
)
|
||||
treffer
|
||||
)
|
||||
|
||||
;; ------------------------------------------------------------
|
||||
;; Anzahl aller Eintraege einer Symboltabelle zaehlen
|
||||
;; (z.B. "BLOCK" inkl. Model/Paper-Space/anonyme, "LAYER").
|
||||
;; ------------------------------------------------------------
|
||||
(defun pb-count-table (tabelle / n def)
|
||||
(setq n 0 def (tblnext tabelle T))
|
||||
(while def
|
||||
(setq n (1+ n))
|
||||
(setq def (tblnext tabelle))
|
||||
)
|
||||
n
|
||||
)
|
||||
|
||||
;; ------------------------------------------------------------
|
||||
;; Im aktiven Dokument unbenutzte Bloecke UND Layer purgen, bis
|
||||
;; stabil. Erst Bloecke, dann Layer (ein nur von einem entfernten
|
||||
;; Block benutzter Layer wird erst danach frei) - daher Schleife
|
||||
;; ueber beide Typen, bis sich nichts mehr aendert.
|
||||
;; ------------------------------------------------------------
|
||||
(defun pb-purge-current-doc ( / vorher aktuell durchlauf max-durchlauf)
|
||||
(setq vorher (+ (pb-count-table "BLOCK") (pb-count-table "LAYER"))
|
||||
aktuell vorher
|
||||
durchlauf 1
|
||||
max-durchlauf 20
|
||||
)
|
||||
(while (and (<= durchlauf max-durchlauf)
|
||||
(progn
|
||||
(command "_.-PURGE" "_B" "*" "_N") ; unbenutzte Bloecke
|
||||
(command "_.-PURGE" "_LA" "*" "_N") ; unbenutzte Layer
|
||||
(setq aktuell (+ (pb-count-table "BLOCK") (pb-count-table "LAYER")))
|
||||
;; weiter, solange noch etwas entfernt wurde
|
||||
(if (< aktuell vorher)
|
||||
(progn (setq vorher aktuell) T)
|
||||
nil
|
||||
)
|
||||
)
|
||||
)
|
||||
(setq durchlauf (1+ durchlauf))
|
||||
)
|
||||
aktuell
|
||||
)
|
||||
|
||||
;; ------------------------------------------------------------
|
||||
;; Eine DWG-Datei oeffnen (falls noetig), purgen, speichern (nur
|
||||
;; bei Aenderung) und schliessen (falls hier geoeffnet).
|
||||
;; Rueckgabe: ('ok blk-entfernt . lay-entfernt) oder ('fehler . meldung)
|
||||
;; ------------------------------------------------------------
|
||||
(defun pb-purge-dwg (dwg-pfad / bereits-offen blk-vor blk-nach lay-vor lay-nach
|
||||
blk-entfernt lay-entfernt fehler)
|
||||
(setq bereits-offen (pb-find-open-doc dwg-pfad))
|
||||
(setq blk-entfernt 0 lay-entfernt 0)
|
||||
(setq fehler
|
||||
(vl-catch-all-apply
|
||||
(function
|
||||
(lambda ()
|
||||
(if bereits-offen
|
||||
(vlax-put-property (vlax-get-acad-object) 'ActiveDocument bereits-offen)
|
||||
(command "_.OPEN" dwg-pfad)
|
||||
)
|
||||
(setq blk-vor (pb-count-table "BLOCK")
|
||||
lay-vor (pb-count-table "LAYER")
|
||||
)
|
||||
(pb-purge-current-doc)
|
||||
(setq blk-nach (pb-count-table "BLOCK")
|
||||
lay-nach (pb-count-table "LAYER")
|
||||
blk-entfernt (- blk-vor blk-nach)
|
||||
lay-entfernt (- lay-vor lay-nach)
|
||||
)
|
||||
(if (or (> blk-entfernt 0) (> lay-entfernt 0))
|
||||
(command "_.QSAVE")
|
||||
)
|
||||
(if (not bereits-offen) (command "_.CLOSE"))
|
||||
)
|
||||
)
|
||||
nil
|
||||
)
|
||||
)
|
||||
(if (vl-catch-all-error-p fehler)
|
||||
(cons 'fehler (vl-catch-all-error-message fehler))
|
||||
(list 'ok blk-entfernt lay-entfernt)
|
||||
)
|
||||
)
|
||||
|
||||
;; ------------------------------------------------------------
|
||||
;; Hauptbefehl - verarbeitet DXFM_DATA/ils
|
||||
;; ------------------------------------------------------------
|
||||
(defun c:ILS_BLOCK_PURGE ( / data-dir dwg-dir dateien datei dwg-pfad ergebnis
|
||||
orig-doc anzahl-ok anzahl-fehler summe-blk summe-lay
|
||||
blk lay fehler-liste geaendert-liste)
|
||||
(setq data-dir (getenv "DXFM_DATA"))
|
||||
(if (not data-dir)
|
||||
(progn
|
||||
(alert "DXFM_DATA ist nicht gesetzt.\nBitte zuerst bin/setenv.bat ausfuehren.")
|
||||
(exit)
|
||||
)
|
||||
)
|
||||
(setq data-dir (vl-string-translate "\\" "/" data-dir)
|
||||
dwg-dir (vl-string-right-trim "/" (strcat data-dir "/ils"))
|
||||
)
|
||||
|
||||
(if (not (findfile dwg-dir))
|
||||
(progn
|
||||
(princ (strcat "\n[BLOCK-PURGE] Verzeichnis nicht gefunden: " dwg-dir))
|
||||
(exit)
|
||||
)
|
||||
)
|
||||
|
||||
(setq dateien (vl-directory-files dwg-dir "*.dwg" 1))
|
||||
(if (not dateien)
|
||||
(progn
|
||||
(princ (strcat "\n[BLOCK-PURGE] Keine DWG-Dateien in: " dwg-dir))
|
||||
(exit)
|
||||
)
|
||||
)
|
||||
|
||||
(setq orig-doc (vla-get-ActiveDocument (vlax-get-acad-object))
|
||||
anzahl-ok 0
|
||||
anzahl-fehler 0
|
||||
summe-blk 0
|
||||
summe-lay 0
|
||||
fehler-liste nil
|
||||
geaendert-liste nil
|
||||
)
|
||||
(foreach datei dateien
|
||||
(setq dwg-pfad (strcat dwg-dir "/" datei))
|
||||
(princ (strcat "\n[BLOCK-PURGE] Bearbeite " datei " ..."))
|
||||
(setq ergebnis (pb-purge-dwg dwg-pfad))
|
||||
(if (equal (car ergebnis) 'fehler)
|
||||
(progn
|
||||
(princ (strcat "\n[BLOCK-PURGE] FEHLER bei " datei ": " (cdr ergebnis)))
|
||||
(setq anzahl-fehler (1+ anzahl-fehler))
|
||||
(setq fehler-liste (cons datei fehler-liste))
|
||||
)
|
||||
(progn
|
||||
(setq anzahl-ok (1+ anzahl-ok)
|
||||
blk (nth 1 ergebnis)
|
||||
lay (nth 2 ergebnis)
|
||||
)
|
||||
(if (or (> blk 0) (> lay 0))
|
||||
(progn
|
||||
(princ (strcat " " (itoa blk) " Block(e), " (itoa lay) " Layer entfernt, gespeichert."))
|
||||
(setq summe-blk (+ summe-blk blk)
|
||||
summe-lay (+ summe-lay lay)
|
||||
)
|
||||
(setq geaendert-liste (cons (strcat datei " (B:" (itoa blk) " L:" (itoa lay) ")") geaendert-liste))
|
||||
)
|
||||
(princ " keine unbenutzten Bloecke/Layer.")
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
(vlax-put-property (vlax-get-acad-object) 'ActiveDocument orig-doc)
|
||||
|
||||
(princ (strcat "\n[BLOCK-PURGE] Fertig: " (itoa anzahl-ok) " Datei(en) bearbeitet, "
|
||||
(itoa summe-blk) " Block(e), "
|
||||
(itoa summe-lay) " Layer entfernt, "
|
||||
(itoa anzahl-fehler) " Fehler."))
|
||||
(if geaendert-liste
|
||||
(progn
|
||||
(princ "\n[BLOCK-PURGE] Geaenderte Dateien:")
|
||||
(foreach datei (reverse geaendert-liste)
|
||||
(princ (strcat "\n - " datei))
|
||||
)
|
||||
)
|
||||
)
|
||||
(if fehler-liste
|
||||
(progn
|
||||
(princ "\n[BLOCK-PURGE] WARNUNG: Fehler bei:")
|
||||
(foreach datei (reverse fehler-liste)
|
||||
(princ (strcat "\n - " datei))
|
||||
)
|
||||
)
|
||||
)
|
||||
(princ)
|
||||
)
|
||||
|
||||
(princ "\npurge_blocks.lsp geladen. Befehl: ILS_BLOCK_PURGE")
|
||||
(princ)
|
||||
+44
-3
@@ -787,7 +787,7 @@
|
||||
;; und Foerderer-Tests) fuehrte das zu minutenlangen Laufzeiten.
|
||||
;; Zum erzwungenen Neu-Einlesen: ssg-block-refresh-reset.
|
||||
;; Rueckgabe: effektiver (suffigierter) Blockname oder nil (Datei nicht gefunden).
|
||||
(defun ssg-ils-block-laden-dim (blockname dim / eff datei base temp-obj osm areq adia)
|
||||
(defun ssg-ils-block-laden-dim (blockname dim / eff datei base temp-obj osm areq adia n)
|
||||
(setq eff (ssg-ils-blockname-dim blockname dim))
|
||||
(setq datei (ssg-ils-block-datei-dim blockname dim))
|
||||
(if (null datei)
|
||||
@@ -825,8 +825,22 @@
|
||||
(if (tblsearch "BLOCK" eff)
|
||||
(command "_.-INSERT" (strcat eff "=" datei) "_Y") ; Redefine bestehender Block
|
||||
(command "_.-INSERT" (strcat eff "=" datei))) ; neu (kein Redefine-Prompt)
|
||||
(if (> (getvar "CMDACTIVE") 0) (command))
|
||||
(if (> (getvar "CMDACTIVE") 0) (command))
|
||||
;; Robust statt fixer 2 Versuche abbrechen: manche Block-DWGs (z.B.
|
||||
;; abweichende INSUNITS) schieben eine zusaetzliche Rueckfrage ein,
|
||||
;; die zwei (command)-Aufrufe nicht immer leeren. Bleibt danach ein
|
||||
;; Befehl aktiv, verschluckt der NAECHSTE (command ...)-Aufruf des
|
||||
;; Aufrufers (die eigentliche Platzierung, z.B. hundm05:bau-sensor/
|
||||
;; ils-insert-station) dessen Argumente als Antwort auf DIESEN noch
|
||||
;; offenen Prompt - Ursache eines real beobachteten kaputten Blocks
|
||||
;; (fehlende Attribute) beim letzten Element eines Testlaufs.
|
||||
(setq n 0)
|
||||
(while (and (> (getvar "CMDACTIVE") 0) (< n 10))
|
||||
(command)
|
||||
(setq n (1+ n)))
|
||||
(if (> (getvar "CMDACTIVE") 0)
|
||||
(princ (strcat "\n[SSG] WARNUNG: Laden von '" eff
|
||||
"' hat einen Befehl aktiv gelassen (CMDACTIVE > 0) -"
|
||||
" nachfolgende Einfuegungen sind evtl. beschaedigt.")))
|
||||
(setvar "OSMODE" osm)(setvar "ATTREQ" areq)(setvar "ATTDIA" adia)))
|
||||
;; Nur merken, wenn die Definition danach wirklich vorhanden ist -
|
||||
;; sonst wuerde ein fehlgeschlagener Ladeversuch dauerhaft gesperrt.
|
||||
@@ -1767,6 +1781,33 @@
|
||||
(cdr (assoc key obj))
|
||||
)
|
||||
|
||||
;; String fuer die Ausgabe in JSON maskieren (Gegenstueck zu ssg-json-string).
|
||||
;; Der Backslash MUSS zuerst geprueft werden, sonst wuerde die Maskierung der
|
||||
;; Anfuehrungszeichen gleich wieder mitmaskiert.
|
||||
;; Hinweis: csv:json-escape in export.lsp leistet dasselbe, ist aber modul-lokal
|
||||
;; am Export-Modul - bewusst nicht zusammengelegt, das waere ein eigener Schritt.
|
||||
(defun ssg-json-escape (s / i c erg)
|
||||
(if (null s) (setq s ""))
|
||||
(setq erg "" i 1)
|
||||
(while (<= i (strlen s))
|
||||
(setq c (substr s i 1))
|
||||
(setq erg
|
||||
(strcat erg
|
||||
(cond
|
||||
((= c "\\") "\\\\")
|
||||
((= c "\"") "\\\"")
|
||||
((= c (chr 10)) "\\n")
|
||||
((= c (chr 13)) "\\r")
|
||||
((= c (chr 9)) "\\t")
|
||||
(T c)
|
||||
)
|
||||
)
|
||||
)
|
||||
(setq i (1+ i))
|
||||
)
|
||||
erg
|
||||
)
|
||||
|
||||
|
||||
;; Verschachteltes JSON-Objekt parsen (1 Ebene tief)
|
||||
;; {"section": {"key": val, ...}, ...}
|
||||
|
||||
@@ -38,6 +38,11 @@
|
||||
;; pattern_btmt_entladung in cfg/export.cfg) aus demselben Grund: sonst bleibt
|
||||
;; ihre ID trotz ATTDEF leer und sie fehlen bei der zeichnungsweiten Duplikat-
|
||||
;; pruefung/Maximum-Ermittlung (ssg-id-check-all).
|
||||
;; Eingang*/Ausgang* (Materialfluss-Ein-/Ausgangssymbole, siehe
|
||||
;; pattern_eingang/pattern_ausgang in cfg/export.cfg) ebenso: die DWGs haben
|
||||
;; seit dem ID-Nachtrag (allocations.json) ein leeres ID-ATTDEF, das hier
|
||||
;; gefuellt werden muss, damit sie eine stabile TeileId fuer die "TrackIds"-
|
||||
;; 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.
|
||||
(defun ssg-id-collect-blocks ( / ss-all ss-out i ename ed bname)
|
||||
@@ -57,6 +62,7 @@
|
||||
(wcmatch bname "Vario*,Staustrecke*,AUS_Element*,EIN_Element*,VF_*,GF_*")
|
||||
(wcmatch bname "Separator_SP*,S-LP*,Scanner*")
|
||||
(wcmatch bname "BTMT-Beladung*,SC_Entladung*")
|
||||
(wcmatch bname "Eingang*,Ausgang*")
|
||||
(wcmatch bname "GR_*")
|
||||
(wcmatch bname "#*")
|
||||
)
|
||||
|
||||
+20
-1
@@ -413,13 +413,32 @@
|
||||
(reverse liste)
|
||||
)
|
||||
|
||||
;; Koordinate mit GENAU 2 Nachkommastellen formatieren - bewusst OHNE rtos.
|
||||
;; rtos haengt an den Zeichnungs-Systemvariablen DIMZIN (Nullunterdrueckung),
|
||||
;; LUPREC und LUNITS: bei dem hier verbreiteten DIMZIN=8 wuerde rtos die
|
||||
;; abschliessenden Nullen wegwerfen (10.00 -> 10), und dieselben Koordinaten
|
||||
;; serialisierten je nach Zeichnungsprofil unterschiedlich. Die Sepliste
|
||||
;; landet als XDATA/Journal PERSISTENT am Block - die Serialisierung muss
|
||||
;; darum reproduzierbar und profilunabhaengig sein. Rundung kaufmaennisch,
|
||||
;; mit Uebertrag (9.999 -> 10.00), Vorzeichen bleibt erhalten.
|
||||
(defun ssg-sepliste-fmt-koord (x / neg i f s)
|
||||
(setq neg (< x 0.0) x (abs x))
|
||||
(setq i (fix x))
|
||||
(setq f (fix (+ 0.5 (* 100.0 (- x i)))))
|
||||
(if (>= f 100) (progn (setq i (1+ i)) (setq f (- f 100))))
|
||||
(setq s (strcat (itoa i) "."
|
||||
(if (< f 10) (strcat "0" (itoa f)) (itoa f))))
|
||||
(if neg (strcat "-" s) s)
|
||||
)
|
||||
|
||||
;; Serialisiert die Sepliste zu "TYP:LFDNR:X:Y,TYP:LFDNR:X:Y,...".
|
||||
(defun ssg-sepliste->string (liste / eintrag out first)
|
||||
(setq out "" first t)
|
||||
(foreach eintrag liste
|
||||
(setq eintrag
|
||||
(strcat (nth 0 eintrag) ":" (itoa (nth 1 eintrag)) ":"
|
||||
(rtos (nth 2 eintrag) 2 2) ":" (rtos (nth 3 eintrag) 2 2)))
|
||||
(ssg-sepliste-fmt-koord (nth 2 eintrag)) ":"
|
||||
(ssg-sepliste-fmt-koord (nth 3 eintrag))))
|
||||
(if first (progn (setq out eintrag) (setq first nil))
|
||||
(setq out (strcat out "," eintrag)))
|
||||
)
|
||||
|
||||
+1
-2
@@ -35,12 +35,11 @@
|
||||
(load (strcat base-path "VarioFoerderer.lsp") "VarioFoerderer.lsp nicht gefunden")
|
||||
(load (strcat base-path "Gefaellestrecke.lsp") "Gefaellestrecke.lsp nicht gefunden")
|
||||
(load (strcat base-path "export.lsp") "export.lsp nicht gefunden")
|
||||
(load (strcat base-path "tests.lsp") "tests.lsp nicht gefunden")
|
||||
(load (strcat base-path "OmniModulInsert.lsp") "OmniModulInsert.lsp nicht gefunden")
|
||||
(load (strcat base-path "Tro_Edit.lsp") "Tro_Edit.lsp nicht gefunden")
|
||||
(load (strcat base-path "Connection_Edit.lsp") "Connection_Edit.lsp nicht gefunden")
|
||||
(load (strcat base-path "SSG_LIB_Commands.lsp") "SSG_LIB_Commands.lsp nicht gefunden")
|
||||
(prompt "\nSSG-Bibliotheken geladen: ssg_core, ssg_lang, ssg_dbg, ssg_dialog, ssg_layer, KreiselInsert, VarioFoerderer, Gefaellestrecke, export, tests, OmniModulInsert, SSG_LIB_Commands")
|
||||
(prompt "\nSSG-Bibliotheken geladen: ssg_core, ssg_lang, ssg_dbg, ssg_dialog, ssg_layer, KreiselInsert, VarioFoerderer, Gefaellestrecke, export, OmniModulInsert, SSG_LIB_Commands")
|
||||
(princ)
|
||||
)
|
||||
|
||||
|
||||
+5
-34
@@ -138,40 +138,11 @@
|
||||
;; [ sin(hz)*cos(vert) cos(hz) sin(hz)*sin(vert) ]
|
||||
;; [ -sin(vert) 0 cos(vert) ]
|
||||
|
||||
(defun insert-hz-incl-scaled-block (blockname startpunkt laenge hz-winkel vert-winkel /
|
||||
rad-hz rad-vert chz shz cv sv scale
|
||||
matrix block-obj endpunkt)
|
||||
(setq scale (/ (float laenge) 1000.0))
|
||||
(setq rad-hz (* (float hz-winkel) (/ pi 180.0)))
|
||||
(setq rad-vert (* (float vert-winkel) (/ pi 180.0)))
|
||||
(setq chz (cos rad-hz) shz (sin rad-hz))
|
||||
(setq cv (cos rad-vert) sv (sin rad-vert))
|
||||
(setq blockname (ensure-block-loaded blockname))
|
||||
(if (not (tblsearch "BLOCK" blockname))
|
||||
(progn
|
||||
(princ (ssg-textf "vfe-block-fehlt-abbruch" (list blockname)))
|
||||
(exit)
|
||||
)
|
||||
)
|
||||
(setq block-obj (vla-InsertBlock modelspace
|
||||
(vlax-3D-point '(0 0 0)) blockname scale 1.0 1.0 0))
|
||||
;; Einzelteil auf die eigene Ebene der Blockdefinition legen - wie in den
|
||||
;; Zwillingen in ssg_ks_insert.lsp; hier fehlte der Aufruf bisher.
|
||||
(ssg-ils-block-auf-ebene block-obj blockname)
|
||||
(setq matrix (vf-rot-matrix chz shz cv sv))
|
||||
(vla-TransformBy block-obj (vlax-tmatrix matrix))
|
||||
(vla-Move block-obj (vlax-3D-point '(0 0 0)) (vlax-3D-point startpunkt))
|
||||
(setq endpunkt (list
|
||||
(+ (car startpunkt) (* laenge chz cv))
|
||||
(+ (cadr startpunkt) (* laenge shz cv))
|
||||
(+ (caddr startpunkt) (* (- sv) laenge))))
|
||||
(princ (ssg-textf "vfe-hz-incl-status"
|
||||
(list blockname (rtos laenge 2 0)
|
||||
(strcat (rtos hz-winkel 2 0) (chr 176))
|
||||
(strcat (rtos vert-winkel 2 0) (chr 176))
|
||||
(rtos (caddr endpunkt) 2 1))))
|
||||
endpunkt
|
||||
)
|
||||
;; HINWEIS: insert-hz-incl-scaled-block wurde entfernt (2026-09-18) - toter Code,
|
||||
;; kein Aufrufer im Repo. Die verbleibenden drei insert-hz-*-Funktionen bleiben,
|
||||
;; weil sie sich in der Platzierungssemantik (KS_EIN vs. Block-Ursprung) bzw. der
|
||||
;; Skalierung+KS+Vertikale-Kombination von den ssg_ks_insert-Primitiven
|
||||
;; unterscheiden und ein Ersatz die Geometrie verschoebe (byte-genaue Pruefung).
|
||||
|
||||
(defun insert-hz-rotated-block-with-ks (blockname startpunkt hz-winkel vert-winkel block-dx block-dz /
|
||||
rad-hz rad-vert chz shz cv sv
|
||||
|
||||
@@ -193,6 +193,17 @@
|
||||
;; etage-foerderanlage-einfuegen (vf_etage.lsp).
|
||||
(if (null *vfk-etage-auslauf-min-clamp*) (setq *vfk-etage-auslauf-min-clamp* 50.0))
|
||||
|
||||
;; Mindest-2D-Laenge (mm) eines Pfad-Segments (LINE-Laenge bzw. ARC-Sehne),
|
||||
;; das der Linienzug-Modus 2/3 aus einer Objektauswahl akzeptiert. Kuerzere
|
||||
;; Objekte sind Geister-/Artefakt-Elemente (z.B. ein von einer Rechteck-Auswahl
|
||||
;; miterfasstes Mini-Segment) und werden VOR der Sortierung ausgeworfen, mit
|
||||
;; Warnung an den Nutzer (vfl-in-segmente). Konservativ deutlich unter jedem
|
||||
;; realen Bauteil (kleinstes Bauteil = Separator 300 mm; kleinster echter
|
||||
;; Eck-Bogen R500/30 Grad hat eine Sehne von ~259 mm) und knapp ueber dem
|
||||
;; allgemeinen Restlaengen-Clamp (100 mm), damit kein legitimes Segment
|
||||
;; faelschlich verworfen wird.
|
||||
(if (null *vfk-pfad-min-segmentlaenge*) (setq *vfk-pfad-min-segmentlaenge* 100.0))
|
||||
|
||||
;; ============================================================
|
||||
;; TEIL 4: FALLBACK-VERSATZWERTE (mm) - AS-/ES-/Gefaellebogen-Masse, falls
|
||||
;; die Blockdefinition/das Koordinatensystem nicht extrahierbar ist
|
||||
|
||||
+435
-165
@@ -2013,6 +2013,59 @@
|
||||
(setq s (substr s (+ pos 1 (strlen sep)))))
|
||||
(reverse (cons s out)))
|
||||
|
||||
;; --- SEGS: Segment-Essenz einer Modus-3-Kette (selbst-enthalten) ---
|
||||
;; Ein SEGS-Wert ist die AUS DEN PFAD-OBJEKTEN ABGELEITETE Zahlenliste, die der
|
||||
;; Modus-3-Bau ohnehin allein verwendet (gf-analysiere-kette + Start/Endpunkte
|
||||
;; aus gf-sortiere-objekte). Sie ersetzt im Journal die frueheren OBJS-Handles:
|
||||
;; dadurch ist die Kette im XDATA vollstaendig beschrieben und beim Doppelklick-
|
||||
;; Replay unabhaengig davon, ob die urspruenglichen LINE/ARC noch existieren
|
||||
;; (robuster als der OBJS-Weg von Modus 2). Siehe doc/variofoerderer.md.
|
||||
;;
|
||||
;; Ein Segment ist eine 9er-Liste, die die "Bau-Essenz" und die fuer die
|
||||
;; AS-Trimmung/das Soll-Ende noetigen absoluten Punkte zusammenfuehrt:
|
||||
;; (typ hz laenge bwinkel bseite spx spy epx epy)
|
||||
;; typ "Linie"/"Bogen" (delimiter-frei, daher unquotiert serialisiert)
|
||||
;; hz Eintritts-Horizontalwinkel (Grad)
|
||||
;; laenge 2D-Laenge / Sehnenmass (mm)
|
||||
;; bwinkel Bogenwinkel (0 bei Linie)
|
||||
;; bseite "links"/"rechts"
|
||||
;; spx spy Startpunkt (XY, mm) des Segments \ aus gf-sortiere-objekte,
|
||||
;; epx epy Endpunkt (XY, mm) des Segments / fuer Trimmung + Soll-Ende
|
||||
;;
|
||||
;; Serialisierung: Segmente per ";" getrennt, Felder je Segment per "|". Beide
|
||||
;; Trenner sind kollisionsfrei - die einzigen String-Felder (typ/bseite) sind
|
||||
;; feste Schluesselwoerter ohne ";" oder "|", alle uebrigen Felder sind Zahlen
|
||||
;; (rtos-Mode-2, wie PT/REAL). Ein leeres SEGS ("") ist eine leere Liste.
|
||||
(defun vfl-seg->string (seg)
|
||||
(vfl-strjoin
|
||||
(list (nth 0 seg) ; typ (String)
|
||||
(rtos (float (nth 1 seg)) 2 6) ; hz
|
||||
(rtos (float (nth 2 seg)) 2 6) ; laenge
|
||||
(rtos (float (nth 3 seg)) 2 6) ; bwinkel
|
||||
(nth 4 seg) ; bseite (String)
|
||||
(rtos (float (nth 5 seg)) 2 6) ; spx
|
||||
(rtos (float (nth 6 seg)) 2 6) ; spy
|
||||
(rtos (float (nth 7 seg)) 2 6) ; epx
|
||||
(rtos (float (nth 8 seg)) 2 6)) ; epy
|
||||
"|"))
|
||||
(defun vfl-string->seg (s / f)
|
||||
(setq f (vfl-strsplit s "|"))
|
||||
(list (nth 0 f) ; typ
|
||||
(atof (nth 1 f)) ; hz
|
||||
(atof (nth 2 f)) ; laenge
|
||||
(fix (atof (nth 3 f))) ; bwinkel (Ganzzahl, wie gf-analysiere-kette)
|
||||
(nth 4 f) ; bseite
|
||||
(atof (nth 5 f)) ; spx
|
||||
(atof (nth 6 f)) ; spy
|
||||
(atof (nth 7 f)) ; epx
|
||||
(atof (nth 8 f)))) ; epy
|
||||
(defun vfl-segs->string (segs)
|
||||
(vfl-strjoin (mapcar 'vfl-seg->string segs) ";"))
|
||||
(defun vfl-string->segs (s)
|
||||
(if (= (strlen s) 0)
|
||||
'()
|
||||
(mapcar 'vfl-string->seg (vfl-strsplit s ";"))))
|
||||
|
||||
;; --- Serialisierung (tagged, selbstbeschreibend) ---
|
||||
;; Zeilenformat "kind:payload", Eintraege per "\n" verkettet. getstring/getreal
|
||||
;; liefern nie ein Newline, daher ist "\n" ein sicherer Record-Trenner.
|
||||
@@ -2020,6 +2073,8 @@
|
||||
;; Entity-Handles (Hex-Strings, kollidieren nie mit dem Komma-Trenner).
|
||||
;; Handles bleiben - anders als Enames - ueber Sitzungen/Undo hinweg stabil
|
||||
;; und sind damit die richtige Persistenzform fuer ssget-Ergebnisse.
|
||||
;; "SEGS" (Segment-Essenz, Modus 3): Payload = ";"-getrennte Segmente, Felder
|
||||
;; per "|" (siehe vfl-segs->string oben).
|
||||
(defun vfl-entry->string (e / k v)
|
||||
(setq k (car e) v (cdr e))
|
||||
(cond
|
||||
@@ -2031,6 +2086,7 @@
|
||||
((= k "STR") (strcat "STR:" v))
|
||||
((= k "STEP") (strcat "STEP:" v))
|
||||
((= k "OBJS") (strcat "OBJS:" (vfl-strjoin v ",")))
|
||||
((= k "SEGS") (strcat "SEGS:" (vfl-segs->string v)))
|
||||
(t "NIL:")))
|
||||
(defun vfl-string->entry (ln / p kind pay c)
|
||||
(setq p (vl-string-search ":" ln))
|
||||
@@ -2048,6 +2104,7 @@
|
||||
((= kind "STR") (cons "STR" pay))
|
||||
((= kind "STEP") (cons "STEP" pay))
|
||||
((= kind "OBJS") (cons "OBJS" (if (> (strlen pay) 0) (vfl-strsplit pay ",") nil)))
|
||||
((= kind "SEGS") (cons "SEGS" (vfl-string->segs pay)))
|
||||
(t (cons "NIL" nil))))))
|
||||
;; forward-journal ist bereits in Bau-Reihenfolge (nicht die umgekehrte
|
||||
;; *vfl-journal*-Rohform) - gemeinsame Serialisierung fuer Ketten- UND
|
||||
@@ -2086,6 +2143,21 @@
|
||||
((= k "OBJS") (strcat "[" (vfl-strjoin
|
||||
(mapcar (function (lambda (h) (strcat "\"" (vfl-json-escape h) "\"")))
|
||||
v) ",") "]"))
|
||||
((= k "SEGS") (strcat "["
|
||||
(vfl-strjoin
|
||||
(mapcar
|
||||
(function (lambda (seg)
|
||||
(strcat "[\"" (vfl-json-escape (nth 0 seg)) "\","
|
||||
(vfl-json-num (float (nth 1 seg))) ","
|
||||
(vfl-json-num (float (nth 2 seg))) ","
|
||||
(vfl-json-num (float (nth 3 seg))) ",\""
|
||||
(vfl-json-escape (nth 4 seg)) "\","
|
||||
(vfl-json-num (float (nth 5 seg))) ","
|
||||
(vfl-json-num (float (nth 6 seg))) ","
|
||||
(vfl-json-num (float (nth 7 seg))) ","
|
||||
(vfl-json-num (float (nth 8 seg))) "]")))
|
||||
v) ",")
|
||||
"]"))
|
||||
(t "null"))
|
||||
"}"))
|
||||
;; forward-journal (Bau-Reihenfolge) als kompakter JSON-Array-String.
|
||||
@@ -2133,7 +2205,7 @@
|
||||
;; Rueckgabe: (marker . journal) oder nil (kein/unbekanntes Journal).
|
||||
(defun vfl-journal-xdata-lesen (ent / xd)
|
||||
(setq xd (vfs-xdata-lesen ent))
|
||||
(if (and xd (member (car xd) '("linienzug" "linienzug2")))
|
||||
(if (and xd (member (car xd) '("linienzug" "linienzug2" "linienzug3")))
|
||||
(cons (car xd) (vfl-string->journal (apply 'strcat (cdr xd))))
|
||||
nil))
|
||||
|
||||
@@ -2306,6 +2378,47 @@
|
||||
;; sich um einen frischen Bau oder einen Editier-Neuaufbau handelte (kein
|
||||
;; Sonderfall mehr noetig). Aufgerufen aus dem *error*-Handler von
|
||||
;; vf-linienzug-modus.
|
||||
;; Den scharfen Abbruch-Wickel-Handler als *error* installieren - gemeinsam
|
||||
;; fuer alle drei Linienzug-Modi (frueher 3x wortgleich ausgeschrieben, nur der
|
||||
;; Marker-String "linienzug"/"linienzug2"/"linienzug3" unterschied sich).
|
||||
;;
|
||||
;; Der Handler faengt jeden Abbruch (ESC / (exit) / Laufzeitfehler) ab, wickelt
|
||||
;; die bis dahin gebaute Teil-Geometrie per vfl-modus-abbruch-sichern zu einem
|
||||
;; VF_n-Block mit dem vollen Journal (Marker als XDATA) und stellt *error*
|
||||
;; wieder her. Details/Begruendung (dynamic scoping, *ssg-ils-dim*-Reset,
|
||||
;; ssg-end) siehe die ausfuehrlichen Kommentare an der frueheren Aufrufstelle
|
||||
;; in vf-linienzug-modus.
|
||||
;;
|
||||
;; VERTRAG (dynamic scoping): Der Aufrufer MUSS als Locals gebunden haben und
|
||||
;; VOR diesem Aufruf gesetzt haben: old-error (Ruecksprung-*error*), lastEnt,
|
||||
;; vfl-nummer, anzahl-gf, anzahl-vf, startpunkt, frame, as-seite, es-seite,
|
||||
;; dbg-an. Sie werden vom Handler-Lambda zur ABBRUCHZEIT dynamisch aufgeloest -
|
||||
;; also gegen den dann noch aktiven Modus-Frame, nicht gegen diesen Konstruktor
|
||||
;; (der ist beim Abbruch laengst zurueckgekehrt). marker wird dagegen ZUR
|
||||
;; INSTALL-ZEIT als String-Literal in den Lambda eingebacken (list-Konstruktion),
|
||||
;; damit der Handler ihn ohne globalen Zwischenzustand selbst traegt.
|
||||
(defun vfl-abbruch-handler-installieren (marker)
|
||||
;; *error* auf eine LAMBDA-LISTE setzen, in die der marker als String-Literal
|
||||
;; eingebaut ist (list-Konstruktion). AutoLISP ruft *error* als Funktion auf,
|
||||
;; egal ob (lambda ...) oder (function (lambda ...)) - die reine Lambda-Liste
|
||||
;; genuegt und vermeidet eval/function-Feinheiten. Alle uebrigen Symbole
|
||||
;; (old-error, lastEnt, ...) bleiben ungequotet-frei und werden zur Aufrufzeit
|
||||
;; dynamisch aufgeloest.
|
||||
(setq *error*
|
||||
(list 'lambda '(msg)
|
||||
'(setq *error* old-error)
|
||||
'(setq *ssg-ils-dim* nil)
|
||||
(list 'vfl-modus-abbruch-sichern 'lastEnt 'vfl-nummer 'anzahl-gf 'anzahl-vf
|
||||
'startpunkt 'frame 'as-seite 'es-seite marker)
|
||||
'(if dbg-an
|
||||
(progn
|
||||
(dbgmsg (strcat "=== ABBRUCH: " (if msg msg "(exit)") " ==="))
|
||||
(dbgreturn nil)
|
||||
(dbgclose)))
|
||||
'(if (and (boundp '*ssg-start-stack*) *ssg-start-stack*) (ssg-end))
|
||||
'(princ)))
|
||||
*error*)
|
||||
|
||||
(defun vfl-modus-abbruch-sichern (lastEnt vfl-nummer anzahl-gf anzahl-vf
|
||||
startpunkt frame as-seite es-seite marker /
|
||||
e cnt vfl-ins wickel-erg grund fwd n trunc)
|
||||
@@ -5943,6 +6056,60 @@
|
||||
(vf-set-es-masse winkel seite)
|
||||
seite)
|
||||
|
||||
;; AS-Winkel (30/90) + Seite abfragen. Gemeinsame Schale fuer die frueher
|
||||
;; wortgleich in vf-linienzug-modus/-modus2/-modus3 UND vfl-qc-linie-mit-gf
|
||||
;; ausgeschriebene AS-Praeambel (Winkel-Frage 30/90, Seiten-Frage links/rechts,
|
||||
;; vf-set-as-masse) - Gegenstueck zu vfl-frage-es-seite. Setzt *vfl-as-winkel*
|
||||
;; und die AS-Masse (aus-dx/dz) fuer die Variante. Rueckgabe: Seite (links/rechts).
|
||||
;;
|
||||
;; seiten-headerkey ist der EINZIGE Unterschied zwischen den Aufrufstellen
|
||||
;; (modus1: "vfl-aus-seite-header", modus2: "gf-seite-aus-header") und daher
|
||||
;; Parameter. Die je Modus unterschiedliche VORANGEHENDE Wizard-Vorbereitung
|
||||
;; (vflw-gruppe-as-impl "AS setzen?" bzw. vflw-gruppe-winkel-seite-impl) bleibt
|
||||
;; bewusst an der Aufrufstelle - die abzudeckende Winkel/Seite-Frage selbst ist
|
||||
;; ueberall identisch. vf-frage-element-winkel/vflw-wahl zeigen den Wizard-
|
||||
;; Winkeldialog bei aktivem Wizard-Modus schon selbst.
|
||||
(defun vfl-frage-as-winkel-seite (seiten-headerkey / antwort as-seite)
|
||||
(princ (ssg-text "vf-winkel-aus-header"))
|
||||
(princ (ssg-text "vf-winkel-90"))
|
||||
(princ (ssg-text "vf-winkel-30"))
|
||||
(setq *vfl-as-winkel*
|
||||
(vfl-in-value "STR"
|
||||
(function (lambda () (vf-frage-element-winkel "vf-winkel-aus-header"))))) ; 30/90 vor Seite
|
||||
(princ (ssg-text seiten-headerkey))
|
||||
(princ (ssg-text "gf-seite-links"))
|
||||
(princ (ssg-text "gf-seite-rechts"))
|
||||
(setq antwort (vfl-menu (ssg-text "prompt-wahl-1-2")
|
||||
(list (ssg-text "gf-seite-links") (ssg-text "gf-seite-rechts")) 1
|
||||
seiten-headerkey))
|
||||
(setq as-seite (if (= antwort "2") "rechts" "links"))
|
||||
(vf-set-as-masse *vfl-as-winkel* as-seite) ; Masse fuer Variante
|
||||
as-seite)
|
||||
|
||||
;; ES-Winkel (30/90) + Seite abfragen - MARKER-FREIE Schale fuer die Modi 2/3,
|
||||
;; die das ES-Element als eigene Praeambel (Start/Ziel bereits fest) abfragen
|
||||
;; und ihr eigenes Journal-/Masse-Schema fuehren. Unterscheidet sich bewusst
|
||||
;; von vfl-frage-es-seite (Modus 1), das zusaetzlich einen Journal-Marker "ES"
|
||||
;; setzt und ueber vfl-es-masse-setzen laeuft - das ist Teil des Modus-1-
|
||||
;; Kettenglied-Replays und darf hier NICHT feuern. Setzt *vfl-es-winkel* und
|
||||
;; die ES-Masse (ein-dx/dz). Rueckgabe: Seite (links/rechts).
|
||||
(defun vfl-frage-es-winkel-seite (seiten-headerkey / antwort es-seite)
|
||||
(princ (ssg-text "vf-winkel-ein-header"))
|
||||
(princ (ssg-text "vf-winkel-90"))
|
||||
(princ (ssg-text "vf-winkel-30"))
|
||||
(setq *vfl-es-winkel*
|
||||
(vfl-in-value "STR"
|
||||
(function (lambda () (vf-frage-element-winkel "vf-winkel-ein-header"))))) ; 30/90 vor Seite
|
||||
(princ (ssg-text seiten-headerkey))
|
||||
(princ (ssg-text "gf-seite-links"))
|
||||
(princ (ssg-text "gf-seite-rechts"))
|
||||
(setq antwort (vfl-menu (ssg-text "prompt-wahl-1-2")
|
||||
(list (ssg-text "gf-seite-links") (ssg-text "gf-seite-rechts")) 1
|
||||
seiten-headerkey))
|
||||
(setq es-seite (if (= antwort "2") "rechts" "links"))
|
||||
(vf-set-es-masse *vfl-es-winkel* es-seite) ; Masse fuer Variante
|
||||
es-seite)
|
||||
|
||||
;; dialog-schon-gezeigt: T, wenn Winkel+Seite BEREITS ueber einen vorherigen
|
||||
;; kombinierten Dialog (vflw-gruppe-as-impl, "ES-Element setzen?" + Winkel +
|
||||
;; Seite in einem Bildschirm) abgefragt und in die Pending-Queue gelegt
|
||||
@@ -6317,32 +6484,11 @@
|
||||
(setq lastEnt (vf-lastent-ohne-attribute))
|
||||
(setq anzahl-gf 0 anzahl-vf 0 frame nil)
|
||||
(setq old-error *error*)
|
||||
;; Abbruch-Handler: zuerst *error* zuruecksetzen (kein rekursiver
|
||||
;; Wiedereintritt bei einem Fehler waehrend des Wickelns), dann wickeln.
|
||||
;; Laeuft der Aufruf innerhalb einer ssg-start-Sitzung (Editier-Pfad via
|
||||
;; c:VARIOFOERDERER_EDIT -> vfl-edit-ent), wird diese mit ssg-end sauber
|
||||
;; geschlossen (Undo-Gruppe, gesicherte Systemvariablen, *error* aus dem
|
||||
;; Sitzungs-Frame) - sonst bliebe die von ssg-start geoeffnete Undo-Gruppe
|
||||
;; offen.
|
||||
;; *ssg-ils-dim*: der Editier-/Konverter-Pfad setzt vor dem Replay einen
|
||||
;; Dimensions-Override und raeumt ihn NACH der Rueckkehr wieder ab. Bei einem
|
||||
;; Abbruch kehrt der Aufruf nie dorthin zurueck (der Handler beendet den
|
||||
;; Befehl), daher MUSS der Override hier zurueckgesetzt werden - sonst bliebe
|
||||
;; er fuer den Rest der Sitzung stehen und alle folgenden Einfuegungen liefen
|
||||
;; in der falschen Dimension.
|
||||
(setq *error*
|
||||
(function (lambda (msg)
|
||||
(setq *error* old-error)
|
||||
(setq *ssg-ils-dim* nil)
|
||||
(vfl-modus-abbruch-sichern lastEnt vfl-nummer anzahl-gf anzahl-vf
|
||||
startpunkt frame as-seite es-seite "linienzug")
|
||||
(if dbg-an
|
||||
(progn
|
||||
(dbgmsg (strcat "=== ABBRUCH: " (if msg msg "(exit)") " ==="))
|
||||
(dbgreturn nil)
|
||||
(dbgclose)))
|
||||
(if (and (boundp '*ssg-start-stack*) *ssg-start-stack*) (ssg-end))
|
||||
(princ))))
|
||||
;; Scharfen Abbruch-Wickel-Handler installieren (gemeinsam fuer alle drei
|
||||
;; Modi, siehe vfl-abbruch-handler-installieren). old-error/lastEnt/vfl-nummer/
|
||||
;; anzahl-gf/anzahl-vf/startpunkt/frame/as-seite/es-seite/dbg-an sind hier als
|
||||
;; Locals gebunden und werden vom Handler zur Abbruchzeit dynamisch gesehen.
|
||||
(vfl-abbruch-handler-installieren "linienzug")
|
||||
|
||||
(if (vfl-wizard-aktiv)
|
||||
(vl-catch-all-apply 'vflw-gruppe-punkt-hoehe-impl
|
||||
@@ -6390,22 +6536,7 @@
|
||||
;; tragen, wenn diesmal kein AS gewaehlt wird.
|
||||
(setq *vfl-as-winkel* nil *vfl-es-winkel* nil)
|
||||
(if as-vorhanden
|
||||
(progn
|
||||
(princ (ssg-text "vf-winkel-aus-header"))
|
||||
(princ (ssg-text "vf-winkel-90"))
|
||||
(princ (ssg-text "vf-winkel-30"))
|
||||
(setq *vfl-as-winkel*
|
||||
(vfl-in-value "STR"
|
||||
(function (lambda () (vf-frage-element-winkel "vf-winkel-aus-header"))))) ; 30/90 vor Seite
|
||||
(princ (ssg-text "vfl-aus-seite-header"))
|
||||
(princ (ssg-text "gf-seite-links"))
|
||||
(princ (ssg-text "gf-seite-rechts"))
|
||||
(setq antwort (vfl-menu (ssg-text "prompt-wahl-1-2")
|
||||
(list (ssg-text "gf-seite-links") (ssg-text "gf-seite-rechts")) 1
|
||||
"vfl-aus-seite-header"))
|
||||
(setq as-seite (if (= antwort "2") "rechts" "links"))
|
||||
(vf-set-as-masse *vfl-as-winkel* as-seite) ; Masse fuer Variante
|
||||
)
|
||||
(setq as-seite (vfl-frage-as-winkel-seite "vfl-aus-seite-header"))
|
||||
)
|
||||
;; ES-Seite wird erst am Kettenende abgefragt (siehe vfl-frage-es-seite),
|
||||
;; da das ES-Element erst dort eingefuegt wird.
|
||||
@@ -8183,22 +8314,29 @@
|
||||
;; und der Override sicher zurueckgesetzt wird. Rueckgabe: T bei Erfolg, sonst nil.
|
||||
;; Bekannte Grenze (nur Modus 2): das Replay von vfl-in-selection braucht die
|
||||
;; Original-Pfadobjekte; wurden sie geloescht, schlaegt der Konverter fuer diesen
|
||||
;; Block sauber fehl (sichtbar am nicht erhoehten Batch-Zaehler).
|
||||
;; Block sauber fehl (sichtbar am nicht erhoehten Batch-Zaehler). Modus 3
|
||||
;; ("linienzug3") hat diese Grenze NICHT: es replayt die Segment-Essenz (SEGS)
|
||||
;; aus dem Journal, nicht die Objekt-Handles - unabhaengig von den Original-LINE/ARC.
|
||||
(defun vfl-konvertiere-ent (ent ziel-dim / bname xd marker journal ok)
|
||||
(setq bname (cdr (assoc 2 (entget ent))))
|
||||
(setq xd (vfl-journal-xdata-lesen ent)) ; (marker . journal) oder nil
|
||||
(setq marker (car xd) journal (cdr xd))
|
||||
(if (and (wcmatch bname "VF_*")
|
||||
(member marker '("linienzug" "linienzug2"))
|
||||
journal)
|
||||
(member marker '("linienzug" "linienzug2" "linienzug3"))
|
||||
journal
|
||||
;; Alte OBJS-"linienzug2"-Bloecke (ohne SEGS) NICHT konvertieren -
|
||||
;; ihr Replay ist mit dem SEGS-Umbau nicht mehr fahrbar (harter
|
||||
;; Schnitt, wie im Doppelklick-Pfad vfl-edit-ent). Sie ueberspringen
|
||||
;; (nil zurueck), damit die Batch-Schleife sauber weiterlaeuft.
|
||||
(or (/= marker "linienzug2") (vfl-journal-hat-segs-p journal)))
|
||||
(progn
|
||||
(setq *ssg-ils-dim* ziel-dim) ; Zieldim erzwingen
|
||||
(entdel ent) ; alten Block weg
|
||||
(vfl-journal-replay-start journal) ; volle Queue, KEIN Truncate
|
||||
(setq ok (vl-catch-all-apply
|
||||
(if (= marker "linienzug2")
|
||||
'vf-linienzug-modus2
|
||||
'vf-linienzug-modus)))
|
||||
(cond ((= marker "linienzug2") 'vf-linienzug-modus2)
|
||||
((= marker "linienzug3") 'vf-linienzug-modus3)
|
||||
(t 'vf-linienzug-modus))))
|
||||
(setq *ssg-ils-dim* nil) ; Override zuruecksetzen
|
||||
;; Fehlgeschlagene Konvertierung NICHT stumm verschlucken: der alte Block
|
||||
;; ist per entdel schon weg, die Teil-Geometrie liegt frei in der
|
||||
@@ -8224,8 +8362,17 @@
|
||||
;; Doppelklick kein *ssg-ils-dim*-Override aktiv ist). Wird VOR dem entdel
|
||||
;; gelesen; der Override greift beim anschliessenden Replay/Weiterbau.
|
||||
(setq dim (ssg-dim-xdata-lesen ent))
|
||||
(if (= marker "linienzug2")
|
||||
(vfl-edit-ent2 ent journal)
|
||||
(cond
|
||||
((= marker "linienzug2")
|
||||
;; Harter Schnitt: nur SEGS-Bloecke (neue Fassung) sind per Doppelklick
|
||||
;; neu aufbaubar. Alte OBJS-Bloecke (Objekt-Handles statt Segment-Essenz)
|
||||
;; wuerden im Replay falsche Daten in den Bau geben - klar abweisen statt
|
||||
;; zu crashen.
|
||||
(if (vfl-journal-hat-segs-p journal)
|
||||
(vfl-edit-ent2 ent journal)
|
||||
(alert (ssg-text "vfl-edit-m2-obsolet"))))
|
||||
((= marker "linienzug3") (vfl-edit-ent3 ent journal))
|
||||
(t
|
||||
(progn
|
||||
(setq glieder (vfl-journal-glieder journal))
|
||||
(setq n (length glieder))
|
||||
@@ -8281,15 +8428,27 @@
|
||||
;; Handler selbst (dort ebenfalls (setq *ssg-ils-dim* nil)), denn
|
||||
;; die naechste Zeile wird dann nicht mehr erreicht.
|
||||
(vf-linienzug-modus)
|
||||
(setq *ssg-ils-dim* nil)))))
|
||||
(setq *ssg-ils-dim* nil))))))
|
||||
(princ))
|
||||
|
||||
;; Modus-2-Block per Doppelklick zuruecksetzen: voller Reset - die komplette
|
||||
;; gespeicherte Eingabe (inkl. der gewaehlten Pfad-Objekte, siehe
|
||||
;; vfl-in-selection) wird 1:1 stumm abgespielt, identischer Neuaufbau. Kein
|
||||
;; T, wenn das Journal einen SEGS-Eintrag traegt (Modus 2 NEU / Modus 3 - die
|
||||
;; Kette ist per Segment-Essenz selbst-enthalten). Alte Modus-2-Bloecke tragen
|
||||
;; hier stattdessen einen OBJS-Eintrag (Objekt-Handles) - fuer die ist der
|
||||
;; SEGS-Replay nicht mehr fahrbar (harter Schnitt, siehe vfl-edit-ent).
|
||||
(defun vfl-journal-hat-segs-p (journal)
|
||||
(and (vl-some (function (lambda (e) (equal (car e) "SEGS"))) journal) t))
|
||||
|
||||
;; Modus-2/3-Block per Doppelklick zuruecksetzen: voller Reset - die komplette
|
||||
;; gespeicherte Eingabe wird 1:1 stumm abgespielt, identischer Neuaufbau. Kein
|
||||
;; Sektions-Dialog; der Nutzer kann den neu entstandenen Block danach ganz
|
||||
;; normal weiterbearbeiten oder loeschen.
|
||||
(defun vfl-edit-ent2 (ent journal / dim)
|
||||
;;
|
||||
;; bau-fn = die Modus-Bau-Funktion, die das Journal abspielt: 'vf-linienzug-modus2
|
||||
;; fuer Marker "linienzug2" (Pfad-Objekte per OBJS-Handles) bzw.
|
||||
;; 'vf-linienzug-modus3 fuer "linienzug3" (Segment-Essenz per SEGS - unabhaengig
|
||||
;; von den Original-Objekten). Beide Modi haben eine flache Klassifizierungs-
|
||||
;; Schleife ohne editierbare Einzelglieder, daher derselbe volle Reset.
|
||||
(defun vfl-edit-ent-voll (ent journal bau-fn / dim)
|
||||
;; Dimension des Bestandsblocks VOR dem entdel merken und beim Neubau als
|
||||
;; Override erzwingen (dimensionstreuer Doppelklick-Neubau, sonst globale
|
||||
;; DXFM_DIM). Danach Override zuruecksetzen.
|
||||
@@ -8300,12 +8459,17 @@
|
||||
(vfl-journal-replay-start journal)
|
||||
;; DIREKTER Aufruf, KEIN vl-catch-all-apply - identische Begruendung wie im
|
||||
;; Sektions-Zweig von vfl-edit-ent (siehe dortiger Kommentar): der alte Block
|
||||
;; ist per entdel schon weg, bei einem Abbruch muss der *error*-Handler von
|
||||
;; vf-linienzug-modus2 die Teil-Geometrie wickeln. Den Dim-Override raeumt im
|
||||
;; Abbruchfall der Handler ab.
|
||||
(vf-linienzug-modus2)
|
||||
;; ist per entdel schon weg, bei einem Abbruch muss der *error*-Handler der
|
||||
;; Modus-Funktion die Teil-Geometrie wickeln. Den Dim-Override raeumt im
|
||||
;; Abbruchfall der Handler ab. bau-fn ist ein Funktions-SYMBOL (quoted beim
|
||||
;; Aufruf) - ueber apply aufrufen, nicht als (bau-fn) (das riefe die Funktion
|
||||
;; namens "bau-fn" auf, nicht den durchgereichten Wert).
|
||||
(apply bau-fn nil)
|
||||
(setq *ssg-ils-dim* nil)
|
||||
(princ))
|
||||
;; Rueckwaertskompatibler Wrapper (Modus 2). vfl-edit-ent3 fuer Modus 3.
|
||||
(defun vfl-edit-ent2 (ent journal) (vfl-edit-ent-voll ent journal 'vf-linienzug-modus2))
|
||||
(defun vfl-edit-ent3 (ent journal) (vfl-edit-ent-voll ent journal 'vf-linienzug-modus3))
|
||||
|
||||
;; ============================================================
|
||||
;; RECOVERY: Kette aus der Sektions-XDATA der Zeichnung neu aufbauen
|
||||
@@ -8701,14 +8865,115 @@
|
||||
(foreach x liste (setq d (abs (- x w))) (if (< d bd) (setq bd d best x)))
|
||||
best)
|
||||
|
||||
;; --- Segment-Essenz einer selektierten Pfad-Kette (Modus 3) --------------
|
||||
;; Fuehrt die 5-Feld-Bau-Segmente aus gf-analysiere-kette mit den absoluten
|
||||
;; Start-/Endpunkten aus gf-sortiere-objekte (kette: (ent sp ep umk)) zu der
|
||||
;; selbstbeschreibenden 9-Feld-Form zusammen, die das SEGS-Journal traegt:
|
||||
;; (typ hz laenge bwinkel bseite spx spy epx epy)
|
||||
;; Beide Listen sind gleich lang und in derselben Reihenfolge (segmente wurde
|
||||
;; genau aus kette abgeleitet). spx/spy/epx/epy sind die planaren XY der
|
||||
;; Segment-Enden - sie ersetzen den spaeteren direkten kette-Zugriff (AS-
|
||||
;; Trimmung am ersten Segment, Soll-Ende-Report), sodass der Bau OHNE die
|
||||
;; Original-Entities auskommt und beim Replay aus dem Journal gespeist wird.
|
||||
(defun vfl-kette->segmente9 (kette segmente / out i seg item sp ep)
|
||||
(setq out '() i 0)
|
||||
(foreach seg segmente
|
||||
(setq item (nth i kette) sp (cadr item) ep (caddr item))
|
||||
(setq out (cons (list (nth 0 seg) (nth 1 seg) (nth 2 seg) (nth 3 seg) (nth 4 seg)
|
||||
(car sp) (cadr sp) (car ep) (cadr ep))
|
||||
out))
|
||||
(setq i (1+ i)))
|
||||
(reverse out))
|
||||
|
||||
;; 2D-Laenge eines Pfad-Objekts: LINE = Abstand Start-Endpunkt, ARC = Sehne
|
||||
;; (Abstand Start-Endpunkt, dasselbe Mass wie gf-analysiere-kette es fuer die
|
||||
;; Segmentlaenge nutzt). Nicht-LINE/ARC liefern 0.0 (werden dadurch als "zu
|
||||
;; kurz" ausgewertet und verworfen). Rein lesend, ohne Nebeneffekt.
|
||||
(defun vfl-obj-2d-laenge (obj / objname sp ep)
|
||||
(setq objname (vla-get-ObjectName obj))
|
||||
(if (or (= objname "AcDbLine") (= objname "AcDbArc"))
|
||||
(progn
|
||||
(setq sp (vlax-safearray->list (vlax-variant-value (vla-get-StartPoint obj))))
|
||||
(setq ep (vlax-safearray->list (vlax-variant-value (vla-get-EndPoint obj))))
|
||||
(gf-abstand-2d sp ep))
|
||||
0.0))
|
||||
|
||||
;; Aus einer Objektliste alle Elemente unter *vfk-pfad-min-segmentlaenge*
|
||||
;; herauswerfen (Geister-/Artefakt-Segmente, z.B. von einer Rechteck-Auswahl
|
||||
;; miterfasste Mini-Objekte). Rueckgabe: (behalten-liste . verworfen-anzahl).
|
||||
;; Reine Filterung, keine Meldung - der Aufrufer entscheidet ueber die Warnung.
|
||||
(defun vfl-filter-mini-objekte (obj-liste / behalten verworfen)
|
||||
(setq behalten '() verworfen 0)
|
||||
(foreach obj obj-liste
|
||||
(if (< (vfl-obj-2d-laenge obj) *vfk-pfad-min-segmentlaenge*)
|
||||
(setq verworfen (1+ verworfen))
|
||||
(setq behalten (cons obj behalten))))
|
||||
(cons (reverse behalten) verworfen))
|
||||
|
||||
;; Objektauswahl + Analyse (Live) ODER Segment-Essenz aus dem Journal (Replay).
|
||||
;; Gegenstueck zu vfl-in-selection, aber persistiert NICHT die Entity-Handles,
|
||||
;; sondern die abgeleitete 9-Feld-Segmentliste (Journal-Art "SEGS"). Damit ist
|
||||
;; der Modus-3-Block im XDATA vollstaendig beschrieben und der Doppelklick-Neubau
|
||||
;; unabhaengig davon, ob die urspruenglichen LINE/ARC noch existieren.
|
||||
;; Rueckgabe: die 9-Feld-Segmentliste oder nil (Abbruch/leer). filter/startpunkt
|
||||
;; wie bei der Live-Auswahl; ecke-tol wird nur im Live-Zweig fuer die
|
||||
;; Eck-Vorpruefung gebraucht (Replay-Daten sind bereits geprueft eingefroren).
|
||||
(defun vfl-in-segmente (filter startpunkt ecke-tol / popped ss k obj-liste kette segmente ecke-bad segs9 filter-erg verworfen)
|
||||
(setq popped (if *vfl-replay-queue* (vfl-replay-pop) nil))
|
||||
(if popped
|
||||
;; --- Replay: fertige Segment-Essenz direkt aus dem Journal ---
|
||||
(progn
|
||||
(setq segs9 (car popped))
|
||||
(if (null segs9)
|
||||
(if (vfl-headless-p) (vfl-headless-abbruch "SEGS-leer")))
|
||||
segs9)
|
||||
;; --- Live: Objekte waehlen, sortieren, analysieren, dann journalisieren ---
|
||||
(progn
|
||||
(if (vfl-headless-p) (vfl-headless-abbruch "SEGS"))
|
||||
(setq ss (ssget filter))
|
||||
(if (null ss)
|
||||
(progn (vfl-journal-record "NIL" nil) nil)
|
||||
(progn
|
||||
;; Auswahlsatz -> VLA-Objektliste (wie im frueheren vfl-in-selection).
|
||||
(setq obj-liste '() k 0)
|
||||
(while (< k (sslength ss))
|
||||
(setq obj-liste (cons (vlax-ename->vla-object (ssname ss k)) obj-liste))
|
||||
(setq k (1+ k)))
|
||||
(setq obj-liste (reverse obj-liste))
|
||||
;; Geister-/Mini-Objekte VOR der Sortierung ausfiltern: ein von einer
|
||||
;; Rechteck-Auswahl miterfasstes winziges Segment (unter
|
||||
;; *vfk-pfad-min-segmentlaenge*) wuerde sonst per Nearest-Neighbor
|
||||
;; stumm in die Kette gehaengt und ein Geister-Bauteil erzeugen (realer
|
||||
;; Bug: 14-mm-Bogen am Kettenende). Verworfene mit Grund melden.
|
||||
(setq filter-erg (vfl-filter-mini-objekte obj-liste))
|
||||
(setq obj-liste (car filter-erg) verworfen (cdr filter-erg))
|
||||
(if (> verworfen 0)
|
||||
(vfl-meldung (ssg-textf "vfl-m3-mini-objekte-verworfen"
|
||||
(list (itoa verworfen) (rtos *vfk-pfad-min-segmentlaenge* 2 0)))))
|
||||
(setq kette (if obj-liste (gf-sortiere-objekte obj-liste startpunkt) nil))
|
||||
(if (null kette)
|
||||
(progn (princ (ssg-text "vfl-m3-fehler-nicht-sortierbar"))
|
||||
(vfl-journal-record "NIL" nil) nil)
|
||||
(progn
|
||||
(setq segmente (gf-analysiere-kette kette))
|
||||
(setq ecke-bad (vfl2-pruefe-eckwinkel kette ecke-tol))
|
||||
(if ecke-bad
|
||||
(progn
|
||||
(vfl-meldung (ssg-textf "vfl-vwnb-alert-eckwinkel" (list (rtos ecke-bad 2 1))))
|
||||
(vfl-journal-record "NIL" nil) nil)
|
||||
(progn
|
||||
(setq segs9 (vfl-kette->segmente9 kette segmente))
|
||||
(vfl-journal-record "SEGS" segs9)
|
||||
segs9)))))))))
|
||||
|
||||
(defun vf-linienzug-modus3 ( / ss obj-liste startpunkt start-hoehe as-seite
|
||||
es-seite kette segmente n i seg seg-ent typ hz laenge
|
||||
es-seite kette segmente segmente9 n i seg seg-ent typ hz laenge
|
||||
bwinkel bseite frame antwort winkel deltaL
|
||||
anzahl-gf anzahl-vf vfl-nummer lastEnt hoehe-bis
|
||||
ecke-bad first-line last-line letzt-winkel
|
||||
aus ein soll-ende ist-ende run-typ richtn best-w
|
||||
kvariante L_VF ent-fp rad3 just-open
|
||||
dbg-an old-error)
|
||||
dbg-an old-error dbg-old-error vfl-ins)
|
||||
(princ "\n\n=========================================")
|
||||
(princ (ssg-text "vfl-vwnb-titel"))
|
||||
(princ "\n=========================================")
|
||||
@@ -8720,34 +8985,40 @@
|
||||
;; automatisch ueber vfl-journal-record mitgeloggt (siehe dort) - hier nur
|
||||
;; noch Session-Start/-Ende + Zwischenergebnisse, die NICHT direkt aus einer
|
||||
;; Nutzereingabe stammen (Analyse-Ergebnis, Segment-Header, Bau-Ergebnis).
|
||||
;; *vfl-journal*/*vflw-pending* werden dabei nebenbei mitbefuellt, aber von
|
||||
;; Modus 3 nirgends gelesen/persistiert (kein Replay/XDATA wie bei Modus 1/2
|
||||
;; - das ist hier bewusst NICHT mit umgebaut, nur das Logging).
|
||||
;; Der *error*-Handler schliesst die Datei bei Abbruch sauber.
|
||||
;; *vfl-journal* wird - wie bei Modus 1/2 - als XDATA (Marker "linienzug3")
|
||||
;; persistiert und ist damit per Doppelklick editierbar (vfl-edit-ent3, voller
|
||||
;; Reset-Replay). Statt der Objekt-Handles traegt es die Segment-ESSENZ (SEGS,
|
||||
;; siehe vfl-in-segmente): der Block ist selbst-enthalten und der Neubau
|
||||
;; unabhaengig von den urspruenglichen LINE/ARC.
|
||||
;; FRUEHER *error*-Handler: schliesst nur die dbg-Datei sauber, falls waehrend
|
||||
;; der Pfad-/Praeambel-Phase (noch keine Geometrie) abgebrochen wird. Der
|
||||
;; eigentliche Abbruch-WICKLER (Teil-Geometrie zu einem VF_n-Block sichern)
|
||||
;; wird erst nach dem Setup scharf geschaltet (siehe unten), sobald
|
||||
;; vfl-nummer/lastEnt feststehen - analog Modus 2.
|
||||
(setq dbg-an (dbg-schalter-open "vfl-modus3" "vfl_modus3.dbg" "DXFM_LOG"))
|
||||
(if dbg-an
|
||||
(progn
|
||||
(dbgf "vf-linienzug-modus3")
|
||||
(dbgmsg "=== SESSION Modus 3 (Vorwaerts-Nachbau) START ===")
|
||||
(dbgflush)))
|
||||
(setq old-error *error*)
|
||||
(setq dbg-old-error *error*)
|
||||
(setq *error*
|
||||
(function (lambda (msg)
|
||||
(setq *error* old-error)
|
||||
(setq *error* dbg-old-error)
|
||||
(if dbg-an
|
||||
(progn
|
||||
(dbgmsg (strcat "=== ABBRUCH: " (if msg msg "(exit)") " ==="))
|
||||
(dbgreturn nil)
|
||||
(dbgclose)))
|
||||
(if old-error (old-error msg) (princ)))))
|
||||
(if dbg-old-error (dbg-old-error msg) (princ)))))
|
||||
|
||||
(vfl-gf-abhaengigkeit-sicherstellen "vfl-m3-alert-gf-modul")
|
||||
|
||||
;; --- 1. Pfad-Objekte waehlen (LINE/ARC) ---
|
||||
(princ (ssg-text "vfl-m3-pfad-waehlen"))
|
||||
(setq ss (vfl-in-selection '((0 . "LINE,ARC"))))
|
||||
(if (null ss) (progn (princ (ssg-text "vfl-m3-keine-objekte")) (exit)))
|
||||
(setq obj-liste (mapcar 'vlax-ename->vla-object ss))
|
||||
;; --- 1./3. Pfad-Objekte + Segment-Essenz: siehe Schritt 3 unten. ---
|
||||
;; Auswahl UND Ableitung laufen zusammen in vfl-in-segmente, weil die
|
||||
;; Sortierung den Startpunkt braucht (Schritt 2) - die Objektauswahl steht
|
||||
;; daher NACH der Startpunkt-/AS-Praeambel, nicht mehr davor. Journalisiert
|
||||
;; wird nur noch die abgeleitete Segment-Essenz (SEGS), nicht die Handles.
|
||||
|
||||
;; --- 2. Startpunkt (hoehere Seite) + Hoehe + AS-Seite ---
|
||||
;; Wizard: Startpunkt+Hoehe als EIN Gruppen-Dialog (analog Modus 2). Die
|
||||
@@ -8784,24 +9055,25 @@
|
||||
(setq as-seite (if (= (vfl-in-string (ssg-text "prompt-wahl-1-2")) "2") "rechts" "links"))
|
||||
(vf-set-as-masse *vfl-as-winkel* as-seite) ; Masse fuer Variante
|
||||
|
||||
;; --- 3. Sortieren + Analysieren ---
|
||||
(setq kette (gf-sortiere-objekte obj-liste startpunkt))
|
||||
(if (null kette)
|
||||
(progn (princ (ssg-text "vfl-m3-fehler-nicht-sortierbar")) (exit)))
|
||||
(setq segmente (gf-analysiere-kette kette))
|
||||
;; --- 3. Pfad waehlen + Sortieren + Analysieren + Eck-Vorpruefung ---
|
||||
;; vfl-in-segmente kapselt Live (ssget -> gf-sortiere-objekte ->
|
||||
;; gf-analysiere-kette -> Eck-Vorpruefung -> 9-Feld-Essenz) UND Replay
|
||||
;; (fertige Essenz aus dem SEGS-Journal). Persistiert die Segment-Essenz
|
||||
;; statt der Objekt-Handles - damit ist der Block selbst-enthalten und der
|
||||
;; Doppelklick-Neubau (vfl-edit-ent3) braucht die Original-LINE/ARC nicht.
|
||||
(princ (ssg-text "vfl-m3-pfad-waehlen"))
|
||||
(setq segmente9 (vfl-in-segmente '((0 . "LINE,ARC")) startpunkt *vfk-eckwinkel-toleranz*))
|
||||
(if (null segmente9) (progn (princ (ssg-text "vfl-m3-keine-objekte")) (exit)))
|
||||
;; segmente = 5-Feld-Bausicht (typ hz laenge bwinkel bseite), abgeleitet aus
|
||||
;; der 9-Feld-Essenz - der bestehende Bau unten arbeitet unveraendert damit.
|
||||
(setq segmente (mapcar (function (lambda (s) (list (nth 0 s) (nth 1 s) (nth 2 s) (nth 3 s) (nth 4 s))))
|
||||
segmente9))
|
||||
(if dbg-an
|
||||
(progn
|
||||
(dbgmsg (strcat "ANALYSE: " (itoa (length segmente)) " Segment(e) erkannt"))
|
||||
(dbg 'segmente)
|
||||
(dbgflush)))
|
||||
|
||||
;; --- 4. Eck-Winkel-Vorpruefung (vor dem Bau) ---
|
||||
(setq ecke-bad (vfl2-pruefe-eckwinkel kette *vfk-eckwinkel-toleranz*))
|
||||
(if ecke-bad
|
||||
(progn
|
||||
(vfl-meldung (ssg-textf "vfl-vwnb-alert-eckwinkel" (list (rtos ecke-bad 2 1))))
|
||||
(exit)))
|
||||
|
||||
;; --- 5. Setup ---
|
||||
(setq aus (if aus-dx aus-dx *vfk-as-es-fallback-dx*) ein (if ein-dx ein-dx *vfk-as-es-fallback-dx*))
|
||||
(setq rad3 (* (float (ssg-cfg-or "vario" "gefaelle_winkel" 3)) (/ pi 180.0)))
|
||||
@@ -8811,7 +9083,19 @@
|
||||
(setq vfl-nummer (vf-next-number))
|
||||
(setq lastEnt (vf-lastent-ohne-attribute))
|
||||
(vfl-acc-reset)
|
||||
(setq anzahl-gf 0 anzahl-vf 0 frame nil n (length segmente))
|
||||
(setq anzahl-gf 0 anzahl-vf 0 frame nil)
|
||||
;; --- Abbruch-Sicherung ab hier scharf (analog Modus 1/2) ---
|
||||
;; Ab Schritt 6 kann jederzeit Geometrie entstehen. Der Wickler sichert die
|
||||
;; bis zum Abbruch gebaute Teil-Geometrie als VF_n-Block mit dem vollen
|
||||
;; Journal (Marker "linienzug3") - sie bleibt stehen und ist per Doppelklick
|
||||
;; fortsetz-/editierbar. Loest den fruehen dbg-Hook ab (Ruecksprungziel bleibt
|
||||
;; dbg-old-error) und uebernimmt das dbgclose. *ssg-ils-dim* zuruecksetzen:
|
||||
;; Begruendung siehe gleichlautende Stelle in vf-linienzug-modus.
|
||||
(setq old-error dbg-old-error)
|
||||
;; Scharfen Abbruch-Wickel-Handler installieren (gemeinsam, siehe
|
||||
;; vfl-abbruch-handler-installieren).
|
||||
(vfl-abbruch-handler-installieren "linienzug3")
|
||||
(setq n (length segmente))
|
||||
;; erste/letzte "Linie" fuer die Trimmung bestimmen
|
||||
(setq first-line -1 last-line -1 i 0)
|
||||
(while (< i n)
|
||||
@@ -8830,13 +9114,19 @@
|
||||
(setq i 0)
|
||||
(while (< i n)
|
||||
(setq seg (nth i segmente) typ (car seg) hz (cadr seg))
|
||||
(setq seg-ent (car (nth i kette))) ; echte LINE/ARC-Entity dieses Segments
|
||||
;; seg-ent: KEINE Live-Entity mehr - Modus 3 baut jetzt aus der Segment-
|
||||
;; Essenz (SEGS), nicht aus durchgereichten LINE/ARC. Damit entfaellt das
|
||||
;; kosmetische Pfad-Segment-Highlight (vfl-seg-highlight ist nil-sicher).
|
||||
;; Der Wegfall ist bewusst: die Essenz macht den Bau/Replay unabhaengig von
|
||||
;; den Original-Objekten, ein Highlight haette beim Doppelklick-Neubau ohnehin
|
||||
;; keine Entity mehr zum Hervorheben.
|
||||
(setq seg-ent nil)
|
||||
;; Wizard: alle Fragen dieses Segments in EINEM Dialog erfassen (die
|
||||
;; unveraenderten vfl-in-*-Aufrufe unten konsumieren die Antworten aus
|
||||
;; *vflw-pending*). Segment vorher in der Zeichnung hervorheben. Bei einem
|
||||
;; Bogen ist Vario-Kurve nur im offenen VF-Lauf erlaubt - deshalb die
|
||||
;; Variante-Antwort nur mitschicken, wenn run-typ="VF" (sonst konsumiert
|
||||
;; der Aufrufer sie nicht und sie wuerde ins naechste Segment lecken).
|
||||
;; *vflw-pending*). Bei einem Bogen ist Vario-Kurve nur im offenen VF-Lauf
|
||||
;; erlaubt - deshalb die Variante-Antwort nur mitschicken, wenn run-typ="VF"
|
||||
;; (sonst konsumiert der Aufrufer sie nicht und sie wuerde ins naechste
|
||||
;; Segment lecken).
|
||||
(if (vfl-wizard-aktiv)
|
||||
(progn
|
||||
(vfl-seg-highlight seg-ent T)
|
||||
@@ -8949,12 +9239,21 @@
|
||||
(setq frame (vfl-insert-es-element "GF" frame (car (frame->hz-winkel frame))
|
||||
(if letzt-winkel letzt-winkel *vfk-gefaelle-winkel*) (caddr (car frame)) es-seite)))
|
||||
|
||||
;; --- 8. Block + Ist-Ziel-Report ---
|
||||
;; --- 8. Block + Journal-XDATA + Ist-Ziel-Report ---
|
||||
(setq hoehe-bis (caddr (car frame)))
|
||||
(vfl-block-erstellen vfl-nummer anzahl-gf anzahl-vf (caddr startpunkt) hoehe-bis
|
||||
(vfl-planar-dist startpunkt (car frame)) as-seite es-seite startpunkt lastEnt)
|
||||
(setq vfl-ins
|
||||
(vfl-block-erstellen vfl-nummer anzahl-gf anzahl-vf (caddr startpunkt) hoehe-bis
|
||||
(vfl-planar-dist startpunkt (car frame)) as-seite es-seite startpunkt lastEnt))
|
||||
;; Eingabe-Journal am fertigen Block persistieren (Marker "linienzug3") ->
|
||||
;; spaeter per Doppelklick editierbar (vfl-edit-ent3: voller Reset-Replay wie
|
||||
;; Modus 2, aus der Segment-Essenz statt aus Objekt-Handles).
|
||||
(if vfl-ins (vfl-journal-xdata-schreiben vfl-ins "linienzug3"))
|
||||
|
||||
(setq soll-ende (caddr (last kette))) ; Endpunkt des letzten gezeichneten Segments
|
||||
;; Endpunkt des letzten gezeichneten Segments - aus der Segment-Essenz
|
||||
;; (epx/epy des letzten Segments), nicht mehr aus den Original-Entities.
|
||||
;; Damit stimmt der Soll-Ende-Report auch beim Doppelklick-Neubau, wenn die
|
||||
;; urspruenglichen LINE/ARC laengst weg sind.
|
||||
(setq soll-ende (list (nth 7 (last segmente9)) (nth 8 (last segmente9))))
|
||||
(setq ist-ende (car frame)) ; ES-KS_AUS
|
||||
(princ "\n\n=========================================")
|
||||
(princ (ssg-text "vfl-vwnb-eingefuegt"))
|
||||
@@ -9199,7 +9498,7 @@
|
||||
100.0))))
|
||||
|
||||
(defun vf-linienzug-modus2 ( / ss k obj-liste startpunkt start-hoehe as-seite
|
||||
endpunkt end-hoehe es-seite kette segmente n i seg
|
||||
endpunkt end-hoehe es-seite kette segmente segmente9 n i seg
|
||||
seg-ent
|
||||
typ hz laenge bwinkel bseite antwort winkel klass
|
||||
plan e ecke-bad vf-start vf-ende dz z-front
|
||||
@@ -9264,11 +9563,14 @@
|
||||
|
||||
(vfl-gf-abhaengigkeit-sicherstellen "vfl-m3-alert-gf-modul")
|
||||
|
||||
;; --- 1. Pfad-Objekte waehlen ---
|
||||
(princ (ssg-text "vfl-m3-pfad-waehlen"))
|
||||
(setq ss (vfl-in-selection '((0 . "LINE,ARC"))))
|
||||
(if (null ss) (progn (princ (ssg-text "vfl-m3-keine-objekte")) (exit)))
|
||||
(setq obj-liste (mapcar 'vlax-ename->vla-object ss))
|
||||
;; --- 1./4. Pfad-Objekte + Segment-Essenz: siehe Schritt 4 unten. ---
|
||||
;; Auswahl UND Ableitung laufen zusammen in vfl-in-segmente (Live: ssget ->
|
||||
;; gf-sortiere-objekte -> gf-analysiere-kette -> Eck-Vorpruefung -> SEGS;
|
||||
;; Replay: fertige Essenz aus dem Journal). Persistiert die Segment-Essenz
|
||||
;; statt der Objekt-Handles - der Block ist damit selbst-enthalten und der
|
||||
;; Doppelklick-Neubau unabhaengig von den Original-LINE/ARC (behebt den
|
||||
;; frueheren OBJS-Replay-Drift). Da vfl-in-segmente den startpunkt fuer die
|
||||
;; Sortierung braucht, steht die Auswahl NACH der Startpunkt-Praeambel.
|
||||
|
||||
;; --- 2. Startpunkt + Z + AS-Seite ---
|
||||
(if (vfl-wizard-aktiv)
|
||||
@@ -9292,22 +9594,7 @@
|
||||
;; Globals pro Lauf zuruecksetzen (siehe Kommentar in vf-linienzug-modus).
|
||||
(setq *vfl-as-winkel* nil *vfl-es-winkel* nil)
|
||||
(if as-vorhanden
|
||||
(progn
|
||||
(princ (ssg-text "vf-winkel-aus-header"))
|
||||
(princ (ssg-text "vf-winkel-90"))
|
||||
(princ (ssg-text "vf-winkel-30"))
|
||||
(setq *vfl-as-winkel*
|
||||
(vfl-in-value "STR"
|
||||
(function (lambda () (vf-frage-element-winkel "vf-winkel-aus-header"))))) ; 30/90 vor Seite
|
||||
(princ (ssg-text "gf-seite-aus-header"))
|
||||
(princ (ssg-text "gf-seite-links"))
|
||||
(princ (ssg-text "gf-seite-rechts"))
|
||||
(setq antwort (vfl-menu (ssg-text "prompt-wahl-1-2")
|
||||
(list (ssg-text "gf-seite-links") (ssg-text "gf-seite-rechts")) 1
|
||||
"gf-seite-aus-header"))
|
||||
(setq as-seite (if (= antwort "2") "rechts" "links"))
|
||||
(vf-set-as-masse *vfl-as-winkel* as-seite) ; Masse fuer Variante
|
||||
)
|
||||
(setq as-seite (vfl-frage-as-winkel-seite "gf-seite-aus-header"))
|
||||
)
|
||||
|
||||
;; --- 3. Endpunkt + Z + ES-Seite (NEU in Modus 3) ---
|
||||
@@ -9330,34 +9617,19 @@
|
||||
"vfl-es-setzen-frage"))
|
||||
(setq es-vorhanden (/= antwort "2"))
|
||||
(if es-vorhanden
|
||||
(progn
|
||||
(princ (ssg-text "vf-winkel-ein-header"))
|
||||
(princ (ssg-text "vf-winkel-90"))
|
||||
(princ (ssg-text "vf-winkel-30"))
|
||||
(setq *vfl-es-winkel*
|
||||
(vfl-in-value "STR"
|
||||
(function (lambda () (vf-frage-element-winkel "vf-winkel-ein-header"))))) ; 30/90 vor Seite
|
||||
(princ (ssg-text "gf-seite-ein-header"))
|
||||
(princ (ssg-text "gf-seite-links"))
|
||||
(princ (ssg-text "gf-seite-rechts"))
|
||||
(setq antwort (vfl-menu (ssg-text "prompt-wahl-1-2")
|
||||
(list (ssg-text "gf-seite-links") (ssg-text "gf-seite-rechts")) 1
|
||||
"gf-seite-ein-header"))
|
||||
(setq es-seite (if (= antwort "2") "rechts" "links"))
|
||||
(vf-set-es-masse *vfl-es-winkel* es-seite) ; Masse fuer Variante
|
||||
)
|
||||
(setq es-seite (vfl-frage-es-winkel-seite "gf-seite-ein-header"))
|
||||
)
|
||||
|
||||
;; --- 4. Sortieren + Analysieren + Eck-Vorpruefung ---
|
||||
(setq kette (gf-sortiere-objekte obj-liste startpunkt))
|
||||
(if (null kette)
|
||||
(progn (princ (ssg-text "vfl-m3-fehler-nicht-sortierbar")) (exit)))
|
||||
(setq segmente (gf-analysiere-kette kette))
|
||||
(setq ecke-bad (vfl2-pruefe-eckwinkel kette *vfk-eckwinkel-toleranz*))
|
||||
(if ecke-bad
|
||||
(progn
|
||||
(vfl-meldung (ssg-textf "vfl-m3-alert-eckwinkel" (list (rtos ecke-bad 2 1))))
|
||||
(exit)))
|
||||
;; --- 4. Pfad waehlen + Sortieren + Analysieren + Eck-Vorpruefung ---
|
||||
;; vfl-in-segmente kapselt Live + Replay und persistiert die Segment-Essenz
|
||||
;; (SEGS) statt der Objekt-Handles - siehe Schritt 1 oben und Modus 3.
|
||||
(princ (ssg-text "vfl-m3-pfad-waehlen"))
|
||||
(setq segmente9 (vfl-in-segmente '((0 . "LINE,ARC")) startpunkt *vfk-eckwinkel-toleranz*))
|
||||
(if (null segmente9) (progn (princ (ssg-text "vfl-m3-keine-objekte")) (exit)))
|
||||
;; segmente = 5-Feld-Bausicht (typ hz laenge bwinkel bseite) aus der 9-Feld-
|
||||
;; Essenz - die Klassifizierungs-Schleife unten arbeitet unveraendert damit.
|
||||
(setq segmente (mapcar (function (lambda (s) (list (nth 0 s) (nth 1 s) (nth 2 s) (nth 3 s) (nth 4 s))))
|
||||
segmente9))
|
||||
|
||||
;; --- 5. Klassifizierung (Phase A: nur speichern, nichts bauen) ---
|
||||
;; Plan-Eintrag Gerade: ("Linie" hz laenge klass winkel) klass=GF/VF
|
||||
@@ -9365,13 +9637,18 @@
|
||||
(setq n (length segmente) i 0 plan '())
|
||||
(while (< i n)
|
||||
(setq seg (nth i segmente) typ (car seg) hz (cadr seg) laenge (caddr seg))
|
||||
(setq seg-ent (car (nth i kette))) ; echte LINE/ARC-Entity dieses Segments
|
||||
;; seg-ent: KEINE Live-Entity mehr - Modus 2 baut jetzt aus der Segment-
|
||||
;; Essenz (SEGS), nicht aus durchgereichten LINE/ARC (siehe Modus 3). Damit
|
||||
;; entfaellt das kosmetische Pfad-Segment-Highlight (vfl-seg-highlight ist
|
||||
;; nil-sicher). Bewusst: die Essenz macht Bau/Replay unabhaengig von den
|
||||
;; Original-Objekten, ein Highlight haette beim Doppelklick-Neubau ohnehin
|
||||
;; keine Entity mehr.
|
||||
(setq seg-ent nil)
|
||||
;; Wizard: alle Fragen dieses Segments in EINEM Dialog erfassen (die
|
||||
;; unveraenderten vfl-menu/vfl-in-*-Aufrufe unten konsumieren die Antworten
|
||||
;; aus *vflw-pending*). Segment vorher in der Zeichnung hervorheben. Der
|
||||
;; nach-kurve-Fall stellt keine Frage (auto-VF) -> kein Dialog. Ebenso
|
||||
;; nach-vf bei einem Bogen: Vario-Kurve ist dann erzwungen (eine VF-
|
||||
;; Einheit kann nicht in einen GF-Bogen auslaufen), auch kein Dialog.
|
||||
;; aus *vflw-pending*). Der nach-kurve-Fall stellt keine Frage (auto-VF) ->
|
||||
;; kein Dialog. Ebenso nach-vf bei einem Bogen: Vario-Kurve ist dann
|
||||
;; erzwungen (eine VF-Einheit kann nicht in einen GF-Bogen auslaufen).
|
||||
(if (and (vfl-wizard-aktiv)
|
||||
(not (and (= typ "Linie") nach-kurve))
|
||||
(not (and (= typ "Bogen") nach-vf)))
|
||||
@@ -9470,9 +9747,14 @@
|
||||
|
||||
(if (/= vf-count 1)
|
||||
(progn
|
||||
;; Konsolen-Diagnose (fuer den Log / dbg-Nachvollzug) ...
|
||||
(princ (ssg-textf "vfl-m3-vf-laeufe" (list (itoa vf-count))))
|
||||
(princ (ssg-text "vfl-m3-vf-lauf-noetig"))
|
||||
(princ (ssg-text "vfl-m3-vf-lauf-m3b"))
|
||||
;; ... UND als sichtbare Meldung, damit die Abweisung nicht in der
|
||||
;; Konsole untergeht (vfl-meldung zeigt bei erlaubter GUI ein alert,
|
||||
;; headless nur princ - blockiert also einen Batch-Lauf nicht).
|
||||
(vfl-meldung (ssg-textf "vfl-m3-vf-lauf-alert" (list (itoa vf-count))))
|
||||
(exit)))
|
||||
;; Traeger-Stueck = laengste VF-Gerade im Lauf (traegt die ganze Hoehe).
|
||||
(setq carrier-idx -1 i vf-start)
|
||||
@@ -9626,22 +9908,10 @@
|
||||
;; dbg-Hook selbst) und uebernehmen das dbgclose gleich mit, sonst wuerde
|
||||
;; bei einem Abbruch ab hier doppelt geschlossen.
|
||||
(setq old-error dbg-old-error)
|
||||
;; *ssg-ils-dim* hier zuruecksetzen - Begruendung siehe gleichlautende Stelle
|
||||
;; im Handler von vf-linienzug-modus (Abbruch kehrt nie zum Aufrufer zurueck,
|
||||
;; der den Override abraeumen wuerde).
|
||||
(setq *error*
|
||||
(function (lambda (msg)
|
||||
(setq *error* old-error)
|
||||
(setq *ssg-ils-dim* nil)
|
||||
(vfl-modus-abbruch-sichern lastEnt vfl-nummer anzahl-gf anzahl-vf
|
||||
startpunkt frame as-seite es-seite "linienzug2")
|
||||
(if dbg-an
|
||||
(progn
|
||||
(dbgmsg (strcat "=== ABBRUCH: " (if msg msg "(exit)") " ==="))
|
||||
(dbgreturn nil)
|
||||
(dbgclose)))
|
||||
(if (and (boundp '*ssg-start-stack*) *ssg-start-stack*) (ssg-end))
|
||||
(princ))))
|
||||
;; Scharfen Abbruch-Wickel-Handler installieren (loest den fruehen dbg-Hook ab,
|
||||
;; Ruecksprungziel bleibt dbg-old-error via old-error). Gemeinsam fuer alle
|
||||
;; Modi - siehe vfl-abbruch-handler-installieren.
|
||||
(vfl-abbruch-handler-installieren "linienzug2")
|
||||
;; erste/letzte Gerade fuer AS/ES-Trimmung bestimmen
|
||||
(setq first-line -1 last-line -1 i 0)
|
||||
(while (< i n)
|
||||
|
||||
@@ -37,6 +37,17 @@
|
||||
# in den Summierungszaehlern "Anzahl aller BTBeladung"/"Anzahl aller
|
||||
# Abwurfstationen" der ILS-Automation-Zeile).
|
||||
#
|
||||
# pattern_eingang/pattern_ausgang: Eingangs-/Ausgangssymbole des Material-
|
||||
# flusses (siehe ils-insert-station in SSG_LIB_Commands.lsp, Bloecke
|
||||
# Eingang_<DIM>/Ausgang_<DIM>). NUR fuer den CSV-Export: export_csv.py fuehrt
|
||||
# sie als eigene TeileArt-Zeilen ("Eingang"/"Ausgang", Merkmale wie BTMT) UND
|
||||
# als frei platzierte Umlauf-Punkte auf einem Kreisel (KREISEL_UMLAUF_TEILEARTEN
|
||||
# in lib/export_neighbors.py), damit sie - wie Separator/AS/ES - in die
|
||||
# "TrackIds"-Spalte gelangen. export_sivas.py schliesst sie bewusst aus (kein
|
||||
# Sivas-Eintrag). Voraussetzung fuer eine stabile TeileId ist ein ID-ATTDEF in
|
||||
# den DWGs (ssg-id-check-all fuellt es vor jedem Export, siehe
|
||||
# ssg-id-collect-blocks in ssg_id.lsp).
|
||||
#
|
||||
# pattern_geruest: Geruest-Baugruppen (GeruestInsert.lsp, GR_<id>_<timestamp>).
|
||||
# Eigenstaendig wie BTMT, kein ANZAHL_*-Attribut an einem Carrier - export_csv.py
|
||||
# UND export_sivas.py fuehren sie als eigene TeileArt-Zeilen.
|
||||
@@ -54,6 +65,8 @@ pattern_separator= Separator_SP*, S-LP*
|
||||
pattern_scanner= Scanner*
|
||||
pattern_btmt_beladung= BTMT-Beladung*
|
||||
pattern_btmt_entladung= SC_Entladung*
|
||||
pattern_eingang= Eingang*
|
||||
pattern_ausgang= Ausgang*
|
||||
pattern_geruest= GR_*
|
||||
pattern_ks_subblocks= KS_EIN, KS_AUS, K1, K2, K3, K4
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"Eingang_2D": {
|
||||
"ID": ""
|
||||
},
|
||||
"Eingang_3D": {
|
||||
"ID": ""
|
||||
},
|
||||
"Ausgang_2D": {
|
||||
"ID": ""
|
||||
},
|
||||
"Ausgang_3D": {
|
||||
"ID": ""
|
||||
}
|
||||
}
|
||||
+107
-45
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"Rohrabhänger": {
|
||||
"id": "Rohrabhaenger",
|
||||
"titel": "Rohrabhaenger",
|
||||
"teileart": "Geruest Rohrabhaenger",
|
||||
"dummy": "Rohrabhaenger_dummy.dwg",
|
||||
"attribute": {
|
||||
@@ -10,11 +11,11 @@
|
||||
"max": 6000,
|
||||
"einheit": "mm"
|
||||
},
|
||||
"Farbe": {
|
||||
"Teilefarbe": {
|
||||
"typ": "auswahl",
|
||||
"optionen": [
|
||||
"RAL7035",
|
||||
"RAL7030"
|
||||
"RAL 7035 Lichtgrau",
|
||||
"RAL 7030 Steingrau"
|
||||
],
|
||||
"frei_erlaubt": true,
|
||||
"frei_option": "Individuell"
|
||||
@@ -133,50 +134,39 @@
|
||||
"sivas_id": 922021003,
|
||||
"menge": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
"1\" Säulen": {
|
||||
"id": "Saeulen_1Zoll",
|
||||
"teileart": "Geruest Saeule 1 Zoll",
|
||||
"dummy": "R2-Saeule_dummy.dwg",
|
||||
"attribute": {
|
||||
"Laenge": {
|
||||
"typ": "number",
|
||||
"min": 0,
|
||||
"max": 6000,
|
||||
"einheit": "mm"
|
||||
},
|
||||
"Farbe": {
|
||||
"typ": "auswahl",
|
||||
"optionen": [
|
||||
"RAL7035",
|
||||
"RAL7030"
|
||||
],
|
||||
"frei_erlaubt": true,
|
||||
"frei_option": "Individuell"
|
||||
}
|
||||
},
|
||||
"geometrie_varianten": [
|
||||
],
|
||||
"konfigurationen": [
|
||||
{
|
||||
"name": "R 1\"",
|
||||
"teile": [
|
||||
{
|
||||
"artikel": "ROHR R 1\" 33,7 x 2,6",
|
||||
"sivas_id": 821006026,
|
||||
"menge": 1
|
||||
},
|
||||
{
|
||||
"artikel": "CAD - BODENSÄULE R 1\" - BODENPLATTE KPL.",
|
||||
"sivas_id": 821004200,
|
||||
"menge": 1
|
||||
}
|
||||
"name": "Abhaengung Spannpratze / Rohrklammer",
|
||||
"variante": "ROHR R 1\" 33,7 x 2,6",
|
||||
"laenge": 2000,
|
||||
"teilefarbe": "RAL 7035 Lichtgrau",
|
||||
"oben": [
|
||||
{ "artikel": "SPANNPRATZE SELBSTSICHERND KPL.", "menge": 1 },
|
||||
{ "artikel": "Schraubenset", "menge": 1 }
|
||||
],
|
||||
"unten": [
|
||||
{ "artikel": "ROHRKLAMMER 1\" KPL. VERTIKAL", "menge": 2 }
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Abhaengung Duebel / T-Verbindung",
|
||||
"variante": "ROHR R 1\" 33,7 x 2,6 einseitig gequetscht",
|
||||
"laenge": 1500,
|
||||
"teilefarbe": "RAL 7035 Lichtgrau",
|
||||
"oben": [
|
||||
{ "artikel": "DURCHSTECKANKER HST M12X115X20", "menge": 2 }
|
||||
],
|
||||
"unten": [
|
||||
{ "artikel": "ROHRKLAMMER 1\" T-VERBINDUNG KPL.", "menge": 1 }
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"2\" Säulen": {
|
||||
"id": "Saeulen_2Zoll",
|
||||
"teileart": "Geruest Saeule 2 Zoll",
|
||||
"Säulen": {
|
||||
"id": "Saeulen",
|
||||
"titel": "Saeulen",
|
||||
"teileart": "Geruest Saeule",
|
||||
"dummy": "R2-Saeule_dummy.dwg",
|
||||
"attribute": {
|
||||
"Laenge": {
|
||||
@@ -185,11 +175,11 @@
|
||||
"max": 6000,
|
||||
"einheit": "mm"
|
||||
},
|
||||
"Farbe": {
|
||||
"Teilefarbe": {
|
||||
"typ": "auswahl",
|
||||
"optionen": [
|
||||
"RAL7035",
|
||||
"RAL7030"
|
||||
"RAL 7035 Lichtgrau",
|
||||
"RAL 7030 Steingrau"
|
||||
],
|
||||
"frei_erlaubt": true,
|
||||
"frei_option": "Individuell"
|
||||
@@ -208,8 +198,25 @@
|
||||
]
|
||||
},
|
||||
"geometrie_varianten": [
|
||||
{
|
||||
"name": "R 1\"",
|
||||
"teileart": "Geruest Saeule 1 Zoll",
|
||||
"teile": [
|
||||
{
|
||||
"artikel": "ROHR R 1\" 33,7 x 2,6",
|
||||
"sivas_id": 821006026,
|
||||
"menge": 1
|
||||
},
|
||||
{
|
||||
"artikel": "CAD - BODENSÄULE R 1\" - BODENPLATTE KPL.",
|
||||
"sivas_id": 821004200,
|
||||
"menge": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "R 2\"",
|
||||
"teileart": "Geruest Saeule 2 Zoll",
|
||||
"teile": [
|
||||
{
|
||||
"artikel": "BODENSÄULE R 2\" 60,3 MIT FUSSPLATTE",
|
||||
@@ -225,6 +232,7 @@
|
||||
},
|
||||
{
|
||||
"name": "R 2\" Haltearm 1-ARMIG",
|
||||
"teileart": "Geruest Saeule 2 Zoll",
|
||||
"teile": [
|
||||
{
|
||||
"artikel": "BODENSÄULE R 2\" 60,3 MIT FUSSPLATTE",
|
||||
@@ -245,6 +253,7 @@
|
||||
},
|
||||
{
|
||||
"name": "R 2\" Haltearm 2-ARMIG 90 Grad",
|
||||
"teileart": "Geruest Saeule 2 Zoll",
|
||||
"teile": [
|
||||
{
|
||||
"artikel": "BODENSÄULE R 2\" 60,3 MIT FUSSPLATTE",
|
||||
@@ -265,6 +274,7 @@
|
||||
},
|
||||
{
|
||||
"name": "R 2\" Haltearm 2-ARMIG 180 Grad",
|
||||
"teileart": "Geruest Saeule 2 Zoll",
|
||||
"teile": [
|
||||
{
|
||||
"artikel": "BODENSÄULE R 2\" 60,3 MIT FUSSPLATTE",
|
||||
@@ -285,6 +295,7 @@
|
||||
},
|
||||
{
|
||||
"name": "R 2\" Haltearm 3-ARMIG",
|
||||
"teileart": "Geruest Saeule 2 Zoll",
|
||||
"teile": [
|
||||
{
|
||||
"artikel": "BODENSÄULE R 2\" 60,3 MIT FUSSPLATTE",
|
||||
@@ -340,10 +351,43 @@
|
||||
"sivas_id": 922083009,
|
||||
"menge": 2
|
||||
}
|
||||
],
|
||||
"konfigurationen": [
|
||||
{
|
||||
"name": "Bodensaeule 1 Zoll, Standardhoehe",
|
||||
"variante": "R 1\"",
|
||||
"laenge": 1000,
|
||||
"teilefarbe": "RAL 7035 Lichtgrau",
|
||||
"oben": [],
|
||||
"unten": []
|
||||
},
|
||||
{
|
||||
"name": "Bodensaeule 2 Zoll, Haltearm 1-armig",
|
||||
"variante": "R 2\" Haltearm 1-ARMIG",
|
||||
"laenge": 1200,
|
||||
"teilefarbe": "RAL 7035 Lichtgrau",
|
||||
"oben": [
|
||||
{ "artikel": "KLEMMRING MIT MUFFE EINFACH KPL.", "menge": 2 }
|
||||
],
|
||||
"unten": []
|
||||
},
|
||||
{
|
||||
"name": "Bodensaeule 2 Zoll, Haltearm 2-armig 90 Grad",
|
||||
"variante": "R 2\" Haltearm 2-ARMIG 90 Grad",
|
||||
"laenge": 1200,
|
||||
"teilefarbe": "RAL 7035 Lichtgrau",
|
||||
"oben": [
|
||||
{ "artikel": "KLEMMRING MIT MUFFE DOPPELT 90 Grad, KPL.", "menge": 2 }
|
||||
],
|
||||
"unten": [
|
||||
{ "artikel": "QUERSCHELLE F. 1\" UND 2\" ROHR GESCHW./VZ. M. 4X M10X30 KPL.", "menge": 2 }
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"Wandbefestigung": {
|
||||
"id": "Wandbefestigung",
|
||||
"titel": "Wandbefestigung",
|
||||
"teileart": "Geruest Wandbefestigung",
|
||||
"dummy": "Rohrabhaenger_dummy.dwg",
|
||||
"geometrie_varianten": [
|
||||
@@ -414,6 +458,24 @@
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"konfigurationen": [
|
||||
{
|
||||
"name": "Wandflansch mit Duebeln",
|
||||
"variante": "WANDFLANSCH EINZELTEIL",
|
||||
"oben": [
|
||||
{ "artikel": "Nylondübel 12x60 inkl. Holzschrauben", "menge": 1 }
|
||||
],
|
||||
"unten": []
|
||||
},
|
||||
{
|
||||
"name": "Winkel 300 mit Schwerlastanker",
|
||||
"variante": "WINKEL 60X60X6X300",
|
||||
"oben": [
|
||||
{ "artikel": "HST M12X115X20", "menge": 1 }
|
||||
],
|
||||
"unten": []
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
// ============================================================
|
||||
// geruest.dcl - Konfiguration einer Geruest-Baugruppe
|
||||
// Ein Dialog fuer ALLE Baugruppen (Rohrabhaenger, Saeulen, Wandbefestigung).
|
||||
// Kopfzeile, Varianten-Dropdown, Farbliste und Anbauteil-Liste werden zur
|
||||
// Laufzeit aus data/json/geruest.json befuellt - siehe
|
||||
// Lisp/GeruestInsert.lsp, Abschnitt "DIALOG".
|
||||
// Baugruppen ohne "attribute"-Block (z.B. Wandbefestigung) bekommen die
|
||||
// Laengen- und Farbfelder per mode_tile gesperrt.
|
||||
// ============================================================
|
||||
|
||||
geruest : dialog {
|
||||
label = "Geruest-Baugruppe konfigurieren";
|
||||
|
||||
: text {
|
||||
key = "kopf";
|
||||
label = "";
|
||||
width = 64;
|
||||
}
|
||||
|
||||
: boxed_column {
|
||||
label = "Basis";
|
||||
|
||||
: popup_list {
|
||||
key = "variante";
|
||||
label = "Variante:";
|
||||
width = 56;
|
||||
}
|
||||
|
||||
: row {
|
||||
: edit_box {
|
||||
key = "laenge";
|
||||
label = "Laenge (mm):";
|
||||
edit_width = 10;
|
||||
}
|
||||
: popup_list {
|
||||
key = "farbe";
|
||||
label = "Farbe:";
|
||||
width = 18;
|
||||
}
|
||||
: edit_box {
|
||||
key = "farbe_frei";
|
||||
label = "eigene:";
|
||||
edit_width = 12;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
: boxed_column {
|
||||
label = "Anbauteile (Mehrfachauswahl mit Strg)";
|
||||
|
||||
: list_box {
|
||||
key = "anbau";
|
||||
label = "";
|
||||
multiple_select = true;
|
||||
width = 64;
|
||||
height = 12;
|
||||
}
|
||||
}
|
||||
|
||||
ok_cancel;
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
# TODO: Modus-2-Solver auf achsenweise Laengen-Bilanz umstellen
|
||||
|
||||
Status: **Vorschlag / noch nicht umgesetzt** (2026-09-18). Mit dem Entwickler zu
|
||||
besprechen, bevor der Solver angefasst wird. Reiner Plan - kein Code geaendert.
|
||||
|
||||
## Kurzfassung
|
||||
|
||||
Der Modus-2-Solver (`vf-linienzug-modus2`, Phase B, `Lisp/vf_linienzug.lsp`
|
||||
ca. Zeile 9915-10145) modelliert den VarioFoerderer-Lauf als EINE gerade
|
||||
Bruecke. Bei einer gefalteten Kette (U-Form: hoch, quer, runter) zieht er die
|
||||
festen Fussabdruecke aus der falschen Achse ab: **die erste GF wird zu lang,
|
||||
die Kletterstrecke zu kurz, Motor/ES landen falsch bzw. fehlen.** Der Fix:
|
||||
Laengen pro Schenkelrichtung bilanzieren statt als eine skalare Spanne.
|
||||
|
||||
Das ist ein **dokumentiertes v1-Naeherungs-Limit**, kein Regressionsfehler -
|
||||
die Umbauten SEGS/Alert-Box/Mini-Filter haben Phase B nicht angefasst.
|
||||
|
||||
## Symptom (echter Testfall: results/test_modus2.dxf, logs/vfl_modus2.dbg)
|
||||
|
||||
U-Form-Kette, 6 Segmente, EIN VF-Lauf (Seg 2-6; die zwei Vario-Kurven zaehlen
|
||||
als VF-Mitglieder):
|
||||
|
||||
```
|
||||
^ Seg2 VF (1500 mm)
|
||||
| Seg1 GF (2500 mm)
|
||||
start Seg4 VF (2257 mm)
|
||||
| +-----------------------+
|
||||
| Seg3 Kurve Seg5 Kurve
|
||||
| |
|
||||
| Seg6 VF (3800 mm)
|
||||
+ v
|
||||
Ziel (3520, 180)
|
||||
```
|
||||
|
||||
Ergebnis: `SOLL-ENDE=(3520, 180, 2000)`, `IST-ENDE=(3333, 2825, 2080)` ->
|
||||
`dY=+2645 mm`, `dZ=+80 mm`. Die erste GF wird zu lang erzeugt; die
|
||||
Kletterstrecke (Seg 6) endet ~2645 mm zu frueh; Motorstation, das
|
||||
VF-Kurven-Zwischenstueck und das ES-Element sitzen falsch bzw. fehlen.
|
||||
|
||||
## Ursache, praezise lokalisiert
|
||||
|
||||
Der Solver waehlt die laengste VF-Gerade (Seg 6, 3800) als Kletterer, der die
|
||||
ganze Hoehe traegt, und rechnet die geneigte Laenge skalar:
|
||||
|
||||
```lisp
|
||||
;; vf_linienzug.lsp:9990 - Solver bekommt die SKALARE Spanne
|
||||
(setq wahl3 (vfl3-waehle-winkel climber-span dH-adj feste-vf))
|
||||
;; feste-vf = Umlenk + Separator (+ Motor) -- ein fester Fussabdruck
|
||||
|
||||
;; vf_linienzug.lsp:10070 - Kletterer bekommt br-lvf proportional
|
||||
(setq this-lvf (max clamp (* br-lvf (/ (caddr seg) climber-span))))
|
||||
;; br-lvf = climber-span MINUS feste-vf
|
||||
;; ABER: Umlenk/GF1/Motor sitzen physisch in ANDEREN Schenkeln
|
||||
;; (GF1+Umlenk am Eingang entlang hz=90, nicht in Seg6/hz=-90)
|
||||
```
|
||||
|
||||
**Der Modellbruch:** `br-lvf` = `climber-span` minus die festen Fussabdruecke
|
||||
(Umlenk 500 + Separator 300 + GF1 `gf-total` + Motor). Diese Teile liegen aber
|
||||
in den ANDEREN U-Schenkeln - nicht in Seg 6. Der Solver zieht sie trotzdem von
|
||||
Seg 6s 3800er-Spanne ab. Weil GF1 = "alles am Einlauf" gewaehlt war, ist
|
||||
`gf-total` gross -> Seg 6 wird um genau diese Summe (~2645 mm) zu kurz. Bei
|
||||
einer GERADEN Bruecke liegen alle Teile auf derselben Achse - dann stimmt die
|
||||
skalare Rechnung. Bei der U-Form nicht.
|
||||
|
||||
Zusaetzlich: die flache Zone nimmt GENAU EIN Uebergangspaar an
|
||||
(`hor-pairs = 1`, Zeile 9950), obwohl die U-Form zwei 90-Grad-Kurven plus
|
||||
Kletterstrecke mischt -> daraus die Rest-dZ von +80 mm.
|
||||
|
||||
## Beleg: dokumentiertes Limit, kein Regressionsfehler
|
||||
|
||||
| Kommentar-Fundstelle | Aussage |
|
||||
|---|---|
|
||||
| `vf_linienzug.lsp:9073-9075` | "v1-Naeherung Laenge ... feinere Laengen-Reservierung -> spaeter" |
|
||||
| `vf_linienzug.lsp:9923-9926` | Modell explizit "EIN Vario mit Horizontal-Mitte" - eine gerade Bruecke ist die Design-Annahme |
|
||||
| `vf_linienzug.lsp:9948-9950` | "flache Zone hat GENAU EIN Uebergangspaar ... unabhaengig von der Zahl der Fueller/Kurven" |
|
||||
|
||||
Verifiziert: SEGS-Umbau, Alert-Box und Mini-Filter haben Phase B (den Solver)
|
||||
nachweislich nicht veraendert. Die Abweichung ist vorbestehend.
|
||||
|
||||
## Vorgeschlagener Umbau in sicheren Etappen
|
||||
|
||||
Nach jeder Etappe eine BricsCAD-Sichtpruefung (Geometrie ist nur interaktiv
|
||||
pruefbar).
|
||||
|
||||
1. **Regressionsnetz zuerst.** Eine bekannt-gute GERADE Modus-2-Kette
|
||||
(GF...VF...GF, eine Achse) bauen und mit `lib/dxf_vf_abbild.py
|
||||
--schreibe-referenz` als Referenz einfrieren. Schuetzt den funktionierenden
|
||||
Normalfall, bevor die Bilanz umgebaut wird.
|
||||
2. **Schenkel erkennen.** Den VF-Lauf (Seg `vf-start`..`vf-ende`) an den
|
||||
Vario-Kurven in Schenkel aufteilen - jeder Schenkel eine Fahrtrichtung (hz).
|
||||
Pro Schenkel: Summe der VF-Geraden-Laengen, welche festen Teile darin liegen.
|
||||
Neue Datenstruktur statt der skalaren `climber-span`. (ersetzt die
|
||||
climber/nonclimber-Schleife 9935-9947)
|
||||
3. **Fussabdruecke dem richtigen Schenkel zuordnen** (Risiko-Kern). Umlenk/GF1
|
||||
nur vom Eingangs-Schenkel abziehen, Motor/GF2/ES nur vom Ausgangs-Schenkel -
|
||||
nicht pauschal von der Kletterstrecke. Reicht ein Schenkel nicht, verteilt
|
||||
sich die Restneigung auf weitere Schenkel. (feste-vf/dH-adj 9978-9989,
|
||||
this-lvf 10070, fill-len 10094-10104)
|
||||
4. **Uebergangspaare pro Kurve** statt pauschal eins. `hor-pairs` aus der
|
||||
tatsaechlichen Schenkel-/Kurvenzahl ableiten - behebt die dZ-Restabweichung.
|
||||
(9950, dH-adj-Bildung 9982-9989)
|
||||
5. **Verifikation.** Regressionsnetz aus Schritt 1 muss gruen bleiben (gerader
|
||||
Fall unveraendert). U-Form interaktiv: erste GF korrekt kurz,
|
||||
Kletterstrecke trifft den Zielpunkt, Motor + Kurven-Zwischenstueck + ES an
|
||||
der richtigen Stelle. SEGS-Journal bleibt formgleich.
|
||||
|
||||
## Risiko-Einschaetzung
|
||||
|
||||
- Der GERADE Fall funktioniert heute - er ist der Normalfall, fuer den der
|
||||
Solver gebaut ist. Ein Umbau der Kern-Bilanz kann ihn brechen -> Schritt 1
|
||||
(Referenznetz) ist nicht optional.
|
||||
- Geometrie nur interaktiv in BricsCAD pruefbar -> mehrere Runden noetig.
|
||||
- Gut eingegrenzt: der Umbau bleibt in Phase B von `vf-linienzug-modus2`
|
||||
(~9915-10145). Klassifizierung, SEGS-Journal, Doppelklick-Replay und die
|
||||
anderen Modi bleiben unberuehrt.
|
||||
|
||||
## Zwischenloesung (falls der Umbau nicht sofort kommt)
|
||||
|
||||
Gefaltete VF-Laeufe (mehr als eine Achsenrichtung im VF-Bereich, z.B. U-Form)
|
||||
erkennen und mit klarer Meldung abweisen, statt still falsche Geometrie zu
|
||||
bauen - analog zur bereits vorhandenen "nur EIN VF-Lauf"-Abweisung
|
||||
(`vfl-m3-vf-lauf-alert`). Macht das Limit ehrlich sichtbar, kleiner Eingriff.
|
||||
+25
-5
@@ -70,8 +70,8 @@ Bounding-Boxen braucht).
|
||||
`vla-update` auf, das allein reichte in diesem Fall nicht aus.
|
||||
7. **`csv:collect-export-blocks`** — sammelt alle relevanten top-level
|
||||
INSERTs (Kreisel, Omniflo, VF/GF-Wrapper, Separator/Scanner,
|
||||
BTMT-Stationen) ueber die Blockname-Muster aus `cfg/export.cfg`
|
||||
`[blockpattern]`.
|
||||
BTMT-Stationen, Eingang/Ausgang) ueber die Blockname-Muster aus
|
||||
`cfg/export.cfg` `[blockpattern]`.
|
||||
8. **`csv:block-to-json`** je Fund — siehe naechster Abschnitt.
|
||||
|
||||
### `csv:block-to-json` — Inhalt eines JSON-Eintrags
|
||||
@@ -277,7 +277,8 @@ Zu beachten:
|
||||
Eine grosse Schleife über alle rohen JSON-Blöcke ordnet jeden Block anhand
|
||||
der `cfg/export.cfg [blockpattern]`-Muster einer TeileArt zu (Kreisel,
|
||||
Eckrad, Omniflo Bogen/Weiche/Gerade, VF-Strecke, Gefaellestrecke,
|
||||
Strecke-Modul, Separator, Scanner, BTMT Be-/Entladung) und baut daraus ein
|
||||
Strecke-Modul, Separator, Scanner, BTMT Be-/Entladung, Eingang/Ausgang) und
|
||||
baut daraus ein
|
||||
Item-dict mit `teileart`, `teileid`, `bezeichnung`, `planquadrat`,
|
||||
`merkmale` und den bbox-/KOS-Spalten (`bbox_columns`). VF_n/GF_n-Items
|
||||
bekommen dabei zusaetzlich `x`/`y` (Kettenanfang, fuer die Schleuselement-
|
||||
@@ -299,6 +300,24 @@ Default 210x150x14mm) und der bekannten Position/Rotation eine synthetische
|
||||
`_bbox`, damit der Separator trotzdem an der Nachbarschaftserkennung
|
||||
teilnimmt.
|
||||
|
||||
#### Eingang/Ausgang — nur im CSV-Export
|
||||
|
||||
Die Materialfluss-Ein-/Ausgangssymbole (Bloecke `Eingang_<DIM>`/`Ausgang_<DIM>`,
|
||||
eingefuegt ueber `ils-insert-station`, Befehle `ILS_EINGANG_INSERT`/
|
||||
`ILS_AUSGANG_INSERT`) werden **nur im CSV-Export** als eigene Zeile gefuehrt
|
||||
(TeileArt `"Eingang"`/`"Ausgang"`, Merkmale wie BTMT: ARTINR/Hoehe/Drehung).
|
||||
`export_sivas.py` ueberspringt sie bewusst — ein Fluss-Symbol hat keinen
|
||||
eigenen Sivas-Artikel.
|
||||
|
||||
Wie Separator/AS/ES nehmen sie als **freie Umlauf-Punkte**
|
||||
(`KREISEL_UMLAUF_TEILEARTEN`) an der `"TrackIds"`-Spalte teil und tauchen so
|
||||
auch auf einem Kreisel auf, auf dessen Bahn sie liegen. Voraussetzung fuer
|
||||
eine ueber Exportlaeufe stabile TeileId ist ein `ID`-ATTDEF in den DWGs
|
||||
(nachgetragen, dokumentiert in `data/ils/allocations.json`); `ssg-id-check-all`
|
||||
fuellt es vor jedem Export, und `ssg-id-collect-blocks` (`Lisp/ssg_id.lsp`)
|
||||
erfasst die Bloecke dafuer. Fehlt die ID (noch), greift wie bei BTMT eine
|
||||
lauf-lokale Fallback-Nummer (`EIN-`/`AUS-`-Praefix).
|
||||
|
||||
### 2. `compute_neighbor_ids` — die generische Bounding-Box-Nachbarschaft
|
||||
|
||||
Datei `lib/export_neighbors.py`. Testet drei Gruppen gegeneinander (NICHT
|
||||
@@ -347,8 +366,9 @@ Weichen zu einer widerspruchsfreien Nachbarschaft zusammenfuehrt. Fuer jeden
|
||||
echten Kreisel werden alle Punkte gesammelt, die dort geometrisch liegen:
|
||||
|
||||
- freie Punkte (`KREISEL_UMLAUF_TEILEARTEN` in `lib/export_neighbors.py`:
|
||||
Separator, BTMT Beladung, BTMT Entladung — alles Stationen direkt auf der
|
||||
Bahn/dem Track), deren Bounding-Box die Kreisel-Box ueberschneidet,
|
||||
Separator, BTMT Beladung, BTMT Entladung, Eingang, Ausgang — alles
|
||||
Stationen/Markierungen direkt auf der Bahn/dem Track), deren Bounding-Box
|
||||
die Kreisel-Box ueberschneidet,
|
||||
- die Kreisel-Kreisel-Weichen aus Schritt 3 (in BEIDEN beteiligten
|
||||
Kreisel-Umlaeufen, da eine Weiche der gemeinsame Verzweigungspunkt ist —
|
||||
man kann von Kreisel A nach B und zurueck),
|
||||
|
||||
+19
-3
@@ -111,6 +111,7 @@
|
||||
"vfl-glied-vario": "Vario-Kurve (horizontale Kurve im VF)",
|
||||
"vfl-glied-offen": "(offen)",
|
||||
"vfl-edit-kein-journal": "Dieser Linienzug-Block traegt kein Eingabe-Journal (Altbestand) und kann nicht schrittweise editiert werden.",
|
||||
"vfl-edit-m2-obsolet": "Dieser Modus-2-Block wurde mit dem alten Objekt-Referenz-Journal gebaut und kann nicht mehr per Doppelklick neu aufgebaut werden. Bitte die Kette mit Modus 2 neu erzeugen (die neue Fassung speichert die Segment-Daten direkt am Block).",
|
||||
"vfl-edit-kette-header": "\n\nLinienzug mit %1 Glied(ern):",
|
||||
"vfl-edit-abgespielt": "\n>>> %1 Glied(er) werden abgespielt, %2 zurueckgenommen - danach interaktiv weiter.",
|
||||
"vfl-edit2-reset-info": "\n>>> Linienzug (Modus 2) wird mit den gespeicherten Angaben identisch neu aufgebaut...",
|
||||
@@ -183,6 +184,8 @@
|
||||
"vfl-m3-vf-laeufe": "\n\n[M3a] Gefundene VF-Laeufe: %1",
|
||||
"vfl-m3-vf-lauf-noetig": "\n[M3a] Genau EIN VF-Lauf noetig (GF...VF...GF; Vario-Kurven duerfen im Lauf liegen).",
|
||||
"vfl-m3-vf-lauf-m3b": "\n[M3a] Mehrere/keine VF-Laeufe -> M3b spaeter.",
|
||||
"vfl-m3-vf-lauf-alert": "VF-Linienzug Modus 2 kann diese Kette nicht bauen.\n\nGefunden: %1 VarioFoerderer-Laeufe.\nModus 2 baut zurzeit nur Ketten mit GENAU EINEM VF-Lauf (GF...VF...GF; Vario-Kurven duerfen innerhalb des Laufs liegen).\n\nBitte den Pfad so aufteilen, dass nur ein zusammenhaengender VF-Bereich entsteht.",
|
||||
"vfl-m3-mini-objekte-verworfen": "%1 zu kurze(s) Objekt(e) wurden aus der Auswahl ausgeschlossen (unter %2 mm 2D-Laenge).\n\nSolche Mini-Segmente sind meist Geister-/Artefakt-Elemente, die eine Rechteck-Auswahl versehentlich miterfasst - ein reales Bauteil (kleinstes: Separator 300 mm) ist nie so kurz. Sie werden ignoriert, damit sie keine Geister-Bausteine in die Kette bringen.",
|
||||
"vfl-m3-vf-lauf-ohne-gerade": "\n[M3a] VF-Lauf ohne VF-Gerade - Abbruch.",
|
||||
"vfl-m3-anker-vorschau-header": "\n M3a ANKER-VORSCHAU (grob geschaetzt; exakte Werte beim Bau)",
|
||||
"vfl-m3-start-hoehe": "\n Start-Hoehe Z: %1 mm",
|
||||
@@ -350,7 +353,6 @@
|
||||
"vfe-gefaellebogen-links-mass": "\n Gefaellebogen links: dx=%1 dz=%2 mm",
|
||||
"vfe-gefaellebogen-rechts-mass": "\n Gefaellebogen rechts: dx=%1 dz=%2 mm",
|
||||
"vfe-gefaellebogen-seite-dx": "\n Gefaellebogen %1: dx=%2 mm",
|
||||
"vfe-hz-incl-status": "\n HzIncl %1 L=%2 hz=%3 v=%4 -> Z=%5",
|
||||
"vfe-hz-rot-status": "\n HzRot %1 hz=%2 v=%3 -> Z=%4",
|
||||
"vfe-hz-rotks-status": "\n HzRotKS %1 hz=%2 -> Z=%3",
|
||||
"vfe-hz-scaleks-status": "\n HzScaleKS %1 %2mm hz=%3 -> Z=%4",
|
||||
@@ -968,7 +970,7 @@
|
||||
"vfl-vwnb-typ-gerade": "\n Typ? 1 = GF (<=3 Grad) 2 = VF-Ab 3 = VF-Auf 4 = VF-Horizontal",
|
||||
"vfl-vwnb-prompt-vario-winkel": "\n Vario-Winkel (3..51 Grad) [3]: ",
|
||||
"vfl-vwnb-kurve-nur-vf": "\n >>> Vario-Kurve nur innerhalb eines VF-Laufs zulaessig - uebersprungen.",
|
||||
"vfl-vwnb-eingefuegt": "\n>>> VF-Linienzug (Modus 2, GF+VF) eingefuegt! <<<",
|
||||
"vfl-vwnb-eingefuegt": "\n>>> VF-Linienzug (Modus 3, GF+VF) eingefuegt! <<<",
|
||||
"vfl-vwnb-soll-ende": "\n Soll-Ende (Pfad): X=%1 Y=%2",
|
||||
"vfl-vwnb-ist-ende": "\n Ist-Ende (ES): X=%1 Y=%2 Z=%3",
|
||||
"vfl-vwnb-abweichung-xy": "\n Abweichung XY: dX=%1 dY=%2 mm",
|
||||
@@ -988,6 +990,20 @@
|
||||
"gr-alert-laenge": "Laenge ungueltig: '%1' mm. Erlaubt: %2 bis %3 mm.",
|
||||
"gr-prompt-einfuegepunkt": "\nEinfuegepunkt waehlen: ",
|
||||
"gr-abgebrochen": "\nAbgebrochen.",
|
||||
"gr-fertig": "\nGeruest-Baugruppe '%1' eingefuegt (Block %2)."
|
||||
"gr-fertig": "\nGeruest-Baugruppe '%1' eingefuegt (Block %2).",
|
||||
"gr-alert-menge": "Ungueltige Stueckzahl. Erlaubt ist eine ganze Zahl ab 1; ein leeres Feld uebernimmt den Vorgabewert.",
|
||||
"gr-position-oben": "oben",
|
||||
"gr-position-unten": "unten",
|
||||
"gr-konfig-keine": "<keine>",
|
||||
"gr-konfig-name": "\nName der Konfiguration: ",
|
||||
"gr-konfig-gespeichert": "\nKonfiguration '%1' gespeichert.",
|
||||
"gr-konfig-geloescht": "\nKonfiguration '%1' geloescht.",
|
||||
"gr-konfig-loeschen-frage": "\nKonfiguration '%1' wirklich loeschen? [Ja/Nein] <Nein>: ",
|
||||
"gr-konfig-nichts-gewaehlt": "\nKeine Konfiguration gewaehlt.",
|
||||
"gr-konfig-bibliothek-fest": "\nKonfigurationen der Bibliothek koennen nicht geloescht werden - nur eigene (mit * markiert).",
|
||||
"gr-konfig-teil-unbekannt": "\nGeruest: Anbauteil '%1' aus Konfiguration '%2' ist bei dieser Baugruppe unbekannt - uebersprungen.",
|
||||
"gr-konfig-variante-unbekannt": "\nGeruest: Variante '%1' aus Konfiguration '%2' ist bei dieser Baugruppe unbekannt - Auswahl unveraendert.",
|
||||
"gr-fehler-schreiben": "\nGeruest: Datei konnte nicht geschrieben werden: %1",
|
||||
"gr-fehler-keine-baugruppen": "\nGeruest: Die Datendatei enthaelt keine Baugruppen."
|
||||
}
|
||||
}
|
||||
|
||||
+19
-3
@@ -111,6 +111,7 @@
|
||||
"vfl-glied-vario": "Vario curve (horizontal curve in VF)",
|
||||
"vfl-glied-offen": "(open)",
|
||||
"vfl-edit-kein-journal": "This chain block carries no input journal (legacy) and cannot be edited step by step.",
|
||||
"vfl-edit-m2-obsolet": "This mode-2 block was built with the old object-reference journal and can no longer be rebuilt by double-click. Please recreate the chain with mode 2 (the new version stores the segment data directly on the block).",
|
||||
"vfl-edit-kette-header": "\n\nChain with %1 segment(s):",
|
||||
"vfl-edit-abgespielt": "\n>>> %1 segment(s) replayed, %2 undone - then continue interactively.",
|
||||
"vfl-edit2-reset-info": "\n>>> Rebuilding this Modus-2 chain identically from the saved inputs...",
|
||||
@@ -183,6 +184,8 @@
|
||||
"vfl-m3-vf-laeufe": "\n\n[M3a] VF runs found: %1",
|
||||
"vfl-m3-vf-lauf-noetig": "\n[M3a] Exactly ONE VF run required (GF...VF...GF; Vario curves may lie within the run).",
|
||||
"vfl-m3-vf-lauf-m3b": "\n[M3a] Several/no VF runs -> M3b later.",
|
||||
"vfl-m3-vf-lauf-alert": "VF line path mode 2 cannot build this chain.\n\nFound: %1 VarioFoerderer runs.\nMode 2 currently builds only chains with EXACTLY ONE VF run (GF...VF...GF; Vario curves may lie within the run).\n\nPlease split the path so that only one contiguous VF section remains.",
|
||||
"vfl-m3-mini-objekte-verworfen": "%1 object(s) too short were excluded from the selection (below %2 mm 2D length).\n\nSuch mini segments are usually ghost/artefact elements a window selection caught by accident - a real part (smallest: separator 300 mm) is never that short. They are ignored so they cannot introduce ghost parts into the chain.",
|
||||
"vfl-m3-vf-lauf-ohne-gerade": "\n[M3a] VF run without a VF straight - aborting.",
|
||||
"vfl-m3-anker-vorschau-header": "\n M3a ANCHOR PREVIEW (rough estimate; exact values during build)",
|
||||
"vfl-m3-start-hoehe": "\n Start height Z: %1 mm",
|
||||
@@ -350,7 +353,6 @@
|
||||
"vfe-gefaellebogen-links-mass": "\n Slope arc left: dx=%1 dz=%2 mm",
|
||||
"vfe-gefaellebogen-rechts-mass": "\n Slope arc right: dx=%1 dz=%2 mm",
|
||||
"vfe-gefaellebogen-seite-dx": "\n Slope arc %1: dx=%2 mm",
|
||||
"vfe-hz-incl-status": "\n HzIncl %1 L=%2 hz=%3 v=%4 -> Z=%5",
|
||||
"vfe-hz-rot-status": "\n HzRot %1 hz=%2 v=%3 -> Z=%4",
|
||||
"vfe-hz-rotks-status": "\n HzRotKS %1 hz=%2 -> Z=%3",
|
||||
"vfe-hz-scaleks-status": "\n HzScaleKS %1 %2mm hz=%3 -> Z=%4",
|
||||
@@ -968,7 +970,7 @@
|
||||
"vfl-vwnb-typ-gerade": "\n Type? 1 = GF (<=3 deg) 2 = VF-down 3 = VF-up 4 = VF-horizontal",
|
||||
"vfl-vwnb-prompt-vario-winkel": "\n Vario angle (3..51 deg) [3]: ",
|
||||
"vfl-vwnb-kurve-nur-vf": "\n >>> Vario curve only allowed within a VF run - skipped.",
|
||||
"vfl-vwnb-eingefuegt": "\n>>> VF line path (mode 2, GF+VF) inserted! <<<",
|
||||
"vfl-vwnb-eingefuegt": "\n>>> VF line path (mode 3, GF+VF) inserted! <<<",
|
||||
"vfl-vwnb-soll-ende": "\n Target end (path): X=%1 Y=%2",
|
||||
"vfl-vwnb-ist-ende": "\n Actual end (ES): X=%1 Y=%2 Z=%3",
|
||||
"vfl-vwnb-abweichung-xy": "\n Deviation XY: dX=%1 dY=%2 mm",
|
||||
@@ -988,6 +990,20 @@
|
||||
"gr-alert-laenge": "Invalid length: '%1' mm. Allowed: %2 to %3 mm.",
|
||||
"gr-prompt-einfuegepunkt": "\nSelect insertion point: ",
|
||||
"gr-abgebrochen": "\nCancelled.",
|
||||
"gr-fertig": "\nScaffold assembly '%1' inserted (block %2)."
|
||||
"gr-fertig": "\nScaffold assembly '%1' inserted (block %2).",
|
||||
"gr-alert-menge": "Invalid quantity. Enter a whole number of 1 or more; an empty field uses the default.",
|
||||
"gr-position-oben": "top",
|
||||
"gr-position-unten": "bottom",
|
||||
"gr-konfig-keine": "<none>",
|
||||
"gr-konfig-name": "\nConfiguration name: ",
|
||||
"gr-konfig-gespeichert": "\nConfiguration '%1' saved.",
|
||||
"gr-konfig-geloescht": "\nConfiguration '%1' deleted.",
|
||||
"gr-konfig-loeschen-frage": "\nReally delete configuration '%1'? [Ja/Nein] <Nein>: ",
|
||||
"gr-konfig-nichts-gewaehlt": "\nNo configuration selected.",
|
||||
"gr-konfig-bibliothek-fest": "\nLibrary configurations cannot be deleted - only your own (marked with *).",
|
||||
"gr-konfig-teil-unbekannt": "\nScaffold: add-on part '%1' from configuration '%2' is unknown for this assembly - skipped.",
|
||||
"gr-konfig-variante-unbekannt": "\nScaffold: variant '%1' from configuration '%2' is unknown for this assembly - selection unchanged.",
|
||||
"gr-fehler-schreiben": "\nScaffold: could not write file: %1",
|
||||
"gr-fehler-keine-baugruppen": "\nScaffold: the data file contains no assemblies."
|
||||
}
|
||||
}
|
||||
|
||||
@@ -886,6 +886,8 @@ def process_blocks(blocks, lookup, dbg=None):
|
||||
scanner_count = 0
|
||||
btmt_beladung_count = 0
|
||||
btmt_entladung_count = 0
|
||||
eingang_count = 0
|
||||
ausgang_count = 0
|
||||
geruest_count = 0
|
||||
|
||||
# Zaehlung fuer die Omniflo-Sum-Zeile (nur Bogen/Weiche/Gerade)
|
||||
@@ -1159,6 +1161,44 @@ def process_blocks(blocks, lookup, dbg=None):
|
||||
})
|
||||
continue
|
||||
|
||||
# Eingangssymbol (Materialfluss-Eingang der Anlage) - eigene
|
||||
# TeileArt-Zeile, analog zu BTMT. Wie BTMT von keinem Carrier-Attribut
|
||||
# mitgezaehlt; anders als BTMT NUR im CSV-Export (export_sivas.py
|
||||
# ueberspringt Eingang/Ausgang). Die TeileId kommt aus dem ID-Attribut
|
||||
# (ssg-id-check-all fuellt es vor jedem Export, ID-ATTDEF seit dem
|
||||
# allocations.json-Nachtrag) - dieselbe TeileId, die die
|
||||
# "TrackIds"-Spalte an Kreisel/Strecke referenziert (KREISEL_UMLAUF_
|
||||
# TEILEARTEN in export_neighbors.py). Fallback-Nummer wie bei BTMT.
|
||||
if matches_any(bname, BLOCKPATTERNS.get("pattern_eingang", [])):
|
||||
elem_nr += 1
|
||||
eingang_count += 1
|
||||
items.append({
|
||||
"nr": elem_nr,
|
||||
"teileart": "Eingang",
|
||||
"teileid": block.get("attribs", {}).get("ID") or format_sensor_id("EIN", eingang_count),
|
||||
"bezeichnung": f"Eingang :{eingang_count}",
|
||||
"planquadrat": planquadrat_column(block, planquadrat_cfg),
|
||||
"merkmale": build_btmt_merkmale(block),
|
||||
**bbox_columns(block),
|
||||
})
|
||||
continue
|
||||
|
||||
# Ausgangssymbol (Materialfluss-Ausgang der Anlage) - analog zum
|
||||
# Eingangssymbol oben.
|
||||
if matches_any(bname, BLOCKPATTERNS.get("pattern_ausgang", [])):
|
||||
elem_nr += 1
|
||||
ausgang_count += 1
|
||||
items.append({
|
||||
"nr": elem_nr,
|
||||
"teileart": "Ausgang",
|
||||
"teileid": block.get("attribs", {}).get("ID") or format_sensor_id("AUS", ausgang_count),
|
||||
"bezeichnung": f"Ausgang :{ausgang_count}",
|
||||
"planquadrat": planquadrat_column(block, planquadrat_cfg),
|
||||
"merkmale": build_btmt_merkmale(block),
|
||||
**bbox_columns(block),
|
||||
})
|
||||
continue
|
||||
|
||||
# Geruest-Baugruppe (GR_<id>_<timestamp>) - eigene TeileArt-Zeile,
|
||||
# analog zu BTMT: kein ANZAHL_*-Attribut an einem Carrier zaehlt sie
|
||||
# mit. TeileId ist das echte ID-Attribut (ssg-id-check-all fuellt es
|
||||
|
||||
+60
-15
@@ -84,8 +84,15 @@ SENSOR_TEILEARTEN = {"ILS 2.0 Separator", "ILS 2.0 Scanner"}
|
||||
# Sensoren - eigene Konstante statt Erweiterung von SENSOR_TEILEARTEN, damit
|
||||
# deren Sensor-spezifische Weiterverarbeitung (z.B. compute_scanner_nearest_
|
||||
# separator) unberuehrt bleibt.
|
||||
# Eingang/Ausgang (Materialfluss-Ein-/Ausgangssymbole, siehe pattern_eingang/
|
||||
# pattern_ausgang in cfg/export.cfg) werden hier wie BTMT als frei platzierte
|
||||
# Umlauf-Punkte gefuehrt - so tauchen sie, wenn sie auf einer Kreiselbahn
|
||||
# liegen, in dessen "TrackIds"-Spalte auf (Nutzeranforderung: wie
|
||||
# Separator/AS/ES behandeln). Die TeileArt-Strings sind bewusst OHNE "ILS 2.0"-
|
||||
# Praefix (siehe export_csv.py) - dieselben Strings muessen hier stehen.
|
||||
KREISEL_UMLAUF_TEILEARTEN = {
|
||||
"ILS 2.0 Separator", "ILS 2.0 BTMT Beladung", "ILS 2.0 BTMT Entladung", "ILS Weiche",
|
||||
"Eingang", "Ausgang",
|
||||
}
|
||||
|
||||
# Nur "ILS 2.0 Kreisel" (echte Kreisel-Bloecke mit AN8/Antrieb + SP8/Spann-
|
||||
@@ -1514,26 +1521,64 @@ def compute_kreisel_umlauf(items, sep_kette, tolerance_mm, durchmesser_mm=800.0,
|
||||
acx = (cap["a"][0] + cap["b"][0]) / 2.0
|
||||
acy = (cap["a"][1] + cap["b"][1]) / 2.0
|
||||
achs_winkel = math.atan2(cap["b"][1] - cap["a"][1], cap["b"][0] - cap["a"][0])
|
||||
cos_achs, sin_achs = math.cos(achs_winkel), math.sin(achs_winkel)
|
||||
# Halbe Achslaenge (Mitte -> a bzw. b) und Radius der Kapsel = die
|
||||
# beiden Halbachsen der Kreisel-BB im lokalen (gedrehten) Koordinaten-
|
||||
# system - siehe kreisel_bounds oben, dieselbe "maximale Ausdehnung".
|
||||
halblaenge = math.hypot(cap["b"][0] - cap["a"][0], cap["b"][1] - cap["a"][1]) / 2.0
|
||||
radius = cap["r"]
|
||||
|
||||
uzs = (drehrichtung or "UZS").strip().upper() != "GUZ"
|
||||
|
||||
def _winkel(pxy):
|
||||
# Rohwinkel relativ zur Achsrichtung, auf [0, 2*pi) normiert IN
|
||||
# UMLAUFRICHTUNG. Vorher (reine Vorgaenger-/Nachfolger-Ermittlung
|
||||
# ohne Startpunkt-Anspruch) wurde UZS durch reverse=True auf dem
|
||||
# rohen mathematischen Winkel erreicht (= "absteigend sortieren");
|
||||
# absteigend sortieren auf theta ist aequivalent zu aufsteigend
|
||||
# sortieren auf -theta - darum wird HIER fuer UZS negiert (NICHT
|
||||
# fuer GUZ, das dem unveraenderten mathematischen Winkel bereits
|
||||
# aufsteigend entspricht). Ohne dieses Vorzeichen liefe der UZS-
|
||||
# Umlauf in die falsche (zu GUZ spiegelverkehrte) Richtung - siehe
|
||||
# Abfolge ueber die BB des Kreisels statt ueber einen Winkel um den
|
||||
# Mittelpunkt: Punkt zuerst ins lokale (um achs_winkel gedrehte)
|
||||
# Koordinatensystem der Kreiselachse bringen (lx = Achsrichtung,
|
||||
# ly = quer dazu), dann auf die BB-Halbachsen normieren
|
||||
# (u = lx/halblaenge, v = ly/radius). Je nachdem, welche der beiden
|
||||
# Groessen (u oder v) betragsmaessig ueberwiegt, liegt der Punkt auf
|
||||
# der rechten/linken Stirnseite (u dominiert) oder der oberen/
|
||||
# unteren Langseite (v dominiert) der BB - dort bestimmt NUR die
|
||||
# jeweils andere (die entlang der Seite laufende) Koordinate die
|
||||
# Position, der ueberwiegende Anteil legt nur noch die Seite fest.
|
||||
# Ein grosser, asymmetrischer Block (z.B. BTMT-Beladung/-Entladung)
|
||||
# hat einen Bbox-Mittelpunkt, der deutlich weiter quer zur Achse
|
||||
# absteht als der Belt-Radius - beim reinen Winkel-um-Mittelpunkt
|
||||
# (frueherer Ansatz) blies das seinen Winkel unverhaeltnismaessig
|
||||
# auf und liess ihn mehrere eng benachbarte Punkte in der engen
|
||||
# Sortierung ueberholen, obwohl er entlang der Achse klar der
|
||||
# letzte ist (realer Bug-Fall: HundM05, BTMT-Entladung "0023").
|
||||
# Hier wirkt sich dieselbe Ueberhoehung nicht mehr aus, solange sie
|
||||
# nicht die Seiten-Zuordnung selbst umkippt.
|
||||
#
|
||||
# t liegt in [0,4) und laeuft GEGEN den Uhrzeigersinn (mathematische
|
||||
# Standardrichtung) einmal um die BB, beginnend bei t=0 auf der
|
||||
# rechten Stirnseite in Achsrichtung (lx=halblaenge, ly=0) - das
|
||||
# ist derselbe Nullpunkt wie beim frueheren "0 Grad = Achsrichtung".
|
||||
# 0..1 rechte Stirnseite (ly steigend), 1..2 obere Langseite (lx
|
||||
# fallend), 2..3 linke Stirnseite (ly fallend), 3..4 untere
|
||||
# Langseite (lx steigend).
|
||||
dx0 = pxy[1] - acx
|
||||
dy0 = pxy[2] - acy
|
||||
lx = dx0 * cos_achs + dy0 * sin_achs
|
||||
ly = -dx0 * sin_achs + dy0 * cos_achs
|
||||
u = lx / halblaenge if halblaenge > 1e-9 else 0.0
|
||||
v = ly / radius if radius > 1e-9 else 0.0
|
||||
if u >= abs(v):
|
||||
t = v / 2.0
|
||||
elif v >= abs(u):
|
||||
t = 1.0 - u / 2.0
|
||||
elif u <= -abs(v):
|
||||
t = 2.0 - v / 2.0
|
||||
else:
|
||||
t = 3.0 + u / 2.0
|
||||
|
||||
# UZS (Uhrzeigersinn, Default) negiert t (= absteigend sortieren
|
||||
# auf t ist aequivalent zu aufsteigend auf -t) - identisches Muster
|
||||
# wie beim vorherigen Winkel-Ansatz, siehe
|
||||
# tests/test_export_kreisel_umlauf.py::TestKreiselUmlaufStartetBeiNullGrad.
|
||||
# Die Normierung auf [0, 2*pi) sorgt zusaetzlich dafuer, dass
|
||||
# Index 0 nach dem Sortieren der kleinste Winkel >= 0 Grad ist
|
||||
# (der gewuenschte Start bei 0 Grad).
|
||||
roh = math.atan2(pxy[2] - acy, pxy[1] - acx) - achs_winkel
|
||||
roh = -roh if uzs else roh
|
||||
return roh % (2.0 * math.pi)
|
||||
t = -t if uzs else t
|
||||
return t % 4.0
|
||||
|
||||
sortiert = sorted(punkte, key=lambda p: _winkel(p))
|
||||
n = len(sortiert)
|
||||
|
||||
@@ -504,6 +504,16 @@ def process_blocks(blocks, lookup):
|
||||
counters["anzahl_abwurfstationen"] += 1
|
||||
continue
|
||||
|
||||
# --- Eingangs-/Ausgangssymbol (Materialfluss-Ein-/Ausgang) ---
|
||||
# Bewusst NUR im CSV-Export als eigene Zeile (siehe export_csv.py) -
|
||||
# hier ohne Sivas-Zeile und ohne eigenen Zaehler ueberspringen. Ein
|
||||
# Eingangs-/Ausgangssymbol ist eine reine Fluss-Markierung ohne Sivas-
|
||||
# Artikel; ein eigener Sivas-Eintrag wuerde die Stueckliste verfaelschen
|
||||
# (Nutzeranforderung: Eingang/Ausgang nur im CSV-Export).
|
||||
if matches_any(bname, BLOCKPATTERNS.get("pattern_eingang", [])) or \
|
||||
matches_any(bname, BLOCKPATTERNS.get("pattern_ausgang", [])):
|
||||
continue
|
||||
|
||||
# --- Geruest-Baugruppe ---
|
||||
# Anders als BTMT/Separator je Block eine EIGENE Zeile statt gruppiert:
|
||||
# ARTINR (Sivas-IDs) und Laenge/Farbe koennen von Block zu Block
|
||||
|
||||
+1
-6
@@ -110,12 +110,7 @@
|
||||
[~APBW 110 R550/67,5 208x347]^C^C(ssg-ensure "OmniModulInsert") OMNI_APBW_R550_675_208
|
||||
[<-~APBW 110 R550/67,5 58x497]^C^C(ssg-ensure "OmniModulInsert") OMNI_APBW_R550_675_58
|
||||
[<-Element bearbeiten]^C^C(ssg-ensure "OmniModulInsert") OMNI_EDIT
|
||||
[->Geruest]
|
||||
[Rohrabhaenger]^C^C(ssg-ensure "GeruestInsert") GERUEST_ROHRABHAENGER
|
||||
[->Saeulen]
|
||||
[2 Zoll Saeulen]^C^C(ssg-ensure "GeruestInsert") GERUEST_SAEULE_2ZOLL
|
||||
[<-1 Zoll Saeulen]^C^C(ssg-ensure "GeruestInsert") GERUEST_SAEULE_1ZOLL
|
||||
[<-Wandbefestigung]^C^C(ssg-ensure "GeruestInsert") GERUEST_WANDBEFESTIGUNG
|
||||
[Geruest...]^C^C(ssg-ensure "GeruestInsert") GERUEST
|
||||
[->SPS]
|
||||
[->TRO]
|
||||
[Marker einfuegen]^C^C(ssg-ensure "Tro_Edit") TRO_INSERT
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
test_export_eingang_ausgang.py - Eingangs-/Ausgangssymbole im Export.
|
||||
Laeuft komplett ohne BricsCAD (reine Python-Logik).
|
||||
|
||||
Kundenwunsch: die Materialfluss-Ein-/Ausgangssymbole (Bloecke
|
||||
Eingang_<DIM>/Ausgang_<DIM>, eingefuegt ueber ils-insert-station) sollen
|
||||
- NUR im CSV-Export - als eigene Zeile erscheinen, inhaltlich aehnlich den
|
||||
BTMT Be-/Entladestationen, und
|
||||
- wie Separator/AS/ES in die "TrackIds" eingebaut werden (auch auf Kreiseln,
|
||||
siehe test_export_kreisel_umlauf.py).
|
||||
Im Sivas-Export duerfen sie NICHT auftauchen.
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "lib"))
|
||||
|
||||
import export_csv # noqa: E402
|
||||
import export_sivas # noqa: E402
|
||||
|
||||
|
||||
def _block(block_name, teileid, artinr="12345", x=0.0, y=0.0):
|
||||
return {
|
||||
"block_name": block_name,
|
||||
"x": x, "y": y, "z": 0.0,
|
||||
"rotation": 0.0,
|
||||
"attribs": {"ID": teileid, "ARTINR": artinr, "LAYER": "ILS_Flow",
|
||||
"ZUORDNUNG": ""},
|
||||
"_bbox": {"cx": x, "cy": y, "cz": 0.0, "dx": 200.0, "dy": 150.0},
|
||||
}
|
||||
|
||||
|
||||
class TestCsvKlassifikation:
|
||||
"""export_csv.process_blocks gibt Eingang/Ausgang je eine eigene
|
||||
TeileArt-Zeile ("Eingang"/"Ausgang") mit der Block-ID als TeileId."""
|
||||
|
||||
def test_eingang_und_ausgang_bekommen_eigene_zeile(self):
|
||||
blocks = [
|
||||
_block("Eingang_2D", "0050", x=0.0),
|
||||
_block("Ausgang_3D", "0051", x=1000.0),
|
||||
]
|
||||
items = export_csv.process_blocks(blocks, lookup={})
|
||||
nach_art = {it["teileart"]: it for it in items}
|
||||
|
||||
assert "Eingang" in nach_art, "Eingang-Zeile fehlt im CSV-Export"
|
||||
assert "Ausgang" in nach_art, "Ausgang-Zeile fehlt im CSV-Export"
|
||||
|
||||
ein = nach_art["Eingang"]
|
||||
aus = nach_art["Ausgang"]
|
||||
# TeileId kommt aus dem ID-Attribut (stabil ueber Exportlaeufe).
|
||||
assert ein["teileid"] == "0050"
|
||||
assert aus["teileid"] == "0051"
|
||||
# Merkmale wie BTMT: ARTINR als Merkmal gefuehrt.
|
||||
assert ein["merkmale"].get("ARTINR") == "12345"
|
||||
|
||||
def test_teileid_fallback_ohne_id_attribut(self):
|
||||
"""Ohne (noch) gefuelltes ID-Attribut greift der Fallback (EIN-/AUS-
|
||||
Praefix), damit die Zeile trotzdem eine TeileId traegt - wie bei BTMT."""
|
||||
blocks = [
|
||||
{"block_name": "Eingang_2D", "x": 0.0, "y": 0.0, "z": 0.0,
|
||||
"rotation": 0.0, "attribs": {},
|
||||
"_bbox": {"cx": 0.0, "cy": 0.0, "cz": 0.0, "dx": 200.0, "dy": 150.0}},
|
||||
]
|
||||
items = export_csv.process_blocks(blocks, lookup={})
|
||||
ein = next(it for it in items if it["teileart"] == "Eingang")
|
||||
assert ein["teileid"].startswith("EIN-")
|
||||
|
||||
|
||||
class TestSivasSchliesstAus:
|
||||
"""export_sivas.process_blocks fuehrt Eingang/Ausgang bewusst NICHT als
|
||||
eigene Zeile und zaehlt sie in keinem Summenzaehler mit."""
|
||||
|
||||
def test_keine_sivas_zeile_und_kein_zaehler(self):
|
||||
blocks = [
|
||||
_block("Eingang_2D", "0050"),
|
||||
_block("Ausgang_3D", "0051"),
|
||||
]
|
||||
items, counters = export_sivas.process_blocks(blocks, lookup={})
|
||||
|
||||
arten = {it.get("teileart", "") for it in items}
|
||||
assert "Eingang" not in arten
|
||||
assert "Ausgang" not in arten
|
||||
# Kein bestehender Zaehler darf durch die zwei Symbole hochgezaehlt
|
||||
# worden sein (alle Zaehler bleiben 0, da nur Eingang/Ausgang im Satz).
|
||||
assert all(v == 0 for v in counters.values()), (
|
||||
f"Eingang/Ausgang haben einen Sivas-Zaehler beeinflusst: "
|
||||
f"{{k: v for k, v in counters.items() if v}}")
|
||||
@@ -64,6 +64,17 @@ def _btmt(teileart, teileid, x, y):
|
||||
}
|
||||
|
||||
|
||||
def _flusssymbol(teileart, teileid, x, y):
|
||||
"""Eingangs-/Ausgangssymbol ("Eingang"/"Ausgang") - frei auf der Bahn
|
||||
platziert wie ein Separator/BTMT, siehe KREISEL_UMLAUF_TEILEARTEN. Die
|
||||
TeileArt-Strings sind bewusst OHNE "ILS 2.0"-Praefix (siehe export_csv.py)."""
|
||||
return {
|
||||
"teileart": teileart,
|
||||
"teileid": teileid,
|
||||
"_bbox": {"cx": x, "cy": y, "cz": 0.0, "dx": 200.0, "dy": 150.0},
|
||||
}
|
||||
|
||||
|
||||
def _zwei_beruehrende_kreisel():
|
||||
"""Zwei Kreisel, deren AN8-Enden sich exakt beruehren (End-an-End, wie im
|
||||
Mubea-Fall: 'Kreis/Kreis'-Beruehrung an der jeweiligen AN8-Kappe).
|
||||
@@ -422,3 +433,25 @@ class TestKreiselTrackidsSpalte:
|
||||
write_kreisel_separatorliste_merkmale(
|
||||
items, kreisel_umlauf, sep_kette_by_key={}, weiche_by_key={})
|
||||
assert k["trackids"] == "0031, 0020, 0030"
|
||||
|
||||
def test_eingang_und_ausgang_zaehlen_als_freie_punkte(self):
|
||||
"""Eingangs-/Ausgangssymbole ("Eingang"/"Ausgang") sind Fluss-
|
||||
Markierungen AUF der Bahn wie ein Separator/BTMT - sie muessen (auf
|
||||
Kundenwunsch) im Kreisel-Umlauf UND in der TrackIds-Spalte des
|
||||
Kreisels auftauchen, genau wie Separator/AS/ES."""
|
||||
k = _kreisel("0001", 0.0, 0.0, 0.0, abstand=1000.0)
|
||||
k["merkmale"] = {}
|
||||
sep = _separator("0020", 300.0, 300.0)
|
||||
ein = _flusssymbol("Eingang", "0040", 900.0, 400.0)
|
||||
aus = _flusssymbol("Ausgang", "0041", 1400.0, -50.0)
|
||||
items = [k, sep, ein, aus]
|
||||
|
||||
kreisel_umlauf = compute_kreisel_umlauf(
|
||||
items, sep_kette={}, tolerance_mm=200.0, durchmesser_mm=DURCHMESSER_MM)
|
||||
keys = [p[0] for p in kreisel_umlauf["0001"]]
|
||||
assert set(keys) == {"0020", "0040", "0041"}, (
|
||||
f"Eingang/Ausgang fehlen im Kreisel-Umlauf: {keys}")
|
||||
|
||||
write_kreisel_separatorliste_merkmale(
|
||||
items, kreisel_umlauf, sep_kette_by_key={}, weiche_by_key={})
|
||||
assert k["trackids"] == "0041, 0020, 0040"
|
||||
|
||||
+41
-9
@@ -135,7 +135,7 @@
|
||||
;; jeder ueber ssg-ils-block-laden aufloesbare Blockname funktioniert. "sensor"
|
||||
;; bleibt als Sammelbegriff fuer den "kind"-Wert (= "kein Kreisel"), auch wenn
|
||||
;; inzwischen nicht mehr nur Separator/Scanner darueberlaufen.
|
||||
(defun hundm05:bau-sensor (obj / id blockname x y z rotation pt eff n ent ed rec)
|
||||
(defun hundm05:bau-sensor (obj / id blockname x y z rotation pt eff n vorher ent ed attribs rec)
|
||||
(setq id (ssg-val obj "id"))
|
||||
(setq blockname (ssg-val obj "block"))
|
||||
(setq x (ssg-val obj "x")
|
||||
@@ -172,6 +172,7 @@
|
||||
(princ (strcat "\n [SENSOR] " id " '" blockname "' -> ("
|
||||
(rtos x 2 0) ", " (rtos y 2 0) ", " (rtos z 2 0)
|
||||
") R=" (rtos rotation 2 1)))
|
||||
(setq vorher (entlast))
|
||||
(command "_.INSERT" eff pt "" "" rotation)
|
||||
;; Verbleibende Prompts mit Enter abfangen, aber GEZAEHLT - siehe
|
||||
;; mubea:build-separator-one (ein Prompt, der Leer-Antworten
|
||||
@@ -186,14 +187,45 @@
|
||||
(princ (strcat "\n WARNUNG: INSERT von '" eff
|
||||
"' nicht sauber beendet - abgebrochen."))))
|
||||
(setq ent (entlast))
|
||||
(if (atoms-family 1 '("ssg-id-generate")) (ssg-id-generate ent))
|
||||
(setq ed (entget ent))
|
||||
(princ (strcat " -> Block " (cdr (assoc 2 ed))))
|
||||
(setq rec (vsp-set rec "block_name" (cdr (assoc 2 ed))))
|
||||
(setq rec (vsp-set rec "block_handle" (cdr (assoc 5 ed))))
|
||||
(setq rec (vsp-set rec "insert_point" (cdr (assoc 10 ed))))
|
||||
(setq rec (vsp-set rec "attribs" (ssg-attrib-read ent)))
|
||||
(vsp-set rec "status" "executed"))))))
|
||||
;; Nicht blind (entlast) vertrauen: eine verschluckte Rueckfrage beim
|
||||
;; Laden ODER Platzieren (siehe ssg-ils-block-laden-dim) kann eine
|
||||
;; unvollstaendige/falsche Blockreferenz ohne jedes Attribut hinterlassen
|
||||
;; (realer Fall: HundM05, letztes Zusatzobjekt = SC_Entladung, erste
|
||||
;; Verwendung dieses Blocknamens im Testlauf). Nur eine ECHT NEUE
|
||||
;; INSERT-Referenz gilt als Erfolg; alles andere wird als Fehler
|
||||
;; gemeldet und die kaputte Restgeometrie sofort entfernt statt sie
|
||||
;; unbemerkt in der Zeichnung zu belassen.
|
||||
(cond
|
||||
((or (null ent) (eq ent vorher)
|
||||
(/= (cdr (assoc 0 (entget ent))) "INSERT"))
|
||||
(princ (strcat "\n [SENSOR] " id " '" blockname
|
||||
"' - FEHLER: INSERT hat keine gueltige neue Blockreferenz"
|
||||
" erzeugt (verschluckte Rueckfrage?)."))
|
||||
(if (and ent (not (eq ent vorher))) (entdel ent))
|
||||
(setq rec (vsp-set (vsp-set rec "status" "abbruch") "fehler_text"
|
||||
"INSERT lieferte keine gueltige neue Blockreferenz")))
|
||||
(T
|
||||
(setq attribs (ssg-attrib-read ent))
|
||||
(setq ed (entget ent))
|
||||
(princ (strcat " -> Block " (cdr (assoc 2 ed))))
|
||||
(setq rec (vsp-set rec "block_name" (cdr (assoc 2 ed))))
|
||||
(setq rec (vsp-set rec "block_handle" (cdr (assoc 5 ed))))
|
||||
(setq rec (vsp-set rec "insert_point" (cdr (assoc 10 ed))))
|
||||
(setq rec (vsp-set rec "attribs" attribs))
|
||||
;; ID nur vergeben, wenn der Block ueberhaupt ein ID-Attribut fuehrt
|
||||
;; (siehe ssg-id-set-and-verify in ssg_id.lsp) - sonst faellt hier
|
||||
;; dieselbe "unsichtbare" Luecke auf, statt sie in der ID-Vergabe zu
|
||||
;; verstecken.
|
||||
(cond
|
||||
((not (assoc "ID" attribs))
|
||||
(princ (strcat "\n [SENSOR] " id " '" blockname
|
||||
"' - WARNUNG: Block hat kein ID-Attribut (ATTDEF"
|
||||
" fehlt/veraltet, ATTSYNC noetig) - keine ID vergeben."))
|
||||
(setq rec (vsp-set (vsp-set rec "status" "warnung") "fehler_text"
|
||||
"Block ohne ID-ATTDEF - ATTSYNC noetig")))
|
||||
(T
|
||||
(if (atoms-family 1 '("ssg-id-generate")) (ssg-id-generate ent))
|
||||
(vsp-set rec "status" "executed"))))))))))
|
||||
|
||||
;; Alle Zusatzobjekte der Datei bauen. Eigener ssg-start-Rahmen, weil
|
||||
;; vsp-bau-datei seinen schon geschlossen hat; ATTREQ/ATTDIA 0 ist Pflicht -
|
||||
|
||||
+419
-25
@@ -19,6 +19,20 @@
|
||||
;; Ergebnis:
|
||||
;; Konsole: PASS/FAIL je Test + Zusammenfassung
|
||||
;; Datei: tests/output/unit_results.txt (von run_tests.bat gelesen)
|
||||
;;
|
||||
;; Ladearchitektur (EINHEITLICH):
|
||||
;; Das Laden der zu testenden Module passiert AUSSCHLIESSLICH auf .scr-
|
||||
;; Top-Level in tests/test_unit.scr - die Core-Module ueber ssg_load.lsp,
|
||||
;; die lazy Feature-Module (GeruestInsert, count_sep_scan) per explizitem
|
||||
;; load. Die Testbloecke hier laden NICHTS nach; sie pruefen nur per
|
||||
;; atoms-family, ob ihr Modul vorhanden ist, und ueberspringen sich sonst
|
||||
;; mit einer FAIL-Meldung.
|
||||
;; Grund: In BricsCAD werden per load definierte Funktionen erst nach
|
||||
;; Rueckkehr zum Top-Level sichtbar. Ein load INNERHALB von c:TEST_UNIT
|
||||
;; oder eines per vl-catch-all-apply gecatchten Testblocks bindet die
|
||||
;; frisch definierten Funktionen im laufenden Durchlauf NICHT (beobachtet:
|
||||
;; geruest-id-string/cs-in-box blieben ungebunden). Darum gehoert alles
|
||||
;; Laden vor den (c:TEST_UNIT)-Aufruf ins .scr.
|
||||
;; ============================================================
|
||||
|
||||
|
||||
@@ -300,11 +314,13 @@
|
||||
(tu-eq "csv:b64-encode-ints/0" "AAAA" (csv:b64-encode-ints '(0)))
|
||||
(tu-eq "csv:trans-encode/0-0-0" "AAAAAAAAAAAA" (csv:trans-encode 0.0 0.0 0.0))
|
||||
|
||||
;; local-to-world: reine Z-Drehung um den Elternpunkt
|
||||
;; local-to-world: Eltern-Orientierung als 3x3-Rotationsmatrix (mat3-rz
|
||||
;; liefert die Z-Drehmatrix aus dem Winkel - Signatur seit dem
|
||||
;; Extrusions-Fix in export.lsp: parent-R statt parent-rot-rad).
|
||||
(tu-eqf "csv:local-to-world/keine-drehung"
|
||||
'(1.0 0.0 0.0) (csv:local-to-world '(0.0 0.0 0.0) 0.0 '(1.0 0.0 0.0)))
|
||||
'(1.0 0.0 0.0) (csv:local-to-world '(0.0 0.0 0.0) (mat3-rz 0.0) '(1.0 0.0 0.0)))
|
||||
(tu-eqf "csv:local-to-world/90-grad"
|
||||
'(0.0 1.0 0.0) (csv:local-to-world '(0.0 0.0 0.0) (/ pi 2.0) '(1.0 0.0 0.0)))
|
||||
'(0.0 1.0 0.0) (csv:local-to-world '(0.0 0.0 0.0) (mat3-rz (/ pi 2.0)) '(1.0 0.0 0.0)))
|
||||
|
||||
;; json-escape: Anfuehrungszeichen maskieren
|
||||
(tu-eq "csv:json-escape/quote" "a\\\"b" (csv:json-escape "a\"b"))
|
||||
@@ -401,6 +417,17 @@
|
||||
(tu-eq "ssg-sepliste-split-feld/normal" '("SEP" "1" "10.00" "20.00")
|
||||
(ssg-sepliste-split-feld "SEP:1:10.00:20.00" ":"))
|
||||
|
||||
;; ssg-sepliste-fmt-koord: GENAU 2 Nachkommastellen, DIMZIN-unabhaengig.
|
||||
;; Ersetzt rtos (das bei DIMZIN=8 abschliessende Nullen verschluckt und die
|
||||
;; XDATA-Serialisierung zeichnungsprofilabhaengig gemacht hat).
|
||||
(tu-eq "sepliste-fmt/ganz" "10.00" (ssg-sepliste-fmt-koord 10.0))
|
||||
(tu-eq "sepliste-fmt/eine-stelle" "30.50" (ssg-sepliste-fmt-koord 30.5))
|
||||
(tu-eq "sepliste-fmt/rundung-ab" "5.01" (ssg-sepliste-fmt-koord 5.007))
|
||||
(tu-eq "sepliste-fmt/uebertrag" "10.00" (ssg-sepliste-fmt-koord 9.999))
|
||||
(tu-eq "sepliste-fmt/negativ" "-5.00" (ssg-sepliste-fmt-koord -5.0))
|
||||
(tu-eq "sepliste-fmt/negativ-rund" "-5.01" (ssg-sepliste-fmt-koord -5.007))
|
||||
(tu-eq "sepliste-fmt/null" "0.00" (ssg-sepliste-fmt-koord 0.0))
|
||||
|
||||
;; ssg-sepliste->string: Serialisierung eines Eintrags
|
||||
(tu-eq "ssg-sepliste->string/ein-eintrag"
|
||||
"SEP:1:10.00:20.00"
|
||||
@@ -471,12 +498,27 @@
|
||||
(tu-eq "json/escape-newline" (chr 10)
|
||||
(ssg-json-get (ssg-json-parse "{\"a\": \"\\n\"}") "a"))
|
||||
|
||||
;; ssg-json-escape: Gegenstueck zum Parser
|
||||
(tu-eq "json-escape/quote" "a\\\"b" (ssg-json-escape "a\"b"))
|
||||
(tu-eq "json-escape/backslash" "a\\\\b" (ssg-json-escape "a\\b"))
|
||||
(tu-eq "json-escape/newline" "a\\nb" (ssg-json-escape (strcat "a" (chr 10) "b")))
|
||||
(tu-eq "json-escape/leer" "" (ssg-json-escape nil))
|
||||
;; Rundlauf: maskieren -> parsen ergibt den Originaltext zurueck
|
||||
(tu-eq "json-escape/rundlauf" "ROHRKLAMMER 1\" KPL. VERTIKAL"
|
||||
(ssg-json-get
|
||||
(ssg-json-parse
|
||||
(strcat "{\"a\": \""
|
||||
(ssg-json-escape "ROHRKLAMMER 1\" KPL. VERTIKAL") "\"}"))
|
||||
"a"))
|
||||
|
||||
;; Echte Datendatei: der eigentliche Praxisfall
|
||||
(setq _datei (strcat (getenv "DXFMAKRO") "/data/json/geruest.json"))
|
||||
(if (findfile _datei)
|
||||
(progn
|
||||
(setq _daten (ssg-json-laden _datei))
|
||||
(tu-eq "json/geruest-baugruppen" 4 (length _daten))
|
||||
;; Drei Bereiche: Rohrabhaenger, Saeulen (1 und 2 Zoll zusammengefuehrt),
|
||||
;; Wandbefestigung
|
||||
(tu-eq "json/geruest-baugruppen" 3 (length _daten))
|
||||
;; Baugruppe ueber das ASCII-Feld "id" finden (aeusserer Schluessel
|
||||
;; traegt Umlaute bzw. Anfuehrungszeichen)
|
||||
(setq _bg nil)
|
||||
@@ -509,20 +551,15 @@
|
||||
;; ------------------------------------------------------------
|
||||
;; TESTS: GeruestInsert.lsp - reine Hilfsfunktionen
|
||||
;; ------------------------------------------------------------
|
||||
(defun tu-tests-geruest ( / _eintrag _gruppe)
|
||||
(defun tu-tests-geruest ( / _eintrag _gruppe _teile _konfig _rec _pfad _f
|
||||
_zurueck _bgtest _saeulen)
|
||||
(princ "\n[GeruestInsert]")
|
||||
(if (and (null (atoms-family 1 '("GERUEST-ARTIKELNUMMERN")))
|
||||
(atoms-family 1 '("SSG-ENSURE")))
|
||||
(ssg-ensure "GeruestInsert")
|
||||
)
|
||||
;; GeruestInsert ist ein lazy Feature-Modul (nicht in der Core-Ladeliste).
|
||||
;; Geladen wird es zentral in test_unit.scr auf .scr-Top-Level; hier nur
|
||||
;; pruefen, ob es da ist (siehe Kopfkommentar zur Ladearchitektur).
|
||||
(if (null (atoms-family 1 '("GERUEST-ARTIKELNUMMERN")))
|
||||
(tu-record nil "geruest/modul" "GeruestInsert.lsp nicht geladen")
|
||||
(progn
|
||||
;; Indizes aus get_tile bei multiple_select
|
||||
(tu-eq "geruest-indizes/leer" '() (geruest-indizes ""))
|
||||
(tu-eq "geruest-indizes/eins" '(0) (geruest-indizes "0"))
|
||||
(tu-eq "geruest-indizes/drei" '(0 3 5) (geruest-indizes "0 3 5"))
|
||||
|
||||
(tu-eq "geruest-id-string/int" "821006026" (geruest-id-string 821006026))
|
||||
(tu-eq "geruest-id-string/str" "0_B10071" (geruest-id-string "0_B10071"))
|
||||
(tu-eq "geruest-id-string/nil" nil (geruest-id-string nil))
|
||||
@@ -547,6 +584,247 @@
|
||||
(tu-eq "geruest-artnr/ohne-menge" '("333")
|
||||
(geruest-artikelnummern
|
||||
(ssg-json-parse "{\"artikel\": \"C\", \"sivas_id\": 333}")))
|
||||
|
||||
;; --- Mengenfeld ---
|
||||
(tu-eq "geruest-zahl-p/ziffern" T (geruest-zahl-p "12"))
|
||||
(tu-eq "geruest-zahl-p/text" nil (geruest-zahl-p "1a"))
|
||||
(tu-eq "geruest-zahl-p/leer" nil (geruest-zahl-p ""))
|
||||
;; Leeres Feld uebernimmt die JSON-Vorgabe, ungueltiges liefert nil
|
||||
(tu-eq "geruest-menge-wert/leer" 2 (geruest-menge-wert "" 2))
|
||||
(tu-eq "geruest-menge-wert/zahl" 5 (geruest-menge-wert "5" 2))
|
||||
(tu-eq "geruest-menge-wert/null" nil (geruest-menge-wert "0" 2))
|
||||
(tu-eq "geruest-menge-wert/text" nil (geruest-menge-wert "abc" 2))
|
||||
(tu-eq "geruest-menge-wert/negativ" nil (geruest-menge-wert "-3" 2))
|
||||
|
||||
;; --- Stueckzahl ersetzt die JSON-Menge (Einzelteil) ---
|
||||
(tu-eq "geruest-artnr-n/einzelteil" '("825002019" "825002019" "825002019")
|
||||
(geruest-artikelnummern-n _eintrag 3))
|
||||
;; --- Gruppe: ganzes Set n-mal, Mengen INNERHALB bleiben erhalten ---
|
||||
(tu-eq "geruest-artnr-n/gruppe" '("111" "222" "222" "111" "222" "222")
|
||||
(geruest-artikelnummern-n _gruppe 2))
|
||||
|
||||
;; --- DCL-Label: Anfuehrungszeichen wuerde die Datei zerstoeren ---
|
||||
(tu-eq "geruest-dcl-label/quote" "ROHRKLAMMER 1'' KPL. VERTIKAL"
|
||||
(geruest-dcl-label "ROHRKLAMMER 1\" KPL. VERTIKAL"))
|
||||
(tu-eq "geruest-dcl-label/ohne" "WINKEL 60X60X6X60"
|
||||
(geruest-dcl-label "WINKEL 60X60X6X60"))
|
||||
|
||||
;; --- Hilfslisten ---
|
||||
(tu-eq "geruest-nil-liste" '(nil nil nil) (geruest-nil-liste 3))
|
||||
(tu-eq "geruest-liste-setzen" '(nil 7 nil)
|
||||
(geruest-liste-setzen (geruest-nil-liste 3) 1 7))
|
||||
(tu-eq "geruest-alist-setzen/neu" '(("a" . 1))
|
||||
(geruest-alist-setzen nil "a" 1))
|
||||
(tu-eq "geruest-alist-setzen/ersetzt" '(("a" . 2))
|
||||
(geruest-alist-setzen '(("a" . 1)) "a" 2))
|
||||
(tu-eq "geruest-zahl-string/int" "2000" (geruest-zahl-string 2000))
|
||||
(tu-eq "geruest-zahl-string/leer" "" (geruest-zahl-string nil))
|
||||
|
||||
;; --- Konfiguration auf Anbauteile abbilden ---
|
||||
(setq _teile (list _eintrag _gruppe))
|
||||
(tu-eq "geruest-name-index/treffer" 1
|
||||
(geruest-name-index "Schraubenset" _teile))
|
||||
(tu-eq "geruest-name-index/fehlt" nil
|
||||
(geruest-name-index "gibt es nicht" _teile))
|
||||
;; Bekanntes Teil wird uebernommen, unbekanntes uebersprungen (nicht
|
||||
;; die ganze Konfiguration verworfen)
|
||||
(setq _konfig (ssg-json-parse
|
||||
(strcat "{\"name\": \"K1\", \"oben\": ["
|
||||
"{\"artikel\": \"Schraubenset\", \"menge\": 3},"
|
||||
"{\"artikel\": \"unbekannt\", \"menge\": 1}]}")))
|
||||
(tu-eq "geruest-konfig-position" '(nil 3)
|
||||
(geruest-konfig-position _konfig "oben" _teile))
|
||||
|
||||
;; --- Variante gewinnt vor Baugruppe (TEILEART/dummy) ---
|
||||
;; Die zusammengefuehrte Saeulen-Baugruppe unterscheidet 1 Zoll und
|
||||
;; 2 Zoll nur noch ueber das teileart-Feld der Variante.
|
||||
(setq _bgtest (ssg-json-parse
|
||||
"{\"teileart\": \"Basis\", \"dummy\": \"basis.dwg\"}"))
|
||||
(tu-eq "geruest-variante-wert/variante-gewinnt" "Speziell"
|
||||
(geruest-variante-wert
|
||||
(ssg-json-parse "{\"teileart\": \"Speziell\"}") _bgtest "teileart"))
|
||||
(tu-eq "geruest-variante-wert/rueckfall" "Basis"
|
||||
(geruest-variante-wert
|
||||
(ssg-json-parse "{\"name\": \"X\"}") _bgtest "teileart"))
|
||||
(tu-eq "geruest-variante-wert/ohne-variante" "basis.dwg"
|
||||
(geruest-variante-wert nil _bgtest "dummy"))
|
||||
|
||||
;; --- Zusammengefuehrte Saeulen-Baugruppe ---
|
||||
(setq _saeulen nil)
|
||||
(foreach _e (geruest-baugruppen-liste)
|
||||
(if (equal (car _e) "Saeulen") (setq _saeulen (cdr _e))))
|
||||
(tu-eq "geruest/saeulen-vorhanden" T (if _saeulen T nil))
|
||||
(if _saeulen
|
||||
(progn
|
||||
(tu-eq "geruest/saeulen-varianten" 6
|
||||
(length (ssg-json-get _saeulen "geometrie_varianten")))
|
||||
(tu-eq "geruest/saeulen-anbauteile" 7
|
||||
(length (ssg-json-get _saeulen "anbaugruppen")))
|
||||
(tu-eq "geruest/saeulen-titel" "Saeulen" (geruest-titel _saeulen))
|
||||
;; R 1" ist die erste Variante und traegt die eigene TEILEART
|
||||
(tu-eq "geruest/saeulen-1zoll-teileart" "Geruest Saeule 1 Zoll"
|
||||
(geruest-variante-wert
|
||||
(car (ssg-json-get _saeulen "geometrie_varianten"))
|
||||
_saeulen "teileart"))
|
||||
)
|
||||
)
|
||||
|
||||
;; --- Rundlauf Schreiber -> Parser ---
|
||||
;; Prueft den Konfigurations-Schreiber ohne BricsCAD-Dialog. Bewusst in
|
||||
;; eine temporaere Datei: ein Test darf cfg/geruest_user.json nicht
|
||||
;; ueberschreiben. Die Testdaten enthalten absichtlich Anfuehrungs-
|
||||
;; zeichen - genau daran wuerde eine fehlende Maskierung scheitern.
|
||||
(setq _rec
|
||||
(list (cons "name" "Mein \"Satz\"")
|
||||
(cons "variante" "ROHR R 1\" 33,7 x 2,6")
|
||||
(cons "laenge" "2000")
|
||||
(cons "teilefarbe" "RAL 7035 Lichtgrau")
|
||||
(cons "oben" (list (list (cons "artikel" "ROHRKLAMMER 1\" KPL. VERTIKAL")
|
||||
(cons "menge" 2))))
|
||||
(cons "unten" nil)))
|
||||
(setq _pfad (vl-filename-mktemp "grtest" nil ".json"))
|
||||
(setq _f (open _pfad "w"))
|
||||
(write-line "{ \"Test\": [" _f)
|
||||
(geruest-konfig-liste-schreiben _f (list _rec))
|
||||
(write-line "] }" _f)
|
||||
(close _f)
|
||||
(setq _zurueck (car (ssg-json-get (ssg-json-laden _pfad) "Test")))
|
||||
(vl-file-delete _pfad)
|
||||
(tu-eq "geruest-schreiber/name" "Mein \"Satz\""
|
||||
(ssg-json-get _zurueck "name"))
|
||||
(tu-eq "geruest-schreiber/variante" "ROHR R 1\" 33,7 x 2,6"
|
||||
(ssg-json-get _zurueck "variante"))
|
||||
(tu-eq "geruest-schreiber/laenge" "2000"
|
||||
(ssg-json-get _zurueck "laenge"))
|
||||
(tu-eq "geruest-schreiber/farbe" "RAL 7035 Lichtgrau"
|
||||
(ssg-json-get _zurueck "teilefarbe"))
|
||||
(tu-eq "geruest-schreiber/oben-artikel" "ROHRKLAMMER 1\" KPL. VERTIKAL"
|
||||
(ssg-json-get (car (ssg-json-get _zurueck "oben")) "artikel"))
|
||||
(tu-eq "geruest-schreiber/oben-menge" 2
|
||||
(ssg-json-get (car (ssg-json-get _zurueck "oben")) "menge"))
|
||||
(tu-eq "geruest-schreiber/unten-leer" nil
|
||||
(ssg-json-get _zurueck "unten"))
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
;; ------------------------------------------------------------
|
||||
;; TESTS: count_sep_scan.lsp - geometrische Sensor-Zuordnung
|
||||
;;
|
||||
;; Testet die durch die Zerlegung von cs-zuordnung-lauf isolierte,
|
||||
;; rein funktionale Kernlogik: Carrier-Records sind plain Listen
|
||||
;; (ename tagS tagP minx miny maxx maxy cx cy id label), Sensoren
|
||||
;; sind Punkte (x y). Kein ssget/entget/entmod - der ename an
|
||||
;; Position 0 wird von den Geometrie-Routinen nie dereferenziert,
|
||||
;; darum genuegt ein Symbol-Platzhalter. *senstol* wird fuer
|
||||
;; deterministische Ergebnisse explizit gesetzt (sonst cfg-abhaengig).
|
||||
;; ------------------------------------------------------------
|
||||
;; Record-Konstruktor fuers Testen: baut einen Carrier-Record so, wie
|
||||
;; ihn cs-sammle-bloecke liefert - nur die Box-/Zentrum-/ID-Felder
|
||||
;; (Index 3-9), die die Geometrie-Routinen lesen, sind relevant; ename
|
||||
;; und label sind reine Platzhalter.
|
||||
;; (name minx miny maxx maxy id) -> voller Carrier-Record
|
||||
(defun tu-mk-carr (name minx miny maxx maxy id)
|
||||
(list name "ANZAHL_SCANNER" "ANZAHL_SEPARATOR"
|
||||
minx miny maxx maxy
|
||||
(/ (+ minx maxx) 2.0) (/ (+ miny maxy) 2.0)
|
||||
id (strcat "L-" name)))
|
||||
|
||||
(defun tu-tests-sepscan ( / _senstol-alt _a _b _c _carr _grid _res)
|
||||
(princ "\n[count_sep_scan]")
|
||||
;; count_sep_scan ist ein lazy Feature-Modul (nicht in der Core-Ladeliste).
|
||||
;; Geladen wird es zentral in test_unit.scr auf .scr-Top-Level; hier nur
|
||||
;; pruefen, ob es da ist (siehe Kopfkommentar zur Ladearchitektur).
|
||||
(if (null (atoms-family 1 '("CS-RESOLVE-SENSOR")))
|
||||
(tu-record nil "sepscan/modul" "count_sep_scan.lsp nicht geladen")
|
||||
(progn
|
||||
(setq _senstol-alt (if (boundp '*senstol*) *senstol*))
|
||||
(setq *senstol* 0.0)
|
||||
|
||||
;; --- cs-in-box: Punkt in Carrier-Box (X/Y, Z ignoriert) ---
|
||||
(setq _a (tu-mk-carr "A" 0.0 0.0 100.0 100.0 "0001"))
|
||||
(tu-true "cs-in-box/mitte" (cs-in-box '(50.0 50.0) _a))
|
||||
(tu-true "cs-in-box/rand" (cs-in-box '(0.0 0.0) _a))
|
||||
(tu-nil "cs-in-box/ausserhalb-x" (cs-in-box '(150.0 50.0) _a))
|
||||
(tu-nil "cs-in-box/ausserhalb-y" (cs-in-box '(50.0 -1.0) _a))
|
||||
|
||||
;; --- *senstol* vergroessert die Box ---
|
||||
(setq *senstol* 10.0)
|
||||
(tu-true "cs-in-box/toleranz-innen" (cs-in-box '(105.0 50.0) _a))
|
||||
(tu-nil "cs-in-box/toleranz-aussen" (cs-in-box '(111.0 50.0) _a))
|
||||
(setq *senstol* 0.0)
|
||||
|
||||
;; --- cs-bump: Zaehler je ename hochzaehlen ---
|
||||
(tu-eq "cs-bump/neu" '(("k" . 1)) (cs-bump nil "k"))
|
||||
(tu-eq "cs-bump/erhoeht" '(("k" . 2)) (cs-bump '(("k" . 1)) "k"))
|
||||
(tu-eq "cs-bump/zweiter-key"
|
||||
'(("m" . 1) ("k" . 1)) (cs-bump '(("k" . 1)) "m"))
|
||||
|
||||
;; --- cs-carrier-by-id: Record ueber ID (Feld 9) finden ---
|
||||
(setq _b (tu-mk-carr "B" 200.0 0.0 300.0 100.0 "0002"))
|
||||
(setq _carr (list _a _b))
|
||||
(tu-eq "cs-carrier-by-id/treffer" _b (cs-carrier-by-id "0002" _carr))
|
||||
(tu-nil "cs-carrier-by-id/fehlt" (cs-carrier-by-id "9999" _carr))
|
||||
(tu-nil "cs-carrier-by-id/leer" (cs-carrier-by-id "" _carr))
|
||||
(tu-nil "cs-carrier-by-id/nil" (cs-carrier-by-id nil _carr))
|
||||
|
||||
;; --- cs-assign: BBox-Zuordnung ueber das Grid ---
|
||||
;; Zwei getrennte Boxen: Punkt in genau einer -> diese.
|
||||
(setq _grid (cs-grid-build _carr))
|
||||
(tu-eq "cs-assign/box-a" _a (cs-assign '(50.0 50.0) _grid))
|
||||
(tu-eq "cs-assign/box-b" _b (cs-assign '(250.0 50.0) _grid))
|
||||
(tu-nil "cs-assign/keine-box" (cs-assign '(1000.0 1000.0) _grid))
|
||||
|
||||
;; Ueberlappende Boxen -> naechstes Box-Zentrum gewinnt (Tiebreak).
|
||||
;; C: 0..100, D: 40..200; Punkt (45,50) liegt in beiden,
|
||||
;; C-Zentrum (50,50) ist naeher als D-Zentrum (120,50).
|
||||
(setq _a (tu-mk-carr "C" 0.0 0.0 100.0 100.0 "0003"))
|
||||
(setq _b (tu-mk-carr "D" 40.0 0.0 200.0 100.0 "0004"))
|
||||
(setq _grid (cs-grid-build (list _a _b)))
|
||||
(tu-eq "cs-assign/overlap-naechstes-zentrum"
|
||||
_a (cs-assign '(45.0 50.0) _grid))
|
||||
|
||||
;; --- cs-nearest-two: die zwei naechsten Carrier nach Zentrum ---
|
||||
;; Zentren: A(50,50) B(250,50) C(50,250). Punkt (60,60):
|
||||
;; naechster A, zweiter B (dx 190 < dy 190? -> Abstand B=~194, C=~190).
|
||||
(setq _a (tu-mk-carr "A" 0.0 0.0 100.0 100.0 "0001"))
|
||||
(setq _b (tu-mk-carr "B" 200.0 0.0 300.0 100.0 "0002"))
|
||||
(setq _c (tu-mk-carr "C" 0.0 200.0 100.0 300.0 "0003"))
|
||||
(setq _res (cs-nearest-two '(60.0 60.0) (list _a _b _c)))
|
||||
(tu-eq "cs-nearest-two/naechster" _a (nth 0 _res))
|
||||
(tu-true "cs-nearest-two/zweiter-vorhanden" (nth 2 _res))
|
||||
;; Abstand zum naechsten (A-Zentrum 50,50) = sqrt(10^2+10^2) ~ 14.14
|
||||
(tu-eqf "cs-nearest-two/best-dist"
|
||||
(distance '(60.0 60.0) '(50.0 50.0)) (nth 1 _res))
|
||||
|
||||
;; Nur ein Carrier -> zweiter ist nil.
|
||||
(setq _res (cs-nearest-two '(60.0 60.0) (list _a)))
|
||||
(tu-eq "cs-nearest-two/einzeln-best" _a (nth 0 _res))
|
||||
(tu-nil "cs-nearest-two/einzeln-kein-zweiter" (nth 2 _res))
|
||||
|
||||
;; --- cs-resolve-sensor: der Entscheider bbox/distance/none ---
|
||||
;; Punkt in einer Box -> modus 'bbox, kein Distanzfeld.
|
||||
(setq _grid (cs-grid-build (list _a _b _c)))
|
||||
(setq _res (cs-resolve-sensor '(50.0 50.0) (list _a _b _c) _grid))
|
||||
(tu-eq "cs-resolve/bbox-modus" 'bbox (nth 0 _res))
|
||||
(tu-eq "cs-resolve/bbox-rec" _a (nth 1 _res))
|
||||
(tu-nil "cs-resolve/bbox-kein-dist" (nth 2 _res))
|
||||
|
||||
;; Punkt ausserhalb aller Boxen, aber Carrier vorhanden -> 'distance.
|
||||
(setq _res (cs-resolve-sensor '(1000.0 1000.0) (list _a _b _c) _grid))
|
||||
(tu-eq "cs-resolve/distance-modus" 'distance (nth 0 _res))
|
||||
(tu-true "cs-resolve/distance-rec" (nth 1 _res))
|
||||
(tu-true "cs-resolve/distance-dist" (nth 2 _res))
|
||||
|
||||
;; Gar keine Carrier -> 'none.
|
||||
(setq _grid (cs-grid-build nil))
|
||||
(setq _res (cs-resolve-sensor '(50.0 50.0) nil _grid))
|
||||
(tu-eq "cs-resolve/none-modus" 'none (nth 0 _res))
|
||||
(tu-nil "cs-resolve/none-rec" (nth 1 _res))
|
||||
|
||||
;; *senstol* wieder herstellen
|
||||
(setq *senstol* _senstol-alt)
|
||||
)
|
||||
)
|
||||
)
|
||||
@@ -577,26 +855,142 @@
|
||||
)
|
||||
|
||||
|
||||
;; ------------------------------------------------------------
|
||||
;; TESTS: vf_linienzug.lsp - SEGS-Journal-Serialisierung (Modus 3)
|
||||
;; ------------------------------------------------------------
|
||||
;; Roundtrip der Segment-Essenz: die Zahlenliste, die Modus 3 aus den Pfad-
|
||||
;; Objekten ableitet, muss verlustfrei durch String<->Liste und durch die
|
||||
;; Journal-Eintrags-Serialisierung laufen - das ist die Grundlage dafuer, dass
|
||||
;; ein Modus-3-Block per Doppelklick 1:1 aus dem XDATA-Journal nachgebaut wird.
|
||||
(defun tu-tests-vfl-segs ( / _seg _segs _s _e)
|
||||
(princ "\n[vf_linienzug/SEGS]")
|
||||
(if (null (atoms-family 1 '("VFL-SEGS->STRING")))
|
||||
(tu-record nil "vfl-segs/modul" "vf_linienzug.lsp nicht geladen (VFL-SEGS->STRING fehlt)")
|
||||
(progn
|
||||
;; Einzelsegment (Bogen, alle Felder gesetzt) Roundtrip
|
||||
(setq _seg '("Bogen" 102.5 707.106781 90 "rechts" 1000.0 2000.0 1500.5 2500.25))
|
||||
(tu-eqf "vfl-seg/roundtrip-bogen"
|
||||
_seg (vfl-string->seg (vfl-seg->string _seg)))
|
||||
|
||||
;; Linie (bwinkel 0, bseite default) Roundtrip
|
||||
(setq _seg '("Linie" 30.0 4200.0 0 "links" 0.0 0.0 3637.31 2100.0))
|
||||
(tu-eqf "vfl-seg/roundtrip-linie"
|
||||
_seg (vfl-string->seg (vfl-seg->string _seg)))
|
||||
|
||||
;; Ganze Segmentliste (Linie + Bogen + Linie) Roundtrip
|
||||
(setq _segs (list '("Linie" 0.0 3000.0 0 "links" 0.0 0.0 3000.0 0.0)
|
||||
'("Bogen" 0.0 707.106781 90 "rechts" 3000.0 0.0 3500.0 -500.0)
|
||||
'("Linie" 270.0 2500.0 0 "links" 3500.0 -500.0 3500.0 -3000.0)))
|
||||
(tu-eqf "vfl-segs/roundtrip-liste"
|
||||
_segs (vfl-string->segs (vfl-segs->string _segs)))
|
||||
|
||||
;; Leere Liste -> "" -> leere Liste
|
||||
(tu-eq "vfl-segs/leer-string" "" (vfl-segs->string '()))
|
||||
(tu-nil "vfl-segs/leer-parse" (vfl-string->segs ""))
|
||||
|
||||
;; Einbettung als Journal-Eintrag: (SEGS . liste) durch
|
||||
;; vfl-entry->string / vfl-string->entry
|
||||
(setq _e (cons "SEGS" _segs))
|
||||
(setq _s (vfl-entry->string _e))
|
||||
(tu-true "vfl-segs/entry-praefix" (= "SEGS:" (substr _s 1 5)))
|
||||
(tu-eqf "vfl-segs/entry-roundtrip"
|
||||
_e (vfl-string->entry _s))
|
||||
|
||||
;; Delimiter-Sicherheit: die serialisierte Form enthaelt genau die
|
||||
;; erwarteten Trenner und KEIN Newline (sonst zerrisse der Record-Trenner)
|
||||
(tu-nil "vfl-segs/kein-newline"
|
||||
(vl-string-search "\n" (vfl-segs->string _segs)))
|
||||
|
||||
;; vfl-journal-hat-segs-p: unterscheidet neue SEGS-Ketten von alten
|
||||
;; OBJS-"linienzug2"-Bloecken (harter Schnitt beim Doppelklick).
|
||||
(if (atoms-family 1 '("VFL-JOURNAL-HAT-SEGS-P"))
|
||||
(progn
|
||||
;; SEGS-Journal (Modus 2 neu / Modus 3): erkannt
|
||||
(tu-true "vfl-hat-segs/mit-segs"
|
||||
(vfl-journal-hat-segs-p
|
||||
(list (cons "PT" '(0.0 0.0 0.0)) (cons "SEGS" _segs))))
|
||||
;; Altes OBJS-Journal (Objekt-Handles): NICHT als SEGS erkannt
|
||||
(tu-nil "vfl-hat-segs/nur-objs"
|
||||
(vfl-journal-hat-segs-p
|
||||
(list (cons "PT" '(0.0 0.0 0.0)) (cons "OBJS" '("A1" "A2")))))
|
||||
;; Leeres Journal: nil
|
||||
(tu-nil "vfl-hat-segs/leer" (vfl-journal-hat-segs-p '())))
|
||||
(tu-record nil "vfl-hat-segs/modul" "VFL-JOURNAL-HAT-SEGS-P fehlt"))
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
;; ------------------------------------------------------------
|
||||
;; TESTS: vf_linienzug.lsp - gemeinsamer Abbruch-Handler-Konstruktor
|
||||
;; ------------------------------------------------------------
|
||||
;; vfl-abbruch-handler-installieren baut *error* als Lambda-Liste, in die der
|
||||
;; Marker ("linienzug"/"linienzug2"/"linienzug3") als String-Literal eingebaut
|
||||
;; ist. Der wortgleiche Wickel-Handler steht damit nur noch EINMAL statt 3x.
|
||||
;; Getestet wird die KONSTRUKTION (Marker an der richtigen Stelle, Struktur
|
||||
;; aufrufbar) - NICHT ein echter Abbruch (der braeuchte Zeichnung/Geometrie).
|
||||
;; *error* wird gesichert und wiederhergestellt, damit der Testlauf unberuehrt
|
||||
;; bleibt.
|
||||
(defun tu-tests-vfl-abbruch ( / _save _h _call)
|
||||
(princ "\n[vf_linienzug/Abbruch-Handler]")
|
||||
(if (null (atoms-family 1 '("VFL-ABBRUCH-HANDLER-INSTALLIEREN")))
|
||||
(tu-record nil "vfl-abbruch/modul"
|
||||
"vf_linienzug.lsp nicht geladen (VFL-ABBRUCH-HANDLER-INSTALLIEREN fehlt)")
|
||||
(progn
|
||||
(setq _save *error*)
|
||||
(setq _h (vfl-abbruch-handler-installieren "linienzug2"))
|
||||
;; Rueckgabe = das gesetzte *error* (identisch)
|
||||
(tu-true "vfl-abbruch/setzt-error" (equal _h *error*))
|
||||
;; Struktur: (lambda (msg) ...) - erstes Element lambda, zweites (msg)
|
||||
(tu-eq "vfl-abbruch/ist-lambda" 'lambda (car _h))
|
||||
(tu-eq "vfl-abbruch/arg-msg" '(msg) (cadr _h))
|
||||
;; Der vfl-modus-abbruch-sichern-Aufruf im Rumpf traegt GENAU den
|
||||
;; uebergebenen Marker als letztes Argument (nicht einen anderen Modus).
|
||||
(setq _call (car (vl-member-if
|
||||
(function (lambda (f)
|
||||
(and (listp f) (eq (car f) 'vfl-modus-abbruch-sichern))))
|
||||
(cddr _h))))
|
||||
(tu-true "vfl-abbruch/ruft-sichern" (not (null _call)))
|
||||
(tu-eq "vfl-abbruch/marker-linienzug2" "linienzug2" (last _call))
|
||||
;; Anderer Marker -> anderes Literal an derselben Position
|
||||
(vfl-abbruch-handler-installieren "linienzug3")
|
||||
(setq _call (car (vl-member-if
|
||||
(function (lambda (f)
|
||||
(and (listp f) (eq (car f) 'vfl-modus-abbruch-sichern))))
|
||||
(cddr *error*))))
|
||||
(tu-eq "vfl-abbruch/marker-linienzug3" "linienzug3" (last _call))
|
||||
;; *error* wiederherstellen - Testlauf darf nicht mit einem Wickel-Handler
|
||||
;; ohne gebundene Modus-Locals zurueckbleiben.
|
||||
(setq *error* _save)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
;; ------------------------------------------------------------
|
||||
;; BEFEHL: TEST_UNIT
|
||||
;; ------------------------------------------------------------
|
||||
;; Testblock geschuetzt aufrufen: ein harter LISP-Fehler in einem Block
|
||||
;; wird als FAIL erfasst, statt c:TEST_UNIT abzubrechen und damit den
|
||||
;; Report zu verhindern. Der Blockname (String) wird per read zur Funktion.
|
||||
(defun tu-run-block (fn / res)
|
||||
(setq res (vl-catch-all-apply (read fn) nil))
|
||||
(if (vl-catch-all-error-p res)
|
||||
(tu-record nil (strcat fn "/ausfuehrung")
|
||||
(strcat "harter Fehler: " (vl-catch-all-error-message res))))
|
||||
)
|
||||
|
||||
(defun c:TEST_UNIT ( / out-dir report)
|
||||
(tu-reset)
|
||||
(princ "\n================================================================")
|
||||
(princ "\n TEST_UNIT - LISP-Standardfunktionen")
|
||||
(princ "\n================================================================")
|
||||
|
||||
(tu-tests-core)
|
||||
(tu-tests-lang)
|
||||
(tu-tests-id)
|
||||
(tu-tests-vfcore)
|
||||
(tu-tests-export)
|
||||
(tu-tests-gf)
|
||||
(tu-tests-omni)
|
||||
(tu-tests-kreisel)
|
||||
(tu-tests-sepliste)
|
||||
(tu-tests-json)
|
||||
(tu-tests-geruest)
|
||||
(foreach fn '("tu-tests-core" "tu-tests-lang" "tu-tests-id" "tu-tests-vfcore"
|
||||
"tu-tests-export" "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-run-block fn))
|
||||
|
||||
(princ "\n\n----------------------------------------------------------------")
|
||||
(princ (strcat "\n Gesamt: " (itoa (+ *tu-pass* *tu-fail*))
|
||||
|
||||
@@ -2,6 +2,14 @@
|
||||
; Laedt SSG_LIB + die Unit-Tests, fuehrt TEST_UNIT aus und beendet BricsCAD.
|
||||
; Pfadunabhaengig ueber DXFMAKRO (von setenv.bat gesetzt).
|
||||
(load (strcat (getenv "DXFMAKRO") "/Lisp/ssg_load.lsp"))
|
||||
; Lazy Feature-Module, die einzelne Unit-Tests brauchen, hier auf .scr-Top-
|
||||
; Level laden. In BricsCAD werden per load definierte Funktionen erst nach
|
||||
; Rueckkehr zum Top-Level sichtbar - ein load INNERHALB von c:TEST_UNIT
|
||||
; (oder eines gecatchten Testblocks) bindet sie im selben Durchlauf nicht.
|
||||
; DIES ist die einzige Ladestelle: Testet ein neuer Block ein weiteres lazy
|
||||
; Modul, gehoert dessen load-Zeile HIER dazu (nicht in test_unit.lsp).
|
||||
(load (strcat (getenv "DXFM_LISP") "/GeruestInsert.lsp") "GeruestInsert.lsp nicht gefunden")
|
||||
(load (strcat (getenv "DXFM_LISP") "/count_sep_scan.lsp") "count_sep_scan.lsp nicht gefunden")
|
||||
(load (strcat (getenv "DXFMAKRO") "/tests/test_unit.lsp"))
|
||||
(c:TEST_UNIT)
|
||||
(command "_.QUIT")
|
||||
|
||||
@@ -173,6 +173,7 @@ EINGABE_ERLAUBT = {
|
||||
"vfl-in-int": {"getint": 1},
|
||||
"vfl-in-real": {"getreal": 1},
|
||||
"vfl-in-selection": {"ssget": 1},
|
||||
"vfl-in-segmente": {"ssget": 1}, # Modus-3-Wrapper: Live-Auswahl -> Segment-Essenz (SEGS), Replay aus Journal
|
||||
"vfl-winkel-live": {"getint": 1}, # livefn fuer vfl-in-value
|
||||
# --- Wizard-Schicht (DCL); bei ssg-gui-aus greift sie nicht ---
|
||||
"vflw-zahl": {"getreal": 1}, # Fallback ohne Dialog
|
||||
|
||||
Vendored
+9
-9
@@ -323,7 +323,7 @@
|
||||
"comment": "Separator 3 (Nachtrag HundM05, reale Koordinate laut Anwender)",
|
||||
"function": "insert",
|
||||
"block": "S-LP",
|
||||
"x": 7831.8,
|
||||
"x": 8549.28,
|
||||
"y": 1169.5,
|
||||
"z": 2154,
|
||||
"rotation": 180
|
||||
@@ -333,7 +333,7 @@
|
||||
"comment": "Scanner zu Separator 3 (Nachtrag HundM05, reale Koordinate laut Anwender)",
|
||||
"function": "insert",
|
||||
"block": "Scanner",
|
||||
"x": 7874.5,
|
||||
"x": 8598.69,
|
||||
"y": 1167.7,
|
||||
"z": 2154,
|
||||
"rotation": 270
|
||||
@@ -343,7 +343,7 @@
|
||||
"comment": "Separator 4 (Nachtrag HundM05, reale Koordinate laut Anwender)",
|
||||
"function": "insert",
|
||||
"block": "S-LP",
|
||||
"x": 12191.0,
|
||||
"x": 12619.88,
|
||||
"y": 1168.2,
|
||||
"z": 2154,
|
||||
"rotation": 180
|
||||
@@ -353,7 +353,7 @@
|
||||
"comment": "Scanner zu Separator 4 (Nachtrag HundM05, reale Koordinate laut Anwender)",
|
||||
"function": "insert",
|
||||
"block": "Scanner",
|
||||
"x": 12233.7,
|
||||
"x": 12669.1,
|
||||
"y": 1166.4,
|
||||
"z": 2154,
|
||||
"rotation": 270
|
||||
@@ -363,7 +363,7 @@
|
||||
"comment": "Separator 5 (Nachtrag HundM05, reale Koordinate laut Anwender)",
|
||||
"function": "insert",
|
||||
"block": "S-LP",
|
||||
"x": 16488.4,
|
||||
"x": 16785.77,
|
||||
"y": 1171.7,
|
||||
"z": 2154,
|
||||
"rotation": 180
|
||||
@@ -373,7 +373,7 @@
|
||||
"comment": "Scanner zu Separator 5 (Nachtrag HundM05, reale Koordinate laut Anwender)",
|
||||
"function": "insert",
|
||||
"block": "Scanner",
|
||||
"x": 16531.1,
|
||||
"x": 16839.52,
|
||||
"y": 1169.8,
|
||||
"z": 2154,
|
||||
"rotation": 270
|
||||
@@ -435,7 +435,7 @@
|
||||
"block": "BTMT-Beladung",
|
||||
"x": 5290.9,
|
||||
"y": 370.2,
|
||||
"z": 0,
|
||||
"z": 2154,
|
||||
"rotation": 179.03
|
||||
},
|
||||
{
|
||||
@@ -445,7 +445,7 @@
|
||||
"block": "BTMT-Beladung",
|
||||
"x": 4261.2,
|
||||
"y": 374.2,
|
||||
"z": 0,
|
||||
"z": 2154,
|
||||
"rotation": 179.18
|
||||
},
|
||||
{
|
||||
@@ -455,7 +455,7 @@
|
||||
"block": "SC_Entladung",
|
||||
"x": 24768.7,
|
||||
"y": 1170.3,
|
||||
"z": 0,
|
||||
"z": 2154,
|
||||
"rotation": 0.97
|
||||
}
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user