poly-extrude 0.3.0 → 0.5.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/poly-extrude.js +205 -65
- package/dist/poly-extrude.js.map +1 -1
- package/dist/poly-extrude.min.js +2 -2
- package/dist/poly-extrude.mjs +204 -66
- package/index.js +2 -2
- package/package.json +3 -2
- package/src/polyline.js +155 -24
package/src/polyline.js
CHANGED
@@ -18,8 +18,49 @@ export function extrudePolylines(lines, options) {
|
|
18
18
|
return result;
|
19
19
|
}
|
20
20
|
|
21
|
+
export function extrudeSlopes(lines, options) {
|
22
|
+
options = Object.assign({}, { depth: 2, lineWidth: 1, side: 'left', sideDepth: 0 }, options);
|
23
|
+
const { depth, side, sideDepth } = options;
|
24
|
+
const results = lines.map(line => {
|
25
|
+
const tempResult = expandLine(line, options);
|
26
|
+
tempResult.line = line;
|
27
|
+
const { leftPoints, rightPoints } = tempResult;
|
28
|
+
const result = { line };
|
29
|
+
let depths;
|
30
|
+
for (let i = 0, len = line.length; i < len; i++) {
|
31
|
+
line[i][2] = line[i][2] || 0;
|
32
|
+
}
|
33
|
+
if (side === 'left') {
|
34
|
+
result.leftPoints = leftPoints;
|
35
|
+
result.rightPoints = line;
|
36
|
+
depths = [sideDepth, depth];
|
37
|
+
} else {
|
38
|
+
result.leftPoints = line;
|
39
|
+
result.rightPoints = rightPoints;
|
40
|
+
depths = [depth, sideDepth];
|
41
|
+
}
|
42
|
+
result.depths = depths;
|
43
|
+
generateTopAndBottom(result, options);
|
44
|
+
generateSides(result, options);
|
45
|
+
result.position = new Float32Array(result.points);
|
46
|
+
result.indices = new Uint32Array(result.index);
|
47
|
+
result.uv = new Float32Array(result.uvs);
|
48
|
+
result.normal = generateNormal(result.indices, result.position);
|
49
|
+
return result;
|
50
|
+
});
|
51
|
+
const result = merge(results);
|
52
|
+
result.lines = lines;
|
53
|
+
return result;
|
54
|
+
}
|
55
|
+
|
21
56
|
function generateTopAndBottom(result, options) {
|
22
57
|
const z = options.depth;
|
58
|
+
const depths = result.depths;
|
59
|
+
let lz = z, rz = z;
|
60
|
+
if (depths) {
|
61
|
+
lz = depths[0];
|
62
|
+
rz = depths[1];
|
63
|
+
}
|
23
64
|
const points = [], index = [], uvs = [];
|
24
65
|
const { leftPoints, rightPoints } = result;
|
25
66
|
let i = 0, len = leftPoints.length;
|
@@ -29,14 +70,14 @@ function generateTopAndBottom(result, options) {
|
|
29
70
|
const [x1, y1, z1] = leftPoints[i];
|
30
71
|
points[idx0] = x1;
|
31
72
|
points[idx0 + 1] = y1;
|
32
|
-
points[idx0 + 2] =
|
73
|
+
points[idx0 + 2] = lz + z1;
|
33
74
|
|
34
75
|
// top right
|
35
76
|
const [x2, y2, z2] = rightPoints[i];
|
36
77
|
const idx1 = len * 3 + idx0;
|
37
78
|
points[idx1] = x2;
|
38
79
|
points[idx1 + 1] = y2;
|
39
|
-
points[idx1 + 2] =
|
80
|
+
points[idx1 + 2] = rz + z2;
|
40
81
|
|
41
82
|
// bottom left
|
42
83
|
const idx2 = (len * 2) * 3 + idx0;
|
@@ -79,16 +120,26 @@ function generateTopAndBottom(result, options) {
|
|
79
120
|
result.index = index;
|
80
121
|
result.points = points;
|
81
122
|
result.uvs = uvs;
|
123
|
+
if (depths) {
|
124
|
+
len = leftPoints.length;
|
125
|
+
i = 0;
|
126
|
+
while (i < len) {
|
127
|
+
leftPoints[i].depth = lz;
|
128
|
+
rightPoints[i].depth = rz;
|
129
|
+
i++;
|
130
|
+
}
|
131
|
+
}
|
82
132
|
}
|
83
133
|
|
84
134
|
function generateSides(result, options) {
|
85
135
|
const { points, index, leftPoints, rightPoints, uvs } = result;
|
86
136
|
const z = options.depth;
|
87
137
|
const rings = [leftPoints, rightPoints];
|
138
|
+
const depthsEnable = result.depths;
|
88
139
|
|
89
140
|
function addOneSideIndex(v1, v2) {
|
90
141
|
const idx = points.length / 3;
|
91
|
-
points.push(v1[0], v1[1], z + v1[2], v2[0], v2[1], z + v2[2], v1[0], v1[1], v1[2], v2[0], v2[1], v2[2]);
|
142
|
+
points.push(v1[0], v1[1], (depthsEnable ? v1.depth : z) + v1[2], v2[0], v2[1], (depthsEnable ? v2.depth : z) + v2[2], v1[0], v1[1], v1[2], v2[0], v2[1], v2[2]);
|
92
143
|
const a = idx + 2, b = idx + 3, c = idx, d = idx + 1;
|
93
144
|
index.push(a, c, b, c, d, b);
|
94
145
|
generateSideWallUV(uvs, points, a, b, c, d);
|
@@ -122,24 +173,31 @@ function generateSides(result, options) {
|
|
122
173
|
const TEMPV1 = { x: 0, y: 0 }, TEMPV2 = { x: 0, y: 0 };
|
123
174
|
|
124
175
|
export function expandLine(line, options) {
|
125
|
-
let preAngle = 0;
|
176
|
+
// let preAngle = 0;
|
126
177
|
const radius = options.lineWidth / 2;
|
127
178
|
const points = [], leftPoints = [], rightPoints = [];
|
128
179
|
const len = line.length;
|
129
180
|
let i = 0;
|
130
|
-
while (i < len
|
131
|
-
|
181
|
+
while (i < len) {
|
182
|
+
let p1 = line[i],
|
132
183
|
p2 = line[i + 1];
|
184
|
+
const currentp = line[i];
|
185
|
+
// last vertex
|
186
|
+
if (i === len - 1) {
|
187
|
+
p1 = line[len - 2];
|
188
|
+
p2 = line[len - 1];
|
189
|
+
}
|
133
190
|
const dy = p2[1] - p1[1],
|
134
191
|
dx = p2[0] - p1[0];
|
135
192
|
let rAngle = 0;
|
136
193
|
const rad = Math.atan(dy / dx);
|
137
194
|
const angle = radToDeg(rad);
|
138
|
-
preAngle = angle;
|
139
|
-
if (i === 0) {
|
195
|
+
// preAngle = angle;
|
196
|
+
if (i === 0 || i === len - 1) {
|
140
197
|
rAngle = angle;
|
141
198
|
rAngle -= 90;
|
142
199
|
} else {
|
200
|
+
// 至少3个顶点才会触发
|
143
201
|
const p0 = line[i - 1];
|
144
202
|
TEMPV1.x = p0[0] - p1[0];
|
145
203
|
TEMPV1.y = p0[1] - p1[1];
|
@@ -149,7 +207,26 @@ export function expandLine(line, options) {
|
|
149
207
|
rAngle = angle - vAngle / 2;
|
150
208
|
}
|
151
209
|
const rRad = degToRad(rAngle);
|
152
|
-
const
|
210
|
+
const p3 = currentp;
|
211
|
+
const x = Math.cos(rRad) + p3[0], y = Math.sin(rRad) + p3[1];
|
212
|
+
const p4 = [x, y];
|
213
|
+
const [line1, line2] = translateLine(p1, p2, radius);
|
214
|
+
let op1 = lineIntersection(line1[0], line1[1], p3, p4);
|
215
|
+
let op2 = lineIntersection(line2[0], line2[1], p3, p4);
|
216
|
+
// 平行,回头路
|
217
|
+
if (!op1 || !op2) {
|
218
|
+
const len1 = points.length;
|
219
|
+
const point1 = points[len1 - 2];
|
220
|
+
const point2 = points[len1 - 1];
|
221
|
+
if (!point1 || !point2) {
|
222
|
+
continue;
|
223
|
+
}
|
224
|
+
op1 = [point1[0], point1[1]];
|
225
|
+
op2 = [point2[0], point2[1]];
|
226
|
+
}
|
227
|
+
op1[2] = currentp[2] || 0;
|
228
|
+
op2[2] = currentp[2] || 0;
|
229
|
+
// const [op1, op2] = calOffsetPoint(rRad, radius, p1);
|
153
230
|
points.push(op1, op2);
|
154
231
|
if (leftOnLine(op1, p1, p2)) {
|
155
232
|
leftPoints.push(op1);
|
@@ -160,24 +237,11 @@ export function expandLine(line, options) {
|
|
160
237
|
}
|
161
238
|
i++;
|
162
239
|
}
|
163
|
-
let rAngle = preAngle;
|
164
|
-
rAngle -= 90;
|
165
|
-
const rRad = degToRad(rAngle);
|
166
|
-
const p1 = line[len - 2];
|
167
|
-
const p2 = line[len - 1];
|
168
|
-
const [op1, op2] = calOffsetPoint(rRad, radius, p2);
|
169
|
-
points.push(op1, op2);
|
170
|
-
if (leftOnLine(op1, p1, p2)) {
|
171
|
-
leftPoints.push(op1);
|
172
|
-
rightPoints.push(op2);
|
173
|
-
} else {
|
174
|
-
leftPoints.push(op2);
|
175
|
-
rightPoints.push(op1);
|
176
|
-
}
|
177
240
|
|
178
241
|
return { offsetPoints: points, leftPoints, rightPoints };
|
179
242
|
}
|
180
243
|
|
244
|
+
// eslint-disable-next-line no-unused-vars
|
181
245
|
function calOffsetPoint(rad, radius, p) {
|
182
246
|
const [x, y] = p;
|
183
247
|
const z = p[2] || 0;
|
@@ -196,9 +260,76 @@ const getAngle = ({ x: x1, y: y1 }, { x: x2, y: y2 }) => {
|
|
196
260
|
return (angle + 360) % 360;
|
197
261
|
};
|
198
262
|
|
199
|
-
function leftOnLine(p, p1, p2) {
|
263
|
+
export function leftOnLine(p, p1, p2) {
|
200
264
|
const [x1, y1] = p1;
|
201
265
|
const [x2, y2] = p2;
|
202
266
|
const [x, y] = p;
|
203
267
|
return (y1 - y2) * x + (x2 - x1) * y + x1 * y2 - x2 * y1 > 0;
|
204
268
|
}
|
269
|
+
|
270
|
+
/**
|
271
|
+
* 平移线
|
272
|
+
* @param {*} p1
|
273
|
+
* @param {*} p2
|
274
|
+
* @param {*} distance
|
275
|
+
* @returns
|
276
|
+
*/
|
277
|
+
function translateLine(p1, p2, distance) {
|
278
|
+
const dy = p2[1] - p1[1], dx = p2[0] - p1[0];
|
279
|
+
const rad = Math.atan2(dy, dx);
|
280
|
+
const rad1 = rad + Math.PI / 2;
|
281
|
+
let offsetX = Math.cos(rad1) * distance, offsetY = Math.sin(rad1) * distance;
|
282
|
+
const tp1 = [p1[0] + offsetX, p1[1] + offsetY];
|
283
|
+
const tp2 = [p2[0] + offsetX, p2[1] + offsetY];
|
284
|
+
const rad2 = rad - Math.PI / 2;
|
285
|
+
offsetX = Math.cos(rad2) * distance;
|
286
|
+
offsetY = Math.sin(rad2) * distance;
|
287
|
+
const tp3 = [p1[0] + offsetX, p1[1] + offsetY];
|
288
|
+
const tp4 = [p2[0] + offsetX, p2[1] + offsetY];
|
289
|
+
return [[tp1, tp2], [tp3, tp4]];
|
290
|
+
}
|
291
|
+
|
292
|
+
/**
|
293
|
+
* 直线交点
|
294
|
+
* @param {*} p1
|
295
|
+
* @param {*} p2
|
296
|
+
* @param {*} p3
|
297
|
+
* @param {*} p4
|
298
|
+
* @returns
|
299
|
+
*/
|
300
|
+
function lineIntersection(p1, p2, p3, p4) {
|
301
|
+
const dx1 = p2[0] - p1[0], dy1 = p2[1] - p1[1];
|
302
|
+
const dx2 = p4[0] - p3[0], dy2 = p4[1] - p3[1];
|
303
|
+
if (dx1 === 0 && dx2 === 0) {
|
304
|
+
return null;
|
305
|
+
}
|
306
|
+
if (dy1 === 0 && dy2 === 0) {
|
307
|
+
return null;
|
308
|
+
}
|
309
|
+
|
310
|
+
const k1 = dy1 / dx1;
|
311
|
+
const k2 = dy2 / dx2;
|
312
|
+
|
313
|
+
const b1 = p1[1] - k1 * p1[0];
|
314
|
+
const b2 = p3[1] - k2 * p3[0];
|
315
|
+
|
316
|
+
let x, y;
|
317
|
+
|
318
|
+
if (dx1 === 0) {
|
319
|
+
x = p1[0];
|
320
|
+
y = k2 * x + b2;
|
321
|
+
} else if (dx2 === 0) {
|
322
|
+
x = p3[0];
|
323
|
+
y = k1 * x + b1;
|
324
|
+
} else if (dy1 === 0) {
|
325
|
+
y = p1[1];
|
326
|
+
x = (y - b2) / k2;
|
327
|
+
} else if (dy2 === 0) {
|
328
|
+
y = p3[1];
|
329
|
+
x = (y - b1) / k1;
|
330
|
+
} else {
|
331
|
+
x = (b2 - b1) / (k1 - k2);
|
332
|
+
y = k1 * x + b1;
|
333
|
+
}
|
334
|
+
return [x, y];
|
335
|
+
}
|