poly-extrude 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. package/.eslintignore +12 -0
  2. package/.eslintrc.js +34 -0
  3. package/.vscode/settings.json +3 -0
  4. package/LICENSE +21 -0
  5. package/babel.config.js +12 -0
  6. package/dist/poly-extrude.js +1317 -0
  7. package/dist/poly-extrude.js.map +1 -0
  8. package/dist/poly-extrude.min.js +4 -0
  9. package/dist/poly-extrude.mjs +1305 -0
  10. package/index.js +3 -0
  11. package/package.json +42 -0
  12. package/pnpm-lock.yaml +3054 -0
  13. package/rollup.config.js +108 -0
  14. package/src/polygon.js +148 -0
  15. package/src/polyline.js +190 -0
  16. package/src/util.js +205 -0
  17. package/test/buildings.html +77 -0
  18. package/test/data/a.png +0 -0
  19. package/test/data/building-texture-dark.jpg +0 -0
  20. package/test/data/building.geojson +1118 -0
  21. package/test/data/buildings-ny.geojson +2845 -0
  22. package/test/data/buildings.geojson +1 -0
  23. package/test/data/free-line.geojson +1 -0
  24. package/test/data/line.geojson +1 -0
  25. package/test/data/polygon.geojson +1 -0
  26. package/test/data/simple-hole.geojson +1 -0
  27. package/test/data/simple-line.geojson +45 -0
  28. package/test/data/simple.geojson +1 -0
  29. package/test/data/street.geojson +1 -0
  30. package/test/data//345/244/252/346/271/226.geojson +8 -0
  31. package/test/data//350/210/237/345/261/261/345/270/202.geojson +1 -0
  32. package/test/data//350/213/217/345/267/236.geojson +1 -0
  33. package/test/data//351/204/261/351/230/263/346/271/226.geojson +1 -0
  34. package/test/line-draw.html +100 -0
  35. package/test/line-uv.html +69 -0
  36. package/test/line.html +56 -0
  37. package/test/multi-polygon.html +53 -0
  38. package/test/ny-building.html +67 -0
  39. package/test/simple.html +61 -0
  40. package/test/street.html +52 -0
  41. package/test/util.js +131 -0
  42. package/test/uv.html +77 -0
