Skip to content

Commit

Permalink
more collinear tests (#92)
Browse files Browse the repository at this point in the history
Since we have a triangulation, there's no need to compute the whole area.
The first non-degenerate triangle we find tells us that the triangulation is not collinear.
This returns immediately in the general case — and it's more accurate in the degenerate cases; and less code!
  • Loading branch information
Fil committed Oct 5, 2019
1 parent b7df1f2 commit c403f4b
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 15 deletions.
28 changes: 13 additions & 15 deletions src/delaunay.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,18 @@ function pointY(p) {
return p[1];
}

function area(hull, points) {
let n = hull.length, x0, y0,
x1 = points[2 * hull[n - 1]],
y1 = points[2 * hull[n - 1] + 1],
area = 0;

for (let i = 0; i < n; i ++) {
x0 = x1, y0 = y1;
x1 = points[2 * hull[i]];
y1 = points[2 * hull[i] + 1];
area += y0 * x1 - x0 * y1;
}

return area / 2;
// A triangulation is collinear if all its triangles have a non-null area
function collinear(d) {
const {triangles, coords} = d;
for (let i = 0; i < triangles.length; i += 3) {
const a = 2 * triangles[i],
b = 2 * triangles[i + 1],
c = 2 * triangles[i + 2],
cross = (coords[c] - coords[a]) * (coords[b + 1] - coords[a + 1])
- (coords[b] - coords[a]) * (coords[c + 1] - coords[a + 1]);
if (cross > 1e-10) return false;
}
return true;
}

function jitter(x, y, r) {
Expand All @@ -50,7 +48,7 @@ export default class Delaunay {
const d = this._delaunator, points = this.points;

// check for collinear
if (d.hull && d.hull.length > 2 && area(d.hull, points) < 1e-10) {
if (d.hull && d.hull.length > 2 && collinear(d)) {
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],
Expand Down
12 changes: 12 additions & 0 deletions test/delaunay-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,18 @@ tape("delaunay.find(x, y) works with collinear points", test => {
test.equal(points[delaunay.find(10, 10, 0)][1], 4);
});

tape("delaunay.find(x, y) works with collinear points 2", test => {
const points = Array.from({ length: 120 }, (_, i) => [i * 4, i / 3 + 100]);
const delaunay = Delaunay.from(points);
test.deepEqual([...delaunay.neighbors(2)], [ 1, 3 ]);
});

tape("delaunay.find(x, y) works with collinear points 3", test => {
const points = Array.from({ length: 120 }, (_, i) => [i * 4, i / 3 + 100]);
const delaunay = Delaunay.from(points);
test.deepEqual([...delaunay.neighbors(2)], [ 1, 3 ]);
});

tape("delaunay.find(x, y) works with collinear points (large)", test => {
const points = Array.from({length: 2000}, (_,i) => [i**2,i**2]);
const delaunay = Delaunay.from(points);
Expand Down

0 comments on commit c403f4b

Please sign in to comment.