Skip to content

Commit f9bbfe6

Browse files
committed
Some bugs remaining
1 parent 9e54352 commit f9bbfe6

File tree

11 files changed

+75
-28
lines changed

11 files changed

+75
-28
lines changed

src/algorithms/triangulation/basic_operations/add_boundary_information.jl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ function add_boundary_information!(tri::Triangulation)
77
I = integer_type(tri)
88
ghost_vertex = I(𝒢)
99
bn = get_boundary_nodes(tri)
10+
# Clear any existing boundary_vertex_to_ghost entries before repopulating
11+
empty!(get_boundary_vertex_to_ghost(tri))
1012
if has_multiple_curves(tri)
1113
add_boundary_curve_information!(tri, bn, ghost_vertex)
1214
elseif has_multiple_sections(tri)
@@ -18,6 +20,7 @@ function add_boundary_information!(tri::Triangulation)
1820
end
1921
function add_boundary_node_information!(tri::Triangulation, bn, ghost_vertex)
2022
n_edge = num_boundary_edges(bn)
23+
n_edge == 0 && return ghost_vertex
2124
u = get_boundary_nodes(bn, n_edge + 1)
2225
for j in n_edge:-1:1
2326
v = get_boundary_nodes(bn, j)

src/algorithms/triangulation/basic_operations/add_ghost_triangles.jl

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@ Adds all the ghost triangles to `tri`.
55
"""
66
function add_ghost_triangles!(tri::Triangulation)
77
T = get_triangles(tri)
8+
# If we have boundary nodes but the boundary_vertex_to_ghost map is empty,
9+
# we need to populate it. This can happen when ghost triangles were deleted
10+
# and are now being re-added.
11+
if has_boundary_nodes(tri) && isempty(get_boundary_vertex_to_ghost(tri))
12+
add_boundary_information!(tri)
13+
end
814
for g in each_ghost_vertex(tri)
915
for e in each_edge(get_adjacent2vertex(tri, g))
1016
u, v = edge_vertices(e)
@@ -13,9 +19,6 @@ function add_ghost_triangles!(tri::Triangulation)
1319
add_adjacent2vertex!(tri, u, v, g)
1420
add_adjacent2vertex!(tri, v, g, u)
1521
add_triangle!(T, u, v, g)
16-
# Add boundary vertices to the boundary_vertex_to_ghost map
17-
add_boundary_vertex_to_ghost!(tri, u, g)
18-
add_boundary_vertex_to_ghost!(tri, v, g)
1922
end
2023
end
2124
set_has_ghosts!(tri, true)

src/algorithms/triangulation/basic_operations/unlock_convex_hull.jl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ function unlock_convex_hull!(tri::Triangulation; reconstruct = false)
2525
bnn_map = get_boundary_edge_map(tri)
2626
empty!(bn)
2727
bn_map[I(𝒢)] = bn
28+
# Clear the boundary_vertex_to_ghost map since we're unlocking the convex hull
29+
# and these are no longer constrained boundary nodes
30+
empty!(get_boundary_vertex_to_ghost(tri))
2831
segments = get_interior_segments(tri)
2932
all_segments = get_all_segments(tri)
3033
for e in keys(bnn_map)

src/algorithms/triangulation/triangulate_convex.jl

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,10 @@ function postprocess_triangulate_convex!(tri::Triangulation, S; delete_ghosts, d
160160
push!(hull, S[begin])
161161
I = integer_type(tri)
162162
ghost_vertex = I(𝒢)
163+
# Only populate boundary_vertex_to_ghost map for triangulations with actual constrained boundary nodes.
164+
# Convex hull vertices (from unconstrained triangulations) should not be in this map.
165+
# This matches the behavior of add_ghost_triangles!
166+
populate_map = has_boundary_nodes(tri) && !delete_ghosts
163167
for i in firstindex(S):(lastindex(S) - 1)
164168
u = S[i]
165169
v = S[i + 1]
@@ -171,8 +175,8 @@ function postprocess_triangulate_convex!(tri::Triangulation, S; delete_ghosts, d
171175
add_adjacent2vertex!(tri, ghost_vertex, v, u)
172176
add_adjacent!(tri, v, u, ghost_vertex)
173177
end
174-
# Add boundary vertex to ghost mapping
175-
add_boundary_vertex_to_ghost!(tri, u, ghost_vertex)
178+
# Add boundary vertex to ghost mapping only for constrained boundaries
179+
populate_map && add_boundary_vertex_to_ghost!(tri, u, ghost_vertex)
176180
end
177181
u = S[end]
178182
v = S[begin]
@@ -183,8 +187,10 @@ function postprocess_triangulate_convex!(tri::Triangulation, S; delete_ghosts, d
183187
add_adjacent2vertex!(tri, ghost_vertex, v, u)
184188
add_adjacent!(tri, v, u, ghost_vertex)
185189
end
186-
# Add the last boundary vertex to ghost mapping
187-
add_boundary_vertex_to_ghost!(tri, u, ghost_vertex)
190+
# Add the last boundary vertex to ghost mapping only for constrained boundaries
191+
populate_map && add_boundary_vertex_to_ghost!(tri, u, ghost_vertex)
192+
# Set has_ghosts flag based on whether we added ghost triangles
193+
set_has_ghosts!(tri, !delete_ghosts)
188194
delete_empty_features && clear_empty_features!(tri)
189195
empty_representative_points!(tri)
190196
cx, cy = mean_points(get_points(tri), S)

src/data_structures/triangulation/methods/boundary_nodes.jl

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,11 +126,18 @@ function split_boundary_edge!(tri::Triangulation, i, j, node)
126126
delete_unoriented_edge!(segments, construct_edge(E, i, j))
127127
!contains_edge(construct_edge(E, node, i), segments) && add_edge!(segments, construct_edge(E, i, node))
128128
!contains_edge(construct_edge(E, j, node), segments) && add_edge!(segments, construct_edge(E, node, j))
129-
# Sometimes, the user might accidentally also put an interior segment in that forms part of the boundary. Let's remove it.
129+
# Sometimes, the user might accidentally also put an interior segment in that forms part of the boundary. Let's remove it.
130130
interior_segments = get_interior_segments(tri)
131131
if contains_unoriented_edge(construct_edge(E, i, j), interior_segments)
132132
delete_unoriented_edge!(interior_segments, construct_edge(E, i, j))
133133
end
134+
# Update boundary_vertex_to_ghost map for the new boundary node
135+
# The new node should map to the same ghost vertex as i and j
136+
bv_map = get_boundary_vertex_to_ghost(tri)
137+
if !isempty(bv_map) && haskey(bv_map, i)
138+
ghost_vertex = bv_map[i]
139+
add_boundary_vertex_to_ghost!(tri, node, ghost_vertex)
140+
end
134141
return tri
135142
end
136143

src/data_structures/triangulation/triangulation.jl

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -385,7 +385,10 @@ has_ghosts(tri::Triangulation) = tri.has_ghosts
385385
386386
Sets the `has_ghosts` flag of the triangulation to `flag`.
387387
"""
388-
set_has_ghosts!(tri::Triangulation, flag::Bool) = tri.has_ghosts = flag
388+
function set_has_ghosts!(tri::Triangulation, flag::Bool)
389+
tri.has_ghosts = flag
390+
return tri
391+
end
389392

