@@ -4,8 +4,19 @@ const EDGE_STACK = new Uint32Array(512);
4
4
5
5
import { orient2d } from 'robust-predicates' ;
6
6
7
+ /** @template {ArrayLike<number>} T */
7
8
export default class Delaunator {
8
9
10
+ /**
11
+ * Constructs a delaunay triangulation object given an array of points (`[x, y]` by default).
12
+ * `getX` and `getY` are optional functions of the form `(point) => value` for custom point formats.
13
+ *
14
+ * @template P
15
+ * @param {P[] } points
16
+ * @param {(p: P) => number } [getX]
17
+ * @param {(p: P) => number } [getY]
18
+ */
19
+ // @ts -expect-error TS2322
9
20
static from ( points , getX = defaultGetX , getY = defaultGetY ) {
10
21
const n = points . length ;
11
22
const coords = new Float64Array ( n * 2 ) ;
@@ -19,6 +30,12 @@ export default class Delaunator {
19
30
return new Delaunator ( coords ) ;
20
31
}
21
32
33
+ /**
34
+ * Constructs a delaunay triangulation object given an array of point coordinates of the form:
35
+ * `[x0, y0, x1, y1, ...]` (use a typed array for best performance). Duplicate points are skipped.
36
+ *
37
+ * @param {T } coords
38
+ */
22
39
constructor ( coords ) {
23
40
const n = coords . length >> 1 ;
24
41
if ( n > 0 && typeof coords [ 0 ] !== 'number' ) throw new Error ( 'Expected coords to contain numbers.' ) ;
@@ -27,23 +44,44 @@ export default class Delaunator {
27
44
28
45
// arrays that will store the triangulation graph
29
46
const maxTriangles = Math . max ( 2 * n - 5 , 0 ) ;
30
- this . _triangles = new Uint32Array ( maxTriangles * 3 ) ;
31
- this . _halfedges = new Int32Array ( maxTriangles * 3 ) ;
47
+ /** @private */ this . _triangles = new Uint32Array ( maxTriangles * 3 ) ;
48
+ /** @private */ this . _halfedges = new Int32Array ( maxTriangles * 3 ) ;
32
49
33
50
// temporary arrays for tracking the edges of the advancing convex hull
34
- this . _hashSize = Math . ceil ( Math . sqrt ( n ) ) ;
35
- this . _hullPrev = new Uint32Array ( n ) ; // edge to prev edge
36
- this . _hullNext = new Uint32Array ( n ) ; // edge to next edge
37
- this . _hullTri = new Uint32Array ( n ) ; // edge to adjacent triangle
38
- this . _hullHash = new Int32Array ( this . _hashSize ) ; // angular edge hash
51
+ /** @private */ this . _hashSize = Math . ceil ( Math . sqrt ( n ) ) ;
52
+ /** @private */ this . _hullPrev = new Uint32Array ( n ) ; // edge to prev edge
53
+ /** @private */ this . _hullNext = new Uint32Array ( n ) ; // edge to next edge
54
+ /** @private */ this . _hullTri = new Uint32Array ( n ) ; // edge to adjacent triangle
55
+ /** @private */ this . _hullHash = new Int32Array ( this . _hashSize ) ; // angular edge hash
39
56
40
57
// temporary arrays for sorting points
41
- this . _ids = new Uint32Array ( n ) ;
42
- this . _dists = new Float64Array ( n ) ;
58
+ /** @private */ this . _ids = new Uint32Array ( n ) ;
59
+ /** @private */ this . _dists = new Float64Array ( n ) ;
60
+
61
+ /** @private */ this . trianglesLen = 0 ;
62
+ /** @private */ this . _cx = 0 ;
63
+ /** @private */ this . _cy = 0 ;
64
+ /** @private */ this . _hullStart = 0 ;
65
+
66
+
67
+ /** A `Uint32Array` array of indices that reference points on the convex hull of the input data, counter-clockwise. */
68
+ this . hull = this . _triangles ;
69
+ /** A `Uint32Array` array of triangle vertex indices (each group of three numbers forms a triangle). All triangles are directed counterclockwise. */
70
+ this . triangles = this . _triangles ;
71
+ /**
72
+ * A `Int32Array` array of triangle half-edge indices that allows you to traverse the triangulation.
73
+ * `i`-th half-edge in the array corresponds to vertex `triangles[i]` the half-edge is coming from.
74
+ * `halfedges[i]` is the index of a twin half-edge in an adjacent triangle (or `-1` for outer half-edges on the convex hull).
75
+ */
76
+ this . halfedges = this . _halfedges ;
43
77
44
78
this . update ( ) ;
45
79
}
46
80
81
+ /**
82
+ * Updates the triangulation if you modified `delaunay.coords` values in place, avoiding expensive memory allocations.
83
+ * Useful for iterative relaxation algorithms such as Lloyd's.
84
+ */
47
85
update ( ) {
48
86
const { coords, _hullPrev : hullPrev , _hullNext : hullNext , _hullTri : hullTri , _hullHash : hullHash } = this ;
49
87
const n = coords . length >> 1 ;
@@ -66,7 +104,7 @@ export default class Delaunator {
66
104
const cx = ( minX + maxX ) / 2 ;
67
105
const cy = ( minY + maxY ) / 2 ;
68
106
69
- let i0 , i1 , i2 ;
107
+ let i0 = 0 , i1 = 0 , i2 = 0 ;
70
108
71
109
// pick a seed point close to the center
72
110
for ( let i = 0 , minDist = Infinity ; i < n ; i ++ ) {
@@ -124,7 +162,7 @@ export default class Delaunator {
124
162
}
125
163
this . hull = hull . subarray ( 0 , j ) ;
126
164
this . triangles = new Uint32Array ( 0 ) ;
127
- this . halfedges = new Uint32Array ( 0 ) ;
165
+ this . halfedges = new Int32Array ( 0 ) ;
128
166
return ;
129
167
}
130
168
@@ -172,7 +210,7 @@ export default class Delaunator {
172
210
this . trianglesLen = 0 ;
173
211
this . _addTriangle ( i0 , i1 , i2 , - 1 , - 1 , - 1 ) ;
174
212
175
- for ( let k = 0 , xp , yp ; k < this . _ids . length ; k ++ ) {
213
+ for ( let k = 0 , xp = 0 , yp = 0 ; k < this . _ids . length ; k ++ ) {
176
214
const i = this . _ids [ k ] ;
177
215
const x = coords [ 2 * i ] ;
178
216
const y = coords [ 2 * i + 1 ] ;
@@ -254,10 +292,23 @@ export default class Delaunator {
254
292
this . halfedges = this . _halfedges . subarray ( 0 , this . trianglesLen ) ;
255
293
}
256
294
295
+ /**
296
+ * Calculate an angle-based key for the edge hash used for advancing convex hull.
297
+ *
298
+ * @param {number } x
299
+ * @param {number } y
300
+ * @private
301
+ */
257
302
_hashKey ( x , y ) {
258
303
return Math . floor ( pseudoAngle ( x - this . _cx , y - this . _cy ) * this . _hashSize ) % this . _hashSize ;
259
304
}
260
305
306
+ /**
307
+ * Flip an edge in a pair of triangles if it doesn't satisfy the Delaunay condition.
308
+ *
309
+ * @param {number } a
310
+ * @private
311
+ */
261
312
_legalize ( a ) {
262
313
const { _triangles : triangles , _halfedges : halfedges , coords} = this ;
263
314
@@ -313,7 +364,7 @@ export default class Delaunator {
313
364
314
365
const hbl = halfedges [ bl ] ;
315
366
316
- // edge swapped on the other side of the hull (rare); fix the halfedge reference
367
+ // edge swapped on the other side of the hull (rare); fix the half-edge reference
317
368
if ( hbl === - 1 ) {
318
369
let e = this . _hullStart ;
319
370
do {
@@ -343,12 +394,28 @@ export default class Delaunator {
343
394
return ar ;
344
395
}
345
396
397
+ /**
398
+ * Link two half-edges to each other.
399
+ * @param {number } a
400
+ * @param {number } b
401
+ * @private
402
+ */
346
403
_link ( a , b ) {
347
404
this . _halfedges [ a ] = b ;
348
405
if ( b !== - 1 ) this . _halfedges [ b ] = a ;
349
406
}
350
407
351
- // add a new triangle given vertex indices and adjacent half-edge ids
408
+ /**
409
+ * Add a new triangle given vertex indices and adjacent half-edge ids.
410
+ *
411
+ * @param {number } i0
412
+ * @param {number } i1
413
+ * @param {number } i2
414
+ * @param {number } a
415
+ * @param {number } b
416
+ * @param {number } c
417
+ * @private
418
+ */
352
419
_addTriangle ( i0 , i1 , i2 , a , b , c ) {
353
420
const t = this . trianglesLen ;
354
421
@@ -366,18 +433,43 @@ export default class Delaunator {
366
433
}
367
434
}
368
435
369
- // monotonically increases with real angle, but doesn't need expensive trigonometry
436
+ /**
437
+ * Monotonically increases with real angle, but doesn't need expensive trigonometry.
438
+ *
439
+ * @param {number } dx
440
+ * @param {number } dy
441
+ */
370
442
function pseudoAngle ( dx , dy ) {
371
443
const p = dx / ( Math . abs ( dx ) + Math . abs ( dy ) ) ;
372
444
return ( dy > 0 ? 3 - p : 1 + p ) / 4 ; // [0..1]
373
445
}
374
446
447
+ /**
448
+ * Squared distance between two points.
449
+ *
450
+ * @param {number } ax
451
+ * @param {number } ay
452
+ * @param {number } bx
453
+ * @param {number } by
454
+ */
375
455
function dist ( ax , ay , bx , by ) {
376
456
const dx = ax - bx ;
377
457
const dy = ay - by ;
378
458
return dx * dx + dy * dy ;
379
459
}
380
460
461
+ /**
462
+ * Checker whether point P is inside a circle formed by points A, B, C.
463
+ *
464
+ * @param {number } ax
465
+ * @param {number } ay
466
+ * @param {number } bx
467
+ * @param {number } by
468
+ * @param {number } cx
469
+ * @param {number } cy
470
+ * @param {number } px
471
+ * @param {number } py
472
+ */
381
473
function inCircle ( ax , ay , bx , by , cx , cy , px , py ) {
382
474
const dx = ax - px ;
383
475
const dy = ay - py ;
@@ -395,6 +487,16 @@ function inCircle(ax, ay, bx, by, cx, cy, px, py) {
395
487
ap * ( ex * fy - ey * fx ) < 0 ;
396
488
}
397
489
490
+ /**
491
+ * Checker whether point P is inside a circle formed by points A, B, C.
492
+ *
493
+ * @param {number } ax
494
+ * @param {number } ay
495
+ * @param {number } bx
496
+ * @param {number } by
497
+ * @param {number } cx
498
+ * @param {number } cy
499
+ */
398
500
function circumradius ( ax , ay , bx , by , cx , cy ) {
399
501
const dx = bx - ax ;
400
502
const dy = by - ay ;
@@ -411,6 +513,16 @@ function circumradius(ax, ay, bx, by, cx, cy) {
411
513
return x * x + y * y ;
412
514
}
413
515
516
+ /**
517
+ * Get coordinates of a circumcenter for points A, B, C.
518
+ *
519
+ * @param {number } ax
520
+ * @param {number } ay
521
+ * @param {number } bx
522
+ * @param {number } by
523
+ * @param {number } cx
524
+ * @param {number } cy
525
+ */
414
526
function circumcenter ( ax , ay , bx , by , cx , cy ) {
415
527
const dx = bx - ax ;
416
528
const dy = by - ay ;
@@ -427,6 +539,14 @@ function circumcenter(ax, ay, bx, by, cx, cy) {
427
539
return { x, y} ;
428
540
}
429
541
542
+ /**
543
+ * Sort points by distance via an array of point indices and an array of calculated distances.
544
+ *
545
+ * @param {Uint32Array } ids
546
+ * @param {Float64Array } dists
547
+ * @param {number } left
548
+ * @param {number } right
549
+ */
430
550
function quicksort ( ids , dists , left , right ) {
431
551
if ( right - left <= 20 ) {
432
552
for ( let i = left + 1 ; i <= right ; i ++ ) {
@@ -466,15 +586,22 @@ function quicksort(ids, dists, left, right) {
466
586
}
467
587
}
468
588
589
+ /**
590
+ * @param {Uint32Array } arr
591
+ * @param {number } i
592
+ * @param {number } j
593
+ */
469
594
function swap ( arr , i , j ) {
470
595
const tmp = arr [ i ] ;
471
596
arr [ i ] = arr [ j ] ;
472
597
arr [ j ] = tmp ;
473
598
}
474
599
600
+ /** @param {[number, number] } p */
475
601
function defaultGetX ( p ) {
476
602
return p [ 0 ] ;
477
603
}
604
+ /** @param {[number, number] } p */
478
605
function defaultGetY ( p ) {
479
606
return p [ 1 ] ;
480
607
}
0 commit comments