Skip to main content

Delaunay

Delaunay triangulation and earcut polygon triangulation with holes support.

import { Delaunay } from '@shopify/klint/plugins';

Point Cloud Triangulation (Bowyer-Watson)​

Compute a Delaunay triangulation from a set of points.

const draw = (K) => {
const points = Array.from({ length: 50 }, () => ({
x: Math.random() * K.width,
y: Math.random() * K.height,
}));

const triangles = Delaunay.triangulate(points);

Delaunay.drawTriangles(K, triangles, {
fill: true,
stroke: true,
fillStyle: '#ffffff20',
strokeStyle: '#ffffff',
});
};

Every triangle in the result satisfies the Delaunay condition: no point lies inside any triangle's circumcircle.

Polygon Triangulation with Holes (Earcut)​

Triangulate a polygon contour with optional holes punched through it.

High-level API​

const outer = [
{ x: 0, y: 0 },
{ x: 400, y: 0 },
{ x: 400, y: 400 },
{ x: 0, y: 400 },
];

const hole = [
{ x: 100, y: 100 },
{ x: 300, y: 100 },
{ x: 300, y: 300 },
{ x: 100, y: 300 },
];

const triangles = Delaunay.triangulatePolygon(outer, [hole]);
Delaunay.drawTriangles(K, triangles);

One-liner: triangulate + draw​

const triangles = Delaunay.drawPolygon(K, outer, [hole], {
fillStyle: '#ff006640',
strokeStyle: '#ffffff80',
});

Low-level earcut API​

For maximum control, use the flat-array interface directly. The earcut method takes a flat coordinate array and returns vertex indices (every 3 consecutive indices form a triangle).

// Convert {x,y} arrays to flat format
const { vertices, holes } = Delaunay.flatten([outer, hole1, hole2]);

// Returns index array: [i0, i1, i2, i3, i4, i5, ...]
const indices = Delaunay.earcut(vertices, holes);

// Use indices to draw or process triangles
for (let i = 0; i < indices.length; i += 3) {
const ax = vertices[indices[i] * 2];
const ay = vertices[indices[i] * 2 + 1];
const bx = vertices[indices[i + 1] * 2];
const by = vertices[indices[i + 1] * 2 + 1];
const cx = vertices[indices[i + 2] * 2];
const cy = vertices[indices[i + 2] * 2 + 1];
// draw triangle (ax,ay) (bx,by) (cx,cy)
}

Checking triangulation quality​

const { vertices, holes } = Delaunay.flatten([outer, hole]);
const indices = Delaunay.earcut(vertices, holes);
const deviation = Delaunay.deviation(vertices, holes, 2, indices);
// 0 = perfect coverage, > 0 = triangles don't perfectly tile the polygon

Voronoi Diagram​

Generate Voronoi edges from a Delaunay triangulation. Each edge connects circumcenters of adjacent triangles.

const triangles = Delaunay.triangulate(points);
const edges = Delaunay.voronoi(triangles);

K.strokeColor('#4ecdc4');
for (const e of edges) {
K.line(e.x1, e.y1, e.x2, e.y2);
}

Triangle Utilities​

const triangles = Delaunay.triangulate(points);

for (const tri of triangles) {
// Circumcenter — equidistant from all 3 vertices
const center = Delaunay.circumcenter(tri);
K.circle(center.x, center.y, 3);

// Point-in-circumcircle test
if (Delaunay.inCircumcircle({ x: mouse.x, y: mouse.y }, tri)) {
// highlight this triangle
}
}

API Reference​

Earcut (polygon triangulation)​

MethodSignatureDescription
earcut(vertices: number[], holes?: number[], dim?: number) => number[]Low-level earcut. Flat coords in, index array out
flatten(rings: Point[][]) => { vertices, holes, dimensions }Convert {x,y} arrays to flat earcut format
deviation(data, holes, dim, triangles) => numberTriangulation quality (0 = perfect)
triangulatePolygon(outer: Point[], holes?: Point[][]) => Triangle[]High-level polygon triangulation
drawPolygon(ctx, outer, holes?, options?) => Triangle[]Triangulate and draw in one call

Delaunay (point cloud)​

MethodSignatureDescription
triangulate(points: Point[]) => Triangle[]Bowyer-Watson Delaunay triangulation
drawTriangles(ctx, triangles, options?) => voidRender triangle array
circumcenter(triangle: Triangle) => PointCircumcenter of a triangle
inCircumcircle(point, triangle) => booleanPoint-in-circumcircle test
voronoi(triangles: Triangle[]) => Edge[]Voronoi edges from Delaunay triangles

Draw options​

{
fill?: boolean; // default: true
stroke?: boolean; // default: true
fillStyle?: string; // override fill color
strokeStyle?: string; // override stroke color
}

Types​

import type { Triangle } from '@shopify/klint/plugins';

interface Triangle {
p1: { x: number; y: number };
p2: { x: number; y: number };
p3: { x: number; y: number };
}