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/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] = z + z1;
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] = z + z2;
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 - 1) {
131
- const p1 = line[i],
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 [op1, op2] = calOffsetPoint(rRad, radius, p1);
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
+ }