From 2c697f87b9d6eb4d794aa2625e85a85fdf0e8909 Mon Sep 17 00:00:00 2001 From: lertlmaier Date: Wed, 23 Jul 2025 15:46:15 +0200 Subject: [PATCH] =?UTF-8?q?Erweiterung=20der=20Konfigurationsdatei=20`shap?= =?UTF-8?q?es.cfg`=20zur=20Unterst=C3=BCtzung=20zus=C3=A4tzlicher=20Formen?= =?UTF-8?q?=20und=20Anpassung=20der=20Funktionen=20zur=20Verarbeitung=20vo?= =?UTF-8?q?n=20"ILS=202.0=20Kreisel"=20und=20"ILS=202.0=20Gef=C3=A4llestre?= =?UTF-8?q?cke".=20Einf=C3=BChrung=20der=20Funktion=20`get=5Fshape=5Fcfg`?= =?UTF-8?q?=20zum=20Auslesen=20von=20Blocknamen=20und=20Offsets=20aus=20de?= =?UTF-8?q?r=20Konfiguration.=20Anpassung=20der=20Handler-Funktionen=20zur?= =?UTF-8?q?=20Verwendung=20dieser=20neuen=20Struktur.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cfg/shapes.cfg | 11 ++++- lib/plant2dxf.py | 104 +++++++++++++++++++++++++++++------------------ 2 files changed, 74 insertions(+), 41 deletions(-) diff --git a/cfg/shapes.cfg b/cfg/shapes.cfg index 430157a..c89a6d4 100644 --- a/cfg/shapes.cfg +++ b/cfg/shapes.cfg @@ -1,2 +1,9 @@ -[simple_types] -shape_names = ILS 2.0 Kreisel \ No newline at end of file +[ILS 2.0 Kreisel] +items = SP8, AN8 +offset_symb1 = 0,0 +offset_symb2 = 0,0 + +[ILS 2.0 Gefällestrecke] +items = AE DS, EE DS +offset_symb1 = 0,0 +offset_symb2 = 0,0 \ No newline at end of file diff --git a/lib/plant2dxf.py b/lib/plant2dxf.py index ceb7574..ef70592 100644 --- a/lib/plant2dxf.py +++ b/lib/plant2dxf.py @@ -16,18 +16,28 @@ import ezdxf from pathlib import Path import math -# --------------------------------------------------------- Mapping TeileArt → Blockname -BLOCKNAME_MAPPING = { - "ILS 2.0 Kreisel": ["SP8", "AN8"] - #"ILS 2.0 Gefällestrecke": ["AE DS", "EE DS"] - # Weitere Zuordnungen nach Bedarf -} - -# --------------------------------------------------------- On-the-fly-Typen (werden direkt im Code erzeugt) -ON_THE_FLY_TYPES = { - "ILS 2.0 Gefällestrecke", - # Weitere Typen nach Bedarf -} +# --------------------------------------------------------- CFG-Leser für shapes.cfg +def get_shape_cfg(teileart, cfg_path): + parser = configparser.ConfigParser() + with open(cfg_path, encoding='utf-8') as f: + parser.read_file(f) + section = teileart + if section not in parser: + return [], [] + # Blöcke + items = parser.get(section, "items", fallback="").replace('"', '').split(",") + blocks = [item.strip() for item in items if item.strip()] + # Offsets (optional) + offset1 = parser.get(section, "offset_symb1", fallback="0,0") + offset2 = parser.get(section, "offset_symb2", fallback="0,0") + offsets = [] + for off in (offset1, offset2): + try: + ox, oy = [float(x) for x in off.split(",")] + offsets.append((ox, oy)) + except Exception: + offsets.append((0.0, 0.0)) + return blocks, offsets # --------------------------------------------------------- Konstante Parameter ATTR_TAG = "TeileId" # Attributtag im Block @@ -110,7 +120,8 @@ def transform_coords(x: float, y: float, height: float) -> tuple[float, float]: """Transformiert Bildschirmkoordinaten (0,0 oben links) ins DXF-KoSy (0,0 unten links).""" return x, height - y -def handle_kreisel(msp, blocknames, teileid, merkmale, row, x, y, height, lib_doc, doc, verbose): +def handle_ils_2_0_kreisel(msp, teileid, merkmale, x, y, doc, lib_doc, verbose, blocks, offsets): + # blocks: [block1, block2], offsets: [(ox1, oy1), (ox2, oy2)] abstand_m = merkmale.get( "Abstand (Kreiselachse A - Kreiselachse) in Meter", "20" ).replace(",", ".") @@ -130,15 +141,15 @@ def handle_kreisel(msp, blocknames, teileid, merkmale, row, x, y, height, lib_do halbabstand = abstand / 2 dx = halbabstand * math.cos(winkel_rad) dy = halbabstand * math.sin(winkel_rad) - pos1 = (x - dx, y - dy) - pos2 = (x + dx, y + dy) + pos1 = (x - dx + offsets[0][0], y - dy + offsets[0][1]) + pos2 = (x + dx + offsets[1][0], y + dy + offsets[1][1]) positions = [pos1, pos2] - for blockname, pos in zip(blocknames, positions): + for blockname, pos in zip(blocks, positions): import_block(blockname, lib_doc, doc) bref = msp.add_blockref(blockname, pos) bref.add_auto_attribs({ATTR_TAG: teileid}) if verbose: - print(f"[INFO] Block '{blockname}' (CSV: 'ILS 2.0 Kreisel') → {teileid} " + print(f"[INFO] Block '{blockname}' (Kreisel) → {teileid} " f"({pos[0]:.1f}, {pos[1]:.1f})") # Linien zeichnen draw_kreisel_lines(msp, pos1, pos2) @@ -152,7 +163,8 @@ def handle_standard(msp, blocknames, teileid, x, y, lib_doc, doc, verbose): print(f"[INFO] Block '{blockname}' (Standard) → {teileid} " f"({x:.1f}, {y:.1f})") -def handle_gefaellestrecke(msp, teileid, merkmale, x, y, verbose): +def handle_ils_2_0_gefaellestrecke(msp, teileid, merkmale, x, y, doc, lib_doc, verbose, blocks, offsets): + # blocks: [block1, block2], offsets: [(ox1, oy1), (ox2, oy2)] # Länge der Strecke (in Meter, Standard 10) laenge_m = merkmale.get("Länge in Meter", "10").replace(",", ".") try: @@ -176,6 +188,33 @@ def handle_gefaellestrecke(msp, teileid, merkmale, x, y, verbose): msp.add_line(start, ende) if verbose: print(f"[INFO] Gefällestrecke → {teileid} Linie von ({start[0]:.1f}, {start[1]:.1f}) nach ({ende[0]:.1f}, {ende[1]:.1f})") + + # Blöcke am Anfang und Ende der Strecke aus der CFG platzieren + if len(blocks) >= 2 and lib_doc is not None: + block_start = blocks[0] + block_end = blocks[1] + import_block(block_start, lib_doc, doc) + bref1 = msp.add_blockref(block_start, (start[0] + offsets[0][0], start[1] + offsets[0][1])) + bref1.add_auto_attribs({ATTR_TAG: teileid}) + import_block(block_end, lib_doc, doc) + bref2 = msp.add_blockref(block_end, (ende[0] + offsets[1][0], ende[1] + offsets[1][1])) + bref2.add_auto_attribs({ATTR_TAG: teileid}) + if verbose: + print(f"[INFO] Block '{block_start}' an Startpunkt {start} und Block '{block_end}' an Endpunkt {ende} für {teileid}") + elif lib_doc is None: + print("[WARN] lib_doc nicht verfügbar, Blöcke werden nicht eingefügt.") + +def normalize_func_name(name): + return ( + name.replace('ä', 'ae') + .replace('ö', 'oe') + .replace('ü', 'ue') + .replace('ß', 'ss') + .replace(' ', '_') + .replace('.', '_') + .lower() + ) + # --------------------------------------------------------- Hauptfunktion def main(csv_path: Path, lib_path: Path, cfg_path: Path, output_path: Path, verbose=False): @@ -217,27 +256,14 @@ def main(csv_path: Path, lib_path: Path, cfg_path: Path, print(f"[WARN] {teileid}: {e}") continue - # On-the-fly-Typen (werden direkt im Code erzeugt) - if teileart in ON_THE_FLY_TYPES: - if teileart == "ILS 2.0 Gefällestrecke": - handle_gefaellestrecke(msp, teileid, merkmale, x, y, verbose) - continue - # Hier können weitere on-the-fly-Typen ergänzt werden - - # Blocktypen aus Mapping - blocknames = BLOCKNAME_MAPPING.get(teileart) - if blocknames: - if isinstance(blocknames, str): - blocknames = [blocknames] - if teileart == "ILS 2.0 Kreisel": - handle_kreisel(msp, blocknames, teileid, merkmale, row, x, y, height, lib_doc, doc, verbose) - continue - # Standardfall - handle_standard(msp, blocknames, teileid, x, y, lib_doc, doc, verbose) - continue - - # Weder on-the-fly noch im Mapping - print(f"[WARN] Keine Zuordnung für TeileArt '{teileart}'. Überspringe '{teileid}'.") + # Funktions-Dispatch: handle_ (mit _ statt Leerzeichen und Punkten, alles klein) + func_name = f'handle_{normalize_func_name(teileart)}' + handler = globals().get(func_name) + blocks, offsets = get_shape_cfg(teileart, cfg_path) + if handler: + handler(msp, teileid, merkmale, x, y, doc, lib_doc, verbose, blocks, offsets) + else: + print(f"[WARN] Keine Routine für TeileArt '{teileart}'. Überspringe '{teileid}'.") continue # DXF speichern