import os import ezdxf from ezdxf.math import Matrix44, Vec3, BoundingBox, Vec2 import math import argparse import sys import shutil import configparser from utils import check_environment_var, setup_logger from pathlib import Path import logging def create_block_library(input_dir, output_file, config, logger=None): """ Erstellt eine DXF-Block-Bibliothek aus einzelnen DXF-Dateien. Diese Funktion liest alle DXF-Dateien aus einem Verzeichnis und erstellt daraus eine Bibliothek mit Blöcken. Die Blöcke werden in einem Raster angeordnet und mit Beschriftungen versehen. Fehlerhafte Dateien werden protokolliert. Args: input_dir (str): Verzeichnis mit den zu verarbeitenden DXF-Dateien output_file (str): Pfad zur zu erstellenden Bibliotheks-DXF-Datei config: ConfigParser-Objekt mit den Konfigurationswerten logger: Optionaler Logger für Logging-Ausgaben Note: - Unterstützte Entity-Typen: LINE, LWPOLYLINE, POLYLINE, SPLINE, CIRCLE, ARC, INSERT - Blöcke werden zentriert und in einem 20x20 Raster angeordnet - Erstellt eine Log-Datei mit Zeitstempel für fehlerhafte Dateien - Automatische Erstellung des Output-Verzeichnisses falls nötig """ doc = ezdxf.new() msp = doc.modelspace() x_offset = 0 y_offset = 0 blocks_in_row = 0 error_files = [] processed_files = [] max_blockspacing_x = 0 max_blockspacing_y = 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", "INSERT", "ATTDEF", "3DFACE", "MESH", "POLYFACE", "POLYFACEMESH", "SURFACE", "3DSURFACE", "EXTRUDEDSURFACE", "REVOLVEDSURFACE", "LOFTEDSURFACE", "SWEPTSURFACE", } filtered_entities = [] att_def= {} for insert in src_msp.query("INSERT"): for attrib in insert.attribs: att_def[attrib.dxf.tag] = attrib.dxf.text for e in entities: if e.dxftype() in allowed_types: filtered_entities.append(e) else: logger.info(f"{e.dxftype()} is nicht in der erlaubten Liste. Diese befindet sich in {filename}") entities = filtered_entities except Exception as e: error_msg = f"Fehler beim Lesen von {filename}: {e}" if logger: logger.error(error_msg) else: print(error_msg) error_files.append((filename, error_msg)) continue # Sicherstellen, dass die im Quell-DXF verwendeten Layer im Zieldokument existieren try: used_layer_names = {e.dxf.layer for e in entities if hasattr(e.dxf, "layer")} for layer_name in used_layer_names: if layer_name and layer_name not in doc.layers: try: src_layer = src_doc.layers.get(layer_name) doc.layers.add( name=layer_name, color=getattr(src_layer.dxf, "color", None), linetype=getattr(src_layer.dxf, "linetype", None), lineweight=getattr(src_layer.dxf, "lineweight", None), ) except Exception: # Fallback: Layer mit Standardwerten anlegen doc.layers.add(name=layer_name) except Exception: pass boundingbox, ausdehnung, center = calculate_block_bounding_box(filtered_entities, doc,src_doc, filename,config) if center is None: error_msg = f"Keine gültige Geometrie in {filename}" if logger: logger.error(error_msg) else: print(error_msg) error_files.append((filename, error_msg)) continue if name in doc.blocks: doc.blocks.delete_block(name) blk = doc.blocks.new(name=name, base_point=(0,0)) for e in entities: cp = copy_entity(logger, error_files, filename, e, center) if cp: blk.add_entity(cp) # add_bounding_box_to_modelspace(blk, boundingbox, centered=True) # Platzierung in Reihen und Spalten # Attribut-Definition (ATTDEF) hinzufügen # Blockreferenz-Layer bestimmen blockref_layer = None try: #Konfiguration erlaubt expliziten Layernamen cfg_layer = None try: cfg_layer = config.get("dxf2lib", "blockref_layer") except Exception: cfg_layer = None if cfg_layer and cfg_layer.strip(): blockref_layer = cfg_layer.strip() else: # Dominanten Ursprungs-Layer verwenden (Mehrheit der Entities) layer_counts = {} for e in entities: ln = getattr(e.dxf, "layer", None) if not ln: continue layer_counts[ln] = layer_counts.get(ln, 0) + 1 if layer_counts: blockref_layer = max(layer_counts.items(), key=lambda kv: kv[1])[0] if blockref_layer and blockref_layer not in doc.layers: # Sicherstellen, dass der Layer existiert try: src_layer = src_doc.layers.get(blockref_layer) doc.layers.add( name=blockref_layer, color=getattr(src_layer.dxf, "color", None), linetype=getattr(src_layer.dxf, "linetype", None), lineweight=getattr(src_layer.dxf, "lineweight", None), ) except Exception: doc.layers.add(name=blockref_layer) except Exception: blockref_layer = None section = "dxf2lib" text_height = get_cfg_value(section, "text_height", DEFAULTS["text_height"]) extra_block_space_x = get_cfg_value(section, "extra_block_space_x", DEFAULTS["extra_block_space_x"]) blocks_per_row = get_cfg_value(section, "blocks_per_row", DEFAULTS["blocks_per_row"]) extra_text_space_y = get_cfg_value(section, "extra_text_space_y", DEFAULTS["extra_text_space_y"]) ausdehnung_x, ausdehung_y = ausdehnung[0], ausdehnung[1] block_spacing_y = ausdehung_y + 400 block_spacing_x = ausdehnung_x + extra_block_space_x max_blockspacing_x = max(max_blockspacing_x, block_spacing_x) max_blockspacing_y = max(max_blockspacing_y, block_spacing_y) x_offset += max_blockspacing_x # Blockreferenz mit optionalem Layer einfügen (Entity-Layer bleiben erhalten) if blockref_layer: test =msp.add_blockref(name, insert=(x_offset, y_offset), dxfattribs={"layer": blockref_layer}) else: test =msp.add_blockref(name, insert=(x_offset, y_offset)) # Text mit Blocknamen über dem Block if name == "a" or name == "b": for tag, value in att_def.items(): tag = tag value = value a =test.add_attrib( tag=tag, text=value, ) a.is_invisible = True # Werte aus Config holen (Block: [dxf2lib]) msp.add_text(name, dxfattribs={'height': text_height, 'insert': (x_offset -ausdehnung_x/2 , y_offset + ausdehung_y/2 + extra_text_space_y)}) processed_files.append(filename) blocks_in_row += 1 # Abstand zwischen Blöcken in einer Reihe if blocks_in_row == blocks_per_row: blocks_in_row = 0 x_offset = 0 y_offset -= max_blockspacing_y # Neue Zeile, nach unten versetzt max_blockspacing_y = 0 max_blockspacing_x = 0 if logger: logger.info(f"Bibliotheks-DXF gespeichert: {output_file}") logger.info(f"Verarbeitete Dateien: {len(processed_files)}") logger.info(f"Fehlerhafte Dateien: {len(error_files)}") if error_files: logger.warning(f"{len(error_files)} Dateien konnten nicht verarbeitet werden:") for filename, error_msg in error_files: logger.error(f"{filename}: {error_msg}") else: logger.info("Keine fehlerhaften Dateien gefunden.") else: print(f"Bibliotheks-DXF gespeichert: {output_file}") print(f"Verarbeitete Dateien: {len(processed_files)}") print(f"Fehlerhafte Dateien: {len(error_files)}") if error_files: print(f"Warnung: {len(error_files)} Dateien konnten nicht verarbeitet werden.") output_dir = output_file.parent if not output_dir.exists(): output_dir.mkdir(parents=True, exist_ok=True) doc.saveas(output_file) def copy_entity(logger, error_files, filename, e, center): try: cp = e.copy() # Geometrie verschieben! cp.translate(-center.x, -center.y,0) # Ursprungs-Layer übernehmen if hasattr(e.dxf, "layer"): cp.dxf.layer = e.dxf.layer if (hasattr(e.dxf, "color")): cp.dxf.color = e.dxf.color return cp except Exception as err: error_msg = f"Fehler beim Verarbeiten von Entity {e.dxftype()} in {filename}: {err}" if logger: logger.error(error_msg) else: print(error_msg) error_files.append((filename, error_msg)) return None # Standardwerte (falls nicht in der Config) DEFAULTS = { "text_height": 20, # Schriftgröße des Texts (in DXF-Einheiten) "blocks_per_row": 20, # Anzahl Blöcke pro Zeile im Raster "extra_block_space_x" : 50, # Extra Platz damit sich Blöcke nicht überlappen "extra_text_space_y" : 50 # Abstand der Überschrift über dem Symbol } def get_cfg_value(section, key, fallback): try: return int(config.get(section, key)) except Exception: return fallback def convert_dxf_to_block_with_inserts(input_filename, output_filename, block_name="CONVERTED_BLOCK"): """ Konvertiert alle Entities einer DXF-Datei in einen neuen Block INSERTs werden als Referenzen beibehalten (nicht explodiert) """ try: # Eingabe-DXF laden input_doc = ezdxf.readfile(input_filename) print(f"Lade DXF-Datei: {input_filename}") # Neue Ausgabe-DXF erstellen output_doc = ezdxf.new('R2010') output_doc.header['$INSUNITS'] = 4 # Millimeter # Zuerst alle Block-Definitionen kopieren copied_blocks = copy_block_definitions(input_doc, output_doc) print(f"Block-Definitionen kopiert: {len(copied_blocks)}") # Neuen Hauptblock erstellen new_block = output_doc.blocks.new(name=block_name) print(f"Erstelle neuen Block: {block_name}") # Alle Entities aus dem Modelspace kopieren msp = input_doc.modelspace() entity_count = 0 insert_count = 0 for entity in msp: if entity.dxftype() == 'INSERT': # INSERT direkt kopieren (nicht explodieren) copy_entity_to_block(entity, new_block) insert_count += 1 else: # Normale Entity kopieren copy_entity_to_block(entity, new_block) entity_count += 1 # Bounding Box berechnen bbox = calculate_block_bounding_box(new_block, output_doc) # Block im Modelspace der neuen Datei platzieren output_msp = output_doc.modelspace() output_msp.add_blockref(block_name, insert=(0, 0)) # Bounding Box als Hilfslinien hinzufügen (optional) if bbox.has_data: add_bounding_box_to_modelspace(output_msp, bbox) # Speichern output_doc.saveas(output_filename) print(f"Konvertierung abgeschlossen:") print(f" - {entity_count} Entities übertragen") print(f" - {insert_count} INSERTs als Referenzen beibehalten") print(f" - Bounding Box: {format_bounding_box(bbox)}") print(f" - Ausgabe: {output_filename}") return bbox except FileNotFoundError: print(f"Fehler: Datei {input_filename} nicht gefunden") return None except ezdxf.DXFStructureError as e: print(f"DXF-Strukturfehler: {e}") return None except Exception as e: print(f"Unerwarteter Fehler: {e}") return None def copy_block_definitions(source_doc, target_doc): """ Kopiert alle Block-Definitionen vom Quell- zum Ziel-Dokument """ copied_blocks = [] for block_name in source_doc.blocks: # Standard-Blöcke (MODEL_SPACE, PAPER_SPACE) überspringen if block_name.startswith('*'): continue source_block = source_doc.blocks[block_name] # Prüfen ob Block bereits existiert if block_name in target_doc.blocks: print(f"Warnung: Block '{block_name}' existiert bereits, wird übersprungen") continue # Neuen Block in Ziel-Dokument erstellen target_block = target_doc.blocks.new(name=block_name) # Alle Entities des Quell-Blocks kopieren for entity in source_block: copy_entity_to_block(entity, target_block) copied_blocks.append(block_name) return copied_blocks def calculate_block_bounding_box(block, doc, src_doc, filename,config): """ Berechnet die Bounding Box eines Blocks inklusive aller INSERTs """ bbox = BoundingBox() for entity in block: entity_bbox = get_entity_bounding_box(entity, doc,src_doc,filename,config) if entity_bbox and entity_bbox.has_data: bbox.extend(entity_bbox) return bbox, (bbox.extmax.x -bbox.extmin.x, bbox.extmax.y -bbox.extmin.y),bbox.center def _bbox_from_virtual_entities(entity, doc, src_doc, filename, config, transform_matrix=None): """ Nutzt virtual_entities(), um komplexe Objekte (z.B. SURFACE) in auswertbare Geometrie zu zerlegen und darauf eine Bounding Box zu berechnen. """ v_bbox = BoundingBox() if not hasattr(entity, "virtual_entities"): return v_bbox try: for ve in entity.virtual_entities(): ve_bbox = get_entity_bounding_box( ve, doc, src_doc, filename, config, transform_matrix ) if ve_bbox and ve_bbox.has_data: v_bbox.extend(ve_bbox) except Exception as err: print(f"Fehler bei virtual_entities() für {entity.dxftype()}: {err}") return v_bbox def get_entity_bounding_box(e, doc,src_doc,filename,config, transform_matrix=None): """ Berechnet die Bounding Box einer einzelnen Entity Berücksichtigt INSERTs mit ihren Block-Inhalten """ bbox = BoundingBox() try: if e.dxftype() == 'LINE': start = Vec3(e.dxf.start) end = Vec3(e.dxf.end) if transform_matrix: start = transform_matrix.transform(start) end = transform_matrix.transform(end) bbox.extend([start]) bbox.extend([end]) elif e.dxftype() == 'CIRCLE': # Kreis durch Punktabtastung (robust bei Transformationen) center = Vec3(e.dxf.center) radius = float(e.dxf.radius) angles = (0.0, math.pi / 2, math.pi, 3 * math.pi / 2) points = [] for ang in angles: px = center.x + radius * math.cos(ang) py = center.y + radius * math.sin(ang) p = Vec3(px, py, center.z) if transform_matrix: p = transform_matrix.transform(p) points.append(p) if points: bbox.extend(points) elif e.dxftype() == 'ARC': # Bogen durch Punktabtastung zwischen Start- und Endwinkel center = Vec3(e.dxf.center) radius = float(e.dxf.radius) start_deg = float(e.dxf.start_angle) end_deg = float(e.dxf.end_angle) start = math.radians(start_deg % 360) end = math.radians(end_deg % 360) def in_sweep(a: float, s: float, e_: float) -> bool: # CCW sweep von s nach e_ mit Wrap-Handling if e_ >= s: return s <= a <= e_ return a >= s or a <= e_ angles = [start, end] for ang in (0.0, math.pi / 2, math.pi, 3 * math.pi / 2): if in_sweep(ang, start, end): angles.append(ang) points = [] for ang in angles: px = center.x + radius * math.cos(ang) py = center.y + radius * math.sin(ang) p = Vec3(px, py, center.z) if transform_matrix: p = transform_matrix.transform(p) points.append(p) if points: bbox.extend(points) elif e.dxftype() == 'LWPOLYLINE': # Nutze virtuelle Entities (Linien/Bögen), inkl. Bulge-Unterstützung ve_bbox = _bbox_from_virtual_entities( e, doc, src_doc, filename, config, transform_matrix ) if ve_bbox.has_data: bbox.extend(ve_bbox) elif e.dxftype() == 'POLYLINE': # 2D/3D Polylines ebenfalls über virtuelle Entities ve_bbox = _bbox_from_virtual_entities( e, doc, src_doc, filename, config, transform_matrix ) if ve_bbox.has_data: bbox.extend(ve_bbox) elif e.dxftype() == '3DFACE': # 3DFace: direkte Eckpunkte verwenden pts = [] try: pts = [Vec3(p) for p in e.get_points()] # ezdxf API except Exception: try: pts = [Vec3(v.dxf.location) for v in e.vertices] except Exception: pts = [] if transform_matrix: pts = [transform_matrix.transform(p) for p in pts] if pts: bbox.extend(pts) elif e.dxftype() in {'MESH', 'POLYFACE', 'POLYFACEMESH'}: # Mesh/Polyface über virtuelle Geometrie auswerten ve_bbox = _bbox_from_virtual_entities( e, doc, src_doc, filename, config, transform_matrix ) if ve_bbox.has_data: bbox.extend(ve_bbox) elif e.dxftype() == 'SPLINE': # Approximation der Spline-Kurve try: pts = list(e.approximate(60)) except Exception: try: pts = list(e.flattening(1.0)) except Exception: pts = [] sampled = [] for pt in pts: try: vx, vy = pt.x, pt.y except Exception: vx, vy = pt[0], pt[1] v = Vec3(vx, vy, 0) if transform_matrix: v = transform_matrix.transform(v) sampled.append(v) if sampled: bbox.extend(sampled) elif e.dxftype() == 'ATTDEF': # Vereinfachung: Nur Insert-Point berücksichtigen insert_point = Vec3(e.dxf.insert) if transform_matrix: insert_point = transform_matrix.transform(insert_point) elif e.dxftype().endswith('SURFACE'): # Viele Surface-Typen liefern ihre Proxy-Geometrie über virtual_entities() ve_bbox = _bbox_from_virtual_entities( e, doc, src_doc, filename, config, transform_matrix ) if ve_bbox.has_data: bbox.extend(ve_bbox) elif e.dxftype() == 'INSERT': # INSERT: Block-Inhalt mit Transformation berücksichtigen insert_bbox = calculate_insert_bounding_box(e, doc,src_doc,filename,config, transform_matrix) if insert_bbox and insert_bbox.has_data and e.dxf.layer not in config.get("dxf2lib","automation_layer"): bbox.extend(insert_bbox) except Exception as e: print(f"Fehler bei Bounding Box Berechnung für {e.dxftype()}: {e}") return bbox def extract_scaling(matrix): sx = math.sqrt(matrix[0, 0]**2 + matrix[0, 1]**2 + matrix[0, 2]**2) sy = math.sqrt(matrix[1, 0]**2 + matrix[1, 1]**2 + matrix[1, 2]**2) return sx, sy, def calculate_insert_bounding_box(insert_entity, doc,src_doc,filename,config,parent_transform=None): """ Berechnet die Bounding Box eines INSERTs inklusive Block-Inhalt """ try: # Block-Definition finden block_name = insert_entity.dxf.name src_blk = src_doc.blocks[block_name] if block_name in doc.blocks: dst_blk = doc.blocks[block_name] new_insert = False else: dst_blk = doc.blocks.new(name=block_name) new_insert = True if block_name not in src_doc.blocks: print(f"Warnung: Block '{block_name}' ") return BoundingBox() block_def = src_blk # Transformation der INSERT-Entity berechnen insert_transform = get_insert_transform_matrix(insert_entity) # Mit übergeordneter Transformation kombinieren if parent_transform: combined_transform = parent_transform * insert_transform else: combined_transform = insert_transform # Bounding Box aller Entities im Block berechnen block_bbox = BoundingBox() for block_entity in block_def: entity_bbox= get_entity_bounding_box(block_entity, doc,src_doc,filename, config,combined_transform) if entity_bbox and entity_bbox.has_data: if new_insert: dst_blk.add_entity(block_entity.copy()) block_bbox.extend(entity_bbox) return block_bbox except Exception as e: print(f"Fehler bei INSERT Bounding Box: {e},{filename}") return BoundingBox() def get_insert_transform_matrix(insert_entity): """ Berechnet die Transformationsmatrix für einen INSERT """ # Position insert_point = Vec3(insert_entity.dxf.insert) # Skalierung xscale = getattr(insert_entity.dxf, 'xscale', 1.0) yscale = getattr(insert_entity.dxf, 'yscale', 1.0) zscale = getattr(insert_entity.dxf, 'zscale', 1.0) # Rotation (in Radiant umwandeln) rotation = math.radians(getattr(insert_entity.dxf, 'rotation', 0.0)) # Transformationsmatrix erstellen matrix = Matrix44.chain( Matrix44.scale(xscale, yscale, zscale), Matrix44.z_rotate(rotation), Matrix44.translate(insert_point.x, insert_point.y, insert_point.z) ) return matrix def copy_entity_to_block(entity, target_block): """ Kopiert eine Entity in einen Zielblock """ try: # Entity kopieren und zum Block hinzufügen entity_copy = entity.copy() target_block.add_entity(entity_copy) except Exception as e: print(f"Fehler beim Kopieren von {entity.dxftype()}: {e}") def add_bounding_box_to_modelspace(msp, bbox, centered=False): """ Fügt die Bounding Box als Hilfslinien zum Modelspace hinzu. Wenn centered=True, wird das Rechteck um den Ursprung (0,0) zentriert und ein roter Punkt in die Mitte gesetzt. """ if not bbox.has_data: return # Bounding Box Rechteck zeichnen min_pt = bbox.extmin max_pt = bbox.extmax width = max_pt.x - min_pt.x height = max_pt.y - min_pt.y if centered: # Rechteck um (0,0) zentriert left = -width / 2.0 right = width / 2.0 bottom = -height / 2.0 top = height / 2.0 bbox_points = [ (left, bottom), (right, bottom), (right, top), (left, top), (left, bottom) ] # Roter Punkt in der Mitte msp.add_circle(center=(0.0, 0.0), radius=max(0.5, min(width, height) * 0.01), dxfattribs={"layer": "BOUNDING_BOX", "color": 1}) else: # Ursprüngliche, nicht-zentrierte Bounding Box bbox_points = [ (min_pt.x, min_pt.y), (max_pt.x, min_pt.y), (max_pt.x, max_pt.y), (min_pt.x, max_pt.y), (min_pt.x, min_pt.y) ] bbox_poly = msp.add_lwpolyline(bbox_points) bbox_poly.dxf.layer = "BOUNDING_BOX" bbox_poly.dxf.color = 1 # Rot # Text mit Abmessungen text_pos = Vec3(bbox_points[0][0], (bbox_points[2][1] if centered else max_pt.y) + 5, 0) msp.add_text(f"Breite: {width:.2f} mm", height=3, dxfattribs={'insert': text_pos, 'layer': "BOUNDING_BOX", 'color': 1}) text_pos2 = Vec3(bbox_points[0][0], (bbox_points[2][1] if centered else max_pt.y) + 10, 0) msp.add_text(f"Höhe: {height:.2f} mm", height=3, dxfattribs={'insert': text_pos2, 'layer': "BOUNDING_BOX", 'color': 1}) def format_bounding_box(bbox): """ Formatiert Bounding Box Information für Ausgabe """ if not bbox.has_data: return "Keine gültigen Geometriedaten gefunden" min_pt = bbox.extmin max_pt = bbox.extmax width = max_pt.x - min_pt.x height = max_pt.y - min_pt.y depth = max_pt.z - min_pt.z return (f"Min: ({min_pt.x:.2f}, {min_pt.y:.2f}, {min_pt.z:.2f}) " f"Max: ({max_pt.x:.2f}, {max_pt.y:.2f}, {max_pt.z:.2f}) " f"Größe: {width:.2f} × {height:.2f} × {depth:.2f} mm") def analyze_source_dxf_with_blocks(filename): """ Analysiert die Quell-DXF inklusive Block-Definitionen """ try: doc = ezdxf.readfile(filename) msp = doc.modelspace() entity_types = {} layer_count = {} insert_blocks = {} block_definitions = {} # Modelspace analysieren for entity in msp: entity_type = entity.dxftype() entity_types[entity_type] = entity_types.get(entity_type, 0) + 1 layer = getattr(entity.dxf, 'layer', '0') layer_count[layer] = layer_count.get(layer, 0) + 1 if entity_type == 'INSERT': block_name = entity.dxf.name insert_blocks[block_name] = insert_blocks.get(block_name, 0) + 1 # Block-Definitionen analysieren for block_name in doc.blocks: if not block_name.startswith('*'): # Keine Standard-Blöcke block_def = doc.blocks[block_name] entity_count = len(list(block_def)) block_definitions[block_name] = entity_count print(f"\nAnalyse von {filename}:") print("=" * 50) print("Entity-Typen im Modelspace:") for etype, count in sorted(entity_types.items()): print(f" {etype}: {count}") print(f"\nLayer ({len(layer_count)}):") for layer, count in sorted(layer_count.items()): print(f" {layer}: {count} entities") if insert_blocks: print(f"\nINSERT-Verwendungen ({sum(insert_blocks.values())} total):") for block, count in sorted(insert_blocks.items()): print(f" {block}: {count}× verwendet") if block_definitions: print(f"\nBlock-Definitionen ({len(block_definitions)}):") for block, count in sorted(block_definitions.items()): print(f" {block}: {count} entities") return entity_types, layer_count, insert_blocks, block_definitions except Exception as e: print(f"Fehler bei der Analyse: {e}") return {}, {}, {}, {} 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=False, type=str, help='Name der zu erzeugenden Bibliothek (optional, wird sonst abgefragt)', default="test") if len(sys.argv) == 2 and sys.argv[1] in ("-h", "--help"): parser.print_help() sys.exit(0) args = parser.parse_args() if not args.name: args.name = input("Bitte Namen der zu erzeugenden Bibliothek eingeben: ").strip() if not args.name: print("Fehler: Kein Name angegeben. Beende.") sys.exit(1) # Verzeichnisse über Umgebungsvariablen oder Fallback if args.input: INPUT_DIR = Path(args.input) print(f"Verwende Input-Verzeichnis: {INPUT_DIR} \n") else: INPUT_DIR = check_environment_var("PROJECT_DATA") / "omniflo" print(f"Kein Input-Verzeichnis angegeben, verwende Standard: {INPUT_DIR} \n") OUTPUT_FILE = check_environment_var("PROJECT_DATA") / "block_libraries" / f"{args.name}.dxf" # Prüfe und erstelle log-Verzeichnis falls nötig log_dir = check_environment_var("PROJECT_LOG") if not log_dir.exists(): log_dir.mkdir(parents=True, exist_ok=True) print(f"Log-Verzeichnis erstellt: {log_dir}") # Logger Setup log_file = Path(os.environ['PROJECT_LOG']) / 'dxf2lib.log' file_handler = logging.FileHandler(str(log_file), 'a', 'utf-8') logger = setup_logger(log_dir, name='dxf2lib') logger.info("=== DXF2LIB Verarbeitung gestartet ===") logger.info(f"Input-Verzeichnis: {INPUT_DIR}") logger.info(f"Output-Datei: {OUTPUT_FILE}") logger.addHandler(file_handler) # Lade Config-Datei config = configparser.ConfigParser() config_path = check_environment_var("PROJECT_CFG") / "allgemein.cfg" config.read(config_path, encoding="utf-8") logger.info(f"Config-Datei geladen: {config_path}") # Erstelle die Block-Bibliothek logger.info(f"Erstelle Block-Bibliothek aus {INPUT_DIR}...") create_block_library(INPUT_DIR, OUTPUT_FILE, config, logger) logger.info("=== DXF2LIB Verarbeitung abgeschlossen ===")