## Boundary Nodes

As mentioned at the start of this section, the interface for representing boundary nodes allows for support for a contiguous boundary, a segmented boundary, and multiple separate boundaries. (There is also support for more complex geometries, as described in the constrained triangulation section, although features like point location have limited support for e.g. non-convex domains and regions with holes inside holes.) This interface is customisable, and we define the following methods for this.

### Necessary Methods

DelaunayTriangulation.has_multiple_curvesFunction
has_multiple_curves(bn::A) where {A}

Returns true if the given set of boundary nodes bn defines multiple curves, meaning disjoint boundary curves. We currently define the methods

has_multiple_curves(::AAA) where {F<:Number,A<:AV{F},AA<:AV{A},AAA<:AV{AA}}
has_multiple_curves(::AA) where {F<:Number,A<:AV{F},AA<:AV{A}}
has_multiple_curves(::A) where {F<:Number,A<:AV{F}}

with the first method returning true, while the last two methods return false, and AV = AbstractVector. You can extend this function as you need.

DelaunayTriangulation.has_multiple_segmentsFunction
has_multiple_segments(bn::A) where {A}

Returns true if the given set of boundary nodes bn contains multiple segments, meaning disjoint boundary curves. We currently define the methods

has_multiple_segments(::AAA) where {F<:Number,A<:AV{F},AA<:AV{A},AAA<:AV{AA}}
has_multiple_segments(::AA) where {F<:Number,A<:AV{F},AA<:AV{A}}
has_multiple_segments(::A) where {F<:Number,A<:AV{F}}

with the first and second methods returning true, while the last method returns false, and AV = AbstractVector. You can extend this function as you need.

DelaunayTriangulation.num_curvesFunction
num_curves(bn::A)

Returns the number of curves defined by the boundary nodes bn. We currently define the methods

num_curves(bn::AAA) where {F<:Number,A<:AV{F},AA<:AV{A},AAA<:AV{AA}}

which simply returns bn.

DelaunayTriangulation.num_segmentsFunction
num_segments(bn::A)

Returns the number of segments defined by the boundary nodes bn. We currently define the method

num_segments(bn::AA) where {F<:Number,A<:AV{F},AA<:AV{A}}

which simply returns length(bn).

DelaunayTriangulation.num_boundary_edgesFunction
num_boundary_edges(bn)

Given a collection of boundary nodes bn, returns the number of edges. This only needs to be defined for individual segments. We define the method

num_boundary_edges(bn::A) where {A<:AbstractVector}

which returns length(bn) - 1 (-1 because it is assumed that bn[begin] == bn[end]). This is the only method that needs to be extended.

See also getboundarynodes.

DelaunayTriangulation.getboundarynodesFunction
getboundarynodes(bn::A, mnℓ...)

Given a collection of boundary nodes bn, returns the specified component of the collection. There are several forms for the methods. In these methods, it is assumed that one-based indexing is used for accessing all the boundary nodes. If you want to use offsets, for example, then define getboundarynodes appropriately (e.g. maybe getboundarynodes(bn, m) could map m to m-4 if 4 is your offset).

The methods that you need to define are those that go down a level, i.e. from a set of curves to a curve, from a set of segments to a set of nodes, and from a set of nodes to a node. Of course, if you only ever use e.g. a set of nodes, then you need only define that method. The methods that we define for this are

getboundarynodes(bn::AAA, m::Integer) where {F<:Number,A<:AV{F},AA<:AV{A},AAA<:AV{AA}}
getboundarynodes(bn::AA, n::Integer) where {F<:Number,A<:AV{F},AA<:AV{A}}
getboundarynodes(bn::A, ℓ::Integer) where {F<:Number,A<:AV{F}}

The first method takes a set of curves to the mth curve, the second takes a set of segments to the nth segment, and the third takes a set of nodes to the ℓth node. These are the only methods that need to be extended. For the set of curves case, we also define

getboundarynodes(bn, m::Integer, n::Integer)
getboundarynodes(bn, (m, n)::NTuple{2,Integer})

which calls getboundarynodes(getboundarynodes(bn, m), n). This does not need to be extended. Lastly, we also define

getboundarynodes(bn::A, ::A) where {A}

which simply returns bn. This is useful when using the result of construct_boundary_map.

DelaunayTriangulation.each_boundary_nodeFunction
each_boundary_node(bn::A)

Returns an iterator that goes over each node in bn. Only defined for single segments so that bn acts like a vector of numbers. The only method currently defined is

each_boundary_node(bn::A) where {F<:Number,A<:AbstractVector{F}}

which just returns bn. You can extend this function as you need. If you really want to loop over every boundary node, you can make use of the result from construct_boundary_map.

