From b8ba738e22e786c8bfcd849797ad4ece9fa923d5 Mon Sep 17 00:00:00 2001 From: Aria Kassaei Date: Wed, 29 May 2024 19:13:45 +0200 Subject: [PATCH 1/3] test: add one unit test that covers the empty points array case --- test/delaunay-test.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/delaunay-test.js b/test/delaunay-test.js index ece0d66..77271e1 100644 --- a/test/delaunay-test.js +++ b/test/delaunay-test.js @@ -138,6 +138,11 @@ it("delaunay.find(x, y) works with one or two points", () => { assert.strictEqual(delaunay.find(0, 1.2), 0); }); +it("delaunay.find(x, y) returns -1 for empty points array", () => { + const delaunay = Delaunay.from([]); + assert.strictEqual(delaunay.find(0, -1), -1); +}); + it("delaunay.find(x, y) works with collinear points", () => { const points = [[0, 1], [0, 2], [0, 4], [0, 0], [0, 3], [0, 4], [0, 4]]; const delaunay = Delaunay.from(points); From 4da1d65786dc39f264b801f340bb9278ca1564f4 Mon Sep 17 00:00:00 2001 From: Aria Kassaei Date: Wed, 29 May 2024 19:15:45 +0200 Subject: [PATCH 2/3] fix: fix NaN cases for delaunay find --- src/delaunay.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/delaunay.js b/src/delaunay.js index fcb9d24..56b23eb 100644 --- a/src/delaunay.js +++ b/src/delaunay.js @@ -137,7 +137,10 @@ export default class Delaunay { } _step(i, x, y) { const {inedges, hull, _hullIndex, halfedges, triangles, points} = this; - if (inedges[i] === -1 || !points.length) return (i + 1) % (points.length >> 1); + if (inedges[i] === -1 || !points.length) { + if (points.length <= 1) return -1; + return (i + 1) % (points.length >> 1); + } let c = i; let dc = pow(x - points[i * 2], 2) + pow(y - points[i * 2 + 1], 2); const e0 = inedges[i]; From 86345bbc4ea256f2db88727f761691aefd7f3954 Mon Sep 17 00:00:00 2001 From: Mike Bostock Date: Wed, 29 May 2024 12:28:21 -0700 Subject: [PATCH 3/3] fixes for odd-length points --- src/delaunay.js | 10 ++++------ test/delaunay-test.js | 27 +++++++++++++++++++++------ 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/src/delaunay.js b/src/delaunay.js index 56b23eb..adc006d 100644 --- a/src/delaunay.js +++ b/src/delaunay.js @@ -54,7 +54,7 @@ export default class Delaunay { // check for collinear if (d.hull && d.hull.length > 2 && collinear(d)) { - this.collinear = Int32Array.from({length: points.length/2}, (_,i) => i) + this.collinear = Int32Array.from({length: points.length / 2}, (_, i) => i) .sort((i, j) => points[2 * i] - points[2 * j] || points[2 * i + 1] - points[2 * j + 1]); // for exact neighbors const e = this.collinear[0], f = this.collinear[this.collinear.length - 1], bounds = [ points[2 * e], points[2 * e + 1], points[2 * f], points[2 * f + 1] ], @@ -137,10 +137,8 @@ export default class Delaunay { } _step(i, x, y) { const {inedges, hull, _hullIndex, halfedges, triangles, points} = this; - if (inedges[i] === -1 || !points.length) { - if (points.length <= 1) return -1; - return (i + 1) % (points.length >> 1); - } + if (points.length < 2) return -1; + if (inedges[i] === -1) return (i + 1) % (points.length >> 1); let c = i; let dc = pow(x - points[i * 2], 2) + pow(y - points[i * 2 + 1], 2); const e0 = inedges[i]; @@ -181,7 +179,7 @@ export default class Delaunay { r = r == undefined ? 2 : +r; const buffer = context == null ? context = new Path : undefined; const {points} = this; - for (let i = 0, n = points.length; i < n; i += 2) { + for (let i = 0, n = points.length & ~1; i < n; i += 2) { // round down if points has odd length const x = points[i], y = points[i + 1]; context.moveTo(x + r, y); context.arc(x, y, r, 0, tau); diff --git a/test/delaunay-test.js b/test/delaunay-test.js index 77271e1..f0804ff 100644 --- a/test/delaunay-test.js +++ b/test/delaunay-test.js @@ -127,11 +127,20 @@ it("delaunay.find(x, y) returns the index of the cell that contains the specifie assert.strictEqual(delaunay.find(51, 51), 4); }); -it("delaunay.find(x, y) works with one or two points", () => { - const points = [[0, 1], [0, 2]]; - const delaunay = Delaunay.from(points); - assert.strictEqual(points[delaunay.find(0, -1)][1], 1); - assert.strictEqual(points[delaunay.find(0, 2.2)][1], 2); +it("delaunay.find(x, y) works with one point", () => { + const delaunay = new Delaunay([0, 1]); + assert.strictEqual(delaunay.find(0, -1), 0); + assert.strictEqual(delaunay.find(0, 2.2), 0); + delaunay.points.fill(0); + delaunay.update(); + assert.strictEqual(delaunay.find(0, -1), 0); + assert.strictEqual(delaunay.find(0, 1.2), 0); +}); + +it("delaunay.find(x, y) works with two points", () => { + const delaunay = new Delaunay([0, 1, 0, 2]); + assert.strictEqual(delaunay.find(0, -1), 0); + assert.strictEqual(delaunay.find(0, 2.2), 1); delaunay.points.fill(0); delaunay.update(); assert.strictEqual(delaunay.find(0, -1), 0); @@ -139,8 +148,14 @@ it("delaunay.find(x, y) works with one or two points", () => { }); it("delaunay.find(x, y) returns -1 for empty points array", () => { - const delaunay = Delaunay.from([]); + const delaunay = new Delaunay([]); + assert.strictEqual(delaunay.find(0, -1), -1); +}); + +it("delaunay.find(x, y) returns -1 for half a point", () => { + const delaunay = new Delaunay([0]); // invalid; considered empty assert.strictEqual(delaunay.find(0, -1), -1); + assert.strictEqual(delaunay.find(0, 2.2), -1); }); it("delaunay.find(x, y) works with collinear points", () => {