Smooth a node path via line-of-sight ("string pulling"). Walks the * input path collapsing runs of nodes into straight segments whenever * isLineClear permits, so the result can leave grid centers and cut * cleanly across open spaces. * * Bails (leaves the path unchanged
(path)
| 512 | * @param {PathFinderNode[]} path |
| 513 | * @private */ |
| 514 | smoothPathStringPull(path) |
| 515 | { |
| 516 | if (path.length <= 2) return; |
| 517 | for (const n of path) |
| 518 | { |
| 519 | if (!n.isClear()) return; |
| 520 | } |
| 521 | |
| 522 | const original = path.slice(); |
| 523 | path.length = 0; |
| 524 | path.push(original[0]); |
| 525 | let searchIndex = 0; |
| 526 | |
| 527 | for (let i = 1; i < original.length; ++i) |
| 528 | { |
| 529 | const node = original[i]; |
| 530 | |
| 531 | // Skip if node is collinear with the search-window start and the |
| 532 | // previous node — it adds no information. Note: a == b is the |
| 533 | // degenerate i=1, searchIndex=0 case; skip the test then. |
| 534 | { |
| 535 | const a = original[searchIndex]; |
| 536 | const b = original[i - 1]; |
| 537 | if (a !== b) |
| 538 | { |
| 539 | const cross = |
| 540 | (b.pos.x - a.pos.x) * (node.pos.y - a.pos.y) - |
| 541 | (b.pos.y - a.pos.y) * (node.pos.x - a.pos.x); |
| 542 | if (cross === 0) continue; |
| 543 | } |
| 544 | } |
| 545 | |
| 546 | if (!this.isLineClear(node.pos, path[path.length - 1].pos)) |
| 547 | { |
| 548 | // Look ahead — if any later node has a clear shot to the |
| 549 | // back of our new path, skip this node and try later. |
| 550 | let foundClearAfter = false; |
| 551 | for (let j = i + 1; j < original.length; ++j) |
| 552 | { |
| 553 | if (this.isLineClear(original[j].pos, path[path.length - 1].pos)) |
| 554 | { |
| 555 | foundClearAfter = true; |
| 556 | break; |
| 557 | } |
| 558 | } |
| 559 | if (foundClearAfter) |
| 560 | { |
| 561 | if (this.debug && this.debugTime > 0) |
| 562 | debugLine(node.posWorld, path[path.length - 1].posWorld, rgb(0, 0, 1, 0.3), 0.02, this.debugTime); |
| 563 | continue; |
| 564 | } |
| 565 | |
| 566 | // No clear line ahead — fall back to the last waypoint we did |
| 567 | // have a clear line to. searchIndex tracks our scan position. |
| 568 | for (; searchIndex < original.length; ++searchIndex) |
| 569 | { |
| 570 | const cand = original[searchIndex]; |
| 571 | if (this.isLineClear(node.pos, cand.pos)) |
no test coverage detected