### Generic Methods

DelaunayTriangulation.construct_boundary_mapFunction
construct_boundary_map(bn; IntegerType::Type{I} = Int) where {I}

Given a set of boundary nodes bn, returns a OrderedDict that maps boundary indices to their position in bn. In particular:

• has_multiple_curves(bn)

In this case, the result is a dict = OrderedDict{I, NTuple{2, I}}. The results will be of the form dict[i] = (m, n), so that boundary indices with value i correspond to nodes at get_boundary_nodes(bn, m, n), i.e. the nth segment of the mth curve.

• has_multiple_segments(bn)

In this case, the result is a dict = OrderedDict{I, I}. The results will be of the form dict[i] = n, so that boundary indices with value i correspond to nodes at get_boundary_nodes(bn, n), i.e. the nth segment.

• else

Here, the result is a dict = OrderedDict{I, F}, mapping -1 back to bn and F = typeof(bn).

Iteration Tips

This dict can be useful for iterating over all boundary nodes. For example, you could do

bn_map = construct_boundary_map(bn)
for segment_index in values(bn_map)
nodes = get_boundary_nodes(bn, segment_index)
## Do something with the nodes
end 

The above will work for any form of bn also.

DelaunayTriangulation.construct_boundary_index_rangesFunction
construct_boundary_index_ranges(boundary_nodes; IntegerType::Type{I}=Int) where {I}

Given a set of boundary_nodes, creates an OrderedDict that maps boundary indices to the range of all boundary indices that the corresponding boundary curve could correspond to. For example, suppose we have

julia> boundary_nodes = [
[
[1, 2, 3, 4], [4, 5, 6, 1]
],
[
[18, 19, 20, 25, 26, 30]
],
[
[50, 51, 52, 53, 54, 55], [55, 56, 57, 58], [58, 101, 103, 105, 107, 120], [120, 121, 122, 50]
]
]

Then the first curve, [[1, 2, 3, 4], [4, 5, 6, 1]] has boundary indices -1 and -2, so the range would be -2:-1. The full Dict we obtain will be

julia> construct_boundary_index_ranges(boundary_nodes)
OrderedDict{Int, UnitRange{Int}} with 7 entries:
-1 => -2:-1
-2 => -2:-1
-3 => -3:-3
-4 => -7:-4
-5 => -7:-4
-6 => -7:-4
-7 => -7:-4
DelaunayTriangulation.get_curve_indexFunction
get_curve_index(dict, i)
get_curve_index(i)

Given a dict from construct_boundary_map and a boundary index i, returns the index of the curve corresponding to that boundary index. The second method maps i to 1 if it is an integer, and i[1] if it is a Tuple.

DelaunayTriangulation.get_segment_indexFunction
get_segment_index(dict, i)
get_segment_index(i)

Given a dict from construct_boundary_map and a boundary index i, returns the index of the segment corresponding to that boundary index. The second method maps i to i if it is an integer, 1 if it is a vector, and i[2] if it is a Tuple.

DelaunayTriangulation.num_outer_boundary_segmentsFunction
num_outer_boundary_segments(boundary_nodes)

Given a set of boundary_nodes, returns the number of segments that correspond to the outer boundary. Note that this also gives the range of outer boundary indices, i.e. -1:-1:-num_outer_boundary_segments(boundary_nodes).

DelaunayTriangulation.construct_boundary_edge_mapFunction
construct_boundary_edge_map(bn::A; IntegerType::Type{I}=Int, EdgeType::Type{E}=NTuple{2,IntegerType}) where {A,I,E}

Constructs a map that takes boundary edges (i,j) to a Tuple giving the edge's position in the corresponding set of boundary nodes.

DelaunayTriangulation.insert_boundary_node!Function
insert_boundary_node!(bn, pos, node)

Inserts a boundary node node into the set of boundary nodes bn at the position pos. The first element of pos finds the set of boundary nodes that lie on the segment corresponding to this first element, and then the second element of pos gives the position of the array to insert node into. In particular,

insert_boundary_node!(bn, pos, node)

is the same as

insert!(get_boundary_nodes(bn, pos[1]), pos[2], node)
DelaunayTriangulation.delete_boundary_node!Function
delete_boundary_node!(bn, pos)

Deletes a boundary node from the set of boundary nodes bn at the position pos. The first element of pos finds the set of boundary nodes that lie on the segment corresponding to this first element, and then the second element of pos gives the position of the array to delete. In particular,

delete_boundary_node!(bn, pos)

is the same as

deleteat!(get_boundary_nodes(bn, pos[1]), pos[2])