|
3 | 3 |
|
4 | 4 | using BinaryTrees
|
5 | 5 |
|
6 |
| - |
7 | 6 | """
|
8 | 7 | bentleyottmann(segments)
|
9 | 8 |
|
@@ -41,86 +40,195 @@ function bentleyottmann(segments)
|
41 | 40 | haskey(𝒞, a) || (𝒞[a] = S[])
|
42 | 41 | haskey(𝒞, b) || (𝒞[b] = S[])
|
43 | 42 | end
|
44 |
| - m = Point(-Inf, -Inf) |
45 |
| - M = Point(Inf, Inf) |
46 |
| - BinaryTrees.insert!(𝒯, (m, m)) |
47 |
| - BinaryTrees.insert!(𝒯, (M, M)) |
48 | 43 |
|
49 | 44 | # sweep line
|
50 | 45 | I = Dict{P,Vector{S}}()
|
51 | 46 | while !isnothing(BinaryTrees.root(𝒬))
|
52 |
| - p = _key(BinaryTrees.root(𝒬)) |
| 47 | + p = _key(_leftmost(BinaryTrees.root(𝒬))) |
53 | 48 | BinaryTrees.delete!(𝒬, p)
|
54 | 49 | handle!(I, p, 𝒬, 𝒯, ℒ, 𝒰, 𝒞)
|
55 | 50 | end
|
56 | 51 | I
|
57 | 52 | end
|
58 | 53 |
|
59 | 54 | function handle!(I, p, 𝒬, 𝒯, ℒ, 𝒰, 𝒞)
|
60 |
| - # Segments that start, end, or intersect at p |
61 |
| - start_segments = ℒ[p] |
62 |
| - end_segments = 𝒰[p] |
63 |
| - intersection_segments = 𝒞[p] |
| 55 | + start_segments = get(ℒ, p, S[]) |
| 56 | + end_segments = get(𝒰, p, S[]) |
| 57 | + intersection_segments = get(𝒞, p, S[]) |
| 58 | + _process_start_segments!(start_segments, 𝒬, 𝒯, 𝒞) |
| 59 | + _process_end_segments!(end_segments, 𝒬, 𝒯, 𝒞) |
| 60 | + _process_intersection_segments!(intersection_segments, 𝒬, 𝒯, 𝒞) |
64 | 61 |
|
65 |
| - # If there are multiple segments intersecting at p, record the intersection |
66 | 62 | if length(start_segments ∪ end_segments ∪ intersection_segments) > 1
|
67 | 63 | I[p] = start_segments ∪ end_segments ∪ intersection_segments
|
68 | 64 | end
|
| 65 | +end |
69 | 66 |
|
70 |
| - # Remove segments that end at p from the status structure |
71 |
| - for s in end_segments ∪ intersection_segments |
72 |
| - BinaryTrees.delete!(𝒯, s) |
73 |
| - end |
74 |
| - |
75 |
| - # Insert segments that start at p into the status structure |
76 |
| - for s in start_segments ∪ intersection_segments |
77 |
| - BinaryTrees.insert!(𝒯, s) |
78 |
| - end |
79 |
| - node = BinaryTrees.root(𝒬) |
80 |
| - |
81 |
| - # Find new event points caused by the insertion or deletion of segments |
| 67 | +function _process_start_segments!(start_segments, 𝒬, 𝒯, 𝒞) |
| 68 | + [BinaryTrees.insert!(𝒯, s) for s in start_segments] |
82 | 69 | for s in start_segments
|
| 70 | + above, below = find_above_below(BinaryTrees.root(𝒯), BinaryTrees.search(𝒯, s)) |
83 | 71 | s = Segment(s)
|
84 |
| - pred = BinaryTrees.left(node) |
85 |
| - succ = BinaryTrees.right(node) |
86 |
| - ns = Segment(pred, succ) |
87 |
| - if pred !== nothing |
88 |
| - new_geom, new_type = _newevent(s, ns) |
89 |
| - if new_geom == IntersectionType(0) |
| 72 | + if above !== nothing && below !== nothing |
| 73 | + new_geom, new_type = _newevent(Segment(_key(above)), Segment(_key(below))) |
| 74 | + if new_type == IntersectionType(0) |
90 | 75 | BinaryTrees.insert!(𝒬, new_geom)
|
| 76 | + haskey(𝒞, new_geom) ? push!(𝒞[new_geom], _key(above), _key(below)) : (𝒞[new_geom] = [_key(above), _key(below)]) |
91 | 77 | end
|
92 | 78 | end
|
93 |
| - if succ !== nothing |
94 |
| - new_geom, new_type = _newevent(s, ns) |
| 79 | + if below !== nothing |
| 80 | + new_geom, new_type = _newevent(Segment(_key(below)), s) |
95 | 81 | if new_type == IntersectionType(0)
|
96 | 82 | BinaryTrees.insert!(𝒬, new_geom)
|
| 83 | + haskey(𝒞, new_geom) ? push!(𝒞[new_geom], _key(below), _segdata(s)) : (𝒞[new_geom] = [_key(below), _segdata(s)]) |
| 84 | + end |
| 85 | + end |
| 86 | + if above !== nothing |
| 87 | + new_geom, new_type = _newevent(s, Segment(_key(above))) |
| 88 | + if new_type == IntersectionType(0) |
| 89 | + BinaryTrees.insert!(𝒬, new_geom) |
| 90 | + haskey(𝒞, new_geom) ? push!(𝒞[new_geom], _segdata(s), _key(above)) : (𝒞[new_geom] = [_segdata(s), _key(above)]) |
97 | 91 | end
|
98 | 92 | end
|
99 | 93 | end
|
| 94 | +end |
100 | 95 |
|
| 96 | +function _process_end_segments!(end_segments, 𝒬, 𝒯, 𝒞) |
101 | 97 | for s in end_segments
|
| 98 | + above, below = find_above_below(BinaryTrees.root(𝒯), BinaryTrees.search(𝒯, s)) |
| 99 | + BinaryTrees.delete!(𝒯, s) |
102 | 100 | s = Segment(s)
|
103 |
| - pred = BinaryTrees.left(node) |
104 |
| - succ = BinaryTrees.right(node) |
105 |
| - ns = Segment(pred, succ) |
106 |
| - if pred !== nothing && succ !== nothing |
107 |
| - new_geom, new_type = _newevent(s, ns) |
| 101 | + if above !== nothing && below !== nothing |
| 102 | + new_geom, new_type = _newevent(Segment(_key(above)), Segment(_key(below))) |
108 | 103 | if new_type == IntersectionType(0)
|
109 | 104 | BinaryTrees.insert!(𝒬, new_geom)
|
| 105 | + haskey(𝒞, new_geom) ? push!(𝒞[new_geom], _key(above), _key(below)) : (𝒞[new_geom] = [_key(above), _key(below)]) |
110 | 106 | end
|
111 | 107 | end
|
112 | 108 | end
|
113 | 109 | end
|
114 | 110 |
|
| 111 | +function _process_intersection_segments!(intersection_segments, 𝒬, 𝒯, 𝒞) |
| 112 | + for s in intersection_segments |
| 113 | + _, below = find_above_below(BinaryTrees.root(𝒯), BinaryTrees.search(𝒯, s)) |
| 114 | + if below !== nothing |
| 115 | + # Swap positions of s and t in 𝒯 |
| 116 | + BinaryTrees.delete!(𝒯, s) |
| 117 | + BinaryTrees.delete!(𝒯, _key(below)) |
| 118 | + BinaryTrees.insert!(𝒯, _key(below)) |
| 119 | + BinaryTrees.insert!(𝒯, s) |
| 120 | + |
| 121 | + # Find segments r and u |
| 122 | + _, r = find_above_below(BinaryTrees.root(𝒯), BinaryTrees.search(𝒯, _key(below))) |
| 123 | + u, _ = find_above_below(BinaryTrees.root(𝒯), BinaryTrees.search(𝒯, s)) |
| 124 | + |
| 125 | + # Remove crossing points rs and tu from event queue |
| 126 | + if r !== nothing |
| 127 | + new_geom, new_type = _newevent(Segment(_key(r)), Segment(s)) |
| 128 | + if new_type == IntersectionType(0) |
| 129 | + BinaryTrees.delete!(𝒬, new_geom) |
| 130 | + end |
| 131 | + end |
| 132 | + if u !== nothing |
| 133 | + new_geom, new_type = _newevent(Segment(_key(u)), Segment(_key(below))) |
| 134 | + if new_type == IntersectionType(0) |
| 135 | + BinaryTrees.delete!(𝒬, new_geom) |
| 136 | + end |
| 137 | + end |
| 138 | + |
| 139 | + # Add crossing points rt and su to event queue |
| 140 | + if r !== nothing |
| 141 | + new_geom, new_type = _newevent(Segment(_key(r)), Segment(_key(below))) |
| 142 | + if new_type == IntersectionType(0) |
| 143 | + BinaryTrees.insert!(𝒬, new_geom) |
| 144 | + haskey(𝒞, new_geom) ? push!(𝒞[new_geom], _key(r), _key(below)) : (𝒞[new_geom] = [_key(r), _key(below)]) |
| 145 | + end |
| 146 | + end |
| 147 | + if u !== nothing |
| 148 | + new_geom, new_type = _newevent(Segment(_key(u)), Segment(s)) |
| 149 | + if new_type == IntersectionType(0) |
| 150 | + BinaryTrees.insert!(𝒬, new_geom) |
| 151 | + haskey(𝒞, new_geom) ? push!(𝒞[new_geom], _key(u), s) : (𝒞[new_geom] = [_key(u), s]) |
| 152 | + end |
| 153 | + end |
| 154 | + end |
| 155 | + end |
| 156 | +end |
| 157 | + |
| 158 | +_segdata(seg::Segment) = seg.vertices.data |
115 | 159 | _key(node::BinaryTrees.AVLNode) = node.key
|
| 160 | +_key(node::Nothing) = nothing |
| 161 | +_leftmost(node::BinaryTrees.AVLNode) = node.left === nothing ? node : _leftmost(node.left) |
116 | 162 | _geom(intersect::Intersection) = intersect.geom
|
117 | 163 | _type(intersect::Intersection) = intersect.type
|
118 | 164 | function _newevent(s₁::Segment, s₂::Segment)
|
119 | 165 | new_event = intersection(s₁, s₂)
|
120 |
| - _geom(new_event), _type(new_event) |
| 166 | + if new_event !== nothing |
| 167 | + _geom(new_event), _type(new_event) |
| 168 | + else |
| 169 | + nothing, nothing |
| 170 | + end |
| 171 | +end |
| 172 | + |
| 173 | +# Helper: return the leftmost node (minimum) in a subtree. |
| 174 | +function _bst_minimum(node::BinaryTrees.AVLNode) |
| 175 | + while node.left !== nothing |
| 176 | + node = node.left |
| 177 | + end |
| 178 | + return node |
121 | 179 | end
|
122 | 180 |
|
| 181 | +# Helper: return the rightmost node (maximum) in a subtree. |
| 182 | +function _bst_maximum(node::BinaryTrees.AVLNode) |
| 183 | + while node.right !== nothing |
| 184 | + node = node.right |
| 185 | + end |
| 186 | + return node |
| 187 | +end |
| 188 | + |
| 189 | +""" |
| 190 | + find_above_below(root, x) |
| 191 | +
|
| 192 | +Find the node above and below `x` in the binary search tree rooted at `root`. |
| 193 | +Returns a tuple `(above, below)` where `above` is the node with the smallest key |
| 194 | +greater than `x.key` and `below` is the node with the largest key smaller than `x.key`. |
| 195 | +If `x` is not found, returns the best candidates for `above` and `below`. |
| 196 | +""" |
| 197 | +function find_above_below(root::BinaryTrees.AVLNode, x::BinaryTrees.AVLNode) |
| 198 | + above = nothing |
| 199 | + below = nothing |
| 200 | + current = root |
| 201 | + # Traverse from the root to the target node, updating candidates. |
| 202 | + while current !== nothing && current.key != x.key |
| 203 | + if x.key < current.key |
| 204 | + # current is a potential above (successor) |
| 205 | + above = current |
| 206 | + current = current.left |
| 207 | + else # x.key > current.key |
| 208 | + # current is a potential below (predecessor) |
| 209 | + below = current |
| 210 | + current = current.right |
| 211 | + end |
| 212 | + end |
| 213 | + |
| 214 | + # If the node wasn't found, return the best candidate values |
| 215 | + if current === nothing |
| 216 | + return (above, below) |
| 217 | + end |
123 | 218 |
|
| 219 | + # Found the node with key equal to x.key. |
| 220 | + # Now, if there is a left subtree, the true below (predecessor) is the maximum in that subtree. |
| 221 | + if current.left !== nothing |
| 222 | + below = _bst_maximum(current.left) |
| 223 | + end |
| 224 | + # Similarly, if there is a right subtree, the true above (successor) is the minimum in that subtree. |
| 225 | + if current.right !== nothing |
| 226 | + above = _bst_minimum(current.right) |
| 227 | + end |
| 228 | + |
| 229 | + (above, below) |
| 230 | +end |
| 231 | +find_above_below(root::BinaryTrees.AVLNode, x::Nothing) = (nothing, nothing) |
124 | 232 | function Segment(node₁::BinaryTrees.BinaryNode, node₂::BinaryTrees.BinaryNode)
|
125 | 233 | node₁ = _key(node₁)
|
126 | 234 | node₂ = _key(node₂)
|
|
0 commit comments