diff --git a/lib/linesweep_circle.py b/lib/linesweep_circle.py index 3030828..49d2484 100644 --- a/lib/linesweep_circle.py +++ b/lib/linesweep_circle.py @@ -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__':