poly-extrude 0.13.0 → 0.15.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.
Files changed (68) hide show
  1. package/dist/cylinder.d.ts +11 -0
  2. package/{src → dist}/cylinder.js +108 -111
  3. package/dist/cylinder.js.map +1 -0
  4. package/dist/index.d.ts +8 -0
  5. package/dist/index.js +9 -0
  6. package/dist/index.js.map +1 -0
  7. package/dist/math/Curve.d.ts +41 -0
  8. package/dist/math/Curve.js +142 -0
  9. package/dist/math/Curve.js.map +1 -0
  10. package/dist/math/Interpolations.d.ts +8 -0
  11. package/dist/math/Interpolations.js +48 -0
  12. package/dist/math/Interpolations.js.map +1 -0
  13. package/dist/math/Matrix4.d.ts +8 -0
  14. package/dist/math/Matrix4.js +582 -0
  15. package/dist/math/Matrix4.js.map +1 -0
  16. package/dist/math/QuadraticBezierCurve3.d.ts +10 -0
  17. package/dist/math/QuadraticBezierCurve3.js +22 -0
  18. package/dist/math/QuadraticBezierCurve3.js.map +1 -0
  19. package/dist/math/Quaternion.d.ts +46 -0
  20. package/dist/math/Quaternion.js +415 -0
  21. package/dist/math/Quaternion.js.map +1 -0
  22. package/dist/math/Vector3.d.ts +42 -0
  23. package/dist/math/Vector3.js +403 -0
  24. package/dist/math/Vector3.js.map +1 -0
  25. package/dist/path/PathPoint.d.ts +15 -0
  26. package/dist/path/PathPoint.js +35 -0
  27. package/dist/path/PathPoint.js.map +1 -0
  28. package/dist/path/PathPointList.d.ts +27 -0
  29. package/dist/path/PathPointList.js +212 -0
  30. package/dist/path/PathPointList.js.map +1 -0
  31. package/dist/path.d.ts +11 -0
  32. package/{src → dist}/path.js +334 -360
  33. package/dist/path.js.map +1 -0
  34. package/dist/plane.d.ts +2 -0
  35. package/{src → dist}/plane.js +57 -58
  36. package/dist/plane.js.map +1 -0
  37. package/dist/poly-extrude.js +1288 -1581
  38. package/dist/poly-extrude.js.map +1 -1
  39. package/dist/poly-extrude.min.js +2 -2
  40. package/dist/poly-extrude.mjs +1287 -1582
  41. package/dist/poly-extrude.mjs.map +1 -0
  42. package/dist/polygon.d.ts +9 -0
  43. package/{src → dist}/polygon.js +163 -179
  44. package/dist/polygon.js.map +1 -0
  45. package/dist/polyline.d.ts +24 -0
  46. package/{src → dist}/polyline.js +420 -456
  47. package/dist/polyline.js.map +1 -0
  48. package/dist/tube.d.ts +12 -0
  49. package/{src → dist}/tube.js +124 -142
  50. package/dist/tube.js.map +1 -0
  51. package/dist/type.d.ts +9 -0
  52. package/dist/type.js +2 -0
  53. package/dist/type.js.map +1 -0
  54. package/dist/util.d.ts +21 -0
  55. package/{src → dist}/util.js +217 -242
  56. package/dist/util.js.map +1 -0
  57. package/package.json +10 -5
  58. package/readme.md +12 -2
  59. package/src/cylinder.ts +124 -0
  60. package/src/index.ts +13 -0
  61. package/src/path.ts +385 -0
  62. package/src/plane.ts +60 -0
  63. package/src/polygon.ts +189 -0
  64. package/src/polyline.ts +473 -0
  65. package/src/tube.ts +155 -0
  66. package/src/type.ts +9 -0
  67. package/src/util.ts +243 -0
  68. package/index.js +0 -7
