Zeichnen von Sensoren und Subdists als Textblöcke hinzugefügt. Übereinanderstaffelung von mehreren Sensoren. Nur einmaliges Zeichnen von UVs

This commit is contained in:
2025-06-05 16:14:27 +02:00
parent a385d579c3
commit b72c01768e
+149 -136
View File
@@ -60,24 +60,24 @@ def new_dxf(plines, out_path):
print("creating new .dxf ..")
doc = ezdxf.new('R2018', setup=True)
create_cables(plines, doc)
draw_cables(plines, doc)
draw_sensors(plines, doc)
draw_subdists(plines, doc)
doc.saveas(out_path)
print("done")
def modify_original_dxf(plines, originaldxf):
""" adds new layer to original .dxf-file that contains cables
"""
print("adding cables into original .dxf ..")
doc = ezdxf.readfile(originaldxf)
create_cables(plines, doc)
draw_cables(plines, doc)
doc.saveas(out_path)
print("done")
def copy_layers_into_new(originaldxf, outpath, plines):
""" creates a new dxf file with a racks, sensors, subdists from original file including cable paths
"""
@@ -86,28 +86,159 @@ def copy_layers_into_new(originaldxf, outpath, plines):
quelle = ezdxf.readfile(originaldxf)
ziel = ezdxf.new('R2018', setup=True)
create_cables(plines, ziel)
draw_cables(plines, ziel)
draw_sensors(plines, ziel)
copy_layers_into_dxf_by_filter(quelle, ziel)
ziel.saveas(out_path)
print("done")
def create_cables(plines, doc):
def draw_cables(plines, doc):
msp = doc.modelspace()
# # Beispiel für Text und Polyline
# add_text(msp)
# Layer mit Zeitstempel erstellen (z.B. "Layer_2025-05-07_14-30")
timestamp = datetime.now().strftime("Kabel_%Y-%m-%d_%H-%M")
if timestamp not in doc.layers:
doc.layers.add(name=timestamp, color=7)
timestamp = datetime.now().strftime("%Y-%m-%d_%H-%M")
cable_layer = f"cables_{timestamp}"
dxfattribs={"layer": timestamp}
# Kabel-Layer anlegen
if cable_layer not in doc.layers:
doc.layers.add(name=cable_layer, color=7)
dxfattribs_cable={"layer": cable_layer}
# Kabel zeichnen
for pl in plines.kabel:
add_polyline(msp, pl, dxfattribs)
# Polyline für Kabel zeichnen
add_polyline(msp, pl, dxfattribs_cable)
def find_close_key(pos2sensors, x, y, tolerance=10): # !!! Toleranz in Config !!!
''' Funktion überprüft ob Sensoren nahezu identisch an der gleichen Stelle liegen und legt sie in diesem fall aufeinander
Wird benötigt, um zusammengehörige Sensoren gestaffelt auf dxf zu zeichen
'''
for (px, py) in pos2sensors:
if abs(px - x) <= tolerance and abs(py - y) <= tolerance:
return (px, py)
return None
def draw_sensors(plines, doc):
msp = doc.modelspace()
timestamp = datetime.now().strftime("%Y-%m-%d_%H-%M")
sensor_layer = f"sensors_{timestamp}"
# Sensor-Layer erzeugen
if sensor_layer not in doc.layers:
doc.layers.add(name=sensor_layer, color=5)
dxfattribs_sensors={"layer": sensor_layer, "height": 100}
# Sensoren nach Endpunkten gruppieren -> mehrfacheinträge gestaffelt zeichnen
pos2sensors = defaultdict(list)
for pl in plines.kabel:
pt2 = pl.coords[-1] #Endpunkt des Kabels = Sensor Position
pos_key = find_close_key(pos2sensors, pt2.x, pt2.y)
if pos_key:
pos2sensors[pos_key].append(pl)
else:
pos2sensors[(pt2.x, pt2.y)].append(pl)
# Sensor Blöcke zeichnen
for (x,y), pls in pos2sensors.items():
for i, pl in enumerate(pls):
sensor_name = pl.id.split('-')[-1]
pt1 = pl.coords[-2]
pt2 = pl.coords[-1]
dx = pt2.x - pt1.x
dy = pt2.y - pt1.y
text = msp.add_text(sensor_name, dxfattribs=dxfattribs_sensors)
# Offsets für Beschriftungen
offsetx = 0
offsety = 0
# Kabel Horizontal
if abs(dx) > abs(dy):
n = len(pls)
center_offset = i - (n - 1) / 2 # Falls mehrere Sensoren -> Verschiebung so, dass Kabel immer in Mitte ankommt
offsety = -80 + center_offset * 110 # Wert -80 über Try-and-Error zur Mitte der Beschriftung angepasst
if dx > 0:
halign = 0 # LEFT
offsetx = 50 # Wert 50 durch Try-and-Error sodass etwas Abstand zu Kabelpritsche
else:
halign = 2 # RIGHT
offsetx = -50 # Wert 50 durch Try-and-Error sodass etwas Abstand zu Kabelpritsche
valign = 1 # BOTTOM
# Kabel vertikal
else:
if dy > 0:
valign = 0 # BASELINE
offsety = 50 + i * 110 # nach oben anfügen
else:
valign = 3 # TOP
offsety = -50 - i * 110 # nach unten anfügen
halign = 1 # CENTER
# Alignments setzen
text.dxf.halign = halign
text.dxf.valign = valign
text.set_placement((pt2.x + offsetx, pt2.y + offsety))
def draw_subdists(plines, doc):
msp = doc.modelspace()
timestamp = datetime.now().strftime("%Y-%m-%d_%H-%M")
subdist_layer = f"subdists_{timestamp}"
# Sensor-Layer erzeugen
if subdist_layer not in doc.layers:
doc.layers.add(name=subdist_layer, color=3)
dxfattribs_subdists={"layer": subdist_layer, "height": 100}
subdist_positions = set()
for pl in plines.kabel:
pt1 = pl.coords[0] # Startposition = UV-Position
pos = (pt1.x, pt1.y)
if pos in subdist_positions:
continue
subdist_positions.add(pos)
subdist_name = pl.id.split('_')[0]
pt2 = pl.coords[1]
dx = pt2.x - pt1.x
dy = pt2.y - pt1.y
# Offsets für Beschriftungen
offsetx = 0
offsety = 0
if abs(dx) > abs(dy): # Horizontal
offsety = -80 # Wert -80 über Try-and-Error zur Mitte der Beschriftung angepasst
if dx > 0:
halign = 0 # LEFT
offsetx = 50 # Wert 50 durch Try-and-Error sodass etwas Abstand zu Kabelpritsche
else:
halign = 2 # RIGHT
offsetx = -50 # Wert 50 durch Try-and-Error sodass etwas Abstand zu Kabelpritsche
valign = 1 # BOTTOM
else: # Vertikal
if dy < 0:
valign = 0 # BASELINE
offsety = 50
else:
valign = 3 # TOP
offsety = -50
halign = 1 # CENTER
# Text platzieren
text = msp.add_text(subdist_name, dxfattribs=dxfattribs_subdists)
text.dxf.halign = halign
text.dxf.valign = valign
text.set_placement((pt1.x + offsetx, pt1.y + offsety))
def model_from_json(json_file):
with open(json_file, encoding='utf-8') as fh:
data = json.load(fh)
@@ -125,7 +256,6 @@ def export_excel(json_file, out_path):
write_excel_from_json(plines, out_path)
print("done")
def write_excel_from_json(plines:Polylines, outpath:str):
wb = Workbook()
length_summary = defaultdict(int)
@@ -191,7 +321,6 @@ def write_excel_from_json(plines:Polylines, outpath:str):
wb.save(outpath)
def check_file_in_work(work_dir, filename):
fexists = True
if not os.path.exists(filename):
@@ -202,94 +331,6 @@ def check_file_in_work(work_dir, filename):
mypath = filename
return (mypath, fexists)
#####
def collect_text_entities(msp):
texts = []
for entity in msp.query("TEXT MTEXT"):
try:
text = entity.dxf.text
pos = tuple(round(c, 4) for c in entity.dxf.insert)
layer = entity.dxf.layer
texts.append((text, pos, layer))
except Exception as e:
print(f"Fehler beim Lesen eines Textobjekts: {e}")
return texts
def compare_texts(source_texts, target_texts):
missing_in_target = [t for t in source_texts if t not in target_texts]
extra_in_target = [t for t in target_texts if t not in source_texts]
if not missing_in_target and not extra_in_target:
print("✅ Alle TEXT/MTEXT-Objekte wurden korrekt kopiert.")
else:
if missing_in_target:
print("\n❌ Fehlende Texte im Ziel:")
for text in missing_in_target:
print(f" - {text}")
if extra_in_target:
print("\n⚠️ Zusätzliche Texte im Ziel:")
for text in extra_in_target:
print(f" - {text}")
def collect_block_references(doc):
msp = doc.modelspace()
blocks = []
for insert in msp.query("INSERT"):
try:
name = insert.dxf.name
pos = tuple(round(c, 4) for c in insert.dxf.insert)
layer = insert.dxf.layer
blocks.append((name, pos, layer))
except Exception as e:
print(f"Fehler beim Lesen eines INSERT-Objekts: {e}")
return blocks
def serialize_entity(e):
"""Wandelt eine Entity in ein vergleichbares Tupel um"""
dxfattribs = {}
for key in e.dxf.__dir__():
try:
value = getattr(e.dxf, key)
if callable(value) or key.startswith("_"):
continue
if isinstance(value, (list, tuple)):
value = tuple(round(v, 4) for v in value)
elif isinstance(value, float):
value = round(value, 4)
dxfattribs[key] = value
except Exception:
continue
return (e.dxftype(), dxfattribs)
def compare_blocks(source_doc, target_doc, used_block_names):
for name in used_block_names:
if name not in source_doc.blocks or name not in target_doc.blocks:
print(f"❌ Block '{name}' fehlt in einer der Dateien.")
continue
source_block = source_doc.blocks.get(name)
target_block = target_doc.blocks.get(name)
source_entities = [serialize_entity(e) for e in source_block]
target_entities = [serialize_entity(e) for e in target_block]
missing_in_target = [e for e in source_entities if e not in target_entities]
extra_in_target = [e for e in target_entities if e not in source_entities]
if not missing_in_target and not extra_in_target:
print(f"✅ Block '{name}' ist identisch.")
else:
print(f"\n🔍 Block '{name}' hat Unterschiede:")
if missing_in_target:
print(f" ❌ Fehlt im Ziel:")
for e in missing_in_target:
print(f" - {e}")
if extra_in_target:
print(f" ⚠️ Zusätzlich im Ziel:")
for e in extra_in_target:
print(f" - {e}")
def copy_layers_into_dxf_by_filter(dxf_source: ezdxf.document.Drawing, dxf_target:ezdxf.document.Drawing):
msp_source = dxf_source.modelspace()
@@ -326,26 +367,6 @@ def copy_layers_into_dxf_by_filter(dxf_source: ezdxf.document.Drawing, dxf_targe
if style.dxf.name not in dxf_target.styles:
dxf_target.styles.new(name=style.dxf.name)
'''
# 2. alle Blockdefinitionen kopieren die benötigt werden
used_blocks = {ins.dxf.name for ins in msp_source.query("INSERT")}
for name in used_blocks:
# skip vorhandene
if name in dxf_target.blocks:
continue
src_block = dxf_source.blocks.get(name)
# neues BLOCK-Objekt anlegen mit Base-Point
new_block = dxf_target.blocks.new(name=name, base_point=src_block.base_point)
# **ALLE** Entities im Block kopieren
for ent in src_block:
new_block.add_entity(ent.copy())
# 3. Jetzt die INSERTs in den Modelspace kopieren
for ins in msp_source.query("INSERT"):
new_ins = ins.copy()
msp_target.add_entity(new_ins)
'''
# 4. Filter-Layernamen bestimmen
@@ -365,15 +386,7 @@ def copy_layers_into_dxf_by_filter(dxf_source: ezdxf.document.Drawing, dxf_targe
# Alle Entities auf diesem Layer kopieren
entities = msp_source.query(f"*[layer=='{layername}']")
for entity in entities:
msp_target.add_entity(entity.copy())
# texts_source = collect_text_entities(msp_source)
# texts_target = collect_text_entities(msp_target)
# compare_texts(texts_source, texts_target)
# used_block_names = set(insert.dxf.name for insert in dxf_source.modelspace().query("INSERT"))
# compare_blocks(dxf_source, dxf_target, used_block_names)
msp_target.add_entity(entity.copy())
if __name__ == '__main__':