Zeichnen von Sensoren und Subdists als Textblöcke hinzugefügt. Übereinanderstaffelung von mehreren Sensoren. Nur einmaliges Zeichnen von UVs
This commit is contained in:
+149
-136
@@ -60,24 +60,24 @@ def new_dxf(plines, out_path):
|
|||||||
print("creating new .dxf ..")
|
print("creating new .dxf ..")
|
||||||
|
|
||||||
doc = ezdxf.new('R2018', setup=True)
|
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)
|
doc.saveas(out_path)
|
||||||
print("done")
|
print("done")
|
||||||
|
|
||||||
|
|
||||||
def modify_original_dxf(plines, originaldxf):
|
def modify_original_dxf(plines, originaldxf):
|
||||||
""" adds new layer to original .dxf-file that contains cables
|
""" adds new layer to original .dxf-file that contains cables
|
||||||
"""
|
"""
|
||||||
print("adding cables into original .dxf ..")
|
print("adding cables into original .dxf ..")
|
||||||
|
|
||||||
doc = ezdxf.readfile(originaldxf)
|
doc = ezdxf.readfile(originaldxf)
|
||||||
create_cables(plines, doc)
|
draw_cables(plines, doc)
|
||||||
|
|
||||||
doc.saveas(out_path)
|
doc.saveas(out_path)
|
||||||
print("done")
|
print("done")
|
||||||
|
|
||||||
|
|
||||||
def copy_layers_into_new(originaldxf, outpath, plines):
|
def copy_layers_into_new(originaldxf, outpath, plines):
|
||||||
""" creates a new dxf file with a racks, sensors, subdists from original file including cable paths
|
""" 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)
|
quelle = ezdxf.readfile(originaldxf)
|
||||||
ziel = ezdxf.new('R2018', setup=True)
|
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)
|
copy_layers_into_dxf_by_filter(quelle, ziel)
|
||||||
|
|
||||||
|
|
||||||
ziel.saveas(out_path)
|
ziel.saveas(out_path)
|
||||||
print("done")
|
print("done")
|
||||||
|
|
||||||
|
def draw_cables(plines, doc):
|
||||||
def create_cables(plines, doc):
|
|
||||||
msp = doc.modelspace()
|
msp = doc.modelspace()
|
||||||
# # Beispiel für Text und Polyline
|
timestamp = datetime.now().strftime("%Y-%m-%d_%H-%M")
|
||||||
# add_text(msp)
|
cable_layer = f"cables_{timestamp}"
|
||||||
# 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)
|
|
||||||
|
|
||||||
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:
|
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):
|
def model_from_json(json_file):
|
||||||
with open(json_file, encoding='utf-8') as fh:
|
with open(json_file, encoding='utf-8') as fh:
|
||||||
data = json.load(fh)
|
data = json.load(fh)
|
||||||
@@ -125,7 +256,6 @@ def export_excel(json_file, out_path):
|
|||||||
write_excel_from_json(plines, out_path)
|
write_excel_from_json(plines, out_path)
|
||||||
print("done")
|
print("done")
|
||||||
|
|
||||||
|
|
||||||
def write_excel_from_json(plines:Polylines, outpath:str):
|
def write_excel_from_json(plines:Polylines, outpath:str):
|
||||||
wb = Workbook()
|
wb = Workbook()
|
||||||
length_summary = defaultdict(int)
|
length_summary = defaultdict(int)
|
||||||
@@ -191,7 +321,6 @@ def write_excel_from_json(plines:Polylines, outpath:str):
|
|||||||
|
|
||||||
wb.save(outpath)
|
wb.save(outpath)
|
||||||
|
|
||||||
|
|
||||||
def check_file_in_work(work_dir, filename):
|
def check_file_in_work(work_dir, filename):
|
||||||
fexists = True
|
fexists = True
|
||||||
if not os.path.exists(filename):
|
if not os.path.exists(filename):
|
||||||
@@ -202,94 +331,6 @@ def check_file_in_work(work_dir, filename):
|
|||||||
mypath = filename
|
mypath = filename
|
||||||
return (mypath, fexists)
|
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):
|
def copy_layers_into_dxf_by_filter(dxf_source: ezdxf.document.Drawing, dxf_target:ezdxf.document.Drawing):
|
||||||
|
|
||||||
msp_source = dxf_source.modelspace()
|
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:
|
if style.dxf.name not in dxf_target.styles:
|
||||||
dxf_target.styles.new(name=style.dxf.name)
|
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
|
# 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
|
# Alle Entities auf diesem Layer kopieren
|
||||||
entities = msp_source.query(f"*[layer=='{layername}']")
|
entities = msp_source.query(f"*[layer=='{layername}']")
|
||||||
for entity in entities:
|
for entity in entities:
|
||||||
msp_target.add_entity(entity.copy())
|
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)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|||||||
Reference in New Issue
Block a user