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 ..")
|
||||
|
||||
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__':
|
||||
|
||||
Reference in New Issue
Block a user