Skip to content

Commit

Permalink
Make Delaunay.find return -1 instead of NaN for edge cases (#145)
Browse files Browse the repository at this point in the history
* test: add one unit test that covers the empty points array case

* fix: fix NaN cases for delaunay find

* fixes for odd-length points

---------

Co-authored-by: Mike Bostock <[email protected]>
  • Loading branch information
akassaei and mbostock authored May 29, 2024
1 parent 7bf3fd0 commit dc894a1
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 8 deletions.
7 changes: 4 additions & 3 deletions src/delaunay.js
Original file line number Diff line number Diff line change
Expand Up @@ -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] ],
Expand Down Expand Up @@ -137,7 +137,8 @@ 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 (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];
Expand Down Expand Up @@ -178,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);
Expand Down
30 changes: 25 additions & 5 deletions test/delaunay-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -127,17 +127,37 @@ 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);
assert.strictEqual(delaunay.find(0, 1.2), 0);
});

it("delaunay.find(x, y) returns -1 for empty points array", () => {
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", () => {
const points = [[0, 1], [0, 2], [0, 4], [0, 0], [0, 3], [0, 4], [0, 4]];
const delaunay = Delaunay.from(points);
Expand Down

0 comments on commit dc894a1

Please sign in to comment.