poly-extrude 0.20.6 → 0.22.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/package.json CHANGED
@@ -1,53 +1,54 @@
1
- {
2
- "name": "poly-extrude",
3
- "version": "0.20.6",
4
- "description": "extrude polyline/polygon etc",
5
- "main": "dist/poly-extrude.js",
6
- "module": "dist/poly-extrude.mjs",
7
- "types": "dist/index.d.ts",
8
- "scripts": {
9
- "tsc": "npx tsc",
10
- "test": "echo \"Error: no test specified\" && exit 1",
11
- "lint": "eslint src/**/*.js",
12
- "build": "npm run lint && npm run tsc && cross-env NODE_ENV=prd rollup -c",
13
- "dev": "npm run lint && cross-env NODE_ENV=dev rollup -c -w"
14
- },
15
- "repository": {
16
- "type": "git",
17
- "url": "git+https://github.com/deyihu/poly-extrude.git"
18
- },
19
- "author": "",
20
- "license": "ISC",
21
- "bugs": {
22
- "url": "https://github.com/deyihu/poly-extrude/issues"
23
- },
24
- "homepage": "https://github.com/deyihu/poly-extrude#readme",
25
- "devDependencies": {
26
- "@babel/core": "^7.17.5",
27
- "@babel/preset-env": "^7.16.11",
28
- "@rollup/plugin-babel": "^5.3.0",
29
- "@rollup/plugin-commonjs": "^21.0.1",
30
- "@rollup/plugin-json": "^4.1.0",
31
- "@rollup/plugin-node-resolve": "^13.1.3",
32
- "@rollup/plugin-typescript": "^8.3.0",
33
- "cross-env": "^5.1.4",
34
- "eslint": "^6.2.2",
35
- "eslint-config-standard": "^14.1.0",
36
- "eslint-plugin-import": "^2.18.2",
37
- "eslint-plugin-node": "^10.0.0",
38
- "eslint-plugin-promise": "^4.2.1",
39
- "eslint-plugin-standard": "^4.0.1",
40
- "rollup": "^2.64.0",
41
- "rollup-plugin-terser": "^7.0.2",
42
- "typescript": "^5.7.2",
43
- "tslib": "^2.8.1"
44
- },
45
- "dependencies": {
46
- "earcut": "^3.0.1"
47
- },
48
- "files": [
49
- "dist/",
50
- "src/",
51
- "index.js"
52
- ]
1
+ {
2
+ "name": "poly-extrude",
3
+ "version": "0.22.0",
4
+ "description": "extrude polyline/polygon etc",
5
+ "main": "dist/poly-extrude.js",
6
+ "module": "dist/poly-extrude.mjs",
7
+ "types": "dist/index.d.ts",
8
+ "scripts": {
9
+ "tsc": "npx tsc",
10
+ "test": "echo \"Error: no test specified\" && exit 1",
11
+ "lint": "eslint src/**/*.js",
12
+ "build": "npm run lint && npm run tsc && cross-env NODE_ENV=prd rollup -c",
13
+ "dev": "npm run lint && cross-env NODE_ENV=dev rollup -c -w"
14
+ },
15
+ "repository": {
16
+ "type": "git",
17
+ "url": "git+https://github.com/deyihu/poly-extrude.git"
18
+ },
19
+ "author": "",
20
+ "license": "ISC",
21
+ "bugs": {
22
+ "url": "https://github.com/deyihu/poly-extrude/issues"
23
+ },
24
+ "homepage": "https://github.com/deyihu/poly-extrude#readme",
25
+ "devDependencies": {
26
+ "@babel/core": "^7.17.5",
27
+ "@babel/preset-env": "^7.16.11",
28
+ "@rollup/plugin-babel": "^5.3.0",
29
+ "@rollup/plugin-commonjs": "^21.0.1",
30
+ "@rollup/plugin-json": "^4.1.0",
31
+ "@rollup/plugin-node-resolve": "^13.1.3",
32
+ "@rollup/plugin-typescript": "^8.3.0",
33
+ "cross-env": "^5.1.4",
34
+ "eslint": "^6.2.2",
35
+ "eslint-config-standard": "^14.1.0",
36
+ "eslint-plugin-import": "^2.18.2",
37
+ "eslint-plugin-node": "^10.0.0",
38
+ "eslint-plugin-promise": "^4.2.1",
39
+ "eslint-plugin-standard": "^4.0.1",
40
+ "rollup": "^2.64.0",
41
+ "rollup-plugin-terser": "^7.0.2",
42
+ "tslib": "^2.8.1",
43
+ "typescript": "^5.7.2"
44
+ },
45
+ "dependencies": {
46
+ "bezier-js": "^6.1.4",
47
+ "earcut": "^3.0.1"
48
+ },
49
+ "files": [
50
+ "dist/",
51
+ "src/",
52
+ "index.js"
53
+ ]
53
54
  }
package/src/index.ts CHANGED
@@ -5,6 +5,7 @@ import { expandPaths } from './path';
5
5
  import { expandTubes } from './tube';
6
6
  import { plane } from './plane';
7
7
  import { extrudePolygonsOnPath } from './polygonpath';
8
+ import { polylineOffset, polylineRound } from './polylineoffset';
8
9
  import { isClockwise, merge } from './util';
9
10
  export {
10
11
  isClockwise, merge,
@@ -12,5 +13,7 @@ export {
12
13
  extrudeSlopes, expandLine, leftOnLine,
13
14
  cylinder, expandPaths, expandTubes, plane,
14
15
  extrudePolygonsOnPath,
15
- polygons
16
+ polygons,
17
+ polylineOffset,
18
+ polylineRound
16
19
  };
package/src/polyline.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { PolylineType, ResultType } from './type';
2
- import { calLineDistance, degToRad, generateNormal, generateSideWallUV, merge, radToDeg } from './util';
2
+ import { calLineDistance, degToRad, generateNormal, generateSideWallUV, merge, radToDeg, pointEqual, pointDistance } from './util';
3
3
 
4
4
  function checkOptions(options) {
5
5
  options.lineWidth = Math.max(0, options.lineWidth);
@@ -351,7 +351,7 @@ export function expandLine(line: Array<Array<number>>, options?: ExpandLineOptio
351
351
  let p1 = line[i],
352
352
  p2 = line[i + 1];
353
353
  const current = p1;
354
- if (pre && equal(pre, current)) {
354
+ if (pre && pointEqual(pre, current)) {
355
355
  repeatVertex();
356
356
  i++;
357
357
  continue;
@@ -361,30 +361,30 @@ export function expandLine(line: Array<Array<number>>, options?: ExpandLineOptio
361
361
  if (i === len - 1) {
362
362
  p1 = line[len - 2];
363
363
  p2 = line[len - 1];
364
- if (equal(p1, p2)) {
364
+ if (pointEqual(p1, p2)) {
365
365
  for (let j = line.indexOf(p1); j >= 0; j--) {
366
366
  const p = line[j];
367
- if (!equal(p, current)) {
367
+ if (!pointEqual(p, current)) {
368
368
  p1 = p;
369
369
  break;
370
370
  }
371
371
  }
372
372
  }
373
373
  } else {
374
- if (equal(p1, p2)) {
374
+ if (pointEqual(p1, p2)) {
375
375
  for (let j = line.indexOf(p2); j < len; j++) {
376
376
  const p = line[j];
377
- if (!equal(p, current)) {
377
+ if (!pointEqual(p, current)) {
378
378
  p2 = p;
379
379
  break;
380
380
  }
381
381
  }
382
382
  }
383
- if (equal(p1, p2)) {
383
+ if (pointEqual(p1, p2)) {
384
384
  lastRepeat = true;
385
385
  for (let j = line.indexOf(p1); j >= 0; j--) {
386
386
  const p = line[j];
387
- if (!equal(p, current)) {
387
+ if (!pointEqual(p, current)) {
388
388
  p1 = p;
389
389
  break;
390
390
  }
@@ -392,7 +392,7 @@ export function expandLine(line: Array<Array<number>>, options?: ExpandLineOptio
392
392
  }
393
393
 
394
394
  }
395
- if (equal(p1, p2)) {
395
+ if (pointEqual(p1, p2)) {
396
396
  console.error('not find next vertex:index:', i, line);
397
397
  repeatVertex();
398
398
  i++;
@@ -410,16 +410,16 @@ export function expandLine(line: Array<Array<number>>, options?: ExpandLineOptio
410
410
  } else {
411
411
  // 至少3个顶点才会触发
412
412
  p0 = line[i - 1];
413
- if (equal(p0, p2) || equal(p0, p1)) {
413
+ if (pointEqual(p0, p2) || pointEqual(p0, p1)) {
414
414
  for (let j = line.indexOf(p2); j >= 0; j--) {
415
415
  const p = line[j];
416
- if (!equal(p, p2) && (!equal(p, p1))) {
416
+ if (!pointEqual(p, p2) && (!pointEqual(p, p1))) {
417
417
  p0 = p;
418
418
  break;
419
419
  }
420
420
  }
421
421
  }
422
- if (equal(p0, p2) || equal(p0, p1) || equal(p1, p2)) {
422
+ if (pointEqual(p0, p2) || pointEqual(p0, p1) || pointEqual(p1, p2)) {
423
423
  console.error('not find pre vertex:index:', i, line);
424
424
  repeatVertex();
425
425
  i++;
@@ -480,13 +480,13 @@ export function expandLine(line: Array<Array<number>>, options?: ExpandLineOptio
480
480
  let needCut = false;
481
481
  if (cutCorner) {
482
482
  const bufferRadius = radius * 2;
483
- if (distance(current, op1) > bufferRadius || distance(current, op2) > bufferRadius) {
483
+ if (pointDistance(current, op1) > bufferRadius || pointDistance(current, op2) > bufferRadius) {
484
484
  needCut = true;
485
485
  }
486
486
  }
487
487
  if (needCut && p0 && preleftline && prerightline) {
488
488
  let cutPoint = op1;
489
- if (distance(op1, p0) < distance(op2, p0)) {
489
+ if (pointDistance(op1, p0) < pointDistance(op2, p0)) {
490
490
  cutPoint = op2;
491
491
  }
492
492
  const dy = cutPoint[1] - current[1], dx = cutPoint[0] - current[0];
@@ -542,10 +542,6 @@ export function expandLine(line: Array<Array<number>>, options?: ExpandLineOptio
542
542
  return { offsetPoints: points, leftPoints, rightPoints, line };
543
543
  }
544
544
 
545
- function equal(p1: Point, p2: Point) {
546
- return p1[0] === p2[0] && p1[1] === p2[1];
547
- }
548
-
549
545
 
550
546
  // eslint-disable-next-line no-unused-vars
551
547
  function calOffsetPoint(rad: number, radius: number, p: Point) {
@@ -567,10 +563,6 @@ const getAngle = ({ x: x1, y: y1 }, { x: x2, y: y2 }) => {
567
563
  // return (angle + 360) % 360;
568
564
  };
569
565
 
570
- function distance(p1: Point, p2: Point) {
571
- const dx = p2[0] - p1[0], dy = p2[1] - p1[1];
572
- return Math.sqrt(dx * dx + dy * dy);
573
- }
574
566
 
575
567
  export function leftOnLine(p: Point, p1: Point, p2: Point) {
576
568
  const [x1, y1] = p1;
@@ -0,0 +1,292 @@
1
+ import { PolylineType } from "./type";
2
+ import { mergeArray, pointDistance, pointEqual } from "./util";
3
+ import { Bezier } from 'bezier-js';
4
+ //https://github.com/bbecquet/Leaflet.PolylineOffset/blob/master/leaflet.polylineoffset.js
5
+
6
+ /**
7
+ Find the coefficients (a,b) of a line of equation y = a.x + b,
8
+ or the constant x for vertical lines
9
+ Return null if there's no equation possible
10
+ */
11
+ type Point = {
12
+ x: number;
13
+ y: number;
14
+ z: number;
15
+ }
16
+
17
+ function lineEquation(pt1: Point, pt2: Point) {
18
+ if (pt1.x === pt2.x) {
19
+ return pt1.y === pt2.y ? null : { x: pt1.x };
20
+ }
21
+
22
+ var a = (pt2.y - pt1.y) / (pt2.x - pt1.x);
23
+ return {
24
+ a: a,
25
+ b: pt1.y - a * pt1.x,
26
+ };
27
+ }
28
+
29
+ function calZ(p1: Point, p2: Point, p: Point) {
30
+ const dx = p2.x - p1.x, dy = p2.y - p1.y;
31
+ const distance = Math.sqrt(dx * dx + dy * dy);
32
+ const dx1 = p.x - p1.x, dy1 = p.y - p1.y;
33
+ const dis = Math.sqrt(dx1 * dx1 + dy1 * dy1);
34
+ const percent = dis / distance;
35
+ const dz = p2.z - p1.z;
36
+ return p1.z + dz * percent;
37
+ }
38
+
39
+ /**
40
+ Return the intersection point of two lines defined by two points each
41
+ Return null when there's no unique intersection
42
+ */
43
+ function intersection(l1a: Point, l1b: Point, l2a: Point, l2b: Point) {
44
+ var line1 = lineEquation(l1a, l1b);
45
+ var line2 = lineEquation(l2a, l2b);
46
+
47
+ if (line1 === null || line2 === null) {
48
+ return null;
49
+ }
50
+
51
+ if (line1.hasOwnProperty('x')) {
52
+ if (line2.hasOwnProperty('x')) {
53
+ return null;
54
+ }
55
+ const p = {
56
+ x: line1.x,
57
+ y: line2.a * line1.x + line2.b,
58
+ z: 0
59
+ };
60
+ p.z = calZ(l1a, l1b, p);
61
+ return p;
62
+ }
63
+ if (line2.hasOwnProperty('x')) {
64
+ const p = {
65
+ x: line2.x,
66
+ y: line1.a * line2.x + line1.b,
67
+ z: 0
68
+ };
69
+ p.z = calZ(l1a, l1b, p);
70
+ return p;
71
+
72
+ }
73
+
74
+ if (line1.a === line2.a) {
75
+ return null;
76
+ }
77
+
78
+ var x = (line2.b - line1.b) / (line1.a - line2.a);
79
+ const p = {
80
+ x: x,
81
+ y: line1.a * x + line1.b,
82
+ z: 0
83
+ };
84
+ p.z = calZ(l1a, l1b, p);
85
+ return p;
86
+ }
87
+
88
+ function translatePoint(pt: Point, dist: number, heading: number) {
89
+ return {
90
+ x: pt.x + dist * Math.cos(heading),
91
+ y: pt.y + dist * Math.sin(heading),
92
+ z: pt.z || 0
93
+ };
94
+ }
95
+
96
+ function offsetPointLine(points, distance: number) {
97
+ var offsetSegments = [];
98
+ for (let i = 1, len = points.length; i < len; i++) {
99
+ let a = points[i - 1], b = points[i];
100
+ const [x1, y1, z1] = a;
101
+ const [x2, y2, z2] = b;
102
+ if (x1 === x2 && y1 === y2) {
103
+ continue;
104
+ }
105
+ a = {
106
+ x: x1,
107
+ y: y1,
108
+ z: z1 || 0
109
+ };
110
+ b = {
111
+ x: x2,
112
+ y: y2,
113
+ z: z2 || 0
114
+ }
115
+ var segmentAngle = Math.atan2(a.y - b.y, a.x - b.x);
116
+ var offsetAngle = segmentAngle - Math.PI / 2;
117
+
118
+ offsetSegments.push({
119
+ offsetAngle: offsetAngle,
120
+ original: [a, b],
121
+ offset: [
122
+ translatePoint(a, distance, offsetAngle),
123
+ translatePoint(b, distance, offsetAngle)
124
+ ]
125
+ });
126
+ }
127
+ return offsetSegments;
128
+
129
+
130
+ }
131
+
132
+ /**
133
+ Join 2 line segments defined by 2 points each with a circular arc
134
+ */
135
+ function joinSegments(s1, s2, offset) {
136
+ // TODO: different join styles
137
+ return circularArc(s1, s2, offset)
138
+ .filter(function (x) { return x; })
139
+ }
140
+
141
+ function joinLineSegments(segments, offset) {
142
+ var joinedPoints = [];
143
+ var first = segments[0];
144
+ var last = segments[segments.length - 1];
145
+
146
+ if (first && last) {
147
+ joinedPoints.push(first.offset[0]);
148
+ for (let i = 1, len = segments.length; i < len; i++) {
149
+ let s1 = segments[i - 1], s2 = segments[i];
150
+ const pts = joinSegments(s1, s2, offset);
151
+ mergeArray(joinedPoints, pts);
152
+ }
153
+ joinedPoints.push(last.offset[1]);
154
+ }
155
+
156
+ return joinedPoints;
157
+ }
158
+
159
+ function segmentAsVector(s) {
160
+ return {
161
+ x: s[1].x - s[0].x,
162
+ y: s[1].y - s[0].y,
163
+ };
164
+ }
165
+
166
+ function getSignedAngle(s1, s2) {
167
+ const a = segmentAsVector(s1);
168
+ const b = segmentAsVector(s2);
169
+ return Math.atan2(a.x * b.y - a.y * b.x, a.x * b.x + a.y * b.y);
170
+ }
171
+
172
+ /**
173
+ Interpolates points between two offset segments in a circular form
174
+ */
175
+ function circularArc(s1, s2, distance) {
176
+ // if the segments are the same angle,
177
+ // there should be a single join point
178
+ if (s1.offsetAngle === s2.offsetAngle) {
179
+ return [s1.offset[1]];
180
+ }
181
+
182
+ const signedAngle = getSignedAngle(s1.offset, s2.offset);
183
+ // for inner angles, just find the offset segments intersection
184
+ if ((signedAngle * distance > 0) &&
185
+ (signedAngle * getSignedAngle(s1.offset, [s1.offset[0], s2.offset[1]]) > 0)) {
186
+ return [intersection(s1.offset[0], s1.offset[1], s2.offset[0], s2.offset[1])];
187
+ }
188
+
189
+ // draws a circular arc with R = offset distance, C = original meeting point
190
+ var points = [];
191
+ var center = s1.original[1];
192
+ // ensure angles go in the anti-clockwise direction
193
+ var rightOffset = distance > 0;
194
+ var startAngle = rightOffset ? s2.offsetAngle : s1.offsetAngle;
195
+ var endAngle = rightOffset ? s1.offsetAngle : s2.offsetAngle;
196
+ // and that the end angle is bigger than the start angle
197
+ if (endAngle < startAngle) {
198
+ endAngle += Math.PI * 2;
199
+ }
200
+ var step = Math.PI / 8;
201
+ for (var alpha = startAngle; alpha < endAngle; alpha += step) {
202
+ points.push(translatePoint(center, distance, alpha));
203
+ }
204
+ points.push(translatePoint(center, distance, endAngle));
205
+
206
+ return rightOffset ? points.reverse() : points;
207
+ }
208
+
209
+
210
+ function offsetPoints(pts: PolylineType, options: polylineOffsetOptions) {
211
+ var offsetSegments = offsetPointLine(pts, options.offset);
212
+ return joinLineSegments(offsetSegments, options.offset);
213
+ }
214
+
215
+ type polylineOffsetOptions = {
216
+ offset: number
217
+ }
218
+ export function polylineOffset(line: PolylineType, options: polylineOffsetOptions): PolylineType {
219
+ options = Object.assign({ offset: 0 }, options);
220
+ if (options.offset === 0) {
221
+ return line;
222
+ }
223
+ const pts = offsetPoints(line, options);
224
+ const result = [];
225
+ for (let i = 0, len = pts.length; i < len; i++) {
226
+ const pt = pts[i];
227
+ if (!pt) {
228
+ continue;
229
+ }
230
+ const { x, y, z } = pt;
231
+ result.push([x, y, z]);
232
+ }
233
+ return result;
234
+ }
235
+
236
+ type polylineRoundOptions = {
237
+ roundSize: number,
238
+ steps?: number;
239
+ }
240
+
241
+ export function polylineRound(line: PolylineType, options: polylineRoundOptions): PolylineType {
242
+ options = Object.assign({ roundSize: 0, steps: 10 }, options);
243
+ if (options.roundSize === 0) {
244
+ return line;
245
+ }
246
+ if (!line || line.length < 3) {
247
+ return line;
248
+ }
249
+ const len = line.length;
250
+ const { roundSize, steps } = options;
251
+
252
+ const pts = [line[0]];
253
+ let pre = line[0];
254
+
255
+ for (let i = 1; i < len; i++) {
256
+ const p1 = line[i - 1], p2 = line[i], p3 = line[i + 1];
257
+ if (pointEqual(pre, p2)) {
258
+ continue;
259
+ }
260
+ if (!p3) {
261
+ continue;
262
+ }
263
+ const d1 = pointDistance(p2, p1), d2 = pointDistance(p2, p3);
264
+ if (d1 < roundSize || d2 < roundSize) {
265
+ pre = p2;
266
+ pts.push(p2);
267
+ continue;
268
+ }
269
+ const dx1 = p2[0] - p1[0], dy1 = p2[1] - p1[1];
270
+ const dx2 = p3[0] - p2[0], dy2 = p3[1] - p2[1];
271
+
272
+ const percent1 = (d1 - roundSize) / d1;
273
+ const percent2 = roundSize / d2;
274
+ const c1 = {
275
+ x: p1[0] + percent1 * dx1,
276
+ y: p1[1] + percent1 * dy1
277
+ };
278
+ const c2 = {
279
+ x: p2[0] + percent2 * dx2,
280
+ y: p2[1] + percent2 * dy2
281
+ };
282
+ const be = new Bezier([c1, { x: p2[0], y: p2[1] }, c2]);
283
+ const path = be.getLUT(steps);
284
+ for (let j = 0, len1 = path.length; j < len1; j++) {
285
+ const p = path[j];
286
+ pts.push([p.x, p.y]);
287
+ }
288
+ pre = p2;
289
+ }
290
+ pts.push(line[len- 1]);
291
+ return pts;
292
+ }
package/src/util.ts CHANGED
@@ -1,6 +1,8 @@
1
1
  import { Vector3 } from './math/Vector3';
2
2
  import { PolygonType, PolylineType, ResultType } from './type';
3
3
 
4
+ type Point = Array<number>;
5
+
4
6
  export function mergeArray(array1, array2) {
5
7
  let index = array1.length - 1;
6
8
  for (let i = 0, len = array2.length; i < len; i++) {
@@ -310,3 +312,13 @@ export function calLineDistance(line) {
310
312
  }
311
313
  return distance;
312
314
  }
315
+
316
+
317
+ export function pointEqual(p1: Point, p2: Point) {
318
+ return p1[0] === p2[0] && p1[1] === p2[1];
319
+ }
320
+
321
+ export function pointDistance(p1: Point, p2: Point) {
322
+ const dx = p2[0] - p1[0], dy = p2[1] - p1[1];
323
+ return Math.sqrt(dx * dx + dy * dy);
324
+ }