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 get_world_position_of_attribute(insert, attrib): """ Berechnet die echte Weltposition eines Block-Attributs (ATTRIB) unter Berücksichtigung von Skalierung, Drehung und Blockverschiebung. :param insert: Blockreferenz-Entity (INSERT) :param attrib: Attribut-Entity (ATTRIB) :return: Vector (x, y, z) in Weltkoordinaten """ # Lokale Position des Attributs local_pos = attrib.dxf.insert # Blockeinfügepunkt block_pos = insert.dxf.insert # Blockskalierung (Standard = 1.0) xscale = getattr(insert.dxf, 'xscale', 1.0) yscale = getattr(insert.dxf, 'yscale', 1.0) # Rotation des Blocks (in Grad) rotation_deg = insert.dxf.rotation # Transformation aufbauen: Skalierung -> Rotation -> Translation m = ( Matrix44.scale(xscale, yscale, 1) @ Matrix44.z_rotate(rotation_deg * math.pi / 180) @ Matrix44.translate(block_pos.x, block_pos.y, block_pos.z) ) # Lokale Position transformieren return m.transform(local_pos) 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 """ 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}") world_pos = get_world_position_of_attribute(insert, attrib) #print(f"-- world --: {world_pos}") ld["block_pos"] = attrib.dxf.insert ld["world_pos"] = world_pos if not id == "": if not id in allIds: allIds[id] = ld else: allIds[id] = merge_two_dicts(allIds[id], ld) return allIds def get_subdistributor_positions(msp): """hole alle Positionen der Unterverteiler """ # # Ü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] = text.dxf.insert 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 """ ret = list() for e in msp.query('LWPOLYLINE[layer=="PRITSCHE_200-60"]'): #print_polyline(e) poly = list() for x, y, start_width, end_width, bulge in e.get_points(): # Gibt Tuple (x, y, start_width, end_width, bulge) point = (x,y) poly.append(point) ret.append(poly) # 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, default=str) 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') 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: if args.sensors: res_pos = get_input_positions(msp) if args.console: print(to_json(res_pos)) if args.dists: res_dist = get_subdistributor_positions(msp) if args.console: print(to_json(res_dist)) if args.rack: res_rac = get_rack_positions(msp) if args.console: print(to_json(res_rac)) else: parser.print_help()