* @zh 使用漏斗算法优化路径 * @en Optimize path using funnel algorithm
(
start: IPoint,
end: IPoint,
polygons: INavPolygon[]
)
| 482 | * @en Optimize path using funnel algorithm |
| 483 | */ |
| 484 | private funnelPath( |
| 485 | start: IPoint, |
| 486 | end: IPoint, |
| 487 | polygons: INavPolygon[] |
| 488 | ): IPoint[] { |
| 489 | if (polygons.length <= 1) { |
| 490 | return [start, end]; |
| 491 | } |
| 492 | |
| 493 | // Collect portals |
| 494 | const portals: IPortal[] = []; |
| 495 | |
| 496 | for (let i = 0; i < polygons.length - 1; i++) { |
| 497 | const portal = polygons[i].portals.get(polygons[i + 1].id); |
| 498 | if (portal) { |
| 499 | portals.push(portal); |
| 500 | } |
| 501 | } |
| 502 | |
| 503 | if (portals.length === 0) { |
| 504 | return [start, end]; |
| 505 | } |
| 506 | |
| 507 | // Simple string pulling algorithm |
| 508 | const path: IPoint[] = [start]; |
| 509 | |
| 510 | let apex = start; |
| 511 | let leftIndex = 0; |
| 512 | let rightIndex = 0; |
| 513 | let left = portals[0].left; |
| 514 | let right = portals[0].right; |
| 515 | |
| 516 | for (let i = 1; i <= portals.length; i++) { |
| 517 | const nextLeft = i < portals.length ? portals[i].left : end; |
| 518 | const nextRight = i < portals.length ? portals[i].right : end; |
| 519 | |
| 520 | // Update right |
| 521 | if (this.triArea2(apex, right, nextRight) <= 0) { |
| 522 | if (apex === right || this.triArea2(apex, left, nextRight) > 0) { |
| 523 | right = nextRight; |
| 524 | rightIndex = i; |
| 525 | } else { |
| 526 | path.push(left); |
| 527 | apex = left; |
| 528 | leftIndex = rightIndex = leftIndex; |
| 529 | left = right = apex; |
| 530 | i = leftIndex; |
| 531 | continue; |
| 532 | } |
| 533 | } |
| 534 | |
| 535 | // Update left |
| 536 | if (this.triArea2(apex, left, nextLeft) >= 0) { |
| 537 | if (apex === left || this.triArea2(apex, right, nextLeft) < 0) { |
| 538 | left = nextLeft; |
| 539 | leftIndex = i; |
| 540 | } else { |
| 541 | path.push(right); |