mehrere oft verwendete Routinen in eigene utils.py eingebaut

This commit is contained in:
2026-01-23 10:23:18 +01:00
parent 37208f61b1
commit 3deebb81f3
9 changed files with 453 additions and 175 deletions
+34 -6
View File
@@ -123,35 +123,35 @@
] ]
}, },
{ {
"name": "getpositions with ST500592_Omniflo.dxf", "name": "getpositions with PR500592_10_5.13_POT_20251216.dxf",
"type": "debugpy", "type": "debugpy",
"request": "launch", "request": "launch",
"program": "${file}", "program": "${file}",
"console": "integratedTerminal", "console": "integratedTerminal",
"args": [ "args": [
"--filename", "--filename",
"ST500592_Omniflo.dxf", "PR500592_10_5.13_POT_20251216.dxf",
"--sensors", "--sensors",
"--rack", "--rack",
"--console", "--console",
"--write", "--write",
"ST500592_Omniflo_positions.json" "PR500592_10_5.13_POT_20251216_positions.json"
] ]
}, },
{ {
"name": "getpositions with ST500592_10_5-11_ILS.dxf", "name": "getpositions with POT_ST1_ST6_12.dxf",
"type": "debugpy", "type": "debugpy",
"request": "launch", "request": "launch",
"program": "${file}", "program": "${file}",
"console": "integratedTerminal", "console": "integratedTerminal",
"args": [ "args": [
"--filename", "--filename",
"ST500592_10_5-11_ILS.dxf", "POT_ST1_ST6_12.dxf",
"--sensors", "--sensors",
"--rack", "--rack",
"--console", "--console",
"--write", "--write",
"ST500592_10_5-11_ILS_positions.json" "POT_ST1_ST6_12_positions.json"
] ]
}, },
{ {
@@ -289,6 +289,21 @@
"ST-Fortna_ASCII_cables.dxf" "ST-Fortna_ASCII_cables.dxf"
] ]
}, },
{
"name": "draw cables for test.json",
"type": "debugpy",
"request": "launch",
"program": "${file}",
"console": "integratedTerminal",
"args": [
"--filename",
"test_todraw.json",
"-n",
"test_cables.dxf",
"-x",
"test_cables.xlsx"
]
},
{ {
"name": "routing for easy_positions.json", "name": "routing for easy_positions.json",
"type": "debugpy", "type": "debugpy",
@@ -316,6 +331,19 @@
"-g" "-g"
] ]
}, },
{
"name": "routing for test_positionsdraw.json",
"type": "debugpy",
"request": "launch",
"program": "${file}",
"console": "integratedTerminal",
"args": [
"--filename",
"test_positionsdraw.json",
"-w",
"test_draw.json",
]
},
{ {
"name": "run_tests.py with easy_3tunnels.dxf", "name": "run_tests.py with easy_3tunnels.dxf",
"type": "debugpy", "type": "debugpy",
+13 -27
View File
@@ -12,12 +12,12 @@ REM echo Dateiname ohne Erweiterung: %FILENAME%
REM echo Erweiterung: %EXT% REM echo Erweiterung: %EXT%
REM echo Verzeichnis: %DIR% REM echo Verzeichnis: %DIR%
REM REM
REM Namen der Zwischenergebnis Dateien REM Namen der auf dem RENAMER Layer gefundenen Symbole, die überschrieben werden sollen
set JSON_POS=%FILENAME%_positionsconv.json set JSON_SYMBOLS=%FILENAME%_symbols.json
set JSON_TODRAW=%FILENAME%_todraw.json
REM Namen der Ergebnisdateien REM Fehlerdatei
set ERROR_DOUBLE=%FILENAME%_errors.json set ERROR_FILE=%FILENAME%_errors.json
set RESULT_TIA=%FILENAME%-*_TIA.xlsx
if exist "%~dp0_setenv.bat" ( if exist "%~dp0_setenv.bat" (
echo Lade lokale Umgebungseinstellungen aus _setenv.bat... echo Lade lokale Umgebungseinstellungen aus _setenv.bat...
@@ -27,31 +27,17 @@ REM Zielverzeichnis
set TARGET_DIR=%PROJECT_IO_RESULTS%\%FILENAME% set TARGET_DIR=%PROJECT_IO_RESULTS%\%FILENAME%
mkdir "%TARGET_DIR%" mkdir "%TARGET_DIR%"
REM lösche alte Fehlermeldungen REM lösche alte Fehlermeldungen
del "%PROJECT_WORK%\%ERROR_DOUBLE%" del "%PROJECT_WORK%\%ERROR_FILE%"
echo. echo === Creating enriched dxf file ===
echo === Fetching Positions === call create_numbers.bat --filename %1 --errorfile %PROJECT_WORK%\%ERROR_FILE% --write %PROJECT_WORK%\%JSON_SYMBOLS%
call getpositions.bat --filename %1 -s -r -w %JSON_POS% -e %ERROR_DOUBLE% if exist "%PROJECT_WORK%\%ERROR_FILE%" (
if exist "%PROJECT_WORK%\%ERROR_DOUBLE%" ( @echo -failed- errors found during processing!
@echo == failed: errors, e.g. duplicate IDs in given layout
pause
move %PROJECT_WORK%\%ERROR_DOUBLE% %TARGET_DIR%
move %PROJECT_WORK%\%JSON_TODRAW% %TARGET_DIR%
goto :eof
)
if not exist "%PROJECT_WORK%\%JSON_POS%" (
@echo == failed: getpositions
pause
goto :eof
)
echo === Creating Excel Files for TIA, WSCAD, .. ===
call portalexport.bat --filename %JSON_POS% --outname %FILENAME%
if not exist "%PROJECT_WORK%\%RESULT_TIA%" (
@echo == failed: creating .xlsx files
pause pause
move %PROJECT_WORK%\%ERROR_FILE% %TARGET_DIR%
move %PROJECT_WORK%\%JSON_SYMBOLS% %TARGET_DIR%
goto :eof goto :eof
) )
echo move %PROJECT_WORK%\%FILENAME%-* %TARGET_DIR% echo move %PROJECT_WORK%\%FILENAME%-* %TARGET_DIR%
+387 -30
View File
@@ -8,10 +8,10 @@ from pathlib import Path
import ezdxf import ezdxf
from ezdxf.addons import iterdxf from ezdxf.addons import iterdxf
from shapely.geometry import Point
from ezdxf.lldxf.const import DXFStructureError from ezdxf.lldxf.const import DXFStructureError
from error_collector import ErrorCollector, write_json_file from error_collector import ErrorCollector, write_json_file
from utils import check_environment_var, check_file_in_work, dxf_is_binary, get_dxf_file
""" """
@@ -56,29 +56,320 @@ Alle Sensoren, Motoren, Aktoren etc. innerhalb der zugehörigen Polylinie nehmen
""" """
def check_file_in_work(work_dir: Path, filename: Path) -> tuple[Path, bool]: def read_config_layers(config_path: Path) -> list:
fexists = True """
if not filename.exists(): Liest die enumerate.cfg und gibt die Layer zurück, auf denen nach Renamer-Blöcken gesucht werden soll.
mypath = work_dir.joinpath(filename) Die Konfiguration hat eine einfache Liste unter [Layers]:
ex = mypath.exists() [Layers]
if not mypath.exists(): RENAMER
fexists = False OTHER_LAYER
else: """
mypath = filename layers = []
return mypath, fexists
def check_environment_var(env_str: str) -> Path: with open(config_path, 'r', encoding='utf-8') as f:
out_path = os.environ.get(env_str) in_layers_section = False
if out_path: for line in f:
return Path(out_path) line = line.strip()
# Überspringe leere Zeilen und Kommentare
if not line or line.startswith('#') or line.startswith(';'):
continue
# Prüfe ob wir in der [Layers] Sektion sind
if line.startswith('['):
in_layers_section = line.lower() == '[layers]'
continue
# Wenn in [Layers], füge Layer hinzu
if in_layers_section:
layers.append(line)
return layers
def extract_block_attributes(insert) -> dict:
"""
Extrahiert alle Attribute aus einem INSERT-Block.
"""
attributes = {}
if insert.dxftype() != 'INSERT':
return attributes
if insert.has_attrib:
for attrib in insert.attribs:
tag = attrib.dxf.tag
value = attrib.dxf.text
attributes[tag] = value
return attributes
def get_boundary_geometry(doc, insert):
"""
Sucht im Block nach einem Rechteck oder einer geschlossenen Polylinie.
Gibt die Eckpunkte zurück.
"""
block_layout = doc.blocks.get(insert.dxf.name)
# Suche nach LWPOLYLINE, POLYLINE oder geschlossenen Linien
for entity in block_layout:
if entity.dxftype() == 'LWPOLYLINE':
# Get points and transform them
points = list(entity.get_points())
# Prüfe ob geschlossen (entweder Flag gesetzt oder erster == letzter Punkt)
is_closed = entity.closed or (entity.dxf.flags & 1)
if not is_closed and len(points) > 1:
# Prüfe ob erster und letzter Punkt gleich sind
first = points[0][:2]
last = points[-1][:2]
if abs(first[0] - last[0]) < 0.001 and abs(first[1] - last[1]) < 0.001:
is_closed = True
if is_closed:
# Transform points relative to insert position
insert_point = insert.dxf.insert
transformed_points = []
for p in points:
# Einfache Translation (ohne Rotation/Skalierung für ersten Ansatz)
transformed_points.append((
insert_point[0] + p[0],
insert_point[1] + p[1]
))
return transformed_points
elif entity.dxftype() == 'POLYLINE':
if entity.is_closed:
points = [(v.dxf.location.x, v.dxf.location.y) for v in entity.vertices]
insert_point = insert.dxf.insert
transformed_points = []
for p in points:
transformed_points.append((
insert_point[0] + p[0],
insert_point[1] + p[1]
))
return transformed_points
return None
def point_in_polygon(point, polygon):
"""
Prüft, ob ein Punkt innerhalb eines Polygons liegt (Ray-casting Algorithmus).
"""
x, y = point
n = len(polygon)
inside = False
p1x, p1y = polygon[0]
for i in range(1, n + 1):
p2x, p2y = polygon[i % n]
if y > min(p1y, p2y):
if y <= max(p1y, p2y):
if x <= max(p1x, p2x):
if p1y != p2y:
xinters = (y - p1y) * (p2x - p1x) / (p2y - p1y) + p1x
if p1x == p2x or x <= xinters:
inside = not inside
p1x, p1y = p2x, p2y
return inside
def find_symbols_in_boundary(doc, msp, boundary, target_layers, attributes):
"""
Findet alle Symbole (INSERT-Blöcke) innerhalb des angegebenen Bereichs auf den Ziel-Layern.
"""
symbols = []
# Bestimme welche Layer durchsucht werden sollen
search_layers = []
for i in range(1, 4): # NAME1, NAME2, NAME3
layer_key = f"LAYER_NAME{i}"
if layer_key in attributes and attributes[layer_key]:
search_layers.append(attributes[layer_key])
# Falls nur NAME/LAYER_NAME vorhanden
if "LAYER_NAME" in attributes and attributes["LAYER_NAME"]:
search_layers.append(attributes["LAYER_NAME"])
# Durchsuche alle INSERT-Blöcke
for entity in msp.query('INSERT'):
if entity.dxf.layer not in search_layers:
continue
# Prüfe ob der Block Attribute hat
if not entity.has_attrib:
continue
# Hole Position des Symbols
pos = entity.dxf.insert
point = (pos[0], pos[1])
# Prüfe ob innerhalb des Bereichs
if point_in_polygon(point, boundary):
# Extrahiere Attribute des Symbols
symbol_attribs = extract_block_attributes(entity)
# Prüfe ob es ein Template ist (enthält @)
has_template = False
for value in symbol_attribs.values():
if '@' in str(value):
has_template = True
break
if has_template:
symbols.append({
'entity': entity,
'position': point,
'attributes': symbol_attribs,
'layer': entity.dxf.layer
})
return symbols
def sort_symbols_by_direction(symbols, direction):
"""
Sortiert die Symbole nach der angegebenen Richtung.
TOP_BOTTOM: nach Y absteigend, dann X
BOTTOM_TOP: nach Y aufsteigend, dann X
LEFT_RIGHT: nach X aufsteigend, dann Y
RIGHT_LEFT: nach X absteigend, dann Y
"""
if direction == "TOP_BOTTOM":
return sorted(symbols, key=lambda s: (-s['position'][1], s['position'][0]))
elif direction == "BOTTOM_TOP":
return sorted(symbols, key=lambda s: (s['position'][1], s['position'][0]))
elif direction == "LEFT_RIGHT":
return sorted(symbols, key=lambda s: (s['position'][0], s['position'][1]))
elif direction == "RIGHT_LEFT":
return sorted(symbols, key=lambda s: (-s['position'][0], s['position'][1]))
else: else:
print(f"Umgebungsvariable {env_str} ist nicht gesetzt oder leer.") # Fallback: LEFT_RIGHT
exit() return sorted(symbols, key=lambda s: (s['position'][0], s['position'][1]))
def enumerate_symbols(symbols, attributes):
"""
Nummeriert die Symbole durch und ersetzt die @@ Platzhalter.
"""
counter = 1
renamed = []
for symbol in symbols:
symbol_attribs = symbol['attributes']
layer = symbol['layer']
# Finde das passende NAME-Template für diesen Layer
name_template = None
for i in range(1, 4):
layer_key = f"LAYER_NAME{i}"
name_key = f"NAME{i}"
if layer_key in attributes and attributes[layer_key] == layer:
if name_key in attributes:
name_template = attributes[name_key]
break
# Falls nur NAME/LAYER_NAME vorhanden
if not name_template and "LAYER_NAME" in attributes and attributes["LAYER_NAME"] == layer:
if "NAME" in attributes:
name_template = attributes["NAME"]
if not name_template:
continue
# Ersetze @-Zeichen durch Zahlen
# Zähle wie viele @ im Template sind
at_count = name_template.count('@')
number_str = str(counter).zfill(at_count)
new_name = name_template.replace('@' * at_count, number_str)
# Aktualisiere Attribute im Symbol
for attrib in symbol['entity'].attribs:
old_value = attrib.dxf.text
if '@' in old_value:
# Ersetze @ durch die Nummer
new_value = old_value.replace('@' * at_count, number_str)
attrib.dxf.text = new_value
renamed.append({
'position': symbol['position'],
'layer': layer,
'old_value': old_value,
'new_value': new_value
})
counter += 1
return renamed
def process_renamer_blocks(doc, msp, renamer_layers, error_collector):
"""
Verarbeitet alle Renamer-Blöcke auf den angegebenen Layern.
"""
all_renamed = []
for layer in renamer_layers:
print(f"Durchsuche Layer: {layer}")
# Finde alle INSERT-Blöcke auf diesem Layer
for insert in msp.query(f'INSERT[layer=="{layer}"]'):
# Extrahiere Attribute
attributes = extract_block_attributes(insert)
if not attributes:
print(f" Block ohne Attribute gefunden an Position {insert.dxf.insert}")
continue
# Prüfe ob es ein Renamer-Block ist
has_name = "NAME" in attributes or "NAME1" in attributes
has_direction = "DIRECTION" in attributes
if not (has_name and has_direction):
continue
print(f" Renamer-Block gefunden: {attributes.get('NAME', attributes.get('NAME1', 'UNKNOWN'))}")
print(f" Direction: {attributes.get('DIRECTION', 'UNKNOWN')}")
print(f" Kennzeichnung: {attributes.get('KENNZEICHNUNG', 'N/A')}")
# Finde Boundary (Rechteck oder Polylinie)
boundary = get_boundary_geometry(doc, insert)
if not boundary:
error_msg = f"Keine Polylinie/Rechteck im Renamer-Block an Position {insert.dxf.insert} gefunden"
print(f" WARNUNG: {error_msg}")
error_collector.add_warnings({"missing_boundary": error_msg})
continue
print(f" Boundary gefunden mit {len(boundary)} Punkten")
# Finde Symbole innerhalb des Bereichs
symbols = find_symbols_in_boundary(doc, msp, boundary, renamer_layers, attributes)
print(f" {len(symbols)} Template-Symbole gefunden")
if not symbols:
continue
# Sortiere nach Richtung
direction = attributes.get("DIRECTION", "LEFT_RIGHT")
sorted_symbols = sort_symbols_by_direction(symbols, direction)
# Nummeriere durch
renamed = enumerate_symbols(sorted_symbols, attributes)
all_renamed.extend(renamed)
print(f" {len(renamed)} Symbole nummeriert")
return all_renamed
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='Nummeriert Symbole in DXF-Dateien basierend auf Renamer-Blöcken', prog='create_numbers')
parser.add_argument('-f', '--filename', action='store', required=True, default="ST_6300_Steuerungstestlayout1_neueBloecke.dwg", help='which file should be fetched', metavar='myfile.dxf') parser.add_argument('-f', '--filename', action='store', required=True, help='DXF-Datei die verarbeitet werden soll', metavar='myfile.dxf')
parser.add_argument('-w', '--write', action='store', help='write results into a json file') parser.add_argument('-e', '--errorfile', action='store', required=False, help='JSON-Datei für Fehler und Warnungen', metavar='errors.json')
parser.add_argument('-w', '--write', action='store', help='Schreibe Ergebnisse der Nummerierung in eine JSON-Datei')
parser.add_argument('-d', '--dryrun', action='store_true', help='Symbole nicht in der DXF-Datei überschreiben, nur Ausgabe auf Konsole')
args = parser.parse_args() args = parser.parse_args()
@@ -86,26 +377,92 @@ if __name__ == '__main__':
work_dir = check_environment_var('PROJECT_WORK') work_dir = check_environment_var('PROJECT_WORK')
config_dir = check_environment_var("PROJECT_CFG") config_dir = check_environment_var("PROJECT_CFG")
# Initialisiere ErrorCollector
error_collector = ErrorCollector()
filename = Path(args.filename) filename = Path(args.filename)
if not filename.suffix == ".dxf": if not filename.suffix == ".dxf":
print("only available for .dxf files") print("Nur für .dxf Dateien verfügbar")
exit() exit(1)
(dxf_path, dexists) = check_file_in_work(work_dir, filename) (dxf_path, dexists) = check_file_in_work(work_dir, filename)
if dexists == False: if dexists == False:
print("no such file ") print(f"Datei nicht gefunden: {filename}")
parser.print_help() parser.print_help()
exit() exit(1)
if dxf_is_binary(dxf_path): # Wenn dxf eine binary ist, dann komplett parsen und modelspace anlegen # Lese Konfiguration
print("Given .dxf-file is binary dxf. Proceeding to read file. Watch RAM-usage.") config_path = Path(config_dir) / "enumerate.cfg"
if not config_path.exists():
print(f"Konfigurationsdatei nicht gefunden: {config_path}")
exit(1)
renamer_layers = read_config_layers(config_path)
print(f"Konfigurierte Layer: {renamer_layers}")
if not renamer_layers:
print("Keine Layer in der Konfiguration gefunden")
exit(1)
# Lese DXF-Datei
if dxf_is_binary(dxf_path):
print("DXF-Datei ist binär. Lese komplette Datei. Achten Sie auf RAM-Nutzung.")
doc = get_dxf_file(dxf_path) doc = get_dxf_file(dxf_path)
msp = doc.modelspace() msp = doc.modelspace()
use_iter = False
else: else:
print("Given .dxf-file is ASCII-dxf. Proceeding to use iterative functions. Process may take longer.") print("DXF-Datei ist ASCII.")
use_iter = True doc = get_dxf_file(dxf_path)
msp = doc.modelspace()
# Verarbeite Renamer-Blöcke
print("\n" + "="*60)
print("Starte Verarbeitung der Renamer-Blöcke")
print("="*60 + "\n")
renamed_symbols = process_renamer_blocks(doc, msp, renamer_layers, error_collector)
print("\n" + "="*60)
print(f"Verarbeitung abgeschlossen: {len(renamed_symbols)} Symbole nummeriert")
print("="*60 + "\n")
# Ausgabe der Ergebnisse
if renamed_symbols:
print("Nummerierte Symbole:")
for item in renamed_symbols:
print(f" {item['old_value']} -> {item['new_value']} (Layer: {item['layer']}, Pos: {item['position']})")
# Speichere DXF-Datei wenn nicht dry-run
if not args.dryrun:
output_path = dxf_path.parent / f"{dxf_path.stem}_numbered{dxf_path.suffix}"
doc.saveas(output_path)
print(f"\nNummerierte DXF-Datei gespeichert: {output_path}")
else: else:
parser.print_help() print("\nDry-run Modus: DXF-Datei wurde nicht überschrieben")
# Schreibe JSON-Ausgabe wenn gewünscht
if args.write:
output_data = {
'renamed_symbols': renamed_symbols,
'total_count': len(renamed_symbols)
}
output_path = Path(args.write)
write_json_file(output_data, output_path.parent, output_path.name)
print(f"Ergebnisse in JSON gespeichert: {args.write}")
# Schreibe Fehler-Datei
if args.errorfile:
error_data = error_collector.get_all_issues()
error_path = Path(args.errorfile)
write_json_file(error_data, error_path.parent, error_path.name)
print(f"Fehler/Warnungen gespeichert: {args.errorfile}")
# Exit-Code basierend auf Fehlern
if error_collector.has_errors():
print("\n!!! Es sind Fehler aufgetreten !!!")
exit(1)
elif error_collector.has_errors_or_warnings():
print("\n(Warnungen vorhanden, aber keine kritischen Fehler)")
exit(0)
else:
print("\nKeine Fehler oder Warnungen")
exit(0)
+1 -10
View File
@@ -14,6 +14,7 @@ import updateconfignames as uc
from pathlib import Path from pathlib import Path
from error_collector import ErrorCollector, write_json_file from error_collector import ErrorCollector, write_json_file
from utils import check_file_in_work
@dataclass @dataclass
@@ -794,16 +795,6 @@ def _create_bom_workbook(outpath, processed_data, bezeichner_cfg):
wb.save(bom_path) wb.save(bom_path)
print(f"BOM exported to Excel-file") print(f"BOM exported to Excel-file")
def check_file_in_work(work_dir, filename):
fexists = True
if not os.path.exists(filename):
mypath = os.path.join(work_dir, filename)
if not os.path.exists(mypath):
fexists = False
else:
mypath = filename
return (mypath, fexists)
def copy_layers_into_dxf_by_filter(dxf_source: ezdxf.document.Drawing, dxf_target:ezdxf.document.Drawing): def copy_layers_into_dxf_by_filter(dxf_source: ezdxf.document.Drawing, dxf_target:ezdxf.document.Drawing):
""" """
Kopiert bestimmte Layer (nach Filter) von einer Quell-DXF in eine Ziel-DXF. Kopiert bestimmte Layer (nach Filter) von einer Quell-DXF in eine Ziel-DXF.
+9 -56
View File
@@ -12,6 +12,15 @@ from shapely.geometry import Point
from ezdxf.lldxf.const import DXFStructureError from ezdxf.lldxf.const import DXFStructureError
from error_collector import ErrorCollector, write_json_file from error_collector import ErrorCollector, write_json_file
from utils import (
check_environment_var,
check_file_in_work,
dxf_is_binary,
get_dxf_file,
merge_two_dicts,
to_json,
write_results,
)
""" """
@@ -24,21 +33,6 @@ Dieses Programm:
""" """
def write_results(jsn_results: str, out_dir: Path, filename: str) -> None:
"""Write results to a JSON file."""
print("writing results to a json file ...")
outfile = os.path.join(out_dir, filename)
with open(outfile, 'w', encoding='utf-8') as fh:
fh.write(jsn_results)
print("done")
def merge_two_dicts(x: dict, y: dict) -> dict:
z = x.copy()
z.update(y)
return z
def get_type_of_name_cfg(name: str) -> str: def get_type_of_name_cfg(name: str) -> str:
prefix = name[:2] prefix = name[:2]
@@ -734,34 +728,6 @@ def scan(dxf_source) -> dict:
ret['all_blocks'] = alle_block_defs ret['all_blocks'] = alle_block_defs
return ret return ret
def to_json(d: object, pretty: bool = True) -> str:
return json.dumps(d, indent=2 if pretty else None, ensure_ascii=False, default=str) #ensure_ascii false für darstellung von "ue"
def get_dxf_file(filepath: Path):
"""Hole das dxf file."""
try:
print("reading file ..", end='')
doc = ezdxf.filemanagement.readfile(filepath)
print("done")
except IOError:
print("Not a DXF file or a generic I/O error.")
sys.exit(1)
except DXFStructureError:
print("Invalid or corrupted DXF file.")
sys.exit(2)
return doc
def check_file_in_work(work_dir: Path, filename: Path) -> tuple[Path, bool]:
fexists = True
if not filename.exists():
mypath = work_dir.joinpath(filename)
ex = mypath.exists()
if not mypath.exists():
fexists = False
else:
mypath = filename
return mypath, fexists
def check_rack_z_coordinates(res_racks: dict, error_collector, config) -> None: def check_rack_z_coordinates(res_racks: dict, error_collector, config) -> None:
""" """
Prüft die z-Koordinaten aller Racks und gibt eine Warnung aus, Prüft die z-Koordinaten aller Racks und gibt eine Warnung aus,
@@ -830,11 +796,6 @@ def check_existance(res_mappings: dict, res_dist: dict, res_pos: dict, res_tunne
ret["overdefined_tunnel"].append(tname) ret["overdefined_tunnel"].append(tname)
return ret return ret
def dxf_is_binary(dxf_path: Path) -> bool:
with open(dxf_path, 'rb') as f:
header = f.read(22)
return b'AutoCAD Binary DXF' in header
def validate_configs() -> None: def validate_configs() -> None:
errors = [] errors = []
@@ -869,14 +830,6 @@ def validate_configs() -> None:
else: else:
print("No inconsistencies found. Continuing with routing process.") print("No inconsistencies found. Continuing with routing process.")
def check_environment_var(env_str: str) -> Path:
out_path = os.environ.get(env_str)
if out_path:
return Path(out_path)
else:
print(f"Umgebungsvariable {env_str} ist nicht gesetzt oder leer.")
exit()
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.dxf') parser.add_argument('-f', '--filename', action='store', required=True, default="ST_6300_Steuerungstestlayout1_neueBloecke.dwg", help='which file should be fetched', metavar='myfile.dxf')
+2 -3
View File
@@ -11,6 +11,8 @@ from shapely.strtree import STRtree
import math import math
import shapely import shapely
from utils import to_json
# Globale Variable, die in main aufgerufen wird und steuert ob Graphen in unittests gezeichnet werden # Globale Variable, die in main aufgerufen wird und steuert ob Graphen in unittests gezeichnet werden
draw = False draw = False
class PointSorter: class PointSorter:
@@ -34,9 +36,6 @@ class PointSorter:
def get_sorted_by_y(self): def get_sorted_by_y(self):
return sorted(self.points, key = lambda p: p.y) return sorted(self.points, key = lambda p: p.y)
def to_json(d, pretty: bool = True) -> str:
return json.dumps(d, indent=2 if pretty else None, default=str) #ensure_ascii false für darstellung von "ue"
class NodeIDs(): class NodeIDs():
''' Klasse, die Punkte verwaltet und NodeIDs zu Punkten zuordnet. ''' Klasse, die Punkte verwaltet und NodeIDs zu Punkten zuordnet.
Die NodeIDs sind ganze Zahlen, die die Position der Punkte in der Liste self.points repräsentieren. Die NodeIDs sind ganze Zahlen, die die Position der Punkte in der Liste self.points repräsentieren.
+2 -16
View File
@@ -5,6 +5,8 @@ from ioconverter import ExcelConverter
import json import json
from pathlib import Path from pathlib import Path
from utils import check_file_in_work, load_json
def process_item(sname, sdata): def process_item(sname, sdata):
data = { data = {
"id": sdata.get("IO", ""), "id": sdata.get("IO", ""),
@@ -57,22 +59,6 @@ def prepare_data(rawdata:dict):
return (dsensors, lsensors) return (dsensors, lsensors)
# einfache Funktionen
def load_json(jsonfilename):
with open(jsonfilename, encoding='utf-8') as fh:
return json.load(fh)
def check_file_in_work(work_dir:Path, filename:Path):
fexists = True
if not filename.exists(): # dann schau im Work Ordner nach
mypath = work_dir.joinpath(filename)
ex = mypath.exists()
if not mypath.exists():
fexists = False
else:
mypath = filename
return (mypath, fexists)
# Helper zum Laden der Error-JSON # Helper zum Laden der Error-JSON
def load_error_json(json_path: Path, work_dir: Path): def load_error_json(json_path: Path, work_dir: Path):
""" """
+2 -16
View File
@@ -8,24 +8,10 @@ import os
import configparser import configparser
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
from utils import load_json, to_json, write_results
# Funktionen # Funktionen
def load_json(jsonfilename):
with open(jsonfilename, encoding='utf-8') as fh:
return json.load(fh)
def write_results(jsnResults, outdir, filename):
""" write results to a json file
"""
print("writing results to a json file ...")
outfile = Path(outdir) / filename
with open(outfile, 'w', encoding='utf-8') as fh:
fh.write(jsnResults)
print("done")
def to_json(d, pretty: bool = True) -> str:
return json.dumps(d, indent=2 if pretty else None, ensure_ascii=False, default=str) #ensure_ascii false für darstellung von "ue"
def create_plant(racks:dict, sensors:dict, distributors:dict, mapping:dict, tunnels: dict, tunlength:dict ) -> dict: def create_plant(racks:dict, sensors:dict, distributors:dict, mapping:dict, tunnels: dict, tunlength:dict ) -> dict:
# racks = {'Rack_1-0': [Point(0, 0), Point(0, 10)], # racks = {'Rack_1-0': [Point(0, 0), Point(0, 10)],
+2 -10
View File
@@ -10,6 +10,8 @@ from fnmatch import fnmatch
import ezdxf import ezdxf
from openpyxl import Workbook from openpyxl import Workbook
from utils import check_environment_var
""" """
Dieses Programm: Dieses Programm:
@@ -24,16 +26,6 @@ Dieses Programm:
""" """
def check_environment_var(env_str: str) -> Path:
"""Prüft ob eine Umgebungsvariable gesetzt ist und gibt den Pfad zurück."""
out_path = os.environ.get(env_str)
if out_path:
return Path(out_path)
else:
print(f"Umgebungsvariable {env_str} ist nicht gesetzt oder leer.")
sys.exit(1)
def load_translation_config(translation_lang: str, translation_dir: Path) -> tuple[dict[str, str], dict[str, str], dict[str, str], dict[str, str]]: def load_translation_config(translation_lang: str, translation_dir: Path) -> tuple[dict[str, str], dict[str, str], dict[str, str], dict[str, str]]:
""" """
Lädt eine Übersetzungs-Config-Datei (z.B. CS.cfg, EN.cfg, FR.cfg). Lädt eine Übersetzungs-Config-Datei (z.B. CS.cfg, EN.cfg, FR.cfg).