Skip to content

Commit 0df0ca1

Browse files
committed
Triangulations are now stored in their own data structures (preparing for refinement)
1 parent 67cfcbb commit 0df0ca1

16 files changed

+236
-68
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.2.0"
4+
version = "0.3.0"
55

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

README.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ p4 = [-1.0, 2.0]
3838
p5 = [4.0, 2.0]
3939
p6 = [-2.0, -1.0]
4040
pts = [p1, p2, p3, p4, p5, p6]
41-
T, adj, adj2v, DG, HG = triangulate_berg(pts)
41+
tri, HG = triangulate_berg(pts)
42+
T, adj, adj2v, DG = tri # tri is a Triangulation struct, see ?Triangulation
4243
```
4344
This function `triangulate_berg` creates the triangulation for the given `pts`, returning:
4445
- `T`: This is the set of triangles, of default type `Set{NTuple{3, Int64}}`. By default, triangles are represented as tuples of indices `(i, j, k)` so that `(pts[i], pts[j], pts[k])` are the points representing the triangle. All triangles `T` are positively oriented.
@@ -166,7 +167,9 @@ y5 = [0.8815, 0.8056, 0.80268, 0.73258, 0.6, 0.598, 0.5777, 0.525, 0.4346, 0.364
166167
x = [x1, x2, x3, x4, x5]
167168
y = [y1, y2, y3, y4, y5]
168169
## Mesh
169-
T, adj, adj2v, DG, pts, BN = generate_mesh(x, y, 0.05; gmsh_path=GMSH_PATH)
170+
tri, BN = generate_mesh(x, y, 0.05; gmsh_path=GMSH_PATH)
171+
T = tri.triangles
172+
pts = tri.points
170173
## Visualise
171174
fig = Figure()
172175
ax = Axis(fig[1, 1])
@@ -358,7 +361,7 @@ This all applies equally as well to `triangulate_berg`.
358361

359362
```julia
360363
Random.seed!(_seed) # Keep the same insertion order for later
361-
T, adj, adj2v, DG = triangulate_berg(pts;
364+
(T, adj, adj2v, DG), _ = triangulate_berg(pts;
362365
IntegerType = Int32,
363366
EdgeType = CustomEdge,
364367
TriangleType = CustomTriangle,

src/DelaunayTriangulation.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ export triangulate_bowyer
4444
export triangulate_berg
4545
export triangulate_structured
4646
export triangulate
47+
export Triangulation
48+
4749
#=
4850
export voronoi
4951
export VoronoiTessellation

src/bowyerwatson.jl

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ end
5656
randomise=true,
5757
trim=true,
5858
try_last_inserted_point=true,
59+
trim_empty_features=true,
5960
skip_pts=Set{Int64}())
6061
6162
Triangulates the set of points `pts` using the Bowyer-Watson algorithm.
@@ -72,13 +73,17 @@ Triangulates the set of points `pts` using the Bowyer-Watson algorithm.
7273
- `randomise=true`: Whether to randomise the insertion order.
7374
- `trim=true`: Whether to remove the ghost triangles at the end.
7475
- `try_last_inserted_point=true`: At each stage, this should be `true` if the point that was last inserted should also be tried for initialising [`jump_and_march`](@ref).
76+
- `trim_empty_features = true`: Whether to remove keys from the `Adjacent` map that refer to deleted edges, and edges from the `DelaunayGraph` that refer to deleted edges.
7577
- `skip_pts`: There may be points you want to avoid adding into the triangulation, but they still exist in `pts`. If this is the case, add the indices for the points into a `Set` and set this keyword to this set.
7678
7779
# Outputs
80+
The output is a `Triangulation` struct, containing
81+
7882
- `T`: The set of triangles.
7983
- `adj`: The [`Adjacent`](@ref) map.
8084
- `adj2v`: The [`Adjacent2Vertex`](@ref) map.
8185
- `DG`: The `[DelaunayGraph`](@ref).
86+
- `pts`: The provided point set.
8287
"""
8388
function triangulate_bowyer(pts;
8489
IntegerType::Type{I}=Int64,
@@ -124,7 +129,7 @@ function triangulate_bowyer(pts;
124129
trim_empty_features && clear_empty_keys!(adj)
125130
trim_empty_features && clear_empty_points!(DG)
126131
trim && remove_ghost_triangles!(T, adj, adj2v, DG)
127-
return T, adj, adj2v, DG
132+
return Triangulation(T, adj, adj2v, DG, pts)
128133
end
129134

130135
function lazy_triangulate_bowyer(pts;

src/data_structures.jl

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -375,4 +375,50 @@ function add_edge!(G::HistoryGraph, T, V::Vararg{Tri,N}) where {Tri,N}
375375
add_edge!(G, T, V)
376376
end
377377
return nothing
378+
end
379+
380+
###################################################
381+
#/
382+
#/
383+
#/ Triangulation
384+
#/
385+
#/
386+
###################################################
387+
"""
388+
Triangulation{T,I,E,Es}
389+
390+
Data structure for a triangulation.
391+
392+
# Fields
393+
- `triangles::T`: Structure containing the collection of triangles.
394+
- `adjacent::Adjacent{I,E}`: The adjacent map.
395+
- `adjacent2vertex::Adjacent2Vertex{I,Es,E}`: The adjacent-to-vertex map.
396+
- `graph::DelaunayGraph{I}`: The Delaunay graph.
397+
- `points::P`: The point set.
398+
"""
399+
struct Triangulation{T,I,E,Es,P}
400+
triangles::T
401+
adjacent::Adjacent{I,E}
402+
adjacent2vertex::Adjacent2Vertex{I,Es,E}
403+
graph::DelaunayGraph{I}
404+
points::P
405+
end
406+
get_triangles(tri::Triangulation) = tri.triangles
407+
get_adjacent(tri::Triangulation) = tri.adjacent
408+
get_adjacent2vertex(tri::Triangulation) = tri.adjacent2vertex
409+
get_graph(tri::Triangulation) = tri.graph
410+
get_points(tri::Triangulation) = tri.points
411+
412+
function Base.iterate(tri::Triangulation, state=1)
413+
if state == 1
414+
return (get_triangles(tri), 2)
415+
elseif state == 2
416+
return (get_adjacent(tri), 3)
417+
elseif state == 3
418+
return (get_adjacent2vertex(tri), 4)
419+
elseif state == 4
420+
return (get_graph(tri), 5)
421+
elseif state == 5
422+
return (get_points(tri), nothing)
423+
end
378424
end

src/deberg.jl

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,45 @@ function add_point_berg!(T, adj::Adjacent{I,E}, adj2v, DG, HG::HistoryGraph{Tri}
2323
return nothing
2424
end
2525

26+
"""
27+
triangulate_berg(pts;
28+
IntegerType::Type{I}=Int64,
29+
EdgeType::Type{E}=NTuple{2,IntegerType},
30+
TriangleType::Type{V}=NTuple{3,IntegerType},
31+
EdgesType::Type{Es}=Set{EdgeType},
32+
TrianglesType::Type{Ts}=Set{TriangleType},
33+
randomise=true,
34+
trim=true,
35+
trim_empty_features=true,
36+
skip_pts=Set{Int64}()) where {I,E,V,Es,Ts}
37+
38+
Triangulates the set of points `pts` using the de Berg's algorithm.
39+
40+
# Inputs
41+
- `pts`: The point set.
42+
43+
# Keyword Arguments
44+
- `IntegerType::Type{I}=Int64`: Type used to represent integers.
45+
- `EdgeType::Type{E}=NTuple{2,IntegerType}`: Type used to represent edges.
46+
- `TriangleType::Type{V}=NTuple{3,IntegerType}`: Type used to represent triangles.
47+
- `EdgesType::Type{Es}=Set{EdgeType}`: Type used to represent a collection of edges.
48+
- `TrianglesType::Type{Ts}=Set{TriangleType}`: Type used to represent a collection of triangles.
49+
- `randomise=true`: Whether to randomise the insertion order.
50+
- `trim=true`: Whether to remove the ghost triangles at the end.
51+
- `trim_empty_features = true`: Whether to remove keys from the `Adjacent` map that refer to deleted edges, and edges from the `DelaunayGraph` that refer to deleted edges.
52+
- `skip_pts`: There may be points you want to avoid adding into the triangulation, but they still exist in `pts`. If this is the case, add the indices for the points into a `Set` and set this keyword to this set.
53+
54+
# Outputs
55+
The output is a `Triangulation` struct, containing
56+
57+
- `T`: The set of triangles.
58+
- `adj`: The [`Adjacent`](@ref) map.
59+
- `adj2v`: The [`Adjacent2Vertex`](@ref) map.
60+
- `DG`: The `[DelaunayGraph`](@ref).
61+
- `pts`: The provided point set.
62+
63+
The second output is `HG`, a [`HistoryGraph`](@ref).
64+
"""
2665
function triangulate_berg(pts;
2766
IntegerType::Type{I}=Int64,
2867
EdgeType::Type{E}=NTuple{2,IntegerType},
@@ -48,7 +87,7 @@ function triangulate_berg(pts;
4887
trim_empty_features && clear_empty_keys!(adj)
4988
trim_empty_features && clear_empty_points!(DG)
5089
trim && remove_bounding_triangle!(T, adj, adj2v, DG)
51-
return T, adj, adj2v, DG, HG
90+
return Triangulation(T, adj, adj2v, DG, pts), HG
5291
end
5392

5493
function remove_bounding_triangle!(T::Ts, adj::Adjacent{I,E}, adj2v, DG) where {I,E,Ts}

src/gmsh.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ function generate_mesh end
142142
end
143143
end
144144
T, adj, adj2v, DG = triangulate(elements, nodes, boundary_nodes)
145-
return T, adj, adj2v, DG, nodes, unique.(boundary_nodes)
145+
return Triangulation(T, adj, adj2v, DG, nodes), unique.(boundary_nodes)
146146
end
147147
@inline function generate_mesh(x::Vector{LinRange{Float64,Int64}}, y::Vector{LinRange{Float64,Int64}}, ref; mesh_algorithm=6, verbosity=0, gmsh_path="./gmsh-4.9.4-Windows64/gmsh.exe", num_threads=Base.Threads.nthreads())
148148
return generate_mesh(collect.(x), collect.(y), ref; verbosity, mesh_algorithm, gmsh_path, num_threads)

src/structured.jl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ function triangulate_structured(a, b, c, d, Nˣ, Nʸ; return_boundary_types=fals
6969
BNy = Vector{Vector{Float64}}([[], [], [], []])
7070
if single_boundary
7171
BN = ch_idx
72-
return T, adj, adj2v, DG, points, BN
72+
return Triangulation(T, adj, adj2v, DG, points), BN
7373
end
7474
for i in ch_idx
7575
if points[1, i] == a
@@ -104,8 +104,8 @@ function triangulate_structured(a, b, c, d, Nˣ, Nʸ; return_boundary_types=fals
104104
BN[2] .= BN[2][idx₂]
105105
BN[3] .= BN[3][idx₃]
106106
BN[4] .= BN[4][idx₄]
107-
return T, adj, adj2v, DG, points, BN
107+
return Triangulation(T, adj, adj2v, DG, points), BN
108108
else
109-
return T, adj, adj2v, DG, points
109+
return Triangulation(T, adj, adj2v, DG, points)
110110
end
111111
end

src/utils.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -467,7 +467,7 @@ set `pts` to those from de Berg's method. If both are identical, return `true`,
467467
out-of-place.
468468
"""
469469
function compare_deberg_to_bowyerwatson(T, adj, adj2v, DG, pts)
470-
_T, _adj, _adj2v, _DG, _ = triangulate_berg(pts)
470+
(_T, _adj, _adj2v, _DG), _ = triangulate_berg(pts)
471471
return compare_deberg_to_bowyerwatson(T, adj, adj2v, DG, _T, _adj, _adj2v, _DG)
472472
end
473473

