# eckrad.py # ILS Eckrad - PyRx-Implementierung # Ersetzt c:ILS_Eckrad und ils-eckrad-insert aus KreiselInsert.lsp # Setzt voraus: PyRx (cad-pyrx) in BricsCAD/AutoCAD geladen # ============================================ import math import PyRx as Rx import PyGe as Ge import PyDb as Db import PyEd as Ed from elemente.utils import ( get_block_path, component_next_number, merge_attribs, ensure_block_from_dwg, create_attrib_defs, insert_block_with_attribs, ) # ============================================================ # Konstanten (aus KreiselInsert.lsp) # ============================================================ KREISEL_DURCHMESSER = 800.0 ECKRAD_DEFAULT_HOEHE = 2000.0 ECKRAD_ATTRIB_DEFS = [ ("NAME", ""), ("DREHRICHTUNG", "UZS"), ("DREHUNG", "0"), ("NUMMER", "0"), ("HOEHE", "0"), ] # ============================================================ # Eckrad-spezifische Funktionen # ============================================================ def ensure_eckrad_block(db, bname, block_path): """AN8.dwg als Basis-Block laden und als ECKRAD_n Block definieren, falls noch nicht vorhanden.""" bt = Db.BlockTable(db.blockTableId(), Db.OpenMode.kForRead) if bt.has(bname): print(f"\n-> Verwende bestehende Blockdefinition: {bname}") return True if not ensure_block_from_dwg(db, "AN8.dwg", block_path): return False # Neue Blockdefinition ECKRAD_n erzeugen bt.upgradeOpen() new_btr = Db.BlockTableRecord() new_btr.setName(bname) bt.add(new_btr) # AN8-Blockdefinition als BlockReference einfuegen an8_id = bt.getAt("AN8") bref = Db.BlockReference(Ge.Point3d(0, 0, 0), an8_id) new_btr.appendAcDbEntity(bref) # Unsichtbare Attribut-Definitionen erzeugen create_attrib_defs(new_btr, ECKRAD_ATTRIB_DEFS) print(f"\n-> Neue Blockdefinition: {bname}") return True def insert_eckrad(db, insert_point, rotation_deg, attribs=None): """Eckrad als Block-Referenz mit Attributen einfuegen. Parameter: db - aktuelle Datenbank insert_point - Ge.Point3d (x, y, z) rotation_deg - Drehwinkel in Grad attribs - dict mit Attribut-Ueberschreibungen (optional) Rueckgabe: ObjectId der eingefuegten BlockReference """ block_path = get_block_path() # Attribute vorbereiten merged = merge_attribs(attribs, ECKRAD_ATTRIB_DEFS) merged["DREHUNG"] = f"{rotation_deg:.1f}" # Hoehe aus Z-Koordinate oder Attribut z_hoehe = insert_point.z if z_hoehe > 0: merged["HOEHE"] = f"{z_hoehe:.0f}" else: try: z_hoehe = float(merged.get("HOEHE", "0")) except ValueError: z_hoehe = 0.0 # Nummer vergeben nummer = component_next_number(db, "ECKRAD_") merged["NUMMER"] = str(nummer) merged["NAME"] = f"ECKRAD_{nummer}" # Blockname bname = f"ECKRAD_{nummer}" # Block-Definition sicherstellen if not ensure_eckrad_block(db, bname, block_path): return None # Block einfuegen mit Attributen pt = Ge.Point3d(insert_point.x, insert_point.y, z_hoehe) obj_id = insert_block_with_attribs(db, bname, pt, rotation_deg, merged) print(f"\n-> Eckrad #{nummer} eingefuegt: {bname}" f" bei {insert_point.x:.1f},{insert_point.y:.1f}" f" Rotation={rotation_deg:.1f} Hoehe={z_hoehe:.0f}") return obj_id # ============================================================ # CAD-Befehl: ILS_Eckrad # ============================================================ @Rx.command("ILS_Eckrad") def ils_eckrad(): """Befehl ILS_Eckrad - fragt Eingaben ab und fuegt Eckrad ein. Ablauf: 1. Beruehrpunkt anklicken (wo der Kreis tangential anliegen soll) 2. Richtungspunkt anklicken (bestimmt Versatzrichtung zum Kreismittelpunkt) 3. Kreismittelpunkt = Beruehrpunkt + Radius in Richtung des 2. Klicks 4. Hoehe aus Z-Koordinate oder manuell """ ed = Ed.Editor() db = Db.HostApplicationServices().workingDatabase() # 1. Beruehrpunkt (Tangentenpunkt) res_tangent = ed.getPoint("\nBeruehrpunkt Eckrad (Tangente): ") if res_tangent[0] != Ed.PromptStatus.eOk: return pt_tangent = res_tangent[1] # 2. Richtungspunkt (Gummiband vom Beruehrpunkt) res_dir = ed.getPoint("\nRichtung zum Kreismittelpunkt: ", pt_tangent) if res_dir[0] != Ed.PromptStatus.eOk: return pt_dir = res_dir[1] # 3. Winkel und Versatz berechnen dx = pt_dir.x - pt_tangent.x dy = pt_dir.y - pt_tangent.y dist = math.sqrt(dx * dx + dy * dy) if dist <= 0.001: print("\nFehler: Beruehr- und Richtungspunkt sind identisch!") return ux = dx / dist uy = dy / dist radius = KREISEL_DURCHMESSER / 2.0 center_x = pt_tangent.x + radius * ux center_y = pt_tangent.y + radius * uy rotation = math.degrees(math.atan2(dy, dx)) # 4. Hoehe bestimmen if pt_tangent.z > 0: hoehe = pt_tangent.z print(f"\n-> Hoehe aus 3D-Punkt uebernommen: {hoehe:.0f}") else: res_hoehe = ed.getDouble(f"\nHoehe (Z-Koordinate) <{ECKRAD_DEFAULT_HOEHE:.0f}>: ") if res_hoehe[0] == Ed.PromptStatus.eOk: hoehe = res_hoehe[1] else: hoehe = ECKRAD_DEFAULT_HOEHE # 5. Einfuegen insert_pt = Ge.Point3d(center_x, center_y, hoehe) insert_eckrad(db, insert_pt, rotation)