@esengine/pathfinding 13.3.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/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/core/GridPathfinder.ts","../src/core/PathValidator.ts","../src/grid/GridMap.ts","../src/navmesh/NavMesh.ts","../src/smoothing/PathSmoother.ts","../src/smoothing/RadiusAwarePathSmoother.ts"],"sourcesContent":["/**\n * @zh 网格寻路器(统一实现)\n * @en Grid Pathfinder (unified implementation)\n */\n\nimport type { IPathfinder, IPathResult, IPathfindingOptions, IPoint } from './IPathfinding';\nimport { EMPTY_PATH_RESULT, DEFAULT_PATHFINDING_OPTIONS } from './IPathfinding';\nimport { GridMap } from '../grid/GridMap';\n\n// =============================================================================\n// 配置 | Configuration\n// =============================================================================\n\n/**\n * @zh 寻路模式\n * @en Pathfinding mode\n */\nexport type GridPathfinderMode = 'standard' | 'fast' | 'bidirectional';\n\n/**\n * @zh 网格寻路器配置\n * @en Grid pathfinder configuration\n */\nexport interface IGridPathfinderConfig {\n /**\n * @zh 寻路模式\n * @en Pathfinding mode\n *\n * - standard: 标准A*,适合小地图\n * - fast: TypedArray优化,适合中大地图\n * - bidirectional: 双向搜索,适合超大地图\n */\n mode?: GridPathfinderMode;\n}\n\n// =============================================================================\n// 常量 | Constants\n// =============================================================================\n\nconst CLOSED_FLAG = 1;\nconst OPENED_FLAG = 2;\nconst BACKWARD_CLOSED = 4;\nconst BACKWARD_OPENED = 8;\n\n// =============================================================================\n// 状态存储 | State Storage\n// =============================================================================\n\nclass GridState {\n private readonly size: number;\n readonly width: number;\n\n private g: Float32Array;\n private f: Float32Array;\n private flags: Uint8Array;\n private parent: Int32Array;\n private heapIndex: Int32Array;\n private version: Uint32Array;\n private currentVersion: number = 1;\n\n // 双向搜索额外状态\n private gBack: Float32Array | null = null;\n private fBack: Float32Array | null = null;\n private parentBack: Int32Array | null = null;\n private heapIndexBack: Int32Array | null = null;\n\n constructor(width: number, height: number, bidirectional: boolean = false) {\n this.width = width;\n this.size = width * height;\n\n this.g = new Float32Array(this.size);\n this.f = new Float32Array(this.size);\n this.flags = new Uint8Array(this.size);\n this.parent = new Int32Array(this.size);\n this.heapIndex = new Int32Array(this.size);\n this.version = new Uint32Array(this.size);\n\n if (bidirectional) {\n this.gBack = new Float32Array(this.size);\n this.fBack = new Float32Array(this.size);\n this.parentBack = new Int32Array(this.size);\n this.heapIndexBack = new Int32Array(this.size);\n }\n }\n\n reset(): void {\n this.currentVersion++;\n if (this.currentVersion > 0xFFFFFFFF) {\n this.version.fill(0);\n this.currentVersion = 1;\n }\n }\n\n private isInit(i: number): boolean {\n return this.version[i] === this.currentVersion;\n }\n\n private init(i: number): void {\n if (!this.isInit(i)) {\n this.g[i] = Infinity;\n this.f[i] = Infinity;\n this.flags[i] = 0;\n this.parent[i] = -1;\n this.heapIndex[i] = -1;\n if (this.gBack) {\n this.gBack[i] = Infinity;\n this.fBack![i] = Infinity;\n this.parentBack![i] = -1;\n this.heapIndexBack![i] = -1;\n }\n this.version[i] = this.currentVersion;\n }\n }\n\n // Forward\n getG(i: number): number { return this.isInit(i) ? this.g[i] : Infinity; }\n setG(i: number, v: number): void { this.init(i); this.g[i] = v; }\n getF(i: number): number { return this.isInit(i) ? this.f[i] : Infinity; }\n setF(i: number, v: number): void { this.init(i); this.f[i] = v; }\n getParent(i: number): number { return this.isInit(i) ? this.parent[i] : -1; }\n setParent(i: number, v: number): void { this.init(i); this.parent[i] = v; }\n getHeapIndex(i: number): number { return this.isInit(i) ? this.heapIndex[i] : -1; }\n setHeapIndex(i: number, v: number): void { this.init(i); this.heapIndex[i] = v; }\n isClosed(i: number): boolean { return this.isInit(i) && (this.flags[i] & CLOSED_FLAG) !== 0; }\n setClosed(i: number): void { this.init(i); this.flags[i] |= CLOSED_FLAG; }\n isOpened(i: number): boolean { return this.isInit(i) && (this.flags[i] & OPENED_FLAG) !== 0; }\n setOpened(i: number): void { this.init(i); this.flags[i] |= OPENED_FLAG; }\n\n // Backward\n getGBack(i: number): number { return this.isInit(i) ? this.gBack![i] : Infinity; }\n setGBack(i: number, v: number): void { this.init(i); this.gBack![i] = v; }\n getFBack(i: number): number { return this.isInit(i) ? this.fBack![i] : Infinity; }\n setFBack(i: number, v: number): void { this.init(i); this.fBack![i] = v; }\n getParentBack(i: number): number { return this.isInit(i) ? this.parentBack![i] : -1; }\n setParentBack(i: number, v: number): void { this.init(i); this.parentBack![i] = v; }\n getHeapIndexBack(i: number): number { return this.isInit(i) ? this.heapIndexBack![i] : -1; }\n setHeapIndexBack(i: number, v: number): void { this.init(i); this.heapIndexBack![i] = v; }\n isClosedBack(i: number): boolean { return this.isInit(i) && (this.flags[i] & BACKWARD_CLOSED) !== 0; }\n setClosedBack(i: number): void { this.init(i); this.flags[i] |= BACKWARD_CLOSED; }\n isOpenedBack(i: number): boolean { return this.isInit(i) && (this.flags[i] & BACKWARD_OPENED) !== 0; }\n setOpenedBack(i: number): void { this.init(i); this.flags[i] |= BACKWARD_OPENED; }\n}\n\n// =============================================================================\n// 堆 | Heap\n// =============================================================================\n\nclass GridHeap {\n private heap: number[] = [];\n private state: GridState;\n private isBack: boolean;\n\n constructor(state: GridState, isBack: boolean = false) {\n this.state = state;\n this.isBack = isBack;\n }\n\n get size(): number { return this.heap.length; }\n get isEmpty(): boolean { return this.heap.length === 0; }\n\n private getF(i: number): number {\n return this.isBack ? this.state.getFBack(i) : this.state.getF(i);\n }\n private getHeapIndex(i: number): number {\n return this.isBack ? this.state.getHeapIndexBack(i) : this.state.getHeapIndex(i);\n }\n private setHeapIndex(i: number, v: number): void {\n if (this.isBack) this.state.setHeapIndexBack(i, v);\n else this.state.setHeapIndex(i, v);\n }\n\n push(i: number): void {\n this.setHeapIndex(i, this.heap.length);\n this.heap.push(i);\n this.bubbleUp(this.heap.length - 1);\n }\n\n pop(): number {\n if (this.heap.length === 0) return -1;\n const result = this.heap[0];\n this.setHeapIndex(result, -1);\n const last = this.heap.pop()!;\n if (this.heap.length > 0) {\n this.heap[0] = last;\n this.setHeapIndex(last, 0);\n this.sinkDown(0);\n }\n return result;\n }\n\n update(i: number): void {\n const pos = this.getHeapIndex(i);\n if (pos >= 0 && pos < this.heap.length) {\n this.bubbleUp(pos);\n this.sinkDown(this.getHeapIndex(i));\n }\n }\n\n clear(): void { this.heap.length = 0; }\n\n private bubbleUp(pos: number): void {\n const idx = this.heap[pos];\n const f = this.getF(idx);\n while (pos > 0) {\n const pp = (pos - 1) >> 1;\n const pi = this.heap[pp];\n if (f >= this.getF(pi)) break;\n this.heap[pos] = pi;\n this.setHeapIndex(pi, pos);\n pos = pp;\n }\n this.heap[pos] = idx;\n this.setHeapIndex(idx, pos);\n }\n\n private sinkDown(pos: number): void {\n const len = this.heap.length;\n const idx = this.heap[pos];\n const f = this.getF(idx);\n const half = len >> 1;\n while (pos < half) {\n const left = (pos << 1) + 1;\n const right = left + 1;\n let smallest = pos, smallestF = f;\n const lf = this.getF(this.heap[left]);\n if (lf < smallestF) { smallest = left; smallestF = lf; }\n if (right < len) {\n const rf = this.getF(this.heap[right]);\n if (rf < smallestF) smallest = right;\n }\n if (smallest === pos) break;\n const si = this.heap[smallest];\n this.heap[pos] = si;\n this.setHeapIndex(si, pos);\n pos = smallest;\n }\n this.heap[pos] = idx;\n this.setHeapIndex(idx, pos);\n }\n}\n\n// =============================================================================\n// 网格寻路器 | Grid Pathfinder\n// =============================================================================\n\n/**\n * @zh 网格寻路器\n * @en Grid Pathfinder\n */\nexport class GridPathfinder implements IPathfinder {\n private readonly map: GridMap;\n private readonly mode: GridPathfinderMode;\n private readonly state: GridState;\n private readonly openList: GridHeap;\n private readonly openListBack: GridHeap | null;\n\n constructor(map: GridMap, config?: IGridPathfinderConfig) {\n this.map = map;\n this.mode = config?.mode ?? 'fast';\n const isBidir = this.mode === 'bidirectional';\n this.state = new GridState(map.width, map.height, isBidir);\n this.openList = new GridHeap(this.state, false);\n this.openListBack = isBidir ? new GridHeap(this.state, true) : null;\n }\n\n findPath(\n startX: number,\n startY: number,\n endX: number,\n endY: number,\n options?: IPathfindingOptions\n ): IPathResult {\n if (this.mode === 'bidirectional') {\n return this.findPathBidirectional(startX, startY, endX, endY, options);\n }\n return this.findPathUnidirectional(startX, startY, endX, endY, options);\n }\n\n private findPathUnidirectional(\n startX: number, startY: number,\n endX: number, endY: number,\n options?: IPathfindingOptions\n ): IPathResult {\n const opts = options ? { ...DEFAULT_PATHFINDING_OPTIONS, ...options } : DEFAULT_PATHFINDING_OPTIONS;\n const { width, height } = this.map;\n\n this.state.reset();\n this.openList.clear();\n\n if (!this.validate(startX, startY, endX, endY)) return EMPTY_PATH_RESULT;\n\n const startIdx = startY * width + startX;\n const endIdx = endY * width + endX;\n\n if (startIdx === endIdx) {\n return { found: true, path: [{ x: startX, y: startY }], cost: 0, nodesSearched: 1 };\n }\n\n const hw = opts.heuristicWeight;\n const h0 = this.map.heuristic({ x: startX, y: startY }, { x: endX, y: endY }) * hw;\n this.state.setG(startIdx, 0);\n this.state.setF(startIdx, h0);\n this.state.setOpened(startIdx);\n this.openList.push(startIdx);\n\n let searched = 0;\n const maxNodes = opts.maxNodes;\n const { allowDiagonal, avoidCorners, diagonalCost } = this.map['options'];\n const nodes = this.map['nodes'];\n const dx = allowDiagonal ? [0, 1, 1, 1, 0, -1, -1, -1] : [0, 1, 0, -1];\n const dy = allowDiagonal ? [-1, -1, 0, 1, 1, 1, 0, -1] : [-1, 0, 1, 0];\n const dirCount = dx.length;\n\n while (!this.openList.isEmpty && searched < maxNodes) {\n const cur = this.openList.pop();\n this.state.setClosed(cur);\n searched++;\n\n if (cur === endIdx) {\n return this.buildPath(startIdx, endIdx, searched);\n }\n\n const cx = cur % width, cy = (cur / width) | 0;\n const curG = this.state.getG(cur);\n\n for (let d = 0; d < dirCount; d++) {\n const nx = cx + dx[d], ny = cy + dy[d];\n if (nx < 0 || nx >= width || ny < 0 || ny >= height) continue;\n\n const neighbor = nodes[ny][nx];\n if (!neighbor.walkable) continue;\n\n if (avoidCorners && dx[d] !== 0 && dy[d] !== 0) {\n if (!nodes[cy][cx + dx[d]].walkable || !nodes[cy + dy[d]][cx].walkable) continue;\n }\n\n const ni = ny * width + nx;\n if (this.state.isClosed(ni)) continue;\n\n const isDiag = dx[d] !== 0 && dy[d] !== 0;\n const cost = isDiag ? neighbor.cost * diagonalCost : neighbor.cost;\n const tentG = curG + cost;\n\n if (!this.state.isOpened(ni)) {\n const h = this.map.heuristic({ x: nx, y: ny }, { x: endX, y: endY }) * hw;\n this.state.setG(ni, tentG);\n this.state.setF(ni, tentG + h);\n this.state.setParent(ni, cur);\n this.state.setOpened(ni);\n this.openList.push(ni);\n } else if (tentG < this.state.getG(ni)) {\n const h = this.state.getF(ni) - this.state.getG(ni);\n this.state.setG(ni, tentG);\n this.state.setF(ni, tentG + h);\n this.state.setParent(ni, cur);\n this.openList.update(ni);\n }\n }\n }\n\n return { found: false, path: [], cost: 0, nodesSearched: searched };\n }\n\n private findPathBidirectional(\n startX: number, startY: number,\n endX: number, endY: number,\n options?: IPathfindingOptions\n ): IPathResult {\n const opts = options ? { ...DEFAULT_PATHFINDING_OPTIONS, ...options } : DEFAULT_PATHFINDING_OPTIONS;\n const { width, height } = this.map;\n\n this.state.reset();\n this.openList.clear();\n this.openListBack!.clear();\n\n if (!this.validate(startX, startY, endX, endY)) return EMPTY_PATH_RESULT;\n\n const startIdx = startY * width + startX;\n const endIdx = endY * width + endX;\n\n if (startIdx === endIdx) {\n return { found: true, path: [{ x: startX, y: startY }], cost: 0, nodesSearched: 1 };\n }\n\n const hw = opts.heuristicWeight;\n const startPos = { x: startX, y: startY };\n const endPos = { x: endX, y: endY };\n\n // Init forward\n const hf = this.map.heuristic(startPos, endPos) * hw;\n this.state.setG(startIdx, 0);\n this.state.setF(startIdx, hf);\n this.state.setOpened(startIdx);\n this.openList.push(startIdx);\n\n // Init backward\n const hb = this.map.heuristic(endPos, startPos) * hw;\n this.state.setGBack(endIdx, 0);\n this.state.setFBack(endIdx, hb);\n this.state.setOpenedBack(endIdx);\n this.openListBack!.push(endIdx);\n\n let searched = 0;\n const maxNodes = opts.maxNodes;\n let meetIdx = -1, bestCost = Infinity;\n\n const { allowDiagonal, avoidCorners, diagonalCost } = this.map['options'];\n const nodes = this.map['nodes'];\n const dx = allowDiagonal ? [0, 1, 1, 1, 0, -1, -1, -1] : [0, 1, 0, -1];\n const dy = allowDiagonal ? [-1, -1, 0, 1, 1, 1, 0, -1] : [-1, 0, 1, 0];\n const dirCount = dx.length;\n\n while ((!this.openList.isEmpty || !this.openListBack!.isEmpty) && searched < maxNodes) {\n // Forward\n if (!this.openList.isEmpty) {\n const cur = this.openList.pop();\n this.state.setClosed(cur);\n searched++;\n\n const curG = this.state.getG(cur);\n if (this.state.isClosedBack(cur)) {\n const total = curG + this.state.getGBack(cur);\n if (total < bestCost) { bestCost = total; meetIdx = cur; }\n }\n if (meetIdx !== -1 && curG >= bestCost) break;\n\n const cx = cur % width, cy = (cur / width) | 0;\n for (let d = 0; d < dirCount; d++) {\n const nx = cx + dx[d], ny = cy + dy[d];\n if (nx < 0 || nx >= width || ny < 0 || ny >= height) continue;\n const neighbor = nodes[ny][nx];\n if (!neighbor.walkable) continue;\n if (avoidCorners && dx[d] !== 0 && dy[d] !== 0) {\n if (!nodes[cy][cx + dx[d]].walkable || !nodes[cy + dy[d]][cx].walkable) continue;\n }\n const ni = ny * width + nx;\n if (this.state.isClosed(ni)) continue;\n const isDiag = dx[d] !== 0 && dy[d] !== 0;\n const cost = isDiag ? neighbor.cost * diagonalCost : neighbor.cost;\n const tentG = curG + cost;\n if (!this.state.isOpened(ni)) {\n const h = this.map.heuristic({ x: nx, y: ny }, endPos) * hw;\n this.state.setG(ni, tentG);\n this.state.setF(ni, tentG + h);\n this.state.setParent(ni, cur);\n this.state.setOpened(ni);\n this.openList.push(ni);\n } else if (tentG < this.state.getG(ni)) {\n const h = this.state.getF(ni) - this.state.getG(ni);\n this.state.setG(ni, tentG);\n this.state.setF(ni, tentG + h);\n this.state.setParent(ni, cur);\n this.openList.update(ni);\n }\n }\n }\n\n // Backward\n if (!this.openListBack!.isEmpty) {\n const cur = this.openListBack!.pop();\n this.state.setClosedBack(cur);\n searched++;\n\n const curG = this.state.getGBack(cur);\n if (this.state.isClosed(cur)) {\n const total = curG + this.state.getG(cur);\n if (total < bestCost) { bestCost = total; meetIdx = cur; }\n }\n if (meetIdx !== -1 && curG >= bestCost) break;\n\n const cx = cur % width, cy = (cur / width) | 0;\n for (let d = 0; d < dirCount; d++) {\n const nx = cx + dx[d], ny = cy + dy[d];\n if (nx < 0 || nx >= width || ny < 0 || ny >= height) continue;\n const neighbor = nodes[ny][nx];\n if (!neighbor.walkable) continue;\n if (avoidCorners && dx[d] !== 0 && dy[d] !== 0) {\n if (!nodes[cy][cx + dx[d]].walkable || !nodes[cy + dy[d]][cx].walkable) continue;\n }\n const ni = ny * width + nx;\n if (this.state.isClosedBack(ni)) continue;\n const isDiag = dx[d] !== 0 && dy[d] !== 0;\n const cost = isDiag ? neighbor.cost * diagonalCost : neighbor.cost;\n const tentG = curG + cost;\n if (!this.state.isOpenedBack(ni)) {\n const h = this.map.heuristic({ x: nx, y: ny }, startPos) * hw;\n this.state.setGBack(ni, tentG);\n this.state.setFBack(ni, tentG + h);\n this.state.setParentBack(ni, cur);\n this.state.setOpenedBack(ni);\n this.openListBack!.push(ni);\n } else if (tentG < this.state.getGBack(ni)) {\n const h = this.state.getFBack(ni) - this.state.getGBack(ni);\n this.state.setGBack(ni, tentG);\n this.state.setFBack(ni, tentG + h);\n this.state.setParentBack(ni, cur);\n this.openListBack!.update(ni);\n }\n }\n }\n }\n\n if (meetIdx === -1) {\n return { found: false, path: [], cost: 0, nodesSearched: searched };\n }\n\n return this.buildPathBidirectional(startIdx, endIdx, meetIdx, searched);\n }\n\n private validate(startX: number, startY: number, endX: number, endY: number): boolean {\n const { width, height } = this.map;\n if (startX < 0 || startX >= width || startY < 0 || startY >= height) return false;\n if (endX < 0 || endX >= width || endY < 0 || endY >= height) return false;\n return this.map.isWalkable(startX, startY) && this.map.isWalkable(endX, endY);\n }\n\n private buildPath(startIdx: number, endIdx: number, searched: number): IPathResult {\n const w = this.state.width;\n const path: IPoint[] = [];\n let cur = endIdx;\n while (cur !== -1) {\n path.push({ x: cur % w, y: (cur / w) | 0 });\n cur = cur === startIdx ? -1 : this.state.getParent(cur);\n }\n path.reverse();\n return { found: true, path, cost: this.state.getG(endIdx), nodesSearched: searched };\n }\n\n private buildPathBidirectional(startIdx: number, endIdx: number, meetIdx: number, searched: number): IPathResult {\n const w = this.state.width;\n const path: IPoint[] = [];\n\n // Forward path\n let cur = meetIdx;\n while (cur !== -1 && cur !== startIdx) {\n path.push({ x: cur % w, y: (cur / w) | 0 });\n cur = this.state.getParent(cur);\n }\n path.push({ x: startIdx % w, y: (startIdx / w) | 0 });\n path.reverse();\n\n // Backward path\n cur = this.state.getParentBack(meetIdx);\n while (cur !== -1 && cur !== endIdx) {\n path.push({ x: cur % w, y: (cur / w) | 0 });\n cur = this.state.getParentBack(cur);\n }\n if (meetIdx !== endIdx) {\n path.push({ x: endIdx % w, y: (endIdx / w) | 0 });\n }\n\n const cost = this.state.getG(meetIdx) + this.state.getGBack(meetIdx);\n return { found: true, path, cost, nodesSearched: searched };\n }\n\n clear(): void {\n this.state.reset();\n this.openList.clear();\n this.openListBack?.clear();\n }\n}\n\n/**\n * @zh 创建网格寻路器\n * @en Create grid pathfinder\n */\nexport function createGridPathfinder(map: GridMap, config?: IGridPathfinderConfig): GridPathfinder {\n return new GridPathfinder(map, config);\n}\n","/**\n * @zh 路径验证器\n * @en Path Validator\n */\n\nimport type { IPoint, IPathfindingMap } from './IPathfinding';\nimport type { IPathValidator, IPathValidationResult } from './IIncrementalPathfinding';\n\n// =============================================================================\n// 路径验证器 | Path Validator\n// =============================================================================\n\n/**\n * @zh 路径验证器\n * @en Path Validator\n *\n * @zh 用于检查现有路径在地图变化后是否仍然有效\n * @en Used to check if an existing path is still valid after map changes\n *\n * @example\n * ```typescript\n * const validator = new PathValidator();\n * const result = validator.validatePath(path, 0, path.length, map);\n *\n * if (!result.valid) {\n * console.log('Path invalid at index:', result.invalidIndex);\n * // Trigger replanning from current position\n * }\n * ```\n */\nexport class PathValidator implements IPathValidator {\n /**\n * @zh 验证路径段的有效性\n * @en Validate path segment validity\n *\n * @param path - @zh 要验证的路径 @en Path to validate\n * @param fromIndex - @zh 起始索引 @en Start index\n * @param toIndex - @zh 结束索引 @en End index\n * @param map - @zh 地图实例 @en Map instance\n * @returns @zh 验证结果 @en Validation result\n */\n validatePath(\n path: readonly IPoint[],\n fromIndex: number,\n toIndex: number,\n map: IPathfindingMap\n ): IPathValidationResult {\n const end = Math.min(toIndex, path.length);\n\n for (let i = fromIndex; i < end; i++) {\n const point = path[i];\n const x = Math.floor(point.x);\n const y = Math.floor(point.y);\n\n if (!map.isWalkable(x, y)) {\n return { valid: false, invalidIndex: i };\n }\n\n if (i > fromIndex) {\n const prev = path[i - 1];\n if (!this.checkLineOfSight(prev.x, prev.y, point.x, point.y, map)) {\n return { valid: false, invalidIndex: i };\n }\n }\n }\n\n return { valid: true, invalidIndex: -1 };\n }\n\n /**\n * @zh 检查两点之间的视线(使用 Bresenham 算法)\n * @en Check line of sight between two points (using Bresenham algorithm)\n *\n * @param x1 - @zh 起点 X @en Start X\n * @param y1 - @zh 起点 Y @en Start Y\n * @param x2 - @zh 终点 X @en End X\n * @param y2 - @zh 终点 Y @en End Y\n * @param map - @zh 地图实例 @en Map instance\n * @returns @zh 是否有视线 @en Whether there is line of sight\n */\n private checkLineOfSight(\n x1: number,\n y1: number,\n x2: number,\n y2: number,\n map: IPathfindingMap\n ): boolean {\n const ix1 = Math.floor(x1);\n const iy1 = Math.floor(y1);\n const ix2 = Math.floor(x2);\n const iy2 = Math.floor(y2);\n\n let dx = Math.abs(ix2 - ix1);\n let dy = Math.abs(iy2 - iy1);\n let x = ix1;\n let y = iy1;\n\n const sx = ix1 < ix2 ? 1 : -1;\n const sy = iy1 < iy2 ? 1 : -1;\n\n if (dx > dy) {\n let err = dx / 2;\n while (x !== ix2) {\n if (!map.isWalkable(x, y)) {\n return false;\n }\n err -= dy;\n if (err < 0) {\n y += sy;\n err += dx;\n }\n x += sx;\n }\n } else {\n let err = dy / 2;\n while (y !== iy2) {\n if (!map.isWalkable(x, y)) {\n return false;\n }\n err -= dx;\n if (err < 0) {\n x += sx;\n err += dy;\n }\n y += sy;\n }\n }\n\n return map.isWalkable(ix2, iy2);\n }\n}\n\n// =============================================================================\n// 障碍物变化管理器 | Obstacle Change Manager\n// =============================================================================\n\n/**\n * @zh 障碍物变化记录\n * @en Obstacle change record\n */\nexport interface IObstacleChange {\n /**\n * @zh X 坐标\n * @en X coordinate\n */\n readonly x: number;\n\n /**\n * @zh Y 坐标\n * @en Y coordinate\n */\n readonly y: number;\n\n /**\n * @zh 变化前是否可通行\n * @en Was walkable before change\n */\n readonly wasWalkable: boolean;\n\n /**\n * @zh 变化时间戳\n * @en Change timestamp\n */\n readonly timestamp: number;\n}\n\n/**\n * @zh 障碍物变化区域\n * @en Obstacle change region\n */\nexport interface IChangeRegion {\n /**\n * @zh 最小 X 坐标\n * @en Minimum X coordinate\n */\n readonly minX: number;\n\n /**\n * @zh 最小 Y 坐标\n * @en Minimum Y coordinate\n */\n readonly minY: number;\n\n /**\n * @zh 最大 X 坐标\n * @en Maximum X coordinate\n */\n readonly maxX: number;\n\n /**\n * @zh 最大 Y 坐标\n * @en Maximum Y coordinate\n */\n readonly maxY: number;\n}\n\n/**\n * @zh 障碍物变化管理器\n * @en Obstacle Change Manager\n *\n * @zh 跟踪地图障碍物变化,用于触发动态重规划\n * @en Tracks map obstacle changes, used to trigger dynamic replanning\n *\n * @example\n * ```typescript\n * const manager = new ObstacleChangeManager();\n *\n * // Record change when obstacle is added/removed\n * manager.recordChange(10, 20, true); // Was walkable, now blocked\n *\n * // Get affected region for notification\n * const region = manager.getAffectedRegion();\n * if (region) {\n * pathfinder.notifyObstacleChange(\n * region.minX, region.minY,\n * region.maxX, region.maxY\n * );\n * }\n *\n * // Clear after notification\n * manager.flush();\n * ```\n */\nexport class ObstacleChangeManager {\n private readonly changes: Map<string, IObstacleChange> = new Map();\n private epoch: number = 0;\n\n /**\n * @zh 记录障碍物变化\n * @en Record obstacle change\n *\n * @param x - @zh X 坐标 @en X coordinate\n * @param y - @zh Y 坐标 @en Y coordinate\n * @param wasWalkable - @zh 变化前是否可通行 @en Was walkable before change\n */\n recordChange(x: number, y: number, wasWalkable: boolean): void {\n const key = `${x},${y}`;\n this.changes.set(key, {\n x,\n y,\n wasWalkable,\n timestamp: Date.now()\n });\n }\n\n /**\n * @zh 获取影响区域\n * @en Get affected region\n *\n * @returns @zh 影响区域或 null(如果没有变化)@en Affected region or null if no changes\n */\n getAffectedRegion(): IChangeRegion | null {\n if (this.changes.size === 0) {\n return null;\n }\n\n let minX = Infinity;\n let minY = Infinity;\n let maxX = -Infinity;\n let maxY = -Infinity;\n\n for (const change of this.changes.values()) {\n minX = Math.min(minX, change.x);\n minY = Math.min(minY, change.y);\n maxX = Math.max(maxX, change.x);\n maxY = Math.max(maxY, change.y);\n }\n\n return { minX, minY, maxX, maxY };\n }\n\n /**\n * @zh 获取所有变化\n * @en Get all changes\n *\n * @returns @zh 变化列表 @en List of changes\n */\n getChanges(): IObstacleChange[] {\n return Array.from(this.changes.values());\n }\n\n /**\n * @zh 检查是否有变化\n * @en Check if there are changes\n *\n * @returns @zh 是否有变化 @en Whether there are changes\n */\n hasChanges(): boolean {\n return this.changes.size > 0;\n }\n\n /**\n * @zh 获取当前 epoch\n * @en Get current epoch\n *\n * @returns @zh 当前 epoch @en Current epoch\n */\n getEpoch(): number {\n return this.epoch;\n }\n\n /**\n * @zh 清空变化记录并推进 epoch\n * @en Clear changes and advance epoch\n */\n flush(): void {\n this.changes.clear();\n this.epoch++;\n }\n\n /**\n * @zh 清空所有状态\n * @en Clear all state\n */\n clear(): void {\n this.changes.clear();\n this.epoch = 0;\n }\n}\n\n// =============================================================================\n// 工厂函数 | Factory Functions\n// =============================================================================\n\n/**\n * @zh 创建路径验证器\n * @en Create path validator\n *\n * @returns @zh 路径验证器实例 @en Path validator instance\n */\nexport function createPathValidator(): PathValidator {\n return new PathValidator();\n}\n\n/**\n * @zh 创建障碍物变化管理器\n * @en Create obstacle change manager\n *\n * @returns @zh 障碍物变化管理器实例 @en Obstacle change manager instance\n */\nexport function createObstacleChangeManager(): ObstacleChangeManager {\n return new ObstacleChangeManager();\n}\n","/**\n * @zh 网格地图实现\n * @en Grid Map Implementation\n */\n\nimport type {\n IPathfindingMap,\n IPathNode,\n IPoint,\n HeuristicFunction\n} from '../core/IPathfinding';\nimport { createPoint, octileDistance } from '../core/IPathfinding';\n\n// =============================================================================\n// 网格节点 | Grid Node\n// =============================================================================\n\n/**\n * @zh 网格节点\n * @en Grid node\n */\nexport class GridNode implements IPathNode {\n readonly id: number;\n readonly position: IPoint;\n readonly x: number;\n readonly y: number;\n cost: number;\n walkable: boolean;\n\n constructor(x: number, y: number, width: number, walkable: boolean = true, cost: number = 1) {\n this.x = x;\n this.y = y;\n this.id = y * width + x;\n this.position = createPoint(x, y);\n this.walkable = walkable;\n this.cost = cost;\n }\n}\n\n// =============================================================================\n// 移动方向 | Movement Directions\n// =============================================================================\n\n/**\n * @zh 4方向偏移 (上下左右)\n * @en 4-directional offsets (up, down, left, right)\n */\nexport const DIRECTIONS_4 = [\n { dx: 0, dy: -1 }, // Up\n { dx: 1, dy: 0 }, // Right\n { dx: 0, dy: 1 }, // Down\n { dx: -1, dy: 0 } // Left\n] as const;\n\n/**\n * @zh 8方向偏移 (含对角线)\n * @en 8-directional offsets (including diagonals)\n */\nexport const DIRECTIONS_8 = [\n { dx: 0, dy: -1 }, // Up\n { dx: 1, dy: -1 }, // Up-Right\n { dx: 1, dy: 0 }, // Right\n { dx: 1, dy: 1 }, // Down-Right\n { dx: 0, dy: 1 }, // Down\n { dx: -1, dy: 1 }, // Down-Left\n { dx: -1, dy: 0 }, // Left\n { dx: -1, dy: -1 } // Up-Left\n] as const;\n\n// =============================================================================\n// 网格地图配置 | Grid Map Options\n// =============================================================================\n\n/**\n * @zh 网格地图配置\n * @en Grid map options\n */\nexport interface IGridMapOptions {\n /** @zh 是否允许对角移动 @en Allow diagonal movement */\n allowDiagonal?: boolean;\n /** @zh 对角移动代价 @en Diagonal movement cost */\n diagonalCost?: number;\n /** @zh 是否避免穿角 @en Avoid corner cutting */\n avoidCorners?: boolean;\n /** @zh 启发式函数 @en Heuristic function */\n heuristic?: HeuristicFunction;\n}\n\n/**\n * @zh 默认网格地图配置\n * @en Default grid map options\n */\nexport const DEFAULT_GRID_OPTIONS: Required<IGridMapOptions> = {\n allowDiagonal: true,\n diagonalCost: Math.SQRT2,\n avoidCorners: true,\n heuristic: octileDistance\n};\n\n// =============================================================================\n// 网格地图 | Grid Map\n// =============================================================================\n\n/**\n * @zh 网格地图\n * @en Grid Map\n *\n * @zh 基于二维数组的网格地图实现,支持4方向和8方向移动\n * @en Grid map implementation based on 2D array, supports 4 and 8 directional movement\n *\n * @example\n * ```typescript\n * // Create a 10x10 grid\n * const grid = new GridMap(10, 10);\n *\n * // Set some cells as obstacles\n * grid.setWalkable(5, 5, false);\n * grid.setWalkable(5, 6, false);\n *\n * // Use with pathfinder\n * const pathfinder = new AStarPathfinder(grid);\n * const result = pathfinder.findPath(0, 0, 9, 9);\n * ```\n */\nexport class GridMap implements IPathfindingMap {\n readonly width: number;\n readonly height: number;\n private readonly nodes: GridNode[][];\n private readonly options: Required<IGridMapOptions>;\n\n constructor(width: number, height: number, options?: IGridMapOptions) {\n this.width = width;\n this.height = height;\n this.options = { ...DEFAULT_GRID_OPTIONS, ...options };\n this.nodes = this.createNodes();\n }\n\n /**\n * @zh 创建网格节点\n * @en Create grid nodes\n */\n private createNodes(): GridNode[][] {\n const nodes: GridNode[][] = [];\n\n for (let y = 0; y < this.height; y++) {\n nodes[y] = [];\n for (let x = 0; x < this.width; x++) {\n nodes[y][x] = new GridNode(x, y, this.width, true, 1);\n }\n }\n\n return nodes;\n }\n\n /**\n * @zh 获取指定位置的节点\n * @en Get node at position\n */\n getNodeAt(x: number, y: number): GridNode | null {\n if (!this.isInBounds(x, y)) {\n return null;\n }\n return this.nodes[y][x];\n }\n\n /**\n * @zh 检查坐标是否在边界内\n * @en Check if coordinates are within bounds\n */\n isInBounds(x: number, y: number): boolean {\n return x >= 0 && x < this.width && y >= 0 && y < this.height;\n }\n\n /**\n * @zh 检查位置是否可通行\n * @en Check if position is walkable\n */\n isWalkable(x: number, y: number): boolean {\n const node = this.getNodeAt(x, y);\n return node !== null && node.walkable;\n }\n\n /**\n * @zh 设置位置是否可通行\n * @en Set position walkability\n */\n setWalkable(x: number, y: number, walkable: boolean): void {\n const node = this.getNodeAt(x, y);\n if (node) {\n node.walkable = walkable;\n }\n }\n\n /**\n * @zh 设置位置的移动代价\n * @en Set movement cost at position\n */\n setCost(x: number, y: number, cost: number): void {\n const node = this.getNodeAt(x, y);\n if (node) {\n node.cost = cost;\n }\n }\n\n /**\n * @zh 获取节点的邻居\n * @en Get neighbors of a node\n */\n getNeighbors(node: IPathNode): GridNode[] {\n const neighbors: GridNode[] = [];\n const { x, y } = node.position;\n const directions = this.options.allowDiagonal ? DIRECTIONS_8 : DIRECTIONS_4;\n\n for (let i = 0; i < directions.length; i++) {\n const dir = directions[i];\n const nx = x + dir.dx;\n const ny = y + dir.dy;\n\n if (nx < 0 || nx >= this.width || ny < 0 || ny >= this.height) {\n continue;\n }\n\n const neighbor = this.nodes[ny][nx];\n\n if (!neighbor.walkable) {\n continue;\n }\n\n if (this.options.avoidCorners && dir.dx !== 0 && dir.dy !== 0) {\n const hNode = this.nodes[y][x + dir.dx];\n const vNode = this.nodes[y + dir.dy][x];\n\n if (!hNode.walkable || !vNode.walkable) {\n continue;\n }\n }\n\n neighbors.push(neighbor);\n }\n\n return neighbors;\n }\n\n /**\n * @zh 遍历节点的邻居(零分配)\n * @en Iterate over neighbors (zero allocation)\n */\n forEachNeighbor(node: IPathNode, callback: (neighbor: GridNode) => boolean | void): void {\n const { x, y } = node.position;\n const directions = this.options.allowDiagonal ? DIRECTIONS_8 : DIRECTIONS_4;\n\n for (let i = 0; i < directions.length; i++) {\n const dir = directions[i];\n const nx = x + dir.dx;\n const ny = y + dir.dy;\n\n if (nx < 0 || nx >= this.width || ny < 0 || ny >= this.height) {\n continue;\n }\n\n const neighbor = this.nodes[ny][nx];\n\n if (!neighbor.walkable) {\n continue;\n }\n\n if (this.options.avoidCorners && dir.dx !== 0 && dir.dy !== 0) {\n const hNode = this.nodes[y][x + dir.dx];\n const vNode = this.nodes[y + dir.dy][x];\n\n if (!hNode.walkable || !vNode.walkable) {\n continue;\n }\n }\n\n if (callback(neighbor) === false) {\n return;\n }\n }\n }\n\n /**\n * @zh 计算启发式距离\n * @en Calculate heuristic distance\n */\n heuristic(a: IPoint, b: IPoint): number {\n return this.options.heuristic(a, b);\n }\n\n /**\n * @zh 计算移动代价\n * @en Calculate movement cost\n */\n getMovementCost(from: IPathNode, to: IPathNode): number {\n const dx = Math.abs(from.position.x - to.position.x);\n const dy = Math.abs(from.position.y - to.position.y);\n\n // Diagonal movement\n if (dx !== 0 && dy !== 0) {\n return to.cost * this.options.diagonalCost;\n }\n\n // Cardinal movement\n return to.cost;\n }\n\n /**\n * @zh 从二维数组加载地图\n * @en Load map from 2D array\n *\n * @param data - @zh 0=可通行,非0=不可通行 @en 0=walkable, non-0=blocked\n */\n loadFromArray(data: number[][]): void {\n for (let y = 0; y < Math.min(data.length, this.height); y++) {\n for (let x = 0; x < Math.min(data[y].length, this.width); x++) {\n this.nodes[y][x].walkable = data[y][x] === 0;\n }\n }\n }\n\n /**\n * @zh 从字符串加载地图\n * @en Load map from string\n *\n * @param str - @zh 地图字符串,'.'=可通行,'#'=障碍 @en Map string, '.'=walkable, '#'=blocked\n */\n loadFromString(str: string): void {\n const lines = str.trim().split('\\n');\n\n for (let y = 0; y < Math.min(lines.length, this.height); y++) {\n const line = lines[y];\n for (let x = 0; x < Math.min(line.length, this.width); x++) {\n this.nodes[y][x].walkable = line[x] !== '#';\n }\n }\n }\n\n /**\n * @zh 导出为字符串\n * @en Export to string\n */\n toString(): string {\n let result = '';\n\n for (let y = 0; y < this.height; y++) {\n for (let x = 0; x < this.width; x++) {\n result += this.nodes[y][x].walkable ? '.' : '#';\n }\n result += '\\n';\n }\n\n return result;\n }\n\n /**\n * @zh 重置所有节点为可通行\n * @en Reset all nodes to walkable\n */\n reset(): void {\n for (let y = 0; y < this.height; y++) {\n for (let x = 0; x < this.width; x++) {\n this.nodes[y][x].walkable = true;\n this.nodes[y][x].cost = 1;\n }\n }\n }\n\n /**\n * @zh 设置矩形区域的通行性\n * @en Set walkability for a rectangle region\n */\n setRectWalkable(\n x: number,\n y: number,\n width: number,\n height: number,\n walkable: boolean\n ): void {\n for (let dy = 0; dy < height; dy++) {\n for (let dx = 0; dx < width; dx++) {\n this.setWalkable(x + dx, y + dy, walkable);\n }\n }\n }\n}\n\n// =============================================================================\n// 工厂函数 | Factory Function\n// =============================================================================\n\n/**\n * @zh 创建网格地图\n * @en Create grid map\n */\nexport function createGridMap(\n width: number,\n height: number,\n options?: IGridMapOptions\n): GridMap {\n return new GridMap(width, height, options);\n}\n","/**\n * @zh 导航网格实现\n * @en NavMesh Implementation\n *\n * @zh 支持动态障碍物:可以临时禁用多边形或添加圆形/矩形障碍物\n * @en Supports dynamic obstacles: can temporarily disable polygons or add circular/rectangular obstacles\n */\n\nimport type {\n IPathfindingMap,\n IPathNode,\n IPoint,\n IPathResult,\n IPathfindingOptions\n} from '../core/IPathfinding';\nimport { createPoint, euclideanDistance, EMPTY_PATH_RESULT, DEFAULT_PATHFINDING_OPTIONS } from '../core/IPathfinding';\nimport { BinaryHeap } from '../core/BinaryHeap';\n\n// =============================================================================\n// 动态障碍物 | Dynamic Obstacles\n// =============================================================================\n\n/**\n * @zh 动态障碍物类型\n * @en Dynamic obstacle type\n */\nexport type ObstacleType = 'circle' | 'rect' | 'polygon';\n\n/**\n * @zh 动态障碍物\n * @en Dynamic obstacle\n */\nexport interface IDynamicObstacle {\n /**\n * @zh 障碍物 ID\n * @en Obstacle ID\n */\n readonly id: number;\n\n /**\n * @zh 障碍物类型\n * @en Obstacle type\n */\n readonly type: ObstacleType;\n\n /**\n * @zh 是否启用\n * @en Whether enabled\n */\n enabled: boolean;\n\n /**\n * @zh 位置(圆形和矩形的中心)\n * @en Position (center for circle and rect)\n */\n position: IPoint;\n\n /**\n * @zh 半径(圆形)或半宽/半高(矩形)\n * @en Radius (circle) or half-width/half-height (rect)\n */\n radius?: number;\n halfWidth?: number;\n halfHeight?: number;\n\n /**\n * @zh 顶点(多边形)\n * @en Vertices (polygon)\n */\n vertices?: readonly IPoint[];\n}\n\n// =============================================================================\n// 导航多边形 | Navigation Polygon\n// =============================================================================\n\n/**\n * @zh 导航多边形\n * @en Navigation polygon\n */\nexport interface INavPolygon {\n /** @zh 多边形ID @en Polygon ID */\n readonly id: number;\n /** @zh 顶点列表 @en Vertex list */\n readonly vertices: readonly IPoint[];\n /** @zh 中心点 @en Center point */\n readonly center: IPoint;\n /** @zh 邻居多边形ID @en Neighbor polygon IDs */\n readonly neighbors: readonly number[];\n /** @zh 到邻居的共享边 @en Shared edges to neighbors */\n readonly portals: ReadonlyMap<number, IPortal>;\n}\n\n/**\n * @zh 入口(两个多边形之间的共享边)\n * @en Portal (shared edge between two polygons)\n */\nexport interface IPortal {\n /** @zh 边的左端点 @en Left endpoint of edge */\n readonly left: IPoint;\n /** @zh 边的右端点 @en Right endpoint of edge */\n readonly right: IPoint;\n}\n\n// =============================================================================\n// 导航网格节点 | NavMesh Node\n// =============================================================================\n\n/**\n * @zh 导航网格节点(包装多边形)\n * @en NavMesh node (wraps polygon)\n */\nclass NavMeshNode implements IPathNode {\n readonly id: number;\n readonly position: IPoint;\n readonly cost: number;\n readonly walkable: boolean;\n readonly polygon: INavPolygon;\n\n constructor(polygon: INavPolygon) {\n this.id = polygon.id;\n this.position = polygon.center;\n this.cost = 1;\n this.walkable = true;\n this.polygon = polygon;\n }\n}\n\n// =============================================================================\n// 导航网格 | Navigation Mesh\n// =============================================================================\n\n/**\n * @zh 导航网格\n * @en Navigation Mesh\n *\n * @zh 使用凸多边形网格进行高效寻路,适合复杂地形\n * @en Uses convex polygon mesh for efficient pathfinding, suitable for complex terrain\n *\n * @example\n * ```typescript\n * const navmesh = new NavMesh();\n *\n * // Add polygons\n * navmesh.addPolygon([\n * { x: 0, y: 0 }, { x: 10, y: 0 },\n * { x: 10, y: 10 }, { x: 0, y: 10 }\n * ]);\n *\n * // Build connections\n * navmesh.build();\n *\n * // Find path\n * const result = navmesh.findPath(1, 1, 8, 8);\n * ```\n */\nexport class NavMesh implements IPathfindingMap {\n private polygons: Map<number, INavPolygon> = new Map();\n private nodes: Map<number, NavMeshNode> = new Map();\n private nextId = 0;\n\n // @zh 动态障碍物支持\n // @en Dynamic obstacle support\n private obstacles: Map<number, IDynamicObstacle> = new Map();\n private nextObstacleId = 0;\n private disabledPolygons: Set<number> = new Set();\n\n /**\n * @zh 添加导航多边形\n * @en Add navigation polygon\n *\n * @returns @zh 多边形ID @en Polygon ID\n */\n addPolygon(vertices: IPoint[], neighbors: number[] = []): number {\n const id = this.nextId++;\n const center = this.calculateCenter(vertices);\n\n const polygon: INavPolygon = {\n id,\n vertices,\n center,\n neighbors,\n portals: new Map()\n };\n\n this.polygons.set(id, polygon);\n this.nodes.set(id, new NavMeshNode(polygon));\n\n return id;\n }\n\n /**\n * @zh 设置两个多边形之间的连接\n * @en Set connection between two polygons\n */\n setConnection(\n polyA: number,\n polyB: number,\n portal: IPortal\n ): void {\n const polygonA = this.polygons.get(polyA);\n const polygonB = this.polygons.get(polyB);\n\n if (!polygonA || !polygonB) {\n return;\n }\n\n // Update neighbors and portals\n const neighborsA = [...polygonA.neighbors];\n const portalsA = new Map(polygonA.portals);\n\n if (!neighborsA.includes(polyB)) {\n neighborsA.push(polyB);\n }\n portalsA.set(polyB, portal);\n\n this.polygons.set(polyA, {\n ...polygonA,\n neighbors: neighborsA,\n portals: portalsA\n });\n\n // Reverse portal for the other direction\n const reversePortal: IPortal = {\n left: portal.right,\n right: portal.left\n };\n\n const neighborsB = [...polygonB.neighbors];\n const portalsB = new Map(polygonB.portals);\n\n if (!neighborsB.includes(polyA)) {\n neighborsB.push(polyA);\n }\n portalsB.set(polyA, reversePortal);\n\n this.polygons.set(polyB, {\n ...polygonB,\n neighbors: neighborsB,\n portals: portalsB\n });\n }\n\n /**\n * @zh 自动检测并建立相邻多边形的连接\n * @en Auto-detect and build connections between adjacent polygons\n */\n build(): void {\n const polygonList = Array.from(this.polygons.values());\n\n for (let i = 0; i < polygonList.length; i++) {\n for (let j = i + 1; j < polygonList.length; j++) {\n const polyA = polygonList[i];\n const polyB = polygonList[j];\n\n const sharedEdge = this.findSharedEdge(polyA.vertices, polyB.vertices);\n\n if (sharedEdge) {\n this.setConnection(polyA.id, polyB.id, sharedEdge);\n }\n }\n }\n }\n\n /**\n * @zh 查找两个多边形的共享边\n * @en Find shared edge between two polygons\n */\n private findSharedEdge(\n verticesA: readonly IPoint[],\n verticesB: readonly IPoint[]\n ): IPortal | null {\n const epsilon = 0.0001;\n\n for (let i = 0; i < verticesA.length; i++) {\n const a1 = verticesA[i];\n const a2 = verticesA[(i + 1) % verticesA.length];\n\n for (let j = 0; j < verticesB.length; j++) {\n const b1 = verticesB[j];\n const b2 = verticesB[(j + 1) % verticesB.length];\n\n // Check if edges match (in either direction)\n const match1 =\n Math.abs(a1.x - b2.x) < epsilon &&\n Math.abs(a1.y - b2.y) < epsilon &&\n Math.abs(a2.x - b1.x) < epsilon &&\n Math.abs(a2.y - b1.y) < epsilon;\n\n const match2 =\n Math.abs(a1.x - b1.x) < epsilon &&\n Math.abs(a1.y - b1.y) < epsilon &&\n Math.abs(a2.x - b2.x) < epsilon &&\n Math.abs(a2.y - b2.y) < epsilon;\n\n if (match1 || match2) {\n return {\n left: a1,\n right: a2\n };\n }\n }\n }\n\n return null;\n }\n\n /**\n * @zh 计算多边形中心\n * @en Calculate polygon center\n */\n private calculateCenter(vertices: readonly IPoint[]): IPoint {\n let x = 0;\n let y = 0;\n\n for (const v of vertices) {\n x += v.x;\n y += v.y;\n }\n\n return createPoint(x / vertices.length, y / vertices.length);\n }\n\n /**\n * @zh 查找包含点的多边形\n * @en Find polygon containing point\n */\n findPolygonAt(x: number, y: number): INavPolygon | null {\n for (const polygon of this.polygons.values()) {\n if (this.isPointInPolygon(x, y, polygon.vertices)) {\n return polygon;\n }\n }\n return null;\n }\n\n /**\n * @zh 检查点是否在多边形内\n * @en Check if point is inside polygon\n */\n private isPointInPolygon(x: number, y: number, vertices: readonly IPoint[]): boolean {\n let inside = false;\n const n = vertices.length;\n\n for (let i = 0, j = n - 1; i < n; j = i++) {\n const xi = vertices[i].x;\n const yi = vertices[i].y;\n const xj = vertices[j].x;\n const yj = vertices[j].y;\n\n if (\n yi > y !== yj > y &&\n x < ((xj - xi) * (y - yi)) / (yj - yi) + xi\n ) {\n inside = !inside;\n }\n }\n\n return inside;\n }\n\n // ==========================================================================\n // IPathfindingMap 接口实现 | IPathfindingMap Interface Implementation\n // ==========================================================================\n\n getNodeAt(x: number, y: number): IPathNode | null {\n const polygon = this.findPolygonAt(x, y);\n return polygon ? this.nodes.get(polygon.id) ?? null : null;\n }\n\n getNeighbors(node: IPathNode): IPathNode[] {\n const navNode = node as NavMeshNode;\n const neighbors: IPathNode[] = [];\n\n for (const neighborId of navNode.polygon.neighbors) {\n const neighbor = this.nodes.get(neighborId);\n if (neighbor) {\n neighbors.push(neighbor);\n }\n }\n\n return neighbors;\n }\n\n heuristic(a: IPoint, b: IPoint): number {\n return euclideanDistance(a, b);\n }\n\n getMovementCost(from: IPathNode, to: IPathNode): number {\n return euclideanDistance(from.position, to.position);\n }\n\n isWalkable(x: number, y: number): boolean {\n return this.findPolygonAt(x, y) !== null;\n }\n\n // ==========================================================================\n // 寻路 | Pathfinding\n // ==========================================================================\n\n /**\n * @zh 在导航网格上寻路\n * @en Find path on navigation mesh\n */\n findPath(\n startX: number,\n startY: number,\n endX: number,\n endY: number,\n options?: IPathfindingOptions\n ): IPathResult {\n const opts = { ...DEFAULT_PATHFINDING_OPTIONS, ...options };\n\n const startPolygon = this.findPolygonAt(startX, startY);\n const endPolygon = this.findPolygonAt(endX, endY);\n\n if (!startPolygon || !endPolygon) {\n return EMPTY_PATH_RESULT;\n }\n\n // Same polygon\n if (startPolygon.id === endPolygon.id) {\n return {\n found: true,\n path: [createPoint(startX, startY), createPoint(endX, endY)],\n cost: euclideanDistance(\n createPoint(startX, startY),\n createPoint(endX, endY)\n ),\n nodesSearched: 1\n };\n }\n\n // A* on polygon graph\n const polygonPath = this.findPolygonPath(startPolygon, endPolygon, opts);\n\n if (!polygonPath.found) {\n return EMPTY_PATH_RESULT;\n }\n\n // Convert polygon path to point path using funnel algorithm\n const start = createPoint(startX, startY);\n const end = createPoint(endX, endY);\n const pointPath = this.funnelPath(start, end, polygonPath.polygons, opts.agentRadius);\n\n return {\n found: true,\n path: pointPath,\n cost: this.calculatePathLength(pointPath),\n nodesSearched: polygonPath.nodesSearched\n };\n }\n\n /**\n * @zh 在多边形图上寻路\n * @en Find path on polygon graph\n *\n * @param start - @zh 起始多边形 @en Start polygon\n * @param end - @zh 目标多边形 @en End polygon\n * @param opts - @zh 寻路选项 @en Pathfinding options\n * @param checkObstacles - @zh 是否检查障碍物 @en Whether to check obstacles\n */\n private findPolygonPath(\n start: INavPolygon,\n end: INavPolygon,\n opts: Required<IPathfindingOptions>,\n checkObstacles: boolean = false\n ): { found: boolean; polygons: INavPolygon[]; nodesSearched: number } {\n interface AStarState {\n polygon: INavPolygon;\n g: number;\n f: number;\n parent: AStarState | null;\n }\n\n const openList = new BinaryHeap<AStarState>((a, b) => a.f - b.f);\n const closed = new Set<number>();\n const states = new Map<number, AStarState>();\n\n const startState: AStarState = {\n polygon: start,\n g: 0,\n f: euclideanDistance(start.center, end.center) * opts.heuristicWeight,\n parent: null\n };\n\n states.set(start.id, startState);\n openList.push(startState);\n\n let nodesSearched = 0;\n\n while (!openList.isEmpty && nodesSearched < opts.maxNodes) {\n const current = openList.pop()!;\n nodesSearched++;\n\n if (current.polygon.id === end.id) {\n // Reconstruct path\n const path: INavPolygon[] = [];\n let state: AStarState | null = current;\n\n while (state) {\n path.unshift(state.polygon);\n state = state.parent;\n }\n\n return { found: true, polygons: path, nodesSearched };\n }\n\n closed.add(current.polygon.id);\n\n for (const neighborId of current.polygon.neighbors) {\n if (closed.has(neighborId)) {\n continue;\n }\n\n // @zh 检查障碍物:跳过被阻挡或禁用的多边形\n // @en Check obstacles: skip blocked or disabled polygons\n if (checkObstacles && this.isPolygonBlocked(neighborId)) {\n continue;\n }\n\n const neighborPolygon = this.polygons.get(neighborId);\n if (!neighborPolygon) {\n continue;\n }\n\n const g = current.g + euclideanDistance(\n current.polygon.center,\n neighborPolygon.center\n );\n\n let neighborState = states.get(neighborId);\n\n if (!neighborState) {\n neighborState = {\n polygon: neighborPolygon,\n g,\n f: g + euclideanDistance(neighborPolygon.center, end.center) * opts.heuristicWeight,\n parent: current\n };\n states.set(neighborId, neighborState);\n openList.push(neighborState);\n } else if (g < neighborState.g) {\n neighborState.g = g;\n neighborState.f = g + euclideanDistance(neighborPolygon.center, end.center) * opts.heuristicWeight;\n neighborState.parent = current;\n openList.update(neighborState);\n }\n }\n }\n\n return { found: false, polygons: [], nodesSearched };\n }\n\n /**\n * @zh 使用漏斗算法优化路径(支持代理半径)\n * @en Optimize path using funnel algorithm (supports agent radius)\n *\n * @param start - @zh 起点 @en Start point\n * @param end - @zh 终点 @en End point\n * @param polygons - @zh 多边形路径 @en Polygon path\n * @param agentRadius - @zh 代理半径 @en Agent radius\n */\n private funnelPath(\n start: IPoint,\n end: IPoint,\n polygons: INavPolygon[],\n agentRadius: number = 0\n ): IPoint[] {\n if (polygons.length <= 1) {\n return [start, end];\n }\n\n // Collect and shrink portals\n const portals: { left: IPoint; right: IPoint; originalLeft: IPoint; originalRight: IPoint }[] = [];\n\n for (let i = 0; i < polygons.length - 1; i++) {\n const portal = polygons[i].portals.get(polygons[i + 1].id);\n if (portal) {\n if (agentRadius > 0) {\n const shrunk = this.shrinkPortal(portal.left, portal.right, agentRadius);\n portals.push({\n left: shrunk.left,\n right: shrunk.right,\n originalLeft: portal.left,\n originalRight: portal.right\n });\n } else {\n portals.push({\n left: portal.left,\n right: portal.right,\n originalLeft: portal.left,\n originalRight: portal.right\n });\n }\n }\n }\n\n if (portals.length === 0) {\n return [start, end];\n }\n\n // Simple string pulling algorithm with radius-aware turning points\n const path: IPoint[] = [start];\n\n let apex = start;\n let apexOriginal = start;\n let leftIndex = 0;\n let rightIndex = 0;\n let left = portals[0].left;\n let right = portals[0].right;\n let leftOriginal = portals[0].originalLeft;\n let rightOriginal = portals[0].originalRight;\n\n for (let i = 1; i <= portals.length; i++) {\n const nextLeft = i < portals.length ? portals[i].left : end;\n const nextRight = i < portals.length ? portals[i].right : end;\n\n // Update right\n if (this.triArea2(apex, right, nextRight) <= 0) {\n if (this.pointsEqual(apex, right) || this.triArea2(apex, left, nextRight) > 0) {\n right = nextRight;\n rightIndex = i;\n if (i < portals.length) {\n rightOriginal = portals[i].originalRight;\n }\n } else {\n // Add turning point with radius offset\n const turnPoint = agentRadius > 0\n ? this.offsetTurningPoint(apexOriginal, leftOriginal, left, agentRadius, 'left')\n : left;\n path.push(turnPoint);\n\n apex = left;\n apexOriginal = leftOriginal;\n leftIndex = rightIndex = leftIndex;\n left = right = apex;\n leftOriginal = rightOriginal = apexOriginal;\n i = leftIndex;\n continue;\n }\n }\n\n // Update left\n if (this.triArea2(apex, left, nextLeft) >= 0) {\n if (this.pointsEqual(apex, left) || this.triArea2(apex, right, nextLeft) < 0) {\n left = nextLeft;\n leftIndex = i;\n if (i < portals.length) {\n leftOriginal = portals[i].originalLeft;\n }\n } else {\n // Add turning point with radius offset\n const turnPoint = agentRadius > 0\n ? this.offsetTurningPoint(apexOriginal, rightOriginal, right, agentRadius, 'right')\n : right;\n path.push(turnPoint);\n\n apex = right;\n apexOriginal = rightOriginal;\n leftIndex = rightIndex = rightIndex;\n left = right = apex;\n leftOriginal = rightOriginal = apexOriginal;\n i = rightIndex;\n continue;\n }\n }\n }\n\n path.push(end);\n\n return path;\n }\n\n /**\n * @zh 收缩 portal(将两端点向内移动 agentRadius)\n * @en Shrink portal (move endpoints inward by agentRadius)\n */\n private shrinkPortal(left: IPoint, right: IPoint, radius: number): { left: IPoint; right: IPoint } {\n const dx = right.x - left.x;\n const dy = right.y - left.y;\n const len = Math.sqrt(dx * dx + dy * dy);\n\n if (len <= radius * 2) {\n // Portal too narrow, return center point\n const cx = (left.x + right.x) / 2;\n const cy = (left.y + right.y) / 2;\n return {\n left: createPoint(cx, cy),\n right: createPoint(cx, cy)\n };\n }\n\n // Normalize direction\n const nx = dx / len;\n const ny = dy / len;\n\n // Shrink both endpoints inward\n return {\n left: createPoint(left.x + nx * radius, left.y + ny * radius),\n right: createPoint(right.x - nx * radius, right.y - ny * radius)\n };\n }\n\n /**\n * @zh 偏移拐点以保持与角落的距离\n * @en Offset turning point to maintain distance from corner\n *\n * @param prevApex - @zh 上一个顶点 @en Previous apex\n * @param cornerOriginal - @zh 原始角落位置 @en Original corner position\n * @param cornerShrunk - @zh 收缩后的角落位置 @en Shrunk corner position\n * @param radius - @zh 代理半径 @en Agent radius\n * @param side - @zh 转向侧 ('left' 或 'right') @en Turn side ('left' or 'right')\n */\n private offsetTurningPoint(\n prevApex: IPoint,\n cornerOriginal: IPoint,\n cornerShrunk: IPoint,\n radius: number,\n side: 'left' | 'right'\n ): IPoint {\n // Direction from previous apex to corner\n const dx = cornerOriginal.x - prevApex.x;\n const dy = cornerOriginal.y - prevApex.y;\n const len = Math.sqrt(dx * dx + dy * dy);\n\n if (len < 0.0001) {\n return cornerShrunk;\n }\n\n // Perpendicular direction (pointing into the walkable area)\n // For left turn, perpendicular is to the right of the direction\n // For right turn, perpendicular is to the left of the direction\n let perpX: number, perpY: number;\n if (side === 'left') {\n perpX = dy / len;\n perpY = -dx / len;\n } else {\n perpX = -dy / len;\n perpY = dx / len;\n }\n\n // Offset the shrunk corner by radius in the perpendicular direction\n // This ensures the agent's circular body clears the corner\n return createPoint(\n cornerShrunk.x + perpX * radius,\n cornerShrunk.y + perpY * radius\n );\n }\n\n /**\n * @zh 检查两点是否相等\n * @en Check if two points are equal\n */\n private pointsEqual(a: IPoint, b: IPoint): boolean {\n return Math.abs(a.x - b.x) < 0.0001 && Math.abs(a.y - b.y) < 0.0001;\n }\n\n /**\n * @zh 计算三角形面积的两倍(用于判断点的相对位置)\n * @en Calculate twice the triangle area (for point relative position)\n */\n private triArea2(a: IPoint, b: IPoint, c: IPoint): number {\n return (c.x - a.x) * (b.y - a.y) - (b.x - a.x) * (c.y - a.y);\n }\n\n /**\n * @zh 计算路径总长度\n * @en Calculate total path length\n */\n private calculatePathLength(path: readonly IPoint[]): number {\n let length = 0;\n\n for (let i = 1; i < path.length; i++) {\n length += euclideanDistance(path[i - 1], path[i]);\n }\n\n return length;\n }\n\n // =========================================================================\n // 动态障碍物管理 | Dynamic Obstacle Management\n // =========================================================================\n\n /**\n * @zh 添加圆形障碍物\n * @en Add circular obstacle\n *\n * @param x - @zh 中心 X @en Center X\n * @param y - @zh 中心 Y @en Center Y\n * @param radius - @zh 半径 @en Radius\n * @returns @zh 障碍物 ID @en Obstacle ID\n */\n addCircleObstacle(x: number, y: number, radius: number): number {\n const id = this.nextObstacleId++;\n this.obstacles.set(id, {\n id,\n type: 'circle',\n enabled: true,\n position: createPoint(x, y),\n radius\n });\n return id;\n }\n\n /**\n * @zh 添加矩形障碍物\n * @en Add rectangular obstacle\n *\n * @param x - @zh 中心 X @en Center X\n * @param y - @zh 中心 Y @en Center Y\n * @param halfWidth - @zh 半宽 @en Half width\n * @param halfHeight - @zh 半高 @en Half height\n * @returns @zh 障碍物 ID @en Obstacle ID\n */\n addRectObstacle(x: number, y: number, halfWidth: number, halfHeight: number): number {\n const id = this.nextObstacleId++;\n this.obstacles.set(id, {\n id,\n type: 'rect',\n enabled: true,\n position: createPoint(x, y),\n halfWidth,\n halfHeight\n });\n return id;\n }\n\n /**\n * @zh 添加多边形障碍物\n * @en Add polygon obstacle\n *\n * @param vertices - @zh 顶点列表 @en Vertex list\n * @returns @zh 障碍物 ID @en Obstacle ID\n */\n addPolygonObstacle(vertices: IPoint[]): number {\n const id = this.nextObstacleId++;\n const center = this.calculateCenter(vertices);\n this.obstacles.set(id, {\n id,\n type: 'polygon',\n enabled: true,\n position: center,\n vertices\n });\n return id;\n }\n\n /**\n * @zh 移除障碍物\n * @en Remove obstacle\n */\n removeObstacle(obstacleId: number): boolean {\n return this.obstacles.delete(obstacleId);\n }\n\n /**\n * @zh 启用/禁用障碍物\n * @en Enable/disable obstacle\n */\n setObstacleEnabled(obstacleId: number, enabled: boolean): void {\n const obstacle = this.obstacles.get(obstacleId);\n if (obstacle) {\n obstacle.enabled = enabled;\n }\n }\n\n /**\n * @zh 更新障碍物位置\n * @en Update obstacle position\n */\n updateObstaclePosition(obstacleId: number, x: number, y: number): void {\n const obstacle = this.obstacles.get(obstacleId);\n if (obstacle) {\n obstacle.position = createPoint(x, y);\n }\n }\n\n /**\n * @zh 获取所有障碍物\n * @en Get all obstacles\n */\n getObstacles(): IDynamicObstacle[] {\n return Array.from(this.obstacles.values());\n }\n\n /**\n * @zh 获取启用的障碍物\n * @en Get enabled obstacles\n */\n getEnabledObstacles(): IDynamicObstacle[] {\n return Array.from(this.obstacles.values()).filter(o => o.enabled);\n }\n\n /**\n * @zh 清除所有障碍物\n * @en Clear all obstacles\n */\n clearObstacles(): void {\n this.obstacles.clear();\n this.nextObstacleId = 0;\n }\n\n // =========================================================================\n // 多边形禁用管理 | Polygon Disable Management\n // =========================================================================\n\n /**\n * @zh 禁用多边形\n * @en Disable polygon\n */\n disablePolygon(polygonId: number): void {\n this.disabledPolygons.add(polygonId);\n }\n\n /**\n * @zh 启用多边形\n * @en Enable polygon\n */\n enablePolygon(polygonId: number): void {\n this.disabledPolygons.delete(polygonId);\n }\n\n /**\n * @zh 检查多边形是否被禁用\n * @en Check if polygon is disabled\n */\n isPolygonDisabled(polygonId: number): boolean {\n return this.disabledPolygons.has(polygonId);\n }\n\n /**\n * @zh 禁用包含指定点的多边形\n * @en Disable polygon containing specified point\n */\n disablePolygonAt(x: number, y: number): number | null {\n const polygon = this.findPolygonAt(x, y);\n if (polygon) {\n this.disablePolygon(polygon.id);\n return polygon.id;\n }\n return null;\n }\n\n /**\n * @zh 清除所有禁用的多边形\n * @en Clear all disabled polygons\n */\n clearDisabledPolygons(): void {\n this.disabledPolygons.clear();\n }\n\n /**\n * @zh 获取被禁用的多边形 ID 列表\n * @en Get list of disabled polygon IDs\n */\n getDisabledPolygons(): number[] {\n return Array.from(this.disabledPolygons);\n }\n\n // =========================================================================\n // 障碍物碰撞检测 | Obstacle Collision Detection\n // =========================================================================\n\n /**\n * @zh 检查点是否在任何障碍物内\n * @en Check if point is inside any obstacle\n */\n isPointInObstacle(x: number, y: number): boolean {\n for (const obstacle of this.obstacles.values()) {\n if (!obstacle.enabled) continue;\n\n if (this.isPointInSingleObstacle(x, y, obstacle)) {\n return true;\n }\n }\n return false;\n }\n\n /**\n * @zh 检查点是否在单个障碍物内\n * @en Check if point is inside single obstacle\n */\n private isPointInSingleObstacle(x: number, y: number, obstacle: IDynamicObstacle): boolean {\n switch (obstacle.type) {\n case 'circle': {\n const dx = x - obstacle.position.x;\n const dy = y - obstacle.position.y;\n return dx * dx + dy * dy <= (obstacle.radius ?? 0) ** 2;\n }\n case 'rect': {\n const hw = obstacle.halfWidth ?? 0;\n const hh = obstacle.halfHeight ?? 0;\n return Math.abs(x - obstacle.position.x) <= hw &&\n Math.abs(y - obstacle.position.y) <= hh;\n }\n case 'polygon': {\n if (!obstacle.vertices) return false;\n return this.isPointInPolygon(x, y, obstacle.vertices);\n }\n default:\n return false;\n }\n }\n\n /**\n * @zh 检查线段是否与任何障碍物相交\n * @en Check if line segment intersects any obstacle\n */\n doesLineIntersectObstacle(x1: number, y1: number, x2: number, y2: number): boolean {\n for (const obstacle of this.obstacles.values()) {\n if (!obstacle.enabled) continue;\n\n if (this.doesLineIntersectSingleObstacle(x1, y1, x2, y2, obstacle)) {\n return true;\n }\n }\n return false;\n }\n\n /**\n * @zh 检查线段是否与单个障碍物相交\n * @en Check if line segment intersects single obstacle\n */\n private doesLineIntersectSingleObstacle(\n x1: number, y1: number, x2: number, y2: number,\n obstacle: IDynamicObstacle\n ): boolean {\n switch (obstacle.type) {\n case 'circle': {\n return this.lineIntersectsCircle(\n x1, y1, x2, y2,\n obstacle.position.x, obstacle.position.y,\n obstacle.radius ?? 0\n );\n }\n case 'rect': {\n const hw = obstacle.halfWidth ?? 0;\n const hh = obstacle.halfHeight ?? 0;\n const minX = obstacle.position.x - hw;\n const maxX = obstacle.position.x + hw;\n const minY = obstacle.position.y - hh;\n const maxY = obstacle.position.y + hh;\n return this.lineIntersectsRect(x1, y1, x2, y2, minX, minY, maxX, maxY);\n }\n case 'polygon': {\n if (!obstacle.vertices) return false;\n return this.lineIntersectsPolygon(x1, y1, x2, y2, obstacle.vertices);\n }\n default:\n return false;\n }\n }\n\n /**\n * @zh 线段与圆相交检测\n * @en Line segment circle intersection\n */\n private lineIntersectsCircle(\n x1: number, y1: number, x2: number, y2: number,\n cx: number, cy: number, r: number\n ): boolean {\n const dx = x2 - x1;\n const dy = y2 - y1;\n const fx = x1 - cx;\n const fy = y1 - cy;\n\n const a = dx * dx + dy * dy;\n const b = 2 * (fx * dx + fy * dy);\n const c = fx * fx + fy * fy - r * r;\n\n let discriminant = b * b - 4 * a * c;\n if (discriminant < 0) return false;\n\n discriminant = Math.sqrt(discriminant);\n const t1 = (-b - discriminant) / (2 * a);\n const t2 = (-b + discriminant) / (2 * a);\n\n return (t1 >= 0 && t1 <= 1) || (t2 >= 0 && t2 <= 1) || (t1 < 0 && t2 > 1);\n }\n\n /**\n * @zh 线段与矩形相交检测\n * @en Line segment rectangle intersection\n */\n private lineIntersectsRect(\n x1: number, y1: number, x2: number, y2: number,\n minX: number, minY: number, maxX: number, maxY: number\n ): boolean {\n // Check if either endpoint is inside\n if ((x1 >= minX && x1 <= maxX && y1 >= minY && y1 <= maxY) ||\n (x2 >= minX && x2 <= maxX && y2 >= minY && y2 <= maxY)) {\n return true;\n }\n\n // Check intersection with each edge\n return this.lineSegmentsIntersect(x1, y1, x2, y2, minX, minY, maxX, minY) ||\n this.lineSegmentsIntersect(x1, y1, x2, y2, maxX, minY, maxX, maxY) ||\n this.lineSegmentsIntersect(x1, y1, x2, y2, maxX, maxY, minX, maxY) ||\n this.lineSegmentsIntersect(x1, y1, x2, y2, minX, maxY, minX, minY);\n }\n\n /**\n * @zh 线段与多边形相交检测\n * @en Line segment polygon intersection\n */\n private lineIntersectsPolygon(\n x1: number, y1: number, x2: number, y2: number,\n vertices: readonly IPoint[]\n ): boolean {\n // Check if either endpoint is inside\n if (this.isPointInPolygon(x1, y1, vertices) ||\n this.isPointInPolygon(x2, y2, vertices)) {\n return true;\n }\n\n // Check intersection with each edge\n for (let i = 0; i < vertices.length; i++) {\n const j = (i + 1) % vertices.length;\n if (this.lineSegmentsIntersect(\n x1, y1, x2, y2,\n vertices[i].x, vertices[i].y,\n vertices[j].x, vertices[j].y\n )) {\n return true;\n }\n }\n return false;\n }\n\n /**\n * @zh 两线段相交检测\n * @en Two line segments intersection\n */\n private lineSegmentsIntersect(\n x1: number, y1: number, x2: number, y2: number,\n x3: number, y3: number, x4: number, y4: number\n ): boolean {\n const d1 = this.direction(x3, y3, x4, y4, x1, y1);\n const d2 = this.direction(x3, y3, x4, y4, x2, y2);\n const d3 = this.direction(x1, y1, x2, y2, x3, y3);\n const d4 = this.direction(x1, y1, x2, y2, x4, y4);\n\n if (((d1 > 0 && d2 < 0) || (d1 < 0 && d2 > 0)) &&\n ((d3 > 0 && d4 < 0) || (d3 < 0 && d4 > 0))) {\n return true;\n }\n\n const epsilon = 0.0001;\n if (Math.abs(d1) < epsilon && this.onSegment(x3, y3, x4, y4, x1, y1)) return true;\n if (Math.abs(d2) < epsilon && this.onSegment(x3, y3, x4, y4, x2, y2)) return true;\n if (Math.abs(d3) < epsilon && this.onSegment(x1, y1, x2, y2, x3, y3)) return true;\n if (Math.abs(d4) < epsilon && this.onSegment(x1, y1, x2, y2, x4, y4)) return true;\n\n return false;\n }\n\n private direction(x1: number, y1: number, x2: number, y2: number, x3: number, y3: number): number {\n return (x3 - x1) * (y2 - y1) - (y3 - y1) * (x2 - x1);\n }\n\n private onSegment(x1: number, y1: number, x2: number, y2: number, x3: number, y3: number): boolean {\n return Math.min(x1, x2) <= x3 && x3 <= Math.max(x1, x2) &&\n Math.min(y1, y2) <= y3 && y3 <= Math.max(y1, y2);\n }\n\n // =========================================================================\n // 障碍物感知寻路 | Obstacle-Aware Pathfinding\n // =========================================================================\n\n /**\n * @zh 检查多边形是否被障碍物阻挡\n * @en Check if polygon is blocked by obstacle\n *\n * @zh 检查以下条件:\n * @en Checks the following conditions:\n * - @zh 多边形是否被禁用 @en Whether polygon is disabled\n * - @zh 多边形中心是否在障碍物内 @en Whether polygon center is inside obstacle\n * - @zh 多边形任意顶点是否在障碍物内 @en Whether any polygon vertex is inside obstacle\n * - @zh 多边形任意边是否与障碍物相交 @en Whether any polygon edge intersects obstacle\n */\n isPolygonBlocked(polygonId: number): boolean {\n if (this.disabledPolygons.has(polygonId)) {\n return true;\n }\n\n const polygon = this.polygons.get(polygonId);\n if (!polygon) return false;\n\n // @zh 检查中心点\n // @en Check center point\n if (this.isPointInObstacle(polygon.center.x, polygon.center.y)) {\n return true;\n }\n\n // @zh 检查所有顶点\n // @en Check all vertices\n for (const vertex of polygon.vertices) {\n if (this.isPointInObstacle(vertex.x, vertex.y)) {\n return true;\n }\n }\n\n // @zh 检查所有边是否与障碍物相交\n // @en Check if any edge intersects with obstacles\n const vertices = polygon.vertices;\n for (let i = 0; i < vertices.length; i++) {\n const v1 = vertices[i];\n const v2 = vertices[(i + 1) % vertices.length];\n if (this.doesLineIntersectObstacle(v1.x, v1.y, v2.x, v2.y)) {\n return true;\n }\n }\n\n return false;\n }\n\n /**\n * @zh 在导航网格上寻路(考虑障碍物)\n * @en Find path on navigation mesh (considering obstacles)\n *\n * @zh 此方法在规划阶段就考虑障碍物,自动绕过被阻挡的多边形\n * @en This method considers obstacles during planning, automatically avoiding blocked polygons\n *\n * @zh 与 findPath 不同,此方法会:\n * @en Unlike findPath, this method will:\n * - @zh 在 A* 搜索中跳过被障碍物阻挡的多边形\n * - @en Skip obstacle-blocked polygons during A* search\n * - @zh 验证起点和终点不在障碍物内\n * - @en Verify start and end points are not inside obstacles\n */\n findPathWithObstacles(\n startX: number,\n startY: number,\n endX: number,\n endY: number,\n options?: IPathfindingOptions\n ): IPathResult {\n const opts = { ...DEFAULT_PATHFINDING_OPTIONS, ...options };\n\n // @zh 检查起点和终点是否在障碍物内\n // @en Check if start and end are inside obstacles\n if (this.isPointInObstacle(startX, startY) || this.isPointInObstacle(endX, endY)) {\n return EMPTY_PATH_RESULT;\n }\n\n const startPolygon = this.findPolygonAt(startX, startY);\n const endPolygon = this.findPolygonAt(endX, endY);\n\n if (!startPolygon || !endPolygon) {\n return EMPTY_PATH_RESULT;\n }\n\n // @zh 检查起点/终点多边形是否被阻挡\n // @en Check if start/end polygons are blocked\n if (this.isPolygonBlocked(startPolygon.id) || this.isPolygonBlocked(endPolygon.id)) {\n return EMPTY_PATH_RESULT;\n }\n\n // @zh 同一多边形内的路径\n // @en Path within same polygon\n if (startPolygon.id === endPolygon.id) {\n const start = createPoint(startX, startY);\n const end = createPoint(endX, endY);\n\n // @zh 检查直线路径是否穿过障碍物\n // @en Check if direct path crosses obstacles\n if (this.doesLineIntersectObstacle(startX, startY, endX, endY)) {\n return EMPTY_PATH_RESULT;\n }\n\n return {\n found: true,\n path: [start, end],\n cost: euclideanDistance(start, end),\n nodesSearched: 1\n };\n }\n\n // @zh 使用障碍物感知的多边形路径搜索\n // @en Use obstacle-aware polygon path search\n const polygonPath = this.findPolygonPath(startPolygon, endPolygon, opts, true);\n\n if (!polygonPath.found) {\n return EMPTY_PATH_RESULT;\n }\n\n // @zh 使用 Funnel 算法生成路径点\n // @en Generate path points using Funnel algorithm\n const start = createPoint(startX, startY);\n const end = createPoint(endX, endY);\n const pointPath = this.funnelPath(start, end, polygonPath.polygons, opts.agentRadius);\n\n return {\n found: true,\n path: pointPath,\n cost: this.calculatePathLength(pointPath),\n nodesSearched: polygonPath.nodesSearched\n };\n }\n\n /**\n * @zh 清空导航网格\n * @en Clear navigation mesh\n */\n clear(): void {\n this.polygons.clear();\n this.nodes.clear();\n this.obstacles.clear();\n this.disabledPolygons.clear();\n this.nextId = 0;\n this.nextObstacleId = 0;\n }\n\n /**\n * @zh 获取所有多边形\n * @en Get all polygons\n */\n getPolygons(): INavPolygon[] {\n return Array.from(this.polygons.values());\n }\n\n /**\n * @zh 获取多边形数量\n * @en Get polygon count\n */\n get polygonCount(): number {\n return this.polygons.size;\n }\n\n /**\n * @zh 获取障碍物数量\n * @en Get obstacle count\n */\n get obstacleCount(): number {\n return this.obstacles.size;\n }\n}\n\n// =============================================================================\n// 工厂函数 | Factory Function\n// =============================================================================\n\n/**\n * @zh 创建导航网格\n * @en Create navigation mesh\n */\nexport function createNavMesh(): NavMesh {\n return new NavMesh();\n}\n","/**\n * @zh 路径平滑算法\n * @en Path Smoothing Algorithms\n */\n\nimport type {\n IPathfindingMap,\n IPathSmoother,\n IPoint\n} from '../core/IPathfinding';\nimport { createPoint } from '../core/IPathfinding';\n\n// =============================================================================\n// 视线检测 | Line of Sight\n// =============================================================================\n\n/**\n * @zh 使用 Bresenham 算法检测视线\n * @en Line of sight check using Bresenham algorithm\n */\nexport function bresenhamLineOfSight(\n x1: number,\n y1: number,\n x2: number,\n y2: number,\n map: IPathfindingMap\n): boolean {\n // Round to grid coordinates\n let ix1 = Math.floor(x1);\n let iy1 = Math.floor(y1);\n const ix2 = Math.floor(x2);\n const iy2 = Math.floor(y2);\n\n const dx = Math.abs(ix2 - ix1);\n const dy = Math.abs(iy2 - iy1);\n\n const sx = ix1 < ix2 ? 1 : -1;\n const sy = iy1 < iy2 ? 1 : -1;\n\n let err = dx - dy;\n\n while (true) {\n if (!map.isWalkable(ix1, iy1)) {\n return false;\n }\n\n if (ix1 === ix2 && iy1 === iy2) {\n break;\n }\n\n const e2 = 2 * err;\n\n if (e2 > -dy) {\n err -= dy;\n ix1 += sx;\n }\n\n if (e2 < dx) {\n err += dx;\n iy1 += sy;\n }\n }\n\n return true;\n}\n\n/**\n * @zh 使用射线投射检测视线(更精确)\n * @en Line of sight check using ray casting (more precise)\n */\nexport function raycastLineOfSight(\n x1: number,\n y1: number,\n x2: number,\n y2: number,\n map: IPathfindingMap,\n stepSize: number = 0.5\n): boolean {\n const dx = x2 - x1;\n const dy = y2 - y1;\n const distance = Math.sqrt(dx * dx + dy * dy);\n\n if (distance === 0) {\n return map.isWalkable(Math.floor(x1), Math.floor(y1));\n }\n\n const steps = Math.ceil(distance / stepSize);\n const stepX = dx / steps;\n const stepY = dy / steps;\n\n let x = x1;\n let y = y1;\n\n for (let i = 0; i <= steps; i++) {\n if (!map.isWalkable(Math.floor(x), Math.floor(y))) {\n return false;\n }\n x += stepX;\n y += stepY;\n }\n\n return true;\n}\n\n// =============================================================================\n// 路径简化器(拐点移除)| Path Simplifier (Waypoint Removal)\n// =============================================================================\n\n/**\n * @zh 路径简化器 - 移除不必要的拐点\n * @en Path Simplifier - Removes unnecessary waypoints\n *\n * @zh 使用视线检测移除可以直接到达的中间点\n * @en Uses line of sight to remove intermediate points that can be reached directly\n */\nexport class LineOfSightSmoother implements IPathSmoother {\n private readonly lineOfSight: typeof bresenhamLineOfSight;\n\n constructor(lineOfSight: typeof bresenhamLineOfSight = bresenhamLineOfSight) {\n this.lineOfSight = lineOfSight;\n }\n\n smooth(path: readonly IPoint[], map: IPathfindingMap): IPoint[] {\n if (path.length <= 2) {\n return [...path];\n }\n\n const result: IPoint[] = [path[0]];\n let current = 0;\n\n while (current < path.length - 1) {\n // Find the furthest point we can see from current\n let furthest = current + 1;\n\n for (let i = path.length - 1; i > current + 1; i--) {\n if (this.lineOfSight(\n path[current].x,\n path[current].y,\n path[i].x,\n path[i].y,\n map\n )) {\n furthest = i;\n break;\n }\n }\n\n result.push(path[furthest]);\n current = furthest;\n }\n\n return result;\n }\n}\n\n// =============================================================================\n// 曲线平滑器 | Curve Smoother\n// =============================================================================\n\n/**\n * @zh Catmull-Rom 样条曲线平滑\n * @en Catmull-Rom spline smoothing\n */\nexport class CatmullRomSmoother implements IPathSmoother {\n private readonly segments: number;\n private readonly tension: number;\n\n /**\n * @param segments - @zh 每段之间的插值点数 @en Number of interpolation points per segment\n * @param tension - @zh 张力 (0-1) @en Tension (0-1)\n */\n constructor(segments: number = 5, tension: number = 0.5) {\n this.segments = segments;\n this.tension = tension;\n }\n\n smooth(path: readonly IPoint[], _map: IPathfindingMap): IPoint[] {\n if (path.length <= 2) {\n return [...path];\n }\n\n const result: IPoint[] = [];\n\n // Add phantom points at the ends\n const points = [\n path[0],\n ...path,\n path[path.length - 1]\n ];\n\n for (let i = 1; i < points.length - 2; i++) {\n const p0 = points[i - 1];\n const p1 = points[i];\n const p2 = points[i + 1];\n const p3 = points[i + 2];\n\n for (let j = 0; j < this.segments; j++) {\n const t = j / this.segments;\n const point = this.interpolate(p0, p1, p2, p3, t);\n result.push(point);\n }\n }\n\n // Add final point\n result.push(path[path.length - 1]);\n\n return result;\n }\n\n /**\n * @zh Catmull-Rom 插值\n * @en Catmull-Rom interpolation\n */\n private interpolate(\n p0: IPoint,\n p1: IPoint,\n p2: IPoint,\n p3: IPoint,\n t: number\n ): IPoint {\n const t2 = t * t;\n const t3 = t2 * t;\n\n const tension = this.tension;\n\n const x =\n 0.5 *\n ((2 * p1.x) +\n (-p0.x + p2.x) * t * tension +\n (2 * p0.x - 5 * p1.x + 4 * p2.x - p3.x) * t2 * tension +\n (-p0.x + 3 * p1.x - 3 * p2.x + p3.x) * t3 * tension);\n\n const y =\n 0.5 *\n ((2 * p1.y) +\n (-p0.y + p2.y) * t * tension +\n (2 * p0.y - 5 * p1.y + 4 * p2.y - p3.y) * t2 * tension +\n (-p0.y + 3 * p1.y - 3 * p2.y + p3.y) * t3 * tension);\n\n return createPoint(x, y);\n }\n}\n\n// =============================================================================\n// 组合平滑器 | Combined Smoother\n// =============================================================================\n\n/**\n * @zh 组合路径平滑器\n * @en Combined path smoother\n *\n * @zh 先简化路径,再用曲线平滑\n * @en First simplify path, then smooth with curves\n */\nexport class CombinedSmoother implements IPathSmoother {\n private readonly simplifier: LineOfSightSmoother;\n private readonly curveSmoother: CatmullRomSmoother;\n\n constructor(curveSegments: number = 5, tension: number = 0.5) {\n this.simplifier = new LineOfSightSmoother();\n this.curveSmoother = new CatmullRomSmoother(curveSegments, tension);\n }\n\n smooth(path: readonly IPoint[], map: IPathfindingMap): IPoint[] {\n // First simplify\n const simplified = this.simplifier.smooth(path, map);\n\n // Then curve smooth\n return this.curveSmoother.smooth(simplified, map);\n }\n}\n\n// =============================================================================\n// 工厂函数 | Factory Functions\n// =============================================================================\n\n/**\n * @zh 创建视线平滑器\n * @en Create line of sight smoother\n */\nexport function createLineOfSightSmoother(\n lineOfSight?: typeof bresenhamLineOfSight\n): LineOfSightSmoother {\n return new LineOfSightSmoother(lineOfSight);\n}\n\n/**\n * @zh 创建曲线平滑器\n * @en Create curve smoother\n */\nexport function createCatmullRomSmoother(\n segments?: number,\n tension?: number\n): CatmullRomSmoother {\n return new CatmullRomSmoother(segments, tension);\n}\n\n/**\n * @zh 创建组合平滑器\n * @en Create combined smoother\n */\nexport function createCombinedSmoother(\n curveSegments?: number,\n tension?: number\n): CombinedSmoother {\n return new CombinedSmoother(curveSegments, tension);\n}\n","/**\n * @zh 半径感知路径平滑器\n * @en Radius-Aware Path Smoother\n *\n * @zh 通用的路径后处理器,确保路径与障碍物保持安全距离\n * @en Generic path post-processor that ensures paths maintain safe distance from obstacles\n */\n\nimport type { IPathfindingMap, IPathSmoother, IPoint } from '../core/IPathfinding';\nimport { createPoint } from '../core/IPathfinding';\n\n// =============================================================================\n// 配置 | Configuration\n// =============================================================================\n\n/**\n * @zh 半径感知平滑器配置\n * @en Radius-aware smoother configuration\n */\nexport interface IRadiusAwareSmootherConfig {\n /**\n * @zh 代理半径\n * @en Agent radius\n */\n agentRadius: number;\n\n /**\n * @zh 额外安全边距\n * @en Extra safety margin\n * @default 0.1\n */\n safetyMargin?: number;\n\n /**\n * @zh 采样方向数量(用于检测周围障碍物)\n * @en Number of sample directions (for detecting nearby obstacles)\n * @default 8\n */\n sampleDirections?: number;\n\n /**\n * @zh 最大偏移尝试次数\n * @en Maximum offset attempts\n * @default 8\n */\n maxOffsetAttempts?: number;\n\n /**\n * @zh 是否处理拐点(角落)\n * @en Whether to process turning points (corners)\n * @default true\n */\n processCorners?: boolean;\n}\n\n/**\n * @zh 默认配置\n * @en Default configuration\n */\nconst DEFAULT_CONFIG: Required<Omit<IRadiusAwareSmootherConfig, 'agentRadius'>> = {\n safetyMargin: 0.1,\n sampleDirections: 8,\n maxOffsetAttempts: 8,\n processCorners: true\n};\n\n// =============================================================================\n// 半径感知路径平滑器 | Radius-Aware Path Smoother\n// =============================================================================\n\n/**\n * @zh 半径感知路径平滑器\n * @en Radius-Aware Path Smoother\n *\n * @zh 对任意寻路算法输出的路径进行后处理,确保路径点与障碍物保持足够距离\n * @en Post-processes paths from any pathfinding algorithm to ensure path points maintain sufficient distance from obstacles\n *\n * @example\n * ```typescript\n * // 创建平滑器\n * const smoother = new RadiusAwarePathSmoother({ agentRadius: 0.5 });\n *\n * // 处理路径\n * const safePath = smoother.smooth(rawPath, map);\n *\n * // 与其他平滑器组合使用\n * const combined = new CombinedRadiusAwareSmoother(\n * new LineOfSightSmoother(),\n * { agentRadius: 0.5 }\n * );\n * ```\n */\nexport class RadiusAwarePathSmoother implements IPathSmoother {\n private readonly config: Required<IRadiusAwareSmootherConfig>;\n private readonly sampleAngles: number[];\n\n constructor(config: IRadiusAwareSmootherConfig) {\n this.config = {\n ...DEFAULT_CONFIG,\n ...config\n };\n\n // 预计算采样角度\n this.sampleAngles = [];\n const step = (Math.PI * 2) / this.config.sampleDirections;\n for (let i = 0; i < this.config.sampleDirections; i++) {\n this.sampleAngles.push(i * step);\n }\n }\n\n /**\n * @zh 平滑路径,确保与障碍物保持安全距离\n * @en Smooth path, ensuring safe distance from obstacles\n *\n * @param path - @zh 原始路径 @en Original path\n * @param map - @zh 地图 @en Map\n * @returns @zh 处理后的安全路径 @en Processed safe path\n */\n smooth(path: readonly IPoint[], map: IPathfindingMap): IPoint[] {\n if (path.length <= 1) {\n return [...path];\n }\n\n const result: IPoint[] = [];\n const clearance = this.config.agentRadius + this.config.safetyMargin;\n\n for (let i = 0; i < path.length; i++) {\n const point = path[i]!;\n const isCorner = this.config.processCorners && i > 0 && i < path.length - 1;\n\n let safePoint: IPoint;\n\n if (isCorner) {\n // 处理拐点\n const prev = path[i - 1]!;\n const next = path[i + 1]!;\n safePoint = this.offsetCornerPoint(point, prev, next, clearance, map);\n } else {\n // 处理普通点\n safePoint = this.offsetPointFromObstacles(point, clearance, map);\n }\n\n result.push(safePoint);\n }\n\n return result;\n }\n\n /**\n * @zh 将点从障碍物偏移\n * @en Offset point away from obstacles\n */\n private offsetPointFromObstacles(\n point: IPoint,\n clearance: number,\n map: IPathfindingMap\n ): IPoint {\n // 检测周围障碍物\n const obstacleDirections = this.detectNearbyObstacles(point, clearance, map);\n\n if (obstacleDirections.length === 0) {\n // 没有障碍物在范围内\n return point;\n }\n\n // 计算平均障碍物方向\n let avgDirX = 0;\n let avgDirY = 0;\n for (const dir of obstacleDirections) {\n avgDirX += dir.x;\n avgDirY += dir.y;\n }\n\n const len = Math.sqrt(avgDirX * avgDirX + avgDirY * avgDirY);\n if (len < 0.0001) {\n // 障碍物方向相互抵消,保持原位\n return point;\n }\n\n // 反方向偏移(远离障碍物)\n const offsetDirX = -avgDirX / len;\n const offsetDirY = -avgDirY / len;\n\n // 尝试不同的偏移距离\n for (let attempt = 1; attempt <= this.config.maxOffsetAttempts; attempt++) {\n const offsetDist = clearance * attempt / this.config.maxOffsetAttempts;\n const newX = point.x + offsetDirX * offsetDist;\n const newY = point.y + offsetDirY * offsetDist;\n\n if (map.isWalkable(Math.floor(newX), Math.floor(newY))) {\n // 检查新位置是否有足够的clearance\n const newObstacles = this.detectNearbyObstacles(\n createPoint(newX, newY),\n clearance,\n map\n );\n\n if (newObstacles.length === 0) {\n return createPoint(newX, newY);\n }\n }\n }\n\n // 无法找到更好的位置,返回原点\n return point;\n }\n\n /**\n * @zh 偏移拐点(角落)\n * @en Offset corner point\n */\n private offsetCornerPoint(\n corner: IPoint,\n prev: IPoint,\n next: IPoint,\n clearance: number,\n map: IPathfindingMap\n ): IPoint {\n // 计算进入方向和离开方向\n const inDirX = corner.x - prev.x;\n const inDirY = corner.y - prev.y;\n const inLen = Math.sqrt(inDirX * inDirX + inDirY * inDirY);\n\n const outDirX = next.x - corner.x;\n const outDirY = next.y - corner.y;\n const outLen = Math.sqrt(outDirX * outDirX + outDirY * outDirY);\n\n if (inLen < 0.0001 || outLen < 0.0001) {\n return this.offsetPointFromObstacles(corner, clearance, map);\n }\n\n // 标准化方向\n const inNormX = inDirX / inLen;\n const inNormY = inDirY / inLen;\n const outNormX = outDirX / outLen;\n const outNormY = outDirY / outLen;\n\n // 计算角平分线方向(指向角的内侧)\n // 角平分线 = 入射方向 + 出射方向的反方向\n const bisectX = inNormX - outNormX;\n const bisectY = inNormY - outNormY;\n const bisectLen = Math.sqrt(bisectX * bisectX + bisectY * bisectY);\n\n if (bisectLen < 0.0001) {\n // 直线,不需要特殊处理\n return this.offsetPointFromObstacles(corner, clearance, map);\n }\n\n // 标准化角平分线\n const bisectNormX = bisectX / bisectLen;\n const bisectNormY = bisectY / bisectLen;\n\n // 计算转角角度\n const dotProduct = inNormX * outNormX + inNormY * outNormY;\n const angle = Math.acos(Math.max(-1, Math.min(1, dotProduct)));\n\n // 计算需要的偏移距离\n // 在角落处,需要偏移 clearance / sin(angle/2) 才能保持与两边的距离\n const halfAngle = angle / 2;\n const sinHalfAngle = Math.sin(halfAngle);\n\n if (sinHalfAngle < 0.1) {\n // 角度太小(几乎是直线),使用普通偏移\n return this.offsetPointFromObstacles(corner, clearance, map);\n }\n\n const offsetDist = clearance / sinHalfAngle;\n\n // 限制最大偏移距离\n const maxOffset = clearance * 3;\n const actualOffset = Math.min(offsetDist, maxOffset);\n\n // 沿角平分线偏移\n const newX = corner.x + bisectNormX * actualOffset;\n const newY = corner.y + bisectNormY * actualOffset;\n\n // 验证新位置是否可行\n if (map.isWalkable(Math.floor(newX), Math.floor(newY))) {\n return createPoint(newX, newY);\n }\n\n // 如果角平分线方向不可行,尝试反方向\n const altX = corner.x - bisectNormX * actualOffset;\n const altY = corner.y - bisectNormY * actualOffset;\n\n if (map.isWalkable(Math.floor(altX), Math.floor(altY))) {\n return createPoint(altX, altY);\n }\n\n // 回退到普通偏移\n return this.offsetPointFromObstacles(corner, clearance, map);\n }\n\n /**\n * @zh 检测附近的障碍物方向\n * @en Detect nearby obstacle directions\n */\n private detectNearbyObstacles(\n point: IPoint,\n clearance: number,\n map: IPathfindingMap\n ): IPoint[] {\n const obstacles: IPoint[] = [];\n\n for (const angle of this.sampleAngles) {\n const dirX = Math.cos(angle);\n const dirY = Math.sin(angle);\n\n // 沿该方向采样\n const sampleX = point.x + dirX * clearance;\n const sampleY = point.y + dirY * clearance;\n\n if (!map.isWalkable(Math.floor(sampleX), Math.floor(sampleY))) {\n // 该方向有障碍物\n obstacles.push(createPoint(dirX, dirY));\n }\n }\n\n return obstacles;\n }\n}\n\n// =============================================================================\n// 组合平滑器 | Combined Smoother\n// =============================================================================\n\n/**\n * @zh 组合半径感知平滑器\n * @en Combined radius-aware smoother\n *\n * @zh 先使用其他平滑器(如 LOS、Catmull-Rom),再应用半径感知处理\n * @en First applies other smoother (like LOS, Catmull-Rom), then applies radius-aware processing\n *\n * @example\n * ```typescript\n * const smoother = new CombinedRadiusAwareSmoother(\n * new LineOfSightSmoother(),\n * { agentRadius: 0.5 }\n * );\n * const path = smoother.smooth(rawPath, map);\n * ```\n */\nexport class CombinedRadiusAwareSmoother implements IPathSmoother {\n private readonly baseSmoother: IPathSmoother;\n private readonly radiusAwareSmoother: RadiusAwarePathSmoother;\n\n constructor(\n baseSmoother: IPathSmoother,\n config: IRadiusAwareSmootherConfig\n ) {\n this.baseSmoother = baseSmoother;\n this.radiusAwareSmoother = new RadiusAwarePathSmoother(config);\n }\n\n smooth(path: readonly IPoint[], map: IPathfindingMap): IPoint[] {\n // 先用基础平滑器处理\n const smoothed = this.baseSmoother.smooth(path, map);\n\n // 再应用半径感知处理\n return this.radiusAwareSmoother.smooth(smoothed, map);\n }\n}\n\n// =============================================================================\n// 工厂函数 | Factory Functions\n// =============================================================================\n\n/**\n * @zh 创建半径感知平滑器\n * @en Create radius-aware smoother\n *\n * @param agentRadius - @zh 代理半径 @en Agent radius\n * @param options - @zh 额外配置 @en Additional options\n *\n * @example\n * ```typescript\n * const smoother = createRadiusAwareSmoother(0.5);\n * const safePath = smoother.smooth(path, map);\n * ```\n */\nexport function createRadiusAwareSmoother(\n agentRadius: number,\n options?: Omit<IRadiusAwareSmootherConfig, 'agentRadius'>\n): RadiusAwarePathSmoother {\n return new RadiusAwarePathSmoother({\n agentRadius,\n ...options\n });\n}\n\n/**\n * @zh 创建组合半径感知平滑器\n * @en Create combined radius-aware smoother\n *\n * @param baseSmoother - @zh 基础平滑器 @en Base smoother\n * @param agentRadius - @zh 代理半径 @en Agent radius\n * @param options - @zh 额外配置 @en Additional options\n *\n * @example\n * ```typescript\n * const smoother = createCombinedRadiusAwareSmoother(\n * new LineOfSightSmoother(),\n * 0.5\n * );\n * ```\n */\nexport function createCombinedRadiusAwareSmoother(\n baseSmoother: IPathSmoother,\n agentRadius: number,\n options?: Omit<IRadiusAwareSmootherConfig, 'agentRadius'>\n): CombinedRadiusAwareSmoother {\n return new CombinedRadiusAwareSmoother(baseSmoother, {\n agentRadius,\n ...options\n });\n}\n"],"mappings":"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","names":["CLOSED_FLAG","OPENED_FLAG","BACKWARD_CLOSED","BACKWARD_OPENED","GridState","width","height","bidirectional","size","g","f","flags","parent","heapIndex","version","currentVersion","gBack","fBack","parentBack","heapIndexBack","Float32Array","Uint8Array","Int32Array","Uint32Array","reset","fill","isInit","i","init","Infinity","getG","setG","v","getF","setF","getParent","setParent","getHeapIndex","setHeapIndex","isClosed","setClosed","isOpened","setOpened","getGBack","setGBack","getFBack","setFBack","getParentBack","setParentBack","getHeapIndexBack","setHeapIndexBack","isClosedBack","setClosedBack","isOpenedBack","setOpenedBack","_a","GridHeap","state","isBack","heap","length","isEmpty","push","bubbleUp","pop","result","last","sinkDown","update","pos","clear","idx","pp","pi","len","half","left","right","smallest","smallestF","lf","rf","si","GridPathfinder","map","config","mode","openList","openListBack","isBidir","findPath","startX","startY","endX","endY","options","findPathBidirectional","findPathUnidirectional","opts","DEFAULT_PATHFINDING_OPTIONS","validate","EMPTY_PATH_RESULT","startIdx","endIdx","found","path","x","y","cost","nodesSearched","hw","heuristicWeight","h0","heuristic","searched","maxNodes","allowDiagonal","avoidCorners","diagonalCost","nodes","dx","dy","dirCount","cur","buildPath","cx","cy","curG","d","nx","ny","neighbor","walkable","ni","isDiag","tentG","h","startPos","endPos","hf","hb","meetIdx","bestCost","total","buildPathBidirectional","isWalkable","w","reverse","createGridPathfinder","PathValidator","validatePath","path","fromIndex","toIndex","map","end","Math","min","length","i","point","x","floor","y","isWalkable","valid","invalidIndex","prev","checkLineOfSight","x1","y1","x2","y2","ix1","iy1","ix2","iy2","dx","abs","dy","sx","sy","err","ObstacleChangeManager","changes","Map","epoch","recordChange","wasWalkable","key","set","timestamp","Date","now","getAffectedRegion","size","minX","Infinity","minY","maxX","maxY","change","values","max","getChanges","Array","from","hasChanges","getEpoch","flush","clear","createPathValidator","createObstacleChangeManager","GridNode","x","y","width","walkable","cost","id","position","createPoint","DIRECTIONS_4","dx","dy","DIRECTIONS_8","DEFAULT_GRID_OPTIONS","allowDiagonal","diagonalCost","Math","SQRT2","avoidCorners","heuristic","octileDistance","GridMap","height","options","nodes","createNodes","getNodeAt","isInBounds","isWalkable","node","setWalkable","setCost","getNeighbors","neighbors","directions","i","length","dir","nx","ny","neighbor","hNode","vNode","push","forEachNeighbor","callback","a","b","getMovementCost","from","to","abs","loadFromArray","data","min","loadFromString","str","lines","trim","split","line","toString","result","reset","setRectWalkable","createGridMap","_a","NavMeshNode","polygon","id","position","cost","walkable","center","NavMesh","polygons","Map","nodes","nextId","obstacles","nextObstacleId","disabledPolygons","Set","addPolygon","vertices","neighbors","calculateCenter","portals","set","setConnection","polyA","polyB","portal","polygonA","get","polygonB","neighborsA","portalsA","includes","push","reversePortal","left","right","neighborsB","portalsB","build","polygonList","Array","from","values","i","length","j","sharedEdge","findSharedEdge","verticesA","verticesB","epsilon","a1","a2","b1","b2","match1","Math","abs","x","y","match2","v","createPoint","findPolygonAt","isPointInPolygon","inside","n","xi","yi","xj","yj","getNodeAt","getNeighbors","node","navNode","neighborId","neighbor","heuristic","a","b","euclideanDistance","getMovementCost","to","isWalkable","findPath","startX","startY","endX","endY","options","opts","DEFAULT_PATHFINDING_OPTIONS","startPolygon","endPolygon","EMPTY_PATH_RESULT","found","path","nodesSearched","polygonPath","findPolygonPath","start","end","pointPath","funnelPath","agentRadius","calculatePathLength","checkObstacles","openList","BinaryHeap","f","closed","states","startState","g","heuristicWeight","parent","isEmpty","maxNodes","current","pop","state","unshift","add","has","isPolygonBlocked","neighborPolygon","neighborState","update","shrunk","shrinkPortal","originalLeft","originalRight","apex","apexOriginal","leftIndex","rightIndex","leftOriginal","rightOriginal","nextLeft","nextRight","triArea2","pointsEqual","turnPoint","offsetTurningPoint","radius","dx","dy","len","sqrt","cx","cy","nx","ny","prevApex","cornerOriginal","cornerShrunk","side","perpX","perpY","c","addCircleObstacle","type","enabled","addRectObstacle","halfWidth","halfHeight","addPolygonObstacle","removeObstacle","obstacleId","delete","setObstacleEnabled","obstacle","updateObstaclePosition","getObstacles","getEnabledObstacles","filter","o","clearObstacles","clear","disablePolygon","polygonId","enablePolygon","isPolygonDisabled","disablePolygonAt","clearDisabledPolygons","getDisabledPolygons","isPointInObstacle","isPointInSingleObstacle","hw","hh","doesLineIntersectObstacle","x1","y1","x2","y2","doesLineIntersectSingleObstacle","lineIntersectsCircle","minX","maxX","minY","maxY","lineIntersectsRect","lineIntersectsPolygon","r","fx","fy","discriminant","t1","t2","lineSegmentsIntersect","x3","y3","x4","y4","d1","direction","d2","d3","d4","onSegment","min","max","vertex","v1","v2","findPathWithObstacles","getPolygons","polygonCount","size","obstacleCount","createNavMesh","bresenhamLineOfSight","x1","y1","x2","y2","map","ix1","Math","floor","iy1","ix2","iy2","dx","abs","dy","sx","sy","err","isWalkable","e2","raycastLineOfSight","stepSize","distance","sqrt","steps","ceil","stepX","stepY","x","y","i","LineOfSightSmoother","lineOfSight","smooth","path","length","result","current","furthest","push","CatmullRomSmoother","segments","tension","_map","points","p0","p1","p2","p3","j","t","point","interpolate","t2","t3","createPoint","CombinedSmoother","curveSegments","simplifier","curveSmoother","simplified","createLineOfSightSmoother","createCatmullRomSmoother","createCombinedSmoother","DEFAULT_CONFIG","safetyMargin","sampleDirections","maxOffsetAttempts","processCorners","RadiusAwarePathSmoother","config","sampleAngles","step","Math","PI","i","push","smooth","path","map","length","result","clearance","agentRadius","point","isCorner","safePoint","prev","next","offsetCornerPoint","offsetPointFromObstacles","obstacleDirections","detectNearbyObstacles","avgDirX","avgDirY","dir","x","y","len","sqrt","offsetDirX","offsetDirY","attempt","offsetDist","newX","newY","isWalkable","floor","newObstacles","createPoint","corner","inDirX","inDirY","inLen","outDirX","outDirY","outLen","inNormX","inNormY","outNormX","outNormY","bisectX","bisectY","bisectLen","bisectNormX","bisectNormY","dotProduct","angle","acos","max","min","halfAngle","sinHalfAngle","sin","maxOffset","actualOffset","altX","altY","obstacles","dirX","cos","dirY","sampleX","sampleY","CombinedRadiusAwareSmoother","baseSmoother","radiusAwareSmoother","smoothed","createRadiusAwareSmoother","options","createCombinedRadiusAwareSmoother"]}
1
+ {"version":3,"sources":["../src/core/GridPathfinder.ts","../src/core/PathValidator.ts","../src/grid/GridMap.ts","../src/navmesh/NavMesh.ts","../src/smoothing/PathSmoother.ts","../src/smoothing/RadiusAwarePathSmoother.ts"],"sourcesContent":["/**\n * @zh 网格寻路器(统一实现)\n * @en Grid Pathfinder (unified implementation)\n */\n\nimport type { IPathfinder, IPathResult, IPathfindingOptions, IPoint } from './IPathfinding';\nimport { EMPTY_PATH_RESULT, DEFAULT_PATHFINDING_OPTIONS } from './IPathfinding';\nimport { GridMap } from '../grid/GridMap';\n\n// =============================================================================\n// 配置 | Configuration\n// =============================================================================\n\n/**\n * @zh 寻路模式\n * @en Pathfinding mode\n */\nexport type GridPathfinderMode = 'standard' | 'fast' | 'bidirectional';\n\n/**\n * @zh 网格寻路器配置\n * @en Grid pathfinder configuration\n */\nexport interface IGridPathfinderConfig {\n /**\n * @zh 寻路模式\n * @en Pathfinding mode\n *\n * - standard: 标准A*,适合小地图\n * - fast: TypedArray优化,适合中大地图\n * - bidirectional: 双向搜索,适合超大地图\n */\n mode?: GridPathfinderMode;\n}\n\n// =============================================================================\n// 常量 | Constants\n// =============================================================================\n\nconst CLOSED_FLAG = 1;\nconst OPENED_FLAG = 2;\nconst BACKWARD_CLOSED = 4;\nconst BACKWARD_OPENED = 8;\n\n// =============================================================================\n// 状态存储 | State Storage\n// =============================================================================\n\nclass GridState {\n private readonly size: number;\n readonly width: number;\n\n private g: Float32Array;\n private f: Float32Array;\n private flags: Uint8Array;\n private parent: Int32Array;\n private heapIndex: Int32Array;\n private version: Uint32Array;\n private currentVersion: number = 1;\n\n // 双向搜索额外状态\n private gBack: Float32Array | null = null;\n private fBack: Float32Array | null = null;\n private parentBack: Int32Array | null = null;\n private heapIndexBack: Int32Array | null = null;\n\n constructor(width: number, height: number, bidirectional: boolean = false) {\n this.width = width;\n this.size = width * height;\n\n this.g = new Float32Array(this.size);\n this.f = new Float32Array(this.size);\n this.flags = new Uint8Array(this.size);\n this.parent = new Int32Array(this.size);\n this.heapIndex = new Int32Array(this.size);\n this.version = new Uint32Array(this.size);\n\n if (bidirectional) {\n this.gBack = new Float32Array(this.size);\n this.fBack = new Float32Array(this.size);\n this.parentBack = new Int32Array(this.size);\n this.heapIndexBack = new Int32Array(this.size);\n }\n }\n\n reset(): void {\n this.currentVersion++;\n if (this.currentVersion > 0xFFFFFFFF) {\n this.version.fill(0);\n this.currentVersion = 1;\n }\n }\n\n private isInit(i: number): boolean {\n return this.version[i] === this.currentVersion;\n }\n\n private init(i: number): void {\n if (!this.isInit(i)) {\n this.g[i] = Infinity;\n this.f[i] = Infinity;\n this.flags[i] = 0;\n this.parent[i] = -1;\n this.heapIndex[i] = -1;\n if (this.gBack) {\n this.gBack[i] = Infinity;\n this.fBack![i] = Infinity;\n this.parentBack![i] = -1;\n this.heapIndexBack![i] = -1;\n }\n this.version[i] = this.currentVersion;\n }\n }\n\n // Forward\n getG(i: number): number { return this.isInit(i) ? this.g[i] : Infinity; }\n setG(i: number, v: number): void { this.init(i); this.g[i] = v; }\n getF(i: number): number { return this.isInit(i) ? this.f[i] : Infinity; }\n setF(i: number, v: number): void { this.init(i); this.f[i] = v; }\n getParent(i: number): number { return this.isInit(i) ? this.parent[i] : -1; }\n setParent(i: number, v: number): void { this.init(i); this.parent[i] = v; }\n getHeapIndex(i: number): number { return this.isInit(i) ? this.heapIndex[i] : -1; }\n setHeapIndex(i: number, v: number): void { this.init(i); this.heapIndex[i] = v; }\n isClosed(i: number): boolean { return this.isInit(i) && (this.flags[i] & CLOSED_FLAG) !== 0; }\n setClosed(i: number): void { this.init(i); this.flags[i] |= CLOSED_FLAG; }\n isOpened(i: number): boolean { return this.isInit(i) && (this.flags[i] & OPENED_FLAG) !== 0; }\n setOpened(i: number): void { this.init(i); this.flags[i] |= OPENED_FLAG; }\n\n // Backward\n getGBack(i: number): number { return this.isInit(i) ? this.gBack![i] : Infinity; }\n setGBack(i: number, v: number): void { this.init(i); this.gBack![i] = v; }\n getFBack(i: number): number { return this.isInit(i) ? this.fBack![i] : Infinity; }\n setFBack(i: number, v: number): void { this.init(i); this.fBack![i] = v; }\n getParentBack(i: number): number { return this.isInit(i) ? this.parentBack![i] : -1; }\n setParentBack(i: number, v: number): void { this.init(i); this.parentBack![i] = v; }\n getHeapIndexBack(i: number): number { return this.isInit(i) ? this.heapIndexBack![i] : -1; }\n setHeapIndexBack(i: number, v: number): void { this.init(i); this.heapIndexBack![i] = v; }\n isClosedBack(i: number): boolean { return this.isInit(i) && (this.flags[i] & BACKWARD_CLOSED) !== 0; }\n setClosedBack(i: number): void { this.init(i); this.flags[i] |= BACKWARD_CLOSED; }\n isOpenedBack(i: number): boolean { return this.isInit(i) && (this.flags[i] & BACKWARD_OPENED) !== 0; }\n setOpenedBack(i: number): void { this.init(i); this.flags[i] |= BACKWARD_OPENED; }\n}\n\n// =============================================================================\n// 堆 | Heap\n// =============================================================================\n\nclass GridHeap {\n private heap: number[] = [];\n private state: GridState;\n private isBack: boolean;\n\n constructor(state: GridState, isBack: boolean = false) {\n this.state = state;\n this.isBack = isBack;\n }\n\n get size(): number { return this.heap.length; }\n get isEmpty(): boolean { return this.heap.length === 0; }\n\n private getF(i: number): number {\n return this.isBack ? this.state.getFBack(i) : this.state.getF(i);\n }\n private getHeapIndex(i: number): number {\n return this.isBack ? this.state.getHeapIndexBack(i) : this.state.getHeapIndex(i);\n }\n private setHeapIndex(i: number, v: number): void {\n if (this.isBack) this.state.setHeapIndexBack(i, v);\n else this.state.setHeapIndex(i, v);\n }\n\n push(i: number): void {\n this.setHeapIndex(i, this.heap.length);\n this.heap.push(i);\n this.bubbleUp(this.heap.length - 1);\n }\n\n pop(): number {\n if (this.heap.length === 0) return -1;\n const result = this.heap[0];\n this.setHeapIndex(result, -1);\n const last = this.heap.pop()!;\n if (this.heap.length > 0) {\n this.heap[0] = last;\n this.setHeapIndex(last, 0);\n this.sinkDown(0);\n }\n return result;\n }\n\n update(i: number): void {\n const pos = this.getHeapIndex(i);\n if (pos >= 0 && pos < this.heap.length) {\n this.bubbleUp(pos);\n this.sinkDown(this.getHeapIndex(i));\n }\n }\n\n clear(): void { this.heap.length = 0; }\n\n private bubbleUp(pos: number): void {\n const idx = this.heap[pos];\n const f = this.getF(idx);\n while (pos > 0) {\n const pp = (pos - 1) >> 1;\n const pi = this.heap[pp];\n if (f >= this.getF(pi)) break;\n this.heap[pos] = pi;\n this.setHeapIndex(pi, pos);\n pos = pp;\n }\n this.heap[pos] = idx;\n this.setHeapIndex(idx, pos);\n }\n\n private sinkDown(pos: number): void {\n const len = this.heap.length;\n const idx = this.heap[pos];\n const f = this.getF(idx);\n const half = len >> 1;\n while (pos < half) {\n const left = (pos << 1) + 1;\n const right = left + 1;\n let smallest = pos, smallestF = f;\n const lf = this.getF(this.heap[left]);\n if (lf < smallestF) { smallest = left; smallestF = lf; }\n if (right < len) {\n const rf = this.getF(this.heap[right]);\n if (rf < smallestF) smallest = right;\n }\n if (smallest === pos) break;\n const si = this.heap[smallest];\n this.heap[pos] = si;\n this.setHeapIndex(si, pos);\n pos = smallest;\n }\n this.heap[pos] = idx;\n this.setHeapIndex(idx, pos);\n }\n}\n\n// =============================================================================\n// 网格寻路器 | Grid Pathfinder\n// =============================================================================\n\n/**\n * @zh 网格寻路器\n * @en Grid Pathfinder\n */\nexport class GridPathfinder implements IPathfinder {\n private readonly map: GridMap;\n private readonly mode: GridPathfinderMode;\n private readonly state: GridState;\n private readonly openList: GridHeap;\n private readonly openListBack: GridHeap | null;\n\n constructor(map: GridMap, config?: IGridPathfinderConfig) {\n this.map = map;\n this.mode = config?.mode ?? 'fast';\n const isBidir = this.mode === 'bidirectional';\n this.state = new GridState(map.width, map.height, isBidir);\n this.openList = new GridHeap(this.state, false);\n this.openListBack = isBidir ? new GridHeap(this.state, true) : null;\n }\n\n findPath(\n startX: number,\n startY: number,\n endX: number,\n endY: number,\n options?: IPathfindingOptions\n ): IPathResult {\n if (this.mode === 'bidirectional') {\n return this.findPathBidirectional(startX, startY, endX, endY, options);\n }\n return this.findPathUnidirectional(startX, startY, endX, endY, options);\n }\n\n private findPathUnidirectional(\n startX: number, startY: number,\n endX: number, endY: number,\n options?: IPathfindingOptions\n ): IPathResult {\n const opts = options ? { ...DEFAULT_PATHFINDING_OPTIONS, ...options } : DEFAULT_PATHFINDING_OPTIONS;\n const { width, height } = this.map;\n\n this.state.reset();\n this.openList.clear();\n\n if (!this.validate(startX, startY, endX, endY)) return EMPTY_PATH_RESULT;\n\n const startIdx = startY * width + startX;\n const endIdx = endY * width + endX;\n\n if (startIdx === endIdx) {\n return { found: true, path: [{ x: startX, y: startY }], cost: 0, nodesSearched: 1 };\n }\n\n const hw = opts.heuristicWeight;\n const h0 = this.map.heuristic({ x: startX, y: startY }, { x: endX, y: endY }) * hw;\n this.state.setG(startIdx, 0);\n this.state.setF(startIdx, h0);\n this.state.setOpened(startIdx);\n this.openList.push(startIdx);\n\n let searched = 0;\n const maxNodes = opts.maxNodes;\n const { allowDiagonal, avoidCorners, diagonalCost } = this.map['options'];\n const nodes = this.map['nodes'];\n const dx = allowDiagonal ? [0, 1, 1, 1, 0, -1, -1, -1] : [0, 1, 0, -1];\n const dy = allowDiagonal ? [-1, -1, 0, 1, 1, 1, 0, -1] : [-1, 0, 1, 0];\n const dirCount = dx.length;\n\n while (!this.openList.isEmpty && searched < maxNodes) {\n const cur = this.openList.pop();\n this.state.setClosed(cur);\n searched++;\n\n if (cur === endIdx) {\n return this.buildPath(startIdx, endIdx, searched);\n }\n\n const cx = cur % width, cy = (cur / width) | 0;\n const curG = this.state.getG(cur);\n\n for (let d = 0; d < dirCount; d++) {\n const nx = cx + dx[d], ny = cy + dy[d];\n if (nx < 0 || nx >= width || ny < 0 || ny >= height) continue;\n\n const neighbor = nodes[ny][nx];\n if (!neighbor.walkable) continue;\n\n if (avoidCorners && dx[d] !== 0 && dy[d] !== 0) {\n if (!nodes[cy][cx + dx[d]].walkable || !nodes[cy + dy[d]][cx].walkable) continue;\n }\n\n const ni = ny * width + nx;\n if (this.state.isClosed(ni)) continue;\n\n const isDiag = dx[d] !== 0 && dy[d] !== 0;\n const cost = isDiag ? neighbor.cost * diagonalCost : neighbor.cost;\n const tentG = curG + cost;\n\n if (!this.state.isOpened(ni)) {\n const h = this.map.heuristic({ x: nx, y: ny }, { x: endX, y: endY }) * hw;\n this.state.setG(ni, tentG);\n this.state.setF(ni, tentG + h);\n this.state.setParent(ni, cur);\n this.state.setOpened(ni);\n this.openList.push(ni);\n } else if (tentG < this.state.getG(ni)) {\n const h = this.state.getF(ni) - this.state.getG(ni);\n this.state.setG(ni, tentG);\n this.state.setF(ni, tentG + h);\n this.state.setParent(ni, cur);\n this.openList.update(ni);\n }\n }\n }\n\n return { found: false, path: [], cost: 0, nodesSearched: searched };\n }\n\n private findPathBidirectional(\n startX: number, startY: number,\n endX: number, endY: number,\n options?: IPathfindingOptions\n ): IPathResult {\n const opts = options ? { ...DEFAULT_PATHFINDING_OPTIONS, ...options } : DEFAULT_PATHFINDING_OPTIONS;\n const { width, height } = this.map;\n\n this.state.reset();\n this.openList.clear();\n this.openListBack!.clear();\n\n if (!this.validate(startX, startY, endX, endY)) return EMPTY_PATH_RESULT;\n\n const startIdx = startY * width + startX;\n const endIdx = endY * width + endX;\n\n if (startIdx === endIdx) {\n return { found: true, path: [{ x: startX, y: startY }], cost: 0, nodesSearched: 1 };\n }\n\n const hw = opts.heuristicWeight;\n const startPos = { x: startX, y: startY };\n const endPos = { x: endX, y: endY };\n\n // Init forward\n const hf = this.map.heuristic(startPos, endPos) * hw;\n this.state.setG(startIdx, 0);\n this.state.setF(startIdx, hf);\n this.state.setOpened(startIdx);\n this.openList.push(startIdx);\n\n // Init backward\n const hb = this.map.heuristic(endPos, startPos) * hw;\n this.state.setGBack(endIdx, 0);\n this.state.setFBack(endIdx, hb);\n this.state.setOpenedBack(endIdx);\n this.openListBack!.push(endIdx);\n\n let searched = 0;\n const maxNodes = opts.maxNodes;\n let meetIdx = -1, bestCost = Infinity;\n\n const { allowDiagonal, avoidCorners, diagonalCost } = this.map['options'];\n const nodes = this.map['nodes'];\n const dx = allowDiagonal ? [0, 1, 1, 1, 0, -1, -1, -1] : [0, 1, 0, -1];\n const dy = allowDiagonal ? [-1, -1, 0, 1, 1, 1, 0, -1] : [-1, 0, 1, 0];\n const dirCount = dx.length;\n\n while ((!this.openList.isEmpty || !this.openListBack!.isEmpty) && searched < maxNodes) {\n // Forward\n if (!this.openList.isEmpty) {\n const cur = this.openList.pop();\n this.state.setClosed(cur);\n searched++;\n\n const curG = this.state.getG(cur);\n if (this.state.isClosedBack(cur)) {\n const total = curG + this.state.getGBack(cur);\n if (total < bestCost) { bestCost = total; meetIdx = cur; }\n }\n if (meetIdx !== -1 && curG >= bestCost) break;\n\n const cx = cur % width, cy = (cur / width) | 0;\n for (let d = 0; d < dirCount; d++) {\n const nx = cx + dx[d], ny = cy + dy[d];\n if (nx < 0 || nx >= width || ny < 0 || ny >= height) continue;\n const neighbor = nodes[ny][nx];\n if (!neighbor.walkable) continue;\n if (avoidCorners && dx[d] !== 0 && dy[d] !== 0) {\n if (!nodes[cy][cx + dx[d]].walkable || !nodes[cy + dy[d]][cx].walkable) continue;\n }\n const ni = ny * width + nx;\n if (this.state.isClosed(ni)) continue;\n const isDiag = dx[d] !== 0 && dy[d] !== 0;\n const cost = isDiag ? neighbor.cost * diagonalCost : neighbor.cost;\n const tentG = curG + cost;\n if (!this.state.isOpened(ni)) {\n const h = this.map.heuristic({ x: nx, y: ny }, endPos) * hw;\n this.state.setG(ni, tentG);\n this.state.setF(ni, tentG + h);\n this.state.setParent(ni, cur);\n this.state.setOpened(ni);\n this.openList.push(ni);\n } else if (tentG < this.state.getG(ni)) {\n const h = this.state.getF(ni) - this.state.getG(ni);\n this.state.setG(ni, tentG);\n this.state.setF(ni, tentG + h);\n this.state.setParent(ni, cur);\n this.openList.update(ni);\n }\n }\n }\n\n // Backward\n if (!this.openListBack!.isEmpty) {\n const cur = this.openListBack!.pop();\n this.state.setClosedBack(cur);\n searched++;\n\n const curG = this.state.getGBack(cur);\n if (this.state.isClosed(cur)) {\n const total = curG + this.state.getG(cur);\n if (total < bestCost) { bestCost = total; meetIdx = cur; }\n }\n if (meetIdx !== -1 && curG >= bestCost) break;\n\n const cx = cur % width, cy = (cur / width) | 0;\n for (let d = 0; d < dirCount; d++) {\n const nx = cx + dx[d], ny = cy + dy[d];\n if (nx < 0 || nx >= width || ny < 0 || ny >= height) continue;\n const neighbor = nodes[ny][nx];\n if (!neighbor.walkable) continue;\n if (avoidCorners && dx[d] !== 0 && dy[d] !== 0) {\n if (!nodes[cy][cx + dx[d]].walkable || !nodes[cy + dy[d]][cx].walkable) continue;\n }\n const ni = ny * width + nx;\n if (this.state.isClosedBack(ni)) continue;\n const isDiag = dx[d] !== 0 && dy[d] !== 0;\n const cost = isDiag ? neighbor.cost * diagonalCost : neighbor.cost;\n const tentG = curG + cost;\n if (!this.state.isOpenedBack(ni)) {\n const h = this.map.heuristic({ x: nx, y: ny }, startPos) * hw;\n this.state.setGBack(ni, tentG);\n this.state.setFBack(ni, tentG + h);\n this.state.setParentBack(ni, cur);\n this.state.setOpenedBack(ni);\n this.openListBack!.push(ni);\n } else if (tentG < this.state.getGBack(ni)) {\n const h = this.state.getFBack(ni) - this.state.getGBack(ni);\n this.state.setGBack(ni, tentG);\n this.state.setFBack(ni, tentG + h);\n this.state.setParentBack(ni, cur);\n this.openListBack!.update(ni);\n }\n }\n }\n }\n\n if (meetIdx === -1) {\n return { found: false, path: [], cost: 0, nodesSearched: searched };\n }\n\n return this.buildPathBidirectional(startIdx, endIdx, meetIdx, searched);\n }\n\n private validate(startX: number, startY: number, endX: number, endY: number): boolean {\n const { width, height } = this.map;\n if (startX < 0 || startX >= width || startY < 0 || startY >= height) return false;\n if (endX < 0 || endX >= width || endY < 0 || endY >= height) return false;\n return this.map.isWalkable(startX, startY) && this.map.isWalkable(endX, endY);\n }\n\n private buildPath(startIdx: number, endIdx: number, searched: number): IPathResult {\n const w = this.state.width;\n const path: IPoint[] = [];\n let cur = endIdx;\n while (cur !== -1) {\n path.push({ x: cur % w, y: (cur / w) | 0 });\n cur = cur === startIdx ? -1 : this.state.getParent(cur);\n }\n path.reverse();\n return { found: true, path, cost: this.state.getG(endIdx), nodesSearched: searched };\n }\n\n private buildPathBidirectional(startIdx: number, endIdx: number, meetIdx: number, searched: number): IPathResult {\n const w = this.state.width;\n const path: IPoint[] = [];\n\n // Forward path\n let cur = meetIdx;\n while (cur !== -1 && cur !== startIdx) {\n path.push({ x: cur % w, y: (cur / w) | 0 });\n cur = this.state.getParent(cur);\n }\n path.push({ x: startIdx % w, y: (startIdx / w) | 0 });\n path.reverse();\n\n // Backward path\n cur = this.state.getParentBack(meetIdx);\n while (cur !== -1 && cur !== endIdx) {\n path.push({ x: cur % w, y: (cur / w) | 0 });\n cur = this.state.getParentBack(cur);\n }\n if (meetIdx !== endIdx) {\n path.push({ x: endIdx % w, y: (endIdx / w) | 0 });\n }\n\n const cost = this.state.getG(meetIdx) + this.state.getGBack(meetIdx);\n return { found: true, path, cost, nodesSearched: searched };\n }\n\n clear(): void {\n this.state.reset();\n this.openList.clear();\n this.openListBack?.clear();\n }\n}\n\n/**\n * @zh 创建网格寻路器\n * @en Create grid pathfinder\n */\nexport function createGridPathfinder(map: GridMap, config?: IGridPathfinderConfig): GridPathfinder {\n return new GridPathfinder(map, config);\n}\n","/**\n * @zh 路径验证器\n * @en Path Validator\n */\n\nimport type { IPoint, IPathfindingMap } from './IPathfinding';\nimport type { IPathValidator, IPathValidationResult } from './IIncrementalPathfinding';\n\n// =============================================================================\n// 路径验证器 | Path Validator\n// =============================================================================\n\n/**\n * @zh 路径验证器\n * @en Path Validator\n *\n * @zh 用于检查现有路径在地图变化后是否仍然有效\n * @en Used to check if an existing path is still valid after map changes\n *\n * @example\n * ```typescript\n * const validator = new PathValidator();\n * const result = validator.validatePath(path, 0, path.length, map);\n *\n * if (!result.valid) {\n * console.log('Path invalid at index:', result.invalidIndex);\n * // Trigger replanning from current position\n * }\n * ```\n */\nexport class PathValidator implements IPathValidator {\n /**\n * @zh 验证路径段的有效性\n * @en Validate path segment validity\n *\n * @param path - @zh 要验证的路径 @en Path to validate\n * @param fromIndex - @zh 起始索引 @en Start index\n * @param toIndex - @zh 结束索引 @en End index\n * @param map - @zh 地图实例 @en Map instance\n * @returns @zh 验证结果 @en Validation result\n */\n validatePath(\n path: readonly IPoint[],\n fromIndex: number,\n toIndex: number,\n map: IPathfindingMap\n ): IPathValidationResult {\n const end = Math.min(toIndex, path.length);\n\n for (let i = fromIndex; i < end; i++) {\n const point = path[i];\n const x = Math.floor(point.x);\n const y = Math.floor(point.y);\n\n if (!map.isWalkable(x, y)) {\n return { valid: false, invalidIndex: i };\n }\n\n if (i > fromIndex) {\n const prev = path[i - 1];\n if (!this.checkLineOfSight(prev.x, prev.y, point.x, point.y, map)) {\n return { valid: false, invalidIndex: i };\n }\n }\n }\n\n return { valid: true, invalidIndex: -1 };\n }\n\n /**\n * @zh 检查两点之间的视线(使用 Bresenham 算法)\n * @en Check line of sight between two points (using Bresenham algorithm)\n *\n * @param x1 - @zh 起点 X @en Start X\n * @param y1 - @zh 起点 Y @en Start Y\n * @param x2 - @zh 终点 X @en End X\n * @param y2 - @zh 终点 Y @en End Y\n * @param map - @zh 地图实例 @en Map instance\n * @returns @zh 是否有视线 @en Whether there is line of sight\n */\n private checkLineOfSight(\n x1: number,\n y1: number,\n x2: number,\n y2: number,\n map: IPathfindingMap\n ): boolean {\n const ix1 = Math.floor(x1);\n const iy1 = Math.floor(y1);\n const ix2 = Math.floor(x2);\n const iy2 = Math.floor(y2);\n\n let dx = Math.abs(ix2 - ix1);\n let dy = Math.abs(iy2 - iy1);\n let x = ix1;\n let y = iy1;\n\n const sx = ix1 < ix2 ? 1 : -1;\n const sy = iy1 < iy2 ? 1 : -1;\n\n if (dx > dy) {\n let err = dx / 2;\n while (x !== ix2) {\n if (!map.isWalkable(x, y)) {\n return false;\n }\n err -= dy;\n if (err < 0) {\n y += sy;\n err += dx;\n }\n x += sx;\n }\n } else {\n let err = dy / 2;\n while (y !== iy2) {\n if (!map.isWalkable(x, y)) {\n return false;\n }\n err -= dx;\n if (err < 0) {\n x += sx;\n err += dy;\n }\n y += sy;\n }\n }\n\n return map.isWalkable(ix2, iy2);\n }\n}\n\n// =============================================================================\n// 障碍物变化管理器 | Obstacle Change Manager\n// =============================================================================\n\n/**\n * @zh 障碍物变化记录\n * @en Obstacle change record\n */\nexport interface IObstacleChange {\n /**\n * @zh X 坐标\n * @en X coordinate\n */\n readonly x: number;\n\n /**\n * @zh Y 坐标\n * @en Y coordinate\n */\n readonly y: number;\n\n /**\n * @zh 变化前是否可通行\n * @en Was walkable before change\n */\n readonly wasWalkable: boolean;\n\n /**\n * @zh 变化时间戳\n * @en Change timestamp\n */\n readonly timestamp: number;\n}\n\n/**\n * @zh 障碍物变化区域\n * @en Obstacle change region\n */\nexport interface IChangeRegion {\n /**\n * @zh 最小 X 坐标\n * @en Minimum X coordinate\n */\n readonly minX: number;\n\n /**\n * @zh 最小 Y 坐标\n * @en Minimum Y coordinate\n */\n readonly minY: number;\n\n /**\n * @zh 最大 X 坐标\n * @en Maximum X coordinate\n */\n readonly maxX: number;\n\n /**\n * @zh 最大 Y 坐标\n * @en Maximum Y coordinate\n */\n readonly maxY: number;\n}\n\n/**\n * @zh 障碍物变化管理器\n * @en Obstacle Change Manager\n *\n * @zh 跟踪地图障碍物变化,用于触发动态重规划\n * @en Tracks map obstacle changes, used to trigger dynamic replanning\n *\n * @example\n * ```typescript\n * const manager = new ObstacleChangeManager();\n *\n * // Record change when obstacle is added/removed\n * manager.recordChange(10, 20, true); // Was walkable, now blocked\n *\n * // Get affected region for notification\n * const region = manager.getAffectedRegion();\n * if (region) {\n * pathfinder.notifyObstacleChange(\n * region.minX, region.minY,\n * region.maxX, region.maxY\n * );\n * }\n *\n * // Clear after notification\n * manager.flush();\n * ```\n */\nexport class ObstacleChangeManager {\n private readonly changes: Map<string, IObstacleChange> = new Map();\n private epoch: number = 0;\n\n /**\n * @zh 记录障碍物变化\n * @en Record obstacle change\n *\n * @param x - @zh X 坐标 @en X coordinate\n * @param y - @zh Y 坐标 @en Y coordinate\n * @param wasWalkable - @zh 变化前是否可通行 @en Was walkable before change\n */\n recordChange(x: number, y: number, wasWalkable: boolean): void {\n const key = `${x},${y}`;\n this.changes.set(key, {\n x,\n y,\n wasWalkable,\n timestamp: Date.now()\n });\n }\n\n /**\n * @zh 获取影响区域\n * @en Get affected region\n *\n * @returns @zh 影响区域或 null(如果没有变化)@en Affected region or null if no changes\n */\n getAffectedRegion(): IChangeRegion | null {\n if (this.changes.size === 0) {\n return null;\n }\n\n let minX = Infinity;\n let minY = Infinity;\n let maxX = -Infinity;\n let maxY = -Infinity;\n\n for (const change of this.changes.values()) {\n minX = Math.min(minX, change.x);\n minY = Math.min(minY, change.y);\n maxX = Math.max(maxX, change.x);\n maxY = Math.max(maxY, change.y);\n }\n\n return { minX, minY, maxX, maxY };\n }\n\n /**\n * @zh 获取所有变化\n * @en Get all changes\n *\n * @returns @zh 变化列表 @en List of changes\n */\n getChanges(): IObstacleChange[] {\n return Array.from(this.changes.values());\n }\n\n /**\n * @zh 检查是否有变化\n * @en Check if there are changes\n *\n * @returns @zh 是否有变化 @en Whether there are changes\n */\n hasChanges(): boolean {\n return this.changes.size > 0;\n }\n\n /**\n * @zh 获取当前 epoch\n * @en Get current epoch\n *\n * @returns @zh 当前 epoch @en Current epoch\n */\n getEpoch(): number {\n return this.epoch;\n }\n\n /**\n * @zh 清空变化记录并推进 epoch\n * @en Clear changes and advance epoch\n */\n flush(): void {\n this.changes.clear();\n this.epoch++;\n }\n\n /**\n * @zh 清空所有状态\n * @en Clear all state\n */\n clear(): void {\n this.changes.clear();\n this.epoch = 0;\n }\n}\n\n// =============================================================================\n// 工厂函数 | Factory Functions\n// =============================================================================\n\n/**\n * @zh 创建路径验证器\n * @en Create path validator\n *\n * @returns @zh 路径验证器实例 @en Path validator instance\n */\nexport function createPathValidator(): PathValidator {\n return new PathValidator();\n}\n\n/**\n * @zh 创建障碍物变化管理器\n * @en Create obstacle change manager\n *\n * @returns @zh 障碍物变化管理器实例 @en Obstacle change manager instance\n */\nexport function createObstacleChangeManager(): ObstacleChangeManager {\n return new ObstacleChangeManager();\n}\n","/**\n * @zh 网格地图实现\n * @en Grid Map Implementation\n */\n\nimport type {\n IPathfindingMap,\n IPathNode,\n IPoint,\n HeuristicFunction\n} from '../core/IPathfinding';\nimport { createPoint, octileDistance } from '../core/IPathfinding';\n\n// =============================================================================\n// 网格节点 | Grid Node\n// =============================================================================\n\n/**\n * @zh 网格节点\n * @en Grid node\n */\nexport class GridNode implements IPathNode {\n readonly id: number;\n readonly position: IPoint;\n readonly x: number;\n readonly y: number;\n cost: number;\n walkable: boolean;\n\n constructor(x: number, y: number, width: number, walkable: boolean = true, cost: number = 1) {\n this.x = x;\n this.y = y;\n this.id = y * width + x;\n this.position = createPoint(x, y);\n this.walkable = walkable;\n this.cost = cost;\n }\n}\n\n// =============================================================================\n// 移动方向 | Movement Directions\n// =============================================================================\n\n/**\n * @zh 4方向偏移 (上下左右)\n * @en 4-directional offsets (up, down, left, right)\n */\nexport const DIRECTIONS_4 = [\n { dx: 0, dy: -1 }, // Up\n { dx: 1, dy: 0 }, // Right\n { dx: 0, dy: 1 }, // Down\n { dx: -1, dy: 0 } // Left\n] as const;\n\n/**\n * @zh 8方向偏移 (含对角线)\n * @en 8-directional offsets (including diagonals)\n */\nexport const DIRECTIONS_8 = [\n { dx: 0, dy: -1 }, // Up\n { dx: 1, dy: -1 }, // Up-Right\n { dx: 1, dy: 0 }, // Right\n { dx: 1, dy: 1 }, // Down-Right\n { dx: 0, dy: 1 }, // Down\n { dx: -1, dy: 1 }, // Down-Left\n { dx: -1, dy: 0 }, // Left\n { dx: -1, dy: -1 } // Up-Left\n] as const;\n\n// =============================================================================\n// 网格地图配置 | Grid Map Options\n// =============================================================================\n\n/**\n * @zh 网格地图配置\n * @en Grid map options\n */\nexport interface IGridMapOptions {\n /** @zh 是否允许对角移动 @en Allow diagonal movement */\n allowDiagonal?: boolean;\n /** @zh 对角移动代价 @en Diagonal movement cost */\n diagonalCost?: number;\n /** @zh 是否避免穿角 @en Avoid corner cutting */\n avoidCorners?: boolean;\n /** @zh 启发式函数 @en Heuristic function */\n heuristic?: HeuristicFunction;\n}\n\n/**\n * @zh 默认网格地图配置\n * @en Default grid map options\n */\nexport const DEFAULT_GRID_OPTIONS: Required<IGridMapOptions> = {\n allowDiagonal: true,\n diagonalCost: Math.SQRT2,\n avoidCorners: true,\n heuristic: octileDistance\n};\n\n// =============================================================================\n// 网格地图 | Grid Map\n// =============================================================================\n\n/**\n * @zh 网格地图\n * @en Grid Map\n *\n * @zh 基于二维数组的网格地图实现,支持4方向和8方向移动\n * @en Grid map implementation based on 2D array, supports 4 and 8 directional movement\n *\n * @example\n * ```typescript\n * // Create a 10x10 grid\n * const grid = new GridMap(10, 10);\n *\n * // Set some cells as obstacles\n * grid.setWalkable(5, 5, false);\n * grid.setWalkable(5, 6, false);\n *\n * // Use with pathfinder\n * const pathfinder = new AStarPathfinder(grid);\n * const result = pathfinder.findPath(0, 0, 9, 9);\n * ```\n */\nexport class GridMap implements IPathfindingMap {\n readonly width: number;\n readonly height: number;\n private readonly nodes: GridNode[][];\n private readonly options: Required<IGridMapOptions>;\n\n constructor(width: number, height: number, options?: IGridMapOptions) {\n if (width <= 0 || !Number.isFinite(width) || !Number.isInteger(width)) {\n throw new Error(`width must be a positive integer, got: ${width}`);\n }\n if (height <= 0 || !Number.isFinite(height) || !Number.isInteger(height)) {\n throw new Error(`height must be a positive integer, got: ${height}`);\n }\n this.width = width;\n this.height = height;\n this.options = { ...DEFAULT_GRID_OPTIONS, ...options };\n this.nodes = this.createNodes();\n }\n\n /**\n * @zh 创建网格节点\n * @en Create grid nodes\n */\n private createNodes(): GridNode[][] {\n const nodes: GridNode[][] = [];\n\n for (let y = 0; y < this.height; y++) {\n nodes[y] = [];\n for (let x = 0; x < this.width; x++) {\n nodes[y][x] = new GridNode(x, y, this.width, true, 1);\n }\n }\n\n return nodes;\n }\n\n /**\n * @zh 获取指定位置的节点\n * @en Get node at position\n */\n getNodeAt(x: number, y: number): GridNode | null {\n if (!this.isInBounds(x, y)) {\n return null;\n }\n return this.nodes[y][x];\n }\n\n /**\n * @zh 检查坐标是否在边界内\n * @en Check if coordinates are within bounds\n */\n isInBounds(x: number, y: number): boolean {\n return x >= 0 && x < this.width && y >= 0 && y < this.height;\n }\n\n /**\n * @zh 检查位置是否可通行\n * @en Check if position is walkable\n */\n isWalkable(x: number, y: number): boolean {\n const node = this.getNodeAt(x, y);\n return node !== null && node.walkable;\n }\n\n /**\n * @zh 设置位置是否可通行\n * @en Set position walkability\n */\n setWalkable(x: number, y: number, walkable: boolean): void {\n const node = this.getNodeAt(x, y);\n if (node) {\n node.walkable = walkable;\n }\n }\n\n /**\n * @zh 设置位置的移动代价\n * @en Set movement cost at position\n *\n * @param x - @zh X 坐标 @en X coordinate\n * @param y - @zh Y 坐标 @en Y coordinate\n * @param cost - @zh 移动代价,必须为正数 @en Movement cost, must be positive\n * @throws @zh 如果 cost 不是正数则抛出错误 @en Throws if cost is not positive\n */\n setCost(x: number, y: number, cost: number): void {\n if (cost <= 0 || !Number.isFinite(cost)) {\n throw new Error(`cost must be a positive finite number, got: ${cost}`);\n }\n const node = this.getNodeAt(x, y);\n if (node) {\n node.cost = cost;\n }\n }\n\n /**\n * @zh 获取节点的邻居\n * @en Get neighbors of a node\n */\n getNeighbors(node: IPathNode): GridNode[] {\n const neighbors: GridNode[] = [];\n const { x, y } = node.position;\n const directions = this.options.allowDiagonal ? DIRECTIONS_8 : DIRECTIONS_4;\n\n for (let i = 0; i < directions.length; i++) {\n const dir = directions[i];\n const nx = x + dir.dx;\n const ny = y + dir.dy;\n\n if (nx < 0 || nx >= this.width || ny < 0 || ny >= this.height) {\n continue;\n }\n\n const neighbor = this.nodes[ny][nx];\n\n if (!neighbor.walkable) {\n continue;\n }\n\n if (this.options.avoidCorners && dir.dx !== 0 && dir.dy !== 0) {\n const hNode = this.nodes[y][x + dir.dx];\n const vNode = this.nodes[y + dir.dy][x];\n\n if (!hNode.walkable || !vNode.walkable) {\n continue;\n }\n }\n\n neighbors.push(neighbor);\n }\n\n return neighbors;\n }\n\n /**\n * @zh 遍历节点的邻居(零分配)\n * @en Iterate over neighbors (zero allocation)\n */\n forEachNeighbor(node: IPathNode, callback: (neighbor: GridNode) => boolean | void): void {\n const { x, y } = node.position;\n const directions = this.options.allowDiagonal ? DIRECTIONS_8 : DIRECTIONS_4;\n\n for (let i = 0; i < directions.length; i++) {\n const dir = directions[i];\n const nx = x + dir.dx;\n const ny = y + dir.dy;\n\n if (nx < 0 || nx >= this.width || ny < 0 || ny >= this.height) {\n continue;\n }\n\n const neighbor = this.nodes[ny][nx];\n\n if (!neighbor.walkable) {\n continue;\n }\n\n if (this.options.avoidCorners && dir.dx !== 0 && dir.dy !== 0) {\n const hNode = this.nodes[y][x + dir.dx];\n const vNode = this.nodes[y + dir.dy][x];\n\n if (!hNode.walkable || !vNode.walkable) {\n continue;\n }\n }\n\n if (callback(neighbor) === false) {\n return;\n }\n }\n }\n\n /**\n * @zh 计算启发式距离\n * @en Calculate heuristic distance\n */\n heuristic(a: IPoint, b: IPoint): number {\n return this.options.heuristic(a, b);\n }\n\n /**\n * @zh 计算移动代价\n * @en Calculate movement cost\n */\n getMovementCost(from: IPathNode, to: IPathNode): number {\n const dx = Math.abs(from.position.x - to.position.x);\n const dy = Math.abs(from.position.y - to.position.y);\n\n // Diagonal movement\n if (dx !== 0 && dy !== 0) {\n return to.cost * this.options.diagonalCost;\n }\n\n // Cardinal movement\n return to.cost;\n }\n\n /**\n * @zh 从二维数组加载地图\n * @en Load map from 2D array\n *\n * @param data - @zh 0=可通行,非0=不可通行 @en 0=walkable, non-0=blocked\n */\n loadFromArray(data: number[][]): void {\n for (let y = 0; y < Math.min(data.length, this.height); y++) {\n for (let x = 0; x < Math.min(data[y].length, this.width); x++) {\n this.nodes[y][x].walkable = data[y][x] === 0;\n }\n }\n }\n\n /**\n * @zh 从字符串加载地图\n * @en Load map from string\n *\n * @param str - @zh 地图字符串,'.'=可通行,'#'=障碍 @en Map string, '.'=walkable, '#'=blocked\n */\n loadFromString(str: string): void {\n const lines = str.trim().split('\\n');\n\n for (let y = 0; y < Math.min(lines.length, this.height); y++) {\n const line = lines[y];\n for (let x = 0; x < Math.min(line.length, this.width); x++) {\n this.nodes[y][x].walkable = line[x] !== '#';\n }\n }\n }\n\n /**\n * @zh 导出为字符串\n * @en Export to string\n */\n toString(): string {\n let result = '';\n\n for (let y = 0; y < this.height; y++) {\n for (let x = 0; x < this.width; x++) {\n result += this.nodes[y][x].walkable ? '.' : '#';\n }\n result += '\\n';\n }\n\n return result;\n }\n\n /**\n * @zh 重置所有节点为可通行\n * @en Reset all nodes to walkable\n */\n reset(): void {\n for (let y = 0; y < this.height; y++) {\n for (let x = 0; x < this.width; x++) {\n this.nodes[y][x].walkable = true;\n this.nodes[y][x].cost = 1;\n }\n }\n }\n\n /**\n * @zh 设置矩形区域的通行性\n * @en Set walkability for a rectangle region\n */\n setRectWalkable(\n x: number,\n y: number,\n width: number,\n height: number,\n walkable: boolean\n ): void {\n for (let dy = 0; dy < height; dy++) {\n for (let dx = 0; dx < width; dx++) {\n this.setWalkable(x + dx, y + dy, walkable);\n }\n }\n }\n}\n\n// =============================================================================\n// 工厂函数 | Factory Function\n// =============================================================================\n\n/**\n * @zh 创建网格地图\n * @en Create grid map\n */\nexport function createGridMap(\n width: number,\n height: number,\n options?: IGridMapOptions\n): GridMap {\n return new GridMap(width, height, options);\n}\n","/**\n * @zh 导航网格实现\n * @en NavMesh Implementation\n *\n * @zh 支持动态障碍物:可以临时禁用多边形或添加圆形/矩形障碍物\n * @en Supports dynamic obstacles: can temporarily disable polygons or add circular/rectangular obstacles\n */\n\nimport type {\n IPathfindingMap,\n IPathNode,\n IPoint,\n IPathResult,\n IPathfindingOptions\n} from '../core/IPathfinding';\nimport { createPoint, euclideanDistance, EMPTY_PATH_RESULT, DEFAULT_PATHFINDING_OPTIONS } from '../core/IPathfinding';\nimport { BinaryHeap } from '../core/BinaryHeap';\n\n// =============================================================================\n// 动态障碍物 | Dynamic Obstacles\n// =============================================================================\n\n/**\n * @zh 动态障碍物类型\n * @en Dynamic obstacle type\n */\nexport type ObstacleType = 'circle' | 'rect' | 'polygon';\n\n/**\n * @zh 动态障碍物\n * @en Dynamic obstacle\n */\nexport interface IDynamicObstacle {\n /**\n * @zh 障碍物 ID\n * @en Obstacle ID\n */\n readonly id: number;\n\n /**\n * @zh 障碍物类型\n * @en Obstacle type\n */\n readonly type: ObstacleType;\n\n /**\n * @zh 是否启用\n * @en Whether enabled\n */\n enabled: boolean;\n\n /**\n * @zh 位置(圆形和矩形的中心)\n * @en Position (center for circle and rect)\n */\n position: IPoint;\n\n /**\n * @zh 半径(圆形)或半宽/半高(矩形)\n * @en Radius (circle) or half-width/half-height (rect)\n */\n radius?: number;\n halfWidth?: number;\n halfHeight?: number;\n\n /**\n * @zh 顶点(多边形)\n * @en Vertices (polygon)\n */\n vertices?: readonly IPoint[];\n}\n\n// =============================================================================\n// 导航多边形 | Navigation Polygon\n// =============================================================================\n\n/**\n * @zh 导航多边形\n * @en Navigation polygon\n */\nexport interface INavPolygon {\n /** @zh 多边形ID @en Polygon ID */\n readonly id: number;\n /** @zh 顶点列表 @en Vertex list */\n readonly vertices: readonly IPoint[];\n /** @zh 中心点 @en Center point */\n readonly center: IPoint;\n /** @zh 邻居多边形ID @en Neighbor polygon IDs */\n readonly neighbors: readonly number[];\n /** @zh 到邻居的共享边 @en Shared edges to neighbors */\n readonly portals: ReadonlyMap<number, IPortal>;\n}\n\n/**\n * @zh 入口(两个多边形之间的共享边)\n * @en Portal (shared edge between two polygons)\n */\nexport interface IPortal {\n /** @zh 边的左端点 @en Left endpoint of edge */\n readonly left: IPoint;\n /** @zh 边的右端点 @en Right endpoint of edge */\n readonly right: IPoint;\n}\n\n// =============================================================================\n// 导航网格节点 | NavMesh Node\n// =============================================================================\n\n/**\n * @zh 导航网格节点(包装多边形)\n * @en NavMesh node (wraps polygon)\n */\nclass NavMeshNode implements IPathNode {\n readonly id: number;\n readonly position: IPoint;\n readonly cost: number;\n readonly walkable: boolean;\n readonly polygon: INavPolygon;\n\n constructor(polygon: INavPolygon) {\n this.id = polygon.id;\n this.position = polygon.center;\n this.cost = 1;\n this.walkable = true;\n this.polygon = polygon;\n }\n}\n\n// =============================================================================\n// 导航网格 | Navigation Mesh\n// =============================================================================\n\n/**\n * @zh 导航网格\n * @en Navigation Mesh\n *\n * @zh 使用凸多边形网格进行高效寻路,适合复杂地形\n * @en Uses convex polygon mesh for efficient pathfinding, suitable for complex terrain\n *\n * @example\n * ```typescript\n * const navmesh = new NavMesh();\n *\n * // Add polygons\n * navmesh.addPolygon([\n * { x: 0, y: 0 }, { x: 10, y: 0 },\n * { x: 10, y: 10 }, { x: 0, y: 10 }\n * ]);\n *\n * // Build connections\n * navmesh.build();\n *\n * // Find path\n * const result = navmesh.findPath(1, 1, 8, 8);\n * ```\n */\nexport class NavMesh implements IPathfindingMap {\n private polygons: Map<number, INavPolygon> = new Map();\n private nodes: Map<number, NavMeshNode> = new Map();\n private nextId = 0;\n\n // @zh 动态障碍物支持\n // @en Dynamic obstacle support\n private obstacles: Map<number, IDynamicObstacle> = new Map();\n private nextObstacleId = 0;\n private disabledPolygons: Set<number> = new Set();\n\n /**\n * @zh 添加导航多边形\n * @en Add navigation polygon\n *\n * @returns @zh 多边形ID @en Polygon ID\n */\n addPolygon(vertices: IPoint[], neighbors: number[] = []): number {\n const id = this.nextId++;\n const center = this.calculateCenter(vertices);\n\n const polygon: INavPolygon = {\n id,\n vertices,\n center,\n neighbors,\n portals: new Map()\n };\n\n this.polygons.set(id, polygon);\n this.nodes.set(id, new NavMeshNode(polygon));\n\n return id;\n }\n\n /**\n * @zh 设置两个多边形之间的连接\n * @en Set connection between two polygons\n */\n setConnection(\n polyA: number,\n polyB: number,\n portal: IPortal\n ): void {\n const polygonA = this.polygons.get(polyA);\n const polygonB = this.polygons.get(polyB);\n\n if (!polygonA || !polygonB) {\n return;\n }\n\n // Update neighbors and portals\n const neighborsA = [...polygonA.neighbors];\n const portalsA = new Map(polygonA.portals);\n\n if (!neighborsA.includes(polyB)) {\n neighborsA.push(polyB);\n }\n portalsA.set(polyB, portal);\n\n this.polygons.set(polyA, {\n ...polygonA,\n neighbors: neighborsA,\n portals: portalsA\n });\n\n // Reverse portal for the other direction\n const reversePortal: IPortal = {\n left: portal.right,\n right: portal.left\n };\n\n const neighborsB = [...polygonB.neighbors];\n const portalsB = new Map(polygonB.portals);\n\n if (!neighborsB.includes(polyA)) {\n neighborsB.push(polyA);\n }\n portalsB.set(polyA, reversePortal);\n\n this.polygons.set(polyB, {\n ...polygonB,\n neighbors: neighborsB,\n portals: portalsB\n });\n }\n\n /**\n * @zh 自动检测并建立相邻多边形的连接\n * @en Auto-detect and build connections between adjacent polygons\n */\n build(): void {\n const polygonList = Array.from(this.polygons.values());\n\n for (let i = 0; i < polygonList.length; i++) {\n for (let j = i + 1; j < polygonList.length; j++) {\n const polyA = polygonList[i];\n const polyB = polygonList[j];\n\n const sharedEdge = this.findSharedEdge(polyA.vertices, polyB.vertices);\n\n if (sharedEdge) {\n this.setConnection(polyA.id, polyB.id, sharedEdge);\n }\n }\n }\n }\n\n /**\n * @zh 查找两个多边形的共享边\n * @en Find shared edge between two polygons\n */\n private findSharedEdge(\n verticesA: readonly IPoint[],\n verticesB: readonly IPoint[]\n ): IPortal | null {\n const epsilon = 0.0001;\n\n for (let i = 0; i < verticesA.length; i++) {\n const a1 = verticesA[i];\n const a2 = verticesA[(i + 1) % verticesA.length];\n\n for (let j = 0; j < verticesB.length; j++) {\n const b1 = verticesB[j];\n const b2 = verticesB[(j + 1) % verticesB.length];\n\n // Check if edges match (in either direction)\n const match1 =\n Math.abs(a1.x - b2.x) < epsilon &&\n Math.abs(a1.y - b2.y) < epsilon &&\n Math.abs(a2.x - b1.x) < epsilon &&\n Math.abs(a2.y - b1.y) < epsilon;\n\n const match2 =\n Math.abs(a1.x - b1.x) < epsilon &&\n Math.abs(a1.y - b1.y) < epsilon &&\n Math.abs(a2.x - b2.x) < epsilon &&\n Math.abs(a2.y - b2.y) < epsilon;\n\n if (match1 || match2) {\n return {\n left: a1,\n right: a2\n };\n }\n }\n }\n\n return null;\n }\n\n /**\n * @zh 计算多边形中心\n * @en Calculate polygon center\n */\n private calculateCenter(vertices: readonly IPoint[]): IPoint {\n let x = 0;\n let y = 0;\n\n for (const v of vertices) {\n x += v.x;\n y += v.y;\n }\n\n return createPoint(x / vertices.length, y / vertices.length);\n }\n\n /**\n * @zh 查找包含点的多边形\n * @en Find polygon containing point\n */\n findPolygonAt(x: number, y: number): INavPolygon | null {\n for (const polygon of this.polygons.values()) {\n if (this.isPointInPolygon(x, y, polygon.vertices)) {\n return polygon;\n }\n }\n return null;\n }\n\n /**\n * @zh 检查点是否在多边形内\n * @en Check if point is inside polygon\n */\n private isPointInPolygon(x: number, y: number, vertices: readonly IPoint[]): boolean {\n let inside = false;\n const n = vertices.length;\n\n for (let i = 0, j = n - 1; i < n; j = i++) {\n const xi = vertices[i].x;\n const yi = vertices[i].y;\n const xj = vertices[j].x;\n const yj = vertices[j].y;\n\n if (\n yi > y !== yj > y &&\n x < ((xj - xi) * (y - yi)) / (yj - yi) + xi\n ) {\n inside = !inside;\n }\n }\n\n return inside;\n }\n\n // ==========================================================================\n // IPathfindingMap 接口实现 | IPathfindingMap Interface Implementation\n // ==========================================================================\n\n getNodeAt(x: number, y: number): IPathNode | null {\n const polygon = this.findPolygonAt(x, y);\n return polygon ? this.nodes.get(polygon.id) ?? null : null;\n }\n\n getNeighbors(node: IPathNode): IPathNode[] {\n const navNode = node as NavMeshNode;\n const neighbors: IPathNode[] = [];\n\n for (const neighborId of navNode.polygon.neighbors) {\n const neighbor = this.nodes.get(neighborId);\n if (neighbor) {\n neighbors.push(neighbor);\n }\n }\n\n return neighbors;\n }\n\n heuristic(a: IPoint, b: IPoint): number {\n return euclideanDistance(a, b);\n }\n\n getMovementCost(from: IPathNode, to: IPathNode): number {\n return euclideanDistance(from.position, to.position);\n }\n\n isWalkable(x: number, y: number): boolean {\n return this.findPolygonAt(x, y) !== null;\n }\n\n // ==========================================================================\n // 寻路 | Pathfinding\n // ==========================================================================\n\n /**\n * @zh 在导航网格上寻路\n * @en Find path on navigation mesh\n */\n findPath(\n startX: number,\n startY: number,\n endX: number,\n endY: number,\n options?: IPathfindingOptions\n ): IPathResult {\n const opts = { ...DEFAULT_PATHFINDING_OPTIONS, ...options };\n\n const startPolygon = this.findPolygonAt(startX, startY);\n const endPolygon = this.findPolygonAt(endX, endY);\n\n if (!startPolygon || !endPolygon) {\n return EMPTY_PATH_RESULT;\n }\n\n // Same polygon\n if (startPolygon.id === endPolygon.id) {\n return {\n found: true,\n path: [createPoint(startX, startY), createPoint(endX, endY)],\n cost: euclideanDistance(\n createPoint(startX, startY),\n createPoint(endX, endY)\n ),\n nodesSearched: 1\n };\n }\n\n // A* on polygon graph\n const polygonPath = this.findPolygonPath(startPolygon, endPolygon, opts);\n\n if (!polygonPath.found) {\n return EMPTY_PATH_RESULT;\n }\n\n // Convert polygon path to point path using funnel algorithm\n const start = createPoint(startX, startY);\n const end = createPoint(endX, endY);\n const pointPath = this.funnelPath(start, end, polygonPath.polygons, opts.agentRadius);\n\n return {\n found: true,\n path: pointPath,\n cost: this.calculatePathLength(pointPath),\n nodesSearched: polygonPath.nodesSearched\n };\n }\n\n /**\n * @zh 在多边形图上寻路\n * @en Find path on polygon graph\n *\n * @param start - @zh 起始多边形 @en Start polygon\n * @param end - @zh 目标多边形 @en End polygon\n * @param opts - @zh 寻路选项 @en Pathfinding options\n * @param checkObstacles - @zh 是否检查障碍物 @en Whether to check obstacles\n */\n private findPolygonPath(\n start: INavPolygon,\n end: INavPolygon,\n opts: Required<IPathfindingOptions>,\n checkObstacles: boolean = false\n ): { found: boolean; polygons: INavPolygon[]; nodesSearched: number } {\n interface AStarState {\n polygon: INavPolygon;\n g: number;\n f: number;\n parent: AStarState | null;\n }\n\n const openList = new BinaryHeap<AStarState>((a, b) => a.f - b.f);\n const closed = new Set<number>();\n const states = new Map<number, AStarState>();\n\n const startState: AStarState = {\n polygon: start,\n g: 0,\n f: euclideanDistance(start.center, end.center) * opts.heuristicWeight,\n parent: null\n };\n\n states.set(start.id, startState);\n openList.push(startState);\n\n let nodesSearched = 0;\n\n while (!openList.isEmpty && nodesSearched < opts.maxNodes) {\n const current = openList.pop()!;\n nodesSearched++;\n\n if (current.polygon.id === end.id) {\n // Reconstruct path\n const path: INavPolygon[] = [];\n let state: AStarState | null = current;\n\n while (state) {\n path.unshift(state.polygon);\n state = state.parent;\n }\n\n return { found: true, polygons: path, nodesSearched };\n }\n\n closed.add(current.polygon.id);\n\n for (const neighborId of current.polygon.neighbors) {\n if (closed.has(neighborId)) {\n continue;\n }\n\n // @zh 检查障碍物:跳过被阻挡或禁用的多边形\n // @en Check obstacles: skip blocked or disabled polygons\n if (checkObstacles && this.isPolygonBlocked(neighborId)) {\n continue;\n }\n\n const neighborPolygon = this.polygons.get(neighborId);\n if (!neighborPolygon) {\n continue;\n }\n\n const g = current.g + euclideanDistance(\n current.polygon.center,\n neighborPolygon.center\n );\n\n let neighborState = states.get(neighborId);\n\n if (!neighborState) {\n neighborState = {\n polygon: neighborPolygon,\n g,\n f: g + euclideanDistance(neighborPolygon.center, end.center) * opts.heuristicWeight,\n parent: current\n };\n states.set(neighborId, neighborState);\n openList.push(neighborState);\n } else if (g < neighborState.g) {\n neighborState.g = g;\n neighborState.f = g + euclideanDistance(neighborPolygon.center, end.center) * opts.heuristicWeight;\n neighborState.parent = current;\n openList.update(neighborState);\n }\n }\n }\n\n return { found: false, polygons: [], nodesSearched };\n }\n\n /**\n * @zh 使用漏斗算法优化路径(支持代理半径)\n * @en Optimize path using funnel algorithm (supports agent radius)\n *\n * @param start - @zh 起点 @en Start point\n * @param end - @zh 终点 @en End point\n * @param polygons - @zh 多边形路径 @en Polygon path\n * @param agentRadius - @zh 代理半径 @en Agent radius\n */\n private funnelPath(\n start: IPoint,\n end: IPoint,\n polygons: INavPolygon[],\n agentRadius: number = 0\n ): IPoint[] {\n if (polygons.length <= 1) {\n return [start, end];\n }\n\n // Collect and shrink portals\n const portals: { left: IPoint; right: IPoint; originalLeft: IPoint; originalRight: IPoint }[] = [];\n\n for (let i = 0; i < polygons.length - 1; i++) {\n const portal = polygons[i].portals.get(polygons[i + 1].id);\n if (portal) {\n if (agentRadius > 0) {\n const shrunk = this.shrinkPortal(portal.left, portal.right, agentRadius);\n portals.push({\n left: shrunk.left,\n right: shrunk.right,\n originalLeft: portal.left,\n originalRight: portal.right\n });\n } else {\n portals.push({\n left: portal.left,\n right: portal.right,\n originalLeft: portal.left,\n originalRight: portal.right\n });\n }\n }\n }\n\n if (portals.length === 0) {\n return [start, end];\n }\n\n // Simple string pulling algorithm with radius-aware turning points\n const path: IPoint[] = [start];\n\n let apex = start;\n let apexOriginal = start;\n let leftIndex = 0;\n let rightIndex = 0;\n let left = portals[0].left;\n let right = portals[0].right;\n let leftOriginal = portals[0].originalLeft;\n let rightOriginal = portals[0].originalRight;\n\n for (let i = 1; i <= portals.length; i++) {\n const nextLeft = i < portals.length ? portals[i].left : end;\n const nextRight = i < portals.length ? portals[i].right : end;\n\n // Update right\n if (this.triArea2(apex, right, nextRight) <= 0) {\n if (this.pointsEqual(apex, right) || this.triArea2(apex, left, nextRight) > 0) {\n right = nextRight;\n rightIndex = i;\n if (i < portals.length) {\n rightOriginal = portals[i].originalRight;\n }\n } else {\n // Add turning point with radius offset\n const turnPoint = agentRadius > 0\n ? this.offsetTurningPoint(apexOriginal, leftOriginal, left, agentRadius, 'left')\n : left;\n path.push(turnPoint);\n\n apex = left;\n apexOriginal = leftOriginal;\n leftIndex = rightIndex = leftIndex;\n left = right = apex;\n leftOriginal = rightOriginal = apexOriginal;\n i = leftIndex;\n continue;\n }\n }\n\n // Update left\n if (this.triArea2(apex, left, nextLeft) >= 0) {\n if (this.pointsEqual(apex, left) || this.triArea2(apex, right, nextLeft) < 0) {\n left = nextLeft;\n leftIndex = i;\n if (i < portals.length) {\n leftOriginal = portals[i].originalLeft;\n }\n } else {\n // Add turning point with radius offset\n const turnPoint = agentRadius > 0\n ? this.offsetTurningPoint(apexOriginal, rightOriginal, right, agentRadius, 'right')\n : right;\n path.push(turnPoint);\n\n apex = right;\n apexOriginal = rightOriginal;\n leftIndex = rightIndex = rightIndex;\n left = right = apex;\n leftOriginal = rightOriginal = apexOriginal;\n i = rightIndex;\n continue;\n }\n }\n }\n\n path.push(end);\n\n return path;\n }\n\n /**\n * @zh 收缩 portal(将两端点向内移动 agentRadius)\n * @en Shrink portal (move endpoints inward by agentRadius)\n */\n private shrinkPortal(left: IPoint, right: IPoint, radius: number): { left: IPoint; right: IPoint } {\n const dx = right.x - left.x;\n const dy = right.y - left.y;\n const len = Math.sqrt(dx * dx + dy * dy);\n\n if (len <= radius * 2) {\n // Portal too narrow, return center point\n const cx = (left.x + right.x) / 2;\n const cy = (left.y + right.y) / 2;\n return {\n left: createPoint(cx, cy),\n right: createPoint(cx, cy)\n };\n }\n\n // Normalize direction\n const nx = dx / len;\n const ny = dy / len;\n\n // Shrink both endpoints inward\n return {\n left: createPoint(left.x + nx * radius, left.y + ny * radius),\n right: createPoint(right.x - nx * radius, right.y - ny * radius)\n };\n }\n\n /**\n * @zh 偏移拐点以保持与角落的距离\n * @en Offset turning point to maintain distance from corner\n *\n * @param prevApex - @zh 上一个顶点 @en Previous apex\n * @param cornerOriginal - @zh 原始角落位置 @en Original corner position\n * @param cornerShrunk - @zh 收缩后的角落位置 @en Shrunk corner position\n * @param radius - @zh 代理半径 @en Agent radius\n * @param side - @zh 转向侧 ('left' 或 'right') @en Turn side ('left' or 'right')\n */\n private offsetTurningPoint(\n prevApex: IPoint,\n cornerOriginal: IPoint,\n cornerShrunk: IPoint,\n radius: number,\n side: 'left' | 'right'\n ): IPoint {\n // Direction from previous apex to corner\n const dx = cornerOriginal.x - prevApex.x;\n const dy = cornerOriginal.y - prevApex.y;\n const len = Math.sqrt(dx * dx + dy * dy);\n\n if (len < 0.0001) {\n return cornerShrunk;\n }\n\n // Perpendicular direction (pointing into the walkable area)\n // For left turn, perpendicular is to the right of the direction\n // For right turn, perpendicular is to the left of the direction\n let perpX: number, perpY: number;\n if (side === 'left') {\n perpX = dy / len;\n perpY = -dx / len;\n } else {\n perpX = -dy / len;\n perpY = dx / len;\n }\n\n // Offset the shrunk corner by radius in the perpendicular direction\n // This ensures the agent's circular body clears the corner\n return createPoint(\n cornerShrunk.x + perpX * radius,\n cornerShrunk.y + perpY * radius\n );\n }\n\n /**\n * @zh 检查两点是否相等\n * @en Check if two points are equal\n */\n private pointsEqual(a: IPoint, b: IPoint): boolean {\n return Math.abs(a.x - b.x) < 0.0001 && Math.abs(a.y - b.y) < 0.0001;\n }\n\n /**\n * @zh 计算三角形面积的两倍(用于判断点的相对位置)\n * @en Calculate twice the triangle area (for point relative position)\n */\n private triArea2(a: IPoint, b: IPoint, c: IPoint): number {\n return (c.x - a.x) * (b.y - a.y) - (b.x - a.x) * (c.y - a.y);\n }\n\n /**\n * @zh 计算路径总长度\n * @en Calculate total path length\n */\n private calculatePathLength(path: readonly IPoint[]): number {\n let length = 0;\n\n for (let i = 1; i < path.length; i++) {\n length += euclideanDistance(path[i - 1], path[i]);\n }\n\n return length;\n }\n\n // =========================================================================\n // 动态障碍物管理 | Dynamic Obstacle Management\n // =========================================================================\n\n /**\n * @zh 添加圆形障碍物\n * @en Add circular obstacle\n *\n * @param x - @zh 中心 X @en Center X\n * @param y - @zh 中心 Y @en Center Y\n * @param radius - @zh 半径 @en Radius\n * @returns @zh 障碍物 ID @en Obstacle ID\n */\n addCircleObstacle(x: number, y: number, radius: number): number {\n const id = this.nextObstacleId++;\n this.obstacles.set(id, {\n id,\n type: 'circle',\n enabled: true,\n position: createPoint(x, y),\n radius\n });\n return id;\n }\n\n /**\n * @zh 添加矩形障碍物\n * @en Add rectangular obstacle\n *\n * @param x - @zh 中心 X @en Center X\n * @param y - @zh 中心 Y @en Center Y\n * @param halfWidth - @zh 半宽 @en Half width\n * @param halfHeight - @zh 半高 @en Half height\n * @returns @zh 障碍物 ID @en Obstacle ID\n */\n addRectObstacle(x: number, y: number, halfWidth: number, halfHeight: number): number {\n const id = this.nextObstacleId++;\n this.obstacles.set(id, {\n id,\n type: 'rect',\n enabled: true,\n position: createPoint(x, y),\n halfWidth,\n halfHeight\n });\n return id;\n }\n\n /**\n * @zh 添加多边形障碍物\n * @en Add polygon obstacle\n *\n * @param vertices - @zh 顶点列表 @en Vertex list\n * @returns @zh 障碍物 ID @en Obstacle ID\n */\n addPolygonObstacle(vertices: IPoint[]): number {\n const id = this.nextObstacleId++;\n const center = this.calculateCenter(vertices);\n this.obstacles.set(id, {\n id,\n type: 'polygon',\n enabled: true,\n position: center,\n vertices\n });\n return id;\n }\n\n /**\n * @zh 移除障碍物\n * @en Remove obstacle\n */\n removeObstacle(obstacleId: number): boolean {\n return this.obstacles.delete(obstacleId);\n }\n\n /**\n * @zh 启用/禁用障碍物\n * @en Enable/disable obstacle\n */\n setObstacleEnabled(obstacleId: number, enabled: boolean): void {\n const obstacle = this.obstacles.get(obstacleId);\n if (obstacle) {\n obstacle.enabled = enabled;\n }\n }\n\n /**\n * @zh 更新障碍物位置\n * @en Update obstacle position\n */\n updateObstaclePosition(obstacleId: number, x: number, y: number): void {\n const obstacle = this.obstacles.get(obstacleId);\n if (obstacle) {\n obstacle.position = createPoint(x, y);\n }\n }\n\n /**\n * @zh 获取所有障碍物\n * @en Get all obstacles\n */\n getObstacles(): IDynamicObstacle[] {\n return Array.from(this.obstacles.values());\n }\n\n /**\n * @zh 获取启用的障碍物\n * @en Get enabled obstacles\n */\n getEnabledObstacles(): IDynamicObstacle[] {\n return Array.from(this.obstacles.values()).filter(o => o.enabled);\n }\n\n /**\n * @zh 清除所有障碍物\n * @en Clear all obstacles\n */\n clearObstacles(): void {\n this.obstacles.clear();\n this.nextObstacleId = 0;\n }\n\n // =========================================================================\n // 多边形禁用管理 | Polygon Disable Management\n // =========================================================================\n\n /**\n * @zh 禁用多边形\n * @en Disable polygon\n */\n disablePolygon(polygonId: number): void {\n this.disabledPolygons.add(polygonId);\n }\n\n /**\n * @zh 启用多边形\n * @en Enable polygon\n */\n enablePolygon(polygonId: number): void {\n this.disabledPolygons.delete(polygonId);\n }\n\n /**\n * @zh 检查多边形是否被禁用\n * @en Check if polygon is disabled\n */\n isPolygonDisabled(polygonId: number): boolean {\n return this.disabledPolygons.has(polygonId);\n }\n\n /**\n * @zh 禁用包含指定点的多边形\n * @en Disable polygon containing specified point\n */\n disablePolygonAt(x: number, y: number): number | null {\n const polygon = this.findPolygonAt(x, y);\n if (polygon) {\n this.disablePolygon(polygon.id);\n return polygon.id;\n }\n return null;\n }\n\n /**\n * @zh 清除所有禁用的多边形\n * @en Clear all disabled polygons\n */\n clearDisabledPolygons(): void {\n this.disabledPolygons.clear();\n }\n\n /**\n * @zh 获取被禁用的多边形 ID 列表\n * @en Get list of disabled polygon IDs\n */\n getDisabledPolygons(): number[] {\n return Array.from(this.disabledPolygons);\n }\n\n // =========================================================================\n // 障碍物碰撞检测 | Obstacle Collision Detection\n // =========================================================================\n\n /**\n * @zh 检查点是否在任何障碍物内\n * @en Check if point is inside any obstacle\n */\n isPointInObstacle(x: number, y: number): boolean {\n for (const obstacle of this.obstacles.values()) {\n if (!obstacle.enabled) continue;\n\n if (this.isPointInSingleObstacle(x, y, obstacle)) {\n return true;\n }\n }\n return false;\n }\n\n /**\n * @zh 检查点是否在单个障碍物内\n * @en Check if point is inside single obstacle\n */\n private isPointInSingleObstacle(x: number, y: number, obstacle: IDynamicObstacle): boolean {\n switch (obstacle.type) {\n case 'circle': {\n const dx = x - obstacle.position.x;\n const dy = y - obstacle.position.y;\n return dx * dx + dy * dy <= (obstacle.radius ?? 0) ** 2;\n }\n case 'rect': {\n const hw = obstacle.halfWidth ?? 0;\n const hh = obstacle.halfHeight ?? 0;\n return Math.abs(x - obstacle.position.x) <= hw &&\n Math.abs(y - obstacle.position.y) <= hh;\n }\n case 'polygon': {\n if (!obstacle.vertices) return false;\n return this.isPointInPolygon(x, y, obstacle.vertices);\n }\n default:\n return false;\n }\n }\n\n /**\n * @zh 检查线段是否与任何障碍物相交\n * @en Check if line segment intersects any obstacle\n */\n doesLineIntersectObstacle(x1: number, y1: number, x2: number, y2: number): boolean {\n for (const obstacle of this.obstacles.values()) {\n if (!obstacle.enabled) continue;\n\n if (this.doesLineIntersectSingleObstacle(x1, y1, x2, y2, obstacle)) {\n return true;\n }\n }\n return false;\n }\n\n /**\n * @zh 检查线段是否与单个障碍物相交\n * @en Check if line segment intersects single obstacle\n */\n private doesLineIntersectSingleObstacle(\n x1: number, y1: number, x2: number, y2: number,\n obstacle: IDynamicObstacle\n ): boolean {\n switch (obstacle.type) {\n case 'circle': {\n return this.lineIntersectsCircle(\n x1, y1, x2, y2,\n obstacle.position.x, obstacle.position.y,\n obstacle.radius ?? 0\n );\n }\n case 'rect': {\n const hw = obstacle.halfWidth ?? 0;\n const hh = obstacle.halfHeight ?? 0;\n const minX = obstacle.position.x - hw;\n const maxX = obstacle.position.x + hw;\n const minY = obstacle.position.y - hh;\n const maxY = obstacle.position.y + hh;\n return this.lineIntersectsRect(x1, y1, x2, y2, minX, minY, maxX, maxY);\n }\n case 'polygon': {\n if (!obstacle.vertices) return false;\n return this.lineIntersectsPolygon(x1, y1, x2, y2, obstacle.vertices);\n }\n default:\n return false;\n }\n }\n\n /**\n * @zh 线段与圆相交检测\n * @en Line segment circle intersection\n */\n private lineIntersectsCircle(\n x1: number, y1: number, x2: number, y2: number,\n cx: number, cy: number, r: number\n ): boolean {\n const dx = x2 - x1;\n const dy = y2 - y1;\n const fx = x1 - cx;\n const fy = y1 - cy;\n\n const a = dx * dx + dy * dy;\n const b = 2 * (fx * dx + fy * dy);\n const c = fx * fx + fy * fy - r * r;\n\n let discriminant = b * b - 4 * a * c;\n if (discriminant < 0) return false;\n\n discriminant = Math.sqrt(discriminant);\n const t1 = (-b - discriminant) / (2 * a);\n const t2 = (-b + discriminant) / (2 * a);\n\n return (t1 >= 0 && t1 <= 1) || (t2 >= 0 && t2 <= 1) || (t1 < 0 && t2 > 1);\n }\n\n /**\n * @zh 线段与矩形相交检测\n * @en Line segment rectangle intersection\n */\n private lineIntersectsRect(\n x1: number, y1: number, x2: number, y2: number,\n minX: number, minY: number, maxX: number, maxY: number\n ): boolean {\n // Check if either endpoint is inside\n if ((x1 >= minX && x1 <= maxX && y1 >= minY && y1 <= maxY) ||\n (x2 >= minX && x2 <= maxX && y2 >= minY && y2 <= maxY)) {\n return true;\n }\n\n // Check intersection with each edge\n return this.lineSegmentsIntersect(x1, y1, x2, y2, minX, minY, maxX, minY) ||\n this.lineSegmentsIntersect(x1, y1, x2, y2, maxX, minY, maxX, maxY) ||\n this.lineSegmentsIntersect(x1, y1, x2, y2, maxX, maxY, minX, maxY) ||\n this.lineSegmentsIntersect(x1, y1, x2, y2, minX, maxY, minX, minY);\n }\n\n /**\n * @zh 线段与多边形相交检测\n * @en Line segment polygon intersection\n */\n private lineIntersectsPolygon(\n x1: number, y1: number, x2: number, y2: number,\n vertices: readonly IPoint[]\n ): boolean {\n // Check if either endpoint is inside\n if (this.isPointInPolygon(x1, y1, vertices) ||\n this.isPointInPolygon(x2, y2, vertices)) {\n return true;\n }\n\n // Check intersection with each edge\n for (let i = 0; i < vertices.length; i++) {\n const j = (i + 1) % vertices.length;\n if (this.lineSegmentsIntersect(\n x1, y1, x2, y2,\n vertices[i].x, vertices[i].y,\n vertices[j].x, vertices[j].y\n )) {\n return true;\n }\n }\n return false;\n }\n\n /**\n * @zh 两线段相交检测\n * @en Two line segments intersection\n */\n private lineSegmentsIntersect(\n x1: number, y1: number, x2: number, y2: number,\n x3: number, y3: number, x4: number, y4: number\n ): boolean {\n const d1 = this.direction(x3, y3, x4, y4, x1, y1);\n const d2 = this.direction(x3, y3, x4, y4, x2, y2);\n const d3 = this.direction(x1, y1, x2, y2, x3, y3);\n const d4 = this.direction(x1, y1, x2, y2, x4, y4);\n\n if (((d1 > 0 && d2 < 0) || (d1 < 0 && d2 > 0)) &&\n ((d3 > 0 && d4 < 0) || (d3 < 0 && d4 > 0))) {\n return true;\n }\n\n const epsilon = 0.0001;\n if (Math.abs(d1) < epsilon && this.onSegment(x3, y3, x4, y4, x1, y1)) return true;\n if (Math.abs(d2) < epsilon && this.onSegment(x3, y3, x4, y4, x2, y2)) return true;\n if (Math.abs(d3) < epsilon && this.onSegment(x1, y1, x2, y2, x3, y3)) return true;\n if (Math.abs(d4) < epsilon && this.onSegment(x1, y1, x2, y2, x4, y4)) return true;\n\n return false;\n }\n\n private direction(x1: number, y1: number, x2: number, y2: number, x3: number, y3: number): number {\n return (x3 - x1) * (y2 - y1) - (y3 - y1) * (x2 - x1);\n }\n\n private onSegment(x1: number, y1: number, x2: number, y2: number, x3: number, y3: number): boolean {\n return Math.min(x1, x2) <= x3 && x3 <= Math.max(x1, x2) &&\n Math.min(y1, y2) <= y3 && y3 <= Math.max(y1, y2);\n }\n\n // =========================================================================\n // 障碍物感知寻路 | Obstacle-Aware Pathfinding\n // =========================================================================\n\n /**\n * @zh 检查多边形是否被障碍物阻挡\n * @en Check if polygon is blocked by obstacle\n *\n * @zh 检查以下条件:\n * @en Checks the following conditions:\n * - @zh 多边形是否被禁用 @en Whether polygon is disabled\n * - @zh 多边形中心是否在障碍物内 @en Whether polygon center is inside obstacle\n * - @zh 多边形任意顶点是否在障碍物内 @en Whether any polygon vertex is inside obstacle\n * - @zh 多边形任意边是否与障碍物相交 @en Whether any polygon edge intersects obstacle\n */\n isPolygonBlocked(polygonId: number): boolean {\n if (this.disabledPolygons.has(polygonId)) {\n return true;\n }\n\n const polygon = this.polygons.get(polygonId);\n if (!polygon) return false;\n\n // @zh 检查中心点\n // @en Check center point\n if (this.isPointInObstacle(polygon.center.x, polygon.center.y)) {\n return true;\n }\n\n // @zh 检查所有顶点\n // @en Check all vertices\n for (const vertex of polygon.vertices) {\n if (this.isPointInObstacle(vertex.x, vertex.y)) {\n return true;\n }\n }\n\n // @zh 检查所有边是否与障碍物相交\n // @en Check if any edge intersects with obstacles\n const vertices = polygon.vertices;\n for (let i = 0; i < vertices.length; i++) {\n const v1 = vertices[i];\n const v2 = vertices[(i + 1) % vertices.length];\n if (this.doesLineIntersectObstacle(v1.x, v1.y, v2.x, v2.y)) {\n return true;\n }\n }\n\n return false;\n }\n\n /**\n * @zh 在导航网格上寻路(考虑障碍物)\n * @en Find path on navigation mesh (considering obstacles)\n *\n * @zh 此方法在规划阶段就考虑障碍物,自动绕过被阻挡的多边形\n * @en This method considers obstacles during planning, automatically avoiding blocked polygons\n *\n * @zh 与 findPath 不同,此方法会:\n * @en Unlike findPath, this method will:\n * - @zh 在 A* 搜索中跳过被障碍物阻挡的多边形\n * - @en Skip obstacle-blocked polygons during A* search\n * - @zh 验证起点和终点不在障碍物内\n * - @en Verify start and end points are not inside obstacles\n */\n findPathWithObstacles(\n startX: number,\n startY: number,\n endX: number,\n endY: number,\n options?: IPathfindingOptions\n ): IPathResult {\n const opts = { ...DEFAULT_PATHFINDING_OPTIONS, ...options };\n\n // @zh 检查起点和终点是否在障碍物内\n // @en Check if start and end are inside obstacles\n if (this.isPointInObstacle(startX, startY) || this.isPointInObstacle(endX, endY)) {\n return EMPTY_PATH_RESULT;\n }\n\n const startPolygon = this.findPolygonAt(startX, startY);\n const endPolygon = this.findPolygonAt(endX, endY);\n\n if (!startPolygon || !endPolygon) {\n return EMPTY_PATH_RESULT;\n }\n\n // @zh 检查起点/终点多边形是否被阻挡\n // @en Check if start/end polygons are blocked\n if (this.isPolygonBlocked(startPolygon.id) || this.isPolygonBlocked(endPolygon.id)) {\n return EMPTY_PATH_RESULT;\n }\n\n // @zh 同一多边形内的路径\n // @en Path within same polygon\n if (startPolygon.id === endPolygon.id) {\n const start = createPoint(startX, startY);\n const end = createPoint(endX, endY);\n\n // @zh 检查直线路径是否穿过障碍物\n // @en Check if direct path crosses obstacles\n if (this.doesLineIntersectObstacle(startX, startY, endX, endY)) {\n return EMPTY_PATH_RESULT;\n }\n\n return {\n found: true,\n path: [start, end],\n cost: euclideanDistance(start, end),\n nodesSearched: 1\n };\n }\n\n // @zh 使用障碍物感知的多边形路径搜索\n // @en Use obstacle-aware polygon path search\n const polygonPath = this.findPolygonPath(startPolygon, endPolygon, opts, true);\n\n if (!polygonPath.found) {\n return EMPTY_PATH_RESULT;\n }\n\n // @zh 使用 Funnel 算法生成路径点\n // @en Generate path points using Funnel algorithm\n const start = createPoint(startX, startY);\n const end = createPoint(endX, endY);\n const pointPath = this.funnelPath(start, end, polygonPath.polygons, opts.agentRadius);\n\n return {\n found: true,\n path: pointPath,\n cost: this.calculatePathLength(pointPath),\n nodesSearched: polygonPath.nodesSearched\n };\n }\n\n /**\n * @zh 清空导航网格\n * @en Clear navigation mesh\n */\n clear(): void {\n this.polygons.clear();\n this.nodes.clear();\n this.obstacles.clear();\n this.disabledPolygons.clear();\n this.nextId = 0;\n this.nextObstacleId = 0;\n }\n\n /**\n * @zh 获取所有多边形\n * @en Get all polygons\n */\n getPolygons(): INavPolygon[] {\n return Array.from(this.polygons.values());\n }\n\n /**\n * @zh 获取多边形数量\n * @en Get polygon count\n */\n get polygonCount(): number {\n return this.polygons.size;\n }\n\n /**\n * @zh 获取障碍物数量\n * @en Get obstacle count\n */\n get obstacleCount(): number {\n return this.obstacles.size;\n }\n}\n\n// =============================================================================\n// 工厂函数 | Factory Function\n// =============================================================================\n\n/**\n * @zh 创建导航网格\n * @en Create navigation mesh\n */\nexport function createNavMesh(): NavMesh {\n return new NavMesh();\n}\n","/**\n * @zh 路径平滑算法\n * @en Path Smoothing Algorithms\n */\n\nimport type {\n IPathfindingMap,\n IPathSmoother,\n IPoint\n} from '../core/IPathfinding';\nimport { createPoint } from '../core/IPathfinding';\n\n// =============================================================================\n// 视线检测 | Line of Sight\n// =============================================================================\n\n/**\n * @zh 使用 Bresenham 算法检测视线\n * @en Line of sight check using Bresenham algorithm\n */\nexport function bresenhamLineOfSight(\n x1: number,\n y1: number,\n x2: number,\n y2: number,\n map: IPathfindingMap\n): boolean {\n // Round to grid coordinates\n let ix1 = Math.floor(x1);\n let iy1 = Math.floor(y1);\n const ix2 = Math.floor(x2);\n const iy2 = Math.floor(y2);\n\n const dx = Math.abs(ix2 - ix1);\n const dy = Math.abs(iy2 - iy1);\n\n const sx = ix1 < ix2 ? 1 : -1;\n const sy = iy1 < iy2 ? 1 : -1;\n\n let err = dx - dy;\n\n while (true) {\n if (!map.isWalkable(ix1, iy1)) {\n return false;\n }\n\n if (ix1 === ix2 && iy1 === iy2) {\n break;\n }\n\n const e2 = 2 * err;\n\n if (e2 > -dy) {\n err -= dy;\n ix1 += sx;\n }\n\n if (e2 < dx) {\n err += dx;\n iy1 += sy;\n }\n }\n\n return true;\n}\n\n/**\n * @zh 使用射线投射检测视线(更精确)\n * @en Line of sight check using ray casting (more precise)\n */\nexport function raycastLineOfSight(\n x1: number,\n y1: number,\n x2: number,\n y2: number,\n map: IPathfindingMap,\n stepSize: number = 0.5\n): boolean {\n const dx = x2 - x1;\n const dy = y2 - y1;\n const distance = Math.sqrt(dx * dx + dy * dy);\n\n if (distance === 0) {\n return map.isWalkable(Math.floor(x1), Math.floor(y1));\n }\n\n const steps = Math.ceil(distance / stepSize);\n const stepX = dx / steps;\n const stepY = dy / steps;\n\n let x = x1;\n let y = y1;\n\n for (let i = 0; i <= steps; i++) {\n if (!map.isWalkable(Math.floor(x), Math.floor(y))) {\n return false;\n }\n x += stepX;\n y += stepY;\n }\n\n return true;\n}\n\n// =============================================================================\n// 路径简化器(拐点移除)| Path Simplifier (Waypoint Removal)\n// =============================================================================\n\n/**\n * @zh 路径简化器 - 移除不必要的拐点\n * @en Path Simplifier - Removes unnecessary waypoints\n *\n * @zh 使用视线检测移除可以直接到达的中间点\n * @en Uses line of sight to remove intermediate points that can be reached directly\n */\nexport class LineOfSightSmoother implements IPathSmoother {\n private readonly lineOfSight: typeof bresenhamLineOfSight;\n\n constructor(lineOfSight: typeof bresenhamLineOfSight = bresenhamLineOfSight) {\n this.lineOfSight = lineOfSight;\n }\n\n smooth(path: readonly IPoint[], map: IPathfindingMap): IPoint[] {\n if (path.length <= 2) {\n return [...path];\n }\n\n const result: IPoint[] = [path[0]];\n let current = 0;\n\n while (current < path.length - 1) {\n // Find the furthest point we can see from current\n let furthest = current + 1;\n\n for (let i = path.length - 1; i > current + 1; i--) {\n if (this.lineOfSight(\n path[current].x,\n path[current].y,\n path[i].x,\n path[i].y,\n map\n )) {\n furthest = i;\n break;\n }\n }\n\n result.push(path[furthest]);\n current = furthest;\n }\n\n return result;\n }\n}\n\n// =============================================================================\n// 曲线平滑器 | Curve Smoother\n// =============================================================================\n\n/**\n * @zh Catmull-Rom 样条曲线平滑\n * @en Catmull-Rom spline smoothing\n */\nexport class CatmullRomSmoother implements IPathSmoother {\n private readonly segments: number;\n private readonly tension: number;\n\n /**\n * @param segments - @zh 每段之间的插值点数 @en Number of interpolation points per segment\n * @param tension - @zh 张力 (0-1) @en Tension (0-1)\n */\n constructor(segments: number = 5, tension: number = 0.5) {\n this.segments = segments;\n this.tension = tension;\n }\n\n smooth(path: readonly IPoint[], _map: IPathfindingMap): IPoint[] {\n if (path.length <= 2) {\n return [...path];\n }\n\n const result: IPoint[] = [];\n\n // Add phantom points at the ends\n const points = [\n path[0],\n ...path,\n path[path.length - 1]\n ];\n\n for (let i = 1; i < points.length - 2; i++) {\n const p0 = points[i - 1];\n const p1 = points[i];\n const p2 = points[i + 1];\n const p3 = points[i + 2];\n\n for (let j = 0; j < this.segments; j++) {\n const t = j / this.segments;\n const point = this.interpolate(p0, p1, p2, p3, t);\n result.push(point);\n }\n }\n\n // Add final point\n result.push(path[path.length - 1]);\n\n return result;\n }\n\n /**\n * @zh Catmull-Rom 插值\n * @en Catmull-Rom interpolation\n */\n private interpolate(\n p0: IPoint,\n p1: IPoint,\n p2: IPoint,\n p3: IPoint,\n t: number\n ): IPoint {\n const t2 = t * t;\n const t3 = t2 * t;\n\n const tension = this.tension;\n\n const x =\n 0.5 *\n ((2 * p1.x) +\n (-p0.x + p2.x) * t * tension +\n (2 * p0.x - 5 * p1.x + 4 * p2.x - p3.x) * t2 * tension +\n (-p0.x + 3 * p1.x - 3 * p2.x + p3.x) * t3 * tension);\n\n const y =\n 0.5 *\n ((2 * p1.y) +\n (-p0.y + p2.y) * t * tension +\n (2 * p0.y - 5 * p1.y + 4 * p2.y - p3.y) * t2 * tension +\n (-p0.y + 3 * p1.y - 3 * p2.y + p3.y) * t3 * tension);\n\n return createPoint(x, y);\n }\n}\n\n// =============================================================================\n// 组合平滑器 | Combined Smoother\n// =============================================================================\n\n/**\n * @zh 组合路径平滑器\n * @en Combined path smoother\n *\n * @zh 先简化路径,再用曲线平滑\n * @en First simplify path, then smooth with curves\n */\nexport class CombinedSmoother implements IPathSmoother {\n private readonly simplifier: LineOfSightSmoother;\n private readonly curveSmoother: CatmullRomSmoother;\n\n constructor(curveSegments: number = 5, tension: number = 0.5) {\n this.simplifier = new LineOfSightSmoother();\n this.curveSmoother = new CatmullRomSmoother(curveSegments, tension);\n }\n\n smooth(path: readonly IPoint[], map: IPathfindingMap): IPoint[] {\n // First simplify\n const simplified = this.simplifier.smooth(path, map);\n\n // Then curve smooth\n return this.curveSmoother.smooth(simplified, map);\n }\n}\n\n// =============================================================================\n// 工厂函数 | Factory Functions\n// =============================================================================\n\n/**\n * @zh 创建视线平滑器\n * @en Create line of sight smoother\n */\nexport function createLineOfSightSmoother(\n lineOfSight?: typeof bresenhamLineOfSight\n): LineOfSightSmoother {\n return new LineOfSightSmoother(lineOfSight);\n}\n\n/**\n * @zh 创建曲线平滑器\n * @en Create curve smoother\n */\nexport function createCatmullRomSmoother(\n segments?: number,\n tension?: number\n): CatmullRomSmoother {\n return new CatmullRomSmoother(segments, tension);\n}\n\n/**\n * @zh 创建组合平滑器\n * @en Create combined smoother\n */\nexport function createCombinedSmoother(\n curveSegments?: number,\n tension?: number\n): CombinedSmoother {\n return new CombinedSmoother(curveSegments, tension);\n}\n","/**\n * @zh 半径感知路径平滑器\n * @en Radius-Aware Path Smoother\n *\n * @zh 通用的路径后处理器,确保路径与障碍物保持安全距离\n * @en Generic path post-processor that ensures paths maintain safe distance from obstacles\n */\n\nimport type { IPathfindingMap, IPathSmoother, IPoint } from '../core/IPathfinding';\nimport { createPoint } from '../core/IPathfinding';\n\n// =============================================================================\n// 配置 | Configuration\n// =============================================================================\n\n/**\n * @zh 半径感知平滑器配置\n * @en Radius-aware smoother configuration\n */\nexport interface IRadiusAwareSmootherConfig {\n /**\n * @zh 代理半径\n * @en Agent radius\n */\n agentRadius: number;\n\n /**\n * @zh 额外安全边距\n * @en Extra safety margin\n * @default 0.1\n */\n safetyMargin?: number;\n\n /**\n * @zh 采样方向数量(用于检测周围障碍物)\n * @en Number of sample directions (for detecting nearby obstacles)\n * @default 8\n */\n sampleDirections?: number;\n\n /**\n * @zh 最大偏移尝试次数\n * @en Maximum offset attempts\n * @default 8\n */\n maxOffsetAttempts?: number;\n\n /**\n * @zh 是否处理拐点(角落)\n * @en Whether to process turning points (corners)\n * @default true\n */\n processCorners?: boolean;\n}\n\n/**\n * @zh 默认配置\n * @en Default configuration\n */\nconst DEFAULT_CONFIG: Required<Omit<IRadiusAwareSmootherConfig, 'agentRadius'>> = {\n safetyMargin: 0.1,\n sampleDirections: 8,\n maxOffsetAttempts: 8,\n processCorners: true\n};\n\n// =============================================================================\n// 半径感知路径平滑器 | Radius-Aware Path Smoother\n// =============================================================================\n\n/**\n * @zh 半径感知路径平滑器\n * @en Radius-Aware Path Smoother\n *\n * @zh 对任意寻路算法输出的路径进行后处理,确保路径点与障碍物保持足够距离\n * @en Post-processes paths from any pathfinding algorithm to ensure path points maintain sufficient distance from obstacles\n *\n * @example\n * ```typescript\n * // 创建平滑器\n * const smoother = new RadiusAwarePathSmoother({ agentRadius: 0.5 });\n *\n * // 处理路径\n * const safePath = smoother.smooth(rawPath, map);\n *\n * // 与其他平滑器组合使用\n * const combined = new CombinedRadiusAwareSmoother(\n * new LineOfSightSmoother(),\n * { agentRadius: 0.5 }\n * );\n * ```\n */\nexport class RadiusAwarePathSmoother implements IPathSmoother {\n private readonly config: Required<IRadiusAwareSmootherConfig>;\n private readonly sampleAngles: number[];\n\n constructor(config: IRadiusAwareSmootherConfig) {\n this.config = {\n ...DEFAULT_CONFIG,\n ...config\n };\n\n // 预计算采样角度\n this.sampleAngles = [];\n const step = (Math.PI * 2) / this.config.sampleDirections;\n for (let i = 0; i < this.config.sampleDirections; i++) {\n this.sampleAngles.push(i * step);\n }\n }\n\n /**\n * @zh 平滑路径,确保与障碍物保持安全距离\n * @en Smooth path, ensuring safe distance from obstacles\n *\n * @param path - @zh 原始路径 @en Original path\n * @param map - @zh 地图 @en Map\n * @returns @zh 处理后的安全路径 @en Processed safe path\n */\n smooth(path: readonly IPoint[], map: IPathfindingMap): IPoint[] {\n if (path.length <= 1) {\n return [...path];\n }\n\n const result: IPoint[] = [];\n const clearance = this.config.agentRadius + this.config.safetyMargin;\n\n for (let i = 0; i < path.length; i++) {\n const point = path[i]!;\n const isCorner = this.config.processCorners && i > 0 && i < path.length - 1;\n\n let safePoint: IPoint;\n\n if (isCorner) {\n // 处理拐点\n const prev = path[i - 1]!;\n const next = path[i + 1]!;\n safePoint = this.offsetCornerPoint(point, prev, next, clearance, map);\n } else {\n // 处理普通点\n safePoint = this.offsetPointFromObstacles(point, clearance, map);\n }\n\n result.push(safePoint);\n }\n\n return result;\n }\n\n /**\n * @zh 将点从障碍物偏移\n * @en Offset point away from obstacles\n */\n private offsetPointFromObstacles(\n point: IPoint,\n clearance: number,\n map: IPathfindingMap\n ): IPoint {\n // 检测周围障碍物\n const obstacleDirections = this.detectNearbyObstacles(point, clearance, map);\n\n if (obstacleDirections.length === 0) {\n // 没有障碍物在范围内\n return point;\n }\n\n // 计算平均障碍物方向\n let avgDirX = 0;\n let avgDirY = 0;\n for (const dir of obstacleDirections) {\n avgDirX += dir.x;\n avgDirY += dir.y;\n }\n\n const len = Math.sqrt(avgDirX * avgDirX + avgDirY * avgDirY);\n if (len < 0.0001) {\n // 障碍物方向相互抵消,保持原位\n return point;\n }\n\n // 反方向偏移(远离障碍物)\n const offsetDirX = -avgDirX / len;\n const offsetDirY = -avgDirY / len;\n\n // 尝试不同的偏移距离\n for (let attempt = 1; attempt <= this.config.maxOffsetAttempts; attempt++) {\n const offsetDist = clearance * attempt / this.config.maxOffsetAttempts;\n const newX = point.x + offsetDirX * offsetDist;\n const newY = point.y + offsetDirY * offsetDist;\n\n if (map.isWalkable(Math.floor(newX), Math.floor(newY))) {\n // 检查新位置是否有足够的clearance\n const newObstacles = this.detectNearbyObstacles(\n createPoint(newX, newY),\n clearance,\n map\n );\n\n if (newObstacles.length === 0) {\n return createPoint(newX, newY);\n }\n }\n }\n\n // 无法找到更好的位置,返回原点\n return point;\n }\n\n /**\n * @zh 偏移拐点(角落)\n * @en Offset corner point\n */\n private offsetCornerPoint(\n corner: IPoint,\n prev: IPoint,\n next: IPoint,\n clearance: number,\n map: IPathfindingMap\n ): IPoint {\n // 计算进入方向和离开方向\n const inDirX = corner.x - prev.x;\n const inDirY = corner.y - prev.y;\n const inLen = Math.sqrt(inDirX * inDirX + inDirY * inDirY);\n\n const outDirX = next.x - corner.x;\n const outDirY = next.y - corner.y;\n const outLen = Math.sqrt(outDirX * outDirX + outDirY * outDirY);\n\n if (inLen < 0.0001 || outLen < 0.0001) {\n return this.offsetPointFromObstacles(corner, clearance, map);\n }\n\n // 标准化方向\n const inNormX = inDirX / inLen;\n const inNormY = inDirY / inLen;\n const outNormX = outDirX / outLen;\n const outNormY = outDirY / outLen;\n\n // 计算角平分线方向(指向角的内侧)\n // 角平分线 = 入射方向 + 出射方向的反方向\n const bisectX = inNormX - outNormX;\n const bisectY = inNormY - outNormY;\n const bisectLen = Math.sqrt(bisectX * bisectX + bisectY * bisectY);\n\n if (bisectLen < 0.0001) {\n // 直线,不需要特殊处理\n return this.offsetPointFromObstacles(corner, clearance, map);\n }\n\n // 标准化角平分线\n const bisectNormX = bisectX / bisectLen;\n const bisectNormY = bisectY / bisectLen;\n\n // 计算转角角度\n const dotProduct = inNormX * outNormX + inNormY * outNormY;\n const angle = Math.acos(Math.max(-1, Math.min(1, dotProduct)));\n\n // 计算需要的偏移距离\n // 在角落处,需要偏移 clearance / sin(angle/2) 才能保持与两边的距离\n const halfAngle = angle / 2;\n const sinHalfAngle = Math.sin(halfAngle);\n\n if (sinHalfAngle < 0.1) {\n // 角度太小(几乎是直线),使用普通偏移\n return this.offsetPointFromObstacles(corner, clearance, map);\n }\n\n const offsetDist = clearance / sinHalfAngle;\n\n // 限制最大偏移距离\n const maxOffset = clearance * 3;\n const actualOffset = Math.min(offsetDist, maxOffset);\n\n // 沿角平分线偏移\n const newX = corner.x + bisectNormX * actualOffset;\n const newY = corner.y + bisectNormY * actualOffset;\n\n // 验证新位置是否可行\n if (map.isWalkable(Math.floor(newX), Math.floor(newY))) {\n return createPoint(newX, newY);\n }\n\n // 如果角平分线方向不可行,尝试反方向\n const altX = corner.x - bisectNormX * actualOffset;\n const altY = corner.y - bisectNormY * actualOffset;\n\n if (map.isWalkable(Math.floor(altX), Math.floor(altY))) {\n return createPoint(altX, altY);\n }\n\n // 回退到普通偏移\n return this.offsetPointFromObstacles(corner, clearance, map);\n }\n\n /**\n * @zh 检测附近的障碍物方向\n * @en Detect nearby obstacle directions\n */\n private detectNearbyObstacles(\n point: IPoint,\n clearance: number,\n map: IPathfindingMap\n ): IPoint[] {\n const obstacles: IPoint[] = [];\n\n for (const angle of this.sampleAngles) {\n const dirX = Math.cos(angle);\n const dirY = Math.sin(angle);\n\n // 沿该方向采样\n const sampleX = point.x + dirX * clearance;\n const sampleY = point.y + dirY * clearance;\n\n if (!map.isWalkable(Math.floor(sampleX), Math.floor(sampleY))) {\n // 该方向有障碍物\n obstacles.push(createPoint(dirX, dirY));\n }\n }\n\n return obstacles;\n }\n}\n\n// =============================================================================\n// 组合平滑器 | Combined Smoother\n// =============================================================================\n\n/**\n * @zh 组合半径感知平滑器\n * @en Combined radius-aware smoother\n *\n * @zh 先使用其他平滑器(如 LOS、Catmull-Rom),再应用半径感知处理\n * @en First applies other smoother (like LOS, Catmull-Rom), then applies radius-aware processing\n *\n * @example\n * ```typescript\n * const smoother = new CombinedRadiusAwareSmoother(\n * new LineOfSightSmoother(),\n * { agentRadius: 0.5 }\n * );\n * const path = smoother.smooth(rawPath, map);\n * ```\n */\nexport class CombinedRadiusAwareSmoother implements IPathSmoother {\n private readonly baseSmoother: IPathSmoother;\n private readonly radiusAwareSmoother: RadiusAwarePathSmoother;\n\n constructor(\n baseSmoother: IPathSmoother,\n config: IRadiusAwareSmootherConfig\n ) {\n this.baseSmoother = baseSmoother;\n this.radiusAwareSmoother = new RadiusAwarePathSmoother(config);\n }\n\n smooth(path: readonly IPoint[], map: IPathfindingMap): IPoint[] {\n // 先用基础平滑器处理\n const smoothed = this.baseSmoother.smooth(path, map);\n\n // 再应用半径感知处理\n return this.radiusAwareSmoother.smooth(smoothed, map);\n }\n}\n\n// =============================================================================\n// 工厂函数 | Factory Functions\n// =============================================================================\n\n/**\n * @zh 创建半径感知平滑器\n * @en Create radius-aware smoother\n *\n * @param agentRadius - @zh 代理半径 @en Agent radius\n * @param options - @zh 额外配置 @en Additional options\n *\n * @example\n * ```typescript\n * const smoother = createRadiusAwareSmoother(0.5);\n * const safePath = smoother.smooth(path, map);\n * ```\n */\nexport function createRadiusAwareSmoother(\n agentRadius: number,\n options?: Omit<IRadiusAwareSmootherConfig, 'agentRadius'>\n): RadiusAwarePathSmoother {\n return new RadiusAwarePathSmoother({\n agentRadius,\n ...options\n });\n}\n\n/**\n * @zh 创建组合半径感知平滑器\n * @en Create combined radius-aware smoother\n *\n * @param baseSmoother - @zh 基础平滑器 @en Base smoother\n * @param agentRadius - @zh 代理半径 @en Agent radius\n * @param options - @zh 额外配置 @en Additional options\n *\n * @example\n * ```typescript\n * const smoother = createCombinedRadiusAwareSmoother(\n * new LineOfSightSmoother(),\n * 0.5\n * );\n * ```\n */\nexport function createCombinedRadiusAwareSmoother(\n baseSmoother: IPathSmoother,\n agentRadius: number,\n options?: Omit<IRadiusAwareSmootherConfig, 'agentRadius'>\n): CombinedRadiusAwareSmoother {\n return new CombinedRadiusAwareSmoother(baseSmoother, {\n agentRadius,\n ...options\n });\n}\n"],"mappings":"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","names":["CLOSED_FLAG","OPENED_FLAG","BACKWARD_CLOSED","BACKWARD_OPENED","GridState","width","height","bidirectional","size","g","f","flags","parent","heapIndex","version","currentVersion","gBack","fBack","parentBack","heapIndexBack","Float32Array","Uint8Array","Int32Array","Uint32Array","reset","fill","isInit","i","init","Infinity","getG","setG","v","getF","setF","getParent","setParent","getHeapIndex","setHeapIndex","isClosed","setClosed","isOpened","setOpened","getGBack","setGBack","getFBack","setFBack","getParentBack","setParentBack","getHeapIndexBack","setHeapIndexBack","isClosedBack","setClosedBack","isOpenedBack","setOpenedBack","_a","GridHeap","state","isBack","heap","length","isEmpty","push","bubbleUp","pop","result","last","sinkDown","update","pos","clear","idx","pp","pi","len","half","left","right","smallest","smallestF","lf","rf","si","GridPathfinder","map","config","mode","openList","openListBack","isBidir","findPath","startX","startY","endX","endY","options","findPathBidirectional","findPathUnidirectional","opts","DEFAULT_PATHFINDING_OPTIONS","validate","EMPTY_PATH_RESULT","startIdx","endIdx","found","path","x","y","cost","nodesSearched","hw","heuristicWeight","h0","heuristic","searched","maxNodes","allowDiagonal","avoidCorners","diagonalCost","nodes","dx","dy","dirCount","cur","buildPath","cx","cy","curG","d","nx","ny","neighbor","walkable","ni","isDiag","tentG","h","startPos","endPos","hf","hb","meetIdx","bestCost","total","buildPathBidirectional","isWalkable","w","reverse","createGridPathfinder","PathValidator","validatePath","path","fromIndex","toIndex","map","end","Math","min","length","i","point","x","floor","y","isWalkable","valid","invalidIndex","prev","checkLineOfSight","x1","y1","x2","y2","ix1","iy1","ix2","iy2","dx","abs","dy","sx","sy","err","ObstacleChangeManager","changes","Map","epoch","recordChange","wasWalkable","key","set","timestamp","Date","now","getAffectedRegion","size","minX","Infinity","minY","maxX","maxY","change","values","max","getChanges","Array","from","hasChanges","getEpoch","flush","clear","createPathValidator","createObstacleChangeManager","GridNode","x","y","width","walkable","cost","id","position","createPoint","DIRECTIONS_4","dx","dy","DIRECTIONS_8","DEFAULT_GRID_OPTIONS","allowDiagonal","diagonalCost","Math","SQRT2","avoidCorners","heuristic","octileDistance","GridMap","height","options","nodes","Number","isFinite","isInteger","Error","createNodes","getNodeAt","isInBounds","isWalkable","node","setWalkable","setCost","getNeighbors","neighbors","directions","i","length","dir","nx","ny","neighbor","hNode","vNode","push","forEachNeighbor","callback","a","b","getMovementCost","from","to","abs","loadFromArray","data","min","loadFromString","str","lines","trim","split","line","toString","result","reset","setRectWalkable","createGridMap","_a","NavMeshNode","polygon","id","position","cost","walkable","center","NavMesh","polygons","Map","nodes","nextId","obstacles","nextObstacleId","disabledPolygons","Set","addPolygon","vertices","neighbors","calculateCenter","portals","set","setConnection","polyA","polyB","portal","polygonA","get","polygonB","neighborsA","portalsA","includes","push","reversePortal","left","right","neighborsB","portalsB","build","polygonList","Array","from","values","i","length","j","sharedEdge","findSharedEdge","verticesA","verticesB","epsilon","a1","a2","b1","b2","match1","Math","abs","x","y","match2","v","createPoint","findPolygonAt","isPointInPolygon","inside","n","xi","yi","xj","yj","getNodeAt","getNeighbors","node","navNode","neighborId","neighbor","heuristic","a","b","euclideanDistance","getMovementCost","to","isWalkable","findPath","startX","startY","endX","endY","options","opts","DEFAULT_PATHFINDING_OPTIONS","startPolygon","endPolygon","EMPTY_PATH_RESULT","found","path","nodesSearched","polygonPath","findPolygonPath","start","end","pointPath","funnelPath","agentRadius","calculatePathLength","checkObstacles","openList","BinaryHeap","f","closed","states","startState","g","heuristicWeight","parent","isEmpty","maxNodes","current","pop","state","unshift","add","has","isPolygonBlocked","neighborPolygon","neighborState","update","shrunk","shrinkPortal","originalLeft","originalRight","apex","apexOriginal","leftIndex","rightIndex","leftOriginal","rightOriginal","nextLeft","nextRight","triArea2","pointsEqual","turnPoint","offsetTurningPoint","radius","dx","dy","len","sqrt","cx","cy","nx","ny","prevApex","cornerOriginal","cornerShrunk","side","perpX","perpY","c","addCircleObstacle","type","enabled","addRectObstacle","halfWidth","halfHeight","addPolygonObstacle","removeObstacle","obstacleId","delete","setObstacleEnabled","obstacle","updateObstaclePosition","getObstacles","getEnabledObstacles","filter","o","clearObstacles","clear","disablePolygon","polygonId","enablePolygon","isPolygonDisabled","disablePolygonAt","clearDisabledPolygons","getDisabledPolygons","isPointInObstacle","isPointInSingleObstacle","hw","hh","doesLineIntersectObstacle","x1","y1","x2","y2","doesLineIntersectSingleObstacle","lineIntersectsCircle","minX","maxX","minY","maxY","lineIntersectsRect","lineIntersectsPolygon","r","fx","fy","discriminant","t1","t2","lineSegmentsIntersect","x3","y3","x4","y4","d1","direction","d2","d3","d4","onSegment","min","max","vertex","v1","v2","findPathWithObstacles","getPolygons","polygonCount","size","obstacleCount","createNavMesh","bresenhamLineOfSight","x1","y1","x2","y2","map","ix1","Math","floor","iy1","ix2","iy2","dx","abs","dy","sx","sy","err","isWalkable","e2","raycastLineOfSight","stepSize","distance","sqrt","steps","ceil","stepX","stepY","x","y","i","LineOfSightSmoother","lineOfSight","smooth","path","length","result","current","furthest","push","CatmullRomSmoother","segments","tension","_map","points","p0","p1","p2","p3","j","t","point","interpolate","t2","t3","createPoint","CombinedSmoother","curveSegments","simplifier","curveSmoother","simplified","createLineOfSightSmoother","createCatmullRomSmoother","createCombinedSmoother","DEFAULT_CONFIG","safetyMargin","sampleDirections","maxOffsetAttempts","processCorners","RadiusAwarePathSmoother","config","sampleAngles","step","Math","PI","i","push","smooth","path","map","length","result","clearance","agentRadius","point","isCorner","safePoint","prev","next","offsetCornerPoint","offsetPointFromObstacles","obstacleDirections","detectNearbyObstacles","avgDirX","avgDirY","dir","x","y","len","sqrt","offsetDirX","offsetDirY","attempt","offsetDist","newX","newY","isWalkable","floor","newObstacles","createPoint","corner","inDirX","inDirY","inLen","outDirX","outDirY","outLen","inNormX","inNormY","outNormX","outNormY","bisectX","bisectY","bisectLen","bisectNormX","bisectNormY","dotProduct","angle","acos","max","min","halfAngle","sinHalfAngle","sin","maxOffset","actualOffset","altX","altY","obstacles","dirX","cos","dirY","sampleX","sampleY","CombinedRadiusAwareSmoother","baseSmoother","radiusAwareSmoother","smoothed","createRadiusAwareSmoother","options","createCombinedRadiusAwareSmoother"]}