import argparse import configparser import ezdxf.document from ezdxf.math import Matrix44 import os import sys import math import json import re """ Dieses Programm: - liest die dxf Datei und holt sich von den Layern der dxf Datei die Positionen + der Motoren, Sensoren und Aktoren + der Unterverteiler + der Polylinien der Kabelpritschen - erzeugt daraus eine .json Datei im Work Ordner """ def write_results(jsnResults, outdir, filename): """ write results to a json file """ print("writing results to a json file ...") outfile = os.path.join(outdir, filename) with open(outfile, 'w', encoding='utf-8') as fh: fh.write(jsnResults) print("done") def merge_two_dicts(x, y): z = x.copy() z.update(y) return z def get_input_positions(msp: ezdxf.document.Drawing.modelspace): """hole alle Positionen der Eingänge !!Sensor Positionen erst nach Offsett-Addition "Mitte-Mitte"!! """ allIds = dict() SpecialKeys = ["MB", # Separator "MA", # Motor "BG", # Stausensor "FC" # Motorschutzschalter ] # Über alle Blockreferenzen (INSERT) im Modelspace laufen for insert in msp.query('INSERT'): if len(insert.attribs) == 0: continue # Überspringe Blöcke ohne Attribute id = "" ld = dict() for attrib in insert.attribs: if len(insert.attribs) == 0: continue # Überspringe Blöcke ohne Attribute #print(f"Attribut Name: {attrib.dxf.tag}, Wert: {attrib.dxf.text}") ld[attrib.dxf.tag] = attrib.dxf.text if attrib.dxf.tag == "IO": id = attrib.dxf.text # print(f"-- coord io {id}--: {attrib.dxf.insert}") # position des Blocks if attrib.dxf.tag == "B": for spec in SpecialKeys: if spec in attrib.dxf.text: id = attrib.dxf.text #print(f"-- coord {attrib.dxf.text} --: {attrib.dxf.insert}") if attrib.dxf.tag == "REALE_POSITION" and attrib.dxf.text == "x": #print(f"-- coord real --: {attrib.dxf.insert}") pos = attrib.dxf.insert #Position Ecke unten links von "x"-Marker auslesen # Hoehe und Breite von "x" addieren, um Mittelpunkt zu finden breite_marker = config.getfloat("Sensor_Marker", "Breite") hoehe_marker = config.getfloat("Sensor_Marker", "Hoehe") pos_midx = pos.x + breite_marker*0.5 pos_midy = pos.y + hoehe_marker*0.5 ld["pos"] = (round(pos_midx, 1), round(pos_midy, 1)) # Nur wenn eine ID vorhanden ist, und eine gültige Position existiert if id and "pos" in ld and isinstance(ld["pos"], tuple) and len(ld["pos"]) == 2: if id in allIds: allIds[id] = merge_two_dicts(allIds[id], ld) #Kombiniert alle infos aus dxf und "pos" else: allIds[id] = ld return allIds def get_subdistributor_positions(msp): """hole alle Positionen der Unterverteiler !!UV-Positionen bereits "Mitte-Mitte"!! """ # # Über alle Texte laufen # for text in msp.query('MTEXT'): # print(f"Inhalt: {text.dxf.text}") # print(f"Layer: {text.dxf.layer}") # print(f"Einfügepunkt: {text.dxf.insert}") # print(f"Breite: {text.dxf.width}") # # print("Farbe:", text.dxf.color) # Achtung: 256 = "ByLayer" # # print("Höhe (height):", text.dxf.height) # # print("Rotation (degrees):", text.dxf.rotation) # # print("Breitenfaktor (width factor):", text.dxf.width) # # print("Style (Schriftart):", text.dxf.style) # # print("Handle:", text.dxf.handle) # print("---") ret = dict() # Alle Texte auf Layer "xy" for text in msp.query('MTEXT[layer=="Busverteiler-Kennzeichnung"]'): print(f"Text auf Layer 'Busverteiler-Kennzeichnung': {text.dxf.text}") match = re.search(r"UC\w+", text.dxf.text) if match: nameUC = match.group(0) ret[nameUC] = (round(text.dxf.insert[0],1), round(text.dxf.insert[1],1)) #nur x und y Koordinate in Json schreiben return ret # helper function def print_line(e): print("LINE on layer: %s\n" % e.dxf.layer) print("points: %s\n" % repr(e.dxf)) def print_polyline(e): print("POLYLINE on layer: %s\n" % e.dxf.layer) #print("points: %s\n" % repr(e.dxf)) #print("y point: %s\n" % e.dxf.y) for x, y, start_width, end_width, bulge in e.get_points(): # Gibt Tuple (x, y, start_width, end_width, bulge) print(f" Punkt: ({x}, {y}), Startbreite: ({start_width}, Endbreite: {end_width})") if e.is_closed: print("Diese Polyline ist geschlossen.") def get_rack_positions(msp): """hole alle Positionen aller Kabelpritschen und nummeriere Racks""" ret = dict() rack_counter = 1 #Zaehler für Rack Nummerierung for e in msp.query('LWPOLYLINE[layer=="PRITSCHE_200-60"]'): #print_polyline(e) rack_key = f"Rack_{rack_counter}" ret[rack_key] = dict() node_counter = 1 for x, y, start_width, end_width, bulge in e.get_points(): # Gibt Tuple (x, y, start_width, end_width, bulge) node_key = f"Node_{node_counter}" ret[rack_key][node_key] = [round(x,1), round(y,1)] node_counter +=1 rack_counter +=1 # iterate over all entities in modelspace # for e in msp: # if e.dxftype() == "LINE": # print_line(e) # if e.dxftype() == "LWPOLYLINE": # print_polyline(e) return ret def to_json(d, pretty: bool = True) -> str: return json.dumps(d, indent=2 if pretty else None, ensure_ascii=False, default=str) #ensure_ascii false für darstellung von "ue" def get_dxf_file(filepath): """hole das dxf file """ try: doc = ezdxf.readfile(filepath) except IOError: print(f"Not a DXF file or a generic I/O error.") sys.exit(1) except ezdxf.DXFStructureError: print(f"Invalid or corrupted DXF file.") sys.exit(2) return doc if __name__ == '__main__': parser = argparse.ArgumentParser(description='fetches the x/y positions from a dxf file', prog='getpositions') parser.add_argument('-f', '--filename', action='store', required=True, default="ST_6300_Steuerungstestlayout1_neueBloecke.dwg", help='which file should be fetched', metavar='myfile.dwg') parser.add_argument('-s', '--sensors', action='store_true', help='fetch all position of sensors, motors, actors') parser.add_argument('-d', '--dists', action='store_true', help='fetch all positions of all subdistributors') parser.add_argument('-r', '--rack', action='store_true', help='fetch all positions of all cable racks') parser.add_argument('-c', '--console', action='store_true', help='print results to output') args = parser.parse_args() out_dir = os.environ.get('PROJECT_DATA') work_dir = os.environ.get('PROJECT_WORK') config_dir = os.environ.get("PROJECT_CFG") filename = args.filename doc = get_dxf_file(os.path.join(work_dir, filename)) # type: ignore msp = doc.modelspace() res_pos = dict() res_dist = dict() res_rac = dict() if args.sensors or args.dists or args.rack: config = configparser.ConfigParser(allow_no_value=True) config.read(os.path.join(config_dir, "getpositions.cfg")) if args.sensors: res_pos = get_input_positions(msp) if args.console: print(to_json(res_pos)) write_results(to_json(res_pos), work_dir, "sensors.json") if args.dists: res_dist = get_subdistributor_positions(msp) if args.console: print(to_json(res_dist)) write_results(to_json(res_dist), work_dir, "subdistributors.json") if args.rack: res_rac = get_rack_positions(msp) if args.console: print(to_json(res_rac)) write_results(to_json(res_rac), work_dir, "racks.json") else: parser.print_help()