# PathSmoothing 路径平滑（Local G2）

## 模块说明（Module Overview）

`PathSmoothing` 是 Hybrid A* 成功输出后的空间参考路径后处理模块。它只保留 Local G2 五次过渡算法：在同一行驶方向的粗路径段内检测车辆曲率跳变，尝试以局部五次曲线替换，并对整条结果进行车辆曲率、全车体碰撞、净空和曲率变化代价复核。

该模块不参与粗路径搜索接受条件，也不做时间参数化、速度、加速度、转向速率或动态障碍物处理。下游只能消费本模块已经发布的空间路径。

## 文件结构（File Structure）

```text
PathSmoothing/
├── Contracts/                 # 请求、结果、配置、状态、质量指标与区域报告
├── Facade/                    # 正式平滑入口和离线比较入口
├── LocalG2/                   # 跳变检测、窗口规划、候选生成、评估、拼接
├── Processing/                # 粗路径预处理、原始基线和几何分析
├── Validation/                # 全车体碰撞与车辆曲率复核
├── Output/
│   ├── Comparison/            # 原始路径与 Local G2 的稳定比较模型和摘要
│   └── Visualization/         # SVG、PNG、CSV 报告模型和导出器
├── Test/                      # 固定夹具、演示入口和 Local G2 诊断证据
│   └── Fixtures/              # 版本化的成功粗路径快照
└── README.md
```

`Algorithms/`、旧的 `Comparison/`、旧的 `Visualization/` 以及 B-spline、局部 Bezier、分段五次选项均已移除。输出相关代码统一归入 `Output/`，与 `CoarsePath/Output/` 的组织方式保持一致。

## 平滑数据流（Smoothing Data Flow）

```text
成功的 CoarsePath
  -> PathSmoothingRequest 快照
  -> 输入校验与 PathSmoothingPreprocessor
  -> RawPathBaselineBuilder 原始路径全局复核
  -> CurvatureTransitionDetector（仅同向 PathSegment 内）
  -> LocalG2WindowPlanner
  -> LocalG2CandidateBuilder / LocalG2CandidateEvaluator
  -> LocalG2PathSplicer
  -> 全路径曲率、碰撞、净空、代价复核
  -> PathSmoothingResult.PublishLocalG2
```

Local G2 不跨换向段建立窗口。它处理的是同一前进或倒退段内、由运动原语摆角变化等原因形成的车辆曲率跳变，而不是把换向点作为平滑对象。

## 结果状态与发布规则（Result Status and Publication Rules）

下列四个状态都会发布已复核的 `Path` 和 `Segments`，可由下游消费：

| 状态 | 含义 |
| --- | --- |
| `Complete` | 检测到的所有 Local G2 区域都被接受并替换。 |
| `PartialImprovement` | 至少一个区域被替换，其余区域保留原始几何。 |
| `NotNeeded` | 没有检测到同向段内的曲率跳变；发布已复核的原始路径。 |
| `Unchanged` | 检测到区域，但所有候选都被拒绝；发布已复核的原始路径，并保留 `RegionReports`。 |

`InvalidInput`、`Cancelled`、`Failed` 和 `Infeasible` 不发布可消费路径。`Unchanged` 不是失败，它表示“安全门或质量门没有接受新候选”，不是“原始粗路径未经验证地回退”。

### 区域报告与拒绝原因

`PathSmoothingRegionReport` 按检测顺序记录每个 Local G2 区域。区域状态为 `Improved` 或 `RetainedOriginal`；后者可进一步给出 `WindowUnavailable`、`CandidateGenerationFailed`、`Collision`、`InsufficientClearance`、`CurvatureExceeded`、`CurvatureOvershoot`、`DeviationExceeded`、`InsufficientImprovement`、`VariationCostRegression` 或 `GlobalValidationRollback`。

候选先进行全车体碰撞复核，再检查净空余量。`MinimumClearanceReserveMeters = 0d` 只取消额外净空储备，不会取消车辆曲率、碰撞、数值有效性、偏差或曲率变化代价门。

## 坐标与单位（Coordinates and Units）

- 路径位置、弧长、窗口长度、偏差、净空和碰撞检查步长：m
- 航向：rad
- 车辆曲率：`1/m`
- 车辆曲率导数：`1/m^2`
- 地图构建输入仍沿用 mm；`PlanningGridMap` 的路径复核查询使用 m