390393
"""
391394
get_boundary_vertex_to_ghost(tri::Triangulation) -> Dict{I, I}

test/data_structures/triangulation.jl

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ global tri = Triangulation(pts; IntegerType=Int32)
5353
DT.construct_polygon_hierarchy(pts; IntegerType=Int32),
5454
nothing, # boundary_enricher
5555
DT.TriangulationCache(nothing, nothing, nothing, nothing, nothing, nothing, nothing, nothing, nothing),
56+
false, # has_ghosts
57+
Dict{Int32,Int32}(), # boundary_vertex_to_ghost
5658
),
5759
DT.Triangulation(
5860
pts,
@@ -73,6 +75,8 @@ global tri = Triangulation(pts; IntegerType=Int32)
7375
DT.construct_polygon_hierarchy(pts; IntegerType=Int32),
7476
nothing, # boundary_enricher
7577
DT.TriangulationCache(nothing, nothing, nothing, nothing, nothing, nothing, nothing, nothing, nothing),
78+
false, # has_ghosts
79+
Dict{Int32,Int32}(), # boundary_vertex_to_ghost
7680
),
7781
Int32[],
7882
Set{NTuple{2,Int32}}(),
@@ -82,6 +86,8 @@ global tri = Triangulation(pts; IntegerType=Int32)
8286
AdaptivePredicates.orient3adapt_cache(Float64),
8387
AdaptivePredicates.insphereexact_cache(Float64),
8488
),
89+
false, # has_ghosts
90+
Dict{Int32,Int32}(), # boundary_vertex_to_ghost
8591
)
8692
end
8793

@@ -1498,7 +1504,7 @@ end
14981504
for f in fieldnames(typeof(tri))
14991505
f in (:weights, :boundary_enricher) && continue
15001506
@test getfield(tri, f) == getfield(tri2, f)
1501-
f == :boundary_curves && continue
1507+
f in (:boundary_curves, :has_ghosts) && continue
15021508
@test !(getfield(tri, f) === getfield(tri2, f))
15031509
end
15041510
end
@@ -1515,7 +1521,7 @@ end
15151521
for f in fieldnames(typeof(tri))
15161522
f in (:weights, :boundary_enricher, :cache) && continue
15171523
@test getfield(tri, f) == getfield(tri2, f)
1518-
f == :boundary_curves && continue
1524+
f in (:boundary_curves, :has_ghosts) && continue
15191525
@test !(getfield(tri, f) === getfield(tri2, f))
15201526
end
15211527
bem = DT.get_boundary_edge_map(tri)
@@ -1563,6 +1569,7 @@ end
15631569
for f in fieldnames(typeof(tri))
15641570
f in (:weights, :cache) && continue
15651571
@test getfield(tri, f) == getfield(tri2, f)
1572+
f in (:has_ghosts,) && continue
15661573
@test !(getfield(tri, f) === getfield(tri2, f))
15671574
end
15681575
enricher = DT.get_boundary_enricher(tri)
@@ -1594,7 +1601,7 @@ end
15941601
for f in fieldnames(typeof(tri))
15951602
f in (:boundary_enricher, :cache) && continue
15961603
@test getfield(tri, f) == getfield(tri2, f)
1597-
f in (:boundary_curves,) && continue
1604+
f in (:boundary_curves, :has_ghosts) && continue
15981605
@test !(getfield(tri, f) === getfield(tri2, f))
15991606
end
16001607
@test get_weights(tri) == get_weights(tri2) && !(get_weights(tri) === get_weights(tri2))

test/helper_functions.jl

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,8 @@ function example_triangulation()
239239
pts, Int, NTuple{2,Int}, NTuple{3,Int},
240240
Set{NTuple{2,Int}}, Set{NTuple{3,Int}}, DT.ZeroWeight(), Val(true),
241241
),
242+
false, # has_ghosts
243+
Dict{Int,Int}(), # boundary_vertex_to_ghost
242244
)
243245
DT.compute_representative_points!(tri)
244246
return tri
@@ -264,6 +266,8 @@ function example_empty_triangulation()
264266
pts, Int, NTuple{2,Int}, NTuple{3,Int},
265267
Set{NTuple{2,Int}}, Set{NTuple{3,Int}}, DT.ZeroWeight(), Val(true),
266268
),
269+
false, # has_ghosts
270+
Dict{Int,Int}(), # boundary_vertex_to_ghost
267271
)
268272
DT.compute_representative_points!(tri)
269273
return tri
@@ -1568,6 +1572,8 @@ function why_not_equal(tri1, tri2)
15681572
DT.get_polygon_hierarchy(tri1) DT.get_polygon_hierarchy(tri2) && println("get_polygon_hierarchy(tri1) ≠ get_polygon_hierarchy(tri2)")
15691573
DT.get_boundary_nodes(tri1) DT.get_boundary_nodes(tri2) && println("get_boundary_nodes(tri1) ≠ get_boundary_nodes(tri2)")
15701574
DT.get_weights(tri1) DT.get_weights(tri2) && println("get_weights(tri1) ≠ get_weights(tri2)")
1575+
DT.has_ghosts(tri1) DT.has_ghosts(tri2) && println("has_ghosts(tri1) ≠ has_ghosts(tri2)")
1576+
DT.get_boundary_vertex_to_ghost(tri1) DT.get_boundary_vertex_to_ghost(tri2) && println("get_boundary_vertex_to_ghost(tri1) ≠ get_boundary_vertex_to_ghost(tri2)")
15711577
end
15721578

15731579
#=

test/operations/lock_convex_hull.jl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,9 @@ end
6767
@test tri.ghost_vertex_map == tri2.ghost_vertex_map
6868
@test tri.boundary_edge_map == tri2.boundary_edge_map
6969
@test tri.convex_hull == tri2.convex_hull
70+
# Test that unlock_convex_hull! clears the boundary_vertex_to_ghost map
71+
@test isempty(DT.get_boundary_vertex_to_ghost(tri))
72+
@test isempty(DT.get_boundary_vertex_to_ghost(tri2))
7073
@test_throws ArgumentError("Cannot unlock the convex hull of a triangulation without boundary nodes.") unlock_convex_hull!(tri2)
7174
lock_convex_hull!(tri)
7275
push!(tri.convex_hull.vertices, 17)

test/predicates/boundaries_and_ghosts.jl

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -280,27 +280,33 @@ end
280280
# Test that boundary_vertex_to_ghost map is correctly maintained
281281
@testset "boundary_vertex_to_ghost consistency" begin
282282
# Test with complicated geometry (multiple curves and sections)
283+
# Note: For junction nodes (nodes shared between sections), the map will only
284+
# contain ONE ghost vertex, whichever was set last during processing.
285+
# So we check that each boundary node IS in the map and maps to a VALID
286+
# ghost vertex (one that is in the ghost vertex range for that curve).
287+
bv_map = DT.get_boundary_vertex_to_ghost(tri)
283288
for (ghost_vertex, segment_index) in get_ghost_vertex_map(tri)
284289
nodes = get_boundary_nodes(tri, segment_index)
285290
for node in nodes
286-
bv_map = DT.get_boundary_vertex_to_ghost(tri)
287291
@test haskey(bv_map, node)
288-
@test bv_map[node] == ghost_vertex
292+
# The mapped ghost vertex should be in the valid range for this curve
293+
mapped_ghost = bv_map[node]
294+
@test mapped_ghost DT.get_ghost_vertex_range(tri, ghost_vertex)
289295
end
290296
end
291297

292298
# Test with simple geometry
299+
bv_map2 = DT.get_boundary_vertex_to_ghost(tri2)
293300
for (ghost_vertex, segment_index) in get_ghost_vertex_map(tri2)
294301
nodes = get_boundary_nodes(tri2, segment_index)
295302
for node in nodes
296-
bv_map = DT.get_boundary_vertex_to_ghost(tri2)
297-
@test haskey(bv_map, node)
298-
@test bv_map[node] == ghost_vertex
303+
@test haskey(bv_map2, node)
304+
mapped_ghost = bv_map2[node]
305+
@test mapped_ghost DT.get_ghost_vertex_range(tri2, ghost_vertex)
299306
end
300307
end
301308

302309
# Test that non-boundary nodes are not in the map
303-
bv_map = DT.get_boundary_vertex_to_ghost(tri)
304310
for node in each_vertex(tri)
305311
if node reduced_bn
306312
@test !haskey(bv_map, node)

0 commit comments

Comments
 (0)