Plant.py arbeitet jetzt mit dem str tree zusammen mit der bbox.

This commit is contained in:
2025-05-26 14:36:20 +02:00
parent e347794373
commit 761bf22636
5 changed files with 265 additions and 395 deletions
+1 -1
View File
@@ -1,4 +1,4 @@
REM @echo off @echo off
if [%1]==[] goto usage if [%1]==[] goto usage
for /F %%i in ("%1") do set FILENAME=%%~ni for /F %%i in ("%1") do set FILENAME=%%~ni
+1 -1
View File
@@ -1,4 +1,4 @@
@echo off @echo off
CALL manage_interpreter.bat activate_interpreter CALL manage_interpreter.bat activate_interpreter
python %PROJECT_LIB%\routing.py %* python -m cProfile -o file.prof %PROJECT_LIB%\routing.py %*
CALL manage_interpreter.bat deactivate_interpreter CALL manage_interpreter.bat deactivate_interpreter
+2
View File
@@ -10,10 +10,12 @@ set PROJECT_DATA=%PROJECT%\data
set PROJECT_WORK=%PROJECT%\work set PROJECT_WORK=%PROJECT%\work
set PROJECT_LOG=%PROJECT%\log set PROJECT_LOG=%PROJECT%\log
set PROJECT_TEST=%PROJECT%\testdata set PROJECT_TEST=%PROJECT%\testdata
set PROJECT_HOT=%PROJECT%\hotfolder
if not exist %PROJECT%\work mkdir %PROJECT%\work if not exist %PROJECT%\work mkdir %PROJECT%\work
if not exist %PROJECT%\log mkdir %PROJECT%\log if not exist %PROJECT%\log mkdir %PROJECT%\log
if not exist %PROJECT%\data mkdir %PROJECT%\data if not exist %PROJECT%\data mkdir %PROJECT%\data
if not exist %PROJECT%\hotfolder mkdir %PROJECT%\hotfolder
popd popd
goto :eof goto :eof
+288 -417
View File
@@ -110,7 +110,7 @@ class NodeIDs():
def show(self): def show(self):
return self._id2cord return self._id2cord
class RackIDs(): class RackIDs():
def __init__(self, tol_snap = 200): def __init__(self, tol_snap = 200.0):
self._point2rack = dict() self._point2rack = dict()
self._rack2begend = dict() self._rack2begend = dict()
# Toleranzen zur Rack anbindung aneinander (Rack Snap) # Toleranzen zur Rack anbindung aneinander (Rack Snap)
@@ -267,7 +267,7 @@ class Anlage():
""" """
def __init__(self, tol_snap=200, snap_step=10, tol_connect=1000, tol_connect_step=50): def __init__(self, tol_snap=200.0, snap_step=10.0, tol_connect=1000.0, tol_connect_step=50.0):
# Container für alle Racks # Container für alle Racks
self._racks = RackIDs(tol_snap=tol_snap) self._racks = RackIDs(tol_snap=tol_snap)
# zuordnung zwischen KnotenID und Punkt # zuordnung zwischen KnotenID und Punkt
@@ -288,6 +288,8 @@ class Anlage():
self._connect_step = tol_connect_step self._connect_step = tol_connect_step
# Infos zum zeichnen des Graphen # Infos zum zeichnen des Graphen
self._node_positions = dict() self._node_positions = dict()
# falls man die rack zu den Sensorpunkten abfragen möchte, ist ein STR Baum nötig
self._rack_tree = None
def set_racks(self, racks:dict[str, list[Point]]): def set_racks(self, racks:dict[str, list[Point]]):
r""" r"""
@@ -362,21 +364,6 @@ class Anlage():
die Rückgabe enthält ein Tuple, welche Sensoren keinem Rack zugeordnet werden konnten die Rückgabe enthält ein Tuple, welche Sensoren keinem Rack zugeordnet werden konnten
''' '''
return self.connect_equipment_to_racks(self._sensors, self._sensor_onpoints) return self.connect_equipment_to_racks(self._sensors, self._sensor_onpoints)
'''
errors = list()
for sname, pos in self._sensors.items():
rack_borders = self._racks.get_racks_borders()
onpoint, rack_name = self.find_nearest_rack_from_point(self._tol_connect, self._connect_step, pos, rack_borders)
if onpoint == None or rack_name == None:
errors.append((sname, pos))
continue
self._sensor_onpoints[sname] = (onpoint, rack_name)
self.add_point_to_rack(onpoint, rack_name)
# Füge "virtuelle Racks" von Sensor zu Aufpunkt von Sensor auf Rack hinzu.
vrackname = f"v-{sname}-{rack_name}"
self._racks.add_rack(pos, onpoint, vrackname)
return errors
'''
def add_distributor(self, dname: str, pos:Point): def add_distributor(self, dname: str, pos:Point):
self._distributors[dname] = pos self._distributors[dname] = pos
@@ -393,21 +380,6 @@ class Anlage():
die Rückage enthält ein Tuple, welche Unterverteiler keinem Rack zugeordnet werden konnten die Rückage enthält ein Tuple, welche Unterverteiler keinem Rack zugeordnet werden konnten
''' '''
return self.connect_equipment_to_racks(self._distributors, self._distributors_onpoints) return self.connect_equipment_to_racks(self._distributors, self._distributors_onpoints)
'''
errors = list()
for dname, pos in self._distributors.items():
rack_borders = self._racks.get_racks_borders()
onpoint, rack_name = self.find_nearest_rack_from_point(self._tol_connect, self._connect_step, pos, rack_borders)
if onpoint == None or rack_name == None:
errors.append((dname, pos))
continue
self._distributors_onpoints[dname] = (onpoint, rack_name)
self.add_point_to_rack(onpoint, rack_name)
# Füge "virtuelle Racks" von Sensor zu Aufpunkt von Sensor auf Rack hinzu.
drackname = f"d-{dname}-{rack_name}"
self._racks.add_rack(pos, onpoint, drackname)
return errors
'''
def join_racks(self): def join_racks(self):
self._racks.join_racks() self._racks.join_racks()
@@ -421,39 +393,19 @@ class Anlage():
self._rack_map[line] = r_name self._rack_map[line] = r_name
self._rack_tree = STRtree(self._rack_lines) self._rack_tree = STRtree(self._rack_lines)
def find_nearest_rack_from_point_tree(self, max_dist, sensor:Point) -> tuple[Point, str]:
if not hasattr(self, "_rack_tree"):
self._build_rack_strtree()
result = self._rack_tree.query_nearest(sensor, return_distance=True)
if result == None:
return None, None
index_array, dist_array = result
nearest_index = index_array[0]
distance = dist_array[0]
#nearest_line, distance = result
if distance > max_dist:
return None, None
nearest_line = self._rack_lines[nearest_index]
rack_name = self._rack_map[nearest_line]
nearest_point = nearest_line.interpolate(nearest_line.project(sensor))
return(nearest_point, rack_name)
def find_nearest_rack_from_point_STR_bbox(self, max_dist, sensor:Point) -> tuple[Point, str]: def find_nearest_rack_from_point_STR_bbox(self, max_dist, sensor:Point) -> tuple[Point, str]:
if not hasattr(self, "_rack_tree"): if self._rack_tree is None:
self._build_rack_strtree() self._build_rack_strtree()
minx, miny, maxx, maxy = sensor.x - max_dist, sensor.y - max_dist, sensor.x + max_dist, sensor.y + max_dist minx, miny, maxx, maxy = sensor.x - max_dist, sensor.y - max_dist, sensor.x + max_dist, sensor.y + max_dist
bbox = box(minx, miny, maxx, maxy) bbox = box(minx, miny, maxx, maxy)
candidates = self._rack_tree.query(box) candidates = self._rack_tree.query(bbox)
if len(candidates) == 0:
if not candidates: raise LookupError("no candidates in box found")
return None, None
candidates = [self._rack_lines[idx] for idx in candidates]
best_dist = max_dist
for line in candidates: for line in candidates:
dist = sensor.distance(line) dist = sensor.distance(line)
if dist < best_dist: if dist < best_dist:
@@ -461,7 +413,7 @@ class Anlage():
best_line = line best_line = line
if best_dist > max_dist: if best_dist > max_dist:
return None, None raise LookupError("no line in correct distance found")
rack_name = self._rack_map[best_line] rack_name = self._rack_map[best_line]
nearest_point = best_line.interpolate(best_line.project(sensor)) nearest_point = best_line.interpolate(best_line.project(sensor))
@@ -475,11 +427,12 @@ class Anlage():
''' '''
errors = [] errors = []
for name, pos in equipment.items(): for name, pos in equipment.items():
onpoint, rackname = self.find_nearest_rack_from_point_STR_bbox(self._tol_connect, pos) try:
if onpoint == None or rackname == None: onpoint, rackname = self.find_nearest_rack_from_point_STR_bbox(self._tol_connect, pos)
onpoints[name] = (onpoint, rackname)
except LookupError:
errors.append((name, pos)) errors.append((name, pos))
continue continue
onpoints[name] = (onpoint, rackname)
self.add_point_to_rack(onpoint, rackname) self.add_point_to_rack(onpoint, rackname)
virtual_rackname = f"v-{name}-{rackname}" virtual_rackname = f"v-{name}-{rackname}"
@@ -487,76 +440,6 @@ class Anlage():
return errors return errors
def connect_equipment_batch(self, equipment:dict, onpoints:dict) -> list:
if not hasattr(self, "_rack_tree"):
self._build_rack_strtree()
devices = list(equipment.items())
device_names = [name for name, _ in devices]
device_points = [pos for _, pos in devices]
idx_rack, distances = self._rack_tree.query_nearest(device_points, return_distance=True, all_matches=False)
# !!! Problem !!!: query gibt mehrere Ergebnisse zurück -> kann dann nicht zugeordnet werden
# Greifen des ersten ergebnisses nicht zielführend, da nicht das näheste
errors = []
for i, (rack_idxs, dist) in enumerate(zip(idx_rack, distances)):
# Nehme ersten Treffer
rack_idx = int(rack_idxs[0])
dist = float(dist)
if dist > self._tol_connect:
errors.append(devices[i])
continue
eqname, eqpos = devices[i]
nearest_line = self._rack_lines[rack_idx]
rackname = self._rack_map[nearest_line]
onpoint = nearest_line.interpolate(nearest_line.project(eqpos))
onpoints[eqname] = (onpoint, rackname)
self.add_point_to_rack(onpoint, rackname)
virtual_rackname = f"v-{eqname}-{rackname}"
self._racks.add_rack(eqpos, onpoint, virtual_rackname)
return errors
def find_nearest_rack_from_point(self, max_dist, coarse_step, sensor:Point, racks:dict) -> tuple[Point, str]:
# 1. grobe Kandidatensuche
candidate_lines = []
radius = coarse_step
rack_lines = dict()
while radius <= max_dist:
circle = sensor.buffer(radius)
for r_name, pts in racks.items():
line = LineString([pts[0], pts[-1]]) #Linestring aus erstem und letzten Eintrag in Rack dict erzeugen
if circle.intersects(line):
candidate_lines.append((r_name, line))
if candidate_lines:
break
radius += coarse_step
if not candidate_lines:
return None, None
# 2. Feinbestimmung über Distanz
candidates_distance = [
(r_name, line, line.distance(sensor))
for r_name, line in candidate_lines
]
# Sortieren nach Abstand
candidates_distance.sort(key=lambda x: x[2])
'''# Theoretisch könnten mehrere ähnlich naheliegende Racks zurückgegeben werden.'''
r_best, line_best, _ = candidates_distance[0] # Hier wird nur das tatsächlich dem Senso nächste Rack gegriffen
# Aufpunkt bestimmen
nearest_point = line_best.interpolate(line_best.project(sensor))
return (nearest_point, r_best)
def search_connections(self, rack_segments, segment_endpoints, tol, tol_step): def search_connections(self, rack_segments, segment_endpoints, tol, tol_step):
''' Aus Rack Segmenten und Endpunkten der Racks wird unter Berücksichtigung von Toleranz naheliegende Endpunkte gefunden. ''' Aus Rack Segmenten und Endpunkten der Racks wird unter Berücksichtigung von Toleranz naheliegende Endpunkte gefunden.
Zuerst echte Schnittpunkte und im Anschluss via Kreissuche neheliegende Punkte und deren gepinnte Berührpunkte Zuerst echte Schnittpunkte und im Anschluss via Kreissuche neheliegende Punkte und deren gepinnte Berührpunkte
@@ -738,130 +621,120 @@ class Anlage():
class TestPlant(unittest.TestCase):
def test_duplicate_points(self):
''' Testet das Nicht-Hinzufügen von doppelten Punkten'''
# Initialisiere die Liste an Knoten
nodeids = NodeIDs()
# Setze gleichen Knoten doppelt
nodeids.add_point(Point(1,1))
nodeids.add_point(Point(1,1))
self.assertEqual(nodeids.size_of(), 1)
def test_cut_rack_in_segments(self):
''' Teilt Rack aus Polyline in mehrere Segmente automatisch auf.'''
racks_data = {
'Rack_1': [Point(0, 0), Point(0, 10), Point (10, 10)],
'Rack_2': [Point(-5, 5), Point(5, 5)]
}
# Initialisiere Racks
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)
self.assertEqual(rack.get_rack_names(), ['Rack_1-1', 'Rack_1-2', 'Rack_2'])
def test_intersect_segments(self):
''' Stellt Schnittpunkte zwischen Racks fest und fügt Schnittpunkt zu Rack hinzu. '''
racks_data = {
'Rack_1': [Point(0, 0), Point(0, 10), Point (10, 10)],
'Rack_2': [Point(-5, 5), Point(5, 5)],
}
# Initialisiere Racks
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)
# Verknüpfe Racks mit echten Schnittpunkten und füge Schnittpunkte (exakt & beinahe) zu jeweiligem Rack hinzu
rack.join_racks()
self.assertEqual(rack.get_points_from_rack("Rack_1-1"), [Point(0, 0), Point(0, 5), Point (0, 10)])
def test_snap_segments(self):
''' Verlängert Anfangs und Endpunkte von Racks, sodass sie auf naheliegenden Racks liegen'''
racks_data = {
'Rack_1': [Point(0, 0), Point(0, 10)],
'Rack_2': [Point(1, 5), Point(5, 5)],
'Rack_3': [Point(1.5, 7.5), Point(5, 7.5)]
}
# Initialisiere Racks
rack = RackIDs(tol_snap=1)
# Füge Racks aus gegebenen Daten hinzu und teile Rack_1 bestehend aus 3 Punkten in 2 Racks auf
rack.add_racks(racks_data)
# Verknüpfe Racks mit echten Schnittpunkten und füge Schnittpunkte (exakt & beinahe) zu jeweiligem Rack hinzu
rack.join_racks()
#Rack 2 wird verlängert auf SP mit Rack 1. Rack 3 ausserhalb der Toleranz
self.assertEqual(rack.get_points_from_rack("Rack_1"), [Point(0, 0), Point(0, 5), Point (0, 10)])
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)],
'Rack_2-1': [Point(0, 10), Point(5, 10)]}
point2rack = RackIDs()
point2rack.add_racks(res_rack_seg)
class TestLinesweep(unittest.TestCase): 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_points_from_rack("Rack_2-0"), [Point(1, 0), Point(1, 8)])
# def test_duplicate_points(self): def test_add_point_interim(self):
# ''' Testet das Nicht-Hinzufügen von doppelten Punkten''' ''' Testet das hinzufügen und einsortieren eines Zwischenpunktes zwischen Rack-Anfang und Rack-Ende'''
# # Initialisiere die Liste an Knoten
# nodeids = NodeIDs()
# # Setze gleichen Knoten doppelt res_rack_seg = {'Rack_1-0': [Point(1, 0), Point(5, 6)],
# nodeids.add_point(Point(1,1)) 'Rack_2-0': [Point(1, 8), Point(1, 0)],
# nodeids.add_point(Point(1,1)) 'Rack_2-1': [Point(0, 10), Point(5, 10)]}
# self.assertEqual(nodeids.size_of(), 1)
# def test_cut_rack_in_segments(self): point2rack = RackIDs()
# ''' Teilt Rack aus Polyline in mehrere Segmente automatisch auf.''' point2rack.add_racks(res_rack_seg)
# racks_data = { point2rack.add_point_to_rack(Point(1,4), "Rack_2-0")
# 'Rack_1': [Point(0, 0), Point(0, 10), Point (10, 10)],
# 'Rack_2': [Point(-5, 5), Point(5, 5)]
# }
# # Initialisiere Racks self.assertEqual(point2rack.get_points_from_rack("Rack_2-0"), [Point(1, 0), Point(1,4), Point(1, 8)])
# 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)
# self.assertEqual(rack.get_rack_names(), ['Rack_1-1', 'Rack_1-2', 'Rack_2']) 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_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)}
# def test_intersect_segments(self): an = Anlage()
# ''' Stellt Schnittpunkte zwischen Racks fest und fügt Schnittpunkt zu Rack hinzu. ''' point2rack = an.set_racks(rack_segs)
an.add_sensors(sensors)
# racks_data = { plist1 = an.get_points_from_rack("Rack_1-0")
# 'Rack_1': [Point(0, 0), Point(0, 10), Point (10, 10)],
# 'Rack_2': [Point(-5, 5), Point(5, 5)],
# }
# # Initialisiere Racks an.connect_sensors_to_racks()
# rack = RackIDs() plist2 = an.get_points_from_rack("Rack_1-0")
# # Füge Racks aus gegebenen Daten hinzu und teile Rack_1 bestehend aus 3 Punkten in 2 Racks auf
# rack.add_racks(racks_data)
# # Verknüpfe Racks mit echten Schnittpunkten und füge Schnittpunkte (exakt & beinahe) zu jeweiligem Rack hinzu
# rack.join_racks()
# self.assertEqual(rack.get_points_from_rack("Rack_1-1"), [Point(0, 0), Point(0, 5), Point (0, 10)])
# def test_snap_segments(self):
# ''' Verlängert Anfangs und Endpunkte von Racks, sodass sie auf naheliegenden Racks liegen'''
# racks_data = {
# 'Rack_1': [Point(0, 0), Point(0, 10)],
# 'Rack_2': [Point(1, 5), Point(5, 5)],
# 'Rack_3': [Point(1.5, 7.5), Point(5, 7.5)]
# }
# # Initialisiere Racks
# rack = RackIDs(tol_snap=1)
# # Füge Racks aus gegebenen Daten hinzu und teile Rack_1 bestehend aus 3 Punkten in 2 Racks auf
# rack.add_racks(racks_data)
# # Verknüpfe Racks mit echten Schnittpunkten und füge Schnittpunkte (exakt & beinahe) zu jeweiligem Rack hinzu
# rack.join_racks()
# #Rack 2 wird verlängert auf SP mit Rack 1. Rack 3 ausserhalb der Toleranz
# self.assertEqual(rack.get_points_from_rack("Rack_1"), [Point(0, 0), Point(0, 5), Point (0, 10)])
# 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)],
# 'Rack_2-1': [Point(0, 10), Point(5, 10)]}
# point2rack = RackIDs()
# point2rack.add_racks(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(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 hinzufügen und einsortieren eines Zwischenpunktes zwischen Rack-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)],
# 'Rack_2-1': [Point(0, 10), Point(5, 10)]}
# point2rack = RackIDs()
# point2rack.add_racks(res_rack_seg)
# 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)])
# 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_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()
# point2rack = an.set_racks(rack_segs)
# an.add_sensors(sensors)
# plist1 = an.get_points_from_rack("Rack_1-0")
# an.connect_sensors_to_racks()
# plist2 = an.get_points_from_rack("Rack_1-0")
# self.assertEqual(plist1, [Point(0, 0), Point(0, 10)])
# self.assertEqual(plist2, [Point(0, 0), Point(0,1), Point(0, 10)])
self.assertEqual(plist1, [Point(0, 0), Point(0, 10)])
self.assertEqual(plist2, [Point(0, 0), Point(0,1), Point(0, 10)])
def test_add_equipment_w_tree(self): def test_add_equipment_w_tree(self):
@@ -876,7 +749,7 @@ class TestLinesweep(unittest.TestCase):
distributors = {'Dist_1': Point(-1, 9), distributors = {'Dist_1': Point(-1, 9),
'Dist_2': Point(11, 0)} 'Dist_2': Point(11, 0)}
an = Anlage(tol_snap=1.5) an = Anlage(tol_snap=1.5, tol_connect=1.5)
an.set_racks(racks) an.set_racks(racks)
an.join_racks() an.join_racks()
@@ -892,192 +765,190 @@ class TestLinesweep(unittest.TestCase):
self.assertEqual(plist1, [Point(0, 0), Point(0, 1), Point(0, 3), Point(0, 9), Point(0, 10)]) self.assertEqual(plist1, [Point(0, 0), Point(0, 1), Point(0, 3), Point(0, 9), Point(0, 10)])
self.assertEqual(plist2, [Point(10, -2), Point(10, 0), Point(10, 2), Point(10, 3), Point(10, 5)]) self.assertEqual(plist2, [Point(10, -2), Point(10, 0), Point(10, 2), Point(10, 3), Point(10, 5)])
def test_wegsuche_str_tree(self):
# def test_add_equipment_w_tree_batch(self): # Beispiel-Daten
points = [Point(x, y) for x, y in [(1, 2), (3, 4), (5, 5), (7, 8)]]
lines = [LineString([(0, 1), (2, 3)]), LineString([(4, 4), (6, 6)]), LineString([(8, 8), (10, 10)])]
# racks = {'Rack_1': [Point(0, 0), Point(0, 10)], # STRtree erstellen mit tatsächlichen LineStrings
# 'Rack_2': [Point(10, -2), Point(10, 5)], tree = STRtree(lines)
# 'Rack_3': [Point(0, 3), Point(10, 3)]}
# sensors = {'Sens_1': Point(1, 1), # Zuordnung
# 'Sens_2': Point(2, 4), nearest_line_for_point = {}
# 'Sens_3': Point(9, 2)} for point in points:
candidates = tree.query(point) # Gibt direkt LineStrings zurück
if not candidates:
continue
candidates = [lines[idx] for idx in candidates]
nearest_line = min(candidates, key=lambda line: line.distance(point))
nearest_line_for_point[point] = nearest_line
# distributors = {'Dist_1': Point(-1, 9), # Ausgabe
# 'Dist_2': Point(11, 0)} for point, line in nearest_line_for_point.items():
print(f"Punkt {point} liegt am nächsten zu Linie {line}")
# an = Anlage(tol_snap=1) def test_wegsuche_w_tree(self):
# an.set_racks(racks) racks = {'Rack_1-0': [Point(0, 0), Point(0, 10)],
# an.join_racks() 'Rack_2-0': [Point(10, -2), Point(10, 5)],
'Rack_2-1': [Point(0, 3), Point(10, 3)]}
# an.add_sensors(sensors) sensors = {'Sens_1': Point(1, 1),
# an.add_distributors(distributors) 'Sens_2': Point(2, 4),
# an.connect_equipment_batch(an._sensors, an._sensor_onpoints) 'Sens_3': Point(9, 2)}
# an.connect_equipment_batch(an._distributors, an._distributors_onpoints)
# plist1 = an.get_points_from_rack("Rack_1") distributors = {'Dist_1': Point(-1, 9),
# plist2 = an.get_points_from_rack("Rack_2") 'Dist_2': Point(11, 0)}
# G1 = nx.Graph() mapping = {'Dist_1': ['Sens_1', 'Sens_2'],
# pos = an.generate_graph(G1) 'Dist_2': ['Sens_3']}
# nx.draw(G1, pos, with_labels=False, node_size=10, font_size=8)
# plt.show() an = Anlage(tol_snap=1)
an.set_racks(racks)
an.join_racks()
an.add_sensors(sensors)
an.add_distributors(distributors)
an.connect_equipment_to_racks(an._sensors, an._sensor_onpoints)
an.connect_equipment_to_racks(an._distributors, an._distributors_onpoints)
an.map_distributors_to_sensors(mapping)
G = nx.Graph()
#Fülle eben erstellten Graphen mit Daten
pos = an.generate_graph(G)
#Extrahiere Farb-Informationen der Kanten
edge_colors = [G[u][v].get('color', 'black') for u, v in G.edges()]
#Zeiche Graphen und zeige in
nx.draw(G, pos, with_labels=False, node_size=10, font_size=8, edge_color=edge_colors)
plt.show()
#Ermittle kürzeste Wege von Unterverteilern zu zugehörigen Sensoren
paths = an.create_cable_paths(G)
paths_by_id = {p['id']: p for p in paths["kabel"]}
# self.assertEqual(plist1, [Point(0, 0), Point(0, 1), Point(0, 3), Point(0, 9), Point(0, 10)]) self.assertEqual(paths_by_id['Dist_1-Sens_1']["coords"], [{'x': -1.0, 'y': 9.0}, {'x': 0.0, 'y': 9.0}, {'x': 0.0, 'y': 3.0}, {'x': 0.0, 'y': 1.0}, {'x': 1.0, 'y': 1.0}])
# self.assertEqual(plist2, [Point(10, -2), Point(10, 0), Point(10, 2), Point(10, 3), Point(10, 5)]) self.assertEqual(paths_by_id['Dist_1-Sens_2']["coords"], [{'x': -1.0, 'y': 9.0}, {'x': 0.0, 'y': 9.0}, {'x': 0.0, 'y': 3.0}, {'x': 2.0, 'y': 3.0}, {'x': 2.0, 'y': 4.0}])
self.assertEqual(paths_by_id['Dist_2-Sens_3']["coords"], [{'x': 11.0, 'y': 0.0}, {'x': 10.0, 'y': 0.0}, {'x': 10.0, 'y': 2.0}, {'x': 9.0, 'y': 2.0}])
self.assertEqual(paths_by_id['Dist_1-Sens_1']["length"], 10)
self.assertEqual(paths_by_id['Dist_1-Sens_2']["length"], 10)
self.assertEqual(paths_by_id['Dist_2-Sens_3']["length"], 4)
def test_generate_graph(self):
'''Generiert einen Graphen in 3 unterschiedlichen Ausbaustufen (nur Racks, Racks+Sensoren, Racks+Sensoren+Unterverteiler)'''
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)}
distributors = {'Dist_1': Point(-1, 9),
'Dist_2': Point(11, 0)}
an = Anlage()
an.set_racks(rack_segs)
an.join_racks
G1 = nx.Graph()
pos = an.generate_graph(G1)
nx.draw(G1, pos, with_labels=False, node_size=10, font_size=8)
plt.show()
an.add_sensors(sensors)
an.connect_sensors_to_racks()
G2 = nx.Graph()
pos = an.generate_graph(G2)
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)
plt.show()
an.add_distributors(distributors)
an.connect_distributor_to_racks()
G3 = nx.Graph()
pos = an.generate_graph(G3)
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()
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': [Point(0, 0), Point(0, 10)],
'Rack_2': [Point(10, -2), Point(10, 5)],
'Rack_3': [Point(0, 3), Point(10, 3)]}
sensors = {'Sens_1': Point(1, 1),
'Sens_2': Point(2, 4),
'Sens_3': Point(9, 2)}
distributors = {'Dist_1': Point(-1, 9),
'Dist_2': Point(11, 0)}
mapping = {'Dist_1': ['Sens_1', 'Sens_2'],
'Dist_2': ['Sens_3']}
#Erstelle Anlage
an = Anlage(tol_snap=1)
#Füge racks aus Daten hinzu
an.set_racks(rack_segs)
#Verbinde Racks miteinander (ggf. verlängere ungenaue Racks)
an.join_racks()
#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()
#Ermittle kürzeste Wege von Unterverteilern zu zugehörigen Sensoren
paths = an.create_cable_paths(G3)
paths_by_id = {p['id']: p for p in paths["kabel"]}
self.assertEqual(paths_by_id['Dist_1-Sens_1']["coords"], [{'x': -1.0, 'y': 9.0}, {'x': 0.0, 'y': 9.0}, {'x': 0.0, 'y': 3.0}, {'x': 0.0, 'y': 1.0}, {'x': 1.0, 'y': 1.0}])
self.assertEqual(paths_by_id['Dist_1-Sens_2']["coords"], [{'x': -1.0, 'y': 9.0}, {'x': 0.0, 'y': 9.0}, {'x': 0.0, 'y': 3.0}, {'x': 2.0, 'y': 3.0}, {'x': 2.0, 'y': 4.0}])
self.assertEqual(paths_by_id['Dist_2-Sens_3']["coords"], [{'x': 11.0, 'y': 0.0}, {'x': 10.0, 'y': 0.0}, {'x': 10.0, 'y': 2.0}, {'x': 9.0, 'y': 2.0}])
# def test_wegsuche_w_tree(self): self.assertEqual(paths_by_id['Dist_1-Sens_1']["length"], 10)
# racks = {'Rack_1-0': [Point(0, 0), Point(0, 10)], self.assertEqual(paths_by_id['Dist_1-Sens_2']["length"], 10)
# 'Rack_2-0': [Point(10, -2), Point(10, 5)], self.assertEqual(paths_by_id['Dist_2-Sens_3']["length"], 4)
# '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)}
# distributors = {'Dist_1': Point(-1, 9),
# 'Dist_2': Point(11, 0)}
# mapping = {'Dist_1': ['Sens_1', 'Sens_2'],
# 'Dist_2': ['Sens_3']}
# an = Anlage(tol_snap=1)
# an.set_racks(racks)
# an.join_racks()
# an.add_sensors(sensors)
# an.add_distributors(distributors)
# an.connect_equipment_to_racks(an._sensors, an._sensor_onpoints)
# an.connect_equipment_to_racks(an._distributors, an._distributors_onpoints)
# an.map_distributors_to_sensors(mapping)
# G = nx.Graph()
# Fülle eben erstellten Graphen mit Daten
# pos = an.generate_graph(G)
# Extrahiere Farb-Informationen der Kanten
# edge_colors = [G[u][v].get('color', 'black') for u, v in G.edges()]
# Zeiche Graphen und zeige in
# nx.draw(G, pos, with_labels=False, node_size=10, font_size=8, edge_color=edge_colors)
# plt.show()
# Ermittle kürzeste Wege von Unterverteilern zu zugehörigen Sensoren
# paths = an.create_cable_paths(G)
# paths_by_id = {p['id']: p for p in paths["kabel"]}
# self.assertEqual(paths_by_id['Dist_1-Sens_1']["coords"], [{'x': -1.0, 'y': 9.0}, {'x': 0.0, 'y': 9.0}, {'x': 0.0, 'y': 3.0}, {'x': 0.0, 'y': 1.0}, {'x': 1.0, 'y': 1.0}])
# self.assertEqual(paths_by_id['Dist_1-Sens_2']["coords"], [{'x': -1.0, 'y': 9.0}, {'x': 0.0, 'y': 9.0}, {'x': 0.0, 'y': 3.0}, {'x': 2.0, 'y': 3.0}, {'x': 2.0, 'y': 4.0}])
# self.assertEqual(paths_by_id['Dist_2-Sens_3']["coords"], [{'x': 11.0, 'y': 0.0}, {'x': 10.0, 'y': 0.0}, {'x': 10.0, 'y': 2.0}, {'x': 9.0, 'y': 2.0}])
# self.assertEqual(paths_by_id['Dist_1-Sens_1']["length"], 10)
# self.assertEqual(paths_by_id['Dist_1-Sens_2']["length"], 10)
# self.assertEqual(paths_by_id['Dist_2-Sens_3']["length"], 4)
# def test_generate_graph(self):
# '''Generiert einen Graphen in 3 unterschiedlichen Ausbaustufen (nur Racks, Racks+Sensoren, Racks+Sensoren+Unterverteiler)'''
# 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)}
# distributors = {'Dist_1': Point(-1, 9),
# 'Dist_2': Point(11, 0)}
# an = Anlage()
# an.set_racks(rack_segs)
# an.join_racks
# G1 = nx.Graph()
# pos = an.generate_graph(G1)
# nx.draw(G1, pos, with_labels=False, node_size=10, font_size=8)
# plt.show()
# an.add_sensors(sensors)
# an.connect_sensors_to_racks()
# G2 = nx.Graph()
# pos = an.generate_graph(G2)
# 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)
# plt.show()
# an.add_distributors(distributors)
# an.connect_distributor_to_racks()
# G3 = nx.Graph()
# pos = an.generate_graph(G3)
# 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()
# 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': [Point(0, 0), Point(0, 10)],
# 'Rack_2': [Point(10, -2), Point(10, 5)],
# 'Rack_3': [Point(0, 3), Point(10, 3)]}
# sensors = {'Sens_1': Point(1, 1),
# 'Sens_2': Point(2, 4),
# 'Sens_3': Point(9, 2)}
# distributors = {'Dist_1': Point(-1, 9),
# 'Dist_2': Point(11, 0)}
# mapping = {'Dist_1': ['Sens_1', 'Sens_2'],
# 'Dist_2': ['Sens_3']}
# Erstelle Anlage
# an = Anlage(tol_snap=1)
# Füge racks aus Daten hinzu
# an.set_racks(rack_segs)
# Verbinde Racks miteinander (ggf. verlängere ungenaue Racks)
# an.join_racks()
# 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()
# Ermittle kürzeste Wege von Unterverteilern zu zugehörigen Sensoren
# paths = an.create_cable_paths(G3)
# paths_by_id = {p['id']: p for p in paths["kabel"]}
# self.assertEqual(paths_by_id['Dist_1-Sens_1']["coords"], [{'x': -1.0, 'y': 9.0}, {'x': 0.0, 'y': 9.0}, {'x': 0.0, 'y': 3.0}, {'x': 0.0, 'y': 1.0}, {'x': 1.0, 'y': 1.0}])
# self.assertEqual(paths_by_id['Dist_1-Sens_2']["coords"], [{'x': -1.0, 'y': 9.0}, {'x': 0.0, 'y': 9.0}, {'x': 0.0, 'y': 3.0}, {'x': 2.0, 'y': 3.0}, {'x': 2.0, 'y': 4.0}])
# self.assertEqual(paths_by_id['Dist_2-Sens_3']["coords"], [{'x': 11.0, 'y': 0.0}, {'x': 10.0, 'y': 0.0}, {'x': 10.0, 'y': 2.0}, {'x': 9.0, 'y': 2.0}])
# self.assertEqual(paths_by_id['Dist_1-Sens_1']["length"], 10)
# self.assertEqual(paths_by_id['Dist_1-Sens_2']["length"], 10)
# self.assertEqual(paths_by_id['Dist_2-Sens_3']["length"], 4)
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() suite = unittest.TestSuite()
suite.addTest(TestPlant('test_duplicate_points'))
suite.addTest(TestPlant('test_cut_rack_in_segments'))
suite.addTest(TestPlant('test_intersect_segments'))
suite.addTest(TestPlant('test_snap_segments'))
suite.addTest(TestPlant('test_ids_to_point'))
suite.addTest(TestPlant('test_add_point_interim'))
suite.addTest(TestPlant('test_add_sensor'))
suite.addTest(TestPlant('test_add_equipment_w_tree'))
suite.addTest(TestPlant('test_add_equipment_w_tree_batch'))
suite.addTest(TestPlant('test_wegsuche_str_tree'))
suite.addTest(TestPlant('test_wegsuche_w_tree'))
suite.addTest(TestPlant('test_generate_graph'))
suite.addTest(TestPlant('test_Wegsuche'))
runner = unittest.TextTestRunner()
runner.run(suite)
#unittest.main()
-3
View File
@@ -20,9 +20,6 @@ pip-tools==7.4.1
PyMuPDF==1.25.5 PyMuPDF==1.25.5
pyparsing==3.2.3 pyparsing==3.2.3
pyproject_hooks==1.2.0 pyproject_hooks==1.2.0
PySide6==6.9.0
PySide6_Addons==6.9.0
PySide6_Essentials==6.9.0
python-dateutil==2.8.2 python-dateutil==2.8.2
pytz==2023.3.post1 pytz==2023.3.post1
setuptools==80.0.0 setuptools==80.0.0