test/data_structures.jl

Lines changed: 69 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ end
210210
@test collect(DT.edges(adj)) == [(2, 3), (5, 7)] || collect(DT.edges(adj)) == [(5, 7), (2, 3)]
211211

212212
@inferred DT.get_edge(adj, 2, 3)
213-
@inferred DT.get_edge(adj, (2,3))
213+
@inferred DT.get_edge(adj, (2, 3))
214214
@inferred DT.get_edge(adj, -3, 50)
215215
end
216216

@@ -306,7 +306,7 @@ end
306306
@test DT.get_neighbour(DG, 3) == Set([1])
307307
@test edges(DG) == DG.graph.E
308308

309-
pts = rand(SVector{2, Float64}, 250)
309+
pts = rand(SVector{2,Float64}, 250)
310310
T, adj, adj2v, DG = DT.triangulate_bowyer(pts)
311311
for i in eachindex(pts)
312312
@test deg(graph(DG), i) == DT.num_neighbours(DG, i)
@@ -377,4 +377,71 @@ end
377377
DT.add_edge!(HH, T₁, T₂)
378378
DT.add_edge!(HH, T₁, T₃)
379379
@test DT.graph(H) == DT.graph(HH)
380+
end
381+
382+
###################################################
383+
#/
384+
#/
385+
#/ Storing a Delaunay triangulation
386+
#/
387+
#/
388+
###################################################
389+
@testset "Testing from the Bowyer-Watson algorithm" begin
390+
pts = rand(2, 500)
391+
Random.seed!(2929292)
392+
T, adj, adj2v, DG = triangulate_bowyer(pts)
393+
tri = Triangulation(T, adj, adj2v, DG, pts)
394+
395+
@test DT.get_triangles(tri) === T
396+
@test DT.get_adjacent(tri) === adj
397+
@test DT.get_adjacent2vertex(tri) === adj2v
398+
@test DT.get_graph(tri) === DG
399+
@test DT.get_points(tri) === pts
400+
401+
_T, _adj, _adj2v, _DG, _pts = tri
402+
@test _T === T
403+
@test _adj === adj
404+
@test _adj2v === adj2v
405+
@test _DG === DG
406+
@test _pts === pts
407+
408+
Random.seed!(2929292)
409+
_tri = triangulate_bowyer(pts)
410+
@test _tri isa Triangulation
411+
@test _tri.triangles == T
412+
@test _tri.adjacent.adjacent == adj.adjacent
413+
@test _tri.adjacent2vertex.adjacent2vertex == adj2v.adjacent2vertex
414+
@test _tri.graph.graph == DG.graph
415+
@test _tri.points == pts
416+
end
417+
418+
@testset "Testing from de Berg's method" begin
419+
pts = rand(2, 500)
420+
Random.seed!(29292222292)
421+
(T, adj, adj2v, DG), HG = triangulate_berg(pts)
422+
@test HG isa DT.HistoryGraph
423+
tri = Triangulation(T, adj, adj2v, DG, pts)
424+
425+
@test DT.get_triangles(tri) === T
426+
@test DT.get_adjacent(tri) === adj
427+
@test DT.get_adjacent2vertex(tri) === adj2v
428+
@test DT.get_graph(tri) === DG
429+
@test DT.get_points(tri) === pts
430+
431+
_T, _adj, _adj2v, _DG, _pts = tri
432+
@test _T === T
433+
@test _adj === adj
434+
@test _adj2v === adj2v
435+
@test _DG === DG
436+
@test _pts === pts
437+
438+
Random.seed!(29292222292)
439+
_tri, _HG = triangulate_berg(pts)
440+
@test _tri isa Triangulation
441+
@test _tri.triangles == T
442+
@test _tri.adjacent.adjacent == adj.adjacent
443+
@test _tri.adjacent2vertex.adjacent2vertex == adj2v.adjacent2vertex
444+
@test _tri.graph.graph == DG.graph
445+
@test _tri.points == pts
446+
@test HG.graph == _HG.graph
380447
end

0 commit comments

Comments
 (0)