Skip to content

Commit

Permalink
Robust circumcenters when the hull is collinear (#142)
Browse files Browse the repository at this point in the history
* fix #141

* bx, by

---------

Co-authored-by: Mike Bostock <mbostock@gmail.com>
  • Loading branch information
Fil and mbostock authored Apr 1, 2023
1 parent 48d091f commit 1f99535
Show file tree
Hide file tree
Showing 2 changed files with 16 additions and 11 deletions.
21 changes: 10 additions & 11 deletions src/voronoi.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export default class Voronoi {
}
_init() {
const {delaunay: {points, hull, triangles}, vectors} = this;
let bx, by; // lazily computed barycenter of the hull

// Compute circumcenters.
const circumcenters = this.circumcenters = this._circumcenters.subarray(0, triangles.length / 3 * 2);
Expand All @@ -39,17 +40,15 @@ export default class Voronoi {
const ab = (dx * ey - dy * ex) * 2;

if (Math.abs(ab) < 1e-9) {
// degenerate case (collinear diagram)
// almost equal points (degenerate triangle)
// the circumcenter is at the infinity, in a
// direction that is:
// 1. orthogonal to the halfedge.
let a = 1e9;
// 2. points away from the center; since the list of triangles starts
// in the center, the first point of the first triangle
// will be our reference
const r = triangles[0] * 2;
a *= Math.sign((points[r] - x1) * ey - (points[r + 1] - y1) * ex);
// For a degenerate triangle, the circumcenter is at the infinity, in a
// direction orthogonal to the halfedge and away from the “center” of
// the diagram <bx, by>, defined as the hull’s barycenter.
if (bx === undefined) {
bx = by = 0;
for (const i of hull) bx += points[i * 2], by += points[i * 2 + 1];
bx /= hull.length, by /= hull.length;
}
const a = 1e9 * Math.sign((bx - x1) * ey - (by - y1) * ex);
x = (x1 + x3) / 2 - a * ey;
y = (y1 + y3) / 2 + a * ex;
} else {
Expand Down
6 changes: 6 additions & 0 deletions test/voronoi-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -122,3 +122,9 @@ it("voronoi returns the expected result (#136)", () => {
const voronoi = Delaunay.from(points).voronoi([0, 0, 1000, 1000]);
assert.strictEqual(voronoi.cellPolygon(3).length, 6);
});

it("voronoi returns the expected result (#141)", () => {
const points = [[10, 190]].concat(Array.from({ length: 7 }, (d, i) => [i * 80, (i * 50) / 7]));
const voronoi = Delaunay.from(points).voronoi([1, 1, 499, 199]);
assert.deepEqual(Array.from(voronoi.cellPolygons(), (d) => d.length), [7, 5, 5, 5, 6, 5, 5, 5]);
});

0 comments on commit 1f99535

Please sign in to comment.