poly-extrude 0.0.6 → 0.0.9

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,5 +1,5 @@
1
1
  /*!
2
- * poly-extrude v0.0.6
2
+ * poly-extrude v0.0.9
3
3
  */
4
4
  var earcut$2 = {exports: {}};
5
5
 
@@ -32,10 +32,10 @@ function earcut(data, holeIndices, dim) {
32
32
 
33
33
 
34
34
  invSize = Math.max(maxX - minX, maxY - minY);
35
- invSize = invSize !== 0 ? 1 / invSize : 0;
35
+ invSize = invSize !== 0 ? 32767 / invSize : 0;
36
36
  }
37
37
 
38
- earcutLinked(outerNode, triangles, dim, minX, minY, invSize);
38
+ earcutLinked(outerNode, triangles, dim, minX, minY, invSize, 0);
39
39
  return triangles;
40
40
  } // create a circular doubly linked list from polygon points in the specified winding order
41
41
 
@@ -99,9 +99,9 @@ function earcutLinked(ear, triangles, dim, minX, minY, invSize, pass) {
99
99
 
100
100
  if (invSize ? isEarHashed(ear, minX, minY, invSize) : isEar(ear)) {
101
101
  // cut off the triangle
102
- triangles.push(prev.i / dim);
103
- triangles.push(ear.i / dim);
104
- triangles.push(next.i / dim);
102
+ triangles.push(prev.i / dim | 0);
103
+ triangles.push(ear.i / dim | 0);
104
+ triangles.push(next.i / dim | 0);
105
105
  removeNode(ear); // skipping the next vertex leads to less sliver triangles
106
106
 
107
107
  ear = next.next;
@@ -135,10 +135,21 @@ function isEar(ear) {
135
135
  if (area(a, b, c) >= 0) return false; // reflex, can't be an ear
136
136
  // now make sure we don't have other points inside the potential ear
137
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;
138
+ var ax = a.x,
139
+ bx = b.x,
140
+ cx = c.x,
141
+ ay = a.y,
142
+ by = b.y,
143
+ cy = c.y; // triangle bbox; min & max are calculated like this for speed
144
+
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;
149
+ var p = c.next;
150
+
151
+ while (p !== a) {
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;
142
153
  p = p.next;
143
154
  }
144
155
 
@@ -150,34 +161,40 @@ function isEarHashed(ear, minX, minY, invSize) {
150
161
  b = ear,
151
162
  c = ear.next;
152
163
  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
164
 
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;
165
+ var ax = a.x,
166
+ bx = b.x,
167
+ cx = c.x,
168
+ ay = a.y,
169
+ by = b.y,
170
+ cy = c.y; // triangle bbox; min & max are calculated like this for speed
171
+
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;
159
176
 
160
- var minZ = zOrder(minTX, minTY, minX, minY, invSize),
161
- maxZ = zOrder(maxTX, maxTY, minX, minY, invSize);
177
+ var minZ = zOrder(x0, y0, minX, minY, invSize),
178
+ maxZ = zOrder(x1, y1, minX, minY, invSize);
162
179
  var p = ear.prevZ,
163
180
  n = ear.nextZ; // look for points inside the triangle in both directions
164
181
 
165
182
  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;
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;
167
184
  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;
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;
169
186
  n = n.nextZ;
170
187
  } // look for remaining points in decreasing z-order
171
188
 
172
189
 
173
190
  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;
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;
175
192
  p = p.prevZ;
176
193
  } // look for remaining points in increasing z-order
177
194
 
178
195
 
179
196
  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;
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;
181
198
  n = n.nextZ;
182
199
  }
183
200
 
@@ -193,9 +210,9 @@ function cureLocalIntersections(start, triangles, dim) {
193
210
  b = p.next.next;
194
211
 
195
212
  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
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
199
216
 
200
217
  removeNode(p);
201
218
  removeNode(p.next);
@@ -224,8 +241,8 @@ function splitEarcut(start, triangles, dim, minX, minY, invSize) {
224
241
  a = filterPoints(a, a.next);
225
242
  c = filterPoints(c, c.next); // run earcut on each half
226
243
 
227
- earcutLinked(a, triangles, dim, minX, minY, invSize);
228
- earcutLinked(c, triangles, dim, minX, minY, invSize);
244
+ earcutLinked(a, triangles, dim, minX, minY, invSize, 0);
245
+ earcutLinked(c, triangles, dim, minX, minY, invSize, 0);
229
246
  return;
230
247
  }
231
248
 
@@ -257,7 +274,6 @@ function eliminateHoles(data, holeIndices, outerNode, dim) {
257
274
 
258
275
  for (i = 0; i < queue.length; i++) {
259
276
  outerNode = eliminateHole(queue[i], outerNode);
260
- outerNode = filterPoints(outerNode, outerNode.next);
261
277
  }
262
278
 
263
279
  return outerNode;
@@ -277,10 +293,8 @@ function eliminateHole(hole, outerNode) {
277
293
 
278
294
  var bridgeReverse = splitPolygon(bridge, hole); // filter collinear points around the cuts
279
295
 
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;
296
+ filterPoints(bridgeReverse, bridgeReverse.next);
297
+ return filterPoints(bridge, bridge.next);
284
298
  } // David Eberly's algorithm for finding a bridge between hole and outer polygon
285
299
 
286
300
 
@@ -298,22 +312,15 @@ function findHoleBridge(hole, outerNode) {
298
312
 
299
313
  if (x <= hx && x > qx) {
300
314
  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
315
  m = p.x < p.next.x ? p : p.next;
316
+ if (x === hx) return m; // hole touches outer segment; pick leftmost endpoint
308
317
  }
309
318
  }
310
319
 
311
320
  p = p.next;
312
321
  } while (p !== outerNode);
313
322
 
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;
323
+ if (!m) return null; // look for points inside the triangle of hole point, segment intersection and endpoint;
317
324
  // if there are no points found, we have a valid connection;
318
325
  // otherwise choose the point of the minimum angle with the ray as connection point
319
326
 
@@ -350,7 +357,7 @@ function indexCurve(start, minX, minY, invSize) {
350
357
  var p = start;
351
358
 
352
359
  do {
353
- if (p.z === null) p.z = zOrder(p.x, p.y, minX, minY, invSize);
360
+ if (p.z === 0) p.z = zOrder(p.x, p.y, minX, minY, invSize);
354
361
  p.prevZ = p.prev;
355
362
  p.nextZ = p.next;
356
363
  p = p.next;
@@ -422,8 +429,8 @@ function sortLinked(list) {
422
429
 
423
430
  function zOrder(x, y, minX, minY, invSize) {
424
431
  // coords are transformed into non-negative 15-bit integer range
425
- x = 32767 * (x - minX) * invSize;
426
- y = 32767 * (y - minY) * invSize;
432
+ x = (x - minX) * invSize | 0;
433
+ y = (y - minY) * invSize | 0;
427
434
  x = (x | x << 8) & 0x00FF00FF;
428
435
  x = (x | x << 4) & 0x0F0F0F0F;
429
436
  x = (x | x << 2) & 0x33333333;
@@ -450,7 +457,7 @@ function getLeftmost(start) {
450
457
 
451
458
 
452
459
  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;
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);
454
461
  } // check if a diagonal between two polygon nodes is valid (lies in polygon interior)
455
462
 
456
463
 
@@ -583,7 +590,7 @@ function Node(i, x, y) {
583
590
  this.prev = null;
584
591
  this.next = null; // z-order curve value
585
592
 
586
- this.z = null; // previous and next nodes in z-order
593
+ this.z = 0; // previous and next nodes in z-order
587
594
 
588
595
  this.prevZ = null;
589
596
  this.nextZ = null; // indicates whether this is a steiner point
@@ -957,11 +964,11 @@ function generateSides$1(result, options) {
957
964
  y1 = v1[1],
958
965
  x2 = v2[0],
959
966
  y2 = v2[1];
960
- points.push(x1, y1, 0, x2, y2, 0, x1, y1, z, x2, y2, z);
961
- var a = idx,
962
- b = idx + 1,
963
- c = idx + 2,
964
- d = idx + 3; // points.push(p3, p4, p1, p2);
967
+ points.push(x1, y1, z, x2, y2, z, x1, y1, 0, x2, y2, 0);
968
+ var a = idx + 2,
969
+ b = idx + 3,
970
+ c = idx,
971
+ d = idx + 1; // points.push(p3, p4, p1, p2);
965
972
 
966
973
  index.push(a, c, b, c, d, b); // index.push(c, d, b);
967
974
 
@@ -1169,11 +1176,11 @@ function generateSides(result, options) {
1169
1176
 
1170
1177
  function addOneSideIndex(v1, v2) {
1171
1178
  var idx = points.length / 3;
1172
- points.push(v1[0], v1[1], 0, v2[0], v2[1], 0, v1[0], v1[1], z, v2[0], v2[1], z);
1173
- var a = idx,
1174
- b = idx + 1,
1175
- c = idx + 2,
1176
- d = idx + 3;
1179
+ points.push(v1[0], v1[1], z, v2[0], v2[1], z, v1[0], v1[1], 0, v2[0], v2[1], 0);
1180
+ var a = idx + 2,
1181
+ b = idx + 3,
1182
+ c = idx,
1183
+ d = idx + 1;
1177
1184
  index.push(a, c, b, c, d, b);
1178
1185
  generateSideWallUV(uvs, points, a, b, c, d);
1179
1186
  }
@@ -1217,7 +1224,6 @@ var TEMPV1 = {
1217
1224
  x: 0,
1218
1225
  y: 0
1219
1226
  };
1220
-
1221
1227
  function expandLine(line, options) {
1222
1228
  var preAngle = 0;
1223
1229
  var radius = options.lineWidth / 2;
@@ -1330,4 +1336,4 @@ function leftOnLine(p, p1, p2) {
1330
1336
  return (y1 - y2) * x + (x2 - x1) * y + x1 * y2 - x2 * y1 > 0;
1331
1337
  }
1332
1338
 
1333
- export { extrudePolygons, extrudePolylines };
1339
+ export { expandLine, extrudePolygons, extrudePolylines };
package/index.js CHANGED
@@ -1,3 +1,3 @@
1
1
  import { extrudePolygons } from './src/polygon';
2
- import { extrudePolylines } from './src/polyline';
3
- export { extrudePolygons, extrudePolylines };
2
+ import { extrudePolylines, expandLine } from './src/polyline';
3
+ export { extrudePolygons, extrudePolylines, expandLine };
package/package.json CHANGED
@@ -1,47 +1,47 @@
1
- {
2
- "name": "poly-extrude",
3
- "version": "0.0.6",
4
- "description": "",
5
- "main": "dist/poly-extrude.js",
6
- "module": "dist/poly-extrude.mjs",
7
- "scripts": {
8
- "test": "echo \"Error: no test specified\" && exit 1",
9
- "lint": "eslint src/**/*.js",
10
- "build": "npm run lint && cross-env NODE_ENV=dev rollup -c"
11
- },
12
- "repository": {
13
- "type": "git",
14
- "url": "git+https://github.com/deyihu/poly-extrude.git"
15
- },
16
- "author": "",
17
- "license": "ISC",
18
- "bugs": {
19
- "url": "https://github.com/deyihu/poly-extrude/issues"
20
- },
21
- "homepage": "https://github.com/deyihu/poly-extrude#readme",
22
- "devDependencies": {
23
- "@babel/core": "^7.17.5",
24
- "@babel/preset-env": "^7.16.11",
25
- "@rollup/plugin-babel": "^5.3.0",
26
- "@rollup/plugin-commonjs": "^21.0.1",
27
- "@rollup/plugin-json": "^4.1.0",
28
- "@rollup/plugin-node-resolve": "^13.1.3",
29
- "cross-env": "^5.1.4",
30
- "eslint": "^6.2.2",
31
- "eslint-config-standard": "^14.1.0",
32
- "eslint-plugin-import": "^2.18.2",
33
- "eslint-plugin-node": "^10.0.0",
34
- "eslint-plugin-promise": "^4.2.1",
35
- "eslint-plugin-standard": "^4.0.1",
36
- "rollup": "^2.64.0",
37
- "rollup-plugin-terser": "^7.0.2"
38
- },
39
- "dependencies": {
40
- "earcut": "^2.2.3"
41
- },
42
- "files": [
43
- "dist/",
44
- "src/",
45
- "index.js"
46
- ]
47
- }
1
+ {
2
+ "name": "poly-extrude",
3
+ "version": "0.0.9",
4
+ "description": "",
5
+ "main": "dist/poly-extrude.js",
6
+ "module": "dist/poly-extrude.mjs",
7
+ "scripts": {
8
+ "test": "echo \"Error: no test specified\" && exit 1",
9
+ "lint": "eslint src/**/*.js",
10
+ "build": "npm run lint && cross-env NODE_ENV=dev rollup -c"
11
+ },
12
+ "repository": {
13
+ "type": "git",
14
+ "url": "git+https://github.com/deyihu/poly-extrude.git"
15
+ },
16
+ "author": "",
17
+ "license": "ISC",
18
+ "bugs": {
19
+ "url": "https://github.com/deyihu/poly-extrude/issues"
20
+ },
21
+ "homepage": "https://github.com/deyihu/poly-extrude#readme",
22
+ "devDependencies": {
23
+ "@babel/core": "^7.17.5",
24
+ "@babel/preset-env": "^7.16.11",
25
+ "@rollup/plugin-babel": "^5.3.0",
26
+ "@rollup/plugin-commonjs": "^21.0.1",
27
+ "@rollup/plugin-json": "^4.1.0",
28
+ "@rollup/plugin-node-resolve": "^13.1.3",
29
+ "cross-env": "^5.1.4",
30
+ "eslint": "^6.2.2",
31
+ "eslint-config-standard": "^14.1.0",
32
+ "eslint-plugin-import": "^2.18.2",
33
+ "eslint-plugin-node": "^10.0.0",
34
+ "eslint-plugin-promise": "^4.2.1",
35
+ "eslint-plugin-standard": "^4.0.1",
36
+ "rollup": "^2.64.0",
37
+ "rollup-plugin-terser": "^7.0.2"
38
+ },
39
+ "dependencies": {
40
+ "earcut": "^2.2.4"
41
+ },
42
+ "files": [
43
+ "dist/",
44
+ "src/",
45
+ "index.js"
46
+ ]
47
+ }
package/readme.md ADDED
@@ -0,0 +1,100 @@
1
+ # poly-extrude
2
+
3
+ Extrude polygons/polylines. Born in [maptalks.three](https://github.com/maptalks/maptalks.three) project<br>
4
+ [building](https://deyihu.github.io/poly-extrude/test/building.html)<br>
5
+ ![](./gallery/building.png)<br>
6
+ [buildings](https://deyihu.github.io/poly-extrude/test/buildings.html)<br>
7
+ ![](./gallery/buildings.png)<br>
8
+ [multi-polygon](https://deyihu.github.io/poly-extrude/test/multi-polygon.html)<br>
9
+ ![](./gallery/multi-polygon.png)<br>
10
+ [street](https://deyihu.github.io/poly-extrude/test/street.html)<br>
11
+ ![](./gallery/street.png)<br>
12
+ [line-uv](https://deyihu.github.io/poly-extrude/test/line-uv.html)<br>
13
+ ![](./gallery/line-uv.png)
14
+
15
+ ## install
16
+
17
+ ```sh
18
+ npm i poly-extrude
19
+
20
+ # or
21
+
22
+ yarn add poly-extrude
23
+
24
+ # or
25
+
26
+ pnpm i poly-extrude
27
+ ```
28
+
29
+ ## API
30
+
31
+ ### ESM
32
+
33
+ ```js
34
+ import {extrudePolygons,extrudePolylines} from 'poly-extrude';
35
+ const polygons=[
36
+ //polygon
37
+ [
38
+ //outring
39
+ [[x,y],[x,y],...........],
40
+ //holes
41
+ [[x,y],[x,y],...........],
42
+ ........
43
+
44
+ ],
45
+ //other polygons
46
+ ......
47
+ ]
48
+
49
+ const result = extrudePolygons(polygons,{depth:2});
50
+ const {positon,normal,uv,indices}=result;
51
+ //do something
52
+
53
+ const polylines=[
54
+ // polyline
55
+ [[x,y],[x,y],...........],
56
+ //polyline
57
+ [[x,y],[x,y],...........],
58
+ ];
59
+
60
+ const result = extrudePolylines(polylines,{depth:2,lineWidth:2});
61
+ const {positon,normal,uv,indices}=result;
62
+ //do something
63
+ ```
64
+
65
+ ### CDN
66
+
67
+ ```html
68
+ <script src="https://unpkg.com/poly-extrude/dist/poly-extrude.js"></script>
69
+
70
+ <script>
71
+ const polygons=[
72
+ //polygon
73
+ [
74
+ //outring
75
+ [[x,y],[x,y],...........],
76
+ //holes
77
+ [[x,y],[x,y],...........],
78
+ ........
79
+
80
+ ],
81
+ //other polygons
82
+ ......
83
+ ]
84
+
85
+ const result = polyextrude.extrudePolygons(polygons,{depth:2})
86
+ const {positon,normal,uv,indices}=result;
87
+ //do something
88
+
89
+ const polylines=[
90
+ // polyline
91
+ [[x,y],[x,y],...........],
92
+ //polyline
93
+ [[x,y],[x,y],...........],
94
+ ];
95
+
96
+ const result = polyextrude.extrudePolylines(polylines,{depth:2,lineWidth:2});
97
+ const {positon,normal,uv,indices}=result;
98
+ //do something
99
+ </script>
100
+ ```
package/src/polygon.js CHANGED
@@ -70,8 +70,8 @@ function generateSides(result, options) {
70
70
  }
71
71
  const idx = points.length / 3;
72
72
  const x1 = v1[0], y1 = v1[1], x2 = v2[0], y2 = v2[1];
73
- points.push(x1, y1, 0, x2, y2, 0, x1, y1, z, x2, y2, z);
74
- const a = idx, b = idx + 1, c = idx + 2, d = idx + 3;
73
+ points.push(x1, y1, z, x2, y2, z, x1, y1, 0, x2, y2, 0);
74
+ const a = idx + 2, b = idx + 3, c = idx, d = idx + 1;
75
75
  // points.push(p3, p4, p1, p2);
76
76
  index.push(a, c, b, c, d, b);
77
77
  // index.push(c, d, b);
package/src/polyline.js CHANGED
@@ -88,8 +88,8 @@ function generateSides(result, options) {
88
88
 
89
89
  function addOneSideIndex(v1, v2) {
90
90
  const idx = points.length / 3;
91
- points.push(v1[0], v1[1], 0, v2[0], v2[1], 0, v1[0], v1[1], z, v2[0], v2[1], z);
92
- const a = idx, b = idx + 1, c = idx + 2, d = idx + 3;
91
+ points.push(v1[0], v1[1], z, v2[0], v2[1], z, v1[0], v1[1], 0, v2[0], v2[1], 0);
92
+ const a = idx + 2, b = idx + 3, c = idx, d = idx + 1;
93
93
  index.push(a, c, b, c, d, b);
94
94
  generateSideWallUV(uvs, points, a, b, c, d);
95
95
  }
@@ -121,7 +121,7 @@ function generateSides(result, options) {
121
121
 
122
122
  const TEMPV1 = { x: 0, y: 0 }, TEMPV2 = { x: 0, y: 0 };
123
123
 
124
- function expandLine(line, options) {
124
+ export function expandLine(line, options) {
125
125
  let preAngle = 0;
126
126
  const radius = options.lineWidth / 2;
127
127
  const points = [], leftPoints = [], rightPoints = [];