i’m the author of Delaunay32, a constrained delaunay triangulator with polygon and hole support. it uses divide-and-conquer rather than incremental insertion, so im curious how it would compare with the delaunay baseline here.
https://github.com/morishuz/delaunay32
i havent benchmarked on your corpus yet, and our current polygon api requires simple rings with non-touching holes. thanks for publishing the datasets, they look useful for testing and comparison!
== world.bin
56472 polygons
whole file, best of 7: earstrip 453.4 ms, delaunay32 1696.9 ms
up to 4 14455 polygons: earstrip 0.3 ms, delaunay32 14.4 ms
5-8 8328 polygons: earstrip 0.6 ms, delaunay32 14.5 ms
9-32 18019 polygons: earstrip 6.8 ms, delaunay32 83.7 ms
33-256 13511 polygons: earstrip 66.6 ms, delaunay32 366.9 ms
257 and more 2159 polygons: earstrip 376.8 ms, delaunay32 1209.4 ms
delaunay32: rejected 3039 (by class 0/28/365/1671/975), empty outer ring 0, area off on 0 covered, 1930016 triangles
earstrip: exact 56338, constrained 134One thing to note is that I deliberately had to reject some of the potential optimizations to keep the library small, so that bundle size doesn't blow up — for most practical applications (e.g. Mapbox GL JS), it's already fast enough (and 4.1k min/gz). Curious how big the WASM build of Earstrip is.
On the C++ side, Mapbox now uses a hybrid approach where small polygons are processed with earcut.hpp, while big and complex polygon switch to a different algorithm based on monotone decomposition, because while it has higher constants in algorithmic complexity, it scales much better with input size.
Having more balanced triangles in this case would only increase the number of vertices. Which means you need more memory on the GPU and the vertex pipeline has more work to do.
Because the polygons are quite small, there's also no culling advantage by having smaller triangles, being able to discard them early in the rendering process.
either way, neat stuff, and the write up itself is excellent.
My experience is that Claude Opus 5 and 5.5 are very good at implementing optimizations, reasonably good at suggesting approaches to try, and not very inclined to identify slow runtime as a problem. It tends to go for simple implementations until I ask about speed, which is certainly conventional wisdom for development.
If you just want areas, or to know if a point is inside or outside the shape there is a better way.
Given a simple closed curve, points (ax, ay) (bx, by) (cx, cy) (dx, dy) as a trivial example.
Line them up a,b,c,d,a vertically and take the "determinant" as we were taught.
Axby - aybx + bxcy - bycx etc etc.
Divide the result by -2 and you have the are, positive is clockwise, negative is anticlockwise.
Put an anticlockwise shape inside a clockwise shape and you have a donut.
There is more, have to go to dinner.
As a consequence of that, the GPU vendors designed then GPUs supporting only triangles in hardware, abandoning earlier attempts to also support other figures.
That has been inherited until today, so any program that wants to use not only the general-purpose computing features of a GPU, but also the dedicated graphics hardware from it, must convert any other kinds of graphics primitives into triangles, before rendering on the GPU.