Finalisierung der Wegsuche. Vorbereitung für Einbau in Hauptskript routing.py

This commit is contained in:
2025-05-16 15:25:31 +02:00
parent 55459c73b1
commit b8b5db45eb
+193 -134
View File
@@ -152,8 +152,6 @@ class RackIDs():
def get_rack_names(self) -> list: def get_rack_names(self) -> list:
return list(self._rack2begend.keys()) return list(self._rack2begend.keys())
def add_point_to_rack(self, point:Point, name:str): def add_point_to_rack(self, point:Point, name:str):
if point in self._point2rack: if point in self._point2rack:
self._point2rack[point].append(name) self._point2rack[point].append(name)
@@ -199,12 +197,10 @@ class RackIDs():
last = Point(l2.coords[1]) last = Point(l2.coords[1])
if l1.distance(first) <= self._tol_snap: if l1.distance(first) <= self._tol_snap:
snap_point = l1.interpolate(l1.project(first)) snap_point = l1.interpolate(l1.project(first))
self.add_point_to_rack(snap_point, rnames[l1])
if l1.distance(last) <= self._tol_snap: if l1.distance(last) <= self._tol_snap:
snap_point = l1.interpolate(l1.project(last)) snap_point = l1.interpolate(l1.project(last))
self.add_point_to_rack(snap_point, rnames[l1])
self.add_point_to_rack(snap_point, rnames[l1])
def rack_is_horizontal(self, name): def rack_is_horizontal(self, name):
[pa, pe] = self._rack2begend[name] [pa, pe] = self._rack2begend[name]
@@ -216,39 +212,52 @@ class RackIDs():
class Anlage(): class Anlage():
r""" r"""
Baut eine Anlage besteend aus Kabeltrassen (Racks), Sensoren und Unterverteilern auf. Baut eine Anlage besteend aus Kabeltrassen (Racks), Sensoren und Unterverteilern auf.
Ermöglicht die Berechnung der günstigsten kabelwege und gibt die Kabellängen von jedem Sensor zum zugehörigen Unterverteiler aus. Ermöglicht die Berechnung der günstigsten Kabelwege und gibt die Kabellängen von jedem Sensor zum zugehörigen Unterverteiler aus.
Parameters Parameters
---------- ----------
G : NetworkX graph
weight : string or function
If this is a string, then edge weights will be accessed via the
edge attribute with this key (that is, the weight of the edge
joining `u` to `v` will be ``G.edges[u, v][weight]``). If no
such edge attribute exists, the weight of the edge is assumed to
be one.
If this is a function, the weight of an edge is the value
returned by the function. The function must accept exactly three
positional arguments: the two endpoints of an edge and the
dictionary of edge attributes for that edge. The function must
return a number.
Returns Returns
------- -------
distance : dictionary
Dictionary, keyed by source and target, of shortest paths.
Examples Examples
-------- --------
>>> graph = nx.DiGraph() >>> # Erstelle Anlage
>>> graph.add_weighted_edges_from( >>> an = Anlage()
... [("0", "3", 3), ("0", "1", -5), ("0", "2", 2), ("1", "2", 4), ("2", "3", 1)] >>> # Füge racks aus Daten hinzu
... ) >>> an.set_racks(rack_segs)
>>> paths = nx.johnson(graph, weight="weight") >>> # Verbinde Racks miteinander (ggf. verlängere ungenaue Racks)
>>> paths["0"]["2"] >>> an.join_racks()
['0', '1', '2'] >>> # Füge Sensoren als Knoten hinzu
>>> an.add_sensors(sensors)
>>> # Verbinde Sensoren mit deren naheliegendsten Racks
>>> an.connect_sensors_to_racks()
>>> # Füge UV hinzu
>>> an.add_distributors(distributors)
>>> # Verbinde UV mit deren naheliegendsten Racks
>>> an.connect_distributor_to_racks()
>>> # Verknüpfe Sensoren mit zugehörigem UV
>>> an.map_distributors_to_sensors(mapping)
>>>
>>> # Initialisiere Graph
>>> G3 = nx.Graph()
>>> # Fülle eben erstellten Graphen mit Daten
>>> pos = an.generate_graph(G3)
>>> # Ermittle kürzeste Wege von Unterverteilern zu zugehörigen Sensoren
>>> paths = an.create_cable_paths(G3)
>>> print(paths['Dist_1-Sens_1']["path_coords"])
... [Point(-1, 9), Point(0, 9), Point(0, 3), Point(0, 1), Point(1, 1)]
>>> print(paths['Dist_1-Sens_2']["path_coords"])
... [Point(-1, 9), Point(0, 9), Point(0, 3), Point(2, 3), Point(2, 4)]
>>> print(paths['Dist_2-Sens_3']["path_coords"])
... [Point(11, 0), Point(10, 0), Point(10, 2), Point(9, 2)]
>>> print(paths['Dist_1-Sens_1']["path_length"])
... 10
""" """
def __init__(self, tol_snap=200, snap_step=10, tol_connect=2, tol_connect_step=0.5): def __init__(self, tol_snap=200, snap_step=10, tol_connect=2, tol_connect_step=0.5):
@@ -273,15 +282,39 @@ class Anlage():
def set_racks(self, racks:dict[str, list[Point]]): def set_racks(self, racks:dict[str, list[Point]]):
r"""
Fügt racks aus eingelsener Datei zu Anlage hinzu.
Parameters
----------
racks - dict{"Rack_1-1": [Point(1, 0), Point(2,0), ...]}
"""
return self._racks.add_racks(racks) return self._racks.add_racks(racks)
def get_racks(self) -> dict: def get_racks(self) -> dict:
r"""
Gibt in Anlage enthaltene Racks zurück.
Returns
----------
dict{Point(0,0): ["Rack_1", "Rack_2", ...]}
"""
return self._racks._point2rack return self._racks._point2rack
def add_point_to_rack(self, point:Point, rname:str): def add_point_to_rack(self, point:Point, rname:str):
r"""
Fügt einen Punkt zu einem angegebenen Rack hinzu.
"""
return self._racks.add_point_to_rack(point, rname) return self._racks.add_point_to_rack(point, rname)
def get_all_rack_points(self): def get_all_rack_points(self):
r"""
Gibt einer Liste von allen Punkten allen Racks zurück.
Returns
----------
[Point(0,0), Point(1,5), Point(2,6)]
"""
ret = list() ret = list()
for rname in self._racks.get_rack_names(): for rname in self._racks.get_rack_names():
ret.extend(self.get_points_from_rack(rname)) ret.extend(self.get_points_from_rack(rname))
@@ -367,6 +400,9 @@ class Anlage():
return(segment_endpoints) return(segment_endpoints)
def join_racks(self):
self._racks.join_racks()
def increase_circle(self, tol, tol_step, line, pt, rack_id, idx, other_rack_id, other_idx, verbindungen, endpoint_pinned): def increase_circle(self, tol, tol_step, line, pt, rack_id, idx, other_rack_id, other_idx, verbindungen, endpoint_pinned):
''' vergrößere Kreis bis Schnittpunkt mit Rack entsteht. ''' vergrößere Kreis bis Schnittpunkt mit Rack entsteht.
@@ -604,7 +640,12 @@ class Anlage():
pfade = dict() pfade = dict()
for sname, dname in self._sensor2dist.items(): for sname, dname in self._sensor2dist.items():
pfad_nodes, pfad_length = self.create_cable_path(G, sname, dname) pfad_nodes, pfad_length = self.create_cable_path(G, sname, dname)
pfade[f"{dname}-{sname}"] = {"pfad": pfad_nodes, "laenge": pfad_length} pfad_coords = self._nodeids.get_points(pfad_nodes)
pfade[f"{dname}-{sname}"] = {"path_nodes": pfad_nodes,
"path_coords": pfad_coords,
"path_length": pfad_length}
return pfade
def show_node_ids(self): def show_node_ids(self):
return self._nodeids.show() return self._nodeids.show()
@@ -617,8 +658,11 @@ class Anlage():
class TestLinesweep(unittest.TestCase): class TestLinesweep(unittest.TestCase):
def test_duplicate_points(self): def test_duplicate_points(self):
''' Testet das Nicht-Hinzufügen von doppelten Punkten'''
# Initialisiere die Liste an Knoten
nodeids = NodeIDs() nodeids = NodeIDs()
# Setze gleichen Knoten doppelt
nodeids.add_point(Point(1,1)) nodeids.add_point(Point(1,1))
nodeids.add_point(Point(1,1)) nodeids.add_point(Point(1,1))
@@ -676,23 +720,27 @@ class TestLinesweep(unittest.TestCase):
'Rack_2': [Point(-5, 5), Point(5, 5)] 'Rack_2': [Point(-5, 5), Point(5, 5)]
} }
# Initialisiere Racks
rack = RackIDs() rack = RackIDs()
# Füge Racks aus gegebenen Daten hinzu und teile Rack_1 bestehend aus 3 Punkten in 2 Racks auf
rack.add_racks(racks_data) rack.add_racks(racks_data)
self.assertEqual(rack.get_rack_names(), ['Rack_1-1', 'Rack_1-2', 'Rack_2']) self.assertEqual(rack.get_rack_names(), ['Rack_1-1', 'Rack_1-2', 'Rack_2'])
def test_intersect_segments(self): def test_intersect_segments(self):
''' Stellt Schnittpunkte zwischen Racks fest und fügt Schnittpunkt zu Rack hinzu. ''' ''' Stellt Schnittpunkte zwischen Racks fest und fügt Schnittpunkt zu Rack hinzu. '''
racks_data = { racks_data = {
'Rack_1': [Point(0, 0), Point(0, 10), Point (10, 10)], 'Rack_1': [Point(0, 0), Point(0, 10), Point (10, 10)],
'Rack_2': [Point(-5, 5), Point(5, 5)], 'Rack_2': [Point(-5, 5), Point(5, 5)],
} }
# Initialisiere Racks
rack = RackIDs() rack = RackIDs()
# Füge Racks aus gegebenen Daten hinzu und teile Rack_1 bestehend aus 3 Punkten in 2 Racks auf
rack.add_racks(racks_data) rack.add_racks(racks_data)
# Verknüpfe Racks mit echten Schniuttpunkten und füge Schnittpunkte (exakt & beinahe) zu jeweiligem Rack hinzu
rack.join_racks() rack.join_racks()
self.assertEqual(rack.get_points_from_rack("Rack_1-1"), [Point(0, 0), Point(0, 5), Point (0, 10)]) self.assertEqual(rack.get_points_from_rack("Rack_1-1"), [Point(0, 0), Point(0, 5), Point (0, 10)])
@@ -704,156 +752,167 @@ class TestLinesweep(unittest.TestCase):
'Rack_2': [Point(1, 5), Point(5, 5)], 'Rack_2': [Point(1, 5), Point(5, 5)],
'Rack_3': [Point(1.5, 7.5), Point(5,7.5)] 'Rack_3': [Point(1.5, 7.5), Point(5,7.5)]
} }
# Initialisiere Racks
rack = RackIDs() rack = RackIDs()
# Füge Racks aus gegebenen Daten hinzu und teile Rack_1 bestehend aus 3 Punkten in 2 Racks auf
rack.add_racks(racks_data) rack.add_racks(racks_data)
# Verknüpfe Racks mit echten Schniuttpunkten und füge Schnittpunkte (exakt & beinahe) zu jeweiligem Rack hinzu
rack.join_racks() rack.join_racks()
self.assertEqual(rack.get_points_from_rack("Rack_1"), [Point(0, 0), Point(0, 5), Point (0, 10)]) self.assertEqual(rack.get_points_from_rack("Rack_1"), [Point(0, 0), Point(0, 5), Point (0, 10)])
# def test_ids_to_point(self): def test_ids_to_point(self):
# ''' Testet, ob gefragter Punkt auf Racks a, b, c liegt''' ''' 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)],
# 'Rack_2-1': [Point(0, 10), Point(5, 10)]} 'Rack_2-1': [Point(0, 10), Point(5, 10)]}
# point2rack = RackIDs(res_rack_seg) point2rack = RackIDs(res_rack_seg)
# self.assertEqual(point2rack.get_racks_from_point(Point(1, 0)), ["Rack_1-0", "Rack_2-0"]) self.assertEqual(point2rack.get_racks_from_point(Point(1, 0)), ["Rack_1-0", "Rack_2-0"])
# 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''' ''' 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)],
# 'Rack_2-1': [Point(0, 10), Point(5, 10)]} 'Rack_2-1': [Point(0, 10), Point(5, 10)]}
# point2rack = RackIDs(res_rack_seg) point2rack = RackIDs(res_rack_seg)
# point2rack.add_point_to_rack(Point(1,4), "Rack_2-0") point2rack.add_point_to_rack(Point(1,4), "Rack_2-0")
# 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).''' ''' 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)], 'Rack_2-0': [Point(10, -2), Point(10, 5)],
# 'Rack_2-0': [Point(10, -2), Point(10, 5)], 'Rack_2-1': [Point(0, 3), Point(10, 3)]}
# 'Rack_2-1': [Point(0, 3), Point(10, 3)]}
# sensors = {'Sens_1': Point(1, 1), sensors = {'Sens_1': Point(1, 1),
# 'Sens_2': Point(2, 4), 'Sens_2': Point(2, 4),
# 'Sens_3': Point(9, 2)} 'Sens_3': Point(9, 2)}
# an = Anlage() an = Anlage()
# point2rack = an.set_racks(rack_segs) point2rack = an.set_racks(rack_segs)
# an.add_sensors(sensors) an.add_sensors(sensors)
# plist1 = an.get_points_from_rack("Rack_1-0") plist1 = an.get_points_from_rack("Rack_1-0")
# an.connect_sensors_to_racks() an.connect_sensors_to_racks()
# plist2 = an.get_points_from_rack("Rack_1-0") plist2 = an.get_points_from_rack("Rack_1-0")
# 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): def test_generate_graph(self):
'''Generiert einen Graphen in 3 unterschiedlichen Ausbauestufen (nur Racks, Racks+Sensoren, Racks+Sensoren+Unterverteiler)'''
# rack_segs = {'Rack_1-0': [Point(0, 0), Point(0, 10)], rack_segs = {'Rack_1-0': [Point(0, 0), Point(0, 10)],
# 'Rack_2-0': [Point(10, -2), Point(10, 5)], 'Rack_2-0': [Point(10, -2), Point(10, 5)],
# 'Rack_2-1': [Point(0, 3), Point(10, 3)]} 'Rack_2-1': [Point(0, 3), Point(10, 3)]}
# sensors = {'Sens_1': Point(1, 1), sensors = {'Sens_1': Point(1, 1),
# 'Sens_2': Point(2, 4), 'Sens_2': Point(2, 4),
# 'Sens_3': Point(9, 2)} 'Sens_3': Point(9, 2)}
# distributors = {'Dist_1': Point(-1, 9), distributors = {'Dist_1': Point(-1, 9),
# 'Dist_2': Point(11, 0)} 'Dist_2': Point(11, 0)}
# an = Anlage() an = Anlage()
# an.set_racks(rack_segs) an.set_racks(rack_segs)
an.join_racks
# G1 = nx.Graph() G1 = nx.Graph()
# pos = an.generate_graph(G1) pos = an.generate_graph(G1)
# nx.draw(G1, pos, with_labels=False, node_size=10, font_size=8) nx.draw(G1, pos, with_labels=False, node_size=10, font_size=8)
# plt.show() plt.show()
# an.add_sensors(sensors) an.add_sensors(sensors)
# an.connect_sensors_to_racks() an.connect_sensors_to_racks()
# G2 = nx.Graph() G2 = nx.Graph()
# pos = an.generate_graph(G2) pos = an.generate_graph(G2)
# edge_colors = [G2[u][v].get('color', 'black') for u, v in G2.edges()] edge_colors = [G2[u][v].get('color', 'black') for u, v in G2.edges()]
# nx.draw(G2, pos, with_labels=False, node_size=10, font_size=8, edge_color=edge_colors) nx.draw(G2, pos, with_labels=False, node_size=10, font_size=8, edge_color=edge_colors)
# plt.show() plt.show()
# an.add_distributors(distributors) an.add_distributors(distributors)
# an.connect_distributor_to_racks() an.connect_distributor_to_racks()
# G3 = nx.Graph() G3 = nx.Graph()
# pos = an.generate_graph(G3) pos = an.generate_graph(G3)
# edge_colors = [G3[u][v].get('color', 'black') for u, v in G3.edges()] edge_colors = [G3[u][v].get('color', 'black') for u, v in G3.edges()]
# nx.draw(G3, pos, with_labels=False, node_size=10, font_size=8, edge_color=edge_colors) nx.draw(G3, pos, with_labels=False, node_size=10, font_size=8, edge_color=edge_colors)
# plt.show() plt.show()
# def test_Wegsuche(self): def test_Wegsuche(self):
''' Erstellt Graphen mit Racks, Sensoren und Unterverteilern und sucht kürzeste Wege von Unterverteiler zu zugehörigen Sensoren'''
# rack_segs = {'Rack_1-0': [Point(0, 0), Point(0, 10)], rack_segs = {'Rack_1-0': [Point(0, 0), Point(0, 10)],
# 'Rack_2-0': [Point(10, -2), Point(10, 5)], 'Rack_2-0': [Point(10, -2), Point(10, 5)],
# 'Rack_2-1': [Point(0, 3), Point(10, 3)]} 'Rack_2-1': [Point(0, 3), Point(10, 3)]}
# sensors = {'Sens_1': Point(1, 1), sensors = {'Sens_1': Point(1, 1),
# 'Sens_2': Point(2, 4), 'Sens_2': Point(2, 4),
# 'Sens_3': Point(9, 2)} 'Sens_3': Point(9, 2)}
# distributors = {'Dist_1': Point(-1, 9), distributors = {'Dist_1': Point(-1, 9),
# 'Dist_2': Point(11, 0)} 'Dist_2': Point(11, 0)}
# mapping = {'Dist_1': ['Sens_1', 'Sens_2'], mapping = {'Dist_1': ['Sens_1', 'Sens_2'],
# 'Dist_2': ['Sens_3']} 'Dist_2': ['Sens_3']}
# an = Anlage() # Erstelle Anlage
# an.set_racks(rack_segs) an = Anlage()
# an.add_sensors(sensors) # Füge racks aus Daten hinzu
# an.connect_sensors_to_racks() an.set_racks(rack_segs)
# an.add_distributors(distributors) # Verbinde Racks miteinander (ggf. verlängere ungenaue Racks)
# an.connect_distributor_to_racks() an.join_racks()
# an.map_distributors_to_sensors(mapping) # Füge Sensoren als Knoten hinzu
an.add_sensors(sensors)
# Verbinde Sensoren mit deren naheliegendsten Racks
an.connect_sensors_to_racks()
# Füge UV hinzu
an.add_distributors(distributors)
# Verbinde UV mit deren naheliegendsten Racks
an.connect_distributor_to_racks()
# Verknüpfe Sensoren mit zugehörigem UV
an.map_distributors_to_sensors(mapping)
# Initialisiere Graph
G3 = nx.Graph()
# Fülle eben erstellten Graphen mit Daten
pos = an.generate_graph(G3)
# Extrahiere Farb-Informationen der Kanten
edge_colors = [G3[u][v].get('color', 'black') for u, v in G3.edges()]
# Zeiche Graphen und zeige in
nx.draw(G3, pos, with_labels=False, node_size=10, font_size=8, edge_color=edge_colors)
plt.show()
# G3 = nx.Graph() # Ermittle kürzeste Wege von Unterverteilern zu zugehörigen Sensoren
# pos = an.generate_graph(G3) paths = an.create_cable_paths(G3)
# print(G3.nodes)
# print(G3.edges)
# print([(n, nbrdict) for n, nbrdict in G3.adjacency()])
# print(an.show_node_ids())
# edge_colors = [G3[u][v].get('color', 'black') for u, v in G3.edges()]
# nx.draw(G3, pos, with_labels=False, node_size=10, font_size=8, edge_color=edge_colors)
# plt.show()
# paths = an.create_cable_paths(G3) self.assertEqual(paths['Dist_1-Sens_1']["path_coords"], [Point(-1, 9), Point(0, 9), Point(0, 3), Point(0, 1), Point(1, 1)])
# self.assertEqual(paths, "") self.assertEqual(paths['Dist_1-Sens_2']["path_coords"], [Point(-1, 9), Point(0, 9), Point(0, 3), Point(2, 3), Point(2, 4)])
self.assertEqual(paths['Dist_2-Sens_3']["path_coords"], [Point(11, 0), Point(10, 0), Point(10, 2), Point(9, 2)])
self.assertEqual(paths['Dist_1-Sens_1']["path_length"], 10)
self.assertEqual(paths['Dist_1-Sens_2']["path_length"], 10)
self.assertEqual(paths['Dist_2-Sens_3']["path_length"], 4)