source: node_modules/d3-delaunay/dist/d3-delaunay.js

Last change on this file was e4c61dd, checked in by istevanoska <ilinastevanoska@…>, 6 months ago

Prototype 1.1

  • Property mode set to 100644
File size: 44.1 KB
Line 
1// https://github.com/d3/d3-delaunay v6.0.4 Copyright 2018-2021 Observable, Inc., 2021 Mapbox
2(function (global, factory) {
3typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
4typeof define === 'function' && define.amd ? define(['exports'], factory) :
5(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.d3 = global.d3 || {}));
6}(this, (function (exports) { 'use strict';
7
8const epsilon$1 = 1.1102230246251565e-16;
9const splitter = 134217729;
10const resulterrbound = (3 + 8 * epsilon$1) * epsilon$1;
11
12// fast_expansion_sum_zeroelim routine from oritinal code
13function sum(elen, e, flen, f, h) {
14 let Q, Qnew, hh, bvirt;
15 let enow = e[0];
16 let fnow = f[0];
17 let eindex = 0;
18 let findex = 0;
19 if ((fnow > enow) === (fnow > -enow)) {
20 Q = enow;
21 enow = e[++eindex];
22 } else {
23 Q = fnow;
24 fnow = f[++findex];
25 }
26 let hindex = 0;
27 if (eindex < elen && findex < flen) {
28 if ((fnow > enow) === (fnow > -enow)) {
29 Qnew = enow + Q;
30 hh = Q - (Qnew - enow);
31 enow = e[++eindex];
32 } else {
33 Qnew = fnow + Q;
34 hh = Q - (Qnew - fnow);
35 fnow = f[++findex];
36 }
37 Q = Qnew;
38 if (hh !== 0) {
39 h[hindex++] = hh;
40 }
41 while (eindex < elen && findex < flen) {
42 if ((fnow > enow) === (fnow > -enow)) {
43 Qnew = Q + enow;
44 bvirt = Qnew - Q;
45 hh = Q - (Qnew - bvirt) + (enow - bvirt);
46 enow = e[++eindex];
47 } else {
48 Qnew = Q + fnow;
49 bvirt = Qnew - Q;
50 hh = Q - (Qnew - bvirt) + (fnow - bvirt);
51 fnow = f[++findex];
52 }
53 Q = Qnew;
54 if (hh !== 0) {
55 h[hindex++] = hh;
56 }
57 }
58 }
59 while (eindex < elen) {
60 Qnew = Q + enow;
61 bvirt = Qnew - Q;
62 hh = Q - (Qnew - bvirt) + (enow - bvirt);
63 enow = e[++eindex];
64 Q = Qnew;
65 if (hh !== 0) {
66 h[hindex++] = hh;
67 }
68 }
69 while (findex < flen) {
70 Qnew = Q + fnow;
71 bvirt = Qnew - Q;
72 hh = Q - (Qnew - bvirt) + (fnow - bvirt);
73 fnow = f[++findex];
74 Q = Qnew;
75 if (hh !== 0) {
76 h[hindex++] = hh;
77 }
78 }
79 if (Q !== 0 || hindex === 0) {
80 h[hindex++] = Q;
81 }
82 return hindex;
83}
84
85function estimate(elen, e) {
86 let Q = e[0];
87 for (let i = 1; i < elen; i++) Q += e[i];
88 return Q;
89}
90
91function vec(n) {
92 return new Float64Array(n);
93}
94
95const ccwerrboundA = (3 + 16 * epsilon$1) * epsilon$1;
96const ccwerrboundB = (2 + 12 * epsilon$1) * epsilon$1;
97const ccwerrboundC = (9 + 64 * epsilon$1) * epsilon$1 * epsilon$1;
98
99const B = vec(4);
100const C1 = vec(8);
101const C2 = vec(12);
102const D = vec(16);
103const u = vec(4);
104
105function orient2dadapt(ax, ay, bx, by, cx, cy, detsum) {
106 let acxtail, acytail, bcxtail, bcytail;
107 let bvirt, c, ahi, alo, bhi, blo, _i, _j, _0, s1, s0, t1, t0, u3;
108
109 const acx = ax - cx;
110 const bcx = bx - cx;
111 const acy = ay - cy;
112 const bcy = by - cy;
113
114 s1 = acx * bcy;
115 c = splitter * acx;
116 ahi = c - (c - acx);
117 alo = acx - ahi;
118 c = splitter * bcy;
119 bhi = c - (c - bcy);
120 blo = bcy - bhi;
121 s0 = alo * blo - (s1 - ahi * bhi - alo * bhi - ahi * blo);
122 t1 = acy * bcx;
123 c = splitter * acy;
124 ahi = c - (c - acy);
125 alo = acy - ahi;
126 c = splitter * bcx;
127 bhi = c - (c - bcx);
128 blo = bcx - bhi;
129 t0 = alo * blo - (t1 - ahi * bhi - alo * bhi - ahi * blo);
130 _i = s0 - t0;
131 bvirt = s0 - _i;
132 B[0] = s0 - (_i + bvirt) + (bvirt - t0);
133 _j = s1 + _i;
134 bvirt = _j - s1;
135 _0 = s1 - (_j - bvirt) + (_i - bvirt);
136 _i = _0 - t1;
137 bvirt = _0 - _i;
138 B[1] = _0 - (_i + bvirt) + (bvirt - t1);
139 u3 = _j + _i;
140 bvirt = u3 - _j;
141 B[2] = _j - (u3 - bvirt) + (_i - bvirt);
142 B[3] = u3;
143
144 let det = estimate(4, B);
145 let errbound = ccwerrboundB * detsum;
146 if (det >= errbound || -det >= errbound) {
147 return det;
148 }
149
150 bvirt = ax - acx;
151 acxtail = ax - (acx + bvirt) + (bvirt - cx);
152 bvirt = bx - bcx;
153 bcxtail = bx - (bcx + bvirt) + (bvirt - cx);
154 bvirt = ay - acy;
155 acytail = ay - (acy + bvirt) + (bvirt - cy);
156 bvirt = by - bcy;
157 bcytail = by - (bcy + bvirt) + (bvirt - cy);
158
159 if (acxtail === 0 && acytail === 0 && bcxtail === 0 && bcytail === 0) {
160 return det;
161 }
162
163 errbound = ccwerrboundC * detsum + resulterrbound * Math.abs(det);
164 det += (acx * bcytail + bcy * acxtail) - (acy * bcxtail + bcx * acytail);
165 if (det >= errbound || -det >= errbound) return det;
166
167 s1 = acxtail * bcy;
168 c = splitter * acxtail;
169 ahi = c - (c - acxtail);
170 alo = acxtail - ahi;
171 c = splitter * bcy;
172 bhi = c - (c - bcy);
173 blo = bcy - bhi;
174 s0 = alo * blo - (s1 - ahi * bhi - alo * bhi - ahi * blo);
175 t1 = acytail * bcx;
176 c = splitter * acytail;
177 ahi = c - (c - acytail);
178 alo = acytail - ahi;
179 c = splitter * bcx;
180 bhi = c - (c - bcx);
181 blo = bcx - bhi;
182 t0 = alo * blo - (t1 - ahi * bhi - alo * bhi - ahi * blo);
183 _i = s0 - t0;
184 bvirt = s0 - _i;
185 u[0] = s0 - (_i + bvirt) + (bvirt - t0);
186 _j = s1 + _i;
187 bvirt = _j - s1;
188 _0 = s1 - (_j - bvirt) + (_i - bvirt);
189 _i = _0 - t1;
190 bvirt = _0 - _i;
191 u[1] = _0 - (_i + bvirt) + (bvirt - t1);
192 u3 = _j + _i;
193 bvirt = u3 - _j;
194 u[2] = _j - (u3 - bvirt) + (_i - bvirt);
195 u[3] = u3;
196 const C1len = sum(4, B, 4, u, C1);
197
198 s1 = acx * bcytail;
199 c = splitter * acx;
200 ahi = c - (c - acx);
201 alo = acx - ahi;
202 c = splitter * bcytail;
203 bhi = c - (c - bcytail);
204 blo = bcytail - bhi;
205 s0 = alo * blo - (s1 - ahi * bhi - alo * bhi - ahi * blo);
206 t1 = acy * bcxtail;
207 c = splitter * acy;
208 ahi = c - (c - acy);
209 alo = acy - ahi;
210 c = splitter * bcxtail;
211 bhi = c - (c - bcxtail);
212 blo = bcxtail - bhi;
213 t0 = alo * blo - (t1 - ahi * bhi - alo * bhi - ahi * blo);
214 _i = s0 - t0;
215 bvirt = s0 - _i;
216 u[0] = s0 - (_i + bvirt) + (bvirt - t0);
217 _j = s1 + _i;
218 bvirt = _j - s1;
219 _0 = s1 - (_j - bvirt) + (_i - bvirt);
220 _i = _0 - t1;
221 bvirt = _0 - _i;
222 u[1] = _0 - (_i + bvirt) + (bvirt - t1);
223 u3 = _j + _i;
224 bvirt = u3 - _j;
225 u[2] = _j - (u3 - bvirt) + (_i - bvirt);
226 u[3] = u3;
227 const C2len = sum(C1len, C1, 4, u, C2);
228
229 s1 = acxtail * bcytail;
230 c = splitter * acxtail;
231 ahi = c - (c - acxtail);
232 alo = acxtail - ahi;
233 c = splitter * bcytail;
234 bhi = c - (c - bcytail);
235 blo = bcytail - bhi;
236 s0 = alo * blo - (s1 - ahi * bhi - alo * bhi - ahi * blo);
237 t1 = acytail * bcxtail;
238 c = splitter * acytail;
239 ahi = c - (c - acytail);
240 alo = acytail - ahi;
241 c = splitter * bcxtail;
242 bhi = c - (c - bcxtail);
243 blo = bcxtail - bhi;
244 t0 = alo * blo - (t1 - ahi * bhi - alo * bhi - ahi * blo);
245 _i = s0 - t0;
246 bvirt = s0 - _i;
247 u[0] = s0 - (_i + bvirt) + (bvirt - t0);
248 _j = s1 + _i;
249 bvirt = _j - s1;
250 _0 = s1 - (_j - bvirt) + (_i - bvirt);
251 _i = _0 - t1;
252 bvirt = _0 - _i;
253 u[1] = _0 - (_i + bvirt) + (bvirt - t1);
254 u3 = _j + _i;
255 bvirt = u3 - _j;
256 u[2] = _j - (u3 - bvirt) + (_i - bvirt);
257 u[3] = u3;
258 const Dlen = sum(C2len, C2, 4, u, D);
259
260 return D[Dlen - 1];
261}
262
263function orient2d(ax, ay, bx, by, cx, cy) {
264 const detleft = (ay - cy) * (bx - cx);
265 const detright = (ax - cx) * (by - cy);
266 const det = detleft - detright;
267
268 if (detleft === 0 || detright === 0 || (detleft > 0) !== (detright > 0)) return det;
269
270 const detsum = Math.abs(detleft + detright);
271 if (Math.abs(det) >= ccwerrboundA * detsum) return det;
272
273 return -orient2dadapt(ax, ay, bx, by, cx, cy, detsum);
274}
275
276const EPSILON = Math.pow(2, -52);
277const EDGE_STACK = new Uint32Array(512);
278
279class Delaunator {
280
281 static from(points, getX = defaultGetX, getY = defaultGetY) {
282 const n = points.length;
283 const coords = new Float64Array(n * 2);
284
285 for (let i = 0; i < n; i++) {
286 const p = points[i];
287 coords[2 * i] = getX(p);
288 coords[2 * i + 1] = getY(p);
289 }
290
291 return new Delaunator(coords);
292 }
293
294 constructor(coords) {
295 const n = coords.length >> 1;
296 if (n > 0 && typeof coords[0] !== 'number') throw new Error('Expected coords to contain numbers.');
297
298 this.coords = coords;
299
300 // arrays that will store the triangulation graph
301 const maxTriangles = Math.max(2 * n - 5, 0);
302 this._triangles = new Uint32Array(maxTriangles * 3);
303 this._halfedges = new Int32Array(maxTriangles * 3);
304
305 // temporary arrays for tracking the edges of the advancing convex hull
306 this._hashSize = Math.ceil(Math.sqrt(n));
307 this._hullPrev = new Uint32Array(n); // edge to prev edge
308 this._hullNext = new Uint32Array(n); // edge to next edge
309 this._hullTri = new Uint32Array(n); // edge to adjacent triangle
310 this._hullHash = new Int32Array(this._hashSize).fill(-1); // angular edge hash
311
312 // temporary arrays for sorting points
313 this._ids = new Uint32Array(n);
314 this._dists = new Float64Array(n);
315
316 this.update();
317 }
318
319 update() {
320 const {coords, _hullPrev: hullPrev, _hullNext: hullNext, _hullTri: hullTri, _hullHash: hullHash} = this;
321 const n = coords.length >> 1;
322
323 // populate an array of point indices; calculate input data bbox
324 let minX = Infinity;
325 let minY = Infinity;
326 let maxX = -Infinity;
327 let maxY = -Infinity;
328
329 for (let i = 0; i < n; i++) {
330 const x = coords[2 * i];
331 const y = coords[2 * i + 1];
332 if (x < minX) minX = x;
333 if (y < minY) minY = y;
334 if (x > maxX) maxX = x;
335 if (y > maxY) maxY = y;
336 this._ids[i] = i;
337 }
338 const cx = (minX + maxX) / 2;
339 const cy = (minY + maxY) / 2;
340
341 let minDist = Infinity;
342 let i0, i1, i2;
343
344 // pick a seed point close to the center
345 for (let i = 0; i < n; i++) {
346 const d = dist(cx, cy, coords[2 * i], coords[2 * i + 1]);
347 if (d < minDist) {
348 i0 = i;
349 minDist = d;
350 }
351 }
352 const i0x = coords[2 * i0];
353 const i0y = coords[2 * i0 + 1];
354
355 minDist = Infinity;
356
357 // find the point closest to the seed
358 for (let i = 0; i < n; i++) {
359 if (i === i0) continue;
360 const d = dist(i0x, i0y, coords[2 * i], coords[2 * i + 1]);
361 if (d < minDist && d > 0) {
362 i1 = i;
363 minDist = d;
364 }
365 }
366 let i1x = coords[2 * i1];
367 let i1y = coords[2 * i1 + 1];
368
369 let minRadius = Infinity;
370
371 // find the third point which forms the smallest circumcircle with the first two
372 for (let i = 0; i < n; i++) {
373 if (i === i0 || i === i1) continue;
374 const r = circumradius(i0x, i0y, i1x, i1y, coords[2 * i], coords[2 * i + 1]);
375 if (r < minRadius) {
376 i2 = i;
377 minRadius = r;
378 }
379 }
380 let i2x = coords[2 * i2];
381 let i2y = coords[2 * i2 + 1];
382
383 if (minRadius === Infinity) {
384 // order collinear points by dx (or dy if all x are identical)
385 // and return the list as a hull
386 for (let i = 0; i < n; i++) {
387 this._dists[i] = (coords[2 * i] - coords[0]) || (coords[2 * i + 1] - coords[1]);
388 }
389 quicksort(this._ids, this._dists, 0, n - 1);
390 const hull = new Uint32Array(n);
391 let j = 0;
392 for (let i = 0, d0 = -Infinity; i < n; i++) {
393 const id = this._ids[i];
394 if (this._dists[id] > d0) {
395 hull[j++] = id;
396 d0 = this._dists[id];
397 }
398 }
399 this.hull = hull.subarray(0, j);
400 this.triangles = new Uint32Array(0);
401 this.halfedges = new Uint32Array(0);
402 return;
403 }
404
405 // swap the order of the seed points for counter-clockwise orientation
406 if (orient2d(i0x, i0y, i1x, i1y, i2x, i2y) < 0) {
407 const i = i1;
408 const x = i1x;
409 const y = i1y;
410 i1 = i2;
411 i1x = i2x;
412 i1y = i2y;
413 i2 = i;
414 i2x = x;
415 i2y = y;
416 }
417
418 const center = circumcenter(i0x, i0y, i1x, i1y, i2x, i2y);
419 this._cx = center.x;
420 this._cy = center.y;
421
422 for (let i = 0; i < n; i++) {
423 this._dists[i] = dist(coords[2 * i], coords[2 * i + 1], center.x, center.y);
424 }
425
426 // sort the points by distance from the seed triangle circumcenter
427 quicksort(this._ids, this._dists, 0, n - 1);
428
429 // set up the seed triangle as the starting hull
430 this._hullStart = i0;
431 let hullSize = 3;
432
433 hullNext[i0] = hullPrev[i2] = i1;
434 hullNext[i1] = hullPrev[i0] = i2;
435 hullNext[i2] = hullPrev[i1] = i0;
436
437 hullTri[i0] = 0;
438 hullTri[i1] = 1;
439 hullTri[i2] = 2;
440
441 hullHash.fill(-1);
442 hullHash[this._hashKey(i0x, i0y)] = i0;
443 hullHash[this._hashKey(i1x, i1y)] = i1;
444 hullHash[this._hashKey(i2x, i2y)] = i2;
445
446 this.trianglesLen = 0;
447 this._addTriangle(i0, i1, i2, -1, -1, -1);
448
449 for (let k = 0, xp, yp; k < this._ids.length; k++) {
450 const i = this._ids[k];
451 const x = coords[2 * i];
452 const y = coords[2 * i + 1];
453
454 // skip near-duplicate points
455 if (k > 0 && Math.abs(x - xp) <= EPSILON && Math.abs(y - yp) <= EPSILON) continue;
456 xp = x;
457 yp = y;
458
459 // skip seed triangle points
460 if (i === i0 || i === i1 || i === i2) continue;
461
462 // find a visible edge on the convex hull using edge hash
463 let start = 0;
464 for (let j = 0, key = this._hashKey(x, y); j < this._hashSize; j++) {
465 start = hullHash[(key + j) % this._hashSize];
466 if (start !== -1 && start !== hullNext[start]) break;
467 }
468
469 start = hullPrev[start];
470 let e = start, q;
471 while (q = hullNext[e], orient2d(x, y, coords[2 * e], coords[2 * e + 1], coords[2 * q], coords[2 * q + 1]) >= 0) {
472 e = q;
473 if (e === start) {
474 e = -1;
475 break;
476 }
477 }
478 if (e === -1) continue; // likely a near-duplicate point; skip it
479
480 // add the first triangle from the point
481 let t = this._addTriangle(e, i, hullNext[e], -1, -1, hullTri[e]);
482
483 // recursively flip triangles from the point until they satisfy the Delaunay condition
484 hullTri[i] = this._legalize(t + 2);
485 hullTri[e] = t; // keep track of boundary triangles on the hull
486 hullSize++;
487
488 // walk forward through the hull, adding more triangles and flipping recursively
489 let n = hullNext[e];
490 while (q = hullNext[n], orient2d(x, y, coords[2 * n], coords[2 * n + 1], coords[2 * q], coords[2 * q + 1]) < 0) {
491 t = this._addTriangle(n, i, q, hullTri[i], -1, hullTri[n]);
492 hullTri[i] = this._legalize(t + 2);
493 hullNext[n] = n; // mark as removed
494 hullSize--;
495 n = q;
496 }
497
498 // walk backward from the other side, adding more triangles and flipping
499 if (e === start) {
500 while (q = hullPrev[e], orient2d(x, y, coords[2 * q], coords[2 * q + 1], coords[2 * e], coords[2 * e + 1]) < 0) {
501 t = this._addTriangle(q, i, e, -1, hullTri[e], hullTri[q]);
502 this._legalize(t + 2);
503 hullTri[q] = t;
504 hullNext[e] = e; // mark as removed
505 hullSize--;
506 e = q;
507 }
508 }
509
510 // update the hull indices
511 this._hullStart = hullPrev[i] = e;
512 hullNext[e] = hullPrev[n] = i;
513 hullNext[i] = n;
514
515 // save the two new edges in the hash table
516 hullHash[this._hashKey(x, y)] = i;
517 hullHash[this._hashKey(coords[2 * e], coords[2 * e + 1])] = e;
518 }
519
520 this.hull = new Uint32Array(hullSize);
521 for (let i = 0, e = this._hullStart; i < hullSize; i++) {
522 this.hull[i] = e;
523 e = hullNext[e];
524 }
525
526 // trim typed triangle mesh arrays
527 this.triangles = this._triangles.subarray(0, this.trianglesLen);
528 this.halfedges = this._halfedges.subarray(0, this.trianglesLen);
529 }
530
531 _hashKey(x, y) {
532 return Math.floor(pseudoAngle(x - this._cx, y - this._cy) * this._hashSize) % this._hashSize;
533 }
534
535 _legalize(a) {
536 const {_triangles: triangles, _halfedges: halfedges, coords} = this;
537
538 let i = 0;
539 let ar = 0;
540
541 // recursion eliminated with a fixed-size stack
542 while (true) {
543 const b = halfedges[a];
544
545 /* if the pair of triangles doesn't satisfy the Delaunay condition
546 * (p1 is inside the circumcircle of [p0, pl, pr]), flip them,
547 * then do the same check/flip recursively for the new pair of triangles
548 *
549 * pl pl
550 * /||\ / \
551 * al/ || \bl al/ \a
552 * / || \ / \
553 * / a||b \ flip /___ar___\
554 * p0\ || /p1 => p0\---bl---/p1
555 * \ || / \ /
556 * ar\ || /br b\ /br
557 * \||/ \ /
558 * pr pr
559 */
560 const a0 = a - a % 3;
561 ar = a0 + (a + 2) % 3;
562
563 if (b === -1) { // convex hull edge
564 if (i === 0) break;
565 a = EDGE_STACK[--i];
566 continue;
567 }
568
569 const b0 = b - b % 3;
570 const al = a0 + (a + 1) % 3;
571 const bl = b0 + (b + 2) % 3;
572
573 const p0 = triangles[ar];
574 const pr = triangles[a];
575 const pl = triangles[al];
576 const p1 = triangles[bl];
577
578 const illegal = inCircle(
579 coords[2 * p0], coords[2 * p0 + 1],
580 coords[2 * pr], coords[2 * pr + 1],
581 coords[2 * pl], coords[2 * pl + 1],
582 coords[2 * p1], coords[2 * p1 + 1]);
583
584 if (illegal) {
585 triangles[a] = p1;
586 triangles[b] = p0;
587
588 const hbl = halfedges[bl];
589
590 // edge swapped on the other side of the hull (rare); fix the halfedge reference
591 if (hbl === -1) {
592 let e = this._hullStart;
593 do {
594 if (this._hullTri[e] === bl) {
595 this._hullTri[e] = a;
596 break;
597 }
598 e = this._hullPrev[e];
599 } while (e !== this._hullStart);
600 }
601 this._link(a, hbl);
602 this._link(b, halfedges[ar]);
603 this._link(ar, bl);
604
605 const br = b0 + (b + 1) % 3;
606
607 // don't worry about hitting the cap: it can only happen on extremely degenerate input
608 if (i < EDGE_STACK.length) {
609 EDGE_STACK[i++] = br;
610 }
611 } else {
612 if (i === 0) break;
613 a = EDGE_STACK[--i];
614 }
615 }
616
617 return ar;
618 }
619
620 _link(a, b) {
621 this._halfedges[a] = b;
622 if (b !== -1) this._halfedges[b] = a;
623 }
624
625 // add a new triangle given vertex indices and adjacent half-edge ids
626 _addTriangle(i0, i1, i2, a, b, c) {
627 const t = this.trianglesLen;
628
629 this._triangles[t] = i0;
630 this._triangles[t + 1] = i1;
631 this._triangles[t + 2] = i2;
632
633 this._link(t, a);
634 this._link(t + 1, b);
635 this._link(t + 2, c);
636
637 this.trianglesLen += 3;
638
639 return t;
640 }
641}
642
643// monotonically increases with real angle, but doesn't need expensive trigonometry
644function pseudoAngle(dx, dy) {
645 const p = dx / (Math.abs(dx) + Math.abs(dy));
646 return (dy > 0 ? 3 - p : 1 + p) / 4; // [0..1]
647}
648
649function dist(ax, ay, bx, by) {
650 const dx = ax - bx;
651 const dy = ay - by;
652 return dx * dx + dy * dy;
653}
654
655function inCircle(ax, ay, bx, by, cx, cy, px, py) {
656 const dx = ax - px;
657 const dy = ay - py;
658 const ex = bx - px;
659 const ey = by - py;
660 const fx = cx - px;
661 const fy = cy - py;
662
663 const ap = dx * dx + dy * dy;
664 const bp = ex * ex + ey * ey;
665 const cp = fx * fx + fy * fy;
666
667 return dx * (ey * cp - bp * fy) -
668 dy * (ex * cp - bp * fx) +
669 ap * (ex * fy - ey * fx) < 0;
670}
671
672function circumradius(ax, ay, bx, by, cx, cy) {
673 const dx = bx - ax;
674 const dy = by - ay;
675 const ex = cx - ax;
676 const ey = cy - ay;
677
678 const bl = dx * dx + dy * dy;
679 const cl = ex * ex + ey * ey;
680 const d = 0.5 / (dx * ey - dy * ex);
681
682 const x = (ey * bl - dy * cl) * d;
683 const y = (dx * cl - ex * bl) * d;
684
685 return x * x + y * y;
686}
687
688function circumcenter(ax, ay, bx, by, cx, cy) {
689 const dx = bx - ax;
690 const dy = by - ay;
691 const ex = cx - ax;
692 const ey = cy - ay;
693
694 const bl = dx * dx + dy * dy;
695 const cl = ex * ex + ey * ey;
696 const d = 0.5 / (dx * ey - dy * ex);
697
698 const x = ax + (ey * bl - dy * cl) * d;
699 const y = ay + (dx * cl - ex * bl) * d;
700
701 return {x, y};
702}
703
704function quicksort(ids, dists, left, right) {
705 if (right - left <= 20) {
706 for (let i = left + 1; i <= right; i++) {
707 const temp = ids[i];
708 const tempDist = dists[temp];
709 let j = i - 1;
710 while (j >= left && dists[ids[j]] > tempDist) ids[j + 1] = ids[j--];
711 ids[j + 1] = temp;
712 }
713 } else {
714 const median = (left + right) >> 1;
715 let i = left + 1;
716 let j = right;
717 swap(ids, median, i);
718 if (dists[ids[left]] > dists[ids[right]]) swap(ids, left, right);
719 if (dists[ids[i]] > dists[ids[right]]) swap(ids, i, right);
720 if (dists[ids[left]] > dists[ids[i]]) swap(ids, left, i);
721
722 const temp = ids[i];
723 const tempDist = dists[temp];
724 while (true) {
725 do i++; while (dists[ids[i]] < tempDist);
726 do j--; while (dists[ids[j]] > tempDist);
727 if (j < i) break;
728 swap(ids, i, j);
729 }
730 ids[left + 1] = ids[j];
731 ids[j] = temp;
732
733 if (right - i + 1 >= j - left) {
734 quicksort(ids, dists, i, right);
735 quicksort(ids, dists, left, j - 1);
736 } else {
737 quicksort(ids, dists, left, j - 1);
738 quicksort(ids, dists, i, right);
739 }
740 }
741}
742
743function swap(arr, i, j) {
744 const tmp = arr[i];
745 arr[i] = arr[j];
746 arr[j] = tmp;
747}
748
749function defaultGetX(p) {
750 return p[0];
751}
752function defaultGetY(p) {
753 return p[1];
754}
755
756const epsilon = 1e-6;
757
758class Path {
759 constructor() {
760 this._x0 = this._y0 = // start of current subpath
761 this._x1 = this._y1 = null; // end of current subpath
762 this._ = "";
763 }
764 moveTo(x, y) {
765 this._ += `M${this._x0 = this._x1 = +x},${this._y0 = this._y1 = +y}`;
766 }
767 closePath() {
768 if (this._x1 !== null) {
769 this._x1 = this._x0, this._y1 = this._y0;
770 this._ += "Z";
771 }
772 }
773 lineTo(x, y) {
774 this._ += `L${this._x1 = +x},${this._y1 = +y}`;
775 }
776 arc(x, y, r) {
777 x = +x, y = +y, r = +r;
778 const x0 = x + r;
779 const y0 = y;
780 if (r < 0) throw new Error("negative radius");
781 if (this._x1 === null) this._ += `M${x0},${y0}`;
782 else if (Math.abs(this._x1 - x0) > epsilon || Math.abs(this._y1 - y0) > epsilon) this._ += "L" + x0 + "," + y0;
783 if (!r) return;
784 this._ += `A${r},${r},0,1,1,${x - r},${y}A${r},${r},0,1,1,${this._x1 = x0},${this._y1 = y0}`;
785 }
786 rect(x, y, w, h) {
787 this._ += `M${this._x0 = this._x1 = +x},${this._y0 = this._y1 = +y}h${+w}v${+h}h${-w}Z`;
788 }
789 value() {
790 return this._ || null;
791 }
792}
793
794class Polygon {
795 constructor() {
796 this._ = [];
797 }
798 moveTo(x, y) {
799 this._.push([x, y]);
800 }
801 closePath() {
802 this._.push(this._[0].slice());
803 }
804 lineTo(x, y) {
805 this._.push([x, y]);
806 }
807 value() {
808 return this._.length ? this._ : null;
809 }
810}
811
812class Voronoi {
813 constructor(delaunay, [xmin, ymin, xmax, ymax] = [0, 0, 960, 500]) {
814 if (!((xmax = +xmax) >= (xmin = +xmin)) || !((ymax = +ymax) >= (ymin = +ymin))) throw new Error("invalid bounds");
815 this.delaunay = delaunay;
816 this._circumcenters = new Float64Array(delaunay.points.length * 2);
817 this.vectors = new Float64Array(delaunay.points.length * 2);
818 this.xmax = xmax, this.xmin = xmin;
819 this.ymax = ymax, this.ymin = ymin;
820 this._init();
821 }
822 update() {
823 this.delaunay.update();
824 this._init();
825 return this;
826 }
827 _init() {
828 const {delaunay: {points, hull, triangles}, vectors} = this;
829 let bx, by; // lazily computed barycenter of the hull
830
831 // Compute circumcenters.
832 const circumcenters = this.circumcenters = this._circumcenters.subarray(0, triangles.length / 3 * 2);
833 for (let i = 0, j = 0, n = triangles.length, x, y; i < n; i += 3, j += 2) {
834 const t1 = triangles[i] * 2;
835 const t2 = triangles[i + 1] * 2;
836 const t3 = triangles[i + 2] * 2;
837 const x1 = points[t1];
838 const y1 = points[t1 + 1];
839 const x2 = points[t2];
840 const y2 = points[t2 + 1];
841 const x3 = points[t3];
842 const y3 = points[t3 + 1];
843
844 const dx = x2 - x1;
845 const dy = y2 - y1;
846 const ex = x3 - x1;
847 const ey = y3 - y1;
848 const ab = (dx * ey - dy * ex) * 2;
849
850 if (Math.abs(ab) < 1e-9) {
851 // For a degenerate triangle, the circumcenter is at the infinity, in a
852 // direction orthogonal to the halfedge and away from the “center” of
853 // the diagram <bx, by>, defined as the hull’s barycenter.
854 if (bx === undefined) {
855 bx = by = 0;
856 for (const i of hull) bx += points[i * 2], by += points[i * 2 + 1];
857 bx /= hull.length, by /= hull.length;
858 }
859 const a = 1e9 * Math.sign((bx - x1) * ey - (by - y1) * ex);
860 x = (x1 + x3) / 2 - a * ey;
861 y = (y1 + y3) / 2 + a * ex;
862 } else {
863 const d = 1 / ab;
864 const bl = dx * dx + dy * dy;
865 const cl = ex * ex + ey * ey;
866 x = x1 + (ey * bl - dy * cl) * d;
867 y = y1 + (dx * cl - ex * bl) * d;
868 }
869 circumcenters[j] = x;
870 circumcenters[j + 1] = y;
871 }
872
873 // Compute exterior cell rays.
874 let h = hull[hull.length - 1];
875 let p0, p1 = h * 4;
876 let x0, x1 = points[2 * h];
877 let y0, y1 = points[2 * h + 1];
878 vectors.fill(0);
879 for (let i = 0; i < hull.length; ++i) {
880 h = hull[i];
881 p0 = p1, x0 = x1, y0 = y1;
882 p1 = h * 4, x1 = points[2 * h], y1 = points[2 * h + 1];
883 vectors[p0 + 2] = vectors[p1] = y0 - y1;
884 vectors[p0 + 3] = vectors[p1 + 1] = x1 - x0;
885 }
886 }
887 render(context) {
888 const buffer = context == null ? context = new Path : undefined;
889 const {delaunay: {halfedges, inedges, hull}, circumcenters, vectors} = this;
890 if (hull.length <= 1) return null;
891 for (let i = 0, n = halfedges.length; i < n; ++i) {
892 const j = halfedges[i];
893 if (j < i) continue;
894 const ti = Math.floor(i / 3) * 2;
895 const tj = Math.floor(j / 3) * 2;
896 const xi = circumcenters[ti];
897 const yi = circumcenters[ti + 1];
898 const xj = circumcenters[tj];
899 const yj = circumcenters[tj + 1];
900 this._renderSegment(xi, yi, xj, yj, context);
901 }
902 let h0, h1 = hull[hull.length - 1];
903 for (let i = 0; i < hull.length; ++i) {
904 h0 = h1, h1 = hull[i];
905 const t = Math.floor(inedges[h1] / 3) * 2;
906 const x = circumcenters[t];
907 const y = circumcenters[t + 1];
908 const v = h0 * 4;
909 const p = this._project(x, y, vectors[v + 2], vectors[v + 3]);
910 if (p) this._renderSegment(x, y, p[0], p[1], context);
911 }
912 return buffer && buffer.value();
913 }
914 renderBounds(context) {
915 const buffer = context == null ? context = new Path : undefined;
916 context.rect(this.xmin, this.ymin, this.xmax - this.xmin, this.ymax - this.ymin);
917 return buffer && buffer.value();
918 }
919 renderCell(i, context) {
920 const buffer = context == null ? context = new Path : undefined;
921 const points = this._clip(i);
922 if (points === null || !points.length) return;
923 context.moveTo(points[0], points[1]);
924 let n = points.length;
925 while (points[0] === points[n-2] && points[1] === points[n-1] && n > 1) n -= 2;
926 for (let i = 2; i < n; i += 2) {
927 if (points[i] !== points[i-2] || points[i+1] !== points[i-1])
928 context.lineTo(points[i], points[i + 1]);
929 }
930 context.closePath();
931 return buffer && buffer.value();
932 }
933 *cellPolygons() {
934 const {delaunay: {points}} = this;
935 for (let i = 0, n = points.length / 2; i < n; ++i) {
936 const cell = this.cellPolygon(i);
937 if (cell) cell.index = i, yield cell;
938 }
939 }
940 cellPolygon(i) {
941 const polygon = new Polygon;
942 this.renderCell(i, polygon);
943 return polygon.value();
944 }
945 _renderSegment(x0, y0, x1, y1, context) {
946 let S;
947 const c0 = this._regioncode(x0, y0);
948 const c1 = this._regioncode(x1, y1);
949 if (c0 === 0 && c1 === 0) {
950 context.moveTo(x0, y0);
951 context.lineTo(x1, y1);
952 } else if (S = this._clipSegment(x0, y0, x1, y1, c0, c1)) {
953 context.moveTo(S[0], S[1]);
954 context.lineTo(S[2], S[3]);
955 }
956 }
957 contains(i, x, y) {
958 if ((x = +x, x !== x) || (y = +y, y !== y)) return false;
959 return this.delaunay._step(i, x, y) === i;
960 }
961 *neighbors(i) {
962 const ci = this._clip(i);
963 if (ci) for (const j of this.delaunay.neighbors(i)) {
964 const cj = this._clip(j);
965 // find the common edge
966 if (cj) loop: for (let ai = 0, li = ci.length; ai < li; ai += 2) {
967 for (let aj = 0, lj = cj.length; aj < lj; aj += 2) {
968 if (ci[ai] === cj[aj]
969 && ci[ai + 1] === cj[aj + 1]
970 && ci[(ai + 2) % li] === cj[(aj + lj - 2) % lj]
971 && ci[(ai + 3) % li] === cj[(aj + lj - 1) % lj]) {
972 yield j;
973 break loop;
974 }
975 }
976 }
977 }
978 }
979 _cell(i) {
980 const {circumcenters, delaunay: {inedges, halfedges, triangles}} = this;
981 const e0 = inedges[i];
982 if (e0 === -1) return null; // coincident point
983 const points = [];
984 let e = e0;
985 do {
986 const t = Math.floor(e / 3);
987 points.push(circumcenters[t * 2], circumcenters[t * 2 + 1]);
988 e = e % 3 === 2 ? e - 2 : e + 1;
989 if (triangles[e] !== i) break; // bad triangulation
990 e = halfedges[e];
991 } while (e !== e0 && e !== -1);
992 return points;
993 }
994 _clip(i) {
995 // degenerate case (1 valid point: return the box)
996 if (i === 0 && this.delaunay.hull.length === 1) {
997 return [this.xmax, this.ymin, this.xmax, this.ymax, this.xmin, this.ymax, this.xmin, this.ymin];
998 }
999 const points = this._cell(i);
1000 if (points === null) return null;
1001 const {vectors: V} = this;
1002 const v = i * 4;
1003 return this._simplify(V[v] || V[v + 1]
1004 ? this._clipInfinite(i, points, V[v], V[v + 1], V[v + 2], V[v + 3])
1005 : this._clipFinite(i, points));
1006 }
1007 _clipFinite(i, points) {
1008 const n = points.length;
1009 let P = null;
1010 let x0, y0, x1 = points[n - 2], y1 = points[n - 1];
1011 let c0, c1 = this._regioncode(x1, y1);
1012 let e0, e1 = 0;
1013 for (let j = 0; j < n; j += 2) {
1014 x0 = x1, y0 = y1, x1 = points[j], y1 = points[j + 1];
1015 c0 = c1, c1 = this._regioncode(x1, y1);
1016 if (c0 === 0 && c1 === 0) {
1017 e0 = e1, e1 = 0;
1018 if (P) P.push(x1, y1);
1019 else P = [x1, y1];
1020 } else {
1021 let S, sx0, sy0, sx1, sy1;
1022 if (c0 === 0) {
1023 if ((S = this._clipSegment(x0, y0, x1, y1, c0, c1)) === null) continue;
1024 [sx0, sy0, sx1, sy1] = S;
1025 } else {
1026 if ((S = this._clipSegment(x1, y1, x0, y0, c1, c0)) === null) continue;
1027 [sx1, sy1, sx0, sy0] = S;
1028 e0 = e1, e1 = this._edgecode(sx0, sy0);
1029 if (e0 && e1) this._edge(i, e0, e1, P, P.length);
1030 if (P) P.push(sx0, sy0);
1031 else P = [sx0, sy0];
1032 }
1033 e0 = e1, e1 = this._edgecode(sx1, sy1);
1034 if (e0 && e1) this._edge(i, e0, e1, P, P.length);
1035 if (P) P.push(sx1, sy1);
1036 else P = [sx1, sy1];
1037 }
1038 }
1039 if (P) {
1040 e0 = e1, e1 = this._edgecode(P[0], P[1]);
1041 if (e0 && e1) this._edge(i, e0, e1, P, P.length);
1042 } else if (this.contains(i, (this.xmin + this.xmax) / 2, (this.ymin + this.ymax) / 2)) {
1043 return [this.xmax, this.ymin, this.xmax, this.ymax, this.xmin, this.ymax, this.xmin, this.ymin];
1044 }
1045 return P;
1046 }
1047 _clipSegment(x0, y0, x1, y1, c0, c1) {
1048 // for more robustness, always consider the segment in the same order
1049 const flip = c0 < c1;
1050 if (flip) [x0, y0, x1, y1, c0, c1] = [x1, y1, x0, y0, c1, c0];
1051 while (true) {
1052 if (c0 === 0 && c1 === 0) return flip ? [x1, y1, x0, y0] : [x0, y0, x1, y1];
1053 if (c0 & c1) return null;
1054 let x, y, c = c0 || c1;
1055 if (c & 0b1000) x = x0 + (x1 - x0) * (this.ymax - y0) / (y1 - y0), y = this.ymax;
1056 else if (c & 0b0100) x = x0 + (x1 - x0) * (this.ymin - y0) / (y1 - y0), y = this.ymin;
1057 else if (c & 0b0010) y = y0 + (y1 - y0) * (this.xmax - x0) / (x1 - x0), x = this.xmax;
1058 else y = y0 + (y1 - y0) * (this.xmin - x0) / (x1 - x0), x = this.xmin;
1059 if (c0) x0 = x, y0 = y, c0 = this._regioncode(x0, y0);
1060 else x1 = x, y1 = y, c1 = this._regioncode(x1, y1);
1061 }
1062 }
1063 _clipInfinite(i, points, vx0, vy0, vxn, vyn) {
1064 let P = Array.from(points), p;
1065 if (p = this._project(P[0], P[1], vx0, vy0)) P.unshift(p[0], p[1]);
1066 if (p = this._project(P[P.length - 2], P[P.length - 1], vxn, vyn)) P.push(p[0], p[1]);
1067 if (P = this._clipFinite(i, P)) {
1068 for (let j = 0, n = P.length, c0, c1 = this._edgecode(P[n - 2], P[n - 1]); j < n; j += 2) {
1069 c0 = c1, c1 = this._edgecode(P[j], P[j + 1]);
1070 if (c0 && c1) j = this._edge(i, c0, c1, P, j), n = P.length;
1071 }
1072 } else if (this.contains(i, (this.xmin + this.xmax) / 2, (this.ymin + this.ymax) / 2)) {
1073 P = [this.xmin, this.ymin, this.xmax, this.ymin, this.xmax, this.ymax, this.xmin, this.ymax];
1074 }
1075 return P;
1076 }
1077 _edge(i, e0, e1, P, j) {
1078 while (e0 !== e1) {
1079 let x, y;
1080 switch (e0) {
1081 case 0b0101: e0 = 0b0100; continue; // top-left
1082 case 0b0100: e0 = 0b0110, x = this.xmax, y = this.ymin; break; // top
1083 case 0b0110: e0 = 0b0010; continue; // top-right
1084 case 0b0010: e0 = 0b1010, x = this.xmax, y = this.ymax; break; // right
1085 case 0b1010: e0 = 0b1000; continue; // bottom-right
1086 case 0b1000: e0 = 0b1001, x = this.xmin, y = this.ymax; break; // bottom
1087 case 0b1001: e0 = 0b0001; continue; // bottom-left
1088 case 0b0001: e0 = 0b0101, x = this.xmin, y = this.ymin; break; // left
1089 }
1090 // Note: this implicitly checks for out of bounds: if P[j] or P[j+1] are
1091 // undefined, the conditional statement will be executed.
1092 if ((P[j] !== x || P[j + 1] !== y) && this.contains(i, x, y)) {
1093 P.splice(j, 0, x, y), j += 2;
1094 }
1095 }
1096 return j;
1097 }
1098 _project(x0, y0, vx, vy) {
1099 let t = Infinity, c, x, y;
1100 if (vy < 0) { // top
1101 if (y0 <= this.ymin) return null;
1102 if ((c = (this.ymin - y0) / vy) < t) y = this.ymin, x = x0 + (t = c) * vx;
1103 } else if (vy > 0) { // bottom
1104 if (y0 >= this.ymax) return null;
1105 if ((c = (this.ymax - y0) / vy) < t) y = this.ymax, x = x0 + (t = c) * vx;
1106 }
1107 if (vx > 0) { // right
1108 if (x0 >= this.xmax) return null;
1109 if ((c = (this.xmax - x0) / vx) < t) x = this.xmax, y = y0 + (t = c) * vy;
1110 } else if (vx < 0) { // left
1111 if (x0 <= this.xmin) return null;
1112 if ((c = (this.xmin - x0) / vx) < t) x = this.xmin, y = y0 + (t = c) * vy;
1113 }
1114 return [x, y];
1115 }
1116 _edgecode(x, y) {
1117 return (x === this.xmin ? 0b0001
1118 : x === this.xmax ? 0b0010 : 0b0000)
1119 | (y === this.ymin ? 0b0100
1120 : y === this.ymax ? 0b1000 : 0b0000);
1121 }
1122 _regioncode(x, y) {
1123 return (x < this.xmin ? 0b0001
1124 : x > this.xmax ? 0b0010 : 0b0000)
1125 | (y < this.ymin ? 0b0100
1126 : y > this.ymax ? 0b1000 : 0b0000);
1127 }
1128 _simplify(P) {
1129 if (P && P.length > 4) {
1130 for (let i = 0; i < P.length; i+= 2) {
1131 const j = (i + 2) % P.length, k = (i + 4) % P.length;
1132 if (P[i] === P[j] && P[j] === P[k] || P[i + 1] === P[j + 1] && P[j + 1] === P[k + 1]) {
1133 P.splice(j, 2), i -= 2;
1134 }
1135 }
1136 if (!P.length) P = null;
1137 }
1138 return P;
1139 }
1140}
1141
1142const tau = 2 * Math.PI, pow = Math.pow;
1143
1144function pointX(p) {
1145 return p[0];
1146}
1147
1148function pointY(p) {
1149 return p[1];
1150}
1151
1152// A triangulation is collinear if all its triangles have a non-null area
1153function collinear(d) {
1154 const {triangles, coords} = d;
1155 for (let i = 0; i < triangles.length; i += 3) {
1156 const a = 2 * triangles[i],
1157 b = 2 * triangles[i + 1],
1158 c = 2 * triangles[i + 2],
1159 cross = (coords[c] - coords[a]) * (coords[b + 1] - coords[a + 1])
1160 - (coords[b] - coords[a]) * (coords[c + 1] - coords[a + 1]);
1161 if (cross > 1e-10) return false;
1162 }
1163 return true;
1164}
1165
1166function jitter(x, y, r) {
1167 return [x + Math.sin(x + y) * r, y + Math.cos(x - y) * r];
1168}
1169
1170class Delaunay {
1171 static from(points, fx = pointX, fy = pointY, that) {
1172 return new Delaunay("length" in points
1173 ? flatArray(points, fx, fy, that)
1174 : Float64Array.from(flatIterable(points, fx, fy, that)));
1175 }
1176 constructor(points) {
1177 this._delaunator = new Delaunator(points);
1178 this.inedges = new Int32Array(points.length / 2);
1179 this._hullIndex = new Int32Array(points.length / 2);
1180 this.points = this._delaunator.coords;
1181 this._init();
1182 }
1183 update() {
1184 this._delaunator.update();
1185 this._init();
1186 return this;
1187 }
1188 _init() {
1189 const d = this._delaunator, points = this.points;
1190
1191 // check for collinear
1192 if (d.hull && d.hull.length > 2 && collinear(d)) {
1193 this.collinear = Int32Array.from({length: points.length/2}, (_,i) => i)
1194 .sort((i, j) => points[2 * i] - points[2 * j] || points[2 * i + 1] - points[2 * j + 1]); // for exact neighbors
1195 const e = this.collinear[0], f = this.collinear[this.collinear.length - 1],
1196 bounds = [ points[2 * e], points[2 * e + 1], points[2 * f], points[2 * f + 1] ],
1197 r = 1e-8 * Math.hypot(bounds[3] - bounds[1], bounds[2] - bounds[0]);
1198 for (let i = 0, n = points.length / 2; i < n; ++i) {
1199 const p = jitter(points[2 * i], points[2 * i + 1], r);
1200 points[2 * i] = p[0];
1201 points[2 * i + 1] = p[1];
1202 }
1203 this._delaunator = new Delaunator(points);
1204 } else {
1205 delete this.collinear;
1206 }
1207
1208 const halfedges = this.halfedges = this._delaunator.halfedges;
1209 const hull = this.hull = this._delaunator.hull;
1210 const triangles = this.triangles = this._delaunator.triangles;
1211 const inedges = this.inedges.fill(-1);
1212 const hullIndex = this._hullIndex.fill(-1);
1213
1214 // Compute an index from each point to an (arbitrary) incoming halfedge
1215 // Used to give the first neighbor of each point; for this reason,
1216 // on the hull we give priority to exterior halfedges
1217 for (let e = 0, n = halfedges.length; e < n; ++e) {
1218 const p = triangles[e % 3 === 2 ? e - 2 : e + 1];
1219 if (halfedges[e] === -1 || inedges[p] === -1) inedges[p] = e;
1220 }
1221 for (let i = 0, n = hull.length; i < n; ++i) {
1222 hullIndex[hull[i]] = i;
1223 }
1224
1225 // degenerate case: 1 or 2 (distinct) points
1226 if (hull.length <= 2 && hull.length > 0) {
1227 this.triangles = new Int32Array(3).fill(-1);
1228 this.halfedges = new Int32Array(3).fill(-1);
1229 this.triangles[0] = hull[0];
1230 inedges[hull[0]] = 1;
1231 if (hull.length === 2) {
1232 inedges[hull[1]] = 0;
1233 this.triangles[1] = hull[1];
1234 this.triangles[2] = hull[1];
1235 }
1236 }
1237 }
1238 voronoi(bounds) {
1239 return new Voronoi(this, bounds);
1240 }
1241 *neighbors(i) {
1242 const {inedges, hull, _hullIndex, halfedges, triangles, collinear} = this;
1243
1244 // degenerate case with several collinear points
1245 if (collinear) {
1246 const l = collinear.indexOf(i);
1247 if (l > 0) yield collinear[l - 1];
1248 if (l < collinear.length - 1) yield collinear[l + 1];
1249 return;
1250 }
1251
1252 const e0 = inedges[i];
1253 if (e0 === -1) return; // coincident point
1254 let e = e0, p0 = -1;
1255 do {
1256 yield p0 = triangles[e];
1257 e = e % 3 === 2 ? e - 2 : e + 1;
1258 if (triangles[e] !== i) return; // bad triangulation
1259 e = halfedges[e];
1260 if (e === -1) {
1261 const p = hull[(_hullIndex[i] + 1) % hull.length];
1262 if (p !== p0) yield p;
1263 return;
1264 }
1265 } while (e !== e0);
1266 }
1267 find(x, y, i = 0) {
1268 if ((x = +x, x !== x) || (y = +y, y !== y)) return -1;
1269 const i0 = i;
1270 let c;
1271 while ((c = this._step(i, x, y)) >= 0 && c !== i && c !== i0) i = c;
1272 return c;
1273 }
1274 _step(i, x, y) {
1275 const {inedges, hull, _hullIndex, halfedges, triangles, points} = this;
1276 if (inedges[i] === -1 || !points.length) return (i + 1) % (points.length >> 1);
1277 let c = i;
1278 let dc = pow(x - points[i * 2], 2) + pow(y - points[i * 2 + 1], 2);
1279 const e0 = inedges[i];
1280 let e = e0;
1281 do {
1282 let t = triangles[e];
1283 const dt = pow(x - points[t * 2], 2) + pow(y - points[t * 2 + 1], 2);
1284 if (dt < dc) dc = dt, c = t;
1285 e = e % 3 === 2 ? e - 2 : e + 1;
1286 if (triangles[e] !== i) break; // bad triangulation
1287 e = halfedges[e];
1288 if (e === -1) {
1289 e = hull[(_hullIndex[i] + 1) % hull.length];
1290 if (e !== t) {
1291 if (pow(x - points[e * 2], 2) + pow(y - points[e * 2 + 1], 2) < dc) return e;
1292 }
1293 break;
1294 }
1295 } while (e !== e0);
1296 return c;
1297 }
1298 render(context) {
1299 const buffer = context == null ? context = new Path : undefined;
1300 const {points, halfedges, triangles} = this;
1301 for (let i = 0, n = halfedges.length; i < n; ++i) {
1302 const j = halfedges[i];
1303 if (j < i) continue;
1304 const ti = triangles[i] * 2;
1305 const tj = triangles[j] * 2;
1306 context.moveTo(points[ti], points[ti + 1]);
1307 context.lineTo(points[tj], points[tj + 1]);
1308 }
1309 this.renderHull(context);
1310 return buffer && buffer.value();
1311 }
1312 renderPoints(context, r) {
1313 if (r === undefined && (!context || typeof context.moveTo !== "function")) r = context, context = null;
1314 r = r == undefined ? 2 : +r;
1315 const buffer = context == null ? context = new Path : undefined;
1316 const {points} = this;
1317 for (let i = 0, n = points.length; i < n; i += 2) {
1318 const x = points[i], y = points[i + 1];
1319 context.moveTo(x + r, y);
1320 context.arc(x, y, r, 0, tau);
1321 }
1322 return buffer && buffer.value();
1323 }
1324 renderHull(context) {
1325 const buffer = context == null ? context = new Path : undefined;
1326 const {hull, points} = this;
1327 const h = hull[0] * 2, n = hull.length;
1328 context.moveTo(points[h], points[h + 1]);
1329 for (let i = 1; i < n; ++i) {
1330 const h = 2 * hull[i];
1331 context.lineTo(points[h], points[h + 1]);
1332 }
1333 context.closePath();
1334 return buffer && buffer.value();
1335 }
1336 hullPolygon() {
1337 const polygon = new Polygon;
1338 this.renderHull(polygon);
1339 return polygon.value();
1340 }
1341 renderTriangle(i, context) {
1342 const buffer = context == null ? context = new Path : undefined;
1343 const {points, triangles} = this;
1344 const t0 = triangles[i *= 3] * 2;
1345 const t1 = triangles[i + 1] * 2;
1346 const t2 = triangles[i + 2] * 2;
1347 context.moveTo(points[t0], points[t0 + 1]);
1348 context.lineTo(points[t1], points[t1 + 1]);
1349 context.lineTo(points[t2], points[t2 + 1]);
1350 context.closePath();
1351 return buffer && buffer.value();
1352 }
1353 *trianglePolygons() {
1354 const {triangles} = this;
1355 for (let i = 0, n = triangles.length / 3; i < n; ++i) {
1356 yield this.trianglePolygon(i);
1357 }
1358 }
1359 trianglePolygon(i) {
1360 const polygon = new Polygon;
1361 this.renderTriangle(i, polygon);
1362 return polygon.value();
1363 }
1364}
1365
1366function flatArray(points, fx, fy, that) {
1367 const n = points.length;
1368 const array = new Float64Array(n * 2);
1369 for (let i = 0; i < n; ++i) {
1370 const p = points[i];
1371 array[i * 2] = fx.call(that, p, i, points);
1372 array[i * 2 + 1] = fy.call(that, p, i, points);
1373 }
1374 return array;
1375}
1376
1377function* flatIterable(points, fx, fy, that) {
1378 let i = 0;
1379 for (const p of points) {
1380 yield fx.call(that, p, i, points);
1381 yield fy.call(that, p, i, points);
1382 ++i;
1383 }
1384}
1385
1386exports.Delaunay = Delaunay;
1387exports.Voronoi = Voronoi;
1388
1389Object.defineProperty(exports, '__esModule', { value: true });
1390
1391})));
Note: See TracBrowser for help on using the repository browser.