@esengine/pathfinding 13.2.0 → 13.3.1
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/{KDTree-2rs2EXvm.d.ts → CollisionResolver-CSgWsegP.d.ts} +122 -86
- package/dist/FlowController-BztOzQsW.d.ts +2781 -0
- package/dist/KDTree-BRpn7O8K.d.ts +216 -0
- package/dist/avoidance.d.ts +26 -4
- package/dist/avoidance.js +10 -2
- package/dist/{chunk-JTZP55BJ.js → chunk-3VEX32JO.js} +385 -9
- package/dist/chunk-3VEX32JO.js.map +1 -0
- package/dist/chunk-H5EFZBBT.js +1 -0
- package/dist/chunk-ZYGBA7VK.js +3831 -0
- package/dist/chunk-ZYGBA7VK.js.map +1 -0
- package/dist/ecs.d.ts +440 -647
- package/dist/ecs.js +1020 -1399
- package/dist/ecs.js.map +1 -1
- package/dist/index.d.ts +158 -711
- package/dist/index.js +1353 -1739
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
- package/dist/IIncrementalPathfinding-3qs7e_pO.d.ts +0 -450
- package/dist/LinearProgram-DyD3pI6v.d.ts +0 -56
- package/dist/chunk-JTZP55BJ.js.map +0 -1
- package/dist/chunk-KEYTX37K.js +0 -1
- package/dist/chunk-VNC2YAAL.js +0 -1650
- package/dist/chunk-VNC2YAAL.js.map +0 -1
- /package/dist/{chunk-KEYTX37K.js.map → chunk-H5EFZBBT.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/IPathfinding.ts","../src/core/BinaryHeap.ts","../src/core/IndexedBinaryHeap.ts","../src/core/AStarPathfinder.ts","../src/core/PathCache.ts","../src/core/IncrementalAStarPathfinder.ts","../src/core/JPSPathfinder.ts","../src/core/HPAPathfinder.ts","../src/interfaces/IPathPlanner.ts","../src/interfaces/ICollisionResolver.ts","../src/interfaces/IFlowController.ts","../src/adapters/NavMeshPathPlannerAdapter.ts","../src/adapters/GridPathfinderAdapter.ts","../src/adapters/IncrementalGridPathPlannerAdapter.ts","../src/adapters/ORCALocalAvoidanceAdapter.ts","../src/adapters/CollisionResolverAdapter.ts","../src/adapters/FlowController.ts"],"sourcesContent":["/**\n * @zh 寻路系统核心接口\n * @en Pathfinding System Core Interfaces\n */\n\n// =============================================================================\n// 基础类型 | Basic Types\n// =============================================================================\n\n/**\n * @zh 2D 坐标点\n * @en 2D coordinate point\n */\nexport interface IPoint {\n readonly x: number;\n readonly y: number;\n}\n\n/**\n * @zh 创建点\n * @en Create a point\n */\nexport function createPoint(x: number, y: number): IPoint {\n return { x, y };\n}\n\n/**\n * @zh 路径节点\n * @en Path node\n */\nexport interface IPathNode {\n /** @zh 节点唯一标识 @en Unique node identifier */\n readonly id: string | number;\n /** @zh 节点位置 @en Node position */\n readonly position: IPoint;\n /** @zh 移动代价 @en Movement cost */\n readonly cost: number;\n /** @zh 是否可通行 @en Is walkable */\n readonly walkable: boolean;\n}\n\n/**\n * @zh 路径结果\n * @en Path result\n */\nexport interface IPathResult {\n /** @zh 是否找到路径 @en Whether path was found */\n readonly found: boolean;\n /** @zh 路径点列表 @en List of path points */\n readonly path: readonly IPoint[];\n /** @zh 路径总代价 @en Total path cost */\n readonly cost: number;\n /** @zh 搜索的节点数 @en Number of nodes searched */\n readonly nodesSearched: number;\n}\n\n/**\n * @zh 空路径结果\n * @en Empty path result\n */\nexport const EMPTY_PATH_RESULT: IPathResult = {\n found: false,\n path: [],\n cost: 0,\n nodesSearched: 0\n};\n\n// =============================================================================\n// 地图接口 | Map Interface\n// =============================================================================\n\n/**\n * @zh 寻路地图接口\n * @en Pathfinding map interface\n */\nexport interface IPathfindingMap {\n /**\n * @zh 获取节点的邻居\n * @en Get neighbors of a node\n */\n getNeighbors(node: IPathNode): IPathNode[];\n\n /**\n * @zh 获取指定位置的节点\n * @en Get node at position\n */\n getNodeAt(x: number, y: number): IPathNode | null;\n\n /**\n * @zh 计算两点间的启发式距离\n * @en Calculate heuristic distance between two points\n */\n heuristic(a: IPoint, b: IPoint): number;\n\n /**\n * @zh 计算两个邻居节点间的移动代价\n * @en Calculate movement cost between two neighbor nodes\n */\n getMovementCost(from: IPathNode, to: IPathNode): number;\n\n /**\n * @zh 检查位置是否可通行\n * @en Check if position is walkable\n */\n isWalkable(x: number, y: number): boolean;\n}\n\n// =============================================================================\n// 启发式函数 | Heuristic Functions\n// =============================================================================\n\n/**\n * @zh 启发式函数类型\n * @en Heuristic function type\n */\nexport type HeuristicFunction = (a: IPoint, b: IPoint) => number;\n\n/**\n * @zh 曼哈顿距离(4方向移动)\n * @en Manhattan distance (4-directional movement)\n */\nexport function manhattanDistance(a: IPoint, b: IPoint): number {\n return Math.abs(a.x - b.x) + Math.abs(a.y - b.y);\n}\n\n/**\n * @zh 欧几里得距离(任意方向移动)\n * @en Euclidean distance (any direction movement)\n */\nexport function euclideanDistance(a: IPoint, b: IPoint): number {\n const dx = a.x - b.x;\n const dy = a.y - b.y;\n return Math.sqrt(dx * dx + dy * dy);\n}\n\n/**\n * @zh 切比雪夫距离(8方向移动)\n * @en Chebyshev distance (8-directional movement)\n */\nexport function chebyshevDistance(a: IPoint, b: IPoint): number {\n return Math.max(Math.abs(a.x - b.x), Math.abs(a.y - b.y));\n}\n\n/**\n * @zh 八角距离(8方向移动,对角线代价为 √2)\n * @en Octile distance (8-directional, diagonal cost √2)\n */\nexport function octileDistance(a: IPoint, b: IPoint): number {\n const dx = Math.abs(a.x - b.x);\n const dy = Math.abs(a.y - b.y);\n const D = 1;\n const D2 = Math.SQRT2;\n return D * (dx + dy) + (D2 - 2 * D) * Math.min(dx, dy);\n}\n\n// =============================================================================\n// 寻路器接口 | Pathfinder Interface\n// =============================================================================\n\n/**\n * @zh 寻路配置\n * @en Pathfinding options\n */\nexport interface IPathfindingOptions {\n /** @zh 最大搜索节点数 @en Maximum nodes to search */\n maxNodes?: number;\n /** @zh 启发式权重 (>1 更快但可能非最优) @en Heuristic weight (>1 faster but may be suboptimal) */\n heuristicWeight?: number;\n /** @zh 是否允许对角移动 @en Allow diagonal movement */\n allowDiagonal?: boolean;\n /** @zh 是否避免穿角 @en Avoid corner cutting */\n avoidCorners?: boolean;\n /**\n * @zh 代理半径,用于生成考虑碰撞体积的路径\n * @en Agent radius, used to generate paths that consider collision volume\n *\n * @zh 如果指定,路径规划器会收缩 portal 宽度并偏移拐点,确保路径与障碍物保持足够距离\n * @en If specified, the path planner will shrink portal widths and offset turning points to ensure sufficient clearance from obstacles\n */\n agentRadius?: number;\n}\n\n/**\n * @zh 默认寻路配置\n * @en Default pathfinding options\n */\nexport const DEFAULT_PATHFINDING_OPTIONS: Required<IPathfindingOptions> = {\n maxNodes: 10000,\n heuristicWeight: 1.0,\n allowDiagonal: true,\n avoidCorners: true,\n agentRadius: 0\n};\n\n/**\n * @zh 寻路器接口\n * @en Pathfinder interface\n */\nexport interface IPathfinder {\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\n /**\n * @zh 清理状态(用于重用)\n * @en Clear state (for reuse)\n */\n clear(): void;\n}\n\n// =============================================================================\n// 路径平滑接口 | Path Smoothing Interface\n// =============================================================================\n\n/**\n * @zh 路径平滑器接口\n * @en Path smoother interface\n */\nexport interface IPathSmoother {\n /**\n * @zh 平滑路径\n * @en Smooth path\n */\n smooth(path: readonly IPoint[], map: IPathfindingMap): IPoint[];\n}\n\n/**\n * @zh 视线检测函数类型\n * @en Line of sight check function type\n */\nexport type LineOfSightCheck = (\n x1: number,\n y1: number,\n x2: number,\n y2: number,\n map: IPathfindingMap\n) => boolean;\n","/**\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 带索引追踪的二叉堆(优先队列)\n * @en Indexed Binary Heap (Priority Queue) with index tracking\n */\n\n/**\n * @zh 可索引的堆元素接口\n * @en Interface for indexable heap elements\n */\nexport interface IHeapIndexable {\n /** @zh 堆中的索引位置 @en Index position in heap */\n heapIndex: number;\n}\n\n/**\n * @zh 带索引追踪的二叉堆\n * @en Binary Heap with index tracking\n */\nexport class IndexedBinaryHeap<T extends IHeapIndexable> {\n private heap: T[] = [];\n private readonly compare: (a: T, b: T) => number;\n\n /**\n * @zh 创建带索引追踪的二叉堆\n * @en Create indexed 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 item.heapIndex = this.heap.length;\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 result.heapIndex = -1;\n\n const last = this.heap.pop()!;\n\n if (this.heap.length > 0) {\n last.heapIndex = 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\n */\n update(item: T): void {\n const index = item.heapIndex;\n if (index >= 0 && index < this.heap.length && this.heap[index] === item) {\n this.bubbleUp(index);\n this.sinkDown(item.heapIndex);\n }\n }\n\n /**\n * @zh 检查是否包含元素\n * @en Check if contains element\n */\n contains(item: T): boolean {\n const index = item.heapIndex;\n return index >= 0 && index < this.heap.length && this.heap[index] === item;\n }\n\n /**\n * @zh 从堆中移除指定元素\n * @en Remove specific element from heap\n */\n remove(item: T): boolean {\n const index = item.heapIndex;\n if (index < 0 || index >= this.heap.length || this.heap[index] !== item) {\n return false;\n }\n\n item.heapIndex = -1;\n\n if (index === this.heap.length - 1) {\n this.heap.pop();\n return true;\n }\n\n const last = this.heap.pop()!;\n last.heapIndex = index;\n this.heap[index] = last;\n this.bubbleUp(index);\n this.sinkDown(last.heapIndex);\n\n return true;\n }\n\n /**\n * @zh 清空堆\n * @en Clear heap\n */\n clear(): void {\n for (const item of this.heap) {\n item.heapIndex = -1;\n }\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 = (index - 1) >> 1;\n const parent = this.heap[parentIndex];\n\n if (this.compare(item, parent) >= 0) {\n break;\n }\n\n parent.heapIndex = index;\n this.heap[index] = parent;\n index = parentIndex;\n }\n\n item.heapIndex = index;\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 const halfLength = length >> 1;\n\n while (index < halfLength) {\n const leftIndex = (index << 1) + 1;\n const rightIndex = leftIndex + 1;\n let smallest = index;\n let smallestItem = item;\n\n const left = this.heap[leftIndex];\n if (this.compare(left, smallestItem) < 0) {\n smallest = leftIndex;\n smallestItem = left;\n }\n\n if (rightIndex < length) {\n const right = this.heap[rightIndex];\n if (this.compare(right, smallestItem) < 0) {\n smallest = rightIndex;\n smallestItem = right;\n }\n }\n\n if (smallest === index) {\n break;\n }\n\n smallestItem.heapIndex = index;\n this.heap[index] = smallestItem;\n index = smallest;\n }\n\n item.heapIndex = index;\n this.heap[index] = item;\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 Path Cache Module\n *\n * @zh 缓存已计算的路径,避免重复计算相同起点终点的路径\n * @en Cache computed paths to avoid recalculating paths with the same start and end points\n */\n\nimport type { IPoint, IPathResult } from './IPathfinding';\n\n// =============================================================================\n// 内部类型 | Internal Types\n// =============================================================================\n\n/**\n * @zh 缓存条目\n * @en Cache entry\n */\ninterface ICacheEntry {\n result: IPathResult;\n timestamp: number;\n mapVersion: number;\n}\n\n/**\n * @zh 缓存配置\n * @en Cache configuration\n */\nexport interface IPathCacheConfig {\n /**\n * @zh 最大缓存条目数\n * @en Maximum number of cache entries\n */\n maxEntries: number;\n\n /**\n * @zh 缓存过期时间(毫秒),0 表示不过期\n * @en Cache expiration time in milliseconds, 0 means no expiration\n */\n ttlMs: number;\n\n /**\n * @zh 是否启用近似匹配(在一定范围内的起点/终点视为相同)\n * @en Whether to enable approximate matching (start/end within range considered same)\n */\n enableApproximateMatch: boolean;\n\n /**\n * @zh 近似匹配范围\n * @en Approximate matching range\n */\n approximateRange: number;\n}\n\n/**\n * @zh 默认缓存配置\n * @en Default cache configuration\n */\nexport const DEFAULT_PATH_CACHE_CONFIG: IPathCacheConfig = {\n maxEntries: 1000,\n ttlMs: 5000,\n enableApproximateMatch: false,\n approximateRange: 2\n};\n\n// =============================================================================\n// 路径缓存 | Path Cache\n// =============================================================================\n\n/**\n * @zh 路径缓存\n * @en Path Cache\n *\n * @zh 缓存已计算的路径,支持 LRU 淘汰策略和 TTL 过期\n * @en Cache computed paths with LRU eviction and TTL expiration\n *\n * @example\n * ```typescript\n * const cache = new PathCache({ maxEntries: 500 });\n * const cached = cache.get(0, 0, 10, 10, mapVersion);\n * if (!cached) {\n * const result = pathfinder.findPath(0, 0, 10, 10);\n * cache.set(0, 0, 10, 10, result, mapVersion);\n * }\n * ```\n */\nexport class PathCache {\n private readonly config: IPathCacheConfig;\n private readonly cache: Map<string, ICacheEntry>;\n private readonly accessOrder: string[];\n\n constructor(config: Partial<IPathCacheConfig> = {}) {\n this.config = { ...DEFAULT_PATH_CACHE_CONFIG, ...config };\n this.cache = new Map();\n this.accessOrder = [];\n }\n\n /**\n * @zh 获取缓存的路径\n * @en Get cached path\n *\n * @param startX - @zh 起点 X 坐标 @en Start X coordinate\n * @param startY - @zh 起点 Y 坐标 @en Start Y coordinate\n * @param endX - @zh 终点 X 坐标 @en End X coordinate\n * @param endY - @zh 终点 Y 坐标 @en End Y coordinate\n * @param mapVersion - @zh 地图版本号 @en Map version number\n * @returns @zh 缓存的路径结果或 null @en Cached path result or null\n */\n get(\n startX: number,\n startY: number,\n endX: number,\n endY: number,\n mapVersion: number\n ): IPathResult | null {\n const key = this.generateKey(startX, startY, endX, endY);\n const entry = this.cache.get(key);\n\n if (!entry) {\n if (this.config.enableApproximateMatch) {\n return this.getApproximate(startX, startY, endX, endY, mapVersion);\n }\n return null;\n }\n\n if (!this.isValid(entry, mapVersion)) {\n this.cache.delete(key);\n this.removeFromAccessOrder(key);\n return null;\n }\n\n this.updateAccessOrder(key);\n return entry.result;\n }\n\n /**\n * @zh 设置缓存路径\n * @en Set cached path\n *\n * @param startX - @zh 起点 X 坐标 @en Start X coordinate\n * @param startY - @zh 起点 Y 坐标 @en Start Y coordinate\n * @param endX - @zh 终点 X 坐标 @en End X coordinate\n * @param endY - @zh 终点 Y 坐标 @en End Y coordinate\n * @param result - @zh 路径结果 @en Path result\n * @param mapVersion - @zh 地图版本号 @en Map version number\n */\n set(\n startX: number,\n startY: number,\n endX: number,\n endY: number,\n result: IPathResult,\n mapVersion: number\n ): void {\n if (this.cache.size >= this.config.maxEntries) {\n this.evictLRU();\n }\n\n const key = this.generateKey(startX, startY, endX, endY);\n const entry: ICacheEntry = {\n result,\n timestamp: Date.now(),\n mapVersion\n };\n\n this.cache.set(key, entry);\n this.updateAccessOrder(key);\n }\n\n /**\n * @zh 使所有缓存失效\n * @en Invalidate all cache\n */\n invalidateAll(): void {\n this.cache.clear();\n this.accessOrder.length = 0;\n }\n\n /**\n * @zh 使指定区域的缓存失效\n * @en Invalidate cache for specified region\n *\n * @param minX - @zh 最小 X 坐标 @en Minimum X coordinate\n * @param minY - @zh 最小 Y 坐标 @en Minimum Y coordinate\n * @param maxX - @zh 最大 X 坐标 @en Maximum X coordinate\n * @param maxY - @zh 最大 Y 坐标 @en Maximum Y coordinate\n */\n invalidateRegion(minX: number, minY: number, maxX: number, maxY: number): void {\n const keysToDelete: string[] = [];\n\n for (const [key, entry] of this.cache) {\n const path = entry.result.path;\n if (path.length === 0) continue;\n\n for (const point of path) {\n if (point.x >= minX && point.x <= maxX &&\n point.y >= minY && point.y <= maxY) {\n keysToDelete.push(key);\n break;\n }\n }\n }\n\n for (const key of keysToDelete) {\n this.cache.delete(key);\n this.removeFromAccessOrder(key);\n }\n }\n\n /**\n * @zh 获取缓存统计信息\n * @en Get cache statistics\n */\n getStats(): { size: number; maxSize: number; hitRate?: number } {\n return {\n size: this.cache.size,\n maxSize: this.config.maxEntries\n };\n }\n\n /**\n * @zh 清理过期条目\n * @en Clean up expired entries\n */\n cleanup(): void {\n if (this.config.ttlMs === 0) return;\n\n const now = Date.now();\n const keysToDelete: string[] = [];\n\n for (const [key, entry] of this.cache) {\n if (now - entry.timestamp > this.config.ttlMs) {\n keysToDelete.push(key);\n }\n }\n\n for (const key of keysToDelete) {\n this.cache.delete(key);\n this.removeFromAccessOrder(key);\n }\n }\n\n // =========================================================================\n // 私有方法 | Private Methods\n // =========================================================================\n\n private generateKey(startX: number, startY: number, endX: number, endY: number): string {\n return `${startX},${startY}->${endX},${endY}`;\n }\n\n private isValid(entry: ICacheEntry, mapVersion: number): boolean {\n if (entry.mapVersion !== mapVersion) {\n return false;\n }\n\n if (this.config.ttlMs > 0) {\n const age = Date.now() - entry.timestamp;\n if (age > this.config.ttlMs) {\n return false;\n }\n }\n\n return true;\n }\n\n private getApproximate(\n startX: number,\n startY: number,\n endX: number,\n endY: number,\n mapVersion: number\n ): IPathResult | null {\n const range = this.config.approximateRange;\n\n for (let sx = startX - range; sx <= startX + range; sx++) {\n for (let sy = startY - range; sy <= startY + range; sy++) {\n for (let ex = endX - range; ex <= endX + range; ex++) {\n for (let ey = endY - range; ey <= endY + range; ey++) {\n const key = this.generateKey(sx, sy, ex, ey);\n const entry = this.cache.get(key);\n if (entry && this.isValid(entry, mapVersion)) {\n this.updateAccessOrder(key);\n return this.adjustPathForApproximate(\n entry.result,\n startX, startY, endX, endY\n );\n }\n }\n }\n }\n }\n\n return null;\n }\n\n private adjustPathForApproximate(\n result: IPathResult,\n newStartX: number,\n newStartY: number,\n newEndX: number,\n newEndY: number\n ): IPathResult {\n if (result.path.length === 0) {\n return result;\n }\n\n const newPath: IPoint[] = [];\n const oldStart = result.path[0];\n const oldEnd = result.path[result.path.length - 1];\n\n if (newStartX !== oldStart.x || newStartY !== oldStart.y) {\n newPath.push({ x: newStartX, y: newStartY });\n }\n\n newPath.push(...result.path);\n\n if (newEndX !== oldEnd.x || newEndY !== oldEnd.y) {\n newPath.push({ x: newEndX, y: newEndY });\n }\n\n return {\n ...result,\n path: newPath\n };\n }\n\n private updateAccessOrder(key: string): void {\n this.removeFromAccessOrder(key);\n this.accessOrder.push(key);\n }\n\n private removeFromAccessOrder(key: string): void {\n const index = this.accessOrder.indexOf(key);\n if (index !== -1) {\n this.accessOrder.splice(index, 1);\n }\n }\n\n private evictLRU(): void {\n const lruKey = this.accessOrder.shift();\n if (lruKey) {\n this.cache.delete(lruKey);\n }\n }\n}\n\n// =============================================================================\n// 工厂函数 | Factory Function\n// =============================================================================\n\n/**\n * @zh 创建路径缓存\n * @en Create path cache\n *\n * @param config - @zh 缓存配置 @en Cache configuration\n * @returns @zh 路径缓存实例 @en Path cache instance\n */\nexport function createPathCache(config?: Partial<IPathCacheConfig>): PathCache {\n return new PathCache(config);\n}\n","/**\n * @zh 增量 A* 寻路算法实现\n * @en Incremental A* Pathfinding Algorithm Implementation\n */\n\nimport { IndexedBinaryHeap, type IHeapIndexable } from './IndexedBinaryHeap';\nimport type {\n IPathfindingMap,\n IPathNode,\n IPoint,\n IPathfindingOptions\n} from './IPathfinding';\nimport { DEFAULT_PATHFINDING_OPTIONS } from './IPathfinding';\nimport type {\n IIncrementalPathfinder,\n IPathRequest,\n IPathProgress,\n IIncrementalPathResult,\n IIncrementalPathfindingOptions\n} from './IIncrementalPathfinding';\nimport { PathfindingState, EMPTY_PROGRESS } from './IIncrementalPathfinding';\nimport { PathCache, type IPathCacheConfig } from './PathCache';\n\n// =============================================================================\n// 内部类型 | Internal Types\n// =============================================================================\n\n/**\n * @zh A* 节点(内部使用)\n * @en A* Node (internal use)\n */\ninterface AStarNode extends IHeapIndexable {\n node: IPathNode;\n g: number;\n h: number;\n f: number;\n parent: AStarNode | null;\n closed: boolean;\n opened: boolean;\n heapIndex: number;\n}\n\n/**\n * @zh 寻路会话(保存跨帧状态)\n * @en Pathfinding session (preserves state across frames)\n */\ninterface PathfindingSession {\n request: IPathRequest;\n state: PathfindingState;\n options: Required<IPathfindingOptions>;\n\n openList: IndexedBinaryHeap<AStarNode>;\n nodeCache: Map<string | number, AStarNode>;\n\n startNode: IPathNode;\n endNode: IPathNode;\n endPosition: IPoint;\n\n nodesSearched: number;\n framesUsed: number;\n initialDistance: number;\n\n result: IIncrementalPathResult | null;\n\n affectedByChange: boolean;\n}\n\n/**\n * @zh 障碍物变化区域\n * @en Obstacle change region\n */\ninterface ChangeRegion {\n minX: number;\n minY: number;\n maxX: number;\n maxY: number;\n timestamp: number;\n}\n\n/**\n * @zh 增量寻路器配置\n * @en Incremental pathfinder configuration\n */\nexport interface IIncrementalPathfinderConfig {\n /**\n * @zh 是否启用路径缓存\n * @en Whether to enable path caching\n */\n enableCache?: boolean;\n\n /**\n * @zh 缓存配置\n * @en Cache configuration\n */\n cacheConfig?: Partial<IPathCacheConfig>;\n}\n\n// =============================================================================\n// 增量 A* 寻路器 | Incremental A* Pathfinder\n// =============================================================================\n\n/**\n * @zh 增量 A* 寻路器\n * @en Incremental A* Pathfinder\n *\n * @zh 支持时间切片的 A* 算法实现,可跨多帧执行搜索\n * @en A* algorithm implementation with time slicing, can execute search across multiple frames\n *\n * @example\n * ```typescript\n * const map = createGridMap(100, 100);\n * const pathfinder = createIncrementalAStarPathfinder(map);\n *\n * // Request path (non-blocking)\n * const request = pathfinder.requestPath(0, 0, 99, 99);\n *\n * // Process over multiple frames\n * function gameLoop() {\n * const progress = pathfinder.step(request.id, 100);\n *\n * if (progress.state === PathfindingState.Completed) {\n * const result = pathfinder.getResult(request.id);\n * console.log('Path found:', result?.path);\n * } else if (progress.state === PathfindingState.InProgress) {\n * requestAnimationFrame(gameLoop);\n * }\n * }\n * gameLoop();\n * ```\n */\nexport class IncrementalAStarPathfinder implements IIncrementalPathfinder {\n private readonly map: IPathfindingMap;\n private readonly sessions: Map<number, PathfindingSession> = new Map();\n private nextRequestId: number = 0;\n\n private readonly affectedRegions: ChangeRegion[] = [];\n private readonly maxRegionAge: number = 5000;\n\n private readonly cache: PathCache | null;\n private readonly enableCache: boolean;\n private mapVersion: number = 0;\n\n private cacheHits: number = 0;\n private cacheMisses: number = 0;\n\n /**\n * @zh 创建增量 A* 寻路器\n * @en Create incremental A* pathfinder\n *\n * @param map - @zh 寻路地图实例 @en Pathfinding map instance\n * @param config - @zh 配置选项 @en Configuration options\n */\n constructor(map: IPathfindingMap, config?: IIncrementalPathfinderConfig) {\n this.map = map;\n this.enableCache = config?.enableCache ?? false;\n this.cache = this.enableCache ? new PathCache(config?.cacheConfig) : null;\n }\n\n /**\n * @zh 请求寻路(非阻塞)\n * @en Request pathfinding (non-blocking)\n */\n requestPath(\n startX: number,\n startY: number,\n endX: number,\n endY: number,\n options?: IIncrementalPathfindingOptions\n ): IPathRequest {\n const id = this.nextRequestId++;\n const priority = options?.priority ?? 50;\n const opts = { ...DEFAULT_PATHFINDING_OPTIONS, ...options };\n\n const request: IPathRequest = {\n id,\n startX,\n startY,\n endX,\n endY,\n options: opts,\n priority,\n createdAt: Date.now()\n };\n\n if (this.cache) {\n const cached = this.cache.get(startX, startY, endX, endY, this.mapVersion);\n if (cached) {\n this.cacheHits++;\n const session: PathfindingSession = {\n request,\n state: cached.found ? PathfindingState.Completed : PathfindingState.Failed,\n options: opts,\n openList: new IndexedBinaryHeap<AStarNode>((a, b) => a.f - b.f),\n nodeCache: new Map(),\n startNode: this.map.getNodeAt(startX, startY)!,\n endNode: this.map.getNodeAt(endX, endY)!,\n endPosition: { x: endX, y: endY },\n nodesSearched: cached.nodesSearched,\n framesUsed: 0,\n initialDistance: 0,\n result: {\n requestId: id,\n found: cached.found,\n path: [...cached.path],\n cost: cached.cost,\n nodesSearched: cached.nodesSearched,\n framesUsed: 0,\n isPartial: false\n },\n affectedByChange: false\n };\n this.sessions.set(id, session);\n return request;\n }\n this.cacheMisses++;\n }\n\n const startNode = this.map.getNodeAt(startX, startY);\n const endNode = this.map.getNodeAt(endX, endY);\n\n if (!startNode || !endNode || !startNode.walkable || !endNode.walkable) {\n const session: PathfindingSession = {\n request,\n state: PathfindingState.Failed,\n options: opts,\n openList: new IndexedBinaryHeap<AStarNode>((a, b) => a.f - b.f),\n nodeCache: new Map(),\n startNode: startNode!,\n endNode: endNode!,\n endPosition: endNode?.position ?? { x: endX, y: endY },\n nodesSearched: 0,\n framesUsed: 0,\n initialDistance: 0,\n result: this.createEmptyResult(id),\n affectedByChange: false\n };\n this.sessions.set(id, session);\n return request;\n }\n\n if (startNode.id === endNode.id) {\n const session: PathfindingSession = {\n request,\n state: PathfindingState.Completed,\n options: opts,\n openList: new IndexedBinaryHeap<AStarNode>((a, b) => a.f - b.f),\n nodeCache: new Map(),\n startNode,\n endNode,\n endPosition: endNode.position,\n nodesSearched: 1,\n framesUsed: 0,\n initialDistance: 0,\n result: {\n requestId: id,\n found: true,\n path: [startNode.position],\n cost: 0,\n nodesSearched: 1,\n framesUsed: 0,\n isPartial: false\n },\n affectedByChange: false\n };\n this.sessions.set(id, session);\n return request;\n }\n\n const initialDistance = this.map.heuristic(startNode.position, endNode.position);\n const openList = new IndexedBinaryHeap<AStarNode>((a, b) => a.f - b.f);\n const nodeCache = new Map<string | number, AStarNode>();\n\n const startAStarNode: AStarNode = {\n node: startNode,\n g: 0,\n h: initialDistance * opts.heuristicWeight,\n f: initialDistance * opts.heuristicWeight,\n parent: null,\n closed: false,\n opened: true,\n heapIndex: -1\n };\n\n nodeCache.set(startNode.id, startAStarNode);\n openList.push(startAStarNode);\n\n const session: PathfindingSession = {\n request,\n state: PathfindingState.InProgress,\n options: opts,\n openList,\n nodeCache,\n startNode,\n endNode,\n endPosition: endNode.position,\n nodesSearched: 0,\n framesUsed: 0,\n initialDistance,\n result: null,\n affectedByChange: false\n };\n\n this.sessions.set(id, session);\n return request;\n }\n\n /**\n * @zh 执行一步搜索\n * @en Execute one step of search\n */\n step(requestId: number, maxIterations: number): IPathProgress {\n const session = this.sessions.get(requestId);\n if (!session) {\n return EMPTY_PROGRESS;\n }\n\n if (session.state !== PathfindingState.InProgress) {\n return this.createProgress(session);\n }\n\n session.framesUsed++;\n let iterations = 0;\n\n while (!session.openList.isEmpty && iterations < maxIterations) {\n const current = session.openList.pop()!;\n current.closed = true;\n session.nodesSearched++;\n iterations++;\n\n if (current.node.id === session.endNode.id) {\n session.state = PathfindingState.Completed;\n session.result = this.buildResult(session, current);\n\n if (this.cache && session.result.found) {\n const req = session.request;\n this.cache.set(\n req.startX, req.startY,\n req.endX, req.endY,\n {\n found: true,\n path: session.result.path,\n cost: session.result.cost,\n nodesSearched: session.result.nodesSearched\n },\n this.mapVersion\n );\n }\n\n return this.createProgress(session);\n }\n\n this.expandNeighbors(session, current);\n\n if (session.nodesSearched >= session.options.maxNodes) {\n session.state = PathfindingState.Failed;\n session.result = this.createEmptyResult(requestId);\n return this.createProgress(session);\n }\n }\n\n if (session.openList.isEmpty && session.state === PathfindingState.InProgress) {\n session.state = PathfindingState.Failed;\n session.result = this.createEmptyResult(requestId);\n }\n\n return this.createProgress(session);\n }\n\n /**\n * @zh 暂停寻路\n * @en Pause pathfinding\n */\n pause(requestId: number): void {\n const session = this.sessions.get(requestId);\n if (session && session.state === PathfindingState.InProgress) {\n session.state = PathfindingState.Paused;\n }\n }\n\n /**\n * @zh 恢复寻路\n * @en Resume pathfinding\n */\n resume(requestId: number): void {\n const session = this.sessions.get(requestId);\n if (session && session.state === PathfindingState.Paused) {\n session.state = PathfindingState.InProgress;\n }\n }\n\n /**\n * @zh 取消寻路\n * @en Cancel pathfinding\n */\n cancel(requestId: number): void {\n const session = this.sessions.get(requestId);\n if (session && (session.state === PathfindingState.InProgress ||\n session.state === PathfindingState.Paused)) {\n session.state = PathfindingState.Cancelled;\n session.result = this.createEmptyResult(requestId);\n }\n }\n\n /**\n * @zh 获取寻路结果\n * @en Get pathfinding result\n */\n getResult(requestId: number): IIncrementalPathResult | null {\n const session = this.sessions.get(requestId);\n return session?.result ?? null;\n }\n\n /**\n * @zh 获取当前进度\n * @en Get current progress\n */\n getProgress(requestId: number): IPathProgress | null {\n const session = this.sessions.get(requestId);\n return session ? this.createProgress(session) : null;\n }\n\n /**\n * @zh 清理已完成的请求\n * @en Clean up completed request\n */\n cleanup(requestId: number): void {\n const session = this.sessions.get(requestId);\n if (session) {\n session.openList.clear();\n session.nodeCache.clear();\n this.sessions.delete(requestId);\n }\n }\n\n /**\n * @zh 通知障碍物变化\n * @en Notify obstacle change\n */\n notifyObstacleChange(\n minX: number,\n minY: number,\n maxX: number,\n maxY: number\n ): void {\n this.mapVersion++;\n\n if (this.cache) {\n this.cache.invalidateRegion(minX, minY, maxX, maxY);\n }\n\n const region: ChangeRegion = {\n minX,\n minY,\n maxX,\n maxY,\n timestamp: Date.now()\n };\n this.affectedRegions.push(region);\n\n for (const session of this.sessions.values()) {\n if (session.state === PathfindingState.InProgress ||\n session.state === PathfindingState.Paused) {\n if (this.sessionAffectedByRegion(session, region)) {\n session.affectedByChange = true;\n }\n }\n }\n\n this.cleanupOldRegions();\n }\n\n /**\n * @zh 清理所有请求\n * @en Clear all requests\n */\n clear(): void {\n for (const session of this.sessions.values()) {\n session.openList.clear();\n session.nodeCache.clear();\n }\n this.sessions.clear();\n this.affectedRegions.length = 0;\n }\n\n /**\n * @zh 清空路径缓存\n * @en Clear path cache\n */\n clearCache(): void {\n if (this.cache) {\n this.cache.invalidateAll();\n this.cacheHits = 0;\n this.cacheMisses = 0;\n }\n }\n\n /**\n * @zh 获取缓存统计信息\n * @en Get cache statistics\n */\n getCacheStats(): { enabled: boolean; hits: number; misses: number; hitRate: number; size: number } {\n if (!this.cache) {\n return { enabled: false, hits: 0, misses: 0, hitRate: 0, size: 0 };\n }\n\n const total = this.cacheHits + this.cacheMisses;\n const hitRate = total > 0 ? this.cacheHits / total : 0;\n\n return {\n enabled: true,\n hits: this.cacheHits,\n misses: this.cacheMisses,\n hitRate,\n size: this.cache.getStats().size\n };\n }\n\n /**\n * @zh 检查会话是否被障碍物变化影响\n * @en Check if session is affected by obstacle change\n */\n isAffectedByChange(requestId: number): boolean {\n const session = this.sessions.get(requestId);\n return session?.affectedByChange ?? false;\n }\n\n /**\n * @zh 清除会话的变化标记\n * @en Clear session's change flag\n */\n clearChangeFlag(requestId: number): void {\n const session = this.sessions.get(requestId);\n if (session) {\n session.affectedByChange = false;\n }\n }\n\n // =========================================================================\n // 私有方法 | Private Methods\n // =========================================================================\n\n /**\n * @zh 展开邻居节点\n * @en Expand neighbor nodes\n */\n private expandNeighbors(session: PathfindingSession, current: AStarNode): void {\n const neighbors = this.map.getNeighbors(current.node);\n\n for (const neighborNode of neighbors) {\n if (!neighborNode.walkable) {\n continue;\n }\n\n let neighbor = session.nodeCache.get(neighborNode.id);\n\n if (!neighbor) {\n neighbor = {\n node: neighborNode,\n g: Infinity,\n h: 0,\n f: Infinity,\n parent: null,\n closed: false,\n opened: false,\n heapIndex: -1\n };\n session.nodeCache.set(neighborNode.id, neighbor);\n }\n\n if (neighbor.closed) {\n continue;\n }\n\n const movementCost = this.map.getMovementCost(current.node, neighborNode);\n const tentativeG = current.g + movementCost;\n\n if (!neighbor.opened) {\n neighbor.g = tentativeG;\n neighbor.h = this.map.heuristic(neighborNode.position, session.endPosition) *\n session.options.heuristicWeight;\n neighbor.f = neighbor.g + neighbor.h;\n neighbor.parent = current;\n neighbor.opened = true;\n session.openList.push(neighbor);\n } else if (tentativeG < neighbor.g) {\n neighbor.g = tentativeG;\n neighbor.f = neighbor.g + neighbor.h;\n neighbor.parent = current;\n session.openList.update(neighbor);\n }\n }\n }\n\n /**\n * @zh 创建进度对象\n * @en Create progress object\n */\n private createProgress(session: PathfindingSession): IPathProgress {\n let estimatedProgress = 0;\n\n if (session.state === PathfindingState.Completed) {\n estimatedProgress = 1;\n } else if (session.state === PathfindingState.InProgress && session.initialDistance > 0) {\n const bestNode = session.openList.peek();\n if (bestNode) {\n const currentDistance = bestNode.h / session.options.heuristicWeight;\n estimatedProgress = Math.max(0, Math.min(1,\n 1 - (currentDistance / session.initialDistance)\n ));\n }\n }\n\n return {\n state: session.state,\n nodesSearched: session.nodesSearched,\n openListSize: session.openList.size,\n estimatedProgress\n };\n }\n\n /**\n * @zh 构建路径结果\n * @en Build path result\n */\n private buildResult(session: PathfindingSession, endNode: AStarNode): IIncrementalPathResult {\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 requestId: session.request.id,\n found: true,\n path,\n cost: endNode.g,\n nodesSearched: session.nodesSearched,\n framesUsed: session.framesUsed,\n isPartial: false\n };\n }\n\n /**\n * @zh 创建空结果\n * @en Create empty result\n */\n private createEmptyResult(requestId: number): IIncrementalPathResult {\n return {\n requestId,\n found: false,\n path: [],\n cost: 0,\n nodesSearched: 0,\n framesUsed: 0,\n isPartial: false\n };\n }\n\n /**\n * @zh 检查会话是否被区域影响\n * @en Check if session is affected by region\n */\n private sessionAffectedByRegion(session: PathfindingSession, region: ChangeRegion): boolean {\n for (const astarNode of session.nodeCache.values()) {\n if (astarNode.opened || astarNode.closed) {\n const pos = astarNode.node.position;\n if (pos.x >= region.minX && pos.x <= region.maxX &&\n pos.y >= region.minY && pos.y <= region.maxY) {\n return true;\n }\n }\n }\n\n const start = session.request;\n const end = session.endPosition;\n\n if ((start.startX >= region.minX && start.startX <= region.maxX &&\n start.startY >= region.minY && start.startY <= region.maxY) ||\n (end.x >= region.minX && end.x <= region.maxX &&\n end.y >= region.minY && end.y <= region.maxY)) {\n return true;\n }\n\n return false;\n }\n\n /**\n * @zh 清理过期的变化区域\n * @en Clean up expired change regions\n */\n private cleanupOldRegions(): void {\n const now = Date.now();\n let i = 0;\n while (i < this.affectedRegions.length) {\n if (now - this.affectedRegions[i].timestamp > this.maxRegionAge) {\n this.affectedRegions.splice(i, 1);\n } else {\n i++;\n }\n }\n }\n}\n\n// =============================================================================\n// 工厂函数 | Factory Function\n// =============================================================================\n\n/**\n * @zh 创建增量 A* 寻路器\n * @en Create incremental A* pathfinder\n *\n * @param map - @zh 寻路地图实例 @en Pathfinding map instance\n * @returns @zh 增量 A* 寻路器实例 @en Incremental A* pathfinder instance\n */\nexport function createIncrementalAStarPathfinder(map: IPathfindingMap): IncrementalAStarPathfinder {\n return new IncrementalAStarPathfinder(map);\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 Path Planner Interface\n *\n * @zh 统一的全局寻路接口,支持 NavMesh、A*、JPS、HPA*、Flow Field 等算法\n * @en Unified global pathfinding interface, supports NavMesh, A*, JPS, HPA*, Flow Field, etc.\n */\n\n/**\n * @zh 2D 向量\n * @en 2D Vector\n */\nexport interface IVector2 {\n x: number;\n y: number;\n}\n\n/**\n * @zh 路径规划结果\n * @en Path planning result\n */\nexport interface IPathPlanResult {\n /**\n * @zh 是否找到路径\n * @en Whether path was found\n */\n readonly found: boolean;\n\n /**\n * @zh 路径点列表(世界坐标)\n * @en List of path points (world coordinates)\n */\n readonly path: readonly IVector2[];\n\n /**\n * @zh 路径总代价\n * @en Total path cost\n */\n readonly cost: number;\n\n /**\n * @zh 搜索的节点数(用于性能监控)\n * @en Number of nodes searched (for performance monitoring)\n */\n readonly nodesSearched: number;\n}\n\n/**\n * @zh 空路径结果\n * @en Empty path result\n */\nexport const EMPTY_PLAN_RESULT: IPathPlanResult = {\n found: false,\n path: [],\n cost: 0,\n nodesSearched: 0\n};\n\n/**\n * @zh 路径规划选项\n * @en Path planning options\n */\nexport interface IPathPlanOptions {\n /**\n * @zh 代理半径,用于生成考虑碰撞的路径\n * @en Agent radius, used to generate collision-aware paths\n *\n * @zh 如果指定,路径规划器会确保生成的路径与障碍物保持足够距离\n * @en If specified, the path planner will ensure the generated path maintains sufficient distance from obstacles\n */\n agentRadius?: number;\n}\n\n/**\n * @zh 路径规划器接口\n * @en Path planner interface\n *\n * @zh 统一的全局寻路接口,支持 NavMesh、A*、JPS、HPA*、Flow Field 等算法\n * @en Unified global pathfinding interface, supports NavMesh, A*, JPS, HPA*, Flow Field, etc.\n *\n * @example\n * ```typescript\n * // 使用 NavMesh 规划器\n * const planner = createNavMeshPathPlanner(navMesh);\n * const result = planner.findPath({ x: 0, y: 0 }, { x: 100, y: 100 });\n *\n * // 使用带半径的路径规划\n * const result = planner.findPath({ x: 0, y: 0 }, { x: 100, y: 100 }, { agentRadius: 0.5 });\n *\n * // 使用 A* 规划器\n * const planner = createAStarPlanner(gridMap);\n * const result = planner.findPath({ x: 0, y: 0 }, { x: 50, y: 50 });\n * ```\n */\nexport interface IPathPlanner {\n /**\n * @zh 规划器类型标识\n * @en Planner type identifier\n */\n readonly type: string;\n\n /**\n * @zh 查找从起点到终点的路径\n * @en Find path from start to end\n *\n * @param start - @zh 起点世界坐标 @en Start world position\n * @param end - @zh 终点世界坐标 @en End world position\n * @param options - @zh 路径规划选项 @en Path planning options\n * @returns @zh 路径规划结果 @en Path planning result\n */\n findPath(start: IVector2, end: IVector2, options?: IPathPlanOptions): IPathPlanResult;\n\n /**\n * @zh 检查位置是否可通行\n * @en Check if position is walkable\n *\n * @param position - @zh 要检查的位置 @en Position to check\n * @returns @zh 是否可通行 @en Whether walkable\n */\n isWalkable(position: IVector2): boolean;\n\n /**\n * @zh 获取最近的可通行位置\n * @en Get nearest walkable position\n *\n * @param position - @zh 参考位置 @en Reference position\n * @returns @zh 最近的可通行位置,如果找不到则返回 null @en Nearest walkable position, or null if not found\n */\n getNearestWalkable(position: IVector2): IVector2 | null;\n\n /**\n * @zh 清理内部状态(用于重用)\n * @en Clear internal state (for reuse)\n */\n clear(): void;\n\n /**\n * @zh 释放资源\n * @en Dispose resources\n */\n dispose(): void;\n}\n\n// =============================================================================\n// 增量路径规划器 | Incremental Path Planner\n// =============================================================================\n\n/**\n * @zh 寻路状态\n * @en Pathfinding state\n */\nexport enum PathPlanState {\n /**\n * @zh 空闲\n * @en Idle\n */\n Idle = 'idle',\n\n /**\n * @zh 进行中\n * @en In progress\n */\n InProgress = 'in_progress',\n\n /**\n * @zh 已完成\n * @en Completed\n */\n Completed = 'completed',\n\n /**\n * @zh 失败\n * @en Failed\n */\n Failed = 'failed',\n\n /**\n * @zh 已取消\n * @en Cancelled\n */\n Cancelled = 'cancelled'\n}\n\n/**\n * @zh 增量寻路请求\n * @en Incremental pathfinding request\n */\nexport interface IIncrementalPathRequest {\n /**\n * @zh 请求 ID\n * @en Request ID\n */\n readonly id: number;\n\n /**\n * @zh 当前状态\n * @en Current state\n */\n readonly state: PathPlanState;\n}\n\n/**\n * @zh 寻路进度信息\n * @en Pathfinding progress info\n */\nexport interface IPathProgress {\n /**\n * @zh 当前状态\n * @en Current state\n */\n readonly state: PathPlanState;\n\n /**\n * @zh 估计进度 (0-1)\n * @en Estimated progress (0-1)\n */\n readonly estimatedProgress: number;\n\n /**\n * @zh 本次步进搜索的节点数\n * @en Nodes searched in this step\n */\n readonly nodesSearched: number;\n\n /**\n * @zh 累计搜索的节点数\n * @en Total nodes searched\n */\n readonly totalNodesSearched: number;\n}\n\n/**\n * @zh 增量路径规划器接口\n * @en Incremental path planner interface\n *\n * @zh 支持时间切片的路径规划器,可以将寻路计算分散到多帧执行\n * @en Path planner with time slicing support, can spread pathfinding computation across multiple frames\n *\n * @example\n * ```typescript\n * const planner = createIncrementalAStarPlanner(gridMap);\n *\n * // 请求路径\n * const request = planner.requestPath({ x: 0, y: 0 }, { x: 100, y: 100 });\n *\n * // 每帧执行一定数量的迭代\n * while (true) {\n * const progress = planner.step(request.id, 100); // 每帧 100 次迭代\n * if (progress.state === PathPlanState.Completed) {\n * const result = planner.getResult(request.id);\n * break;\n * }\n * if (progress.state === PathPlanState.Failed) {\n * break;\n * }\n * await nextFrame();\n * }\n *\n * planner.cleanup(request.id);\n * ```\n */\nexport interface IIncrementalPathPlanner extends IPathPlanner {\n /**\n * @zh 是否支持增量计算\n * @en Whether supports incremental computation\n */\n readonly supportsIncremental: true;\n\n /**\n * @zh 请求路径(异步开始)\n * @en Request path (async start)\n *\n * @param start - @zh 起点 @en Start position\n * @param end - @zh 终点 @en End position\n * @param options - @zh 选项 @en Options\n * @returns @zh 请求对象 @en Request object\n */\n requestPath(start: IVector2, end: IVector2, options?: IPathPlanOptions): IIncrementalPathRequest;\n\n /**\n * @zh 执行指定次数的迭代\n * @en Execute specified number of iterations\n *\n * @param requestId - @zh 请求 ID @en Request ID\n * @param iterations - @zh 迭代次数 @en Number of iterations\n * @returns @zh 进度信息 @en Progress info\n */\n step(requestId: number, iterations: number): IPathProgress;\n\n /**\n * @zh 获取结果\n * @en Get result\n *\n * @param requestId - @zh 请求 ID @en Request ID\n * @returns @zh 结果,如果未完成或不存在返回 null @en Result, null if not completed or not found\n */\n getResult(requestId: number): IPathPlanResult | null;\n\n /**\n * @zh 取消请求\n * @en Cancel request\n *\n * @param requestId - @zh 请求 ID @en Request ID\n */\n cancel(requestId: number): void;\n\n /**\n * @zh 清理请求(释放资源)\n * @en Cleanup request (release resources)\n *\n * @param requestId - @zh 请求 ID @en Request ID\n */\n cleanup(requestId: number): void;\n\n /**\n * @zh 获取活跃请求数量\n * @en Get active request count\n */\n getActiveRequestCount(): number;\n}\n\n/**\n * @zh 类型守卫:检查是否为增量路径规划器\n * @en Type guard: check if is incremental path planner\n */\nexport function isIncrementalPlanner(planner: IPathPlanner): planner is IIncrementalPathPlanner {\n return 'supportsIncremental' in planner && (planner as IIncrementalPathPlanner).supportsIncremental === true;\n}\n","/**\n * @zh 碰撞解决器接口\n * @en Collision Resolver Interface\n *\n * @zh 提供位置级别的硬碰撞检测和解决\n * @en Provides position-level hard collision detection and resolution\n */\n\nimport type { IVector2 } from './IPathPlanner';\nimport type { IObstacleData } from './ILocalAvoidance';\n\n/**\n * @zh 碰撞检测结果\n * @en Collision detection result\n */\nexport interface ICollisionResult {\n /**\n * @zh 是否发生碰撞\n * @en Whether collision occurred\n */\n readonly collided: boolean;\n\n /**\n * @zh 穿透深度\n * @en Penetration depth\n */\n readonly penetration: number;\n\n /**\n * @zh 碰撞法线(从障碍物指向代理)\n * @en Collision normal (pointing from obstacle to agent)\n */\n readonly normal: IVector2;\n\n /**\n * @zh 障碍物上的最近点\n * @en Closest point on obstacle\n */\n readonly closestPoint: IVector2;\n}\n\n/**\n * @zh 空碰撞结果\n * @en Empty collision result\n */\nexport const EMPTY_COLLISION_RESULT: ICollisionResult = {\n collided: false,\n penetration: 0,\n normal: { x: 0, y: 0 },\n closestPoint: { x: 0, y: 0 }\n};\n\n/**\n * @zh 碰撞解决器接口\n * @en Collision resolver interface\n *\n * @zh 提供位置级别的硬碰撞检测和解决,作为避让算法失效时的安全保护层\n * @en Provides position-level hard collision detection and resolution, as safety layer when avoidance fails\n *\n * @example\n * ```typescript\n * const resolver = createDefaultCollisionResolver();\n *\n * // 检测碰撞\n * const collision = resolver.detectCollision(position, radius, obstacles);\n * if (collision.collided) {\n * // 解决碰撞\n * const newPos = resolver.resolveCollision(position, radius, obstacles);\n * }\n *\n * // 验证速度\n * const safeVelocity = resolver.validateVelocity(\n * position, velocity, radius, obstacles, deltaTime\n * );\n * ```\n */\nexport interface ICollisionResolver {\n /**\n * @zh 解决器类型标识\n * @en Resolver type identifier\n */\n readonly type: string;\n\n /**\n * @zh 检测圆与障碍物的碰撞\n * @en Detect collision between circle and obstacles\n *\n * @param position - @zh 圆心位置 @en Circle center position\n * @param radius - @zh 圆半径 @en Circle radius\n * @param obstacles - @zh 障碍物列表 @en List of obstacles\n * @returns @zh 最严重的碰撞结果 @en Most severe collision result\n */\n detectCollision(\n position: IVector2,\n radius: number,\n obstacles: readonly IObstacleData[]\n ): ICollisionResult;\n\n /**\n * @zh 解决碰撞,返回修正后的位置\n * @en Resolve collision, return corrected position\n *\n * @param position - @zh 当前位置 @en Current position\n * @param radius - @zh 半径 @en Radius\n * @param obstacles - @zh 障碍物列表 @en List of obstacles\n * @returns @zh 修正后的位置 @en Corrected position\n */\n resolveCollision(\n position: IVector2,\n radius: number,\n obstacles: readonly IObstacleData[]\n ): IVector2;\n\n /**\n * @zh 验证速度是否会导致碰撞,返回安全速度\n * @en Validate velocity won't cause collision, return safe velocity\n *\n * @param position - @zh 当前位置 @en Current position\n * @param velocity - @zh 目标速度 @en Target velocity\n * @param radius - @zh 半径 @en Radius\n * @param obstacles - @zh 障碍物列表 @en List of obstacles\n * @param deltaTime - @zh 时间步长 @en Time step\n * @returns @zh 安全速度 @en Safe velocity\n */\n validateVelocity(\n position: IVector2,\n velocity: IVector2,\n radius: number,\n obstacles: readonly IObstacleData[],\n deltaTime: number\n ): IVector2;\n\n /**\n * @zh 检测两个代理之间的碰撞\n * @en Detect collision between two agents\n *\n * @param posA - @zh 代理 A 位置 @en Agent A position\n * @param radiusA - @zh 代理 A 半径 @en Agent A radius\n * @param posB - @zh 代理 B 位置 @en Agent B position\n * @param radiusB - @zh 代理 B 半径 @en Agent B radius\n * @returns @zh 碰撞结果 @en Collision result\n */\n detectAgentCollision(\n posA: IVector2,\n radiusA: number,\n posB: IVector2,\n radiusB: number\n ): ICollisionResult;\n\n /**\n * @zh 释放资源\n * @en Dispose resources\n */\n dispose(): void;\n}\n","/**\n * @zh 流量控制器接口\n * @en Flow Controller Interface\n *\n * @zh 管理拥堵区域的代理通行,防止死锁\n * @en Manages agent passage through congested areas, prevents deadlocks\n */\n\nimport type { IVector2 } from './IPathPlanner';\n\n// =============================================================================\n// 通行许可 | Pass Permission\n// =============================================================================\n\n/**\n * @zh 通行许可类型\n * @en Pass permission type\n */\nexport enum PassPermission {\n /**\n * @zh 可以通行\n * @en Can proceed\n */\n Proceed = 'proceed',\n\n /**\n * @zh 需要等待\n * @en Need to wait\n */\n Wait = 'wait',\n\n /**\n * @zh 需要让路(减速或侧移)\n * @en Need to yield (slow down or move aside)\n */\n Yield = 'yield'\n}\n\n// =============================================================================\n// 拥堵区域 | Congestion Zone\n// =============================================================================\n\n/**\n * @zh 拥堵区域\n * @en Congestion zone\n */\nexport interface ICongestionZone {\n /**\n * @zh 区域 ID\n * @en Zone ID\n */\n id: number;\n\n /**\n * @zh 区域中心\n * @en Zone center\n */\n center: IVector2;\n\n /**\n * @zh 区域半径\n * @en Zone radius\n */\n radius: number;\n\n /**\n * @zh 区域内的代理 ID 列表\n * @en List of agent IDs in the zone\n */\n agentIds: number[];\n\n /**\n * @zh 区域容量(可同时通过的代理数)\n * @en Zone capacity (agents that can pass simultaneously)\n */\n capacity: number;\n\n /**\n * @zh 拥堵程度 (0-1, 1 表示完全堵塞)\n * @en Congestion level (0-1, 1 means fully blocked)\n */\n congestionLevel: number;\n}\n\n// =============================================================================\n// 代理流量数据 | Agent Flow Data\n// =============================================================================\n\n/**\n * @zh 代理流量数据\n * @en Agent flow data\n */\nexport interface IFlowAgentData {\n /**\n * @zh 代理 ID\n * @en Agent ID\n */\n id: number;\n\n /**\n * @zh 当前位置\n * @en Current position\n */\n position: IVector2;\n\n /**\n * @zh 目标位置\n * @en Destination position\n */\n destination: IVector2 | null;\n\n /**\n * @zh 当前路径点\n * @en Current waypoint\n */\n currentWaypoint: IVector2 | null;\n\n /**\n * @zh 代理半径\n * @en Agent radius\n */\n radius: number;\n\n /**\n * @zh 优先级(数值越小优先级越高)\n * @en Priority (lower number = higher priority)\n */\n priority: number;\n\n /**\n * @zh 进入拥堵区域的时间戳\n * @en Timestamp when entered congestion zone\n */\n enterTime?: number;\n}\n\n// =============================================================================\n// 流量控制结果 | Flow Control Result\n// =============================================================================\n\n/**\n * @zh 流量控制结果\n * @en Flow control result\n */\nexport interface IFlowControlResult {\n /**\n * @zh 通行许可\n * @en Pass permission\n */\n permission: PassPermission;\n\n /**\n * @zh 如果需要等待,等待位置\n * @en Wait position if waiting is required\n */\n waitPosition: IVector2 | null;\n\n /**\n * @zh 如果需要让路,建议的速度倍率 (0-1)\n * @en Suggested speed multiplier if yielding (0-1)\n */\n speedMultiplier: number;\n\n /**\n * @zh 所在的拥堵区域(如果有)\n * @en Congestion zone the agent is in (if any)\n */\n zone: ICongestionZone | null;\n\n /**\n * @zh 在队列中的位置(0 表示最前)\n * @en Position in queue (0 means front)\n */\n queuePosition: number;\n}\n\n// =============================================================================\n// 流量控制器接口 | Flow Controller Interface\n// =============================================================================\n\n/**\n * @zh 流量控制器配置\n * @en Flow controller configuration\n */\nexport interface IFlowControllerConfig {\n /**\n * @zh 拥堵检测半径\n * @en Congestion detection radius\n */\n detectionRadius?: number;\n\n /**\n * @zh 触发拥堵的最小代理数\n * @en Minimum agents to trigger congestion\n */\n minAgentsForCongestion?: number;\n\n /**\n * @zh 默认区域容量\n * @en Default zone capacity\n */\n defaultCapacity?: number;\n\n /**\n * @zh 等待点距离(到拥堵区域边缘的距离)\n * @en Wait point distance (from congestion zone edge)\n */\n waitPointDistance?: number;\n\n /**\n * @zh 让路速度倍率\n * @en Yield speed multiplier\n */\n yieldSpeedMultiplier?: number;\n}\n\n/**\n * @zh 默认流量控制器配置\n * @en Default flow controller configuration\n */\nexport const DEFAULT_FLOW_CONTROLLER_CONFIG: Required<IFlowControllerConfig> = {\n detectionRadius: 3.0,\n minAgentsForCongestion: 3,\n defaultCapacity: 2,\n waitPointDistance: 1.5,\n yieldSpeedMultiplier: 0.3\n};\n\n/**\n * @zh 流量控制器接口\n * @en Flow controller interface\n *\n * @zh 管理代理在拥堵区域的通行顺序,防止死锁和回头现象\n * @en Manages agent passage order in congested areas, prevents deadlocks and turning back\n *\n * @example\n * ```typescript\n * const flowController = createFlowController();\n * navSystem.setFlowController(flowController);\n *\n * // 流量控制会自动:\n * // 1. 检测拥堵区域\n * // 2. 分配通行优先级\n * // 3. 管理等待队列\n * ```\n */\nexport interface IFlowController {\n /**\n * @zh 控制器类型标识\n * @en Controller type identifier\n */\n readonly type: string;\n\n /**\n * @zh 更新流量控制状态\n * @en Update flow control state\n *\n * @param agents - @zh 所有代理数据 @en All agent data\n * @param deltaTime - @zh 时间步长 @en Time step\n */\n update(agents: readonly IFlowAgentData[], deltaTime: number): void;\n\n /**\n * @zh 获取代理的流量控制结果\n * @en Get flow control result for an agent\n *\n * @param agentId - @zh 代理 ID @en Agent ID\n * @returns @zh 流量控制结果 @en Flow control result\n */\n getFlowControl(agentId: number): IFlowControlResult;\n\n /**\n * @zh 获取所有检测到的拥堵区域\n * @en Get all detected congestion zones\n *\n * @returns @zh 拥堵区域列表 @en List of congestion zones\n */\n getCongestionZones(): readonly ICongestionZone[];\n\n /**\n * @zh 手动标记一个区域为拥堵区域\n * @en Manually mark an area as congestion zone\n *\n * @param center - @zh 区域中心 @en Zone center\n * @param radius - @zh 区域半径 @en Zone radius\n * @param capacity - @zh 区域容量 @en Zone capacity\n * @returns @zh 区域 ID @en Zone ID\n */\n addStaticZone(center: IVector2, radius: number, capacity: number): number;\n\n /**\n * @zh 移除手动标记的拥堵区域\n * @en Remove manually marked congestion zone\n *\n * @param zoneId - @zh 区域 ID @en Zone ID\n */\n removeStaticZone(zoneId: number): void;\n\n /**\n * @zh 清除所有状态\n * @en Clear all state\n */\n clear(): void;\n\n /**\n * @zh 释放资源\n * @en Dispose resources\n */\n dispose(): void;\n}\n","/**\n * @zh NavMesh 路径规划器适配器\n * @en NavMesh Path Planner Adapter\n *\n * @zh 将现有 NavMesh 适配到 IPathPlanner 接口\n * @en Adapts existing NavMesh to IPathPlanner interface\n */\n\nimport type { IPathPlanner, IPathPlanResult, IPathPlanOptions, IVector2 } from '../interfaces/IPathPlanner';\nimport type { NavMesh } from '../navmesh/NavMesh';\nimport { EMPTY_PLAN_RESULT } from '../interfaces/IPathPlanner';\n\n/**\n * @zh NavMesh 路径规划器适配器\n * @en NavMesh path planner adapter\n *\n * @example\n * ```typescript\n * const navMesh = createNavMesh();\n * navMesh.addPolygon([...]);\n * navMesh.build();\n *\n * const planner = createNavMeshPathPlanner(navMesh);\n * const result = planner.findPath({ x: 0, y: 0 }, { x: 100, y: 100 });\n * ```\n */\nexport class NavMeshPathPlannerAdapter implements IPathPlanner {\n readonly type = 'navmesh';\n\n constructor(private readonly navMesh: NavMesh) {}\n\n findPath(start: IVector2, end: IVector2, options?: IPathPlanOptions): IPathPlanResult {\n const result = this.navMesh.findPathWithObstacles(\n start.x, start.y,\n end.x, end.y,\n options ? { agentRadius: options.agentRadius } : undefined\n );\n\n if (!result.found) {\n return EMPTY_PLAN_RESULT;\n }\n\n return {\n found: true,\n path: result.path.map(p => ({ x: p.x, y: p.y })),\n cost: result.cost,\n nodesSearched: result.nodesSearched\n };\n }\n\n isWalkable(position: IVector2): boolean {\n return this.navMesh.isWalkable(position.x, position.y);\n }\n\n getNearestWalkable(position: IVector2): IVector2 | null {\n const polygon = this.navMesh.findPolygonAt(position.x, position.y);\n if (polygon) {\n return { x: position.x, y: position.y };\n }\n\n const polygons = this.navMesh.getPolygons();\n if (polygons.length === 0) {\n return null;\n }\n\n let nearestDist = Infinity;\n let nearestPoint: IVector2 | null = null;\n\n for (const poly of polygons) {\n const dx = poly.center.x - position.x;\n const dy = poly.center.y - position.y;\n const dist = dx * dx + dy * dy;\n\n if (dist < nearestDist) {\n nearestDist = dist;\n nearestPoint = { x: poly.center.x, y: poly.center.y };\n }\n }\n\n return nearestPoint;\n }\n\n clear(): void {\n // NavMesh manages its own state\n }\n\n dispose(): void {\n // NavMesh lifecycle managed externally\n }\n}\n\n/**\n * @zh 创建 NavMesh 路径规划器\n * @en Create NavMesh path planner\n *\n * @param navMesh - @zh NavMesh 实例 @en NavMesh instance\n * @returns @zh 路径规划器 @en Path planner\n *\n * @example\n * ```typescript\n * const planner = createNavMeshPathPlanner(navMesh);\n * navSystem.setPathPlanner(planner);\n * ```\n */\nexport function createNavMeshPathPlanner(navMesh: NavMesh): IPathPlanner {\n return new NavMeshPathPlannerAdapter(navMesh);\n}\n","/**\n * @zh 网格寻路器适配器\n * @en Grid Pathfinder Adapter\n *\n * @zh 将现有 IPathfinder (A*, JPS, HPA*) 适配到 IPathPlanner 接口\n * @en Adapts existing IPathfinder (A*, JPS, HPA*) to IPathPlanner interface\n */\n\nimport type { IPathPlanner, IPathPlanResult, IVector2 } from '../interfaces/IPathPlanner';\nimport type { IPathfinder, IPathfindingMap, IPathfindingOptions } from '../core/IPathfinding';\nimport { EMPTY_PLAN_RESULT } from '../interfaces/IPathPlanner';\nimport { AStarPathfinder } from '../core/AStarPathfinder';\nimport { JPSPathfinder } from '../core/JPSPathfinder';\nimport { HPAPathfinder } from '../core/HPAPathfinder';\nimport type { IHPAConfig } from '../core/HPAPathfinder';\n\n/**\n * @zh 网格寻路器适配器配置\n * @en Grid pathfinder adapter configuration\n */\nexport interface IGridPathfinderAdapterConfig {\n /**\n * @zh 网格单元格大小(像素),用于坐标转换\n * @en Grid cell size (pixels), used for coordinate conversion\n *\n * @zh 如果设置了此值,输入的像素坐标会自动转换为网格坐标,输出的网格坐标会转换回像素坐标\n * @en If set, input pixel coordinates are converted to grid coordinates, output grid coordinates are converted back to pixel coordinates\n *\n * @default 1 (no conversion)\n */\n cellSize?: number;\n\n /**\n * @zh 是否将输出坐标对齐到单元格中心\n * @en Whether to align output coordinates to cell center\n *\n * @zh 为 true 时,输出坐标会偏移 cellSize * 0.5,指向单元格中心\n * @en When true, output coordinates are offset by cellSize * 0.5, pointing to cell center\n *\n * @zh 默认:当 cellSize > 1 时为 true(像素坐标场景),cellSize = 1 时为 false(网格坐标场景)\n * @en Default: true when cellSize > 1 (pixel coordinate scenario), false when cellSize = 1 (grid coordinate scenario)\n */\n alignToCenter?: boolean;\n}\n\n/**\n * @zh 网格寻路器适配器\n * @en Grid pathfinder adapter\n *\n * @zh 将 A*、JPS、HPA* 等网格寻路器适配到统一的 IPathPlanner 接口\n * @en Adapts A*, JPS, HPA* grid pathfinders to unified IPathPlanner interface\n */\nexport class GridPathfinderAdapter implements IPathPlanner {\n readonly type: string;\n private readonly cellSize: number;\n private readonly alignToCenter: boolean;\n\n constructor(\n private readonly pathfinder: IPathfinder,\n private readonly map: IPathfindingMap,\n private readonly options?: IPathfindingOptions,\n type: string = 'grid',\n config?: IGridPathfinderAdapterConfig\n ) {\n this.type = type;\n const cellSize = config?.cellSize ?? 1;\n if (cellSize <= 0 || !Number.isFinite(cellSize)) {\n throw new Error(`cellSize must be a positive finite number, got: ${cellSize}`);\n }\n this.cellSize = cellSize;\n this.alignToCenter = config?.alignToCenter ?? (cellSize > 1);\n }\n\n /**\n * @zh 像素坐标转网格坐标\n * @en Convert pixel coordinate to grid coordinate\n */\n private toGridCoord(pixel: number): number {\n return Math.floor(pixel / this.cellSize);\n }\n\n /**\n * @zh 网格坐标转像素坐标\n * @en Convert grid coordinate to pixel coordinate\n *\n * @zh 根据 alignToCenter 配置决定是否偏移到单元格中心\n * @en Offsets to cell center based on alignToCenter configuration\n */\n private toPixelCoord(grid: number): number {\n const base = grid * this.cellSize;\n return this.alignToCenter ? base + this.cellSize * 0.5 : base;\n }\n\n findPath(start: IVector2, end: IVector2): IPathPlanResult {\n const startGridX = this.toGridCoord(start.x);\n const startGridY = this.toGridCoord(start.y);\n const endGridX = this.toGridCoord(end.x);\n const endGridY = this.toGridCoord(end.y);\n\n const result = this.pathfinder.findPath(\n startGridX,\n startGridY,\n endGridX,\n endGridY,\n this.options\n );\n\n if (!result.found) {\n return EMPTY_PLAN_RESULT;\n }\n\n return {\n found: true,\n path: result.path.map(p => ({\n x: this.toPixelCoord(p.x),\n y: this.toPixelCoord(p.y)\n })),\n cost: result.cost,\n nodesSearched: result.nodesSearched\n };\n }\n\n isWalkable(position: IVector2): boolean {\n return this.map.isWalkable(\n this.toGridCoord(position.x),\n this.toGridCoord(position.y)\n );\n }\n\n getNearestWalkable(position: IVector2): IVector2 | null {\n const x = this.toGridCoord(position.x);\n const y = this.toGridCoord(position.y);\n\n if (this.map.isWalkable(x, y)) {\n return {\n x: this.toPixelCoord(x),\n y: this.toPixelCoord(y)\n };\n }\n\n for (let radius = 1; radius <= 10; radius++) {\n for (let dx = -radius; dx <= radius; dx++) {\n for (let dy = -radius; dy <= radius; dy++) {\n if (Math.abs(dx) === radius || Math.abs(dy) === radius) {\n if (this.map.isWalkable(x + dx, y + dy)) {\n return {\n x: this.toPixelCoord(x + dx),\n y: this.toPixelCoord(y + dy)\n };\n }\n }\n }\n }\n }\n\n return null;\n }\n\n clear(): void {\n this.pathfinder.clear();\n }\n\n dispose(): void {\n this.pathfinder.clear();\n }\n}\n\n/**\n * @zh 创建 A* 路径规划器\n * @en Create A* path planner\n *\n * @param map - @zh 寻路地图 @en Pathfinding map\n * @param options - @zh 寻路选项 @en Pathfinding options\n * @param config - @zh 适配器配置(包含 cellSize)@en Adapter config (includes cellSize)\n * @returns @zh 路径规划器 @en Path planner\n *\n * @example\n * ```typescript\n * const gridMap = createGridMap(100, 100);\n * // 如果使用像素坐标,需要指定 cellSize\n * const planner = createAStarPlanner(gridMap, undefined, { cellSize: 20 });\n * navSystem.setPathPlanner(planner);\n * ```\n */\nexport function createAStarPlanner(\n map: IPathfindingMap,\n options?: IPathfindingOptions,\n config?: IGridPathfinderAdapterConfig\n): IPathPlanner {\n return new GridPathfinderAdapter(\n new AStarPathfinder(map),\n map,\n options,\n 'astar',\n config\n );\n}\n\n/**\n * @zh 创建 JPS 路径规划器\n * @en Create JPS path planner\n *\n * @zh JPS(Jump Point Search)适用于均匀代价的网格地图,比 A* 快 10-100 倍\n * @en JPS (Jump Point Search) is optimized for uniform-cost grids, 10-100x faster than A*\n *\n * @param map - @zh 寻路地图 @en Pathfinding map\n * @param options - @zh 寻路选项 @en Pathfinding options\n * @param config - @zh 适配器配置(包含 cellSize)@en Adapter config (includes cellSize)\n * @returns @zh 路径规划器 @en Path planner\n *\n * @example\n * ```typescript\n * const gridMap = createGridMap(100, 100);\n * const planner = createJPSPlanner(gridMap, undefined, { cellSize: 20 });\n * navSystem.setPathPlanner(planner);\n * ```\n */\nexport function createJPSPlanner(\n map: IPathfindingMap,\n options?: IPathfindingOptions,\n config?: IGridPathfinderAdapterConfig\n): IPathPlanner {\n return new GridPathfinderAdapter(\n new JPSPathfinder(map),\n map,\n options,\n 'jps',\n config\n );\n}\n\n/**\n * @zh 创建 HPA* 路径规划器\n * @en Create HPA* path planner\n *\n * @zh HPA*(Hierarchical Pathfinding A*)适用于超大地图(1000x1000+)\n * @en HPA* (Hierarchical Pathfinding A*) is optimized for very large maps (1000x1000+)\n *\n * @param map - @zh 寻路地图 @en Pathfinding map\n * @param hpaConfig - @zh HPA* 配置 @en HPA* configuration\n * @param options - @zh 寻路选项 @en Pathfinding options\n * @param adapterConfig - @zh 适配器配置(包含 cellSize)@en Adapter config (includes cellSize)\n * @returns @zh 路径规划器 @en Path planner\n *\n * @example\n * ```typescript\n * const gridMap = createGridMap(2000, 2000);\n * const planner = createHPAPlanner(gridMap, { clusterSize: 16 }, undefined, { cellSize: 20 });\n * navSystem.setPathPlanner(planner);\n * ```\n */\nexport function createHPAPlanner(\n map: IPathfindingMap,\n hpaConfig?: Partial<IHPAConfig>,\n options?: IPathfindingOptions,\n adapterConfig?: IGridPathfinderAdapterConfig\n): IPathPlanner {\n return new GridPathfinderAdapter(\n new HPAPathfinder(map, hpaConfig),\n map,\n options,\n 'hpa',\n adapterConfig\n );\n}\n","/**\n * @zh 增量网格寻路器适配器\n * @en Incremental Grid Pathfinder Adapter\n *\n * @zh 将 IncrementalAStarPathfinder 适配到 IIncrementalPathPlanner 接口\n * @en Adapts IncrementalAStarPathfinder to IIncrementalPathPlanner interface\n */\n\nimport type {\n IIncrementalPathPlanner,\n IIncrementalPathRequest,\n IPathProgress,\n IPathPlanResult,\n IPathPlanOptions,\n IVector2,\n PathPlanState\n} from '../interfaces/IPathPlanner';\nimport { EMPTY_PLAN_RESULT } from '../interfaces/IPathPlanner';\nimport { PathPlanState as PlanState } from '../interfaces/IPathPlanner';\nimport type { IPathfindingMap, IPathfindingOptions } from '../core/IPathfinding';\nimport { IncrementalAStarPathfinder, type IIncrementalPathfinderConfig } from '../core/IncrementalAStarPathfinder';\nimport { PathfindingState } from '../core/IIncrementalPathfinding';\n\n/**\n * @zh 增量网格寻路器适配器配置\n * @en Incremental grid pathfinder adapter configuration\n */\nexport interface IIncrementalGridPathPlannerConfig extends IIncrementalPathfinderConfig {\n /**\n * @zh 网格单元格大小(像素),用于坐标转换\n * @en Grid cell size (pixels), used for coordinate conversion\n *\n * @default 1 (no conversion)\n */\n cellSize?: number;\n\n /**\n * @zh 是否将输出坐标对齐到单元格中心\n * @en Whether to align output coordinates to cell center\n *\n * @zh 为 true 时,输出坐标会偏移 cellSize * 0.5,指向单元格中心\n * @en When true, output coordinates are offset by cellSize * 0.5, pointing to cell center\n *\n * @zh 默认:当 cellSize > 1 时为 true(像素坐标场景),cellSize = 1 时为 false(网格坐标场景)\n * @en Default: true when cellSize > 1 (pixel coordinate scenario), false when cellSize = 1 (grid coordinate scenario)\n */\n alignToCenter?: boolean;\n}\n\n/**\n * @zh 将 PathfindingState 转换为 PathPlanState\n * @en Convert PathfindingState to PathPlanState\n */\nfunction toPathPlanState(state: PathfindingState): PathPlanState {\n switch (state) {\n case PathfindingState.Idle:\n return PlanState.Idle;\n case PathfindingState.InProgress:\n return PlanState.InProgress;\n case PathfindingState.Completed:\n return PlanState.Completed;\n case PathfindingState.Failed:\n return PlanState.Failed;\n case PathfindingState.Cancelled:\n return PlanState.Cancelled;\n default:\n return PlanState.Idle;\n }\n}\n\n/**\n * @zh 增量网格寻路器适配器\n * @en Incremental grid pathfinder adapter\n *\n * @zh 将 IncrementalAStarPathfinder 适配到 IIncrementalPathPlanner 接口,支持时间切片\n * @en Adapts IncrementalAStarPathfinder to IIncrementalPathPlanner interface, supports time slicing\n *\n * @example\n * ```typescript\n * const gridMap = createGridMap(100, 100);\n * const planner = createIncrementalAStarPlanner(gridMap, { cellSize: 20 });\n *\n * // 请求路径(像素坐标)\n * const request = planner.requestPath({ x: 100, y: 100 }, { x: 500, y: 300 });\n *\n * // 每帧执行一定数量的迭代\n * const progress = planner.step(request.id, 100);\n * if (progress.state === PathPlanState.Completed) {\n * const result = planner.getResult(request.id);\n * // result.path 是像素坐标\n * }\n * ```\n */\nexport class IncrementalGridPathPlannerAdapter implements IIncrementalPathPlanner {\n readonly type: string = 'incremental-astar';\n readonly supportsIncremental: true = true;\n\n private readonly pathfinder: IncrementalAStarPathfinder;\n private readonly map: IPathfindingMap;\n private readonly options?: IPathfindingOptions;\n private readonly cellSize: number;\n private readonly alignToCenter: boolean;\n\n /**\n * @zh 活跃请求 ID 集合(用于跟踪)\n * @en Active request IDs set (for tracking)\n */\n private readonly activeRequests: Set<number> = new Set();\n\n /**\n * @zh 每个请求的累计搜索节点数\n * @en Accumulated searched nodes per request\n */\n private readonly requestTotalNodes: Map<number, number> = new Map();\n\n constructor(\n map: IPathfindingMap,\n options?: IPathfindingOptions,\n config?: IIncrementalGridPathPlannerConfig\n ) {\n this.map = map;\n this.options = options;\n const cellSize = config?.cellSize ?? 1;\n if (cellSize <= 0 || !Number.isFinite(cellSize)) {\n throw new Error(`cellSize must be a positive finite number, got: ${cellSize}`);\n }\n this.cellSize = cellSize;\n this.alignToCenter = config?.alignToCenter ?? (cellSize > 1);\n this.pathfinder = new IncrementalAStarPathfinder(map, config);\n }\n\n /**\n * @zh 像素坐标转网格坐标\n * @en Convert pixel coordinate to grid coordinate\n */\n private toGridCoord(pixel: number): number {\n return Math.floor(pixel / this.cellSize);\n }\n\n /**\n * @zh 网格坐标转像素坐标\n * @en Convert grid coordinate to pixel coordinate\n *\n * @zh 根据 alignToCenter 配置决定是否偏移到单元格中心\n * @en Offsets to cell center based on alignToCenter configuration\n */\n private toPixelCoord(grid: number): number {\n const base = grid * this.cellSize;\n return this.alignToCenter ? base + this.cellSize * 0.5 : base;\n }\n\n // =========================================================================\n // IPathPlanner 基础接口 | IPathPlanner Base Interface\n // =========================================================================\n\n findPath(start: IVector2, end: IVector2, options?: IPathPlanOptions): IPathPlanResult {\n const startGridX = this.toGridCoord(start.x);\n const startGridY = this.toGridCoord(start.y);\n const endGridX = this.toGridCoord(end.x);\n const endGridY = this.toGridCoord(end.y);\n\n // 使用同步方式:请求 → 完全执行 → 获取结果\n const request = this.pathfinder.requestPath(\n startGridX,\n startGridY,\n endGridX,\n endGridY,\n this.options\n );\n\n // 执行足够多的迭代以完成\n let progress = this.pathfinder.step(request.id, 100000);\n while (progress.state === PathfindingState.InProgress) {\n progress = this.pathfinder.step(request.id, 100000);\n }\n\n const result = this.pathfinder.getResult(request.id);\n this.pathfinder.cleanup(request.id);\n\n if (!result || !result.found) {\n return EMPTY_PLAN_RESULT;\n }\n\n return {\n found: true,\n path: result.path.map(p => ({\n x: this.toPixelCoord(p.x),\n y: this.toPixelCoord(p.y)\n })),\n cost: result.cost,\n nodesSearched: result.nodesSearched\n };\n }\n\n isWalkable(position: IVector2): boolean {\n return this.map.isWalkable(\n this.toGridCoord(position.x),\n this.toGridCoord(position.y)\n );\n }\n\n getNearestWalkable(position: IVector2): IVector2 | null {\n const x = this.toGridCoord(position.x);\n const y = this.toGridCoord(position.y);\n\n if (this.map.isWalkable(x, y)) {\n return {\n x: this.toPixelCoord(x),\n y: this.toPixelCoord(y)\n };\n }\n\n for (let radius = 1; radius <= 10; radius++) {\n for (let dx = -radius; dx <= radius; dx++) {\n for (let dy = -radius; dy <= radius; dy++) {\n if (Math.abs(dx) === radius || Math.abs(dy) === radius) {\n if (this.map.isWalkable(x + dx, y + dy)) {\n return {\n x: this.toPixelCoord(x + dx),\n y: this.toPixelCoord(y + dy)\n };\n }\n }\n }\n }\n }\n\n return null;\n }\n\n clear(): void {\n this.pathfinder.clear();\n this.activeRequests.clear();\n this.requestTotalNodes.clear();\n }\n\n dispose(): void {\n this.pathfinder.clear();\n this.activeRequests.clear();\n this.requestTotalNodes.clear();\n }\n\n // =========================================================================\n // IIncrementalPathPlanner 增量接口 | IIncrementalPathPlanner Incremental Interface\n // =========================================================================\n\n requestPath(start: IVector2, end: IVector2, options?: IPathPlanOptions): IIncrementalPathRequest {\n const startGridX = this.toGridCoord(start.x);\n const startGridY = this.toGridCoord(start.y);\n const endGridX = this.toGridCoord(end.x);\n const endGridY = this.toGridCoord(end.y);\n\n const request = this.pathfinder.requestPath(\n startGridX,\n startGridY,\n endGridX,\n endGridY,\n this.options\n );\n\n this.activeRequests.add(request.id);\n this.requestTotalNodes.set(request.id, 0);\n\n return {\n id: request.id,\n state: PlanState.InProgress\n };\n }\n\n step(requestId: number, iterations: number): IPathProgress {\n const progress = this.pathfinder.step(requestId, iterations);\n\n // Track total nodes searched across all steps\n const prevTotal = this.requestTotalNodes.get(requestId) ?? 0;\n const newTotal = prevTotal + progress.nodesSearched;\n this.requestTotalNodes.set(requestId, newTotal);\n\n return {\n state: toPathPlanState(progress.state),\n estimatedProgress: progress.estimatedProgress,\n nodesSearched: progress.nodesSearched,\n totalNodesSearched: newTotal\n };\n }\n\n getResult(requestId: number): IPathPlanResult | null {\n const result = this.pathfinder.getResult(requestId);\n\n if (!result) {\n return null;\n }\n\n if (!result.found) {\n return EMPTY_PLAN_RESULT;\n }\n\n return {\n found: true,\n path: result.path.map(p => ({\n x: this.toPixelCoord(p.x),\n y: this.toPixelCoord(p.y)\n })),\n cost: result.cost,\n nodesSearched: result.nodesSearched\n };\n }\n\n cancel(requestId: number): void {\n this.pathfinder.cancel(requestId);\n }\n\n cleanup(requestId: number): void {\n this.pathfinder.cleanup(requestId);\n this.activeRequests.delete(requestId);\n this.requestTotalNodes.delete(requestId);\n }\n\n getActiveRequestCount(): number {\n return this.activeRequests.size;\n }\n}\n\n/**\n * @zh 创建增量 A* 路径规划器\n * @en Create incremental A* path planner\n *\n * @zh 支持时间切片的 A* 路径规划器,可以将寻路计算分散到多帧执行\n * @en A* path planner with time slicing support, can spread pathfinding computation across multiple frames\n *\n * @param map - @zh 寻路地图 @en Pathfinding map\n * @param options - @zh 寻路选项 @en Pathfinding options\n * @param config - @zh 适配器配置(包含 cellSize 和缓存配置)@en Adapter config (includes cellSize and cache config)\n * @returns @zh 增量路径规划器 @en Incremental path planner\n *\n * @example\n * ```typescript\n * const gridMap = createGridMap(100, 100);\n * const planner = createIncrementalAStarPlanner(gridMap, undefined, {\n * cellSize: 20,\n * enableCache: true\n * });\n *\n * // 与 NavigationSystem 集成\n * navSystem.setPathPlanner(planner);\n *\n * // 启用时间切片(NavigationSystem 会自动检测)\n * const navSystem = new NavigationSystem({\n * enableTimeSlicing: true,\n * iterationsBudget: 1000,\n * maxAgentsPerFrame: 10\n * });\n * ```\n */\nexport function createIncrementalAStarPlanner(\n map: IPathfindingMap,\n options?: IPathfindingOptions,\n config?: IIncrementalGridPathPlannerConfig\n): IIncrementalPathPlanner {\n return new IncrementalGridPathPlannerAdapter(map, options, config);\n}\n","/**\n * @zh ORCA 局部避让适配器\n * @en ORCA Local Avoidance Adapter\n *\n * @zh 将现有 ORCA 求解器适配到 ILocalAvoidance 接口\n * @en Adapts existing ORCA solver to ILocalAvoidance interface\n */\n\nimport type {\n ILocalAvoidance,\n IAvoidanceAgentData,\n IObstacleData,\n IAvoidanceResult\n} from '../interfaces/ILocalAvoidance';\nimport { ORCASolver, createORCASolver } from '../avoidance/ORCASolver';\nimport { KDTree, createKDTree } from '../avoidance/KDTree';\nimport type { IAvoidanceAgent, IORCASolverConfig, IObstacle } from '../avoidance/ILocalAvoidance';\n\n/**\n * @zh ORCA 默认参数\n * @en ORCA default parameters\n */\nexport interface IORCAParams {\n /**\n * @zh 邻居检测距离\n * @en Neighbor detection distance\n */\n neighborDist: number;\n\n /**\n * @zh 最大邻居数量\n * @en Maximum number of neighbors\n */\n maxNeighbors: number;\n\n /**\n * @zh 代理避让时间视野\n * @en Time horizon for agent avoidance\n */\n timeHorizon: number;\n\n /**\n * @zh 障碍物避让时间视野\n * @en Time horizon for obstacle avoidance\n */\n timeHorizonObst: number;\n}\n\n/**\n * @zh ORCA 默认参数值\n * @en ORCA default parameter values\n */\nexport const DEFAULT_ORCA_PARAMS: IORCAParams = {\n neighborDist: 15.0,\n maxNeighbors: 10,\n timeHorizon: 2.0,\n timeHorizonObst: 1.0\n};\n\n/**\n * @zh ORCA 局部避让适配器\n * @en ORCA local avoidance adapter\n *\n * @example\n * ```typescript\n * const avoidance = createORCAAvoidance();\n * navSystem.setLocalAvoidance(avoidance);\n *\n * // 自定义参数\n * const avoidance = createORCAAvoidance({\n * timeStep: 1/60\n * });\n * avoidance.setDefaultParams({ timeHorizon: 3.0 });\n * ```\n */\nexport class ORCALocalAvoidanceAdapter implements ILocalAvoidance {\n readonly type = 'orca';\n\n private solver: ORCASolver;\n private kdTree: KDTree;\n private defaultParams: IORCAParams;\n\n constructor(config?: IORCASolverConfig) {\n this.solver = createORCASolver(config);\n this.kdTree = createKDTree();\n this.defaultParams = { ...DEFAULT_ORCA_PARAMS };\n }\n\n /**\n * @zh 设置默认 ORCA 参数\n * @en Set default ORCA parameters\n *\n * @param params - @zh 参数 @en Parameters\n */\n setDefaultParams(params: Partial<IORCAParams>): void {\n Object.assign(this.defaultParams, params);\n }\n\n /**\n * @zh 获取默认 ORCA 参数\n * @en Get default ORCA parameters\n */\n getDefaultParams(): Readonly<IORCAParams> {\n return this.defaultParams;\n }\n\n computeAvoidanceVelocity(\n agent: IAvoidanceAgentData,\n neighbors: readonly IAvoidanceAgentData[],\n obstacles: readonly IObstacleData[],\n deltaTime: number\n ): IAvoidanceResult {\n const orcaAgent = this.toORCAAgent(agent);\n const orcaNeighbors = neighbors.map(n => this.toORCAAgent(n));\n const orcaObstacles = obstacles.map(o => this.toORCAObstacle(o));\n\n const result = this.solver.computeNewVelocityWithResult(\n orcaAgent,\n orcaNeighbors,\n orcaObstacles,\n deltaTime\n );\n\n return {\n velocity: result.velocity,\n feasible: result.feasible\n };\n }\n\n computeBatchAvoidance(\n agents: readonly IAvoidanceAgentData[],\n obstacles: readonly IObstacleData[],\n deltaTime: number\n ): Map<number, IAvoidanceResult> {\n const results = new Map<number, IAvoidanceResult>();\n const orcaAgents = agents.map(a => this.toORCAAgent(a));\n const orcaObstacles = obstacles.map(o => this.toORCAObstacle(o));\n\n this.kdTree.build(orcaAgents);\n\n for (let i = 0; i < agents.length; i++) {\n const agent = orcaAgents[i]!;\n\n const neighborResults = this.kdTree.queryNeighbors(\n agent.position,\n agent.neighborDist,\n agent.maxNeighbors,\n agent.id\n );\n\n const result = this.solver.computeNewVelocityWithResult(\n agent,\n neighborResults.map(r => r.agent),\n orcaObstacles,\n deltaTime\n );\n\n results.set(agents[i]!.id, {\n velocity: result.velocity,\n feasible: result.feasible\n });\n }\n\n return results;\n }\n\n dispose(): void {\n this.kdTree.clear();\n }\n\n private toORCAAgent(agent: IAvoidanceAgentData): IAvoidanceAgent {\n return {\n id: agent.id,\n position: { x: agent.position.x, y: agent.position.y },\n velocity: { x: agent.velocity.x, y: agent.velocity.y },\n preferredVelocity: { x: agent.preferredVelocity.x, y: agent.preferredVelocity.y },\n radius: agent.radius,\n maxSpeed: agent.maxSpeed,\n neighborDist: this.defaultParams.neighborDist,\n maxNeighbors: this.defaultParams.maxNeighbors,\n timeHorizon: this.defaultParams.timeHorizon,\n timeHorizonObst: this.defaultParams.timeHorizonObst\n };\n }\n\n private toORCAObstacle(obstacle: IObstacleData): IObstacle {\n return {\n vertices: obstacle.vertices.map(v => ({ x: v.x, y: v.y }))\n };\n }\n}\n\n/**\n * @zh 创建 ORCA 局部避让\n * @en Create ORCA local avoidance\n *\n * @param config - @zh ORCA 求解器配置 @en ORCA solver configuration\n * @returns @zh 局部避让实例 @en Local avoidance instance\n *\n * @example\n * ```typescript\n * const avoidance = createORCAAvoidance();\n * navSystem.setLocalAvoidance(avoidance);\n * ```\n */\nexport function createORCAAvoidance(config?: IORCASolverConfig): ORCALocalAvoidanceAdapter {\n return new ORCALocalAvoidanceAdapter(config);\n}\n","/**\n * @zh 碰撞解决器适配器\n * @en Collision Resolver Adapter\n *\n * @zh 将现有 CollisionResolver 适配到 ICollisionResolver 接口\n * @en Adapts existing CollisionResolver to ICollisionResolver interface\n */\n\nimport type { ICollisionResolver, ICollisionResult } from '../interfaces/ICollisionResolver';\nimport type { IObstacleData } from '../interfaces/ILocalAvoidance';\nimport type { IVector2 } from '../interfaces/IPathPlanner';\nimport {\n CollisionResolver,\n createCollisionResolver,\n type ICollisionResolverConfig\n} from '../avoidance/CollisionResolver';\nimport { EMPTY_COLLISION_RESULT } from '../interfaces/ICollisionResolver';\n\n/**\n * @zh 碰撞解决器适配器\n * @en Collision resolver adapter\n *\n * @example\n * ```typescript\n * const resolver = createDefaultCollisionResolver();\n * navSystem.setCollisionResolver(resolver);\n * ```\n */\nexport class CollisionResolverAdapter implements ICollisionResolver {\n readonly type = 'default';\n\n private resolver: CollisionResolver;\n\n constructor(config?: ICollisionResolverConfig) {\n this.resolver = createCollisionResolver(config);\n }\n\n detectCollision(\n position: IVector2,\n radius: number,\n obstacles: readonly IObstacleData[]\n ): ICollisionResult {\n if (obstacles.length === 0) {\n return EMPTY_COLLISION_RESULT;\n }\n\n const result = this.resolver.detectCollisions(\n position,\n radius,\n obstacles.map(o => ({ vertices: o.vertices.map(v => ({ x: v.x, y: v.y })) }))\n );\n\n return {\n collided: result.collided,\n penetration: result.penetration,\n normal: { x: result.normal.x, y: result.normal.y },\n closestPoint: { x: result.closestPoint.x, y: result.closestPoint.y }\n };\n }\n\n resolveCollision(\n position: IVector2,\n radius: number,\n obstacles: readonly IObstacleData[]\n ): IVector2 {\n if (obstacles.length === 0) {\n return { x: position.x, y: position.y };\n }\n\n const resolved = this.resolver.resolveCollision(\n position,\n radius,\n obstacles.map(o => ({ vertices: o.vertices.map(v => ({ x: v.x, y: v.y })) }))\n );\n\n return { x: resolved.x, y: resolved.y };\n }\n\n validateVelocity(\n position: IVector2,\n velocity: IVector2,\n radius: number,\n obstacles: readonly IObstacleData[],\n deltaTime: number\n ): IVector2 {\n if (obstacles.length === 0) {\n return { x: velocity.x, y: velocity.y };\n }\n\n const result = this.resolver.validateVelocity(\n position,\n velocity,\n radius,\n obstacles.map(o => ({ vertices: o.vertices.map(v => ({ x: v.x, y: v.y })) })),\n deltaTime\n );\n\n return { x: result.x, y: result.y };\n }\n\n detectAgentCollision(\n posA: IVector2,\n radiusA: number,\n posB: IVector2,\n radiusB: number\n ): ICollisionResult {\n const result = this.resolver.detectAgentCollision(posA, radiusA, posB, radiusB);\n\n return {\n collided: result.collided,\n penetration: result.penetration,\n normal: { x: result.normal.x, y: result.normal.y },\n closestPoint: { x: result.closestPoint.x, y: result.closestPoint.y }\n };\n }\n\n dispose(): void {\n // No resources to dispose\n }\n}\n\n/**\n * @zh 创建默认碰撞解决器\n * @en Create default collision resolver\n *\n * @param config - @zh 配置 @en Configuration\n * @returns @zh 碰撞解决器 @en Collision resolver\n *\n * @example\n * ```typescript\n * const resolver = createDefaultCollisionResolver();\n * navSystem.setCollisionResolver(resolver);\n *\n * // 自定义配置\n * const resolver = createDefaultCollisionResolver({\n * responseFactor: 1.0,\n * safetyMargin: 0.01\n * });\n * ```\n */\nexport function createDefaultCollisionResolver(config?: ICollisionResolverConfig): ICollisionResolver {\n return new CollisionResolverAdapter(config);\n}\n","/**\n * @zh 流量控制器实现\n * @en Flow Controller Implementation\n *\n * @zh 管理拥堵区域的代理通行,使用 FIFO + 优先级策略防止死锁\n * @en Manages agent passage through congested areas using FIFO + priority to prevent deadlocks\n */\n\nimport type { IVector2 } from '../interfaces/IPathPlanner';\nimport type {\n IFlowController,\n IFlowControllerConfig,\n IFlowAgentData,\n IFlowControlResult,\n ICongestionZone\n} from '../interfaces/IFlowController';\nimport {\n PassPermission,\n DEFAULT_FLOW_CONTROLLER_CONFIG\n} from '../interfaces/IFlowController';\n\n// =============================================================================\n// 内部类型 | Internal Types\n// =============================================================================\n\n/**\n * @zh 代理队列项\n * @en Agent queue item\n */\ninterface QueueEntry {\n agentId: number;\n enterTime: number;\n priority: number;\n}\n\n/**\n * @zh 区域状态\n * @en Zone state\n */\ninterface ZoneState {\n zone: ICongestionZone;\n queue: QueueEntry[];\n passingAgents: Set<number>;\n isStatic: boolean;\n}\n\n// =============================================================================\n// 流量控制器 | Flow Controller\n// =============================================================================\n\n/**\n * @zh 流量控制器\n * @en Flow Controller\n *\n * @zh 检测拥堵区域并管理代理通行顺序\n * @en Detects congestion zones and manages agent passage order\n *\n * @example\n * ```typescript\n * const flowController = createFlowController({\n * detectionRadius: 3.0,\n * minAgentsForCongestion: 3,\n * defaultCapacity: 2\n * });\n *\n * // 每帧更新\n * flowController.update(agents, deltaTime);\n *\n * // 获取代理的流量控制\n * const result = flowController.getFlowControl(agentId);\n * if (result.permission === PassPermission.Wait) {\n * // 移动到等待位置\n * agent.setDestination(result.waitPosition);\n * }\n * ```\n */\nexport class FlowController implements IFlowController {\n readonly type = 'fifo-priority';\n\n private config: Required<IFlowControllerConfig>;\n private zoneStates: Map<number, ZoneState> = new Map();\n private agentZoneMap: Map<number, number> = new Map();\n private agentResults: Map<number, IFlowControlResult> = new Map();\n private nextZoneId: number = 1;\n private currentTime: number = 0;\n\n constructor(config: IFlowControllerConfig = {}) {\n this.config = { ...DEFAULT_FLOW_CONTROLLER_CONFIG, ...config };\n }\n\n /**\n * @zh 更新流量控制状态\n * @en Update flow control state\n */\n update(agents: readonly IFlowAgentData[], deltaTime: number): void {\n this.currentTime += deltaTime;\n this.agentResults.clear();\n\n // Step 1: 检测动态拥堵区域\n this.detectDynamicCongestion(agents);\n\n // Step 2: 更新每个区域的队列\n this.updateZoneQueues(agents);\n\n // Step 3: 计算每个代理的流量控制结果\n this.computeFlowControlResults(agents);\n\n // Step 4: 清理空的动态区域\n this.cleanupEmptyZones();\n }\n\n /**\n * @zh 获取代理的流量控制结果\n * @en Get flow control result for an agent\n */\n getFlowControl(agentId: number): IFlowControlResult {\n return this.agentResults.get(agentId) ?? {\n permission: PassPermission.Proceed,\n waitPosition: null,\n speedMultiplier: 1.0,\n zone: null,\n queuePosition: 0\n };\n }\n\n /**\n * @zh 获取所有拥堵区域\n * @en Get all congestion zones\n */\n getCongestionZones(): readonly ICongestionZone[] {\n return Array.from(this.zoneStates.values()).map(s => s.zone);\n }\n\n /**\n * @zh 添加静态拥堵区域\n * @en Add static congestion zone\n */\n addStaticZone(center: IVector2, radius: number, capacity: number): number {\n const zoneId = this.nextZoneId++;\n const zone: ICongestionZone = {\n id: zoneId,\n center: { x: center.x, y: center.y },\n radius,\n agentIds: [],\n capacity,\n congestionLevel: 0\n };\n\n this.zoneStates.set(zoneId, {\n zone,\n queue: [],\n passingAgents: new Set(),\n isStatic: true\n });\n\n return zoneId;\n }\n\n /**\n * @zh 移除静态拥堵区域\n * @en Remove static congestion zone\n */\n removeStaticZone(zoneId: number): void {\n const state = this.zoneStates.get(zoneId);\n if (state?.isStatic) {\n for (const agentId of state.zone.agentIds) {\n this.agentZoneMap.delete(agentId);\n }\n this.zoneStates.delete(zoneId);\n }\n }\n\n /**\n * @zh 清除所有状态\n * @en Clear all state\n */\n clear(): void {\n this.zoneStates.clear();\n this.agentZoneMap.clear();\n this.agentResults.clear();\n this.currentTime = 0;\n }\n\n /**\n * @zh 释放资源\n * @en Dispose resources\n */\n dispose(): void {\n this.clear();\n }\n\n // =========================================================================\n // 私有方法 | Private Methods\n // =========================================================================\n\n /**\n * @zh 检测动态拥堵区域\n * @en Detect dynamic congestion zones\n */\n private detectDynamicCongestion(agents: readonly IFlowAgentData[]): void {\n const clusters = this.clusterAgents(agents);\n\n for (const cluster of clusters) {\n if (cluster.length < this.config.minAgentsForCongestion) {\n continue;\n }\n\n const center = this.computeClusterCenter(cluster);\n const radius = this.computeClusterRadius(cluster, center);\n\n const existingZone = this.findZoneContaining(center);\n if (existingZone && !existingZone.isStatic) {\n this.updateDynamicZone(existingZone, cluster, center, radius);\n } else if (!existingZone) {\n this.createDynamicZone(cluster, center, radius);\n }\n }\n }\n\n /**\n * @zh 聚类代理\n * @en Cluster agents\n */\n private clusterAgents(agents: readonly IFlowAgentData[]): IFlowAgentData[][] {\n const clusters: IFlowAgentData[][] = [];\n const visited = new Set<number>();\n const detectionRadiusSq = this.config.detectionRadius * this.config.detectionRadius;\n\n for (const agent of agents) {\n if (visited.has(agent.id) || !agent.destination) {\n continue;\n }\n\n const cluster: IFlowAgentData[] = [agent];\n visited.add(agent.id);\n\n const queue = [agent];\n while (queue.length > 0) {\n const current = queue.shift()!;\n\n for (const other of agents) {\n if (visited.has(other.id) || !other.destination) {\n continue;\n }\n\n const dx = other.position.x - current.position.x;\n const dy = other.position.y - current.position.y;\n const distSq = dx * dx + dy * dy;\n\n if (distSq <= detectionRadiusSq) {\n visited.add(other.id);\n cluster.push(other);\n queue.push(other);\n }\n }\n }\n\n if (cluster.length >= this.config.minAgentsForCongestion) {\n clusters.push(cluster);\n }\n }\n\n return clusters;\n }\n\n /**\n * @zh 计算聚类中心\n * @en Compute cluster center\n */\n private computeClusterCenter(cluster: readonly IFlowAgentData[]): IVector2 {\n let sumX = 0, sumY = 0;\n for (const agent of cluster) {\n sumX += agent.position.x;\n sumY += agent.position.y;\n }\n return {\n x: sumX / cluster.length,\n y: sumY / cluster.length\n };\n }\n\n /**\n * @zh 计算聚类半径\n * @en Compute cluster radius\n */\n private computeClusterRadius(cluster: readonly IFlowAgentData[], center: IVector2): number {\n let maxDistSq = 0;\n for (const agent of cluster) {\n const dx = agent.position.x - center.x;\n const dy = agent.position.y - center.y;\n const distSq = dx * dx + dy * dy;\n maxDistSq = Math.max(maxDistSq, distSq);\n }\n return Math.sqrt(maxDistSq) + this.config.detectionRadius * 0.5;\n }\n\n /**\n * @zh 查找包含点的区域\n * @en Find zone containing point\n */\n private findZoneContaining(point: IVector2): ZoneState | null {\n for (const state of this.zoneStates.values()) {\n const dx = point.x - state.zone.center.x;\n const dy = point.y - state.zone.center.y;\n const distSq = dx * dx + dy * dy;\n if (distSq <= state.zone.radius * state.zone.radius) {\n return state;\n }\n }\n return null;\n }\n\n /**\n * @zh 更新动态区域\n * @en Update dynamic zone\n */\n private updateDynamicZone(\n state: ZoneState,\n cluster: readonly IFlowAgentData[],\n center: IVector2,\n radius: number\n ): void {\n state.zone.center = center;\n state.zone.radius = Math.max(state.zone.radius, radius);\n state.zone.agentIds = cluster.map(a => a.id);\n state.zone.congestionLevel = Math.min(1, cluster.length / (state.zone.capacity * 2));\n }\n\n /**\n * @zh 创建动态区域\n * @en Create dynamic zone\n */\n private createDynamicZone(\n cluster: readonly IFlowAgentData[],\n center: IVector2,\n radius: number\n ): void {\n const zoneId = this.nextZoneId++;\n\n const capacityEstimate = Math.max(\n this.config.defaultCapacity,\n Math.floor((Math.PI * radius * radius) / (Math.PI * 0.5 * 0.5 * 4))\n );\n\n const zone: ICongestionZone = {\n id: zoneId,\n center,\n radius,\n agentIds: cluster.map(a => a.id),\n capacity: capacityEstimate,\n congestionLevel: Math.min(1, cluster.length / (capacityEstimate * 2))\n };\n\n this.zoneStates.set(zoneId, {\n zone,\n queue: [],\n passingAgents: new Set(),\n isStatic: false\n });\n }\n\n /**\n * @zh 更新区域队列\n * @en Update zone queues\n */\n private updateZoneQueues(agents: readonly IFlowAgentData[]): void {\n const agentMap = new Map(agents.map(a => [a.id, a]));\n\n for (const state of this.zoneStates.values()) {\n const zone = state.zone;\n const newAgentIds: number[] = [];\n\n for (const agent of agents) {\n if (!agent.destination) continue;\n\n const dx = agent.position.x - zone.center.x;\n const dy = agent.position.y - zone.center.y;\n const distSq = dx * dx + dy * dy;\n const expandedRadius = zone.radius + this.config.waitPointDistance;\n\n if (distSq <= expandedRadius * expandedRadius) {\n newAgentIds.push(agent.id);\n\n const existingEntry = state.queue.find(e => e.agentId === agent.id);\n if (!existingEntry) {\n state.queue.push({\n agentId: agent.id,\n enterTime: agent.enterTime ?? this.currentTime,\n priority: agent.priority\n });\n this.agentZoneMap.set(agent.id, zone.id);\n }\n }\n }\n\n state.queue = state.queue.filter(entry => {\n const agent = agentMap.get(entry.agentId);\n if (!agent || !agent.destination) {\n state.passingAgents.delete(entry.agentId);\n this.agentZoneMap.delete(entry.agentId);\n return false;\n }\n\n const dx = agent.position.x - zone.center.x;\n const dy = agent.position.y - zone.center.y;\n const distSq = dx * dx + dy * dy;\n const expandedRadius = zone.radius + this.config.waitPointDistance * 2;\n\n if (distSq > expandedRadius * expandedRadius) {\n state.passingAgents.delete(entry.agentId);\n this.agentZoneMap.delete(entry.agentId);\n return false;\n }\n\n return true;\n });\n\n state.queue.sort((a, b) => {\n if (a.priority !== b.priority) {\n return a.priority - b.priority;\n }\n return a.enterTime - b.enterTime;\n });\n\n zone.agentIds = state.queue.map(e => e.agentId);\n zone.congestionLevel = Math.min(1, zone.agentIds.length / (zone.capacity * 2));\n }\n }\n\n /**\n * @zh 计算流量控制结果\n * @en Compute flow control results\n */\n private computeFlowControlResults(agents: readonly IFlowAgentData[]): void {\n const agentMap = new Map(agents.map(a => [a.id, a]));\n\n for (const state of this.zoneStates.values()) {\n const zone = state.zone;\n const capacity = zone.capacity;\n\n let passingCount = 0;\n for (const entry of state.queue) {\n const agent = agentMap.get(entry.agentId);\n if (!agent) continue;\n\n const dx = agent.position.x - zone.center.x;\n const dy = agent.position.y - zone.center.y;\n const distSq = dx * dx + dy * dy;\n const isInsideZone = distSq <= zone.radius * zone.radius;\n\n const queuePosition = state.queue.findIndex(e => e.agentId === entry.agentId);\n\n if (passingCount < capacity) {\n state.passingAgents.add(entry.agentId);\n passingCount++;\n\n const speedMult = isInsideZone && zone.congestionLevel > 0.5\n ? 1.0 - (zone.congestionLevel - 0.5)\n : 1.0;\n\n this.agentResults.set(entry.agentId, {\n permission: PassPermission.Proceed,\n waitPosition: null,\n speedMultiplier: speedMult,\n zone,\n queuePosition\n });\n } else if (state.passingAgents.has(entry.agentId) && isInsideZone) {\n this.agentResults.set(entry.agentId, {\n permission: PassPermission.Yield,\n waitPosition: null,\n speedMultiplier: this.config.yieldSpeedMultiplier,\n zone,\n queuePosition\n });\n } else {\n const waitPos = this.computeWaitPosition(agent, zone);\n this.agentResults.set(entry.agentId, {\n permission: PassPermission.Wait,\n waitPosition: waitPos,\n speedMultiplier: 0,\n zone,\n queuePosition\n });\n }\n }\n }\n }\n\n /**\n * @zh 计算等待位置\n * @en Compute wait position\n */\n private computeWaitPosition(agent: IFlowAgentData, zone: ICongestionZone): IVector2 {\n const dx = agent.position.x - zone.center.x;\n const dy = agent.position.y - zone.center.y;\n const dist = Math.sqrt(dx * dx + dy * dy);\n\n if (dist < 0.001) {\n return {\n x: zone.center.x + zone.radius + this.config.waitPointDistance,\n y: zone.center.y\n };\n }\n\n const dirX = dx / dist;\n const dirY = dy / dist;\n const waitDist = zone.radius + this.config.waitPointDistance;\n\n return {\n x: zone.center.x + dirX * waitDist,\n y: zone.center.y + dirY * waitDist\n };\n }\n\n /**\n * @zh 清理空的动态区域\n * @en Cleanup empty dynamic zones\n */\n private cleanupEmptyZones(): void {\n const toRemove: number[] = [];\n\n for (const [zoneId, state] of this.zoneStates) {\n if (!state.isStatic && state.queue.length === 0) {\n toRemove.push(zoneId);\n }\n }\n\n for (const zoneId of toRemove) {\n this.zoneStates.delete(zoneId);\n }\n }\n}\n\n/**\n * @zh 创建流量控制器\n * @en Create flow controller\n *\n * @param config - @zh 配置参数 @en Configuration\n * @returns @zh 流量控制器实例 @en Flow controller instance\n */\nexport function createFlowController(config?: IFlowControllerConfig): FlowController {\n return new FlowController(config);\n}\n"],"mappings":"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","names":["createPoint","x","y","EMPTY_PATH_RESULT","found","path","cost","nodesSearched","manhattanDistance","a","b","Math","abs","euclideanDistance","dx","dy","sqrt","chebyshevDistance","max","octileDistance","D","D2","SQRT2","min","DEFAULT_PATHFINDING_OPTIONS","maxNodes","heuristicWeight","allowDiagonal","avoidCorners","agentRadius","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","IndexedBinaryHeap","compare","heap","size","length","isEmpty","push","item","heapIndex","bubbleUp","pop","undefined","result","last","sinkDown","peek","update","index","contains","remove","clear","parentIndex","parent","halfLength","leftIndex","rightIndex","smallest","smallestItem","left","right","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","DEFAULT_PATH_CACHE_CONFIG","maxEntries","ttlMs","enableApproximateMatch","approximateRange","PathCache","config","cache","accessOrder","Map","get","startX","startY","endX","endY","mapVersion","key","generateKey","entry","getApproximate","isValid","delete","removeFromAccessOrder","updateAccessOrder","result","set","size","evictLRU","timestamp","Date","now","invalidateAll","clear","length","invalidateRegion","minX","minY","maxX","maxY","keysToDelete","path","point","x","y","push","getStats","maxSize","cleanup","age","range","sx","sy","ex","ey","adjustPathForApproximate","newStartX","newStartY","newEndX","newEndY","newPath","oldStart","oldEnd","index","indexOf","splice","lruKey","shift","createPathCache","IncrementalAStarPathfinder","map","config","sessions","Map","nextRequestId","affectedRegions","maxRegionAge","cache","enableCache","mapVersion","cacheHits","cacheMisses","PathCache","cacheConfig","requestPath","startX","startY","endX","endY","options","id","priority","opts","DEFAULT_PATHFINDING_OPTIONS","request","createdAt","Date","now","cached","get","session","state","found","PathfindingState","Completed","Failed","openList","IndexedBinaryHeap","a","b","f","nodeCache","startNode","getNodeAt","endNode","endPosition","x","y","nodesSearched","framesUsed","initialDistance","result","requestId","path","cost","isPartial","affectedByChange","set","walkable","position","createEmptyResult","heuristic","startAStarNode","node","g","h","heuristicWeight","parent","closed","opened","heapIndex","push","InProgress","step","maxIterations","EMPTY_PROGRESS","createProgress","iterations","isEmpty","current","pop","buildResult","req","expandNeighbors","maxNodes","pause","Paused","resume","cancel","Cancelled","getResult","getProgress","cleanup","clear","delete","notifyObstacleChange","minX","minY","maxX","maxY","invalidateRegion","region","timestamp","values","sessionAffectedByRegion","cleanupOldRegions","length","clearCache","invalidateAll","getCacheStats","enabled","hits","misses","hitRate","size","total","getStats","isAffectedByChange","clearChangeFlag","neighbors","getNeighbors","neighborNode","neighbor","Infinity","movementCost","getMovementCost","tentativeG","update","estimatedProgress","bestNode","peek","currentDistance","Math","max","min","openListSize","reverse","astarNode","pos","start","end","i","splice","createIncrementalAStarPathfinder","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","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","_a","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","EMPTY_PLAN_RESULT","found","path","cost","nodesSearched","PathPlanState","isIncrementalPlanner","planner","supportsIncremental","EMPTY_COLLISION_RESULT","collided","penetration","normal","x","y","closestPoint","PassPermission","DEFAULT_FLOW_CONTROLLER_CONFIG","detectionRadius","minAgentsForCongestion","defaultCapacity","waitPointDistance","yieldSpeedMultiplier","NavMeshPathPlannerAdapter","navMesh","type","findPath","start","end","options","result","findPathWithObstacles","x","y","agentRadius","undefined","found","EMPTY_PLAN_RESULT","path","map","p","cost","nodesSearched","isWalkable","position","getNearestWalkable","polygon","findPolygonAt","polygons","getPolygons","length","nearestDist","Infinity","nearestPoint","poly","dx","center","dy","dist","clear","dispose","createNavMeshPathPlanner","GridPathfinderAdapter","pathfinder","map","options","type","config","cellSize","alignToCenter","Number","isFinite","Error","toGridCoord","pixel","Math","floor","toPixelCoord","grid","base","findPath","start","end","startGridX","x","startGridY","y","endGridX","endGridY","result","found","EMPTY_PLAN_RESULT","path","p","cost","nodesSearched","isWalkable","position","getNearestWalkable","radius","dx","dy","abs","clear","dispose","createAStarPlanner","AStarPathfinder","createJPSPlanner","JPSPathfinder","createHPAPlanner","hpaConfig","adapterConfig","HPAPathfinder","toPathPlanState","state","PathfindingState","Idle","PlanState","InProgress","Completed","Failed","Cancelled","IncrementalGridPathPlannerAdapter","map","options","config","type","supportsIncremental","pathfinder","cellSize","alignToCenter","activeRequests","Set","requestTotalNodes","Map","Number","isFinite","Error","IncrementalAStarPathfinder","toGridCoord","pixel","Math","floor","toPixelCoord","grid","base","findPath","start","end","startGridX","x","startGridY","y","endGridX","endGridY","request","requestPath","progress","step","id","result","getResult","cleanup","found","EMPTY_PLAN_RESULT","path","p","cost","nodesSearched","isWalkable","position","getNearestWalkable","radius","dx","dy","abs","clear","dispose","add","set","requestId","iterations","prevTotal","get","newTotal","estimatedProgress","totalNodesSearched","cancel","delete","getActiveRequestCount","size","createIncrementalAStarPlanner","DEFAULT_ORCA_PARAMS","neighborDist","maxNeighbors","timeHorizon","timeHorizonObst","ORCALocalAvoidanceAdapter","config","type","solver","kdTree","defaultParams","createORCASolver","createKDTree","setDefaultParams","params","Object","assign","getDefaultParams","computeAvoidanceVelocity","agent","neighbors","obstacles","deltaTime","orcaAgent","toORCAAgent","orcaNeighbors","map","n","orcaObstacles","o","toORCAObstacle","result","computeNewVelocityWithResult","velocity","feasible","computeBatchAvoidance","agents","results","Map","orcaAgents","a","build","i","length","neighborResults","queryNeighbors","position","id","r","set","dispose","clear","x","y","preferredVelocity","radius","maxSpeed","obstacle","vertices","v","createORCAAvoidance","CollisionResolverAdapter","config","type","resolver","createCollisionResolver","detectCollision","position","radius","obstacles","length","EMPTY_COLLISION_RESULT","result","detectCollisions","map","o","vertices","v","x","y","collided","penetration","normal","closestPoint","resolveCollision","resolved","validateVelocity","velocity","deltaTime","detectAgentCollision","posA","radiusA","posB","radiusB","dispose","createDefaultCollisionResolver","FlowController","config","type","zoneStates","Map","agentZoneMap","agentResults","nextZoneId","currentTime","DEFAULT_FLOW_CONTROLLER_CONFIG","update","agents","deltaTime","clear","detectDynamicCongestion","updateZoneQueues","computeFlowControlResults","cleanupEmptyZones","getFlowControl","agentId","get","permission","PassPermission","Proceed","waitPosition","speedMultiplier","zone","queuePosition","getCongestionZones","Array","from","values","map","s","addStaticZone","center","radius","capacity","zoneId","id","x","y","agentIds","congestionLevel","set","queue","passingAgents","Set","isStatic","removeStaticZone","state","delete","dispose","clusters","clusterAgents","cluster","length","minAgentsForCongestion","computeClusterCenter","computeClusterRadius","existingZone","findZoneContaining","updateDynamicZone","createDynamicZone","visited","detectionRadiusSq","detectionRadius","agent","has","destination","add","current","shift","other","dx","position","dy","distSq","push","sumX","sumY","maxDistSq","Math","max","sqrt","point","a","min","capacityEstimate","defaultCapacity","floor","PI","agentMap","newAgentIds","expandedRadius","waitPointDistance","existingEntry","find","e","enterTime","priority","filter","entry","sort","b","passingCount","isInsideZone","findIndex","speedMult","Yield","yieldSpeedMultiplier","waitPos","computeWaitPosition","Wait","dist","dirX","dirY","waitDist","toRemove","createFlowController"]}
|