poly-extrude 0.18.1 → 0.20.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.ts CHANGED
@@ -7,13 +7,23 @@ function checkOptions(options) {
7
7
  options.sideDepth = Math.max(0, options.sideDepth);
8
8
  }
9
9
 
10
- type PolylinesOptions = {
11
- depth?: number;
10
+ type ExpandLineOptions = {
12
11
  lineWidth?: number;
12
+ cutCorner?: boolean;
13
+ }
14
+
15
+ type PolylinesOptions = ExpandLineOptions & {
16
+ depth?: number;
13
17
  bottomStickGround?: boolean;
14
18
  pathUV?: boolean;
15
19
  }
16
20
 
21
+ type SlopesOptions = PolylinesOptions & {
22
+ side?: 'left' | 'right',
23
+ sideDepth?: number
24
+ }
25
+
26
+
17
27
  type PolylinesResult = ResultType & {
18
28
  lines: Array<PolylineType>;
19
29
  }
@@ -37,11 +47,6 @@ export function extrudePolylines(lines: Array<PolylineType>, opts?: PolylinesOpt
37
47
  return result;
38
48
  }
39
49
 
40
- type SlopesOptions = PolylinesOptions & {
41
- side?: 'left' | 'right',
42
- sideDepth?: number
43
- }
44
-
45
50
  export function extrudeSlopes(lines: Array<PolylineType>, opts?: SlopesOptions): PolylinesResult {
46
51
  const options = Object.assign({}, { depth: 2, lineWidth: 1, side: 'left', sideDepth: 0, bottomStickGround: false, pathUV: false, isSlope: true }, opts);
47
52
  checkOptions(options);
@@ -90,10 +95,15 @@ function generateTopAndBottom(result, options) {
90
95
  const { leftPoints, rightPoints } = result;
91
96
  const line = result.line;
92
97
  const pathUV = options.pathUV;
98
+ let uvCalPath = line;
99
+ // let needCalUV = false;
100
+ if (leftPoints.length > uvCalPath.length) {
101
+ uvCalPath = leftPoints;
102
+ }
93
103
  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;
104
+ calLineDistance(uvCalPath);
105
+ for (let i = 0, len = uvCalPath.length; i < len; i++) {
106
+ leftPoints[i].distance = rightPoints[i].distance = uvCalPath[i].distance;
97
107
  }
98
108
  }
99
109
  let i = 0, len = leftPoints.length;
@@ -106,6 +116,8 @@ function generateTopAndBottom(result, options) {
106
116
  points[idx0 + 1] = y1;
107
117
  points[idx0 + 2] = lz + z1;
108
118
 
119
+ // const p1 = leftPoints[i];
120
+
109
121
  // top right
110
122
  const [x2, y2, z2] = rightPoints[i];
111
123
  const idx1 = len * 3 + idx0;
@@ -113,6 +125,8 @@ function generateTopAndBottom(result, options) {
113
125
  points[idx1 + 1] = y2;
114
126
  points[idx1 + 2] = rz + z2;
115
127
 
128
+ // const p2 = rightPoints[i];
129
+
116
130
  // bottom left
117
131
  const idx2 = (len * 2) * 3 + idx0;
118
132
  points[idx2] = x1;
@@ -133,8 +147,8 @@ function generateTopAndBottom(result, options) {
133
147
 
134
148
  // generate path uv
135
149
  if (pathUV) {
136
- const p = line[i];
137
- const uvx = p.distance;
150
+ const p = uvCalPath[i];
151
+ let uvx = p.distance;
138
152
 
139
153
  const uIndex0 = i * 2;
140
154
  uv[uIndex0] = uvx;
@@ -307,56 +321,118 @@ function generateSides(result, options) {
307
321
 
308
322
  const TEMPV1 = { x: 0, y: 0 }, TEMPV2 = { x: 0, y: 0 };
309
323
 
310
- export function expandLine(line, options) {
311
- // let preAngle = 0;
324
+ export function expandLine(line, options?: ExpandLineOptions) {
325
+ options = Object.assign({}, { lineWidth: 1, cutCorner: false }, options);
312
326
  let radius = options.lineWidth / 2;
313
- if (options.isSlope) {
327
+ if ((options as any).isSlope) {
314
328
  radius *= 2;
315
329
  }
330
+ const { cutCorner } = options;
316
331
  const points: Array<number[]> = [], leftPoints: Array<number[]> = [], rightPoints: Array<number[]> = [];
317
332
  const len = line.length;
333
+
334
+ const repeatVertex = () => {
335
+ const len1 = leftPoints.length;
336
+ if (len1) {
337
+ leftPoints.push(leftPoints[len1 - 1]);
338
+ rightPoints.push(rightPoints[len1 - 1]);
339
+ const len2 = points.length;
340
+ points.push(points[len2 - 2], points[len2 - 1]);
341
+ }
342
+ };
343
+
344
+ const equal = (p1, p2) => {
345
+ return p1[0] === p2[0] && p1[1] === p2[1];
346
+ };
347
+
318
348
  let i = 0;
349
+ let preleftline, prerightline;
319
350
  while (i < len) {
351
+ let p0;
320
352
  let p1 = line[i],
321
353
  p2 = line[i + 1];
322
- const currentp = line[i];
354
+ const currentp = p1;
323
355
  // last vertex
324
356
  if (i === len - 1) {
325
357
  p1 = line[len - 2];
326
358
  p2 = line[len - 1];
359
+ if (equal(p1, p2)) {
360
+ for (let j = line.indexOf(p1); j >= 0; j--) {
361
+ const p = line[j];
362
+ if (!equal(p, currentp)) {
363
+ p1 = p;
364
+ break;
365
+ }
366
+ }
367
+ }
368
+ } else {
369
+ if (equal(p1, p2)) {
370
+ for (let j = line.indexOf(p2); j < len; j++) {
371
+ const p = line[j];
372
+ if (!equal(p, currentp)) {
373
+ p2 = p;
374
+ break;
375
+ }
376
+ }
377
+ }
378
+ }
379
+ if (equal(p1, p2)) {
380
+ repeatVertex();
381
+ i++;
382
+ continue;
327
383
  }
328
- const dy = p2[1] - p1[1],
384
+
385
+ let dy = p2[1] - p1[1],
329
386
  dx = p2[0] - p1[0];
387
+
330
388
  let rAngle = 0;
331
- const rad = Math.atan(dy / dx);
389
+ const rad = Math.atan2(dy, dx);
332
390
  const angle = radToDeg(rad);
333
- // preAngle = angle;
334
391
  if (i === 0 || i === len - 1) {
335
392
  rAngle = angle;
336
393
  rAngle -= 90;
337
394
  } else {
338
395
  // 至少3个顶点才会触发
339
- const p0 = line[i - 1];
396
+ p0 = line[i - 1];
397
+ if (equal(p0, p2) || equal(p0, p1)) {
398
+ for (let j = line.indexOf(p2); j >= 0; j--) {
399
+ const p = line[j];
400
+ if (!equal(p, p2) && (!equal(p, p1))) {
401
+ p0 = p;
402
+ break;
403
+ }
404
+ }
405
+ }
406
+ if (equal(p0, p2) || equal(p0, p1) || equal(p1, p2)) {
407
+ repeatVertex();
408
+ i++;
409
+ continue;
410
+ }
340
411
  TEMPV1.x = p0[0] - p1[0];
341
412
  TEMPV1.y = p0[1] - p1[1];
342
413
  TEMPV2.x = p2[0] - p1[0];
343
414
  TEMPV2.y = p2[1] - p1[1];
415
+ if ((TEMPV1.x === 0 && TEMPV1.y === 0) || (TEMPV2.x === 0 && TEMPV2.y === 0)) {
416
+ console.error('has repeat vertex,the index:', i);
417
+ }
344
418
  const vAngle = getAngle(TEMPV1, TEMPV2);
345
419
  rAngle = angle - vAngle / 2;
346
420
  }
421
+
347
422
  const rRad = degToRad(rAngle);
348
423
  const p3 = currentp;
349
424
  const x = Math.cos(rRad) + p3[0], y = Math.sin(rRad) + p3[1];
350
425
  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);
426
+ const [leftline, rightline] = translateLine(p1, p2, radius);
427
+ let op1 = lineIntersection(leftline[0], leftline[1], p3, p4);
428
+ let op2 = lineIntersection(rightline[0], rightline[1], p3, p4);
354
429
  // 平行,回头路
355
430
  if (!op1 || !op2) {
356
431
  const len1 = points.length;
357
432
  const point1 = points[len1 - 2];
358
433
  const point2 = points[len1 - 1];
359
434
  if (!point1 || !point2) {
435
+ i++;
360
436
  continue;
361
437
  }
362
438
  op1 = [point1[0], point1[1]];
@@ -366,13 +442,64 @@ export function expandLine(line, options) {
366
442
  op2[2] = currentp[2] || 0;
367
443
  // const [op1, op2] = calOffsetPoint(rRad, radius, p1);
368
444
  points.push(op1, op2);
369
- if (leftOnLine(op1, p1, p2)) {
370
- leftPoints.push(op1);
371
- rightPoints.push(op2);
445
+ let needCut = false;
446
+ if (cutCorner) {
447
+ const bufferRadius = radius * 2;
448
+ if (distance(currentp, op1) > bufferRadius || distance(currentp, op2) > bufferRadius) {
449
+ needCut = true;
450
+ }
451
+ }
452
+ if (needCut && p0 && preleftline && prerightline) {
453
+ let cutPoint = op1;
454
+ if (distance(op1, p0) < distance(op2, p0)) {
455
+ cutPoint = op2;
456
+ }
457
+ const dy = cutPoint[1] - currentp[1], dx = cutPoint[0] - currentp[0];
458
+ const cutAngle = Math.atan2(dy, dx) / Math.PI * 180;
459
+ const cutRad = degToRad(cutAngle);
460
+ const x1 = Math.cos(cutRad) * radius + currentp[0];
461
+ const y1 = Math.sin(cutRad) * radius + currentp[1];
462
+ const v1 = [x1, y1];
463
+
464
+ const hcutangle = cutAngle + 90;
465
+ // console.log(i, cutAngle, hcutangle);
466
+ const hcutRad = degToRad(hcutangle);
467
+ const x2 = Math.cos(hcutRad) + x1;
468
+ const y2 = Math.sin(hcutRad) + y1;
469
+ const v2 = [x2, y2];
470
+
471
+ let preline = preleftline;
472
+ let currentLine = leftline;
473
+ let appendArray = leftPoints;
474
+ let repeatArray = rightPoints;
475
+ if (!leftOnLine(cutPoint, p1, p2)) {
476
+ preline = prerightline;
477
+ currentLine = rightline;
478
+ appendArray = rightPoints;
479
+ repeatArray = leftPoints;
480
+ }
481
+
482
+ let cross1 = lineIntersection(preline[0], preline[1], v1, v2);
483
+ let cross2 = lineIntersection(currentLine[0], currentLine[1], v1, v2);
484
+
485
+ cross1[2] = currentp[2] || 0;
486
+ cross2[2] = currentp[2] || 0;
487
+ const repeatPoint = cutPoint === op1 ? op2 : op1;
488
+ appendArray.push(cross1, cross2);
489
+ repeatArray.push(repeatPoint, [...repeatPoint]);
372
490
  } else {
373
- leftPoints.push(op2);
374
- rightPoints.push(op1);
491
+ if (leftOnLine(op1, p1, p2)) {
492
+ leftPoints.push(op1);
493
+ rightPoints.push(op2);
494
+ } else {
495
+ leftPoints.push(op2);
496
+ rightPoints.push(op1);
497
+ }
375
498
  }
499
+
500
+ preleftline = leftline;
501
+ prerightline = rightline;
502
+
376
503
  i++;
377
504
  }
378
505
 
@@ -395,9 +522,15 @@ const getAngle = ({ x: x1, y: y1 }, { x: x2, y: y2 }) => {
395
522
  const dot = x1 * x2 + y1 * y2;
396
523
  const det = x1 * y2 - y1 * x2;
397
524
  const angle = Math.atan2(det, dot) / Math.PI * 180;
398
- return (angle + 360) % 360;
525
+ return (angle);
526
+ // return (angle + 360) % 360;
399
527
  };
400
528
 
529
+ function distance(p1, p2) {
530
+ const dx = p2[0] - p1[0], dy = p2[1] - p1[1];
531
+ return Math.sqrt(dx * dx + dy * dy);
532
+ }
533
+
401
534
  export function leftOnLine(p, p1, p2) {
402
535
  const [x1, y1] = p1;
403
536
  const [x2, y2] = p2;
@@ -412,8 +545,11 @@ export function leftOnLine(p, p1, p2) {
412
545
  * @param {*} distance
413
546
  * @returns
414
547
  */
415
- function translateLine(p1, p2, distance) {
548
+ export function translateLine(p1, p2, distance) {
416
549
  const dy = p2[1] - p1[1], dx = p2[0] - p1[0];
550
+ if (dy === 0 && dx === 0) {
551
+ return null;
552
+ }
417
553
  const rad = Math.atan2(dy, dx);
418
554
  const rad1 = rad + Math.PI / 2;
419
555
  let offsetX = Math.cos(rad1) * distance, offsetY = Math.sin(rad1) * distance;
@@ -438,13 +574,14 @@ function translateLine(p1, p2, distance) {
438
574
  function lineIntersection(p1, p2, p3, p4): Array<number> | null {
439
575
  const dx1 = p2[0] - p1[0], dy1 = p2[1] - p1[1];
440
576
  const dx2 = p4[0] - p3[0], dy2 = p4[1] - p3[1];
577
+ //vertical
441
578
  if (dx1 === 0 && dx2 === 0) {
442
579
  return null;
443
580
  }
581
+ //horizontal
444
582
  if (dy1 === 0 && dy2 === 0) {
445
583
  return null;
446
584
  }
447
-
448
585
  const k1 = dy1 / dx1;
449
586
  const k2 = dy2 / dx2;
450
587