Skip to content

Commit 37438a1

Browse files
authored
Check changes to a triangulation without having to make them (#53)
2 parents a9215ad + 254aac7 commit 37438a1

File tree

7 files changed

+136
-88
lines changed

7 files changed

+136
-88
lines changed

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "DelaunayTriangulation"
22
uuid = "927a84f5-c5f4-47a5-9785-b46e178433df"
33
authors = ["Daniel VandenHeuvel <[email protected]>"]
4-
version = "0.6.2"
4+
version = "0.6.3"
55

66
[deps]
77
DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8"

src/operations/add_point.jl

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@
1919
rng,
2020
check_existence=Val(has_multiple_segments(tri)),
2121
exterior_curve_index
22-
)
22+
),
23+
peek = Val(false),
2324
)
2425
2526
Adds the point `new_point` to the triangulation `tri`.
@@ -39,6 +40,7 @@ Adds the point `new_point` to the triangulation `tri`.
3940
- `event_history = nothing`: The event history to store the events in. See [`InsertionEventHistory`](@ref). Only needed if `is_true(store_event_history)`. This object is not returned, instead we just mutate it inplace.
4041
- `exterior_curve_index=1`: The curve (or curves) corresponding to the outermost boundary.
4142
- `V=jump_and_march(tri, new_point isa Integer ? get_point(tri, new_point) : new_point; m=nothing, point_indices=nothing, try_points=nothing, k=initial_search_point, rng, check_existence=Val(has_multiple_segments(tri)), exterior_curve_index=exterior_curve_index)`: The triangle that `q` is in.
43+
- `peek=Val(false)`: If `is_true(peek)`, then we don't actually add the point, but all operations that update the history will be run. (So you should only really want this if you are using `event_history`.)
4244
4345
# Outputs
4446
The triangulation is updated in-place with the new point, but we also return the triangle `V` containing `new_point`.
@@ -63,25 +65,15 @@ function add_point!(tri::Triangulation, new_point;
6365
rng,
6466
check_existence=Val(has_multiple_segments(tri)),
6567
exterior_curve_index
66-
))
68+
),
69+
peek=Val(false))
6770
if !(new_point isa Integer)
6871
push_point!(tri, new_point)
6972
new_point = num_points(tri)
7073
end
71-
#=
72-
return add_point_bowyer_watson!(
73-
tri,
74-
new_point,
75-
initial_search_point,
76-
rng,
77-
update_representative_point,
78-
store_event_history,
79-
event_history,
80-
exterior_curve_index)
81-
=#
8274
q = get_point(tri, new_point)
8375
flag = point_position_relative_to_triangle(tri, V, q)
84-
return add_point_bowyer_watson_and_process_after_found_triangle!(tri, new_point, V, q, flag, update_representative_point, store_event_history, event_history)
76+
return add_point_bowyer_watson_and_process_after_found_triangle!(tri, new_point, V, q, flag, update_representative_point, store_event_history, event_history, peek)
8577
end
8678

