docs: gate Local G2 pipeline on stable region order

This commit is contained in:
梁薄云
2026-07-31 16:05:21 +08:00
parent e8c4704d87
commit 5b072c0e35
@@ -1189,6 +1189,7 @@ git commit -m "feat: validate local G2 candidate quality"
**Files:**
- Create: `ClumsyPilot/ParkrobTrajplanner/PathSmoothing/LocalG2/LocalG2PreSmoothingPipeline.cs`
- Consume unchanged: `ClumsyPilot/ParkrobTrajplanner/PathSmoothing/LocalG2/LocalG2RegionWorkOrder.cs`
- Modify: `ClumsyPilot/ParkrobTrajplanner/PathSmoothing/Facade/PathSmoothingService.cs`
- Create: `ClumsyPilot/tests/verify_path_smoothing_local_g2_integration.ps1`
- Modify: `ClumsyPilot/tests/verify_path_smoothing_service.ps1`
@@ -1196,6 +1197,8 @@ git commit -m "feat: validate local G2 candidate quality"
**Interfaces:**
- Consumes: validated request, prepared path and fair raw baseline.
- Consumes `LocalG2RegionWorkOrder.TryCreate(...)`; pipeline iteration must not use report-order regions directly.
- Publishes region reports in the detector's original ascending order, independently of processing order.
- Produces:
```csharp
@@ -1242,6 +1245,21 @@ Assert-True ($result.Diagnostics.Metrics.MinimumBodyClearanceMeters -ge 0.02) `
For `Complete` and `PartialImprovement`, require at least one region report with `Improved`. For `PartialImprovement`, require at least one `RetainedOriginal`. Run every fixture twice and compare status, point count, coordinates and region reports.
Create one deterministic same-direction fixture with two disjoint detected
regions. Both accepted candidates must change their local replacement length.
Assert:
1. the larger-original-arc region is evaluated first;
2. the second processed region still matches the intended original front
window endpoints;
3. both reports are `Improved`;
4. reports are published in ascending original arc order;
5. both Local G2 replacements are present in the final full path;
6. two identical requests produce equal status, candidate indices, report
order, point count and point coordinates.
The test must fail if the pipeline replaces `workRegions` with `regions`.
Also create two explicit service cases:
```powershell
@@ -1273,31 +1291,68 @@ Expected: fail because the service cannot resolve `LocalG2Quintic`.
Pipeline pseudocode must be implemented directly:
```csharp
if (!_workOrder.TryCreate(
regions,
out IReadOnlyList<LocalG2SmoothingRegion> workRegions,
out string orderReason))
{
return PathSmoothingResult.Failure(
PathSmoothingStatus.Failed,
new PathSmoothingDiagnostics(
new PathQualityMetrics(),
TimeSpan.Zero,
0,
0d,
orderReason));
}
PreparedPath current = preparedPath;
var reports = new List<PathSmoothingRegionReport>();
var reportsByRegion = new Dictionary<LocalG2SmoothingRegion, PathSmoothingRegionReport>();
int improvedCount = 0;
foreach (LocalG2SmoothingRegion region in regions)
foreach (LocalG2SmoothingRegion region in workRegions)
{
cancellationToken.ThrowIfCancellationRequested();
IReadOnlyList<LocalG2CandidateGeometry> candidates =
_builder.Build(preparedPath.Segments[region.SegmentIndex], region, outputSpacing, options, cancellationToken);
_builder.Build(
preparedPath.Segments[region.SegmentIndex],
region,
outputSpacing,
options,
cancellationToken);
var evaluations = new List<LocalG2CandidateEvaluation>();
foreach (LocalG2CandidateGeometry candidate in candidates)
evaluations.Add(_evaluator.Evaluate(preparedPath, current, region, candidate, request, options, cancellationToken));
{
evaluations.Add(
_evaluator.Evaluate(
preparedPath,
current,
region,
candidate,
request,
options,
cancellationToken));
}
LocalG2CandidateEvaluation best = LocalG2CandidateEvaluator.SelectBest(evaluations);
LocalG2CandidateEvaluation best =
LocalG2CandidateEvaluator.SelectBest(evaluations);
if (best != null && best.Accepted)
{
current = best.SplicedPreparedPath;
improvedCount++;
reports.Add(CreateImprovedReport(region, best));
reportsByRegion.Add(region, CreateImprovedReport(region, best));
}
else
{
reports.Add(CreateRetainedReport(region, evaluations));
reportsByRegion.Add(
region,
CreateRetainedReport(region, evaluations));
}
}
var reports = new List<PathSmoothingRegionReport>(regions.Count);
for (int reportIndex = 0; reportIndex < regions.Count; reportIndex++)
reports.Add(reportsByRegion[regions[reportIndex]]);
```
Regions are disjoint after merging, so successful earlier replacements remain when a later region fails.