发布路径保留成功粗路径的首尾位姿，因此末端误差继承粗规划器已接受的目标容差。

## 最小调用示例（Minimal Call Example）

```csharp
if (coarseResult.PlanningResult.Status != PlanningStatus.Success)
    return;

var request = new PathSmoothingRequest(
    coarseResult.PlanningResult.Path,
    coarseResult.PlanningResult.Segments,
    coarseResult.MapResult.Map,
    job.Vehicle,
    new PathSmoothingConfiguration());

PathSmoothingResult result = new PathSmoothingService().Smooth(request, cancellationToken);
bool published = result.Status == PathSmoothingStatus.Complete ||
    result.Status == PathSmoothingStatus.PartialImprovement ||
    result.Status == PathSmoothingStatus.NotNeeded ||
    result.Status == PathSmoothingStatus.Unchanged;

if (published)
    ConsumeSpatialReference(result.Path, result.Segments);
```

`PathSmoothingConfiguration` 没有算法选择开关；正式入口始终执行 Local G2。

## 详细使用指南（Detailed Usage Guide）

1. 长期持有 `PathSmoothingService`，只向它传入成功的粗路径、方向分段、规划地图和车辆参数。
2. 使用 `PathSmoothingConfiguration` 调整输出采样、碰撞检查步长和 Local G2 窗口/质量门参数。
3. `MinimumClearanceReserveMeters` 当前默认 `0d`。需要额外净空时显式设置正值；碰撞约束始终存在。
4. 按上表判断结果是否已发布，随后消费 `Path` 和 `Segments`；不要以 `Failed` 或 `Cancelled` 的空路径继续规划。
5. 对 `PartialImprovement` 或 `Unchanged`，读取 `RegionReports` 判断被保留的区域以及拒绝原因。

Local G2 关键选项位于 `LocalG2Quintic`：最小、首选和最大窗口长度，最大偏差，曲率跳变阈值，峰值曲率导数改善比，曲率变化代价回退比，以及每区候选数。

## 固定夹具报告与可视化（Fixture Reports and Visualization）

`SmoothingScenarioFixtureLoader.LoadAndVerify` 会校验 JSON 夹具的版本和指纹；夹具报告不重新运行 Hybrid A*。离线比较始终输出“原始粗路径 + Local G2”两组数据。

`SmoothingReportExporter.Export(SmoothingReportExportRequest)` 为每个场景写入 CSV、SVG 和 PNG。常规图固定为四张：

1. `01-coarse-path-overview`
2. `02-all-paths-comparison`
3. `03-local-g2-overview`
4. `04-curvature-comparison`

当模型显式附带诊断候选时，额外写入 `05-local-g2-diagnostic-candidate`。诊断候选仅用于解释拒绝，不是发布路径。

报告默认写入 `ClumsyPilot/obj/path_smoothing_reports` 的调用方指定子目录。PNG 需要 Windows 的 `SimSun` 与 `Times New Roman`；若字体不可用，导出返回 `FontUnavailable`，SVG 和 CSV 仍可单独使用。

## 常见错误（Common Errors）

- 将未成功的 CoarsePath 直接传入平滑：应先检查 `PlanningStatus.Success`。
- 把 `Unchanged` 当作失败：它仍然包含已复核的原始路径和区域报告。
- 认为净空余量为 0 会关闭碰撞检查：它只取消额外储备，不能绕过全车体碰撞和车辆曲率门。
- 在换向点两侧强行连续平滑：当前窗口检测明确不跨方向段。
- 使用过期夹具：修改粗路径场景或规划配置后，应按夹具生成/验证脚本更新快照。

## 第一版限制（First-Version Limits）

- 仅平滑同向段内的车辆曲率跳变；不跨换向点。
- 仅包含 Local G2 五次局部过渡，不提供多算法比较或算法回退。
- 只输出几何空间路径；没有时间、速度、加速度、转向速率和动态障碍物约束。
- Local G2 候选必须通过严格的全路径复核；在当前夹具上，`Unchanged` 和 `Failed` 仍是有价值的诊断结果，而不是自动放宽安全约束的信号。
