diff --git a/.vscode/launch.json b/.vscode/launch.json index e3a79c0..cc235dc 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -84,7 +84,7 @@ ] }, { - "name": "draw cable dxf from easy.json to a new dxf", + "name": "draw cable dxf with copied layers from easy_todraw.json", "type": "debugpy", "request": "launch", "program": "${file}", @@ -93,7 +93,11 @@ "--filename", "easy_todraw.json", "--new", - "easy_cables" + "easy_cables.dxf", + "--copy_layer", + "easy_layer_copy.dxf", + "--origin", + "easy.dxf" ] }, { diff --git a/lib/drawdxf.py b/lib/drawdxf.py index 6a12100..a42df60 100644 --- a/lib/drawdxf.py +++ b/lib/drawdxf.py @@ -9,6 +9,8 @@ from datetime import datetime from openpyxl import Workbook import math from collections import defaultdict +import configparser + @@ -40,54 +42,78 @@ def add_polyline(msp, points:Polyline, dxf_attribs): pline = msp.add_lwpolyline(points=pts, dxfattribs=dxf_attribs) pline.rgb = (255, 128, 0) -def new_dxf(json_file, out_path, dxf_file=False): +def new_dxf(plines, out_path): """ creates a new dxf file with a polyline inside which is created by the given json file """ print("creating dxf ..") - anlage = model_from_json(json_file) - if dxf_file: - # bestehende DXF-Datei laden - doc = ezdxf.readfile(dxf_file) - else: - # neue Zeichnung im DXF format of AutoCAD 2010 - doc = ezdxf.new('R2018', setup=True) + doc = ezdxf.new('R2018', setup=True) + create_cables(plines, doc) - # 2. 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) + doc.saveas(out_path) + print("done") + - # add new entities to the modelspace - msp = doc.modelspace() - # # Beispiel für Text und Polyline - # add_text(msp) - dxfattribs={"layer": timestamp} - for pl in anlage.kabel: - add_polyline(msp, pl, dxfattribs) +def modify_original_dxf(plines, originaldxf): + """ adds new layer to original .dxf-file that contains cables + """ + print("adding cables to original .dxf") + + doc = ezdxf.readfile(originaldxf) + create_cables(plines, doc) doc.saveas(out_path) print("done") + +def copy_layers_into_new(originaldxf, outpath): + """ creates a new dxf file with a racks, sensors, subdists from original file including cable paths + """ + print("copying layers from original .dxf into new .dxf") + + quelle = ezdxf.readfile(originaldxf) + ziel = ezdxf.readfile(outpath) + + copy_layers_into_dxf_by_filter(quelle, ziel) + create_cables(plines, quelle) + + ziel.saveas(out_path) + print("done") + + +def create_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) + + dxfattribs={"layer": timestamp} + for pl in plines.kabel: + add_polyline(msp, pl, dxfattribs) + + def model_from_json(json_file): with open(json_file, encoding='utf-8') as fh: data = json.load(fh) - anlage = from_dict( + plines = from_dict( data_class=Polylines, data=data ) - return anlage + return plines def export_excel(json_file, out_path): # Hier für Excel Export print("creating excel file ..") - anlage = model_from_json(json_file) - write_excel_from_json(anlage, out_path) + plines = model_from_json(json_file) + write_excel_from_json(plines, out_path) print("done") -def write_excel_from_json(anlage:Polylines, outpath:str): +def write_excel_from_json(plines:Polylines, outpath:str): wb = Workbook() length_summary = defaultdict(int) @@ -96,7 +122,7 @@ def write_excel_from_json(anlage:Polylines, outpath:str): ws1.title = "Kabellängen" ws1.append(["Kabel-ID", "Länge aus Json (m)", "Gerundete Länge (m)"]) - for pl in anlage.kabel: + for pl in plines.kabel: length = pl.length /1000 # Umrechnung von mm in m rounded_len = math.ceil(length/10)*10 length_summary[rounded_len] +=1 @@ -113,6 +139,9 @@ def write_excel_from_json(anlage:Polylines, outpath:str): def check_file_in_work(work_dir, filename): + print("workdir", work_dir) + print("filename:", filename) + fexists = True if not os.path.exists(filename): mypath = os.path.join(work_dir, filename) @@ -122,43 +151,101 @@ def check_file_in_work(work_dir, filename): mypath = filename return (mypath, fexists) +def copy_layers_into_dxf_by_filter(dxf_source: ezdxf.document.Drawing, dxf_target:ezdxf.document.Drawing): + + msp_source = dxf_source.modelspace() + msp_target = dxf_target.modelspace() + + + subdist_layers = list(config.items('GetPos-Layer_Distributors')) + rack_layers = list(config.items('GetPos-Layer_Racks')) + + layernames = list() + layernames.extend(subdist_layers) + layernames.extend(rack_layers) + + for (layername,v) in layernames: + if layername not in dxf_source.layers: + continue + # Falls der Layer noch nicht im Zieldokument existiert, neu anlegen + if layername not in dxf_target.layers: + quelle_layer = dxf_source.layers.get(layername) + dxf_target.layers.add( + name=layername, + color=quelle_layer.color, + linetype=quelle_layer.dxf.linetype, + lineweight=quelle_layer.dxf.lineweight + ) + + # Alle Entities auf diesem Layer kopieren + for entity in msp_source.query(f"*[layer=='{layername}']"): + msp_target.add_entity(entity.copy()) + + if __name__ == '__main__': parser = argparse.ArgumentParser(description='draws a dxf file with the given cable coordinates', prog='drawdxf') parser.add_argument('-f', '--filename', action='store', required=True, help='this json file contains all cables and its coordinates which should be drawn. Saved with an unique timestamp', metavar='myfile.json') - parser.add_argument('-d', '--dxf', action='store', help='this dxf drawing will be copied and the new layer with the cables will be added', metavar='myfile.dxf') - parser.add_argument('-n', '--new', action='store', help='create a new dxf file with cables in it. Name is basename and a timestamp') + parser.add_argument('-d', '--dxf', action='store', help='this dxf drawing will be copied and the new layer with the cables will be added. Original file must be added with --origin', metavar='myfile.dxf') + parser.add_argument('-c', '--copy_layer', action='store', help='copy layers of racks, sensors, distributors into a new .dxf-file. File also contains cable paths. Original file must be added with --origin', metavar='original.dxf') + parser.add_argument('-n', '--new', action='store', help='create a new dxf file only with cables in it. Name is basename and a timestamp') parser.add_argument('-x', '--excel', action='store', help='create a xlsx file with cables data', metavar='allCables.xls') + parser.add_argument('-o', '--origin', action='store', help='name of original .dxf file used by -d and -a', metavar='original.dxf') args = parser.parse_args() + + config_dir = os.environ.get("PROJECT_CFG") work_dir = os.fspath(os.environ.get('PROJECT_WORK')) - jfile = args.filename - (json_path, jexists) = check_file_in_work(work_dir, jfile) + json_file = args.filename + (json_path, jexists) = check_file_in_work(work_dir, json_file) if not jexists: - print("file %s does not exit", jfile) + print(f"file {json_file} does not exist") parser.print_help() exit() + print(json_path) + plines = model_from_json(json_path) + + + config = configparser.ConfigParser(allow_no_value=True, delimiters=("=")) + config.optionxform = lambda option: option # preserve case for letters + + config.read(os.path.join(config_dir, "allgemein.cfg")) + + dxf_file = args.dxf + + if args.dxf or args.copy_layer: + if not args.origin: + parser.print_help() + exit() + else: + (origin_path, dexists) = check_file_in_work(work_dir, args.origin) + if args.dxf: - # falls ein neuer Layer hinzu gefügt werden soll - dxf_file = args.dxf (dxf_path, dexists) = check_file_in_work(work_dir, dxf_file) if not dexists: - print("file %s does not exit", dxf_file) + print(f"file {dxf_file} does not exist") parser.print_help() exit() out_path = dxf_path - res_pos = new_dxf(json_path, out_path, dxf_file=dxf_path) - else: - # erzeuge eine neue dxf Datei mit aktuellen Zeitstempel im Namen - #basename = os.path.splitext(dxf_path)[0] - #timestamp = datetime.now().strftime(basename+"_%Y%m%d-%H%M%S.dxf") - #timestamp = datetime.now().strftime("%Y%m%d-%H%M%S.dxf") + res_pos = new_dxf(plines, dxf_path) + + if args.copy_layer: + + out_path = os.path.join(work_dir, args.copy_layer) + res_pos = new_dxf(plines, out_path) + + copy_layers_into_new(origin_path, out_path) + + if args.new: + # erzeuge dxf Datei nur mit Kabeln out_path = os.path.join(work_dir, args.new) - res_pos = new_dxf(json_path, out_path) + res_pos = new_dxf(plines, out_path) if args.excel: excel_path = os.path.join(work_dir, args.excel) export_excel(json_path, excel_path) + + diff --git a/lib/getpositions.py b/lib/getpositions.py index 46da5be..1ef1dae 100644 --- a/lib/getpositions.py +++ b/lib/getpositions.py @@ -70,8 +70,8 @@ def get_input_positions(msp: ezdxf.document.Drawing.modelspace): 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") + breite_marker = config.getfloat("GetPos-Geom-Sensor", "Breite") + hoehe_marker = config.getfloat("GetPos-Geom-Sensor", "Hoehe") pos_midx = pos.x + breite_marker*0.5 pos_midy = pos.y + hoehe_marker*0.5 @@ -143,7 +143,7 @@ def get_subdistributor_positions(msp, dist2sensors): ret = dict() # Alle Texte auf Layer "xy" all_distributors = dist2sensors.keys() - all_layers = config.items('Layer_Busverteiler') + all_layers = config.items('GetPos-Layer_Distributors') for (layer,v) in all_layers: for distname in all_distributors: selectstr = f'MTEXT[layer=="{layer}"]' @@ -165,7 +165,7 @@ def get_tunnel_positions(msp): allTunnels = dict() tunnel_length = dict() # Alle Text mit "Tunnel" als Inhalt auf Layer "xy" - all_layers = config.items('Layer_Tunnel') + all_layers = config.items('GetPos-Layer_Tunnel') for (layer,v) in all_layers: selectstr = f'MTEXT[layer=="{layer}"]' for text in msp.query(selectstr): @@ -209,7 +209,7 @@ def get_rack_positions(msp): ret = dict() rack_counter = 1 #Zaehler für Rack Nummerierung - all_layers = list(config.items('Layer_Pritschen')) + all_layers = list(config.items('GetPos-Layer_Racks')) for (layer,v) in all_layers: selectstr = f'LWPOLYLINE[layer=="{layer}"]' for e in msp.query(selectstr): @@ -286,7 +286,7 @@ if __name__ == '__main__': config = configparser.ConfigParser(allow_no_value=True, delimiters=("=")) config.optionxform = lambda option: option # preserve case for letters - config.read(os.path.join(config_dir, "getpositions.cfg")) + config.read(os.path.join(config_dir, "allgemein.cfg")) output_results = dict() if args.sensors: diff --git a/lib/routing.py b/lib/routing.py index 69f54ab..9416742 100644 --- a/lib/routing.py +++ b/lib/routing.py @@ -166,7 +166,7 @@ if __name__ == "__main__": config = configparser.ConfigParser(allow_no_value=True, delimiters=("=")) config.optionxform = lambda option: option # preserve case for letters - config.read(os.path.join(config_dir, "routing.cfg")) + config.read(os.path.join(config_dir, "allgemein.cfg")) # virtuelle Anlage erstellen