Methode für ausgabe von verbundenen Racks hinzugefügt. Erste Graph-Bau Methoden eingeführt

This commit is contained in:
2025-05-15 11:37:32 +02:00
parent 81b5c55254
commit a84ea5c1e0
+91 -27
View File
@@ -4,6 +4,7 @@ from shapely.ops import nearest_points
import unittest import unittest
from collections import defaultdict from collections import defaultdict
import bisect import bisect
import networkx as nx
class PointSorter: class PointSorter:
def __init__(self): def __init__(self):
@@ -89,7 +90,7 @@ class RackIDs():
self._rack2begend = dict() self._rack2begend = dict()
self.add_racks(racks) self.add_racks(racks)
def add_rack(self, beg:Point, end:Point, name): #Hier wird Rack nur mit Anfang und Ende hinzugefügt -> wie macht man Zwischenpunkte? def add_rack(self, beg:Point, end:Point, name:str): #Hier wird Rack nur mit Anfang und Ende hinzugefügt -> wie macht man Zwischenpunkte?
if beg in self._point2rack: if beg in self._point2rack:
self._point2rack[beg].append(name) self._point2rack[beg].append(name)
else: else:
@@ -112,6 +113,9 @@ class RackIDs():
{Point(0, 0): ["Rack_1-0", "Rack_2-0", ...]} {Point(0, 0): ["Rack_1-0", "Rack_2-0", ...]}
''' '''
return self._point2rack return self._point2rack
def get_rack_names(self):
return self._rack2begend.keys()
def add_racks(self, racks:dict): def add_racks(self, racks:dict):
for name,v in racks.items(): for name,v in racks.items():
@@ -152,12 +156,14 @@ class RackIDs():
return False return False
class Anlage(): class Anlage():
def __init__(self, ): def __init__(self, tol=200, tol_step=10):
self._points = PointSorter() #self._points = PointSorter()
self._racks = RackIDs() self._racks = RackIDs()
self._nodeids = NodeIDs() #self._nodeids = NodeIDs()
self._sensors = dict() self._sensors = dict()
self._sensor_onpoints = dict() self._sensor_onpoints = dict()
self._tol = tol
self._tol_step = tol_step
def set_racks(self, racks:dict[str, list[Point]]): def set_racks(self, racks:dict[str, list[Point]]):
return self._racks.add_racks(racks) return self._racks.add_racks(racks)
@@ -170,7 +176,22 @@ class Anlage():
def get_points_from_rack(self, rname:str): def get_points_from_rack(self, rname:str):
return self._racks.get_points_from_rack(rname) return self._racks.get_points_from_rack(rname)
def get_all_rack_points(self):
ret = list()
for rname in self._racks.get_rack_names():
ret.append(self.get_points_from_rack(rname))
s = set()
for r in ret:
s.add(r)
return s
def get_points_from_sensors(self):
return self._sensors.values()
def get_sensor_onpoints(self):
return self._sensor_onpoints.values()
def add_sensor(self, sname: str, pos:Point): def add_sensor(self, sname: str, pos:Point):
self._sensors[sname] = pos self._sensors[sname] = pos
@@ -186,8 +207,7 @@ class Anlage():
self.add_point_to_rack(onpoint, rack_name) self.add_point_to_rack(onpoint, rack_name)
return self._sensor_onpoints return self._sensor_onpoints
def rack_segmentation(self, racks:dict) -> list[tuple[str, int, LineString]]:
def rack_segmentation(self, racks:dict):
''' Racks werden zu LineString konvertiert. Racks bestehend aus Polylinine werden in einzelne Segmente zerlegt und in Liste gesammelt. ''' Racks werden zu LineString konvertiert. Racks bestehend aus Polylinine werden in einzelne Segmente zerlegt und in Liste gesammelt.
''' '''
rack_segments = [] rack_segments = []
@@ -316,15 +336,15 @@ class Anlage():
# === Endpunkte aktualisieren === # === Endpunkte aktualisieren ===
# Dict erstellen, dass mit dem Key "Rack_id - index" dahinter die Koordinaten von Anfang und Endpunkt speichert # Dict erstellen, dass mit dem Key "Rack_id - index" dahinter die Koordinaten von Anfang und Endpunkt speichert
d_racks_segments = dict() rack_segments_pinned = dict()
for rack_id, idx, linestring in rack_segments: for rack_id, idx, linestring in rack_segments:
key = f"{rack_id}-{idx}" key = f"{rack_id}-{idx}"
d_racks_segments[key] = [Point(linestring.coords[0]), Point(linestring.coords[1])] #Alle Racks in ihrer eingelesenen Form zum Dict hinzufügen rack_segments_pinned[key] = [Point(linestring.coords[0]), Point(linestring.coords[1])] #Alle Racks in ihrer eingelesenen Form zum Dict hinzufügen
for rack_id, idx, old_pt, new_pt, taget_rack in endpoint_pinned: #Durch verschobene Endpunkte laufen... for rack_id, idx, old_pt, new_pt, taget_rack in endpoint_pinned: #Durch verschobene Endpunkte laufen...
key = f"{rack_id}-{idx}" key = f"{rack_id}-{idx}"
coords = d_racks_segments.get(key) coords = rack_segments_pinned.get(key)
if coords: #...und bei Übereinstimmung von Start oder Endkoordinate die ursprüngliche (eingelesene) mit der gepinnten überschreiben if coords: #...und bei Übereinstimmung von Start oder Endkoordinate die ursprüngliche (eingelesene) mit der gepinnten überschreiben
# Vergleich mit Startpunkt # Vergleich mit Startpunkt
@@ -334,7 +354,7 @@ class Anlage():
elif Point(coords[1]).equals(old_pt): elif Point(coords[1]).equals(old_pt):
coords[1] = Point(new_pt.x, new_pt.y) coords[1] = Point(new_pt.x, new_pt.y)
d_racks_segments[key] = coords # aktualisieren rack_segments_pinned[key] = coords # aktualisieren
#Dict erstellen, dass alle Punkte die an einem Rack anschließen speichert #Dict erstellen, dass alle Punkte die an einem Rack anschließen speichert
d_rack_conn_points = dict() d_rack_conn_points = dict()
@@ -346,7 +366,7 @@ class Anlage():
d_rack_to_points = dict() #neues Dict für Rack_id - Idx: Alle Punkte auf dem Rack d_rack_to_points = dict() #neues Dict für Rack_id - Idx: Alle Punkte auf dem Rack
for key, coords in d_racks_segments.items(): # Erst Anfangs und Endpunkt aus d_racks_segments holen for key, coords in rack_segments_pinned.items(): # Erst Anfangs und Endpunkt aus d_racks_segments holen
# coords = [start_point end_point] # coords = [start_point end_point]
d_rack_to_points[key] = coords.copy() d_rack_to_points[key] = coords.copy()
@@ -359,19 +379,48 @@ class Anlage():
unique_points = list({(pt.x, pt.y): pt for pt in d_rack_to_points[key]}.values()) unique_points = list({(pt.x, pt.y): pt for pt in d_rack_to_points[key]}.values())
d_rack_to_points[key] = unique_points d_rack_to_points[key] = unique_points
return rack_segments_pinned
def generate_connected_racks(self, racks_json:dict[str, list[Point]]) -> dict:
rack_segments = self.rack_segmentation(racks_json)
rack_endpoints = self.find_rack_endpoints(rack_segments) # könnte man hier auch get_racks_borders nehmen?
return [d_racks_segments, d_rack_conn_points] connected_racks = self.search_connections(rack_segments, rack_endpoints, self._tol, self._tol_step) #Kann man diese Ausgabe jetzt nochmal in sowas wie add_Racks aufrufen um "eingelesene Racks" zu überscheiben?
self._racks.add_racks(connected_racks)
return connected_racks
def generate_graph(self):
points = list()
G = nx.Graph()
points.append(self.get_all_rack_points())
points.append(self.get_points_from_sensors())
nodeids = NodeIDs(points)
for p in points:
nid = nodeids.get_id(p)
G.add_node(nid) # Knoten für Startpunkt
# for p in points:
# pos = {nid: (p.x, p.y) for nid in G.nodes()}
pos = {node: (node.x, node.y) for node in G.nodes()}
#nx.draw(G, pos, with_labels=False, node_size=10, font_size=8)
return G
class TestLinesweep(unittest.TestCase): class TestLinesweep(unittest.TestCase):
def test_linesweep(self): def test_linesweep(self):
# === Konfiguration === ''' Prüft ob aus ungeanuen Endpunkten von Racks innerhalb einer Json ein neues Rack-Gerüst mit aufeinander Liegenden
Endpunkten auf Racks erzeugt wird.
'''
tol = 200 tol = 200
tol_step = 10 tol_step = 10
@@ -401,17 +450,8 @@ class TestLinesweep(unittest.TestCase):
an = Anlage() an = Anlage()
# === 1. Racks in Segmente zerlegen === connected_racks = an.generate_connected_racks(racks_json)
''' Hier werden Racks, die aus "echter" Polylinie bestehen (mehrere Nodes, z.B. Rack 2 in easy.dxf) in einzelne Segmente zerlegt (Node1 -> Node2, Node2 -> Node3)'''
rack_segments = an.rack_segmentation(racks_json)
# === 2. Alle Endpunkte sammeln ===
''' Alle Endpunkte aller Racks als Point gespeichert, um shapely funktionen verwenden zu können'''
segment_endpoints = an.find_rack_endpoints(rack_segments)
d_racks_segments, d_rack_conn_points = an.search_connections(rack_segments, segment_endpoints, tol, tol_step)
res_rack_seg = {'Rack_1-0': [Point(4946.5, 15865.5), Point(4946.5, 3777.6)], res_rack_seg = {'Rack_1-0': [Point(4946.5, 15865.5), Point(4946.5, 3777.6)],
'Rack_2-0': [Point(0.1, 57.6), Point(0.1, 3777.6)], 'Rack_2-0': [Point(0.1, 57.6), Point(0.1, 3777.6)],
'Rack_2-1': [Point(0.1, 3777.6), Point(14755.1, 3777.6)], 'Rack_2-1': [Point(0.1, 3777.6), Point(14755.1, 3777.6)],
@@ -420,10 +460,11 @@ class TestLinesweep(unittest.TestCase):
'Rack_5-0': [Point(8866.1, 15865.5), Point(8866.1, 3777.6)] 'Rack_5-0': [Point(8866.1, 15865.5), Point(8866.1, 3777.6)]
} }
log_res = to_json(res_rack_seg) self.assertEqual(connected_racks, res_rack_seg)
self.assertEqual(d_racks_segments, res_rack_seg)
def test_ids_to_point(self): def test_ids_to_point(self):
''' Testet, ob gefragter Punkt auf Racks a, b, c liegt'''
res_rack_seg = {'Rack_1-0': [Point(1, 0), Point(5, 6)], res_rack_seg = {'Rack_1-0': [Point(1, 0), Point(5, 6)],
'Rack_2-0': [Point(1, 8), Point(1, 0)], 'Rack_2-0': [Point(1, 8), Point(1, 0)],
@@ -436,7 +477,9 @@ class TestLinesweep(unittest.TestCase):
self.assertEqual(point2rack.get_racks_from_point(Point(5, 6)), ["Rack_1-0"]) self.assertEqual(point2rack.get_racks_from_point(Point(5, 6)), ["Rack_1-0"])
self.assertEqual(point2rack.get_points_from_rack("Rack_2-0"), [Point(1, 0), Point(1, 8)]) self.assertEqual(point2rack.get_points_from_rack("Rack_2-0"), [Point(1, 0), Point(1, 8)])
def test_add_point_interim(self): def test_add_point_interim(self):
''' Testet das inzufügen und einsortieren eines Zwischenpunktes zwische nRack-Anfang und Rack-Ende'''
res_rack_seg = {'Rack_1-0': [Point(1, 0), Point(5, 6)], res_rack_seg = {'Rack_1-0': [Point(1, 0), Point(5, 6)],
'Rack_2-0': [Point(1, 8), Point(1, 0)], 'Rack_2-0': [Point(1, 8), Point(1, 0)],
@@ -448,7 +491,9 @@ class TestLinesweep(unittest.TestCase):
self.assertEqual(point2rack.get_points_from_rack("Rack_2-0"), [Point(1, 0), Point(1,4), Point(1, 8)]) self.assertEqual(point2rack.get_points_from_rack("Rack_2-0"), [Point(1, 0), Point(1,4), Point(1, 8)])
def test_add_sensor(self): def test_add_sensor(self):
''' Erzeugt Aufpunkt an dem Sensor nähesten Rack und fügt diesen auf Rack ein (sortiert).'''
rack_segs = {'Rack_1-0': [Point(0, 0), Point(0, 10)], rack_segs = {'Rack_1-0': [Point(0, 0), Point(0, 10)],
@@ -472,9 +517,28 @@ class TestLinesweep(unittest.TestCase):
self.assertEqual(plist1, [Point(0, 0), Point(0, 10)]) self.assertEqual(plist1, [Point(0, 0), Point(0, 10)])
self.assertEqual(plist2, [Point(0, 0), Point(0,1), Point(0, 10)]) self.assertEqual(plist2, [Point(0, 0), Point(0,1), Point(0, 10)])
def test_generate_graph(self):
rack_segs = {'Rack_1-0': [Point(0, 0), Point(0, 10)],
'Rack_2-0': [Point(10, -2), Point(10, 5)],
'Rack_2-1': [Point(0, 3), Point(10, 3)]}
sensors = {'Sens_1': Point(1, 1),
'Sens_2': Point(2, 4),
'Sens_3': Point(9, 2)}
an = Anlage()
an.set_racks(rack_segs)
graph_racks = an.generate_graph()
an.add_sensors(sensors)
an.connect_sensors_to_racks()
graph_racks_sensors = an.generate_graph()
if __name__ == '__main__': if __name__ == '__main__':