Erweiterung des Skripts mit Linienverlängerung. Code allerdings unscoen, if-edundanzen, etc. Kein zufriedenstellendes Ergebnis.

This commit is contained in:
2025-05-09 16:05:58 +02:00
parent 0aa82f9674
commit 22d7d97341
2 changed files with 177 additions and 51 deletions
+109 -51
View File
@@ -2,7 +2,7 @@ from bisect import bisect_left, bisect_right,insort
import unittest import unittest
from collections import namedtuple from collections import namedtuple
import math import math
from shapely.geometry import LineString from shapely.geometry import LineString, Point
from itertools import combinations from itertools import combinations
@@ -31,7 +31,6 @@ def find_intersections(horizontal_segments, vertical_segments, epsilon=0.0):
return intersections return intersections
def find_all_intersections(segments): def find_all_intersections(segments):
# segments: List of ((x1, y1), (x2, y2)) # segments: List of ((x1, y1), (x2, y2))
lines = [LineString([p1, p2]) for p1, p2 in segments] lines = [LineString([p1, p2]) for p1, p2 in segments]
@@ -48,7 +47,7 @@ def find_all_intersections(segments):
return list(intersections) return list(intersections)
def find_touch_cut_close(segments): def find_touch_cut_close(segments, tol):
# segments: Liste aus ((x1, y1), (x2,y2)) mit 1=Anfang, 2=Ende # segments: Liste aus ((x1, y1), (x2,y2)) mit 1=Anfang, 2=Ende
verbindungen = [] verbindungen = []
for i,(s1_start, s1_end) in enumerate(segments): for i,(s1_start, s1_end) in enumerate(segments):
@@ -58,11 +57,67 @@ def find_touch_cut_close(segments):
continue continue
line2 = LineString([s2_start,s2_end]) line2 = LineString([s2_start,s2_end])
if line1.distance(line2) < 0.5: #Toleranz 0,5 Hardcode if line1.distance(line2) < tol:
verbindungen.append((i,j,line1.intersection(line2))) verbindungen.append((i,j,line1.intersection(line2)))
return verbindungen return verbindungen
def find_touch_cut_close_ext(segments,tol):
# segments: Liste aus ((x1, y1), (x2,y2)) mit 1=Anfang, 2=Ende
verbindungen = []
for i,(s1_start, s1_end) in enumerate(segments):
line1 = LineString([s1_start, s1_end])
for j, ([s2_start, s2_end]) in enumerate(segments):
if i >= j:
continue
line2 = LineString([s2_start,s2_end])
#Prüfe Abstand
if line1.distance(line2) < tol:
schnitt = line1.intersection(line2) #Existiert tatsächlicher SP?
if schnitt.is_empty:
#Prüfen, welcher Endpunkt von Segment näer an line2
dist_start = Point(s2_start).distance(line1) #Abstand Statpunkt v. Linie1 zu Linie2
dist_end = Point(s2_end).distance(line1) #Abstand Endpunkt v. Linie 1 zu Linie2
if dist_start > dist_end:
line2_ext = extend_from_point(s2_start, s2_end)
else:
line2_ext =extend_from_point(s2_end, s2_start)
if dist_start < dist_end:
line1_ext = extend_from_point(s1_start, s1_end)
else:
line1_ext = extend_from_point(s1_end, s1_start)
schnitt_ext1 = line2_ext.intersection(line1)
schnitt_ext2 = line1_ext.intersection(line2)
if not schnitt_ext1.is_empty:
verbindungen.append((i,j,schnitt_ext1))
if not schnitt_ext2.is_empty:
verbindungen.append((i,j,schnitt_ext2))
else:
verbindungen.append((i,j,schnitt))
return verbindungen
def extend_from_point(p1, p2, max_extension=0.3):
"""Verlängert eine Linie von p1 in Richtung p2 um `max_extension`."""
dx = p2[0] - p1[0]
dy = p2[1] - p1[1]
length = math.hypot(dx, dy)
if length == 0:
return LineString([p1, p1]) # Kein Verlängern möglich
# Normierter Richtungsvektor * (ursprüngliche Länge + Verlängerung)
scale = (length + max_extension) / length
new_end = (p1[0] + dx * scale, p1[1] + dy * scale)
return LineString([p1, new_end])
@@ -109,61 +164,48 @@ def find_touch_cut_close(segments):
# self.assertEqual( [(0,0),(0,0)], b) # self.assertEqual( [(0,0),(0,0)], b)
# class TestScanLineAllgMethods(unittest.TestCase): # class TestScanLineAllgMethods(unittest.TestCase):
# def test_sweep(self): def test_sweep(self):
# seks = [((1, 2), (5, 2)), ((3, 4), (7, 4)), ((4, 1), (4, 5)), ((6, 3), (6, 6))] seks = [((1, 2), (5, 2)), ((3, 4), (7, 4)), ((4, 1), (4, 5)), ((6, 3), (6, 6))]
# a = find_all_intersections(seks) a = find_all_intersections(seks)
# self.assertEqual( [(4,2),(4,4),(6,4)], a) self.assertEqual( [(4,2),(4,4),(6,4)], a)
# def test_tol_hor(self): def test_tol_hor(self):
# """Testet die Anzahl der Schnittpunkte bei gegebener Toleranz """Testet die Anzahl der Schnittpunkte bei gegebener Toleranz
# schnittpunkt zwischen gegebener horizontalen und zu kurzen vertikalen schnittpunkt zwischen gegebener horizontalen und zu kurzen vertikalen
# """ """
# seks = [((0, 0), (10, 0)), ((4, 0.6), (4, 5)), ((6, 0.2), (6, 6)),((8,-0.2),(8, 4))] seks = [((0, 0), (10, 0)), ((4, 0.6), (4, 5)), ((6, 0.2), (6, 6)),((8,-0.2),(8, 4))]
# b = find_all_intersections(seks, 0.5) b = find_all_intersections(seks, 0.5)
# self.assertEqual( len(b), 2) self.assertEqual( len(b), 2)
# self.assertEqual( [(6,0),(8,0)], b) self.assertEqual( [(6,0),(8,0)], b)
# def test_tol_ver(self): def test_tol_ver(self):
# """Testet die Anzahl der Schnittpunkte bei gegebener Toleranz """Testet die Anzahl der Schnittpunkte bei gegebener Toleranz
# schnittpunkt zwischen gegebener vertikalen und zu kurzen horizontalen schnittpunkt zwischen gegebener vertikalen und zu kurzen horizontalen
# """ """
# seks = [((0.2, 0), (9.8, 0)), ((0, 0), (0, 10)), ((10, 0), (10, 10))] seks = [((0.2, 0), (9.8, 0)), ((0, 0), (0, 10)), ((10, 0), (10, 10))]
# b = find_all_intersections(seks, 0.5) b = find_all_intersections(seks, 0.5)
# self.assertEqual( len(b), 2) self.assertEqual( len(b), 2)
# self.assertEqual( [(6,0),(8,0)], b) self.assertEqual( [(6,0),(8,0)], b)
# def test_tol_diag(self): def test_tol_diag(self):
# """Testet die Anzahl der Schnittpunkte bei gegebener Toleranz """Testet die Anzahl der Schnittpunkte bei gegebener Toleranz
# Horizontale mit Diagonalen Horizontale mit Diagonalen
# """ """
# seks = [((0, 0), (5, 0)), ((0, -5), (10, 5))] seks = [((0, 0), (5, 0)), ((0, -5), (10, 5))]
# b = find_all_intersections(seks, 0.5) b = find_all_intersections(seks, 0.5)
# self.assertEqual( len(b), 1) self.assertEqual( len(b), 1)
# self.assertEqual( [(6,0),(8,0)], b) self.assertEqual( [(6,0),(8,0)], b)
# def test_shapely(self): def test_shapely(self):
# # Beispiel # Beispiel
# segments = [
# ((0, 0), (4, 4)), # Diagonal /
# ((0, 4), (4, 0)), # Diagonal \
# ((2, -1), (2, 5)), # Vertikal
# ((-1, 2), (5, 2)) # Horizontal
# ]
# result = find_all_intersections(segments)
# print(result)
class TestShapely(unittest.TestCase):
def test_shapely_2_Stern(self):
# Beispiel !Stern mit gemeinsamen Schnittpunkt in (2,2)
segments = [ segments = [
((0, 0), (4, 4)), # Diagonal / ((0, 0), (4, 4)), # Diagonal /
((0, 4), (4, 0)), # Diagonal \ ((0, 4), (4, 0)), # Diagonal \
@@ -171,10 +213,12 @@ class TestShapely(unittest.TestCase):
((-1, 2), (5, 2)) # Horizontal ((-1, 2), (5, 2)) # Horizontal
] ]
result = find_touch_cut_close(segments) result = find_all_intersections(segments)
self.assertEqual(len(result),1) print(result)
def test_shapely_2_Rand(self):
class TestShapely(unittest.TestCase):
def test_shapely(self):
#Test mit Strecken horizontal, vertikal, diagonal, Schnittpunkt u. Annaeherung #Test mit Strecken horizontal, vertikal, diagonal, Schnittpunkt u. Annaeherung
segments = [ segments = [
((0, 0), (5, 0)), # Horizontale ((0, 0), (5, 0)), # Horizontale
@@ -183,8 +227,22 @@ class TestShapely(unittest.TestCase):
((0.25, 4), (4, 3)) # Diagonale \ mit 0.25 Abstand zu vertikaler und 1 zu horizontaler ((0.25, 4), (4, 3)) # Diagonale \ mit 0.25 Abstand zu vertikaler und 1 zu horizontaler
] ]
result = find_touch_cut_close(segments) result = find_touch_cut_close(segments, 0.5)
self.assertEqual(len(result),3) self.assertEqual(len(result),3)
def test_shapely_ext(self):
#Test mit Strecken horizontal, vertikal, diagonal, Schnittpunkt u. Annaeherung
segments = [
((0, 0), (5, 0)), # Horizontale
((0, 0), (0, 5)), # Vertikale mit Schnitt Horizontal in 0,0
((0.25, 2), (5, 2)), # Horizontale mit 0.25 Abstand zu vertikaler
((0.25, 4), (4, 3)), # Diagonale \ mit 0.25 Abstand zu vertikaler und 1 zu horizontaler
((5.10, -1), (5.1, 3)) # Vertikale mit 0,25 Abstand zu erster u zweiter Horizontalen
]
result = find_touch_cut_close_ext(segments, 0.5)
self.assertEqual(len(result),3)
if __name__ == '__main__': if __name__ == '__main__':
+68
View File
@@ -0,0 +1,68 @@
from shapely.geometry import LineString, Point
from shapely.ops import nearest_points
racks = [
((0, 0), (5, 0)), # Horizontal
((0, 0), (0, 5)), # Vertikal (schneidet exakt)
((0.25, 2), (5, 2)), # Parallel mit 0.25 Abstand zur Vertikalen
((0.25, 4), (4, 3)), # Diagonal
((5.10, -0.25), (5.1, 3)) # Parallel sehr nah an erstem Rack
]
tol = 0.5
tol_step = 0.05
rack_lines = [LineString([start, end]) for start, end in racks]
rack_endpoints = [(i, pt) for i, rack in enumerate(racks) for pt in rack]
verbindungen = []
# Überprüfe jedes Rack
for i, rack_line in enumerate(rack_lines):
print(f"\n=== Prüfe Rack {i}: {rack_line}")
for j, pt_coords in rack_endpoints:
if i == j:
continue # Eigenpunkte ignorieren
pt = Point(pt_coords)
# Prüfe auf exakten Schnittpunkt
if rack_line.intersects(pt):
intersection = rack_line.intersection(pt)
print(f" ✅ Echter Schnittpunkt mit Endpunkt von Rack {j}: {intersection}")
verbindungen.append((i,j, intersection))
continue #diesen Punkt überspringen
#alle Endpunkte prüfen, die NICHT exakt auf der Linie liegen
for j, pt_coords in rack_endpoints:
if i == j:
continue # Eigenpunkte ignorieren
pt = Point(pt_coords)
# Prüfe nur, wenn der Punkt **nicht** genau auf der Linie liegt
if rack_line.intersects(pt):
continue # Exakte Schnittpunkte nicht erneut behandeln
dist = rack_line.distance(pt)
#überprüfen, ob der Punkt im Toleranzbereich ist
if dist < tol:
print(f" 🔍 Punkt {pt} liegt {dist:.3f} von Linie {i} entfernt")
radius = tol_step
while radius <= tol:
circle = pt.buffer(radius) # Kreis wächst mit dem Toleranzradius
if circle.intersects(rack_line): # Wenn der Kreis die Linie schneidet
contact = circle.intersection(rack_line)
if contact.geom_type == "Point":
nearest = contact
else:
nearest = nearest_points(pt, contact)[1] # Erster Kontaktpunkt von rack_line
print(f" 🟡 Berührpunkt bei Radius {radius:.2f}: {nearest}")
verbindungen.append((i,j,nearest))
break
radius += tol_step