earcut 2.2.3 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/earcut.js CHANGED
@@ -1,31 +1,27 @@
1
- 'use strict';
2
1
 
3
- module.exports = earcut;
4
- module.exports.default = earcut;
2
+ export default function earcut(data, holeIndices, dim = 2) {
5
3
 
6
- function earcut(data, holeIndices, dim) {
7
-
8
- dim = dim || 2;
9
-
10
- var hasHoles = holeIndices && holeIndices.length,
11
- outerLen = hasHoles ? holeIndices[0] * dim : data.length,
12
- outerNode = linkedList(data, 0, outerLen, dim, true),
13
- triangles = [];
4
+ const hasHoles = holeIndices && holeIndices.length;
5
+ const outerLen = hasHoles ? holeIndices[0] * dim : data.length;
6
+ let outerNode = linkedList(data, 0, outerLen, dim, true);
7
+ const triangles = [];
14
8
 
15
9
  if (!outerNode || outerNode.next === outerNode.prev) return triangles;
16
10
 
17
- var minX, minY, maxX, maxY, x, y, invSize;
11
+ let minX, minY, invSize;
18
12
 
19
13
  if (hasHoles) outerNode = eliminateHoles(data, holeIndices, outerNode, dim);
20
14
 
21
15
  // if the shape is not too simple, we'll use z-order curve hash later; calculate polygon bbox
22
16
  if (data.length > 80 * dim) {
23
- minX = maxX = data[0];
24
- minY = maxY = data[1];
25
-
26
- for (var i = dim; i < outerLen; i += dim) {
27
- x = data[i];
28
- y = data[i + 1];
17
+ minX = Infinity;
18
+ minY = Infinity;
19
+ let maxX = -Infinity;
20
+ let maxY = -Infinity;
21
+
22
+ for (let i = dim; i < outerLen; i += dim) {
23
+ const x = data[i];
24
+ const y = data[i + 1];
29
25
  if (x < minX) minX = x;
30
26
  if (y < minY) minY = y;
31
27
  if (x > maxX) maxX = x;
@@ -34,22 +30,22 @@ function earcut(data, holeIndices, dim) {
34
30
 
35
31
  // minX, minY and invSize are later used to transform coords into integers for z-order calculation
36
32
  invSize = Math.max(maxX - minX, maxY - minY);
37
- invSize = invSize !== 0 ? 1 / invSize : 0;
33
+ invSize = invSize !== 0 ? 32767 / invSize : 0;
38
34
  }
39
35
 
40
- earcutLinked(outerNode, triangles, dim, minX, minY, invSize);
36
+ earcutLinked(outerNode, triangles, dim, minX, minY, invSize, 0);
41
37
 
42
38
  return triangles;
43
39
  }
44
40
 
45
41
  // create a circular doubly linked list from polygon points in the specified winding order
46
42
  function linkedList(data, start, end, dim, clockwise) {
47
- var i, last;
43
+ let last;
48
44
 
49
45
  if (clockwise === (signedArea(data, start, end, dim) > 0)) {
50
- for (i = start; i < end; i += dim) last = insertNode(i, data[i], data[i + 1], last);
46
+ for (let i = start; i < end; i += dim) last = insertNode(i / dim | 0, data[i], data[i + 1], last);
51
47
  } else {
52
- for (i = end - dim; i >= start; i -= dim) last = insertNode(i, data[i], data[i + 1], last);
48
+ for (let i = end - dim; i >= start; i -= dim) last = insertNode(i / dim | 0, data[i], data[i + 1], last);
53
49
  }
54
50
 
55
51
  if (last && equals(last, last.next)) {
@@ -65,7 +61,7 @@ function filterPoints(start, end) {
65
61
  if (!start) return start;
66
62
  if (!end) end = start;
67
63
 
68
- var p = start,
64
+ let p = start,
69
65
  again;
70
66
  do {
71
67
  again = false;
@@ -91,19 +87,15 @@ function earcutLinked(ear, triangles, dim, minX, minY, invSize, pass) {
91
87
  // interlink polygon nodes in z-order
92
88
  if (!pass && invSize) indexCurve(ear, minX, minY, invSize);
93
89
 
94
- var stop = ear,
95
- prev, next;
90
+ let stop = ear;
96
91
 
97
92
  // iterate through ears, slicing them one by one
98
93
  while (ear.prev !== ear.next) {
99
- prev = ear.prev;
100
- next = ear.next;
94
+ const prev = ear.prev;
95
+ const next = ear.next;
101
96
 
102
97
  if (invSize ? isEarHashed(ear, minX, minY, invSize) : isEar(ear)) {
103
- // cut off the triangle
104
- triangles.push(prev.i / dim);
105
- triangles.push(ear.i / dim);
106
- triangles.push(next.i / dim);
98
+ triangles.push(prev.i, ear.i, next.i); // cut off the triangle
107
99
 
108
100
  removeNode(ear);
109
101
 
@@ -124,7 +116,7 @@ function earcutLinked(ear, triangles, dim, minX, minY, invSize, pass) {
124
116
 
125
117
  // if this didn't work, try curing all small self-intersections locally
126
118
  } else if (pass === 1) {
127
- ear = cureLocalIntersections(filterPoints(ear), triangles, dim);
119
+ ear = cureLocalIntersections(filterPoints(ear), triangles);
128
120
  earcutLinked(ear, triangles, dim, minX, minY, invSize, 2);
129
121
 
130
122
  // as a last resort, try splitting the remaining polygon into two
@@ -139,17 +131,25 @@ function earcutLinked(ear, triangles, dim, minX, minY, invSize, pass) {
139
131
 
140
132
  // check whether a polygon node forms a valid ear with adjacent nodes
141
133
  function isEar(ear) {
142
- var a = ear.prev,
134
+ const a = ear.prev,
143
135
  b = ear,
144
136
  c = ear.next;
145
137
 
146
138
  if (area(a, b, c) >= 0) return false; // reflex, can't be an ear
147
139
 
148
140
  // now make sure we don't have other points inside the potential ear
149
- var p = ear.next.next;
141
+ const ax = a.x, bx = b.x, cx = c.x, ay = a.y, by = b.y, cy = c.y;
150
142
 
151
- while (p !== ear.prev) {
152
- if (pointInTriangle(a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y) &&
143
+ // triangle bbox; min & max are calculated like this for speed
144
+ const x0 = ax < bx ? (ax < cx ? ax : cx) : (bx < cx ? bx : cx),
145
+ y0 = ay < by ? (ay < cy ? ay : cy) : (by < cy ? by : cy),
146
+ x1 = ax > bx ? (ax > cx ? ax : cx) : (bx > cx ? bx : cx),
147
+ y1 = ay > by ? (ay > cy ? ay : cy) : (by > cy ? by : cy);
148
+
149
+ let p = c.next;
150
+ while (p !== a) {
151
+ if (p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 &&
152
+ pointInTriangle(ax, ay, bx, by, cx, cy, p.x, p.y) &&
153
153
  area(p.prev, p, p.next) >= 0) return false;
154
154
  p = p.next;
155
155
  }
@@ -158,51 +158,49 @@ function isEar(ear) {
158
158
  }
159
159
 
160
160
  function isEarHashed(ear, minX, minY, invSize) {
161
- var a = ear.prev,
161
+ const a = ear.prev,
162
162
  b = ear,
163
163
  c = ear.next;
164
164
 
165
165
  if (area(a, b, c) >= 0) return false; // reflex, can't be an ear
166
166
 
167
+ const ax = a.x, bx = b.x, cx = c.x, ay = a.y, by = b.y, cy = c.y;
168
+
167
169
  // triangle bbox; min & max are calculated like this for speed
168
- var minTX = a.x < b.x ? (a.x < c.x ? a.x : c.x) : (b.x < c.x ? b.x : c.x),
169
- minTY = a.y < b.y ? (a.y < c.y ? a.y : c.y) : (b.y < c.y ? b.y : c.y),
170
- maxTX = a.x > b.x ? (a.x > c.x ? a.x : c.x) : (b.x > c.x ? b.x : c.x),
171
- maxTY = a.y > b.y ? (a.y > c.y ? a.y : c.y) : (b.y > c.y ? b.y : c.y);
170
+ const x0 = ax < bx ? (ax < cx ? ax : cx) : (bx < cx ? bx : cx),
171
+ y0 = ay < by ? (ay < cy ? ay : cy) : (by < cy ? by : cy),
172
+ x1 = ax > bx ? (ax > cx ? ax : cx) : (bx > cx ? bx : cx),
173
+ y1 = ay > by ? (ay > cy ? ay : cy) : (by > cy ? by : cy);
172
174
 
173
175
  // z-order range for the current triangle bbox;
174
- var minZ = zOrder(minTX, minTY, minX, minY, invSize),
175
- maxZ = zOrder(maxTX, maxTY, minX, minY, invSize);
176
+ const minZ = zOrder(x0, y0, minX, minY, invSize),
177
+ maxZ = zOrder(x1, y1, minX, minY, invSize);
176
178
 
177
- var p = ear.prevZ,
179
+ let p = ear.prevZ,
178
180
  n = ear.nextZ;
179
181
 
180
182
  // look for points inside the triangle in both directions
181
183
  while (p && p.z >= minZ && n && n.z <= maxZ) {
182
- if (p !== ear.prev && p !== ear.next &&
183
- pointInTriangle(a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y) &&
184
- area(p.prev, p, p.next) >= 0) return false;
184
+ if (p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 && p !== a && p !== c &&
185
+ pointInTriangle(ax, ay, bx, by, cx, cy, p.x, p.y) && area(p.prev, p, p.next) >= 0) return false;
185
186
  p = p.prevZ;
186
187
 
187
- if (n !== ear.prev && n !== ear.next &&
188
- pointInTriangle(a.x, a.y, b.x, b.y, c.x, c.y, n.x, n.y) &&
189
- area(n.prev, n, n.next) >= 0) return false;
188
+ if (n.x >= x0 && n.x <= x1 && n.y >= y0 && n.y <= y1 && n !== a && n !== c &&
189
+ pointInTriangle(ax, ay, bx, by, cx, cy, n.x, n.y) && area(n.prev, n, n.next) >= 0) return false;
190
190
  n = n.nextZ;
191
191
  }
192
192
 
193
193
  // look for remaining points in decreasing z-order
194
194
  while (p && p.z >= minZ) {
195
- if (p !== ear.prev && p !== ear.next &&
196
- pointInTriangle(a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y) &&
197
- area(p.prev, p, p.next) >= 0) return false;
195
+ if (p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 && p !== a && p !== c &&
196
+ pointInTriangle(ax, ay, bx, by, cx, cy, p.x, p.y) && area(p.prev, p, p.next) >= 0) return false;
198
197
  p = p.prevZ;
199
198
  }
200
199
 
201
200
  // look for remaining points in increasing z-order
202
201
  while (n && n.z <= maxZ) {
203
- if (n !== ear.prev && n !== ear.next &&
204
- pointInTriangle(a.x, a.y, b.x, b.y, c.x, c.y, n.x, n.y) &&
205
- area(n.prev, n, n.next) >= 0) return false;
202
+ if (n.x >= x0 && n.x <= x1 && n.y >= y0 && n.y <= y1 && n !== a && n !== c &&
203
+ pointInTriangle(ax, ay, bx, by, cx, cy, n.x, n.y) && area(n.prev, n, n.next) >= 0) return false;
206
204
  n = n.nextZ;
207
205
  }
208
206
 
@@ -210,17 +208,15 @@ function isEarHashed(ear, minX, minY, invSize) {
210
208
  }
211
209
 
212
210
  // go through all polygon nodes and cure small local self-intersections
213
- function cureLocalIntersections(start, triangles, dim) {
214
- var p = start;
211
+ function cureLocalIntersections(start, triangles) {
212
+ let p = start;
215
213
  do {
216
- var a = p.prev,
214
+ const a = p.prev,
217
215
  b = p.next.next;
218
216
 
219
217
  if (!equals(a, b) && intersects(a, p, p.next, b) && locallyInside(a, b) && locallyInside(b, a)) {
220
218
 
221
- triangles.push(a.i / dim);
222
- triangles.push(p.i / dim);
223
- triangles.push(b.i / dim);
219
+ triangles.push(a.i, p.i, b.i);
224
220
 
225
221
  // remove two nodes involved
226
222
  removeNode(p);
@@ -237,21 +233,21 @@ function cureLocalIntersections(start, triangles, dim) {
237
233
  // try splitting polygon into two and triangulate them independently
238
234
  function splitEarcut(start, triangles, dim, minX, minY, invSize) {
239
235
  // look for a valid diagonal that divides the polygon into two
240
- var a = start;
236
+ let a = start;
241
237
  do {
242
- var b = a.next.next;
238
+ let b = a.next.next;
243
239
  while (b !== a.prev) {
244
240
  if (a.i !== b.i && isValidDiagonal(a, b)) {
245
241
  // split the polygon in two by the diagonal
246
- var c = splitPolygon(a, b);
242
+ let c = splitPolygon(a, b);
247
243
 
248
244
  // filter colinear points around the cuts
249
245
  a = filterPoints(a, a.next);
250
246
  c = filterPoints(c, c.next);
251
247
 
252
248
  // run earcut on each half
253
- earcutLinked(a, triangles, dim, minX, minY, invSize);
254
- earcutLinked(c, triangles, dim, minX, minY, invSize);
249
+ earcutLinked(a, triangles, dim, minX, minY, invSize, 0);
250
+ earcutLinked(c, triangles, dim, minX, minY, invSize, 0);
255
251
  return;
256
252
  }
257
253
  b = b.next;
@@ -262,13 +258,12 @@ function splitEarcut(start, triangles, dim, minX, minY, invSize) {
262
258
 
263
259
  // link every hole into the outer loop, producing a single-ring polygon without holes
264
260
  function eliminateHoles(data, holeIndices, outerNode, dim) {
265
- var queue = [],
266
- i, len, start, end, list;
261
+ const queue = [];
267
262
 
268
- for (i = 0, len = holeIndices.length; i < len; i++) {
269
- start = holeIndices[i] * dim;
270
- end = i < len - 1 ? holeIndices[i + 1] * dim : data.length;
271
- list = linkedList(data, start, end, dim, false);
263
+ for (let i = 0, len = holeIndices.length; i < len; i++) {
264
+ const start = holeIndices[i] * dim;
265
+ const end = i < len - 1 ? holeIndices[i + 1] * dim : data.length;
266
+ const list = linkedList(data, start, end, dim, false);
272
267
  if (list === list.next) list.steiner = true;
273
268
  queue.push(getLeftmost(list));
274
269
  }
@@ -276,9 +271,8 @@ function eliminateHoles(data, holeIndices, outerNode, dim) {
276
271
  queue.sort(compareX);
277
272
 
278
273
  // process holes from left to right
279
- for (i = 0; i < queue.length; i++) {
274
+ for (let i = 0; i < queue.length; i++) {
280
275
  outerNode = eliminateHole(queue[i], outerNode);
281
- outerNode = filterPoints(outerNode, outerNode.next);
282
276
  }
283
277
 
284
278
  return outerNode;
@@ -290,41 +284,35 @@ function compareX(a, b) {
290
284
 
291
285
  // find a bridge between vertices that connects hole with an outer ring and and link it
292
286
  function eliminateHole(hole, outerNode) {
293
- var bridge = findHoleBridge(hole, outerNode);
287
+ const bridge = findHoleBridge(hole, outerNode);
294
288
  if (!bridge) {
295
289
  return outerNode;
296
290
  }
297
291
 
298
- var bridgeReverse = splitPolygon(bridge, hole);
292
+ const bridgeReverse = splitPolygon(bridge, hole);
299
293
 
300
294
  // filter collinear points around the cuts
301
- var filteredBridge = filterPoints(bridge, bridge.next);
302
295
  filterPoints(bridgeReverse, bridgeReverse.next);
303
-
304
- // Check if input node was removed by the filtering
305
- return outerNode === bridge ? filteredBridge : outerNode;
296
+ return filterPoints(bridge, bridge.next);
306
297
  }
307
298
 
308
299
  // David Eberly's algorithm for finding a bridge between hole and outer polygon
309
300
  function findHoleBridge(hole, outerNode) {
310
- var p = outerNode,
311
- hx = hole.x,
312
- hy = hole.y,
313
- qx = -Infinity,
314
- m;
301
+ let p = outerNode;
302
+ const hx = hole.x;
303
+ const hy = hole.y;
304
+ let qx = -Infinity;
305
+ let m;
315
306
 
316
307
  // find a segment intersected by a ray from the hole's leftmost point to the left;
317
308
  // segment's endpoint with lesser x will be potential connection point
318
309
  do {
319
310
  if (hy <= p.y && hy >= p.next.y && p.next.y !== p.y) {
320
- var x = p.x + (hy - p.y) * (p.next.x - p.x) / (p.next.y - p.y);
311
+ const x = p.x + (hy - p.y) * (p.next.x - p.x) / (p.next.y - p.y);
321
312
  if (x <= hx && x > qx) {
322
313
  qx = x;
323
- if (x === hx) {
324
- if (hy === p.y) return p;
325
- if (hy === p.next.y) return p.next;
326
- }
327
314
  m = p.x < p.next.x ? p : p.next;
315
+ if (x === hx) return m; // hole touches outer segment; pick leftmost endpoint
328
316
  }
329
317
  }
330
318
  p = p.next;
@@ -332,17 +320,14 @@ function findHoleBridge(hole, outerNode) {
332
320
 
333
321
  if (!m) return null;
334
322
 
335
- if (hx === qx) return m; // hole touches outer segment; pick leftmost endpoint
336
-
337
323
  // look for points inside the triangle of hole point, segment intersection and endpoint;
338
324
  // if there are no points found, we have a valid connection;
339
325
  // otherwise choose the point of the minimum angle with the ray as connection point
340
326
 
341
- var stop = m,
342
- mx = m.x,
343
- my = m.y,
344
- tanMin = Infinity,
345
- tan;
327
+ const stop = m;
328
+ const mx = m.x;
329
+ const my = m.y;
330
+ let tanMin = Infinity;
346
331
 
347
332
  p = m;
348
333
 
@@ -350,7 +335,7 @@ function findHoleBridge(hole, outerNode) {
350
335
  if (hx >= p.x && p.x >= mx && hx !== p.x &&
351
336
  pointInTriangle(hy < my ? hx : qx, hy, mx, my, hy < my ? qx : hx, hy, p.x, p.y)) {
352
337
 
353
- tan = Math.abs(hy - p.y) / (hx - p.x); // tangential
338
+ const tan = Math.abs(hy - p.y) / (hx - p.x); // tangential
354
339
 
355
340
  if (locallyInside(p, hole) &&
356
341
  (tan < tanMin || (tan === tanMin && (p.x > m.x || (p.x === m.x && sectorContainsSector(m, p)))))) {
@@ -372,9 +357,9 @@ function sectorContainsSector(m, p) {
372
357
 
373
358
  // interlink polygon nodes in z-order
374
359
  function indexCurve(start, minX, minY, invSize) {
375
- var p = start;
360
+ let p = start;
376
361
  do {
377
- if (p.z === null) p.z = zOrder(p.x, p.y, minX, minY, invSize);
362
+ if (p.z === 0) p.z = zOrder(p.x, p.y, minX, minY, invSize);
378
363
  p.prevZ = p.prev;
379
364
  p.nextZ = p.next;
380
365
  p = p.next;
@@ -389,25 +374,26 @@ function indexCurve(start, minX, minY, invSize) {
389
374
  // Simon Tatham's linked list merge sort algorithm
390
375
  // http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html
391
376
  function sortLinked(list) {
392
- var i, p, q, e, tail, numMerges, pSize, qSize,
393
- inSize = 1;
377
+ let numMerges;
378
+ let inSize = 1;
394
379
 
395
380
  do {
396
- p = list;
381
+ let p = list;
382
+ let e;
397
383
  list = null;
398
- tail = null;
384
+ let tail = null;
399
385
  numMerges = 0;
400
386
 
401
387
  while (p) {
402
388
  numMerges++;
403
- q = p;
404
- pSize = 0;
405
- for (i = 0; i < inSize; i++) {
389
+ let q = p;
390
+ let pSize = 0;
391
+ for (let i = 0; i < inSize; i++) {
406
392
  pSize++;
407
393
  q = q.nextZ;
408
394
  if (!q) break;
409
395
  }
410
- qSize = inSize;
396
+ let qSize = inSize;
411
397
 
412
398
  while (pSize > 0 || (qSize > 0 && q)) {
413
399
 
@@ -442,8 +428,8 @@ function sortLinked(list) {
442
428
  // z-order of a point given coords and inverse of the longer side of data bbox
443
429
  function zOrder(x, y, minX, minY, invSize) {
444
430
  // coords are transformed into non-negative 15-bit integer range
445
- x = 32767 * (x - minX) * invSize;
446
- y = 32767 * (y - minY) * invSize;
431
+ x = (x - minX) * invSize | 0;
432
+ y = (y - minY) * invSize | 0;
447
433
 
448
434
  x = (x | (x << 8)) & 0x00FF00FF;
449
435
  x = (x | (x << 4)) & 0x0F0F0F0F;
@@ -460,7 +446,7 @@ function zOrder(x, y, minX, minY, invSize) {
460
446
 
461
447
  // find the leftmost node of a polygon ring
462
448
  function getLeftmost(start) {
463
- var p = start,
449
+ let p = start,
464
450
  leftmost = start;
465
451
  do {
466
452
  if (p.x < leftmost.x || (p.x === leftmost.x && p.y < leftmost.y)) leftmost = p;
@@ -472,9 +458,9 @@ function getLeftmost(start) {
472
458
 
473
459
  // check if a point lies within a convex triangle
474
460
  function pointInTriangle(ax, ay, bx, by, cx, cy, px, py) {
475
- return (cx - px) * (ay - py) - (ax - px) * (cy - py) >= 0 &&
476
- (ax - px) * (by - py) - (bx - px) * (ay - py) >= 0 &&
477
- (bx - px) * (cy - py) - (cx - px) * (by - py) >= 0;
461
+ return (cx - px) * (ay - py) >= (ax - px) * (cy - py) &&
462
+ (ax - px) * (by - py) >= (bx - px) * (ay - py) &&
463
+ (bx - px) * (cy - py) >= (cx - px) * (by - py);
478
464
  }
479
465
 
480
466
  // check if a diagonal between two polygon nodes is valid (lies in polygon interior)
@@ -497,10 +483,10 @@ function equals(p1, p2) {
497
483
 
498
484
  // check if two segments intersect
499
485
  function intersects(p1, q1, p2, q2) {
500
- var o1 = sign(area(p1, q1, p2));
501
- var o2 = sign(area(p1, q1, q2));
502
- var o3 = sign(area(p2, q2, p1));
503
- var o4 = sign(area(p2, q2, q1));
486
+ const o1 = sign(area(p1, q1, p2));
487
+ const o2 = sign(area(p1, q1, q2));
488
+ const o3 = sign(area(p2, q2, p1));
489
+ const o4 = sign(area(p2, q2, q1));
504
490
 
505
491
  if (o1 !== o2 && o3 !== o4) return true; // general case
506
492
 
@@ -523,7 +509,7 @@ function sign(num) {
523
509
 
524
510
  // check if a polygon diagonal intersects any polygon segments
525
511
  function intersectsPolygon(a, b) {
526
- var p = a;
512
+ let p = a;
527
513
  do {
528
514
  if (p.i !== a.i && p.next.i !== a.i && p.i !== b.i && p.next.i !== b.i &&
529
515
  intersects(p, p.next, a, b)) return true;
@@ -542,10 +528,10 @@ function locallyInside(a, b) {
542
528
 
543
529
  // check if the middle point of a polygon diagonal is inside the polygon
544
530
  function middleInside(a, b) {
545
- var p = a,
546
- inside = false,
547
- px = (a.x + b.x) / 2,
548
- py = (a.y + b.y) / 2;
531
+ let p = a;
532
+ let inside = false;
533
+ const px = (a.x + b.x) / 2;
534
+ const py = (a.y + b.y) / 2;
549
535
  do {
550
536
  if (((p.y > py) !== (p.next.y > py)) && p.next.y !== p.y &&
551
537
  (px < (p.next.x - p.x) * (py - p.y) / (p.next.y - p.y) + p.x))
@@ -559,8 +545,8 @@ function middleInside(a, b) {
559
545
  // link two polygon vertices with a bridge; if the vertices belong to the same ring, it splits polygon into two;
560
546
  // if one belongs to the outer ring and another to a hole, it merges it into a single ring
561
547
  function splitPolygon(a, b) {
562
- var a2 = new Node(a.i, a.x, a.y),
563
- b2 = new Node(b.i, b.x, b.y),
548
+ const a2 = createNode(a.i, a.x, a.y),
549
+ b2 = createNode(b.i, b.x, b.y),
564
550
  an = a.next,
565
551
  bp = b.prev;
566
552
 
@@ -581,7 +567,7 @@ function splitPolygon(a, b) {
581
567
 
582
568
  // create a node and optionally link it with previous one (in a circular doubly linked list)
583
569
  function insertNode(i, x, y, last) {
584
- var p = new Node(i, x, y);
570
+ const p = createNode(i, x, y);
585
571
 
586
572
  if (!last) {
587
573
  p.prev = p;
@@ -604,49 +590,39 @@ function removeNode(p) {
604
590
  if (p.nextZ) p.nextZ.prevZ = p.prevZ;
605
591
  }
606
592
 
607
- function Node(i, x, y) {
608
- // vertex index in coordinates array
609
- this.i = i;
610
-
611
- // vertex coordinates
612
- this.x = x;
613
- this.y = y;
614
-
615
- // previous and next vertex nodes in a polygon ring
616
- this.prev = null;
617
- this.next = null;
618
-
619
- // z-order curve value
620
- this.z = null;
621
-
622
- // previous and next nodes in z-order
623
- this.prevZ = null;
624
- this.nextZ = null;
625
-
626
- // indicates whether this is a steiner point
627
- this.steiner = false;
593
+ function createNode(i, x, y) {
594
+ return {
595
+ i, // vertex index in coordinates array
596
+ x, y, // vertex coordinates
597
+ prev: null, // previous and next vertex nodes in a polygon ring
598
+ next: null,
599
+ z: 0, // z-order curve value
600
+ prevZ: null, // previous and next nodes in z-order
601
+ nextZ: null,
602
+ steiner: false // indicates whether this is a steiner point
603
+ };
628
604
  }
629
605
 
630
606
  // return a percentage difference between the polygon area and its triangulation area;
631
607
  // used to verify correctness of triangulation
632
- earcut.deviation = function (data, holeIndices, dim, triangles) {
633
- var hasHoles = holeIndices && holeIndices.length;
634
- var outerLen = hasHoles ? holeIndices[0] * dim : data.length;
608
+ export function deviation(data, holeIndices, dim, triangles) {
609
+ const hasHoles = holeIndices && holeIndices.length;
610
+ const outerLen = hasHoles ? holeIndices[0] * dim : data.length;
635
611
 
636
- var polygonArea = Math.abs(signedArea(data, 0, outerLen, dim));
612
+ let polygonArea = Math.abs(signedArea(data, 0, outerLen, dim));
637
613
  if (hasHoles) {
638
- for (var i = 0, len = holeIndices.length; i < len; i++) {
639
- var start = holeIndices[i] * dim;
640
- var end = i < len - 1 ? holeIndices[i + 1] * dim : data.length;
614
+ for (let i = 0, len = holeIndices.length; i < len; i++) {
615
+ const start = holeIndices[i] * dim;
616
+ const end = i < len - 1 ? holeIndices[i + 1] * dim : data.length;
641
617
  polygonArea -= Math.abs(signedArea(data, start, end, dim));
642
618
  }
643
619
  }
644
620
 
645
- var trianglesArea = 0;
646
- for (i = 0; i < triangles.length; i += 3) {
647
- var a = triangles[i] * dim;
648
- var b = triangles[i + 1] * dim;
649
- var c = triangles[i + 2] * dim;
621
+ let trianglesArea = 0;
622
+ for (let i = 0; i < triangles.length; i += 3) {
623
+ const a = triangles[i] * dim;
624
+ const b = triangles[i + 1] * dim;
625
+ const c = triangles[i + 2] * dim;
650
626
  trianglesArea += Math.abs(
651
627
  (data[a] - data[c]) * (data[b + 1] - data[a + 1]) -
652
628
  (data[a] - data[b]) * (data[c + 1] - data[a + 1]));
@@ -654,11 +630,11 @@ earcut.deviation = function (data, holeIndices, dim, triangles) {
654
630
 
655
631
  return polygonArea === 0 && trianglesArea === 0 ? 0 :
656
632
  Math.abs((trianglesArea - polygonArea) / polygonArea);
657
- };
633
+ }
658
634
 
659
635
  function signedArea(data, start, end, dim) {
660
- var sum = 0;
661
- for (var i = start, j = end - dim; i < end; i += dim) {
636
+ let sum = 0;
637
+ for (let i = start, j = end - dim; i < end; i += dim) {
662
638
  sum += (data[j] - data[i]) * (data[i + 1] + data[j + 1]);
663
639
  j = i;
664
640
  }
@@ -666,19 +642,22 @@ function signedArea(data, start, end, dim) {
666
642
  }
667
643
 
668
644
  // turn a polygon in a multi-dimensional array form (e.g. as in GeoJSON) into a form Earcut accepts
669
- earcut.flatten = function (data) {
670
- var dim = data[0][0].length,
671
- result = {vertices: [], holes: [], dimensions: dim},
672
- holeIndex = 0;
673
-
674
- for (var i = 0; i < data.length; i++) {
675
- for (var j = 0; j < data[i].length; j++) {
676
- for (var d = 0; d < dim; d++) result.vertices.push(data[i][j][d]);
645
+ export function flatten(data) {
646
+ const vertices = [];
647
+ const holes = [];
648
+ const dimensions = data[0][0].length;
649
+ let holeIndex = 0;
650
+ let prevLen = 0;
651
+
652
+ for (const ring of data) {
653
+ for (const p of ring) {
654
+ for (let d = 0; d < dimensions; d++) vertices.push(p[d]);
677
655
  }
678
- if (i > 0) {
679
- holeIndex += data[i - 1].length;
680
- result.holes.push(holeIndex);
656
+ if (prevLen) {
657
+ holeIndex += prevLen;
658
+ holes.push(holeIndex);
681
659
  }
660
+ prevLen = ring.length;
682
661
  }
683
- return result;
684
- };
662
+ return {vertices, holes, dimensions};
663
+ }