Launch angepasst auf ASCII Fortna layout und binary Fortna Layout. Neues Icon erstellt. Kleiner Bugfix in Darw für Positionierung von UV Text. Getpositions mit Support für iterdxf (low Memory)
This commit is contained in:
Vendored
+22
-6
@@ -55,6 +55,22 @@
|
||||
"ST-Fortna_positions.json"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "getpositions with ST-Fortna_ASCII.dxf",
|
||||
"type": "debugpy",
|
||||
"request": "launch",
|
||||
"program": "${file}",
|
||||
"console": "integratedTerminal",
|
||||
"args": [
|
||||
"--filename",
|
||||
"ST-Fortna_ASCII.dxf",
|
||||
"--sensors",
|
||||
"--rack",
|
||||
"--console",
|
||||
"--write",
|
||||
"ST-Fortna_ASCII_positions.json"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "getpositions with HundM.dxf",
|
||||
"type": "debugpy",
|
||||
@@ -116,17 +132,17 @@
|
||||
"easy.dxf"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "draw cable dxf from easy.json to new layer",
|
||||
{
|
||||
"name": "draw cables from ST-Fortna_todraw",
|
||||
"type": "debugpy",
|
||||
"request": "launch",
|
||||
"program": "${file}",
|
||||
"console": "integratedTerminal",
|
||||
"args": [
|
||||
"--json",
|
||||
"easy.json",
|
||||
"--dxf",
|
||||
"easy.dxf"
|
||||
"--filename",
|
||||
"ST-Fortna_ASCII_todraw.json",
|
||||
"-n",
|
||||
"ST-Fortna_ASCII_cables.dxf"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 3.1 MiB After Width: | Height: | Size: 663 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 1.0 MiB After Width: | Height: | Size: 1.2 MiB |
+2
-2
@@ -204,7 +204,7 @@ def draw_subdists(plines, doc):
|
||||
continue
|
||||
subdist_positions.add(pos)
|
||||
|
||||
subdist_name = pl.id.split('_')[0]
|
||||
subdist_name = pl.id.split('-')[0]
|
||||
|
||||
pt2 = pl.coords[1]
|
||||
dx = pt2.x - pt1.x
|
||||
@@ -216,7 +216,7 @@ def draw_subdists(plines, doc):
|
||||
|
||||
if abs(dx) > abs(dy): # Horizontal
|
||||
offsety = -80 # Wert -80 über Try-and-Error zur Mitte der Beschriftung angepasst
|
||||
if dx > 0:
|
||||
if dx < 0:
|
||||
halign = 0 # LEFT
|
||||
offsetx = 50 # Wert 50 durch Try-and-Error sodass etwas Abstand zu Kabelpritsche
|
||||
else:
|
||||
|
||||
+193
-40
@@ -8,14 +8,17 @@ import json
|
||||
import re
|
||||
from shapely import Point
|
||||
from itertools import combinations
|
||||
from ezdxf.addons import iterdxf
|
||||
import re
|
||||
import time
|
||||
|
||||
|
||||
"""
|
||||
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
|
||||
+ der Motoren, Sensoren und Aktoren
|
||||
+ der Unterverteiler
|
||||
+ der Polylinien der Kabelpritschen
|
||||
- erzeugt daraus eine .json Datei im Work Ordner
|
||||
|
||||
"""
|
||||
@@ -49,6 +52,61 @@ def get_input_positions(msp: ezdxf.document.Drawing.modelspace):
|
||||
continue # Überspringe Blöcke ohne Attribute
|
||||
id = ""
|
||||
ld = dict()
|
||||
for attrib in insert.attribs:
|
||||
attr_tag = attrib.dxf.tag
|
||||
attr_text = attrib.dxf.text
|
||||
if len(insert.attribs) == 0:
|
||||
continue # Überspringe Blöcke ohne Attribute
|
||||
#print(f"Attribut Name: {attrib.dxf.tag}, Wert: {attrib.dxf.text}")
|
||||
ld[attr_tag] = attr_text
|
||||
if attr_tag == "IO":
|
||||
id = attr_text
|
||||
#print(f"-- coord io {id}--: {attrib.dxf.insert}") # position des Blocks
|
||||
pos = attrib.dxf.insert #Position aufzeichnen und bei Bedarf später mit REAL_POS überschreiben
|
||||
ld["pos"] = (round(pos.x, 1), round(pos.y, 1))
|
||||
|
||||
if attr_tag == "B":
|
||||
for spec in SpecialKeys:
|
||||
if spec in attr_text:
|
||||
id = attr_text
|
||||
#print(f"-- coord {attrib.dxf.text} --: {attrib.dxf.insert}")
|
||||
if attr_tag == "REALE_POSITION" and attr_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("GetPos-Geom-Sensor", "Breite")
|
||||
hoehe_marker = config.getfloat("GetPos-Geom-Sensor", "Hoehe")
|
||||
midx = pos[0] + breite_marker * 0.5
|
||||
midy = pos[1] + hoehe_marker * 0.5
|
||||
ld["pos"] = (round(midx, 1), round(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_input_positions_iter(dxf_path) -> dict:
|
||||
"""
|
||||
Iterative Version für große DXF-Dateien mit iterdxf (kein Context Manager!).
|
||||
"""
|
||||
|
||||
SpecialKeys = ["MB", "MA", "BG", "FC"]
|
||||
allIds = dict()
|
||||
|
||||
|
||||
for insert in iterdxf.modelspace(dxf_path):
|
||||
if insert.dxftype() != 'INSERT':
|
||||
continue
|
||||
|
||||
attribs = {att.dxf.tag: att.dxf.text for att in insert.attribs or []}
|
||||
id = ""
|
||||
ld = dict()
|
||||
|
||||
for attrib in insert.attribs:
|
||||
attr_tag = attrib.dxf.tag
|
||||
attr_text = attrib.dxf.text
|
||||
@@ -85,6 +143,7 @@ def get_input_positions(msp: ezdxf.document.Drawing.modelspace):
|
||||
allIds[id] = merge_two_dicts(allIds[id], ld) #Kombiniert alle infos aus dxf und "pos"
|
||||
else:
|
||||
allIds[id] = ld
|
||||
|
||||
return allIds
|
||||
|
||||
def create_mappings(positions:dict) -> dict:
|
||||
@@ -128,20 +187,6 @@ def create_mappings(positions:dict) -> dict:
|
||||
def get_subdistributor_positions(msp, dist2sensors):
|
||||
"""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"
|
||||
all_distributors = dist2sensors.keys()
|
||||
@@ -161,6 +206,28 @@ def get_subdistributor_positions(msp, dist2sensors):
|
||||
# print("---")
|
||||
return ret
|
||||
|
||||
def get_subdistributor_positions_iter(dxf_path, dist2sensors):
|
||||
"""Hole alle Positionen der Unterverteiler aus MTEXT-Objekten mithilfe von iterdxf."""
|
||||
ret = {}
|
||||
all_distributors = dist2sensors.keys()
|
||||
all_layers = config.items('GetPos-Layer_Distributors')
|
||||
|
||||
for entity in iterdxf.modelspace(dxf_path):
|
||||
if entity.dxftype() != "MTEXT":
|
||||
continue
|
||||
entity_text = entity.dxf.text
|
||||
entity_layer = entity.dxf.layer
|
||||
insert_point = entity.dxf.insert
|
||||
|
||||
for (layer_name, _) in all_layers:
|
||||
if entity_layer != layer_name:
|
||||
continue
|
||||
for distname in all_distributors:
|
||||
if f"-{distname}" in entity_text:
|
||||
ret[distname] = (round(insert_point[0], 1), round(insert_point[1], 1))
|
||||
|
||||
return ret
|
||||
|
||||
def get_tunnel_positions(msp):
|
||||
"""hole alle Positionen aller Tunnel Ein und Ausgänge
|
||||
"""
|
||||
@@ -171,11 +238,6 @@ def get_tunnel_positions(msp):
|
||||
for (layer,v) in all_layers:
|
||||
selectstr = f'MTEXT[layer=="{layer}"]'
|
||||
for text in msp.query(selectstr):
|
||||
#print(f"Text auf Layer 'Busverteiler-Kennzeichnung': {text.dxf.text}")
|
||||
# match = re.search("Tunnel-", text.dxf.text)
|
||||
# if match:
|
||||
# if tunnelname in allTunnels:
|
||||
# pos = (round(text.dxf.insert[0],1), round(text.dxf.insert[1],1)) #nur x und y Koordinate in Json schreiben
|
||||
txt = text.dxf.text
|
||||
pattern = r"(TUNNEL\d+)-(\d+)"
|
||||
match = re.search(pattern, txt)
|
||||
@@ -192,6 +254,40 @@ def get_tunnel_positions(msp):
|
||||
allTunnels['length'] = tunnel_length
|
||||
return allTunnels
|
||||
|
||||
def get_tunnel_positions_iter(dxf_path):
|
||||
"""Hole alle Positionen aller Tunnel Ein- und Ausgänge mithilfe von iterdxf."""
|
||||
allTunnels = dict()
|
||||
tunnel_length = dict()
|
||||
|
||||
all_layers = config.items('GetPos-Layer_Tunnel')
|
||||
|
||||
for entity in iterdxf.modelspace(dxf_path):
|
||||
if entity.dxftype() != "MTEXT":
|
||||
continue
|
||||
|
||||
txt = entity.dxf.text
|
||||
layer = entity.dxf.layer
|
||||
insert = entity.dxf.insert
|
||||
|
||||
for (layer_name, _) in all_layers:
|
||||
if layer != layer_name:
|
||||
continue
|
||||
|
||||
pattern = r"(TUNNEL\d+)-(\d+)"
|
||||
match = re.search(pattern, txt)
|
||||
if match:
|
||||
tunnelname = match.group(1)
|
||||
laenge = match.group(2)
|
||||
pos = (round(insert[0], 1), round(insert[1], 1))
|
||||
|
||||
if tunnelname not in allTunnels:
|
||||
allTunnels[tunnelname] = []
|
||||
allTunnels[tunnelname].append(pos)
|
||||
tunnel_length[tunnelname] = laenge
|
||||
|
||||
allTunnels['length'] = tunnel_length
|
||||
return allTunnels
|
||||
|
||||
# helper function
|
||||
def print_line(e):
|
||||
print("LINE on layer: %s\n" % e.dxf.layer)
|
||||
@@ -222,12 +318,34 @@ def get_rack_positions(msp):
|
||||
p = [round(x,1), round(y,1)]
|
||||
ret[rack_key].append(p)
|
||||
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 get_rack_positions_iter(dxf_path):
|
||||
"""Hole alle Positionen aller Kabelpritschen (Racks) mithilfe von iterdxf."""
|
||||
ret = dict()
|
||||
rack_counter = 1 # Zähler für Rack-Nummerierung
|
||||
|
||||
all_layers = config.items('GetPos-Layer_Racks')
|
||||
|
||||
for entity in iterdxf.modelspace(dxf_path):
|
||||
if entity.dxftype() != "LWPOLYLINE":
|
||||
continue
|
||||
|
||||
layer = entity.dxf.layer
|
||||
|
||||
if not any(layer == cfg_layer for cfg_layer, _ in all_layers):
|
||||
continue
|
||||
|
||||
rack_key = f"Rack_{rack_counter}"
|
||||
ret[rack_key] = []
|
||||
|
||||
# Verwende entity.vertices() statt get_points()
|
||||
for point in entity.vertices(): # (x, y, start_width, end_width, bulge)
|
||||
x, y, *_ = point # wir interessieren uns nur für x und y
|
||||
ret[rack_key].append([round(x, 1), round(y, 1)])
|
||||
|
||||
rack_counter += 1
|
||||
|
||||
return ret
|
||||
|
||||
def scan(dxf_source:ezdxf.document.Drawing):
|
||||
@@ -282,6 +400,10 @@ def check_existance(res_mappings, res_dist, res_pos):
|
||||
|
||||
return ret
|
||||
|
||||
def dxf_is_binary(dxf_path):
|
||||
with open(dxf_path, 'rb') as f:
|
||||
header = f.read(22)
|
||||
return b'AutoCAD Binary DXF' in header
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
@@ -293,7 +415,6 @@ if __name__ == '__main__':
|
||||
parser.add_argument('-c', '--console', action='store_true', help='print results to output')
|
||||
parser.add_argument('-n', '--scan', action='store_true', help='print all layer of racs, distributes and equiment not empty')
|
||||
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
out_dir = os.environ.get('PROJECT_DATA')
|
||||
@@ -303,19 +424,22 @@ if __name__ == '__main__':
|
||||
filename = args.filename
|
||||
(dxf_path, dexists) = check_file_in_work(work_dir, filename)
|
||||
|
||||
zeitanfang = time.time()
|
||||
|
||||
if dxf_is_binary(dxf_path): # Wenn dxf eine binary ist, dann komplett parsen und modelspace anlegen
|
||||
doc = get_dxf_file(dxf_path)
|
||||
msp = doc.modelspace()
|
||||
use_iter = False
|
||||
else:
|
||||
use_iter = True
|
||||
|
||||
doc = get_dxf_file(dxf_path) # type: ignore
|
||||
msp = doc.modelspace()
|
||||
|
||||
if args.scan:
|
||||
res = scan(doc)
|
||||
print(to_json(res))
|
||||
sys.exit()
|
||||
|
||||
|
||||
res_pos = dict()
|
||||
res_dist = dict()
|
||||
res_rac = dict()
|
||||
res_mappings = dict()
|
||||
|
||||
if args.sensors or args.dists or args.rack:
|
||||
|
||||
config = configparser.ConfigParser(allow_no_value=True, delimiters=("="))
|
||||
@@ -324,37 +448,66 @@ if __name__ == '__main__':
|
||||
config.read(os.path.join(config_dir, "allgemein.cfg"))
|
||||
|
||||
output_results = dict()
|
||||
|
||||
if args.sensors:
|
||||
res_pos = get_input_positions(msp)
|
||||
# Sensoren auslesen
|
||||
if use_iter:
|
||||
res_pos = get_input_positions_iter(dxf_path)
|
||||
else:
|
||||
res_pos = get_input_positions(msp)
|
||||
|
||||
output_results['sensors'] = res_pos
|
||||
|
||||
if args.console:
|
||||
print(to_json(res_pos))
|
||||
|
||||
# Mapping zu Sensoren auslesen
|
||||
(res_mappings, warnings) = create_mappings(res_pos)
|
||||
output_results['mappings'] = res_mappings
|
||||
if args.console:
|
||||
print(to_json(res_mappings))
|
||||
|
||||
res_dist = get_subdistributor_positions(msp, res_mappings)
|
||||
# Distributoren auslesen
|
||||
if use_iter:
|
||||
res_dist = get_subdistributor_positions_iter(dxf_path, res_mappings)
|
||||
else:
|
||||
res_dist = get_subdistributor_positions(msp, res_mappings)
|
||||
|
||||
output_results['distributors'] = res_dist
|
||||
|
||||
if args.console:
|
||||
print(to_json(res_dist))
|
||||
|
||||
res_tunnel = get_tunnel_positions(msp)
|
||||
# Tunnel auslesen
|
||||
if use_iter:
|
||||
res_tunnel = get_tunnel_positions_iter(dxf_path)
|
||||
else:
|
||||
res_tunnel = get_tunnel_positions(msp)
|
||||
|
||||
output_results['tunnels'] = res_tunnel
|
||||
|
||||
if args.console:
|
||||
print(to_json(res_tunnel))
|
||||
|
||||
if args.rack:
|
||||
res_rac = get_rack_positions(msp)
|
||||
if use_iter:
|
||||
res_rac = get_rack_positions_iter(dxf_path)
|
||||
else:
|
||||
res_rac = get_rack_positions(msp)
|
||||
|
||||
output_results['racks'] = res_rac
|
||||
|
||||
if args.console:
|
||||
print(to_json(res_rac))
|
||||
|
||||
|
||||
if args.write:
|
||||
basename = os.path.splitext(args.write)[0]
|
||||
res_not_found = check_existance(res_mappings, res_dist, res_pos)
|
||||
output_results["not_found"] = res_not_found
|
||||
write_results(to_json(output_results), work_dir, f"{basename}.json")
|
||||
zeitende = time.time()
|
||||
print(zeitende-zeitanfang)
|
||||
|
||||
else:
|
||||
parser.print_help()
|
||||
|
||||
Reference in New Issue
Block a user