-1

Recently I have learnt about the Delaunay Triangulation and using the Bowyer-Watson algorithm to solve it. When implementing, I followed along from the wikipedia pseudocode and other sources to create my own solution in lua. However, I noticed that when changing the order of the points it sometimes changes the output - resulting in the incorrect outcome but works perfectly other times. The code below is the main triangulation function.

function polygon:Triangulate(superTriangle)
    local vertices = {}
    for _, v in ipairs(self.nodes) do
        table.insert(vertices, v)
    end
    for _, v in ipairs(superTriangle:GetConnectedNodes()) do
        table.insert(vertices, v)
    end
    table.insert(self.triangles, superTriangle)

    for _, v in ipairs(vertices) do
        local edgeBuffer = {}
        local badTriangles = {}
        for i = #self.triangles, 1, - 1 do
            local tri = self.triangles[i]
            local circle = circumcircle.fromTriangle(tri)
            if circle:ContainsNode(v) then
                table.insert(badTriangles, tri)
            end
        end

        for _, tri1 in ipairs(badTriangles) do
            local edges1 = tri1:GetEdges()
            for j1 = 1, 3 do
                for _, tri2 in ipairs(badTriangles) do
                    if tri1 == tri2 then goto continue end
                    local edges2 = tri2:GetEdges()
                    for j2 = 1, 3 do
                        if edges1[j1]:CompareTo(edges2[j2]) then
                            goto ignore
                        end
                    end
                    ::continue::
                end
                table.insert(edgeBuffer, edges1[j1])
                ::ignore::
            end
        end

        for _, tri1 in pairs(badTriangles) do
            for i, tri2 in pairs(self.triangles) do
                if tri2 == tri1 then
                    table.remove(self.triangles, i)
                    break
                end
            end
        end

        for _, edge in ipairs(edgeBuffer) do
            local newTriangle = triangle.new(edge.node1, edge.node2, v)
            table.insert(self.triangles, newTriangle)
        end
    end
    
    for i = #self.triangles, 1, -1 do
        local nodes = self.triangles[i]:GetConnectedNodes()
        for j = 1, 3 do
            local current = nodes[j]
            if superTriangle:SharesNode(current) then
                table.remove(self.triangles, i)
                goto skip
            end
        end
        ::skip::
    end

The attributes nodes contains the input points, and triangles is an initially empty list which stores the output triangles. The node class just contains an x and y position, whilst the edge class contains two nodes. The triangle is therefore made up of 3 nodes (which also has all 3 edges as an attribute). The ContainsNode method for circumcircle, is below

function circumcircle:ContainsNode(node)
    local newRadius = math.sqrt((node.x - self.x)^2 + (node.y - self.y)^2)
    return newRadius <= self.radius
end

The CompareTo function checks to see if the x and y attributes are equal - and for the edge check the possible nodes and compares those.

When testing, I used the following points {x = 30, y = 45},
{x = 50, y = 65},
{x = 0, y = 0},
{x = 0, y = 100},
{x = 100, y = 100},
{x = 100, y = 0}
Which produces the following output:
Output
(The blue lines are the calculated triangles, where the red triangle is the super triangle) When changing the order of the points to {x = 0, y = 0},
{x = 0, y = 100},
{x = 100, y = 100},
{x = 100, y = 0}
{x = 30, y = 45},
{x = 50, y = 65},
It breaks the output, producing:
Broken output

I have looked into the functions used to validate whether a node falls into the circumcircle, and don't think it is incorrect but I am not too versed on triangulation and am new to the subject. It would be great if anyone could help. I think I may just be missing something here so poking me in the right direction would be excellent.

3
  • I'm not sure that this is your problem, but return newRadius <= self.radius --> return newRadius < self.radius. Nodes on the circumference of a circle are not contained within the circle. Commented Jul 13 at 0:12
  • 1
    But the provided code isn't complete enough to review; there are too many missing definitions. If I were you, though, the first thing that I would do is refactor that gigantic polygon:Triangulate function into several smaller functions so that the main Triangulate function can be expressed more clearly. In the process you may find your issue. Commented Jul 13 at 0:15
  • @adabsurdum Thanks for the response, going to look into refactoring the Triangulate function in hopes I find the issue. Also, I believe I was misinformed in that I thought that the node is considered in the circle if it lies on the circumference - and have now fixed it.
    – Thomasssb1
    Commented Jul 15 at 17:51

0

Browse other questions tagged or ask your own question.