Alte Hilfsfunktionen gelöscht. Erste Funktionen aus linesweep_cicle implementiert

This commit is contained in:
2025-05-12 17:27:07 +02:00
parent c087e3ada9
commit 58e121bdcf
+54 -168
View File
@@ -5,118 +5,37 @@ import heapq
import math
import matplotlib.pyplot as plt
import networkx as nx
from shapely.geometry import LineString, Point
from shapely.ops import nearest_points
# Hilfsfunktionen
def load_json(filepath):
with open(filepath, 'r', encoding='utf-8') as f:
return json.load(f)
# Funktionen
def parse_pos(pos_str):
""" Konvertiert '(x, y)' oder '(x, y, z)' in ein Tuple """
try:
return tuple(map(float, pos_str.strip('[]').split(',')))
except Exception:
raise ValueError(f"Ungültiges Positionsformat: {pos_str}")
def distance(p1, p2):
""" Euklidische Distanz in 2D """
return math.sqrt((p1[0] - p2[0])**2 + (p1[1] - p2[1])**2)
def add_edge(graph, node1, node2, dist):
""" Fügt eine ungerichtete Kante zwischen zwei Knoten hinzu, aber nur einmal """
if node1 not in graph:
graph[node1] = []
if node2 not in graph:
graph[node2] = []
# Nur hinzufügen, wenn Kante noch nicht existiert (ungerichtet)
if not any(n == node2 for n, _ in graph[node1]):
graph[node1].append((node2, dist))
if not any(n == node1 for n, _ in graph[node2]):
graph[node2].append((node1, dist))
def project_point_on_segment(p, a, b):
""" Projektion eines Punktes p auf ein Liniensegment a-b """
ax, ay = a
bx, by = b
px, py = p
dx = bx - ax
dy = by - ay
if dx == dy == 0:
return a
t = ((px - ax) * dx + (py - ay) * dy) / (dx * dx + dy * dy)
t = max(0, min(1, t)) # Begrenze t auf [0,1]
return (ax + t * dx, ay + t * dy)
def dijkstra(graph, start):
""" Dijkstra-Algorithmus, um die kürzesten Wege im Graphen zu berechnen """
distances = {node: float('inf') for node in graph}
distances[start] = 0
priority_queue = [(0, start)] # (Distanz, Knoten)
def rack_segmentation(racks):
''' Racks werden zu LineString konvertiert. Racks bestehend aus Polylinine werden in einzelne Segmente zerlegt.'''
rack_segments = []
for rack_id, nodes in racks.items():
# Sortiere Node_1, Node_2, ...
sorted_keys = sorted(nodes.keys(), key=lambda k: int(k.split("_")[1]))
coords = [tuple(nodes[k]) for k in sorted_keys]
for i in range(len(coords) - 1):
p1, p2 = coords[i], coords[i+1]
line = LineString([p1, p2])
rack_segments.append((rack_id, i, line))
while priority_queue:
current_distance, current_node = heapq.heappop(priority_queue)
return(rack_segments)
if current_distance > distances[current_node]:
continue
def rack_endpoints(rack_segments)
''' Endpunkte der Racks werden in Points konvertiert'''
segment_endpoints = []
for rack_id, idx, line in rack_segments:
for pt in [line.coords[0], line.coords[1]]:
segment_endpoints.append((rack_id, idx, Point(pt)))
for neighbor, weight in graph[current_node]:
distance = current_distance + weight
return(segment_endpoints)
if distance < distances[neighbor]:
distances[neighbor] = distance
heapq.heappush(priority_queue, (distance, neighbor))
return distances
def print_graph(graph):
printed = set()
for node, edges in graph.items():
for neighbor, dist in edges:
edge_id = tuple(sorted((node, neighbor)))
if edge_id not in printed:
printed.add(edge_id)
print(f"{edge_id[0]} --> {edge_id[1]} (Distanz: {dist})")
def visualize_graph(graph, racks):
G = nx.Graph()
pos = {}
for node, edges in graph.items():
pos[node] = node_to_coords(node, racks)
for neighbor, distance in edges:
if not G.has_edge(node, neighbor): # Doppelte Kanten vermeiden
G.add_edge(node, neighbor, weight=round(distance, 1))
plt.figure(figsize=(10, 10))
nx.draw(
G, pos,
with_labels=True,
node_size=100,
font_size=8,
node_color='skyblue',
edge_color='gray'
)
edge_labels = nx.get_edge_attributes(G, 'weight')
nx.draw_networkx_edge_labels(G, pos, edge_labels=edge_labels, font_size=6)
plt.title("Rack-Graph (aus racks.json)")
plt.axis("equal")
plt.tight_layout()
plt.show()
def node_to_coords(node_name, racks):
"""Extrahiert die Koordinaten aus dem Knotennamen wie 'Rack_1_Node_2'"""
parts = node_name.split("_")
rack = f"{parts[0]}_{parts[1]}"
node = f"{parts[2]}_{parts[3]}"
coords = racks[rack][node]
return tuple(coords)
def pin_rack_endpoints(rack_segments, segment_endpoints)
'''Erstellung eines Dicts, welches unter dem Key "Rack_id - Index" die Endpunkte der Racks speichert. Endpunkte von Racks innerhalb der Toleranz werden an nahegelegenes Rack gepinnt.'''
@@ -142,73 +61,40 @@ if __name__ == "__main__":
subdists = data["distributors"]
racks = data["racks"]
# Graph erstellen
graph = {}
for rack_id, rack in racks.items():
nodes = list(rack.values()) # Liste aller Knoten im Rack
for i in range(len(nodes) - 1):
segment_start = tuple(nodes[i])
segment_end = tuple(nodes[i + 1])
dist = distance(segment_start, segment_end)
# Erstelle Kanten zwischen den benachbarten Knoten
add_edge(graph, f"{rack_id}_Node_{i+1}", f"{rack_id}_Node_{i+2}", dist)
# Graph in Kommandozeile beschreiben und mittels matplotlib ausgeben
print("\nGraph basierend auf den Racks (ungerichtet, eindeutige Kanten):")
print_graph(graph)
visualize_graph(graph, racks)
# 1. Alle Kreuzungspunkte der Racks ermitteln
''' Funktion linesweep_circle wird aufgerufen.
Eingabe für Funktion: Nummerierte Racks aus getpositions.py. Reine Liste aus Koordinaten [((Anfang), (Ende)), ((Anfang), (Ende)), ... ] wird in Funktion erstellt
Racks werden abgelaufen und tatsächliche Schnittpunkte sowie Nahezu-Schnitte erfasst.
Ausgabe von Linesweep Circle: Liste von Endpunkten der Racks aus .dxf & Liste von SP von Rack_a mit Rack_b
'''
"""# 1. Vom Sensor zum Rack laufen und Knoten einfügen
for sensor_id, sensor_info in sensors.items():
sensor_pos = tuple(sensor_info['pos'])
for rack in racks:
for segment_start, segment_end in zip(rack[:-1], rack[1:]):
# Berechne Distanz von Sensor zur Kabeltrasse
px, py = project_point_on_segment(sensor_pos, segment_start, segment_end)
dist = distance(sensor_pos, (px, py))
rack_id = f"rack_{rack}"
# Sensor zum Rack Knoten verbinden
add_edge(graph, sensor_id, rack_id, dist)
# 2. Graph aus Racks erstellen
''' Zunächst leeren Graph erstellen.
Endpunkte der Racks wie in .dxf als Knoten hinzufügen. Kanten zwischen den Knoten ebenso hinzufügen.
Mittels ausgabe von linesweep_cirle: weitere Knoten auf Kanten hinzufügen und graph vollständig verknüpfen
# 2. Vom Unterverteiler (UV) zum Rack laufen und Knoten einfügen
for uc_id, uc_pos in subdists.items():
for rack in racks:
for segment_start, segment_end in zip(rack[:-1], rack[1:]):
# Berechne Distanz von UV zur Kabeltrasse
px, py = project_point_on_segment(uc_pos, segment_start, segment_end)
dist = distance(uc_pos, (px, py))
rack_id = f"rack_{rack}"
# UV zum Rack Knoten verbinden
add_edge(graph, uc_id, rack_id, dist)
Frage: Problematisch, wenn Knoten sehr nahe beieinander liegen also teoretischen "Doppelt" sind? -> lieber Endpunkte von Racks, die über linesweep_circle gefunden werden überschreiben?
# 3. Vom Sensor Knoten zum zugehörigen Unterverteiler Knoten entlang der Racks
for sensor_id, sensor_info in sensors.items():
subdist_id = None
if 'KENNZEICHNUNG' in sensor_info:
for uc_id in subdists:
if uc_id in sensor_info['KENNZEICHNUNG']:
subdist_id = uc_id
break
if subdist_id:
# Verbinde den Sensor mit dem zugehörigen Unterverteiler
sensor_pos = tuple(sensor_info['pos'])
uc_pos = subdists[subdist_id]
# Berechne Distanz von Sensor zum Unterverteiler (über Trassen)
dist = distance(sensor_pos, uc_pos)
add_edge(graph, sensor_id, subdist_id, dist)
Zusätzlich: über shapely und distance funktion sämtliche Distanzen bestimmen und Graph gewichten
'''
# 4. Berechnung der kürzesten Wege mit Dijkstra
routing_result = {}
for sensor_id in sensors:
distances = dijkstra(graph, sensor_id)
routing_result[sensor_id] = distances
# 3. Sensoren mit nächstgelegenen Racks verknüpfen
''' Für jeden Sensor: Sensor pos aus json zu Graph hinzufügen
Für jeden Sensor: shapely.distance aufrufen und distance zu allen Racks bzw. Edges ermitteln. (if distance(a) > distance(b) -> Circle_methode um Sensor und Schnittpunkt zu Rack_b ermitteln)
SP von Sensor mit Rack als Node hinzufügen und Connection zwischen Sensor, Node, Edge herstellen
'''
if args.console:
print(json.dumps(routing_result, indent=2))"""
# 4. Unterverteiler mit nächstegelegenen Racks verknüpfen
''' siehe 3.
'''
# 5. Bestimmung des küzesten Wegs
''' über Graphen-Toolbox z.B. nx wird für jeden Knoten zu dessen zugehörigen Unterverteilung der kürzeste Weg gefunden.
Schreiben der Ergebnisse in eine seperate kabel.json z.B.
'''