forked from gisalgs/geom
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathline_seg_intersection.py
148 lines (133 loc) · 4 KB
/
line_seg_intersection.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
"""
Line segment intersections using the Bentley-Ottmann Algorithm.
Contact:
Ningchuan Xiao
The Ohio State University
Columbus, OH
"""
__author__ = "Ningchuan Xiao <[email protected]>"
import sys
sys.path.append("..")
from contrib.bintrees import AVLTree
from .point import *
from .intersection import *
from .line_seg_eventqueue import *
def get_edges(t, p):
"""
Gets the edges (segments) that contain point p as their right
endpoint or in the interior
"""
lr = []
lc = []
for s in AVLTree(t):
if s.rp == p:
lr.append(s)
elif s.lp == p and s.status == INTERIOR:
lc.append(s)
elif sideplr(p, s.lp, s.rp) == 0:
lc.append(s)
return lr, lc
def get_lr(T, s):
"""
Returns the left and right neighbors (branches) of s in T.
"""
try:
sl = T.floor_key(s)
except KeyError:
sl = None
try:
sr = T.ceiling_key(s)
except KeyError:
sr = None
return sl, sr
def get_lrmost(T, segs):
"""
Finds the leftmost and rightmost segments of segs in T
"""
l = []
for s in list(T):
if s in segs:
l.append(s)
if len(l) < 1:
return None, None
return l[0], l[-1]
def find_new_event(s1, s2, p, q):
"""
Tests if s1 intersects s2 at a point that is not in the event queue.
When a new intersection point is found, a new event will be created
and added to the event queue.
Input:
s1: line segment
s2: line segment
p: the point of the current event
q: event queue
Output:
True if a new point is found, False otherwise
Change: the content in the queue (q) may change.
"""
ip = intersectx(s1, s2)
if ip is None:
return False
if q.find(ip) is not -1:
return False
if ip.x>p.x or (ip.x==p.x and ip.y >= p.y):
e0 = Event()
e0.p = ip
e0.edges = [s1, s2]
q.add(e0)
return True
def intersectx(s1, s2):
"""
Tests intersection of 2 input segments. If intersection is possible,
the actual intersection point will be calculated and returned.
"""
if not test_intersect(s1, s2):
return None
p = getIntersectionPoint(s1, s2) # an intersection
return p
def intersections(psegs):
"""
Implementation of the Bentley-Ottmann algorithm.
Input
psegs: a list of segments
Output
intpoints: a list of intersection points
"""
eq = EventQueue(psegs)
intpoints = []
T = AVLTree()
L=[]
while not eq.is_empty(): # for all events
e = eq.events.pop(0) # remove the event
p = e.p # get event point
L = e.edges # segments with p as left end
R,C = get_edges(T, p) # p: right (R) and interior (C)
if len(L+R+C) > 1: # Intersection at p among L+R+C
for s in L+R+C:
if not s.contains(p): # if p is interior
s.lp = p # change lp and
s.status = INTERIOR # status
intpoints.append(p)
R,C = get_edges(T, p)
for s in R+C:
T.discard(s)
for s in L+C:
T.insert(s, str(s))
if len(L+C) == 0:
s = R[0]
if s is not None:
sl, sr = get_lr(T, s)
find_new_event(sl, sr, p, eq)
else:
sp, spp = get_lrmost(T, L+C)
try:
sl = T.prev_key(sp)
except KeyError: # only on last key
sl = None
try:
sr = T.succ_key(spp)
except KeyError: # only on last key
sr = None
find_new_event(sl, sp, p, eq)
find_new_event(sr, spp, p, eq)
return intpoints