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/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/poly-extrude.js +2256 -21
- package/dist/poly-extrude.js.map +1 -1
- package/dist/poly-extrude.min.js +2 -2
- package/dist/poly-extrude.mjs +2255 -22
- package/dist/poly-extrude.mjs.map +1 -1
- package/dist/polyline.js +14 -21
- package/dist/polyline.js.map +1 -1
- package/dist/polylineoffset.d.ts +11 -0
- package/dist/polylineoffset.js +241 -0
- package/dist/polylineoffset.js.map +1 -0
- package/dist/util.d.ts +4 -0
- package/dist/util.js +7 -0
- package/dist/util.js.map +1 -1
- package/package.json +53 -52
- package/src/index.ts +4 -1
- package/src/polyline.ts +14 -22
- package/src/polylineoffset.ts +292 -0
- package/src/util.ts +12 -0
package/package.json
CHANGED
@@ -1,53 +1,54 @@
|
|
1
|
-
{
|
2
|
-
"name": "poly-extrude",
|
3
|
-
"version": "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
|
-
"
|
43
|
-
"
|
44
|
-
},
|
45
|
-
"dependencies": {
|
46
|
-
"
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
"
|
51
|
-
"
|
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 &&
|
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 (
|
364
|
+
if (pointEqual(p1, p2)) {
|
365
365
|
for (let j = line.indexOf(p1); j >= 0; j--) {
|
366
366
|
const p = line[j];
|
367
|
-
if (!
|
367
|
+
if (!pointEqual(p, current)) {
|
368
368
|
p1 = p;
|
369
369
|
break;
|
370
370
|
}
|
371
371
|
}
|
372
372
|
}
|
373
373
|
} else {
|
374
|
-
if (
|
374
|
+
if (pointEqual(p1, p2)) {
|
375
375
|
for (let j = line.indexOf(p2); j < len; j++) {
|
376
376
|
const p = line[j];
|
377
|
-
if (!
|
377
|
+
if (!pointEqual(p, current)) {
|
378
378
|
p2 = p;
|
379
379
|
break;
|
380
380
|
}
|
381
381
|
}
|
382
382
|
}
|
383
|
-
if (
|
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 (!
|
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 (
|
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 (
|
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 (!
|
416
|
+
if (!pointEqual(p, p2) && (!pointEqual(p, p1))) {
|
417
417
|
p0 = p;
|
418
418
|
break;
|
419
419
|
}
|
420
420
|
}
|
421
421
|
}
|
422
|
-
if (
|
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 (
|
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 (
|
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
|
+
}
|