Skip to content

Commit 3d1607f

Browse files
committed
more collinear tests (#92)
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!
1 parent b7df1f2 commit 3d1607f

File tree

2 files changed

+25
-15
lines changed

2 files changed

+25
-15
lines changed

src/delaunay.js

+13-15
Original file line numberDiff line numberDiff line change
@@ -13,20 +13,18 @@ function pointY(p) {
1313
return p[1];
1414
}
1515

16-
function area(hull, points) {
17-
let n = hull.length, x0, y0,
18-
x1 = points[2 * hull[n - 1]],
19-
y1 = points[2 * hull[n - 1] + 1],
20-
area = 0;
21-
22-
for (let i = 0; i < n; i ++) {
23-
x0 = x1, y0 = y1;
24-
x1 = points[2 * hull[i]];
25-
y1 = points[2 * hull[i] + 1];
26-
area += y0 * x1 - x0 * y1;
27-
}
28-
29-
return area / 2;
16+
// A triangulation is collinear if all its triangles have a non-null area
17+
function collinear(d) {
18+
const {triangles, coords} = d;
19+
for (let i = 0; i < triangles.length; i += 3) {
20+
const a = 2 * triangles[i],
21+
b = 2 * triangles[i + 1],
22+
c = 2 * triangles[i + 2],
23+
cross = (coords[c] - coords[a]) * (coords[b + 1] - coords[a + 1])
24+
- (coords[b] - coords[a]) * (coords[c + 1] - coords[a + 1]);
25+
if (cross > 1e-10) return false;
26+
}
27+
return true;
3028
}
3129

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

5250
// check for collinear
53-
if (d.hull && d.hull.length > 2 && area(d.hull, points) < 1e-10) {
51+
if (d.hull && d.hull.length > 2 && collinear(d)) {
5452
this.collinear = Int32Array.from({length: points.length/2}, (_,i) => i)
5553
.sort((i, j) => points[2 * i] - points[2 * j] || points[2 * i + 1] - points[2 * j + 1]); // for exact neighbors
5654
const e = this.collinear[0], f = this.collinear[this.collinear.length - 1],

test/delaunay-test.js

+12
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,18 @@ tape("delaunay.find(x, y) works with collinear points", test => {
135135
test.equal(points[delaunay.find(10, 10, 0)][1], 4);
136136
});
137137

138+
tape("delaunay.find(x, y) works with collinear points 2", test => {
139+
const points = Array.from({ length: 120 }, (_, i) => [i * 4, i / 3 + 100]);
140+
const delaunay = Delaunay.from(points);
141+
test.deepEqual([...delaunay.neighbors(2)], [ 1, 3 ]);
142+
});
143+
144+
tape("delaunay.find(x, y) works with collinear points 3", test => {
145+
const points = Array.from({ length: 120 }, (_, i) => [i * 4, i / 3 + 100]);
146+
const delaunay = Delaunay.from(points);
147+
test.deepEqual([...delaunay.neighbors(2)], [ 1, 3 ]);
148+
});
149+
138150
tape("delaunay.find(x, y) works with collinear points (large)", test => {
139151
const points = Array.from({length: 2000}, (_,i) => [i**2,i**2]);
140152
const delaunay = Delaunay.from(points);

0 commit comments

Comments
 (0)