Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion src/earcut.js
Original file line number Diff line number Diff line change
Expand Up @@ -933,7 +933,14 @@ export function refine(triangles, coords, dim = 2) {
if (hStamp[h] !== gen) { hTable[h] = e; hStamp[h] = gen; } // first occurrence: insert
}

while (i > 0) {
// Cap total flips: with non-robust inCircle, roundoff can make a quad and its flip both test
// as illegal, so a cascade can cycle forever (a legalized edge gets re-queued and flipped back).
// A converging cascade needs O(triangles) flips in practice, so a generous multiple of the
// half-edge count bounds legitimate work while breaking float-induced cycles; the worst case is
// then a few not-quite-Delaunay edges, never a hang.
let budget = 25 * n;

while (i > 0 && budget-- > 0) {
const a = edgeStack[--i];
edgeStamp[a] = 0;
const b = he[a];
Expand Down
14 changes: 14 additions & 0 deletions test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,20 @@ test('refine preserves a concave polygon', () => {
assert.equal(deviation(vertices, null, 2, triangles), 0);
});

test('refine terminates on near-cocircular points', {timeout: 5000}, () => {
const vertices = [
127.65906365022843, 9.336137742499535, 124.21725103117963, 30.888097161477972,
91.35514946628345, 89.65621376119454, 40.10446780041529, 121.5550560957686,
-110.83205604043928, 64.03323632184248, -127.20394987965459, -14.253249980770189,
61.074962259031416, -112.48932831632469, 127.37846573978545, -12.598669206638515,
127.77010311801033, -7.668164657400608];
const triangles = earcut(vertices);
const length = triangles.length;
refine(triangles, vertices);
assert.equal(triangles.length, length);
assert.ok(deviation(vertices, null, 2, triangles) < 1e-9);
});

test('refine legalizes all convex interior edges in earcut fixture', () => {
const coords = JSON.parse(fs.readFileSync(new URL('fixtures/earcut.json', import.meta.url)));
const data = flatten(coords);
Expand Down