# elemente/utils.py # Gemeinsame Hilfsfunktionen fuer alle ILS-Elemente (Kreisel, Eckrad, etc.) # ============================================ import os import math import PyDb as Db import PyGe as Ge # Globale Zaehler pro Komponententyp (pro Sitzung) _letzte_nummern = {} def get_block_path(): """Block-Pfad aus Umgebungsvariable DXFM_BLOCKS lesen.""" bp = os.environ.get("DXFM_BLOCKS", "") if not bp: bp = "C:/Users/y.wang/Documents/dxfmakros/Blocks/" print(f"\nUmgebungsvariable DXFM_BLOCKS nicht gefunden. Nutze Standardpfad: {bp}") bp = bp.replace("\\", "/").rstrip("/") + "/" return bp def component_next_number(db, prefix): """Naechste freie Nummer fuer einen Komponententyp ermitteln. Scannt alle INSERT-Entities im Modelspace deren Blockname mit `prefix` beginnt (z.B. "ECKRAD_", "KREISEL_") und liest das NUMMER-Attribut aus. Gibt die naechste freie Nummer zurueck. Entspricht component-next-number aus KreiselInsert.lsp. Parameter: db - aktuelle Datenbank prefix - Blockname-Praefix, z.B. "ECKRAD_" oder "KREISEL_" Rueckgabe: naechste freie Nummer (int) """ global _letzte_nummern prefix_upper = prefix.upper() max_nr = 0 model = Db.BlockTableRecord(db.modelSpaceId(), Db.OpenMode.kForRead) for obj_id in model: ent = Db.Entity(obj_id, Db.OpenMode.kForRead) if not ent.isKindOf(Db.BlockReference.desc()): continue bref = Db.BlockReference(obj_id, Db.OpenMode.kForRead) btr = Db.BlockTableRecord(bref.blockTableRecord(), Db.OpenMode.kForRead) bname = btr.getName() if not bname.upper().startswith(prefix_upper): continue for att_id in bref.attributeIds(): att = Db.AttributeReference(att_id, Db.OpenMode.kForRead) if att.tag().upper() == "NUMMER": try: val = int(att.textString()) if val > max_nr: max_nr = val except ValueError: pass if max_nr == 0: max_nr = _letzte_nummern.get(prefix_upper, 0) _letzte_nummern[prefix_upper] = max_nr + 1 return _letzte_nummern[prefix_upper] def merge_attribs(overrides, attrib_defs): """Attribut-Defaults mit Ueberschreibungen zusammenfuehren. Parameter: overrides - dict mit Ueberschreibungen (darf None sein) attrib_defs - Liste von (TAG, DEFAULT) Tupeln Rueckgabe: dict mit allen Tags """ result = {tag: default for tag, default in attrib_defs} if overrides: result.update(overrides) return result def read_block_attribs(bref): """Alle Attribute einer BlockReference als dict lesen.""" attribs = {} for att_id in bref.attributeIds(): att = Db.AttributeReference(att_id, Db.OpenMode.kForRead) attribs[att.tag()] = att.textString() return attribs def ensure_layer(db, layer_name, color_index, set_active=False): """Layer anlegen falls nicht vorhanden, optional aktiv setzen.""" lt = Db.LayerTable(db.layerTableId(), Db.OpenMode.kForRead) if not lt.has(layer_name): lt.upgradeOpen() lr = Db.LayerTableRecord() lr.setName(layer_name) c = Db.Color() c.setColorIndex(int(color_index)) lr.setColor(c) lt.add(lr) if set_active: layer_id = lt.getAt(layer_name) db.setClayer(layer_id) def ensure_textstyle(db, style_name="Kreisel_Arial", font="Arial"): """Textstil anlegen falls nicht vorhanden.""" tst = Db.TextStyleTable(db.textStyleTableId(), Db.OpenMode.kForRead) if not tst.has(style_name): tst.upgradeOpen() ts = Db.TextStyleTableRecord() ts.setName(style_name) ts.setFont(font, False, False, 0, 0) tst.add(ts) return style_name def ensure_block_from_dwg(db, dwg_name, block_path=None): """Externen DWG-Block in die Datenbank laden falls nicht vorhanden.""" if block_path is None: block_path = get_block_path() bt = Db.BlockTable(db.blockTableId(), Db.OpenMode.kForRead) base_name = os.path.splitext(dwg_name)[0] if not bt.has(base_name): dwg_path = block_path + dwg_name if not os.path.isfile(dwg_path): print(f"\nFehler: {dwg_name} nicht gefunden unter: {dwg_path}") return False aux_db = Db.Database(False, True) aux_db.readDwg(dwg_path) db.insert(aux_db, base_name) return True def create_attrib_defs(btr, attrib_defs, text_height=50.0): """Unsichtbare Attribut-Definitionen in einer BlockTableRecord erzeugen. Parameter: btr - Db.BlockTableRecord (kForWrite) attrib_defs - Liste von (TAG, DEFAULT) Tupeln text_height - Texthoehe der ATTDEFs """ y_pos = 0.0 for tag, default in attrib_defs: attdef = Db.AttributeDefinition() attdef.setPosition(Ge.Point3d(0, y_pos, 0)) attdef.setHeight(text_height) attdef.setTextString(default) attdef.setPrompt(tag) attdef.setTag(tag) attdef.setInvisible(True) btr.appendAcDbEntity(attdef) y_pos -= text_height * 2.0 def insert_block_with_attribs(db, bname, insert_point, rotation_deg, attrib_values): """Block einfuegen und Attribute aus dict setzen. Parameter: db - aktuelle Datenbank bname - Name der Blockdefinition insert_point - Ge.Point3d rotation_deg - Drehwinkel in Grad attrib_values - dict {TAG: Wert} Rueckgabe: ObjectId der eingefuegten BlockReference """ bt = Db.BlockTable(db.blockTableId(), Db.OpenMode.kForRead) block_id = bt.getAt(bname) model = Db.BlockTableRecord(db.modelSpaceId(), Db.OpenMode.kForWrite) bref = Db.BlockReference(insert_point, block_id) bref.setRotation(math.radians(rotation_deg)) model.appendAcDbEntity(bref) # Attribute aus Block-Definition erzeugen und Werte setzen btr = Db.BlockTableRecord(block_id, 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) attref = Db.AttributeReference() attref.setPropertiesFrom(attdef) attref.setTag(attdef.tag()) attref.setInvisible(attdef.isInvisible()) attref.setPosition(attdef.position()) attref.setHeight(attdef.height()) val = attrib_values.get(attdef.tag(), attdef.textString()) attref.setTextString(val) bref.appendAttribute(attref) return bref.objectId()