diff --git a/bin/set_coords.bat b/bin/set_coords.bat new file mode 100644 index 0000000..4bc3eee --- /dev/null +++ b/bin/set_coords.bat @@ -0,0 +1,8 @@ +@echo off +REM ================================================================ +REM Setzt Einfuegepunkte fuer Omniflo DXF-Dateien +REM ================================================================ + +call "%~dp0setenv.bat" + +python "%DXFM_LIB%\set_koords.py" %* diff --git a/lib/set_koords.py b/lib/set_koords.py index 43baf38..373172c 100644 --- a/lib/set_koords.py +++ b/lib/set_koords.py @@ -79,18 +79,140 @@ def insert_ks(msp, name, point, rx=0, ry=0, rz=0): return insert +def read_ks(doc, name): + """ + Liest ein Koordinatensystem aus einer DXF-Datei zurueck. + + Bestimmt Position und Rotationswinkel (rx, ry, rz) aus den + tatsaechlichen Linienendpunkten des aufgeloesten INSERT-Blocks. + + Args: + doc: ezdxf DXF-Dokument. + name: Block-Name (z.B. "K1"). + + Returns: + Dict mit 'name', 'point', 'rx', 'ry', 'rz' oder None. + """ + msp = doc.modelspace() + for entity in msp: + if entity.dxftype() == "INSERT" and entity.dxf.name == name: + # Linien aus Block-Referenz aufloesen (virtuelle Entities) + lines = [e for e in entity.virtual_entities() if e.dxftype() == "LINE"] + if len(lines) != 3: + return None + + # Gemeinsamer Startpunkt = Einfuegepunkt + point = (lines[0].dxf.start[0], lines[0].dxf.start[1], lines[0].dxf.start[2]) + + # Richtungsvektoren aus den Endpunkten extrahieren + axes = {} + for line in lines: + end = line.dxf.end + dx = end[0] - point[0] + dy = end[1] - point[1] + dz = end[2] - point[2] + length = (dx**2 + dy**2 + dz**2) ** 0.5 + axes[line.dxf.color] = (dx / length, dy / length, dz / length) + + # X-Achse (color=1), Y-Achse (color=3), Z-Achse (color=5) + x_axis = axes.get(1, (1, 0, 0)) + y_axis = axes.get(3, (0, 1, 0)) + z_axis = axes.get(5, (0, 0, 1)) + + # Rotationswinkel aus Rotationsmatrix R = Rz * Ry * Rx + # Spalten von R: x_axis, y_axis, z_axis + # R20 = -sin(ry) = x_axis[2] + # R21 = cos(ry)*sin(rx) = y_axis[2] + # R22 = cos(ry)*cos(rx) = z_axis[2] + # R10 = sin(rz)*cos(ry) = x_axis[1] + # R00 = cos(rz)*cos(ry) = x_axis[0] + ry = math.asin(max(-1, min(1, -x_axis[2]))) + cos_ry = math.cos(ry) + + if abs(cos_ry) > 1e-6: + rx = math.atan2(y_axis[2] / cos_ry, z_axis[2] / cos_ry) + rz = math.atan2(x_axis[1] / cos_ry, x_axis[0] / cos_ry) + else: + # Gimbal Lock: ry = +/-90, rx und rz nicht unabhaengig + rz = 0 + rx = math.atan2(-z_axis[0], y_axis[0]) + + return { + "name": name, + "point": point, + "rx": math.degrees(rx), + "ry": math.degrees(ry), + "rz": math.degrees(rz), + } + return None + + +def verify_ks(dxf_path, expected): + """ + Liest KS-Bloecke aus einer DXF-Datei und vergleicht mit Erwartungswerten. + + Args: + dxf_path: Pfad zur DXF-Datei. + expected: Liste von Dicts mit 'name', 'point', 'rx', 'ry', 'rz'. + + Returns: + True wenn alle Werte uebereinstimmen (Toleranz 0.01). + """ + doc = ezdxf.readfile(dxf_path) + all_ok = True + tol = 0.01 + + for exp in expected: + result = read_ks(doc, exp["name"]) + if result is None: + print(f"FEHLER: Block '{exp['name']}' nicht gefunden") + all_ok = False + continue + + errors = [] + for i, axis in enumerate(("x", "y", "z")): + if abs(result["point"][i] - exp["point"][i]) > tol: + errors.append(f"{axis}={result['point'][i]:.3f} (erwartet {exp['point'][i]:.3f})") + + for angle in ("rx", "ry", "rz"): + diff = abs(result[angle] - exp[angle]) + if diff > 360 - tol: + diff = abs(diff - 360) + if diff > tol: + errors.append(f"{angle}={result[angle]:.2f} (erwartet {exp[angle]:.2f})") + + if errors: + print(f"FEHLER {exp['name']}: {', '.join(errors)}") + all_ok = False + else: + print(f"OK {exp['name']}: point=({result['point'][0]:.2f},{result['point'][1]:.2f},{result['point'][2]:.2f}) " + f"rx={result['rx']:.2f} ry={result['ry']:.2f} rz={result['rz']:.2f}") + + return all_ok + + if __name__ == "__main__": + import os + doc = ezdxf.new(dxfversion="R2010") msp = doc.modelspace() - insert_ks(msp, "K1", (0, 0, 0)) - insert_ks(msp, "K2", (10, 0, 0), rz=90) - insert_ks(msp, "K3", (20, 0, 0), ry=45) - insert_ks(msp, "K4", (30, 0, 0), rx=30, ry=45, rz=60) + test_cases = [ + {"name": "K1", "point": (0, 0, 0), "rx": 0, "ry": 0, "rz": 0}, + {"name": "K2", "point": (10, 0, 0), "rx": 0, "ry": 0, "rz": 90}, + {"name": "K3", "point": (20, 0, 0), "rx": 0, "ry": 45, "rz": 0}, + {"name": "K4", "point": (30, 0, 0), "rx": 30, "ry": 45, "rz": 60}, + ] + + for tc in test_cases: + insert_ks(msp, tc["name"], tc["point"], tc["rx"], tc["ry"], tc["rz"]) - import os results_dir = os.environ.get("DXFM_RESULTS", "results") os.makedirs(results_dir, exist_ok=True) out_path = os.path.join(results_dir, "ks_test.dxf") doc.saveas(out_path) - print(f"Testdatei gespeichert: {out_path}") + print(f"Testdatei gespeichert: {out_path}\n") + + print("Verifikation:") + ok = verify_ks(out_path, test_cases) + print(f"\nErgebnis: {'ALLE OK' if ok else 'FEHLER GEFUNDEN'}")