diff --git a/CLAUDE.md b/CLAUDE.md index cde9c1a..1df2ac1 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -81,14 +81,14 @@ Abhaengigkeiten: `ezdxf`, Standard-Library. Benoetigen Umgebungsvariablen (`DXFM | `omniflo_utils.py` | Gemeinsame Hilfsfunktionen fuer Omniflo-Skripte: `ROW_GROUPS` (Reihen-Gruppierung), `SWITCH_FILTERS` (Schalter-Filter), `build_row_layout`, `import_element_as_block`, `draw_cross`, `load_omniflo_data` | | `set_einfuegepkt.py` | Setzt `$INSBASE` (Einfuegepunkt) in Omniflo-DXF-Dateien. Schalter je Typ: `--boegen`, `--weichen45`, `--weichen90`, `--weichenkoerper`, `--weichen-parallel`, `--delta`, `--dreifachweiche`, `--sternweiche`, `--show-omniflo` | | `set_koords.py` | Setzt Koordinatensystem-Bloecke (K1-K4) in Omniflo-DXF-Dateien. Schalter: `--k1set` bis `--k4set`, `--set-all`, `--force`, `--show-omniflo`, `--test`, `--number` | -| `attradd.py` | Fuegt ATTDEF-Attribute zu Omniflo-DXF-Dateien hinzu. Liest Konfiguration aus `cfg/attradd.cfg`. Schalter: `--number`, `--dry-run` | +| `set_attributs.py` | Fuegt ATTDEF-Attribute zu Omniflo-DXF-Dateien hinzu. Liest Konfiguration aus `cfg/attradd.cfg`. Schalter: `--number`, `--dry-run` | | `export_sivas.py` | Erzeugt Sivas-Export-CSV mit Summierungszeilen (ILS Automation, Omniflo Sum). Aufruf: `python export_sivas.py ` | | `export_csv.py` | Erzeugt einfache Item-Liste als CSV (ohne Summierung). Aufruf: `python export_csv.py ` | | `testpycall.py` | Testskript fuer LISP-Python-Aufruf via CALLPYTHON | ### Typische Verarbeitungskette (Omniflo-DXF) -1. `attradd.py` - Attribute zu Quell-DXFs hinzufuegen +1. `set_attributs.py` - Attribute zu Quell-DXFs hinzufuegen 2. `set_einfuegepkt.py` - Einfuegepunkte berechnen und setzen 3. `set_koords.py` - Koordinatensysteme (K1-K4) setzen 4. `export_sivas.py` / `export_csv.py` - Export aus Zeichnung diff --git a/bin/add_attr.bat b/bin/set_attributs.bat similarity index 85% rename from bin/add_attr.bat rename to bin/set_attributs.bat index d754ea0..c048e8c 100644 --- a/bin/add_attr.bat +++ b/bin/set_attributs.bat @@ -5,4 +5,4 @@ REM ================================================================ call "%~dp0setenv.bat" -python "%DXFM_LIB%\attradd.py" %* +python "%DXFM_LIB%\set_attributs.py" %* diff --git a/cfg/attradd.cfg b/cfg/attradd.cfg index 6bae22d..b96f0f4 100644 --- a/cfg/attradd.cfg +++ b/cfg/attradd.cfg @@ -19,7 +19,7 @@ # ------------------------------------------------------------ # Layer-Zuordnung nach Elementkategorie -# attradd.py bestimmt die Kategorie anhand KurvenWinkel und +# set_attributs.py bestimmt die Kategorie anhand KurvenWinkel und # WeichenTyp aus den JSON-Daten und setzt LAYER entsprechend. # ------------------------------------------------------------ [layer] @@ -45,8 +45,7 @@ TEILEART = "Omniflo Kurve" RADIUS = Radius WINKEL = KurvenWinkel SIVASNR_TEF = SivasnrTEF -HOEHE = "2000" -DREHUNG = "0" + [weiche] BESCHR = ProfilTyp @@ -56,8 +55,6 @@ TEILEART = "Omniflo Weiche" # LAYER = "A-OF-Weiche" WEICHENTYP = WeichenTyp WINKEL = KurvenWinkel -RADIUS = Breite RICHTUNG = KurvenRichtung SIVASNR_TEF = SivasnrTEF -HOEHE = "2000" -DREHUNG = "0" + diff --git a/doc/tools.md b/doc/tools.md index bceb1e1..5b4aa66 100644 --- a/doc/tools.md +++ b/doc/tools.md @@ -35,7 +35,7 @@ Diese Werkzeuge ermöglichen die massenhafte Aufbereitung von einzelnen dxf Date - [--number SIVASNR](#--number-sivasnr-1) - [Uebersicht K-Zuordnung](#uebersicht-k-zuordnung) - [Umgebungsvariablen](#umgebungsvariablen-1) -- [attradd](#attradd) +- [set_attributs](#set_attributs) - [Aufruf](#aufruf-2) - [Datenquellen](#datenquellen-2) - [Ablauf](#ablauf-2) @@ -149,7 +149,7 @@ Alle 107 Items (27 Boegen + 80 Weichen) sind exklusiv genau einem Schalter zugeo ## Uebersicht aller Schalter | Schalter | Items | WeichenTyp | KurvenWinkel | Einfuegepunkt-Kriterium | -|---|---|---|---|---| +| --- | --- | --- | --- | --- | | `--boegen` | 27 | - | 22.5, 45, 67.5, 90, 180 | Tangentenschnittpunkt am Bogen (180: Mittelpunkt) | | `--weichen45` | 32 | Einzel-, Doppel-, Dreiwegeweiche | 45 | Tangente oberer Bogenpunkt x laengste Vertikale | | `--weichen90` | 24 | Einzel-, Doppel-, Dreiwegeweiche | 90 | Tangente oberer Bogenpunkt x laengste Vertikale | @@ -259,7 +259,7 @@ Nur die angegebene 9-stellige Sivasnr verarbeiten. Kombinierbar mit jedem Schalt ## Uebersicht K-Zuordnung | K | Boegen | Weichen | Weichenkoerper | Dreifach/Delta/Stern | -|---|---|---|---|---| +| --- | --- | --- | --- | --- | | K1 | Oberste H-Linie (rz=0) | Unterste V-Linie (rz=90) | Unterste V-Linie (rz=90) | Unterste V-Linie (rz=90) | | K2 | Anderes Kettenende | Linker Bogenzweig | Linke Diagonale | Linkes H-Linienende | | K3 | - | Rechter Bogenzweig (2+ Boegen) | Rechte Diagonale (2+ Diag.) | Rechtes H-Linienende | @@ -274,14 +274,14 @@ Nur die angegebene 9-stellige Sivasnr verarbeiten. Kombinierbar mit jedem Schalt --- -# attradd +# set_attributs Fuegt Attribute (ATTDEF) zu allen Omniflo DXF-Dateien hinzu. Die Attribut-Tags und deren Werte werden ueber eine Konfigurationsdatei gesteuert. ## Aufruf ``` -python lib/attradd.py [--number SIVASNR] [--dry-run] +python lib/set_attributs.py [--number SIVASNR] [--dry-run] ``` ## Datenquellen @@ -303,34 +303,68 @@ python lib/attradd.py [--number SIVASNR] [--dry-run] ## Konfiguration (attradd.cfg) -Die Config-Datei ist im INI-Format mit Abschnitten je Elementtyp: - -```ini -[bogen] -BESCHR = ProfilTyp -ARTINR = Sivasnr -TEILEART = "Omniflo Kurve" -LAYER = "A-OF-Bogen" -RADIUS = Radius -WINKEL = KurvenWinkel -SIVASNR_TEF = SivasnrTEF - -[weiche] -BESCHR = ProfilTyp -ARTINR = Sivasnr -TEILEART = "Omniflo Weiche" -LAYER = "A-OF-Weiche" -WEICHENTYP = WeichenTyp -WINKEL = KurvenWinkel -RADIUS = Breite -SIVASNR_TEF = SivasnrTEF -``` - +Die Config-Datei ist im INI-Format mit Abschnitten je Elementtyp. Quellwerte koennen sein: - **JSON-Feldname** (z.B. `ProfilTyp`) - Wert wird aus dem JSON-Eintrag gelesen - **Fester Text** in Anfuehrungszeichen (z.B. `"Omniflo Kurve"`) - **Platzhalter** `{sivasnr}` - wird durch die Sivasnr ersetzt +### Attribute Omniflo Kurve (Bogen) + +| ATTDEF-Tag | Quelle | Beschreibung | +| --- | --- | --- | +| `BESCHR` | `ProfilTyp` | Profilbezeichnung aus JSON | +| `ARTINR` | `Sivasnr` | Sivas-Artikelnummer | +| `TEILEART` | `"Omniflo Kurve"` | Fester Typname | +| `RADIUS` | `Radius` | Kurvenradius in mm | +| `WINKEL` | `KurvenWinkel` | Kurvenwinkel in Grad | +| `SIVASNR_TEF` | `SivasnrTEF` | Sivas-Nr. des TEF-Antriebs (leer = kein Antrieb) | +| `HOEHE` | `"2000"` | Montagehoehe in mm (wird beim Export aus Z-Koordinate aktualisiert) | +| `DREHUNG` | `"0"` | Drehwinkel in Grad (wird beim Export aus CAD-Rotation aktualisiert) | +| `LAYER` | *(aus [layer])* | Layer-Name gemaess Kategorisierung | + +### Attribute Omniflo Weiche + +| ATTDEF-Tag | Quelle | Beschreibung | +| --- | --- | --- | +| `BESCHR` | `ProfilTyp` | Profilbezeichnung aus JSON | +| `ARTINR` | `Sivasnr` | Sivas-Artikelnummer | +| `TEILEART` | `"Omniflo Weiche"` | Fester Typname | +| `WEICHENTYP` | `WeichenTyp` | Weichentyp (Einzelweiche, Doppelweiche, Dreiwegeweiche, ...) | +| `WINKEL` | `KurvenWinkel` | Kurvenwinkel in Grad | +| `RICHTUNG` | `KurvenRichtung` | Richtungskennung (1=Links, 2=Rechts, 3=Beide, 7=Dreiweg) | +| `SIVASNR_TEF` | `SivasnrTEF` | Sivas-Nr. des TEF-Antriebs (leer = kein Antrieb) | +| `HOEHE` | `"2000"` | Montagehoehe in mm (wird beim Export aus Z-Koordinate aktualisiert) | +| `DREHUNG` | `"0"` | Drehwinkel in Grad (wird beim Export aus CAD-Rotation aktualisiert) | +| `LAYER` | *(aus [layer])* | Layer-Name gemaess Kategorisierung | + +### CSV-Export-Felder (Merkmale) + +Die Attribute werden beim CSV-Export (`export_csv.py` / `OMNI_EXPORT`) wie folgt in CSV-Merkmale ueberfuehrt. +CSV-Format: `Elementnummer;TeileArt;TeileId;Bezeichnung;Anzahl;Merkmale` + +**Omniflo Kurve:** + +| Merkmal | Quelle | Typ | +| --- | --- | --- | +| `Kurvenwinkel` | JSON `KurvenWinkel` | float | +| `Radius` | JSON `Radius` | float | +| `Höhe` | Attribut `HOEHE` / Z-Koordinate | string | +| `Drehung` | Attribut `DREHUNG` / CAD-Rotation | float | +| `SivasNummer` | JSON `Sivasnr` | string | + +**Omniflo Weiche:** + +| Merkmal | Quelle | Typ | +| --- | --- | --- | +| `Weichentyp` | JSON `WeichenTyp` | string | +| `Richtung` | JSON `KurvenRichtung` | string | +| `Weichenwinkel` | JSON `KurvenWinkel` | float | +| `Höhe` | Attribut `HOEHE` / Z-Koordinate | string | +| `Drehung` | Attribut `DREHUNG` / CAD-Rotation | float | +| `Antrieb Kurve` | `SivasnrTEF` != null | bool | +| `SivasNummer` | JSON `Sivasnr` | string | + ## Schalter ### --number SIVASNR / -n SIVASNR diff --git a/lib/attradd.py b/lib/set_attributs.py similarity index 88% rename from lib/attradd.py rename to lib/set_attributs.py index bdb523e..a75637c 100644 --- a/lib/attradd.py +++ b/lib/set_attributs.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- """ -attradd.py - Fuegt Attribute (ATTDEF) zu allen Omniflo DXF-Dateien hinzu. +set_attributs.py - Fuegt Attribute (ATTDEF) zu allen Omniflo DXF-Dateien hinzu. Liest die Attribut-Konfiguration aus cfg/attradd.cfg und die Element-Daten aus data/json/omniflo_boegen.json und omniflo_weichen.json. @@ -13,7 +13,7 @@ Umgebungsvariablen: DXFM_RESULTS - Pfad zum results/-Verzeichnis Aufruf: - python lib/attradd.py [--number SIVASNR] [--dry-run] + python lib/set_attributs.py [--number SIVASNR] [--dry-run] """ import argparse @@ -157,11 +157,32 @@ ATTDEF_HEIGHT = 5.0 ATTDEF_LAYER = "ATTRIB" +def wrap_entities_in_block(doc, block_name): + """ + Verschiebt alle Entities aus dem Modelspace in eine Blockdefinition + mit dem Namen block_name und fuegt eine Blockreferenz bei (0, 0) ein. + Vorhandene Blockdefinition mit gleichem Namen wird ersetzt (fuer Re-Runs). + """ + msp = doc.modelspace() + + # Vorhandene Blockdefinition entfernen + if block_name in doc.blocks: + doc.blocks.delete_block(block_name, safe=False) + + blk = doc.blocks.new(block_name) + + for entity in list(msp): + msp.move_to_layout(entity, blk) + + msp.add_blockref(block_name, (0, 0)) + + def add_attdefs_to_dxf(dxf_path, output_path, attr_defs, json_entry, sivasnr, layer_value=""): """ - Oeffnet eine DXF-Datei, fuegt ATTDEF-Entities in den Modelspace ein - und speichert das Ergebnis. + Oeffnet eine DXF-Datei, fuegt ATTDEF-Entities in den Modelspace ein, + fasst alle Entities anschliessend in einen Block mit dem Namen sivasnr + zusammen und speichert das Ergebnis. attr_defs: Liste von (TAG, source_expression) aus der Config json_entry: Dict mit den JSON-Daten fuer dieses Element @@ -205,6 +226,9 @@ def add_attdefs_to_dxf(dxf_path, output_path, attr_defs, json_entry, sivasnr, y_pos += ATTDEF_SPACING count += 1 + # Alle Entities (Geometrie + ATTDEFs) in Block mit Sivasnr-Namen fassen + wrap_entities_in_block(doc, sivasnr) + doc.saveas(output_path) return count @@ -219,7 +243,7 @@ def process_all(data_dir, cfg_path, results_dir, single_nr=None, dry_run=False): # Config laden attr_config = load_config(cfg_path) layer_map = attr_config.pop("layer", {}) - print(f"[attradd] Config geladen: {list(attr_config.keys())}") + print(f"[set_attributs] Config geladen: {list(attr_config.keys())}") if layer_map: print(f" [layer] {len(layer_map)} Zuordnungen: " f"{', '.join(f'{k}={v}' for k, v in layer_map.items())}") @@ -231,7 +255,7 @@ def process_all(data_dir, cfg_path, results_dir, single_nr=None, dry_run=False): boegen = load_json(os.path.join(data_dir, "json", "omniflo_boegen.json")) weichen = load_json(os.path.join(data_dir, "json", "omniflo_weichen.json")) lookup = build_lookup(boegen, weichen) - print(f"[attradd] {len(boegen)} Boegen, {len(weichen)} Weichen geladen.") + print(f"[set_attributs] {len(boegen)} Boegen, {len(weichen)} Weichen geladen.") # Ausgabeverzeichnis out_dir = os.path.join(results_dir, "omniflo") @@ -284,10 +308,10 @@ def process_all(data_dir, cfg_path, results_dir, single_nr=None, dry_run=False): errors += 1 print(f" FEHLER: {sivasnr}: {e}") - print(f"\n[attradd] Fertig: {processed} verarbeitet, " + print(f"\n[set_attributs] Fertig: {processed} verarbeitet, " f"{skipped} uebersprungen, {errors} Fehler.") if not dry_run: - print(f"[attradd] Ausgabe in: {out_dir}") + print(f"[set_attributs] Ausgabe in: {out_dir}") def main(): @@ -317,7 +341,7 @@ def main(): cfg_path = os.path.join(cfg_dir, "attradd.cfg") if not os.path.exists(cfg_path): - print(f"[attradd] FEHLER: Config nicht gefunden: {cfg_path}") + print(f"[set_attributs] FEHLER: Config nicht gefunden: {cfg_path}") sys.exit(1) process_all(data_dir, cfg_path, results_dir,