@esengine/pathfinding 13.1.0 → 13.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/avoidance/ILocalAvoidance.ts","../src/avoidance/LinearProgram.ts","../src/avoidance/ObstacleBuilder.ts","../src/avoidance/ORCASolver.ts","../src/avoidance/KDTree.ts","../src/avoidance/CollisionResolver.ts"],"sourcesContent":["/**\n * @zh ORCA 局部避让接口定义\n * @en ORCA Local Avoidance Interface Definitions\n */\n\nimport type { IVector2 } from '@esengine/ecs-framework-math';\n\nexport type { IVector2 };\n\n/**\n * @zh ORCA 约束线(半平面)\n * @en ORCA constraint line (half-plane)\n *\n * @zh 约束线定义了一个半平面,代理的速度必须在允许的一侧\n * @en A constraint line defines a half-plane, agent's velocity must be on the allowed side\n */\nexport interface IORCALine {\n /**\n * @zh 线上的一点\n * @en A point on the line\n */\n point: IVector2;\n\n /**\n * @zh 线的方向向量(单位向量,允许区域在左侧)\n * @en Direction vector of the line (unit vector, allowed region is on the left)\n */\n direction: IVector2;\n}\n\n// =============================================================================\n// 代理数据 | Agent Data\n// =============================================================================\n\n/**\n * @zh 避让代理数据\n * @en Avoidance agent data\n *\n * @zh 包含计算 ORCA 所需的所有代理信息\n * @en Contains all agent information needed for ORCA computation\n */\nexport interface IAvoidanceAgent {\n /**\n * @zh 代理唯一标识\n * @en Unique identifier for the agent\n */\n id: number;\n\n /**\n * @zh 当前位置\n * @en Current position\n */\n position: IVector2;\n\n /**\n * @zh 当前速度\n * @en Current velocity\n */\n velocity: IVector2;\n\n /**\n * @zh 首选速度(通常指向目标方向)\n * @en Preferred velocity (usually towards target)\n */\n preferredVelocity: IVector2;\n\n /**\n * @zh 代理半径\n * @en Agent radius\n */\n radius: number;\n\n /**\n * @zh 最大速度\n * @en Maximum speed\n */\n maxSpeed: number;\n\n /**\n * @zh 邻居检测距离\n * @en Neighbor detection distance\n */\n neighborDist: number;\n\n /**\n * @zh 最大邻居数量\n * @en Maximum number of neighbors to consider\n */\n maxNeighbors: number;\n\n /**\n * @zh 代理避让时间视野(秒)\n * @en Time horizon for agent avoidance (seconds)\n *\n * @zh 更大的值会让代理更早开始避让\n * @en Larger values make agents start avoiding earlier\n */\n timeHorizon: number;\n\n /**\n * @zh 障碍物避让时间视野(秒)\n * @en Time horizon for obstacle avoidance (seconds)\n */\n timeHorizonObst: number;\n}\n\n// =============================================================================\n// 障碍物 | Obstacles\n// =============================================================================\n\n/**\n * @zh 静态障碍物顶点(链表节点)\n * @en Static obstacle vertex (linked list node)\n */\nexport interface IObstacleVertex {\n /**\n * @zh 顶点位置\n * @en Vertex position\n */\n point: IVector2;\n\n /**\n * @zh 下一个顶点(构成障碍物边,循环链表)\n * @en Next vertex (forms obstacle edge, circular linked list)\n */\n next: IObstacleVertex;\n\n /**\n * @zh 前一个顶点(循环链表)\n * @en Previous vertex (circular linked list)\n */\n previous: IObstacleVertex;\n\n /**\n * @zh 边的单位方向向量(从此顶点指向 next 顶点)\n * @en Unit direction vector of edge (from this vertex towards next vertex)\n */\n direction: IVector2;\n\n /**\n * @zh 是否为凸顶点\n * @en Whether this is a convex vertex\n */\n isConvex: boolean;\n\n /**\n * @zh 顶点 ID(用于调试)\n * @en Vertex ID (for debugging)\n */\n id: number;\n}\n\n/**\n * @zh 静态障碍物(多边形)\n * @en Static obstacle (polygon)\n *\n * @zh 重要:顶点必须按逆时针(CCW)顺序排列(在 Y 轴向上的坐标系中)\n * @en Important: Vertices must be in counter-clockwise (CCW) order (in Y-axis up coordinate system)\n *\n * @zh 可以使用 math 库中的 Polygon.ensureCCW() 确保正确顺序\n * @en Use Polygon.ensureCCW() from math library to ensure correct order\n *\n * @zh 在 Y 轴向下的坐标系(如 Canvas)中,视觉上的 CCW 需要传入 yAxisDown=true\n * @en In Y-axis down coordinate system (like Canvas), use yAxisDown=true for visual CCW\n *\n * @example\n * ```typescript\n * import { Polygon } from '@esengine/ecs-framework-math';\n *\n * // 标准 Y 轴向上坐标系\n * const obstacle: IObstacle = {\n * vertices: Polygon.ensureCCW(myVertices)\n * };\n *\n * // Canvas/屏幕坐标系(Y 轴向下)\n * const obstacle: IObstacle = {\n * vertices: Polygon.ensureCCW(myVertices, true)\n * };\n * ```\n */\nexport interface IObstacle {\n /**\n * @zh 顶点列表(逆时针顺序,Y 轴向上坐标系)\n * @en Vertex list (counter-clockwise order in Y-axis up coordinate system)\n */\n vertices: IVector2[];\n}\n\n// =============================================================================\n// 求解器接口 | Solver Interface\n// =============================================================================\n\n/**\n * @zh ORCA 求解器配置\n * @en ORCA solver configuration\n */\nexport interface IORCASolverConfig {\n /**\n * @zh 默认时间视野(代理)\n * @en Default time horizon for agents\n */\n defaultTimeHorizon?: number;\n\n /**\n * @zh 默认时间视野(障碍物)\n * @en Default time horizon for obstacles\n */\n defaultTimeHorizonObst?: number;\n\n /**\n * @zh 时间步长(用于碰撞响应)\n * @en Time step (for collision response)\n */\n timeStep?: number;\n\n /**\n * @zh 数值精度阈值\n * @en Numerical precision threshold\n */\n epsilon?: number;\n\n /**\n * @zh 是否使用 Y 轴向下的坐标系(如 Canvas/屏幕坐标)\n * @en Whether using Y-axis down coordinate system (like Canvas/screen coords)\n *\n * @zh 这会影响障碍物顶点顺序的判断(CCW 检测)\n * @en This affects obstacle vertex order detection (CCW check)\n *\n * @default false\n */\n yAxisDown?: boolean;\n}\n\n/**\n * @zh ORCA 求解结果\n * @en ORCA solve result\n */\nexport interface IORCAResult {\n /**\n * @zh 计算得到的新速度\n * @en Computed new velocity\n */\n velocity: IVector2;\n\n /**\n * @zh 是否找到可行解(满足所有约束)\n * @en Whether a feasible solution was found (satisfies all constraints)\n */\n feasible: boolean;\n\n /**\n * @zh 生成的 ORCA 约束线数量\n * @en Number of ORCA lines generated\n */\n numLines: number;\n\n /**\n * @zh 违反的约束数量\n * @en Number of violated constraints\n */\n violatedConstraints: number;\n}\n\n/**\n * @zh ORCA 求解器接口\n * @en ORCA solver interface\n */\nexport interface IORCASolver {\n /**\n * @zh 计算代理的新速度\n * @en Compute new velocity for agent\n *\n * @param agent - @zh 当前代理 @en Current agent\n * @param neighbors - @zh 邻近代理列表 @en List of neighbor agents\n * @param obstacles - @zh 静态障碍物列表 @en List of static obstacles\n * @param deltaTime - @zh 时间步长 @en Time step\n * @returns @zh 新速度 @en New velocity\n */\n computeNewVelocity(\n agent: IAvoidanceAgent,\n neighbors: readonly IAvoidanceAgent[],\n obstacles: readonly IObstacle[],\n deltaTime: number\n ): IVector2;\n}\n\n// =============================================================================\n// 空间索引接口 | Spatial Index Interface\n// =============================================================================\n\n/**\n * @zh 邻居查询结果\n * @en Neighbor query result\n */\nexport interface INeighborResult {\n /**\n * @zh 代理数据\n * @en Agent data\n */\n agent: IAvoidanceAgent;\n\n /**\n * @zh 距离的平方\n * @en Squared distance\n */\n distanceSq: number;\n}\n\n/**\n * @zh 空间索引接口(用于快速邻居查询)\n * @en Spatial index interface (for fast neighbor queries)\n */\nexport interface ISpatialIndex {\n /**\n * @zh 构建空间索引\n * @en Build spatial index\n *\n * @param agents - @zh 代理列表 @en List of agents\n */\n build(agents: readonly IAvoidanceAgent[]): void;\n\n /**\n * @zh 查询指定范围内的邻居\n * @en Query neighbors within specified range\n *\n * @param position - @zh 查询位置 @en Query position\n * @param radius - @zh 查询半径 @en Query radius\n * @param maxResults - @zh 最大返回数量 @en Maximum number of results\n * @param excludeId - @zh 排除的代理 ID @en Agent ID to exclude\n * @returns @zh 邻居列表(按距离排序)@en List of neighbors (sorted by distance)\n */\n queryNeighbors(\n position: IVector2,\n radius: number,\n maxResults: number,\n excludeId?: number\n ): INeighborResult[];\n\n /**\n * @zh 清空索引\n * @en Clear the index\n */\n clear(): void;\n}\n\n// =============================================================================\n// 默认配置 | Default Configuration\n// =============================================================================\n\n/**\n * @zh 默认 ORCA 求解器配置\n * @en Default ORCA solver configuration\n */\nexport const DEFAULT_ORCA_CONFIG: Required<IORCASolverConfig> = {\n defaultTimeHorizon: 2.0,\n defaultTimeHorizonObst: 1.0,\n timeStep: 1 / 60,\n epsilon: 0.00001,\n yAxisDown: false\n};\n\n/**\n * @zh 默认代理参数\n * @en Default agent parameters\n */\nexport const DEFAULT_AGENT_PARAMS = {\n radius: 0.5,\n maxSpeed: 5.0,\n neighborDist: 15.0,\n maxNeighbors: 10,\n timeHorizon: 2.0,\n timeHorizonObst: 1.0\n};\n","/**\n * @zh 2D 线性规划求解器\n * @en 2D Linear Programming Solver\n *\n * @zh 用于 ORCA 算法中的速度优化求解\n * @en Used for velocity optimization in ORCA algorithm\n */\n\nimport { Vector2, type IVector2 } from '@esengine/ecs-framework-math';\nimport type { IORCALine } from './ILocalAvoidance';\n\n// =============================================================================\n// 常量 | Constants\n// =============================================================================\n\n/**\n * @zh 数值精度阈值\n * @en Numerical precision threshold\n */\nconst EPSILON = 0.00001;\n\nconst { dot, det, lengthSq } = Vector2;\n\n// =============================================================================\n// 线性规划求解 | Linear Programming Solver\n// =============================================================================\n\n/**\n * @zh 1D 线性规划\n * @en 1D Linear Programming\n *\n * @zh 在一条线上找到满足约束的最优点\n * @en Find optimal point on a line that satisfies constraints\n *\n * @param lines - @zh 约束线列表 @en List of constraint lines\n * @param lineNo - @zh 当前处理的线索引 @en Index of current line being processed\n * @param radius - @zh 最大速度(圆盘半径)@en Maximum speed (disk radius)\n * @param optVelocity - @zh 首选速度 @en Preferred velocity\n * @param directionOpt - @zh 是否优化方向 @en Whether to optimize direction\n * @param result - @zh 结果向量(输出)@en Result vector (output)\n * @returns @zh 是否找到可行解 @en Whether a feasible solution was found\n */\nfunction linearProgram1(\n lines: readonly IORCALine[],\n lineNo: number,\n radius: number,\n optVelocity: IVector2,\n directionOpt: boolean,\n result: Vector2\n): boolean {\n const line = lines[lineNo]!;\n const dotProduct = dot(line.point, line.direction);\n const discriminant = dotProduct * dotProduct + radius * radius - lengthSq(line.point);\n\n if (discriminant < 0) {\n return false;\n }\n\n const sqrtDiscriminant = Math.sqrt(discriminant);\n let tLeft = -dotProduct - sqrtDiscriminant;\n let tRight = -dotProduct + sqrtDiscriminant;\n\n for (let i = 0; i < lineNo; i++) {\n const constraint = lines[i]!;\n const denominator = det(line.direction, constraint.direction);\n const numerator = det(constraint.direction, {\n x: line.point.x - constraint.point.x,\n y: line.point.y - constraint.point.y\n });\n\n if (Math.abs(denominator) <= EPSILON) {\n if (numerator < 0) {\n return false;\n }\n continue;\n }\n\n const t = numerator / denominator;\n\n if (denominator >= 0) {\n tRight = Math.min(tRight, t);\n } else {\n tLeft = Math.max(tLeft, t);\n }\n\n if (tLeft > tRight) {\n return false;\n }\n }\n\n let t: number;\n if (directionOpt) {\n if (dot(optVelocity, line.direction) > 0) {\n t = tRight;\n } else {\n t = tLeft;\n }\n } else {\n t = dot(line.direction, {\n x: optVelocity.x - line.point.x,\n y: optVelocity.y - line.point.y\n });\n\n if (t < tLeft) {\n t = tLeft;\n } else if (t > tRight) {\n t = tRight;\n }\n }\n\n result.x = line.point.x + t * line.direction.x;\n result.y = line.point.y + t * line.direction.y;\n\n return true;\n}\n\n/**\n * @zh 2D 线性规划\n * @en 2D Linear Programming\n *\n * @zh 在多个半平面约束下找到最优速度\n * @en Find optimal velocity under multiple half-plane constraints\n *\n * @param lines - @zh 约束线列表 @en List of constraint lines\n * @param radius - @zh 最大速度(圆盘半径)@en Maximum speed (disk radius)\n * @param optVelocity - @zh 首选速度 @en Preferred velocity\n * @param directionOpt - @zh 是否优化方向 @en Whether to optimize direction\n * @param result - @zh 结果向量(输出)@en Result vector (output)\n * @returns @zh 第一个失败的约束索引,如果成功则返回 lines.length @en Index of first failed constraint, or lines.length if successful\n */\nexport function linearProgram2(\n lines: readonly IORCALine[],\n radius: number,\n optVelocity: IVector2,\n directionOpt: boolean,\n result: Vector2\n): number {\n if (directionOpt) {\n result.x = optVelocity.x * radius;\n result.y = optVelocity.y * radius;\n } else if (lengthSq(optVelocity) > radius * radius) {\n const len = Math.sqrt(lengthSq(optVelocity));\n result.x = optVelocity.x / len * radius;\n result.y = optVelocity.y / len * radius;\n } else {\n result.x = optVelocity.x;\n result.y = optVelocity.y;\n }\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i]!;\n const detVal = det(line.direction, { x: line.point.x - result.x, y: line.point.y - result.y });\n if (detVal > 0) {\n const tempResult = result.clone();\n if (!linearProgram1(lines, i, radius, optVelocity, directionOpt, result)) {\n result.copy(tempResult);\n return i;\n }\n }\n }\n\n return lines.length;\n}\n\n/**\n * @zh 3D 线性规划(回退方案)\n * @en 3D Linear Programming (fallback)\n *\n * @zh 当 2D 线性规划失败时,使用此方法找到最小穿透的速度\n * @en When 2D LP fails, use this to find velocity with minimum penetration\n *\n * @zh 重要:障碍物约束线(前 numObstLines 条)具有最高优先级,绝不会被违反\n * @en Important: Obstacle constraint lines (first numObstLines) have highest priority and are never violated\n *\n * @param lines - @zh 约束线列表 @en List of constraint lines\n * @param numObstLines - @zh 障碍物约束线数量 @en Number of obstacle constraint lines\n * @param beginLine - @zh 开始处理的线索引 @en Index of line to start processing\n * @param radius - @zh 最大速度 @en Maximum speed\n * @param result - @zh 结果向量(输入/输出)@en Result vector (input/output)\n */\nexport function linearProgram3(\n lines: IORCALine[],\n numObstLines: number,\n beginLine: number,\n radius: number,\n result: Vector2\n): void {\n let distance = 0;\n\n for (let i = beginLine; i < lines.length; i++) {\n const line = lines[i]!;\n if (det(line.direction, { x: line.point.x - result.x, y: line.point.y - result.y }) > distance) {\n const projLines: IORCALine[] = [];\n\n for (let j = 0; j < numObstLines; j++) {\n projLines.push(lines[j]!);\n }\n\n for (let j = numObstLines; j < i; j++) {\n const line1 = lines[j]!;\n const line2 = lines[i]!;\n\n let newLine: IORCALine;\n const determinant = det(line1.direction, line2.direction);\n\n if (Math.abs(determinant) <= EPSILON) {\n if (dot(line1.direction, line2.direction) > 0) {\n continue;\n }\n\n newLine = {\n point: {\n x: 0.5 * (line1.point.x + line2.point.x),\n y: 0.5 * (line1.point.y + line2.point.y)\n },\n direction: { x: 0, y: 0 }\n };\n } else {\n const diff = {\n x: line1.point.x - line2.point.x,\n y: line1.point.y - line2.point.y\n };\n const t = det(line2.direction, diff) / determinant;\n\n newLine = {\n point: {\n x: line1.point.x + t * line1.direction.x,\n y: line1.point.y + t * line1.direction.y\n },\n direction: { x: 0, y: 0 }\n };\n }\n\n const dirDiff = {\n x: line1.direction.x - line2.direction.x,\n y: line1.direction.y - line2.direction.y\n };\n const dirLen = Math.sqrt(lengthSq(dirDiff));\n if (dirLen > EPSILON) {\n newLine.direction.x = dirDiff.x / dirLen;\n newLine.direction.y = dirDiff.y / dirLen;\n }\n\n projLines.push(newLine);\n }\n\n const tempResult = result.clone();\n const optVelocity = { x: -lines[i]!.direction.y, y: lines[i]!.direction.x };\n\n if (linearProgram2(projLines, radius, optVelocity, true, result) < projLines.length) {\n result.copy(tempResult);\n }\n\n // @zh 验证结果不违反障碍物约束\n // @en Verify result doesn't violate obstacle constraints\n if (!verifyObstacleConstraints(lines, numObstLines, result)) {\n result.copy(tempResult);\n }\n\n distance = det(lines[i]!.direction, {\n x: lines[i]!.point.x - result.x,\n y: lines[i]!.point.y - result.y\n });\n }\n }\n}\n\n/**\n * @zh 验证速度是否满足所有障碍物约束\n * @en Verify velocity satisfies all obstacle constraints\n */\nfunction verifyObstacleConstraints(\n lines: readonly IORCALine[],\n numObstLines: number,\n velocity: IVector2\n): boolean {\n for (let i = 0; i < numObstLines; i++) {\n const line = lines[i]!;\n const detVal = det(line.direction, {\n x: line.point.x - velocity.x,\n y: line.point.y - velocity.y\n });\n if (detVal > EPSILON) {\n return false;\n }\n }\n return true;\n}\n\n/**\n * @zh ORCA 线性规划求解结果\n * @en ORCA Linear Programming solve result\n */\nexport interface IORCALPResult {\n /**\n * @zh 计算得到的速度\n * @en Computed velocity\n */\n velocity: Vector2;\n\n /**\n * @zh 是否找到可行解(满足所有约束)\n * @en Whether a feasible solution was found (satisfies all constraints)\n */\n feasible: boolean;\n\n /**\n * @zh 违反的约束数量\n * @en Number of violated constraints\n */\n violatedConstraints: number;\n}\n\n/**\n * @zh 求解 ORCA 线性规划\n * @en Solve ORCA Linear Programming\n *\n * @zh 综合使用 2D 和 3D 线性规划求解最优速度\n * @en Use both 2D and 3D LP to solve for optimal velocity\n *\n * @zh 注意:此函数不包含回退逻辑,调用方应通过返回的 feasible 标志判断是否需要流量控制\n * @en Note: This function does not include fallback logic, caller should check feasible flag for flow control\n *\n * @param lines - @zh ORCA 约束线列表 @en List of ORCA constraint lines\n * @param numObstLines - @zh 障碍物约束线数量 @en Number of obstacle lines\n * @param maxSpeed - @zh 最大速度 @en Maximum speed\n * @param preferredVelocity - @zh 首选速度 @en Preferred velocity\n * @returns @zh 求解结果,包含速度和可行性标志 @en Solve result with velocity and feasibility flag\n */\nexport function solveORCALinearProgram(\n lines: IORCALine[],\n numObstLines: number,\n maxSpeed: number,\n preferredVelocity: IVector2\n): IORCALPResult {\n const result = new Vector2();\n\n const lineFail = linearProgram2(lines, maxSpeed, preferredVelocity, false, result);\n\n let feasible = lineFail >= lines.length;\n let violatedConstraints = 0;\n\n if (!feasible) {\n linearProgram3(lines, numObstLines, lineFail, maxSpeed, result);\n violatedConstraints = lines.length - lineFail;\n }\n\n // @zh 检查是否违反障碍物约束\n // @en Check if obstacle constraints are violated\n if (numObstLines > 0 && !verifyObstacleConstraints(lines, numObstLines, result)) {\n feasible = false;\n violatedConstraints = Math.max(violatedConstraints, 1);\n }\n\n return {\n velocity: result,\n feasible,\n violatedConstraints\n };\n}\n","/**\n * @zh 障碍物构建器\n * @en Obstacle Builder\n */\n\nimport type { IVector2 } from '@esengine/ecs-framework-math';\nimport type { IObstacle, IObstacleVertex } from './ILocalAvoidance';\n\nconst EPSILON = 0.00001;\n\n/**\n * @zh 计算点相对于线段的位置(左侧判断)\n * @en Compute point position relative to line segment (left-of test)\n *\n * @zh 使用叉积判断点在向量的哪一侧\n * @en Use cross product to determine which side of the vector the point is on\n *\n * @zh 返回值 > 0 表示 p3 在向量 p1->p2 的左边\n * @en Returns > 0 if p3 is to the left of vector p1->p2\n */\nfunction leftOf(p1: IVector2, p2: IVector2, p3: IVector2): number {\n return (p1.x - p3.x) * (p2.y - p1.y) - (p1.y - p3.y) * (p2.x - p1.x);\n}\n\n/**\n * @zh 从顶点数组创建障碍物链表\n * @en Create obstacle linked list from vertex array\n *\n * @param vertices - @zh 顶点数组(CCW 顺序)@en Vertex array (CCW order)\n * @param startId - @zh 起始顶点 ID @en Starting vertex ID\n */\nexport function createObstacleVertices(\n vertices: readonly IVector2[],\n startId: number = 0\n): IObstacleVertex[] {\n const n = vertices.length;\n if (n < 2) {\n return [];\n }\n\n const obstacleVertices: IObstacleVertex[] = [];\n for (let i = 0; i < n; i++) {\n obstacleVertices.push({\n point: { x: vertices[i]!.x, y: vertices[i]!.y },\n direction: { x: 0, y: 0 },\n next: null as unknown as IObstacleVertex,\n previous: null as unknown as IObstacleVertex,\n isConvex: false,\n id: startId + i\n });\n }\n\n for (let i = 0; i < n; i++) {\n const curr = obstacleVertices[i]!;\n const next = obstacleVertices[(i + 1) % n]!;\n const prev = obstacleVertices[(i + n - 1) % n]!;\n\n curr.next = next;\n curr.previous = prev;\n\n const dx = next.point.x - curr.point.x;\n const dy = next.point.y - curr.point.y;\n const edgeLen = Math.sqrt(dx * dx + dy * dy);\n\n if (edgeLen > EPSILON) {\n curr.direction = { x: dx / edgeLen, y: dy / edgeLen };\n } else {\n curr.direction = { x: 1, y: 0 };\n }\n }\n\n for (let i = 0; i < n; i++) {\n const curr = obstacleVertices[i]!;\n const prev = curr.previous;\n const next = curr.next;\n curr.isConvex = leftOf(prev.point, curr.point, next.point) >= 0;\n }\n\n return obstacleVertices;\n}\n\n/**\n * @zh 构建障碍物顶点的选项\n * @en Options for building obstacle vertices\n */\nexport interface IBuildObstacleOptions {\n /**\n * @zh 是否使用 Y 轴向下的坐标系(如 Canvas/屏幕坐标)\n * @en Whether using Y-axis down coordinate system (like Canvas/screen coords)\n *\n * @zh 这会影响障碍物顶点顺序的判断\n * @en This affects obstacle vertex order detection\n *\n * @default false\n */\n yAxisDown?: boolean;\n}\n\n/**\n * @zh 从障碍物数组创建所有障碍物顶点\n * @en Create all obstacle vertices from obstacle array\n *\n * @zh 自动检测并纠正顶点顺序为 CCW(逆时针)\n * @en Automatically detects and corrects vertex order to CCW (counter-clockwise)\n *\n * @param obstacles - @zh 障碍物数组 @en Array of obstacles\n * @param options - @zh 构建选项 @en Build options\n */\nexport function buildObstacleVertices(\n obstacles: readonly IObstacle[],\n options: IBuildObstacleOptions = {}\n): IObstacleVertex[] {\n const { yAxisDown = false } = options;\n const allVertices: IObstacleVertex[] = [];\n let nextId = 0;\n\n for (const obstacle of obstacles) {\n // @zh 自动确保顶点为 CCW 顺序\n // @en Automatically ensure vertices are in CCW order\n const ccwVertices = ensureCCW([...obstacle.vertices], yAxisDown);\n const vertices = createObstacleVertices(ccwVertices, nextId);\n allVertices.push(...vertices);\n nextId += vertices.length;\n }\n\n return allVertices;\n}\n\n/**\n * @zh 确保顶点按逆时针顺序排列\n * @en Ensure vertices are in counter-clockwise order\n */\nexport function ensureCCW(vertices: IVector2[], yAxisDown: boolean = false): IVector2[] {\n if (vertices.length < 3) {\n return vertices;\n }\n\n let signedArea = 0;\n for (let i = 0; i < vertices.length; i++) {\n const curr = vertices[i]!;\n const next = vertices[(i + 1) % vertices.length]!;\n signedArea += (curr.x * next.y - next.x * curr.y);\n }\n signedArea *= 0.5;\n\n const isCCW = yAxisDown ? signedArea < 0 : signedArea > 0;\n\n if (isCCW) {\n return vertices;\n }\n\n return [...vertices].reverse();\n}\n","/**\n * @zh ORCA 避让算法求解器\n * @en ORCA Avoidance Algorithm Solver\n *\n * @zh 实现最优互惠碰撞避免(ORCA)算法,用于多代理局部避让\n * @en Implements Optimal Reciprocal Collision Avoidance (ORCA) algorithm for multi-agent local avoidance\n */\n\nimport { Vector2, type IVector2 } from '@esengine/ecs-framework-math';\nimport type {\n IAvoidanceAgent,\n IObstacle,\n IObstacleVertex,\n IORCALine,\n IORCASolver,\n IORCASolverConfig\n} from './ILocalAvoidance';\nimport { DEFAULT_ORCA_CONFIG } from './ILocalAvoidance';\nimport { solveORCALinearProgram, type IORCALPResult } from './LinearProgram';\nimport { buildObstacleVertices } from './ObstacleBuilder';\n\n/**\n * @zh 数值精度阈值\n * @en Numerical precision threshold\n */\nconst EPSILON = 0.00001;\n\nconst { det, dot, lengthSq, len } = Vector2;\n\n/**\n * @zh 向量归一化\n * @en Normalize vector\n */\nfunction normalize(v: IVector2): IVector2 {\n const length = len(v);\n if (length < EPSILON) {\n return { x: 0, y: 0 };\n }\n return { x: v.x / length, y: v.y / length };\n}\n\n/**\n * @zh ORCA 求解器实现\n * @en ORCA Solver implementation\n *\n * @zh 实现最优互惠碰撞避免算法,计算代理的安全速度\n * @en Implements Optimal Reciprocal Collision Avoidance algorithm to compute safe velocities for agents\n */\nexport class ORCASolver implements IORCASolver {\n private readonly config: Required<IORCASolverConfig>;\n\n constructor(config: IORCASolverConfig = {}) {\n this.config = { ...DEFAULT_ORCA_CONFIG, ...config };\n }\n\n /**\n * @zh 计算代理的新速度\n * @en Compute new velocity for agent\n *\n * @param agent - @zh 当前代理 @en Current agent\n * @param neighbors - @zh 邻近代理列表 @en List of neighboring agents\n * @param obstacles - @zh 障碍物列表 @en List of obstacles\n * @param deltaTime - @zh 时间步长 @en Time step\n * @returns @zh 计算得到的新速度 @en Computed new velocity\n */\n computeNewVelocity(\n agent: IAvoidanceAgent,\n neighbors: readonly IAvoidanceAgent[],\n obstacles: readonly IObstacle[],\n deltaTime: number\n ): IVector2 {\n const result = this.computeNewVelocityWithResult(agent, neighbors, obstacles, deltaTime);\n return result.velocity;\n }\n\n /**\n * @zh 计算代理的新速度(带完整结果)\n * @en Compute new velocity for agent (with full result)\n *\n * @param agent - @zh 当前代理 @en Current agent\n * @param neighbors - @zh 邻近代理列表 @en List of neighboring agents\n * @param obstacles - @zh 障碍物列表 @en List of obstacles\n * @param deltaTime - @zh 时间步长 @en Time step\n * @returns @zh 完整求解结果 @en Full solve result\n */\n computeNewVelocityWithResult(\n agent: IAvoidanceAgent,\n neighbors: readonly IAvoidanceAgent[],\n obstacles: readonly IObstacle[],\n deltaTime: number\n ): IORCALPResult & { numLines: number } {\n const orcaLines: IORCALine[] = [];\n\n const obstacleVertices = buildObstacleVertices(obstacles, {\n yAxisDown: this.config.yAxisDown\n });\n const numObstLines = this.createObstacleORCALines(agent, obstacleVertices, orcaLines);\n this.createAgentORCALines(agent, neighbors, deltaTime, orcaLines);\n\n const result = solveORCALinearProgram(\n orcaLines,\n numObstLines,\n agent.maxSpeed,\n agent.preferredVelocity\n );\n\n return {\n ...result,\n numLines: orcaLines.length\n };\n }\n\n /**\n * @zh 创建代理间的 ORCA 约束线\n * @en Create ORCA constraint lines for agent-agent avoidance\n */\n private createAgentORCALines(\n agent: IAvoidanceAgent,\n neighbors: readonly IAvoidanceAgent[],\n deltaTime: number,\n orcaLines: IORCALine[]\n ): void {\n const invTimeHorizon = 1.0 / agent.timeHorizon;\n\n for (const other of neighbors) {\n if (other.id === agent.id) continue;\n\n const relativePosition: IVector2 = {\n x: other.position.x - agent.position.x,\n y: other.position.y - agent.position.y\n };\n\n const relativeVelocity: IVector2 = {\n x: agent.velocity.x - other.velocity.x,\n y: agent.velocity.y - other.velocity.y\n };\n\n const distSq = lengthSq(relativePosition);\n const combinedRadius = agent.radius + other.radius;\n const combinedRadiusSq = combinedRadius * combinedRadius;\n\n const line: IORCALine = {\n point: { x: 0, y: 0 },\n direction: { x: 0, y: 0 }\n };\n\n let u: IVector2;\n\n if (distSq > combinedRadiusSq) {\n // @zh 无碰撞情况\n // @en No collision case\n const w: IVector2 = {\n x: relativeVelocity.x - invTimeHorizon * relativePosition.x,\n y: relativeVelocity.y - invTimeHorizon * relativePosition.y\n };\n\n const wLengthSq = lengthSq(w);\n const dotProduct1 = dot(w, relativePosition);\n\n if (dotProduct1 < 0 && dotProduct1 * dotProduct1 > combinedRadiusSq * wLengthSq) {\n // @zh 投影到截止圆\n // @en Project on cut-off circle\n const wLength = Math.sqrt(wLengthSq);\n const unitW = normalize(w);\n\n line.direction = { x: unitW.y, y: -unitW.x };\n u = {\n x: (combinedRadius * invTimeHorizon - wLength) * unitW.x,\n y: (combinedRadius * invTimeHorizon - wLength) * unitW.y\n };\n } else {\n // @zh 投影到腿部\n // @en Project on legs\n const leg = Math.sqrt(distSq - combinedRadiusSq);\n\n if (det(relativePosition, w) > 0) {\n line.direction = {\n x: (relativePosition.x * leg - relativePosition.y * combinedRadius) / distSq,\n y: (relativePosition.x * combinedRadius + relativePosition.y * leg) / distSq\n };\n } else {\n line.direction = {\n x: -(relativePosition.x * leg + relativePosition.y * combinedRadius) / distSq,\n y: -(-relativePosition.x * combinedRadius + relativePosition.y * leg) / distSq\n };\n }\n\n const dotProduct2 = dot(relativeVelocity, line.direction);\n u = {\n x: dotProduct2 * line.direction.x - relativeVelocity.x,\n y: dotProduct2 * line.direction.y - relativeVelocity.y\n };\n }\n } else {\n // @zh 碰撞情况\n // @en Collision case\n const invTimeStep = 1.0 / deltaTime;\n\n const w: IVector2 = {\n x: relativeVelocity.x - invTimeStep * relativePosition.x,\n y: relativeVelocity.y - invTimeStep * relativePosition.y\n };\n\n const wLength = len(w);\n const unitW = wLength > EPSILON\n ? { x: w.x / wLength, y: w.y / wLength }\n : { x: 1, y: 0 };\n\n line.direction = { x: unitW.y, y: -unitW.x };\n u = {\n x: (combinedRadius * invTimeStep - wLength) * unitW.x,\n y: (combinedRadius * invTimeStep - wLength) * unitW.y\n };\n }\n\n line.point = {\n x: agent.velocity.x + 0.5 * u.x,\n y: agent.velocity.y + 0.5 * u.y\n };\n\n orcaLines.push(line);\n }\n }\n\n /**\n * @zh 创建障碍物的 ORCA 约束线\n * @en Create ORCA constraint lines for obstacle avoidance\n */\n private createObstacleORCALines(\n agent: IAvoidanceAgent,\n obstacleVertices: IObstacleVertex[],\n orcaLines: IORCALine[]\n ): number {\n const invTimeHorizonObst = 1.0 / agent.timeHorizonObst;\n const radiusSq = agent.radius * agent.radius;\n let numObstLines = 0;\n\n for (const obstacle1 of obstacleVertices) {\n const obstacle2 = obstacle1.next;\n\n const relativePosition1: IVector2 = {\n x: obstacle1.point.x - agent.position.x,\n y: obstacle1.point.y - agent.position.y\n };\n const relativePosition2: IVector2 = {\n x: obstacle2.point.x - agent.position.x,\n y: obstacle2.point.y - agent.position.y\n };\n\n // @zh 跳过代理位于内侧的边(对于 CCW 多边形,内侧在左边)\n // @en Skip edges where agent is on interior side (for CCW polygons, interior is on left)\n const obstacleVector: IVector2 = {\n x: obstacle2.point.x - obstacle1.point.x,\n y: obstacle2.point.y - obstacle1.point.y\n };\n const signedDistToEdge = det(obstacleVector, relativePosition1);\n\n if (signedDistToEdge < -EPSILON) {\n continue;\n }\n\n // @zh 检查是否已被现有 ORCA 线覆盖\n // @en Check if already covered by existing ORCA lines\n let alreadyCovered = false;\n for (const existingLine of orcaLines) {\n const scaledRelPos1: IVector2 = {\n x: invTimeHorizonObst * relativePosition1.x - existingLine.point.x,\n y: invTimeHorizonObst * relativePosition1.y - existingLine.point.y\n };\n const scaledRelPos2: IVector2 = {\n x: invTimeHorizonObst * relativePosition2.x - existingLine.point.x,\n y: invTimeHorizonObst * relativePosition2.y - existingLine.point.y\n };\n\n if (det(scaledRelPos1, existingLine.direction) - invTimeHorizonObst * agent.radius >= -EPSILON &&\n det(scaledRelPos2, existingLine.direction) - invTimeHorizonObst * agent.radius >= -EPSILON) {\n alreadyCovered = true;\n break;\n }\n }\n\n if (alreadyCovered) {\n continue;\n }\n\n const distSq1 = lengthSq(relativePosition1);\n const distSq2 = lengthSq(relativePosition2);\n const obstacleVectorSq = lengthSq(obstacleVector);\n\n const s = obstacleVectorSq > EPSILON\n ? -dot(relativePosition1, obstacleVector) / obstacleVectorSq\n : 0;\n\n const distSqLineToEdge = lengthSq({\n x: -relativePosition1.x - s * obstacleVector.x,\n y: -relativePosition1.y - s * obstacleVector.y\n });\n\n const line: IORCALine = {\n point: { x: 0, y: 0 },\n direction: { x: 0, y: 0 }\n };\n\n // @zh 与左顶点碰撞\n // @en Collision with left vertex\n if (s < 0 && distSq1 <= radiusSq) {\n if (obstacle1.isConvex) {\n line.point = { x: 0, y: 0 };\n line.direction = normalize({ x: -relativePosition1.y, y: relativePosition1.x });\n orcaLines.push(line);\n numObstLines++;\n }\n continue;\n }\n\n // @zh 与右顶点碰撞\n // @en Collision with right vertex\n if (s > 1 && distSq2 <= radiusSq) {\n if (obstacle2.isConvex && det(relativePosition2, obstacle2.direction) >= 0) {\n line.point = { x: 0, y: 0 };\n line.direction = normalize({ x: -relativePosition2.y, y: relativePosition2.x });\n orcaLines.push(line);\n numObstLines++;\n }\n continue;\n }\n\n // @zh 与边碰撞\n // @en Collision with edge segment\n if (s >= 0 && s <= 1 && distSqLineToEdge <= radiusSq) {\n line.point = { x: 0, y: 0 };\n line.direction = { x: -obstacle1.direction.x, y: -obstacle1.direction.y };\n orcaLines.push(line);\n numObstLines++;\n continue;\n }\n\n // @zh 无碰撞 - 计算腿部方向\n // @en No collision - compute leg directions\n let obs1 = obstacle1;\n let obs2 = obstacle2;\n let leftLegDirection: IVector2;\n let rightLegDirection: IVector2;\n\n if (s < 0 && distSqLineToEdge <= radiusSq) {\n // @zh 从左顶点斜视\n // @en Obliquely viewed from left vertex\n if (!obstacle1.isConvex) continue;\n obs2 = obstacle1;\n\n const leg1 = Math.sqrt(Math.max(0, distSq1 - radiusSq));\n leftLegDirection = {\n x: (relativePosition1.x * leg1 - relativePosition1.y * agent.radius) / distSq1,\n y: (relativePosition1.x * agent.radius + relativePosition1.y * leg1) / distSq1\n };\n rightLegDirection = {\n x: (relativePosition1.x * leg1 + relativePosition1.y * agent.radius) / distSq1,\n y: (-relativePosition1.x * agent.radius + relativePosition1.y * leg1) / distSq1\n };\n } else if (s > 1 && distSqLineToEdge <= radiusSq) {\n // @zh 从右顶点斜视\n // @en Obliquely viewed from right vertex\n if (!obstacle2.isConvex) continue;\n obs1 = obstacle2;\n\n const leg2 = Math.sqrt(Math.max(0, distSq2 - radiusSq));\n leftLegDirection = {\n x: (relativePosition2.x * leg2 - relativePosition2.y * agent.radius) / distSq2,\n y: (relativePosition2.x * agent.radius + relativePosition2.y * leg2) / distSq2\n };\n rightLegDirection = {\n x: (relativePosition2.x * leg2 + relativePosition2.y * agent.radius) / distSq2,\n y: (-relativePosition2.x * agent.radius + relativePosition2.y * leg2) / distSq2\n };\n } else {\n // @zh 正常情况\n // @en Normal case\n if (obstacle1.isConvex) {\n const leg1 = Math.sqrt(Math.max(0, distSq1 - radiusSq));\n leftLegDirection = {\n x: (relativePosition1.x * leg1 - relativePosition1.y * agent.radius) / distSq1,\n y: (relativePosition1.x * agent.radius + relativePosition1.y * leg1) / distSq1\n };\n } else {\n leftLegDirection = { x: -obstacle1.direction.x, y: -obstacle1.direction.y };\n }\n\n if (obstacle2.isConvex) {\n const leg2 = Math.sqrt(Math.max(0, distSq2 - radiusSq));\n rightLegDirection = {\n x: (relativePosition2.x * leg2 + relativePosition2.y * agent.radius) / distSq2,\n y: (-relativePosition2.x * agent.radius + relativePosition2.y * leg2) / distSq2\n };\n } else {\n rightLegDirection = { x: obstacle1.direction.x, y: obstacle1.direction.y };\n }\n }\n\n // @zh 检查外部腿\n // @en Check for foreign legs\n const leftNeighbor = obs1.previous;\n let isLeftLegForeign = false;\n let isRightLegForeign = false;\n\n if (obs1.isConvex) {\n const negLeftNeighborDir = { x: -leftNeighbor.direction.x, y: -leftNeighbor.direction.y };\n if (det(leftLegDirection, negLeftNeighborDir) >= 0) {\n leftLegDirection = negLeftNeighborDir;\n isLeftLegForeign = true;\n }\n }\n\n if (obs2.isConvex) {\n if (det(rightLegDirection, obs2.direction) <= 0) {\n rightLegDirection = { x: obs2.direction.x, y: obs2.direction.y };\n isRightLegForeign = true;\n }\n }\n\n // @zh 计算截止中心点\n // @en Compute cut-off centers\n const leftCutoff: IVector2 = {\n x: invTimeHorizonObst * (obs1.point.x - agent.position.x),\n y: invTimeHorizonObst * (obs1.point.y - agent.position.y)\n };\n const rightCutoff: IVector2 = {\n x: invTimeHorizonObst * (obs2.point.x - agent.position.x),\n y: invTimeHorizonObst * (obs2.point.y - agent.position.y)\n };\n const cutoffVector: IVector2 = {\n x: rightCutoff.x - leftCutoff.x,\n y: rightCutoff.y - leftCutoff.y\n };\n\n const sameVertex = obs1 === obs2;\n const cutoffVectorSq = lengthSq(cutoffVector);\n const t = sameVertex\n ? 0.5\n : (cutoffVectorSq > EPSILON\n ? dot({ x: agent.velocity.x - leftCutoff.x, y: agent.velocity.y - leftCutoff.y }, cutoffVector) / cutoffVectorSq\n : 0.5);\n\n const tLeft = dot({ x: agent.velocity.x - leftCutoff.x, y: agent.velocity.y - leftCutoff.y }, leftLegDirection);\n const tRight = dot({ x: agent.velocity.x - rightCutoff.x, y: agent.velocity.y - rightCutoff.y }, rightLegDirection);\n\n // @zh 投影到左截止圆\n // @en Project on left cut-off circle\n if ((t < 0 && tLeft < 0) || (sameVertex && tLeft < 0 && tRight < 0)) {\n const unitW = normalize({ x: agent.velocity.x - leftCutoff.x, y: agent.velocity.y - leftCutoff.y });\n line.direction = { x: unitW.y, y: -unitW.x };\n line.point = {\n x: leftCutoff.x + agent.radius * invTimeHorizonObst * unitW.x,\n y: leftCutoff.y + agent.radius * invTimeHorizonObst * unitW.y\n };\n orcaLines.push(line);\n numObstLines++;\n continue;\n }\n\n // @zh 投影到右截止圆\n // @en Project on right cut-off circle\n if (t > 1 && tRight < 0) {\n const unitW = normalize({ x: agent.velocity.x - rightCutoff.x, y: agent.velocity.y - rightCutoff.y });\n line.direction = { x: unitW.y, y: -unitW.x };\n line.point = {\n x: rightCutoff.x + agent.radius * invTimeHorizonObst * unitW.x,\n y: rightCutoff.y + agent.radius * invTimeHorizonObst * unitW.y\n };\n orcaLines.push(line);\n numObstLines++;\n continue;\n }\n\n // @zh 计算投影距离\n // @en Compute projection distances\n const distSqCutoff = (t < 0 || t > 1 || sameVertex)\n ? Infinity\n : lengthSq({\n x: agent.velocity.x - (leftCutoff.x + t * cutoffVector.x),\n y: agent.velocity.y - (leftCutoff.y + t * cutoffVector.y)\n });\n\n const distSqLeft = tLeft < 0\n ? Infinity\n : lengthSq({\n x: agent.velocity.x - (leftCutoff.x + tLeft * leftLegDirection.x),\n y: agent.velocity.y - (leftCutoff.y + tLeft * leftLegDirection.y)\n });\n\n const distSqRight = tRight < 0\n ? Infinity\n : lengthSq({\n x: agent.velocity.x - (rightCutoff.x + tRight * rightLegDirection.x),\n y: agent.velocity.y - (rightCutoff.y + tRight * rightLegDirection.y)\n });\n\n // @zh 投影到截止线\n // @en Project on cut-off line\n if (distSqCutoff <= distSqLeft && distSqCutoff <= distSqRight) {\n line.direction = { x: -obs1.direction.x, y: -obs1.direction.y };\n line.point = {\n x: leftCutoff.x + agent.radius * invTimeHorizonObst * (-line.direction.y),\n y: leftCutoff.y + agent.radius * invTimeHorizonObst * line.direction.x\n };\n orcaLines.push(line);\n numObstLines++;\n continue;\n }\n\n // @zh 投影到左腿\n // @en Project on left leg\n if (distSqLeft <= distSqRight) {\n if (isLeftLegForeign) {\n continue;\n }\n\n line.direction = { x: leftLegDirection.x, y: leftLegDirection.y };\n line.point = {\n x: leftCutoff.x + agent.radius * invTimeHorizonObst * (-line.direction.y),\n y: leftCutoff.y + agent.radius * invTimeHorizonObst * line.direction.x\n };\n orcaLines.push(line);\n numObstLines++;\n continue;\n }\n\n // @zh 投影到右腿\n // @en Project on right leg\n if (isRightLegForeign) {\n continue;\n }\n\n line.direction = { x: -rightLegDirection.x, y: -rightLegDirection.y };\n line.point = {\n x: rightCutoff.x + agent.radius * invTimeHorizonObst * (-line.direction.y),\n y: rightCutoff.y + agent.radius * invTimeHorizonObst * line.direction.x\n };\n orcaLines.push(line);\n numObstLines++;\n }\n\n return numObstLines;\n }\n}\n\n/**\n * @zh 创建 ORCA 求解器\n * @en Create ORCA solver\n *\n * @param config - @zh 可选配置参数 @en Optional configuration parameters\n * @returns @zh ORCA 求解器实例 @en ORCA solver instance\n */\nexport function createORCASolver(config?: IORCASolverConfig): ORCASolver {\n return new ORCASolver(config);\n}\n","/**\n * @zh KD-Tree 空间索引\n * @en KD-Tree Spatial Index\n *\n * @zh 用于快速查询指定范围内的邻近代理\n * @en Used for fast neighbor queries within specified range\n */\n\nimport type { IVector2 } from '@esengine/ecs-framework-math';\nimport type { IAvoidanceAgent, ISpatialIndex, INeighborResult } from './ILocalAvoidance';\n\n// =============================================================================\n// KD-Tree 节点 | KD-Tree Node\n// =============================================================================\n\n/**\n * @zh KD-Tree 节点\n * @en KD-Tree node\n */\ninterface KDTreeNode {\n /**\n * @zh 代理索引(叶节点)或分割维度(内部节点)\n * @en Agent index (leaf) or split dimension (internal node)\n */\n agentIndex: number;\n\n /**\n * @zh 分割值\n * @en Split value\n */\n splitValue: number;\n\n /**\n * @zh 左子节点索引\n * @en Left child index\n */\n left: number;\n\n /**\n * @zh 右子节点索引\n * @en Right child index\n */\n right: number;\n\n /**\n * @zh 子树中代理索引的起始位置\n * @en Start index of agents in subtree\n */\n begin: number;\n\n /**\n * @zh 子树中代理索引的结束位置\n * @en End index of agents in subtree\n */\n end: number;\n\n /**\n * @zh 边界框最小值\n * @en Bounding box minimum\n */\n minX: number;\n minY: number;\n\n /**\n * @zh 边界框最大值\n * @en Bounding box maximum\n */\n maxX: number;\n maxY: number;\n}\n\n// =============================================================================\n// KD-Tree 实现 | KD-Tree Implementation\n// =============================================================================\n\n/**\n * @zh KD-Tree 空间索引\n * @en KD-Tree spatial index\n *\n * @zh 每帧重建,支持高效的范围查询\n * @en Rebuilt every frame, supports efficient range queries\n */\nexport class KDTree implements ISpatialIndex {\n private agents: IAvoidanceAgent[] = [];\n private agentIndices: number[] = [];\n private nodes: KDTreeNode[] = [];\n\n /**\n * @zh 最大叶节点大小\n * @en Maximum leaf size\n */\n private readonly maxLeafSize = 10;\n\n /**\n * @zh 构建 KD-Tree\n * @en Build KD-Tree\n */\n build(agents: readonly IAvoidanceAgent[]): void {\n this.agents = agents as IAvoidanceAgent[];\n this.agentIndices = [];\n this.nodes = [];\n\n if (agents.length === 0) {\n return;\n }\n\n // 初始化代理索引数组\n for (let i = 0; i < agents.length; i++) {\n this.agentIndices.push(i);\n }\n\n // 递归构建树\n this.buildRecursive(0, agents.length, 0);\n }\n\n /**\n * @zh 递归构建 KD-Tree\n * @en Recursively build KD-Tree\n */\n private buildRecursive(begin: number, end: number, depth: number): number {\n const nodeIndex = this.nodes.length;\n\n const node: KDTreeNode = {\n agentIndex: -1,\n splitValue: 0,\n left: -1,\n right: -1,\n begin,\n end,\n minX: Infinity,\n minY: Infinity,\n maxX: -Infinity,\n maxY: -Infinity\n };\n\n this.nodes.push(node);\n\n // 计算边界框\n for (let i = begin; i < end; i++) {\n const agent = this.agents[this.agentIndices[i]!]!;\n node.minX = Math.min(node.minX, agent.position.x);\n node.minY = Math.min(node.minY, agent.position.y);\n node.maxX = Math.max(node.maxX, agent.position.x);\n node.maxY = Math.max(node.maxY, agent.position.y);\n }\n\n const count = end - begin;\n\n if (count <= this.maxLeafSize) {\n // 叶节点\n return nodeIndex;\n }\n\n // 选择分割维度(交替使用 x 和 y)\n const splitDim = depth % 2;\n\n // 按分割维度排序\n if (splitDim === 0) {\n this.sortByX(begin, end);\n } else {\n this.sortByY(begin, end);\n }\n\n // 找到中点\n const mid = Math.floor((begin + end) / 2);\n const midAgent = this.agents[this.agentIndices[mid]!]!;\n node.splitValue = splitDim === 0 ? midAgent.position.x : midAgent.position.y;\n\n // 递归构建子树\n node.left = this.buildRecursive(begin, mid, depth + 1);\n node.right = this.buildRecursive(mid, end, depth + 1);\n\n return nodeIndex;\n }\n\n /**\n * @zh 按 X 坐标排序\n * @en Sort by X coordinate\n */\n private sortByX(begin: number, end: number): void {\n const indices = this.agentIndices;\n const agents = this.agents;\n\n for (let i = begin + 1; i < end; i++) {\n const key = indices[i]!;\n const keyX = agents[key]!.position.x;\n let j = i - 1;\n\n while (j >= begin && agents[indices[j]!]!.position.x > keyX) {\n indices[j + 1] = indices[j]!;\n j--;\n }\n indices[j + 1] = key;\n }\n }\n\n /**\n * @zh 按 Y 坐标排序\n * @en Sort by Y coordinate\n */\n private sortByY(begin: number, end: number): void {\n const indices = this.agentIndices;\n const agents = this.agents;\n\n for (let i = begin + 1; i < end; i++) {\n const key = indices[i]!;\n const keyY = agents[key]!.position.y;\n let j = i - 1;\n\n while (j >= begin && agents[indices[j]!]!.position.y > keyY) {\n indices[j + 1] = indices[j]!;\n j--;\n }\n indices[j + 1] = key;\n }\n }\n\n /**\n * @zh 查询邻居\n * @en Query neighbors\n */\n queryNeighbors(\n position: IVector2,\n radius: number,\n maxResults: number,\n excludeId?: number\n ): INeighborResult[] {\n const results: INeighborResult[] = [];\n const radiusSq = radius * radius;\n\n if (this.nodes.length === 0) {\n return results;\n }\n\n this.queryRecursive(0, position, radiusSq, maxResults, excludeId, results);\n\n // 按距离排序\n results.sort((a, b) => a.distanceSq - b.distanceSq);\n\n // 截取最大数量\n if (results.length > maxResults) {\n results.length = maxResults;\n }\n\n return results;\n }\n\n /**\n * @zh 递归查询\n * @en Recursive query\n */\n private queryRecursive(\n nodeIndex: number,\n position: IVector2,\n radiusSq: number,\n maxResults: number,\n excludeId: number | undefined,\n results: INeighborResult[]\n ): void {\n const node = this.nodes[nodeIndex];\n if (!node) return;\n\n // 检查边界框是否与查询圆相交\n const closestX = Math.max(node.minX, Math.min(position.x, node.maxX));\n const closestY = Math.max(node.minY, Math.min(position.y, node.maxY));\n const dx = position.x - closestX;\n const dy = position.y - closestY;\n const distSqToBBox = dx * dx + dy * dy;\n\n if (distSqToBBox > radiusSq) {\n return;\n }\n\n // 叶节点:检查所有代理\n if (node.left === -1 && node.right === -1) {\n for (let i = node.begin; i < node.end; i++) {\n const agentIndex = this.agentIndices[i]!;\n const agent = this.agents[agentIndex]!;\n\n if (excludeId !== undefined && agent.id === excludeId) {\n continue;\n }\n\n const adx = position.x - agent.position.x;\n const ady = position.y - agent.position.y;\n const distSq = adx * adx + ady * ady;\n\n if (distSq < radiusSq) {\n results.push({ agent, distanceSq: distSq });\n }\n }\n return;\n }\n\n // 递归查询子节点\n if (node.left !== -1) {\n this.queryRecursive(node.left, position, radiusSq, maxResults, excludeId, results);\n }\n if (node.right !== -1) {\n this.queryRecursive(node.right, position, radiusSq, maxResults, excludeId, results);\n }\n }\n\n /**\n * @zh 清空索引\n * @en Clear the index\n */\n clear(): void {\n this.agents = [];\n this.agentIndices = [];\n this.nodes = [];\n }\n\n /**\n * @zh 获取代理数量\n * @en Get agent count\n */\n get agentCount(): number {\n return this.agents.length;\n }\n}\n\n/**\n * @zh 创建 KD-Tree\n * @en Create KD-Tree\n */\nexport function createKDTree(): KDTree {\n return new KDTree();\n}\n","/**\n * @zh 碰撞解决器\n * @en Collision Resolver\n *\n * @zh 提供位置级别的硬碰撞检测和解决,作为 ORCA 的补充保护层\n * @en Provides position-level hard collision detection and resolution as a supplementary protection layer for ORCA\n */\n\nimport type { IVector2 } from '@esengine/ecs-framework-math';\nimport type { IObstacle } from './ILocalAvoidance';\n\nconst EPSILON = 0.00001;\n\n// =============================================================================\n// 碰撞检测结果 | Collision Detection Result\n// =============================================================================\n\n/**\n * @zh 碰撞检测结果\n * @en Collision detection result\n */\nexport interface ICollisionResult {\n /**\n * @zh 是否发生碰撞\n * @en Whether collision occurred\n */\n collided: boolean;\n\n /**\n * @zh 穿透深度\n * @en Penetration depth\n */\n penetration: number;\n\n /**\n * @zh 碰撞法线(从障碍物指向代理)\n * @en Collision normal (pointing from obstacle to agent)\n */\n normal: IVector2;\n\n /**\n * @zh 最近点\n * @en Closest point on obstacle\n */\n closestPoint: IVector2;\n}\n\n/**\n * @zh 空碰撞结果\n * @en Empty collision result\n */\nexport const EMPTY_COLLISION: ICollisionResult = {\n collided: false,\n penetration: 0,\n normal: { x: 0, y: 0 },\n closestPoint: { x: 0, y: 0 }\n};\n\n// =============================================================================\n// 几何工具函数 | Geometry Utilities\n// =============================================================================\n\n/**\n * @zh 计算点到线段的最近点\n * @en Calculate closest point on line segment to a point\n */\nfunction closestPointOnSegment(\n point: IVector2,\n segStart: IVector2,\n segEnd: IVector2\n): IVector2 {\n const dx = segEnd.x - segStart.x;\n const dy = segEnd.y - segStart.y;\n const lengthSq = dx * dx + dy * dy;\n\n if (lengthSq < EPSILON) {\n return { x: segStart.x, y: segStart.y };\n }\n\n const t = Math.max(0, Math.min(1,\n ((point.x - segStart.x) * dx + (point.y - segStart.y) * dy) / lengthSq\n ));\n\n return {\n x: segStart.x + t * dx,\n y: segStart.y + t * dy\n };\n}\n\n/**\n * @zh 检查点是否在多边形内(射线法)\n * @en Check if point is inside polygon (ray casting)\n */\nfunction isPointInPolygon(point: IVector2, vertices: readonly IVector2[]): 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 > point.y !== yj > point.y &&\n point.x < ((xj - xi) * (point.y - yi)) / (yj - yi) + xi\n ) {\n inside = !inside;\n }\n }\n\n return inside;\n}\n\n/**\n * @zh 计算点到多边形的最近点和距离\n * @en Calculate closest point on polygon and distance to point\n */\nfunction closestPointOnPolygon(\n point: IVector2,\n vertices: readonly IVector2[]\n): { point: IVector2; distanceSq: number; edgeIndex: number } {\n let minDistSq = Infinity;\n let closestPt: IVector2 = { x: 0, y: 0 };\n let closestEdge = 0;\n\n for (let i = 0; i < vertices.length; i++) {\n const j = (i + 1) % vertices.length;\n const closest = closestPointOnSegment(point, vertices[i]!, vertices[j]!);\n const dx = point.x - closest.x;\n const dy = point.y - closest.y;\n const distSq = dx * dx + dy * dy;\n\n if (distSq < minDistSq) {\n minDistSq = distSq;\n closestPt = closest;\n closestEdge = i;\n }\n }\n\n return { point: closestPt, distanceSq: minDistSq, edgeIndex: closestEdge };\n}\n\n// =============================================================================\n// 碰撞解决器 | Collision Resolver\n// =============================================================================\n\n/**\n * @zh 碰撞解决器配置\n * @en Collision resolver configuration\n */\nexport interface ICollisionResolverConfig {\n /**\n * @zh 碰撞响应系数(0-1,1 表示完全推出)\n * @en Collision response factor (0-1, 1 means fully push out)\n */\n responseFactor?: number;\n\n /**\n * @zh 安全边距(额外距离)\n * @en Safety margin (extra distance)\n */\n safetyMargin?: number;\n}\n\n/**\n * @zh 默认配置\n * @en Default configuration\n */\nexport const DEFAULT_COLLISION_CONFIG: Required<ICollisionResolverConfig> = {\n responseFactor: 1.0,\n safetyMargin: 0.01\n};\n\n/**\n * @zh 碰撞解决器\n * @en Collision Resolver\n *\n * @zh 提供位置级别的硬碰撞检测和解决\n * @en Provides position-level hard collision detection and resolution\n */\nexport class CollisionResolver {\n private readonly config: Required<ICollisionResolverConfig>;\n\n constructor(config: ICollisionResolverConfig = {}) {\n this.config = { ...DEFAULT_COLLISION_CONFIG, ...config };\n }\n\n /**\n * @zh 检测圆与单个障碍物的碰撞\n * @en Detect collision between circle and single obstacle\n *\n * @param position - @zh 圆心位置 @en Circle center position\n * @param radius - @zh 圆半径 @en Circle radius\n * @param obstacle - @zh 障碍物 @en Obstacle\n * @returns @zh 碰撞结果 @en Collision result\n */\n detectCollision(\n position: IVector2,\n radius: number,\n obstacle: IObstacle\n ): ICollisionResult {\n const vertices = obstacle.vertices;\n if (vertices.length < 3) {\n return EMPTY_COLLISION;\n }\n\n const isInside = isPointInPolygon(position, vertices);\n const closest = closestPointOnPolygon(position, vertices);\n const distance = Math.sqrt(closest.distanceSq);\n\n let penetration: number;\n let normalX: number;\n let normalY: number;\n\n if (isInside) {\n penetration = radius + distance;\n const dx = closest.point.x - position.x;\n const dy = closest.point.y - position.y;\n const len = Math.sqrt(dx * dx + dy * dy);\n if (len > EPSILON) {\n normalX = dx / len;\n normalY = dy / len;\n } else {\n normalX = 1;\n normalY = 0;\n }\n } else if (distance < radius) {\n penetration = radius - distance;\n const dx = position.x - closest.point.x;\n const dy = position.y - closest.point.y;\n const len = Math.sqrt(dx * dx + dy * dy);\n if (len > EPSILON) {\n normalX = dx / len;\n normalY = dy / len;\n } else {\n normalX = 1;\n normalY = 0;\n }\n } else {\n return EMPTY_COLLISION;\n }\n\n return {\n collided: true,\n penetration,\n normal: { x: normalX, y: normalY },\n closestPoint: closest.point\n };\n }\n\n /**\n * @zh 检测圆与所有障碍物的碰撞\n * @en Detect collision between circle and all obstacles\n *\n * @param position - @zh 圆心位置 @en Circle center position\n * @param radius - @zh 圆半径 @en Circle radius\n * @param obstacles - @zh 障碍物列表 @en List of obstacles\n * @returns @zh 最严重的碰撞结果 @en Most severe collision result\n */\n detectCollisions(\n position: IVector2,\n radius: number,\n obstacles: readonly IObstacle[]\n ): ICollisionResult {\n let worstCollision = EMPTY_COLLISION;\n let maxPenetration = 0;\n\n for (const obstacle of obstacles) {\n const collision = this.detectCollision(position, radius, obstacle);\n if (collision.collided && collision.penetration > maxPenetration) {\n maxPenetration = collision.penetration;\n worstCollision = collision;\n }\n }\n\n return worstCollision;\n }\n\n /**\n * @zh 解决碰撞,返回修正后的位置\n * @en Resolve collision, return corrected position\n *\n * @param position - @zh 当前位置 @en Current position\n * @param radius - @zh 半径 @en Radius\n * @param obstacles - @zh 障碍物列表 @en List of obstacles\n * @returns @zh 修正后的位置 @en Corrected position\n */\n resolveCollision(\n position: IVector2,\n radius: number,\n obstacles: readonly IObstacle[]\n ): IVector2 {\n const result = { x: position.x, y: position.y };\n const maxIterations = 4;\n\n for (let iter = 0; iter < maxIterations; iter++) {\n const collision = this.detectCollisions(result, radius, obstacles);\n\n if (!collision.collided) {\n break;\n }\n\n const pushDistance = (collision.penetration + this.config.safetyMargin) * this.config.responseFactor;\n result.x += collision.normal.x * pushDistance;\n result.y += collision.normal.y * pushDistance;\n }\n\n return result;\n }\n\n /**\n * @zh 验证速度是否会导致碰撞,返回安全速度\n * @en Validate velocity won't cause collision, return safe velocity\n *\n * @param position - @zh 当前位置 @en Current position\n * @param velocity - @zh 目标速度 @en Target velocity\n * @param radius - @zh 半径 @en Radius\n * @param obstacles - @zh 障碍物列表 @en List of obstacles\n * @param deltaTime - @zh 时间步长 @en Time step\n * @returns @zh 安全速度 @en Safe velocity\n */\n validateVelocity(\n position: IVector2,\n velocity: IVector2,\n radius: number,\n obstacles: readonly IObstacle[],\n deltaTime: number\n ): IVector2 {\n const speed = Math.sqrt(velocity.x * velocity.x + velocity.y * velocity.y);\n if (speed < EPSILON) {\n return velocity;\n }\n\n const newPos = {\n x: position.x + velocity.x * deltaTime,\n y: position.y + velocity.y * deltaTime\n };\n\n const collision = this.detectCollisions(newPos, radius, obstacles);\n\n if (!collision.collided) {\n return velocity;\n }\n\n const dotProduct = velocity.x * collision.normal.x + velocity.y * collision.normal.y;\n\n if (dotProduct >= 0) {\n return velocity;\n }\n\n // 移除朝向障碍物的速度分量,沿障碍物边缘滑动\n const slideVelocity = {\n x: velocity.x - dotProduct * collision.normal.x,\n y: velocity.y - dotProduct * collision.normal.y\n };\n\n // 检查滑动速度是否太小(几乎垂直撞向障碍物)\n const slideSpeed = Math.sqrt(slideVelocity.x * slideVelocity.x + slideVelocity.y * slideVelocity.y);\n if (slideSpeed < speed * 0.1) {\n // 速度几乎完全朝向障碍物角落,选择沿障碍物边缘滑动的方向\n // 计算垂直于法线的两个方向\n const perpDir1 = { x: -collision.normal.y, y: collision.normal.x };\n const perpDir2 = { x: collision.normal.y, y: -collision.normal.x };\n\n // 选择与原速度方向夹角较小的方向(点积较大)\n const dot1 = velocity.x * perpDir1.x + velocity.y * perpDir1.y;\n const dot2 = velocity.x * perpDir2.x + velocity.y * perpDir2.y;\n const chosenDir = dot1 >= dot2 ? perpDir1 : perpDir2;\n\n // 返回沿障碍物边缘的速度,保持原速度大小\n return {\n x: chosenDir.x * speed,\n y: chosenDir.y * speed\n };\n }\n\n return slideVelocity;\n }\n\n /**\n * @zh 检测两个代理之间的碰撞\n * @en Detect collision between two agents\n *\n * @param posA - @zh 代理 A 位置 @en Agent A position\n * @param radiusA - @zh 代理 A 半径 @en Agent A radius\n * @param posB - @zh 代理 B 位置 @en Agent B position\n * @param radiusB - @zh 代理 B 半径 @en Agent B radius\n * @returns @zh 碰撞结果 @en Collision result\n */\n detectAgentCollision(\n posA: IVector2,\n radiusA: number,\n posB: IVector2,\n radiusB: number\n ): ICollisionResult {\n const dx = posB.x - posA.x;\n const dy = posB.y - posA.y;\n const distSq = dx * dx + dy * dy;\n const combinedRadius = radiusA + radiusB;\n\n if (distSq >= combinedRadius * combinedRadius) {\n return EMPTY_COLLISION;\n }\n\n const distance = Math.sqrt(distSq);\n const penetration = combinedRadius - distance;\n\n let normalX: number, normalY: number;\n if (distance > EPSILON) {\n normalX = -dx / distance;\n normalY = -dy / distance;\n } else {\n normalX = 1;\n normalY = 0;\n }\n\n return {\n collided: true,\n penetration,\n normal: { x: normalX, y: normalY },\n closestPoint: {\n x: posA.x + normalX * radiusA,\n y: posA.y + normalY * radiusA\n }\n };\n }\n\n /**\n * @zh 解决代理之间的碰撞\n * @en Resolve collision between agents\n *\n * @param posA - @zh 代理 A 位置 @en Agent A position\n * @param radiusA - @zh 代理 A 半径 @en Agent A radius\n * @param posB - @zh 代理 B 位置 @en Agent B position\n * @param radiusB - @zh 代理 B 半径 @en Agent B radius\n * @returns @zh 修正后的位置 [A, B] @en Corrected positions [A, B]\n */\n resolveAgentCollision(\n posA: IVector2,\n radiusA: number,\n posB: IVector2,\n radiusB: number\n ): [IVector2, IVector2] {\n const collision = this.detectAgentCollision(posA, radiusA, posB, radiusB);\n\n if (!collision.collided) {\n return [posA, posB];\n }\n\n const halfPush = (collision.penetration + this.config.safetyMargin) * 0.5 * this.config.responseFactor;\n\n return [\n {\n x: posA.x + collision.normal.x * halfPush,\n y: posA.y + collision.normal.y * halfPush\n },\n {\n x: posB.x - collision.normal.x * halfPush,\n y: posB.y - collision.normal.y * halfPush\n }\n ];\n }\n}\n\n/**\n * @zh 创建碰撞解决器\n * @en Create collision resolver\n */\nexport function createCollisionResolver(config?: ICollisionResolverConfig): CollisionResolver {\n return new CollisionResolver(config);\n}\n"],"mappings":";;;;;;AAiWO,IAAMA,sBAAmD;EAC5DC,oBAAoB;EACpBC,wBAAwB;EACxBC,UAAU,IAAI;EACdC,SAAS;EACTC,WAAW;AACf;AAMO,IAAMC,uBAAuB;EAChCC,QAAQ;EACRC,UAAU;EACVC,cAAc;EACdC,cAAc;EACdC,aAAa;EACbC,iBAAiB;AACrB;;;AC5WA,SAASC,eAA8B;AAWvC,IAAMC,UAAU;AAEhB,IAAM,EAAEC,KAAKC,KAAKC,SAAQ,IAAKC;AAqB/B,SAASC,eACLC,OACAC,QACAC,QACAC,aACAC,cACAC,QAAe;AAEf,QAAMC,OAAON,MAAMC,MAAAA;AACnB,QAAMM,aAAaZ,IAAIW,KAAKE,OAAOF,KAAKG,SAAS;AACjD,QAAMC,eAAeH,aAAaA,aAAaL,SAASA,SAASL,SAASS,KAAKE,KAAK;AAEpF,MAAIE,eAAe,GAAG;AAClB,WAAO;EACX;AAEA,QAAMC,mBAAmBC,KAAKC,KAAKH,YAAAA;AACnC,MAAII,QAAQ,CAACP,aAAaI;AAC1B,MAAII,SAAS,CAACR,aAAaI;AAE3B,WAASK,IAAI,GAAGA,IAAIf,QAAQe,KAAK;AAC7B,UAAMC,aAAajB,MAAMgB,CAAAA;AACzB,UAAME,cAActB,IAAIU,KAAKG,WAAWQ,WAAWR,SAAS;AAC5D,UAAMU,YAAYvB,IAAIqB,WAAWR,WAAW;MACxCW,GAAGd,KAAKE,MAAMY,IAAIH,WAAWT,MAAMY;MACnCC,GAAGf,KAAKE,MAAMa,IAAIJ,WAAWT,MAAMa;IACvC,CAAA;AAEA,QAAIT,KAAKU,IAAIJ,WAAAA,KAAgBxB,SAAS;AAClC,UAAIyB,YAAY,GAAG;AACf,eAAO;MACX;AACA;IACJ;AAEA,UAAMI,KAAIJ,YAAYD;AAEtB,QAAIA,eAAe,GAAG;AAClBH,eAASH,KAAKY,IAAIT,QAAQQ,EAAAA;IAC9B,OAAO;AACHT,cAAQF,KAAKa,IAAIX,OAAOS,EAAAA;IAC5B;AAEA,QAAIT,QAAQC,QAAQ;AAChB,aAAO;IACX;EACJ;AAEA,MAAIQ;AACJ,MAAInB,cAAc;AACd,QAAIT,IAAIQ,aAAaG,KAAKG,SAAS,IAAI,GAAG;AACtCc,UAAIR;IACR,OAAO;AACHQ,UAAIT;IACR;EACJ,OAAO;AACHS,QAAI5B,IAAIW,KAAKG,WAAW;MACpBW,GAAGjB,YAAYiB,IAAId,KAAKE,MAAMY;MAC9BC,GAAGlB,YAAYkB,IAAIf,KAAKE,MAAMa;IAClC,CAAA;AAEA,QAAIE,IAAIT,OAAO;AACXS,UAAIT;IACR,WAAWS,IAAIR,QAAQ;AACnBQ,UAAIR;IACR;EACJ;AAEAV,SAAOe,IAAId,KAAKE,MAAMY,IAAIG,IAAIjB,KAAKG,UAAUW;AAC7Cf,SAAOgB,IAAIf,KAAKE,MAAMa,IAAIE,IAAIjB,KAAKG,UAAUY;AAE7C,SAAO;AACX;AAxEStB;AAwFF,SAAS2B,eACZ1B,OACAE,QACAC,aACAC,cACAC,QAAe;AAEf,MAAID,cAAc;AACdC,WAAOe,IAAIjB,YAAYiB,IAAIlB;AAC3BG,WAAOgB,IAAIlB,YAAYkB,IAAInB;EAC/B,WAAWL,SAASM,WAAAA,IAAeD,SAASA,QAAQ;AAChD,UAAMyB,OAAMf,KAAKC,KAAKhB,SAASM,WAAAA,CAAAA;AAC/BE,WAAOe,IAAIjB,YAAYiB,IAAIO,OAAMzB;AACjCG,WAAOgB,IAAIlB,YAAYkB,IAAIM,OAAMzB;EACrC,OAAO;AACHG,WAAOe,IAAIjB,YAAYiB;AACvBf,WAAOgB,IAAIlB,YAAYkB;EAC3B;AAEA,WAASL,IAAI,GAAGA,IAAIhB,MAAM4B,QAAQZ,KAAK;AACnC,UAAMV,OAAON,MAAMgB,CAAAA;AACnB,UAAMa,SAASjC,IAAIU,KAAKG,WAAW;MAAEW,GAAGd,KAAKE,MAAMY,IAAIf,OAAOe;MAAGC,GAAGf,KAAKE,MAAMa,IAAIhB,OAAOgB;IAAE,CAAA;AAC5F,QAAIQ,SAAS,GAAG;AACZ,YAAMC,aAAazB,OAAO0B,MAAK;AAC/B,UAAI,CAAChC,eAAeC,OAAOgB,GAAGd,QAAQC,aAAaC,cAAcC,MAAAA,GAAS;AACtEA,eAAO2B,KAAKF,UAAAA;AACZ,eAAOd;MACX;IACJ;EACJ;AAEA,SAAOhB,MAAM4B;AACjB;AAhCgBF;AAkDT,SAASO,eACZjC,OACAkC,cACAC,WACAjC,QACAG,QAAe;AAEf,MAAI+B,WAAW;AAEf,WAASpB,IAAImB,WAAWnB,IAAIhB,MAAM4B,QAAQZ,KAAK;AAC3C,UAAMV,OAAON,MAAMgB,CAAAA;AACnB,QAAIpB,IAAIU,KAAKG,WAAW;MAAEW,GAAGd,KAAKE,MAAMY,IAAIf,OAAOe;MAAGC,GAAGf,KAAKE,MAAMa,IAAIhB,OAAOgB;IAAE,CAAA,IAAKe,UAAU;AAC5F,YAAMC,YAAyB,CAAA;AAE/B,eAASC,IAAI,GAAGA,IAAIJ,cAAcI,KAAK;AACnCD,kBAAUE,KAAKvC,MAAMsC,CAAAA,CAAE;MAC3B;AAEA,eAASA,IAAIJ,cAAcI,IAAItB,GAAGsB,KAAK;AACnC,cAAME,QAAQxC,MAAMsC,CAAAA;AACpB,cAAMG,QAAQzC,MAAMgB,CAAAA;AAEpB,YAAI0B;AACJ,cAAMC,cAAc/C,IAAI4C,MAAM/B,WAAWgC,MAAMhC,SAAS;AAExD,YAAIG,KAAKU,IAAIqB,WAAAA,KAAgBjD,SAAS;AAClC,cAAIC,IAAI6C,MAAM/B,WAAWgC,MAAMhC,SAAS,IAAI,GAAG;AAC3C;UACJ;AAEAiC,oBAAU;YACNlC,OAAO;cACHY,GAAG,OAAOoB,MAAMhC,MAAMY,IAAIqB,MAAMjC,MAAMY;cACtCC,GAAG,OAAOmB,MAAMhC,MAAMa,IAAIoB,MAAMjC,MAAMa;YAC1C;YACAZ,WAAW;cAAEW,GAAG;cAAGC,GAAG;YAAE;UAC5B;QACJ,OAAO;AACH,gBAAMuB,OAAO;YACTxB,GAAGoB,MAAMhC,MAAMY,IAAIqB,MAAMjC,MAAMY;YAC/BC,GAAGmB,MAAMhC,MAAMa,IAAIoB,MAAMjC,MAAMa;UACnC;AACA,gBAAME,IAAI3B,IAAI6C,MAAMhC,WAAWmC,IAAAA,IAAQD;AAEvCD,oBAAU;YACNlC,OAAO;cACHY,GAAGoB,MAAMhC,MAAMY,IAAIG,IAAIiB,MAAM/B,UAAUW;cACvCC,GAAGmB,MAAMhC,MAAMa,IAAIE,IAAIiB,MAAM/B,UAAUY;YAC3C;YACAZ,WAAW;cAAEW,GAAG;cAAGC,GAAG;YAAE;UAC5B;QACJ;AAEA,cAAMwB,UAAU;UACZzB,GAAGoB,MAAM/B,UAAUW,IAAIqB,MAAMhC,UAAUW;UACvCC,GAAGmB,MAAM/B,UAAUY,IAAIoB,MAAMhC,UAAUY;QAC3C;AACA,cAAMyB,SAASlC,KAAKC,KAAKhB,SAASgD,OAAAA,CAAAA;AAClC,YAAIC,SAASpD,SAAS;AAClBgD,kBAAQjC,UAAUW,IAAIyB,QAAQzB,IAAI0B;AAClCJ,kBAAQjC,UAAUY,IAAIwB,QAAQxB,IAAIyB;QACtC;AAEAT,kBAAUE,KAAKG,OAAAA;MACnB;AAEA,YAAMZ,aAAazB,OAAO0B,MAAK;AAC/B,YAAM5B,cAAc;QAAEiB,GAAG,CAACpB,MAAMgB,CAAAA,EAAIP,UAAUY;QAAGA,GAAGrB,MAAMgB,CAAAA,EAAIP,UAAUW;MAAE;AAE1E,UAAIM,eAAeW,WAAWnC,QAAQC,aAAa,MAAME,MAAAA,IAAUgC,UAAUT,QAAQ;AACjFvB,eAAO2B,KAAKF,UAAAA;MAChB;AAIA,UAAI,CAACiB,0BAA0B/C,OAAOkC,cAAc7B,MAAAA,GAAS;AACzDA,eAAO2B,KAAKF,UAAAA;MAChB;AAEAM,iBAAWxC,IAAII,MAAMgB,CAAAA,EAAIP,WAAW;QAChCW,GAAGpB,MAAMgB,CAAAA,EAAIR,MAAMY,IAAIf,OAAOe;QAC9BC,GAAGrB,MAAMgB,CAAAA,EAAIR,MAAMa,IAAIhB,OAAOgB;MAClC,CAAA;IACJ;EACJ;AACJ;AArFgBY;AA2FhB,SAASc,0BACL/C,OACAkC,cACAc,UAAkB;AAElB,WAAShC,IAAI,GAAGA,IAAIkB,cAAclB,KAAK;AACnC,UAAMV,OAAON,MAAMgB,CAAAA;AACnB,UAAMa,SAASjC,IAAIU,KAAKG,WAAW;MAC/BW,GAAGd,KAAKE,MAAMY,IAAI4B,SAAS5B;MAC3BC,GAAGf,KAAKE,MAAMa,IAAI2B,SAAS3B;IAC/B,CAAA;AACA,QAAIQ,SAASnC,SAAS;AAClB,aAAO;IACX;EACJ;AACA,SAAO;AACX;AAhBSqD;AA0DF,SAASE,uBACZjD,OACAkC,cACAgB,UACAC,mBAA2B;AAE3B,QAAM9C,SAAS,IAAIP,QAAAA;AAEnB,QAAMsD,WAAW1B,eAAe1B,OAAOkD,UAAUC,mBAAmB,OAAO9C,MAAAA;AAE3E,MAAIgD,WAAWD,YAAYpD,MAAM4B;AACjC,MAAI0B,sBAAsB;AAE1B,MAAI,CAACD,UAAU;AACXpB,mBAAejC,OAAOkC,cAAckB,UAAUF,UAAU7C,MAAAA;AACxDiD,0BAAsBtD,MAAM4B,SAASwB;EACzC;AAIA,MAAIlB,eAAe,KAAK,CAACa,0BAA0B/C,OAAOkC,cAAc7B,MAAAA,GAAS;AAC7EgD,eAAW;AACXC,0BAAsB1C,KAAKa,IAAI6B,qBAAqB,CAAA;EACxD;AAEA,SAAO;IACHN,UAAU3C;IACVgD;IACAC;EACJ;AACJ;AA9BgBL;;;ACjUhB,IAAMM,WAAU;AAYhB,SAASC,OAAOC,IAAcC,IAAcC,IAAY;AACpD,UAAQF,GAAGG,IAAID,GAAGC,MAAMF,GAAGG,IAAIJ,GAAGI,MAAMJ,GAAGI,IAAIF,GAAGE,MAAMH,GAAGE,IAAIH,GAAGG;AACtE;AAFSJ;AAWF,SAASM,uBACZC,UACAC,UAAkB,GAAC;AAEnB,QAAMC,IAAIF,SAASG;AACnB,MAAID,IAAI,GAAG;AACP,WAAO,CAAA;EACX;AAEA,QAAME,mBAAsC,CAAA;AAC5C,WAASC,IAAI,GAAGA,IAAIH,GAAGG,KAAK;AACxBD,qBAAiBE,KAAK;MAClBC,OAAO;QAAEV,GAAGG,SAASK,CAAAA,EAAIR;QAAGC,GAAGE,SAASK,CAAAA,EAAIP;MAAE;MAC9CU,WAAW;QAAEX,GAAG;QAAGC,GAAG;MAAE;MACxBW,MAAM;MACNC,UAAU;MACVC,UAAU;MACVC,IAAIX,UAAUI;IAClB,CAAA;EACJ;AAEA,WAASA,IAAI,GAAGA,IAAIH,GAAGG,KAAK;AACxB,UAAMQ,OAAOT,iBAAiBC,CAAAA;AAC9B,UAAMI,OAAOL,kBAAkBC,IAAI,KAAKH,CAAAA;AACxC,UAAMY,OAAOV,kBAAkBC,IAAIH,IAAI,KAAKA,CAAAA;AAE5CW,SAAKJ,OAAOA;AACZI,SAAKH,WAAWI;AAEhB,UAAMC,KAAKN,KAAKF,MAAMV,IAAIgB,KAAKN,MAAMV;AACrC,UAAMmB,KAAKP,KAAKF,MAAMT,IAAIe,KAAKN,MAAMT;AACrC,UAAMmB,UAAUC,KAAKC,KAAKJ,KAAKA,KAAKC,KAAKA,EAAAA;AAEzC,QAAIC,UAAUzB,UAAS;AACnBqB,WAAKL,YAAY;QAAEX,GAAGkB,KAAKE;QAASnB,GAAGkB,KAAKC;MAAQ;IACxD,OAAO;AACHJ,WAAKL,YAAY;QAAEX,GAAG;QAAGC,GAAG;MAAE;IAClC;EACJ;AAEA,WAASO,IAAI,GAAGA,IAAIH,GAAGG,KAAK;AACxB,UAAMQ,OAAOT,iBAAiBC,CAAAA;AAC9B,UAAMS,OAAOD,KAAKH;AAClB,UAAMD,OAAOI,KAAKJ;AAClBI,SAAKF,WAAWlB,OAAOqB,KAAKP,OAAOM,KAAKN,OAAOE,KAAKF,KAAK,KAAK;EAClE;AAEA,SAAOH;AACX;AAhDgBL;AA6ET,SAASqB,sBACZC,WACAC,UAAiC,CAAC,GAAC;AAEnC,QAAM,EAAEC,YAAY,MAAK,IAAKD;AAC9B,QAAME,cAAiC,CAAA;AACvC,MAAIC,SAAS;AAEb,aAAWC,YAAYL,WAAW;AAG9B,UAAMM,cAAcC,UAAU;SAAIF,SAAS1B;OAAWuB,SAAAA;AACtD,UAAMvB,WAAWD,uBAAuB4B,aAAaF,MAAAA;AACrDD,gBAAYlB,KAAI,GAAIN,QAAAA;AACpByB,cAAUzB,SAASG;EACvB;AAEA,SAAOqB;AACX;AAlBgBJ;AAwBT,SAASQ,UAAU5B,UAAsBuB,YAAqB,OAAK;AACtE,MAAIvB,SAASG,SAAS,GAAG;AACrB,WAAOH;EACX;AAEA,MAAI6B,aAAa;AACjB,WAASxB,IAAI,GAAGA,IAAIL,SAASG,QAAQE,KAAK;AACtC,UAAMQ,OAAOb,SAASK,CAAAA;AACtB,UAAMI,OAAOT,UAAUK,IAAI,KAAKL,SAASG,MAAM;AAC/C0B,kBAAehB,KAAKhB,IAAIY,KAAKX,IAAIW,KAAKZ,IAAIgB,KAAKf;EACnD;AACA+B,gBAAc;AAEd,QAAMC,QAAQP,YAAYM,aAAa,IAAIA,aAAa;AAExD,MAAIC,OAAO;AACP,WAAO9B;EACX;AAEA,SAAO;OAAIA;IAAU+B,QAAO;AAChC;AApBgBH;;;AC5HhB,SAASI,WAAAA,gBAA8B;AAiBvC,IAAMC,WAAU;AAEhB,IAAM,EAAEC,KAAAA,MAAKC,KAAAA,MAAKC,UAAAA,WAAUC,IAAG,IAAKC;AAMpC,SAASC,UAAUC,GAAW;AAC1B,QAAMC,SAASJ,IAAIG,CAAAA;AACnB,MAAIC,SAASR,UAAS;AAClB,WAAO;MAAES,GAAG;MAAGC,GAAG;IAAE;EACxB;AACA,SAAO;IAAED,GAAGF,EAAEE,IAAID;IAAQE,GAAGH,EAAEG,IAAIF;EAAO;AAC9C;AANSF;AAeF,IAAMK,cAAN,MAAMA,YAAAA;EAGT,YAAYC,SAA4B,CAAC,GAAG;AAF3BA;AAGb,SAAKA,SAAS;MAAE,GAAGC;MAAqB,GAAGD;IAAO;EACtD;;;;;;;;;;;EAYAE,mBACIC,OACAC,WACAC,WACAC,WACQ;AACR,UAAMC,SAAS,KAAKC,6BAA6BL,OAAOC,WAAWC,WAAWC,SAAAA;AAC9E,WAAOC,OAAOE;EAClB;;;;;;;;;;;EAYAD,6BACIL,OACAC,WACAC,WACAC,WACoC;AACpC,UAAMI,YAAyB,CAAA;AAE/B,UAAMC,mBAAmBC,sBAAsBP,WAAW;MACtDQ,WAAW,KAAKb,OAAOa;IAC3B,CAAA;AACA,UAAMC,eAAe,KAAKC,wBAAwBZ,OAAOQ,kBAAkBD,SAAAA;AAC3E,SAAKM,qBAAqBb,OAAOC,WAAWE,WAAWI,SAAAA;AAEvD,UAAMH,SAASU,uBACXP,WACAI,cACAX,MAAMe,UACNf,MAAMgB,iBAAiB;AAG3B,WAAO;MACH,GAAGZ;MACHa,UAAUV,UAAUd;IACxB;EACJ;;;;;EAMQoB,qBACJb,OACAC,WACAE,WACAI,WACI;AACJ,UAAMW,iBAAiB,IAAMlB,MAAMmB;AAEnC,eAAWC,SAASnB,WAAW;AAC3B,UAAImB,MAAMC,OAAOrB,MAAMqB,GAAI;AAE3B,YAAMC,mBAA6B;QAC/B5B,GAAG0B,MAAMG,SAAS7B,IAAIM,MAAMuB,SAAS7B;QACrCC,GAAGyB,MAAMG,SAAS5B,IAAIK,MAAMuB,SAAS5B;MACzC;AAEA,YAAM6B,mBAA6B;QAC/B9B,GAAGM,MAAMM,SAASZ,IAAI0B,MAAMd,SAASZ;QACrCC,GAAGK,MAAMM,SAASX,IAAIyB,MAAMd,SAASX;MACzC;AAEA,YAAM8B,SAASrC,UAASkC,gBAAAA;AACxB,YAAMI,iBAAiB1B,MAAM2B,SAASP,MAAMO;AAC5C,YAAMC,mBAAmBF,iBAAiBA;AAE1C,YAAMG,OAAkB;QACpBC,OAAO;UAAEpC,GAAG;UAAGC,GAAG;QAAE;QACpBoC,WAAW;UAAErC,GAAG;UAAGC,GAAG;QAAE;MAC5B;AAEA,UAAIqC;AAEJ,UAAIP,SAASG,kBAAkB;AAG3B,cAAMK,IAAc;UAChBvC,GAAG8B,iBAAiB9B,IAAIwB,iBAAiBI,iBAAiB5B;UAC1DC,GAAG6B,iBAAiB7B,IAAIuB,iBAAiBI,iBAAiB3B;QAC9D;AAEA,cAAMuC,YAAY9C,UAAS6C,CAAAA;AAC3B,cAAME,cAAchD,KAAI8C,GAAGX,gBAAAA;AAE3B,YAAIa,cAAc,KAAKA,cAAcA,cAAcP,mBAAmBM,WAAW;AAG7E,gBAAME,UAAUC,KAAKC,KAAKJ,SAAAA;AAC1B,gBAAMK,QAAQhD,UAAU0C,CAAAA;AAExBJ,eAAKE,YAAY;YAAErC,GAAG6C,MAAM5C;YAAGA,GAAG,CAAC4C,MAAM7C;UAAE;AAC3CsC,cAAI;YACAtC,IAAIgC,iBAAiBR,iBAAiBkB,WAAWG,MAAM7C;YACvDC,IAAI+B,iBAAiBR,iBAAiBkB,WAAWG,MAAM5C;UAC3D;QACJ,OAAO;AAGH,gBAAM6C,MAAMH,KAAKC,KAAKb,SAASG,gBAAAA;AAE/B,cAAI1C,KAAIoC,kBAAkBW,CAAAA,IAAK,GAAG;AAC9BJ,iBAAKE,YAAY;cACbrC,IAAI4B,iBAAiB5B,IAAI8C,MAAMlB,iBAAiB3B,IAAI+B,kBAAkBD;cACtE9B,IAAI2B,iBAAiB5B,IAAIgC,iBAAiBJ,iBAAiB3B,IAAI6C,OAAOf;YAC1E;UACJ,OAAO;AACHI,iBAAKE,YAAY;cACbrC,GAAG,EAAE4B,iBAAiB5B,IAAI8C,MAAMlB,iBAAiB3B,IAAI+B,kBAAkBD;cACvE9B,GAAG,EAAE,CAAC2B,iBAAiB5B,IAAIgC,iBAAiBJ,iBAAiB3B,IAAI6C,OAAOf;YAC5E;UACJ;AAEA,gBAAMgB,cAActD,KAAIqC,kBAAkBK,KAAKE,SAAS;AACxDC,cAAI;YACAtC,GAAG+C,cAAcZ,KAAKE,UAAUrC,IAAI8B,iBAAiB9B;YACrDC,GAAG8C,cAAcZ,KAAKE,UAAUpC,IAAI6B,iBAAiB7B;UACzD;QACJ;MACJ,OAAO;AAGH,cAAM+C,cAAc,IAAMvC;AAE1B,cAAM8B,IAAc;UAChBvC,GAAG8B,iBAAiB9B,IAAIgD,cAAcpB,iBAAiB5B;UACvDC,GAAG6B,iBAAiB7B,IAAI+C,cAAcpB,iBAAiB3B;QAC3D;AAEA,cAAMyC,UAAU/C,IAAI4C,CAAAA;AACpB,cAAMM,QAAQH,UAAUnD,WAClB;UAAES,GAAGuC,EAAEvC,IAAI0C;UAASzC,GAAGsC,EAAEtC,IAAIyC;QAAQ,IACrC;UAAE1C,GAAG;UAAGC,GAAG;QAAE;AAEnBkC,aAAKE,YAAY;UAAErC,GAAG6C,MAAM5C;UAAGA,GAAG,CAAC4C,MAAM7C;QAAE;AAC3CsC,YAAI;UACAtC,IAAIgC,iBAAiBgB,cAAcN,WAAWG,MAAM7C;UACpDC,IAAI+B,iBAAiBgB,cAAcN,WAAWG,MAAM5C;QACxD;MACJ;AAEAkC,WAAKC,QAAQ;QACTpC,GAAGM,MAAMM,SAASZ,IAAI,MAAMsC,EAAEtC;QAC9BC,GAAGK,MAAMM,SAASX,IAAI,MAAMqC,EAAErC;MAClC;AAEAY,gBAAUoC,KAAKd,IAAAA;IACnB;EACJ;;;;;EAMQjB,wBACJZ,OACAQ,kBACAD,WACM;AACN,UAAMqC,qBAAqB,IAAM5C,MAAM6C;AACvC,UAAMC,WAAW9C,MAAM2B,SAAS3B,MAAM2B;AACtC,QAAIhB,eAAe;AAEnB,eAAWoC,aAAavC,kBAAkB;AACtC,YAAMwC,YAAYD,UAAUE;AAE5B,YAAMC,oBAA8B;QAChCxD,GAAGqD,UAAUjB,MAAMpC,IAAIM,MAAMuB,SAAS7B;QACtCC,GAAGoD,UAAUjB,MAAMnC,IAAIK,MAAMuB,SAAS5B;MAC1C;AACA,YAAMwD,oBAA8B;QAChCzD,GAAGsD,UAAUlB,MAAMpC,IAAIM,MAAMuB,SAAS7B;QACtCC,GAAGqD,UAAUlB,MAAMnC,IAAIK,MAAMuB,SAAS5B;MAC1C;AAIA,YAAMyD,iBAA2B;QAC7B1D,GAAGsD,UAAUlB,MAAMpC,IAAIqD,UAAUjB,MAAMpC;QACvCC,GAAGqD,UAAUlB,MAAMnC,IAAIoD,UAAUjB,MAAMnC;MAC3C;AACA,YAAM0D,mBAAmBnE,KAAIkE,gBAAgBF,iBAAAA;AAE7C,UAAIG,mBAAmB,CAACpE,UAAS;AAC7B;MACJ;AAIA,UAAIqE,iBAAiB;AACrB,iBAAWC,gBAAgBhD,WAAW;AAClC,cAAMiD,gBAA0B;UAC5B9D,GAAGkD,qBAAqBM,kBAAkBxD,IAAI6D,aAAazB,MAAMpC;UACjEC,GAAGiD,qBAAqBM,kBAAkBvD,IAAI4D,aAAazB,MAAMnC;QACrE;AACA,cAAM8D,gBAA0B;UAC5B/D,GAAGkD,qBAAqBO,kBAAkBzD,IAAI6D,aAAazB,MAAMpC;UACjEC,GAAGiD,qBAAqBO,kBAAkBxD,IAAI4D,aAAazB,MAAMnC;QACrE;AAEA,YAAIT,KAAIsE,eAAeD,aAAaxB,SAAS,IAAIa,qBAAqB5C,MAAM2B,UAAU,CAAC1C,YACnFC,KAAIuE,eAAeF,aAAaxB,SAAS,IAAIa,qBAAqB5C,MAAM2B,UAAU,CAAC1C,UAAS;AAC5FqE,2BAAiB;AACjB;QACJ;MACJ;AAEA,UAAIA,gBAAgB;AAChB;MACJ;AAEA,YAAMI,UAAUtE,UAAS8D,iBAAAA;AACzB,YAAMS,UAAUvE,UAAS+D,iBAAAA;AACzB,YAAMS,mBAAmBxE,UAASgE,cAAAA;AAElC,YAAMS,IAAID,mBAAmB3E,WACvB,CAACE,KAAI+D,mBAAmBE,cAAAA,IAAkBQ,mBAC1C;AAEN,YAAME,mBAAmB1E,UAAS;QAC9BM,GAAG,CAACwD,kBAAkBxD,IAAImE,IAAIT,eAAe1D;QAC7CC,GAAG,CAACuD,kBAAkBvD,IAAIkE,IAAIT,eAAezD;MACjD,CAAA;AAEA,YAAMkC,OAAkB;QACpBC,OAAO;UAAEpC,GAAG;UAAGC,GAAG;QAAE;QACpBoC,WAAW;UAAErC,GAAG;UAAGC,GAAG;QAAE;MAC5B;AAIA,UAAIkE,IAAI,KAAKH,WAAWZ,UAAU;AAC9B,YAAIC,UAAUgB,UAAU;AACpBlC,eAAKC,QAAQ;YAAEpC,GAAG;YAAGC,GAAG;UAAE;AAC1BkC,eAAKE,YAAYxC,UAAU;YAAEG,GAAG,CAACwD,kBAAkBvD;YAAGA,GAAGuD,kBAAkBxD;UAAE,CAAA;AAC7Ea,oBAAUoC,KAAKd,IAAAA;AACflB;QACJ;AACA;MACJ;AAIA,UAAIkD,IAAI,KAAKF,WAAWb,UAAU;AAC9B,YAAIE,UAAUe,YAAY7E,KAAIiE,mBAAmBH,UAAUjB,SAAS,KAAK,GAAG;AACxEF,eAAKC,QAAQ;YAAEpC,GAAG;YAAGC,GAAG;UAAE;AAC1BkC,eAAKE,YAAYxC,UAAU;YAAEG,GAAG,CAACyD,kBAAkBxD;YAAGA,GAAGwD,kBAAkBzD;UAAE,CAAA;AAC7Ea,oBAAUoC,KAAKd,IAAAA;AACflB;QACJ;AACA;MACJ;AAIA,UAAIkD,KAAK,KAAKA,KAAK,KAAKC,oBAAoBhB,UAAU;AAClDjB,aAAKC,QAAQ;UAAEpC,GAAG;UAAGC,GAAG;QAAE;AAC1BkC,aAAKE,YAAY;UAAErC,GAAG,CAACqD,UAAUhB,UAAUrC;UAAGC,GAAG,CAACoD,UAAUhB,UAAUpC;QAAE;AACxEY,kBAAUoC,KAAKd,IAAAA;AACflB;AACA;MACJ;AAIA,UAAIqD,OAAOjB;AACX,UAAIkB,OAAOjB;AACX,UAAIkB;AACJ,UAAIC;AAEJ,UAAIN,IAAI,KAAKC,oBAAoBhB,UAAU;AAGvC,YAAI,CAACC,UAAUgB,SAAU;AACzBE,eAAOlB;AAEP,cAAMqB,OAAO/B,KAAKC,KAAKD,KAAKgC,IAAI,GAAGX,UAAUZ,QAAAA,CAAAA;AAC7CoB,2BAAmB;UACfxE,IAAIwD,kBAAkBxD,IAAI0E,OAAOlB,kBAAkBvD,IAAIK,MAAM2B,UAAU+B;UACvE/D,IAAIuD,kBAAkBxD,IAAIM,MAAM2B,SAASuB,kBAAkBvD,IAAIyE,QAAQV;QAC3E;AACAS,4BAAoB;UAChBzE,IAAIwD,kBAAkBxD,IAAI0E,OAAOlB,kBAAkBvD,IAAIK,MAAM2B,UAAU+B;UACvE/D,IAAI,CAACuD,kBAAkBxD,IAAIM,MAAM2B,SAASuB,kBAAkBvD,IAAIyE,QAAQV;QAC5E;MACJ,WAAWG,IAAI,KAAKC,oBAAoBhB,UAAU;AAG9C,YAAI,CAACE,UAAUe,SAAU;AACzBC,eAAOhB;AAEP,cAAMsB,OAAOjC,KAAKC,KAAKD,KAAKgC,IAAI,GAAGV,UAAUb,QAAAA,CAAAA;AAC7CoB,2BAAmB;UACfxE,IAAIyD,kBAAkBzD,IAAI4E,OAAOnB,kBAAkBxD,IAAIK,MAAM2B,UAAUgC;UACvEhE,IAAIwD,kBAAkBzD,IAAIM,MAAM2B,SAASwB,kBAAkBxD,IAAI2E,QAAQX;QAC3E;AACAQ,4BAAoB;UAChBzE,IAAIyD,kBAAkBzD,IAAI4E,OAAOnB,kBAAkBxD,IAAIK,MAAM2B,UAAUgC;UACvEhE,IAAI,CAACwD,kBAAkBzD,IAAIM,MAAM2B,SAASwB,kBAAkBxD,IAAI2E,QAAQX;QAC5E;MACJ,OAAO;AAGH,YAAIZ,UAAUgB,UAAU;AACpB,gBAAMK,OAAO/B,KAAKC,KAAKD,KAAKgC,IAAI,GAAGX,UAAUZ,QAAAA,CAAAA;AAC7CoB,6BAAmB;YACfxE,IAAIwD,kBAAkBxD,IAAI0E,OAAOlB,kBAAkBvD,IAAIK,MAAM2B,UAAU+B;YACvE/D,IAAIuD,kBAAkBxD,IAAIM,MAAM2B,SAASuB,kBAAkBvD,IAAIyE,QAAQV;UAC3E;QACJ,OAAO;AACHQ,6BAAmB;YAAExE,GAAG,CAACqD,UAAUhB,UAAUrC;YAAGC,GAAG,CAACoD,UAAUhB,UAAUpC;UAAE;QAC9E;AAEA,YAAIqD,UAAUe,UAAU;AACpB,gBAAMO,OAAOjC,KAAKC,KAAKD,KAAKgC,IAAI,GAAGV,UAAUb,QAAAA,CAAAA;AAC7CqB,8BAAoB;YAChBzE,IAAIyD,kBAAkBzD,IAAI4E,OAAOnB,kBAAkBxD,IAAIK,MAAM2B,UAAUgC;YACvEhE,IAAI,CAACwD,kBAAkBzD,IAAIM,MAAM2B,SAASwB,kBAAkBxD,IAAI2E,QAAQX;UAC5E;QACJ,OAAO;AACHQ,8BAAoB;YAAEzE,GAAGqD,UAAUhB,UAAUrC;YAAGC,GAAGoD,UAAUhB,UAAUpC;UAAE;QAC7E;MACJ;AAIA,YAAM4E,eAAeP,KAAKQ;AAC1B,UAAIC,mBAAmB;AACvB,UAAIC,oBAAoB;AAExB,UAAIV,KAAKD,UAAU;AACf,cAAMY,qBAAqB;UAAEjF,GAAG,CAAC6E,aAAaxC,UAAUrC;UAAGC,GAAG,CAAC4E,aAAaxC,UAAUpC;QAAE;AACxF,YAAIT,KAAIgF,kBAAkBS,kBAAAA,KAAuB,GAAG;AAChDT,6BAAmBS;AACnBF,6BAAmB;QACvB;MACJ;AAEA,UAAIR,KAAKF,UAAU;AACf,YAAI7E,KAAIiF,mBAAmBF,KAAKlC,SAAS,KAAK,GAAG;AAC7CoC,8BAAoB;YAAEzE,GAAGuE,KAAKlC,UAAUrC;YAAGC,GAAGsE,KAAKlC,UAAUpC;UAAE;AAC/D+E,8BAAoB;QACxB;MACJ;AAIA,YAAME,aAAuB;QACzBlF,GAAGkD,sBAAsBoB,KAAKlC,MAAMpC,IAAIM,MAAMuB,SAAS7B;QACvDC,GAAGiD,sBAAsBoB,KAAKlC,MAAMnC,IAAIK,MAAMuB,SAAS5B;MAC3D;AACA,YAAMkF,cAAwB;QAC1BnF,GAAGkD,sBAAsBqB,KAAKnC,MAAMpC,IAAIM,MAAMuB,SAAS7B;QACvDC,GAAGiD,sBAAsBqB,KAAKnC,MAAMnC,IAAIK,MAAMuB,SAAS5B;MAC3D;AACA,YAAMmF,eAAyB;QAC3BpF,GAAGmF,YAAYnF,IAAIkF,WAAWlF;QAC9BC,GAAGkF,YAAYlF,IAAIiF,WAAWjF;MAClC;AAEA,YAAMoF,aAAaf,SAASC;AAC5B,YAAMe,iBAAiB5F,UAAS0F,YAAAA;AAChC,YAAMG,IAAIF,aACJ,MACCC,iBAAiB/F,WACdE,KAAI;QAAEO,GAAGM,MAAMM,SAASZ,IAAIkF,WAAWlF;QAAGC,GAAGK,MAAMM,SAASX,IAAIiF,WAAWjF;MAAE,GAAGmF,YAAAA,IAAgBE,iBAChG;AAEV,YAAME,QAAQ/F,KAAI;QAAEO,GAAGM,MAAMM,SAASZ,IAAIkF,WAAWlF;QAAGC,GAAGK,MAAMM,SAASX,IAAIiF,WAAWjF;MAAE,GAAGuE,gBAAAA;AAC9F,YAAMiB,SAAShG,KAAI;QAAEO,GAAGM,MAAMM,SAASZ,IAAImF,YAAYnF;QAAGC,GAAGK,MAAMM,SAASX,IAAIkF,YAAYlF;MAAE,GAAGwE,iBAAAA;AAIjG,UAAKc,IAAI,KAAKC,QAAQ,KAAOH,cAAcG,QAAQ,KAAKC,SAAS,GAAI;AACjE,cAAM5C,QAAQhD,UAAU;UAAEG,GAAGM,MAAMM,SAASZ,IAAIkF,WAAWlF;UAAGC,GAAGK,MAAMM,SAASX,IAAIiF,WAAWjF;QAAE,CAAA;AACjGkC,aAAKE,YAAY;UAAErC,GAAG6C,MAAM5C;UAAGA,GAAG,CAAC4C,MAAM7C;QAAE;AAC3CmC,aAAKC,QAAQ;UACTpC,GAAGkF,WAAWlF,IAAIM,MAAM2B,SAASiB,qBAAqBL,MAAM7C;UAC5DC,GAAGiF,WAAWjF,IAAIK,MAAM2B,SAASiB,qBAAqBL,MAAM5C;QAChE;AACAY,kBAAUoC,KAAKd,IAAAA;AACflB;AACA;MACJ;AAIA,UAAIsE,IAAI,KAAKE,SAAS,GAAG;AACrB,cAAM5C,QAAQhD,UAAU;UAAEG,GAAGM,MAAMM,SAASZ,IAAImF,YAAYnF;UAAGC,GAAGK,MAAMM,SAASX,IAAIkF,YAAYlF;QAAE,CAAA;AACnGkC,aAAKE,YAAY;UAAErC,GAAG6C,MAAM5C;UAAGA,GAAG,CAAC4C,MAAM7C;QAAE;AAC3CmC,aAAKC,QAAQ;UACTpC,GAAGmF,YAAYnF,IAAIM,MAAM2B,SAASiB,qBAAqBL,MAAM7C;UAC7DC,GAAGkF,YAAYlF,IAAIK,MAAM2B,SAASiB,qBAAqBL,MAAM5C;QACjE;AACAY,kBAAUoC,KAAKd,IAAAA;AACflB;AACA;MACJ;AAIA,YAAMyE,eAAgBH,IAAI,KAAKA,IAAI,KAAKF,aAClCM,WACAjG,UAAS;QACPM,GAAGM,MAAMM,SAASZ,KAAKkF,WAAWlF,IAAIuF,IAAIH,aAAapF;QACvDC,GAAGK,MAAMM,SAASX,KAAKiF,WAAWjF,IAAIsF,IAAIH,aAAanF;MAC3D,CAAA;AAEJ,YAAM2F,aAAaJ,QAAQ,IACrBG,WACAjG,UAAS;QACPM,GAAGM,MAAMM,SAASZ,KAAKkF,WAAWlF,IAAIwF,QAAQhB,iBAAiBxE;QAC/DC,GAAGK,MAAMM,SAASX,KAAKiF,WAAWjF,IAAIuF,QAAQhB,iBAAiBvE;MACnE,CAAA;AAEJ,YAAM4F,cAAcJ,SAAS,IACvBE,WACAjG,UAAS;QACPM,GAAGM,MAAMM,SAASZ,KAAKmF,YAAYnF,IAAIyF,SAAShB,kBAAkBzE;QAClEC,GAAGK,MAAMM,SAASX,KAAKkF,YAAYlF,IAAIwF,SAAShB,kBAAkBxE;MACtE,CAAA;AAIJ,UAAIyF,gBAAgBE,cAAcF,gBAAgBG,aAAa;AAC3D1D,aAAKE,YAAY;UAAErC,GAAG,CAACsE,KAAKjC,UAAUrC;UAAGC,GAAG,CAACqE,KAAKjC,UAAUpC;QAAE;AAC9DkC,aAAKC,QAAQ;UACTpC,GAAGkF,WAAWlF,IAAIM,MAAM2B,SAASiB,qBAAsB,CAACf,KAAKE,UAAUpC;UACvEA,GAAGiF,WAAWjF,IAAIK,MAAM2B,SAASiB,qBAAqBf,KAAKE,UAAUrC;QACzE;AACAa,kBAAUoC,KAAKd,IAAAA;AACflB;AACA;MACJ;AAIA,UAAI2E,cAAcC,aAAa;AAC3B,YAAId,kBAAkB;AAClB;QACJ;AAEA5C,aAAKE,YAAY;UAAErC,GAAGwE,iBAAiBxE;UAAGC,GAAGuE,iBAAiBvE;QAAE;AAChEkC,aAAKC,QAAQ;UACTpC,GAAGkF,WAAWlF,IAAIM,MAAM2B,SAASiB,qBAAsB,CAACf,KAAKE,UAAUpC;UACvEA,GAAGiF,WAAWjF,IAAIK,MAAM2B,SAASiB,qBAAqBf,KAAKE,UAAUrC;QACzE;AACAa,kBAAUoC,KAAKd,IAAAA;AACflB;AACA;MACJ;AAIA,UAAI+D,mBAAmB;AACnB;MACJ;AAEA7C,WAAKE,YAAY;QAAErC,GAAG,CAACyE,kBAAkBzE;QAAGC,GAAG,CAACwE,kBAAkBxE;MAAE;AACpEkC,WAAKC,QAAQ;QACTpC,GAAGmF,YAAYnF,IAAIM,MAAM2B,SAASiB,qBAAsB,CAACf,KAAKE,UAAUpC;QACxEA,GAAGkF,YAAYlF,IAAIK,MAAM2B,SAASiB,qBAAqBf,KAAKE,UAAUrC;MAC1E;AACAa,gBAAUoC,KAAKd,IAAAA;AACflB;IACJ;AAEA,WAAOA;EACX;AACJ;AA/eaf;AAAN,IAAMA,aAAN;AAwfA,SAAS4F,iBAAiB3F,QAA0B;AACvD,SAAO,IAAID,WAAWC,MAAAA;AAC1B;AAFgB2F;;;ACtdT,IAAMC,UAAN,MAAMA,QAAAA;EAAN;AACKC,kCAA4B,CAAA;AAC5BC,wCAAyB,CAAA;AACzBC,iCAAsB,CAAA;AAMbC;;;;uCAAc;;;;;;EAM/BC,MAAMJ,QAA0C;AAC5C,SAAKA,SAASA;AACd,SAAKC,eAAe,CAAA;AACpB,SAAKC,QAAQ,CAAA;AAEb,QAAIF,OAAOK,WAAW,GAAG;AACrB;IACJ;AAGA,aAASC,IAAI,GAAGA,IAAIN,OAAOK,QAAQC,KAAK;AACpC,WAAKL,aAAaM,KAAKD,CAAAA;IAC3B;AAGA,SAAKE,eAAe,GAAGR,OAAOK,QAAQ,CAAA;EAC1C;;;;;EAMQG,eAAeC,OAAeC,KAAaC,OAAuB;AACtE,UAAMC,YAAY,KAAKV,MAAMG;AAE7B,UAAMQ,OAAmB;MACrBC,YAAY;MACZC,YAAY;MACZC,MAAM;MACNC,OAAO;MACPR;MACAC;MACAQ,MAAMC;MACNC,MAAMD;MACNE,MAAM;MACNC,MAAM;IACV;AAEA,SAAKpB,MAAMK,KAAKM,IAAAA;AAGhB,aAASP,IAAIG,OAAOH,IAAII,KAAKJ,KAAK;AAC9B,YAAMiB,QAAQ,KAAKvB,OAAO,KAAKC,aAAaK,CAAAA,CAAE;AAC9CO,WAAKK,OAAOM,KAAKC,IAAIZ,KAAKK,MAAMK,MAAMG,SAASC,CAAC;AAChDd,WAAKO,OAAOI,KAAKC,IAAIZ,KAAKO,MAAMG,MAAMG,SAASE,CAAC;AAChDf,WAAKQ,OAAOG,KAAKK,IAAIhB,KAAKQ,MAAME,MAAMG,SAASC,CAAC;AAChDd,WAAKS,OAAOE,KAAKK,IAAIhB,KAAKS,MAAMC,MAAMG,SAASE,CAAC;IACpD;AAEA,UAAME,QAAQpB,MAAMD;AAEpB,QAAIqB,SAAS,KAAK3B,aAAa;AAE3B,aAAOS;IACX;AAGA,UAAMmB,WAAWpB,QAAQ;AAGzB,QAAIoB,aAAa,GAAG;AAChB,WAAKC,QAAQvB,OAAOC,GAAAA;IACxB,OAAO;AACH,WAAKuB,QAAQxB,OAAOC,GAAAA;IACxB;AAGA,UAAMwB,MAAMV,KAAKW,OAAO1B,QAAQC,OAAO,CAAA;AACvC,UAAM0B,WAAW,KAAKpC,OAAO,KAAKC,aAAaiC,GAAAA,CAAI;AACnDrB,SAAKE,aAAagB,aAAa,IAAIK,SAASV,SAASC,IAAIS,SAASV,SAASE;AAG3Ef,SAAKG,OAAO,KAAKR,eAAeC,OAAOyB,KAAKvB,QAAQ,CAAA;AACpDE,SAAKI,QAAQ,KAAKT,eAAe0B,KAAKxB,KAAKC,QAAQ,CAAA;AAEnD,WAAOC;EACX;;;;;EAMQoB,QAAQvB,OAAeC,KAAmB;AAC9C,UAAM2B,UAAU,KAAKpC;AACrB,UAAMD,SAAS,KAAKA;AAEpB,aAASM,IAAIG,QAAQ,GAAGH,IAAII,KAAKJ,KAAK;AAClC,YAAMgC,MAAMD,QAAQ/B,CAAAA;AACpB,YAAMiC,OAAOvC,OAAOsC,GAAAA,EAAMZ,SAASC;AACnC,UAAIa,IAAIlC,IAAI;AAEZ,aAAOkC,KAAK/B,SAAST,OAAOqC,QAAQG,CAAAA,CAAE,EAAId,SAASC,IAAIY,MAAM;AACzDF,gBAAQG,IAAI,CAAA,IAAKH,QAAQG,CAAAA;AACzBA;MACJ;AACAH,cAAQG,IAAI,CAAA,IAAKF;IACrB;EACJ;;;;;EAMQL,QAAQxB,OAAeC,KAAmB;AAC9C,UAAM2B,UAAU,KAAKpC;AACrB,UAAMD,SAAS,KAAKA;AAEpB,aAASM,IAAIG,QAAQ,GAAGH,IAAII,KAAKJ,KAAK;AAClC,YAAMgC,MAAMD,QAAQ/B,CAAAA;AACpB,YAAMmC,OAAOzC,OAAOsC,GAAAA,EAAMZ,SAASE;AACnC,UAAIY,IAAIlC,IAAI;AAEZ,aAAOkC,KAAK/B,SAAST,OAAOqC,QAAQG,CAAAA,CAAE,EAAId,SAASE,IAAIa,MAAM;AACzDJ,gBAAQG,IAAI,CAAA,IAAKH,QAAQG,CAAAA;AACzBA;MACJ;AACAH,cAAQG,IAAI,CAAA,IAAKF;IACrB;EACJ;;;;;EAMAI,eACIhB,UACAiB,QACAC,YACAC,WACiB;AACjB,UAAMC,UAA6B,CAAA;AACnC,UAAMC,WAAWJ,SAASA;AAE1B,QAAI,KAAKzC,MAAMG,WAAW,GAAG;AACzB,aAAOyC;IACX;AAEA,SAAKE,eAAe,GAAGtB,UAAUqB,UAAUH,YAAYC,WAAWC,OAAAA;AAGlEA,YAAQG,KAAK,CAACC,GAAGC,MAAMD,EAAEE,aAAaD,EAAEC,UAAU;AAGlD,QAAIN,QAAQzC,SAASuC,YAAY;AAC7BE,cAAQzC,SAASuC;IACrB;AAEA,WAAOE;EACX;;;;;EAMQE,eACJpC,WACAc,UACAqB,UACAH,YACAC,WACAC,SACI;AACJ,UAAMjC,OAAO,KAAKX,MAAMU,SAAAA;AACxB,QAAI,CAACC,KAAM;AAGX,UAAMwC,WAAW7B,KAAKK,IAAIhB,KAAKK,MAAMM,KAAKC,IAAIC,SAASC,GAAGd,KAAKQ,IAAI,CAAA;AACnE,UAAMiC,WAAW9B,KAAKK,IAAIhB,KAAKO,MAAMI,KAAKC,IAAIC,SAASE,GAAGf,KAAKS,IAAI,CAAA;AACnE,UAAMiC,KAAK7B,SAASC,IAAI0B;AACxB,UAAMG,KAAK9B,SAASE,IAAI0B;AACxB,UAAMG,eAAeF,KAAKA,KAAKC,KAAKA;AAEpC,QAAIC,eAAeV,UAAU;AACzB;IACJ;AAGA,QAAIlC,KAAKG,SAAS,MAAMH,KAAKI,UAAU,IAAI;AACvC,eAASX,IAAIO,KAAKJ,OAAOH,IAAIO,KAAKH,KAAKJ,KAAK;AACxC,cAAMQ,aAAa,KAAKb,aAAaK,CAAAA;AACrC,cAAMiB,QAAQ,KAAKvB,OAAOc,UAAAA;AAE1B,YAAI+B,cAAca,UAAanC,MAAMoC,OAAOd,WAAW;AACnD;QACJ;AAEA,cAAMe,MAAMlC,SAASC,IAAIJ,MAAMG,SAASC;AACxC,cAAMkC,MAAMnC,SAASE,IAAIL,MAAMG,SAASE;AACxC,cAAMkC,SAASF,MAAMA,MAAMC,MAAMA;AAEjC,YAAIC,SAASf,UAAU;AACnBD,kBAAQvC,KAAK;YAAEgB;YAAO6B,YAAYU;UAAO,CAAA;QAC7C;MACJ;AACA;IACJ;AAGA,QAAIjD,KAAKG,SAAS,IAAI;AAClB,WAAKgC,eAAenC,KAAKG,MAAMU,UAAUqB,UAAUH,YAAYC,WAAWC,OAAAA;IAC9E;AACA,QAAIjC,KAAKI,UAAU,IAAI;AACnB,WAAK+B,eAAenC,KAAKI,OAAOS,UAAUqB,UAAUH,YAAYC,WAAWC,OAAAA;IAC/E;EACJ;;;;;EAMAiB,QAAc;AACV,SAAK/D,SAAS,CAAA;AACd,SAAKC,eAAe,CAAA;AACpB,SAAKC,QAAQ,CAAA;EACjB;;;;;EAMA,IAAI8D,aAAqB;AACrB,WAAO,KAAKhE,OAAOK;EACvB;AACJ;AA9OaN;AAAN,IAAMA,SAAN;AAoPA,SAASkE,eAAAA;AACZ,SAAO,IAAIlE,OAAAA;AACf;AAFgBkE;;;AC3ThB,IAAMC,WAAU;AAwCT,IAAMC,kBAAoC;EAC7CC,UAAU;EACVC,aAAa;EACbC,QAAQ;IAAEC,GAAG;IAAGC,GAAG;EAAE;EACrBC,cAAc;IAAEF,GAAG;IAAGC,GAAG;EAAE;AAC/B;AAUA,SAASE,sBACLC,OACAC,UACAC,QAAgB;AAEhB,QAAMC,KAAKD,OAAON,IAAIK,SAASL;AAC/B,QAAMQ,KAAKF,OAAOL,IAAII,SAASJ;AAC/B,QAAMQ,YAAWF,KAAKA,KAAKC,KAAKA;AAEhC,MAAIC,YAAWd,UAAS;AACpB,WAAO;MAAEK,GAAGK,SAASL;MAAGC,GAAGI,SAASJ;IAAE;EAC1C;AAEA,QAAMS,IAAIC,KAAKC,IAAI,GAAGD,KAAKE,IAAI,KACzBT,MAAMJ,IAAIK,SAASL,KAAKO,MAAMH,MAAMH,IAAII,SAASJ,KAAKO,MAAMC,SAAAA,CAAAA;AAGlE,SAAO;IACHT,GAAGK,SAASL,IAAIU,IAAIH;IACpBN,GAAGI,SAASJ,IAAIS,IAAIF;EACxB;AACJ;AArBSL;AA2BT,SAASW,iBAAiBV,OAAiBW,UAA6B;AACpE,MAAIC,SAAS;AACb,QAAMC,IAAIF,SAASG;AAEnB,WAASC,IAAI,GAAGC,IAAIH,IAAI,GAAGE,IAAIF,GAAGG,IAAID,KAAK;AACvC,UAAME,KAAKN,SAASI,CAAAA,EAAInB;AACxB,UAAMsB,KAAKP,SAASI,CAAAA,EAAIlB;AACxB,UAAMsB,KAAKR,SAASK,CAAAA,EAAIpB;AACxB,UAAMwB,KAAKT,SAASK,CAAAA,EAAInB;AAExB,QACIqB,KAAKlB,MAAMH,MAAMuB,KAAKpB,MAAMH,KAC5BG,MAAMJ,KAAMuB,KAAKF,OAAOjB,MAAMH,IAAIqB,OAAQE,KAAKF,MAAMD,IACvD;AACEL,eAAS,CAACA;IACd;EACJ;AAEA,SAAOA;AACX;AAnBSF;AAyBT,SAASW,sBACLrB,OACAW,UAA6B;AAE7B,MAAIW,YAAYC;AAChB,MAAIC,YAAsB;IAAE5B,GAAG;IAAGC,GAAG;EAAE;AACvC,MAAI4B,cAAc;AAElB,WAASV,IAAI,GAAGA,IAAIJ,SAASG,QAAQC,KAAK;AACtC,UAAMC,KAAKD,IAAI,KAAKJ,SAASG;AAC7B,UAAMY,UAAU3B,sBAAsBC,OAAOW,SAASI,CAAAA,GAAKJ,SAASK,CAAAA,CAAE;AACtE,UAAMb,KAAKH,MAAMJ,IAAI8B,QAAQ9B;AAC7B,UAAMQ,KAAKJ,MAAMH,IAAI6B,QAAQ7B;AAC7B,UAAM8B,SAASxB,KAAKA,KAAKC,KAAKA;AAE9B,QAAIuB,SAASL,WAAW;AACpBA,kBAAYK;AACZH,kBAAYE;AACZD,oBAAcV;IAClB;EACJ;AAEA,SAAO;IAAEf,OAAOwB;IAAWI,YAAYN;IAAWO,WAAWJ;EAAY;AAC7E;AAvBSJ;AAmDF,IAAMS,2BAA+D;EACxEC,gBAAgB;EAChBC,cAAc;AAClB;AASO,IAAMC,qBAAN,MAAMA,mBAAAA;EAGT,YAAYC,SAAmC,CAAC,GAAG;AAFlCA;AAGb,SAAKA,SAAS;MAAE,GAAGJ;MAA0B,GAAGI;IAAO;EAC3D;;;;;;;;;;EAWAC,gBACIC,UACAC,QACAC,UACgB;AAChB,UAAM3B,WAAW2B,SAAS3B;AAC1B,QAAIA,SAASG,SAAS,GAAG;AACrB,aAAOtB;IACX;AAEA,UAAM+C,WAAW7B,iBAAiB0B,UAAUzB,QAAAA;AAC5C,UAAMe,UAAUL,sBAAsBe,UAAUzB,QAAAA;AAChD,UAAM6B,WAAWjC,KAAKkC,KAAKf,QAAQE,UAAU;AAE7C,QAAIlC;AACJ,QAAIgD;AACJ,QAAIC;AAEJ,QAAIJ,UAAU;AACV7C,oBAAc2C,SAASG;AACvB,YAAMrC,KAAKuB,QAAQ1B,MAAMJ,IAAIwC,SAASxC;AACtC,YAAMQ,KAAKsB,QAAQ1B,MAAMH,IAAIuC,SAASvC;AACtC,YAAM+C,OAAMrC,KAAKkC,KAAKtC,KAAKA,KAAKC,KAAKA,EAAAA;AACrC,UAAIwC,OAAMrD,UAAS;AACfmD,kBAAUvC,KAAKyC;AACfD,kBAAUvC,KAAKwC;MACnB,OAAO;AACHF,kBAAU;AACVC,kBAAU;MACd;IACJ,WAAWH,WAAWH,QAAQ;AAC1B3C,oBAAc2C,SAASG;AACvB,YAAMrC,KAAKiC,SAASxC,IAAI8B,QAAQ1B,MAAMJ;AACtC,YAAMQ,KAAKgC,SAASvC,IAAI6B,QAAQ1B,MAAMH;AACtC,YAAM+C,OAAMrC,KAAKkC,KAAKtC,KAAKA,KAAKC,KAAKA,EAAAA;AACrC,UAAIwC,OAAMrD,UAAS;AACfmD,kBAAUvC,KAAKyC;AACfD,kBAAUvC,KAAKwC;MACnB,OAAO;AACHF,kBAAU;AACVC,kBAAU;MACd;IACJ,OAAO;AACH,aAAOnD;IACX;AAEA,WAAO;MACHC,UAAU;MACVC;MACAC,QAAQ;QAAEC,GAAG8C;QAAS7C,GAAG8C;MAAQ;MACjC7C,cAAc4B,QAAQ1B;IAC1B;EACJ;;;;;;;;;;EAWA6C,iBACIT,UACAC,QACAS,WACgB;AAChB,QAAIC,iBAAiBvD;AACrB,QAAIwD,iBAAiB;AAErB,eAAWV,YAAYQ,WAAW;AAC9B,YAAMG,YAAY,KAAKd,gBAAgBC,UAAUC,QAAQC,QAAAA;AACzD,UAAIW,UAAUxD,YAAYwD,UAAUvD,cAAcsD,gBAAgB;AAC9DA,yBAAiBC,UAAUvD;AAC3BqD,yBAAiBE;MACrB;IACJ;AAEA,WAAOF;EACX;;;;;;;;;;EAWAG,iBACId,UACAC,QACAS,WACQ;AACR,UAAMK,SAAS;MAAEvD,GAAGwC,SAASxC;MAAGC,GAAGuC,SAASvC;IAAE;AAC9C,UAAMuD,gBAAgB;AAEtB,aAASC,OAAO,GAAGA,OAAOD,eAAeC,QAAQ;AAC7C,YAAMJ,YAAY,KAAKJ,iBAAiBM,QAAQd,QAAQS,SAAAA;AAExD,UAAI,CAACG,UAAUxD,UAAU;AACrB;MACJ;AAEA,YAAM6D,gBAAgBL,UAAUvD,cAAc,KAAKwC,OAAOF,gBAAgB,KAAKE,OAAOH;AACtFoB,aAAOvD,KAAKqD,UAAUtD,OAAOC,IAAI0D;AACjCH,aAAOtD,KAAKoD,UAAUtD,OAAOE,IAAIyD;IACrC;AAEA,WAAOH;EACX;;;;;;;;;;;;EAaAI,iBACInB,UACAoB,UACAnB,QACAS,WACAW,WACQ;AACR,UAAMC,QAAQnD,KAAKkC,KAAKe,SAAS5D,IAAI4D,SAAS5D,IAAI4D,SAAS3D,IAAI2D,SAAS3D,CAAC;AACzE,QAAI6D,QAAQnE,UAAS;AACjB,aAAOiE;IACX;AAEA,UAAMG,SAAS;MACX/D,GAAGwC,SAASxC,IAAI4D,SAAS5D,IAAI6D;MAC7B5D,GAAGuC,SAASvC,IAAI2D,SAAS3D,IAAI4D;IACjC;AAEA,UAAMR,YAAY,KAAKJ,iBAAiBc,QAAQtB,QAAQS,SAAAA;AAExD,QAAI,CAACG,UAAUxD,UAAU;AACrB,aAAO+D;IACX;AAEA,UAAMI,aAAaJ,SAAS5D,IAAIqD,UAAUtD,OAAOC,IAAI4D,SAAS3D,IAAIoD,UAAUtD,OAAOE;AAEnF,QAAI+D,cAAc,GAAG;AACjB,aAAOJ;IACX;AAGA,UAAMK,gBAAgB;MAClBjE,GAAG4D,SAAS5D,IAAIgE,aAAaX,UAAUtD,OAAOC;MAC9CC,GAAG2D,SAAS3D,IAAI+D,aAAaX,UAAUtD,OAAOE;IAClD;AAGA,UAAMiE,aAAavD,KAAKkC,KAAKoB,cAAcjE,IAAIiE,cAAcjE,IAAIiE,cAAchE,IAAIgE,cAAchE,CAAC;AAClG,QAAIiE,aAAaJ,QAAQ,KAAK;AAG1B,YAAMK,WAAW;QAAEnE,GAAG,CAACqD,UAAUtD,OAAOE;QAAGA,GAAGoD,UAAUtD,OAAOC;MAAE;AACjE,YAAMoE,WAAW;QAAEpE,GAAGqD,UAAUtD,OAAOE;QAAGA,GAAG,CAACoD,UAAUtD,OAAOC;MAAE;AAGjE,YAAMqE,OAAOT,SAAS5D,IAAImE,SAASnE,IAAI4D,SAAS3D,IAAIkE,SAASlE;AAC7D,YAAMqE,QAAOV,SAAS5D,IAAIoE,SAASpE,IAAI4D,SAAS3D,IAAImE,SAASnE;AAC7D,YAAMsE,YAAYF,QAAQC,QAAOH,WAAWC;AAG5C,aAAO;QACHpE,GAAGuE,UAAUvE,IAAI8D;QACjB7D,GAAGsE,UAAUtE,IAAI6D;MACrB;IACJ;AAEA,WAAOG;EACX;;;;;;;;;;;EAYAO,qBACIC,MACAC,SACAC,MACAC,SACgB;AAChB,UAAMrE,KAAKoE,KAAK3E,IAAIyE,KAAKzE;AACzB,UAAMQ,KAAKmE,KAAK1E,IAAIwE,KAAKxE;AACzB,UAAM8B,SAASxB,KAAKA,KAAKC,KAAKA;AAC9B,UAAMqE,iBAAiBH,UAAUE;AAEjC,QAAI7C,UAAU8C,iBAAiBA,gBAAgB;AAC3C,aAAOjF;IACX;AAEA,UAAMgD,WAAWjC,KAAKkC,KAAKd,MAAAA;AAC3B,UAAMjC,cAAc+E,iBAAiBjC;AAErC,QAAIE,SAAiBC;AACrB,QAAIH,WAAWjD,UAAS;AACpBmD,gBAAU,CAACvC,KAAKqC;AAChBG,gBAAU,CAACvC,KAAKoC;IACpB,OAAO;AACHE,gBAAU;AACVC,gBAAU;IACd;AAEA,WAAO;MACHlD,UAAU;MACVC;MACAC,QAAQ;QAAEC,GAAG8C;QAAS7C,GAAG8C;MAAQ;MACjC7C,cAAc;QACVF,GAAGyE,KAAKzE,IAAI8C,UAAU4B;QACtBzE,GAAGwE,KAAKxE,IAAI8C,UAAU2B;MAC1B;IACJ;EACJ;;;;;;;;;;;EAYAI,sBACIL,MACAC,SACAC,MACAC,SACoB;AACpB,UAAMvB,YAAY,KAAKmB,qBAAqBC,MAAMC,SAASC,MAAMC,OAAAA;AAEjE,QAAI,CAACvB,UAAUxD,UAAU;AACrB,aAAO;QAAC4E;QAAME;;IAClB;AAEA,UAAMI,YAAY1B,UAAUvD,cAAc,KAAKwC,OAAOF,gBAAgB,MAAM,KAAKE,OAAOH;AAExF,WAAO;MACH;QACInC,GAAGyE,KAAKzE,IAAIqD,UAAUtD,OAAOC,IAAI+E;QACjC9E,GAAGwE,KAAKxE,IAAIoD,UAAUtD,OAAOE,IAAI8E;MACrC;MACA;QACI/E,GAAG2E,KAAK3E,IAAIqD,UAAUtD,OAAOC,IAAI+E;QACjC9E,GAAG0E,KAAK1E,IAAIoD,UAAUtD,OAAOE,IAAI8E;MACrC;;EAER;AACJ;AA1Ra1C;AAAN,IAAMA,oBAAN;AAgSA,SAAS2C,wBAAwB1C,QAAiC;AACrE,SAAO,IAAID,kBAAkBC,MAAAA;AACjC;AAFgB0C;","names":["DEFAULT_ORCA_CONFIG","defaultTimeHorizon","defaultTimeHorizonObst","timeStep","epsilon","yAxisDown","DEFAULT_AGENT_PARAMS","radius","maxSpeed","neighborDist","maxNeighbors","timeHorizon","timeHorizonObst","Vector2","EPSILON","dot","det","lengthSq","Vector2","linearProgram1","lines","lineNo","radius","optVelocity","directionOpt","result","line","dotProduct","point","direction","discriminant","sqrtDiscriminant","Math","sqrt","tLeft","tRight","i","constraint","denominator","numerator","x","y","abs","t","min","max","linearProgram2","len","length","detVal","tempResult","clone","copy","linearProgram3","numObstLines","beginLine","distance","projLines","j","push","line1","line2","newLine","determinant","diff","dirDiff","dirLen","verifyObstacleConstraints","velocity","solveORCALinearProgram","maxSpeed","preferredVelocity","lineFail","feasible","violatedConstraints","EPSILON","leftOf","p1","p2","p3","x","y","createObstacleVertices","vertices","startId","n","length","obstacleVertices","i","push","point","direction","next","previous","isConvex","id","curr","prev","dx","dy","edgeLen","Math","sqrt","buildObstacleVertices","obstacles","options","yAxisDown","allVertices","nextId","obstacle","ccwVertices","ensureCCW","signedArea","isCCW","reverse","Vector2","EPSILON","det","dot","lengthSq","len","Vector2","normalize","v","length","x","y","ORCASolver","config","DEFAULT_ORCA_CONFIG","computeNewVelocity","agent","neighbors","obstacles","deltaTime","result","computeNewVelocityWithResult","velocity","orcaLines","obstacleVertices","buildObstacleVertices","yAxisDown","numObstLines","createObstacleORCALines","createAgentORCALines","solveORCALinearProgram","maxSpeed","preferredVelocity","numLines","invTimeHorizon","timeHorizon","other","id","relativePosition","position","relativeVelocity","distSq","combinedRadius","radius","combinedRadiusSq","line","point","direction","u","w","wLengthSq","dotProduct1","wLength","Math","sqrt","unitW","leg","dotProduct2","invTimeStep","push","invTimeHorizonObst","timeHorizonObst","radiusSq","obstacle1","obstacle2","next","relativePosition1","relativePosition2","obstacleVector","signedDistToEdge","alreadyCovered","existingLine","scaledRelPos1","scaledRelPos2","distSq1","distSq2","obstacleVectorSq","s","distSqLineToEdge","isConvex","obs1","obs2","leftLegDirection","rightLegDirection","leg1","max","leg2","leftNeighbor","previous","isLeftLegForeign","isRightLegForeign","negLeftNeighborDir","leftCutoff","rightCutoff","cutoffVector","sameVertex","cutoffVectorSq","t","tLeft","tRight","distSqCutoff","Infinity","distSqLeft","distSqRight","createORCASolver","KDTree","agents","agentIndices","nodes","maxLeafSize","build","length","i","push","buildRecursive","begin","end","depth","nodeIndex","node","agentIndex","splitValue","left","right","minX","Infinity","minY","maxX","maxY","agent","Math","min","position","x","y","max","count","splitDim","sortByX","sortByY","mid","floor","midAgent","indices","key","keyX","j","keyY","queryNeighbors","radius","maxResults","excludeId","results","radiusSq","queryRecursive","sort","a","b","distanceSq","closestX","closestY","dx","dy","distSqToBBox","undefined","id","adx","ady","distSq","clear","agentCount","createKDTree","EPSILON","EMPTY_COLLISION","collided","penetration","normal","x","y","closestPoint","closestPointOnSegment","point","segStart","segEnd","dx","dy","lengthSq","t","Math","max","min","isPointInPolygon","vertices","inside","n","length","i","j","xi","yi","xj","yj","closestPointOnPolygon","minDistSq","Infinity","closestPt","closestEdge","closest","distSq","distanceSq","edgeIndex","DEFAULT_COLLISION_CONFIG","responseFactor","safetyMargin","CollisionResolver","config","detectCollision","position","radius","obstacle","isInside","distance","sqrt","normalX","normalY","len","detectCollisions","obstacles","worstCollision","maxPenetration","collision","resolveCollision","result","maxIterations","iter","pushDistance","validateVelocity","velocity","deltaTime","speed","newPos","dotProduct","slideVelocity","slideSpeed","perpDir1","perpDir2","dot1","dot2","chosenDir","detectAgentCollision","posA","radiusA","posB","radiusB","combinedRadius","resolveAgentCollision","halfPush","createCollisionResolver"]}
@@ -0,0 +1 @@
1
+ //# sourceMappingURL=chunk-H5EFZBBT.js.map