257 lines
11 KiB
Markdown
257 lines
11 KiB
Markdown
# Coarse Path Search Elapsed Implementation Plan
|
|||
|
|
|
||
|
|
> **For agentic workers:** REQUIRED SUB-SKILL: Use `executing-plans` to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||
|
|
|
||
|
|
**Goal:** 在保留总耗时和总超时语义的前提下,记录并显示地图就绪后生成最终粗路径的独立耗时。
|
||
|
|
|
||
|
|
**Architecture:** `PlanningDiagnostics` 增加兼容的 `PathSearchElapsed` 只读字段。`HybridAStarPlanner` 在调用 `HybridAStarSearch.Search` 前启动本地秒表,并把搜索、回溯、装配和最终复核的耗时传入诊断对象;门面总预算和 `Elapsed` 不改变。MovementTest 图层和 Toast 同时显示总耗时与路径搜索耗时。
|
||
|
|
|
||
|
|
**Tech Stack:** C# / .NET Standard 2.0、`System.Diagnostics.Stopwatch`、PowerShell 回归脚本、Clumsy `MovementTest` Painter。
|
||
|
|
|
||
|
|
## Global Constraints
|
||
|
|
|
||
|
|
- `PlanningDiagnostics.Elapsed` 继续表示从 `CoarsePathPlanningService.Plan` 入口开始的总耗时。
|
||
|
|
- `PathSearchElapsed` 不包括地图来源读取、缓存、栅格化和距离场构建。
|
||
|
|
- `PathSearchElapsed` 包含二维启发式、Hybrid A*、回溯、装配、方向分段和最终复核。
|
||
|
|
- 搜索开始前失败时 `PathSearchElapsed` 必须为 `TimeSpan.Zero`;搜索阶段失败时保留已消耗时间。
|
||
|
|
- 新构造函数参数必须放在现有参数之后并提供默认值,保持现有位置参数调用的兼容性。
|
||
|
|
- 不修改 `PlanningOperationBudget`、取消机制、超时预算或地图缓存行为。
|
||
|
|
- 不执行 Git 操作。
|
||
|
|
|
||
|
|
## 文件结构
|
||
|
|
|
||
|
|
- Modify: `ClumsyPilot/ParkrobTrajplanner/CoarsePath/Contracts/PlanningDiagnostics.cs` — 公开独立路径搜索耗时。
|
||
|
|
- Modify: `ClumsyPilot/ParkrobTrajplanner/CoarsePath/HybridAStarPlanner.cs` — 在地图就绪后的路径产出阶段计时,并写入诊断对象。
|
||
|
|
- Modify: `ClumsyPilot/ParkrobTrajplanner/CoarsePath/Test/MovementTest.CoarsePathTest.cs` — 在状态图层和 Toast 显示两种耗时。
|
||
|
|
- Modify: `ClumsyPilot/ParkrobTrajplanner/CoarsePath/README.md` — 说明两个耗时的计时边界。
|
||
|
|
- Modify: `ClumsyPilot/tests/verify_coarse_path_integration.ps1` — 验证真实路径搜索耗时和地图阶段失败的零值。
|
||
|
|
- Modify: `ClumsyPilot/tests/verify_coarse_path_ui.ps1` — 验证 UI/README 使用新字段。
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### Task 1: 路径搜索耗时诊断契约
|
||
|
|
|
||
|
|
**Files:**
|
||
|
|
- Modify: `ClumsyPilot/tests/verify_coarse_path_integration.ps1:100-108,199-204`
|
||
|
|
- Modify: `ClumsyPilot/ParkrobTrajplanner/CoarsePath/Contracts/PlanningDiagnostics.cs:10-60`
|
||
|
|
- Modify: `ClumsyPilot/ParkrobTrajplanner/CoarsePath/HybridAStarPlanner.cs:1-105,185-210`
|
||
|
|
|
||
|
|
**Interfaces:**
|
||
|
|
- Consumes: `PlanningResult.Diagnostics.Elapsed`、`HybridAStarPlanner.Plan(PlanningRequest, PlanningOperationBudget)`。
|
||
|
|
- Produces: `PlanningDiagnostics.PathSearchElapsed : TimeSpan`。
|
||
|
|
- Contract: 成功结果满足 `TimeSpan.Zero <= PathSearchElapsed <= Elapsed`;地图阶段取消的结果为 `TimeSpan.Zero`。
|
||
|
|
|
||
|
|
- [ ] **Step 1: 在集成脚本写入失败断言**
|
||
|
|
|
||
|
|
在空地图成功规划的现有诊断断言之后加入:
|
||
|
|
|
||
|
|
```powershell
|
||
|
|
Assert-True ($result.Diagnostics.PathSearchElapsed -ge [TimeSpan]::Zero) `
|
||
|
|
'Planner diagnostics must retain a non-negative path-search elapsed time.'
|
||
|
|
Assert-True ($result.Diagnostics.PathSearchElapsed -le $result.Diagnostics.Elapsed) `
|
||
|
|
'Path-search elapsed time must not exceed total planning elapsed time.'
|
||
|
|
```
|
||
|
|
|
||
|
|
在 `$cancelledFacadeResult` 的现有断言之后加入:
|
||
|
|
|
||
|
|
```powershell
|
||
|
|
Assert-Equal ([TimeSpan]::Zero) $cancelledFacadeResult.PlanningResult.Diagnostics.PathSearchElapsed `
|
||
|
|
'Map-stage cancellation must not report path-search time.'
|
||
|
|
```
|
||
|
|
|
||
|
|
- [ ] **Step 2: 运行集成脚本并确认红灯**
|
||
|
|
|
||
|
|
Run: `powershell -ExecutionPolicy Bypass -File .\ClumsyPilot\tests\verify_coarse_path_integration.ps1`
|
||
|
|
|
||
|
|
Expected: FAIL,提示 `PathSearchElapsed` 不存在或无法通过新增的路径搜索耗时断言;此前的地图和门面检查仍先通过。
|
||
|
|
|
||
|
|
- [ ] **Step 3: 以兼容形式扩展诊断对象**
|
||
|
|
|
||
|
|
在 `PlanningDiagnostics` 构造函数的最后一个参数之后增加:
|
||
|
|
|
||
|
|
```csharp
|
||
|
|
TimeSpan pathSearchElapsed = default(TimeSpan)
|
||
|
|
```
|
||
|
|
|
||
|
|
并在构造函数中加入:
|
||
|
|
|
||
|
|
```csharp
|
||
|
|
PathSearchElapsed = pathSearchElapsed;
|
||
|
|
```
|
||
|
|
|
||
|
|
在 `Elapsed` 属性之后加入:
|
||
|
|
|
||
|
|
```csharp
|
||
|
|
/// <summary>
|
||
|
|
/// 地图就绪后搜索、回溯、装配和最终复核得到最终粗路径的耗时;不含建图。搜索开始前失败时为零。
|
||
|
|
/// </summary>
|
||
|
|
public TimeSpan PathSearchElapsed { get; }
|
||
|
|
```
|
||
|
|
|
||
|
|
同时更新构造函数 XML 注释,明确 `elapsed` 是总耗时而 `pathSearchElapsed` 是不含建图的路径产出耗时。
|
||
|
|
|
||
|
|
- [ ] **Step 4: 在规划器的正确边界计时**
|
||
|
|
|
||
|
|
在 `HybridAStarPlanner.cs` 顶部加入:
|
||
|
|
|
||
|
|
```csharp
|
||
|
|
using System.Diagnostics;
|
||
|
|
```
|
||
|
|
|
||
|
|
在 `Plan(PlanningRequest request, PlanningOperationBudget budget)` 的 `try` 外部声明:
|
||
|
|
|
||
|
|
```csharp
|
||
|
|
Stopwatch pathSearchStopwatch = null;
|
||
|
|
```
|
||
|
|
|
||
|
|
在第二次 `budget.GetStopReason()` 通过、且紧接 `_search.Search(request, budget)` 前写入:
|
||
|
|
|
||
|
|
```csharp
|
||
|
|
pathSearchStopwatch = Stopwatch.StartNew();
|
||
|
|
HybridAStarSearchResult searchResult = _search.Search(request, budget);
|
||
|
|
```
|
||
|
|
|
||
|
|
将 `Failure` 签名扩展为:
|
||
|
|
|
||
|
|
```csharp
|
||
|
|
private static PlanningResult Failure(PlanningStatus status, PlanningOperationBudget budget, string reason,
|
||
|
|
HybridAStarSearchResult searchResult, Stopwatch pathSearchStopwatch = null)
|
||
|
|
```
|
||
|
|
|
||
|
|
并在内部取得:
|
||
|
|
|
||
|
|
```csharp
|
||
|
|
TimeSpan pathSearchElapsed = pathSearchStopwatch == null ? TimeSpan.Zero : pathSearchStopwatch.Elapsed;
|
||
|
|
return PlanningResult.Failure(status, CreateDiagnostics(searchResult, budget.Elapsed, 0d, 0d, reason,
|
||
|
|
pathSearchElapsed));
|
||
|
|
```
|
||
|
|
|
||
|
|
将 `_search.Search` 之后的每个失败返回和 `catch` 都传入 `pathSearchStopwatch`。成功结果调用改为:
|
||
|
|
|
||
|
|
```csharp
|
||
|
|
return PlanningResult.Success(path, segments, CreateDiagnostics(searchResult, budget.Elapsed, pathLengthMeters,
|
||
|
|
minimumClearanceMeters, string.Empty, pathSearchStopwatch.Elapsed));
|
||
|
|
```
|
||
|
|
|
||
|
|
最后将 `CreateDiagnostics` 扩展为接收最后一个 `TimeSpan pathSearchElapsed` 参数,并将其作为 `PlanningDiagnostics` 的最后一个实参传入。
|
||
|
|
|
||
|
|
- [ ] **Step 5: 运行集成脚本并确认绿灯**
|
||
|
|
|
||
|
|
Run: `dotnet build .\ClumsyPilot\ClumsyPilot.csproj --no-restore`
|
||
|
|
|
||
|
|
Expected: exit code 0;只允许项目既有的过时 API 警告。
|
||
|
|
|
||
|
|
Run: `powershell -ExecutionPolicy Bypass -File .\ClumsyPilot\tests\verify_coarse_path_integration.ps1`
|
||
|
|
|
||
|
|
Expected: `Coarse path integration checks passed.`、`Coarse path facade checks passed.`、`Coarse path P1 scenario checks passed.`。
|
||
|
|
|
||
|
|
### Task 2: 图层、Toast 与 README 展示
|
||
|
|
|
||
|
|
**Files:**
|
||
|
|
- Modify: `ClumsyPilot/tests/verify_coarse_path_ui.ps1:15-70`
|
||
|
|
- Modify: `ClumsyPilot/ParkrobTrajplanner/CoarsePath/Test/MovementTest.CoarsePathTest.cs:494-513`
|
||
|
|
- Modify: `ClumsyPilot/ParkrobTrajplanner/CoarsePath/README.md:285-337`
|
||
|
|
|
||
|
|
**Interfaces:**
|
||
|
|
- Consumes: `result.PlanningResult.Diagnostics.Elapsed` 和 Task 1 提供的 `PathSearchElapsed`。
|
||
|
|
- Produces: 状态图层与 Toast 中的“总耗时”和“路径搜索”文本,以及对应 README 说明。
|
||
|
|
- Contract: 展示值均使用毫秒、`InvariantCulture` 和 `F0` 格式;不改变后台任务、取消或 Painter 图层名称。
|
||
|
|
|
||
|
|
- [ ] **Step 1: 为 UI 和 README 写入失败检查**
|
||
|
|
|
||
|
|
在 UI 源码断言区域加入:
|
||
|
|
|
||
|
|
```powershell
|
||
|
|
Assert-True (([regex]::Matches($source, 'PathSearchElapsed')).Count -ge 2) `
|
||
|
|
'The status layer and Toast must both show path-search elapsed time.'
|
||
|
|
Assert-Match $source '路径搜索' 'The UI must label the independent path-search elapsed time.'
|
||
|
|
```
|
||
|
|
|
||
|
|
在 `$readmeStructure` 数组加入:
|
||
|
|
|
||
|
|
```powershell
|
||
|
|
'PathSearchElapsed',
|
||
|
|
'路径搜索耗时',
|
||
|
|
```
|
||
|
|
|
||
|
|
- [ ] **Step 2: 运行 UI 脚本并确认红灯**
|
||
|
|
|
||
|
|
Run: `powershell -ExecutionPolicy Bypass -File .\ClumsyPilot\tests\verify_coarse_path_ui.ps1`
|
||
|
|
|
||
|
|
Expected: FAIL,提示状态图层与 Toast 尚未显示 `PathSearchElapsed`,或 README 尚未说明该字段。
|
||
|
|
|
||
|
|
- [ ] **Step 3: 同时更新状态图层和 Toast**
|
||
|
|
|
||
|
|
在 `DrawStatus` 中将单一耗时文本替换为:
|
||
|
|
|
||
|
|
```csharp
|
||
|
|
Painter.DrawText(Color.White, "栅格:" + resolution + ",规划:" + result.PlanningResult.Status + ",总耗时:" +
|
||
|
|
result.PlanningResult.Diagnostics.Elapsed.TotalMilliseconds.ToString("F0", CultureInfo.InvariantCulture) +
|
||
|
|
" ms,路径搜索:" + result.PlanningResult.Diagnostics.PathSearchElapsed.TotalMilliseconds.ToString("F0", CultureInfo.InvariantCulture) +
|
||
|
|
" ms", x, y + 240f);
|
||
|
|
```
|
||
|
|
|
||
|
|
在 `BuildToastMessage` 中将返回字符串替换为:
|
||
|
|
|
||
|
|
```csharp
|
||
|
|
return "粗路径[" + scenarioName + "]:地图=" + result.MapResult.Status + ",规划=" +
|
||
|
|
result.PlanningResult.Status + ",总耗时=" +
|
||
|
|
result.PlanningResult.Diagnostics.Elapsed.TotalMilliseconds.ToString("F0", CultureInfo.InvariantCulture) +
|
||
|
|
"ms,路径搜索=" + result.PlanningResult.Diagnostics.PathSearchElapsed.TotalMilliseconds.ToString("F0", CultureInfo.InvariantCulture) +
|
||
|
|
"ms。";
|
||
|
|
```
|
||
|
|
|
||
|
|
- [ ] **Step 4: 补充 README 的耗时定义**
|
||
|
|
|
||
|
|
在 “P1 手动测试与可视化” 的 “后台执行、停止与图层” 小节,在当前 `PlanningGridMap` 说明之后插入:
|
||
|
|
|
||
|
|
```markdown
|
||
|
|
状态图层和 Toast 同时显示总耗时与 `PathSearchElapsed`(路径搜索耗时)。总耗时从
|
||
|
|
`CoarsePathPlanningService.Plan` 入口开始,包含地图创建;路径搜索耗时从地图和起终点
|
||
|
|
预检通过、即将进入 Hybrid A* 时开始,包含二维启发式、Hybrid A*、回溯、装配与最终复核,
|
||
|
|
不包含建图。搜索开始前即失败时该值为 0 ms。
|
||
|
|
```
|
||
|
|
|
||
|
|
- [ ] **Step 5: 运行 UI 检查并确认绿灯**
|
||
|
|
|
||
|
|
Run: `powershell -ExecutionPolicy Bypass -File .\ClumsyPilot\tests\verify_coarse_path_ui.ps1`
|
||
|
|
|
||
|
|
Expected: `Coarse path P1 UI source checks passed.`。
|
||
|
|
|
||
|
|
### Task 3: 最终回归与验收
|
||
|
|
|
||
|
|
**Files:**
|
||
|
|
- Verify: `ClumsyPilot/ParkrobTrajplanner/CoarsePath/Contracts/PlanningDiagnostics.cs`
|
||
|
|
- Verify: `ClumsyPilot/ParkrobTrajplanner/CoarsePath/HybridAStarPlanner.cs`
|
||
|
|
- Verify: `ClumsyPilot/ParkrobTrajplanner/CoarsePath/Test/MovementTest.CoarsePathTest.cs`
|
||
|
|
- Verify: `ClumsyPilot/ParkrobTrajplanner/CoarsePath/README.md`
|
||
|
|
|
||
|
|
**Interfaces:**
|
||
|
|
- Consumes: 任务 1 和任务 2 的已完成代码与脚本。
|
||
|
|
- Produces: 已验证的构建、集成回归和 UI/README 检查结果。
|
||
|
|
|
||
|
|
- [ ] **Step 1: 重新阅读计时边界**
|
||
|
|
|
||
|
|
确认 `PathSearchElapsed` 只在 `_search.Search` 前启动;所有搜索后成功和失败路径均使用同一秒表;任何搜索前返回保持零值;总预算仍由 `PlanningOperationBudget` 控制。
|
||
|
|
|
||
|
|
- [ ] **Step 2: 运行最终构建**
|
||
|
|
|
||
|
|
Run: `dotnet build .\ClumsyPilot\ClumsyPilot.csproj --no-restore`
|
||
|
|
|
||
|
|
Expected: exit code 0。
|
||
|
|
|
||
|
|
- [ ] **Step 3: 运行最终自动化验证**
|
||
|
|
|
||
|
|
Run: `powershell -ExecutionPolicy Bypass -File .\ClumsyPilot\tests\verify_coarse_path_ui.ps1`
|
||
|
|
|
||
|
|
Expected: `Coarse path P1 UI source checks passed.`。
|
||
|
|
|
||
|
|
Run: `powershell -ExecutionPolicy Bypass -File .\ClumsyPilot\tests\verify_coarse_path_integration.ps1`
|
||
|
|
|
||
|
|
Expected: `Coarse path integration checks passed.`、`Coarse path facade checks passed.`、`Coarse path P1 scenario checks passed.`。
|
||
|
|
|
||
|
|
- [ ] **Step 4: 进行手动界面验收**
|
||
|
|
|
||
|
|
在可用 Clumsy 界面运行“粗路径规划-显式空图”或“粗路径规划-单矩形绕行”,确认状态图层和 Toast 都包含 `总耗时` 与 `路径搜索` 两个毫秒值,且点击停止仍能取消当前任务。
|
||
|
|
|