8779
function add_point!(tri::Triangulation, new_point_x, new_point_y;
@@ -104,9 +96,10 @@ function add_point!(tri::Triangulation, new_point_x, new_point_y;
10496
rng,
10597
check_existence=Val(has_multiple_segments(tri)),
10698
exterior_curve_index
107-
))
99+
),
100+
peek=Val(false))
108101
push_point!(tri, new_point_x, new_point_y)
109-
return add_point!(
102+
VV = add_point!(
110103
tri,
111104
num_points(tri);
112105
point_indices=point_indices,
@@ -118,5 +111,8 @@ function add_point!(tri::Triangulation, new_point_x, new_point_y;
118111
store_event_history=store_event_history,
119112
event_history=event_history,
120113
exterior_curve_index=exterior_curve_index,
121-
V)
114+
V,
115+
peek)
116+
is_true(peek) && pop_point!(tri)
117+
return VV
122118
end

src/predicates/general.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,7 @@ tests the position of `p` relative to the oriented outer halfplane defined
303303
by `(a, b)`. The returned values are:
304304
305305
- `Cert.Outside`: `p` is outside of the oriented outer halfplane, meaning to the right of the line `(a, b)` or collinear with `a` and `b` but not on the line segment `(a, b)`.
306-
- `Cert.On`: `p` is on the open line segment `(a, b)`.
306+
- `Cert.On`: `p` is on the line segment `[a, b]`.
307307
- `Cert.Inside`: `p` is inside of the oriented outer halfplane, meaning to the left of the line `(a, b)`.
308308
309309
!!! note
@@ -314,7 +314,7 @@ function point_position_relative_to_oriented_outer_halfplane(a, b, p)
314314
in_open_halfplane = point_position_relative_to_line(a, b, p)
315315
if is_collinear(in_open_halfplane)
316316
is_on_boundary_edge = point_position_on_line_segment(a, b, p)
317-
if is_on(is_on_boundary_edge)
317+
if is_on(is_on_boundary_edge) || is_degenerate(is_on_boundary_edge)
318318
return Cert.On
319319
else
320320
return Cert.Outside

src/triangulation/bowyer_watson.jl

Lines changed: 55 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -137,11 +137,12 @@ function add_point_bowyer_watson_and_process_after_found_triangle!(
137137
flag,
138138
update_representative_point=true,
139139
store_event_history=Val(false),
140-
event_history=nothing)
140+
event_history=nothing,
141+
peek=Val(false))
141142
I = integer_type(tri)
142143
new_point = I(new_point)
143-
add_point_bowyer_watson_after_found_triangle!(tri, new_point, V, q, flag, update_representative_point, store_event_history, event_history)
144-
add_point_bowyer_watson_onto_constrained_segment!(tri, new_point, V, q, flag, update_representative_point, store_event_history, event_history)
144+
add_point_bowyer_watson_after_found_triangle!(tri, new_point, V, q, flag, update_representative_point, store_event_history, event_history, peek)
145+
add_point_bowyer_watson_onto_constrained_segment!(tri, new_point, V, q, flag, update_representative_point, store_event_history, event_history, peek)
145146
return V
146147
end
147148

@@ -153,13 +154,14 @@ function add_point_bowyer_watson!(
153154
update_representative_point=true,
154155
store_event_history=Val(false),
155156
event_history=nothing,
156-
exterior_curve_index=1) where {I}
157+
exterior_curve_index=1,
158+
peek=Val(false)) where {I}
157159
new_point = I(new_point)
158160
q = get_point(tri, new_point)
159161
V = jump_and_march(tri, q; m=nothing, point_indices=nothing, try_points=nothing,
160162
k=initial_search_point, rng, check_existence=Val(has_multiple_segments(tri)), exterior_curve_index)
161163
flag = point_position_relative_to_triangle(tri, V, q)
162-
add_point_bowyer_watson_and_process_after_found_triangle!(tri, new_point, V, q, flag, update_representative_point, store_event_history, event_history)
164+
add_point_bowyer_watson_and_process_after_found_triangle!(tri, new_point, V, q, flag, update_representative_point, store_event_history, event_history, peek)
163165
return V
164166
end
165167

