Files
dxfmakros/lib/elemente/kreisel.py
T

684 lines
23 KiB
Python

# kreisel.py
# ILS Kreisel - PyRx-Implementierung
# Ersetzt alle Kreisel-Routinen aus KreiselInsert.lsp
# Befehle: KreiselInsert, KreiselConnect, KreiselRedraw,
# KreiselQuick, KreiselEdit, KreiselParams,
# KreiselLabelSetup, KreiselLabelPos, KreiselLabelHoehe
# ============================================
import math
import PyRx as Rx
import PyGe as Ge
import PyDb as Db
import PyEd as Ed
import wx
from elemente.utils import (
get_block_path,
component_next_number,
merge_attribs,
read_block_attribs,
ensure_layer,
ensure_textstyle,
ensure_block_from_dwg,
create_attrib_defs,
insert_block_with_attribs,
)
# ============================================================
# Konstanten (aus KreiselInsert.lsp)
# ============================================================
KREISEL_DURCHMESSER = 800.0
KREISEL_PIN_ABSTAND = 100.0
KREISEL_DEFAULT_LAENGE = 2300.0
KREISEL_DEFAULT_HOEHE = 2000.0
KREISEL_ATTRIB_DEFS = [
("NAME", ""),
("DREHRICHTUNG", "UZS"),
("N_SEPARATOREN", "2"),
("KREISELART", "STANDARD"),
("N_SCANNER", "0"),
("N_RAMPEN", "0"),
("DREHUNG", "0"),
("ABSTAND", "2300"),
("NUMMER", "0"),
("HOEHE", "0"),
]
# Ausrichtungs-Definitionen: (Label, Rotation in Grad)
KREISEL_AUSRICHTUNGEN = [
("Horizontal MS", 0.0),
("Horizontal SM", 180.0),
("Vertikal MS", 90.0),
("Vertikal SM", 270.0),
]
# Globaler Zustand (pro Sitzung)
_kreisel_typ = "STANDARD"
# Beschriftungs-Einstellungen
_beschriftung_layer = "S_KRS_BESCHR"
_beschriftung_hoehe = 100.0
_beschriftung_farbe = 7
_beschriftung_abstand_oben = 0.0
_beschriftung_abstand_x = 0.0
_beschriftung_abstand_y = 0.0
# ============================================================
# Kreisel-spezifische Hilfsfunktionen
# ============================================================
def rotation_to_idx(rot):
"""Rotation (Grad) -> Index in KREISEL_AUSRICHTUNGEN."""
best_idx = 0
for i, (_, r) in enumerate(KREISEL_AUSRICHTUNGEN):
diff = abs((rot % 360) - (r % 360))
if diff < 1.0:
best_idx = i
return best_idx
def idx_to_rotation(idx):
"""Index in KREISEL_AUSRICHTUNGEN -> Rotation (Grad)."""
return KREISEL_AUSRICHTUNGEN[idx][1]
# ============================================================
# Kern-Funktion: draw_module (entspricht draw-module in LISP)
# ============================================================
def draw_module(db, base_point, abstand, rotation_deg, attribs=None):
"""Kreisel-Geometrie zeichnen, Block definieren, einfuegen, Attribute setzen.
Parameter:
db - aktuelle Datenbank
base_point - Ge.Point3d (x, y, z) Basispunkt AN-Seite
abstand - Tangentenlaenge zwischen Kreismitten (mm)
rotation_deg - Einfuegewinkel in Grad
attribs - dict mit Attribut-Ueberschreibungen (optional)
Rueckgabe: ObjectId der eingefuegten BlockReference
"""
block_path = get_block_path()
radius = KREISEL_DURCHMESSER / 2.0
pin_y = radius - KREISEL_PIN_ABSTAND
# Attribute vorbereiten
merged = merge_attribs(attribs, KREISEL_ATTRIB_DEFS)
merged["ABSTAND"] = f"{abstand:.0f}"
merged["DREHUNG"] = f"{rotation_deg:.1f}"
# Hoehe bestimmen
z_hoehe = base_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
merged["HOEHE"] = f"{z_hoehe:.0f}" if z_hoehe > 0 else merged.get("HOEHE", "0")
is_pin = merged.get("KREISELART", "STANDARD") == "PIN"
# Nummer: bestehende beibehalten (Redraw/Edit), sonst neue vergeben
try:
kreisel_nummer = int(merged.get("NUMMER", "0"))
except ValueError:
kreisel_nummer = 0
if kreisel_nummer <= 0:
kreisel_nummer = component_next_number(db, "KREISEL_")
merged["NUMMER"] = str(kreisel_nummer)
merged["NAME"] = f"Kreisel{kreisel_nummer}"
# Blockname: KREISEL_1_PIN_2300 oder KREISEL_1_STANDARD_2300
art_str = "PIN" if is_pin else "STANDARD"
bname = f"KREISEL_{kreisel_nummer}_{art_str}_{abstand:.0f}"
bname = bname.replace(".", "")
bt = Db.BlockTable(db.blockTableId(), Db.OpenMode.kForRead)
block_exists = bt.has(bname)
if not block_exists:
# AN8.dwg und SP8.dwg laden
if not ensure_block_from_dwg(db, "AN8.dwg", block_path):
return None
if not ensure_block_from_dwg(db, "SP8.dwg", block_path):
return None
bt.upgradeOpen()
new_btr = Db.BlockTableRecord()
new_btr.setName(bname)
bt.add(new_btr)
# AN8 bei (radius, 0)
an8_id = bt.getAt("AN8")
bref_an8 = Db.BlockReference(Ge.Point3d(radius, 0, 0), an8_id)
new_btr.appendAcDbEntity(bref_an8)
# SP8 bei (radius+abstand, 0)
sp8_id = bt.getAt("SP8")
bref_sp8 = Db.BlockReference(Ge.Point3d(radius + abstand, 0, 0), sp8_id)
new_btr.appendAcDbEntity(bref_sp8)
# Tangenten-Linien auf Layer S_LP
ensure_layer(db, "S_LP", 7)
lp_lt = Db.LayerTable(db.layerTableId(), Db.OpenMode.kForRead)
lp_layer_id = lp_lt.getAt("S_LP")
line_color = Db.Color()
line_color.setColorIndex(5 if is_pin else 1)
# Obere Tangente
line_top = Db.Line(Ge.Point3d(radius, radius, 0),
Ge.Point3d(radius + abstand, radius, 0))
line_top.setLayer(lp_layer_id)
line_top.setColor(line_color)
new_btr.appendAcDbEntity(line_top)
# Untere Tangente
line_bot = Db.Line(Ge.Point3d(radius, -radius, 0),
Ge.Point3d(radius + abstand, -radius, 0))
line_bot.setLayer(lp_layer_id)
line_bot.setColor(line_color)
new_btr.appendAcDbEntity(line_bot)
# PIN-Linien
if is_pin:
ensure_layer(db, "pinbereich", 3)
pin_lt = Db.LayerTable(db.layerTableId(), Db.OpenMode.kForRead)
pin_layer_id = pin_lt.getAt("pinbereich")
pin_color = Db.Color()
pin_color.setColorIndex(3)
pin_top = Db.Line(Ge.Point3d(KREISEL_DURCHMESSER, pin_y, 0),
Ge.Point3d(abstand, pin_y, 0))
pin_top.setLayer(pin_layer_id)
pin_top.setColor(pin_color)
new_btr.appendAcDbEntity(pin_top)
pin_bot = Db.Line(Ge.Point3d(KREISEL_DURCHMESSER, -pin_y, 0),
Ge.Point3d(abstand, -pin_y, 0))
pin_bot.setLayer(pin_layer_id)
pin_bot.setColor(pin_color)
new_btr.appendAcDbEntity(pin_bot)
# Beschriftung
ensure_layer(db, _beschriftung_layer, _beschriftung_farbe)
style_name = ensure_textstyle(db)
tst = Db.TextStyleTable(db.textStyleTableId(), Db.OpenMode.kForRead)
style_id = tst.getAt(style_name)
descr_lt = Db.LayerTable(db.layerTableId(), Db.OpenMode.kForRead)
descr_layer_id = descr_lt.getAt(_beschriftung_layer)
label_text = f"KREISEL {kreisel_nummer}: {art_str}_{abstand:.0f}"
mitte_x = radius + abstand / 2.0
mitte_y = _beschriftung_abstand_oben
label_color = Db.Color()
label_color.setColorIndex(_beschriftung_farbe)
txt = Db.Text()
txt.setPosition(Ge.Point3d(mitte_x, mitte_y, 0))
txt.setAlignmentPoint(Ge.Point3d(mitte_x, mitte_y, 0))
txt.setHeight(_beschriftung_hoehe)
txt.setTextString(label_text)
txt.setTextStyle(style_id)
txt.setLayer(descr_layer_id)
txt.setColor(label_color)
txt.setHorizontalMode(Db.TextHorzMode.kTextCenter)
txt.setVerticalMode(Db.TextVertMode.kTextVertMid)
new_btr.appendAcDbEntity(txt)
# Unsichtbare Attribut-Definitionen
create_attrib_defs(new_btr, KREISEL_ATTRIB_DEFS)
print(f"\n-> Neue Blockdefinition: {bname}")
else:
print(f"\n-> Verwende bestehende Blockdefinition: {bname}")
# Block am Zielpunkt einfuegen
pt = Ge.Point3d(base_point.x, base_point.y, z_hoehe)
obj_id = insert_block_with_attribs(db, bname, pt, rotation_deg, merged)
print(f"\n-> Kreisel #{kreisel_nummer} eingefuegt: {bname} (Hoehe={z_hoehe:.0f})")
return obj_id
# ============================================================
# Befehle
# ============================================================
@Rx.command("KreiselInsert")
def cmd_kreisel_insert():
"""KreiselInsert: Manuell Position + Parameter."""
ed = Ed.Editor()
db = Db.HostApplicationServices().workingDatabase()
# 1. Einfuegepunkt
res = ed.getPoint("\nBasispunkt (AN-Seite): ")
if res[0] != Ed.PromptStatus.eOk:
print("\nBefehl abgebrochen.")
return
pt = res[1]
# 2. Hoehe bestimmen
hoehe = _get_hoehe(ed, pt)
# 3. Abstand
pdo = Ed.PromptDistanceOptions("\nAbstand (Tangentenlaenge): ")
pdo.setDefaultValue(KREISEL_DEFAULT_LAENGE)
pdo.setAllowNone(True)
res_dist = ed.getDist(pdo)
if res_dist[0] == Ed.PromptStatus.eOk:
abstand = res_dist[1]
else:
abstand = KREISEL_DEFAULT_LAENGE
print(f"\n-> Abstand: {abstand:.0f} mm")
# 4. Rotation
res_rot = ed.getString("\nRotation in Grad <0>: ")
if res_rot[0] == Ed.PromptStatus.eOk and res_rot[1]:
try:
rotation = float(res_rot[1])
except ValueError:
rotation = 0.0
else:
rotation = 0.0
# 5. Kreiselart
typ = _ask_kreiselart(ed)
print(f"\n-> Rotation: {rotation:.1f} Hoehe: {hoehe:.0f} Kreiselart: {typ}")
# 6. Modul einfuegen
draw_module(db, Ge.Point3d(pt.x, pt.y, hoehe), abstand, rotation,
{"KREISELART": typ, "HOEHE": f"{hoehe:.0f}"})
print("\nKreisel Modul eingefuegt.")
@Rx.command("KreiselConnect")
def cmd_kreisel_connect():
"""KreiselConnect: Linie zeichnen fuer Kreisel-Platzierung (AN -> SP)."""
ed = Ed.Editor()
db = Db.HostApplicationServices().workingDatabase()
print("\n--- Kreisel durch Linie definieren (AN -> SP) ---")
# 1. Startpunkt (AN-Seite)
res_start = ed.getPoint("\nStartpunkt (AN-Seite aussen): ")
if res_start[0] != Ed.PromptStatus.eOk:
print("\nAbgebrochen.")
return
pt_start = res_start[1]
# 2. Endpunkt (SP-Seite) mit Gummiband
res_end = ed.getPoint("\nEndpunkt (SP-Seite aussen): ", pt_start)
if res_end[0] != Ed.PromptStatus.eOk:
print("\nAbgebrochen.")
return
pt_end = res_end[1]
# 3. Geometrie berechnen
dx = pt_end.x - pt_start.x
dy = pt_end.y - pt_start.y
dist = math.sqrt(dx * dx + dy * dy)
abstand = dist - KREISEL_DURCHMESSER
if abstand <= 0.0:
print(f"\nDistanz zu klein! ({dist:.0f} < {KREISEL_DURCHMESSER:.0f})")
return
# 4. Rotation
rotation = math.degrees(math.atan2(dy, dx))
# 5. Hoehe
hoehe = pt_start.z if pt_start.z > 0 else 0.0
if hoehe <= 0.0:
res_h = ed.getDouble(f"\nHoehe (Z-Koordinate) <{KREISEL_DEFAULT_HOEHE:.0f}>: ")
hoehe = res_h[1] if res_h[0] == Ed.PromptStatus.eOk else KREISEL_DEFAULT_HOEHE
else:
print(f"\n-> Hoehe aus Startpunkt uebernommen: {hoehe:.0f}")
# 6. Kreiselart
typ = _ask_kreiselart(ed)
print(f"\n-> Abstand: {abstand:.0f} mm Rotation: {rotation:.1f} Grad"
f" Hoehe: {hoehe:.0f} Kreiselart: {typ}")
# 7. Modul einfuegen
draw_module(db, Ge.Point3d(pt_start.x, pt_start.y, hoehe), abstand, rotation,
{"KREISELART": typ, "HOEHE": f"{hoehe:.0f}"})
print("\nKreisel Connect erfolgreich!")
@Rx.command("KreiselRedraw")
def cmd_kreisel_redraw():
"""KreiselRedraw: Bestehenden Kreisel neu zeichnen."""
ed = Ed.Editor()
db = Db.HostApplicationServices().workingDatabase()
# 1. Bestehenden Kreisel-Block auswaehlen
res = ed.entSel("\nKreisel-Block auswaehlen: ")
if res[0] != Ed.PromptStatus.eOk:
return
ent_id = res[1]
ent = Db.Entity(ent_id, Db.OpenMode.kForRead)
if not ent.isKindOf(Db.BlockReference.desc()):
print("\nKein Block ausgewaehlt!")
return
bref = Db.BlockReference(ent_id, Db.OpenMode.kForRead)
attribs = read_block_attribs(bref)
base_point = bref.position()
rotation = math.degrees(bref.rotation())
if "ABSTAND" not in attribs:
print("\nKein Kreisel-Block! (Attribut ABSTAND fehlt)")
return
print(f"\n-> Bestehend: Abstand={attribs.get('ABSTAND', '?')}"
f" Drehung={attribs.get('DREHUNG', '?')}"
f" Hoehe={attribs.get('HOEHE', '?')}"
f" Art={attribs.get('KREISELART', '?')}")
# 2. Neuen Abstand abfragen
old_abstand = float(attribs.get("ABSTAND", "2300"))
res_a = ed.getDouble(f"\nNeuer Abstand <{old_abstand:.0f}>: ")
new_abstand = res_a[1] if res_a[0] == Ed.PromptStatus.eOk else old_abstand
# 3. Neue Hoehe abfragen
old_hoehe = float(attribs.get("HOEHE", "0"))
res_h = ed.getDouble(f"\nNeue Hoehe <{old_hoehe:.0f}>: ")
new_hoehe = res_h[1] if res_h[0] == Ed.PromptStatus.eOk else old_hoehe
# 4. Alten Block loeschen
bref.upgradeOpen()
bref.erase()
# 5. Neu zeichnen mit bestehenden Attributen + neuem Abstand
draw_module(db, Ge.Point3d(base_point.x, base_point.y, new_hoehe),
new_abstand, rotation, attribs)
print(f"\nKreisel neu gezeichnet. Abstand={new_abstand:.0f}")
@Rx.command("KreiselQuick")
def cmd_kreisel_quick():
"""KreiselQuick: Schnell mit Defaults (horizontal)."""
ed = Ed.Editor()
db = Db.HostApplicationServices().workingDatabase()
res = ed.getPoint("\nBasispunkt (AN-Seite): ")
if res[0] != Ed.PromptStatus.eOk:
return
pt = res[1]
res_h = ed.getDouble("\nHoehe (Z-Koordinate) <0>: ")
hoehe = res_h[1] if res_h[0] == Ed.PromptStatus.eOk else 0.0
draw_module(db, Ge.Point3d(pt.x, pt.y, hoehe),
KREISEL_DEFAULT_LAENGE, 0.0,
{"HOEHE": f"{hoehe:.0f}"})
print("\nSchnell Einfuegen fertig.")
def kreisel_edit_entity(db, ent_id):
"""Kreisel per wxPython-Dialog bearbeiten (fuer eine bestimmte Entity-ID).
Wird von KreiselEdit und SSG_BLOCKEDIT aufgerufen.
"""
bref = Db.BlockReference(ent_id, Db.OpenMode.kForRead)
attribs = read_block_attribs(bref)
base_point = bref.position()
rotation = math.degrees(bref.rotation())
if "ABSTAND" not in attribs:
print("\nKein Kreisel-Block! (Attribut ABSTAND fehlt)")
return
# Fehlende Attribute mit Defaults auffuellen
for tag, default in KREISEL_ATTRIB_DEFS:
if tag not in attribs:
attribs[tag] = default
# HOEHE aus Z-Koordinate
attribs["HOEHE"] = f"{base_point.z:.1f}" if base_point.z > 0 else attribs.get("HOEHE", "0")
print(f"\n-> Bestehend: Abstand={attribs.get('ABSTAND')}"
f" Drehung={rotation:.1f}"
f" Art={attribs.get('KREISELART')}")
# wxPython-Dialog
dlg = KreiselEditDialog(None, attribs, rotation)
result = dlg.ShowModal()
if result == wx.ID_OK:
new_values = dlg.get_values()
dlg.Destroy()
attribs["NAME"] = new_values["name"]
attribs["HOEHE"] = new_values["hoehe"]
attribs["KREISELART"] = new_values["kreiselart"]
attribs["DREHRICHTUNG"] = new_values["drehrichtung"]
new_abstand = float(new_values["abstand"])
new_rotation = new_values["rotation"]
# Alten Block loeschen
bref.upgradeOpen()
bref.erase()
# Neu zeichnen
draw_module(db,
Ge.Point3d(base_point.x, base_point.y, float(new_values["hoehe"])),
new_abstand, new_rotation, attribs)
print(f"\nKreisel aktualisiert: Name={new_values['name']}"
f" Abstand={new_abstand:.0f} Hoehe={new_values['hoehe']}"
f" Rotation={new_rotation:.1f}")
else:
dlg.Destroy()
print("\nAbgebrochen.")
@Rx.command("KreiselEdit")
def cmd_kreisel_edit():
"""KreiselEdit: Bestehenden Kreisel per wxPython-Dialog bearbeiten."""
ed = Ed.Editor()
db = Db.HostApplicationServices().workingDatabase()
res = ed.entSel("\nKreisel-Block auswaehlen: ")
if res[0] != Ed.PromptStatus.eOk:
return
ent_id = res[1]
ent = Db.Entity(ent_id, Db.OpenMode.kForRead)
if not ent.isKindOf(Db.BlockReference.desc()):
print("\nKein Block ausgewaehlt!")
return
kreisel_edit_entity(db, ent_id)
@Rx.command("KreiselParams")
def cmd_kreisel_params():
"""KreiselParams: Aktuelle Parameter anzeigen."""
print("\n=== Kreisel Parameter ===")
print(f"\nKreiselart: {_kreisel_typ}")
print(f"\nDurchmesser: {KREISEL_DURCHMESSER:.0f}")
print(f"\nDefault-Laenge: {KREISEL_DEFAULT_LAENGE:.0f}")
print(f"\nDefault-Hoehe: {KREISEL_DEFAULT_HOEHE:.0f}")
print("\nAttribute im Block:")
for tag, default in KREISEL_ATTRIB_DEFS:
print(f"\n {tag} = {default}")
print("\n=========================\n")
@Rx.command("KreiselLabelSetup")
def cmd_kreisel_label_setup():
"""KreiselLabelSetup: Beschriftungs-Einstellungen aendern."""
global _beschriftung_hoehe, _beschriftung_farbe, _beschriftung_abstand_oben
ed = Ed.Editor()
res = ed.getDouble(f"\nSchrifthoehe <{_beschriftung_hoehe:.0f}>: ")
if res[0] == Ed.PromptStatus.eOk:
_beschriftung_hoehe = res[1]
res = ed.getInteger(f"\nSchriftfarbe (1-7) <{_beschriftung_farbe}>: ")
if res[0] == Ed.PromptStatus.eOk:
_beschriftung_farbe = res[1]
res = ed.getDouble(f"\nAbstand ueber Kreisel-Mitte <{_beschriftung_abstand_oben:.0f}>: ")
if res[0] == Ed.PromptStatus.eOk:
_beschriftung_abstand_oben = res[1]
print(f"\nNeue Einstellungen: Hoehe={_beschriftung_hoehe:.0f}"
f", Farbe={_beschriftung_farbe}"
f", Y-Versatz={_beschriftung_abstand_oben:.0f}"
f", Schriftart=Arial")
@Rx.command("KreiselLabelPos")
def cmd_kreisel_label_pos():
"""KreiselLabelPos: Beschriftungsposition aendern."""
global _beschriftung_abstand_x, _beschriftung_abstand_y
ed = Ed.Editor()
res = ed.getDouble(f"\nX-Abstand von AN8-Mitte <{_beschriftung_abstand_x:.0f}>: ")
if res[0] == Ed.PromptStatus.eOk:
_beschriftung_abstand_x = res[1]
res = ed.getDouble(f"\nY-Abstand von AN8-Mitte <{_beschriftung_abstand_y:.0f}>: ")
if res[0] == Ed.PromptStatus.eOk:
_beschriftung_abstand_y = res[1]
print(f"\nNeue Beschriftungsposition: X={_beschriftung_abstand_x:.0f}"
f" Y={_beschriftung_abstand_y:.0f}")
@Rx.command("KreiselLabelHoehe")
def cmd_kreisel_label_hoehe():
"""KreiselLabelHoehe: Texthoehe aendern."""
global _beschriftung_hoehe
ed = Ed.Editor()
res = ed.getDouble(f"\nTexthoehe <{_beschriftung_hoehe:.0f}>: ")
if res[0] == Ed.PromptStatus.eOk:
_beschriftung_hoehe = res[1]
print(f"\nNeue Texthoehe: {_beschriftung_hoehe:.0f}")
# ============================================================
# Interne Helfer fuer Befehle
# ============================================================
def _get_hoehe(ed, pt):
"""Hoehe aus 3D-Punkt oder manuell abfragen."""
if pt.z > 0:
print(f"\n-> Hoehe aus 3D-Punkt uebernommen: {pt.z:.0f}")
return pt.z
res = ed.getDouble(f"\nHoehe (Z-Koordinate) <{KREISEL_DEFAULT_HOEHE:.0f}>: ")
if res[0] == Ed.PromptStatus.eOk:
return res[1]
return KREISEL_DEFAULT_HOEHE
def _ask_kreiselart(ed):
"""Kreiselart (PIN/STANDARD) abfragen."""
global _kreisel_typ
default_str = "2" if _kreisel_typ == "PIN" else "1"
print(f"\n[1] STANDARD (ohne PIN)")
print(f"\n[2] PIN")
res = ed.getString(f"\nBitte waehlen <{default_str}>: ")
if res[0] == Ed.PromptStatus.eOk and res[1] == "2":
_kreisel_typ = "PIN"
else:
_kreisel_typ = "STANDARD"
return _kreisel_typ
# ============================================================
# wxPython-Dialog: Ersetzt kreisel_edit.dcl
# ============================================================
class KreiselEditDialog(wx.Dialog):
"""Dialog zum Bearbeiten eines bestehenden Kreisels.
Ersetzt den DCL-Dialog kreisel_edit.dcl."""
def __init__(self, parent, attribs, rotation):
super().__init__(parent, title="Kreisel bearbeiten",
size=(380, 300),
style=wx.DEFAULT_DIALOG_STYLE)
panel = wx.Panel(self)
sizer = wx.BoxSizer(wx.VERTICAL)
# Name
row_name = wx.BoxSizer(wx.HORIZONTAL)
row_name.Add(wx.StaticText(panel, label="Kreiselname:"), 0,
wx.ALIGN_CENTER_VERTICAL | wx.RIGHT, 5)
self.txt_name = wx.TextCtrl(panel, value=attribs.get("NAME", ""), size=(200, -1))
row_name.Add(self.txt_name, 1)
sizer.Add(row_name, 0, wx.EXPAND | wx.ALL, 5)
# Abstand + Hoehe
row_ah = wx.BoxSizer(wx.HORIZONTAL)
row_ah.Add(wx.StaticText(panel, label="Abstand (mm):"), 0,
wx.ALIGN_CENTER_VERTICAL | wx.RIGHT, 5)
self.txt_abstand = wx.TextCtrl(panel, value=attribs.get("ABSTAND", "2300"), size=(80, -1))
row_ah.Add(self.txt_abstand, 0, wx.RIGHT, 15)
row_ah.Add(wx.StaticText(panel, label="Hoehe (mm):"), 0,
wx.ALIGN_CENTER_VERTICAL | wx.RIGHT, 5)
self.txt_hoehe = wx.TextCtrl(panel, value=attribs.get("HOEHE", "0"), size=(80, -1))
row_ah.Add(self.txt_hoehe, 0)
sizer.Add(row_ah, 0, wx.EXPAND | wx.ALL, 5)
# Ausrichtung
row_aus = wx.BoxSizer(wx.HORIZONTAL)
row_aus.Add(wx.StaticText(panel, label="Ausrichtung:"), 0,
wx.ALIGN_CENTER_VERTICAL | wx.RIGHT, 5)
choices = [label for label, _ in KREISEL_AUSRICHTUNGEN]
self.cb_ausrichtung = wx.Choice(panel, choices=choices)
self.cb_ausrichtung.SetSelection(rotation_to_idx(rotation))
row_aus.Add(self.cb_ausrichtung, 1)
sizer.Add(row_aus, 0, wx.EXPAND | wx.ALL, 5)
# Drehrichtung + Kreiselart
row_dk = wx.BoxSizer(wx.HORIZONTAL)
row_dk.Add(wx.StaticText(panel, label="Drehrichtung:"), 0,
wx.ALIGN_CENTER_VERTICAL | wx.RIGHT, 5)
self.cb_drehrichtung = wx.Choice(panel, choices=["UZS", "GUZ"])
self.cb_drehrichtung.SetSelection(1 if attribs.get("DREHRICHTUNG") == "GUZ" else 0)
row_dk.Add(self.cb_drehrichtung, 0, wx.RIGHT, 15)
row_dk.Add(wx.StaticText(panel, label="Typ:"), 0,
wx.ALIGN_CENTER_VERTICAL | wx.RIGHT, 5)
self.cb_kreiselart = wx.Choice(panel, choices=["STANDARD", "PIN"])
self.cb_kreiselart.SetSelection(1 if attribs.get("KREISELART") == "PIN" else 0)
row_dk.Add(self.cb_kreiselart, 0)
sizer.Add(row_dk, 0, wx.EXPAND | wx.ALL, 5)
# OK / Cancel
btn_sizer = self.CreateStdDialogButtonSizer(wx.OK | wx.CANCEL)
sizer.Add(btn_sizer, 0, wx.EXPAND | wx.ALL, 10)
panel.SetSizer(sizer)
self.Fit()
self.CenterOnScreen()
def get_values(self):
"""Dialog-Werte als dict zurueckgeben."""
idx = self.cb_ausrichtung.GetSelection()
return {
"name": self.txt_name.GetValue(),
"abstand": self.txt_abstand.GetValue(),
"hoehe": self.txt_hoehe.GetValue(),
"rotation": idx_to_rotation(idx),
"drehrichtung": "GUZ" if self.cb_drehrichtung.GetSelection() == 1 else "UZS",
"kreiselart": "PIN" if self.cb_kreiselart.GetSelection() == 1 else "STANDARD",
}