poly-extrude 0.18.1 → 0.20.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.
@@ -1,62 +1,29 @@
1
1
  /*!
2
- * poly-extrude v0.18.1
2
+ * poly-extrude v0.20.0
3
3
  */
4
- function _defineProperties(target, props) {
5
- for (var i = 0; i < props.length; i++) {
6
- var descriptor = props[i];
7
- descriptor.enumerable = descriptor.enumerable || false;
8
- descriptor.configurable = true;
9
- if ("value" in descriptor) descriptor.writable = true;
10
- Object.defineProperty(target, descriptor.key, descriptor);
11
- }
12
- }
4
+ var earcut$2 = {exports: {}};
13
5
 
14
- function _createClass(Constructor, protoProps, staticProps) {
15
- if (protoProps) _defineProperties(Constructor.prototype, protoProps);
16
- if (staticProps) _defineProperties(Constructor, staticProps);
17
- Object.defineProperty(Constructor, "prototype", {
18
- writable: false
19
- });
20
- return Constructor;
21
- }
6
+ earcut$2.exports = earcut;
22
7
 
23
- function _inheritsLoose(subClass, superClass) {
24
- subClass.prototype = Object.create(superClass.prototype);
25
- subClass.prototype.constructor = subClass;
26
-
27
- _setPrototypeOf(subClass, superClass);
28
- }
29
-
30
- function _setPrototypeOf(o, p) {
31
- _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function _setPrototypeOf(o, p) {
32
- o.__proto__ = p;
33
- return o;
34
- };
35
- return _setPrototypeOf(o, p);
36
- }
8
+ earcut$2.exports["default"] = earcut;
37
9
 
