From e214e9d21ee3cdbdd01f96a3acf7ca302bf4e3e9 Mon Sep 17 00:00:00 2001 From: mistangl Date: Mon, 26 Jan 2026 19:09:02 +0100 Subject: [PATCH] =?UTF-8?q?Ausserhalb=20der=20Bereiche=20liegende=20Symbol?= =?UTF-8?q?e=20werden=20im=20dxf=20von=20einem=20Kreis=20umgeben,=20um=20n?= =?UTF-8?q?eben=20der=20Consoleausgabe=20auch=20ein=20graphisches=20Feedba?= =?UTF-8?q?ck=20zu=20bekommen.=20Angabe=20des=20Einf=C3=BCgepunktes=20am?= =?UTF-8?q?=20Symbol=20in=20der=20Config=20m=C3=B6glich.=20Der=20MA=20Bloc?= =?UTF-8?q?k=20kann=20im=20Zentrum,=20an=20der=20linken=20oberen=20Ecke=20?= =?UTF-8?q?etc.=20positioniert=20werden.=20Nummerierung2=20wurde=20vergr?= =?UTF-8?q?=C3=B6ssert,=20damit=20die=20Symbole=20sich=20nicht=20=C3=BCber?= =?UTF-8?q?schneiden.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cfg/create_tests.json | 54 +++---- lib/create_example.py | 351 ++++++++++++++++++++++++++++++++++++------ lib/create_numbers.py | 37 ++++- 3 files changed, 365 insertions(+), 77 deletions(-) diff --git a/cfg/create_tests.json b/cfg/create_tests.json index 97e1d57..358bf42 100644 --- a/cfg/create_tests.json +++ b/cfg/create_tests.json @@ -71,70 +71,70 @@ }, "Nummerierung2": { - "description": "Test-Szene mit komplexem Layout - 8 MA-1@@ Symbole in verschiedenen Anordnungen", + "description": "Test-Szene mit zirkulärer Nummerierung des Layouts - 8 MA-1@@ Symbole entlang einer Polyline nummerieren", "ma_groups": [ { "name": "MA-1@@_top_left", "count": 1, "layout_type": "single", - "base_x": 200, - "base_y": 1400, + "base_x": 400, + "base_y": 2800, "spacing": 0 }, { "name": "MA-1@@_top_right", "count": 1, "layout_type": "single", - "base_x": 240000, - "base_y": 1400, + "base_x": 4800, + "base_y": 2800, "spacing": 0 }, { "name": "MA-1@@_middle_left", "count": 1, "layout_type": "single", - "base_x": 600, - "base_y": 900, + "base_x": 1200, + "base_y": 1800, "spacing": 0 }, { "name": "MA-1@@_middle_right", "count": 1, "layout_type": "single", - "base_x": 1700, - "base_y": 900, + "base_x": 3400, + "base_y": 1800, "spacing": 0 }, { "name": "MA-1@@_bottom_center", "count": 1, "layout_type": "single", - "base_x": 1240, - "base_y": 400, + "base_x": 2480, + "base_y": 800, "spacing": 0 }, { "name": "MA-1@@_right_top", "count": 1, "layout_type": "single", - "base_x": 3200, - "base_y": 1200, + "base_x": 6400, + "base_y": 2400, "spacing": 0 }, { "name": "MA-1@@_right_middle", "count": 1, "layout_type": "single", - "base_x": 3200, - "base_y": 700, + "base_x": 6400, + "base_y": 1400, "spacing": 0 }, { "name": "MA-1@@_right_bottom", "count": 1, "layout_type": "single", - "base_x": 3040, - "base_y": 400, + "base_x": 6080, + "base_y": 800, "spacing": 0 } ], @@ -147,15 +147,15 @@ "layer_name": "ILS_MOTOR", "direction": "POLYLINE_PATH", "path_points": [ - {"x": 200, "y": 1400}, - {"x": 2400, "y": 1400}, - {"x": 3200, "y": 1200}, - {"x": 3200, "y": 700}, - {"x": 3040, "y": 400}, - {"x": 1240, "y": 400}, - {"x": 600, "y": 900}, - {"x": 1700, "y": 900}, - {"x": 200, "y": 1400} + {"x": 400, "y": 2800}, + {"x": 4800, "y": 2800}, + {"x": 6400, "y": 2400}, + {"x": 6400, "y": 1400}, + {"x": 6080, "y": 800}, + {"x": 2480, "y": 800}, + {"x": 3400, "y": 1800}, + {"x": 1200, "y": 1800}, + {"x": 400, "y": 2800} ] } ] @@ -194,6 +194,8 @@ "_description": "MA Frame-Typ Attribute (einfache Frames für MA, MG, etc.)", "layer": "ILS_RENAMER", "color": 1, + "insert_point": "center", + "_insert_point_description": "Einfügepunkt für MA-Blöcke. Mögliche Werte: left_top_corner, left_bottom_corner, right_top_corner, right_bottom_corner, center, top_center, bottom_center", "attdef_positions": { "_description": "ATTDEF Positionen im inneren Block RENAMER_ATTRIB_MA", "NAME": { diff --git a/lib/create_example.py b/lib/create_example.py index 1c9f9e9..1727686 100644 --- a/lib/create_example.py +++ b/lib/create_example.py @@ -88,6 +88,7 @@ class TestDataGenerator: {'name': '0', 'color': 7}, # Standard-Layer {'name': 'ILS_MOTOR', 'color': 7}, {'name': 'ILS_RENAMER', 'color': 1}, # Rot + {'name': 'VALIDATION_ERROR', 'color': 1}, # Rot für Fehlerkreise {'name': 'TEXT-D', 'color': -7}, # Ausgeschaltet (negativ) {'name': 'TEXT-E', 'color': 7}, {'name': 'TEXT-ES', 'color': 7}, @@ -573,7 +574,31 @@ class TestDataGenerator: else: print("Fehler in Config ... terminating") - def _generate_ma_group(self, group, ma_defaults, width_per_char, fixed_height, spacing_factor, y_offsets_list): + def _calculate_insert_offset(self, insert_point, symbol_width, symbol_height): + """ + Berechnet den Offset vom Einfügepunkt zur linken oberen Ecke + + Args: + insert_point: String mit dem Einfügepunkt (z.B. "left_top_corner", "center") + symbol_width: Breite des Symbols + symbol_height: Höhe des Symbols + + Returns: + (offset_x, offset_y) - Offset vom Einfügepunkt zur linken oberen Ecke + """ + offset_map = { + 'left_top_corner': (0, 0), + 'left_bottom_corner': (0, symbol_height), + 'right_top_corner': (-symbol_width, 0), + 'right_bottom_corner': (-symbol_width, symbol_height), + 'center': (-symbol_width / 2, symbol_height / 2), + 'top_center': (-symbol_width / 2, 0), + 'bottom_center': (-symbol_width / 2, symbol_height) + } + + return offset_map.get(insert_point, (0, 0)) # Default: left_top_corner + + def _generate_ma_group(self, group, ma_defaults, width_per_char, fixed_height, spacing_factor, y_offsets_list, insert_point='left_top_corner'): """ Generiert eine Gruppe von MA-Symbolen @@ -584,6 +609,7 @@ class TestDataGenerator: fixed_height: Fixe Symbol-Höhe spacing_factor: Spacing-Faktor zwischen Symbolen y_offsets_list: Liste von Y-Offsets für horizontal_offset Layout + insert_point: Einfügepunkt des Blocks (z.B. "left_top_corner", "center") """ name = group['name'] count = group['count'] @@ -607,6 +633,9 @@ class TestDataGenerator: attributes = ma_defaults.get('attributes', {}) layer = ma_defaults.get('layer', 'ILS_MOTOR') + # Berechne Offset basierend auf Einfügepunkt + offset_x, offset_y = self._calculate_insert_offset(insert_point, symbol_width, fixed_height) + # Generiere Symbole basierend auf Layout-Typ for i in range(count): if layout_type == 'single': @@ -622,12 +651,15 @@ class TestDataGenerator: print(f"Unbekannter Layout-Typ: {layout_type}") continue + # Berechne die linke obere Ecke basierend auf dem Einfügepunkt + left_top_x = x + offset_x + left_top_y = y + offset_y - + # DXF-Block wird an der linken unteren Ecke eingefügt + # (da der io-Block bei (0,0) startet und nach oben geht) blockref = self.msp.add_blockref( 'io', - #insert=(block_insert_x, block_insert_y), - insert=(x, y), + insert=(left_top_x, left_top_y - fixed_height), dxfattribs={'layer': layer} ) @@ -637,11 +669,12 @@ class TestDataGenerator: attrib_values['BEZEICHNUNG'] = f"Motor {io_pattern}" blockref.add_auto_attribs(attrib_values) - + # Speichere Symbol-Position für spätere Validierung + # Speichere immer die linke obere Ecke self.generated_symbols.append({ - 'x': x, - 'y': y, + 'x': left_top_x, + 'y': left_top_y, 'io': io_pattern, 'group_name': name, 'layer': layer @@ -668,9 +701,13 @@ class TestDataGenerator: spacing_factor = layout.get('symbol_spacing_factor', 1.2) y_offsets_list = layout.get('horizontal_offset_y_offsets', [0, -50, 50]) + # Hole Einfügepunkt aus Config (default: left_top_corner) + ma_frame = general.get('ma_frame', {}) + insert_point = ma_frame.get('insert_point', 'left_top_corner') + # Generiere MA-Gruppen aus Config for group in scene.get('ma_groups', []): - self._generate_ma_group(group, ma_defaults, width_per_char, fixed_height, spacing_factor, y_offsets_list) + self._generate_ma_group(group, ma_defaults, width_per_char, fixed_height, spacing_factor, y_offsets_list, insert_point) # Generiere Renamer-Rahmen aus Config for frame_config in scene.get('renaming_frames', []): @@ -704,16 +741,46 @@ class TestDataGenerator: def _point_in_rectangle(self, point, rect_x, rect_y, rect_width, rect_height): """ Prüft ob ein Punkt innerhalb eines Rechtecks liegt. - + Args: point: (x, y) Tupel rect_x, rect_y: Linke obere Ecke des Rechtecks rect_width, rect_height: Breite und Höhe des Rechtecks """ x, y = point - return (rect_x <= x <= rect_x + rect_width and + return (rect_x <= x <= rect_x + rect_width and rect_y <= y <= rect_y + rect_height) + def _calculate_shift_to_rectangle(self, point, rect_x, rect_y, rect_width, rect_height): + """ + Berechnet den minimalen Verschiebungsvektor, um einen Punkt in ein Rechteck zu verschieben. + + Args: + point: (x, y) Tupel + rect_x, rect_y: Linke untere Ecke des Rechtecks + rect_width, rect_height: Breite und Höhe des Rechtecks + + Returns: + (delta_x, delta_y) - Verschiebungsvektor + """ + x, y = point + delta_x = 0 + delta_y = 0 + + # Berechne Verschiebung in x-Richtung + if x < rect_x: + delta_x = rect_x - x + elif x > rect_x + rect_width: + delta_x = (rect_x + rect_width) - x + + # Berechne Verschiebung in y-Richtung + if y < rect_y: + delta_y = rect_y - y + elif y > rect_y + rect_height: + delta_y = (rect_y + rect_height) - y + + return (delta_x, delta_y) + def _point_in_polygon(self, point, polygon): """ Prüft, ob ein Punkt innerhalb eines Polygons liegt (Ray-casting Algorithmus). @@ -736,34 +803,109 @@ class TestDataGenerator: return inside + def _circle_intersects_polyline(self, center, radius, polyline): + """ + Prüft ob ein Kreis mit Mittelpunkt 'center' und Radius 'radius' + irgendein Segment der Polylinie schneidet. + + Args: + center: (x, y) Mittelpunkt des Kreises + radius: Radius des Kreises + polyline: Liste von (x, y) Punkten der Polylinie + + Returns: + True wenn der Kreis die Polylinie schneidet + """ + cx, cy = center + + # Prüfe jedes Segment der Polylinie + for i in range(len(polyline) - 1): + p1 = polyline[i] + p2 = polyline[i + 1] + + # Berechne den kürzesten Abstand vom Kreis-Mittelpunkt zum Linien-Segment + dist = self._distance_point_to_segment(center, p1, p2) + + # Wenn Abstand <= Radius, dann gibt es eine Schnittmenge + if dist <= radius: + return True + + return False + + def _distance_point_to_segment(self, point, seg_start, seg_end): + """ + Berechnet den kürzesten Abstand von einem Punkt zu einem Linien-Segment. + + Args: + point: (x, y) Punkt + seg_start: (x, y) Start des Segments + seg_end: (x, y) Ende des Segments + + Returns: + Kürzester Abstand + """ + px, py = point + x1, y1 = seg_start + x2, y2 = seg_end + + # Vektor von seg_start zu seg_end + dx = x2 - x1 + dy = y2 - y1 + + # Spezialfall: Segment ist ein Punkt + if dx == 0 and dy == 0: + return ((px - x1)**2 + (py - y1)**2)**0.5 + + # Parameter t für die Projektion des Punktes auf die Linie + # t = 0 bedeutet seg_start, t = 1 bedeutet seg_end + t = max(0, min(1, ((px - x1) * dx + (py - y1) * dy) / (dx * dx + dy * dy))) + + # Nächster Punkt auf dem Segment + closest_x = x1 + t * dx + closest_y = y1 + t * dy + + # Abstand vom Punkt zum nächsten Punkt auf dem Segment + return ((px - closest_x)**2 + (py - closest_y)**2)**0.5 + def _validate_symbols_in_frames(self, scene): """ Prüft ob alle generierten Symbole aus ma_groups in mindestens einem Renamer-Frame liegen. - Gibt Warnungen aus für Symbole, die außerhalb liegen. + + Für POLYLINE_PATH Frames: Prüft ob die Polylinie einen Kreis um das Symbol schneidet + Für andere Frames: Prüft ob das Symbol innerhalb des Frames liegt + + Gibt Warnungen aus für Symbole, die nicht die Kriterien erfüllen. """ if not self.generated_symbols: return - + print("\n" + "="*60) print("Prüfe ob alle generierten Symbole in Renamer-Frames liegen") print("="*60) - + + # Hole Symbol-Dimensionen aus Config + dimensions = self.config.get('ma_defaults', {}).get('dimensions', {}) + width_per_char = dimensions.get('width_per_char', 201.49) + fixed_height = dimensions.get('fixed_height', 380.94) + # Sammle alle Frame-Boundaries frame_boundaries = [] for frame_config in scene.get('renaming_frames', []): frame_type = frame_config.get('type', 'rectangle') + direction = frame_config.get('direction', '') layer_name = frame_config.get('layer_name', '') - - if frame_type == 'polyline_path': + + if frame_type == 'polyline_path' or direction == 'POLYLINE_PATH': # Polyline-Pfad: verwende path_points direkt path_points = frame_config.get('path_points', []) if path_points: - polygon = [(p['x'], p['y']) for p in path_points] + polyline = [(p['x'], p['y']) for p in path_points] frame_boundaries.append({ - 'type': 'polygon', - 'boundary': polygon, + 'validation_type': 'polyline_path', + 'polyline': polyline, 'name': frame_config.get('name', 'UNKNOWN'), - 'layer_name': layer_name + 'layer_name': layer_name, + 'direction': direction }) else: # Rechteck: berechne Eckpunkte @@ -771,7 +913,7 @@ class TestDataGenerator: rect_y = frame_config.get('y', 0) rect_width = frame_config.get('width', 0) rect_height = frame_config.get('height', 0) - + # Erstelle Rechteck als Polygon (4 Eckpunkte) polygon = [ (rect_x, rect_y), @@ -780,29 +922,60 @@ class TestDataGenerator: (rect_x, rect_y + rect_height) ] frame_boundaries.append({ - 'type': 'rectangle', + 'validation_type': 'containment', 'boundary': polygon, 'rect_x': rect_x, 'rect_y': rect_y, 'rect_width': rect_width, 'rect_height': rect_height, 'name': frame_config.get('name', 'UNKNOWN'), - 'layer_name': layer_name + 'layer_name': layer_name, + 'direction': direction }) - + # Prüfe jedes generierte Symbol symbols_outside = [] for symbol in self.generated_symbols: - symbol_point = (symbol['x'], symbol['y']) + # Berechne Symbol-Dimensionen + io_text = symbol['io'] + symbol_width = len(io_text) * width_per_char + symbol_height = fixed_height + + # Berechne Mittelpunkt des Symbols + # symbol['x'], symbol['y'] ist die linke obere Ecke + symbol_center_x = symbol['x'] + symbol_width / 2 + symbol_center_y = symbol['y'] - symbol_height / 2 + symbol_point = (symbol_center_x, symbol_center_y) + + # Radius für Kreis-Test + symbol_radius = max(symbol_width, symbol_height) / 2 + in_any_frame = False - + validation_type_used = None + + closest_frame = None + min_shift_distance = float('inf') + best_shift = (0, 0) + for frame in frame_boundaries: # Prüfe ob Symbol auf dem richtigen Layer ist if frame['layer_name'] and symbol['layer'] != frame['layer_name']: continue - - # Prüfe ob Symbol innerhalb des Frames liegt - if frame['type'] == 'rectangle': + + # Speichere den Validierungstyp für Fehlermeldung + if validation_type_used is None: + validation_type_used = frame['validation_type'] + + # Wähle Validierungsmethode basierend auf Frame-Typ + if frame['validation_type'] == 'polyline_path': + # POLYLINE_PATH: Prüfe ob Polylinie den Kreis um das Symbol schneidet + if self._circle_intersects_polyline(symbol_point, symbol_radius, frame['polyline']): + in_any_frame = True + break + # Für Polyline-Pfade: Berechne minimalen Abstand zur Polylinie + # (vereinfacht: nicht implementiert, da komplex) + else: + # Containment: Prüfe ob Symbol innerhalb des Frames liegt if self._point_in_rectangle( symbol_point, frame['rect_x'], @@ -812,23 +985,79 @@ class TestDataGenerator: ): in_any_frame = True break - else: # polygon - if self._point_in_polygon(symbol_point, frame['boundary']): - in_any_frame = True - break - + + # Berechne Verschiebung für diesen Frame + shift_x, shift_y = self._calculate_shift_to_rectangle( + symbol_point, + frame['rect_x'], + frame['rect_y'], + frame['rect_width'], + frame['rect_height'] + ) + shift_distance = (shift_x**2 + shift_y**2)**0.5 + + # Speichere den nächsten Frame + if shift_distance < min_shift_distance: + min_shift_distance = shift_distance + best_shift = (shift_x, shift_y) + closest_frame = frame + if not in_any_frame: - symbols_outside.append(symbol) - - # Gib Warnungen aus + symbol_with_type = symbol.copy() + symbol_with_type['validation_type'] = validation_type_used + symbol_with_type['symbol_radius'] = symbol_radius + symbol_with_type['shift_x'] = best_shift[0] + symbol_with_type['shift_y'] = best_shift[1] + symbol_with_type['closest_frame'] = closest_frame.get('name', 'UNKNOWN') if closest_frame else 'UNKNOWN' + symbols_outside.append(symbol_with_type) + + # Gib Warnungen aus und zeichne Fehlerkreise if symbols_outside: - print(f"\nWARNUNG: {len(symbols_outside)} Symbol(e) liegen außerhalb aller Renamer-Frames:") + print(f"\nWARNUNG: {len(symbols_outside)} Symbol(e) erfüllen nicht die Frame-Kriterien:") for symbol in symbols_outside: - print(f" Symbol IO='{symbol['io']}' aus Gruppe '{symbol['group_name']}' " - f"an Position ({symbol['x']:.1f}, {symbol['y']:.1f}) " - f"auf Layer '{symbol['layer']}' liegt in keinem Renamer-Frame") + base_msg = (f" Symbol IO='{symbol['io']}' aus Gruppe '{symbol['group_name']}' " + f"an Position ({symbol['x']:.1f}, {symbol['y']:.1f}) " + f"auf Layer '{symbol['layer']}'") + + if symbol.get('validation_type') == 'polyline_path': + print(f"{base_msg}: " + f"Die Polylinie schneidet nicht den Umkreis des Symbols " + f"(Radius: {symbol['symbol_radius']:.1f})") + else: + shift_x = symbol.get('shift_x', 0) + shift_y = symbol.get('shift_y', 0) + closest_frame = symbol.get('closest_frame', 'UNKNOWN') + + if shift_x != 0 or shift_y != 0: + print(f"{base_msg}: " + f"Symbol liegt nicht innerhalb des Renamer-Rahmens '{closest_frame}'. " + f"Verschieben Sie um dx={shift_x:.1f}, dy={shift_y:.1f}") + else: + print(f"{base_msg}: " + f"Symbol liegt nicht innerhalb des Renamer-Rahmens") + + # Zeichne Fehlerkreis um das Symbol + self._draw_error_circle(symbol['x'], symbol['y'], symbol['symbol_radius']) else: - print(f"\n✓ Alle {len(self.generated_symbols)} generierten Symbole liegen in Renamer-Frames") + print(f"\nOK: Alle {len(self.generated_symbols)} generierten Symbole erfüllen die Frame-Kriterien") + + def _draw_error_circle(self, center_x, center_y, radius): + """ + Zeichnet einen roten Kreis um ein fehlerhaftes Symbol in die DXF-Datei. + + Args: + center_x: X-Koordinate des Kreismittelpunkts + center_y: Y-Koordinate des Kreismittelpunkts + radius: Radius des Kreises + """ + self.msp.add_circle( + center=(center_x, center_y), + radius=radius, + dxfattribs={ + 'layer': 'VALIDATION_ERROR', + 'color': 1 # Rot + } + ) @@ -858,8 +1087,42 @@ class TestDataGenerator: def main(): """Hauptfunktion mit Argparse""" + # Versuche Config zu lesen für --help Ausgabe + default_config = 'create_tests.json' + config_path = Path(PROJECT_CFG) / default_config + available_scenes = [] + scene_descriptions = {} + + if config_path.exists(): + try: + with open(config_path, 'r', encoding='utf-8') as f: + config = json.load(f) + if 'test_scenes' in config: + for scene_name, scene_data in config['test_scenes'].items(): + available_scenes.append(scene_name) + if 'description' in scene_data: + scene_descriptions[scene_name] = scene_data['description'] + except Exception: + pass # Ignoriere Fehler beim Lesen für --help + + # Erstelle Epilog mit verfügbaren Szenen + epilog_text = "\nVerfügbare Test-Szenen:\n" + if available_scenes: + for scene in sorted(available_scenes): + desc = scene_descriptions.get(scene, '') + if desc: + epilog_text += f" {scene}: {desc}\n" + else: + epilog_text += f" {scene}\n" + epilog_text += f"\n(aus Konfigurationsdatei: {config_path})" + else: + epilog_text += " (keine Szenen konfiguriert oder Config-Datei nicht gefunden)\n" + epilog_text += f" Standard-Pfad: {config_path}" + parser = argparse.ArgumentParser( - description='Erzeugt Test-DXF-Dateien für verschiedene Testszenarien' + description='Erzeugt Test-DXF-Dateien für verschiedene Testszenarien', + epilog=epilog_text, + formatter_class=argparse.RawDescriptionHelpFormatter ) parser.add_argument( @@ -886,8 +1149,8 @@ def main(): parser.add_argument( '--config', type=str, - default='create_tests.json', - help='JSON-Konfigurationsdatei (Standard: create_tests.json)' + default=default_config, + help=f'JSON-Konfigurationsdatei (Standard: {default_config})' ) args = parser.parse_args() diff --git a/lib/create_numbers.py b/lib/create_numbers.py index 33d9ac0..ae44638 100644 --- a/lib/create_numbers.py +++ b/lib/create_numbers.py @@ -693,7 +693,35 @@ def process_renamer_blocks(doc, msp, renamer_layers, error_collector): if __name__ == '__main__': - parser = argparse.ArgumentParser(description='Nummeriert Symbole in DXF-Dateien basierend auf Renamer-Blöcken', prog='create_numbers') + # Lese Umgebungsvariablen vor argparse, um Config-Info in Hilfe anzuzeigen + out_dir = check_environment_var('PROJECT_DATA') + work_dir = check_environment_var('PROJECT_WORK') + config_dir = check_environment_var("PROJECT_CFG") + + # Versuche Config zu lesen für --help Ausgabe + config_path = Path(config_dir) / "enumerate.cfg" + available_layers = [] + if config_path.exists(): + try: + available_layers = read_config_layers(config_path) + except Exception: + pass # Ignoriere Fehler beim Lesen für --help + + # Erstelle Epilog mit verfügbaren Layern + epilog_text = "\nKonfigurierte Renamer-Layer:\n" + if available_layers: + epilog_text += " " + ", ".join(available_layers) + "\n" + epilog_text += f"\n(aus Konfigurationsdatei: {config_path})" + else: + epilog_text += " (keine Layer konfiguriert oder Config-Datei nicht gefunden)\n" + epilog_text += f" Standard-Pfad: {config_path}" + + parser = argparse.ArgumentParser( + description='Nummeriert Symbole in DXF-Dateien basierend auf Renamer-Blöcken', + prog='create_numbers', + epilog=epilog_text, + formatter_class=argparse.RawDescriptionHelpFormatter + ) parser.add_argument('-f', '--filename', action='store', required=True, help='DXF-Datei die verarbeitet werden soll', metavar='myfile.dxf') parser.add_argument('-e', '--errorfile', action='store', required=False, help='JSON-Datei für Fehler und Warnungen', metavar='errors.json') parser.add_argument('-w', '--write', action='store', help='Schreibe Ergebnisse der Nummerierung in eine JSON-Datei') @@ -701,10 +729,6 @@ if __name__ == '__main__': args = parser.parse_args() - out_dir = check_environment_var('PROJECT_DATA') - work_dir = check_environment_var('PROJECT_WORK') - config_dir = check_environment_var("PROJECT_CFG") - # Initialisiere ErrorCollector error_collector = ErrorCollector() @@ -719,8 +743,7 @@ if __name__ == '__main__': parser.print_help() exit(1) - # Lese Konfiguration - config_path = Path(config_dir) / "enumerate.cfg" + # Config-Datei existiert bereits (wurde für --help geprüft) if not config_path.exists(): print(f"Konfigurationsdatei nicht gefunden: {config_path}") exit(1)