Omniflo Boegen und Weichen auch durch .py erzeugen und ändern.
This commit is contained in:
File diff suppressed because it is too large
Load Diff
+2
-2
@@ -25,10 +25,10 @@
|
||||
(dbgopen "debugfile.dbg" "DXFM_LOG") ; Debug-Datei im Log-Verzeichnis oeffnen
|
||||
(load (strcat base-path "ssg_dialog.lsp") "ssg_dialog.lsp nicht gefunden")
|
||||
(load (strcat base-path "ssg_layer.lsp") "ssg_layer.lsp nicht gefunden")
|
||||
(load (strcat base-path "KreiselInsert.lsp") "KreiselInsert.lsp nicht gefunden")
|
||||
;; KreiselInsert.lsp entfernt - ersetzt durch Python/PyRx (lib/elemente/kreisel.py, eckrad.py)
|
||||
(load (strcat base-path "VarioFoerderer.lsp") "VarioFoerderer.lsp nicht gefunden")
|
||||
(load (strcat base-path "tests.lsp") "tests.lsp nicht gefunden")
|
||||
(load (strcat base-path "OmniModulInsert.lsp") "OmniModulInsert.lsp nicht gefunden")
|
||||
;; OmniModulInsert.lsp entfernt - ersetzt durch Python/PyRx (lib/elemente/omniflo*.py)
|
||||
(load (strcat base-path "SSG_LIB_Commands.lsp") "SSG_LIB_Commands.lsp nicht gefunden")
|
||||
(prompt "\nSSG-Bibliotheken geladen: ssg_core, ssg_dbg, ssg_dialog, ssg_layer")
|
||||
(princ)
|
||||
|
||||
+4
-1
@@ -60,9 +60,12 @@
|
||||
(princ "\n[SSG_LIB] WARNUNG: DXFMAKRO nicht gesetzt, Menue nicht geladen!")
|
||||
)
|
||||
|
||||
;; DBLCLKEDIT deaktivieren (Block-Editor nicht bei Doppelklick oeffnen)
|
||||
(setvar "DBLCLKEDIT" 0)
|
||||
|
||||
;; Python-Module laden (PyRx)
|
||||
(if menu-pfad
|
||||
(foreach pymod '("eckrad" "kreisel")
|
||||
(foreach pymod '("eckrad" "kreisel" "dblclick" "omniflo" "omniflo_boegen" "omniflo_weichen")
|
||||
(if (findfile (strcat menu-pfad "/lib/elemente/" pymod ".py"))
|
||||
(progn
|
||||
(command "PYLOAD" (strcat menu-pfad "/lib/elemente/" pymod ".py"))
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
// ============================================================
|
||||
// omniflo_boegen.dcl - Bogen-Auswahl Dialog fuer Omniflo
|
||||
// Zeigt gefilterte Boegen nach Winkel mit Details an.
|
||||
// ============================================================
|
||||
|
||||
omniflo_boegen : dialog {
|
||||
label = "Omniflo Bogen Auswahl";
|
||||
|
||||
: row {
|
||||
: popup_list {
|
||||
key = "bogenart";
|
||||
label = "Bogenart:";
|
||||
width = 42;
|
||||
}
|
||||
: edit_box {
|
||||
key = "val_sivasnr";
|
||||
label = "SivasNr:";
|
||||
width = 22;
|
||||
is_enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
: row {
|
||||
: edit_box {
|
||||
key = "val_winkel";
|
||||
label = "Winkel:";
|
||||
width = 16;
|
||||
is_enabled = false;
|
||||
}
|
||||
: edit_box {
|
||||
key = "val_radius";
|
||||
label = "Radius:";
|
||||
width = 16;
|
||||
is_enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
: row {
|
||||
: edit_box {
|
||||
key = "val_breite";
|
||||
label = "Breite:";
|
||||
width = 16;
|
||||
is_enabled = false;
|
||||
}
|
||||
: edit_box {
|
||||
key = "val_laenge";
|
||||
label = "Laenge:";
|
||||
width = 16;
|
||||
is_enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
ok_cancel;
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
// ============================================================
|
||||
// omniflo_weichen.dcl - Weichen-Auswahl Dialog fuer Omniflo
|
||||
// Zeigt gefilterte Weichen mit Details und Filteroptionen an.
|
||||
// ============================================================
|
||||
|
||||
omniflo_weichen : dialog {
|
||||
label = "Omniflo Weichen Auswahl";
|
||||
|
||||
: row {
|
||||
: popup_list {
|
||||
key = "profiltyp";
|
||||
label = "Profiltyp-Auswahl:";
|
||||
width = 50;
|
||||
}
|
||||
}
|
||||
|
||||
: row {
|
||||
: boxed_radio_column {
|
||||
key = "schaltung";
|
||||
label = "Schaltungstyp";
|
||||
: radio_button { key = "sch_alle"; label = "Alle"; value = "1"; }
|
||||
: radio_button { key = "sch_m"; label = "Mechanisch (M)"; }
|
||||
: radio_button { key = "sch_p"; label = "Pneumatisch (P)"; }
|
||||
}
|
||||
: boxed_radio_column {
|
||||
key = "richtung";
|
||||
label = "Richtung";
|
||||
: radio_button { key = "ri_alle"; label = "Alle"; value = "1"; }
|
||||
: radio_button { key = "ri_links"; label = "Links"; }
|
||||
: radio_button { key = "ri_rechts"; label = "Rechts"; }
|
||||
}
|
||||
}
|
||||
|
||||
: row {
|
||||
: edit_box {
|
||||
key = "val_sivasnr";
|
||||
label = "SivasNr:";
|
||||
width = 22;
|
||||
is_enabled = false;
|
||||
}
|
||||
: edit_box {
|
||||
key = "val_winkel";
|
||||
label = "Winkel:";
|
||||
width = 12;
|
||||
is_enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
: row {
|
||||
: edit_box {
|
||||
key = "val_breite";
|
||||
label = "Breite:";
|
||||
width = 12;
|
||||
is_enabled = false;
|
||||
}
|
||||
: edit_box {
|
||||
key = "val_laenge";
|
||||
label = "Laenge:";
|
||||
width = 12;
|
||||
is_enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
ok_cancel;
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
# dblclick.py
|
||||
# SSG_BLOCKEDIT - Dispatcher fuer Rechtsklick-Bearbeitung von SSG-Bloecken
|
||||
# Prueft den selektierten Block und oeffnet den passenden Dialog.
|
||||
# ============================================
|
||||
|
||||
import PyRx as Rx
|
||||
import PyDb as Db
|
||||
import PyEd as Ed
|
||||
|
||||
from elemente.kreisel import kreisel_edit_entity
|
||||
from elemente.eckrad import eckrad_edit_entity
|
||||
|
||||
|
||||
@Rx.command("SSG_BLOCKEDIT")
|
||||
def ssg_blockedit():
|
||||
"""Dispatcher: prueft selektierten Block und oeffnet passenden Dialog.
|
||||
|
||||
Wird aus dem Rechtsklick-Kontextmenue aufgerufen.
|
||||
Erkennt KREISEL_* und ECKRAD_* Bloecke und oeffnet den jeweiligen
|
||||
wxPython-Bearbeitungsdialog. Bei anderen Bloecken wird BEDIT gestartet.
|
||||
"""
|
||||
ed = Ed.Editor()
|
||||
db = Db.HostApplicationServices().workingDatabase()
|
||||
|
||||
# Implied Selection nutzen (bereits selektiertes Objekt)
|
||||
res = ed.selectImplied()
|
||||
if res[0] != Ed.PromptStatus.eOk:
|
||||
return
|
||||
|
||||
ss = res[1]
|
||||
if ss.length() == 0:
|
||||
return
|
||||
|
||||
ent_id = ss.getObjectIds()[0]
|
||||
ent = Db.Entity(ent_id, Db.OpenMode.kForRead)
|
||||
|
||||
if not ent.isKindOf(Db.BlockReference.desc()):
|
||||
return
|
||||
|
||||
bref = Db.BlockReference(ent_id, Db.OpenMode.kForRead)
|
||||
btr = Db.BlockTableRecord(bref.blockTableRecord(), Db.OpenMode.kForRead)
|
||||
bname = btr.getName().upper()
|
||||
|
||||
if bname.startswith("KREISEL_"):
|
||||
kreisel_edit_entity(db, ent_id)
|
||||
elif bname.startswith("ECKRAD_"):
|
||||
eckrad_edit_entity(db, ent_id)
|
||||
else:
|
||||
# Anderer Block -> normaler Block-Editor
|
||||
ed.runCommand("_.BEDIT\n")
|
||||
@@ -10,11 +10,13 @@ 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_block_from_dwg,
|
||||
create_attrib_defs,
|
||||
insert_block_with_attribs,
|
||||
@@ -178,3 +180,126 @@ def ils_eckrad():
|
||||
# 5. Einfuegen
|
||||
insert_pt = Ge.Point3d(center_x, center_y, hoehe)
|
||||
insert_eckrad(db, insert_pt, rotation)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Eckrad bearbeiten (wx-Dialog)
|
||||
# ============================================================
|
||||
|
||||
class EckradEditDialog(wx.Dialog):
|
||||
"""Dialog zum Bearbeiten eines bestehenden Eckrads."""
|
||||
|
||||
def __init__(self, parent, attribs):
|
||||
super().__init__(parent, title="Eckrad bearbeiten",
|
||||
size=(320, 220),
|
||||
style=wx.DEFAULT_DIALOG_STYLE)
|
||||
|
||||
panel = wx.Panel(self)
|
||||
sizer = wx.BoxSizer(wx.VERTICAL)
|
||||
|
||||
# Name (readonly)
|
||||
row_name = wx.BoxSizer(wx.HORIZONTAL)
|
||||
row_name.Add(wx.StaticText(panel, label="Name:"), 0,
|
||||
wx.ALIGN_CENTER_VERTICAL | wx.RIGHT, 5)
|
||||
self.txt_name = wx.TextCtrl(panel, value=attribs.get("NAME", ""),
|
||||
size=(180, -1), style=wx.TE_READONLY)
|
||||
row_name.Add(self.txt_name, 1)
|
||||
sizer.Add(row_name, 0, wx.EXPAND | wx.ALL, 5)
|
||||
|
||||
# Drehrichtung
|
||||
row_dreh = wx.BoxSizer(wx.HORIZONTAL)
|
||||
row_dreh.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_dreh.Add(self.cb_drehrichtung, 0)
|
||||
sizer.Add(row_dreh, 0, wx.EXPAND | wx.ALL, 5)
|
||||
|
||||
# Hoehe
|
||||
row_hoehe = wx.BoxSizer(wx.HORIZONTAL)
|
||||
row_hoehe.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_hoehe.Add(self.txt_hoehe, 0)
|
||||
sizer.Add(row_hoehe, 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."""
|
||||
return {
|
||||
"drehrichtung": "GUZ" if self.cb_drehrichtung.GetSelection() == 1 else "UZS",
|
||||
"hoehe": self.txt_hoehe.GetValue(),
|
||||
}
|
||||
|
||||
|
||||
def eckrad_edit_entity(db, ent_id):
|
||||
"""Eckrad per wxPython-Dialog bearbeiten (fuer eine bestimmte Entity-ID).
|
||||
|
||||
Wird von EckradEdit und SSG_BLOCKEDIT aufgerufen.
|
||||
"""
|
||||
bref = Db.BlockReference(ent_id, Db.OpenMode.kForRead)
|
||||
attribs = read_block_attribs(bref)
|
||||
base_point = bref.position()
|
||||
rotation_deg = math.degrees(bref.rotation())
|
||||
|
||||
# HOEHE aus Z-Koordinate
|
||||
if base_point.z > 0:
|
||||
attribs["HOEHE"] = f"{base_point.z:.0f}"
|
||||
|
||||
print(f"\n-> Bestehend: Name={attribs.get('NAME', '?')}"
|
||||
f" Drehrichtung={attribs.get('DREHRICHTUNG', '?')}"
|
||||
f" Hoehe={attribs.get('HOEHE', '?')}")
|
||||
|
||||
dlg = EckradEditDialog(None, attribs)
|
||||
result = dlg.ShowModal()
|
||||
|
||||
if result == wx.ID_OK:
|
||||
new_values = dlg.get_values()
|
||||
dlg.Destroy()
|
||||
|
||||
attribs["DREHRICHTUNG"] = new_values["drehrichtung"]
|
||||
attribs["HOEHE"] = new_values["hoehe"]
|
||||
|
||||
new_hoehe = float(new_values["hoehe"])
|
||||
|
||||
# Alten Block loeschen
|
||||
bref.upgradeOpen()
|
||||
bref.erase()
|
||||
|
||||
# Neu einfuegen
|
||||
insert_pt = Ge.Point3d(base_point.x, base_point.y, new_hoehe)
|
||||
insert_eckrad(db, insert_pt, rotation_deg, attribs)
|
||||
|
||||
print(f"\nEckrad aktualisiert: Drehrichtung={new_values['drehrichtung']}"
|
||||
f" Hoehe={new_values['hoehe']}")
|
||||
else:
|
||||
dlg.Destroy()
|
||||
print("\nAbgebrochen.")
|
||||
|
||||
|
||||
@Rx.command("EckradEdit")
|
||||
def cmd_eckrad_edit():
|
||||
"""EckradEdit: Bestehenden Eckrad per wxPython-Dialog bearbeiten."""
|
||||
ed = Ed.Editor()
|
||||
db = Db.HostApplicationServices().workingDatabase()
|
||||
|
||||
res = ed.entSel("\nEckrad-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
|
||||
|
||||
eckrad_edit_entity(db, ent_id)
|
||||
|
||||
+24
-18
@@ -426,23 +426,11 @@ def cmd_kreisel_quick():
|
||||
print("\nSchnell Einfuegen fertig.")
|
||||
|
||||
|
||||
@Rx.command("KreiselEdit")
|
||||
def cmd_kreisel_edit():
|
||||
"""KreiselEdit: Bestehenden Kreisel per wxPython-Dialog bearbeiten."""
|
||||
ed = Ed.Editor()
|
||||
db = Db.HostApplicationServices().workingDatabase()
|
||||
|
||||
# 1. 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
|
||||
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()
|
||||
@@ -464,7 +452,7 @@ def cmd_kreisel_edit():
|
||||
f" Drehung={rotation:.1f}"
|
||||
f" Art={attribs.get('KREISELART')}")
|
||||
|
||||
# 2. wxPython-Dialog (ersetzt DCL)
|
||||
# wxPython-Dialog
|
||||
dlg = KreiselEditDialog(None, attribs, rotation)
|
||||
result = dlg.ShowModal()
|
||||
|
||||
@@ -472,7 +460,6 @@ def cmd_kreisel_edit():
|
||||
new_values = dlg.get_values()
|
||||
dlg.Destroy()
|
||||
|
||||
# Attribute aktualisieren
|
||||
attribs["NAME"] = new_values["name"]
|
||||
attribs["HOEHE"] = new_values["hoehe"]
|
||||
attribs["KREISELART"] = new_values["kreiselart"]
|
||||
@@ -498,6 +485,25 @@ def cmd_kreisel_edit():
|
||||
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."""
|
||||
|
||||
@@ -0,0 +1,400 @@
|
||||
# omniflo.py
|
||||
# Omniflo Kern-Modul: JSON-Daten, DXF-Insert, Aluprofil, TEF-Dummies
|
||||
# Ersetzt den Kern von OmniModulInsert.lsp
|
||||
# ============================================
|
||||
|
||||
import os
|
||||
import math
|
||||
from datetime import datetime
|
||||
|
||||
import PyRx as Rx
|
||||
import PyGe as Ge
|
||||
import PyDb as Db
|
||||
import PyEd as Ed
|
||||
|
||||
from elemente.utils import (
|
||||
get_data_path,
|
||||
load_json_data,
|
||||
get_block_path,
|
||||
read_block_attribs,
|
||||
ensure_block_from_dxf,
|
||||
)
|
||||
|
||||
# ============================================================
|
||||
# JSON-Daten Cache
|
||||
# ============================================================
|
||||
|
||||
_boegen_data = None
|
||||
_weichen_data = None
|
||||
|
||||
|
||||
def load_boegen():
|
||||
"""omniflo_boegen.json laden und cachen."""
|
||||
global _boegen_data
|
||||
if _boegen_data is not None:
|
||||
return _boegen_data
|
||||
_boegen_data = load_json_data("json/omniflo_boegen.json")
|
||||
print(f"\n[OMNI] {len(_boegen_data)} Boegen geladen.")
|
||||
return _boegen_data
|
||||
|
||||
|
||||
def load_weichen():
|
||||
"""omniflo_weichen.json laden und cachen."""
|
||||
global _weichen_data
|
||||
if _weichen_data is not None:
|
||||
return _weichen_data
|
||||
_weichen_data = load_json_data("json/omniflo_weichen.json")
|
||||
print(f"\n[OMNI] {len(_weichen_data)} Weichen geladen.")
|
||||
return _weichen_data
|
||||
|
||||
|
||||
def filter_by(data, key, value):
|
||||
"""Eintraege nach key/value filtern."""
|
||||
return [e for e in data if e.get(key) == value]
|
||||
|
||||
|
||||
def get_by_sivasnr(data, sivasnr):
|
||||
"""Eintrag anhand Sivasnr suchen."""
|
||||
s = str(sivasnr)
|
||||
for e in data:
|
||||
if str(e.get("Sivasnr", "")) == s:
|
||||
return e
|
||||
return None
|
||||
|
||||
|
||||
def sivasnr_to_str(val):
|
||||
"""SivasNr-Wert als String zurueckgeben."""
|
||||
if val is None:
|
||||
return ""
|
||||
if isinstance(val, float):
|
||||
return str(int(val))
|
||||
return str(val)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# DXF-Block einfuegen
|
||||
# ============================================================
|
||||
|
||||
def insert_dxf_block(sivasnr_str):
|
||||
"""DXF aus data/omniflo/ als Block einfuegen.
|
||||
|
||||
User waehlt Einfuegepunkt und Drehwinkel.
|
||||
Rueckgabe: Einfuegepunkt oder None bei Abbruch.
|
||||
"""
|
||||
dp = get_data_path()
|
||||
if not dp:
|
||||
return None
|
||||
|
||||
dxf_path = f"{dp}/omniflo/{sivasnr_str}.dxf"
|
||||
ed = Ed.Editor()
|
||||
|
||||
res_pt = ed.getPoint("\nEinfuegepunkt waehlen: ")
|
||||
if res_pt[0] != Ed.PromptStatus.eOk:
|
||||
print("\n[OMNI] Abgebrochen.")
|
||||
return None
|
||||
pt = res_pt[1]
|
||||
|
||||
res_ang = ed.getAngle("\nDrehwinkel <0>: ", pt)
|
||||
angle_rad = res_ang[1] if res_ang[0] == Ed.PromptStatus.eOk else 0.0
|
||||
|
||||
db = Db.HostApplicationServices().workingDatabase()
|
||||
|
||||
# DXF als Block-Definition laden
|
||||
if not ensure_block_from_dxf(db, dxf_path, sivasnr_str):
|
||||
return None
|
||||
|
||||
# Block einfuegen
|
||||
bt = Db.BlockTable(db.blockTableId(), Db.OpenMode.kForRead)
|
||||
block_id = bt.getAt(sivasnr_str)
|
||||
model = Db.BlockTableRecord(db.modelSpaceId(), Db.OpenMode.kForWrite)
|
||||
|
||||
bref = Db.BlockReference(pt, block_id)
|
||||
bref.setRotation(angle_rad)
|
||||
model.appendAcDbEntity(bref)
|
||||
|
||||
print(f"\n[OMNI] {sivasnr_str} eingefuegt.")
|
||||
return pt
|
||||
|
||||
|
||||
def insert_from_entry(eintrag):
|
||||
"""Eintrag aus Dialog-Ergebnis einfuegen (DXF anhand Sivasnr)."""
|
||||
if not eintrag:
|
||||
return None
|
||||
sivasnr_str = sivasnr_to_str(eintrag.get("Sivasnr"))
|
||||
profil = eintrag.get("ProfilTyp", "?")
|
||||
print(f"\n[OMNI] Einfuegen: {profil} ({sivasnr_str})")
|
||||
return insert_dxf_block(sivasnr_str)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Aluprofil-Fahrstrecke einfuegen
|
||||
# ============================================================
|
||||
|
||||
def insert_aluprofil(blockname, laengemax):
|
||||
"""Aluprofil-Fahrstrecke einfuegen (AP60/AP110/APG110).
|
||||
|
||||
Ablauf:
|
||||
1. Quell-Block (.dwg) laden und Attribute lesen
|
||||
2. Nutzer waehlt Einfuegepunkt -> Text wird platziert
|
||||
3. Nutzer waehlt Endpunkt -> Laengenvalidierung
|
||||
4. Compound-Block aus Linie + ATTDEFs wird erzeugt
|
||||
5. Text wird gedreht und oberhalb der Linie positioniert
|
||||
"""
|
||||
ed = Ed.Editor()
|
||||
db = Db.HostApplicationServices().workingDatabase()
|
||||
block_path = get_block_path()
|
||||
|
||||
text_height = 100.0
|
||||
text_gap = 20.0
|
||||
|
||||
# Quell-Block laden und Attribute lesen
|
||||
dwg_path = block_path + blockname + ".dwg"
|
||||
if not os.path.isfile(dwg_path):
|
||||
print(f"\n[OMNI] FEHLER: {dwg_path} nicht gefunden!")
|
||||
return
|
||||
|
||||
src_block_name = f"_SRC_{blockname}"
|
||||
bt = Db.BlockTable(db.blockTableId(), Db.OpenMode.kForRead)
|
||||
if not bt.has(src_block_name):
|
||||
aux_db = Db.Database(False, True)
|
||||
aux_db.readDwg(dwg_path)
|
||||
db.insert(aux_db, src_block_name)
|
||||
|
||||
# Attribute aus Quell-Block lesen
|
||||
src_attribs = {}
|
||||
bt = Db.BlockTable(db.blockTableId(), Db.OpenMode.kForRead)
|
||||
if bt.has(src_block_name):
|
||||
btr = Db.BlockTableRecord(bt.getAt(src_block_name), Db.OpenMode.kForRead)
|
||||
for ent_id in btr:
|
||||
ent = Db.Entity(ent_id, Db.OpenMode.kForRead)
|
||||
if ent.isKindOf(Db.AttributeDefinition.desc()):
|
||||
attdef = Db.AttributeDefinition(ent_id, Db.OpenMode.kForRead)
|
||||
src_attribs[attdef.tag()] = attdef.textString()
|
||||
|
||||
# LAENGEMAX aus Quell-Attribut ueberschreiben falls vorhanden
|
||||
if "LAENGEMAX" in src_attribs and src_attribs["LAENGEMAX"]:
|
||||
try:
|
||||
laengemax = float(src_attribs["LAENGEMAX"])
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
# 1. Einfuegepunkt
|
||||
res_pt = ed.getPoint("\nEinfuegepunkt waehlen: ")
|
||||
if res_pt[0] != Ed.PromptStatus.eOk:
|
||||
print("\n[OMNI] Abgebrochen.")
|
||||
return
|
||||
pt = res_pt[1]
|
||||
z_val = pt.z if pt.z != 0 else 0.0
|
||||
|
||||
# Text-Entity am Einfuegepunkt erzeugen
|
||||
model = Db.BlockTableRecord(db.modelSpaceId(), Db.OpenMode.kForWrite)
|
||||
text_ent = Db.Text()
|
||||
text_ent.setPosition(Ge.Point3d(pt.x, pt.y, z_val))
|
||||
text_ent.setHeight(text_height)
|
||||
text_ent.setTextString(blockname)
|
||||
text_ent.setRotation(0.0)
|
||||
model.appendAcDbEntity(text_ent)
|
||||
|
||||
# 2. Endpunkt-Schleife mit Laengenvalidierung
|
||||
while True:
|
||||
res_end = ed.getPoint("\nEndpunkt der Fahrstrecke waehlen: ", pt)
|
||||
if res_end[0] != Ed.PromptStatus.eOk:
|
||||
text_ent.upgradeOpen()
|
||||
text_ent.erase()
|
||||
print("\n[OMNI] Abgebrochen.")
|
||||
return
|
||||
|
||||
pt2 = res_end[1]
|
||||
dx = pt2.x - pt.x
|
||||
dy = pt2.y - pt.y
|
||||
laenge = math.sqrt(dx * dx + dy * dy)
|
||||
|
||||
if laenge > laengemax:
|
||||
print(f"\n[OMNI] Fahrstreckenlaenge {laenge:.0f} mm ueberschreitet "
|
||||
f"Maximum von {laengemax:.0f} mm. Bitte neu definieren!")
|
||||
continue
|
||||
|
||||
angle = math.atan2(dy, dx)
|
||||
laenge_str = f"{laenge:.0f}"
|
||||
|
||||
# 3. Compound-Block erzeugen: Linie + Attribute
|
||||
timestamp = datetime.now().strftime("%Y%m%d%H%M%S")
|
||||
bname = f"{blockname}_{timestamp}"
|
||||
|
||||
bt = Db.BlockTable(db.blockTableId(), Db.OpenMode.kForRead)
|
||||
if bt.has(bname):
|
||||
bname = f"{bname}_2"
|
||||
|
||||
bt.upgradeOpen()
|
||||
new_btr = Db.BlockTableRecord()
|
||||
new_btr.setName(bname)
|
||||
bt.add(new_btr)
|
||||
|
||||
# Linie von (0,0) bis (laenge, 0)
|
||||
line = Db.Line(Ge.Point3d(0, 0, 0), Ge.Point3d(laenge, 0, 0))
|
||||
new_btr.appendAcDbEntity(line)
|
||||
|
||||
# Attribute aus Quell-Block als ATTDEFs
|
||||
y_pos = 0.0
|
||||
attdef_height = 50.0
|
||||
for tag, default in src_attribs.items():
|
||||
attdef = Db.AttributeDefinition()
|
||||
attdef.setPosition(Ge.Point3d(0, y_pos, 0))
|
||||
attdef.setHeight(attdef_height)
|
||||
attdef.setTextString(default)
|
||||
attdef.setPrompt(tag)
|
||||
attdef.setTag(tag)
|
||||
attdef.setInvisible(True)
|
||||
new_btr.appendAcDbEntity(attdef)
|
||||
y_pos -= attdef_height * 2.0
|
||||
|
||||
# Block einfuegen
|
||||
block_id = bt.getAt(bname)
|
||||
bref = Db.BlockReference(pt, block_id)
|
||||
bref.setRotation(angle)
|
||||
model.appendAcDbEntity(bref)
|
||||
|
||||
# Attribute setzen: Quell-Werte + LAENGE/A aktualisieren
|
||||
attrib_values = dict(src_attribs)
|
||||
attrib_values["LAENGE"] = laenge_str
|
||||
attrib_values["A"] = laenge_str
|
||||
|
||||
btr_def = Db.BlockTableRecord(block_id, Db.OpenMode.kForRead)
|
||||
for ent_id in btr_def:
|
||||
ent = Db.Entity(ent_id, Db.OpenMode.kForRead)
|
||||
if ent.isKindOf(Db.AttributeDefinition.desc()):
|
||||
ad = Db.AttributeDefinition(ent_id, Db.OpenMode.kForRead)
|
||||
attref = Db.AttributeReference()
|
||||
attref.setPropertiesFrom(ad)
|
||||
attref.setTag(ad.tag())
|
||||
attref.setInvisible(ad.isInvisible())
|
||||
attref.setPosition(ad.position())
|
||||
attref.setHeight(ad.height())
|
||||
val = attrib_values.get(ad.tag(), ad.textString())
|
||||
attref.setTextString(val)
|
||||
bref.appendAttribute(attref)
|
||||
|
||||
# 4. Text aktualisieren: oberhalb der Linie positionieren
|
||||
perp_x = -math.sin(angle) * text_gap
|
||||
perp_y = math.cos(angle) * text_gap
|
||||
text_pt = Ge.Point3d(pt.x + perp_x, pt.y + perp_y, z_val)
|
||||
|
||||
text_ent.upgradeOpen()
|
||||
text_ent.setPosition(text_pt)
|
||||
text_ent.setRotation(angle)
|
||||
text_ent.setTextString(f"{blockname} L={laenge_str}")
|
||||
|
||||
print(f"\n[OMNI] {bname} eingefuegt. Laenge={laenge_str} mm")
|
||||
break
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Aluprofil-Commands
|
||||
# ============================================================
|
||||
|
||||
@Rx.command("OMNI_AP60")
|
||||
def cmd_omni_ap60():
|
||||
insert_aluprofil("AP60", 7000.0)
|
||||
|
||||
@Rx.command("OMNI_AP110")
|
||||
def cmd_omni_ap110():
|
||||
insert_aluprofil("AP110", 6000.0)
|
||||
|
||||
@Rx.command("OMNI_APG110")
|
||||
def cmd_omni_apg110():
|
||||
insert_aluprofil("APG110", 6000.0)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# TEF / KettenFoerderer Dummy-Commands
|
||||
# ============================================================
|
||||
|
||||
@Rx.command("OMNI_TEF_UmlenkR")
|
||||
def cmd_tef_umlenkr():
|
||||
print("\n[DUMMY] Umlenkspannst. rechts fuer TEF links")
|
||||
|
||||
@Rx.command("OMNI_TEF_UmlenkL")
|
||||
def cmd_tef_umlenkl():
|
||||
print("\n[DUMMY] Umlenkspannst. links fuer TEF rechts")
|
||||
|
||||
@Rx.command("OMNI_TEF_AntriebL")
|
||||
def cmd_tef_antriebl():
|
||||
print("\n[DUMMY] Antriebst. links fuer TEF links")
|
||||
|
||||
@Rx.command("OMNI_TEF_AntriebR")
|
||||
def cmd_tef_antriebr():
|
||||
print("\n[DUMMY] Antriebst. rechts fuer TEF rechts")
|
||||
|
||||
@Rx.command("OMNI_TEF_Gerade")
|
||||
def cmd_tef_gerade():
|
||||
print("\n[DUMMY] TEF Gerade")
|
||||
|
||||
@Rx.command("OMNI_KettenFoerderer")
|
||||
def cmd_kettenfoerderer():
|
||||
print("\n[DUMMY] KettenFoerderer")
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Info-Commands
|
||||
# ============================================================
|
||||
|
||||
@Rx.command("OMNI_LOAD")
|
||||
def cmd_omni_load():
|
||||
"""Daten neu laden (Cache leeren)."""
|
||||
global _boegen_data, _weichen_data
|
||||
_boegen_data = None
|
||||
_weichen_data = None
|
||||
load_boegen()
|
||||
load_weichen()
|
||||
|
||||
@Rx.command("OMNI_INFO_BOGEN")
|
||||
def cmd_omni_info_bogen():
|
||||
"""Bogen-Info anhand SivasId anzeigen."""
|
||||
ed = Ed.Editor()
|
||||
res = ed.getString("\nSivasId des Bogens eingeben: ")
|
||||
if res[0] != Ed.PromptStatus.eOk or not res[1]:
|
||||
print("\nAbgebrochen.")
|
||||
return
|
||||
sid = res[1]
|
||||
try:
|
||||
sid_val = int(sid)
|
||||
except ValueError:
|
||||
sid_val = sid
|
||||
eintrag = get_by_sivasnr(load_boegen(), sid_val)
|
||||
if eintrag:
|
||||
print(f"\n ProfilTyp: {eintrag.get('ProfilTyp', '?')}")
|
||||
print(f" Radius: {eintrag.get('Radius', '?')}")
|
||||
print(f" KurvenWinkel: {eintrag.get('KurvenWinkel', '?')}")
|
||||
print(f" Breite: {eintrag.get('Breite', '?')}")
|
||||
print(f" Laenge: {eintrag.get('Länge', '?')}")
|
||||
print(f" Antriebsart: {eintrag.get('Antriebsart', '?')}")
|
||||
else:
|
||||
print(f"\nKein Bogen mit SivasId '{sid}' gefunden.")
|
||||
|
||||
@Rx.command("OMNI_INFO_WEICHE")
|
||||
def cmd_omni_info_weiche():
|
||||
"""Weichen-Info anhand SivasId anzeigen."""
|
||||
ed = Ed.Editor()
|
||||
res = ed.getString("\nSivasId der Weiche eingeben: ")
|
||||
if res[0] != Ed.PromptStatus.eOk or not res[1]:
|
||||
print("\nAbgebrochen.")
|
||||
return
|
||||
sid = res[1]
|
||||
try:
|
||||
sid_val = int(sid)
|
||||
except ValueError:
|
||||
sid_val = sid
|
||||
eintrag = get_by_sivasnr(load_weichen(), sid_val)
|
||||
if eintrag:
|
||||
print(f"\n ProfilTyp: {eintrag.get('ProfilTyp', '?')}")
|
||||
print(f" WeichenTyp: {eintrag.get('WeichenTyp', '?')}")
|
||||
print(f" KurvenWinkel: {eintrag.get('KurvenWinkel', '?')}")
|
||||
print(f" Schaltungstyp: {eintrag.get('Schaltungstyp', '?')}")
|
||||
print(f" Breite: {eintrag.get('Breite', '?')}")
|
||||
print(f" Laenge: {eintrag.get('Länge', '?')}")
|
||||
print(f" KurvenRichtung: {eintrag.get('KurvenRichtung', '?')}")
|
||||
wkl = eintrag.get("WeichenkörperLänge")
|
||||
if wkl:
|
||||
print(f" WK-Laenge: {wkl}")
|
||||
else:
|
||||
print(f"\nKeine Weiche mit SivasId '{sid}' gefunden.")
|
||||
@@ -0,0 +1,161 @@
|
||||
# omniflo_boegen.py
|
||||
# Omniflo Bogen-Auswahl-Dialog (wx) und Bogen-Commands
|
||||
# Ersetzt die Bogen-Teile von OmniModulInsert.lsp + omniflo_boegen.dcl
|
||||
# ============================================
|
||||
|
||||
import wx
|
||||
|
||||
import PyRx as Rx
|
||||
import PyDb as Db
|
||||
import PyEd as Ed
|
||||
|
||||
from elemente.omniflo import (
|
||||
load_boegen,
|
||||
filter_by,
|
||||
insert_from_entry,
|
||||
sivasnr_to_str,
|
||||
)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Bogen-Auswahl-Dialog (ersetzt omniflo_boegen.dcl)
|
||||
# ============================================================
|
||||
|
||||
class BogenSelectDialog(wx.Dialog):
|
||||
"""Bogen-Auswahl-Dialog.
|
||||
|
||||
Layout:
|
||||
- Dropdown: Bogenart (ProfilTyp-Liste)
|
||||
- Detail-Felder (readonly): SivasNr, Winkel, Radius, Breite, Laenge
|
||||
- OK / Abbrechen
|
||||
"""
|
||||
|
||||
def __init__(self, parent, boegen_liste):
|
||||
super().__init__(parent, title="Omniflo Bogen auswaehlen",
|
||||
size=(460, 260),
|
||||
style=wx.DEFAULT_DIALOG_STYLE)
|
||||
self._boegen = boegen_liste
|
||||
self._selected_idx = 0
|
||||
|
||||
panel = wx.Panel(self)
|
||||
sizer = wx.BoxSizer(wx.VERTICAL)
|
||||
|
||||
# Dropdown: Bogenart
|
||||
row_art = wx.BoxSizer(wx.HORIZONTAL)
|
||||
row_art.Add(wx.StaticText(panel, label="Bogenart:"), 0,
|
||||
wx.ALIGN_CENTER_VERTICAL | wx.RIGHT, 5)
|
||||
profil_list = [e.get("ProfilTyp", "?") for e in boegen_liste]
|
||||
self.cb_bogenart = wx.Choice(panel, choices=profil_list)
|
||||
self.cb_bogenart.SetSelection(0)
|
||||
self.cb_bogenart.Bind(wx.EVT_CHOICE, self._on_selection)
|
||||
row_art.Add(self.cb_bogenart, 1)
|
||||
sizer.Add(row_art, 0, wx.EXPAND | wx.ALL, 5)
|
||||
|
||||
# Detail-Felder (2 Spalten)
|
||||
grid = wx.FlexGridSizer(cols=4, hgap=10, vgap=5)
|
||||
grid.AddGrowableCol(1)
|
||||
grid.AddGrowableCol(3)
|
||||
|
||||
grid.Add(wx.StaticText(panel, label="SivasNr:"), 0, wx.ALIGN_CENTER_VERTICAL)
|
||||
self.txt_sivasnr = wx.TextCtrl(panel, style=wx.TE_READONLY, size=(140, -1))
|
||||
grid.Add(self.txt_sivasnr, 0)
|
||||
|
||||
grid.Add(wx.StaticText(panel, label="Winkel:"), 0, wx.ALIGN_CENTER_VERTICAL)
|
||||
self.txt_winkel = wx.TextCtrl(panel, style=wx.TE_READONLY, size=(100, -1))
|
||||
grid.Add(self.txt_winkel, 0)
|
||||
|
||||
grid.Add(wx.StaticText(panel, label="Radius:"), 0, wx.ALIGN_CENTER_VERTICAL)
|
||||
self.txt_radius = wx.TextCtrl(panel, style=wx.TE_READONLY, size=(100, -1))
|
||||
grid.Add(self.txt_radius, 0)
|
||||
|
||||
grid.Add(wx.StaticText(panel, label="Breite:"), 0, wx.ALIGN_CENTER_VERTICAL)
|
||||
self.txt_breite = wx.TextCtrl(panel, style=wx.TE_READONLY, size=(100, -1))
|
||||
grid.Add(self.txt_breite, 0)
|
||||
|
||||
grid.Add(wx.StaticText(panel, label="Laenge:"), 0, wx.ALIGN_CENTER_VERTICAL)
|
||||
self.txt_laenge = wx.TextCtrl(panel, style=wx.TE_READONLY, size=(100, -1))
|
||||
grid.Add(self.txt_laenge, 0)
|
||||
|
||||
sizer.Add(grid, 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()
|
||||
|
||||
# Startwerte
|
||||
self._update_details(0)
|
||||
|
||||
def _on_selection(self, event):
|
||||
self._selected_idx = self.cb_bogenart.GetSelection()
|
||||
self._update_details(self._selected_idx)
|
||||
|
||||
def _update_details(self, idx):
|
||||
if idx < 0 or idx >= len(self._boegen):
|
||||
return
|
||||
e = self._boegen[idx]
|
||||
self.txt_sivasnr.SetValue(sivasnr_to_str(e.get("Sivasnr")))
|
||||
wkl = e.get("KurvenWinkel", 0)
|
||||
self.txt_winkel.SetValue(f"{wkl} Grad")
|
||||
self.txt_radius.SetValue(str(e.get("Radius", "?")))
|
||||
self.txt_breite.SetValue(str(e.get("Breite", "?")))
|
||||
self.txt_laenge.SetValue(str(e.get("Länge", "?")))
|
||||
|
||||
def get_selected(self):
|
||||
"""Gewaehlten Bogen-Eintrag zurueckgeben."""
|
||||
if 0 <= self._selected_idx < len(self._boegen):
|
||||
return self._boegen[self._selected_idx]
|
||||
return None
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Generische Bogen-Einfuege-Logik
|
||||
# ============================================================
|
||||
|
||||
def _bogen_command(winkel):
|
||||
"""Bogen-Dialog oeffnen, Auswahl einfuegen."""
|
||||
boegen = filter_by(load_boegen(), "KurvenWinkel", winkel)
|
||||
if not boegen:
|
||||
wkl_str = f"{winkel}" if isinstance(winkel, int) else f"{winkel:.1f}"
|
||||
print(f"\nKeine Boegen fuer {wkl_str} Grad gefunden.")
|
||||
return
|
||||
|
||||
dlg = BogenSelectDialog(None, boegen)
|
||||
if dlg.ShowModal() == wx.ID_OK:
|
||||
eintrag = dlg.get_selected()
|
||||
dlg.Destroy()
|
||||
if eintrag:
|
||||
insert_from_entry(eintrag)
|
||||
else:
|
||||
print("\n[BOGEN] Kein Eintrag ausgewaehlt.")
|
||||
else:
|
||||
dlg.Destroy()
|
||||
print("\n[BOGEN] Abgebrochen.")
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Bogen-Commands (gleiche Namen wie LISP)
|
||||
# ============================================================
|
||||
|
||||
@Rx.command("OMNI_APB_630_90")
|
||||
def cmd_bogen_90():
|
||||
_bogen_command(90)
|
||||
|
||||
@Rx.command("OMNI_APB_550_675")
|
||||
def cmd_bogen_675():
|
||||
_bogen_command(67.5)
|
||||
|
||||
@Rx.command("OMNI_APB_630_45")
|
||||
def cmd_bogen_45():
|
||||
_bogen_command(45)
|
||||
|
||||
@Rx.command("OMNI_APB_550_225")
|
||||
def cmd_bogen_225():
|
||||
_bogen_command(22.5)
|
||||
|
||||
@Rx.command("OMNI_APB_650_180")
|
||||
def cmd_bogen_180():
|
||||
_bogen_command(180)
|
||||
@@ -0,0 +1,267 @@
|
||||
# omniflo_weichen.py
|
||||
# Omniflo Weichen-Auswahl-Dialog (wx) und Weichen-Commands
|
||||
# Ersetzt die Weichen-Teile von OmniModulInsert.lsp + omniflo_weichen.dcl
|
||||
# ============================================
|
||||
|
||||
import wx
|
||||
|
||||
import PyRx as Rx
|
||||
import PyDb as Db
|
||||
import PyEd as Ed
|
||||
|
||||
from elemente.omniflo import (
|
||||
load_weichen,
|
||||
filter_by,
|
||||
insert_from_entry,
|
||||
sivasnr_to_str,
|
||||
)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Weichen-Auswahl-Dialog (ersetzt omniflo_weichen.dcl)
|
||||
# ============================================================
|
||||
|
||||
class WeichenSelectDialog(wx.Dialog):
|
||||
"""Weichen-Auswahl-Dialog mit Filtern.
|
||||
|
||||
Layout:
|
||||
- Dropdown: ProfilTyp (gefiltert)
|
||||
- Filter-Gruppe Schaltungstyp: Alle / M / P (wx.RadioBox)
|
||||
- Filter-Gruppe Richtung: Alle / Links / Rechts (wx.RadioBox)
|
||||
- Detail-Felder (readonly): SivasNr, Winkel, Breite, Laenge
|
||||
- OK / Abbrechen
|
||||
"""
|
||||
|
||||
def __init__(self, parent, basis_liste):
|
||||
super().__init__(parent, title="Omniflo Weiche auswaehlen",
|
||||
size=(500, 320),
|
||||
style=wx.DEFAULT_DIALOG_STYLE)
|
||||
self._basis = basis_liste
|
||||
self._gefiltert = list(basis_liste)
|
||||
self._selected_idx = 0
|
||||
|
||||
panel = wx.Panel(self)
|
||||
sizer = wx.BoxSizer(wx.VERTICAL)
|
||||
|
||||
# Dropdown: ProfilTyp
|
||||
row_profil = wx.BoxSizer(wx.HORIZONTAL)
|
||||
row_profil.Add(wx.StaticText(panel, label="Profiltyp:"), 0,
|
||||
wx.ALIGN_CENTER_VERTICAL | wx.RIGHT, 5)
|
||||
self.cb_profil = wx.Choice(panel, choices=[])
|
||||
self.cb_profil.Bind(wx.EVT_CHOICE, self._on_selection)
|
||||
row_profil.Add(self.cb_profil, 1)
|
||||
sizer.Add(row_profil, 0, wx.EXPAND | wx.ALL, 5)
|
||||
|
||||
# Filter-Gruppe: Schaltungstyp + Richtung nebeneinander
|
||||
filter_sizer = wx.BoxSizer(wx.HORIZONTAL)
|
||||
|
||||
self.rb_schaltung = wx.RadioBox(panel, label="Schaltungstyp",
|
||||
choices=["Alle", "M", "P"],
|
||||
majorDimension=1,
|
||||
style=wx.RA_SPECIFY_COLS)
|
||||
self.rb_schaltung.Bind(wx.EVT_RADIOBOX, self._apply_filter)
|
||||
filter_sizer.Add(self.rb_schaltung, 1, wx.EXPAND | wx.RIGHT, 5)
|
||||
|
||||
self.rb_richtung = wx.RadioBox(panel, label="Richtung",
|
||||
choices=["Alle", "Links", "Rechts"],
|
||||
majorDimension=1,
|
||||
style=wx.RA_SPECIFY_COLS)
|
||||
self.rb_richtung.Bind(wx.EVT_RADIOBOX, self._apply_filter)
|
||||
filter_sizer.Add(self.rb_richtung, 1, wx.EXPAND)
|
||||
|
||||
sizer.Add(filter_sizer, 0, wx.EXPAND | wx.ALL, 5)
|
||||
|
||||
# Detail-Felder (2 Spalten)
|
||||
grid = wx.FlexGridSizer(cols=4, hgap=10, vgap=5)
|
||||
grid.AddGrowableCol(1)
|
||||
grid.AddGrowableCol(3)
|
||||
|
||||
grid.Add(wx.StaticText(panel, label="SivasNr:"), 0, wx.ALIGN_CENTER_VERTICAL)
|
||||
self.txt_sivasnr = wx.TextCtrl(panel, style=wx.TE_READONLY, size=(140, -1))
|
||||
grid.Add(self.txt_sivasnr, 0)
|
||||
|
||||
grid.Add(wx.StaticText(panel, label="Winkel:"), 0, wx.ALIGN_CENTER_VERTICAL)
|
||||
self.txt_winkel = wx.TextCtrl(panel, style=wx.TE_READONLY, size=(100, -1))
|
||||
grid.Add(self.txt_winkel, 0)
|
||||
|
||||
grid.Add(wx.StaticText(panel, label="Breite:"), 0, wx.ALIGN_CENTER_VERTICAL)
|
||||
self.txt_breite = wx.TextCtrl(panel, style=wx.TE_READONLY, size=(100, -1))
|
||||
grid.Add(self.txt_breite, 0)
|
||||
|
||||
grid.Add(wx.StaticText(panel, label="Laenge:"), 0, wx.ALIGN_CENTER_VERTICAL)
|
||||
self.txt_laenge = wx.TextCtrl(panel, style=wx.TE_READONLY, size=(100, -1))
|
||||
grid.Add(self.txt_laenge, 0)
|
||||
|
||||
sizer.Add(grid, 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()
|
||||
|
||||
# Initiale Befuellung
|
||||
self._refresh_dropdown()
|
||||
|
||||
def _apply_filter(self, event=None):
|
||||
"""Filter anwenden und Dropdown neu befuellen."""
|
||||
self._refresh_dropdown()
|
||||
|
||||
def _refresh_dropdown(self):
|
||||
"""Dropdown mit gefilterter Liste neu fuellen."""
|
||||
sch_idx = self.rb_schaltung.GetSelection()
|
||||
ri_idx = self.rb_richtung.GetSelection()
|
||||
|
||||
# Schaltungstyp-Filter
|
||||
sch_filter = {0: None, 1: "M", 2: "P"}.get(sch_idx)
|
||||
# Richtungs-Filter (1=links, 2=rechts)
|
||||
ri_filter = {0: None, 1: 1, 2: 2}.get(ri_idx)
|
||||
|
||||
self._gefiltert = []
|
||||
for e in self._basis:
|
||||
if sch_filter and e.get("Schaltungstyp") != sch_filter:
|
||||
continue
|
||||
if ri_filter and e.get("KurvenRichtung") != ri_filter:
|
||||
continue
|
||||
self._gefiltert.append(e)
|
||||
|
||||
# Dropdown neu befuellen
|
||||
self.cb_profil.Clear()
|
||||
for e in self._gefiltert:
|
||||
self.cb_profil.Append(e.get("ProfilTyp", "?"))
|
||||
|
||||
if self._gefiltert:
|
||||
self.cb_profil.SetSelection(0)
|
||||
self._selected_idx = 0
|
||||
self._update_details(0)
|
||||
else:
|
||||
self._selected_idx = -1
|
||||
self.txt_sivasnr.SetValue("---")
|
||||
self.txt_winkel.SetValue("---")
|
||||
self.txt_breite.SetValue("---")
|
||||
self.txt_laenge.SetValue("---")
|
||||
|
||||
def _on_selection(self, event):
|
||||
self._selected_idx = self.cb_profil.GetSelection()
|
||||
self._update_details(self._selected_idx)
|
||||
|
||||
def _update_details(self, idx):
|
||||
if idx < 0 or idx >= len(self._gefiltert):
|
||||
return
|
||||
e = self._gefiltert[idx]
|
||||
self.txt_sivasnr.SetValue(sivasnr_to_str(e.get("Sivasnr")))
|
||||
wkl = e.get("KurvenWinkel", 0)
|
||||
self.txt_winkel.SetValue(f"{wkl} Grad")
|
||||
self.txt_breite.SetValue(str(e.get("Breite", "?")))
|
||||
self.txt_laenge.SetValue(str(e.get("Länge", "?")))
|
||||
|
||||
def get_selected(self):
|
||||
"""Gewaehlten Weichen-Eintrag zurueckgeben."""
|
||||
if 0 <= self._selected_idx < len(self._gefiltert):
|
||||
return self._gefiltert[self._selected_idx]
|
||||
return None
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Generische Weichen-Einfuege-Logik
|
||||
# ============================================================
|
||||
|
||||
def _weichen_command(winkel, weichentyp):
|
||||
"""Weichen-Dialog oeffnen, Auswahl einfuegen."""
|
||||
alle = load_weichen()
|
||||
|
||||
# Nach Winkel filtern (None = alle Winkel)
|
||||
if winkel is not None:
|
||||
basis = filter_by(alle, "KurvenWinkel", winkel)
|
||||
else:
|
||||
basis = list(alle)
|
||||
|
||||
# Nach WeichenTyp filtern
|
||||
if weichentyp:
|
||||
basis = [e for e in basis if e.get("WeichenTyp") == weichentyp]
|
||||
|
||||
if not basis:
|
||||
wkl_str = "alle Winkel" if winkel is None else f"{winkel} Grad"
|
||||
typ_str = f" / {weichentyp}" if weichentyp else ""
|
||||
print(f"\nKeine Weichen fuer {wkl_str}{typ_str} gefunden.")
|
||||
return
|
||||
|
||||
dlg = WeichenSelectDialog(None, basis)
|
||||
if dlg.ShowModal() == wx.ID_OK:
|
||||
eintrag = dlg.get_selected()
|
||||
dlg.Destroy()
|
||||
if eintrag:
|
||||
insert_from_entry(eintrag)
|
||||
else:
|
||||
print("\n[WEICHE] Kein Eintrag ausgewaehlt.")
|
||||
else:
|
||||
dlg.Destroy()
|
||||
print("\n[WEICHE] Abgebrochen.")
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Weichen-Commands (gleiche Namen wie LISP)
|
||||
# ============================================================
|
||||
|
||||
# --- 90 Grad ---
|
||||
@Rx.command("OMNI_W90_Einfach")
|
||||
def cmd_w90_einfach():
|
||||
_weichen_command(90, "Einzelweiche")
|
||||
|
||||
@Rx.command("OMNI_W90_Doppel")
|
||||
def cmd_w90_doppel():
|
||||
_weichen_command(90, "Doppelweiche")
|
||||
|
||||
@Rx.command("OMNI_W90_Dreiwege")
|
||||
def cmd_w90_dreiwege():
|
||||
_weichen_command(90, "Dreiwegeweiche")
|
||||
|
||||
# --- 45 Grad ---
|
||||
@Rx.command("OMNI_W45_Einfach")
|
||||
def cmd_w45_einfach():
|
||||
_weichen_command(45, "Einzelweiche")
|
||||
|
||||
@Rx.command("OMNI_W45_Doppel")
|
||||
def cmd_w45_doppel():
|
||||
_weichen_command(45, "Doppelweiche")
|
||||
|
||||
@Rx.command("OMNI_W45_Dreiwege")
|
||||
def cmd_w45_dreiwege():
|
||||
_weichen_command(45, "Dreiwegeweiche")
|
||||
|
||||
# --- Parallel (KurvenWinkel=0) ---
|
||||
@Rx.command("OMNI_WP_Einfach")
|
||||
def cmd_wp_einfach():
|
||||
_weichen_command(0, "Einzelweiche")
|
||||
|
||||
@Rx.command("OMNI_WP_Doppel")
|
||||
def cmd_wp_doppel():
|
||||
_weichen_command(0, "Doppelweiche")
|
||||
|
||||
@Rx.command("OMNI_WP_Dreiwege")
|
||||
def cmd_wp_dreiwege():
|
||||
_weichen_command(0, "Dreiwegeweiche")
|
||||
|
||||
# --- Weichenkoerper (KurvenWinkel=22.5) ---
|
||||
@Rx.command("OMNI_WK_Einfach")
|
||||
def cmd_wk_einfach():
|
||||
_weichen_command(22.5, "Einzelweiche")
|
||||
|
||||
@Rx.command("OMNI_WK_Doppel")
|
||||
def cmd_wk_doppel():
|
||||
_weichen_command(22.5, "Doppelweiche")
|
||||
|
||||
@Rx.command("OMNI_WK_Dreiwege")
|
||||
def cmd_wk_dreiwege():
|
||||
_weichen_command(22.5, "Dreiwegeweiche")
|
||||
|
||||
# --- Weichenkombinationen ---
|
||||
@Rx.command("OMNI_WKomb_Delta")
|
||||
def cmd_wkomb_delta():
|
||||
_weichen_command(None, "Deltaweiche")
|
||||
|
||||
@Rx.command("OMNI_WKomb_Star")
|
||||
def cmd_wkomb_star():
|
||||
_weichen_command(None, "Sternweiche")
|
||||
@@ -3,6 +3,7 @@
|
||||
# ============================================
|
||||
|
||||
import os
|
||||
import json
|
||||
import math
|
||||
|
||||
import PyDb as Db
|
||||
@@ -12,6 +13,34 @@ import PyGe as Ge
|
||||
_letzte_nummern = {}
|
||||
|
||||
|
||||
def get_data_path():
|
||||
"""Daten-Pfad aus Umgebungsvariable DXFM_DATA lesen."""
|
||||
dp = os.environ.get("DXFM_DATA", "")
|
||||
if not dp:
|
||||
print("\nFEHLER: DXFM_DATA nicht gesetzt!")
|
||||
return None
|
||||
return dp.replace("\\", "/").rstrip("/")
|
||||
|
||||
|
||||
def load_json_data(rel_path):
|
||||
"""JSON-Datei relativ zum DXFM_DATA-Pfad laden.
|
||||
|
||||
Parameter:
|
||||
rel_path - relativer Pfad, z.B. "json/omniflo_boegen.json"
|
||||
Rueckgabe: geparste Daten oder leere Liste bei Fehler
|
||||
"""
|
||||
dp = get_data_path()
|
||||
if not dp:
|
||||
return []
|
||||
path = f"{dp}/{rel_path}"
|
||||
try:
|
||||
with open(path, "r", encoding="utf-8") as f:
|
||||
return json.load(f)
|
||||
except (FileNotFoundError, json.JSONDecodeError) as e:
|
||||
print(f"\nFEHLER beim Laden von {path}: {e}")
|
||||
return []
|
||||
|
||||
|
||||
def get_block_path():
|
||||
"""Block-Pfad aus Umgebungsvariable DXFM_BLOCKS lesen."""
|
||||
bp = os.environ.get("DXFM_BLOCKS", "")
|
||||
@@ -135,6 +164,28 @@ def ensure_block_from_dwg(db, dwg_name, block_path=None):
|
||||
return True
|
||||
|
||||
|
||||
def ensure_block_from_dxf(db, dxf_path, block_name=None):
|
||||
"""DXF-Datei als Block-Definition laden falls nicht vorhanden.
|
||||
|
||||
Parameter:
|
||||
db - aktuelle Datenbank
|
||||
dxf_path - absoluter Pfad zur DXF-Datei
|
||||
block_name - Name der Block-Definition (default: Dateiname ohne .dxf)
|
||||
Rueckgabe: True wenn erfolgreich, False bei Fehler
|
||||
"""
|
||||
if block_name is None:
|
||||
block_name = os.path.splitext(os.path.basename(dxf_path))[0]
|
||||
bt = Db.BlockTable(db.blockTableId(), Db.OpenMode.kForRead)
|
||||
if not bt.has(block_name):
|
||||
if not os.path.isfile(dxf_path):
|
||||
print(f"\nFehler: DXF nicht gefunden: {dxf_path}")
|
||||
return False
|
||||
aux_db = Db.Database(False, True)
|
||||
aux_db.dxfIn(dxf_path)
|
||||
db.insert(aux_db, block_name)
|
||||
return True
|
||||
|
||||
|
||||
def create_attrib_defs(btr, attrib_defs, text_height=50.0):
|
||||
"""Unsichtbare Attribut-Definitionen in einer BlockTableRecord erzeugen.
|
||||
|
||||
|
||||
@@ -80,3 +80,7 @@
|
||||
[Call Python]^C^CCALLPYTHON
|
||||
[Export Sivas]^C^CEXPORTSIVAS
|
||||
[<-Export CSV]^C^CEXPORTCSV
|
||||
|
||||
***POP501
|
||||
[SSG_LIB Edit Context]
|
||||
[SSG Bearbeiten]^C^CSSG_BLOCKEDIT
|
||||
|
||||
Reference in New Issue
Block a user