38
10
  function earcut(data, holeIndices, dim) {
39
- if (dim === void 0) {
40
- dim = 2;
41
- }
42
-
43
- var hasHoles = holeIndices && holeIndices.length;
44
- var outerLen = hasHoles ? holeIndices[0] * dim : data.length;
45
- var outerNode = linkedList(data, 0, outerLen, dim, true);
46
- var triangles = [];
11
+ dim = dim || 2;
12
+ var hasHoles = holeIndices && holeIndices.length,
13
+ outerLen = hasHoles ? holeIndices[0] * dim : data.length,
14
+ outerNode = linkedList(data, 0, outerLen, dim, true),
15
+ triangles = [];
47
16
  if (!outerNode || outerNode.next === outerNode.prev) return triangles;
48
- var minX, minY, invSize;
17
+ var minX, minY, maxX, maxY, x, y, invSize;
49
18
  if (hasHoles) outerNode = eliminateHoles(data, holeIndices, outerNode, dim); // if the shape is not too simple, we'll use z-order curve hash later; calculate polygon bbox
50
19
 
51
20
  if (data.length > 80 * dim) {
52
- minX = Infinity;
53
- minY = Infinity;
54
- var maxX = -Infinity;
55
- var maxY = -Infinity;
21
+ minX = maxX = data[0];
22
+ minY = maxY = data[1];
56
23
 
57
24
  for (var i = dim; i < outerLen; i += dim) {
58
- var x = data[i];
59
- var y = data[i + 1];
25
+ x = data[i];
26
+ y = data[i + 1];
60
27
  if (x < minX) minX = x;
61
28
  if (y < minY) minY = y;
62
29
  if (x > maxX) maxX = x;
@@ -72,16 +39,17 @@ function earcut(data, holeIndices, dim) {
72
39
  return triangles;
73
40
  } // create a circular doubly linked list from polygon points in the specified winding order
74
41
 
42
+
75
43
  function linkedList(data, start, end, dim, clockwise) {
76
- var last;
44
+ var i, last;
77
45
 
78
46
  if (clockwise === signedArea(data, start, end, dim) > 0) {
79
- for (var i = start; i < end; i += dim) {
80
- last = insertNode(i / dim | 0, data[i], data[i + 1], last);
47
+ for (i = start; i < end; i += dim) {
48
+ last = insertNode(i, data[i], data[i + 1], last);
81
49
  }
82
50
  } else {
83
- for (var _i = end - dim; _i >= start; _i -= dim) {
84
- last = insertNode(_i / dim | 0, data[_i], data[_i + 1], last);
51
+ for (i = end - dim; i >= start; i -= dim) {
52
+ last = insertNode(i, data[i], data[i + 1], last);
85
53
  }
86
54
  }
87
55
 
@@ -121,15 +89,19 @@ function earcutLinked(ear, triangles, dim, minX, minY, invSize, pass) {
121
89
  if (!ear) return; // interlink polygon nodes in z-order
122
90
 
123
91
  if (!pass && invSize) indexCurve(ear, minX, minY, invSize);
124
- var stop = ear; // iterate through ears, slicing them one by one
92
+ var stop = ear,
93
+ prev,
94
+ next; // iterate through ears, slicing them one by one
125
95
 
126
96
  while (ear.prev !== ear.next) {
127
- var prev = ear.prev;
128
- var next = ear.next;
97
+ prev = ear.prev;
98
+ next = ear.next;
129
99
 
130
100
  if (invSize ? isEarHashed(ear, minX, minY, invSize) : isEar(ear)) {
131
- triangles.push(prev.i, ear.i, next.i); // cut off the triangle
132
-
101
+ // cut off the triangle
102
+ triangles.push(prev.i / dim | 0);
103
+ triangles.push(ear.i / dim | 0);
104
+ triangles.push(next.i / dim | 0);
133
105
  removeNode(ear); // skipping the next vertex leads to less sliver triangles
134
106
 
135
107
  ear = next.next;
@@ -144,7 +116,7 @@ function earcutLinked(ear, triangles, dim, minX, minY, invSize, pass) {
144
116
  if (!pass) {
145
117
  earcutLinked(filterPoints(ear), triangles, dim, minX, minY, invSize, 1); // if this didn't work, try curing all small self-intersections locally
146
118
  } else if (pass === 1) {
147
- ear = cureLocalIntersections(filterPoints(ear), triangles);
119
+ ear = cureLocalIntersections(filterPoints(ear), triangles, dim);
148
120
  earcutLinked(ear, triangles, dim, minX, minY, invSize, 2); // as a last resort, try splitting the remaining polygon into two
149
121
  } else if (pass === 2) {
150
122
  splitEarcut(ear, triangles, dim, minX, minY, invSize);
@@ -168,16 +140,16 @@ function isEar(ear) {
168
140
  cx = c.x,
169
141
  ay = a.y,
170
142
  by = b.y,
171
- cy = c.y; // triangle bbox
143
+ cy = c.y; // triangle bbox; min & max are calculated like this for speed
172
144
 
173
- var x0 = Math.min(ax, bx, cx),
174
- y0 = Math.min(ay, by, cy),
175
- x1 = Math.max(ax, bx, cx),
176
- y1 = Math.max(ay, by, cy);
145
+ var x0 = ax < bx ? ax < cx ? ax : cx : bx < cx ? bx : cx,
146
+ y0 = ay < by ? ay < cy ? ay : cy : by < cy ? by : cy,
147
+ x1 = ax > bx ? ax > cx ? ax : cx : bx > cx ? bx : cx,
148
+ y1 = ay > by ? ay > cy ? ay : cy : by > cy ? by : cy;
177
149
  var p = c.next;
178
150
 
179
151
  while (p !== a) {
180
- if (p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 && pointInTriangleExceptFirst(ax, ay, bx, by, cx, cy, p.x, p.y) && area(p.prev, p, p.next) >= 0) return false;
152
+ if (p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 && pointInTriangle(ax, ay, bx, by, cx, cy, p.x, p.y) && area(p.prev, p, p.next) >= 0) return false;
181
153
  p = p.next;
182
154
  }
183
155
 
@@ -195,12 +167,12 @@ function isEarHashed(ear, minX, minY, invSize) {
195
167
  cx = c.x,
196
168
  ay = a.y,
197
169
  by = b.y,
198
- cy = c.y; // triangle bbox
170
+ cy = c.y; // triangle bbox; min & max are calculated like this for speed
199
171
 
200
- var x0 = Math.min(ax, bx, cx),
201
- y0 = Math.min(ay, by, cy),
202
- x1 = Math.max(ax, bx, cx),
203
- y1 = Math.max(ay, by, cy); // z-order range for the current triangle bbox;
172
+ var x0 = ax < bx ? ax < cx ? ax : cx : bx < cx ? bx : cx,
173
+ y0 = ay < by ? ay < cy ? ay : cy : by < cy ? by : cy,
174
+ x1 = ax > bx ? ax > cx ? ax : cx : bx > cx ? bx : cx,
175
+ y1 = ay > by ? ay > cy ? ay : cy : by > cy ? by : cy; // z-order range for the current triangle bbox;
204
176
 
205
177
  var minZ = zOrder(x0, y0, minX, minY, invSize),
206
178
  maxZ = zOrder(x1, y1, minX, minY, invSize);
@@ -208,21 +180,21 @@ function isEarHashed(ear, minX, minY, invSize) {
208
180
  n = ear.nextZ; // look for points inside the triangle in both directions
209
181
 
210
182
  while (p && p.z >= minZ && n && n.z <= maxZ) {
211
- if (p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 && p !== a && p !== c && pointInTriangleExceptFirst(ax, ay, bx, by, cx, cy, p.x, p.y) && area(p.prev, p, p.next) >= 0) return false;
183
+ if (p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 && p !== a && p !== c && pointInTriangle(ax, ay, bx, by, cx, cy, p.x, p.y) && area(p.prev, p, p.next) >= 0) return false;
212
184
  p = p.prevZ;
213
- if (n.x >= x0 && n.x <= x1 && n.y >= y0 && n.y <= y1 && n !== a && n !== c && pointInTriangleExceptFirst(ax, ay, bx, by, cx, cy, n.x, n.y) && area(n.prev, n, n.next) >= 0) return false;
185
+ if (n.x >= x0 && n.x <= x1 && n.y >= y0 && n.y <= y1 && n !== a && n !== c && pointInTriangle(ax, ay, bx, by, cx, cy, n.x, n.y) && area(n.prev, n, n.next) >= 0) return false;
214
186
  n = n.nextZ;
215
187
  } // look for remaining points in decreasing z-order
216
188
 
217
189
 
218
190
  while (p && p.z >= minZ) {
219
- if (p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 && p !== a && p !== c && pointInTriangleExceptFirst(ax, ay, bx, by, cx, cy, p.x, p.y) && area(p.prev, p, p.next) >= 0) return false;
191
+ if (p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 && p !== a && p !== c && pointInTriangle(ax, ay, bx, by, cx, cy, p.x, p.y) && area(p.prev, p, p.next) >= 0) return false;
220
192
  p = p.prevZ;
221
193
  } // look for remaining points in increasing z-order
222
194
 
223
195
 
224
196
  while (n && n.z <= maxZ) {
225
- if (n.x >= x0 && n.x <= x1 && n.y >= y0 && n.y <= y1 && n !== a && n !== c && pointInTriangleExceptFirst(ax, ay, bx, by, cx, cy, n.x, n.y) && area(n.prev, n, n.next) >= 0) return false;
197
+ if (n.x >= x0 && n.x <= x1 && n.y >= y0 && n.y <= y1 && n !== a && n !== c && pointInTriangle(ax, ay, bx, by, cx, cy, n.x, n.y) && area(n.prev, n, n.next) >= 0) return false;
226
198
  n = n.nextZ;
227
199
  }
228
200
 
@@ -230,7 +202,7 @@ function isEarHashed(ear, minX, minY, invSize) {
230
202
  } // go through all polygon nodes and cure small local self-intersections
231
203
 
232
204
 
233
- function cureLocalIntersections(start, triangles) {
205
+ function cureLocalIntersections(start, triangles, dim) {
234
206
  var p = start;
235
207
 
236
208
  do {
@@ -238,7 +210,9 @@ function cureLocalIntersections(start, triangles) {
238
210
  b = p.next.next;
239
211
 
240
212
  if (!equals(a, b) && intersects(a, p, p.next, b) && locallyInside(a, b) && locallyInside(b, a)) {
241
- triangles.push(a.i, p.i, b.i); // remove two nodes involved
213
+ triangles.push(a.i / dim | 0);
214
+ triangles.push(p.i / dim | 0);
215
+ triangles.push(b.i / dim | 0); // remove two nodes involved
242
216
 
243
217
  removeNode(p);
244
218
  removeNode(p.next);
@@ -281,40 +255,32 @@ function splitEarcut(start, triangles, dim, minX, minY, invSize) {
281
255
 
282
256
 
283
257
  function eliminateHoles(data, holeIndices, outerNode, dim) {
284
- var queue = [];
285
-
286
- for (var i = 0, len = holeIndices.length; i < len; i++) {
287
- var start = holeIndices[i] * dim;
288
- var end = i < len - 1 ? holeIndices[i + 1] * dim : data.length;
289
- var list = linkedList(data, start, end, dim, false);
258
+ var queue = [],
259
+ i,
260
+ len,
261
+ start,
262
+ end,
263
+ list;
264
+
265
+ for (i = 0, len = holeIndices.length; i < len; i++) {
266
+ start = holeIndices[i] * dim;
267
+ end = i < len - 1 ? holeIndices[i + 1] * dim : data.length;
268
+ list = linkedList(data, start, end, dim, false);
290
269
  if (list === list.next) list.steiner = true;
291
270
  queue.push(getLeftmost(list));
292
271
  }
293
272
 
294
- queue.sort(compareXYSlope); // process holes from left to right
273
+ queue.sort(compareX); // process holes from left to right
295
274
 
296
- for (var _i2 = 0; _i2 < queue.length; _i2++) {
297
- outerNode = eliminateHole(queue[_i2], outerNode);
275
+ for (i = 0; i < queue.length; i++) {
276
+ outerNode = eliminateHole(queue[i], outerNode);
298
277
  }
299
278
 
300
279
  return outerNode;
301
280
  }
302
281
 
303
- function compareXYSlope(a, b) {
304
- var result = a.x - b.x; // when the left-most point of 2 holes meet at a vertex, sort the holes counterclockwise so that when we find
305
- // the bridge to the outer shell is always the point that they meet at.
306
-
307
- if (result === 0) {
308
- result = a.y - b.y;
309
-
310
- if (result === 0) {
311
- var aSlope = (a.next.y - a.y) / (a.next.x - a.x);
312
- var bSlope = (b.next.y - b.y) / (b.next.x - b.x);
313
- result = aSlope - bSlope;
314
- }
315
- }
316
-
317
- return result;
282
+ function compareX(a, b) {
283
+ return a.x - b.x;
318
284
  } // find a bridge between vertices that connects hole with an outer ring and and link it
319
285
 
320
286
 
@@ -333,18 +299,15 @@ function eliminateHole(hole, outerNode) {
333
299
 
334
300
 
335
301
  function findHoleBridge(hole, outerNode) {
336
- var p = outerNode;
337
- var hx = hole.x;
338
- var hy = hole.y;
339
- var qx = -Infinity;
340
- var m; // find a segment intersected by a ray from the hole's leftmost point to the left;
302
+ var p = outerNode,
303
+ hx = hole.x,
304
+ hy = hole.y,
305
+ qx = -Infinity,
306
+ m; // find a segment intersected by a ray from the hole's leftmost point to the left;
341
307
  // segment's endpoint with lesser x will be potential connection point
342
- // unless they intersect at a vertex, then choose the vertex
343
-
344
- if (equals(hole, p)) return p;
345
308
 
346
309
  do {
347
- if (equals(hole, p.next)) return p.next;else if (hy <= p.y && hy >= p.next.y && p.next.y !== p.y) {
310
+ if (hy <= p.y && hy >= p.next.y && p.next.y !== p.y) {
348
311
  var x = p.x + (hy - p.y) * (p.next.x - p.x) / (p.next.y - p.y);
349
312
 
350
313
  if (x <= hx && x > qx) {
@@ -353,6 +316,7 @@ function findHoleBridge(hole, outerNode) {
353
316
  if (x === hx) return m; // hole touches outer segment; pick leftmost endpoint
354
317
  }
355
318
  }
319
+
356
320
  p = p.next;
357
321
  } while (p !== outerNode);
358
322
 
@@ -360,15 +324,16 @@ function findHoleBridge(hole, outerNode) {
360
324
  // if there are no points found, we have a valid connection;
361
325
  // otherwise choose the point of the minimum angle with the ray as connection point
362
326
 
363
- var stop = m;
364
- var mx = m.x;
365
- var my = m.y;
366
- var tanMin = Infinity;
327
+ var stop = m,
328
+ mx = m.x,
329
+ my = m.y,
330
+ tanMin = Infinity,
331
+ tan;
367
332
  p = m;
368
333
 
369
334
  do {
370
335
  if (hx >= p.x && p.x >= mx && hx !== p.x && pointInTriangle(hy < my ? hx : qx, hy, mx, my, hy < my ? qx : hx, hy, p.x, p.y)) {
371
- var tan = Math.abs(hy - p.y) / (hx - p.x); // tangential
336
+ tan = Math.abs(hy - p.y) / (hx - p.x); // tangential
372
337
 
373
338
  if (locallyInside(p, hole) && (tan < tanMin || tan === tanMin && (p.x > m.x || p.x === m.x && sectorContainsSector(m, p)))) {
374
339
  m = p;
@@ -406,28 +371,34 @@ function indexCurve(start, minX, minY, invSize) {
406
371
 
407
372
 
408
373
  function sortLinked(list) {
409
- var numMerges;
410
- var inSize = 1;
374
+ var i,
375
+ p,
376
+ q,
377
+ e,
378
+ tail,
379
+ numMerges,
380
+ pSize,
381
+ qSize,
382
+ inSize = 1;
411
383
 
412
384
  do {
413
- var p = list;
414
- var e = void 0;
385
+ p = list;
415
386
  list = null;
416
- var tail = null;
387
+ tail = null;
417
388
  numMerges = 0;
418
389
 
419
390
  while (p) {
420
391
  numMerges++;
421
- var q = p;
422
- var pSize = 0;
392
+ q = p;
393
+ pSize = 0;
423
394
 
424
- for (var i = 0; i < inSize; i++) {
395
+ for (i = 0; i < inSize; i++) {
425
396
  pSize++;
426
397
  q = q.nextZ;
427
398
  if (!q) break;
428
399
  }
429
400
 
430
- var qSize = inSize;
401
+ qSize = inSize;
431
402
 
432
403
  while (pSize > 0 || qSize > 0 && q) {
433
404
  if (pSize !== 0 && (qSize === 0 || !q || p.z <= q.z)) {
@@ -487,11 +458,6 @@ function getLeftmost(start) {
487
458
 
488
459
  function pointInTriangle(ax, ay, bx, by, cx, cy, px, py) {
489
460
  return (cx - px) * (ay - py) >= (ax - px) * (cy - py) && (ax - px) * (by - py) >= (bx - px) * (ay - py) && (bx - px) * (cy - py) >= (cx - px) * (by - py);
490
- } // check if a point lies within a convex triangle but false if its equal to the first point of the triangle
491
-
492
-
493
- function pointInTriangleExceptFirst(ax, ay, bx, by, cx, cy, px, py) {
494
- return !(ax === px && ay === py) && pointInTriangle(ax, ay, bx, by, cx, cy, px, py);
495
461
  } // check if a diagonal between two polygon nodes is valid (lies in polygon interior)
496
462
 
497
463
 
@@ -559,10 +525,10 @@ function locallyInside(a, b) {
559
525
 
560
526
 
561
527
  function middleInside(a, b) {
562
- var p = a;
563
- var inside = false;
564
- var px = (a.x + b.x) / 2;
565
- var py = (a.y + b.y) / 2;
528
+ var p = a,
529
+ inside = false,
530
+ px = (a.x + b.x) / 2,
531
+ py = (a.y + b.y) / 2;
566
532
 
567
533
  do {
568
534
  if (p.y > py !== p.next.y > py && p.next.y !== p.y && px < (p.next.x - p.x) * (py - p.y) / (p.next.y - p.y) + p.x) inside = !inside;
@@ -575,8 +541,8 @@ function middleInside(a, b) {
575
541
 
576
542
 
577
543
  function splitPolygon(a, b) {
578
- var a2 = createNode(a.i, a.x, a.y),
579
- b2 = createNode(b.i, b.x, b.y),
544
+ var a2 = new Node(a.i, a.x, a.y),
545
+ b2 = new Node(b.i, b.x, b.y),
580
546
  an = a.next,
581
547
  bp = b.prev;
582
548
  a.next = b;
@@ -592,7 +558,7 @@ function splitPolygon(a, b) {
592
558
 
593
559
 
594
560
  function insertNode(i, x, y, last) {
595
- var p = createNode(i, x, y);
561
+ var p = new Node(i, x, y);
596
562
 
597
563
  if (!last) {
598
564
  p.prev = p;
@@ -614,25 +580,50 @@ function removeNode(p) {
614
580
  if (p.nextZ) p.nextZ.prevZ = p.prevZ;
615
581
  }
616
582
 
617
- function createNode(i, x, y) {
618
- return {
619
- i: i,
620
- // vertex index in coordinates array
621
- x: x,
622
- y: y,
623
- // vertex coordinates
624
- prev: null,
625
- // previous and next vertex nodes in a polygon ring
626
- next: null,
627
- z: 0,
628
- // z-order curve value
629
- prevZ: null,
630
- // previous and next nodes in z-order
631
- nextZ: null,
632
- steiner: false // indicates whether this is a steiner point
583
+ function Node(i, x, y) {
584
+ // vertex index in coordinates array
585
+ this.i = i; // vertex coordinates
633
586
 
634
- };
587
+ this.x = x;
588
+ this.y = y; // previous and next vertex nodes in a polygon ring
589
+
590
+ this.prev = null;
591
+ this.next = null; // z-order curve value
592
+
593
+ this.z = 0; // previous and next nodes in z-order
594
+
595
+ this.prevZ = null;
596
+ this.nextZ = null; // indicates whether this is a steiner point
597
+
598
+ this.steiner = false;
635
599
  } // return a percentage difference between the polygon area and its triangulation area;
600
+ // used to verify correctness of triangulation
601
+
602
+
603
+ earcut.deviation = function (data, holeIndices, dim, triangles) {
604
+ var hasHoles = holeIndices && holeIndices.length;
605
+ var outerLen = hasHoles ? holeIndices[0] * dim : data.length;
606
+ var polygonArea = Math.abs(signedArea(data, 0, outerLen, dim));
607
+
608
+ if (hasHoles) {
609
+ for (var i = 0, len = holeIndices.length; i < len; i++) {
610
+ var start = holeIndices[i] * dim;
611
+ var end = i < len - 1 ? holeIndices[i + 1] * dim : data.length;
612
+ polygonArea -= Math.abs(signedArea(data, start, end, dim));
613
+ }
614
+ }
615
+
616
+ var trianglesArea = 0;
617
+
618
+ for (i = 0; i < triangles.length; i += 3) {
619
+ var a = triangles[i] * dim;
620
+ var b = triangles[i + 1] * dim;
621
+ var c = triangles[i + 2] * dim;
622
+ trianglesArea += Math.abs((data[a] - data[c]) * (data[b + 1] - data[a + 1]) - (data[a] - data[b]) * (data[c + 1] - data[a + 1]));
623
+ }
624
+
625
+ return polygonArea === 0 && trianglesArea === 0 ? 0 : Math.abs((trianglesArea - polygonArea) / polygonArea);
626
+ };
636
627
 
637
628
  function signedArea(data, start, end, dim) {
638
629
  var sum = 0;
@@ -645,6 +636,68 @@ function signedArea(data, start, end, dim) {
645
636
  return sum;
646
637
  } // turn a polygon in a multi-dimensional array form (e.g. as in GeoJSON) into a form Earcut accepts
647
638
 
639
+
640
+ earcut.flatten = function (data) {
641
+ var dim = data[0][0].length,
642
+ result = {
643
+ vertices: [],
644
+ holes: [],
645
+ dimensions: dim
646
+ },
647
+ holeIndex = 0;
648
+
649
+ for (var i = 0; i < data.length; i++) {
650
+ for (var j = 0; j < data[i].length; j++) {
651
+ for (var d = 0; d < dim; d++) {
652
+ result.vertices.push(data[i][j][d]);
653
+ }
654
+ }
655
+
656
+ if (i > 0) {
657
+ holeIndex += data[i - 1].length;
658
+ result.holes.push(holeIndex);
659
+ }
660
+ }
661
+
662
+ return result;
663
+ };
664
+
665
+ var earcut$1 = earcut$2.exports;
666
+
667
+ function _defineProperties(target, props) {
668
+ for (var i = 0; i < props.length; i++) {
669
+ var descriptor = props[i];
670
+ descriptor.enumerable = descriptor.enumerable || false;
671
+ descriptor.configurable = true;
672
+ if ("value" in descriptor) descriptor.writable = true;
673
+ Object.defineProperty(target, descriptor.key, descriptor);
674
+ }
675
+ }
676
+
677
+ function _createClass(Constructor, protoProps, staticProps) {
678
+ if (protoProps) _defineProperties(Constructor.prototype, protoProps);
679
+ if (staticProps) _defineProperties(Constructor, staticProps);
680
+ Object.defineProperty(Constructor, "prototype", {
681
+ writable: false
682
+ });
683
+ return Constructor;
684
+ }
685
+
686
+ function _inheritsLoose(subClass, superClass) {
687
+ subClass.prototype = Object.create(superClass.prototype);
688
+ subClass.prototype.constructor = subClass;
689
+
690
+ _setPrototypeOf(subClass, superClass);
691
+ }
692
+
693
+ function _setPrototypeOf(o, p) {
694
+ _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function _setPrototypeOf(o, p) {
695
+ o.__proto__ = p;
696
+ return o;
697
+ };
698
+ return _setPrototypeOf(o, p);
699
+ }
700
+
648
701
  // code copy from https://github.com/mrdoob/three.js/blob/dev/src/math/Quaternion.js
649
702
  // import { clamp } from './MathUtils.js';
650
703
  var Quaternion = /*#__PURE__*/function () {
@@ -1980,7 +2033,7 @@ function extrudePolygons(polygons, opts) {
1980
2033
  validatePolygon(polygon, true);
1981
2034
  const result = flatVertices(polygon, options);
1982
2035
  result.polygon = polygon;
1983
- const triangles = earcut(result.flatVertices, result.holes, 2);
2036
+ const triangles = earcut$1(result.flatVertices, result.holes, 2);
1984
2037
  generateTopAndBottom$1(result, triangles, options);
1985
2038
  generateSides$1(result, options);
1986
2039
  result.position = new Float32Array(result.points);
@@ -2126,7 +2179,7 @@ function simplePolygon(polygon, options = {}) {
2126
2179
  uv[++uvIndex] = c[1];
2127
2180
  }
2128
2181
  }
2129
- const triangles = earcut(flatVertices, holes, 2);
2182
+ const triangles = earcut$1(flatVertices, holes, 2);
2130
2183
  const normal = generateNormal(triangles, points);
2131
2184
  return {
2132
2185
  normal,
@@ -2223,10 +2276,15 @@ function generateTopAndBottom(result, options) {
2223
2276
  const { leftPoints, rightPoints } = result;
2224
2277
  const line = result.line;
2225
2278
  const pathUV = options.pathUV;
2279
+ let uvCalPath = line;
2280
+ // let needCalUV = false;
2281
+ if (leftPoints.length > uvCalPath.length) {
2282
+ uvCalPath = leftPoints;
2283
+ }
2226
2284
  if (pathUV) {
2227
- calLineDistance(line);
2228
- for (let i = 0, len = line.length; i < len; i++) {
2229
- leftPoints[i].distance = rightPoints[i].distance = line[i].distance;
2285
+ calLineDistance(uvCalPath);
2286
+ for (let i = 0, len = uvCalPath.length; i < len; i++) {
2287
+ leftPoints[i].distance = rightPoints[i].distance = uvCalPath[i].distance;
2230
2288
  }
2231
2289
  }
2232
2290
  let i = 0, len = leftPoints.length;
@@ -2238,12 +2296,14 @@ function generateTopAndBottom(result, options) {
2238
2296
  points[idx0] = x1;
2239
2297
  points[idx0 + 1] = y1;
2240
2298
  points[idx0 + 2] = lz + z1;
2299
+ // const p1 = leftPoints[i];
2241
2300
  // top right
2242
2301
  const [x2, y2, z2] = rightPoints[i];
2243
2302
  const idx1 = len * 3 + idx0;
2244
2303
  points[idx1] = x2;
2245
2304
  points[idx1 + 1] = y2;
2246
2305
  points[idx1 + 2] = rz + z2;
2306
+ // const p2 = rightPoints[i];
2247
2307
  // bottom left
2248
2308
  const idx2 = (len * 2) * 3 + idx0;
2249
2309
  points[idx2] = x1;
@@ -2262,8 +2322,8 @@ function generateTopAndBottom(result, options) {
2262
2322
  }
2263
2323
  // generate path uv
2264
2324
  if (pathUV) {
2265
- const p = line[i];
2266
- const uvx = p.distance;
2325
+ const p = uvCalPath[i];
2326
+ let uvx = p.distance;
2267
2327
  const uIndex0 = i * 2;
2268
2328
  uv[uIndex0] = uvx;
2269
2329
  uv[uIndex0 + 1] = 1;
@@ -2413,38 +2473,94 @@ function generateSides(result, options) {
2413
2473
  }
2414
2474
  const TEMPV1 = { x: 0, y: 0 }, TEMPV2 = { x: 0, y: 0 };
2415
2475
  function expandLine(line, options) {
2416
- // let preAngle = 0;
2476
+ options = Object.assign({}, { lineWidth: 1, cutCorner: false }, options);
2417
2477
  let radius = options.lineWidth / 2;
2418
2478
  if (options.isSlope) {
2419
2479
  radius *= 2;
2420
2480
  }
2481
+ const { cutCorner } = options;
2421
2482
  const points = [], leftPoints = [], rightPoints = [];
2422
2483
  const len = line.length;
2484
+ const repeatVertex = () => {
2485
+ const len1 = leftPoints.length;
2486
+ if (len1) {
2487
+ leftPoints.push(leftPoints[len1 - 1]);
2488
+ rightPoints.push(rightPoints[len1 - 1]);
2489
+ const len2 = points.length;
2490
+ points.push(points[len2 - 2], points[len2 - 1]);
2491
+ }
2492
+ };
2493
+ const equal = (p1, p2) => {
2494
+ return p1[0] === p2[0] && p1[1] === p2[1];
2495
+ };
2423
2496
  let i = 0;
2497
+ let preleftline, prerightline;
2424
2498
  while (i < len) {
2499
+ let p0;
2425
2500
  let p1 = line[i], p2 = line[i + 1];
2426
- const currentp = line[i];
2501
+ const currentp = p1;
2427
2502
  // last vertex
2428
2503
  if (i === len - 1) {
2429
2504
  p1 = line[len - 2];
2430
2505
  p2 = line[len - 1];
2506
+ if (equal(p1, p2)) {
2507
+ for (let j = line.indexOf(p1); j >= 0; j--) {
2508
+ const p = line[j];
2509
+ if (!equal(p, currentp)) {
2510
+ p1 = p;
2511
+ break;
2512
+ }
2513
+ }
2514
+ }
2515
+ }
2516
+ else {
2517
+ if (equal(p1, p2)) {
2518
+ for (let j = line.indexOf(p2); j < len; j++) {
2519
+ const p = line[j];
2520
+ if (!equal(p, currentp)) {
2521
+ p2 = p;
2522
+ break;
2523
+ }
2524
+ }
2525
+ }
2526
+ }
2527
+ if (equal(p1, p2)) {
2528
+ repeatVertex();
2529
+ i++;
2530
+ continue;
2431
2531
  }
2432
- const dy = p2[1] - p1[1], dx = p2[0] - p1[0];
2532
+ let dy = p2[1] - p1[1], dx = p2[0] - p1[0];
2433
2533
  let rAngle = 0;
2434
- const rad = Math.atan(dy / dx);
2534
+ const rad = Math.atan2(dy, dx);
2435
2535
  const angle = radToDeg(rad);
2436
- // preAngle = angle;
2437
2536
  if (i === 0 || i === len - 1) {
2438
2537
  rAngle = angle;
2439
2538
  rAngle -= 90;
2440
2539
  }
2441
2540
  else {
2442
2541
  // 至少3个顶点才会触发
2443
- const p0 = line[i - 1];
2542
+ p0 = line[i - 1];
2543
+ if (equal(p0, p2) || equal(p0, p1)) {
2544
+ for (let j = line.indexOf(p2); j >= 0; j--) {
2545
+ const p = line[j];
2546
+ if (!equal(p, p2) && (!equal(p, p1))) {
2547
+ p0 = p;
2548
+ break;
2549
+ }
2550
+ }
2551
+ }
2552
+ if (equal(p0, p2) || equal(p0, p1) || equal(p1, p2)) {
2553
+ repeatVertex();
2554
+ i++;
2555
+ continue;
2556
+ }
2444
2557
  TEMPV1.x = p0[0] - p1[0];
2445
2558
  TEMPV1.y = p0[1] - p1[1];
2446
2559
  TEMPV2.x = p2[0] - p1[0];
2447
2560
  TEMPV2.y = p2[1] - p1[1];
2561
+ if ((TEMPV1.x === 0 && TEMPV1.y === 0) || (TEMPV2.x === 0 && TEMPV2.y === 0)) {
2562
+ console.error('has repeat vertex,the index:', i);
2563
+ }
2448
2564
  const vAngle = getAngle$1(TEMPV1, TEMPV2);
2449
2565
  rAngle = angle - vAngle / 2;
2450
2566
  }
@@ -2452,15 +2568,16 @@ function expandLine(line, options) {
2452
2568
  const p3 = currentp;
2453
2569
  const x = Math.cos(rRad) + p3[0], y = Math.sin(rRad) + p3[1];
2454
2570
  const p4 = [x, y];
2455
- const [line1, line2] = translateLine(p1, p2, radius);
2456
- let op1 = lineIntersection(line1[0], line1[1], p3, p4);
2457
- let op2 = lineIntersection(line2[0], line2[1], p3, p4);
2571
+ const [leftline, rightline] = translateLine(p1, p2, radius);
2572
+ let op1 = lineIntersection(leftline[0], leftline[1], p3, p4);
2573
+ let op2 = lineIntersection(rightline[0], rightline[1], p3, p4);
2458
2574
  // 平行,回头路
2459
2575
  if (!op1 || !op2) {
2460
2576
  const len1 = points.length;
2461
2577
  const point1 = points[len1 - 2];
2462
2578
  const point2 = points[len1 - 1];
2463
2579
  if (!point1 || !point2) {
2580
+ i++;
2464
2581
  continue;
2465
2582
  }
2466
2583
  op1 = [point1[0], point1[1]];
@@ -2470,14 +2587,60 @@ function expandLine(line, options) {
2470
2587
  op2[2] = currentp[2] || 0;
2471
2588
  // const [op1, op2] = calOffsetPoint(rRad, radius, p1);
2472
2589
  points.push(op1, op2);
2473
- if (leftOnLine(op1, p1, p2)) {
2474
- leftPoints.push(op1);
2475
- rightPoints.push(op2);
2590
+ let needCut = false;
2591
+ if (cutCorner) {
2592
+ const bufferRadius = radius * 2;
2593
+ if (distance(currentp, op1) > bufferRadius || distance(currentp, op2) > bufferRadius) {
2594
+ needCut = true;
2595
+ }
2596
+ }
2597
+ if (needCut && p0 && preleftline && prerightline) {
2598
+ let cutPoint = op1;
2599
+ if (distance(op1, p0) < distance(op2, p0)) {
2600
+ cutPoint = op2;
2601
+ }
2602
+ const dy = cutPoint[1] - currentp[1], dx = cutPoint[0] - currentp[0];
2603
+ const cutAngle = Math.atan2(dy, dx) / Math.PI * 180;
2604
+ const cutRad = degToRad(cutAngle);
2605
+ const x1 = Math.cos(cutRad) * radius + currentp[0];
2606
+ const y1 = Math.sin(cutRad) * radius + currentp[1];
2607
+ const v1 = [x1, y1];
2608
+ const hcutangle = cutAngle + 90;
2609
+ // console.log(i, cutAngle, hcutangle);
2610
+ const hcutRad = degToRad(hcutangle);
2611
+ const x2 = Math.cos(hcutRad) + x1;
2612
+ const y2 = Math.sin(hcutRad) + y1;
2613
+ const v2 = [x2, y2];
2614
+ let preline = preleftline;
2615
+ let currentLine = leftline;
2616
+ let appendArray = leftPoints;
2617
+ let repeatArray = rightPoints;
2618
+ if (!leftOnLine(cutPoint, p1, p2)) {
2619
+ preline = prerightline;
2620
+ currentLine = rightline;
2621
+ appendArray = rightPoints;
2622
+ repeatArray = leftPoints;
2623
+ }
2624
+ let cross1 = lineIntersection(preline[0], preline[1], v1, v2);
2625
+ let cross2 = lineIntersection(currentLine[0], currentLine[1], v1, v2);
2626
+ cross1[2] = currentp[2] || 0;
2627
+ cross2[2] = currentp[2] || 0;
2628
+ const repeatPoint = cutPoint === op1 ? op2 : op1;
2629
+ appendArray.push(cross1, cross2);
2630
+ repeatArray.push(repeatPoint, [...repeatPoint]);
2476
2631
  }
2477
2632
  else {
2478
- leftPoints.push(op2);
2479
- rightPoints.push(op1);
2633
+ if (leftOnLine(op1, p1, p2)) {
2634
+ leftPoints.push(op1);
2635
+ rightPoints.push(op2);
2636
+ }
2637
+ else {
2638
+ leftPoints.push(op2);
2639
+ rightPoints.push(op1);
2640
+ }
2480
2641
  }
2642
+ preleftline = leftline;
2643
+ prerightline = rightline;
2481
2644
  i++;
2482
2645
  }
2483
2646
  return { offsetPoints: points, leftPoints, rightPoints, line };
@@ -2486,8 +2649,13 @@ const getAngle$1 = ({ x: x1, y: y1 }, { x: x2, y: y2 }) => {
2486
2649
  const dot = x1 * x2 + y1 * y2;
2487
2650
  const det = x1 * y2 - y1 * x2;
2488
2651
  const angle = Math.atan2(det, dot) / Math.PI * 180;
2489
- return (angle + 360) % 360;
2652
+ return (angle);
2653
+ // return (angle + 360) % 360;
2490
2654
  };
2655
+ function distance(p1, p2) {
2656
+ const dx = p2[0] - p1[0], dy = p2[1] - p1[1];
2657
+ return Math.sqrt(dx * dx + dy * dy);
2658
+ }
2491
2659
  function leftOnLine(p, p1, p2) {
2492
2660
  const [x1, y1] = p1;
2493
2661
  const [x2, y2] = p2;
@@ -2503,6 +2671,9 @@ function leftOnLine(p, p1, p2) {
2503
2671
  */
2504
2672
  function translateLine(p1, p2, distance) {
2505
2673
  const dy = p2[1] - p1[1], dx = p2[0] - p1[0];
2674
+ if (dy === 0 && dx === 0) {
2675
+ return null;
2676
+ }
2506
2677
  const rad = Math.atan2(dy, dx);
2507
2678
  const rad1 = rad + Math.PI / 2;
2508
2679
  let offsetX = Math.cos(rad1) * distance, offsetY = Math.sin(rad1) * distance;
@@ -2526,9 +2697,11 @@ function translateLine(p1, p2, distance) {
2526
2697
  function lineIntersection(p1, p2, p3, p4) {
2527
2698
  const dx1 = p2[0] - p1[0], dy1 = p2[1] - p1[1];
2528
2699
  const dx2 = p4[0] - p3[0], dy2 = p4[1] - p3[1];
2700
+ //vertical
2529
2701
  if (dx1 === 0 && dx2 === 0) {
2530
2702
  return null;
2531
2703
  }
2704
+ //horizontal
2532
2705
  if (dy1 === 0 && dy2 === 0) {
2533
2706
  return null;
2534
2707
  }
@@ -4657,7 +4830,7 @@ function generateStartAndEnd(result, polygon, options) {
4657
4830
  flatVertices[++pIndex] = c[1];
4658
4831
  }
4659
4832
  }
4660
- const triangles = earcut(flatVertices, holes, 2);
4833
+ const triangles = earcut$1(flatVertices, holes, 2);
4661
4834
  const { points, normal, uv, indices, startPoints, endPoints, polygonLen } = result;
4662
4835
  pIndex = 0;
4663
4836
  let uIndex = 0;