Skip to content

Speed up triangulation, especially hole bridging (~52% faster)#195

Open
mourner wants to merge 18 commits into
mainfrom
faster-holes
Open

Speed up triangulation, especially hole bridging (~52% faster)#195
mourner wants to merge 18 commits into
mainfrom
faster-holes

Conversation

@mourner

@mourner mourner commented Jun 26, 2026

Copy link
Copy Markdown
Member

Closes #183. Makes earcut substantially faster on its primary workload — integer-coordinate polygons from Mapbox Vector Tiles — without any API or output-contract change. On a representative 132-tile fixture (119,680 polygons, 1.9M verts, 6.8% with holes), total triangulation time drops from ~1000 ms to ~480 ms (~52% faster).

Total-time win per zoom bracket

Bracket Polys Verts main PR Win
z5–z8 60.2k 940k ~774 ms ~331 ms ~443 ms (−57%)
z9–z11 27.4k 595k ~200 ms ~126 ms ~73 ms (−37%)
z12+ 27.3k 325k ~30 ms ~27 ms ~3 ms (−11%)

Want the z12+ number broken down further (e.g. per individual zoom), or is the three-bracket picture enough?

What changed

Hole bridging block index. findHoleBridge previously ran two unindexed O(n) scans of the merged ring per hole — 41.7% of total time. It now skip-walks an append-only block index (flat per-block bounding boxes, sized once and reused across calls, no per-call allocation):

  • Leftward-ray scan skips any block whose bbox can't cross the ray (~97.5% of edge tests eliminated).
  • Refinement scan skips any block that can't overlap the candidate triangle.

Combined, this took findHoleBridge from 41.7% → 11.8% of self-time and the holey-polygon bucket from ~948 ms → ~590 ms. Block size K=16 confirmed optimal by sweep.

intersectsPolygon diagonal prune. The split fallback's diagonal validity check now skips edges whose bbox can't overlap the (short) diagonal — bit-identical output, ~3% speedup.

z-order sort: linked-list merge sort → array quicksort. The cache-hostile pointer-chasing sortLinked is replaced with a cache-friendly array quicksort over node refs. Byte-identical output, removes code, ~2.5% speedup.

microoptimized earcutLinked: hoisted cheap reflex vertex check out of isEar / isEarHashed so that a common path doesn't call non-inlined functions. ~6% speedup.

microoptimized isEarHashed: inlined point in triangle checks in isEarHashed — the calls weren't inline due to being over inlining budget. ~2% speedup.

Faster hole merging & point filtering. filterPoints now heals only the dirty window around each bridge/diagonal cut (O(window)) instead of re-walking the whole ring per removal (was quadratic on holey polygons), with one upfront full-ring collapse after hole elimination to preserve global cleanup. ~4%

Dropped the "skip next vertex" sliver heuristic. It cost ~10% (+55% inner-loop iterations to relocate ears) for no quality benefit on real data — triangle shape is irrelevant to GPU fill rendering. ~5%. Adjusts a few canonical fixture outputs and loosens some tolerances on invalid/degenerate-prone polygons.

Minor cleanup. cureLocalIntersections skips its trailing full-ring filterPoints when it cured nothing (a guaranteed no-op on already-filtered rings). Removed steiner field from the Node shape since this is a rare path that shouldn't bring the cost to the common one.

@mourner mourner requested a review from a team as a code owner June 26, 2026 21:12
@mourner mourner requested review from stepankuzmin and removed request for a team June 26, 2026 21:12
@mourner mourner changed the title Speed up triangulation, especially hole bridging (~33% faster total) Speed up triangulation, especially hole bridging (~37% faster) Jun 27, 2026
@mourner mourner changed the title Speed up triangulation, especially hole bridging (~37% faster) Speed up triangulation, especially hole bridging (~41% faster) Jun 27, 2026
@mourner mourner changed the title Speed up triangulation, especially hole bridging (~41% faster) Speed up triangulation, especially hole bridging (~43% faster) Jun 27, 2026
@mourner mourner changed the title Speed up triangulation, especially hole bridging (~43% faster) Speed up triangulation, especially hole bridging (~52% faster) Jun 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Hole cutting performance

1 participant