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.
- package/dist/poly-extrude.js +4538 -4365
- package/dist/poly-extrude.js.map +1 -1
- package/dist/poly-extrude.min.js +2 -2
- package/dist/poly-extrude.mjs +347 -174
- package/dist/poly-extrude.mjs.map +1 -1
- package/dist/polyline.d.ts +18 -7
- package/dist/polyline.js +141 -21
- package/dist/polyline.js.map +1 -1
- package/package.json +1 -1
- package/readme.md +1 -0
- package/src/polyline.ts +168 -31
package/dist/poly-extrude.mjs
CHANGED
@@ -1,62 +1,29 @@
|
|
1
1
|
/*!
|
2
|
-
* poly-extrude v0.
|
2
|
+
* poly-extrude v0.20.0
|
3
3
|
*/
|
4
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
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 =
|
53
|
-
minY =
|
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
|
-
|
59
|
-
|
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 (
|
80
|
-
last = insertNode(i
|
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 (
|
84
|
-
last = insertNode(
|
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
|
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
|
-
|
128
|
-
|
97
|
+
prev = ear.prev;
|
98
|
+
next = ear.next;
|
129
99
|
|
130
100
|
if (invSize ? isEarHashed(ear, minX, minY, invSize) : isEar(ear)) {
|
131
|
-
|
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 =
|
174
|
-
y0 =
|
175
|
-
x1 =
|
176
|
-
y1 =
|
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 &&
|
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 =
|
201
|
-
y0 =
|
202
|
-
x1 =
|
203
|
-
y1 =
|
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 &&
|
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 &&
|
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 &&
|
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 &&
|
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
|
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
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
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(
|
273
|
+
queue.sort(compareX); // process holes from left to right
|
295
274
|
|
296
|
-
for (
|
297
|
-
outerNode = eliminateHole(queue[
|
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
|
304
|
-
|
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
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
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 (
|
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
|
-
|
365
|
-
|
366
|
-
|
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
|
-
|
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
|
410
|
-
|
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
|
-
|
414
|
-
var e = void 0;
|
385
|
+
p = list;
|
415
386
|
list = null;
|
416
|
-
|
387
|
+
tail = null;
|
417
388
|
numMerges = 0;
|
418
389
|
|
419
390
|
while (p) {
|
420
391
|
numMerges++;
|
421
|
-
|
422
|
-
|
392
|
+
q = p;
|
393
|
+
pSize = 0;
|
423
394
|
|
424
|
-
for (
|
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
|
-
|
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
|
-
|
564
|
-
|
565
|
-
|
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 =
|
579
|
-
b2 =
|
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 =
|
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
|
618
|
-
|
619
|
-
|
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(
|
2228
|
-
for (let i = 0, len =
|
2229
|
-
leftPoints[i].distance = rightPoints[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 =
|
2266
|
-
|
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
|
-
|
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 =
|
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
|
-
|
2532
|
+
let dy = p2[1] - p1[1], dx = p2[0] - p1[0];
|
2433
2533
|
let rAngle = 0;
|
2434
|
-
const rad = Math.
|
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
|
-
|
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 [
|
2456
|
-
let op1 = lineIntersection(
|
2457
|
-
let op2 = lineIntersection(
|
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
|
-
|
2474
|
-
|
2475
|
-
|
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
|
-
|
2479
|
-
|
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
|
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;
|