@@ -0,0 +1,1305 @@
1
+ /*!
2
+ * poly-extrude v0.0.1
3
+ */
4
+ var earcut$2 = {exports: {}};
5
+
6
+ earcut$2.exports = earcut;
7
+
8
+ earcut$2.exports["default"] = earcut;
9
+
10
+ function earcut(data, holeIndices, dim) {
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 = [];
16
+ if (!outerNode || outerNode.next === outerNode.prev) return triangles;
17
+ var minX, minY, maxX, maxY, x, y, invSize;
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
19
+
20
+ if (data.length > 80 * dim) {
21
+ minX = maxX = data[0];
22
+ minY = maxY = data[1];
23
+
24
+ for (var i = dim; i < outerLen; i += dim) {
25
+ x = data[i];
26
+ y = data[i + 1];
27
+ if (x < minX) minX = x;
28
+ if (y < minY) minY = y;
29
+ if (x > maxX) maxX = x;
30
+ if (y > maxY) maxY = y;
31
+ } // minX, minY and invSize are later used to transform coords into integers for z-order calculation
32
+
33
+
34
+ invSize = Math.max(maxX - minX, maxY - minY);
35
+ invSize = invSize !== 0 ? 1 / invSize : 0;
36
+ }
37
+
38
+ earcutLinked(outerNode, triangles, dim, minX, minY, invSize);
39
+ return triangles;
40
+ } // create a circular doubly linked list from polygon points in the specified winding order
41
+
42
+
43
+ function linkedList(data, start, end, dim, clockwise) {
44
+ var i, last;
45
+
46
+ if (clockwise === signedArea(data, start, end, dim) > 0) {
47
+ for (i = start; i < end; i += dim) {
48
+ last = insertNode(i, data[i], data[i + 1], last);
49
+ }
50
+ } else {
51
+ for (i = end - dim; i >= start; i -= dim) {
52
+ last = insertNode(i, data[i], data[i + 1], last);
53
+ }
54
+ }
55
+
56
+ if (last && equals(last, last.next)) {
57
+ removeNode(last);
58
+ last = last.next;
59
+ }
60
+
61
+ return last;
62
+ } // eliminate colinear or duplicate points
63
+
64
+
65
+ function filterPoints(start, end) {
66
+ if (!start) return start;
67
+ if (!end) end = start;
68
+ var p = start,
69
+ again;
70
+
71
+ do {
72
+ again = false;
73
+
74
+ if (!p.steiner && (equals(p, p.next) || area(p.prev, p, p.next) === 0)) {
75
+ removeNode(p);
76
+ p = end = p.prev;
77
+ if (p === p.next) break;
78
+ again = true;
79
+ } else {
80
+ p = p.next;
81
+ }
82
+ } while (again || p !== end);
83
+
84
+ return end;
85
+ } // main ear slicing loop which triangulates a polygon (given as a linked list)
86
+
87
+
88
+ function earcutLinked(ear, triangles, dim, minX, minY, invSize, pass) {
89
+ if (!ear) return; // interlink polygon nodes in z-order
90
+
91
+ if (!pass && invSize) indexCurve(ear, minX, minY, invSize);
92
+ var stop = ear,
93
+ prev,
94
+ next; // iterate through ears, slicing them one by one
95
+
96
+ while (ear.prev !== ear.next) {
97
+ prev = ear.prev;
98
+ next = ear.next;
99
+
100
+ if (invSize ? isEarHashed(ear, minX, minY, invSize) : isEar(ear)) {
101
+ // cut off the triangle
102
+ triangles.push(prev.i / dim);
103
+ triangles.push(ear.i / dim);
104
+ triangles.push(next.i / dim);
105
+ removeNode(ear); // skipping the next vertex leads to less sliver triangles
106
+
107
+ ear = next.next;
108
+ stop = next.next;
109
+ continue;
110
+ }
111
+
112
+ ear = next; // if we looped through the whole remaining polygon and can't find any more ears
113
+
114
+ if (ear === stop) {
115
+ // try filtering points and slicing again
116
+ if (!pass) {
117
+ earcutLinked(filterPoints(ear), triangles, dim, minX, minY, invSize, 1); // if this didn't work, try curing all small self-intersections locally
118
+ } else if (pass === 1) {
119
+ ear = cureLocalIntersections(filterPoints(ear), triangles, dim);
120
+ earcutLinked(ear, triangles, dim, minX, minY, invSize, 2); // as a last resort, try splitting the remaining polygon into two
121
+ } else if (pass === 2) {
122
+ splitEarcut(ear, triangles, dim, minX, minY, invSize);
123
+ }
124
+
125
+ break;
126
+ }
127
+ }
128
+ } // check whether a polygon node forms a valid ear with adjacent nodes
129
+
130
+
131
+ function isEar(ear) {
132
+ var a = ear.prev,
133
+ b = ear,
134
+ c = ear.next;
135
+ if (area(a, b, c) >= 0) return false; // reflex, can't be an ear
136
+ // now make sure we don't have other points inside the potential ear
137
+
138
+ var p = ear.next.next;
139
+
140
+ while (p !== ear.prev) {
141
+ if (pointInTriangle(a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y) && area(p.prev, p, p.next) >= 0) return false;
142
+ p = p.next;
143
+ }
144
+
145
+ return true;
146
+ }
147
+
148
+ function isEarHashed(ear, minX, minY, invSize) {
149
+ var a = ear.prev,
150
+ b = ear,
151
+ c = ear.next;
152
+ if (area(a, b, c) >= 0) return false; // reflex, can't be an ear
153
+ // triangle bbox; min & max are calculated like this for speed
154
+
155
+ var minTX = a.x < b.x ? a.x < c.x ? a.x : c.x : b.x < c.x ? b.x : c.x,
156
+ minTY = a.y < b.y ? a.y < c.y ? a.y : c.y : b.y < c.y ? b.y : c.y,
157
+ maxTX = a.x > b.x ? a.x > c.x ? a.x : c.x : b.x > c.x ? b.x : c.x,
158
+ maxTY = a.y > b.y ? a.y > c.y ? a.y : c.y : b.y > c.y ? b.y : c.y; // z-order range for the current triangle bbox;
159
+
160
+ var minZ = zOrder(minTX, minTY, minX, minY, invSize),
161
+ maxZ = zOrder(maxTX, maxTY, minX, minY, invSize);
162
+ var p = ear.prevZ,
163
+ n = ear.nextZ; // look for points inside the triangle in both directions
164
+
165
+ while (p && p.z >= minZ && n && n.z <= maxZ) {
166
+ if (p !== ear.prev && p !== ear.next && pointInTriangle(a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y) && area(p.prev, p, p.next) >= 0) return false;
167
+ p = p.prevZ;
168
+ if (n !== ear.prev && n !== ear.next && pointInTriangle(a.x, a.y, b.x, b.y, c.x, c.y, n.x, n.y) && area(n.prev, n, n.next) >= 0) return false;
169
+ n = n.nextZ;
170
+ } // look for remaining points in decreasing z-order
171
+
172
+
173
+ while (p && p.z >= minZ) {
174
+ if (p !== ear.prev && p !== ear.next && pointInTriangle(a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y) && area(p.prev, p, p.next) >= 0) return false;
175
+ p = p.prevZ;
176
+ } // look for remaining points in increasing z-order
177
+
178
+
179
+ while (n && n.z <= maxZ) {
180
+ if (n !== ear.prev && n !== ear.next && pointInTriangle(a.x, a.y, b.x, b.y, c.x, c.y, n.x, n.y) && area(n.prev, n, n.next) >= 0) return false;
181
+ n = n.nextZ;
182
+ }
183
+
184
+ return true;
185
+ } // go through all polygon nodes and cure small local self-intersections
186
+
187
+
188
+ function cureLocalIntersections(start, triangles, dim) {
189
+ var p = start;
190
+
191
+ do {
192
+ var a = p.prev,
193
+ b = p.next.next;
194
+
195
+ if (!equals(a, b) && intersects(a, p, p.next, b) && locallyInside(a, b) && locallyInside(b, a)) {
196
+ triangles.push(a.i / dim);
197
+ triangles.push(p.i / dim);
198
+ triangles.push(b.i / dim); // remove two nodes involved
199
+
200
+ removeNode(p);
201
+ removeNode(p.next);
202
+ p = start = b;
203
+ }
204
+
205
+ p = p.next;
206
+ } while (p !== start);
207
+
208
+ return filterPoints(p);
209
+ } // try splitting polygon into two and triangulate them independently
210
+
211
+
212
+ function splitEarcut(start, triangles, dim, minX, minY, invSize) {
213
+ // look for a valid diagonal that divides the polygon into two
214
+ var a = start;
215
+
216
+ do {
217
+ var b = a.next.next;
218
+
219
+ while (b !== a.prev) {
220
+ if (a.i !== b.i && isValidDiagonal(a, b)) {
221
+ // split the polygon in two by the diagonal
222
+ var c = splitPolygon(a, b); // filter colinear points around the cuts
223
+
224
+ a = filterPoints(a, a.next);
225
+ c = filterPoints(c, c.next); // run earcut on each half
226
+
227
+ earcutLinked(a, triangles, dim, minX, minY, invSize);
228
+ earcutLinked(c, triangles, dim, minX, minY, invSize);
229
+ return;
230
+ }
231
+
232
+ b = b.next;
233
+ }
234
+
235
+ a = a.next;
236
+ } while (a !== start);
237
+ } // link every hole into the outer loop, producing a single-ring polygon without holes
238
+
239
+
240
+ function eliminateHoles(data, holeIndices, outerNode, dim) {
241
+ var queue = [],
242
+ i,
243
+ len,
244
+ start,
245
+ end,
246
+ list;
247
+
248
+ for (i = 0, len = holeIndices.length; i < len; i++) {
249
+ start = holeIndices[i] * dim;
250
+ end = i < len - 1 ? holeIndices[i + 1] * dim : data.length;
251
+ list = linkedList(data, start, end, dim, false);
252
+ if (list === list.next) list.steiner = true;
253
+ queue.push(getLeftmost(list));
254
+ }
255
+
256
+ queue.sort(compareX); // process holes from left to right
257
+
258
+ for (i = 0; i < queue.length; i++) {
259
+ outerNode = eliminateHole(queue[i], outerNode);
260
+ outerNode = filterPoints(outerNode, outerNode.next);
261
+ }
262
+
263
+ return outerNode;
264
+ }
265
+
266
+ function compareX(a, b) {
267
+ return a.x - b.x;
268
+ } // find a bridge between vertices that connects hole with an outer ring and and link it
269
+
270
+
271
+ function eliminateHole(hole, outerNode) {
272
+ var bridge = findHoleBridge(hole, outerNode);
273
+
274
+ if (!bridge) {
275
+ return outerNode;
276
+ }
277
+
278
+ var bridgeReverse = splitPolygon(bridge, hole); // filter collinear points around the cuts
279
+
280
+ var filteredBridge = filterPoints(bridge, bridge.next);
281
+ filterPoints(bridgeReverse, bridgeReverse.next); // Check if input node was removed by the filtering
282
+
283
+ return outerNode === bridge ? filteredBridge : outerNode;
284
+ } // David Eberly's algorithm for finding a bridge between hole and outer polygon
285
+
286
+
287
+ function findHoleBridge(hole, outerNode) {
288
+ var p = outerNode,
289
+ hx = hole.x,
290
+ hy = hole.y,
291
+ qx = -Infinity,
292
+ m; // find a segment intersected by a ray from the hole's leftmost point to the left;
293
+ // segment's endpoint with lesser x will be potential connection point
294
+
295
+ do {
296
+ if (hy <= p.y && hy >= p.next.y && p.next.y !== p.y) {
297
+ var x = p.x + (hy - p.y) * (p.next.x - p.x) / (p.next.y - p.y);
298
+
299
+ if (x <= hx && x > qx) {
300
+ qx = x;
301
+
302
+ if (x === hx) {
303
+ if (hy === p.y) return p;
304
+ if (hy === p.next.y) return p.next;
305
+ }
306
+
307
+ m = p.x < p.next.x ? p : p.next;
308
+ }
309
+ }
310
+
311
+ p = p.next;
312
+ } while (p !== outerNode);
313
+
314
+ if (!m) return null;
315
+ if (hx === qx) return m; // hole touches outer segment; pick leftmost endpoint
316
+ // look for points inside the triangle of hole point, segment intersection and endpoint;
317
+ // if there are no points found, we have a valid connection;
318
+ // otherwise choose the point of the minimum angle with the ray as connection point
319
+
320
+ var stop = m,
321
+ mx = m.x,
322
+ my = m.y,
323
+ tanMin = Infinity,
324
+ tan;
325
+ p = m;
326
+
327
+ do {
328
+ 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)) {
329
+ tan = Math.abs(hy - p.y) / (hx - p.x); // tangential
330
+
331
+ if (locallyInside(p, hole) && (tan < tanMin || tan === tanMin && (p.x > m.x || p.x === m.x && sectorContainsSector(m, p)))) {
332
+ m = p;
333
+ tanMin = tan;
334
+ }
335
+ }
336
+
337
+ p = p.next;
338
+ } while (p !== stop);
339
+
340
+ return m;
341
+ } // whether sector in vertex m contains sector in vertex p in the same coordinates
342
+
343
+
344
+ function sectorContainsSector(m, p) {
345
+ return area(m.prev, m, p.prev) < 0 && area(p.next, m, m.next) < 0;
346
+ } // interlink polygon nodes in z-order
347
+
348
+
349
+ function indexCurve(start, minX, minY, invSize) {
350
+ var p = start;
351
+
352
+ do {
353
+ if (p.z === null) p.z = zOrder(p.x, p.y, minX, minY, invSize);
354
+ p.prevZ = p.prev;
355
+ p.nextZ = p.next;
356
+ p = p.next;
357
+ } while (p !== start);
358
+
359
+ p.prevZ.nextZ = null;
360
+ p.prevZ = null;
361
+ sortLinked(p);
362
+ } // Simon Tatham's linked list merge sort algorithm
363
+ // http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html
364
+
365
+
366
+ function sortLinked(list) {
367
+ var i,
368
+ p,
369
+ q,
370
+ e,
371
+ tail,
372
+ numMerges,
373
+ pSize,
374
+ qSize,
375
+ inSize = 1;
376
+
377
+ do {
378
+ p = list;
379
+ list = null;
380
+ tail = null;
381
+ numMerges = 0;
382
+
383
+ while (p) {
384
+ numMerges++;
385
+ q = p;
386
+ pSize = 0;
387
+
388
+ for (i = 0; i < inSize; i++) {
389
+ pSize++;
390
+ q = q.nextZ;
391
+ if (!q) break;
392
+ }
393
+
394
+ qSize = inSize;
395
+
396
+ while (pSize > 0 || qSize > 0 && q) {
397
+ if (pSize !== 0 && (qSize === 0 || !q || p.z <= q.z)) {
398
+ e = p;
399
+ p = p.nextZ;
400
+ pSize--;
401
+ } else {
402
+ e = q;
403
+ q = q.nextZ;
404
+ qSize--;
405
+ }
406
+
407
+ if (tail) tail.nextZ = e;else list = e;
408
+ e.prevZ = tail;
409
+ tail = e;
410
+ }
411
+
412
+ p = q;
413
+ }
414
+
415
+ tail.nextZ = null;
416
+ inSize *= 2;
417
+ } while (numMerges > 1);
418
+
419
+ return list;
420
+ } // z-order of a point given coords and inverse of the longer side of data bbox
421
+
422
+
423
+ function zOrder(x, y, minX, minY, invSize) {
424
+ // coords are transformed into non-negative 15-bit integer range
425
+ x = 32767 * (x - minX) * invSize;
426
+ y = 32767 * (y - minY) * invSize;
427
+ x = (x | x << 8) & 0x00FF00FF;
428
+ x = (x | x << 4) & 0x0F0F0F0F;
429
+ x = (x | x << 2) & 0x33333333;
430
+ x = (x | x << 1) & 0x55555555;
431
+ y = (y | y << 8) & 0x00FF00FF;
432
+ y = (y | y << 4) & 0x0F0F0F0F;
433
+ y = (y | y << 2) & 0x33333333;
434
+ y = (y | y << 1) & 0x55555555;
435
+ return x | y << 1;
436
+ } // find the leftmost node of a polygon ring
437
+
438
+
439
+ function getLeftmost(start) {
440
+ var p = start,
441
+ leftmost = start;
442
+
443
+ do {
444
+ if (p.x < leftmost.x || p.x === leftmost.x && p.y < leftmost.y) leftmost = p;
445
+ p = p.next;
446
+ } while (p !== start);
447
+
448
+ return leftmost;
449
+ } // check if a point lies within a convex triangle
450
+
451
+
452
+ function pointInTriangle(ax, ay, bx, by, cx, cy, px, py) {
453
+ return (cx - px) * (ay - py) - (ax - px) * (cy - py) >= 0 && (ax - px) * (by - py) - (bx - px) * (ay - py) >= 0 && (bx - px) * (cy - py) - (cx - px) * (by - py) >= 0;
454
+ } // check if a diagonal between two polygon nodes is valid (lies in polygon interior)
455
+
456
+
457
+ function isValidDiagonal(a, b) {
458
+ return a.next.i !== b.i && a.prev.i !== b.i && !intersectsPolygon(a, b) && ( // dones't intersect other edges
459
+ locallyInside(a, b) && locallyInside(b, a) && middleInside(a, b) && ( // locally visible
460
+ area(a.prev, a, b.prev) || area(a, b.prev, b)) || // does not create opposite-facing sectors
461
+ equals(a, b) && area(a.prev, a, a.next) > 0 && area(b.prev, b, b.next) > 0); // special zero-length case
462
+ } // signed area of a triangle
463
+
464
+
465
+ function area(p, q, r) {
466
+ return (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y);
467
+ } // check if two points are equal
468
+
469
+
470
+ function equals(p1, p2) {
471
+ return p1.x === p2.x && p1.y === p2.y;
472
+ } // check if two segments intersect
473
+
474
+
475
+ function intersects(p1, q1, p2, q2) {
476
+ var o1 = sign(area(p1, q1, p2));
477
+ var o2 = sign(area(p1, q1, q2));
478
+ var o3 = sign(area(p2, q2, p1));
479
+ var o4 = sign(area(p2, q2, q1));
480
+ if (o1 !== o2 && o3 !== o4) return true; // general case
481
+
482
+ if (o1 === 0 && onSegment(p1, p2, q1)) return true; // p1, q1 and p2 are collinear and p2 lies on p1q1
483
+
484
+ if (o2 === 0 && onSegment(p1, q2, q1)) return true; // p1, q1 and q2 are collinear and q2 lies on p1q1
485
+
486
+ if (o3 === 0 && onSegment(p2, p1, q2)) return true; // p2, q2 and p1 are collinear and p1 lies on p2q2
487
+
488
+ if (o4 === 0 && onSegment(p2, q1, q2)) return true; // p2, q2 and q1 are collinear and q1 lies on p2q2
489
+
490
+ return false;
491
+ } // for collinear points p, q, r, check if point q lies on segment pr
492
+
493
+
494
+ function onSegment(p, q, r) {
495
+ return q.x <= Math.max(p.x, r.x) && q.x >= Math.min(p.x, r.x) && q.y <= Math.max(p.y, r.y) && q.y >= Math.min(p.y, r.y);
496
+ }
497
+
498
+ function sign(num) {
499
+ return num > 0 ? 1 : num < 0 ? -1 : 0;
500
+ } // check if a polygon diagonal intersects any polygon segments
501
+
502
+
503
+ function intersectsPolygon(a, b) {
504
+ var p = a;
505
+
506
+ do {
507
+ if (p.i !== a.i && p.next.i !== a.i && p.i !== b.i && p.next.i !== b.i && intersects(p, p.next, a, b)) return true;
508
+ p = p.next;
509
+ } while (p !== a);
510
+
511
+ return false;
512
+ } // check if a polygon diagonal is locally inside the polygon
513
+
514
+
515
+ function locallyInside(a, b) {
516
+ return area(a.prev, a, a.next) < 0 ? area(a, b, a.next) >= 0 && area(a, a.prev, b) >= 0 : area(a, b, a.prev) < 0 || area(a, a.next, b) < 0;
517
+ } // check if the middle point of a polygon diagonal is inside the polygon
518
+
519
+
520
+ function middleInside(a, b) {
521
+ var p = a,
522
+ inside = false,
523
+ px = (a.x + b.x) / 2,
524
+ py = (a.y + b.y) / 2;
525
+
526
+ do {
527
+ 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;
528
+ p = p.next;
529
+ } while (p !== a);
530
+
531
+ return inside;
532
+ } // link two polygon vertices with a bridge; if the vertices belong to the same ring, it splits polygon into two;
533
+ // if one belongs to the outer ring and another to a hole, it merges it into a single ring
534
+
535
+
536
+ function splitPolygon(a, b) {
537
+ var a2 = new Node(a.i, a.x, a.y),
538
+ b2 = new Node(b.i, b.x, b.y),
539
+ an = a.next,
540
+ bp = b.prev;
541
+ a.next = b;
542
+ b.prev = a;
543
+ a2.next = an;
544
+ an.prev = a2;
545
+ b2.next = a2;
546
+ a2.prev = b2;
547
+ bp.next = b2;
548
+ b2.prev = bp;
549
+ return b2;
550
+ } // create a node and optionally link it with previous one (in a circular doubly linked list)
551
+
552
+
553
+ function insertNode(i, x, y, last) {
554
+ var p = new Node(i, x, y);
555
+
556
+ if (!last) {
557
+ p.prev = p;
558
+ p.next = p;
559
+ } else {
560
+ p.next = last.next;
561
+ p.prev = last;
562
+ last.next.prev = p;
563
+ last.next = p;
564
+ }
565
+
566
+ return p;
567
+ }
568
+
569
+ function removeNode(p) {
570
+ p.next.prev = p.prev;
571
+ p.prev.next = p.next;
572
+ if (p.prevZ) p.prevZ.nextZ = p.nextZ;
573
+ if (p.nextZ) p.nextZ.prevZ = p.prevZ;
574
+ }
575
+
576
+ function Node(i, x, y) {
577
+ // vertex index in coordinates array
578
+ this.i = i; // vertex coordinates
579
+
580
+ this.x = x;
581
+ this.y = y; // previous and next vertex nodes in a polygon ring
582
+
583
+ this.prev = null;
584
+ this.next = null; // z-order curve value
585
+
586
+ this.z = null; // previous and next nodes in z-order
587
+
588
+ this.prevZ = null;
589
+ this.nextZ = null; // indicates whether this is a steiner point
590
+
591
+ this.steiner = false;
592
+ } // return a percentage difference between the polygon area and its triangulation area;
593
+ // used to verify correctness of triangulation
594
+
595
+
596
+ earcut.deviation = function (data, holeIndices, dim, triangles) {
597
+ var hasHoles = holeIndices && holeIndices.length;
598
+ var outerLen = hasHoles ? holeIndices[0] * dim : data.length;
599
+ var polygonArea = Math.abs(signedArea(data, 0, outerLen, dim));
600
+
601
+ if (hasHoles) {
602
+ for (var i = 0, len = holeIndices.length; i < len; i++) {
603
+ var start = holeIndices[i] * dim;
604
+ var end = i < len - 1 ? holeIndices[i + 1] * dim : data.length;
605
+ polygonArea -= Math.abs(signedArea(data, start, end, dim));
606
+ }
607
+ }
608
+
609
+ var trianglesArea = 0;
610
+
611
+ for (i = 0; i < triangles.length; i += 3) {
612
+ var a = triangles[i] * dim;
613
+ var b = triangles[i + 1] * dim;
614
+ var c = triangles[i + 2] * dim;
615
+ trianglesArea += Math.abs((data[a] - data[c]) * (data[b + 1] - data[a + 1]) - (data[a] - data[b]) * (data[c + 1] - data[a + 1]));
616
+ }
617
+
618
+ return polygonArea === 0 && trianglesArea === 0 ? 0 : Math.abs((trianglesArea - polygonArea) / polygonArea);
619
+ };
620
+
621
+ function signedArea(data, start, end, dim) {
622
+ var sum = 0;
623
+
624
+ for (var i = start, j = end - dim; i < end; i += dim) {
625
+ sum += (data[j] - data[i]) * (data[i + 1] + data[j + 1]);
626
+ j = i;
627
+ }
628
+
629
+ return sum;
630
+ } // turn a polygon in a multi-dimensional array form (e.g. as in GeoJSON) into a form Earcut accepts
631
+
632
+
633
+ earcut.flatten = function (data) {
634
+ var dim = data[0][0].length,
635
+ result = {
636
+ vertices: [],
637
+ holes: [],
638
+ dimensions: dim
639
+ },
640
+ holeIndex = 0;
641
+
642
+ for (var i = 0; i < data.length; i++) {
643
+ for (var j = 0; j < data[i].length; j++) {
644
+ for (var d = 0; d < dim; d++) {
645
+ result.vertices.push(data[i][j][d]);
646
+ }
647
+ }
648
+
649
+ if (i > 0) {
650
+ holeIndex += data[i - 1].length;
651
+ result.holes.push(holeIndex);
652
+ }
653
+ }
654
+
655
+ return result;
656
+ };
657
+
658
+ var earcut$1 = earcut$2.exports;
659
+
660
+ /**
661
+ * https://github.com/Turfjs/turf/blob/master/packages/turf-boolean-clockwise/index.ts
662
+ * @param {*} ring
663
+ * @returns
664
+ */
665
+ function isClockwise(ring) {
666
+ var sum = 0;
667
+ var i = 1;
668
+ var prev;
669
+ var cur;
670
+ var len = ring.length;
671
+
672
+ while (i < len) {
673
+ prev = cur || ring[0];
674
+ cur = ring[i];
675
+ sum += (cur[0] - prev[0]) * (cur[1] + prev[1]);
676
+ i++;
677
+ }
678
+
679
+ return sum > 0;
680
+ }
681
+
682
+ function v3Sub(out, v1, v2) {
683
+ out[0] = v1[0] - v2[0];
684
+ out[1] = v1[1] - v2[1];
685
+ out[2] = v1[2] - v2[2];
686
+ return out;
687
+ }
688
+
689
+ function v3Normalize(out, v) {
690
+ var x = v[0];
691
+ var y = v[1];
692
+ var z = v[2];
693
+ var d = Math.sqrt(x * x + y * y + z * z) || 1;
694
+ out[0] = x / d;
695
+ out[1] = y / d;
696
+ out[2] = z / d;
697
+ return out;
698
+ }
699
+
700
+ function v3Cross(out, v1, v2) {
701
+ var ax = v1[0],
702
+ ay = v1[1],
703
+ az = v1[2],
704
+ bx = v2[0],
705
+ by = v2[1],
706
+ bz = v2[2];
707
+ out[0] = ay * bz - az * by;
708
+ out[1] = az * bx - ax * bz;
709
+ out[2] = ax * by - ay * bx;
710
+ return out;
711
+ }
712
+
713
+ function generateNormal(indices, position) {
714
+ function v3Set(p, a, b, c) {
715
+ p[0] = a;
716
+ p[1] = b;
717
+ p[2] = c;
718
+ }
719
+
720
+ var p1 = [];
721
+ var p2 = [];
722
+ var p3 = [];
723
+ var v21 = [];
724
+ var v32 = [];
725
+ var n = [];
726
+ var len = indices.length;
727
+ var normals = new Float32Array(position.length);
728
+
729
+ for (var f = 0; f < len; f += 3) {
730
+ // const i1 = indices[f++] * 3;
731
+ // const i2 = indices[f++] * 3;
732
+ // const i3 = indices[f++] * 3;
733
+ // const i1 = indices[f];
734
+ // const i2 = indices[f + 1];
735
+ // const i3 = indices[f + 2];
736
+ var a = indices[f],
737
+ b = indices[f + 1],
738
+ c = indices[f + 2];
739
+ var i1 = a * 3,
740
+ i2 = b * 3,
741
+ i3 = c * 3;
742
+ v3Set(p1, position[i1], position[i1 + 1], position[i1 + 2]);
743
+ v3Set(p2, position[i2], position[i2 + 1], position[i2 + 2]);
744
+ v3Set(p3, position[i3], position[i3 + 1], position[i3 + 2]); // pA.fromBufferAttribute(positionAttribute, vA);
745
+ // pB.fromBufferAttribute(positionAttribute, vB);
746
+ // pC.fromBufferAttribute(positionAttribute, vC);
747
+ // cb.subVectors(pC, pB);
748
+ // ab.subVectors(pA, pB);
749
+ // cb.cross(ab);
750
+
751
+ v3Sub(v32, p3, p2);
752
+ v3Sub(v21, p1, p2);
753
+ v3Cross(n, v32, v21); // Already be weighted by the triangle area
754
+
755
+ for (var i = 0; i < 3; i++) {
756
+ normals[i1 + i] += n[i];
757
+ normals[i2 + i] += n[i];
758
+ normals[i3 + i] += n[i];
759
+ }
760
+ }
761
+
762
+ for (var _i = 0; _i < normals.length; _i += 3) {
763
+ v3Set(n, normals[_i], normals[_i + 1], normals[_i + 2]);
764
+ v3Normalize(n, n);
765
+ normals[_i] = n[0] || 1;
766
+ normals[_i + 1] = n[1] || 1;
767
+ normals[_i + 2] = n[2] || 1;
768
+ }
769
+
770
+ return normals;
771
+ }
772
+ function merge(results) {
773
+ if (results.length === 1) {
774
+ var _result = {
775
+ position: results[0].position,
776
+ normal: results[0].normal,
777
+ uv: results[0].uv,
778
+ indices: results[0].indices,
779
+ results: results
780
+ };
781
+ return _result;
782
+ }
783
+
784
+ var plen = 0,
785
+ ilen = 0;
786
+
787
+ for (var i = 0, len = results.length; i < len; i++) {
788
+ var _results$i = results[i],
789
+ position = _results$i.position,
790
+ indices = _results$i.indices;
791
+ plen += position.length;
792
+ ilen += indices.length;
793
+ }
794
+
795
+ var result = {
796
+ position: new Float32Array(plen),
797
+ normal: new Float32Array(plen),
798
+ uv: new Float32Array(plen / 3 * 2),
799
+ indices: new Uint32Array(ilen),
800
+ results: results
801
+ };
802
+ var pOffset = 0,
803
+ pCount = 0,
804
+ iIdx = 0,
805
+ uvOffset = 0;
806
+
807
+ for (var _i2 = 0, _len = results.length; _i2 < _len; _i2++) {
808
+ var _results$_i = results[_i2],
809
+ _position = _results$_i.position,
810
+ _indices = _results$_i.indices,
811
+ normal = _results$_i.normal,
812
+ uv = _results$_i.uv;
813
+ result.position.set(_position, pOffset);
814
+ result.normal.set(normal, pOffset);
815
+ result.uv.set(uv, uvOffset);
816
+
817
+ for (var j = 0, len1 = _indices.length; j < len1; j++) {
818
+ var pIndex = _indices[j] + pCount;
819
+ result.indices[iIdx] = pIndex;
820
+ iIdx++;
821
+ }
822
+
823
+ uvOffset += uv.length;
824
+ pOffset += _position.length;
825
+ pCount += _position.length / 3;
826
+ }
827
+
828
+ return result;
829
+ }
830
+ function radToDeg(rad) {
831
+ return rad * 180 / Math.PI;
832
+ }
833
+ function degToRad(angle) {
834
+ return angle / 180 * Math.PI;
835
+ } // https://github.com/mrdoob/three.js/blob/16f13e3b07e31d0e9a00df7c3366bbe0e464588c/src/geometries/ExtrudeGeometry.js?_pjax=%23js-repo-pjax-container#L736
836
+
837
+ function generateSideWallUV(uvs, vertices, indexA, indexB, indexC, indexD) {
838
+ var a_x = vertices[indexA * 3];
839
+ var a_y = vertices[indexA * 3 + 1];
840
+ var a_z = vertices[indexA * 3 + 2];
841
+ var b_x = vertices[indexB * 3];
842
+ var b_y = vertices[indexB * 3 + 1];
843
+ var b_z = vertices[indexB * 3 + 2];
844
+ var c_x = vertices[indexC * 3];
845
+ var c_y = vertices[indexC * 3 + 1];
846
+ var c_z = vertices[indexC * 3 + 2];
847
+ var d_x = vertices[indexD * 3];
848
+ var d_y = vertices[indexD * 3 + 1];
849
+ var d_z = vertices[indexD * 3 + 2];
850
+
851
+ if (Math.abs(a_y - b_y) < Math.abs(a_x - b_x)) {
852
+ uvs.push(a_x, 1 - a_z);
853
+ uvs.push(b_x, 1 - b_z);
854
+ uvs.push(c_x, 1 - c_z);
855
+ uvs.push(d_x, 1 - d_z); // return [
856
+ // new Vector2(a_x, 1 - a_z),
857
+ // new Vector2(b_x, 1 - b_z),
858
+ // new Vector2(c_x, 1 - c_z),
859
+ // new Vector2(d_x, 1 - d_z)
860
+ // ];
861
+ } else {
862
+ uvs.push(a_y, 1 - a_z);
863
+ uvs.push(b_y, 1 - b_z);
864
+ uvs.push(c_y, 1 - c_z);
865
+ uvs.push(d_y, 1 - d_z); // return [
866
+ // new Vector2(a_y, 1 - a_z),
867
+ // new Vector2(b_y, 1 - b_z),
868
+ // new Vector2(c_y, 1 - c_z),
869
+ // new Vector2(d_y, 1 - d_z)
870
+ // ];
871
+ }
872
+ }
873
+
874
+ function extrudePolygons(polygons, options) {
875
+ options = Object.assign({}, {
876
+ depth: 2
877
+ }, options);
878
+ var results = polygons.map(function (polygon) {
879
+ if (!isClockwise(polygon[0])) {
880
+ polygon[0] = polygon[0].reverse();
881
+ }
882
+
883
+ polygon.slice(1, Infinity).forEach(function (coordinates, index) {
884
+ if (isClockwise(coordinates)) {
885
+ polygon[index + 1] = coordinates.reverse();
886
+ }
887
+ });
888
+ polygon.forEach(function (ring) {
889
+ var len = ring.length;
890
+ var _ring$ = ring[0],
891
+ x1 = _ring$[0],
892
+ y1 = _ring$[1],
893
+ _ring = ring[len - 1],
894
+ x2 = _ring[0],
895
+ y2 = _ring[1];
896
+
897
+ if (x1 === x2 && y1 === y2) {
898
+ ring.splice(len - 1, 1);
899
+ }
900
+ });
901
+ var result = flatVertices(polygon, options);
902
+ result.polygon = polygon;
903
+ var time = 'earcut';
904
+ console.time(time);
905
+ var triangles = earcut$1(result.flatVertices, result.holes, 2);
906
+ console.timeEnd(time);
907
+ generateTopAndBottom$1(result, triangles);
908
+ generateSides$1(result, options);
909
+ result.position = new Float32Array(result.points);
910
+ result.indices = new Uint32Array(result.index);
911
+ result.uv = new Float32Array(result.uvs);
912
+ result.normal = generateNormal(result.indices, result.position);
913
+ return result;
914
+ });
915
+ var result = merge(results);
916
+ result.polygons = polygons;
917
+ return result;
918
+ }
919
+
920
+ function generateTopAndBottom$1(result, triangles) {
921
+ var index = [];
922
+ var count = result.count;
923
+
924
+ for (var i = 0, len = triangles.length; i < len; i += 3) {
925
+ // top
926
+ var a = triangles[i],
927
+ b = triangles[i + 1],
928
+ c = triangles[i + 2];
929
+ index[i] = a;
930
+ index[i + 1] = b;
931
+ index[i + 2] = c; // bottom
932
+
933
+ var idx = len + i;
934
+ var a1 = count + a,
935
+ b1 = count + b,
936
+ c1 = count + c;
937
+ index[idx] = a1;
938
+ index[idx + 1] = b1;
939
+ index[idx + 2] = c1;
940
+ }
941
+
942
+ result.index = index;
943
+ }
944
+
945
+ function generateSides$1(result, options) {
946
+ var points = result.points,
947
+ index = result.index,
948
+ polygon = result.polygon,
949
+ uvs = result.uvs;
950
+ var z = options.depth;
951
+
952
+ for (var i = 0, len = polygon.length; i < len; i++) {
953
+ var ring = polygon[i];
954
+
955
+ for (var j = 0, len1 = ring.length; j < len1; j++) {
956
+ var v1 = ring[j];
957
+ var v2 = ring[j + 1];
958
+
959
+ if (j === len1 - 1) {
960
+ v2 = ring[0];
961
+ } // const p1 = [v1[0], v1[1], options.depth],
962
+ // p2 = [v2[0], v2[1], options.depth],
963
+ // p3 = [v1[0], v1[1], 0],
964
+ // p4 = [v2[0], v2[1], 0];
965
+
966
+
967
+ var idx = points.length / 3;
968
+ points.push(v1[0], v1[1], 0, v2[0], v2[1], 0, v1[0], v1[1], z, v2[0], v2[1], z);
969
+ var a = idx,
970
+ b = idx + 1,
971
+ c = idx + 2,
972
+ d = idx + 3; // points.push(p3, p4, p1, p2);
973
+
974
+ index.push(a, c, b);
975
+ index.push(c, d, b);
976
+ generateSideWallUV(uvs, points, a, b, c, d);
977
+ }
978
+ }
979
+ }
980
+
981
+ function calPolygonPointsCount(polygon) {
982
+ var count = 0;
983
+ var i = 0;
984
+ var len = polygon.length;
985
+
986
+ while (i < len) {
987
+ count += polygon[i].length;
988
+ i++;
989
+ }
990
+
991
+ return count;
992
+ }
993
+
994
+ function flatVertices(polygon, options) {
995
+ var count = calPolygonPointsCount(polygon);
996
+ var len = polygon.length;
997
+ var holes = [],
998
+ flatVertices = new Float32Array(count * 2),
999
+ points = [],
1000
+ uvs = [];
1001
+ var pOffset = count * 3,
1002
+ uOffset = count * 2;
1003
+ var z = options.depth;
1004
+ var idx0 = 0,
1005
+ idx1 = 0,
1006
+ idx2 = 0;
1007
+
1008
+ for (var i = 0; i < len; i++) {
1009
+ var ring = polygon[i];
1010
+
1011
+ if (i > 0) {
1012
+ holes.push(idx0 / 2);
1013
+ }
1014
+
1015
+ for (var j = 0, len1 = ring.length; j < len1; j++) {
1016
+ var c = ring[j];
1017
+ var x = c[0],
1018
+ y = c[1];
1019
+ flatVertices[idx0++] = x;
1020
+ flatVertices[idx0++] = y; // top vertices
1021
+
1022
+ points[idx1] = x;
1023
+ points[idx1 + 1] = y;
1024
+ points[idx1 + 2] = z; // bottom vertices
1025
+
1026
+ points[pOffset + idx1] = x;
1027
+ points[pOffset + idx1 + 1] = y;
1028
+ points[pOffset + idx1 + 2] = 0;
1029
+ uvs[idx2] = x;
1030
+ uvs[idx2 + 1] = y;
1031
+ uvs[uOffset + idx2] = x;
1032
+ uvs[uOffset + idx2 + 1] = y;
1033
+ idx1 += 3;
1034
+ idx2 += 2;
1035
+ }
1036
+ }
1037
+
1038
+ return {
1039
+ flatVertices: flatVertices,
1040
+ holes: holes,
1041
+ points: points,
1042
+ count: count,
1043
+ uvs: uvs
1044
+ };
1045
+ }
1046
+
1047
+ function extrudePolylines(lines, options) {
1048
+ options = Object.assign({}, {
1049
+ depth: 2,
1050
+ lineWidth: 1
1051
+ }, options);
1052
+ var results = lines.map(function (line) {
1053
+ var result = expandLine(line, options);
1054
+ result.line = line;
1055
+ generateTopAndBottom(result, options);
1056
+ generateSides(result, options);
1057
+ result.position = new Float32Array(result.points);
1058
+ result.indices = new Uint32Array(result.index);
1059
+ result.uv = new Float32Array(result.uvs);
1060
+ result.normal = generateNormal(result.indices, result.position);
1061
+ return result;
1062
+ });
1063
+ var result = merge(results);
1064
+ result.lines = lines;
1065
+ return result;
1066
+ }
1067
+
1068
+ function generateTopAndBottom(result, options) {
1069
+ var z = options.depth;
1070
+ var points = [],
1071
+ index = [],
1072
+ uvs = [];
1073
+ var leftPoints = result.leftPoints,
1074
+ rightPoints = result.rightPoints;
1075
+
1076
+ for (var i = 0, len = leftPoints.length; i < len; i++) {
1077
+ // top left
1078
+ var idx0 = i * 3;
1079
+ var _leftPoints$i = leftPoints[i],
1080
+ x1 = _leftPoints$i[0],
1081
+ y1 = _leftPoints$i[1];
1082
+ points[idx0] = x1;
1083
+ points[idx0 + 1] = y1;
1084
+ points[idx0 + 2] = z; // top right
1085
+
1086
+ var _rightPoints$i = rightPoints[i],
1087
+ x2 = _rightPoints$i[0],
1088
+ y2 = _rightPoints$i[1];
1089
+ var idx1 = len * 3 + idx0;
1090
+ points[idx1] = x2;
1091
+ points[idx1 + 1] = y2;
1092
+ points[idx1 + 2] = z; // bottom left
1093
+
1094
+ var idx2 = len * 2 * 3 + idx0;
1095
+ points[idx2] = x1;
1096
+ points[idx2 + 1] = y1;
1097
+ points[idx2 + 2] = 0; // bottom right
1098
+
1099
+ var idx3 = len * 2 * 3 + len * 3 + idx0;
1100
+ points[idx3] = x2;
1101
+ points[idx3 + 1] = y2;
1102
+ points[idx3 + 2] = 0;
1103
+ }
1104
+
1105
+ for (var _i = 0, _len = points.length; _i < _len; _i += 3) {
1106
+ var x = points[_i],
1107
+ y = points[_i + 1];
1108
+ uvs.push(x, y);
1109
+ }
1110
+
1111
+ for (var _i2 = 0, _len2 = leftPoints.length; _i2 < _len2 - 1; _i2++) {
1112
+ // top
1113
+ // left1 left2 right1,right2
1114
+ var a1 = _i2,
1115
+ b1 = _i2 + 1,
1116
+ c1 = a1 + _len2,
1117
+ d1 = b1 + _len2;
1118
+ index.push(a1, c1, b1);
1119
+ index.push(c1, d1, b1); // bottom
1120
+ // left1 left2 right1,right2
1121
+
1122
+ var len2 = _len2 * 2;
1123
+ var a2 = _i2 + len2,
1124
+ b2 = a2 + 1,
1125
+ c2 = a2 + _len2,
1126
+ d2 = b2 + _len2;
1127
+ index.push(a2, c2, b2);
1128
+ index.push(c2, d2, b2);
1129
+ }
1130
+
1131
+ result.index = index;
1132
+ result.points = points;
1133
+ result.uvs = uvs;
1134
+ }
1135
+
1136
+ function generateSides(result, options) {
1137
+ var points = result.points,
1138
+ index = result.index,
1139
+ leftPoints = result.leftPoints,
1140
+ rightPoints = result.rightPoints,
1141
+ uvs = result.uvs;
1142
+ var z = options.depth;
1143
+ var rings = [leftPoints, rightPoints];
1144
+
1145
+ function addOneSideIndex(v1, v2) {
1146
+ var idx = points.length / 3;
1147
+ points.push(v1[0], v1[1], 0, v2[0], v2[1], 0, v1[0], v1[1], z, v2[0], v2[1], z);
1148
+ var a = idx,
1149
+ b = idx + 1,
1150
+ c = idx + 2,
1151
+ d = idx + 3; // points.push(p3, p4, p1, p2);
1152
+
1153
+ index.push(a, c, b);
1154
+ index.push(c, d, b);
1155
+ generateSideWallUV(uvs, points, a, b, c, d);
1156
+ }
1157
+
1158
+ for (var i = 0, _len3 = rings.length; i < _len3; i++) {
1159
+ var ring = rings[i];
1160
+
1161
+ if (i > 0) {
1162
+ ring = ring.map(function (p) {
1163
+ return p;
1164
+ });
1165
+ ring = ring.reverse();
1166
+ }
1167
+
1168
+ for (var j = 0, len1 = ring.length - 1; j < len1; j++) {
1169
+ var v1 = ring[j];
1170
+ var v2 = ring[j + 1];
1171
+ addOneSideIndex(v1, v2);
1172
+ }
1173
+ }
1174
+
1175
+ var len = leftPoints.length;
1176
+ var vs = [rightPoints[0], leftPoints[0], leftPoints[len - 1], rightPoints[len - 1]];
1177
+
1178
+ for (var _i3 = 0; _i3 < vs.length; _i3 += 2) {
1179
+ var _v = vs[_i3],
1180
+ _v2 = vs[_i3 + 1];
1181
+ addOneSideIndex(_v, _v2);
1182
+ }
1183
+ }
1184
+
1185
+ var TEMPV1 = {
1186
+ x: 0,
1187
+ y: 0
1188
+ },
1189
+ TEMPV2 = {
1190
+ x: 0,
1191
+ y: 0
1192
+ };
1193
+
1194
+ function expandLine(line, options) {
1195
+ var preAngle = 0;
1196
+ var radius = options.lineWidth / 2;
1197
+ var points = [],
1198
+ leftPoints = [],
1199
+ rightPoints = [];
1200
+ var len = line.length;
1201
+
1202
+ for (var i = 0; i < len - 1; i++) {
1203
+ var _p = line[i],
1204
+ _p2 = line[i + 1];
1205
+ var dy = _p2[1] - _p[1],
1206
+ dx = _p2[0] - _p[0];
1207
+ var _rAngle = 0;
1208
+ var rad = Math.atan(dy / dx);
1209
+ var angle = radToDeg(rad);
1210
+ preAngle = angle;
1211
+
1212
+ if (i === 0) {
1213
+ _rAngle = angle;
1214
+ _rAngle -= 90;
1215
+ } else {
1216
+ var p0 = line[i - 1];
1217
+ TEMPV1.x = p0[0] - _p[0];
1218
+ TEMPV1.y = p0[1] - _p[1];
1219
+ TEMPV2.x = _p2[0] - _p[0];
1220
+ TEMPV2.y = _p2[1] - _p[1];
1221
+ var vAngle = getAngle(TEMPV1, TEMPV2);
1222
+ _rAngle = angle - vAngle / 2;
1223
+ }
1224
+
1225
+ var _rRad = degToRad(_rAngle);
1226
+
1227
+ var _calOffsetPoint = calOffsetPoint(_rRad, radius, _p),
1228
+ _op = _calOffsetPoint[0],
1229
+ _op2 = _calOffsetPoint[1];
1230
+
1231
+ points.push(_op, _op2);
1232
+
1233
+ if (leftOnLine(_op, _p, _p2)) {
1234
+ leftPoints.push(_op);
1235
+ rightPoints.push(_op2);
1236
+ } else {
1237
+ leftPoints.push(_op2);
1238
+ rightPoints.push(_op);
1239
+ }
1240
+ }
1241
+
1242
+ var rAngle = preAngle;
1243
+ rAngle -= 90;
1244
+ var rRad = degToRad(rAngle);
1245
+ var p1 = line[len - 2];
1246
+ var p2 = line[len - 1];
1247
+
1248
+ var _calOffsetPoint2 = calOffsetPoint(rRad, radius, p2),
1249
+ op1 = _calOffsetPoint2[0],
1250
+ op2 = _calOffsetPoint2[1];
1251
+
1252
+ points.push(op1, op2);
1253
+
1254
+ if (leftOnLine(op1, p1, p2)) {
1255
+ leftPoints.push(op1);
1256
+ rightPoints.push(op2);
1257
+ } else {
1258
+ leftPoints.push(op2);
1259
+ rightPoints.push(op1);
1260
+ }
1261
+
1262
+ return {
1263
+ offsetPoints: points,
1264
+ leftPoints: leftPoints,
1265
+ rightPoints: rightPoints
1266
+ };
1267
+ }
1268
+
1269
+ function calOffsetPoint(rad, radius, p) {
1270
+ var x = p[0],
1271
+ y = p[1];
1272
+ var x1 = Math.cos(rad) * radius,
1273
+ y1 = Math.sin(rad) * radius;
1274
+ var p1 = [x + x1, y + y1];
1275
+ var rad1 = rad += Math.PI;
1276
+ var x2 = Math.cos(rad1) * radius,
1277
+ y2 = Math.sin(rad1) * radius;
1278
+ var p2 = [x + x2, y + y2];
1279
+ return [p1, p2];
1280
+ }
1281
+
1282
+ var getAngle = function getAngle(_ref, _ref2) {
1283
+ var x1 = _ref.x,
1284
+ y1 = _ref.y;
1285
+ var x2 = _ref2.x,
1286
+ y2 = _ref2.y;
1287
+ var dot = x1 * x2 + y1 * y2;
1288
+ var det = x1 * y2 - y1 * x2;
1289
+ var angle = Math.atan2(det, dot) / Math.PI * 180;
1290
+ return (angle + 360) % 360;
1291
+ };
1292
+
1293
+ function leftOnLine(p, p1, p2) {
1294
+ var x1 = p1[0],
1295
+ y1 = p1[1];
1296
+ var x2 = p2[0],
1297
+ y2 = p2[1];
1298
+ var x = p[0],
1299
+ y = p[1];
1300
+ return (y1 - y2) * x + (x2 - x1) * y + x1 * y2 - x2 * y1 > 0;
1301
+ }
1302
+
1303
+ export { extrudePolygons, extrudePolylines };
1304
+
1305
+ typeof console !== 'undefined' && console.log('poly-extrude v0.0.1');