Skip to main content

Simple Polygon Triangulation

Every simple polygon with nn vertices admits a triangulation into exactly n−2n - 2 triangles using only its vertices — the Two Ears Theorem of Meisters guarantees that any simple polygon with at least four vertices has at least two ears, where an ear is a vertex whose two neighbors can be joined by a diagonal that lies entirely inside the polygon.

Ear clipping exploits that fact directly: repeatedly find an ear, emit the triangle formed by the ear vertex and its two neighbors, and delete the ear from the vertex list. After n−2n - 2 clips the polygon collapses to a single triangle. It is the simplest correct triangulation algorithm; O(nlog⁡n)O(n \log n) and O(n)O(n) alternatives (Chazelle's monotone-polygon sweep, Seidel's randomized algorithm) exist for performance-critical code.

Codes​

def solve(xs):
polygon = xs[0]
n = len(polygon)
if n < 3:
return []

def cross(o, a, b):
return ((a[0]-o[0])*(b[1]-o[1]) - (a[1]-o[1])*(b[0]-o[0]))

area2 = 0
for i in range(n):
x1, y1 = polygon[i]
x2, y2 = polygon[(i+1) % n]
area2 += x1*y2 - x2*y1
idx = list(range(n))
if area2 < 0:
idx.reverse()

def in_triangle(p, a, b, c):
d1 = cross(a, b, p)
d2 = cross(b, c, p)
d3 = cross(c, a, p)
has_neg = (d1 < 0) or (d2 < 0) or (d3 < 0)
has_pos = (d1 > 0) or (d2 > 0) or (d3 > 0)
return not (has_neg and has_pos)

def is_ear(i):
m = len(idx)
prev_i = idx[(i - 1) % m]
curr_i = idx[i]
next_i = idx[(i + 1) % m]
a = polygon[prev_i]
b = polygon[curr_i]
c = polygon[next_i]
if cross(a, b, c) <= 0:
return False
for j in range(m):
k = idx[j]
if k in (prev_i, curr_i, next_i):
continue
if in_triangle(polygon[k], a, b, c):
return False
return True

triangles = []
guard = 0
while len(idx) > 3 and guard < n * n:
guard += 1
found = False
for i in range(len(idx)):
if is_ear(i):
m = len(idx)
prev_i = idx[(i - 1) % m]
curr_i = idx[i]
next_i = idx[(i + 1) % m]
triangles.append(sorted([prev_i, curr_i, next_i]))
idx.pop(i)
found = True
break
if not found:
break
if len(idx) == 3:
triangles.append(sorted(idx))
triangles.sort()
return triangles

Example​

Loading Python runner...

Description​

Run time analysis​

O(n3)O(n^3) for the naive ear-clipping loop. Each of the n−2n - 2 clips scans every remaining vertex for ear status, and the ear test itself walks the remaining vertices. The running time drops to O(n2)O(n^2) if one caches the ear status of each vertex and only updates its two neighbors after a clip.

Space analysis​

O(n)O(n). We maintain a single vertex index list plus the output triangle list, both of length linear in the input.

Proof of correctness​

Meisters' Two Ears Theorem states that every simple polygon with n≥4n \ge 4 vertices has at least two ears. Therefore, as long as the current polygon has at least four vertices, the inner loop finds at least one ear, clips it, and the remaining vertex sequence is again a simple polygon (the clip replaces two consecutive edges with one diagonal, and the diagonal lies inside the polygon by the definition of an ear, so no self-intersection is introduced). Induction on the number of vertices completes the proof: the three-vertex polygon is trivially a single triangle, and an ear clip reduces the problem from nn to n−1n - 1 vertices while emitting exactly one triangle. The total number of emitted triangles is n−2n - 2.

Extensions​

Applications​

References​

  • de Berg, Cheong, van Kreveld, Overmars. Computational Geometry: Algorithms and Applications, 3rd ed., Chapter 3 (Polygon Triangulation).
  • Meisters, G. H. "Polygons have ears." The American Mathematical Monthly, 1975.
  • Chazelle, B. "Triangulating a simple polygon in linear time." Discrete and Computational Geometry, 1991.
  • cp-algorithms — Computational geometry