Methode für ausgabe von verbundenen Racks hinzugefügt. Erste Graph-Bau Methoden eingeführt
This commit is contained in:
+91
-27
@@ -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__':
|
||||
|
||||
Reference in New Issue
Block a user