diff --git a/bin/dxfs2lib.bat b/bin/dxfs2lib.bat new file mode 100644 index 0000000..14cdf5a --- /dev/null +++ b/bin/dxfs2lib.bat @@ -0,0 +1,10 @@ +@echo off +REM ~dp0 steht für das Verzeichnis, in der diese Datei liegt + +call setenv.bat + +REM Beispielaufruf mit Parametern: +REM --in: Ordner mit .dxf-Dateien (optional. Standard: work/converted_dxfs) +REM --name: Name der zu erzeugenden Bibliothek + +python %PROJECT_LIB%\dxf2lib.py %* \ No newline at end of file diff --git a/bin/svg2dxf.bat b/bin/svg2dxf.bat new file mode 100644 index 0000000..a8ba4c8 --- /dev/null +++ b/bin/svg2dxf.bat @@ -0,0 +1,10 @@ +@echo off +REM ~dp0 steht für das Verzeichnis, in der diese Datei liegt + +call setenv.bat + +REM Beispielaufruf mit Parametern: +REM --in: Ordner mit .svg bzw. .xml-Dateien (optional. Standard: data/svg) +REM --out: Zielverzeichnis (optional. Standard: work/converted_dxfs) + +python %PROJECT_LIB%\svg2dxf.py %* \ No newline at end of file diff --git a/lib/dxf2lib.py b/lib/dxf2lib.py new file mode 100644 index 0000000..b73a5b6 --- /dev/null +++ b/lib/dxf2lib.py @@ -0,0 +1,118 @@ +import os +import ezdxf +from ezdxf.math import Vec2 +import argparse +import sys +# Hilfsfunktion für Umgebungsvariablen mit Fallback + +def check_environment_var(env_str: str, fallback: str) -> str: + out_path = os.environ.get(env_str) + if out_path: + return out_path + print(f"[WARN] Umgebungsvariable {env_str} ist nicht gesetzt oder leer. Verwende '{fallback}'.") + return fallback + +def get_bbox(entities): + min_x, min_y = float('inf'), float('inf') + max_x, max_y = float('-inf'), float('-inf') + for e in entities: + try: + # Für POLYLINE-Entities: Bounding Box manuell berechnen + if e.dxftype() == "POLYLINE": + if hasattr(e, 'vertices') and len(e.vertices) > 0: + for vertex in e.vertices: + if hasattr(vertex, 'dxf') and hasattr(vertex.dxf, 'location'): + x, y = vertex.dxf.location.x, vertex.dxf.location.y + min_x, min_y = min(min_x, x), min(min_y, y) + max_x, max_y = max(max_x, x), max(max_y, y) + else: + # Für andere Entity-Typen: Standard bbox() verwenden + box = e.bbox() + if box: + (x1, y1), (x2, y2) = box.extmin, box.extmax + min_x, min_y = min(min_x, x1), min(min_y, y1) + max_x, max_y = max(max_x, x2), max(max_y, y2) + except Exception as err: + print(f" BBox Fehler für {e.dxftype()}: {err}") + continue + if min_x == float('inf'): + return None + return Vec2((min_x + max_x) / 2, (min_y + max_y) / 2) + +if __name__ == "__main__": + # Argumentparser für Kommandozeilenoptionen + parser = argparse.ArgumentParser(description="SVG/XML zu DXF Konverter") + parser.add_argument('-i', '--input', type=str, help='Input-Verzeichnis mit SVG/XML-Dateien') + parser.add_argument('-n', '--name', required=True, type=str, help='Name der zu erzeugenden Bibliothek') + + if len(sys.argv) == 2 and sys.argv[1] in ("-h", "--help"): + parser.print_help() + sys.exit(0) + + args = parser.parse_args() + + # Verzeichnisse über Umgebungsvariablen oder Fallback + if args.input: + INPUT_DIR = args.input + print(f"Verwende Input-Verzeichnis: {INPUT_DIR}") + else: + INPUT_DIR = os.path.join(check_environment_var("PROJECT_WORK", "."), "converted_dxfs") + print(f"Kein Input-Verzeichnis angegeben, verwende Standard: {INPUT_DIR}") + + OUTPUT_FILE = os.path.join(check_environment_var("PROJECT_DATA", "."),"block_libaries", f"{args.name}.dxf") + + doc = ezdxf.new() + msp = doc.modelspace() + + x_offset = 0 + y_offset = 0 + blocks_in_row = 0 + + for filename in os.listdir(INPUT_DIR): + if not filename.lower().endswith(".dxf"): + continue + + filepath = os.path.join(INPUT_DIR, filename) + name = os.path.splitext(filename)[0] + + try: + src_doc = ezdxf.readfile(filepath) + src_msp = src_doc.modelspace() + entities = list(src_msp) + allowed_types = {"LINE", "LWPOLYLINE", "POLYLINE", "SPLINE", "CIRCLE", "ARC"} + filtered_entities = [e for e in entities if e.dxftype() in allowed_types] + entities = filtered_entities + except Exception as e: + print(f"Fehler beim Lesen von {filename}: {e}") + continue + + center = get_bbox(entities) + if center is None: + print(f"Keine gültige Geometrie in {filename}") + continue + + if name in doc.blocks: + doc.blocks.delete_block(name) + + blk = doc.blocks.new(name=name, base_point=center) + + for e in entities: + try: + blk.add_entity(e.copy()) + except Exception as err: + print(f"Fehler in {filename}: {err}") + + # Platzierung in Reihen und Spalten + msp.add_blockref(name, insert=(x_offset, y_offset)) + # Text mit Blocknamen über dem Block + text_y = y_offset + 150 # 150 Einheiten über dem Block + msp.add_text(name, dxfattribs={'height': 20, 'insert': (x_offset-150, text_y)}) + blocks_in_row += 1 + x_offset += 350 # Abstand zwischen Blöcken in einer Reihe + if blocks_in_row == 20: + blocks_in_row = 0 + x_offset = 0 + y_offset -= 500 # Neue Zeile, nach unten versetzt + + print(f"Bibliotheks-DXF gespeichert: {OUTPUT_FILE}") + doc.saveas(OUTPUT_FILE) diff --git a/lib/svg2dxf.py b/lib/svg2dxf.py index a942832..2c21891 100644 --- a/lib/svg2dxf.py +++ b/lib/svg2dxf.py @@ -1,6 +1,7 @@ import os import subprocess import sys +import argparse # Hilfsfunktion wie in plant2dxf.py @@ -11,23 +12,48 @@ def check_environment_var(env_str: str, fallback: str) -> str: print(f"[WARN] Umgebungsvariable {env_str} ist nicht gesetzt oder leer. Verwende '{fallback}'.") return fallback -# Verzeichnisse über Umgebungsvariablen oder Fallback -INPUT_DIR = os.path.join(check_environment_var("PROJECT_WORK", "."), "input_svg") -OUTPUT_DIR = os.path.join(check_environment_var("PROJECT_WORK", "."), "converted_dxfs") -INKSCAPE = "inkscape" # ggf. vollständiger Pfad angeben -os.makedirs(OUTPUT_DIR, exist_ok=True) +if __name__ == "__main__": + # Argumentparser für Kommandozeilenoptionen + parser = argparse.ArgumentParser(description="SVG/XML zu DXF Konverter") + parser.add_argument('-i', '--input', type=str, help='Input-Verzeichnis mit SVG/XML-Dateien') + parser.add_argument('-o', '--output', type=str, help='Output-Verzeichnis für DXF-Dateien') + + if len(sys.argv) == 2 and sys.argv[1] in ("-h", "--help"): + parser.print_help() + sys.exit(0) + + args = parser.parse_args() -for filename in os.listdir(INPUT_DIR): - if filename.lower().endswith((".svg", ".xml")): - in_path = os.path.join(INPUT_DIR, filename) - name_wo_ext = os.path.splitext(filename)[0] - out_path = os.path.join(OUTPUT_DIR, name_wo_ext + ".dxf") + # Verzeichnisse über Umgebungsvariablen oder Fallback + if args.input: + INPUT_DIR = args.input + print(f"Input-Verzeichnis: {INPUT_DIR}") + else: + INPUT_DIR = os.path.join(check_environment_var("PROJECT_DATA", "."), "svg") + print(f"Kein Input-Verzeichnis angegeben, verwende Standard: {INPUT_DIR}") - print(f"Konvertiere: {filename} → {out_path}") - subprocess.run([ - INKSCAPE, - in_path, - "--export-type=dxf", - f"--export-filename={out_path}" - ], check=True) + if args.output: + OUTPUT_DIR = args.output + print(f"Output-Verzeichnis: {OUTPUT_DIR}") + else: + OUTPUT_DIR = os.path.join(check_environment_var("PROJECT_WORK", "."), "converted_dxfs") + print(f"Kein Output-Verzeichnis angegeben, verwende Standard: {OUTPUT_DIR}") + + INKSCAPE = "inkscape" # ggf. vollständiger Pfad angeben + + os.makedirs(OUTPUT_DIR, exist_ok=True) + + for filename in os.listdir(INPUT_DIR): + if filename.lower().endswith((".svg", ".xml")): + in_path = os.path.join(INPUT_DIR, filename) + name_wo_ext = os.path.splitext(filename)[0] + out_path = os.path.join(OUTPUT_DIR, name_wo_ext + ".dxf") + + print(f"Konvertiere: {filename} → {out_path}") + subprocess.run([ + INKSCAPE, + in_path, + "--export-type=dxf", + f"--export-filename={out_path}" + ], check=True)