@@ -171,7 +173,8 @@ function add_point_bowyer_watson_onto_constrained_segment!(
171173
flag,
172174
update_representative_point=true,
173175
store_event_history=Val(false),
174-
event_history=nothing)
176+
event_history=nothing,
177+
peek=Val(false))
175178
if is_on(flag) && is_constrained(tri)
176179
# If the point we are adding appears on a segment, then we perform the depth-first search
177180
# on each side the segment. We also need to update the
@@ -181,16 +184,18 @@ function add_point_bowyer_watson_onto_constrained_segment!(
181184
w = get_adjacent(tri, v, u)
182185
T = triangle_type(tri)
183186
V = construct_triangle(T, v, u, w)
184-
add_point_bowyer_watson_dig_cavities!(tri, new_point, V, q, flag, update_representative_point, store_event_history, event_history)
187+
add_point_bowyer_watson_dig_cavities!(tri, new_point, V, q, flag, update_representative_point, store_event_history, event_history, peek)
185188
# Now, we need to replace the segment by this new segment.
186189
E = edge_type(tri)
187190
constrained_edges = get_constrained_edges(tri)
188191
all_constrained_edges = get_all_constrained_edges(tri)
189-
for edges in (constrained_edges, all_constrained_edges)
190-
delete_edge!(edges, construct_edge(E, u, v))
191-
delete_edge!(edges, construct_edge(E, v, u))
192-
add_edge!(edges, construct_edge(E, u, new_point))
193-
add_edge!(edges, construct_edge(E, new_point, v))
192+
if !is_true(peek)
193+
for edges in (constrained_edges, all_constrained_edges)
194+
delete_edge!(edges, construct_edge(E, u, v))
195+
delete_edge!(edges, construct_edge(E, v, u))
196+
add_edge!(edges, construct_edge(E, u, new_point))
197+
add_edge!(edges, construct_edge(E, new_point, v))
198+
end
194199
end
195200
if is_true(store_event_history)
196201
delete_edge!(event_history, construct_edge(E, u, v))
@@ -199,15 +204,11 @@ function add_point_bowyer_watson_onto_constrained_segment!(
199204
end
200205
end
201206
if contains_boundary_edge(tri, u, v)
202-
split_boundary_edge!(tri, u, v, new_point)
203-
if is_true(store_event_history)
204-
split_boundary_edge!(event_history, u, v, new_point)
205-
end
207+
!is_true(peek) && split_boundary_edge!(tri, u, v, new_point)
208+
is_true(store_event_history) && split_boundary_edge!(event_history, u, v, new_point)
206209
elseif contains_boundary_edge(tri, v, u)
207-
split_boundary_edge!(tri, v, u, new_point)
208-
if is_true(store_event_history)
209-
split_boundary_edge!(event_history, v, u, new_point)
210-
end
210+
!is_true(peek) && split_boundary_edge!(tri, v, u, new_point)
211+
is_true(store_event_history) && split_boundary_edge!(event_history, v, u, new_point)
211212
end
212213
end
213214
end
@@ -220,20 +221,20 @@ function add_point_bowyer_watson_after_found_triangle!(
220221
flag,
221222
update_representative_point=true,
222223
store_event_history=Val(false),
223-
event_history=nothing)
224+
event_history=nothing,
225+
peek=Val(false))
224226
if is_ghost_triangle(V) && is_constrained(tri)
225227
# When we have a constrained boundary edge, we don't want to walk into its
226228
# interior. So let's just check this case now.
227229
V = rotate_ghost_triangle_to_standard_form(V)
228230
u, v, w = indices(V)
229231
if !contains_boundary_edge(tri, v, u)
230-
add_point_bowyer_watson_dig_cavities!(tri, new_point, V, q, flag, update_representative_point, store_event_history, event_history)
232+
add_point_bowyer_watson_dig_cavities!(tri, new_point, V, q, flag, update_representative_point, store_event_history, event_history, peek)
231233
end
232234
else
233-
add_point_bowyer_watson_dig_cavities!(tri, new_point, V, q, flag, update_representative_point, store_event_history, event_history)
235+
add_point_bowyer_watson_dig_cavities!(tri, new_point, V, q, flag, update_representative_point, store_event_history, event_history, peek)
234236
end
235237
end
236-
# add_point_bowyer_watson!(tri, new_point, V, q, flag, update_representative_point, store_event_history, event_history)
237238

238239
function add_point_bowyer_watson_dig_cavities!(
239240
tri::Triangulation,
@@ -243,18 +244,17 @@ function add_point_bowyer_watson_dig_cavities!(
243244
flag,
244245
update_representative_point=true,
245246
store_event_history=Val(false),
246-
event_history=nothing) where {I}
247+
event_history=nothing,
248+
peek=Val(false)) where {I}
247249
i, j, k = indices(V)
248250
ℓ₁ = get_adjacent(tri, j, i)
249251
ℓ₂ = get_adjacent(tri, k, j)
250252
ℓ₃ = get_adjacent(tri, i, k)
251-
delete_triangle!(tri, V; protect_boundary=true, update_ghost_edges=false)
252-
if is_true(store_event_history)
253-
delete_triangle!(event_history, V)
254-
end
255-
dig_cavity!(tri, new_point, i, j, ℓ₁, flag, V, store_event_history, event_history)
256-
dig_cavity!(tri, new_point, j, k, ℓ₂, flag, V, store_event_history, event_history)
257-
dig_cavity!(tri, new_point, k, i, ℓ₃, flag, V, store_event_history, event_history)
253+
!is_true(peek) && delete_triangle!(tri, V; protect_boundary=true, update_ghost_edges=false)
254+
is_true(store_event_history) && delete_triangle!(event_history, V)
255+
dig_cavity!(tri, new_point, i, j, ℓ₁, flag, V, store_event_history, event_history, peek)
256+
dig_cavity!(tri, new_point, j, k, ℓ₂, flag, V, store_event_history, event_history, peek)
257+
dig_cavity!(tri, new_point, k, i, ℓ₃, flag, V, store_event_history, event_history, peek)
258258
if is_on(flag) && (is_boundary_triangle(tri, V) || is_ghost_triangle(V) && !is_boundary_node(tri, new_point)[1])
259259
# ^ Need to fix the ghost edges if the point is added onto an existing boundary edge. Note that the last
260260
# condition is in case the ghost edges were already correctly added.
@@ -265,10 +265,12 @@ function add_point_bowyer_watson_dig_cavities!(
265265
u, v = v, u
266266
end
267267
g = get_adjacent(tri, u, v)
268-
delete_triangle!(tri, v, u, new_point; protect_boundary=true, update_ghost_edges=false)
269-
delete_triangle!(tri, u, v, g; protect_boundary=true, update_ghost_edges=false)
270-
add_triangle!(tri, new_point, v, g; update_ghost_edges=false)
271-
add_triangle!(tri, u, new_point, g; update_ghost_edges=false)
268+
if !is_true(peek)
269+
delete_triangle!(tri, v, u, new_point; protect_boundary=true, update_ghost_edges=false)
270+
delete_triangle!(tri, u, v, g; protect_boundary=true, update_ghost_edges=false)
271+
add_triangle!(tri, new_point, v, g; update_ghost_edges=false)
272+
add_triangle!(tri, u, new_point, g; update_ghost_edges=false)
273+
end
272274
if is_true(store_event_history)
273275
trit = triangle_type(tri)
274276
delete_triangle!(event_history, construct_triangle(trit, u, v, g))
@@ -278,23 +280,21 @@ function add_point_bowyer_watson_dig_cavities!(
278280
if is_constrained(tri) && (contains_boundary_edge(tri, u, v) || contains_boundary_edge(tri, v, u)) # If we don't do this here now, then when we try and do it later we will get a KeyError since we've already modified the boundary edge but we wouldn't have updated the constrained fields
279281
# We also only do this if contains_boundary_edge since we want to assume that (u, v) does not appear in constrained_edges
280282
if contains_boundary_edge(tri, u, v)
281-
split_boundary_edge!(tri, u, v, new_point)
282-
if is_true(store_event_history)
283-
split_boundary_edge!(event_history, u, v, new_point)
284-
end
283+
!is_true(peek) && split_boundary_edge!(tri, u, v, new_point)
284+
is_true(store_event_history) && split_boundary_edge!(event_history, u, v, new_point)
285285
elseif contains_boundary_edge(tri, v, u)
286-
split_boundary_edge!(tri, v, u, new_point)
287-
if is_true(store_event_history)
288-
split_boundary_edge!(event_history, v, u, new_point)
289-
end
286+
!is_true(peek) && split_boundary_edge!(tri, v, u, new_point)
287+
is_true(store_event_history) && split_boundary_edge!(event_history, v, u, new_point)
290288
end
291289
E = edge_type(tri)
292290
# constrained_edges = get_constrained_edges(tri) < -- Don't need this actually, we're just looking at boundary edges here, so no need to consider individually constrained edges
293291
all_constrained_edges = get_all_constrained_edges(tri)
294-
delete_edge!(all_constrained_edges, construct_edge(E, u, v))
295-
delete_edge!(all_constrained_edges, construct_edge(E, v, u))
296-
add_edge!(all_constrained_edges, construct_edge(E, u, new_point))
297-
add_edge!(all_constrained_edges, construct_edge(E, new_point, v))
292+
if !is_true(peek)
293+
delete_edge!(all_constrained_edges, construct_edge(E, u, v))
294+
delete_edge!(all_constrained_edges, construct_edge(E, v, u))
295+
add_edge!(all_constrained_edges, construct_edge(E, u, new_point))
296+
add_edge!(all_constrained_edges, construct_edge(E, new_point, v))
297+
end
298298
if is_true(store_event_history)
299299
delete_edge!(event_history, construct_edge(E, u, v))
300300
add_edge!(event_history, construct_edge(E, u, new_point))
@@ -303,11 +303,11 @@ function add_point_bowyer_watson_dig_cavities!(
303303
end
304304
end
305305
end
306-
update_representative_point && update_centroid_after_addition!(tri, I(1), q) # How do we efficiently determine which curve to update for a given q when adding into an existing triangulation?
306+
update_representative_point && !is_true(peek) && update_centroid_after_addition!(tri, I(1), q) # How do we efficiently determine which curve to update for a given q when adding into an existing triangulation?
307307
return nothing
308308
end
309309

310-
@inline function dig_cavity!(tri::Triangulation, r::I, i, j, ℓ, flag, V, store_event_history=Val(false), event_history=nothing) where {I}
310+
@inline function dig_cavity!(tri::Triangulation, r::I, i, j, ℓ, flag, V, store_event_history=Val(false), event_history=nothing, peek=Val(false)) where {I}
311311
if !edge_exists(ℓ)
312312
# The triangle has already been deleted in this case.
313313
return nothing
@@ -317,9 +317,9 @@ end
317317
!is_boundary_index(ℓ)
318318
ℓ₁ = get_adjacent(tri, ℓ, i)
319319
ℓ₂ = get_adjacent(tri, j, ℓ)
320-
delete_triangle!(tri, j, i, ℓ; protect_boundary=true, update_ghost_edges=false)
321-
dig_cavity!(tri, r, i, ℓ, ℓ₁, flag, V, store_event_history, event_history)
322-
dig_cavity!(tri, r, ℓ, j, ℓ₂, flag, V, store_event_history, event_history)
320+
!is_true(peek) && delete_triangle!(tri, j, i, ℓ; protect_boundary=true, update_ghost_edges=false)
321+
dig_cavity!(tri, r, i, ℓ, ℓ₁, flag, V, store_event_history, event_history, peek)
322+
dig_cavity!(tri, r, ℓ, j, ℓ₂, flag, V, store_event_history, event_history, peek)
323323
if is_true(store_event_history)
324324
trit = triangle_type(tri)
325325
delete_triangle!(event_history, construct_triangle(trit, j, i, ℓ))
@@ -336,14 +336,14 @@ end
336336
if u == i && v == j
337337
return nothing
338338
else
339-
add_triangle!(tri, r, i, j; update_ghost_edges=false)
339+
!is_true(peek) && add_triangle!(tri, r, i, j; update_ghost_edges=false)
340340
if is_true(store_event_history)
341341
trit = triangle_type(tri)
342342
add_triangle!(event_history, construct_triangle(trit, r, i, j))
343343
end
344344
end
345345
else
346-
add_triangle!(tri, r, i, j; update_ghost_edges=false)
346+
!is_true(peek) && add_triangle!(tri, r, i, j; update_ghost_edges=false)
347347
if is_true(store_event_history)
348348
trit = triangle_type(tri)
349349
add_triangle!(event_history, construct_triangle(trit, r, i, j))

0 commit comments

Comments
 (0)