Files
dxfmakros/lib/elemente/eckrad.py
T

181 lines
5.3 KiB
Python

# 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)