Omniflo Boegen und Weichen auch durch .py erzeugen und ändern.

This commit is contained in:
2026-06-01 11:08:19 +02:00
parent 35e4e707aa
commit d0373d09f3
13 changed files with 1088 additions and 1277 deletions
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -25,10 +25,10 @@
(dbgopen "debugfile.dbg" "DXFM_LOG") ; Debug-Datei im Log-Verzeichnis oeffnen (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_dialog.lsp") "ssg_dialog.lsp nicht gefunden")
(load (strcat base-path "ssg_layer.lsp") "ssg_layer.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 "VarioFoerderer.lsp") "VarioFoerderer.lsp nicht gefunden")
(load (strcat base-path "tests.lsp") "tests.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") (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") (prompt "\nSSG-Bibliotheken geladen: ssg_core, ssg_dbg, ssg_dialog, ssg_layer")
(princ) (princ)
+4 -1
View File
@@ -60,9 +60,12 @@
(princ "\n[SSG_LIB] WARNUNG: DXFMAKRO nicht gesetzt, Menue nicht geladen!") (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) ;; Python-Module laden (PyRx)
(if menu-pfad (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")) (if (findfile (strcat menu-pfad "/lib/elemente/" pymod ".py"))
(progn (progn
(command "PYLOAD" (strcat menu-pfad "/lib/elemente/" pymod ".py")) (command "PYLOAD" (strcat menu-pfad "/lib/elemente/" pymod ".py"))
-54
View File
@@ -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;
}
-65
View File
@@ -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;
}
+50
View File
@@ -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")
+125
View File
@@ -10,11 +10,13 @@ import PyRx as Rx
import PyGe as Ge import PyGe as Ge
import PyDb as Db import PyDb as Db
import PyEd as Ed import PyEd as Ed
import wx
from elemente.utils import ( from elemente.utils import (
get_block_path, get_block_path,
component_next_number, component_next_number,
merge_attribs, merge_attribs,
read_block_attribs,
ensure_block_from_dwg, ensure_block_from_dwg,
create_attrib_defs, create_attrib_defs,
insert_block_with_attribs, insert_block_with_attribs,
@@ -178,3 +180,126 @@ def ils_eckrad():
# 5. Einfuegen # 5. Einfuegen
insert_pt = Ge.Point3d(center_x, center_y, hoehe) insert_pt = Ge.Point3d(center_x, center_y, hoehe)
insert_eckrad(db, insert_pt, rotation) 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
View File
@@ -426,23 +426,11 @@ def cmd_kreisel_quick():
print("\nSchnell Einfuegen fertig.") print("\nSchnell Einfuegen fertig.")
@Rx.command("KreiselEdit") def kreisel_edit_entity(db, ent_id):
def cmd_kreisel_edit(): """Kreisel per wxPython-Dialog bearbeiten (fuer eine bestimmte Entity-ID).
"""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
Wird von KreiselEdit und SSG_BLOCKEDIT aufgerufen.
"""
bref = Db.BlockReference(ent_id, Db.OpenMode.kForRead) bref = Db.BlockReference(ent_id, Db.OpenMode.kForRead)
attribs = read_block_attribs(bref) attribs = read_block_attribs(bref)
base_point = bref.position() base_point = bref.position()
@@ -464,7 +452,7 @@ def cmd_kreisel_edit():
f" Drehung={rotation:.1f}" f" Drehung={rotation:.1f}"
f" Art={attribs.get('KREISELART')}") f" Art={attribs.get('KREISELART')}")
# 2. wxPython-Dialog (ersetzt DCL) # wxPython-Dialog
dlg = KreiselEditDialog(None, attribs, rotation) dlg = KreiselEditDialog(None, attribs, rotation)
result = dlg.ShowModal() result = dlg.ShowModal()
@@ -472,7 +460,6 @@ def cmd_kreisel_edit():
new_values = dlg.get_values() new_values = dlg.get_values()
dlg.Destroy() dlg.Destroy()
# Attribute aktualisieren
attribs["NAME"] = new_values["name"] attribs["NAME"] = new_values["name"]
attribs["HOEHE"] = new_values["hoehe"] attribs["HOEHE"] = new_values["hoehe"]
attribs["KREISELART"] = new_values["kreiselart"] attribs["KREISELART"] = new_values["kreiselart"]
@@ -498,6 +485,25 @@ def cmd_kreisel_edit():
print("\nAbgebrochen.") 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") @Rx.command("KreiselParams")
def cmd_kreisel_params(): def cmd_kreisel_params():
"""KreiselParams: Aktuelle Parameter anzeigen.""" """KreiselParams: Aktuelle Parameter anzeigen."""
+400
View File
@@ -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.")
+161
View File
@@ -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)
+267
View File
@@ -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")
+51
View File
@@ -3,6 +3,7 @@
# ============================================ # ============================================
import os import os
import json
import math import math
import PyDb as Db import PyDb as Db
@@ -12,6 +13,34 @@ import PyGe as Ge
_letzte_nummern = {} _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(): def get_block_path():
"""Block-Pfad aus Umgebungsvariable DXFM_BLOCKS lesen.""" """Block-Pfad aus Umgebungsvariable DXFM_BLOCKS lesen."""
bp = os.environ.get("DXFM_BLOCKS", "") bp = os.environ.get("DXFM_BLOCKS", "")
@@ -135,6 +164,28 @@ def ensure_block_from_dwg(db, dwg_name, block_path=None):
return True 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): def create_attrib_defs(btr, attrib_defs, text_height=50.0):
"""Unsichtbare Attribut-Definitionen in einer BlockTableRecord erzeugen. """Unsichtbare Attribut-Definitionen in einer BlockTableRecord erzeugen.
+4
View File
@@ -80,3 +80,7 @@
[Call Python]^C^CCALLPYTHON [Call Python]^C^CCALLPYTHON
[Export Sivas]^C^CEXPORTSIVAS [Export Sivas]^C^CEXPORTSIVAS
[<-Export CSV]^C^CEXPORTCSV [<-Export CSV]^C^CEXPORTCSV
***POP501
[SSG_LIB Edit Context]
[SSG Bearbeiten]^C^CSSG_BLOCKEDIT