package/src/polygon.ts ADDED
@@ -0,0 +1,189 @@
1
+
2
+ import earcut from 'earcut';
3
+ import { generateNormal, generateSideWallUV, isClockwise, merge } from './util';
4
+ import { PolylineType, PolygonType, ResultType } from './type';
5
+
6
+ type PolygonsOptions = {
7
+ depth?: number
8
+ }
9
+
10
+ type PolygonsResult = ResultType & {
11
+ polygons: Array<PolygonType>;
12
+ }
13
+
14
+
15
+ export function extrudePolygons(polygons: Array<PolygonType>, options?: PolygonsOptions): PolygonsResult {
16
+ options = Object.assign({}, { depth: 2 }, options);
17
+ const results = polygons.map(polygon => {
18
+ for (let i = 0, len = polygon.length; i < len; i++) {
19
+ const ring = polygon[i];
20
+ validateRing(ring);
21
+ if (i === 0) {
22
+ if (!isClockwise(ring)) {
23
+ polygon[i] = ring.reverse();
24
+ }
25
+ } else if (isClockwise(ring)) {
26
+ polygon[i] = ring.reverse();
27
+ }
28
+ if (isClosedRing(ring)) {
29
+ ring.splice(ring.length - 1, 1);
30
+ }
31
+ }
32
+ const result = flatVertices(polygon, options) as Record<string, any>;
33
+ result.polygon = polygon;
34
+ const triangles = earcut(result.flatVertices, result.holes, 2);
35
+ generateTopAndBottom(result, triangles);
36
+ generateSides(result, options);
37
+ result.position = new Float32Array(result.points);
38
+ result.indices = new Uint32Array(result.indices);
39
+ result.uv = new Float32Array(result.uv);
40
+ result.normal = generateNormal(result.indices, result.position);
41
+ return result;
42
+ });
43
+ const result = merge(results as Array<ResultType>) as PolygonsResult;
44
+ result.polygons = polygons;
45
+ return result;
46
+
47
+ }
48
+
49
+ function generateTopAndBottom(result, triangles) {
50
+ const indices: number[] = [];
51
+ const { count } = result;
52
+ for (let i = 0, len = triangles.length; i < len; i += 3) {
53
+ // top
54
+ const a = triangles[i], b = triangles[i + 1], c = triangles[i + 2];
55
+ indices[i] = a;
56
+ indices[i + 1] = b;
57
+ indices[i + 2] = c;
58
+ // bottom
59
+ const idx = len + i;
60
+ const a1 = count + a, b1 = count + b, c1 = count + c;
61
+ indices[idx] = a1;
62
+ indices[idx + 1] = b1;
63
+ indices[idx + 2] = c1;
64
+ }
65
+ result.indices = indices;
66
+ }
67
+
68
+ function generateSides(result, options) {
69
+ const { points, indices, polygon, uv } = result;
70
+ const depth = options.depth;
71
+ let pIndex = points.length - 1;
72
+ let iIndex = indices.length - 1;
73
+ for (let i = 0, len = polygon.length; i < len; i++) {
74
+ const ring = polygon[i];
75
+ let j = 0;
76
+ const len1 = ring.length;
77
+ while (j < len1) {
78
+ const v1 = ring[j];
79
+ let v2 = ring[j + 1];
80
+ if (j === len1 - 1) {
81
+ v2 = ring[0];
82
+ }
83
+ const idx = points.length / 3;
84
+ const x1 = v1[0], y1 = v1[1], z1 = v1[2] || 0, x2 = v2[0], y2 = v2[1], z2 = v2[2] || 0;
85
+ points[++pIndex] = x1;
86
+ points[++pIndex] = y1;
87
+ points[++pIndex] = z1 + depth;
88
+ points[++pIndex] = x2;
89
+ points[++pIndex] = y2;
90
+ points[++pIndex] = z2 + depth;
91
+ points[++pIndex] = x1;
92
+ points[++pIndex] = y1;
93
+ points[++pIndex] = z1;
94
+ points[++pIndex] = x2;
95
+ points[++pIndex] = y2;
96
+ points[++pIndex] = z2;
97
+ // points.push(x1, y1, z, x2, y2, z, x1, y1, 0, x2, y2, 0);
98
+ const a = idx + 2, b = idx + 3, c = idx, d = idx + 1;
99
+ // points.push(p3, p4, p1, p2);
100
+ // index.push(a, c, b, c, d, b);
101
+ indices[++iIndex] = a;
102
+ indices[++iIndex] = c;
103
+ indices[++iIndex] = b;
104
+ indices[++iIndex] = c;
105
+ indices[++iIndex] = d;
106
+ indices[++iIndex] = b;
107
+ // index.push(c, d, b);
108
+
109
+ generateSideWallUV(uv, points, a, b, c, d);
110
+ j++;
111
+ }
112
+ }
113
+ }
114
+
115
+ function calPolygonPointsCount(polygon) {
116
+ let count = 0;
117
+ let i = 0;
118
+ const len = polygon.length;
119
+ while (i < len) {
120
+ count += (polygon[i].length);
121
+ i++;
122
+ }
123
+ return count;
124
+ }
125
+
126
+ function flatVertices(polygon, options) {
127
+ const count = calPolygonPointsCount(polygon);
128
+ const len = polygon.length;
129
+ const holes: number[] = [], flatVertices = new Float32Array(count * 2), points: number[] = [], uv: number[] = [];
130
+ const pOffset = count * 3, uOffset = count * 2;
131
+ const depth = options.depth;
132
+
133
+ let idx0 = 0, idx1 = 0, idx2 = 0;
134
+ for (let i = 0; i < len; i++) {
135
+ const ring = polygon[i];
136
+ if (i > 0) {
137
+ holes.push(idx0 / 2);
138
+ }
139
+ let j = 0;
140
+ const len1 = ring.length;
141
+ while (j < len1) {
142
+ const c = ring[j];
143
+ const x = c[0], y = c[1], z = c[2] || 0;
144
+
145
+ flatVertices[idx0++] = x;
146
+ flatVertices[idx0++] = y;
147
+
148
+ // top vertices
149
+ points[idx1] = x;
150
+ points[idx1 + 1] = y;
151
+ points[idx1 + 2] = depth + z;
152
+
153
+ // bottom vertices
154
+ points[pOffset + idx1] = x;
155
+ points[pOffset + idx1 + 1] = y;
156
+ points[pOffset + idx1 + 2] = z;
157
+
158
+ uv[idx2] = x;
159
+ uv[idx2 + 1] = y;
160
+
161
+ uv[uOffset + idx2] = x;
162
+ uv[uOffset + idx2 + 1] = y;
163
+
164
+ idx1 += 3;
165
+ idx2 += 2;
166
+ j++;
167
+ }
168
+ }
169
+ return {
170
+ flatVertices,
171
+ holes,
172
+ points,
173
+ count,
174
+ uv
175
+ };
176
+
177
+ }
178
+
179
+ function validateRing(ring: PolylineType) {
180
+ if (!isClosedRing(ring)) {
181
+ ring.push(ring[0]);
182
+ }
183
+ }
184
+
185
+ function isClosedRing(ring: PolylineType) {
186
+ const len = ring.length;
187
+ const [x1, y1] = ring[0], [x2, y2] = ring[len - 1];
188
+ return (x1 === x2 && y1 === y2);
189
+ }
@@ -0,0 +1,473 @@
1
+ import { PolylineType, ResultType } from './type';
2
+ import { calLineDistance, degToRad, generateNormal, generateSideWallUV, merge, radToDeg } from './util';
3
+
4
+ function checkOptions(options) {
5
+ options.lineWidth = Math.max(0, options.lineWidth);
6
+ options.depth = Math.max(0, options.depth);
7
+ options.sideDepth = Math.max(0, options.sideDepth);
8
+ }
9
+
10
+ type PolylinesOptions = {
11
+ depth?: number;
12
+ lineWidth?: number;
13
+ bottomStickGround?: boolean;
14
+ pathUV?: boolean;
15
+ }
16
+
17
+ type PolylinesResult = ResultType & {
18
+ lines: Array<PolylineType>;
19
+ }
20
+
21
+ export function extrudePolylines(lines: Array<PolylineType>, options?: PolylinesOptions): PolylinesResult {
22
+ options = Object.assign({}, { depth: 2, lineWidth: 1, bottomStickGround: false, pathUV: false }, options);
23
+ checkOptions(options);
24
+ const results = lines.map(line => {
25
+ const result = expandLine(line, options) as Record<string, any>;
26
+ result.line = line;
27
+ generateTopAndBottom(result, options);
28
+ generateSides(result, options);
29
+ result.position = new Float32Array(result.points);
30
+ result.indices = new Uint32Array(result.indices);
31
+ result.uv = new Float32Array(result.uv);
32
+ result.normal = generateNormal(result.indices, result.position);
33
+ return result;
34
+ });
35
+ const result = merge(results as Array<ResultType>) as PolylinesResult;
36
+ result.lines = lines;
37
+ return result;
38
+ }
39
+
40
+ type SlopesOptions = PolylinesOptions & {
41
+ side?: 'left' | 'right',
42
+ sideDepth?: number
43
+ }
44
+
45
+ export function extrudeSlopes(lines: Array<PolylineType>, options?: SlopesOptions): PolylinesResult {
46
+ options = Object.assign({}, { depth: 2, lineWidth: 1, side: 'left', sideDepth: 0, bottomStickGround: false, pathUV: false, isSlope: true }, options);
47
+ checkOptions(options);
48
+ const { depth, side, sideDepth } = options;
49
+ const results = lines.map(line => {
50
+ const tempResult = expandLine(line, options);
51
+ tempResult.line = line;
52
+ const { leftPoints, rightPoints } = tempResult;
53
+ const result: Record<string, any> = { line };
54
+ let depths;
55
+ for (let i = 0, len = line.length; i < len; i++) {
56
+ line[i][2] = line[i][2] || 0;
57
+ }
58
+ if (side === 'left') {
59
+ result.leftPoints = leftPoints;
60
+ result.rightPoints = line;
61
+ depths = [sideDepth, depth];
62
+ } else {
63
+ result.leftPoints = line;
64
+ result.rightPoints = rightPoints;
65
+ depths = [depth, sideDepth];
66
+ }
67
+ result.depths = depths;
68
+ generateTopAndBottom(result, options);
69
+ generateSides(result, options);
70
+ result.position = new Float32Array(result.points);
71
+ result.indices = new Uint32Array(result.indices);
72
+ result.uv = new Float32Array(result.uv);
73
+ result.normal = generateNormal(result.indices, result.position);
74
+ return result;
75
+ });
76
+ const result = merge(results as Array<ResultType>) as PolylinesResult;
77
+ result.lines = lines;
78
+ return result;
79
+ }
80
+
81
+ function generateTopAndBottom(result, options) {
82
+ const bottomStickGround = options.bottomStickGround;
83
+ const z = options.depth;
84
+ const depths = result.depths;
85
+ let lz = z, rz = z;
86
+ if (depths) {
87
+ lz = depths[0];
88
+ rz = depths[1];
89
+ }
90
+ const { leftPoints, rightPoints } = result;
91
+ const line = result.line;
92
+ const pathUV = options.pathUV;
93
+ if (pathUV) {
94
+ calLineDistance(line);
95
+ for (let i = 0, len = line.length; i < len; i++) {
96
+ leftPoints[i].distance = rightPoints[i].distance = line[i].distance;
97
+ }
98
+ }
99
+ let i = 0, len = leftPoints.length;
100
+ const points: number[] = [], indices: number[] = [], uv: number[] = [];
101
+ while (i < len) {
102
+ // top left
103
+ const idx0 = i * 3;
104
+ const [x1, y1, z1] = leftPoints[i];
105
+ points[idx0] = x1;
106
+ points[idx0 + 1] = y1;
107
+ points[idx0 + 2] = lz + z1;
108
+
109
+ // top right
110
+ const [x2, y2, z2] = rightPoints[i];
111
+ const idx1 = len * 3 + idx0;
112
+ points[idx1] = x2;
113
+ points[idx1 + 1] = y2;
114
+ points[idx1 + 2] = rz + z2;
115
+
116
+ // bottom left
117
+ const idx2 = (len * 2) * 3 + idx0;
118
+ points[idx2] = x1;
119
+ points[idx2 + 1] = y1;
120
+ points[idx2 + 2] = z1;
121
+ if (bottomStickGround) {
122
+ points[idx2 + 2] = 0;
123
+ }
124
+
125
+ // bottom right
126
+ const idx3 = (len * 2) * 3 + len * 3 + idx0;
127
+ points[idx3] = x2;
128
+ points[idx3 + 1] = y2;
129
+ points[idx3 + 2] = z2;
130
+ if (bottomStickGround) {
131
+ points[idx3 + 2] = 0;
132
+ }
133
+
134
+ // generate path uv
135
+ if (pathUV) {
136
+ const p = line[i];
137
+ const uvx = p.distance;
138
+
139
+ const uIndex0 = i * 2;
140
+ uv[uIndex0] = uvx;
141
+ uv[uIndex0 + 1] = 1;
142
+
143
+ const uIndex1 = len * 2 + uIndex0;
144
+ uv[uIndex1] = uvx;
145
+ uv[uIndex1 + 1] = 0;
146
+
147
+ const uIndex2 = (len * 2) * 2 + uIndex0;
148
+ uv[uIndex2] = uvx;
149
+ uv[uIndex2 + 1] = 1;
150
+
151
+ const uIndex3 = (len * 2) * 2 + len * 2 + uIndex0;
152
+ uv[uIndex3] = uvx;
153
+ uv[uIndex3 + 1] = 0;
154
+
155
+ }
156
+ i++;
157
+ }
158
+ if (!pathUV) {
159
+ i = 0;
160
+ len = points.length;
161
+ let uIndex = uv.length - 1;
162
+ while (i < len) {
163
+ const x = points[i], y = points[i + 1];
164
+ uv[++uIndex] = x;
165
+ uv[++uIndex] = y;
166
+ // uvs.push(x, y);
167
+ i += 3;
168
+ }
169
+ }
170
+
171
+ i = 0;
172
+ len = leftPoints.length;
173
+ let iIndex = indices.length - 1;
174
+ while (i < len - 1) {
175
+ // top
176
+ // left1 left2 right1,right2
177
+ const a1 = i, b1 = i + 1, c1 = a1 + len, d1 = b1 + len;
178
+ indices[++iIndex] = a1;
179
+ indices[++iIndex] = c1;
180
+ indices[++iIndex] = b1;
181
+ indices[++iIndex] = c1;
182
+ indices[++iIndex] = d1;
183
+ indices[++iIndex] = b1;
184
+ // index.push(a1, c1, b1);
185
+ // index.push(c1, d1, b1);
186
+
187
+ // bottom
188
+ // left1 left2 right1,right2
189
+ const len2 = len * 2;
190
+ const a2 = i + len2, b2 = a2 + 1, c2 = a2 + len, d2 = b2 + len;
191
+ indices[++iIndex] = a2;
192
+ indices[++iIndex] = c2;
193
+ indices[++iIndex] = b2;
194
+ indices[++iIndex] = c2;
195
+ indices[++iIndex] = d2;
196
+ indices[++iIndex] = b2;
197
+ // index.push(a2, c2, b2);
198
+ // index.push(c2, d2, b2);
199
+ i++;
200
+ }
201
+ result.indices = indices;
202
+ result.points = points;
203
+ result.uv = uv;
204
+ if (depths) {
205
+ len = leftPoints.length;
206
+ i = 0;
207
+ while (i < len) {
208
+ leftPoints[i].depth = lz;
209
+ rightPoints[i].depth = rz;
210
+ i++;
211
+ }
212
+ }
213
+ }
214
+
215
+ function generateSides(result, options) {
216
+ const { points, indices, leftPoints, rightPoints, uv } = result;
217
+ const z = options.depth;
218
+ const bottomStickGround = options.bottomStickGround;
219
+ const rings = [leftPoints, rightPoints];
220
+ const depthsEnable = result.depths;
221
+ const pathUV = options.pathUV;
222
+ const lineWidth = options.lineWidth;
223
+
224
+ let pIndex = points.length - 1;
225
+ let iIndex = indices.length - 1;
226
+ let uIndex = uv.length - 1;
227
+
228
+ function addOneSideIndex(v1, v2) {
229
+ const idx = points.length / 3;
230
+ // let pIndex = points.length - 1;
231
+
232
+ const v1Depth = (depthsEnable ? v1.depth : z);
233
+ const v2Depth = (depthsEnable ? v2.depth : z);
234
+
235
+ // top
236
+ points[++pIndex] = v1[0];
237
+ points[++pIndex] = v1[1];
238
+ points[++pIndex] = v1Depth + v1[2];
239
+
240
+ points[++pIndex] = v2[0];
241
+ points[++pIndex] = v2[1];
242
+ points[++pIndex] = v2Depth + v2[2];
243
+
244
+ // points.push(v1[0], v1[1], (depthsEnable ? v1.depth : z) + v1[2], v2[0], v2[1], (depthsEnable ? v2.depth : z) + v2[2]);
245
+
246
+ // bottom
247
+
248
+ points[++pIndex] = v1[0];
249
+ points[++pIndex] = v1[1];
250
+ points[++pIndex] = bottomStickGround ? 0 : v1[2];
251
+
252
+ points[++pIndex] = v2[0];
253
+ points[++pIndex] = v2[1];
254
+ points[++pIndex] = bottomStickGround ? 0 : v2[2];
255
+
256
+ // points.push(v1[0], v1[1], v1[2], v2[0], v2[1], v2[2]);
257
+
258
+ const a = idx + 2, b = idx + 3, c = idx, d = idx + 1;
259
+ indices[++iIndex] = a;
260
+ indices[++iIndex] = c;
261
+ indices[++iIndex] = b;
262
+ indices[++iIndex] = c;
263
+ indices[++iIndex] = d;
264
+ indices[++iIndex] = b;
265
+ // index.push(a, c, b, c, d, b);
266
+ if (!pathUV) {
267
+ generateSideWallUV(uv, points, a, b, c, d);
268
+ } else {
269
+ uv[++uIndex] = v1.distance;
270
+ uv[++uIndex] = v1Depth / lineWidth;
271
+
272
+ uv[++uIndex] = v2.distance;
273
+ uv[++uIndex] = v2Depth / lineWidth;
274
+
275
+ uv[++uIndex] = v1.distance;
276
+ uv[++uIndex] = 0;
277
+
278
+ uv[++uIndex] = v2.distance;
279
+ uv[++uIndex] = 0;
280
+ }
281
+ }
282
+
283
+ for (let i = 0, len = rings.length; i < len; i++) {
284
+ let ring = rings[i];
285
+ if (i > 0) {
286
+ ring = ring.map(p => {
287
+ return p;
288
+ });
289
+ ring = ring.reverse();
290
+ }
291
+ let j = 0;
292
+ const len1 = ring.length - 1;
293
+ while (j < len1) {
294
+ const v1 = ring[j];
295
+ const v2 = ring[j + 1];
296
+ addOneSideIndex(v1, v2);
297
+ j++;
298
+ }
299
+ }
300
+ const len = leftPoints.length;
301
+ const vs = [rightPoints[0], leftPoints[0], leftPoints[len - 1], rightPoints[len - 1]];
302
+ for (let i = 0; i < vs.length; i += 2) {
303
+ const v1 = vs[i], v2 = vs[i + 1];
304
+ addOneSideIndex(v1, v2);
305
+ }
306
+ }
307
+
308
+ const TEMPV1 = { x: 0, y: 0 }, TEMPV2 = { x: 0, y: 0 };
309
+
310
+ export function expandLine(line, options) {
311
+ // let preAngle = 0;
312
+ let radius = options.lineWidth / 2;
313
+ if (options.isSlope) {
314
+ radius *= 2;
315
+ }
316
+ const points: Array<number[]> = [], leftPoints: Array<number[]> = [], rightPoints: Array<number[]> = [];
317
+ const len = line.length;
318
+ let i = 0;
319
+ while (i < len) {
320
+ let p1 = line[i],
321
+ p2 = line[i + 1];
322
+ const currentp = line[i];
323
+ // last vertex
324
+ if (i === len - 1) {
325
+ p1 = line[len - 2];
326
+ p2 = line[len - 1];
327
+ }
328
+ const dy = p2[1] - p1[1],
329
+ dx = p2[0] - p1[0];
330
+ let rAngle = 0;
331
+ const rad = Math.atan(dy / dx);
332
+ const angle = radToDeg(rad);
333
+ // preAngle = angle;
334
+ if (i === 0 || i === len - 1) {
335
+ rAngle = angle;
336
+ rAngle -= 90;
337
+ } else {
338
+ // 至少3个顶点才会触发
339
+ const p0 = line[i - 1];
340
+ TEMPV1.x = p0[0] - p1[0];
341
+ TEMPV1.y = p0[1] - p1[1];
342
+ TEMPV2.x = p2[0] - p1[0];
343
+ TEMPV2.y = p2[1] - p1[1];
344
+ const vAngle = getAngle(TEMPV1, TEMPV2);
345
+ rAngle = angle - vAngle / 2;
346
+ }
347
+ const rRad = degToRad(rAngle);
348
+ const p3 = currentp;
349
+ const x = Math.cos(rRad) + p3[0], y = Math.sin(rRad) + p3[1];
350
+ const p4 = [x, y];
351
+ const [line1, line2] = translateLine(p1, p2, radius);
352
+ let op1 = lineIntersection(line1[0], line1[1], p3, p4);
353
+ let op2 = lineIntersection(line2[0], line2[1], p3, p4);
354
+ // 平行,回头路
355
+ if (!op1 || !op2) {
356
+ const len1 = points.length;
357
+ const point1 = points[len1 - 2];
358
+ const point2 = points[len1 - 1];
359
+ if (!point1 || !point2) {
360
+ continue;
361
+ }
362
+ op1 = [point1[0], point1[1]];
363
+ op2 = [point2[0], point2[1]];
364
+ }
365
+ op1[2] = currentp[2] || 0;
366
+ op2[2] = currentp[2] || 0;
367
+ // const [op1, op2] = calOffsetPoint(rRad, radius, p1);
368
+ points.push(op1, op2);
369
+ if (leftOnLine(op1, p1, p2)) {
370
+ leftPoints.push(op1);
371
+ rightPoints.push(op2);
372
+ } else {
373
+ leftPoints.push(op2);
374
+ rightPoints.push(op1);
375
+ }
376
+ i++;
377
+ }
378
+
379
+ return { offsetPoints: points, leftPoints, rightPoints, line };
380
+ }
381
+
382
+ // eslint-disable-next-line no-unused-vars
383
+ function calOffsetPoint(rad, radius, p) {
384
+ const [x, y] = p;
385
+ const z = p[2] || 0;
386
+ const x1 = Math.cos(rad) * radius, y1 = Math.sin(rad) * radius;
387
+ const p1 = [x + x1, y + y1, z];
388
+ const rad1 = rad += Math.PI;
389
+ const x2 = Math.cos(rad1) * radius, y2 = Math.sin(rad1) * radius;
390
+ const p2 = [x + x2, y + y2, z];
391
+ return [p1, p2];
392
+ }
393
+
394
+ const getAngle = ({ x: x1, y: y1 }, { x: x2, y: y2 }) => {
395
+ const dot = x1 * x2 + y1 * y2;
396
+ const det = x1 * y2 - y1 * x2;
397
+ const angle = Math.atan2(det, dot) / Math.PI * 180;
398
+ return (angle + 360) % 360;
399
+ };
400
+
401
+ export function leftOnLine(p, p1, p2) {
402
+ const [x1, y1] = p1;
403
+ const [x2, y2] = p2;
404
+ const [x, y] = p;
405
+ return (y1 - y2) * x + (x2 - x1) * y + x1 * y2 - x2 * y1 > 0;
406
+ }
407
+
408
+ /**
409
+ * 平移线
410
+ * @param {*} p1
411
+ * @param {*} p2
412
+ * @param {*} distance
413
+ * @returns
414
+ */
415
+ function translateLine(p1, p2, distance) {
416
+ const dy = p2[1] - p1[1], dx = p2[0] - p1[0];
417
+ const rad = Math.atan2(dy, dx);
418
+ const rad1 = rad + Math.PI / 2;
419
+ let offsetX = Math.cos(rad1) * distance, offsetY = Math.sin(rad1) * distance;
420
+ const tp1 = [p1[0] + offsetX, p1[1] + offsetY];
421
+ const tp2 = [p2[0] + offsetX, p2[1] + offsetY];
422
+ const rad2 = rad - Math.PI / 2;
423
+ offsetX = Math.cos(rad2) * distance;
424
+ offsetY = Math.sin(rad2) * distance;
425
+ const tp3 = [p1[0] + offsetX, p1[1] + offsetY];
426
+ const tp4 = [p2[0] + offsetX, p2[1] + offsetY];
427
+ return [[tp1, tp2], [tp3, tp4]];
428
+ }
429
+
430
+ /**
431
+ * 直线交点
432
+ * @param {*} p1
433
+ * @param {*} p2
434
+ * @param {*} p3
435
+ * @param {*} p4
436
+ * @returns
437
+ */
438
+ function lineIntersection(p1, p2, p3, p4): Array<number> | null {
439
+ const dx1 = p2[0] - p1[0], dy1 = p2[1] - p1[1];
440
+ const dx2 = p4[0] - p3[0], dy2 = p4[1] - p3[1];
441
+ if (dx1 === 0 && dx2 === 0) {
442
+ return null;
443
+ }
444
+ if (dy1 === 0 && dy2 === 0) {
445
+ return null;
446
+ }
447
+
448
+ const k1 = dy1 / dx1;
449
+ const k2 = dy2 / dx2;
450
+
451
+ const b1 = p1[1] - k1 * p1[0];
452
+ const b2 = p3[1] - k2 * p3[0];
453
+
454
+ let x, y;
455
+
456
+ if (dx1 === 0) {
457
+ x = p1[0];
458
+ y = k2 * x + b2;
459
+ } else if (dx2 === 0) {
460
+ x = p3[0];
461
+ y = k1 * x + b1;
462
+ } else if (dy1 === 0) {
463
+ y = p1[1];
464
+ x = (y - b2) / k2;
465
+ } else if (dy2 === 0) {
466
+ y = p3[1];
467
+ x = (y - b1) / k1;
468
+ } else {
469
+ x = (b2 - b1) / (k1 - k2);
470
+ y = k1 * x + b1;
471
+ }
472
+ return [x, y];
473
+ }