Zusätzliche Abfragen für Fehler durch überlappende Renaming Frames eingebaut
This commit is contained in:
@@ -25,7 +25,7 @@
|
|||||||
"name": "MA-2@@_bottom",
|
"name": "MA-2@@_bottom",
|
||||||
"count": 3,
|
"count": 3,
|
||||||
"layout_type": "horizontal_offset",
|
"layout_type": "horizontal_offset",
|
||||||
"base_x": 1800,
|
"base_x": 1850,
|
||||||
"base_y": 400,
|
"base_y": 400,
|
||||||
"spacing": 1450
|
"spacing": 1450
|
||||||
}
|
}
|
||||||
@@ -51,7 +51,7 @@
|
|||||||
"direction": "LEFT_RIGHT",
|
"direction": "LEFT_RIGHT",
|
||||||
"x": 400,
|
"x": 400,
|
||||||
"y": 75,
|
"y": 75,
|
||||||
"width": 1400,
|
"width": 1150,
|
||||||
"height": 480,
|
"height": 480,
|
||||||
"use_polyline": true
|
"use_polyline": true
|
||||||
},
|
},
|
||||||
@@ -149,11 +149,11 @@
|
|||||||
"path_points": [
|
"path_points": [
|
||||||
{"x": 400, "y": 2800},
|
{"x": 400, "y": 2800},
|
||||||
{"x": 4800, "y": 2800},
|
{"x": 4800, "y": 2800},
|
||||||
{"x": 6400, "y": 2400},
|
{"x": 6500, "y": 2400},
|
||||||
{"x": 6400, "y": 1400},
|
{"x": 6500, "y": 1400},
|
||||||
{"x": 6080, "y": 800},
|
{"x": 6080, "y": 800},
|
||||||
{"x": 2480, "y": 800},
|
{"x": 2480, "y": 800},
|
||||||
{"x": 3400, "y": 1800},
|
{"x": 3500, "y": 1800},
|
||||||
{"x": 1200, "y": 1800},
|
{"x": 1200, "y": 1800},
|
||||||
{"x": 400, "y": 2800}
|
{"x": 400, "y": 2800}
|
||||||
]
|
]
|
||||||
@@ -322,7 +322,7 @@
|
|||||||
"kennzeichnung": "",
|
"kennzeichnung": "",
|
||||||
"layer_name1": "ILS_Eingang",
|
"layer_name1": "ILS_Eingang",
|
||||||
"direction": "LEFT_RIGHT",
|
"direction": "LEFT_RIGHT",
|
||||||
"x": 6000,
|
"x": 6500,
|
||||||
"y": 800,
|
"y": 800,
|
||||||
"width": 3210,
|
"width": 3210,
|
||||||
"height": 600,
|
"height": 600,
|
||||||
|
|||||||
+320
-21
@@ -883,7 +883,7 @@ class TestDataGenerator:
|
|||||||
|
|
||||||
# Generiere Renamer-Rahmen aus Config
|
# Generiere Renamer-Rahmen aus Config
|
||||||
for frame_config in scene.get('renaming_frames', []):
|
for frame_config in scene.get('renaming_frames', []):
|
||||||
frame_type = frame_config.get('type', 'rectangle')
|
frame_type = frame_config.get('type', 'rectangle')
|
||||||
|
|
||||||
if frame_type == 'polyline_path':
|
if frame_type == 'polyline_path':
|
||||||
# Polyline-Pfad Frame
|
# Polyline-Pfad Frame
|
||||||
@@ -933,6 +933,245 @@ class TestDataGenerator:
|
|||||||
# Prüfe ob alle generierten Symbole in einem Renamer-Frame liegen
|
# Prüfe ob alle generierten Symbole in einem Renamer-Frame liegen
|
||||||
self._validate_symbols_in_frames(scene)
|
self._validate_symbols_in_frames(scene)
|
||||||
|
|
||||||
|
# Prüfe ob sich Renamer-Rechtecke überlappen (außer POLYLINE_PATH)
|
||||||
|
self._check_overlapping_frames(scene)
|
||||||
|
|
||||||
|
def _rectangles_overlap(self, rect1, rect2):
|
||||||
|
"""
|
||||||
|
Prüft ob sich zwei Rechtecke überlappen.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
rect1: Dictionary mit 'x', 'y', 'width', 'height'
|
||||||
|
rect2: Dictionary mit 'x', 'y', 'width', 'height'
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
True wenn sich die Rechtecke überlappen
|
||||||
|
"""
|
||||||
|
# Rechteck 1
|
||||||
|
r1_left = rect1['x']
|
||||||
|
r1_right = rect1['x'] + rect1['width']
|
||||||
|
r1_bottom = rect1['y']
|
||||||
|
r1_top = rect1['y'] + rect1['height']
|
||||||
|
|
||||||
|
# Rechteck 2
|
||||||
|
r2_left = rect2['x']
|
||||||
|
r2_right = rect2['x'] + rect2['width']
|
||||||
|
r2_bottom = rect2['y']
|
||||||
|
r2_top = rect2['y'] + rect2['height']
|
||||||
|
|
||||||
|
# Prüfe ob keine Überlappung (dann ist das Gegenteil eine Überlappung)
|
||||||
|
no_overlap = (r1_right <= r2_left or # R1 ist links von R2
|
||||||
|
r2_right <= r1_left or # R2 ist links von R1
|
||||||
|
r1_top <= r2_bottom or # R1 ist unter R2
|
||||||
|
r2_top <= r1_bottom) # R2 ist unter R1
|
||||||
|
|
||||||
|
return not no_overlap
|
||||||
|
|
||||||
|
def _calculate_overlap_area(self, rect1, rect2):
|
||||||
|
"""
|
||||||
|
Berechnet die Überlappungsfläche zweier Rechtecke.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
rect1: Dictionary mit 'x', 'y', 'width', 'height'
|
||||||
|
rect2: Dictionary mit 'x', 'y', 'width', 'height'
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Überlappungsfläche in Quadrateinheiten
|
||||||
|
"""
|
||||||
|
# Rechteck 1
|
||||||
|
r1_left = rect1['x']
|
||||||
|
r1_right = rect1['x'] + rect1['width']
|
||||||
|
r1_bottom = rect1['y']
|
||||||
|
r1_top = rect1['y'] + rect1['height']
|
||||||
|
|
||||||
|
# Rechteck 2
|
||||||
|
r2_left = rect2['x']
|
||||||
|
r2_right = rect2['x'] + rect2['width']
|
||||||
|
r2_bottom = rect2['y']
|
||||||
|
r2_top = rect2['y'] + rect2['height']
|
||||||
|
|
||||||
|
# Berechne überlappenden Bereich
|
||||||
|
overlap_left = max(r1_left, r2_left)
|
||||||
|
overlap_right = min(r1_right, r2_right)
|
||||||
|
overlap_bottom = max(r1_bottom, r2_bottom)
|
||||||
|
overlap_top = min(r1_top, r2_top)
|
||||||
|
|
||||||
|
# Wenn keine Überlappung, gib 0 zurück
|
||||||
|
if overlap_right <= overlap_left or overlap_top <= overlap_bottom:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
# Berechne Fläche
|
||||||
|
overlap_width = overlap_right - overlap_left
|
||||||
|
overlap_height = overlap_top - overlap_bottom
|
||||||
|
return overlap_width * overlap_height
|
||||||
|
|
||||||
|
def _calculate_overlap_recommendations(self, frame1, frame2):
|
||||||
|
"""
|
||||||
|
Berechnet Empfehlungen zur Behebung einer Überlappung zwischen zwei Frames.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
frame1: Dictionary mit 'x', 'y', 'width', 'height', 'name'
|
||||||
|
frame2: Dictionary mit 'x', 'y', 'width', 'height', 'name'
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Liste von Empfehlungs-Strings
|
||||||
|
"""
|
||||||
|
recommendations = []
|
||||||
|
|
||||||
|
# Berechne Kanten
|
||||||
|
f1_left = frame1['x']
|
||||||
|
f1_right = frame1['x'] + frame1['width']
|
||||||
|
f1_bottom = frame1['y']
|
||||||
|
f1_top = frame1['y'] + frame1['height']
|
||||||
|
|
||||||
|
f2_left = frame2['x']
|
||||||
|
f2_right = frame2['x'] + frame2['width']
|
||||||
|
f2_bottom = frame2['y']
|
||||||
|
f2_top = frame2['y'] + frame2['height']
|
||||||
|
|
||||||
|
# Berechne Überlappungsbereiche
|
||||||
|
overlap_left = max(f1_left, f2_left)
|
||||||
|
overlap_right = min(f1_right, f2_right)
|
||||||
|
overlap_bottom = max(f1_bottom, f2_bottom)
|
||||||
|
overlap_top = min(f1_top, f2_top)
|
||||||
|
|
||||||
|
overlap_width = overlap_right - overlap_left
|
||||||
|
overlap_height = overlap_top - overlap_bottom
|
||||||
|
|
||||||
|
# Horizontale Überlappung
|
||||||
|
if overlap_width > 0:
|
||||||
|
# Frame 1 ist links von Frame 2
|
||||||
|
if f1_left < f2_left:
|
||||||
|
# Option 1: Frame 1 width reduzieren
|
||||||
|
new_width1 = f1_right - f1_left - overlap_width - 1
|
||||||
|
recommendations.append(
|
||||||
|
f"Reduziere '{frame1['name']}' width von {frame1['width']} auf {new_width1:.0f} "
|
||||||
|
f"(um {overlap_width + 1:.0f} Einheiten)"
|
||||||
|
)
|
||||||
|
# Option 2: Frame 2 nach rechts verschieben
|
||||||
|
new_x2 = f2_left + overlap_width + 1
|
||||||
|
recommendations.append(
|
||||||
|
f"Verschiebe '{frame2['name']}' x von {frame2['x']} auf {new_x2:.0f} "
|
||||||
|
f"(um {overlap_width + 1:.0f} Einheiten nach rechts)"
|
||||||
|
)
|
||||||
|
# Frame 2 ist links von Frame 1
|
||||||
|
else:
|
||||||
|
# Option 1: Frame 2 width reduzieren
|
||||||
|
new_width2 = f2_right - f2_left - overlap_width - 1
|
||||||
|
recommendations.append(
|
||||||
|
f"Reduziere '{frame2['name']}' width von {frame2['width']} auf {new_width2:.0f} "
|
||||||
|
f"(um {overlap_width + 1:.0f} Einheiten)"
|
||||||
|
)
|
||||||
|
# Option 2: Frame 1 nach rechts verschieben
|
||||||
|
new_x1 = f1_left + overlap_width + 1
|
||||||
|
recommendations.append(
|
||||||
|
f"Verschiebe '{frame1['name']}' x von {frame1['x']} auf {new_x1:.0f} "
|
||||||
|
f"(um {overlap_width + 1:.0f} Einheiten nach rechts)"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Vertikale Überlappung
|
||||||
|
if overlap_height > 0:
|
||||||
|
# Frame 1 ist unter Frame 2
|
||||||
|
if f1_bottom < f2_bottom:
|
||||||
|
# Option 1: Frame 1 height reduzieren
|
||||||
|
new_height1 = f1_top - f1_bottom - overlap_height - 1
|
||||||
|
recommendations.append(
|
||||||
|
f"Reduziere '{frame1['name']}' height von {frame1['height']} auf {new_height1:.0f} "
|
||||||
|
f"(um {overlap_height + 1:.0f} Einheiten)"
|
||||||
|
)
|
||||||
|
# Option 2: Frame 2 nach oben verschieben
|
||||||
|
new_y2 = f2_bottom + overlap_height + 1
|
||||||
|
recommendations.append(
|
||||||
|
f"Verschiebe '{frame2['name']}' y von {frame2['y']} auf {new_y2:.0f} "
|
||||||
|
f"(um {overlap_height + 1:.0f} Einheiten nach oben)"
|
||||||
|
)
|
||||||
|
# Frame 2 ist unter Frame 1
|
||||||
|
else:
|
||||||
|
# Option 1: Frame 2 height reduzieren
|
||||||
|
new_height2 = f2_top - f2_bottom - overlap_height - 1
|
||||||
|
recommendations.append(
|
||||||
|
f"Reduziere '{frame2['name']}' height von {frame2['height']} auf {new_height2:.0f} "
|
||||||
|
f"(um {overlap_height + 1:.0f} Einheiten)"
|
||||||
|
)
|
||||||
|
# Option 2: Frame 1 nach oben verschieben
|
||||||
|
new_y1 = f1_bottom + overlap_height + 1
|
||||||
|
recommendations.append(
|
||||||
|
f"Verschiebe '{frame1['name']}' y von {frame1['y']} auf {new_y1:.0f} "
|
||||||
|
f"(um {overlap_height + 1:.0f} Einheiten nach oben)"
|
||||||
|
)
|
||||||
|
|
||||||
|
return recommendations
|
||||||
|
|
||||||
|
def _check_overlapping_frames(self, scene):
|
||||||
|
"""
|
||||||
|
Prüft ob sich Renamer-Rechtecke überlappen.
|
||||||
|
Polyline-Pfade (DIRECTION=POLYLINE_PATH) werden nicht geprüft.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
scene: Scene-Configuration Dictionary
|
||||||
|
"""
|
||||||
|
print("\n" + "="*60)
|
||||||
|
print("Prüfe auf überlappende Renamer-Rechtecke")
|
||||||
|
print("="*60)
|
||||||
|
|
||||||
|
# Sammle alle Rechteck-Frames (ohne POLYLINE_PATH)
|
||||||
|
rectangle_frames = []
|
||||||
|
for frame_config in scene.get('renaming_frames', []):
|
||||||
|
frame_type = frame_config.get('type', 'rectangle')
|
||||||
|
direction = frame_config.get('direction', '')
|
||||||
|
|
||||||
|
# Überspringe POLYLINE_PATH Frames
|
||||||
|
if frame_type == 'polyline_path' or direction == 'POLYLINE_PATH':
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Überspringe Frames ohne Positionsangaben
|
||||||
|
if 'x' not in frame_config or 'y' not in frame_config:
|
||||||
|
continue
|
||||||
|
|
||||||
|
rectangle_frames.append({
|
||||||
|
'name': frame_config.get('name', 'UNKNOWN'),
|
||||||
|
'x': frame_config['x'],
|
||||||
|
'y': frame_config['y'],
|
||||||
|
'width': frame_config.get('width', 0),
|
||||||
|
'height': frame_config.get('height', 0),
|
||||||
|
'direction': direction
|
||||||
|
})
|
||||||
|
|
||||||
|
# Prüfe alle Paare von Rechtecken auf Überlappung
|
||||||
|
overlaps_found = []
|
||||||
|
for i in range(len(rectangle_frames)):
|
||||||
|
for j in range(i + 1, len(rectangle_frames)):
|
||||||
|
frame1 = rectangle_frames[i]
|
||||||
|
frame2 = rectangle_frames[j]
|
||||||
|
|
||||||
|
if self._rectangles_overlap(frame1, frame2):
|
||||||
|
overlap_area = self._calculate_overlap_area(frame1, frame2)
|
||||||
|
recommendations = self._calculate_overlap_recommendations(frame1, frame2)
|
||||||
|
overlaps_found.append({
|
||||||
|
'frame1': frame1,
|
||||||
|
'frame2': frame2,
|
||||||
|
'overlap_area': overlap_area,
|
||||||
|
'recommendations': recommendations
|
||||||
|
})
|
||||||
|
|
||||||
|
# Gib Warnungen aus
|
||||||
|
if overlaps_found:
|
||||||
|
print(f"\nWARNUNG: {len(overlaps_found)} Überlappung(en) zwischen Renamer-Rechtecken gefunden:")
|
||||||
|
for overlap in overlaps_found:
|
||||||
|
f1 = overlap['frame1']
|
||||||
|
f2 = overlap['frame2']
|
||||||
|
area = overlap['overlap_area']
|
||||||
|
print(f" Frame '{f1['name']}' (Position: {f1['x']}, {f1['y']}, "
|
||||||
|
f"Größe: {f1['width']}x{f1['height']}) "
|
||||||
|
f"überlappt mit Frame '{f2['name']}' "
|
||||||
|
f"(Position: {f2['x']}, {f2['y']}, Größe: {f2['width']}x{f2['height']})")
|
||||||
|
print(f" Überlappungsfläche: {area:.1f} Quadrateinheiten")
|
||||||
|
print(f" Empfohlene Änderungen (wähle eine):")
|
||||||
|
for rec in overlap['recommendations']:
|
||||||
|
print(f" - {rec}")
|
||||||
|
else:
|
||||||
|
print(f"\nOK: Keine Überlappungen zwischen {len(rectangle_frames)} Renamer-Rechtecken gefunden")
|
||||||
|
|
||||||
def _point_in_rectangle(self, point, rect_x, rect_y, rect_width, rect_height):
|
def _point_in_rectangle(self, point, rect_x, rect_y, rect_width, rect_height):
|
||||||
"""
|
"""
|
||||||
Prüft ob ein Punkt innerhalb eines Rechtecks liegt.
|
Prüft ob ein Punkt innerhalb eines Rechtecks liegt.
|
||||||
@@ -1347,15 +1586,21 @@ def main():
|
|||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'--scene',
|
'--scene',
|
||||||
type=str,
|
type=str,
|
||||||
required=True,
|
default=None,
|
||||||
help='Name der Testszene (z.B. Nummerierung1, Nummerierung2). Muss in der Config existieren.'
|
help='Name der Testszene (z.B. Nummerierung1, Nummerierung2). Muss in der Config existieren.'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
parser.add_argument(
|
||||||
|
'--all',
|
||||||
|
action='store_true',
|
||||||
|
help='Erzeugt alle konfigurierten Testszenen'
|
||||||
|
)
|
||||||
|
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'--filename',
|
'--filename',
|
||||||
type=str,
|
type=str,
|
||||||
default=None,
|
default=None,
|
||||||
help='Name der zu erzeugenden Testdatei (z.B. Nummerierung1.dxf). Falls nicht angegeben, wird scene + .dxf verwendet.'
|
help='Name der zu erzeugenden Testdatei (z.B. Nummerierung1.dxf). Falls nicht angegeben, wird scene + .dxf verwendet. Wird bei --all ignoriert.'
|
||||||
)
|
)
|
||||||
|
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
@@ -1380,29 +1625,83 @@ def main():
|
|||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
# Bestimme Filename: entweder angegeben oder aus scene ableiten
|
# Validierung: entweder --scene oder --all muss angegeben sein
|
||||||
if args.filename:
|
if not args.scene and not args.all:
|
||||||
filename = args.filename
|
parser.error("Entweder --scene oder --all muss angegeben werden")
|
||||||
|
|
||||||
|
if args.scene and args.all:
|
||||||
|
parser.error("--scene und --all können nicht zusammen verwendet werden")
|
||||||
|
|
||||||
|
# Bestimme welche Szenen zu erzeugen sind
|
||||||
|
if args.all:
|
||||||
|
# Lade Config, um alle Szenen zu bekommen
|
||||||
|
config_path = Path(PROJECT_CFG) / args.config
|
||||||
|
if not config_path.exists():
|
||||||
|
print(f"FEHLER: Config-Datei nicht gefunden: {config_path}")
|
||||||
|
return 1
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(config_path, 'r', encoding='utf-8') as f:
|
||||||
|
config = json.load(f)
|
||||||
|
except json.JSONDecodeError as e:
|
||||||
|
print(f"FEHLER beim Parsen der Config-Datei: {e}")
|
||||||
|
return 1
|
||||||
|
|
||||||
|
if 'test_scenes' not in config:
|
||||||
|
print("FEHLER: Config enthält keinen 'test_scenes' Abschnitt")
|
||||||
|
return 1
|
||||||
|
|
||||||
|
scenes_to_generate = list(config['test_scenes'].keys())
|
||||||
|
print(f"Erzeuge alle {len(scenes_to_generate)} konfigurierten Testszenen:")
|
||||||
|
for scene in scenes_to_generate:
|
||||||
|
print(f" - {scene}")
|
||||||
|
print()
|
||||||
else:
|
else:
|
||||||
filename = args.scene + '.dxf'
|
# Einzelne Szene
|
||||||
|
scenes_to_generate = [args.scene]
|
||||||
|
|
||||||
# Stelle sicher, dass Dateiname .dxf Endung hat
|
# Generiere alle Szenen
|
||||||
if not filename.endswith('.dxf'):
|
success_count = 0
|
||||||
filename += '.dxf'
|
error_count = 0
|
||||||
|
|
||||||
# Generiere Testdaten
|
for scene_name in scenes_to_generate:
|
||||||
generator = TestDataGenerator(filename, args.scene, config_file=args.config)
|
# Bestimme Filename: entweder angegeben (nur bei einzelner Szene) oder aus scene ableiten
|
||||||
|
if args.filename and not args.all:
|
||||||
|
filename = args.filename
|
||||||
|
else:
|
||||||
|
filename = scene_name + '.dxf'
|
||||||
|
|
||||||
if generator.generate():
|
# Stelle sicher, dass Dateiname .dxf Endung hat
|
||||||
# Zeichne Symbol-Rahmen wenn gewünscht
|
if not filename.endswith('.dxf'):
|
||||||
if args.show_symbol_frames:
|
filename += '.dxf'
|
||||||
generator.draw_frames_for_generated_symbols()
|
|
||||||
|
|
||||||
generator.save(args.output_dir)
|
print(f"\n{'='*60}")
|
||||||
return 0
|
print(f"Erzeuge Testszene: {scene_name}")
|
||||||
else:
|
print(f"Datei: {filename}")
|
||||||
print("Fehler bei der Generierung der Testdaten")
|
print(f"{'='*60}")
|
||||||
return 1
|
|
||||||
|
# Generiere Testdaten
|
||||||
|
generator = TestDataGenerator(filename, scene_name, config_file=args.config)
|
||||||
|
|
||||||
|
if generator.generate():
|
||||||
|
# Zeichne Symbol-Rahmen wenn gewünscht
|
||||||
|
if args.show_symbol_frames:
|
||||||
|
generator.draw_frames_for_generated_symbols()
|
||||||
|
|
||||||
|
generator.save(args.output_dir)
|
||||||
|
success_count += 1
|
||||||
|
else:
|
||||||
|
print(f"Fehler bei der Generierung von {scene_name}")
|
||||||
|
error_count += 1
|
||||||
|
|
||||||
|
# Zusammenfassung
|
||||||
|
print(f"\n{'='*60}")
|
||||||
|
print(f"Zusammenfassung:")
|
||||||
|
print(f" Erfolgreich: {success_count}")
|
||||||
|
print(f" Fehler: {error_count}")
|
||||||
|
print(f"{'='*60}")
|
||||||
|
|
||||||
|
return 0 if error_count == 0 else 1
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|||||||
+110
-3
@@ -881,6 +881,98 @@ def check_symbols_in_boundaries(doc, msp, renamer_groups, error_collector):
|
|||||||
print(f" Alle {len(symbols_with_at)} Symbole mit '@' im IO liegen in einem Renamer-Bereich.")
|
print(f" Alle {len(symbols_with_at)} Symbole mit '@' im IO liegen in einem Renamer-Bereich.")
|
||||||
|
|
||||||
|
|
||||||
|
def rectangles_overlap(boundary1, boundary2):
|
||||||
|
"""
|
||||||
|
Prüft ob sich zwei Rechteck-Boundaries überlappen.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
boundary1: Liste von (x, y) Punkten (mindestens 4 Eckpunkte)
|
||||||
|
boundary2: Liste von (x, y) Punkten (mindestens 4 Eckpunkte)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
True wenn sich die Rechtecke überlappen
|
||||||
|
"""
|
||||||
|
# Extrahiere Min/Max für beide Rechtecke
|
||||||
|
b1_xs = [p[0] for p in boundary1]
|
||||||
|
b1_ys = [p[1] for p in boundary1]
|
||||||
|
b1_left, b1_right = min(b1_xs), max(b1_xs)
|
||||||
|
b1_bottom, b1_top = min(b1_ys), max(b1_ys)
|
||||||
|
|
||||||
|
b2_xs = [p[0] for p in boundary2]
|
||||||
|
b2_ys = [p[1] for p in boundary2]
|
||||||
|
b2_left, b2_right = min(b2_xs), max(b2_xs)
|
||||||
|
b2_bottom, b2_top = min(b2_ys), max(b2_ys)
|
||||||
|
|
||||||
|
# Prüfe ob keine Überlappung
|
||||||
|
no_overlap = (b1_right <= b2_left or # B1 ist links von B2
|
||||||
|
b2_right <= b1_left or # B2 ist links von B1
|
||||||
|
b1_top <= b2_bottom or # B1 ist unter B2
|
||||||
|
b2_top <= b1_bottom) # B2 ist unter B1
|
||||||
|
|
||||||
|
return not no_overlap
|
||||||
|
|
||||||
|
|
||||||
|
def check_overlapping_renamer_blocks(renamer_groups, error_collector):
|
||||||
|
"""
|
||||||
|
Prüft ob sich Renamer-Rechtecke überlappen.
|
||||||
|
Polyline-Pfade (DIRECTION=POLYLINE_PATH) werden nicht geprüft.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
renamer_groups: Dictionary mit gruppierten Renamer-Blöcken
|
||||||
|
error_collector: ErrorCollector für Fehlerbehandlung
|
||||||
|
"""
|
||||||
|
print("\n" + "="*60)
|
||||||
|
print("Prüfe auf überlappende Renamer-Bereiche")
|
||||||
|
print("="*60)
|
||||||
|
|
||||||
|
# Sammle alle Rechteck-Renamer (ohne POLYLINE_PATH)
|
||||||
|
rectangle_renamers = []
|
||||||
|
for config_key, group_blocks in renamer_groups.items():
|
||||||
|
for insert, boundary, attributes, is_rectangle in group_blocks:
|
||||||
|
direction = attributes.get("DIRECTION", "")
|
||||||
|
block_name = attributes.get('NAME', attributes.get('NAME1', 'UNKNOWN'))
|
||||||
|
|
||||||
|
# Überspringe POLYLINE_PATH
|
||||||
|
if direction == 'POLYLINE_PATH':
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Nur Rechtecke prüfen
|
||||||
|
if is_rectangle:
|
||||||
|
rectangle_renamers.append({
|
||||||
|
'name': block_name,
|
||||||
|
'position': insert.dxf.insert,
|
||||||
|
'boundary': boundary,
|
||||||
|
'direction': direction,
|
||||||
|
'is_rectangle': is_rectangle
|
||||||
|
})
|
||||||
|
|
||||||
|
# Prüfe alle Paare auf Überlappung
|
||||||
|
overlaps_found = []
|
||||||
|
for i in range(len(rectangle_renamers)):
|
||||||
|
for j in range(i + 1, len(rectangle_renamers)):
|
||||||
|
r1 = rectangle_renamers[i]
|
||||||
|
r2 = rectangle_renamers[j]
|
||||||
|
|
||||||
|
if rectangles_overlap(r1['boundary'], r2['boundary']):
|
||||||
|
overlaps_found.append((r1, r2))
|
||||||
|
|
||||||
|
# Melde Fehler
|
||||||
|
if overlaps_found:
|
||||||
|
print(f"\nFEHLER: {len(overlaps_found)} Überlappung(en) zwischen Renamer-Bereichen gefunden:")
|
||||||
|
for r1, r2 in overlaps_found:
|
||||||
|
error_msg = (
|
||||||
|
f"Renamer-Bereich '{r1['name']}' an Position "
|
||||||
|
f"({r1['position'][0]:.1f}, {r1['position'][1]:.1f}) "
|
||||||
|
f"überlappt mit Renamer-Bereich '{r2['name']}' an Position "
|
||||||
|
f"({r2['position'][0]:.1f}, {r2['position'][1]:.1f}). "
|
||||||
|
f"Symbole könnten mehrfach nummeriert werden."
|
||||||
|
)
|
||||||
|
print(f" {error_msg}")
|
||||||
|
error_collector.add_errors({"overlapping_renamer_blocks": error_msg})
|
||||||
|
else:
|
||||||
|
print(f"\nOK: Keine Überlappungen zwischen {len(rectangle_renamers)} Renamer-Rechtecken gefunden")
|
||||||
|
|
||||||
|
|
||||||
def process_renamer_blocks(doc, msp, renamer_layers, error_collector):
|
def process_renamer_blocks(doc, msp, renamer_layers, error_collector):
|
||||||
"""
|
"""
|
||||||
Verarbeitet alle Renamer-Blöcke auf den angegebenen Layern.
|
Verarbeitet alle Renamer-Blöcke auf den angegebenen Layern.
|
||||||
@@ -895,6 +987,9 @@ def process_renamer_blocks(doc, msp, renamer_layers, error_collector):
|
|||||||
# Erster Pass: Sammle und gruppiere alle Renamer-Blöcke
|
# Erster Pass: Sammle und gruppiere alle Renamer-Blöcke
|
||||||
renamer_groups = collect_and_group_renamer_blocks(doc, msp, renamer_layers, error_collector)
|
renamer_groups = collect_and_group_renamer_blocks(doc, msp, renamer_layers, error_collector)
|
||||||
|
|
||||||
|
# Prüfe auf überlappende Renamer-Bereiche
|
||||||
|
check_overlapping_renamer_blocks(renamer_groups, error_collector)
|
||||||
|
|
||||||
# Zweiter Pass: Verarbeite jede Gruppe
|
# Zweiter Pass: Verarbeite jede Gruppe
|
||||||
all_renamed = process_renamer_groups(doc, msp, renamer_layers, renamer_groups, error_collector)
|
all_renamed = process_renamer_groups(doc, msp, renamer_layers, renamer_groups, error_collector)
|
||||||
|
|
||||||
@@ -975,10 +1070,15 @@ if __name__ == '__main__':
|
|||||||
parser.add_argument('-e', '--errorfile', action='store', required=False, help='JSON-Datei für Fehler und Warnungen', metavar='errors.json')
|
parser.add_argument('-e', '--errorfile', action='store', required=False, help='JSON-Datei für Fehler und Warnungen', metavar='errors.json')
|
||||||
parser.add_argument('-i', '--info', action='store', help='Schreibe Ergebnisse der Nummerierung in eine JSON-Datei')
|
parser.add_argument('-i', '--info', action='store', help='Schreibe Ergebnisse der Nummerierung in eine JSON-Datei')
|
||||||
parser.add_argument('-d', '--dryrun', action='store_true', help='Symbole nicht in der DXF-Datei überschreiben, nur Ausgabe auf Konsole')
|
parser.add_argument('-d', '--dryrun', action='store_true', help='Symbole nicht in der DXF-Datei überschreiben, nur Ausgabe auf Konsole')
|
||||||
|
parser.add_argument('--overwrite', action='store_true', help='Überschreibt die Originaldatei anstatt eine neue Datei mit Suffix _numbered zu erstellen')
|
||||||
parser.add_argument('--show_symbol_frames', action='store_true', help='Zeichne Rahmen um jedes Symbol, um die Grenze des Symbols zu visualisieren')
|
parser.add_argument('--show_symbol_frames', action='store_true', help='Zeichne Rahmen um jedes Symbol, um die Grenze des Symbols zu visualisieren')
|
||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
# Validierung: --overwrite und --dryrun können nicht zusammen verwendet werden
|
||||||
|
if args.overwrite and args.dryrun:
|
||||||
|
parser.error("--overwrite und --dryrun können nicht zusammen verwendet werden")
|
||||||
|
|
||||||
# Initialisiere ErrorCollector
|
# Initialisiere ErrorCollector
|
||||||
error_collector = ErrorCollector()
|
error_collector = ErrorCollector()
|
||||||
|
|
||||||
@@ -1042,9 +1142,16 @@ if __name__ == '__main__':
|
|||||||
|
|
||||||
# Speichere DXF-Datei wenn nicht dry-run
|
# Speichere DXF-Datei wenn nicht dry-run
|
||||||
if not args.dryrun:
|
if not args.dryrun:
|
||||||
output_path = dxf_path.parent / f"{dxf_path.stem}_numbered{dxf_path.suffix}"
|
if args.overwrite:
|
||||||
doc.saveas(output_path)
|
# Überschreibe die Originaldatei
|
||||||
print(f"\nNummerierte DXF-Datei gespeichert: {output_path}")
|
output_path = dxf_path
|
||||||
|
doc.saveas(output_path)
|
||||||
|
print(f"\nOriginaldatei überschrieben: {output_path}")
|
||||||
|
else:
|
||||||
|
# Erstelle neue Datei mit _numbered Suffix
|
||||||
|
output_path = dxf_path.parent / f"{dxf_path.stem}_numbered{dxf_path.suffix}"
|
||||||
|
doc.saveas(output_path)
|
||||||
|
print(f"\nNummerierte DXF-Datei gespeichert: {output_path}")
|
||||||
else:
|
else:
|
||||||
print("\nDry-run Modus: DXF-Datei wurde nicht überschrieben")
|
print("\nDry-run Modus: DXF-Datei wurde nicht überschrieben")
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user