@esengine/pathfinding 13.2.0 → 13.3.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/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/core/BinaryHeap.ts","../src/core/AStarPathfinder.ts","../src/core/GridPathfinder.ts","../src/core/JPSPathfinder.ts","../src/core/HPAPathfinder.ts","../src/navmesh/NavMesh.ts"],"sourcesContent":["/**\n * @zh 二叉堆(优先队列)\n * @en Binary Heap (Priority Queue)\n *\n * @zh 用于 A* 算法的高效开放列表\n * @en Efficient open list for A* algorithm\n */\nexport class BinaryHeap<T> {\n private heap: T[] = [];\n private readonly compare: (a: T, b: T) => number;\n\n /**\n * @zh 创建二叉堆\n * @en Create binary heap\n *\n * @param compare - @zh 比较函数,返回负数表示 a < b @en Compare function, returns negative if a < b\n */\n constructor(compare: (a: T, b: T) => number) {\n this.compare = compare;\n }\n\n /**\n * @zh 堆大小\n * @en Heap size\n */\n get size(): number {\n return this.heap.length;\n }\n\n /**\n * @zh 是否为空\n * @en Is empty\n */\n get isEmpty(): boolean {\n return this.heap.length === 0;\n }\n\n /**\n * @zh 插入元素\n * @en Push element\n */\n push(item: T): void {\n this.heap.push(item);\n this.bubbleUp(this.heap.length - 1);\n }\n\n /**\n * @zh 弹出最小元素\n * @en Pop minimum element\n */\n pop(): T | undefined {\n if (this.heap.length === 0) {\n return undefined;\n }\n\n const result = this.heap[0];\n const last = this.heap.pop()!;\n\n if (this.heap.length > 0) {\n this.heap[0] = last;\n this.sinkDown(0);\n }\n\n return result;\n }\n\n /**\n * @zh 查看最小元素(不移除)\n * @en Peek minimum element (without removing)\n */\n peek(): T | undefined {\n return this.heap[0];\n }\n\n /**\n * @zh 更新元素(重新排序)\n * @en Update element (re-sort)\n */\n update(item: T): void {\n const index = this.heap.indexOf(item);\n if (index !== -1) {\n this.bubbleUp(index);\n this.sinkDown(index);\n }\n }\n\n /**\n * @zh 检查是否包含元素\n * @en Check if contains element\n */\n contains(item: T): boolean {\n return this.heap.indexOf(item) !== -1;\n }\n\n /**\n * @zh 清空堆\n * @en Clear heap\n */\n clear(): void {\n this.heap.length = 0;\n }\n\n /**\n * @zh 上浮操作\n * @en Bubble up operation\n */\n private bubbleUp(index: number): void {\n const item = this.heap[index];\n\n while (index > 0) {\n const parentIndex = Math.floor((index - 1) / 2);\n const parent = this.heap[parentIndex];\n\n if (this.compare(item, parent) >= 0) {\n break;\n }\n\n this.heap[index] = parent;\n index = parentIndex;\n }\n\n this.heap[index] = item;\n }\n\n /**\n * @zh 下沉操作\n * @en Sink down operation\n */\n private sinkDown(index: number): void {\n const length = this.heap.length;\n const item = this.heap[index];\n\n while (true) {\n const leftIndex = 2 * index + 1;\n const rightIndex = 2 * index + 2;\n let smallest = index;\n\n if (leftIndex < length && this.compare(this.heap[leftIndex], this.heap[smallest]) < 0) {\n smallest = leftIndex;\n }\n\n if (rightIndex < length && this.compare(this.heap[rightIndex], this.heap[smallest]) < 0) {\n smallest = rightIndex;\n }\n\n if (smallest === index) {\n break;\n }\n\n this.heap[index] = this.heap[smallest];\n this.heap[smallest] = item;\n index = smallest;\n }\n }\n}\n","/**\n * @zh A* 寻路算法实现\n * @en A* Pathfinding Algorithm Implementation\n */\n\nimport { IndexedBinaryHeap, type IHeapIndexable } from './IndexedBinaryHeap';\nimport type {\n IPathfindingMap,\n IPathfinder,\n IPathResult,\n IPathfindingOptions,\n IPathNode,\n IPoint\n} from './IPathfinding';\nimport { EMPTY_PATH_RESULT, DEFAULT_PATHFINDING_OPTIONS } from './IPathfinding';\n\n// =============================================================================\n// 内部节点类型 | Internal Node Type\n// =============================================================================\n\ninterface AStarNode extends IHeapIndexable {\n node: IPathNode;\n g: number; // Cost from start\n h: number; // Heuristic to end\n f: number; // Total cost (g + h)\n parent: AStarNode | null;\n closed: boolean;\n opened: boolean;\n heapIndex: number; // For IndexedBinaryHeap O(log n) update\n}\n\n// =============================================================================\n// A* 寻路器 | A* Pathfinder\n// =============================================================================\n\n/**\n * @zh A* 寻路器\n * @en A* Pathfinder\n *\n * @zh 使用 A* 算法在地图上查找最短路径\n * @en Uses A* algorithm to find shortest path on a map\n *\n * @example\n * ```typescript\n * const map = new GridMap(width, height);\n * const pathfinder = new AStarPathfinder(map);\n * const result = pathfinder.findPath(0, 0, 10, 10);\n * if (result.found) {\n * console.log('Path:', result.path);\n * }\n * ```\n */\nexport class AStarPathfinder implements IPathfinder {\n private readonly map: IPathfindingMap;\n private nodeCache: Map<string | number, AStarNode> = new Map();\n private openList: IndexedBinaryHeap<AStarNode>;\n\n constructor(map: IPathfindingMap) {\n this.map = map;\n this.openList = new IndexedBinaryHeap<AStarNode>((a, b) => a.f - b.f);\n }\n\n /**\n * @zh 查找路径\n * @en Find path\n */\n findPath(\n startX: number,\n startY: number,\n endX: number,\n endY: number,\n options?: IPathfindingOptions\n ): IPathResult {\n const opts = { ...DEFAULT_PATHFINDING_OPTIONS, ...options };\n\n // Clear previous state\n this.clear();\n\n // Get start and end nodes\n const startNode = this.map.getNodeAt(startX, startY);\n const endNode = this.map.getNodeAt(endX, endY);\n\n // Validate nodes\n if (!startNode || !endNode) {\n return EMPTY_PATH_RESULT;\n }\n\n if (!startNode.walkable || !endNode.walkable) {\n return EMPTY_PATH_RESULT;\n }\n\n // Same position\n if (startNode.id === endNode.id) {\n return {\n found: true,\n path: [startNode.position],\n cost: 0,\n nodesSearched: 1\n };\n }\n\n // Initialize start node\n const start = this.getOrCreateAStarNode(startNode);\n start.g = 0;\n start.h = this.map.heuristic(startNode.position, endNode.position) * opts.heuristicWeight;\n start.f = start.h;\n start.opened = true;\n\n this.openList.push(start);\n\n let nodesSearched = 0;\n const endPosition = endNode.position;\n\n // A* main loop\n while (!this.openList.isEmpty && nodesSearched < opts.maxNodes) {\n const current = this.openList.pop()!;\n current.closed = true;\n nodesSearched++;\n\n // Found the goal\n if (current.node.id === endNode.id) {\n return this.buildPath(current, nodesSearched);\n }\n\n // Explore neighbors\n const neighbors = this.map.getNeighbors(current.node);\n\n for (const neighborNode of neighbors) {\n // Skip if not walkable or already closed\n if (!neighborNode.walkable) {\n continue;\n }\n\n const neighbor = this.getOrCreateAStarNode(neighborNode);\n\n if (neighbor.closed) {\n continue;\n }\n\n // Calculate tentative g score\n const movementCost = this.map.getMovementCost(current.node, neighborNode);\n const tentativeG = current.g + movementCost;\n\n // Check if this path is better\n if (!neighbor.opened) {\n // First time visiting this node\n neighbor.g = tentativeG;\n neighbor.h = this.map.heuristic(neighborNode.position, endPosition) * opts.heuristicWeight;\n neighbor.f = neighbor.g + neighbor.h;\n neighbor.parent = current;\n neighbor.opened = true;\n this.openList.push(neighbor);\n } else if (tentativeG < neighbor.g) {\n // Found a better path\n neighbor.g = tentativeG;\n neighbor.f = neighbor.g + neighbor.h;\n neighbor.parent = current;\n this.openList.update(neighbor);\n }\n }\n }\n\n // No path found\n return {\n found: false,\n path: [],\n cost: 0,\n nodesSearched\n };\n }\n\n /**\n * @zh 清理状态\n * @en Clear state\n */\n clear(): void {\n this.nodeCache.clear();\n this.openList.clear();\n }\n\n /**\n * @zh 获取或创建 A* 节点\n * @en Get or create A* node\n */\n private getOrCreateAStarNode(node: IPathNode): AStarNode {\n let astarNode = this.nodeCache.get(node.id);\n\n if (!astarNode) {\n astarNode = {\n node,\n g: Infinity,\n h: 0,\n f: Infinity,\n parent: null,\n closed: false,\n opened: false,\n heapIndex: -1\n };\n this.nodeCache.set(node.id, astarNode);\n }\n\n return astarNode;\n }\n\n /**\n * @zh 构建路径结果\n * @en Build path result\n */\n private buildPath(endNode: AStarNode, nodesSearched: number): IPathResult {\n const path: IPoint[] = [];\n let current: AStarNode | null = endNode;\n\n while (current) {\n path.push(current.node.position);\n current = current.parent;\n }\n\n path.reverse();\n\n return {\n found: true,\n path,\n cost: endNode.g,\n nodesSearched\n };\n }\n}\n\n// =============================================================================\n// 工厂函数 | Factory Function\n// =============================================================================\n\n/**\n * @zh 创建 A* 寻路器\n * @en Create A* pathfinder\n */\nexport function createAStarPathfinder(map: IPathfindingMap): AStarPathfinder {\n return new AStarPathfinder(map);\n}\n","/**\n * @zh 网格寻路器(统一实现)\n * @en Grid Pathfinder (unified implementation)\n */\n\nimport type { IPathfinder, IPathResult, IPathfindingOptions, IPoint } from './IPathfinding';\nimport { EMPTY_PATH_RESULT, DEFAULT_PATHFINDING_OPTIONS } from './IPathfinding';\nimport { GridMap } from '../grid/GridMap';\n\n// =============================================================================\n// 配置 | Configuration\n// =============================================================================\n\n/**\n * @zh 寻路模式\n * @en Pathfinding mode\n */\nexport type GridPathfinderMode = 'standard' | 'fast' | 'bidirectional';\n\n/**\n * @zh 网格寻路器配置\n * @en Grid pathfinder configuration\n */\nexport interface IGridPathfinderConfig {\n /**\n * @zh 寻路模式\n * @en Pathfinding mode\n *\n * - standard: 标准A*,适合小地图\n * - fast: TypedArray优化,适合中大地图\n * - bidirectional: 双向搜索,适合超大地图\n */\n mode?: GridPathfinderMode;\n}\n\n// =============================================================================\n// 常量 | Constants\n// =============================================================================\n\nconst CLOSED_FLAG = 1;\nconst OPENED_FLAG = 2;\nconst BACKWARD_CLOSED = 4;\nconst BACKWARD_OPENED = 8;\n\n// =============================================================================\n// 状态存储 | State Storage\n// =============================================================================\n\nclass GridState {\n private readonly size: number;\n readonly width: number;\n\n private g: Float32Array;\n private f: Float32Array;\n private flags: Uint8Array;\n private parent: Int32Array;\n private heapIndex: Int32Array;\n private version: Uint32Array;\n private currentVersion: number = 1;\n\n // 双向搜索额外状态\n private gBack: Float32Array | null = null;\n private fBack: Float32Array | null = null;\n private parentBack: Int32Array | null = null;\n private heapIndexBack: Int32Array | null = null;\n\n constructor(width: number, height: number, bidirectional: boolean = false) {\n this.width = width;\n this.size = width * height;\n\n this.g = new Float32Array(this.size);\n this.f = new Float32Array(this.size);\n this.flags = new Uint8Array(this.size);\n this.parent = new Int32Array(this.size);\n this.heapIndex = new Int32Array(this.size);\n this.version = new Uint32Array(this.size);\n\n if (bidirectional) {\n this.gBack = new Float32Array(this.size);\n this.fBack = new Float32Array(this.size);\n this.parentBack = new Int32Array(this.size);\n this.heapIndexBack = new Int32Array(this.size);\n }\n }\n\n reset(): void {\n this.currentVersion++;\n if (this.currentVersion > 0xFFFFFFFF) {\n this.version.fill(0);\n this.currentVersion = 1;\n }\n }\n\n private isInit(i: number): boolean {\n return this.version[i] === this.currentVersion;\n }\n\n private init(i: number): void {\n if (!this.isInit(i)) {\n this.g[i] = Infinity;\n this.f[i] = Infinity;\n this.flags[i] = 0;\n this.parent[i] = -1;\n this.heapIndex[i] = -1;\n if (this.gBack) {\n this.gBack[i] = Infinity;\n this.fBack![i] = Infinity;\n this.parentBack![i] = -1;\n this.heapIndexBack![i] = -1;\n }\n this.version[i] = this.currentVersion;\n }\n }\n\n // Forward\n getG(i: number): number { return this.isInit(i) ? this.g[i] : Infinity; }\n setG(i: number, v: number): void { this.init(i); this.g[i] = v; }\n getF(i: number): number { return this.isInit(i) ? this.f[i] : Infinity; }\n setF(i: number, v: number): void { this.init(i); this.f[i] = v; }\n getParent(i: number): number { return this.isInit(i) ? this.parent[i] : -1; }\n setParent(i: number, v: number): void { this.init(i); this.parent[i] = v; }\n getHeapIndex(i: number): number { return this.isInit(i) ? this.heapIndex[i] : -1; }\n setHeapIndex(i: number, v: number): void { this.init(i); this.heapIndex[i] = v; }\n isClosed(i: number): boolean { return this.isInit(i) && (this.flags[i] & CLOSED_FLAG) !== 0; }\n setClosed(i: number): void { this.init(i); this.flags[i] |= CLOSED_FLAG; }\n isOpened(i: number): boolean { return this.isInit(i) && (this.flags[i] & OPENED_FLAG) !== 0; }\n setOpened(i: number): void { this.init(i); this.flags[i] |= OPENED_FLAG; }\n\n // Backward\n getGBack(i: number): number { return this.isInit(i) ? this.gBack![i] : Infinity; }\n setGBack(i: number, v: number): void { this.init(i); this.gBack![i] = v; }\n getFBack(i: number): number { return this.isInit(i) ? this.fBack![i] : Infinity; }\n setFBack(i: number, v: number): void { this.init(i); this.fBack![i] = v; }\n getParentBack(i: number): number { return this.isInit(i) ? this.parentBack![i] : -1; }\n setParentBack(i: number, v: number): void { this.init(i); this.parentBack![i] = v; }\n getHeapIndexBack(i: number): number { return this.isInit(i) ? this.heapIndexBack![i] : -1; }\n setHeapIndexBack(i: number, v: number): void { this.init(i); this.heapIndexBack![i] = v; }\n isClosedBack(i: number): boolean { return this.isInit(i) && (this.flags[i] & BACKWARD_CLOSED) !== 0; }\n setClosedBack(i: number): void { this.init(i); this.flags[i] |= BACKWARD_CLOSED; }\n isOpenedBack(i: number): boolean { return this.isInit(i) && (this.flags[i] & BACKWARD_OPENED) !== 0; }\n setOpenedBack(i: number): void { this.init(i); this.flags[i] |= BACKWARD_OPENED; }\n}\n\n// =============================================================================\n// 堆 | Heap\n// =============================================================================\n\nclass GridHeap {\n private heap: number[] = [];\n private state: GridState;\n private isBack: boolean;\n\n constructor(state: GridState, isBack: boolean = false) {\n this.state = state;\n this.isBack = isBack;\n }\n\n get size(): number { return this.heap.length; }\n get isEmpty(): boolean { return this.heap.length === 0; }\n\n private getF(i: number): number {\n return this.isBack ? this.state.getFBack(i) : this.state.getF(i);\n }\n private getHeapIndex(i: number): number {\n return this.isBack ? this.state.getHeapIndexBack(i) : this.state.getHeapIndex(i);\n }\n private setHeapIndex(i: number, v: number): void {\n if (this.isBack) this.state.setHeapIndexBack(i, v);\n else this.state.setHeapIndex(i, v);\n }\n\n push(i: number): void {\n this.setHeapIndex(i, this.heap.length);\n this.heap.push(i);\n this.bubbleUp(this.heap.length - 1);\n }\n\n pop(): number {\n if (this.heap.length === 0) return -1;\n const result = this.heap[0];\n this.setHeapIndex(result, -1);\n const last = this.heap.pop()!;\n if (this.heap.length > 0) {\n this.heap[0] = last;\n this.setHeapIndex(last, 0);\n this.sinkDown(0);\n }\n return result;\n }\n\n update(i: number): void {\n const pos = this.getHeapIndex(i);\n if (pos >= 0 && pos < this.heap.length) {\n this.bubbleUp(pos);\n this.sinkDown(this.getHeapIndex(i));\n }\n }\n\n clear(): void { this.heap.length = 0; }\n\n private bubbleUp(pos: number): void {\n const idx = this.heap[pos];\n const f = this.getF(idx);\n while (pos > 0) {\n const pp = (pos - 1) >> 1;\n const pi = this.heap[pp];\n if (f >= this.getF(pi)) break;\n this.heap[pos] = pi;\n this.setHeapIndex(pi, pos);\n pos = pp;\n }\n this.heap[pos] = idx;\n this.setHeapIndex(idx, pos);\n }\n\n private sinkDown(pos: number): void {\n const len = this.heap.length;\n const idx = this.heap[pos];\n const f = this.getF(idx);\n const half = len >> 1;\n while (pos < half) {\n const left = (pos << 1) + 1;\n const right = left + 1;\n let smallest = pos, smallestF = f;\n const lf = this.getF(this.heap[left]);\n if (lf < smallestF) { smallest = left; smallestF = lf; }\n if (right < len) {\n const rf = this.getF(this.heap[right]);\n if (rf < smallestF) smallest = right;\n }\n if (smallest === pos) break;\n const si = this.heap[smallest];\n this.heap[pos] = si;\n this.setHeapIndex(si, pos);\n pos = smallest;\n }\n this.heap[pos] = idx;\n this.setHeapIndex(idx, pos);\n }\n}\n\n// =============================================================================\n// 网格寻路器 | Grid Pathfinder\n// =============================================================================\n\n/**\n * @zh 网格寻路器\n * @en Grid Pathfinder\n */\nexport class GridPathfinder implements IPathfinder {\n private readonly map: GridMap;\n private readonly mode: GridPathfinderMode;\n private readonly state: GridState;\n private readonly openList: GridHeap;\n private readonly openListBack: GridHeap | null;\n\n constructor(map: GridMap, config?: IGridPathfinderConfig) {\n this.map = map;\n this.mode = config?.mode ?? 'fast';\n const isBidir = this.mode === 'bidirectional';\n this.state = new GridState(map.width, map.height, isBidir);\n this.openList = new GridHeap(this.state, false);\n this.openListBack = isBidir ? new GridHeap(this.state, true) : null;\n }\n\n findPath(\n startX: number,\n startY: number,\n endX: number,\n endY: number,\n options?: IPathfindingOptions\n ): IPathResult {\n if (this.mode === 'bidirectional') {\n return this.findPathBidirectional(startX, startY, endX, endY, options);\n }\n return this.findPathUnidirectional(startX, startY, endX, endY, options);\n }\n\n private findPathUnidirectional(\n startX: number, startY: number,\n endX: number, endY: number,\n options?: IPathfindingOptions\n ): IPathResult {\n const opts = options ? { ...DEFAULT_PATHFINDING_OPTIONS, ...options } : DEFAULT_PATHFINDING_OPTIONS;\n const { width, height } = this.map;\n\n this.state.reset();\n this.openList.clear();\n\n if (!this.validate(startX, startY, endX, endY)) return EMPTY_PATH_RESULT;\n\n const startIdx = startY * width + startX;\n const endIdx = endY * width + endX;\n\n if (startIdx === endIdx) {\n return { found: true, path: [{ x: startX, y: startY }], cost: 0, nodesSearched: 1 };\n }\n\n const hw = opts.heuristicWeight;\n const h0 = this.map.heuristic({ x: startX, y: startY }, { x: endX, y: endY }) * hw;\n this.state.setG(startIdx, 0);\n this.state.setF(startIdx, h0);\n this.state.setOpened(startIdx);\n this.openList.push(startIdx);\n\n let searched = 0;\n const maxNodes = opts.maxNodes;\n const { allowDiagonal, avoidCorners, diagonalCost } = this.map['options'];\n const nodes = this.map['nodes'];\n const dx = allowDiagonal ? [0, 1, 1, 1, 0, -1, -1, -1] : [0, 1, 0, -1];\n const dy = allowDiagonal ? [-1, -1, 0, 1, 1, 1, 0, -1] : [-1, 0, 1, 0];\n const dirCount = dx.length;\n\n while (!this.openList.isEmpty && searched < maxNodes) {\n const cur = this.openList.pop();\n this.state.setClosed(cur);\n searched++;\n\n if (cur === endIdx) {\n return this.buildPath(startIdx, endIdx, searched);\n }\n\n const cx = cur % width, cy = (cur / width) | 0;\n const curG = this.state.getG(cur);\n\n for (let d = 0; d < dirCount; d++) {\n const nx = cx + dx[d], ny = cy + dy[d];\n if (nx < 0 || nx >= width || ny < 0 || ny >= height) continue;\n\n const neighbor = nodes[ny][nx];\n if (!neighbor.walkable) continue;\n\n if (avoidCorners && dx[d] !== 0 && dy[d] !== 0) {\n if (!nodes[cy][cx + dx[d]].walkable || !nodes[cy + dy[d]][cx].walkable) continue;\n }\n\n const ni = ny * width + nx;\n if (this.state.isClosed(ni)) continue;\n\n const isDiag = dx[d] !== 0 && dy[d] !== 0;\n const cost = isDiag ? neighbor.cost * diagonalCost : neighbor.cost;\n const tentG = curG + cost;\n\n if (!this.state.isOpened(ni)) {\n const h = this.map.heuristic({ x: nx, y: ny }, { x: endX, y: endY }) * hw;\n this.state.setG(ni, tentG);\n this.state.setF(ni, tentG + h);\n this.state.setParent(ni, cur);\n this.state.setOpened(ni);\n this.openList.push(ni);\n } else if (tentG < this.state.getG(ni)) {\n const h = this.state.getF(ni) - this.state.getG(ni);\n this.state.setG(ni, tentG);\n this.state.setF(ni, tentG + h);\n this.state.setParent(ni, cur);\n this.openList.update(ni);\n }\n }\n }\n\n return { found: false, path: [], cost: 0, nodesSearched: searched };\n }\n\n private findPathBidirectional(\n startX: number, startY: number,\n endX: number, endY: number,\n options?: IPathfindingOptions\n ): IPathResult {\n const opts = options ? { ...DEFAULT_PATHFINDING_OPTIONS, ...options } : DEFAULT_PATHFINDING_OPTIONS;\n const { width, height } = this.map;\n\n this.state.reset();\n this.openList.clear();\n this.openListBack!.clear();\n\n if (!this.validate(startX, startY, endX, endY)) return EMPTY_PATH_RESULT;\n\n const startIdx = startY * width + startX;\n const endIdx = endY * width + endX;\n\n if (startIdx === endIdx) {\n return { found: true, path: [{ x: startX, y: startY }], cost: 0, nodesSearched: 1 };\n }\n\n const hw = opts.heuristicWeight;\n const startPos = { x: startX, y: startY };\n const endPos = { x: endX, y: endY };\n\n // Init forward\n const hf = this.map.heuristic(startPos, endPos) * hw;\n this.state.setG(startIdx, 0);\n this.state.setF(startIdx, hf);\n this.state.setOpened(startIdx);\n this.openList.push(startIdx);\n\n // Init backward\n const hb = this.map.heuristic(endPos, startPos) * hw;\n this.state.setGBack(endIdx, 0);\n this.state.setFBack(endIdx, hb);\n this.state.setOpenedBack(endIdx);\n this.openListBack!.push(endIdx);\n\n let searched = 0;\n const maxNodes = opts.maxNodes;\n let meetIdx = -1, bestCost = Infinity;\n\n const { allowDiagonal, avoidCorners, diagonalCost } = this.map['options'];\n const nodes = this.map['nodes'];\n const dx = allowDiagonal ? [0, 1, 1, 1, 0, -1, -1, -1] : [0, 1, 0, -1];\n const dy = allowDiagonal ? [-1, -1, 0, 1, 1, 1, 0, -1] : [-1, 0, 1, 0];\n const dirCount = dx.length;\n\n while ((!this.openList.isEmpty || !this.openListBack!.isEmpty) && searched < maxNodes) {\n // Forward\n if (!this.openList.isEmpty) {\n const cur = this.openList.pop();\n this.state.setClosed(cur);\n searched++;\n\n const curG = this.state.getG(cur);\n if (this.state.isClosedBack(cur)) {\n const total = curG + this.state.getGBack(cur);\n if (total < bestCost) { bestCost = total; meetIdx = cur; }\n }\n if (meetIdx !== -1 && curG >= bestCost) break;\n\n const cx = cur % width, cy = (cur / width) | 0;\n for (let d = 0; d < dirCount; d++) {\n const nx = cx + dx[d], ny = cy + dy[d];\n if (nx < 0 || nx >= width || ny < 0 || ny >= height) continue;\n const neighbor = nodes[ny][nx];\n if (!neighbor.walkable) continue;\n if (avoidCorners && dx[d] !== 0 && dy[d] !== 0) {\n if (!nodes[cy][cx + dx[d]].walkable || !nodes[cy + dy[d]][cx].walkable) continue;\n }\n const ni = ny * width + nx;\n if (this.state.isClosed(ni)) continue;\n const isDiag = dx[d] !== 0 && dy[d] !== 0;\n const cost = isDiag ? neighbor.cost * diagonalCost : neighbor.cost;\n const tentG = curG + cost;\n if (!this.state.isOpened(ni)) {\n const h = this.map.heuristic({ x: nx, y: ny }, endPos) * hw;\n this.state.setG(ni, tentG);\n this.state.setF(ni, tentG + h);\n this.state.setParent(ni, cur);\n this.state.setOpened(ni);\n this.openList.push(ni);\n } else if (tentG < this.state.getG(ni)) {\n const h = this.state.getF(ni) - this.state.getG(ni);\n this.state.setG(ni, tentG);\n this.state.setF(ni, tentG + h);\n this.state.setParent(ni, cur);\n this.openList.update(ni);\n }\n }\n }\n\n // Backward\n if (!this.openListBack!.isEmpty) {\n const cur = this.openListBack!.pop();\n this.state.setClosedBack(cur);\n searched++;\n\n const curG = this.state.getGBack(cur);\n if (this.state.isClosed(cur)) {\n const total = curG + this.state.getG(cur);\n if (total < bestCost) { bestCost = total; meetIdx = cur; }\n }\n if (meetIdx !== -1 && curG >= bestCost) break;\n\n const cx = cur % width, cy = (cur / width) | 0;\n for (let d = 0; d < dirCount; d++) {\n const nx = cx + dx[d], ny = cy + dy[d];\n if (nx < 0 || nx >= width || ny < 0 || ny >= height) continue;\n const neighbor = nodes[ny][nx];\n if (!neighbor.walkable) continue;\n if (avoidCorners && dx[d] !== 0 && dy[d] !== 0) {\n if (!nodes[cy][cx + dx[d]].walkable || !nodes[cy + dy[d]][cx].walkable) continue;\n }\n const ni = ny * width + nx;\n if (this.state.isClosedBack(ni)) continue;\n const isDiag = dx[d] !== 0 && dy[d] !== 0;\n const cost = isDiag ? neighbor.cost * diagonalCost : neighbor.cost;\n const tentG = curG + cost;\n if (!this.state.isOpenedBack(ni)) {\n const h = this.map.heuristic({ x: nx, y: ny }, startPos) * hw;\n this.state.setGBack(ni, tentG);\n this.state.setFBack(ni, tentG + h);\n this.state.setParentBack(ni, cur);\n this.state.setOpenedBack(ni);\n this.openListBack!.push(ni);\n } else if (tentG < this.state.getGBack(ni)) {\n const h = this.state.getFBack(ni) - this.state.getGBack(ni);\n this.state.setGBack(ni, tentG);\n this.state.setFBack(ni, tentG + h);\n this.state.setParentBack(ni, cur);\n this.openListBack!.update(ni);\n }\n }\n }\n }\n\n if (meetIdx === -1) {\n return { found: false, path: [], cost: 0, nodesSearched: searched };\n }\n\n return this.buildPathBidirectional(startIdx, endIdx, meetIdx, searched);\n }\n\n private validate(startX: number, startY: number, endX: number, endY: number): boolean {\n const { width, height } = this.map;\n if (startX < 0 || startX >= width || startY < 0 || startY >= height) return false;\n if (endX < 0 || endX >= width || endY < 0 || endY >= height) return false;\n return this.map.isWalkable(startX, startY) && this.map.isWalkable(endX, endY);\n }\n\n private buildPath(startIdx: number, endIdx: number, searched: number): IPathResult {\n const w = this.state.width;\n const path: IPoint[] = [];\n let cur = endIdx;\n while (cur !== -1) {\n path.push({ x: cur % w, y: (cur / w) | 0 });\n cur = cur === startIdx ? -1 : this.state.getParent(cur);\n }\n path.reverse();\n return { found: true, path, cost: this.state.getG(endIdx), nodesSearched: searched };\n }\n\n private buildPathBidirectional(startIdx: number, endIdx: number, meetIdx: number, searched: number): IPathResult {\n const w = this.state.width;\n const path: IPoint[] = [];\n\n // Forward path\n let cur = meetIdx;\n while (cur !== -1 && cur !== startIdx) {\n path.push({ x: cur % w, y: (cur / w) | 0 });\n cur = this.state.getParent(cur);\n }\n path.push({ x: startIdx % w, y: (startIdx / w) | 0 });\n path.reverse();\n\n // Backward path\n cur = this.state.getParentBack(meetIdx);\n while (cur !== -1 && cur !== endIdx) {\n path.push({ x: cur % w, y: (cur / w) | 0 });\n cur = this.state.getParentBack(cur);\n }\n if (meetIdx !== endIdx) {\n path.push({ x: endIdx % w, y: (endIdx / w) | 0 });\n }\n\n const cost = this.state.getG(meetIdx) + this.state.getGBack(meetIdx);\n return { found: true, path, cost, nodesSearched: searched };\n }\n\n clear(): void {\n this.state.reset();\n this.openList.clear();\n this.openListBack?.clear();\n }\n}\n\n/**\n * @zh 创建网格寻路器\n * @en Create grid pathfinder\n */\nexport function createGridPathfinder(map: GridMap, config?: IGridPathfinderConfig): GridPathfinder {\n return new GridPathfinder(map, config);\n}\n","/**\n * @zh JPS (Jump Point Search) 寻路算法实现\n * @en JPS (Jump Point Search) Pathfinding Algorithm Implementation\n *\n * @zh JPS 是 A* 的优化版本,通过跳跃点剪枝大幅提升开放地形的搜索效率\n * @en JPS is an optimized version of A* that significantly improves search efficiency on open terrain through jump point pruning\n */\n\nimport { BinaryHeap } from './BinaryHeap';\nimport type {\n IPathfindingMap,\n IPathNode,\n IPoint,\n IPathResult,\n IPathfinder,\n IPathfindingOptions\n} from './IPathfinding';\nimport { DEFAULT_PATHFINDING_OPTIONS, EMPTY_PATH_RESULT } from './IPathfinding';\n\n// =============================================================================\n// 内部类型 | Internal Types\n// =============================================================================\n\n/**\n * @zh JPS 节点\n * @en JPS Node\n */\ninterface JPSNode {\n x: number;\n y: number;\n g: number;\n h: number;\n f: number;\n parent: JPSNode | null;\n closed: boolean;\n}\n\n// =============================================================================\n// JPS 寻路器 | JPS Pathfinder\n// =============================================================================\n\n/**\n * @zh JPS 寻路器\n * @en JPS Pathfinder\n *\n * @zh 适用于均匀代价网格地图,在开放地形上比标准 A* 快 10-100 倍\n * @en Suitable for uniform cost grid maps, 10-100x faster than standard A* on open terrain\n *\n * @example\n * ```typescript\n * const map = createGridMap(100, 100);\n * const pathfinder = new JPSPathfinder(map);\n * const result = pathfinder.findPath(0, 0, 99, 99);\n * ```\n */\nexport class JPSPathfinder implements IPathfinder {\n private readonly map: IPathfindingMap;\n private readonly width: number;\n private readonly height: number;\n\n private openList: BinaryHeap<JPSNode>;\n private nodeGrid: (JPSNode | null)[][];\n\n constructor(map: IPathfindingMap) {\n this.map = map;\n\n // 获取地图尺寸\n const bounds = this.getMapBounds();\n this.width = bounds.width;\n this.height = bounds.height;\n\n this.openList = new BinaryHeap<JPSNode>((a, b) => a.f - b.f);\n this.nodeGrid = [];\n }\n\n /**\n * @zh 寻找路径\n * @en Find path\n */\n findPath(\n startX: number,\n startY: number,\n endX: number,\n endY: number,\n options?: Partial<IPathfindingOptions>\n ): IPathResult {\n const opts = { ...DEFAULT_PATHFINDING_OPTIONS, ...options };\n\n // 验证起点和终点\n if (!this.map.isWalkable(startX, startY) || !this.map.isWalkable(endX, endY)) {\n return EMPTY_PATH_RESULT;\n }\n\n // 相同位置\n if (startX === endX && startY === endY) {\n return {\n found: true,\n path: [{ x: startX, y: startY }],\n cost: 0,\n nodesSearched: 1\n };\n }\n\n // 初始化\n this.initGrid();\n this.openList.clear();\n\n const startNode = this.getOrCreateNode(startX, startY);\n startNode.g = 0;\n startNode.h = this.heuristic(startX, startY, endX, endY) * opts.heuristicWeight;\n startNode.f = startNode.h;\n this.openList.push(startNode);\n\n let nodesSearched = 0;\n\n while (!this.openList.isEmpty && nodesSearched < opts.maxNodes) {\n const current = this.openList.pop()!;\n current.closed = true;\n nodesSearched++;\n\n // 到达终点\n if (current.x === endX && current.y === endY) {\n return {\n found: true,\n path: this.buildPath(current),\n cost: current.g,\n nodesSearched\n };\n }\n\n // 查找跳跃点\n this.identifySuccessors(current, endX, endY, opts);\n }\n\n return {\n found: false,\n path: [],\n cost: 0,\n nodesSearched\n };\n }\n\n /**\n * @zh 清理状态\n * @en Clear state\n */\n clear(): void {\n this.openList.clear();\n this.nodeGrid = [];\n }\n\n // =========================================================================\n // 私有方法 | Private Methods\n // =========================================================================\n\n /**\n * @zh 获取地图边界\n * @en Get map bounds\n */\n private getMapBounds(): { width: number; height: number } {\n // 尝试从地图获取尺寸\n const mapAny = this.map as any;\n if (typeof mapAny.width === 'number' && typeof mapAny.height === 'number') {\n return { width: mapAny.width, height: mapAny.height };\n }\n // 默认尺寸\n return { width: 1000, height: 1000 };\n }\n\n /**\n * @zh 初始化节点网格\n * @en Initialize node grid\n */\n private initGrid(): void {\n this.nodeGrid = [];\n for (let i = 0; i < this.width; i++) {\n this.nodeGrid[i] = [];\n }\n }\n\n /**\n * @zh 获取或创建节点\n * @en Get or create node\n */\n private getOrCreateNode(x: number, y: number): JPSNode {\n // Bounds check to ensure valid array indices\n const xi = x | 0;\n const yi = y | 0;\n if (xi < 0 || xi >= this.width || yi < 0 || yi >= this.height) {\n throw new Error('[JPSPathfinder] Invalid grid coordinates');\n }\n if (!this.nodeGrid[xi]) {\n this.nodeGrid[xi] = [];\n }\n if (!this.nodeGrid[xi][yi]) {\n this.nodeGrid[xi][yi] = {\n x: xi,\n y: yi,\n g: Infinity,\n h: 0,\n f: Infinity,\n parent: null,\n closed: false\n };\n }\n return this.nodeGrid[xi][yi]!;\n }\n\n /**\n * @zh 启发式函数(八方向距离)\n * @en Heuristic function (octile distance)\n */\n private heuristic(x1: number, y1: number, x2: number, y2: number): number {\n const dx = Math.abs(x1 - x2);\n const dy = Math.abs(y1 - y2);\n return dx + dy + (Math.SQRT2 - 2) * Math.min(dx, dy);\n }\n\n /**\n * @zh 识别后继节点(跳跃点)\n * @en Identify successors (jump points)\n */\n private identifySuccessors(\n node: JPSNode,\n endX: number,\n endY: number,\n opts: Required<IPathfindingOptions>\n ): void {\n const neighbors = this.findNeighbors(node);\n\n for (const neighbor of neighbors) {\n const jumpPoint = this.jump(\n neighbor.x,\n neighbor.y,\n node.x,\n node.y,\n endX,\n endY\n );\n\n if (jumpPoint) {\n const jx = jumpPoint.x;\n const jy = jumpPoint.y;\n\n const jpNode = this.getOrCreateNode(jx, jy);\n if (jpNode.closed) continue;\n\n const dx = Math.abs(jx - node.x);\n const dy = Math.abs(jy - node.y);\n const distance = Math.sqrt(dx * dx + dy * dy);\n const tentativeG = node.g + distance;\n\n if (tentativeG < jpNode.g) {\n jpNode.g = tentativeG;\n jpNode.h = this.heuristic(jx, jy, endX, endY) * opts.heuristicWeight;\n jpNode.f = jpNode.g + jpNode.h;\n jpNode.parent = node;\n\n if (!this.openList.contains(jpNode)) {\n this.openList.push(jpNode);\n } else {\n this.openList.update(jpNode);\n }\n }\n }\n }\n }\n\n /**\n * @zh 查找邻居(根据父节点方向剪枝)\n * @en Find neighbors (pruned based on parent direction)\n */\n private findNeighbors(node: JPSNode): IPoint[] {\n const { x, y, parent } = node;\n const neighbors: IPoint[] = [];\n\n // 无父节点,返回所有可通行邻居\n if (!parent) {\n for (let dx = -1; dx <= 1; dx++) {\n for (let dy = -1; dy <= 1; dy++) {\n if (dx === 0 && dy === 0) continue;\n const nx = x + dx;\n const ny = y + dy;\n if (this.isWalkableAt(nx, ny)) {\n // 对角线移动检查\n if (dx !== 0 && dy !== 0) {\n if (this.isWalkableAt(x + dx, y) || this.isWalkableAt(x, y + dy)) {\n neighbors.push({ x: nx, y: ny });\n }\n } else {\n neighbors.push({ x: nx, y: ny });\n }\n }\n }\n }\n return neighbors;\n }\n\n // 有父节点,根据方向剪枝\n const dx = Math.sign(x - parent.x);\n const dy = Math.sign(y - parent.y);\n\n // 对角线移动\n if (dx !== 0 && dy !== 0) {\n // 自然邻居\n if (this.isWalkableAt(x, y + dy)) {\n neighbors.push({ x, y: y + dy });\n }\n if (this.isWalkableAt(x + dx, y)) {\n neighbors.push({ x: x + dx, y });\n }\n if (this.isWalkableAt(x, y + dy) || this.isWalkableAt(x + dx, y)) {\n if (this.isWalkableAt(x + dx, y + dy)) {\n neighbors.push({ x: x + dx, y: y + dy });\n }\n }\n\n // 强制邻居\n if (!this.isWalkableAt(x - dx, y) && this.isWalkableAt(x, y + dy)) {\n if (this.isWalkableAt(x - dx, y + dy)) {\n neighbors.push({ x: x - dx, y: y + dy });\n }\n }\n if (!this.isWalkableAt(x, y - dy) && this.isWalkableAt(x + dx, y)) {\n if (this.isWalkableAt(x + dx, y - dy)) {\n neighbors.push({ x: x + dx, y: y - dy });\n }\n }\n }\n // 水平移动\n else if (dx !== 0) {\n if (this.isWalkableAt(x + dx, y)) {\n neighbors.push({ x: x + dx, y });\n\n // 强制邻居\n if (!this.isWalkableAt(x, y + 1) && this.isWalkableAt(x + dx, y + 1)) {\n neighbors.push({ x: x + dx, y: y + 1 });\n }\n if (!this.isWalkableAt(x, y - 1) && this.isWalkableAt(x + dx, y - 1)) {\n neighbors.push({ x: x + dx, y: y - 1 });\n }\n }\n }\n // 垂直移动\n else if (dy !== 0) {\n if (this.isWalkableAt(x, y + dy)) {\n neighbors.push({ x, y: y + dy });\n\n // 强制邻居\n if (!this.isWalkableAt(x + 1, y) && this.isWalkableAt(x + 1, y + dy)) {\n neighbors.push({ x: x + 1, y: y + dy });\n }\n if (!this.isWalkableAt(x - 1, y) && this.isWalkableAt(x - 1, y + dy)) {\n neighbors.push({ x: x - 1, y: y + dy });\n }\n }\n }\n\n return neighbors;\n }\n\n /**\n * @zh 跳跃函数(迭代版本,避免递归开销)\n * @en Jump function (iterative version to avoid recursion overhead)\n */\n private jump(\n startX: number,\n startY: number,\n px: number,\n py: number,\n endX: number,\n endY: number\n ): IPoint | null {\n const dx = startX - px;\n const dy = startY - py;\n\n let x = startX;\n let y = startY;\n\n while (true) {\n if (!this.isWalkableAt(x, y)) {\n return null;\n }\n\n if (x === endX && y === endY) {\n return { x, y };\n }\n\n if (dx !== 0 && dy !== 0) {\n if ((this.isWalkableAt(x - dx, y + dy) && !this.isWalkableAt(x - dx, y)) ||\n (this.isWalkableAt(x + dx, y - dy) && !this.isWalkableAt(x, y - dy))) {\n return { x, y };\n }\n\n if (this.jumpStraight(x + dx, y, dx, 0, endX, endY) ||\n this.jumpStraight(x, y + dy, 0, dy, endX, endY)) {\n return { x, y };\n }\n\n if (!this.isWalkableAt(x + dx, y) && !this.isWalkableAt(x, y + dy)) {\n return null;\n }\n } else if (dx !== 0) {\n if ((this.isWalkableAt(x + dx, y + 1) && !this.isWalkableAt(x, y + 1)) ||\n (this.isWalkableAt(x + dx, y - 1) && !this.isWalkableAt(x, y - 1))) {\n return { x, y };\n }\n } else if (dy !== 0) {\n if ((this.isWalkableAt(x + 1, y + dy) && !this.isWalkableAt(x + 1, y)) ||\n (this.isWalkableAt(x - 1, y + dy) && !this.isWalkableAt(x - 1, y))) {\n return { x, y };\n }\n }\n\n x += dx;\n y += dy;\n }\n }\n\n /**\n * @zh 直线跳跃(水平或垂直方向)\n * @en Straight jump (horizontal or vertical direction)\n */\n private jumpStraight(\n startX: number,\n startY: number,\n dx: number,\n dy: number,\n endX: number,\n endY: number\n ): boolean {\n let x = startX;\n let y = startY;\n\n while (true) {\n if (!this.isWalkableAt(x, y)) {\n return false;\n }\n\n if (x === endX && y === endY) {\n return true;\n }\n\n if (dx !== 0) {\n if ((this.isWalkableAt(x + dx, y + 1) && !this.isWalkableAt(x, y + 1)) ||\n (this.isWalkableAt(x + dx, y - 1) && !this.isWalkableAt(x, y - 1))) {\n return true;\n }\n } else if (dy !== 0) {\n if ((this.isWalkableAt(x + 1, y + dy) && !this.isWalkableAt(x + 1, y)) ||\n (this.isWalkableAt(x - 1, y + dy) && !this.isWalkableAt(x - 1, y))) {\n return true;\n }\n }\n\n x += dx;\n y += dy;\n }\n }\n\n /**\n * @zh 检查位置是否可通行\n * @en Check if position is walkable\n */\n private isWalkableAt(x: number, y: number): boolean {\n if (x < 0 || x >= this.width || y < 0 || y >= this.height) {\n return false;\n }\n return this.map.isWalkable(x, y);\n }\n\n /**\n * @zh 构建路径\n * @en Build path\n */\n private buildPath(endNode: JPSNode): IPoint[] {\n const path: IPoint[] = [];\n let current: JPSNode | null = endNode;\n\n while (current) {\n path.unshift({ x: current.x, y: current.y });\n current = current.parent;\n }\n\n // 插值跳跃点之间的路径\n return this.interpolatePath(path);\n }\n\n /**\n * @zh 插值路径(在跳跃点之间填充中间点)\n * @en Interpolate path (fill intermediate points between jump points)\n */\n private interpolatePath(jumpPoints: IPoint[]): IPoint[] {\n if (jumpPoints.length < 2) {\n return jumpPoints;\n }\n\n const path: IPoint[] = [jumpPoints[0]];\n\n for (let i = 1; i < jumpPoints.length; i++) {\n const prev = jumpPoints[i - 1];\n const curr = jumpPoints[i];\n\n const dx = curr.x - prev.x;\n const dy = curr.y - prev.y;\n const steps = Math.max(Math.abs(dx), Math.abs(dy));\n\n const stepX = dx === 0 ? 0 : dx / Math.abs(dx);\n const stepY = dy === 0 ? 0 : dy / Math.abs(dy);\n\n let x = prev.x;\n let y = prev.y;\n\n for (let j = 0; j < steps; j++) {\n // 优先对角移动\n if (x !== curr.x && y !== curr.y) {\n x += stepX;\n y += stepY;\n } else if (x !== curr.x) {\n x += stepX;\n } else if (y !== curr.y) {\n y += stepY;\n }\n\n if (x !== prev.x || y !== prev.y) {\n path.push({ x, y });\n }\n }\n }\n\n return path;\n }\n}\n\n// =============================================================================\n// 工厂函数 | Factory Function\n// =============================================================================\n\n/**\n * @zh 创建 JPS 寻路器\n * @en Create JPS pathfinder\n *\n * @param map - @zh 寻路地图实例 @en Pathfinding map instance\n * @returns @zh JPS 寻路器实例 @en JPS pathfinder instance\n */\nexport function createJPSPathfinder(map: IPathfindingMap): JPSPathfinder {\n return new JPSPathfinder(map);\n}\n","/**\n * @zh HPA* (Hierarchical Pathfinding A*) 寻路算法实现\n * @en HPA* (Hierarchical Pathfinding A*) Pathfinding Algorithm Implementation\n *\n * @zh HPA* 是一种分层寻路算法,适用于超大地图 (1000x1000+)\n * @en HPA* is a hierarchical pathfinding algorithm suitable for very large maps (1000x1000+)\n *\n * @zh 工作原理:\n * 1. 将地图划分为集群 (clusters)\n * 2. 在集群边界检测入口点 (entrances)\n * 3. 构建抽象图 (abstract graph) 连接入口点\n * 4. 预计算集群内入口点之间的真实路径代价\n * 5. 先在抽象图上寻路,再利用缓存细化为详细路径\n *\n * @en How it works:\n * 1. Divide map into clusters\n * 2. Detect entrances at cluster boundaries\n * 3. Build abstract graph connecting entrances\n * 4. Precompute actual path costs between entrances within clusters\n * 5. First find path on abstract graph, then refine using cached paths\n */\n\nimport { IndexedBinaryHeap, IHeapIndexable } from './IndexedBinaryHeap';\nimport type {\n IPathfindingMap,\n IPoint,\n IPathResult,\n IPathfinder,\n IPathfindingOptions,\n IPathNode\n} from './IPathfinding';\nimport { DEFAULT_PATHFINDING_OPTIONS, EMPTY_PATH_RESULT } from './IPathfinding';\nimport { AStarPathfinder } from './AStarPathfinder';\nimport { PathCache } from './PathCache';\n\n// =============================================================================\n// 类型定义 | Type Definitions\n// =============================================================================\n\n/**\n * @zh HPA* 配置\n * @en HPA* Configuration\n */\nexport interface IHPAConfig {\n /**\n * @zh 集群大小(边长)\n * @en Cluster size (side length)\n */\n clusterSize: number;\n\n /**\n * @zh 最大入口宽度(超过此宽度会拆分或使用端点策略)\n * @en Maximum entrance width (entrances wider than this will be split or use endpoint strategy)\n */\n maxEntranceWidth: number;\n\n /**\n * @zh 是否启用内部路径缓存\n * @en Whether to enable internal path caching\n */\n cacheInternalPaths: boolean;\n\n /**\n * @zh 入口策略:'middle' 在中间放节点,'end' 在宽入口两端各放节点\n * @en Entrance strategy: 'middle' places node at center, 'end' places nodes at both ends for wide entrances\n */\n entranceStrategy?: 'middle' | 'end';\n\n /**\n * @zh 是否延迟计算 intra-edges(大幅加速预处理,首次查询时计算真实路径)\n * @en Whether to lazily compute intra-edges (greatly speeds up preprocessing, computes actual paths on first query)\n */\n lazyIntraEdges?: boolean;\n}\n\n/**\n * @zh 默认 HPA* 配置\n * @en Default HPA* configuration\n */\nexport const DEFAULT_HPA_CONFIG: IHPAConfig = {\n clusterSize: 64,\n maxEntranceWidth: 16,\n cacheInternalPaths: true,\n entranceStrategy: 'end',\n lazyIntraEdges: true\n};\n\n/**\n * @zh 抽象边信息\n * @en Abstract edge information\n */\ninterface AbstractEdge {\n /** @zh 目标节点 ID @en Target node ID */\n targetNodeId: number;\n /** @zh 边代价(真实路径代价)@en Edge cost (actual path cost) */\n cost: number;\n /** @zh 是否为跨集群边 @en Is inter-cluster edge */\n isInterEdge: boolean;\n /** @zh 缓存的具体路径(ConcreteNodeId 列表)@en Cached concrete path (ConcreteNodeId list) */\n innerPath: number[] | null;\n}\n\n/**\n * @zh 抽象节点\n * @en Abstract node\n */\ninterface AbstractNode {\n /** @zh 节点 ID @en Node ID */\n id: number;\n /** @zh 位置(地图坐标)@en Position (map coordinates) */\n position: IPoint;\n /** @zh 所属集群 ID @en Cluster ID */\n clusterId: number;\n /** @zh 对应的具体地图节点 ID (y * width + x) @en Corresponding concrete node ID */\n concreteNodeId: number;\n /** @zh 出边列表 @en Outgoing edges */\n edges: AbstractEdge[];\n}\n\n/**\n * @zh A* 搜索节点\n * @en A* search node\n */\ninterface SearchNode extends IHeapIndexable {\n node: AbstractNode;\n g: number;\n h: number;\n f: number;\n parent: SearchNode | null;\n closed: boolean;\n opened: boolean;\n heapIndex: number;\n}\n\n/**\n * @zh 入口区间(边界上连续可通行的区域)\n * @en Entrance span (continuous walkable region on boundary)\n */\ninterface EntranceSpan {\n start: number;\n end: number;\n}\n\n// =============================================================================\n// SubMap 子地图类 (Slice) | SubMap Class (Slice)\n// =============================================================================\n\n/**\n * @zh 子地图 - 为集群提供隔离的地图视图\n * @en SubMap - Provides isolated map view for cluster\n *\n * @zh 不复制数据,只做坐标转换并委托给父地图\n * @en Doesn't copy data, just transforms coordinates and delegates to parent map\n */\nclass SubMap implements IPathfindingMap {\n readonly width: number;\n readonly height: number;\n\n constructor(\n private readonly parentMap: IPathfindingMap,\n private readonly originX: number,\n private readonly originY: number,\n width: number,\n height: number\n ) {\n this.width = width;\n this.height = height;\n }\n\n /**\n * @zh 局部坐标转全局坐标\n * @en Convert local to global coordinates\n */\n localToGlobal(localX: number, localY: number): IPoint {\n return {\n x: this.originX + localX,\n y: this.originY + localY\n };\n }\n\n /**\n * @zh 全局坐标转局部坐标\n * @en Convert global to local coordinates\n */\n globalToLocal(globalX: number, globalY: number): IPoint {\n return {\n x: globalX - this.originX,\n y: globalY - this.originY\n };\n }\n\n isWalkable(x: number, y: number): boolean {\n if (x < 0 || x >= this.width || y < 0 || y >= this.height) {\n return false;\n }\n return this.parentMap.isWalkable(this.originX + x, this.originY + y);\n }\n\n getNodeAt(x: number, y: number): IPathNode | null {\n if (x < 0 || x >= this.width || y < 0 || y >= this.height) {\n return null;\n }\n const globalNode = this.parentMap.getNodeAt(this.originX + x, this.originY + y);\n if (!globalNode) return null;\n\n // 创建局部节点(调整坐标)\n return {\n id: y * this.width + x,\n position: { x, y },\n cost: globalNode.cost,\n walkable: globalNode.walkable\n };\n }\n\n getNeighbors(node: IPathNode): IPathNode[] {\n const neighbors: IPathNode[] = [];\n const { x, y } = node.position;\n\n // 8方向邻居\n const directions = [\n { dx: 0, dy: -1 }, // N\n { dx: 1, dy: -1 }, // NE\n { dx: 1, dy: 0 }, // E\n { dx: 1, dy: 1 }, // SE\n { dx: 0, dy: 1 }, // S\n { dx: -1, dy: 1 }, // SW\n { dx: -1, dy: 0 }, // W\n { dx: -1, dy: -1 } // NW\n ];\n\n for (const dir of directions) {\n const nx = x + dir.dx;\n const ny = y + dir.dy;\n\n if (nx < 0 || nx >= this.width || ny < 0 || ny >= this.height) {\n continue;\n }\n\n if (!this.isWalkable(nx, ny)) {\n continue;\n }\n\n // 对角线移动:检查是否被角落阻挡\n if (dir.dx !== 0 && dir.dy !== 0) {\n if (!this.isWalkable(x + dir.dx, y) || !this.isWalkable(x, y + dir.dy)) {\n continue;\n }\n }\n\n const neighborNode = this.getNodeAt(nx, ny);\n if (neighborNode) {\n neighbors.push(neighborNode);\n }\n }\n\n return neighbors;\n }\n\n heuristic(a: IPoint, b: IPoint): number {\n // Octile 距离\n const dx = Math.abs(a.x - b.x);\n const dy = Math.abs(a.y - b.y);\n return dx + dy + (Math.SQRT2 - 2) * Math.min(dx, dy);\n }\n\n getMovementCost(from: IPathNode, to: IPathNode): number {\n const dx = Math.abs(to.position.x - from.position.x);\n const dy = Math.abs(to.position.y - from.position.y);\n const baseCost = (dx !== 0 && dy !== 0) ? Math.SQRT2 : 1;\n return baseCost * to.cost;\n }\n}\n\n// =============================================================================\n// Cluster 集群类 | Cluster Class\n// =============================================================================\n\n/**\n * @zh 集群 - 管理地图的一个区域\n * @en Cluster - Manages a region of the map\n */\nclass Cluster {\n readonly id: number;\n readonly originX: number;\n readonly originY: number;\n readonly width: number;\n readonly height: number;\n readonly subMap: SubMap;\n\n /** @zh 集群内的抽象节点 ID 列表 @en Abstract node IDs in this cluster */\n nodeIds: number[] = [];\n\n /** @zh 预计算的距离缓存 @en Precomputed distance cache */\n private readonly distanceCache: Map<string, number> = new Map();\n\n /** @zh 预计算的路径缓存 @en Precomputed path cache */\n private readonly pathCache: Map<string, number[]> = new Map();\n\n constructor(\n id: number,\n originX: number,\n originY: number,\n width: number,\n height: number,\n parentMap: IPathfindingMap\n ) {\n this.id = id;\n this.originX = originX;\n this.originY = originY;\n this.width = width;\n this.height = height;\n this.subMap = new SubMap(parentMap, originX, originY, width, height);\n }\n\n /**\n * @zh 检查点是否在集群内\n * @en Check if point is in cluster\n */\n containsPoint(x: number, y: number): boolean {\n return x >= this.originX && x < this.originX + this.width &&\n y >= this.originY && y < this.originY + this.height;\n }\n\n /**\n * @zh 添加节点 ID\n * @en Add node ID\n */\n addNodeId(nodeId: number): void {\n if (!this.nodeIds.includes(nodeId)) {\n this.nodeIds.push(nodeId);\n }\n }\n\n /**\n * @zh 移除节点 ID\n * @en Remove node ID\n */\n removeNodeId(nodeId: number): void {\n const idx = this.nodeIds.indexOf(nodeId);\n if (idx !== -1) {\n this.nodeIds.splice(idx, 1);\n }\n }\n\n /**\n * @zh 生成缓存键\n * @en Generate cache key\n */\n private getCacheKey(fromId: number, toId: number): string {\n return `${fromId}->${toId}`;\n }\n\n /**\n * @zh 设置缓存\n * @en Set cache\n */\n setCache(fromId: number, toId: number, cost: number, path: number[]): void {\n const key = this.getCacheKey(fromId, toId);\n this.distanceCache.set(key, cost);\n this.pathCache.set(key, path);\n }\n\n /**\n * @zh 获取缓存的距离\n * @en Get cached distance\n */\n getCachedDistance(fromId: number, toId: number): number | undefined {\n return this.distanceCache.get(this.getCacheKey(fromId, toId));\n }\n\n /**\n * @zh 获取缓存的路径\n * @en Get cached path\n */\n getCachedPath(fromId: number, toId: number): number[] | undefined {\n return this.pathCache.get(this.getCacheKey(fromId, toId));\n }\n\n /**\n * @zh 清除缓存\n * @en Clear cache\n */\n clearCache(): void {\n this.distanceCache.clear();\n this.pathCache.clear();\n }\n\n /**\n * @zh 获取缓存大小\n * @en Get cache size\n */\n getCacheSize(): number {\n return this.distanceCache.size;\n }\n}\n\n// =============================================================================\n// HPA* 寻路器 | HPA* Pathfinder\n// =============================================================================\n\n/**\n * @zh HPA* 寻路器\n * @en HPA* Pathfinder\n *\n * @zh 适用于超大地图的分层寻路算法\n * @en Hierarchical pathfinding algorithm for very large maps\n *\n * @example\n * ```typescript\n * const map = createGridMap(1000, 1000);\n * const pathfinder = new HPAPathfinder(map, { clusterSize: 20 });\n *\n * // Preprocess (do once after map changes)\n * pathfinder.preprocess();\n *\n * // Find path\n * const result = pathfinder.findPath(0, 0, 999, 999);\n * ```\n */\nexport class HPAPathfinder implements IPathfinder {\n private readonly map: IPathfindingMap;\n private readonly config: Required<IHPAConfig>;\n private readonly mapWidth: number;\n private readonly mapHeight: number;\n\n // 集群管理\n private clusters: Cluster[] = [];\n private clusterGrid: (number | null)[][] = []; // [cx][cy] -> clusterId\n private clustersX: number = 0;\n private clustersY: number = 0;\n\n // 抽象图\n private abstractNodes: Map<number, AbstractNode> = new Map();\n private nodesByCluster: Map<number, number[]> = new Map();\n private nextNodeId: number = 0;\n\n // 入口统计\n private entranceCount: number = 0;\n\n // 内部寻路器\n private readonly localPathfinder: AStarPathfinder;\n\n // 完整路径缓存\n private readonly pathCache: PathCache;\n private mapVersion: number = 0;\n\n private preprocessed: boolean = false;\n\n constructor(map: IPathfindingMap, config?: Partial<IHPAConfig>) {\n this.map = map;\n this.config = { ...DEFAULT_HPA_CONFIG, ...config } as Required<IHPAConfig>;\n\n const bounds = this.getMapBounds();\n this.mapWidth = bounds.width;\n this.mapHeight = bounds.height;\n\n this.localPathfinder = new AStarPathfinder(map);\n this.pathCache = new PathCache({ maxEntries: 1000, ttlMs: 0 });\n }\n\n // =========================================================================\n // 公共 API | Public API\n // =========================================================================\n\n /**\n * @zh 预处理地图(构建抽象图)\n * @en Preprocess map (build abstract graph)\n */\n preprocess(): void {\n this.clear();\n\n // 1. 构建集群\n this.buildClusters();\n\n // 2. 检测入口并创建抽象节点\n this.buildEntrances();\n\n // 3. 创建集群内边(计算真实代价)\n this.buildIntraEdges();\n\n this.preprocessed = true;\n }\n\n /**\n * @zh 寻找路径\n * @en Find path\n */\n findPath(\n startX: number,\n startY: number,\n endX: number,\n endY: number,\n options?: Partial<IPathfindingOptions>\n ): IPathResult {\n if (!this.preprocessed) {\n this.preprocess();\n }\n\n const opts = { ...DEFAULT_PATHFINDING_OPTIONS, ...options };\n\n // 验证起点终点\n if (!this.map.isWalkable(startX, startY) || !this.map.isWalkable(endX, endY)) {\n return EMPTY_PATH_RESULT;\n }\n\n // 同一点\n if (startX === endX && startY === endY) {\n return {\n found: true,\n path: [{ x: startX, y: startY }],\n cost: 0,\n nodesSearched: 1\n };\n }\n\n // 检查路径缓存\n const cached = this.pathCache.get(startX, startY, endX, endY, this.mapVersion);\n if (cached) {\n return cached;\n }\n\n const startCluster = this.getClusterAt(startX, startY);\n const endCluster = this.getClusterAt(endX, endY);\n\n if (!startCluster || !endCluster) {\n return EMPTY_PATH_RESULT;\n }\n\n let result: IPathResult;\n\n // 同一集群:直接局部搜索\n if (startCluster.id === endCluster.id) {\n result = this.findLocalPath(startX, startY, endX, endY, opts);\n } else {\n // 跨集群:HPA* 搜索\n const startTemp = this.insertTempNode(startX, startY, startCluster);\n const endTemp = this.insertTempNode(endX, endY, endCluster);\n\n const abstractPath = this.abstractSearch(startTemp, endTemp, opts);\n\n this.removeTempNode(startTemp, startCluster);\n this.removeTempNode(endTemp, endCluster);\n\n if (!abstractPath || abstractPath.length === 0) {\n return EMPTY_PATH_RESULT;\n }\n\n result = this.refinePath(abstractPath, startX, startY, endX, endY, opts);\n }\n\n // 缓存结果\n if (result.found) {\n this.pathCache.set(startX, startY, endX, endY, result, this.mapVersion);\n }\n\n return result;\n }\n\n /**\n * @zh 清理状态\n * @en Clear state\n */\n clear(): void {\n this.clusters = [];\n this.clusterGrid = [];\n this.abstractNodes.clear();\n this.nodesByCluster.clear();\n this.nextNodeId = 0;\n this.entranceCount = 0;\n this.pathCache.invalidateAll();\n this.mapVersion++;\n this.preprocessed = false;\n }\n\n /**\n * @zh 通知地图区域变化\n * @en Notify map region change\n */\n notifyRegionChange(minX: number, minY: number, maxX: number, maxY: number): void {\n // 找出受影响的集群并重建其 intra-edges\n const affectedClusters = this.getAffectedClusters(minX, minY, maxX, maxY);\n\n for (const cluster of affectedClusters) {\n // 清除该集群的缓存\n cluster.clearCache();\n\n // 移除该集群内所有节点的 intra-edges\n for (const nodeId of cluster.nodeIds) {\n const node = this.abstractNodes.get(nodeId);\n if (node) {\n node.edges = node.edges.filter(e => e.isInterEdge);\n }\n }\n\n // 重建 intra-edges\n this.buildClusterIntraEdges(cluster);\n }\n\n this.pathCache.invalidateRegion(minX, minY, maxX, maxY);\n this.mapVersion++;\n }\n\n /**\n * @zh 获取预处理统计信息\n * @en Get preprocessing statistics\n */\n getStats(): {\n clusters: number;\n entrances: number;\n abstractNodes: number;\n cacheSize: number;\n } {\n let cacheSize = 0;\n for (const cluster of this.clusters) {\n cacheSize += cluster.getCacheSize();\n }\n\n return {\n clusters: this.clusters.length,\n entrances: this.entranceCount,\n abstractNodes: this.abstractNodes.size,\n cacheSize\n };\n }\n\n // =========================================================================\n // 预处理方法 | Preprocessing Methods\n // =========================================================================\n\n private getMapBounds(): { width: number; height: number } {\n const mapAny = this.map as any;\n if (typeof mapAny.width === 'number' && typeof mapAny.height === 'number') {\n return { width: mapAny.width, height: mapAny.height };\n }\n return { width: 1000, height: 1000 };\n }\n\n /**\n * @zh 构建集群\n * @en Build clusters\n */\n private buildClusters(): void {\n const clusterSize = this.config.clusterSize;\n this.clustersX = Math.ceil(this.mapWidth / clusterSize);\n this.clustersY = Math.ceil(this.mapHeight / clusterSize);\n\n // 初始化集群网格\n this.clusterGrid = [];\n for (let cx = 0; cx < this.clustersX; cx++) {\n this.clusterGrid[cx] = [];\n for (let cy = 0; cy < this.clustersY; cy++) {\n this.clusterGrid[cx][cy] = null;\n }\n }\n\n // 创建集群\n let clusterId = 0;\n for (let cy = 0; cy < this.clustersY; cy++) {\n for (let cx = 0; cx < this.clustersX; cx++) {\n const originX = cx * clusterSize;\n const originY = cy * clusterSize;\n const width = Math.min(clusterSize, this.mapWidth - originX);\n const height = Math.min(clusterSize, this.mapHeight - originY);\n\n const cluster = new Cluster(\n clusterId,\n originX,\n originY,\n width,\n height,\n this.map\n );\n\n this.clusters.push(cluster);\n this.clusterGrid[cx][cy] = clusterId;\n this.nodesByCluster.set(clusterId, []);\n clusterId++;\n }\n }\n }\n\n /**\n * @zh 检测入口并创建抽象节点\n * @en Detect entrances and create abstract nodes\n */\n private buildEntrances(): void {\n const clusterSize = this.config.clusterSize;\n\n for (let cy = 0; cy < this.clustersY; cy++) {\n for (let cx = 0; cx < this.clustersX; cx++) {\n const clusterId = this.clusterGrid[cx][cy];\n if (clusterId === null) continue;\n\n const cluster1 = this.clusters[clusterId];\n\n // 右边相邻集群\n if (cx < this.clustersX - 1) {\n const cluster2Id = this.clusterGrid[cx + 1][cy];\n if (cluster2Id !== null) {\n const cluster2 = this.clusters[cluster2Id];\n this.detectAndCreateEntrances(cluster1, cluster2, 'vertical');\n }\n }\n\n // 下边相邻集群\n if (cy < this.clustersY - 1) {\n const cluster2Id = this.clusterGrid[cx][cy + 1];\n if (cluster2Id !== null) {\n const cluster2 = this.clusters[cluster2Id];\n this.detectAndCreateEntrances(cluster1, cluster2, 'horizontal');\n }\n }\n }\n }\n }\n\n /**\n * @zh 检测并创建两个相邻集群之间的入口\n * @en Detect and create entrances between two adjacent clusters\n */\n private detectAndCreateEntrances(\n cluster1: Cluster,\n cluster2: Cluster,\n boundaryDirection: 'horizontal' | 'vertical'\n ): void {\n const spans = this.detectEntranceSpans(cluster1, cluster2, boundaryDirection);\n\n for (const span of spans) {\n this.createEntranceNodes(cluster1, cluster2, span, boundaryDirection);\n }\n }\n\n /**\n * @zh 检测边界上的连续可通行区间\n * @en Detect continuous walkable spans on boundary\n */\n private detectEntranceSpans(\n cluster1: Cluster,\n cluster2: Cluster,\n boundaryDirection: 'horizontal' | 'vertical'\n ): EntranceSpan[] {\n const spans: EntranceSpan[] = [];\n\n if (boundaryDirection === 'vertical') {\n // cluster1 在左,cluster2 在右\n const x1 = cluster1.originX + cluster1.width - 1;\n const x2 = cluster2.originX;\n const startY = Math.max(cluster1.originY, cluster2.originY);\n const endY = Math.min(\n cluster1.originY + cluster1.height,\n cluster2.originY + cluster2.height\n );\n\n let spanStart: number | null = null;\n\n for (let y = startY; y < endY; y++) {\n const walkable1 = this.map.isWalkable(x1, y);\n const walkable2 = this.map.isWalkable(x2, y);\n\n if (walkable1 && walkable2) {\n if (spanStart === null) {\n spanStart = y;\n }\n } else {\n if (spanStart !== null) {\n spans.push({ start: spanStart, end: y - 1 });\n spanStart = null;\n }\n }\n }\n\n if (spanStart !== null) {\n spans.push({ start: spanStart, end: endY - 1 });\n }\n } else {\n // cluster1 在上,cluster2 在下\n const y1 = cluster1.originY + cluster1.height - 1;\n const y2 = cluster2.originY;\n const startX = Math.max(cluster1.originX, cluster2.originX);\n const endX = Math.min(\n cluster1.originX + cluster1.width,\n cluster2.originX + cluster2.width\n );\n\n let spanStart: number | null = null;\n\n for (let x = startX; x < endX; x++) {\n const walkable1 = this.map.isWalkable(x, y1);\n const walkable2 = this.map.isWalkable(x, y2);\n\n if (walkable1 && walkable2) {\n if (spanStart === null) {\n spanStart = x;\n }\n } else {\n if (spanStart !== null) {\n spans.push({ start: spanStart, end: x - 1 });\n spanStart = null;\n }\n }\n }\n\n if (spanStart !== null) {\n spans.push({ start: spanStart, end: endX - 1 });\n }\n }\n\n return spans;\n }\n\n /**\n * @zh 为入口区间创建抽象节点\n * @en Create abstract nodes for entrance span\n */\n private createEntranceNodes(\n cluster1: Cluster,\n cluster2: Cluster,\n span: EntranceSpan,\n boundaryDirection: 'horizontal' | 'vertical'\n ): void {\n const spanLength = span.end - span.start + 1;\n const maxWidth = this.config.maxEntranceWidth;\n const strategy = this.config.entranceStrategy;\n\n // 确定要放置节点的位置\n const positions: number[] = [];\n\n if (spanLength <= maxWidth) {\n // 窄入口:放在中间\n positions.push(Math.floor((span.start + span.end) / 2));\n } else {\n // 宽入口:均匀分布多个节点\n // Wide entrance: distribute multiple nodes evenly\n const numNodes = Math.ceil(spanLength / maxWidth);\n const spacing = spanLength / numNodes;\n\n for (let i = 0; i < numNodes; i++) {\n // 在每个子区间的中心放置节点\n const pos = Math.floor(span.start + spacing * (i + 0.5));\n positions.push(Math.min(pos, span.end));\n }\n\n // 如果使用 'end' 策略,确保两端也有节点\n if (strategy === 'end') {\n if (!positions.includes(span.start)) {\n positions.unshift(span.start);\n }\n if (!positions.includes(span.end)) {\n positions.push(span.end);\n }\n }\n }\n\n // 为每个位置创建节点对\n for (const pos of positions) {\n let p1: IPoint, p2: IPoint;\n\n if (boundaryDirection === 'vertical') {\n // cluster1 在左,cluster2 在右\n p1 = { x: cluster1.originX + cluster1.width - 1, y: pos };\n p2 = { x: cluster2.originX, y: pos };\n } else {\n // cluster1 在上,cluster2 在下\n p1 = { x: pos, y: cluster1.originY + cluster1.height - 1 };\n p2 = { x: pos, y: cluster2.originY };\n }\n\n // 创建节点对\n const node1 = this.createAbstractNode(p1, cluster1);\n const node2 = this.createAbstractNode(p2, cluster2);\n\n // 创建 inter-edge(代价为 1,相邻格子)\n const interCost = 1;\n\n node1.edges.push({\n targetNodeId: node2.id,\n cost: interCost,\n isInterEdge: true,\n innerPath: null\n });\n\n node2.edges.push({\n targetNodeId: node1.id,\n cost: interCost,\n isInterEdge: true,\n innerPath: null\n });\n\n this.entranceCount++;\n }\n }\n\n /**\n * @zh 创建抽象节点\n * @en Create abstract node\n */\n private createAbstractNode(position: IPoint, cluster: Cluster): AbstractNode {\n // 检查是否已存在相同位置的节点\n const concreteId = position.y * this.mapWidth + position.x;\n\n for (const nodeId of cluster.nodeIds) {\n const existing = this.abstractNodes.get(nodeId);\n if (existing && existing.concreteNodeId === concreteId) {\n return existing;\n }\n }\n\n // 创建新节点\n const node: AbstractNode = {\n id: this.nextNodeId++,\n position: { x: position.x, y: position.y },\n clusterId: cluster.id,\n concreteNodeId: concreteId,\n edges: []\n };\n\n this.abstractNodes.set(node.id, node);\n cluster.addNodeId(node.id);\n\n const clusterNodes = this.nodesByCluster.get(cluster.id);\n if (clusterNodes) {\n clusterNodes.push(node.id);\n }\n\n return node;\n }\n\n /**\n * @zh 构建所有集群的 intra-edges\n * @en Build intra-edges for all clusters\n */\n private buildIntraEdges(): void {\n for (const cluster of this.clusters) {\n this.buildClusterIntraEdges(cluster);\n }\n }\n\n /**\n * @zh 构建单个集群的 intra-edges\n * @en Build intra-edges for single cluster\n */\n private buildClusterIntraEdges(cluster: Cluster): void {\n const nodeIds = cluster.nodeIds;\n\n if (nodeIds.length < 2) return;\n\n if (this.config.lazyIntraEdges) {\n // 延迟计算模式:只用启发式距离创建边,真实路径在首次使用时计算\n this.buildLazyIntraEdges(cluster);\n } else {\n // 立即计算模式:预处理时计算所有真实路径\n this.buildEagerIntraEdges(cluster);\n }\n }\n\n /**\n * @zh 延迟构建 intra-edges(只用启发式距离)\n * @en Build lazy intra-edges (using heuristic distance only)\n */\n private buildLazyIntraEdges(cluster: Cluster): void {\n const nodeIds = cluster.nodeIds;\n\n for (let i = 0; i < nodeIds.length; i++) {\n for (let j = i + 1; j < nodeIds.length; j++) {\n const node1 = this.abstractNodes.get(nodeIds[i])!;\n const node2 = this.abstractNodes.get(nodeIds[j])!;\n\n // 使用启发式距离作为估计代价\n const heuristicCost = this.heuristic(node1.position, node2.position);\n\n // 创建双向 intra-edge(innerPath = null 表示未计算)\n node1.edges.push({\n targetNodeId: node2.id,\n cost: heuristicCost,\n isInterEdge: false,\n innerPath: null // 标记为未计算\n });\n\n node2.edges.push({\n targetNodeId: node1.id,\n cost: heuristicCost,\n isInterEdge: false,\n innerPath: null\n });\n }\n }\n }\n\n /**\n * @zh 立即构建 intra-edges(计算真实路径)\n * @en Build eager intra-edges (compute actual paths)\n */\n private buildEagerIntraEdges(cluster: Cluster): void {\n const nodeIds = cluster.nodeIds;\n\n // 为子地图创建 A* 寻路器\n const subPathfinder = new AStarPathfinder(cluster.subMap);\n\n // 计算所有节点对之间的真实路径\n for (let i = 0; i < nodeIds.length; i++) {\n for (let j = i + 1; j < nodeIds.length; j++) {\n const node1 = this.abstractNodes.get(nodeIds[i])!;\n const node2 = this.abstractNodes.get(nodeIds[j])!;\n\n // 转换为局部坐标\n const local1 = cluster.subMap.globalToLocal(node1.position.x, node1.position.y);\n const local2 = cluster.subMap.globalToLocal(node2.position.x, node2.position.y);\n\n // A* 计算真实路径\n const result = subPathfinder.findPath(\n local1.x, local1.y,\n local2.x, local2.y\n );\n\n if (result.found && result.path.length > 0) {\n // 转换路径为全局 ConcreteNodeId\n const globalPath: number[] = result.path.map(p => {\n const global = cluster.subMap.localToGlobal(p.x, p.y);\n return global.y * this.mapWidth + global.x;\n });\n\n // 缓存到集群\n if (this.config.cacheInternalPaths) {\n cluster.setCache(node1.id, node2.id, result.cost, globalPath);\n cluster.setCache(node2.id, node1.id, result.cost, [...globalPath].reverse());\n }\n\n // 创建双向 intra-edge\n node1.edges.push({\n targetNodeId: node2.id,\n cost: result.cost,\n isInterEdge: false,\n innerPath: this.config.cacheInternalPaths ? globalPath : null\n });\n\n node2.edges.push({\n targetNodeId: node1.id,\n cost: result.cost,\n isInterEdge: false,\n innerPath: this.config.cacheInternalPaths ? [...globalPath].reverse() : null\n });\n }\n // 如果路径不存在,不创建边(集群内不连通)\n }\n }\n }\n\n /**\n * @zh 按需计算 intra-edge 的真实路径\n * @en Compute actual path for intra-edge on demand\n */\n private computeIntraEdgePath(\n fromNode: AbstractNode,\n toNode: AbstractNode,\n edge: AbstractEdge\n ): { cost: number; path: number[] } | null {\n const cluster = this.clusters[fromNode.clusterId];\n if (!cluster) return null;\n\n // 检查集群缓存\n const cachedPath = cluster.getCachedPath(fromNode.id, toNode.id);\n const cachedCost = cluster.getCachedDistance(fromNode.id, toNode.id);\n if (cachedPath && cachedCost !== undefined) {\n // 更新边的代价和路径\n edge.cost = cachedCost;\n (edge as any).innerPath = cachedPath;\n return { cost: cachedCost, path: cachedPath };\n }\n\n // 计算真实路径\n const subPathfinder = new AStarPathfinder(cluster.subMap);\n const local1 = cluster.subMap.globalToLocal(fromNode.position.x, fromNode.position.y);\n const local2 = cluster.subMap.globalToLocal(toNode.position.x, toNode.position.y);\n\n const result = subPathfinder.findPath(local1.x, local1.y, local2.x, local2.y);\n\n if (result.found && result.path.length > 0) {\n // 转换路径为全局 ConcreteNodeId\n const globalPath: number[] = result.path.map(p => {\n const global = cluster.subMap.localToGlobal(p.x, p.y);\n return global.y * this.mapWidth + global.x;\n });\n\n // 缓存结果\n if (this.config.cacheInternalPaths) {\n cluster.setCache(fromNode.id, toNode.id, result.cost, globalPath);\n // 也缓存反向路径\n cluster.setCache(toNode.id, fromNode.id, result.cost, [...globalPath].reverse());\n }\n\n // 更新边\n edge.cost = result.cost;\n (edge as any).innerPath = globalPath;\n\n // 更新反向边\n const reverseEdge = toNode.edges.find(e => e.targetNodeId === fromNode.id);\n if (reverseEdge) {\n reverseEdge.cost = result.cost;\n (reverseEdge as any).innerPath = [...globalPath].reverse();\n }\n\n return { cost: result.cost, path: globalPath };\n }\n\n return null;\n }\n\n // =========================================================================\n // 搜索方法 | Search Methods\n // =========================================================================\n\n /**\n * @zh 获取指定位置的集群\n * @en Get cluster at position\n */\n private getClusterAt(x: number, y: number): Cluster | null {\n const cx = Math.floor(x / this.config.clusterSize);\n const cy = Math.floor(y / this.config.clusterSize);\n\n if (cx < 0 || cx >= this.clustersX || cy < 0 || cy >= this.clustersY) {\n return null;\n }\n\n const clusterId = this.clusterGrid[cx]?.[cy];\n if (clusterId === null || clusterId === undefined) {\n return null;\n }\n\n return this.clusters[clusterId] || null;\n }\n\n /**\n * @zh 获取受影响的集群\n * @en Get affected clusters\n */\n private getAffectedClusters(minX: number, minY: number, maxX: number, maxY: number): Cluster[] {\n const affected: Cluster[] = [];\n const clusterSize = this.config.clusterSize;\n\n const minCX = Math.floor(minX / clusterSize);\n const maxCX = Math.floor(maxX / clusterSize);\n const minCY = Math.floor(minY / clusterSize);\n const maxCY = Math.floor(maxY / clusterSize);\n\n for (let cy = minCY; cy <= maxCY; cy++) {\n for (let cx = minCX; cx <= maxCX; cx++) {\n if (cx >= 0 && cx < this.clustersX && cy >= 0 && cy < this.clustersY) {\n const clusterId = this.clusterGrid[cx]?.[cy];\n if (clusterId !== null && clusterId !== undefined) {\n affected.push(this.clusters[clusterId]);\n }\n }\n }\n }\n\n return affected;\n }\n\n /**\n * @zh 插入临时节点\n * @en Insert temporary node\n */\n private insertTempNode(x: number, y: number, cluster: Cluster): AbstractNode {\n const concreteId = y * this.mapWidth + x;\n\n // 检查是否已存在该位置的节点\n for (const nodeId of cluster.nodeIds) {\n const existing = this.abstractNodes.get(nodeId);\n if (existing && existing.concreteNodeId === concreteId) {\n return existing;\n }\n }\n\n // 创建临时节点\n const tempNode: AbstractNode = {\n id: this.nextNodeId++,\n position: { x, y },\n clusterId: cluster.id,\n concreteNodeId: concreteId,\n edges: []\n };\n\n this.abstractNodes.set(tempNode.id, tempNode);\n cluster.addNodeId(tempNode.id);\n\n // 计算到集群内所有其他节点的真实路径\n const subPathfinder = new AStarPathfinder(cluster.subMap);\n const localPos = cluster.subMap.globalToLocal(x, y);\n\n for (const existingNodeId of cluster.nodeIds) {\n if (existingNodeId === tempNode.id) continue;\n\n const existingNode = this.abstractNodes.get(existingNodeId);\n if (!existingNode) continue;\n\n const targetLocalPos = cluster.subMap.globalToLocal(\n existingNode.position.x,\n existingNode.position.y\n );\n\n const result = subPathfinder.findPath(\n localPos.x, localPos.y,\n targetLocalPos.x, targetLocalPos.y\n );\n\n if (result.found && result.path.length > 0) {\n // 转换路径\n const globalPath: number[] = result.path.map(p => {\n const global = cluster.subMap.localToGlobal(p.x, p.y);\n return global.y * this.mapWidth + global.x;\n });\n\n // 添加双向边\n tempNode.edges.push({\n targetNodeId: existingNode.id,\n cost: result.cost,\n isInterEdge: false,\n innerPath: globalPath\n });\n\n existingNode.edges.push({\n targetNodeId: tempNode.id,\n cost: result.cost,\n isInterEdge: false,\n innerPath: [...globalPath].reverse()\n });\n }\n }\n\n return tempNode;\n }\n\n /**\n * @zh 移除临时节点\n * @en Remove temporary node\n */\n private removeTempNode(node: AbstractNode, cluster: Cluster): void {\n // 移除其他节点指向此节点的边\n for (const existingNodeId of cluster.nodeIds) {\n if (existingNodeId === node.id) continue;\n\n const existingNode = this.abstractNodes.get(existingNodeId);\n if (existingNode) {\n existingNode.edges = existingNode.edges.filter(\n e => e.targetNodeId !== node.id\n );\n }\n }\n\n // 从集群和图中移除\n cluster.removeNodeId(node.id);\n this.abstractNodes.delete(node.id);\n }\n\n /**\n * @zh 在抽象图上进行 A* 搜索\n * @en Perform A* search on abstract graph\n */\n private abstractSearch(\n startNode: AbstractNode,\n endNode: AbstractNode,\n opts: Required<IPathfindingOptions>\n ): AbstractNode[] | null {\n const openList = new IndexedBinaryHeap<SearchNode>((a, b) => a.f - b.f);\n const nodeMap = new Map<number, SearchNode>();\n\n const endPosition = endNode.position;\n\n // 初始化起点\n const h = this.heuristic(startNode.position, endPosition) * opts.heuristicWeight;\n const startSearchNode: SearchNode = {\n node: startNode,\n g: 0,\n h,\n f: h,\n parent: null,\n closed: false,\n opened: true,\n heapIndex: -1\n };\n\n openList.push(startSearchNode);\n nodeMap.set(startNode.id, startSearchNode);\n\n let nodesSearched = 0;\n\n while (!openList.isEmpty && nodesSearched < opts.maxNodes) {\n const current = openList.pop()!;\n current.closed = true;\n nodesSearched++;\n\n // 找到目标\n if (current.node.id === endNode.id) {\n return this.reconstructPath(current);\n }\n\n // 扩展邻居\n for (const edge of current.node.edges) {\n let neighbor = nodeMap.get(edge.targetNodeId);\n\n if (!neighbor) {\n const neighborNode = this.abstractNodes.get(edge.targetNodeId);\n if (!neighborNode) continue;\n\n const nh = this.heuristic(neighborNode.position, endPosition) * opts.heuristicWeight;\n neighbor = {\n node: neighborNode,\n g: Infinity,\n h: nh,\n f: Infinity,\n parent: null,\n closed: false,\n opened: false,\n heapIndex: -1\n };\n nodeMap.set(edge.targetNodeId, neighbor);\n }\n\n if (neighbor.closed) continue;\n\n const tentativeG = current.g + edge.cost;\n\n if (!neighbor.opened) {\n neighbor.g = tentativeG;\n neighbor.f = tentativeG + neighbor.h;\n neighbor.parent = current;\n neighbor.opened = true;\n openList.push(neighbor);\n } else if (tentativeG < neighbor.g) {\n neighbor.g = tentativeG;\n neighbor.f = tentativeG + neighbor.h;\n neighbor.parent = current;\n openList.update(neighbor);\n }\n }\n }\n\n return null;\n }\n\n /**\n * @zh 重建抽象路径\n * @en Reconstruct abstract path\n */\n private reconstructPath(endNode: SearchNode): AbstractNode[] {\n const path: AbstractNode[] = [];\n let current: SearchNode | null = endNode;\n\n while (current) {\n path.unshift(current.node);\n current = current.parent;\n }\n\n return path;\n }\n\n /**\n * @zh 细化抽象路径为具体路径\n * @en Refine abstract path to concrete path\n */\n private refinePath(\n abstractPath: AbstractNode[],\n startX: number,\n startY: number,\n endX: number,\n endY: number,\n opts: Required<IPathfindingOptions>\n ): IPathResult {\n if (abstractPath.length === 0) {\n return EMPTY_PATH_RESULT;\n }\n\n const fullPath: IPoint[] = [];\n let totalCost = 0;\n let nodesSearched = abstractPath.length;\n\n // 处理抽象路径中的每一段\n for (let i = 0; i < abstractPath.length - 1; i++) {\n const fromNode = abstractPath[i];\n const toNode = abstractPath[i + 1];\n\n // 查找连接边\n const edge = fromNode.edges.find(e => e.targetNodeId === toNode.id);\n\n if (!edge) {\n // 边不存在,需要实时计算\n const segResult = this.findLocalPath(\n fromNode.position.x, fromNode.position.y,\n toNode.position.x, toNode.position.y,\n opts\n );\n\n if (segResult.found) {\n this.appendPath(fullPath, segResult.path);\n totalCost += segResult.cost;\n nodesSearched += segResult.nodesSearched;\n }\n } else if (edge.isInterEdge) {\n // Inter-edge:直接连接\n if (fullPath.length === 0 ||\n fullPath[fullPath.length - 1].x !== fromNode.position.x ||\n fullPath[fullPath.length - 1].y !== fromNode.position.y) {\n fullPath.push({ x: fromNode.position.x, y: fromNode.position.y });\n }\n fullPath.push({ x: toNode.position.x, y: toNode.position.y });\n totalCost += edge.cost;\n } else if (edge.innerPath && edge.innerPath.length > 0) {\n // Intra-edge:使用缓存路径\n const concretePath = edge.innerPath.map(id => ({\n x: id % this.mapWidth,\n y: Math.floor(id / this.mapWidth)\n }));\n this.appendPath(fullPath, concretePath);\n totalCost += edge.cost;\n } else {\n // Lazy intra-edge 或没有缓存路径:按需计算真实路径\n // Lazy intra-edge or no cached path: compute actual path on demand\n const computed = this.computeIntraEdgePath(fromNode, toNode, edge);\n\n if (computed && computed.path.length > 0) {\n // 使用计算出的路径\n const concretePath = computed.path.map(id => ({\n x: id % this.mapWidth,\n y: Math.floor(id / this.mapWidth)\n }));\n this.appendPath(fullPath, concretePath);\n totalCost += computed.cost;\n } else {\n // 路径计算失败,回退到实时搜索\n // Path computation failed, fall back to real-time search\n const segResult = this.findLocalPath(\n fromNode.position.x, fromNode.position.y,\n toNode.position.x, toNode.position.y,\n opts\n );\n\n if (segResult.found) {\n this.appendPath(fullPath, segResult.path);\n totalCost += segResult.cost;\n nodesSearched += segResult.nodesSearched;\n }\n }\n }\n }\n\n // 确保起点正确\n if (fullPath.length > 0 && (fullPath[0].x !== startX || fullPath[0].y !== startY)) {\n // 连接起点到路径开头\n const firstPoint = fullPath[0];\n if (Math.abs(firstPoint.x - startX) <= 1 && Math.abs(firstPoint.y - startY) <= 1) {\n fullPath.unshift({ x: startX, y: startY });\n } else {\n const segResult = this.findLocalPath(startX, startY, firstPoint.x, firstPoint.y, opts);\n if (segResult.found) {\n fullPath.splice(0, 0, ...segResult.path.slice(0, -1));\n totalCost += segResult.cost;\n }\n }\n }\n\n // 确保终点正确\n if (fullPath.length > 0) {\n const lastPoint = fullPath[fullPath.length - 1];\n if (lastPoint.x !== endX || lastPoint.y !== endY) {\n if (Math.abs(lastPoint.x - endX) <= 1 && Math.abs(lastPoint.y - endY) <= 1) {\n fullPath.push({ x: endX, y: endY });\n } else {\n const segResult = this.findLocalPath(lastPoint.x, lastPoint.y, endX, endY, opts);\n if (segResult.found) {\n fullPath.push(...segResult.path.slice(1));\n totalCost += segResult.cost;\n }\n }\n }\n }\n\n return {\n found: fullPath.length > 0,\n path: fullPath,\n cost: totalCost,\n nodesSearched\n };\n }\n\n /**\n * @zh 追加路径(避免重复点)\n * @en Append path (avoid duplicate points)\n */\n private appendPath(fullPath: IPoint[], segment: readonly IPoint[]): void {\n if (segment.length === 0) return;\n\n let startIdx = 0;\n\n // 避免重复第一个点\n if (fullPath.length > 0) {\n const last = fullPath[fullPath.length - 1];\n if (last.x === segment[0].x && last.y === segment[0].y) {\n startIdx = 1;\n }\n }\n\n for (let i = startIdx; i < segment.length; i++) {\n fullPath.push({ x: segment[i].x, y: segment[i].y });\n }\n }\n\n /**\n * @zh 局部寻路\n * @en Local pathfinding\n */\n private findLocalPath(\n startX: number,\n startY: number,\n endX: number,\n endY: number,\n opts: Required<IPathfindingOptions>\n ): IPathResult {\n return this.localPathfinder.findPath(startX, startY, endX, endY, opts);\n }\n\n /**\n * @zh 启发式函数(Octile 距离)\n * @en Heuristic function (Octile distance)\n */\n private heuristic(a: IPoint, b: IPoint): number {\n const dx = Math.abs(a.x - b.x);\n const dy = Math.abs(a.y - b.y);\n return dx + dy + (Math.SQRT2 - 2) * Math.min(dx, dy);\n }\n}\n\n// =============================================================================\n// 工厂函数 | Factory Function\n// =============================================================================\n\n/**\n * @zh 创建 HPA* 寻路器\n * @en Create HPA* pathfinder\n *\n * @param map - @zh 寻路地图实例 @en Pathfinding map instance\n * @param config - @zh HPA* 配置 @en HPA* configuration\n * @returns @zh HPA* 寻路器实例 @en HPA* pathfinder instance\n */\nexport function createHPAPathfinder(\n map: IPathfindingMap,\n config?: Partial<IHPAConfig>\n): HPAPathfinder {\n return new HPAPathfinder(map, config);\n}\n","/**\n * @zh 导航网格实现\n * @en NavMesh Implementation\n */\n\nimport type {\n IPathfindingMap,\n IPathNode,\n IPoint,\n IPathResult,\n IPathfindingOptions\n} from '../core/IPathfinding';\nimport { createPoint, euclideanDistance, EMPTY_PATH_RESULT, DEFAULT_PATHFINDING_OPTIONS } from '../core/IPathfinding';\nimport { BinaryHeap } from '../core/BinaryHeap';\n\n// =============================================================================\n// 导航多边形 | Navigation Polygon\n// =============================================================================\n\n/**\n * @zh 导航多边形\n * @en Navigation polygon\n */\nexport interface INavPolygon {\n /** @zh 多边形ID @en Polygon ID */\n readonly id: number;\n /** @zh 顶点列表 @en Vertex list */\n readonly vertices: readonly IPoint[];\n /** @zh 中心点 @en Center point */\n readonly center: IPoint;\n /** @zh 邻居多边形ID @en Neighbor polygon IDs */\n readonly neighbors: readonly number[];\n /** @zh 到邻居的共享边 @en Shared edges to neighbors */\n readonly portals: ReadonlyMap<number, IPortal>;\n}\n\n/**\n * @zh 入口(两个多边形之间的共享边)\n * @en Portal (shared edge between two polygons)\n */\nexport interface IPortal {\n /** @zh 边的左端点 @en Left endpoint of edge */\n readonly left: IPoint;\n /** @zh 边的右端点 @en Right endpoint of edge */\n readonly right: IPoint;\n}\n\n// =============================================================================\n// 导航网格节点 | NavMesh Node\n// =============================================================================\n\n/**\n * @zh 导航网格节点(包装多边形)\n * @en NavMesh node (wraps polygon)\n */\nclass NavMeshNode implements IPathNode {\n readonly id: number;\n readonly position: IPoint;\n readonly cost: number;\n readonly walkable: boolean;\n readonly polygon: INavPolygon;\n\n constructor(polygon: INavPolygon) {\n this.id = polygon.id;\n this.position = polygon.center;\n this.cost = 1;\n this.walkable = true;\n this.polygon = polygon;\n }\n}\n\n// =============================================================================\n// 导航网格 | Navigation Mesh\n// =============================================================================\n\n/**\n * @zh 导航网格\n * @en Navigation Mesh\n *\n * @zh 使用凸多边形网格进行高效寻路,适合复杂地形\n * @en Uses convex polygon mesh for efficient pathfinding, suitable for complex terrain\n *\n * @example\n * ```typescript\n * const navmesh = new NavMesh();\n *\n * // Add polygons\n * navmesh.addPolygon([\n * { x: 0, y: 0 }, { x: 10, y: 0 },\n * { x: 10, y: 10 }, { x: 0, y: 10 }\n * ]);\n *\n * // Build connections\n * navmesh.build();\n *\n * // Find path\n * const result = navmesh.findPath(1, 1, 8, 8);\n * ```\n */\nexport class NavMesh implements IPathfindingMap {\n private polygons: Map<number, INavPolygon> = new Map();\n private nodes: Map<number, NavMeshNode> = new Map();\n private nextId = 0;\n\n /**\n * @zh 添加导航多边形\n * @en Add navigation polygon\n *\n * @returns @zh 多边形ID @en Polygon ID\n */\n addPolygon(vertices: IPoint[], neighbors: number[] = []): number {\n const id = this.nextId++;\n const center = this.calculateCenter(vertices);\n\n const polygon: INavPolygon = {\n id,\n vertices,\n center,\n neighbors,\n portals: new Map()\n };\n\n this.polygons.set(id, polygon);\n this.nodes.set(id, new NavMeshNode(polygon));\n\n return id;\n }\n\n /**\n * @zh 设置两个多边形之间的连接\n * @en Set connection between two polygons\n */\n setConnection(\n polyA: number,\n polyB: number,\n portal: IPortal\n ): void {\n const polygonA = this.polygons.get(polyA);\n const polygonB = this.polygons.get(polyB);\n\n if (!polygonA || !polygonB) {\n return;\n }\n\n // Update neighbors and portals\n const neighborsA = [...polygonA.neighbors];\n const portalsA = new Map(polygonA.portals);\n\n if (!neighborsA.includes(polyB)) {\n neighborsA.push(polyB);\n }\n portalsA.set(polyB, portal);\n\n this.polygons.set(polyA, {\n ...polygonA,\n neighbors: neighborsA,\n portals: portalsA\n });\n\n // Reverse portal for the other direction\n const reversePortal: IPortal = {\n left: portal.right,\n right: portal.left\n };\n\n const neighborsB = [...polygonB.neighbors];\n const portalsB = new Map(polygonB.portals);\n\n if (!neighborsB.includes(polyA)) {\n neighborsB.push(polyA);\n }\n portalsB.set(polyA, reversePortal);\n\n this.polygons.set(polyB, {\n ...polygonB,\n neighbors: neighborsB,\n portals: portalsB\n });\n }\n\n /**\n * @zh 自动检测并建立相邻多边形的连接\n * @en Auto-detect and build connections between adjacent polygons\n */\n build(): void {\n const polygonList = Array.from(this.polygons.values());\n\n for (let i = 0; i < polygonList.length; i++) {\n for (let j = i + 1; j < polygonList.length; j++) {\n const polyA = polygonList[i];\n const polyB = polygonList[j];\n\n const sharedEdge = this.findSharedEdge(polyA.vertices, polyB.vertices);\n\n if (sharedEdge) {\n this.setConnection(polyA.id, polyB.id, sharedEdge);\n }\n }\n }\n }\n\n /**\n * @zh 查找两个多边形的共享边\n * @en Find shared edge between two polygons\n */\n private findSharedEdge(\n verticesA: readonly IPoint[],\n verticesB: readonly IPoint[]\n ): IPortal | null {\n const epsilon = 0.0001;\n\n for (let i = 0; i < verticesA.length; i++) {\n const a1 = verticesA[i];\n const a2 = verticesA[(i + 1) % verticesA.length];\n\n for (let j = 0; j < verticesB.length; j++) {\n const b1 = verticesB[j];\n const b2 = verticesB[(j + 1) % verticesB.length];\n\n // Check if edges match (in either direction)\n const match1 =\n Math.abs(a1.x - b2.x) < epsilon &&\n Math.abs(a1.y - b2.y) < epsilon &&\n Math.abs(a2.x - b1.x) < epsilon &&\n Math.abs(a2.y - b1.y) < epsilon;\n\n const match2 =\n Math.abs(a1.x - b1.x) < epsilon &&\n Math.abs(a1.y - b1.y) < epsilon &&\n Math.abs(a2.x - b2.x) < epsilon &&\n Math.abs(a2.y - b2.y) < epsilon;\n\n if (match1 || match2) {\n return {\n left: a1,\n right: a2\n };\n }\n }\n }\n\n return null;\n }\n\n /**\n * @zh 计算多边形中心\n * @en Calculate polygon center\n */\n private calculateCenter(vertices: readonly IPoint[]): IPoint {\n let x = 0;\n let y = 0;\n\n for (const v of vertices) {\n x += v.x;\n y += v.y;\n }\n\n return createPoint(x / vertices.length, y / vertices.length);\n }\n\n /**\n * @zh 查找包含点的多边形\n * @en Find polygon containing point\n */\n findPolygonAt(x: number, y: number): INavPolygon | null {\n for (const polygon of this.polygons.values()) {\n if (this.isPointInPolygon(x, y, polygon.vertices)) {\n return polygon;\n }\n }\n return null;\n }\n\n /**\n * @zh 检查点是否在多边形内\n * @en Check if point is inside polygon\n */\n private isPointInPolygon(x: number, y: number, vertices: readonly IPoint[]): boolean {\n let inside = false;\n const n = vertices.length;\n\n for (let i = 0, j = n - 1; i < n; j = i++) {\n const xi = vertices[i].x;\n const yi = vertices[i].y;\n const xj = vertices[j].x;\n const yj = vertices[j].y;\n\n if (\n yi > y !== yj > y &&\n x < ((xj - xi) * (y - yi)) / (yj - yi) + xi\n ) {\n inside = !inside;\n }\n }\n\n return inside;\n }\n\n // ==========================================================================\n // IPathfindingMap 接口实现 | IPathfindingMap Interface Implementation\n // ==========================================================================\n\n getNodeAt(x: number, y: number): IPathNode | null {\n const polygon = this.findPolygonAt(x, y);\n return polygon ? this.nodes.get(polygon.id) ?? null : null;\n }\n\n getNeighbors(node: IPathNode): IPathNode[] {\n const navNode = node as NavMeshNode;\n const neighbors: IPathNode[] = [];\n\n for (const neighborId of navNode.polygon.neighbors) {\n const neighbor = this.nodes.get(neighborId);\n if (neighbor) {\n neighbors.push(neighbor);\n }\n }\n\n return neighbors;\n }\n\n heuristic(a: IPoint, b: IPoint): number {\n return euclideanDistance(a, b);\n }\n\n getMovementCost(from: IPathNode, to: IPathNode): number {\n return euclideanDistance(from.position, to.position);\n }\n\n isWalkable(x: number, y: number): boolean {\n return this.findPolygonAt(x, y) !== null;\n }\n\n // ==========================================================================\n // 寻路 | Pathfinding\n // ==========================================================================\n\n /**\n * @zh 在导航网格上寻路\n * @en Find path on navigation mesh\n */\n findPath(\n startX: number,\n startY: number,\n endX: number,\n endY: number,\n options?: IPathfindingOptions\n ): IPathResult {\n const opts = { ...DEFAULT_PATHFINDING_OPTIONS, ...options };\n\n const startPolygon = this.findPolygonAt(startX, startY);\n const endPolygon = this.findPolygonAt(endX, endY);\n\n if (!startPolygon || !endPolygon) {\n return EMPTY_PATH_RESULT;\n }\n\n // Same polygon\n if (startPolygon.id === endPolygon.id) {\n return {\n found: true,\n path: [createPoint(startX, startY), createPoint(endX, endY)],\n cost: euclideanDistance(\n createPoint(startX, startY),\n createPoint(endX, endY)\n ),\n nodesSearched: 1\n };\n }\n\n // A* on polygon graph\n const polygonPath = this.findPolygonPath(startPolygon, endPolygon, opts);\n\n if (!polygonPath.found) {\n return EMPTY_PATH_RESULT;\n }\n\n // Convert polygon path to point path using funnel algorithm\n const start = createPoint(startX, startY);\n const end = createPoint(endX, endY);\n const pointPath = this.funnelPath(start, end, polygonPath.polygons);\n\n return {\n found: true,\n path: pointPath,\n cost: this.calculatePathLength(pointPath),\n nodesSearched: polygonPath.nodesSearched\n };\n }\n\n /**\n * @zh 在多边形图上寻路\n * @en Find path on polygon graph\n */\n private findPolygonPath(\n start: INavPolygon,\n end: INavPolygon,\n opts: Required<IPathfindingOptions>\n ): { found: boolean; polygons: INavPolygon[]; nodesSearched: number } {\n interface AStarState {\n polygon: INavPolygon;\n g: number;\n f: number;\n parent: AStarState | null;\n }\n\n const openList = new BinaryHeap<AStarState>((a, b) => a.f - b.f);\n const closed = new Set<number>();\n const states = new Map<number, AStarState>();\n\n const startState: AStarState = {\n polygon: start,\n g: 0,\n f: euclideanDistance(start.center, end.center) * opts.heuristicWeight,\n parent: null\n };\n\n states.set(start.id, startState);\n openList.push(startState);\n\n let nodesSearched = 0;\n\n while (!openList.isEmpty && nodesSearched < opts.maxNodes) {\n const current = openList.pop()!;\n nodesSearched++;\n\n if (current.polygon.id === end.id) {\n // Reconstruct path\n const path: INavPolygon[] = [];\n let state: AStarState | null = current;\n\n while (state) {\n path.unshift(state.polygon);\n state = state.parent;\n }\n\n return { found: true, polygons: path, nodesSearched };\n }\n\n closed.add(current.polygon.id);\n\n for (const neighborId of current.polygon.neighbors) {\n if (closed.has(neighborId)) {\n continue;\n }\n\n const neighborPolygon = this.polygons.get(neighborId);\n if (!neighborPolygon) {\n continue;\n }\n\n const g = current.g + euclideanDistance(\n current.polygon.center,\n neighborPolygon.center\n );\n\n let neighborState = states.get(neighborId);\n\n if (!neighborState) {\n neighborState = {\n polygon: neighborPolygon,\n g,\n f: g + euclideanDistance(neighborPolygon.center, end.center) * opts.heuristicWeight,\n parent: current\n };\n states.set(neighborId, neighborState);\n openList.push(neighborState);\n } else if (g < neighborState.g) {\n neighborState.g = g;\n neighborState.f = g + euclideanDistance(neighborPolygon.center, end.center) * opts.heuristicWeight;\n neighborState.parent = current;\n openList.update(neighborState);\n }\n }\n }\n\n return { found: false, polygons: [], nodesSearched };\n }\n\n /**\n * @zh 使用漏斗算法优化路径\n * @en Optimize path using funnel algorithm\n */\n private funnelPath(\n start: IPoint,\n end: IPoint,\n polygons: INavPolygon[]\n ): IPoint[] {\n if (polygons.length <= 1) {\n return [start, end];\n }\n\n // Collect portals\n const portals: IPortal[] = [];\n\n for (let i = 0; i < polygons.length - 1; i++) {\n const portal = polygons[i].portals.get(polygons[i + 1].id);\n if (portal) {\n portals.push(portal);\n }\n }\n\n if (portals.length === 0) {\n return [start, end];\n }\n\n // Simple string pulling algorithm\n const path: IPoint[] = [start];\n\n let apex = start;\n let leftIndex = 0;\n let rightIndex = 0;\n let left = portals[0].left;\n let right = portals[0].right;\n\n for (let i = 1; i <= portals.length; i++) {\n const nextLeft = i < portals.length ? portals[i].left : end;\n const nextRight = i < portals.length ? portals[i].right : end;\n\n // Update right\n if (this.triArea2(apex, right, nextRight) <= 0) {\n if (apex === right || this.triArea2(apex, left, nextRight) > 0) {\n right = nextRight;\n rightIndex = i;\n } else {\n path.push(left);\n apex = left;\n leftIndex = rightIndex = leftIndex;\n left = right = apex;\n i = leftIndex;\n continue;\n }\n }\n\n // Update left\n if (this.triArea2(apex, left, nextLeft) >= 0) {\n if (apex === left || this.triArea2(apex, right, nextLeft) < 0) {\n left = nextLeft;\n leftIndex = i;\n } else {\n path.push(right);\n apex = right;\n leftIndex = rightIndex = rightIndex;\n left = right = apex;\n i = rightIndex;\n continue;\n }\n }\n }\n\n path.push(end);\n\n return path;\n }\n\n /**\n * @zh 计算三角形面积的两倍(用于判断点的相对位置)\n * @en Calculate twice the triangle area (for point relative position)\n */\n private triArea2(a: IPoint, b: IPoint, c: IPoint): number {\n return (c.x - a.x) * (b.y - a.y) - (b.x - a.x) * (c.y - a.y);\n }\n\n /**\n * @zh 计算路径总长度\n * @en Calculate total path length\n */\n private calculatePathLength(path: readonly IPoint[]): number {\n let length = 0;\n\n for (let i = 1; i < path.length; i++) {\n length += euclideanDistance(path[i - 1], path[i]);\n }\n\n return length;\n }\n\n /**\n * @zh 清空导航网格\n * @en Clear navigation mesh\n */\n clear(): void {\n this.polygons.clear();\n this.nodes.clear();\n this.nextId = 0;\n }\n\n /**\n * @zh 获取所有多边形\n * @en Get all polygons\n */\n getPolygons(): INavPolygon[] {\n return Array.from(this.polygons.values());\n }\n\n /**\n * @zh 获取多边形数量\n * @en Get polygon count\n */\n get polygonCount(): number {\n return this.polygons.size;\n }\n}\n\n// =============================================================================\n// 工厂函数 | Factory Function\n// =============================================================================\n\n/**\n * @zh 创建导航网格\n * @en Create navigation mesh\n */\nexport function createNavMesh(): NavMesh {\n return new NavMesh();\n}\n"],"mappings":"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","names":["BinaryHeap","compare","heap","size","length","isEmpty","push","item","bubbleUp","pop","undefined","result","last","sinkDown","peek","update","index","indexOf","contains","clear","parentIndex","Math","floor","parent","leftIndex","rightIndex","smallest","AStarPathfinder","map","nodeCache","Map","openList","IndexedBinaryHeap","a","b","f","findPath","startX","startY","endX","endY","options","opts","DEFAULT_PATHFINDING_OPTIONS","clear","startNode","getNodeAt","endNode","EMPTY_PATH_RESULT","walkable","id","found","path","position","cost","nodesSearched","start","getOrCreateAStarNode","g","h","heuristic","heuristicWeight","opened","push","endPosition","isEmpty","maxNodes","current","pop","closed","node","buildPath","neighbors","getNeighbors","neighborNode","neighbor","movementCost","getMovementCost","tentativeG","parent","update","astarNode","get","Infinity","heapIndex","set","reverse","createAStarPathfinder","CLOSED_FLAG","OPENED_FLAG","BACKWARD_CLOSED","BACKWARD_OPENED","GridState","width","height","bidirectional","size","g","f","flags","parent","heapIndex","version","currentVersion","gBack","fBack","parentBack","heapIndexBack","Float32Array","Uint8Array","Int32Array","Uint32Array","reset","fill","isInit","i","init","Infinity","getG","setG","v","getF","setF","getParent","setParent","getHeapIndex","setHeapIndex","isClosed","setClosed","isOpened","setOpened","getGBack","setGBack","getFBack","setFBack","getParentBack","setParentBack","getHeapIndexBack","setHeapIndexBack","isClosedBack","setClosedBack","isOpenedBack","setOpenedBack","_a","GridHeap","state","isBack","heap","length","isEmpty","push","bubbleUp","pop","result","last","sinkDown","update","pos","clear","idx","pp","pi","len","half","left","right","smallest","smallestF","lf","rf","si","GridPathfinder","map","config","mode","openList","openListBack","isBidir","findPath","startX","startY","endX","endY","options","findPathBidirectional","findPathUnidirectional","opts","DEFAULT_PATHFINDING_OPTIONS","validate","EMPTY_PATH_RESULT","startIdx","endIdx","found","path","x","y","cost","nodesSearched","hw","heuristicWeight","h0","heuristic","searched","maxNodes","allowDiagonal","avoidCorners","diagonalCost","nodes","dx","dy","dirCount","cur","buildPath","cx","cy","curG","d","nx","ny","neighbor","walkable","ni","isDiag","tentG","h","startPos","endPos","hf","hb","meetIdx","bestCost","total","buildPathBidirectional","isWalkable","w","reverse","createGridPathfinder","JPSPathfinder","map","width","height","openList","nodeGrid","bounds","getMapBounds","BinaryHeap","a","b","f","findPath","startX","startY","endX","endY","options","opts","DEFAULT_PATHFINDING_OPTIONS","isWalkable","EMPTY_PATH_RESULT","found","path","x","y","cost","nodesSearched","initGrid","clear","startNode","getOrCreateNode","g","h","heuristic","heuristicWeight","push","isEmpty","maxNodes","current","pop","closed","buildPath","identifySuccessors","mapAny","i","xi","yi","Error","Infinity","parent","x1","y1","x2","y2","dx","Math","abs","dy","SQRT2","min","node","neighbors","findNeighbors","neighbor","jumpPoint","jump","jx","jy","jpNode","distance","sqrt","tentativeG","contains","update","nx","ny","isWalkableAt","sign","px","py","jumpStraight","endNode","unshift","interpolatePath","jumpPoints","length","prev","curr","steps","max","stepX","stepY","j","createJPSPathfinder","DEFAULT_HPA_CONFIG","clusterSize","maxEntranceWidth","cacheInternalPaths","entranceStrategy","lazyIntraEdges","_a","SubMap","parentMap","originX","originY","width","height","localToGlobal","localX","localY","x","y","globalToLocal","globalX","globalY","isWalkable","getNodeAt","globalNode","id","position","cost","walkable","getNeighbors","node","neighbors","directions","dx","dy","dir","nx","ny","neighborNode","push","heuristic","a","b","Math","abs","SQRT2","min","getMovementCost","from","to","baseCost","Cluster","subMap","nodeIds","distanceCache","Map","pathCache","containsPoint","addNodeId","nodeId","includes","removeNodeId","idx","indexOf","splice","getCacheKey","fromId","toId","setCache","path","key","set","getCachedDistance","get","getCachedPath","clearCache","clear","getCacheSize","size","HPAPathfinder","map","config","mapWidth","mapHeight","clusters","clusterGrid","clustersX","clustersY","abstractNodes","nodesByCluster","nextNodeId","entranceCount","localPathfinder","mapVersion","preprocessed","bounds","getMapBounds","AStarPathfinder","PathCache","maxEntries","ttlMs","preprocess","buildClusters","buildEntrances","buildIntraEdges","findPath","startX","startY","endX","endY","options","opts","DEFAULT_PATHFINDING_OPTIONS","EMPTY_PATH_RESULT","found","nodesSearched","cached","startCluster","getClusterAt","endCluster","result","findLocalPath","startTemp","insertTempNode","endTemp","abstractPath","abstractSearch","removeTempNode","length","refinePath","invalidateAll","notifyRegionChange","minX","minY","maxX","maxY","affectedClusters","getAffectedClusters","cluster","edges","filter","e","isInterEdge","buildClusterIntraEdges","invalidateRegion","getStats","cacheSize","entrances","mapAny","ceil","cx","cy","clusterId","cluster1","cluster2Id","cluster2","detectAndCreateEntrances","boundaryDirection","spans","detectEntranceSpans","span","createEntranceNodes","x1","x2","max","spanStart","walkable1","walkable2","start","end","y1","y2","spanLength","maxWidth","strategy","positions","floor","numNodes","spacing","i","pos","unshift","p1","p2","node1","createAbstractNode","node2","interCost","targetNodeId","innerPath","concreteId","existing","concreteNodeId","clusterNodes","buildLazyIntraEdges","buildEagerIntraEdges","j","heuristicCost","subPathfinder","local1","local2","globalPath","p","global","reverse","computeIntraEdgePath","fromNode","toNode","edge","cachedPath","cachedCost","undefined","reverseEdge","find","affected","minCX","maxCX","minCY","maxCY","tempNode","localPos","existingNodeId","existingNode","targetLocalPos","delete","startNode","endNode","openList","IndexedBinaryHeap","f","nodeMap","endPosition","h","heuristicWeight","startSearchNode","g","parent","closed","opened","heapIndex","isEmpty","maxNodes","current","pop","reconstructPath","neighbor","nh","Infinity","tentativeG","update","fullPath","totalCost","segResult","appendPath","concretePath","computed","firstPoint","slice","lastPoint","segment","startIdx","last","createHPAPathfinder","_a","NavMeshNode","polygon","id","position","cost","walkable","center","NavMesh","polygons","Map","nodes","nextId","addPolygon","vertices","neighbors","calculateCenter","portals","set","setConnection","polyA","polyB","portal","polygonA","get","polygonB","neighborsA","portalsA","includes","push","reversePortal","left","right","neighborsB","portalsB","build","polygonList","Array","from","values","i","length","j","sharedEdge","findSharedEdge","verticesA","verticesB","epsilon","a1","a2","b1","b2","match1","Math","abs","x","y","match2","v","createPoint","findPolygonAt","isPointInPolygon","inside","n","xi","yi","xj","yj","getNodeAt","getNeighbors","node","navNode","neighborId","neighbor","heuristic","a","b","euclideanDistance","getMovementCost","to","isWalkable","findPath","startX","startY","endX","endY","options","opts","DEFAULT_PATHFINDING_OPTIONS","startPolygon","endPolygon","EMPTY_PATH_RESULT","found","path","nodesSearched","polygonPath","findPolygonPath","start","end","pointPath","funnelPath","calculatePathLength","openList","BinaryHeap","f","closed","Set","states","startState","g","heuristicWeight","parent","isEmpty","maxNodes","current","pop","state","unshift","add","has","neighborPolygon","neighborState","update","apex","leftIndex","rightIndex","nextLeft","nextRight","triArea2","c","clear","getPolygons","polygonCount","size","createNavMesh"]}
1
+ {"version":3,"sources":["../src/core/GridPathfinder.ts","../src/core/PathValidator.ts","../src/grid/GridMap.ts","../src/navmesh/NavMesh.ts","../src/smoothing/PathSmoother.ts","../src/smoothing/RadiusAwarePathSmoother.ts"],"sourcesContent":["/**\n * @zh 网格寻路器(统一实现)\n * @en Grid Pathfinder (unified implementation)\n */\n\nimport type { IPathfinder, IPathResult, IPathfindingOptions, IPoint } from './IPathfinding';\nimport { EMPTY_PATH_RESULT, DEFAULT_PATHFINDING_OPTIONS } from './IPathfinding';\nimport { GridMap } from '../grid/GridMap';\n\n// =============================================================================\n// 配置 | Configuration\n// =============================================================================\n\n/**\n * @zh 寻路模式\n * @en Pathfinding mode\n */\nexport type GridPathfinderMode = 'standard' | 'fast' | 'bidirectional';\n\n/**\n * @zh 网格寻路器配置\n * @en Grid pathfinder configuration\n */\nexport interface IGridPathfinderConfig {\n /**\n * @zh 寻路模式\n * @en Pathfinding mode\n *\n * - standard: 标准A*,适合小地图\n * - fast: TypedArray优化,适合中大地图\n * - bidirectional: 双向搜索,适合超大地图\n */\n mode?: GridPathfinderMode;\n}\n\n// =============================================================================\n// 常量 | Constants\n// =============================================================================\n\nconst CLOSED_FLAG = 1;\nconst OPENED_FLAG = 2;\nconst BACKWARD_CLOSED = 4;\nconst BACKWARD_OPENED = 8;\n\n// =============================================================================\n// 状态存储 | State Storage\n// =============================================================================\n\nclass GridState {\n private readonly size: number;\n readonly width: number;\n\n private g: Float32Array;\n private f: Float32Array;\n private flags: Uint8Array;\n private parent: Int32Array;\n private heapIndex: Int32Array;\n private version: Uint32Array;\n private currentVersion: number = 1;\n\n // 双向搜索额外状态\n private gBack: Float32Array | null = null;\n private fBack: Float32Array | null = null;\n private parentBack: Int32Array | null = null;\n private heapIndexBack: Int32Array | null = null;\n\n constructor(width: number, height: number, bidirectional: boolean = false) {\n this.width = width;\n this.size = width * height;\n\n this.g = new Float32Array(this.size);\n this.f = new Float32Array(this.size);\n this.flags = new Uint8Array(this.size);\n this.parent = new Int32Array(this.size);\n this.heapIndex = new Int32Array(this.size);\n this.version = new Uint32Array(this.size);\n\n if (bidirectional) {\n this.gBack = new Float32Array(this.size);\n this.fBack = new Float32Array(this.size);\n this.parentBack = new Int32Array(this.size);\n this.heapIndexBack = new Int32Array(this.size);\n }\n }\n\n reset(): void {\n this.currentVersion++;\n if (this.currentVersion > 0xFFFFFFFF) {\n this.version.fill(0);\n this.currentVersion = 1;\n }\n }\n\n private isInit(i: number): boolean {\n return this.version[i] === this.currentVersion;\n }\n\n private init(i: number): void {\n if (!this.isInit(i)) {\n this.g[i] = Infinity;\n this.f[i] = Infinity;\n this.flags[i] = 0;\n this.parent[i] = -1;\n this.heapIndex[i] = -1;\n if (this.gBack) {\n this.gBack[i] = Infinity;\n this.fBack![i] = Infinity;\n this.parentBack![i] = -1;\n this.heapIndexBack![i] = -1;\n }\n this.version[i] = this.currentVersion;\n }\n }\n\n // Forward\n getG(i: number): number { return this.isInit(i) ? this.g[i] : Infinity; }\n setG(i: number, v: number): void { this.init(i); this.g[i] = v; }\n getF(i: number): number { return this.isInit(i) ? this.f[i] : Infinity; }\n setF(i: number, v: number): void { this.init(i); this.f[i] = v; }\n getParent(i: number): number { return this.isInit(i) ? this.parent[i] : -1; }\n setParent(i: number, v: number): void { this.init(i); this.parent[i] = v; }\n getHeapIndex(i: number): number { return this.isInit(i) ? this.heapIndex[i] : -1; }\n setHeapIndex(i: number, v: number): void { this.init(i); this.heapIndex[i] = v; }\n isClosed(i: number): boolean { return this.isInit(i) && (this.flags[i] & CLOSED_FLAG) !== 0; }\n setClosed(i: number): void { this.init(i); this.flags[i] |= CLOSED_FLAG; }\n isOpened(i: number): boolean { return this.isInit(i) && (this.flags[i] & OPENED_FLAG) !== 0; }\n setOpened(i: number): void { this.init(i); this.flags[i] |= OPENED_FLAG; }\n\n // Backward\n getGBack(i: number): number { return this.isInit(i) ? this.gBack![i] : Infinity; }\n setGBack(i: number, v: number): void { this.init(i); this.gBack![i] = v; }\n getFBack(i: number): number { return this.isInit(i) ? this.fBack![i] : Infinity; }\n setFBack(i: number, v: number): void { this.init(i); this.fBack![i] = v; }\n getParentBack(i: number): number { return this.isInit(i) ? this.parentBack![i] : -1; }\n setParentBack(i: number, v: number): void { this.init(i); this.parentBack![i] = v; }\n getHeapIndexBack(i: number): number { return this.isInit(i) ? this.heapIndexBack![i] : -1; }\n setHeapIndexBack(i: number, v: number): void { this.init(i); this.heapIndexBack![i] = v; }\n isClosedBack(i: number): boolean { return this.isInit(i) && (this.flags[i] & BACKWARD_CLOSED) !== 0; }\n setClosedBack(i: number): void { this.init(i); this.flags[i] |= BACKWARD_CLOSED; }\n isOpenedBack(i: number): boolean { return this.isInit(i) && (this.flags[i] & BACKWARD_OPENED) !== 0; }\n setOpenedBack(i: number): void { this.init(i); this.flags[i] |= BACKWARD_OPENED; }\n}\n\n// =============================================================================\n// 堆 | Heap\n// =============================================================================\n\nclass GridHeap {\n private heap: number[] = [];\n private state: GridState;\n private isBack: boolean;\n\n constructor(state: GridState, isBack: boolean = false) {\n this.state = state;\n this.isBack = isBack;\n }\n\n get size(): number { return this.heap.length; }\n get isEmpty(): boolean { return this.heap.length === 0; }\n\n private getF(i: number): number {\n return this.isBack ? this.state.getFBack(i) : this.state.getF(i);\n }\n private getHeapIndex(i: number): number {\n return this.isBack ? this.state.getHeapIndexBack(i) : this.state.getHeapIndex(i);\n }\n private setHeapIndex(i: number, v: number): void {\n if (this.isBack) this.state.setHeapIndexBack(i, v);\n else this.state.setHeapIndex(i, v);\n }\n\n push(i: number): void {\n this.setHeapIndex(i, this.heap.length);\n this.heap.push(i);\n this.bubbleUp(this.heap.length - 1);\n }\n\n pop(): number {\n if (this.heap.length === 0) return -1;\n const result = this.heap[0];\n this.setHeapIndex(result, -1);\n const last = this.heap.pop()!;\n if (this.heap.length > 0) {\n this.heap[0] = last;\n this.setHeapIndex(last, 0);\n this.sinkDown(0);\n }\n return result;\n }\n\n update(i: number): void {\n const pos = this.getHeapIndex(i);\n if (pos >= 0 && pos < this.heap.length) {\n this.bubbleUp(pos);\n this.sinkDown(this.getHeapIndex(i));\n }\n }\n\n clear(): void { this.heap.length = 0; }\n\n private bubbleUp(pos: number): void {\n const idx = this.heap[pos];\n const f = this.getF(idx);\n while (pos > 0) {\n const pp = (pos - 1) >> 1;\n const pi = this.heap[pp];\n if (f >= this.getF(pi)) break;\n this.heap[pos] = pi;\n this.setHeapIndex(pi, pos);\n pos = pp;\n }\n this.heap[pos] = idx;\n this.setHeapIndex(idx, pos);\n }\n\n private sinkDown(pos: number): void {\n const len = this.heap.length;\n const idx = this.heap[pos];\n const f = this.getF(idx);\n const half = len >> 1;\n while (pos < half) {\n const left = (pos << 1) + 1;\n const right = left + 1;\n let smallest = pos, smallestF = f;\n const lf = this.getF(this.heap[left]);\n if (lf < smallestF) { smallest = left; smallestF = lf; }\n if (right < len) {\n const rf = this.getF(this.heap[right]);\n if (rf < smallestF) smallest = right;\n }\n if (smallest === pos) break;\n const si = this.heap[smallest];\n this.heap[pos] = si;\n this.setHeapIndex(si, pos);\n pos = smallest;\n }\n this.heap[pos] = idx;\n this.setHeapIndex(idx, pos);\n }\n}\n\n// =============================================================================\n// 网格寻路器 | Grid Pathfinder\n// =============================================================================\n\n/**\n * @zh 网格寻路器\n * @en Grid Pathfinder\n */\nexport class GridPathfinder implements IPathfinder {\n private readonly map: GridMap;\n private readonly mode: GridPathfinderMode;\n private readonly state: GridState;\n private readonly openList: GridHeap;\n private readonly openListBack: GridHeap | null;\n\n constructor(map: GridMap, config?: IGridPathfinderConfig) {\n this.map = map;\n this.mode = config?.mode ?? 'fast';\n const isBidir = this.mode === 'bidirectional';\n this.state = new GridState(map.width, map.height, isBidir);\n this.openList = new GridHeap(this.state, false);\n this.openListBack = isBidir ? new GridHeap(this.state, true) : null;\n }\n\n findPath(\n startX: number,\n startY: number,\n endX: number,\n endY: number,\n options?: IPathfindingOptions\n ): IPathResult {\n if (this.mode === 'bidirectional') {\n return this.findPathBidirectional(startX, startY, endX, endY, options);\n }\n return this.findPathUnidirectional(startX, startY, endX, endY, options);\n }\n\n private findPathUnidirectional(\n startX: number, startY: number,\n endX: number, endY: number,\n options?: IPathfindingOptions\n ): IPathResult {\n const opts = options ? { ...DEFAULT_PATHFINDING_OPTIONS, ...options } : DEFAULT_PATHFINDING_OPTIONS;\n const { width, height } = this.map;\n\n this.state.reset();\n this.openList.clear();\n\n if (!this.validate(startX, startY, endX, endY)) return EMPTY_PATH_RESULT;\n\n const startIdx = startY * width + startX;\n const endIdx = endY * width + endX;\n\n if (startIdx === endIdx) {\n return { found: true, path: [{ x: startX, y: startY }], cost: 0, nodesSearched: 1 };\n }\n\n const hw = opts.heuristicWeight;\n const h0 = this.map.heuristic({ x: startX, y: startY }, { x: endX, y: endY }) * hw;\n this.state.setG(startIdx, 0);\n this.state.setF(startIdx, h0);\n this.state.setOpened(startIdx);\n this.openList.push(startIdx);\n\n let searched = 0;\n const maxNodes = opts.maxNodes;\n const { allowDiagonal, avoidCorners, diagonalCost } = this.map['options'];\n const nodes = this.map['nodes'];\n const dx = allowDiagonal ? [0, 1, 1, 1, 0, -1, -1, -1] : [0, 1, 0, -1];\n const dy = allowDiagonal ? [-1, -1, 0, 1, 1, 1, 0, -1] : [-1, 0, 1, 0];\n const dirCount = dx.length;\n\n while (!this.openList.isEmpty && searched < maxNodes) {\n const cur = this.openList.pop();\n this.state.setClosed(cur);\n searched++;\n\n if (cur === endIdx) {\n return this.buildPath(startIdx, endIdx, searched);\n }\n\n const cx = cur % width, cy = (cur / width) | 0;\n const curG = this.state.getG(cur);\n\n for (let d = 0; d < dirCount; d++) {\n const nx = cx + dx[d], ny = cy + dy[d];\n if (nx < 0 || nx >= width || ny < 0 || ny >= height) continue;\n\n const neighbor = nodes[ny][nx];\n if (!neighbor.walkable) continue;\n\n if (avoidCorners && dx[d] !== 0 && dy[d] !== 0) {\n if (!nodes[cy][cx + dx[d]].walkable || !nodes[cy + dy[d]][cx].walkable) continue;\n }\n\n const ni = ny * width + nx;\n if (this.state.isClosed(ni)) continue;\n\n const isDiag = dx[d] !== 0 && dy[d] !== 0;\n const cost = isDiag ? neighbor.cost * diagonalCost : neighbor.cost;\n const tentG = curG + cost;\n\n if (!this.state.isOpened(ni)) {\n const h = this.map.heuristic({ x: nx, y: ny }, { x: endX, y: endY }) * hw;\n this.state.setG(ni, tentG);\n this.state.setF(ni, tentG + h);\n this.state.setParent(ni, cur);\n this.state.setOpened(ni);\n this.openList.push(ni);\n } else if (tentG < this.state.getG(ni)) {\n const h = this.state.getF(ni) - this.state.getG(ni);\n this.state.setG(ni, tentG);\n this.state.setF(ni, tentG + h);\n this.state.setParent(ni, cur);\n this.openList.update(ni);\n }\n }\n }\n\n return { found: false, path: [], cost: 0, nodesSearched: searched };\n }\n\n private findPathBidirectional(\n startX: number, startY: number,\n endX: number, endY: number,\n options?: IPathfindingOptions\n ): IPathResult {\n const opts = options ? { ...DEFAULT_PATHFINDING_OPTIONS, ...options } : DEFAULT_PATHFINDING_OPTIONS;\n const { width, height } = this.map;\n\n this.state.reset();\n this.openList.clear();\n this.openListBack!.clear();\n\n if (!this.validate(startX, startY, endX, endY)) return EMPTY_PATH_RESULT;\n\n const startIdx = startY * width + startX;\n const endIdx = endY * width + endX;\n\n if (startIdx === endIdx) {\n return { found: true, path: [{ x: startX, y: startY }], cost: 0, nodesSearched: 1 };\n }\n\n const hw = opts.heuristicWeight;\n const startPos = { x: startX, y: startY };\n const endPos = { x: endX, y: endY };\n\n // Init forward\n const hf = this.map.heuristic(startPos, endPos) * hw;\n this.state.setG(startIdx, 0);\n this.state.setF(startIdx, hf);\n this.state.setOpened(startIdx);\n this.openList.push(startIdx);\n\n // Init backward\n const hb = this.map.heuristic(endPos, startPos) * hw;\n this.state.setGBack(endIdx, 0);\n this.state.setFBack(endIdx, hb);\n this.state.setOpenedBack(endIdx);\n this.openListBack!.push(endIdx);\n\n let searched = 0;\n const maxNodes = opts.maxNodes;\n let meetIdx = -1, bestCost = Infinity;\n\n const { allowDiagonal, avoidCorners, diagonalCost } = this.map['options'];\n const nodes = this.map['nodes'];\n const dx = allowDiagonal ? [0, 1, 1, 1, 0, -1, -1, -1] : [0, 1, 0, -1];\n const dy = allowDiagonal ? [-1, -1, 0, 1, 1, 1, 0, -1] : [-1, 0, 1, 0];\n const dirCount = dx.length;\n\n while ((!this.openList.isEmpty || !this.openListBack!.isEmpty) && searched < maxNodes) {\n // Forward\n if (!this.openList.isEmpty) {\n const cur = this.openList.pop();\n this.state.setClosed(cur);\n searched++;\n\n const curG = this.state.getG(cur);\n if (this.state.isClosedBack(cur)) {\n const total = curG + this.state.getGBack(cur);\n if (total < bestCost) { bestCost = total; meetIdx = cur; }\n }\n if (meetIdx !== -1 && curG >= bestCost) break;\n\n const cx = cur % width, cy = (cur / width) | 0;\n for (let d = 0; d < dirCount; d++) {\n const nx = cx + dx[d], ny = cy + dy[d];\n if (nx < 0 || nx >= width || ny < 0 || ny >= height) continue;\n const neighbor = nodes[ny][nx];\n if (!neighbor.walkable) continue;\n if (avoidCorners && dx[d] !== 0 && dy[d] !== 0) {\n if (!nodes[cy][cx + dx[d]].walkable || !nodes[cy + dy[d]][cx].walkable) continue;\n }\n const ni = ny * width + nx;\n if (this.state.isClosed(ni)) continue;\n const isDiag = dx[d] !== 0 && dy[d] !== 0;\n const cost = isDiag ? neighbor.cost * diagonalCost : neighbor.cost;\n const tentG = curG + cost;\n if (!this.state.isOpened(ni)) {\n const h = this.map.heuristic({ x: nx, y: ny }, endPos) * hw;\n this.state.setG(ni, tentG);\n this.state.setF(ni, tentG + h);\n this.state.setParent(ni, cur);\n this.state.setOpened(ni);\n this.openList.push(ni);\n } else if (tentG < this.state.getG(ni)) {\n const h = this.state.getF(ni) - this.state.getG(ni);\n this.state.setG(ni, tentG);\n this.state.setF(ni, tentG + h);\n this.state.setParent(ni, cur);\n this.openList.update(ni);\n }\n }\n }\n\n // Backward\n if (!this.openListBack!.isEmpty) {\n const cur = this.openListBack!.pop();\n this.state.setClosedBack(cur);\n searched++;\n\n const curG = this.state.getGBack(cur);\n if (this.state.isClosed(cur)) {\n const total = curG + this.state.getG(cur);\n if (total < bestCost) { bestCost = total; meetIdx = cur; }\n }\n if (meetIdx !== -1 && curG >= bestCost) break;\n\n const cx = cur % width, cy = (cur / width) | 0;\n for (let d = 0; d < dirCount; d++) {\n const nx = cx + dx[d], ny = cy + dy[d];\n if (nx < 0 || nx >= width || ny < 0 || ny >= height) continue;\n const neighbor = nodes[ny][nx];\n if (!neighbor.walkable) continue;\n if (avoidCorners && dx[d] !== 0 && dy[d] !== 0) {\n if (!nodes[cy][cx + dx[d]].walkable || !nodes[cy + dy[d]][cx].walkable) continue;\n }\n const ni = ny * width + nx;\n if (this.state.isClosedBack(ni)) continue;\n const isDiag = dx[d] !== 0 && dy[d] !== 0;\n const cost = isDiag ? neighbor.cost * diagonalCost : neighbor.cost;\n const tentG = curG + cost;\n if (!this.state.isOpenedBack(ni)) {\n const h = this.map.heuristic({ x: nx, y: ny }, startPos) * hw;\n this.state.setGBack(ni, tentG);\n this.state.setFBack(ni, tentG + h);\n this.state.setParentBack(ni, cur);\n this.state.setOpenedBack(ni);\n this.openListBack!.push(ni);\n } else if (tentG < this.state.getGBack(ni)) {\n const h = this.state.getFBack(ni) - this.state.getGBack(ni);\n this.state.setGBack(ni, tentG);\n this.state.setFBack(ni, tentG + h);\n this.state.setParentBack(ni, cur);\n this.openListBack!.update(ni);\n }\n }\n }\n }\n\n if (meetIdx === -1) {\n return { found: false, path: [], cost: 0, nodesSearched: searched };\n }\n\n return this.buildPathBidirectional(startIdx, endIdx, meetIdx, searched);\n }\n\n private validate(startX: number, startY: number, endX: number, endY: number): boolean {\n const { width, height } = this.map;\n if (startX < 0 || startX >= width || startY < 0 || startY >= height) return false;\n if (endX < 0 || endX >= width || endY < 0 || endY >= height) return false;\n return this.map.isWalkable(startX, startY) && this.map.isWalkable(endX, endY);\n }\n\n private buildPath(startIdx: number, endIdx: number, searched: number): IPathResult {\n const w = this.state.width;\n const path: IPoint[] = [];\n let cur = endIdx;\n while (cur !== -1) {\n path.push({ x: cur % w, y: (cur / w) | 0 });\n cur = cur === startIdx ? -1 : this.state.getParent(cur);\n }\n path.reverse();\n return { found: true, path, cost: this.state.getG(endIdx), nodesSearched: searched };\n }\n\n private buildPathBidirectional(startIdx: number, endIdx: number, meetIdx: number, searched: number): IPathResult {\n const w = this.state.width;\n const path: IPoint[] = [];\n\n // Forward path\n let cur = meetIdx;\n while (cur !== -1 && cur !== startIdx) {\n path.push({ x: cur % w, y: (cur / w) | 0 });\n cur = this.state.getParent(cur);\n }\n path.push({ x: startIdx % w, y: (startIdx / w) | 0 });\n path.reverse();\n\n // Backward path\n cur = this.state.getParentBack(meetIdx);\n while (cur !== -1 && cur !== endIdx) {\n path.push({ x: cur % w, y: (cur / w) | 0 });\n cur = this.state.getParentBack(cur);\n }\n if (meetIdx !== endIdx) {\n path.push({ x: endIdx % w, y: (endIdx / w) | 0 });\n }\n\n const cost = this.state.getG(meetIdx) + this.state.getGBack(meetIdx);\n return { found: true, path, cost, nodesSearched: searched };\n }\n\n clear(): void {\n this.state.reset();\n this.openList.clear();\n this.openListBack?.clear();\n }\n}\n\n/**\n * @zh 创建网格寻路器\n * @en Create grid pathfinder\n */\nexport function createGridPathfinder(map: GridMap, config?: IGridPathfinderConfig): GridPathfinder {\n return new GridPathfinder(map, config);\n}\n","/**\n * @zh 路径验证器\n * @en Path Validator\n */\n\nimport type { IPoint, IPathfindingMap } from './IPathfinding';\nimport type { IPathValidator, IPathValidationResult } from './IIncrementalPathfinding';\n\n// =============================================================================\n// 路径验证器 | Path Validator\n// =============================================================================\n\n/**\n * @zh 路径验证器\n * @en Path Validator\n *\n * @zh 用于检查现有路径在地图变化后是否仍然有效\n * @en Used to check if an existing path is still valid after map changes\n *\n * @example\n * ```typescript\n * const validator = new PathValidator();\n * const result = validator.validatePath(path, 0, path.length, map);\n *\n * if (!result.valid) {\n * console.log('Path invalid at index:', result.invalidIndex);\n * // Trigger replanning from current position\n * }\n * ```\n */\nexport class PathValidator implements IPathValidator {\n /**\n * @zh 验证路径段的有效性\n * @en Validate path segment validity\n *\n * @param path - @zh 要验证的路径 @en Path to validate\n * @param fromIndex - @zh 起始索引 @en Start index\n * @param toIndex - @zh 结束索引 @en End index\n * @param map - @zh 地图实例 @en Map instance\n * @returns @zh 验证结果 @en Validation result\n */\n validatePath(\n path: readonly IPoint[],\n fromIndex: number,\n toIndex: number,\n map: IPathfindingMap\n ): IPathValidationResult {\n const end = Math.min(toIndex, path.length);\n\n for (let i = fromIndex; i < end; i++) {\n const point = path[i];\n const x = Math.floor(point.x);\n const y = Math.floor(point.y);\n\n if (!map.isWalkable(x, y)) {\n return { valid: false, invalidIndex: i };\n }\n\n if (i > fromIndex) {\n const prev = path[i - 1];\n if (!this.checkLineOfSight(prev.x, prev.y, point.x, point.y, map)) {\n return { valid: false, invalidIndex: i };\n }\n }\n }\n\n return { valid: true, invalidIndex: -1 };\n }\n\n /**\n * @zh 检查两点之间的视线(使用 Bresenham 算法)\n * @en Check line of sight between two points (using Bresenham algorithm)\n *\n * @param x1 - @zh 起点 X @en Start X\n * @param y1 - @zh 起点 Y @en Start Y\n * @param x2 - @zh 终点 X @en End X\n * @param y2 - @zh 终点 Y @en End Y\n * @param map - @zh 地图实例 @en Map instance\n * @returns @zh 是否有视线 @en Whether there is line of sight\n */\n private checkLineOfSight(\n x1: number,\n y1: number,\n x2: number,\n y2: number,\n map: IPathfindingMap\n ): boolean {\n const ix1 = Math.floor(x1);\n const iy1 = Math.floor(y1);\n const ix2 = Math.floor(x2);\n const iy2 = Math.floor(y2);\n\n let dx = Math.abs(ix2 - ix1);\n let dy = Math.abs(iy2 - iy1);\n let x = ix1;\n let y = iy1;\n\n const sx = ix1 < ix2 ? 1 : -1;\n const sy = iy1 < iy2 ? 1 : -1;\n\n if (dx > dy) {\n let err = dx / 2;\n while (x !== ix2) {\n if (!map.isWalkable(x, y)) {\n return false;\n }\n err -= dy;\n if (err < 0) {\n y += sy;\n err += dx;\n }\n x += sx;\n }\n } else {\n let err = dy / 2;\n while (y !== iy2) {\n if (!map.isWalkable(x, y)) {\n return false;\n }\n err -= dx;\n if (err < 0) {\n x += sx;\n err += dy;\n }\n y += sy;\n }\n }\n\n return map.isWalkable(ix2, iy2);\n }\n}\n\n// =============================================================================\n// 障碍物变化管理器 | Obstacle Change Manager\n// =============================================================================\n\n/**\n * @zh 障碍物变化记录\n * @en Obstacle change record\n */\nexport interface IObstacleChange {\n /**\n * @zh X 坐标\n * @en X coordinate\n */\n readonly x: number;\n\n /**\n * @zh Y 坐标\n * @en Y coordinate\n */\n readonly y: number;\n\n /**\n * @zh 变化前是否可通行\n * @en Was walkable before change\n */\n readonly wasWalkable: boolean;\n\n /**\n * @zh 变化时间戳\n * @en Change timestamp\n */\n readonly timestamp: number;\n}\n\n/**\n * @zh 障碍物变化区域\n * @en Obstacle change region\n */\nexport interface IChangeRegion {\n /**\n * @zh 最小 X 坐标\n * @en Minimum X coordinate\n */\n readonly minX: number;\n\n /**\n * @zh 最小 Y 坐标\n * @en Minimum Y coordinate\n */\n readonly minY: number;\n\n /**\n * @zh 最大 X 坐标\n * @en Maximum X coordinate\n */\n readonly maxX: number;\n\n /**\n * @zh 最大 Y 坐标\n * @en Maximum Y coordinate\n */\n readonly maxY: number;\n}\n\n/**\n * @zh 障碍物变化管理器\n * @en Obstacle Change Manager\n *\n * @zh 跟踪地图障碍物变化,用于触发动态重规划\n * @en Tracks map obstacle changes, used to trigger dynamic replanning\n *\n * @example\n * ```typescript\n * const manager = new ObstacleChangeManager();\n *\n * // Record change when obstacle is added/removed\n * manager.recordChange(10, 20, true); // Was walkable, now blocked\n *\n * // Get affected region for notification\n * const region = manager.getAffectedRegion();\n * if (region) {\n * pathfinder.notifyObstacleChange(\n * region.minX, region.minY,\n * region.maxX, region.maxY\n * );\n * }\n *\n * // Clear after notification\n * manager.flush();\n * ```\n */\nexport class ObstacleChangeManager {\n private readonly changes: Map<string, IObstacleChange> = new Map();\n private epoch: number = 0;\n\n /**\n * @zh 记录障碍物变化\n * @en Record obstacle change\n *\n * @param x - @zh X 坐标 @en X coordinate\n * @param y - @zh Y 坐标 @en Y coordinate\n * @param wasWalkable - @zh 变化前是否可通行 @en Was walkable before change\n */\n recordChange(x: number, y: number, wasWalkable: boolean): void {\n const key = `${x},${y}`;\n this.changes.set(key, {\n x,\n y,\n wasWalkable,\n timestamp: Date.now()\n });\n }\n\n /**\n * @zh 获取影响区域\n * @en Get affected region\n *\n * @returns @zh 影响区域或 null(如果没有变化)@en Affected region or null if no changes\n */\n getAffectedRegion(): IChangeRegion | null {\n if (this.changes.size === 0) {\n return null;\n }\n\n let minX = Infinity;\n let minY = Infinity;\n let maxX = -Infinity;\n let maxY = -Infinity;\n\n for (const change of this.changes.values()) {\n minX = Math.min(minX, change.x);\n minY = Math.min(minY, change.y);\n maxX = Math.max(maxX, change.x);\n maxY = Math.max(maxY, change.y);\n }\n\n return { minX, minY, maxX, maxY };\n }\n\n /**\n * @zh 获取所有变化\n * @en Get all changes\n *\n * @returns @zh 变化列表 @en List of changes\n */\n getChanges(): IObstacleChange[] {\n return Array.from(this.changes.values());\n }\n\n /**\n * @zh 检查是否有变化\n * @en Check if there are changes\n *\n * @returns @zh 是否有变化 @en Whether there are changes\n */\n hasChanges(): boolean {\n return this.changes.size > 0;\n }\n\n /**\n * @zh 获取当前 epoch\n * @en Get current epoch\n *\n * @returns @zh 当前 epoch @en Current epoch\n */\n getEpoch(): number {\n return this.epoch;\n }\n\n /**\n * @zh 清空变化记录并推进 epoch\n * @en Clear changes and advance epoch\n */\n flush(): void {\n this.changes.clear();\n this.epoch++;\n }\n\n /**\n * @zh 清空所有状态\n * @en Clear all state\n */\n clear(): void {\n this.changes.clear();\n this.epoch = 0;\n }\n}\n\n// =============================================================================\n// 工厂函数 | Factory Functions\n// =============================================================================\n\n/**\n * @zh 创建路径验证器\n * @en Create path validator\n *\n * @returns @zh 路径验证器实例 @en Path validator instance\n */\nexport function createPathValidator(): PathValidator {\n return new PathValidator();\n}\n\n/**\n * @zh 创建障碍物变化管理器\n * @en Create obstacle change manager\n *\n * @returns @zh 障碍物变化管理器实例 @en Obstacle change manager instance\n */\nexport function createObstacleChangeManager(): ObstacleChangeManager {\n return new ObstacleChangeManager();\n}\n","/**\n * @zh 网格地图实现\n * @en Grid Map Implementation\n */\n\nimport type {\n IPathfindingMap,\n IPathNode,\n IPoint,\n HeuristicFunction\n} from '../core/IPathfinding';\nimport { createPoint, octileDistance } from '../core/IPathfinding';\n\n// =============================================================================\n// 网格节点 | Grid Node\n// =============================================================================\n\n/**\n * @zh 网格节点\n * @en Grid node\n */\nexport class GridNode implements IPathNode {\n readonly id: number;\n readonly position: IPoint;\n readonly x: number;\n readonly y: number;\n cost: number;\n walkable: boolean;\n\n constructor(x: number, y: number, width: number, walkable: boolean = true, cost: number = 1) {\n this.x = x;\n this.y = y;\n this.id = y * width + x;\n this.position = createPoint(x, y);\n this.walkable = walkable;\n this.cost = cost;\n }\n}\n\n// =============================================================================\n// 移动方向 | Movement Directions\n// =============================================================================\n\n/**\n * @zh 4方向偏移 (上下左右)\n * @en 4-directional offsets (up, down, left, right)\n */\nexport const DIRECTIONS_4 = [\n { dx: 0, dy: -1 }, // Up\n { dx: 1, dy: 0 }, // Right\n { dx: 0, dy: 1 }, // Down\n { dx: -1, dy: 0 } // Left\n] as const;\n\n/**\n * @zh 8方向偏移 (含对角线)\n * @en 8-directional offsets (including diagonals)\n */\nexport const DIRECTIONS_8 = [\n { dx: 0, dy: -1 }, // Up\n { dx: 1, dy: -1 }, // Up-Right\n { dx: 1, dy: 0 }, // Right\n { dx: 1, dy: 1 }, // Down-Right\n { dx: 0, dy: 1 }, // Down\n { dx: -1, dy: 1 }, // Down-Left\n { dx: -1, dy: 0 }, // Left\n { dx: -1, dy: -1 } // Up-Left\n] as const;\n\n// =============================================================================\n// 网格地图配置 | Grid Map Options\n// =============================================================================\n\n/**\n * @zh 网格地图配置\n * @en Grid map options\n */\nexport interface IGridMapOptions {\n /** @zh 是否允许对角移动 @en Allow diagonal movement */\n allowDiagonal?: boolean;\n /** @zh 对角移动代价 @en Diagonal movement cost */\n diagonalCost?: number;\n /** @zh 是否避免穿角 @en Avoid corner cutting */\n avoidCorners?: boolean;\n /** @zh 启发式函数 @en Heuristic function */\n heuristic?: HeuristicFunction;\n}\n\n/**\n * @zh 默认网格地图配置\n * @en Default grid map options\n */\nexport const DEFAULT_GRID_OPTIONS: Required<IGridMapOptions> = {\n allowDiagonal: true,\n diagonalCost: Math.SQRT2,\n avoidCorners: true,\n heuristic: octileDistance\n};\n\n// =============================================================================\n// 网格地图 | Grid Map\n// =============================================================================\n\n/**\n * @zh 网格地图\n * @en Grid Map\n *\n * @zh 基于二维数组的网格地图实现,支持4方向和8方向移动\n * @en Grid map implementation based on 2D array, supports 4 and 8 directional movement\n *\n * @example\n * ```typescript\n * // Create a 10x10 grid\n * const grid = new GridMap(10, 10);\n *\n * // Set some cells as obstacles\n * grid.setWalkable(5, 5, false);\n * grid.setWalkable(5, 6, false);\n *\n * // Use with pathfinder\n * const pathfinder = new AStarPathfinder(grid);\n * const result = pathfinder.findPath(0, 0, 9, 9);\n * ```\n */\nexport class GridMap implements IPathfindingMap {\n readonly width: number;\n readonly height: number;\n private readonly nodes: GridNode[][];\n private readonly options: Required<IGridMapOptions>;\n\n constructor(width: number, height: number, options?: IGridMapOptions) {\n this.width = width;\n this.height = height;\n this.options = { ...DEFAULT_GRID_OPTIONS, ...options };\n this.nodes = this.createNodes();\n }\n\n /**\n * @zh 创建网格节点\n * @en Create grid nodes\n */\n private createNodes(): GridNode[][] {\n const nodes: GridNode[][] = [];\n\n for (let y = 0; y < this.height; y++) {\n nodes[y] = [];\n for (let x = 0; x < this.width; x++) {\n nodes[y][x] = new GridNode(x, y, this.width, true, 1);\n }\n }\n\n return nodes;\n }\n\n /**\n * @zh 获取指定位置的节点\n * @en Get node at position\n */\n getNodeAt(x: number, y: number): GridNode | null {\n if (!this.isInBounds(x, y)) {\n return null;\n }\n return this.nodes[y][x];\n }\n\n /**\n * @zh 检查坐标是否在边界内\n * @en Check if coordinates are within bounds\n */\n isInBounds(x: number, y: number): boolean {\n return x >= 0 && x < this.width && y >= 0 && y < this.height;\n }\n\n /**\n * @zh 检查位置是否可通行\n * @en Check if position is walkable\n */\n isWalkable(x: number, y: number): boolean {\n const node = this.getNodeAt(x, y);\n return node !== null && node.walkable;\n }\n\n /**\n * @zh 设置位置是否可通行\n * @en Set position walkability\n */\n setWalkable(x: number, y: number, walkable: boolean): void {\n const node = this.getNodeAt(x, y);\n if (node) {\n node.walkable = walkable;\n }\n }\n\n /**\n * @zh 设置位置的移动代价\n * @en Set movement cost at position\n */\n setCost(x: number, y: number, cost: number): void {\n const node = this.getNodeAt(x, y);\n if (node) {\n node.cost = cost;\n }\n }\n\n /**\n * @zh 获取节点的邻居\n * @en Get neighbors of a node\n */\n getNeighbors(node: IPathNode): GridNode[] {\n const neighbors: GridNode[] = [];\n const { x, y } = node.position;\n const directions = this.options.allowDiagonal ? DIRECTIONS_8 : DIRECTIONS_4;\n\n for (let i = 0; i < directions.length; i++) {\n const dir = directions[i];\n const nx = x + dir.dx;\n const ny = y + dir.dy;\n\n if (nx < 0 || nx >= this.width || ny < 0 || ny >= this.height) {\n continue;\n }\n\n const neighbor = this.nodes[ny][nx];\n\n if (!neighbor.walkable) {\n continue;\n }\n\n if (this.options.avoidCorners && dir.dx !== 0 && dir.dy !== 0) {\n const hNode = this.nodes[y][x + dir.dx];\n const vNode = this.nodes[y + dir.dy][x];\n\n if (!hNode.walkable || !vNode.walkable) {\n continue;\n }\n }\n\n neighbors.push(neighbor);\n }\n\n return neighbors;\n }\n\n /**\n * @zh 遍历节点的邻居(零分配)\n * @en Iterate over neighbors (zero allocation)\n */\n forEachNeighbor(node: IPathNode, callback: (neighbor: GridNode) => boolean | void): void {\n const { x, y } = node.position;\n const directions = this.options.allowDiagonal ? DIRECTIONS_8 : DIRECTIONS_4;\n\n for (let i = 0; i < directions.length; i++) {\n const dir = directions[i];\n const nx = x + dir.dx;\n const ny = y + dir.dy;\n\n if (nx < 0 || nx >= this.width || ny < 0 || ny >= this.height) {\n continue;\n }\n\n const neighbor = this.nodes[ny][nx];\n\n if (!neighbor.walkable) {\n continue;\n }\n\n if (this.options.avoidCorners && dir.dx !== 0 && dir.dy !== 0) {\n const hNode = this.nodes[y][x + dir.dx];\n const vNode = this.nodes[y + dir.dy][x];\n\n if (!hNode.walkable || !vNode.walkable) {\n continue;\n }\n }\n\n if (callback(neighbor) === false) {\n return;\n }\n }\n }\n\n /**\n * @zh 计算启发式距离\n * @en Calculate heuristic distance\n */\n heuristic(a: IPoint, b: IPoint): number {\n return this.options.heuristic(a, b);\n }\n\n /**\n * @zh 计算移动代价\n * @en Calculate movement cost\n */\n getMovementCost(from: IPathNode, to: IPathNode): number {\n const dx = Math.abs(from.position.x - to.position.x);\n const dy = Math.abs(from.position.y - to.position.y);\n\n // Diagonal movement\n if (dx !== 0 && dy !== 0) {\n return to.cost * this.options.diagonalCost;\n }\n\n // Cardinal movement\n return to.cost;\n }\n\n /**\n * @zh 从二维数组加载地图\n * @en Load map from 2D array\n *\n * @param data - @zh 0=可通行,非0=不可通行 @en 0=walkable, non-0=blocked\n */\n loadFromArray(data: number[][]): void {\n for (let y = 0; y < Math.min(data.length, this.height); y++) {\n for (let x = 0; x < Math.min(data[y].length, this.width); x++) {\n this.nodes[y][x].walkable = data[y][x] === 0;\n }\n }\n }\n\n /**\n * @zh 从字符串加载地图\n * @en Load map from string\n *\n * @param str - @zh 地图字符串,'.'=可通行,'#'=障碍 @en Map string, '.'=walkable, '#'=blocked\n */\n loadFromString(str: string): void {\n const lines = str.trim().split('\\n');\n\n for (let y = 0; y < Math.min(lines.length, this.height); y++) {\n const line = lines[y];\n for (let x = 0; x < Math.min(line.length, this.width); x++) {\n this.nodes[y][x].walkable = line[x] !== '#';\n }\n }\n }\n\n /**\n * @zh 导出为字符串\n * @en Export to string\n */\n toString(): string {\n let result = '';\n\n for (let y = 0; y < this.height; y++) {\n for (let x = 0; x < this.width; x++) {\n result += this.nodes[y][x].walkable ? '.' : '#';\n }\n result += '\\n';\n }\n\n return result;\n }\n\n /**\n * @zh 重置所有节点为可通行\n * @en Reset all nodes to walkable\n */\n reset(): void {\n for (let y = 0; y < this.height; y++) {\n for (let x = 0; x < this.width; x++) {\n this.nodes[y][x].walkable = true;\n this.nodes[y][x].cost = 1;\n }\n }\n }\n\n /**\n * @zh 设置矩形区域的通行性\n * @en Set walkability for a rectangle region\n */\n setRectWalkable(\n x: number,\n y: number,\n width: number,\n height: number,\n walkable: boolean\n ): void {\n for (let dy = 0; dy < height; dy++) {\n for (let dx = 0; dx < width; dx++) {\n this.setWalkable(x + dx, y + dy, walkable);\n }\n }\n }\n}\n\n// =============================================================================\n// 工厂函数 | Factory Function\n// =============================================================================\n\n/**\n * @zh 创建网格地图\n * @en Create grid map\n */\nexport function createGridMap(\n width: number,\n height: number,\n options?: IGridMapOptions\n): GridMap {\n return new GridMap(width, height, options);\n}\n","/**\n * @zh 导航网格实现\n * @en NavMesh Implementation\n *\n * @zh 支持动态障碍物:可以临时禁用多边形或添加圆形/矩形障碍物\n * @en Supports dynamic obstacles: can temporarily disable polygons or add circular/rectangular obstacles\n */\n\nimport type {\n IPathfindingMap,\n IPathNode,\n IPoint,\n IPathResult,\n IPathfindingOptions\n} from '../core/IPathfinding';\nimport { createPoint, euclideanDistance, EMPTY_PATH_RESULT, DEFAULT_PATHFINDING_OPTIONS } from '../core/IPathfinding';\nimport { BinaryHeap } from '../core/BinaryHeap';\n\n// =============================================================================\n// 动态障碍物 | Dynamic Obstacles\n// =============================================================================\n\n/**\n * @zh 动态障碍物类型\n * @en Dynamic obstacle type\n */\nexport type ObstacleType = 'circle' | 'rect' | 'polygon';\n\n/**\n * @zh 动态障碍物\n * @en Dynamic obstacle\n */\nexport interface IDynamicObstacle {\n /**\n * @zh 障碍物 ID\n * @en Obstacle ID\n */\n readonly id: number;\n\n /**\n * @zh 障碍物类型\n * @en Obstacle type\n */\n readonly type: ObstacleType;\n\n /**\n * @zh 是否启用\n * @en Whether enabled\n */\n enabled: boolean;\n\n /**\n * @zh 位置(圆形和矩形的中心)\n * @en Position (center for circle and rect)\n */\n position: IPoint;\n\n /**\n * @zh 半径(圆形)或半宽/半高(矩形)\n * @en Radius (circle) or half-width/half-height (rect)\n */\n radius?: number;\n halfWidth?: number;\n halfHeight?: number;\n\n /**\n * @zh 顶点(多边形)\n * @en Vertices (polygon)\n */\n vertices?: readonly IPoint[];\n}\n\n// =============================================================================\n// 导航多边形 | Navigation Polygon\n// =============================================================================\n\n/**\n * @zh 导航多边形\n * @en Navigation polygon\n */\nexport interface INavPolygon {\n /** @zh 多边形ID @en Polygon ID */\n readonly id: number;\n /** @zh 顶点列表 @en Vertex list */\n readonly vertices: readonly IPoint[];\n /** @zh 中心点 @en Center point */\n readonly center: IPoint;\n /** @zh 邻居多边形ID @en Neighbor polygon IDs */\n readonly neighbors: readonly number[];\n /** @zh 到邻居的共享边 @en Shared edges to neighbors */\n readonly portals: ReadonlyMap<number, IPortal>;\n}\n\n/**\n * @zh 入口(两个多边形之间的共享边)\n * @en Portal (shared edge between two polygons)\n */\nexport interface IPortal {\n /** @zh 边的左端点 @en Left endpoint of edge */\n readonly left: IPoint;\n /** @zh 边的右端点 @en Right endpoint of edge */\n readonly right: IPoint;\n}\n\n// =============================================================================\n// 导航网格节点 | NavMesh Node\n// =============================================================================\n\n/**\n * @zh 导航网格节点(包装多边形)\n * @en NavMesh node (wraps polygon)\n */\nclass NavMeshNode implements IPathNode {\n readonly id: number;\n readonly position: IPoint;\n readonly cost: number;\n readonly walkable: boolean;\n readonly polygon: INavPolygon;\n\n constructor(polygon: INavPolygon) {\n this.id = polygon.id;\n this.position = polygon.center;\n this.cost = 1;\n this.walkable = true;\n this.polygon = polygon;\n }\n}\n\n// =============================================================================\n// 导航网格 | Navigation Mesh\n// =============================================================================\n\n/**\n * @zh 导航网格\n * @en Navigation Mesh\n *\n * @zh 使用凸多边形网格进行高效寻路,适合复杂地形\n * @en Uses convex polygon mesh for efficient pathfinding, suitable for complex terrain\n *\n * @example\n * ```typescript\n * const navmesh = new NavMesh();\n *\n * // Add polygons\n * navmesh.addPolygon([\n * { x: 0, y: 0 }, { x: 10, y: 0 },\n * { x: 10, y: 10 }, { x: 0, y: 10 }\n * ]);\n *\n * // Build connections\n * navmesh.build();\n *\n * // Find path\n * const result = navmesh.findPath(1, 1, 8, 8);\n * ```\n */\nexport class NavMesh implements IPathfindingMap {\n private polygons: Map<number, INavPolygon> = new Map();\n private nodes: Map<number, NavMeshNode> = new Map();\n private nextId = 0;\n\n // @zh 动态障碍物支持\n // @en Dynamic obstacle support\n private obstacles: Map<number, IDynamicObstacle> = new Map();\n private nextObstacleId = 0;\n private disabledPolygons: Set<number> = new Set();\n\n /**\n * @zh 添加导航多边形\n * @en Add navigation polygon\n *\n * @returns @zh 多边形ID @en Polygon ID\n */\n addPolygon(vertices: IPoint[], neighbors: number[] = []): number {\n const id = this.nextId++;\n const center = this.calculateCenter(vertices);\n\n const polygon: INavPolygon = {\n id,\n vertices,\n center,\n neighbors,\n portals: new Map()\n };\n\n this.polygons.set(id, polygon);\n this.nodes.set(id, new NavMeshNode(polygon));\n\n return id;\n }\n\n /**\n * @zh 设置两个多边形之间的连接\n * @en Set connection between two polygons\n */\n setConnection(\n polyA: number,\n polyB: number,\n portal: IPortal\n ): void {\n const polygonA = this.polygons.get(polyA);\n const polygonB = this.polygons.get(polyB);\n\n if (!polygonA || !polygonB) {\n return;\n }\n\n // Update neighbors and portals\n const neighborsA = [...polygonA.neighbors];\n const portalsA = new Map(polygonA.portals);\n\n if (!neighborsA.includes(polyB)) {\n neighborsA.push(polyB);\n }\n portalsA.set(polyB, portal);\n\n this.polygons.set(polyA, {\n ...polygonA,\n neighbors: neighborsA,\n portals: portalsA\n });\n\n // Reverse portal for the other direction\n const reversePortal: IPortal = {\n left: portal.right,\n right: portal.left\n };\n\n const neighborsB = [...polygonB.neighbors];\n const portalsB = new Map(polygonB.portals);\n\n if (!neighborsB.includes(polyA)) {\n neighborsB.push(polyA);\n }\n portalsB.set(polyA, reversePortal);\n\n this.polygons.set(polyB, {\n ...polygonB,\n neighbors: neighborsB,\n portals: portalsB\n });\n }\n\n /**\n * @zh 自动检测并建立相邻多边形的连接\n * @en Auto-detect and build connections between adjacent polygons\n */\n build(): void {\n const polygonList = Array.from(this.polygons.values());\n\n for (let i = 0; i < polygonList.length; i++) {\n for (let j = i + 1; j < polygonList.length; j++) {\n const polyA = polygonList[i];\n const polyB = polygonList[j];\n\n const sharedEdge = this.findSharedEdge(polyA.vertices, polyB.vertices);\n\n if (sharedEdge) {\n this.setConnection(polyA.id, polyB.id, sharedEdge);\n }\n }\n }\n }\n\n /**\n * @zh 查找两个多边形的共享边\n * @en Find shared edge between two polygons\n */\n private findSharedEdge(\n verticesA: readonly IPoint[],\n verticesB: readonly IPoint[]\n ): IPortal | null {\n const epsilon = 0.0001;\n\n for (let i = 0; i < verticesA.length; i++) {\n const a1 = verticesA[i];\n const a2 = verticesA[(i + 1) % verticesA.length];\n\n for (let j = 0; j < verticesB.length; j++) {\n const b1 = verticesB[j];\n const b2 = verticesB[(j + 1) % verticesB.length];\n\n // Check if edges match (in either direction)\n const match1 =\n Math.abs(a1.x - b2.x) < epsilon &&\n Math.abs(a1.y - b2.y) < epsilon &&\n Math.abs(a2.x - b1.x) < epsilon &&\n Math.abs(a2.y - b1.y) < epsilon;\n\n const match2 =\n Math.abs(a1.x - b1.x) < epsilon &&\n Math.abs(a1.y - b1.y) < epsilon &&\n Math.abs(a2.x - b2.x) < epsilon &&\n Math.abs(a2.y - b2.y) < epsilon;\n\n if (match1 || match2) {\n return {\n left: a1,\n right: a2\n };\n }\n }\n }\n\n return null;\n }\n\n /**\n * @zh 计算多边形中心\n * @en Calculate polygon center\n */\n private calculateCenter(vertices: readonly IPoint[]): IPoint {\n let x = 0;\n let y = 0;\n\n for (const v of vertices) {\n x += v.x;\n y += v.y;\n }\n\n return createPoint(x / vertices.length, y / vertices.length);\n }\n\n /**\n * @zh 查找包含点的多边形\n * @en Find polygon containing point\n */\n findPolygonAt(x: number, y: number): INavPolygon | null {\n for (const polygon of this.polygons.values()) {\n if (this.isPointInPolygon(x, y, polygon.vertices)) {\n return polygon;\n }\n }\n return null;\n }\n\n /**\n * @zh 检查点是否在多边形内\n * @en Check if point is inside polygon\n */\n private isPointInPolygon(x: number, y: number, vertices: readonly IPoint[]): boolean {\n let inside = false;\n const n = vertices.length;\n\n for (let i = 0, j = n - 1; i < n; j = i++) {\n const xi = vertices[i].x;\n const yi = vertices[i].y;\n const xj = vertices[j].x;\n const yj = vertices[j].y;\n\n if (\n yi > y !== yj > y &&\n x < ((xj - xi) * (y - yi)) / (yj - yi) + xi\n ) {\n inside = !inside;\n }\n }\n\n return inside;\n }\n\n // ==========================================================================\n // IPathfindingMap 接口实现 | IPathfindingMap Interface Implementation\n // ==========================================================================\n\n getNodeAt(x: number, y: number): IPathNode | null {\n const polygon = this.findPolygonAt(x, y);\n return polygon ? this.nodes.get(polygon.id) ?? null : null;\n }\n\n getNeighbors(node: IPathNode): IPathNode[] {\n const navNode = node as NavMeshNode;\n const neighbors: IPathNode[] = [];\n\n for (const neighborId of navNode.polygon.neighbors) {\n const neighbor = this.nodes.get(neighborId);\n if (neighbor) {\n neighbors.push(neighbor);\n }\n }\n\n return neighbors;\n }\n\n heuristic(a: IPoint, b: IPoint): number {\n return euclideanDistance(a, b);\n }\n\n getMovementCost(from: IPathNode, to: IPathNode): number {\n return euclideanDistance(from.position, to.position);\n }\n\n isWalkable(x: number, y: number): boolean {\n return this.findPolygonAt(x, y) !== null;\n }\n\n // ==========================================================================\n // 寻路 | Pathfinding\n // ==========================================================================\n\n /**\n * @zh 在导航网格上寻路\n * @en Find path on navigation mesh\n */\n findPath(\n startX: number,\n startY: number,\n endX: number,\n endY: number,\n options?: IPathfindingOptions\n ): IPathResult {\n const opts = { ...DEFAULT_PATHFINDING_OPTIONS, ...options };\n\n const startPolygon = this.findPolygonAt(startX, startY);\n const endPolygon = this.findPolygonAt(endX, endY);\n\n if (!startPolygon || !endPolygon) {\n return EMPTY_PATH_RESULT;\n }\n\n // Same polygon\n if (startPolygon.id === endPolygon.id) {\n return {\n found: true,\n path: [createPoint(startX, startY), createPoint(endX, endY)],\n cost: euclideanDistance(\n createPoint(startX, startY),\n createPoint(endX, endY)\n ),\n nodesSearched: 1\n };\n }\n\n // A* on polygon graph\n const polygonPath = this.findPolygonPath(startPolygon, endPolygon, opts);\n\n if (!polygonPath.found) {\n return EMPTY_PATH_RESULT;\n }\n\n // Convert polygon path to point path using funnel algorithm\n const start = createPoint(startX, startY);\n const end = createPoint(endX, endY);\n const pointPath = this.funnelPath(start, end, polygonPath.polygons, opts.agentRadius);\n\n return {\n found: true,\n path: pointPath,\n cost: this.calculatePathLength(pointPath),\n nodesSearched: polygonPath.nodesSearched\n };\n }\n\n /**\n * @zh 在多边形图上寻路\n * @en Find path on polygon graph\n *\n * @param start - @zh 起始多边形 @en Start polygon\n * @param end - @zh 目标多边形 @en End polygon\n * @param opts - @zh 寻路选项 @en Pathfinding options\n * @param checkObstacles - @zh 是否检查障碍物 @en Whether to check obstacles\n */\n private findPolygonPath(\n start: INavPolygon,\n end: INavPolygon,\n opts: Required<IPathfindingOptions>,\n checkObstacles: boolean = false\n ): { found: boolean; polygons: INavPolygon[]; nodesSearched: number } {\n interface AStarState {\n polygon: INavPolygon;\n g: number;\n f: number;\n parent: AStarState | null;\n }\n\n const openList = new BinaryHeap<AStarState>((a, b) => a.f - b.f);\n const closed = new Set<number>();\n const states = new Map<number, AStarState>();\n\n const startState: AStarState = {\n polygon: start,\n g: 0,\n f: euclideanDistance(start.center, end.center) * opts.heuristicWeight,\n parent: null\n };\n\n states.set(start.id, startState);\n openList.push(startState);\n\n let nodesSearched = 0;\n\n while (!openList.isEmpty && nodesSearched < opts.maxNodes) {\n const current = openList.pop()!;\n nodesSearched++;\n\n if (current.polygon.id === end.id) {\n // Reconstruct path\n const path: INavPolygon[] = [];\n let state: AStarState | null = current;\n\n while (state) {\n path.unshift(state.polygon);\n state = state.parent;\n }\n\n return { found: true, polygons: path, nodesSearched };\n }\n\n closed.add(current.polygon.id);\n\n for (const neighborId of current.polygon.neighbors) {\n if (closed.has(neighborId)) {\n continue;\n }\n\n // @zh 检查障碍物:跳过被阻挡或禁用的多边形\n // @en Check obstacles: skip blocked or disabled polygons\n if (checkObstacles && this.isPolygonBlocked(neighborId)) {\n continue;\n }\n\n const neighborPolygon = this.polygons.get(neighborId);\n if (!neighborPolygon) {\n continue;\n }\n\n const g = current.g + euclideanDistance(\n current.polygon.center,\n neighborPolygon.center\n );\n\n let neighborState = states.get(neighborId);\n\n if (!neighborState) {\n neighborState = {\n polygon: neighborPolygon,\n g,\n f: g + euclideanDistance(neighborPolygon.center, end.center) * opts.heuristicWeight,\n parent: current\n };\n states.set(neighborId, neighborState);\n openList.push(neighborState);\n } else if (g < neighborState.g) {\n neighborState.g = g;\n neighborState.f = g + euclideanDistance(neighborPolygon.center, end.center) * opts.heuristicWeight;\n neighborState.parent = current;\n openList.update(neighborState);\n }\n }\n }\n\n return { found: false, polygons: [], nodesSearched };\n }\n\n /**\n * @zh 使用漏斗算法优化路径(支持代理半径)\n * @en Optimize path using funnel algorithm (supports agent radius)\n *\n * @param start - @zh 起点 @en Start point\n * @param end - @zh 终点 @en End point\n * @param polygons - @zh 多边形路径 @en Polygon path\n * @param agentRadius - @zh 代理半径 @en Agent radius\n */\n private funnelPath(\n start: IPoint,\n end: IPoint,\n polygons: INavPolygon[],\n agentRadius: number = 0\n ): IPoint[] {\n if (polygons.length <= 1) {\n return [start, end];\n }\n\n // Collect and shrink portals\n const portals: { left: IPoint; right: IPoint; originalLeft: IPoint; originalRight: IPoint }[] = [];\n\n for (let i = 0; i < polygons.length - 1; i++) {\n const portal = polygons[i].portals.get(polygons[i + 1].id);\n if (portal) {\n if (agentRadius > 0) {\n const shrunk = this.shrinkPortal(portal.left, portal.right, agentRadius);\n portals.push({\n left: shrunk.left,\n right: shrunk.right,\n originalLeft: portal.left,\n originalRight: portal.right\n });\n } else {\n portals.push({\n left: portal.left,\n right: portal.right,\n originalLeft: portal.left,\n originalRight: portal.right\n });\n }\n }\n }\n\n if (portals.length === 0) {\n return [start, end];\n }\n\n // Simple string pulling algorithm with radius-aware turning points\n const path: IPoint[] = [start];\n\n let apex = start;\n let apexOriginal = start;\n let leftIndex = 0;\n let rightIndex = 0;\n let left = portals[0].left;\n let right = portals[0].right;\n let leftOriginal = portals[0].originalLeft;\n let rightOriginal = portals[0].originalRight;\n\n for (let i = 1; i <= portals.length; i++) {\n const nextLeft = i < portals.length ? portals[i].left : end;\n const nextRight = i < portals.length ? portals[i].right : end;\n\n // Update right\n if (this.triArea2(apex, right, nextRight) <= 0) {\n if (this.pointsEqual(apex, right) || this.triArea2(apex, left, nextRight) > 0) {\n right = nextRight;\n rightIndex = i;\n if (i < portals.length) {\n rightOriginal = portals[i].originalRight;\n }\n } else {\n // Add turning point with radius offset\n const turnPoint = agentRadius > 0\n ? this.offsetTurningPoint(apexOriginal, leftOriginal, left, agentRadius, 'left')\n : left;\n path.push(turnPoint);\n\n apex = left;\n apexOriginal = leftOriginal;\n leftIndex = rightIndex = leftIndex;\n left = right = apex;\n leftOriginal = rightOriginal = apexOriginal;\n i = leftIndex;\n continue;\n }\n }\n\n // Update left\n if (this.triArea2(apex, left, nextLeft) >= 0) {\n if (this.pointsEqual(apex, left) || this.triArea2(apex, right, nextLeft) < 0) {\n left = nextLeft;\n leftIndex = i;\n if (i < portals.length) {\n leftOriginal = portals[i].originalLeft;\n }\n } else {\n // Add turning point with radius offset\n const turnPoint = agentRadius > 0\n ? this.offsetTurningPoint(apexOriginal, rightOriginal, right, agentRadius, 'right')\n : right;\n path.push(turnPoint);\n\n apex = right;\n apexOriginal = rightOriginal;\n leftIndex = rightIndex = rightIndex;\n left = right = apex;\n leftOriginal = rightOriginal = apexOriginal;\n i = rightIndex;\n continue;\n }\n }\n }\n\n path.push(end);\n\n return path;\n }\n\n /**\n * @zh 收缩 portal(将两端点向内移动 agentRadius)\n * @en Shrink portal (move endpoints inward by agentRadius)\n */\n private shrinkPortal(left: IPoint, right: IPoint, radius: number): { left: IPoint; right: IPoint } {\n const dx = right.x - left.x;\n const dy = right.y - left.y;\n const len = Math.sqrt(dx * dx + dy * dy);\n\n if (len <= radius * 2) {\n // Portal too narrow, return center point\n const cx = (left.x + right.x) / 2;\n const cy = (left.y + right.y) / 2;\n return {\n left: createPoint(cx, cy),\n right: createPoint(cx, cy)\n };\n }\n\n // Normalize direction\n const nx = dx / len;\n const ny = dy / len;\n\n // Shrink both endpoints inward\n return {\n left: createPoint(left.x + nx * radius, left.y + ny * radius),\n right: createPoint(right.x - nx * radius, right.y - ny * radius)\n };\n }\n\n /**\n * @zh 偏移拐点以保持与角落的距离\n * @en Offset turning point to maintain distance from corner\n *\n * @param prevApex - @zh 上一个顶点 @en Previous apex\n * @param cornerOriginal - @zh 原始角落位置 @en Original corner position\n * @param cornerShrunk - @zh 收缩后的角落位置 @en Shrunk corner position\n * @param radius - @zh 代理半径 @en Agent radius\n * @param side - @zh 转向侧 ('left' 或 'right') @en Turn side ('left' or 'right')\n */\n private offsetTurningPoint(\n prevApex: IPoint,\n cornerOriginal: IPoint,\n cornerShrunk: IPoint,\n radius: number,\n side: 'left' | 'right'\n ): IPoint {\n // Direction from previous apex to corner\n const dx = cornerOriginal.x - prevApex.x;\n const dy = cornerOriginal.y - prevApex.y;\n const len = Math.sqrt(dx * dx + dy * dy);\n\n if (len < 0.0001) {\n return cornerShrunk;\n }\n\n // Perpendicular direction (pointing into the walkable area)\n // For left turn, perpendicular is to the right of the direction\n // For right turn, perpendicular is to the left of the direction\n let perpX: number, perpY: number;\n if (side === 'left') {\n perpX = dy / len;\n perpY = -dx / len;\n } else {\n perpX = -dy / len;\n perpY = dx / len;\n }\n\n // Offset the shrunk corner by radius in the perpendicular direction\n // This ensures the agent's circular body clears the corner\n return createPoint(\n cornerShrunk.x + perpX * radius,\n cornerShrunk.y + perpY * radius\n );\n }\n\n /**\n * @zh 检查两点是否相等\n * @en Check if two points are equal\n */\n private pointsEqual(a: IPoint, b: IPoint): boolean {\n return Math.abs(a.x - b.x) < 0.0001 && Math.abs(a.y - b.y) < 0.0001;\n }\n\n /**\n * @zh 计算三角形面积的两倍(用于判断点的相对位置)\n * @en Calculate twice the triangle area (for point relative position)\n */\n private triArea2(a: IPoint, b: IPoint, c: IPoint): number {\n return (c.x - a.x) * (b.y - a.y) - (b.x - a.x) * (c.y - a.y);\n }\n\n /**\n * @zh 计算路径总长度\n * @en Calculate total path length\n */\n private calculatePathLength(path: readonly IPoint[]): number {\n let length = 0;\n\n for (let i = 1; i < path.length; i++) {\n length += euclideanDistance(path[i - 1], path[i]);\n }\n\n return length;\n }\n\n // =========================================================================\n // 动态障碍物管理 | Dynamic Obstacle Management\n // =========================================================================\n\n /**\n * @zh 添加圆形障碍物\n * @en Add circular obstacle\n *\n * @param x - @zh 中心 X @en Center X\n * @param y - @zh 中心 Y @en Center Y\n * @param radius - @zh 半径 @en Radius\n * @returns @zh 障碍物 ID @en Obstacle ID\n */\n addCircleObstacle(x: number, y: number, radius: number): number {\n const id = this.nextObstacleId++;\n this.obstacles.set(id, {\n id,\n type: 'circle',\n enabled: true,\n position: createPoint(x, y),\n radius\n });\n return id;\n }\n\n /**\n * @zh 添加矩形障碍物\n * @en Add rectangular obstacle\n *\n * @param x - @zh 中心 X @en Center X\n * @param y - @zh 中心 Y @en Center Y\n * @param halfWidth - @zh 半宽 @en Half width\n * @param halfHeight - @zh 半高 @en Half height\n * @returns @zh 障碍物 ID @en Obstacle ID\n */\n addRectObstacle(x: number, y: number, halfWidth: number, halfHeight: number): number {\n const id = this.nextObstacleId++;\n this.obstacles.set(id, {\n id,\n type: 'rect',\n enabled: true,\n position: createPoint(x, y),\n halfWidth,\n halfHeight\n });\n return id;\n }\n\n /**\n * @zh 添加多边形障碍物\n * @en Add polygon obstacle\n *\n * @param vertices - @zh 顶点列表 @en Vertex list\n * @returns @zh 障碍物 ID @en Obstacle ID\n */\n addPolygonObstacle(vertices: IPoint[]): number {\n const id = this.nextObstacleId++;\n const center = this.calculateCenter(vertices);\n this.obstacles.set(id, {\n id,\n type: 'polygon',\n enabled: true,\n position: center,\n vertices\n });\n return id;\n }\n\n /**\n * @zh 移除障碍物\n * @en Remove obstacle\n */\n removeObstacle(obstacleId: number): boolean {\n return this.obstacles.delete(obstacleId);\n }\n\n /**\n * @zh 启用/禁用障碍物\n * @en Enable/disable obstacle\n */\n setObstacleEnabled(obstacleId: number, enabled: boolean): void {\n const obstacle = this.obstacles.get(obstacleId);\n if (obstacle) {\n obstacle.enabled = enabled;\n }\n }\n\n /**\n * @zh 更新障碍物位置\n * @en Update obstacle position\n */\n updateObstaclePosition(obstacleId: number, x: number, y: number): void {\n const obstacle = this.obstacles.get(obstacleId);\n if (obstacle) {\n obstacle.position = createPoint(x, y);\n }\n }\n\n /**\n * @zh 获取所有障碍物\n * @en Get all obstacles\n */\n getObstacles(): IDynamicObstacle[] {\n return Array.from(this.obstacles.values());\n }\n\n /**\n * @zh 获取启用的障碍物\n * @en Get enabled obstacles\n */\n getEnabledObstacles(): IDynamicObstacle[] {\n return Array.from(this.obstacles.values()).filter(o => o.enabled);\n }\n\n /**\n * @zh 清除所有障碍物\n * @en Clear all obstacles\n */\n clearObstacles(): void {\n this.obstacles.clear();\n this.nextObstacleId = 0;\n }\n\n // =========================================================================\n // 多边形禁用管理 | Polygon Disable Management\n // =========================================================================\n\n /**\n * @zh 禁用多边形\n * @en Disable polygon\n */\n disablePolygon(polygonId: number): void {\n this.disabledPolygons.add(polygonId);\n }\n\n /**\n * @zh 启用多边形\n * @en Enable polygon\n */\n enablePolygon(polygonId: number): void {\n this.disabledPolygons.delete(polygonId);\n }\n\n /**\n * @zh 检查多边形是否被禁用\n * @en Check if polygon is disabled\n */\n isPolygonDisabled(polygonId: number): boolean {\n return this.disabledPolygons.has(polygonId);\n }\n\n /**\n * @zh 禁用包含指定点的多边形\n * @en Disable polygon containing specified point\n */\n disablePolygonAt(x: number, y: number): number | null {\n const polygon = this.findPolygonAt(x, y);\n if (polygon) {\n this.disablePolygon(polygon.id);\n return polygon.id;\n }\n return null;\n }\n\n /**\n * @zh 清除所有禁用的多边形\n * @en Clear all disabled polygons\n */\n clearDisabledPolygons(): void {\n this.disabledPolygons.clear();\n }\n\n /**\n * @zh 获取被禁用的多边形 ID 列表\n * @en Get list of disabled polygon IDs\n */\n getDisabledPolygons(): number[] {\n return Array.from(this.disabledPolygons);\n }\n\n // =========================================================================\n // 障碍物碰撞检测 | Obstacle Collision Detection\n // =========================================================================\n\n /**\n * @zh 检查点是否在任何障碍物内\n * @en Check if point is inside any obstacle\n */\n isPointInObstacle(x: number, y: number): boolean {\n for (const obstacle of this.obstacles.values()) {\n if (!obstacle.enabled) continue;\n\n if (this.isPointInSingleObstacle(x, y, obstacle)) {\n return true;\n }\n }\n return false;\n }\n\n /**\n * @zh 检查点是否在单个障碍物内\n * @en Check if point is inside single obstacle\n */\n private isPointInSingleObstacle(x: number, y: number, obstacle: IDynamicObstacle): boolean {\n switch (obstacle.type) {\n case 'circle': {\n const dx = x - obstacle.position.x;\n const dy = y - obstacle.position.y;\n return dx * dx + dy * dy <= (obstacle.radius ?? 0) ** 2;\n }\n case 'rect': {\n const hw = obstacle.halfWidth ?? 0;\n const hh = obstacle.halfHeight ?? 0;\n return Math.abs(x - obstacle.position.x) <= hw &&\n Math.abs(y - obstacle.position.y) <= hh;\n }\n case 'polygon': {\n if (!obstacle.vertices) return false;\n return this.isPointInPolygon(x, y, obstacle.vertices);\n }\n default:\n return false;\n }\n }\n\n /**\n * @zh 检查线段是否与任何障碍物相交\n * @en Check if line segment intersects any obstacle\n */\n doesLineIntersectObstacle(x1: number, y1: number, x2: number, y2: number): boolean {\n for (const obstacle of this.obstacles.values()) {\n if (!obstacle.enabled) continue;\n\n if (this.doesLineIntersectSingleObstacle(x1, y1, x2, y2, obstacle)) {\n return true;\n }\n }\n return false;\n }\n\n /**\n * @zh 检查线段是否与单个障碍物相交\n * @en Check if line segment intersects single obstacle\n */\n private doesLineIntersectSingleObstacle(\n x1: number, y1: number, x2: number, y2: number,\n obstacle: IDynamicObstacle\n ): boolean {\n switch (obstacle.type) {\n case 'circle': {\n return this.lineIntersectsCircle(\n x1, y1, x2, y2,\n obstacle.position.x, obstacle.position.y,\n obstacle.radius ?? 0\n );\n }\n case 'rect': {\n const hw = obstacle.halfWidth ?? 0;\n const hh = obstacle.halfHeight ?? 0;\n const minX = obstacle.position.x - hw;\n const maxX = obstacle.position.x + hw;\n const minY = obstacle.position.y - hh;\n const maxY = obstacle.position.y + hh;\n return this.lineIntersectsRect(x1, y1, x2, y2, minX, minY, maxX, maxY);\n }\n case 'polygon': {\n if (!obstacle.vertices) return false;\n return this.lineIntersectsPolygon(x1, y1, x2, y2, obstacle.vertices);\n }\n default:\n return false;\n }\n }\n\n /**\n * @zh 线段与圆相交检测\n * @en Line segment circle intersection\n */\n private lineIntersectsCircle(\n x1: number, y1: number, x2: number, y2: number,\n cx: number, cy: number, r: number\n ): boolean {\n const dx = x2 - x1;\n const dy = y2 - y1;\n const fx = x1 - cx;\n const fy = y1 - cy;\n\n const a = dx * dx + dy * dy;\n const b = 2 * (fx * dx + fy * dy);\n const c = fx * fx + fy * fy - r * r;\n\n let discriminant = b * b - 4 * a * c;\n if (discriminant < 0) return false;\n\n discriminant = Math.sqrt(discriminant);\n const t1 = (-b - discriminant) / (2 * a);\n const t2 = (-b + discriminant) / (2 * a);\n\n return (t1 >= 0 && t1 <= 1) || (t2 >= 0 && t2 <= 1) || (t1 < 0 && t2 > 1);\n }\n\n /**\n * @zh 线段与矩形相交检测\n * @en Line segment rectangle intersection\n */\n private lineIntersectsRect(\n x1: number, y1: number, x2: number, y2: number,\n minX: number, minY: number, maxX: number, maxY: number\n ): boolean {\n // Check if either endpoint is inside\n if ((x1 >= minX && x1 <= maxX && y1 >= minY && y1 <= maxY) ||\n (x2 >= minX && x2 <= maxX && y2 >= minY && y2 <= maxY)) {\n return true;\n }\n\n // Check intersection with each edge\n return this.lineSegmentsIntersect(x1, y1, x2, y2, minX, minY, maxX, minY) ||\n this.lineSegmentsIntersect(x1, y1, x2, y2, maxX, minY, maxX, maxY) ||\n this.lineSegmentsIntersect(x1, y1, x2, y2, maxX, maxY, minX, maxY) ||\n this.lineSegmentsIntersect(x1, y1, x2, y2, minX, maxY, minX, minY);\n }\n\n /**\n * @zh 线段与多边形相交检测\n * @en Line segment polygon intersection\n */\n private lineIntersectsPolygon(\n x1: number, y1: number, x2: number, y2: number,\n vertices: readonly IPoint[]\n ): boolean {\n // Check if either endpoint is inside\n if (this.isPointInPolygon(x1, y1, vertices) ||\n this.isPointInPolygon(x2, y2, vertices)) {\n return true;\n }\n\n // Check intersection with each edge\n for (let i = 0; i < vertices.length; i++) {\n const j = (i + 1) % vertices.length;\n if (this.lineSegmentsIntersect(\n x1, y1, x2, y2,\n vertices[i].x, vertices[i].y,\n vertices[j].x, vertices[j].y\n )) {\n return true;\n }\n }\n return false;\n }\n\n /**\n * @zh 两线段相交检测\n * @en Two line segments intersection\n */\n private lineSegmentsIntersect(\n x1: number, y1: number, x2: number, y2: number,\n x3: number, y3: number, x4: number, y4: number\n ): boolean {\n const d1 = this.direction(x3, y3, x4, y4, x1, y1);\n const d2 = this.direction(x3, y3, x4, y4, x2, y2);\n const d3 = this.direction(x1, y1, x2, y2, x3, y3);\n const d4 = this.direction(x1, y1, x2, y2, x4, y4);\n\n if (((d1 > 0 && d2 < 0) || (d1 < 0 && d2 > 0)) &&\n ((d3 > 0 && d4 < 0) || (d3 < 0 && d4 > 0))) {\n return true;\n }\n\n const epsilon = 0.0001;\n if (Math.abs(d1) < epsilon && this.onSegment(x3, y3, x4, y4, x1, y1)) return true;\n if (Math.abs(d2) < epsilon && this.onSegment(x3, y3, x4, y4, x2, y2)) return true;\n if (Math.abs(d3) < epsilon && this.onSegment(x1, y1, x2, y2, x3, y3)) return true;\n if (Math.abs(d4) < epsilon && this.onSegment(x1, y1, x2, y2, x4, y4)) return true;\n\n return false;\n }\n\n private direction(x1: number, y1: number, x2: number, y2: number, x3: number, y3: number): number {\n return (x3 - x1) * (y2 - y1) - (y3 - y1) * (x2 - x1);\n }\n\n private onSegment(x1: number, y1: number, x2: number, y2: number, x3: number, y3: number): boolean {\n return Math.min(x1, x2) <= x3 && x3 <= Math.max(x1, x2) &&\n Math.min(y1, y2) <= y3 && y3 <= Math.max(y1, y2);\n }\n\n // =========================================================================\n // 障碍物感知寻路 | Obstacle-Aware Pathfinding\n // =========================================================================\n\n /**\n * @zh 检查多边形是否被障碍物阻挡\n * @en Check if polygon is blocked by obstacle\n *\n * @zh 检查以下条件:\n * @en Checks the following conditions:\n * - @zh 多边形是否被禁用 @en Whether polygon is disabled\n * - @zh 多边形中心是否在障碍物内 @en Whether polygon center is inside obstacle\n * - @zh 多边形任意顶点是否在障碍物内 @en Whether any polygon vertex is inside obstacle\n * - @zh 多边形任意边是否与障碍物相交 @en Whether any polygon edge intersects obstacle\n */\n isPolygonBlocked(polygonId: number): boolean {\n if (this.disabledPolygons.has(polygonId)) {\n return true;\n }\n\n const polygon = this.polygons.get(polygonId);\n if (!polygon) return false;\n\n // @zh 检查中心点\n // @en Check center point\n if (this.isPointInObstacle(polygon.center.x, polygon.center.y)) {\n return true;\n }\n\n // @zh 检查所有顶点\n // @en Check all vertices\n for (const vertex of polygon.vertices) {\n if (this.isPointInObstacle(vertex.x, vertex.y)) {\n return true;\n }\n }\n\n // @zh 检查所有边是否与障碍物相交\n // @en Check if any edge intersects with obstacles\n const vertices = polygon.vertices;\n for (let i = 0; i < vertices.length; i++) {\n const v1 = vertices[i];\n const v2 = vertices[(i + 1) % vertices.length];\n if (this.doesLineIntersectObstacle(v1.x, v1.y, v2.x, v2.y)) {\n return true;\n }\n }\n\n return false;\n }\n\n /**\n * @zh 在导航网格上寻路(考虑障碍物)\n * @en Find path on navigation mesh (considering obstacles)\n *\n * @zh 此方法在规划阶段就考虑障碍物,自动绕过被阻挡的多边形\n * @en This method considers obstacles during planning, automatically avoiding blocked polygons\n *\n * @zh 与 findPath 不同,此方法会:\n * @en Unlike findPath, this method will:\n * - @zh 在 A* 搜索中跳过被障碍物阻挡的多边形\n * - @en Skip obstacle-blocked polygons during A* search\n * - @zh 验证起点和终点不在障碍物内\n * - @en Verify start and end points are not inside obstacles\n */\n findPathWithObstacles(\n startX: number,\n startY: number,\n endX: number,\n endY: number,\n options?: IPathfindingOptions\n ): IPathResult {\n const opts = { ...DEFAULT_PATHFINDING_OPTIONS, ...options };\n\n // @zh 检查起点和终点是否在障碍物内\n // @en Check if start and end are inside obstacles\n if (this.isPointInObstacle(startX, startY) || this.isPointInObstacle(endX, endY)) {\n return EMPTY_PATH_RESULT;\n }\n\n const startPolygon = this.findPolygonAt(startX, startY);\n const endPolygon = this.findPolygonAt(endX, endY);\n\n if (!startPolygon || !endPolygon) {\n return EMPTY_PATH_RESULT;\n }\n\n // @zh 检查起点/终点多边形是否被阻挡\n // @en Check if start/end polygons are blocked\n if (this.isPolygonBlocked(startPolygon.id) || this.isPolygonBlocked(endPolygon.id)) {\n return EMPTY_PATH_RESULT;\n }\n\n // @zh 同一多边形内的路径\n // @en Path within same polygon\n if (startPolygon.id === endPolygon.id) {\n const start = createPoint(startX, startY);\n const end = createPoint(endX, endY);\n\n // @zh 检查直线路径是否穿过障碍物\n // @en Check if direct path crosses obstacles\n if (this.doesLineIntersectObstacle(startX, startY, endX, endY)) {\n return EMPTY_PATH_RESULT;\n }\n\n return {\n found: true,\n path: [start, end],\n cost: euclideanDistance(start, end),\n nodesSearched: 1\n };\n }\n\n // @zh 使用障碍物感知的多边形路径搜索\n // @en Use obstacle-aware polygon path search\n const polygonPath = this.findPolygonPath(startPolygon, endPolygon, opts, true);\n\n if (!polygonPath.found) {\n return EMPTY_PATH_RESULT;\n }\n\n // @zh 使用 Funnel 算法生成路径点\n // @en Generate path points using Funnel algorithm\n const start = createPoint(startX, startY);\n const end = createPoint(endX, endY);\n const pointPath = this.funnelPath(start, end, polygonPath.polygons, opts.agentRadius);\n\n return {\n found: true,\n path: pointPath,\n cost: this.calculatePathLength(pointPath),\n nodesSearched: polygonPath.nodesSearched\n };\n }\n\n /**\n * @zh 清空导航网格\n * @en Clear navigation mesh\n */\n clear(): void {\n this.polygons.clear();\n this.nodes.clear();\n this.obstacles.clear();\n this.disabledPolygons.clear();\n this.nextId = 0;\n this.nextObstacleId = 0;\n }\n\n /**\n * @zh 获取所有多边形\n * @en Get all polygons\n */\n getPolygons(): INavPolygon[] {\n return Array.from(this.polygons.values());\n }\n\n /**\n * @zh 获取多边形数量\n * @en Get polygon count\n */\n get polygonCount(): number {\n return this.polygons.size;\n }\n\n /**\n * @zh 获取障碍物数量\n * @en Get obstacle count\n */\n get obstacleCount(): number {\n return this.obstacles.size;\n }\n}\n\n// =============================================================================\n// 工厂函数 | Factory Function\n// =============================================================================\n\n/**\n * @zh 创建导航网格\n * @en Create navigation mesh\n */\nexport function createNavMesh(): NavMesh {\n return new NavMesh();\n}\n","/**\n * @zh 路径平滑算法\n * @en Path Smoothing Algorithms\n */\n\nimport type {\n IPathfindingMap,\n IPathSmoother,\n IPoint\n} from '../core/IPathfinding';\nimport { createPoint } from '../core/IPathfinding';\n\n// =============================================================================\n// 视线检测 | Line of Sight\n// =============================================================================\n\n/**\n * @zh 使用 Bresenham 算法检测视线\n * @en Line of sight check using Bresenham algorithm\n */\nexport function bresenhamLineOfSight(\n x1: number,\n y1: number,\n x2: number,\n y2: number,\n map: IPathfindingMap\n): boolean {\n // Round to grid coordinates\n let ix1 = Math.floor(x1);\n let iy1 = Math.floor(y1);\n const ix2 = Math.floor(x2);\n const iy2 = Math.floor(y2);\n\n const dx = Math.abs(ix2 - ix1);\n const dy = Math.abs(iy2 - iy1);\n\n const sx = ix1 < ix2 ? 1 : -1;\n const sy = iy1 < iy2 ? 1 : -1;\n\n let err = dx - dy;\n\n while (true) {\n if (!map.isWalkable(ix1, iy1)) {\n return false;\n }\n\n if (ix1 === ix2 && iy1 === iy2) {\n break;\n }\n\n const e2 = 2 * err;\n\n if (e2 > -dy) {\n err -= dy;\n ix1 += sx;\n }\n\n if (e2 < dx) {\n err += dx;\n iy1 += sy;\n }\n }\n\n return true;\n}\n\n/**\n * @zh 使用射线投射检测视线(更精确)\n * @en Line of sight check using ray casting (more precise)\n */\nexport function raycastLineOfSight(\n x1: number,\n y1: number,\n x2: number,\n y2: number,\n map: IPathfindingMap,\n stepSize: number = 0.5\n): boolean {\n const dx = x2 - x1;\n const dy = y2 - y1;\n const distance = Math.sqrt(dx * dx + dy * dy);\n\n if (distance === 0) {\n return map.isWalkable(Math.floor(x1), Math.floor(y1));\n }\n\n const steps = Math.ceil(distance / stepSize);\n const stepX = dx / steps;\n const stepY = dy / steps;\n\n let x = x1;\n let y = y1;\n\n for (let i = 0; i <= steps; i++) {\n if (!map.isWalkable(Math.floor(x), Math.floor(y))) {\n return false;\n }\n x += stepX;\n y += stepY;\n }\n\n return true;\n}\n\n// =============================================================================\n// 路径简化器(拐点移除)| Path Simplifier (Waypoint Removal)\n// =============================================================================\n\n/**\n * @zh 路径简化器 - 移除不必要的拐点\n * @en Path Simplifier - Removes unnecessary waypoints\n *\n * @zh 使用视线检测移除可以直接到达的中间点\n * @en Uses line of sight to remove intermediate points that can be reached directly\n */\nexport class LineOfSightSmoother implements IPathSmoother {\n private readonly lineOfSight: typeof bresenhamLineOfSight;\n\n constructor(lineOfSight: typeof bresenhamLineOfSight = bresenhamLineOfSight) {\n this.lineOfSight = lineOfSight;\n }\n\n smooth(path: readonly IPoint[], map: IPathfindingMap): IPoint[] {\n if (path.length <= 2) {\n return [...path];\n }\n\n const result: IPoint[] = [path[0]];\n let current = 0;\n\n while (current < path.length - 1) {\n // Find the furthest point we can see from current\n let furthest = current + 1;\n\n for (let i = path.length - 1; i > current + 1; i--) {\n if (this.lineOfSight(\n path[current].x,\n path[current].y,\n path[i].x,\n path[i].y,\n map\n )) {\n furthest = i;\n break;\n }\n }\n\n result.push(path[furthest]);\n current = furthest;\n }\n\n return result;\n }\n}\n\n// =============================================================================\n// 曲线平滑器 | Curve Smoother\n// =============================================================================\n\n/**\n * @zh Catmull-Rom 样条曲线平滑\n * @en Catmull-Rom spline smoothing\n */\nexport class CatmullRomSmoother implements IPathSmoother {\n private readonly segments: number;\n private readonly tension: number;\n\n /**\n * @param segments - @zh 每段之间的插值点数 @en Number of interpolation points per segment\n * @param tension - @zh 张力 (0-1) @en Tension (0-1)\n */\n constructor(segments: number = 5, tension: number = 0.5) {\n this.segments = segments;\n this.tension = tension;\n }\n\n smooth(path: readonly IPoint[], _map: IPathfindingMap): IPoint[] {\n if (path.length <= 2) {\n return [...path];\n }\n\n const result: IPoint[] = [];\n\n // Add phantom points at the ends\n const points = [\n path[0],\n ...path,\n path[path.length - 1]\n ];\n\n for (let i = 1; i < points.length - 2; i++) {\n const p0 = points[i - 1];\n const p1 = points[i];\n const p2 = points[i + 1];\n const p3 = points[i + 2];\n\n for (let j = 0; j < this.segments; j++) {\n const t = j / this.segments;\n const point = this.interpolate(p0, p1, p2, p3, t);\n result.push(point);\n }\n }\n\n // Add final point\n result.push(path[path.length - 1]);\n\n return result;\n }\n\n /**\n * @zh Catmull-Rom 插值\n * @en Catmull-Rom interpolation\n */\n private interpolate(\n p0: IPoint,\n p1: IPoint,\n p2: IPoint,\n p3: IPoint,\n t: number\n ): IPoint {\n const t2 = t * t;\n const t3 = t2 * t;\n\n const tension = this.tension;\n\n const x =\n 0.5 *\n ((2 * p1.x) +\n (-p0.x + p2.x) * t * tension +\n (2 * p0.x - 5 * p1.x + 4 * p2.x - p3.x) * t2 * tension +\n (-p0.x + 3 * p1.x - 3 * p2.x + p3.x) * t3 * tension);\n\n const y =\n 0.5 *\n ((2 * p1.y) +\n (-p0.y + p2.y) * t * tension +\n (2 * p0.y - 5 * p1.y + 4 * p2.y - p3.y) * t2 * tension +\n (-p0.y + 3 * p1.y - 3 * p2.y + p3.y) * t3 * tension);\n\n return createPoint(x, y);\n }\n}\n\n// =============================================================================\n// 组合平滑器 | Combined Smoother\n// =============================================================================\n\n/**\n * @zh 组合路径平滑器\n * @en Combined path smoother\n *\n * @zh 先简化路径,再用曲线平滑\n * @en First simplify path, then smooth with curves\n */\nexport class CombinedSmoother implements IPathSmoother {\n private readonly simplifier: LineOfSightSmoother;\n private readonly curveSmoother: CatmullRomSmoother;\n\n constructor(curveSegments: number = 5, tension: number = 0.5) {\n this.simplifier = new LineOfSightSmoother();\n this.curveSmoother = new CatmullRomSmoother(curveSegments, tension);\n }\n\n smooth(path: readonly IPoint[], map: IPathfindingMap): IPoint[] {\n // First simplify\n const simplified = this.simplifier.smooth(path, map);\n\n // Then curve smooth\n return this.curveSmoother.smooth(simplified, map);\n }\n}\n\n// =============================================================================\n// 工厂函数 | Factory Functions\n// =============================================================================\n\n/**\n * @zh 创建视线平滑器\n * @en Create line of sight smoother\n */\nexport function createLineOfSightSmoother(\n lineOfSight?: typeof bresenhamLineOfSight\n): LineOfSightSmoother {\n return new LineOfSightSmoother(lineOfSight);\n}\n\n/**\n * @zh 创建曲线平滑器\n * @en Create curve smoother\n */\nexport function createCatmullRomSmoother(\n segments?: number,\n tension?: number\n): CatmullRomSmoother {\n return new CatmullRomSmoother(segments, tension);\n}\n\n/**\n * @zh 创建组合平滑器\n * @en Create combined smoother\n */\nexport function createCombinedSmoother(\n curveSegments?: number,\n tension?: number\n): CombinedSmoother {\n return new CombinedSmoother(curveSegments, tension);\n}\n","/**\n * @zh 半径感知路径平滑器\n * @en Radius-Aware Path Smoother\n *\n * @zh 通用的路径后处理器,确保路径与障碍物保持安全距离\n * @en Generic path post-processor that ensures paths maintain safe distance from obstacles\n */\n\nimport type { IPathfindingMap, IPathSmoother, IPoint } from '../core/IPathfinding';\nimport { createPoint } from '../core/IPathfinding';\n\n// =============================================================================\n// 配置 | Configuration\n// =============================================================================\n\n/**\n * @zh 半径感知平滑器配置\n * @en Radius-aware smoother configuration\n */\nexport interface IRadiusAwareSmootherConfig {\n /**\n * @zh 代理半径\n * @en Agent radius\n */\n agentRadius: number;\n\n /**\n * @zh 额外安全边距\n * @en Extra safety margin\n * @default 0.1\n */\n safetyMargin?: number;\n\n /**\n * @zh 采样方向数量(用于检测周围障碍物)\n * @en Number of sample directions (for detecting nearby obstacles)\n * @default 8\n */\n sampleDirections?: number;\n\n /**\n * @zh 最大偏移尝试次数\n * @en Maximum offset attempts\n * @default 8\n */\n maxOffsetAttempts?: number;\n\n /**\n * @zh 是否处理拐点(角落)\n * @en Whether to process turning points (corners)\n * @default true\n */\n processCorners?: boolean;\n}\n\n/**\n * @zh 默认配置\n * @en Default configuration\n */\nconst DEFAULT_CONFIG: Required<Omit<IRadiusAwareSmootherConfig, 'agentRadius'>> = {\n safetyMargin: 0.1,\n sampleDirections: 8,\n maxOffsetAttempts: 8,\n processCorners: true\n};\n\n// =============================================================================\n// 半径感知路径平滑器 | Radius-Aware Path Smoother\n// =============================================================================\n\n/**\n * @zh 半径感知路径平滑器\n * @en Radius-Aware Path Smoother\n *\n * @zh 对任意寻路算法输出的路径进行后处理,确保路径点与障碍物保持足够距离\n * @en Post-processes paths from any pathfinding algorithm to ensure path points maintain sufficient distance from obstacles\n *\n * @example\n * ```typescript\n * // 创建平滑器\n * const smoother = new RadiusAwarePathSmoother({ agentRadius: 0.5 });\n *\n * // 处理路径\n * const safePath = smoother.smooth(rawPath, map);\n *\n * // 与其他平滑器组合使用\n * const combined = new CombinedRadiusAwareSmoother(\n * new LineOfSightSmoother(),\n * { agentRadius: 0.5 }\n * );\n * ```\n */\nexport class RadiusAwarePathSmoother implements IPathSmoother {\n private readonly config: Required<IRadiusAwareSmootherConfig>;\n private readonly sampleAngles: number[];\n\n constructor(config: IRadiusAwareSmootherConfig) {\n this.config = {\n ...DEFAULT_CONFIG,\n ...config\n };\n\n // 预计算采样角度\n this.sampleAngles = [];\n const step = (Math.PI * 2) / this.config.sampleDirections;\n for (let i = 0; i < this.config.sampleDirections; i++) {\n this.sampleAngles.push(i * step);\n }\n }\n\n /**\n * @zh 平滑路径,确保与障碍物保持安全距离\n * @en Smooth path, ensuring safe distance from obstacles\n *\n * @param path - @zh 原始路径 @en Original path\n * @param map - @zh 地图 @en Map\n * @returns @zh 处理后的安全路径 @en Processed safe path\n */\n smooth(path: readonly IPoint[], map: IPathfindingMap): IPoint[] {\n if (path.length <= 1) {\n return [...path];\n }\n\n const result: IPoint[] = [];\n const clearance = this.config.agentRadius + this.config.safetyMargin;\n\n for (let i = 0; i < path.length; i++) {\n const point = path[i]!;\n const isCorner = this.config.processCorners && i > 0 && i < path.length - 1;\n\n let safePoint: IPoint;\n\n if (isCorner) {\n // 处理拐点\n const prev = path[i - 1]!;\n const next = path[i + 1]!;\n safePoint = this.offsetCornerPoint(point, prev, next, clearance, map);\n } else {\n // 处理普通点\n safePoint = this.offsetPointFromObstacles(point, clearance, map);\n }\n\n result.push(safePoint);\n }\n\n return result;\n }\n\n /**\n * @zh 将点从障碍物偏移\n * @en Offset point away from obstacles\n */\n private offsetPointFromObstacles(\n point: IPoint,\n clearance: number,\n map: IPathfindingMap\n ): IPoint {\n // 检测周围障碍物\n const obstacleDirections = this.detectNearbyObstacles(point, clearance, map);\n\n if (obstacleDirections.length === 0) {\n // 没有障碍物在范围内\n return point;\n }\n\n // 计算平均障碍物方向\n let avgDirX = 0;\n let avgDirY = 0;\n for (const dir of obstacleDirections) {\n avgDirX += dir.x;\n avgDirY += dir.y;\n }\n\n const len = Math.sqrt(avgDirX * avgDirX + avgDirY * avgDirY);\n if (len < 0.0001) {\n // 障碍物方向相互抵消,保持原位\n return point;\n }\n\n // 反方向偏移(远离障碍物)\n const offsetDirX = -avgDirX / len;\n const offsetDirY = -avgDirY / len;\n\n // 尝试不同的偏移距离\n for (let attempt = 1; attempt <= this.config.maxOffsetAttempts; attempt++) {\n const offsetDist = clearance * attempt / this.config.maxOffsetAttempts;\n const newX = point.x + offsetDirX * offsetDist;\n const newY = point.y + offsetDirY * offsetDist;\n\n if (map.isWalkable(Math.floor(newX), Math.floor(newY))) {\n // 检查新位置是否有足够的clearance\n const newObstacles = this.detectNearbyObstacles(\n createPoint(newX, newY),\n clearance,\n map\n );\n\n if (newObstacles.length === 0) {\n return createPoint(newX, newY);\n }\n }\n }\n\n // 无法找到更好的位置,返回原点\n return point;\n }\n\n /**\n * @zh 偏移拐点(角落)\n * @en Offset corner point\n */\n private offsetCornerPoint(\n corner: IPoint,\n prev: IPoint,\n next: IPoint,\n clearance: number,\n map: IPathfindingMap\n ): IPoint {\n // 计算进入方向和离开方向\n const inDirX = corner.x - prev.x;\n const inDirY = corner.y - prev.y;\n const inLen = Math.sqrt(inDirX * inDirX + inDirY * inDirY);\n\n const outDirX = next.x - corner.x;\n const outDirY = next.y - corner.y;\n const outLen = Math.sqrt(outDirX * outDirX + outDirY * outDirY);\n\n if (inLen < 0.0001 || outLen < 0.0001) {\n return this.offsetPointFromObstacles(corner, clearance, map);\n }\n\n // 标准化方向\n const inNormX = inDirX / inLen;\n const inNormY = inDirY / inLen;\n const outNormX = outDirX / outLen;\n const outNormY = outDirY / outLen;\n\n // 计算角平分线方向(指向角的内侧)\n // 角平分线 = 入射方向 + 出射方向的反方向\n const bisectX = inNormX - outNormX;\n const bisectY = inNormY - outNormY;\n const bisectLen = Math.sqrt(bisectX * bisectX + bisectY * bisectY);\n\n if (bisectLen < 0.0001) {\n // 直线,不需要特殊处理\n return this.offsetPointFromObstacles(corner, clearance, map);\n }\n\n // 标准化角平分线\n const bisectNormX = bisectX / bisectLen;\n const bisectNormY = bisectY / bisectLen;\n\n // 计算转角角度\n const dotProduct = inNormX * outNormX + inNormY * outNormY;\n const angle = Math.acos(Math.max(-1, Math.min(1, dotProduct)));\n\n // 计算需要的偏移距离\n // 在角落处,需要偏移 clearance / sin(angle/2) 才能保持与两边的距离\n const halfAngle = angle / 2;\n const sinHalfAngle = Math.sin(halfAngle);\n\n if (sinHalfAngle < 0.1) {\n // 角度太小(几乎是直线),使用普通偏移\n return this.offsetPointFromObstacles(corner, clearance, map);\n }\n\n const offsetDist = clearance / sinHalfAngle;\n\n // 限制最大偏移距离\n const maxOffset = clearance * 3;\n const actualOffset = Math.min(offsetDist, maxOffset);\n\n // 沿角平分线偏移\n const newX = corner.x + bisectNormX * actualOffset;\n const newY = corner.y + bisectNormY * actualOffset;\n\n // 验证新位置是否可行\n if (map.isWalkable(Math.floor(newX), Math.floor(newY))) {\n return createPoint(newX, newY);\n }\n\n // 如果角平分线方向不可行,尝试反方向\n const altX = corner.x - bisectNormX * actualOffset;\n const altY = corner.y - bisectNormY * actualOffset;\n\n if (map.isWalkable(Math.floor(altX), Math.floor(altY))) {\n return createPoint(altX, altY);\n }\n\n // 回退到普通偏移\n return this.offsetPointFromObstacles(corner, clearance, map);\n }\n\n /**\n * @zh 检测附近的障碍物方向\n * @en Detect nearby obstacle directions\n */\n private detectNearbyObstacles(\n point: IPoint,\n clearance: number,\n map: IPathfindingMap\n ): IPoint[] {\n const obstacles: IPoint[] = [];\n\n for (const angle of this.sampleAngles) {\n const dirX = Math.cos(angle);\n const dirY = Math.sin(angle);\n\n // 沿该方向采样\n const sampleX = point.x + dirX * clearance;\n const sampleY = point.y + dirY * clearance;\n\n if (!map.isWalkable(Math.floor(sampleX), Math.floor(sampleY))) {\n // 该方向有障碍物\n obstacles.push(createPoint(dirX, dirY));\n }\n }\n\n return obstacles;\n }\n}\n\n// =============================================================================\n// 组合平滑器 | Combined Smoother\n// =============================================================================\n\n/**\n * @zh 组合半径感知平滑器\n * @en Combined radius-aware smoother\n *\n * @zh 先使用其他平滑器(如 LOS、Catmull-Rom),再应用半径感知处理\n * @en First applies other smoother (like LOS, Catmull-Rom), then applies radius-aware processing\n *\n * @example\n * ```typescript\n * const smoother = new CombinedRadiusAwareSmoother(\n * new LineOfSightSmoother(),\n * { agentRadius: 0.5 }\n * );\n * const path = smoother.smooth(rawPath, map);\n * ```\n */\nexport class CombinedRadiusAwareSmoother implements IPathSmoother {\n private readonly baseSmoother: IPathSmoother;\n private readonly radiusAwareSmoother: RadiusAwarePathSmoother;\n\n constructor(\n baseSmoother: IPathSmoother,\n config: IRadiusAwareSmootherConfig\n ) {\n this.baseSmoother = baseSmoother;\n this.radiusAwareSmoother = new RadiusAwarePathSmoother(config);\n }\n\n smooth(path: readonly IPoint[], map: IPathfindingMap): IPoint[] {\n // 先用基础平滑器处理\n const smoothed = this.baseSmoother.smooth(path, map);\n\n // 再应用半径感知处理\n return this.radiusAwareSmoother.smooth(smoothed, map);\n }\n}\n\n// =============================================================================\n// 工厂函数 | Factory Functions\n// =============================================================================\n\n/**\n * @zh 创建半径感知平滑器\n * @en Create radius-aware smoother\n *\n * @param agentRadius - @zh 代理半径 @en Agent radius\n * @param options - @zh 额外配置 @en Additional options\n *\n * @example\n * ```typescript\n * const smoother = createRadiusAwareSmoother(0.5);\n * const safePath = smoother.smooth(path, map);\n * ```\n */\nexport function createRadiusAwareSmoother(\n agentRadius: number,\n options?: Omit<IRadiusAwareSmootherConfig, 'agentRadius'>\n): RadiusAwarePathSmoother {\n return new RadiusAwarePathSmoother({\n agentRadius,\n ...options\n });\n}\n\n/**\n * @zh 创建组合半径感知平滑器\n * @en Create combined radius-aware smoother\n *\n * @param baseSmoother - @zh 基础平滑器 @en Base smoother\n * @param agentRadius - @zh 代理半径 @en Agent radius\n * @param options - @zh 额外配置 @en Additional options\n *\n * @example\n * ```typescript\n * const smoother = createCombinedRadiusAwareSmoother(\n * new LineOfSightSmoother(),\n * 0.5\n * );\n * ```\n */\nexport function createCombinedRadiusAwareSmoother(\n baseSmoother: IPathSmoother,\n agentRadius: number,\n options?: Omit<IRadiusAwareSmootherConfig, 'agentRadius'>\n): CombinedRadiusAwareSmoother {\n return new CombinedRadiusAwareSmoother(baseSmoother, {\n agentRadius,\n ...options\n });\n}\n"],"mappings":"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","names":["CLOSED_FLAG","OPENED_FLAG","BACKWARD_CLOSED","BACKWARD_OPENED","GridState","width","height","bidirectional","size","g","f","flags","parent","heapIndex","version","currentVersion","gBack","fBack","parentBack","heapIndexBack","Float32Array","Uint8Array","Int32Array","Uint32Array","reset","fill","isInit","i","init","Infinity","getG","setG","v","getF","setF","getParent","setParent","getHeapIndex","setHeapIndex","isClosed","setClosed","isOpened","setOpened","getGBack","setGBack","getFBack","setFBack","getParentBack","setParentBack","getHeapIndexBack","setHeapIndexBack","isClosedBack","setClosedBack","isOpenedBack","setOpenedBack","_a","GridHeap","state","isBack","heap","length","isEmpty","push","bubbleUp","pop","result","last","sinkDown","update","pos","clear","idx","pp","pi","len","half","left","right","smallest","smallestF","lf","rf","si","GridPathfinder","map","config","mode","openList","openListBack","isBidir","findPath","startX","startY","endX","endY","options","findPathBidirectional","findPathUnidirectional","opts","DEFAULT_PATHFINDING_OPTIONS","validate","EMPTY_PATH_RESULT","startIdx","endIdx","found","path","x","y","cost","nodesSearched","hw","heuristicWeight","h0","heuristic","searched","maxNodes","allowDiagonal","avoidCorners","diagonalCost","nodes","dx","dy","dirCount","cur","buildPath","cx","cy","curG","d","nx","ny","neighbor","walkable","ni","isDiag","tentG","h","startPos","endPos","hf","hb","meetIdx","bestCost","total","buildPathBidirectional","isWalkable","w","reverse","createGridPathfinder","PathValidator","validatePath","path","fromIndex","toIndex","map","end","Math","min","length","i","point","x","floor","y","isWalkable","valid","invalidIndex","prev","checkLineOfSight","x1","y1","x2","y2","ix1","iy1","ix2","iy2","dx","abs","dy","sx","sy","err","ObstacleChangeManager","changes","Map","epoch","recordChange","wasWalkable","key","set","timestamp","Date","now","getAffectedRegion","size","minX","Infinity","minY","maxX","maxY","change","values","max","getChanges","Array","from","hasChanges","getEpoch","flush","clear","createPathValidator","createObstacleChangeManager","GridNode","x","y","width","walkable","cost","id","position","createPoint","DIRECTIONS_4","dx","dy","DIRECTIONS_8","DEFAULT_GRID_OPTIONS","allowDiagonal","diagonalCost","Math","SQRT2","avoidCorners","heuristic","octileDistance","GridMap","height","options","nodes","createNodes","getNodeAt","isInBounds","isWalkable","node","setWalkable","setCost","getNeighbors","neighbors","directions","i","length","dir","nx","ny","neighbor","hNode","vNode","push","forEachNeighbor","callback","a","b","getMovementCost","from","to","abs","loadFromArray","data","min","loadFromString","str","lines","trim","split","line","toString","result","reset","setRectWalkable","createGridMap","_a","NavMeshNode","polygon","id","position","cost","walkable","center","NavMesh","polygons","Map","nodes","nextId","obstacles","nextObstacleId","disabledPolygons","Set","addPolygon","vertices","neighbors","calculateCenter","portals","set","setConnection","polyA","polyB","portal","polygonA","get","polygonB","neighborsA","portalsA","includes","push","reversePortal","left","right","neighborsB","portalsB","build","polygonList","Array","from","values","i","length","j","sharedEdge","findSharedEdge","verticesA","verticesB","epsilon","a1","a2","b1","b2","match1","Math","abs","x","y","match2","v","createPoint","findPolygonAt","isPointInPolygon","inside","n","xi","yi","xj","yj","getNodeAt","getNeighbors","node","navNode","neighborId","neighbor","heuristic","a","b","euclideanDistance","getMovementCost","to","isWalkable","findPath","startX","startY","endX","endY","options","opts","DEFAULT_PATHFINDING_OPTIONS","startPolygon","endPolygon","EMPTY_PATH_RESULT","found","path","nodesSearched","polygonPath","findPolygonPath","start","end","pointPath","funnelPath","agentRadius","calculatePathLength","checkObstacles","openList","BinaryHeap","f","closed","states","startState","g","heuristicWeight","parent","isEmpty","maxNodes","current","pop","state","unshift","add","has","isPolygonBlocked","neighborPolygon","neighborState","update","shrunk","shrinkPortal","originalLeft","originalRight","apex","apexOriginal","leftIndex","rightIndex","leftOriginal","rightOriginal","nextLeft","nextRight","triArea2","pointsEqual","turnPoint","offsetTurningPoint","radius","dx","dy","len","sqrt","cx","cy","nx","ny","prevApex","cornerOriginal","cornerShrunk","side","perpX","perpY","c","addCircleObstacle","type","enabled","addRectObstacle","halfWidth","halfHeight","addPolygonObstacle","removeObstacle","obstacleId","delete","setObstacleEnabled","obstacle","updateObstaclePosition","getObstacles","getEnabledObstacles","filter","o","clearObstacles","clear","disablePolygon","polygonId","enablePolygon","isPolygonDisabled","disablePolygonAt","clearDisabledPolygons","getDisabledPolygons","isPointInObstacle","isPointInSingleObstacle","hw","hh","doesLineIntersectObstacle","x1","y1","x2","y2","doesLineIntersectSingleObstacle","lineIntersectsCircle","minX","maxX","minY","maxY","lineIntersectsRect","lineIntersectsPolygon","r","fx","fy","discriminant","t1","t2","lineSegmentsIntersect","x3","y3","x4","y4","d1","direction","d2","d3","d4","onSegment","min","max","vertex","v1","v2","findPathWithObstacles","getPolygons","polygonCount","size","obstacleCount","createNavMesh","bresenhamLineOfSight","x1","y1","x2","y2","map","ix1","Math","floor","iy1","ix2","iy2","dx","abs","dy","sx","sy","err","isWalkable","e2","raycastLineOfSight","stepSize","distance","sqrt","steps","ceil","stepX","stepY","x","y","i","LineOfSightSmoother","lineOfSight","smooth","path","length","result","current","furthest","push","CatmullRomSmoother","segments","tension","_map","points","p0","p1","p2","p3","j","t","point","interpolate","t2","t3","createPoint","CombinedSmoother","curveSegments","simplifier","curveSmoother","simplified","createLineOfSightSmoother","createCatmullRomSmoother","createCombinedSmoother","DEFAULT_CONFIG","safetyMargin","sampleDirections","maxOffsetAttempts","processCorners","RadiusAwarePathSmoother","config","sampleAngles","step","Math","PI","i","push","smooth","path","map","length","result","clearance","agentRadius","point","isCorner","safePoint","prev","next","offsetCornerPoint","offsetPointFromObstacles","obstacleDirections","detectNearbyObstacles","avgDirX","avgDirY","dir","x","y","len","sqrt","offsetDirX","offsetDirY","attempt","offsetDist","newX","newY","isWalkable","floor","newObstacles","createPoint","corner","inDirX","inDirY","inLen","outDirX","outDirY","outLen","inNormX","inNormY","outNormX","outNormY","bisectX","bisectY","bisectLen","bisectNormX","bisectNormY","dotProduct","angle","acos","max","min","halfAngle","sinHalfAngle","sin","maxOffset","actualOffset","altX","altY","obstacles","dirX","cos","dirY","sampleX","sampleY","CombinedRadiusAwareSmoother","baseSmoother","radiusAwareSmoother","smoothed","createRadiusAwareSmoother","options","createCombinedRadiusAwareSmoother"]}