From c64ae8478e94fdf5b0ca795f326a2ccc9a73fe15 Mon Sep 17 00:00:00 2001 From: Tim Heap Date: Tue, 13 Aug 2024 15:43:18 +1000 Subject: [PATCH] Generate a fan triangulation for convex polygons The ear clipping method is correct for all polygons, but slow. For convex polygons a fan triangulation is much quicker. Most polygons will be convex. For an example dataset this sped up triangulation on my machine from around 6 seconds to 1 second. --- src/emsarray/operations/triangulate.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/emsarray/operations/triangulate.py b/src/emsarray/operations/triangulate.py index 52ac842..29409b1 100644 --- a/src/emsarray/operations/triangulate.py +++ b/src/emsarray/operations/triangulate.py @@ -3,6 +3,7 @@ """ from typing import cast +import numpy import xarray from shapely.geometry import LineString, MultiPoint, Polygon @@ -149,6 +150,19 @@ def _triangulate_polygon(polygon: Polygon) -> list[tuple[Vertex, Vertex, Vertex] if not polygon.is_simple: raise ValueError("_triangulate_polygon only supports simple polygons") + # The 'ear clipping' method used below is correct for all polygons, but not + # performant. If the polygon is convex we can use a shortcut method. + if polygon.equals(polygon.convex_hull): + # Make a fan triangulation. For a polygon with n vertices the triangles + # will have vertices: + # (1, 2, 3), (1, 3, 4), (1, 4, 5), ... (1, n-1, n) + vertices = numpy.array(polygon.exterior.coords)[:-1] + num_triangles = len(vertices) - 2 + v0 = numpy.broadcast_to(vertices[0], (num_triangles, 2)) + v1 = vertices[1:-1] + v2 = vertices[2:] + return list(zip(map(tuple, v0), map(tuple, v1), map(tuple, v2))) + # This is the 'ear clipping' method of polygon triangulation. # In any simple polygon, there is guaranteed to be at least two 'ears' # - three neighbouring vertices whos diagonal is inside the polygon.