poly-extrude 0.13.0 → 0.14.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/cylinder.d.ts +11 -0
- package/{src → dist}/cylinder.js +108 -111
- package/dist/cylinder.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/math/Curve.d.ts +41 -0
- package/dist/math/Curve.js +142 -0
- package/dist/math/Curve.js.map +1 -0
- package/dist/math/Interpolations.d.ts +8 -0
- package/dist/math/Interpolations.js +48 -0
- package/dist/math/Interpolations.js.map +1 -0
- package/dist/math/Matrix4.d.ts +8 -0
- package/dist/math/Matrix4.js +582 -0
- package/dist/math/Matrix4.js.map +1 -0
- package/dist/math/QuadraticBezierCurve3.d.ts +10 -0
- package/dist/math/QuadraticBezierCurve3.js +22 -0
- package/dist/math/QuadraticBezierCurve3.js.map +1 -0
- package/dist/math/Quaternion.d.ts +46 -0
- package/dist/math/Quaternion.js +415 -0
- package/dist/math/Quaternion.js.map +1 -0
- package/dist/math/Vector3.d.ts +42 -0
- package/dist/math/Vector3.js +403 -0
- package/dist/math/Vector3.js.map +1 -0
- package/dist/path/PathPoint.d.ts +15 -0
- package/dist/path/PathPoint.js +35 -0
- package/dist/path/PathPoint.js.map +1 -0
- package/dist/path/PathPointList.d.ts +27 -0
- package/dist/path/PathPointList.js +212 -0
- package/dist/path/PathPointList.js.map +1 -0
- package/dist/path.d.ts +11 -0
- package/{src → dist}/path.js +334 -360
- package/dist/path.js.map +1 -0
- package/dist/plane.d.ts +2 -0
- package/{src → dist}/plane.js +57 -58
- package/dist/plane.js.map +1 -0
- package/dist/poly-extrude.js +1286 -1581
- package/dist/poly-extrude.js.map +1 -1
- package/dist/poly-extrude.min.js +2 -2
- package/dist/poly-extrude.mjs +1286 -1581
- package/dist/poly-extrude.mjs.map +1 -0
- package/dist/polygon.d.ts +9 -0
- package/{src → dist}/polygon.js +163 -179
- package/dist/polygon.js.map +1 -0
- package/dist/polyline.d.ts +24 -0
- package/{src → dist}/polyline.js +420 -456
- package/dist/polyline.js.map +1 -0
- package/dist/tube.d.ts +12 -0
- package/{src → dist}/tube.js +124 -142
- package/dist/tube.js.map +1 -0
- package/dist/type.d.ts +9 -0
- package/dist/type.js +2 -0
- package/dist/type.js.map +1 -0
- package/dist/util.d.ts +20 -0
- package/dist/util.js +217 -0
- package/dist/util.js.map +1 -0
- package/package.json +53 -48
- package/readme.md +12 -2
- package/src/cylinder.ts +124 -0
- package/src/index.ts +7 -0
- package/src/path.ts +385 -0
- package/src/plane.ts +60 -0
- package/src/polygon.ts +189 -0
- package/src/polyline.ts +473 -0
- package/src/tube.ts +155 -0
- package/src/type.ts +9 -0
- package/src/{util.js → util.ts} +1 -1
- package/index.js +0 -7
package/src/polyline.ts
ADDED
@@ -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 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 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
|
+
}
|
package/src/tube.ts
ADDED
@@ -0,0 +1,155 @@
|
|
1
|
+
import { Vector3 } from './math/Vector3';
|
2
|
+
import { PathPoint } from './path/PathPoint';
|
3
|
+
import { PathPointList } from './path/PathPointList';
|
4
|
+
import { PolylineType, ResultType } from './type';
|
5
|
+
import { line2Vectors, merge } from './util';
|
6
|
+
const UP = new Vector3(0, 0, 1);
|
7
|
+
const normalDir = new Vector3();
|
8
|
+
|
9
|
+
type TubesOptions = {
|
10
|
+
radius?: number;
|
11
|
+
cornerSplit?: number;
|
12
|
+
radialSegments?: number;
|
13
|
+
startRad?: number;
|
14
|
+
}
|
15
|
+
|
16
|
+
type TubesResult = ResultType & {
|
17
|
+
lines: Array<PolylineType>;
|
18
|
+
}
|
19
|
+
|
20
|
+
export function expandTubes(lines: Array<PolylineType>, options?: TubesOptions) {
|
21
|
+
options = Object.assign({}, { radius: 1, cornerSplit: 0, radialSegments: 8, startRad: -Math.PI / 4 }, options);
|
22
|
+
const results = lines.map(line => {
|
23
|
+
const points = line2Vectors(line);
|
24
|
+
const pathPointList = new PathPointList();
|
25
|
+
//@ts-ignore
|
26
|
+
pathPointList.set(points, 0, options.cornerSplit, UP);
|
27
|
+
const result = generateTubeVertexData(pathPointList, options) as Record<string, any>;
|
28
|
+
result.line = line;
|
29
|
+
result.position = new Float32Array(result.points);
|
30
|
+
result.indices = new Uint32Array(result.indices);
|
31
|
+
result.uv = new Float32Array(result.uv);
|
32
|
+
result.normal = new Float32Array(result.normal);
|
33
|
+
return result;
|
34
|
+
});
|
35
|
+
const result = merge(results) as TubesResult;
|
36
|
+
result.lines = lines;
|
37
|
+
return result;
|
38
|
+
}
|
39
|
+
|
40
|
+
// Vertex Data Generate Functions
|
41
|
+
// code copy from https://github.com/shawn0326/three.path/blob/master/src/PathGeometry.js
|
42
|
+
function generateTubeVertexData(pathPointList, options) {
|
43
|
+
const radius = Math.max(options.radius || 1, 0.00000001);
|
44
|
+
const progress = options.progress !== undefined ? options.progress : 1;
|
45
|
+
const radialSegments = Math.max(3, options.radialSegments || 8);
|
46
|
+
const startRad = options.startRad || 0;
|
47
|
+
|
48
|
+
const circum = radius * 2 * Math.PI;
|
49
|
+
const totalDistance = pathPointList.distance();
|
50
|
+
const progressDistance = progress * totalDistance;
|
51
|
+
if (progressDistance === 0) {
|
52
|
+
return null;
|
53
|
+
}
|
54
|
+
|
55
|
+
let count = 0;
|
56
|
+
|
57
|
+
// modify data
|
58
|
+
const points: number[] = [];
|
59
|
+
const normal: number[] = [];
|
60
|
+
const uv: number[] = [];
|
61
|
+
// const uv2 = [];
|
62
|
+
const indices: number[] = [];
|
63
|
+
let verticesCount = 0;
|
64
|
+
|
65
|
+
let pIndex = -1;
|
66
|
+
let nIndex = -1;
|
67
|
+
let uIndex = -1;
|
68
|
+
let iIndex = -1;
|
69
|
+
function addVertices(pathPoint, radius, radialSegments) {
|
70
|
+
const first = points.length === 0;
|
71
|
+
const uvDist = pathPoint.dist / circum;
|
72
|
+
// const uvDist2 = pathPoint.dist / totalDistance;
|
73
|
+
|
74
|
+
for (let i = 0; i <= radialSegments; i++) {
|
75
|
+
let r = i;
|
76
|
+
if (r === radialSegments) {
|
77
|
+
r = 0;
|
78
|
+
}
|
79
|
+
normalDir.copy(pathPoint.up).applyAxisAngle(pathPoint.dir, startRad + Math.PI * 2 * r / radialSegments).normalize();
|
80
|
+
|
81
|
+
const scale = radius * pathPoint.widthScale;
|
82
|
+
points[++pIndex] = pathPoint.pos.x + normalDir.x * scale;
|
83
|
+
points[++pIndex] = pathPoint.pos.y + normalDir.y * scale;
|
84
|
+
points[++pIndex] = pathPoint.pos.z + normalDir.z * scale;
|
85
|
+
|
86
|
+
normal[++nIndex] = normalDir.x;
|
87
|
+
normal[++nIndex] = normalDir.y;
|
88
|
+
normal[++nIndex] = normalDir.z;
|
89
|
+
|
90
|
+
uv[++uIndex] = uvDist;
|
91
|
+
uv[++uIndex] = i / radialSegments;
|
92
|
+
|
93
|
+
// uvs.push(uvDist, r / radialSegments);
|
94
|
+
|
95
|
+
// if (generateUv2) {
|
96
|
+
// uv2.push(uvDist2, r / radialSegments);
|
97
|
+
// }
|
98
|
+
|
99
|
+
verticesCount++;
|
100
|
+
}
|
101
|
+
|
102
|
+
if (!first) {
|
103
|
+
const begin1 = verticesCount - (radialSegments + 1) * 2;
|
104
|
+
const begin2 = verticesCount - (radialSegments + 1);
|
105
|
+
|
106
|
+
for (let i = 0; i < radialSegments; i++) {
|
107
|
+
indices[++iIndex] = begin2 + i;
|
108
|
+
indices[++iIndex] = begin1 + i;
|
109
|
+
indices[++iIndex] = begin1 + i + 1;
|
110
|
+
indices[++iIndex] = begin2 + i;
|
111
|
+
indices[++iIndex] = begin1 + i + 1;
|
112
|
+
indices[++iIndex] = begin2 + i + 1;
|
113
|
+
// index.push(
|
114
|
+
// begin2 + i,
|
115
|
+
// begin1 + i,
|
116
|
+
// begin1 + i + 1,
|
117
|
+
// begin2 + i,
|
118
|
+
// begin1 + i + 1,
|
119
|
+
// begin2 + i + 1
|
120
|
+
// );
|
121
|
+
|
122
|
+
count += 6;
|
123
|
+
}
|
124
|
+
}
|
125
|
+
}
|
126
|
+
|
127
|
+
if (progressDistance > 0) {
|
128
|
+
for (let i = 0; i < pathPointList.count; i++) {
|
129
|
+
const pathPoint = pathPointList.array[i];
|
130
|
+
|
131
|
+
if (pathPoint.dist > progressDistance) {
|
132
|
+
const prevPoint = pathPointList.array[i - 1];
|
133
|
+
const lastPoint = new PathPoint();
|
134
|
+
|
135
|
+
// linear lerp for progress
|
136
|
+
const alpha = (progressDistance - prevPoint.dist) / (pathPoint.dist - prevPoint.dist);
|
137
|
+
lastPoint.lerpPathPoints(prevPoint, pathPoint, alpha);
|
138
|
+
|
139
|
+
addVertices(lastPoint, radius, radialSegments);
|
140
|
+
break;
|
141
|
+
} else {
|
142
|
+
addVertices(pathPoint, radius, radialSegments);
|
143
|
+
}
|
144
|
+
}
|
145
|
+
}
|
146
|
+
|
147
|
+
return {
|
148
|
+
points,
|
149
|
+
normal,
|
150
|
+
uv,
|
151
|
+
// uv2,
|
152
|
+
indices,
|
153
|
+
count
|
154
|
+
};
|
155
|
+
}
|
package/src/type.ts
ADDED
package/src/{util.js → util.ts}
RENAMED
@@ -212,7 +212,7 @@ export function generateSideWallUV(uvs, vertices, indexA, indexB, indexC, indexD
|
|
212
212
|
}
|
213
213
|
|
214
214
|
export function line2Vectors(line) {
|
215
|
-
const points = [];
|
215
|
+
const points: Vector3[] = [];
|
216
216
|
for (let i = 0, len = line.length; i < len; i++) {
|
217
217
|
const p = line[i];
|
218
218
|
const [x, y, z] = p;
|
package/index.js
DELETED
@@ -1,7 +0,0 @@
|
|
1
|
-
import { extrudePolygons } from './src/polygon';
|
2
|
-
import { extrudePolylines, expandLine, leftOnLine, extrudeSlopes } from './src/polyline';
|
3
|
-
import { cylinder } from './src/cylinder';
|
4
|
-
import { expandPaths } from './src/path';
|
5
|
-
import { expandTubes } from './src/tube';
|
6
|
-
import { plane } from './src/plane';
|
7
|
-
export { extrudePolygons, extrudePolylines, extrudeSlopes, expandLine, leftOnLine, cylinder, expandPaths, expandTubes, plane };
|