简体   繁体   中英

Algorithm for polygon triangulation

I have written the following code for the generation of all "triangulations" of a regular or convex polygon:

def getTriangles(points,i,j):
    print('i={}, j={}'.format(i,j))
    ee = []
    if j-i<2:
        return []
    if j-i==2:
        return [[[i,i+1,j]]]
    for k in range(i+1,j):
        print('    k={}'.format(k))
        e1= getTriangles(points,i,k)
        e2 = getTriangles(points,k,j)
        for x in e1:
            for y in e2:
                e = [[i,k,j]]
                e.extend(x)
                e.extend(y)
                ee.append(e)
        if len(e1)==0:
            for y in e2:
                e = [[i,k,j]]
                e.extend(y)
                ee.append(e)
        if len(e2)==0:
            for a in e1:
                e = [[i,k,j]]
                e.extend(x)
                ee.append(e)
        print('        e1={}, e2={}, ee={}'.format(e1,e2,ee))
    return ee

n=5
tr = getTriangles(range(1,n+1),0,n-1)
print()
print(tr)
print(len(tr))

For n=3,4 it is correct, and in general "navigates" through the right number of possible triangulations (that is the Catalan number) for n=3,4,5,6,7,8, but the triangulations are not unique. here the formatted output for n=5, consisting of a list of triangles (eg three vertices in [0,1,2,3,4]):

[[[0, 1, 4], [1, 2, 4], [2, 3, 4]],
 [[0, 1, 4], [1, 3, 4], [1, 2, 3]],
 [[0, 2, 4], [0, 1, 2], [2, 3, 4]],
 [[0, 3, 4], [0, 2, 3], [0, 1, 2]], 
 [[0, 3, 4], [0, 2, 3], [0, 1, 2]]]

as you can see the last two are equal. Where is the error? Intuitively the code is more complex than needed.

EDIT As you can see I'm not in bad company for this error: here is Robert Sedgewick, a computer science professor at Princeton University and in the background you see that the n=5 is correct but for n=6 there are double;-)

在此处输入图像描述

The following code seams to work. The change is in the middle. The algorithm fix the edge [i,j] and k moves from i+1 to j-1. The triangle ijk is fixed and split the polygon in three sub-polygons: itself, the polygon i...k, and the polygon, k..j. If k=i+1 or k=j-1, one of the two polygon is degenerate (empty):

def getTriangles(points,i,j):
    print('i={}, j={}'.format(i,j))
    ee = []
    if j-i<2:
        return []
    if j-i==2:
        return [[[i,i+1,j]]]
    for k in range(i+1,j): # k is the vertex such that the triangle ikj split the polygon 1j in 2 subspace plus the triangle ikj
        print('    k={}'.format(k))
        e1= getTriangles(points,i,k)
        e2 = getTriangles(points,k,j)
        if k==i+1:
            for y in e2:
                e = [[i,k,j]]
                e.extend(y)
                ee.append(e)
        elif k==j-+1:
            for x in e1:
                e = [[i,k,j]]
                e.extend(x)
                ee.append(e)
        else:
            for x in e1:
                for y in e2:
                    e = [[i,k,j]]
                    e.extend(x)
                    e.extend(y)
                    ee.append(e)
        print('        e1={}, e2={}, ee={}'.format(e1,e2,ee))
    return ee

n=5
tr = getTriangles(range(1,n+1),0,n-1)
print()
print(tr)
print(len(tr))

Here's a more Pythonic version of the above:

def genTriangles(i, j):
    if j - i < 2:
        yield []
        return
    
    if j - i == 2:
        yield [(i, i+1, j)]
        return 
    
    for k in range(i + 1, j):
        for x in genTriangles(i, k):
            for y in genTriangles(k, j):
                yield x + y + [(i, k, j)]

n = 5
for k, tr in enumerate(genTriangles(0, n - 1), 1):
    print(k, tr)

1 [(2, 3, 4), (1, 2, 4), (0, 1, 4)]
2 [(1, 2, 3), (1, 3, 4), (0, 1, 4)]
3 [(0, 1, 2), (2, 3, 4), (0, 2, 4)]
4 [(1, 2, 3), (0, 1, 3), (0, 3, 4)]
5 [(0, 1, 2), (0, 2, 3), (0, 3, 4)]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM