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
from collections import defaultdict
import bisect
import networkx as nx
class PointSorter:
def __init__(self):
@@ -89,7 +90,7 @@ class RackIDs():
self._rack2begend = dict()
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:
self._point2rack[beg].append(name)
else:
@@ -112,6 +113,9 @@ class RackIDs():
{Point(0, 0): ["Rack_1-0", "Rack_2-0", ...]}
'''
return self._point2rack
def get_rack_names(self):
return self._rack2begend.keys()
def add_racks(self, racks:dict):
for name,v in racks.items():
@@ -152,12 +156,14 @@ class RackIDs():
return False
class Anlage():
def __init__(self, ):
self._points = PointSorter()
def __init__(self, tol=200, tol_step=10):
#self._points = PointSorter()
self._racks = RackIDs()
self._nodeids = NodeIDs()
#self._nodeids = NodeIDs()
self._sensors = dict()
self._sensor_onpoints = dict()
self._tol = tol
self._tol_step = tol_step
def set_racks(self, racks:dict[str, list[Point]]):
return self._racks.add_racks(racks)
@@ -170,7 +176,22 @@ class Anlage():
def get_points_from_rack(self, rname:str):
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):
self._sensors[sname] = pos
@@ -186,8 +207,7 @@ class Anlage():
self.add_point_to_rack(onpoint, rack_name)
return self._sensor_onpoints
def rack_segmentation(self, racks:dict):
def rack_segmentation(self, racks:dict) -> list[tuple[str, int, LineString]]:
''' Racks werden zu LineString konvertiert. Racks bestehend aus Polylinine werden in einzelne Segmente zerlegt und in Liste gesammelt.
'''
rack_segments = []
@@ -316,15 +336,15 @@ class Anlage():
# === Endpunkte aktualisieren ===
# 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:
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...
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
# Vergleich mit Startpunkt
@@ -334,7 +354,7 @@ class Anlage():
elif Point(coords[1]).equals(old_pt):
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
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
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]
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())
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):
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_step = 10
@@ -401,17 +450,8 @@ class TestLinesweep(unittest.TestCase):
an = Anlage()
# === 1. Racks in Segmente zerlegen ===
''' 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)
connected_racks = an.generate_connected_racks(racks_json)
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-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)]
}
log_res = to_json(res_rack_seg)
self.assertEqual(d_racks_segments, res_rack_seg)
self.assertEqual(connected_racks, res_rack_seg)
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)],
'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_points_from_rack("Rack_2-0"), [Point(1, 0), Point(1, 8)])
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)],
'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)])
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)],
@@ -472,9 +517,28 @@ class TestLinesweep(unittest.TestCase):
self.assertEqual(plist1, [Point(0, 0), 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__':