227 lines
7.7 KiB
Python
227 lines
7.7 KiB
Python
import argparse
|
|
import configparser
|
|
#import ezdxf
|
|
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('TEXT[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()
|