13.8 Delaunay Triangulation 761
T.v(3) are the same integer. The triangle object is also assumed to have an opera-
tion
T.adj(i) that returns a reference to the adjacent triangle that shares the edge
<T.v(i),T.v(i + 1)>. If there is no adjacent triangle to that edge, the reference is null.
The edge object
E is assumed to have an operation E.adj(i) that returns a reference
to an adjacent triangle (at most two such triangles).
Figure 13.46 shows the various quantities used in the pseudocode in the loop
where the stack of triangle pairs is processed. Theoretically, the loop can be infinite if a
triangle pair has all vertices on a common circumcircle. Here is where the typical con-
dition is specified by the computational geometers: no four points in the input set can
be cocircular. However, an implementation must guard against this when floating-
point arithmetic is used. It is possible that four points are not exactly cocircular, but
floating-point round-off errors can make the triangle pair behave as if the points are
cocircular. If such a pair is revisited in the loop, they might very well be swapped back
to their original configuration, and the entire process starts over. To avoid the infi-
nite loop, an implementation can evaluate both circumcircle tests, one for the current
triangle configuration and one for the swapped configuration. If both tests indicate
a swap should occur, then the swap should not be made. Be aware, though, that if
the circumcircle test accepts two adjacent triangles as input, additional care must be
taken to pass the triangles in the same order. Otherwise, the floating-point calcu-
lations involving the triangles might possibly cause the Boolean return value to dif-
fer. That is, if the function prototype is
bool FirstInCircumcircleOfSecond(Triangle,
Triangle)
, the calls FirstInCircumcircleOfSecond(T0,T1) and FirstInCircumcircle-
OfSecond(T1,T0)
might return different values. One way to obtain a consistent order-
ing is as follows. The two vertices that are opposite the shared edge of the triangles
have indices maintained by the mesh object. Pass the triangles so that the first triangle
has the vertex of the smallest index between the two triangles.
Once all the points are inserted into the triangulation and all necessary edge swaps
have occurred, any triangles that exist only because they share a vertex from the su-
pertriangle must be removed. Another potential pitfall here is that all triangles might
be removed. This is the case when the initial points all lie on the same line. If an
application really needs the incremental algorithm to apply to such a set (interpo-
lation based on a collection of data points is one such application), some type of
preprocessing must occur to detect the collinearity. Probably the best bet is to use
the relationship between the 2D Delaunay triangulation and the 3D convex hull that
is described later in this section. The convex hull algorithms appear to be better suited
for handling degeneracies due to the fact that the intrinsic dimensionality of the input
point set is smaller than the dimension of the space in which the points lie.
13.8.2 Incremental Construction in General Dimensions
An attempt at extending the 2D edge swapping algorithm to 3D has a couple of
technical issues to consider. The first involves the extension of the linear walk that
was used to find a containing triangle. Each input point P is inserted into the current