Constrained Triangulations

Constrained Segments

In this tutorial, we introduce constrained triangulations, starting with the simple case of only having constrained segments, meaning edges that are forced to be in the final triangulation. To start, let us load in the packages we will need.

using DelaunayTriangulation
using CairoMakie

We consider triangulating the following set of points:

a = (0.0, 0.0)
b = (0.0, 1.0)
c = (0.0, 2.5)
d = (2.0, 0.0)
e = (6.0, 0.0)
f = (8.0, 0.0)
g = (8.0, 0.5)
h = (7.5, 1.0)
i = (4.0, 1.0)
j = (4.0, 2.5)
k = (8.0, 2.5)
pts = [a, b, c, d, e, f, g, h, i, j, k]
11-element Vector{Tuple{Float64, Float64}}:
 (0.0, 0.0)
 (0.0, 1.0)
 (0.0, 2.5)
 (2.0, 0.0)
 (6.0, 0.0)
 (8.0, 0.0)
 (8.0, 0.5)
 (7.5, 1.0)
 (4.0, 1.0)
 (4.0, 2.5)
 (8.0, 2.5)

To now define the segments, we define:

C = Set([(2, 1), (2, 11), (2, 7), (2, 5)])
Set{Tuple{Int64, Int64}} with 4 elements:
  (2, 5)
  (2, 11)
  (2, 1)
  (2, 7)

With this notation, each Tuple is an individual edge to include in the triangulation, with (i, j) meaning the edge connecting the points pts[i] and pts[j] together. Let us now make the triangulation, comparing it to its unconstrained counterpart.

tri = triangulate(pts)
Delaunay Triangulation.
   Number of vertices: 11
   Number of triangles: 11
   Number of edges: 21
   Has boundary nodes: false
   Has ghost triangles: true
   Curve-bounded: false
   Weighted: false
   Constrained: false
cons_tri = triangulate(pts; segments = C)
Delaunay Triangulation.
   Number of vertices: 11
   Number of triangles: 11
   Number of edges: 21
   Has boundary nodes: false
   Has ghost triangles: true
   Curve-bounded: false
   Weighted: false
   Constrained: true
fig = Figure()
ax1 = Axis(
    fig[1, 1], xlabel = "x", ylabel = L"y",
    title = "(a): Unconstrained", titlealign = :left,
    width = 300, height = 300,
)
ax2 = Axis(
    fig[1, 2], xlabel = "x", ylabel = L"y",
    title = "(b): Constrained", titlealign = :left,
    width = 300, height = 300,
)
triplot!(ax1, tri)
triplot!(ax2, cons_tri, show_constrained_edges = true)
resize_to_layout!(fig)
fig
Example block output

As you can see, the constrained edges in magenta have now been included in the triangulation in (b), whereas in (a) most were previously not included.

You can view the constrained edges by using

get_interior_segments(cons_tri)
Set{Tuple{Int64, Int64}} with 4 elements:
  (1, 2)
  (2, 5)
  (7, 2)
  (11, 2)

There is also a function get_all_segments, which in this case is the same as get_interior_segments, but in the case of a triangulation with constrained boundaries, it will also include the boundary segments whereas get_interior_segments will not; this is demonstrated in the later tutorials.

Just the code

An uncommented version of this example is given below. You can view the source code for this file here.

using DelaunayTriangulation
using CairoMakie

a = (0.0, 0.0)
b = (0.0, 1.0)
c = (0.0, 2.5)
d = (2.0, 0.0)
e = (6.0, 0.0)
f = (8.0, 0.0)
g = (8.0, 0.5)
h = (7.5, 1.0)
i = (4.0, 1.0)
j = (4.0, 2.5)
k = (8.0, 2.5)
pts = [a, b, c, d, e, f, g, h, i, j, k]

C = Set([(2, 1), (2, 11), (2, 7), (2, 5)])

tri = triangulate(pts)

cons_tri = triangulate(pts; segments = C)

fig = Figure()
ax1 = Axis(
    fig[1, 1], xlabel = "x", ylabel = L"y",
    title = "(a): Unconstrained", titlealign = :left,
    width = 300, height = 300,
)
ax2 = Axis(
    fig[1, 2], xlabel = "x", ylabel = L"y",
    title = "(b): Constrained", titlealign = :left,
    width = 300, height = 300,
)
triplot!(ax1, tri)
triplot!(ax2, cons_tri, show_constrained_edges = true)
resize_to_layout!(fig)
fig

get_interior_segments(cons_tri)

This page was generated using Literate.jl.