Koordinaten der Unterverteiler, Sensoren und Kabelpritsche aus .dxf Datei festgestellt. Bisher Ausgabe nur in Konsole.

This commit is contained in:
2025-04-29 18:34:05 +02:00
parent 6ad0478020
commit 73fa459dda
6 changed files with 203 additions and 61 deletions
+18 -3
View File
@@ -21,7 +21,22 @@
"justMyCode": true "justMyCode": true
}, },
{ {
"name": "use filename and default", "name": "use easy.dwg",
"type": "debugpy",
"request": "launch",
"program": "${file}",
"console": "integratedTerminal",
"justMyCode": true,
"args": [
"--filename",
"easy.dxf",
"-s",
"-d",
"-r"
],
},
{
"name": "use Steuerungstestlayout",
"type": "debugpy", "type": "debugpy",
"request": "launch", "request": "launch",
"program": "${file}", "program": "${file}",
@@ -30,8 +45,8 @@
"args": [ "args": [
"--filename", "--filename",
"ST_6300_Steuerungstestlayout1_neueBloecke.dxf", "ST_6300_Steuerungstestlayout1_neueBloecke.dxf",
"-i", "-s",
"-o", "-d",
"-r" "-r"
], ],
} }
+6
View File
@@ -0,0 +1,6 @@
{
"python.languageServer": "Pylance",
"cSpell.words": [
"ezdxf"
]
}
+1 -1
View File
@@ -1,4 +1,4 @@
@echo off @echo off
CALL manage_interpreter.bat activate_interpreter CALL manage_interpreter.bat activate_interpreter
python %PROJECT_LIB%\getpositions.py python %PROJECT_LIB%\getpositions.py %*
CALL manage_interpreter.bat deactivate_interpreter CALL manage_interpreter.bat deactivate_interpreter
+106 -56
View File
@@ -1,9 +1,14 @@
import argparse import argparse
import configparser import configparser
import ezdxf #import ezdxf
import ezdxf.document
from ezdxf.math import Matrix44 from ezdxf.math import Matrix44
import os import os
import sys import sys
import math
import json
import re
""" """
Dieses Programm: Dieses Programm:
@@ -49,53 +54,71 @@ def get_world_position_of_attribute(insert, attrib):
# Transformation aufbauen: Skalierung -> Rotation -> Translation # Transformation aufbauen: Skalierung -> Rotation -> Translation
m = ( m = (
Matrix44.scale(xscale, yscale, 1) @ Matrix44.scale(xscale, yscale, 1) @
Matrix44.z_rotate(rotation_deg * 3.141592653589793 / 180) @ Matrix44.z_rotate(rotation_deg * math.pi / 180) @
Matrix44.translate(block_pos.x, block_pos.y, block_pos.z) Matrix44.translate(block_pos.x, block_pos.y, block_pos.z)
) )
# Lokale Position transformieren # Lokale Position transformieren
return m.transform(local_pos) return m.transform(local_pos)
def get_input_positions(doc): 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 """hole alle Positionen der Eingänge
""" """
msp = doc.modelspace() allIds = dict()
SpecialKeys = ["MB", # Separator
"MA", # Motor
"BG", # Stausensor
"FC" # Motorschutzschalter
]
# Über alle Blockreferenzen (INSERT) im Modelspace laufen # Über alle Blockreferenzen (INSERT) im Modelspace laufen
for insert in msp.query('INSERT'): for insert in msp.query('INSERT'):
if len(insert.attribs) == 0: if len(insert.attribs) == 0:
continue # Überspringe Blöcke ohne Attribute continue # Überspringe Blöcke ohne Attribute
id = ""
ld = dict()
for attrib in insert.attribs: for attrib in insert.attribs:
# Position des Blocks ist attrib.dxf.insert if len(insert.attribs) == 0:
print(f"Attribut Name: {attrib.dxf.tag}, Wert: {attrib.dxf.text}") 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": if attrib.dxf.tag == "REALE_POSITION" and attrib.dxf.text == "x":
print(f"-- coord --: {attrib.dxf.insert}") #print(f"-- coord real --: {attrib.dxf.insert}")
if attrib.dxf.tag == "B" and "MB" in attrib.dxf.text:
print(f"-- coord --: {attrib.dxf.insert}")
if attrib.dxf.tag == "B" and "BG" in attrib.dxf.text:
print(f"-- coord --: {attrib.dxf.insert}")
# attrib.layer
world_pos = get_world_position_of_attribute(insert, attrib) 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
# # Attribute abrufen (als Liste von ATTRIB-Objekten) if not id == "":
# attribs = {attrib.dxf.tag: attrib.dxf.text for attrib in insert.attribs} if not id in allIds:
allIds[id] = ld
# # Hier z.B. filtern: Blocke, die ein "NAME"-Attribut haben else:
# if "NAME" in attribs: allIds[id] = merge_two_dicts(allIds[id], ld)
# print(f"Blockname: {insert.dxf.name}") return allIds
# print(f"NAME-Attribut: {attribs['NAME']}")
# # Zugriff auf weitere Attribute
# # z.B. "ID", "TYP" usw.
# if "ID" in attribs:
# print(f"ID: {attribs['ID']}")
# msp = doc.modelspace() def get_subdistributor_positions(msp):
"""hole alle Positionen der Unterverteiler
"""
# # Über alle Texte laufen # # Über alle Texte laufen
# for text in msp.query('TEXT'): # for text in msp.query('MTEXT'):
# print(f"Inhalt: {text.dxf.text}") # print(f"Inhalt: {text.dxf.text}")
# print(f"Layer: {text.dxf.layer}") # print(f"Layer: {text.dxf.layer}")
# print(f"Einfügepunkt: {text.dxf.insert}") # print(f"Einfügepunkt: {text.dxf.insert}")
# print(f"Breite: {text.dxf.width}")
# # print("Farbe:", text.dxf.color) # Achtung: 256 = "ByLayer" # # print("Farbe:", text.dxf.color) # Achtung: 256 = "ByLayer"
# # print("Höhe (height):", text.dxf.height) # # print("Höhe (height):", text.dxf.height)
# # print("Rotation (degrees):", text.dxf.rotation) # # print("Rotation (degrees):", text.dxf.rotation)
@@ -104,37 +127,53 @@ def get_input_positions(doc):
# # print("Handle:", text.dxf.handle) # # print("Handle:", text.dxf.handle)
# print("---") # print("---")
ret = dict()
# Alle Texte auf Layer "xy"
def get_output_positions(doc): for text in msp.query('TEXT[layer=="Busverteiler-Kennzeichnung"]'):
"""hole alle Positionen der Ausgänge print(f"Text auf Layer 'Busverteiler-Kennzeichnung': {text.dxf.text}")
""" match = re.search(r"UC\w+", text.dxf.text)
pass if match:
nameUC = match.group(0)
ret[nameUC] = text.dxf.insert
return ret
# helper function # helper function
def print_entity(e): def print_line(e):
print("LINE on layer: %s\n" % e.dxf.layer) print("LINE on layer: %s\n" % e.dxf.layer)
print("points: %s\n" % repr(e.dxf.points())) print("points: %s\n" % repr(e.dxf))
#print("y point: %s\n" % e.dxf.y)
def get_rack_positions(doc): 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 """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 # iterate over all entities in modelspace
msp = doc.modelspace()
# for e in msp: # for e in msp:
# if e.dxftype() == "LINE":
# print_line(e)
# if e.dxftype() == "LWPOLYLINE": # if e.dxftype() == "LWPOLYLINE":
# print_entity(e) # print_polyline(e)
return ret
# # entity query for all LINE entities in modelspace
# for e in msp.query("LWPOLYLINE"):
# print_entity(e)
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): def get_dxf_file(filepath):
"""hole das dxf file """hole das dxf file
@@ -152,9 +191,10 @@ def get_dxf_file(filepath):
if __name__ == '__main__': if __name__ == '__main__':
parser = argparse.ArgumentParser(description='fetches the x/y positions from a dxf file', prog='getpositions') 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('-f', '--filename', action='store', required=True, default="ST_6300_Steuerungstestlayout1_neueBloecke.dwg", help='which file should be fetched', metavar='myfile.dwg')
parser.add_argument('-i', '--input', action='store_true', help='fetch all position of inputs') parser.add_argument('-s', '--sensors', action='store_true', help='fetch all position of sensors, motors, actors')
parser.add_argument('-o', '--output', action='store_true', help='fetch all positions of outputs') 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('-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() args = parser.parse_args()
@@ -162,15 +202,25 @@ if __name__ == '__main__':
work_dir = os.environ.get('PROJECT_WORK') work_dir = os.environ.get('PROJECT_WORK')
filename = args.filename filename = args.filename
doc = get_dxf_file(os.path.join(work_dir, filename)) doc = get_dxf_file(os.path.join(work_dir, filename)) # type: ignore
msp = doc.modelspace()
res = dict() res_pos = dict()
if args.input: res_dist = dict()
res = get_input_positions(doc) res_rac = dict()
if args.output: if args.sensors or args.dists or args.rack:
get_output_positions(doc) if args.sensors:
if args.rack: res_pos = get_input_positions(msp)
get_rack_positions(doc) 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: else:
parser.print_help() parser.print_help()
+66
View File
@@ -0,0 +1,66 @@
from dataclasses import dataclass, asdict, fields
from dacite import from_dict
from typing import List
import json
@dataclass
class Sensor:
id: str
x: float
y: float
@dataclass
class Aktor:
id: str
x: float
y: float
@dataclass
class Pritsche:
id: str
x: float
y: float
@dataclass
class Anlage:
name: str
sensoren: List[Sensor]
aktoren: List[Aktor]
kabelpritschen: List[Pritsche]
def to_json(self, pretty: bool = True) -> str:
d = self.to_dict()
return json.dumps(d, indent=2 if pretty else None, default=str)
def to_dict(self) -> dict:
"""Konvertiert das Objekt in ein dict datetime wird als ISO-String dargestellt."""
result = asdict(self)
# hier um irgendwas ergänzen
# result["startdatum"] = self.startdatum.isoformat()
return result
if __name__ == '__main__':
json_string = '''{
"name": "H&M",
"sensoren": [
{"id": "AP4321", "x": 14, "y": 50},
{"id": "AP4322", "x": 22, "y": 100}
],
"aktoren": [
{"id": "AP4321", "x": 14, "y": 50},
{"id": "AP4322", "x": 22, "y": 100}
],
"kabelpritschen": [
{"id": "p1", "x": 1, "y": 0},
{"id": "p2", "x": 22, "y": 10}
]
}
'''
data = json.loads(json_string)
anlage = from_dict(
data_class=Anlage,
data=data
)
print(anlage)
+5
View File
@@ -0,0 +1,5 @@
{
"typeCheckingMode": "basic",
"reportMissingTypeStubs": true,
"useLibraryCodeForTypes": true
}