TriangleNet.Mesh.TriangulatePolygon C# (CSharp) Method

TriangulatePolygon() private method

Find the Delaunay triangulation of a polygon that has a certain "nice" shape. This includes the polygons that result from deletion of a vertex or insertion of a segment.
This is a conceptually difficult routine. The starting assumption is that we have a polygon with n sides. n - 1 of these sides are currently represented as edges in the mesh. One side, called the "base", need not be. Inside the polygon is a structure I call a "fan", consisting of n - 1 triangles that share a common origin. For each of these triangles, the edge opposite the origin is one of the sides of the polygon. The primary edge of each triangle is the edge directed from the origin to the destination; note that this is not the same edge that is a side of the polygon. 'firstedge' is the primary edge of the first triangle. From there, the triangles follow in counterclockwise order about the polygon, until 'lastedge', the primary edge of the last triangle. 'firstedge' and 'lastedge' are probably connected to other triangles beyond the extremes of the fan, but their identity is not important, as long as the fan remains connected to them. Imagine the polygon oriented so that its base is at the bottom. This puts 'firstedge' on the far right, and 'lastedge' on the far left. The right vertex of the base is the destination of 'firstedge', and the left vertex of the base is the apex of 'lastedge'. The challenge now is to find the right sequence of edge flips to transform the fan into a Delaunay triangulation of the polygon. Each edge flip effectively removes one triangle from the fan, committing it to the polygon. The resulting polygon has one fewer edge. If 'doflip' is set, the final flip will be performed, resulting in a fan of one (useless?) triangle. If 'doflip' is not set, the final flip is not performed, resulting in a fan of two triangles, and an unfinished triangular polygon that is not yet filled out with a single triangle. On completion of the routine, 'lastedge' is the last remaining triangle, or the leftmost of the last two. Although the flips are performed in the order described above, the decisions about what flips to perform are made in precisely the reverse order. The recursive triangulatepolygon() procedure makes a decision, uses up to two recursive calls to triangulate the "subproblems" (polygons with fewer edges), and then performs an edge flip. The "decision" it makes is which vertex of the polygon should be connected to the base. This decision is made by testing every possible vertex. Once the best vertex is found, the two edges that connect this vertex to the base become the bases for two smaller polygons. These are triangulated recursively. Unfortunately, this approach can take O(n^2) time not only in the worst case, but in many common cases. It's rarely a big deal for vertex deletion, where n is rarely larger than ten, but it could be a big deal for segment insertion, especially if there's a lot of long segments that each cut many triangles. I ought to code a faster algorithm some day.
private TriangulatePolygon ( TriangleNet.Data.Otri firstedge, TriangleNet.Data.Otri lastedge, int edgecount, bool doflip, bool triflaws ) : void
firstedge TriangleNet.Data.Otri The primary edge of the first triangle.
lastedge TriangleNet.Data.Otri The primary edge of the last triangle.
edgecount int The number of sides of the polygon, including its /// base.
doflip bool A flag, wether to perform the last flip.
triflaws bool A flag that determines whether the new triangles should /// be tested for quality, and enqueued if they are bad.
return void
        private void TriangulatePolygon(Otri firstedge, Otri lastedge,
                                int edgecount, bool doflip, bool triflaws)
        {
            Otri testtri = default(Otri);
            Otri besttri = default(Otri);
            Otri tempedge = default(Otri);
            Vertex leftbasevertex, rightbasevertex;
            Vertex testvertex;
            Vertex bestvertex;

            int bestnumber = 1;

            // Identify the base vertices.
            leftbasevertex = lastedge.Apex();
            rightbasevertex = firstedge.Dest();

            // Find the best vertex to connect the base to.
            firstedge.Onext(ref besttri);
            bestvertex = besttri.Dest();
            besttri.Copy(ref testtri);

            for (int i = 2; i <= edgecount - 2; i++)
            {
                testtri.OnextSelf();
                testvertex = testtri.Dest();
                // Is this a better vertex?
                if (Primitives.InCircle(leftbasevertex, rightbasevertex, bestvertex, testvertex) > 0.0)
                {
                    testtri.Copy(ref besttri);
                    bestvertex = testvertex;
                    bestnumber = i;
                }
            }

            if (bestnumber > 1)
            {
                // Recursively triangulate the smaller polygon on the right.
                besttri.Oprev(ref tempedge);
                TriangulatePolygon(firstedge, tempedge, bestnumber + 1, true, triflaws);
            }

            if (bestnumber < edgecount - 2)
            {
                // Recursively triangulate the smaller polygon on the left.
                besttri.Sym(ref tempedge);
                TriangulatePolygon(besttri, lastedge, edgecount - bestnumber, true, triflaws);
                // Find 'besttri' again; it may have been lost to edge flips.
                tempedge.Sym(ref besttri);
            }

            if (doflip)
            {
                // Do one final edge flip.
                Flip(ref besttri);
                if (triflaws)
                {
                    // Check the quality of the newly committed triangle.
                    besttri.Sym(ref testtri);
                    quality.TestTriangle(ref testtri);
                }
            }
            // Return the base triangle.
            besttri.Copy(ref lastedge);
        }