""" Setzt den Einfuegepunkt ($INSBASE) von Omniflo DXF-Dateien. Mit --boegen: Einfuegepunkt auf den Schnittpunkt der Tangenten am Anfangs- und Endpunkt der Bogenkurve. Mit --weichen45 / --weichen90: Einfuegepunkt auf den Schnittpunkt der laengsten vertikalen Linie und des Endpunktes der Bogenkurve. """ import argparse import json import math import os import sys import ezdxf def find_arc(doc): """Findet die erste ARC-Entity im Modelspace.""" msp = doc.modelspace() for entity in msp: if entity.dxftype() == "ARC": return entity return None def tangent_intersection(arc): """Berechnet den Schnittpunkt der Tangenten am Start- und Endpunkt des Bogens. Bei 180-Grad-Boegen wird der Mittelpunkt zwischen Start und Ende verwendet. """ cx, cy, _ = arc.dxf.center r = arc.dxf.radius a_start = math.radians(arc.dxf.start_angle) a_end = math.radians(arc.dxf.end_angle) # Start- und Endpunkt p1x = cx + r * math.cos(a_start) p1y = cy + r * math.sin(a_start) p2x = cx + r * math.cos(a_end) p2y = cy + r * math.sin(a_end) # Tangentenrichtungen (senkrecht zum Radius) d1x = -math.sin(a_start) d1y = math.cos(a_start) d2x = -math.sin(a_end) d2y = math.cos(a_end) # Determinante det = d1x * (-d2y) - (-d2x) * d1y if abs(det) < 1e-9: # Tangenten parallel (z.B. 180-Grad-Bogen) -> Mittelpunkt return (p1x + p2x) / 2, (p1y + p2y) / 2 dx = p2x - p1x dy = p2y - p1y t = (-dx * d2y + dy * d2x) / det ix = p1x + t * d1x iy = p1y + t * d1y return ix, iy def find_longest_vertical_line(doc): """Findet die laengste vertikale Linie im Modelspace und gibt deren x-Koordinate zurueck.""" msp = doc.modelspace() longest = None longest_len = 0 for entity in msp: if entity.dxftype() != "LINE": continue start = entity.dxf.start end = entity.dxf.end dx = abs(end[0] - start[0]) if dx > 0.01: continue length = abs(end[1] - start[1]) if length > longest_len: longest_len = length longest = entity return longest def arc_endpoint(arc): """Gibt den Endpunkt (end_angle) des Bogens zurueck.""" cx, cy, _ = arc.dxf.center r = arc.dxf.radius a_end = math.radians(arc.dxf.end_angle) return cx + r * math.cos(a_end), cy + r * math.sin(a_end) def weichen_insertion_point(doc): """Berechnet den Einfuegepunkt fuer eine Weiche: Schnittpunkt der laengsten vertikalen Linie mit einer Horizontalen durch den Endpunkt der Bogenkurve. """ vline = find_longest_vertical_line(doc) if vline is None: return None arc = find_arc(doc) if arc is None: return None vx = vline.dxf.start[0] _, ey = arc_endpoint(arc) return vx, ey def process_weichen(data_dir, json_path, results_dir, kurven_winkel): """Verarbeitet Weichen-DXF-Dateien fuer den angegebenen KurvenWinkel.""" with open(json_path, "r", encoding="utf-8") as f: weichen = json.load(f) omniflo_dir = os.path.join(data_dir, "omniflo") filtered = [w for w in weichen if w["KurvenWinkel"] == kurven_winkel] if not filtered: print(f"Keine Weichen mit KurvenWinkel={kurven_winkel} gefunden.") return for weiche in filtered: sivasnr = str(weiche["Sivasnr"]) dxf_path = os.path.join(omniflo_dir, f"{sivasnr}.dxf") if not os.path.exists(dxf_path): print(f"WARNUNG: {dxf_path} nicht gefunden, ueberspringe.") continue doc = ezdxf.readfile(dxf_path) result = weichen_insertion_point(doc) if result is None: print(f"WARNUNG: Kein ARC oder keine vertikale Linie in {sivasnr}.dxf, ueberspringe.") continue ix, iy = result old_base = doc.header.get("$INSBASE", (0, 0, 0)) doc.header["$INSBASE"] = (ix, iy, 0) out_path = os.path.join(results_dir, f"{sivasnr}.dxf") doc.saveas(out_path) print( f"{sivasnr}: INSBASE ({old_base[0]:.2f}, {old_base[1]:.2f}) " f"-> ({ix:.2f}, {iy:.2f}) [{weiche['ProfilTyp']}]" ) print(f"\nErgebnisse in: {results_dir}") def process_boegen(data_dir, json_path, results_dir): """Verarbeitet alle Boegen-DXF-Dateien.""" with open(json_path, "r", encoding="utf-8") as f: boegen = json.load(f) omniflo_dir = os.path.join(data_dir, "omniflo") for bogen in boegen: sivasnr = str(bogen["Sivasnr"]) dxf_path = os.path.join(omniflo_dir, f"{sivasnr}.dxf") if not os.path.exists(dxf_path): print(f"WARNUNG: {dxf_path} nicht gefunden, ueberspringe.") continue doc = ezdxf.readfile(dxf_path) arc = find_arc(doc) if arc is None: print(f"WARNUNG: Kein ARC in {sivasnr}.dxf gefunden, ueberspringe.") continue ix, iy = tangent_intersection(arc) old_base = doc.header.get("$INSBASE", (0, 0, 0)) doc.header["$INSBASE"] = (ix, iy, 0) out_path = os.path.join(results_dir, f"{sivasnr}.dxf") doc.saveas(out_path) print( f"{sivasnr}: INSBASE ({old_base[0]:.2f}, {old_base[1]:.2f}) " f"-> ({ix:.2f}, {iy:.2f}) [{bogen['ProfilTyp']}]" ) print(f"\nErgebnisse in: {results_dir}") def main(): parser = argparse.ArgumentParser( description="Setzt Einfuegepunkte fuer Omniflo DXF-Dateien" ) parser.add_argument( "--boegen", action="store_true", help="Einfuegepunkt auf Tangentenschnittpunkt der Bogenkurve setzen", ) parser.add_argument( "--weichen45", action="store_true", help="Einfuegepunkt fuer 45-Grad-Weichen setzen", ) parser.add_argument( "--weichen90", action="store_true", help="Einfuegepunkt fuer 90-Grad-Weichen setzen", ) args = parser.parse_args() if not args.boegen and not args.weichen45 and not args.weichen90: parser.print_help() sys.exit(1) data_dir = os.environ.get("DXFM_DATA") results_dir = os.environ.get("DXFM_RESULTS") if not data_dir or not results_dir: print("FEHLER: Umgebungsvariablen DXFM_DATA und DXFM_RESULTS muessen gesetzt sein.") print("Bitte zuerst setenv.bat ausfuehren.") sys.exit(1) os.makedirs(results_dir, exist_ok=True) if args.boegen: json_path = os.path.join(data_dir, "json", "omniflo_boegen.json") if not os.path.exists(json_path): print(f"FEHLER: {json_path} nicht gefunden.") sys.exit(1) process_boegen(data_dir, json_path, results_dir) if args.weichen45 or args.weichen90: json_path = os.path.join(data_dir, "json", "omniflo_weichen.json") if not os.path.exists(json_path): print(f"FEHLER: {json_path} nicht gefunden.") sys.exit(1) if args.weichen45: print("=== Weichen 45 Grad ===") process_weichen(data_dir, json_path, results_dir, 45) if args.weichen90: print("=== Weichen 90 Grad ===") process_weichen(data_dir, json_path, results_dir, 90) if __name__ == "__main__": main()