docs: align path smoothing design and execution plan
This commit is contained in:
@@ -14,13 +14,18 @@
|
||||
- Preserve start, goal, direction-segment order, gear-switch count, and gear-switch poses exactly.
|
||||
- Never differentiate, resample, or fit across a gear-switch duplicate pair.
|
||||
- Default output spacing is `0.05 m`; default swept-collision step is `0.025 m`.
|
||||
- Default clearance reserve is `0.02 m`; default smoothing strength is `1.00`.
|
||||
- A formal result publishes a path only for `Success` or explicitly verified `FallbackToCoarsePath`.
|
||||
- Movement-bound rejection is retryable; invalid input, singular coefficients, and non-finite geometry are terminal failures.
|
||||
- Every algorithm uses a read-only snapshot of its strong-typed options and maps evaluated points to the original direction segment by local arc length, never by raw point index.
|
||||
- Rejected candidates may appear only in comparison diagnostics, never in `PathSmoothingResult.Path`.
|
||||
- No speed, acceleration, time, SQP, Frenet, chassis, sensor, localization, or UI dependencies.
|
||||
- Figure size is `7.16 × 5.2 in`; PNG size is `2148 × 1560 px` with 300 dpi metadata.
|
||||
- Figure size is `7.16 × 5.2 in`; PNG size is `4296 × 3120 px` with 600 dpi metadata.
|
||||
- Chinese text uses `SimSun`; English, numbers, Greek, and mathematics use `Times New Roman`.
|
||||
- Fixed method colors are raw `#4D4D4D`, B-spline `#0072B2`, Bézier `#D55E00`, quintic `#009E73`, and curvature limits `#CC79A7`.
|
||||
- `System.Drawing.Common` is a Windows-only report-rendering dependency; smoothing, validation, comparison, SVG, and CSV remain independent of its runtime availability.
|
||||
- Text SVG is the editable master, not a directly submittable IEEE artifact; submission conversion to font-embedded or outlined PDF/EPS is an explicit external publishing step.
|
||||
- Offline timing uses one warm-up and five measured deterministic runs per scenario and method; ranking uses the measured median only.
|
||||
- Follow TDD for every task: failing verification first, minimal implementation second, full relevant verification before commit.
|
||||
|
||||
---
|
||||
@@ -460,7 +465,124 @@ git add -- ClumsyPilot/ParkrobTrajplanner/PathSmoothing/Algorithms/CubicBSplineS
|
||||
git commit -m "feat: add cubic b-spline path smoother"
|
||||
```
|
||||
|
||||
### Task 6: Local cubic Bézier smoother
|
||||
### Task 6: Align retryable feasibility, option snapshots, and arc-length references
|
||||
|
||||
**Context:** Tasks 1–5 are already committed. This corrective task resolves the review-discovered contract gaps before adding the remaining algorithms.
|
||||
|
||||
**Files:**
|
||||
- Create: `ClumsyPilot/ParkrobTrajplanner/PathSmoothing/Algorithms/SmoothingOptionsSnapshot.cs`
|
||||
- Create: `ClumsyPilot/ParkrobTrajplanner/PathSmoothing/Processing/PathReferenceInterpolator.cs`
|
||||
- Modify: `ClumsyPilot/ParkrobTrajplanner/PathSmoothing/Algorithms/SmoothingCandidate.cs`
|
||||
- Modify: `ClumsyPilot/ParkrobTrajplanner/PathSmoothing/Algorithms/SmoothingAlgorithmInput.cs`
|
||||
- Modify: `ClumsyPilot/ParkrobTrajplanner/PathSmoothing/Algorithms/SmoothingAlgorithmRunner.cs`
|
||||
- Modify: `ClumsyPilot/ParkrobTrajplanner/PathSmoothing/Algorithms/CubicBSplineSmoother.cs`
|
||||
- Test: `ClumsyPilot/tests/verify_path_smoothing_runner.ps1`
|
||||
- Test: `ClumsyPilot/tests/verify_path_smoothing_bspline.ps1`
|
||||
- Test: `ClumsyPilot/tests/verify_path_smoothing_algorithm_input.ps1`
|
||||
|
||||
**Interfaces:**
|
||||
- Produces: `SmoothingCandidateStatus.Success`, `RetryableInfeasible`, or `Failed`.
|
||||
- Produces: immutable method-specific option snapshots carried by `SmoothingAlgorithmInput`.
|
||||
- Produces: `PathReferenceInterpolator.TryInterpolateByArcLength(IReadOnlyList<SmoothingPoint2D> points, double targetArcLength, out SmoothingPoint2D reference, out string reason)` for all three algorithms.
|
||||
|
||||
- [ ] **Step 1: Write failing status, snapshot, and reference tests**
|
||||
|
||||
The reflection tests must prove:
|
||||
|
||||
```text
|
||||
RetryableInfeasible attempts exactly 1.00, 0.75, 0.50, 0.25 and ends Infeasible
|
||||
Failed attempts exactly once and ends Failed
|
||||
request/config mutation after construction cannot change the internal option snapshot
|
||||
custom EndpointTangentScale changes the B-spline endpoint handle
|
||||
non-uniform source samples interpolate by local ArcLength, not point-index ratio
|
||||
non-finite/non-positive option scalars and a threshold outside (0, π] are rejected before retry
|
||||
```
|
||||
|
||||
Use a non-uniform source with local arc lengths `0.00, 0.05, 0.10, 0.125`; at target arc `0.1125`, the reference must lie halfway through the final interval regardless of point count.
|
||||
|
||||
- [ ] **Step 2: Run and confirm RED**
|
||||
|
||||
```powershell
|
||||
powershell -ExecutionPolicy Bypass -File .\ClumsyPilot\tests\verify_path_smoothing_algorithm_input.ps1
|
||||
powershell -ExecutionPolicy Bypass -File .\ClumsyPilot\tests\verify_path_smoothing_runner.ps1
|
||||
powershell -ExecutionPolicy Bypass -File .\ClumsyPilot\tests\verify_path_smoothing_bspline.ps1
|
||||
```
|
||||
|
||||
Expected: missing candidate status/snapshot/interpolator assertions fail, and B-spline still ignores the configured endpoint scale.
|
||||
|
||||
- [ ] **Step 3: Implement the retryable candidate state**
|
||||
|
||||
Use the exact internal states:
|
||||
|
||||
```csharp
|
||||
internal enum SmoothingCandidateStatus
|
||||
{
|
||||
Success,
|
||||
RetryableInfeasible,
|
||||
Failed,
|
||||
}
|
||||
```
|
||||
|
||||
`SmoothingCandidate.Success(...)` requires complete segments. `RetryableInfeasible(reason)` and `Failed(reason)` carry no executable geometry. The runner continues only for `RetryableInfeasible`; it stops immediately for `Failed`. Exhausting retryable outcomes returns `AlgorithmRunResult.Infeasible(...)` even when no rejected comparison geometry exists.
|
||||
|
||||
- [ ] **Step 4: Implement immutable options and arc-length interpolation**
|
||||
|
||||
`SmoothingOptionsSnapshot` copies these six scalars from the request configuration into get-only values:
|
||||
|
||||
```text
|
||||
CubicBSplineEndpointTangentScale
|
||||
BezierCornerHeadingThresholdRadians
|
||||
BezierMaximumWindowLengthMeters
|
||||
BezierHandleLengthRatio
|
||||
QuinticKnotSpacingMeters
|
||||
QuinticMinimumKnotSpacingMeters
|
||||
```
|
||||
|
||||
Snapshot construction rejects non-finite values; all scales, ratios, windows, and knot lengths must be positive, the Bézier threshold must lie in `(0, π]`, and quintic knot spacing must be at least its configured minimum. These are terminal input failures, not retryable geometry outcomes.
|
||||
|
||||
Use this construction boundary:
|
||||
|
||||
```csharp
|
||||
internal SmoothingOptionsSnapshot(PathSmoothingConfiguration configuration);
|
||||
|
||||
internal SmoothingAlgorithmInput(
|
||||
PreparedPath originalPath,
|
||||
PlanningGridMap map,
|
||||
VehicleParameters vehicle,
|
||||
double maximumCollisionCheckStepMeters,
|
||||
double minimumClearanceReserveMeters,
|
||||
SmoothingOptionsSnapshot options);
|
||||
```
|
||||
|
||||
`SmoothingAlgorithmInput.Options` is get-only and never exposes the mutable public configuration objects.
|
||||
|
||||
`PathReferenceInterpolator.TryInterpolateByArcLength` locates the bracketing source samples by `SmoothingPoint2D.ArcLength` and linearly interpolates position, heading, unwrapped heading, and clearance. A normalized full-segment parameter maps to `targetArc = u * segment.Points[last].ArcLength`; local algorithms map their window or knot interval directly to its endpoint arc lengths.
|
||||
|
||||
- [ ] **Step 5: Correct B-spline option and rejection semantics**
|
||||
|
||||
Replace the hard-coded endpoint scale with `input.Options.CubicBSplineEndpointTangentScale`. Replace point-index reference interpolation with `PathReferenceInterpolator`. Evaluated-point movement excess returns `RetryableInfeasible`; invalid values, impossible endpoint-tangent construction, and non-finite controls remain `Failed`. Never clamp evaluated curve samples.
|
||||
|
||||
- [ ] **Step 6: Run corrective and shared regression checks**
|
||||
|
||||
```powershell
|
||||
dotnet build .\ClumsyPilot\ClumsyPilot.csproj --no-restore
|
||||
powershell -ExecutionPolicy Bypass -File .\ClumsyPilot\tests\verify_path_smoothing_algorithm_input.ps1
|
||||
powershell -ExecutionPolicy Bypass -File .\ClumsyPilot\tests\verify_path_smoothing_runner.ps1
|
||||
powershell -ExecutionPolicy Bypass -File .\ClumsyPilot\tests\verify_path_smoothing_bspline.ps1
|
||||
powershell -ExecutionPolicy Bypass -File .\ClumsyPilot\tests\verify_path_smoothing_geometry.ps1
|
||||
powershell -ExecutionPolicy Bypass -File .\ClumsyPilot\tests\verify_path_smoothing_validation.ps1
|
||||
```
|
||||
|
||||
Expected: all pass; retryable geometry rejection uses all four strengths, while numerical failure still uses one.
|
||||
|
||||
- [ ] **Step 7: Commit**
|
||||
|
||||
```powershell
|
||||
git add -- ClumsyPilot/ParkrobTrajplanner/PathSmoothing/Algorithms/SmoothingOptionsSnapshot.cs ClumsyPilot/ParkrobTrajplanner/PathSmoothing/Processing/PathReferenceInterpolator.cs ClumsyPilot/ParkrobTrajplanner/PathSmoothing/Algorithms/SmoothingCandidate.cs ClumsyPilot/ParkrobTrajplanner/PathSmoothing/Algorithms/SmoothingAlgorithmInput.cs ClumsyPilot/ParkrobTrajplanner/PathSmoothing/Algorithms/SmoothingAlgorithmRunner.cs ClumsyPilot/ParkrobTrajplanner/PathSmoothing/Algorithms/CubicBSplineSmoother.cs ClumsyPilot/tests/verify_path_smoothing_algorithm_input.ps1 ClumsyPilot/tests/verify_path_smoothing_runner.ps1 ClumsyPilot/tests/verify_path_smoothing_bspline.ps1
|
||||
git commit -m "fix: align smoothing feasibility and option flow"
|
||||
```
|
||||
|
||||
### Task 7: Local cubic Bézier smoother
|
||||
|
||||
**Files:**
|
||||
- Create: `ClumsyPilot/ParkrobTrajplanner/PathSmoothing/Algorithms/LocalCubicBezierSmoother.cs`
|
||||
@@ -468,7 +590,7 @@ git commit -m "feat: add cubic b-spline path smoother"
|
||||
|
||||
**Interfaces:**
|
||||
- Implements: `IPathSmoother.Method == SmoothingMethod.LocalCubicBezier`.
|
||||
- Consumes: heading-change threshold, maximum local window, handle-length ratio.
|
||||
- Consumes: the immutable Bézier heading-change threshold, maximum local window, and handle-length ratio from `SmoothingAlgorithmInput.Options`.
|
||||
|
||||
- [ ] **Step 1: Write failing local-behavior tests**
|
||||
|
||||
@@ -496,7 +618,9 @@ SmoothingPoint2D value =
|
||||
t * t * t * p3;
|
||||
```
|
||||
|
||||
For each evaluated point, compare its displacement from the parameter-matched interpolated original reference with `max(0, reference.BodyClearance - MinimumClearanceReserveMeters)`. If any point exceeds that radius, return a failed candidate with no geometry; do not pointwise clamp or project curve samples. Retain original samples outside merged windows.
|
||||
For each evaluated point, map `t` to `s_ref = s_entry + t * (s_exit - s_entry)` and obtain the source reference through `PathReferenceInterpolator`. Compare displacement with `max(0, reference.BodyClearance - MinimumClearanceReserveMeters)`. If any point exceeds that radius, return `RetryableInfeasible` with no executable geometry; do not pointwise clamp or project curve samples. Retain original samples outside merged windows.
|
||||
|
||||
Tests must set non-default threshold, window length, and handle ratio values and prove each option changes only its intended behavior.
|
||||
|
||||
- [ ] **Step 4: Run Bézier and regression checks**
|
||||
|
||||
@@ -516,7 +640,7 @@ git add -- ClumsyPilot/ParkrobTrajplanner/PathSmoothing/Algorithms/LocalCubicBez
|
||||
git commit -m "feat: add local cubic bezier smoother"
|
||||
```
|
||||
|
||||
### Task 7: Piecewise quintic Hermite smoother
|
||||
### Task 8: Piecewise quintic Hermite smoother
|
||||
|
||||
**Files:**
|
||||
- Create: `ClumsyPilot/ParkrobTrajplanner/PathSmoothing/Algorithms/PiecewiseQuinticSmoother.cs`
|
||||
@@ -524,6 +648,7 @@ git commit -m "feat: add local cubic bezier smoother"
|
||||
|
||||
**Interfaces:**
|
||||
- Implements: `IPathSmoother.Method == SmoothingMethod.PiecewiseQuintic`.
|
||||
- Consumes: immutable knot and minimum-knot spacing from `SmoothingAlgorithmInput.Options`.
|
||||
- Produces: C2-connected local polynomial segments without crossing direction boundaries.
|
||||
|
||||
- [ ] **Step 1: Write failing continuity and degeneracy tests**
|
||||
@@ -550,6 +675,8 @@ p''(0)=a0, p''(1)=a1
|
||||
|
||||
Derive endpoint velocities from travel tangents times interval length. Blend shared accelerations once per knot and reuse the same value on both adjacent intervals. Reject singular or non-finite coefficients before sampling.
|
||||
|
||||
Map every interval sample to `s_ref = s_knot0 + t * (s_knot1 - s_knot0)` through `PathReferenceInterpolator`. Movement-bound excess returns `RetryableInfeasible`; singular coefficients, non-finite derivatives, and invalid spacing return `Failed`. Never clamp evaluated polynomial samples.
|
||||
|
||||
- [ ] **Step 4: Run quintic, geometry, and validator checks**
|
||||
|
||||
```powershell
|
||||
@@ -568,7 +695,7 @@ git add -- ClumsyPilot/ParkrobTrajplanner/PathSmoothing/Algorithms/PiecewiseQuin
|
||||
git commit -m "feat: add piecewise quintic path smoother"
|
||||
```
|
||||
|
||||
### Task 8: Formal smoothing facade and explicit coarse-path fallback
|
||||
### Task 9: Formal smoothing facade and explicit coarse-path fallback
|
||||
|
||||
**Files:**
|
||||
- Create: `ClumsyPilot/ParkrobTrajplanner/PathSmoothing/Facade/PathSmoothingService.cs`
|
||||
@@ -580,7 +707,7 @@ git commit -m "feat: add piecewise quintic path smoother"
|
||||
|
||||
- [ ] **Step 1: Write failing facade tests**
|
||||
|
||||
Cover valid straight success, invalid input, cancellation, infeasible-without-fallback, and infeasible-with-verified-fallback. Assert fallback points use `CoarsePathFallback` and status never equals `Success`.
|
||||
Cover valid straight success, invalid input, cancellation, infeasible-without-fallback, and infeasible-with-verified-fallback. Invalid input must include NaN, non-positive scales/windows/spacing, Bézier threshold outside `(0, π]`, and `KnotSpacingMeters < MinimumKnotSpacingMeters`. Assert fallback points use `CoarsePathFallback` and status never equals `Success`.
|
||||
|
||||
- [ ] **Step 2: Run and confirm RED**
|
||||
|
||||
@@ -605,7 +732,7 @@ private IPathSmoother Resolve(SmoothingMethod method) =>
|
||||
};
|
||||
```
|
||||
|
||||
Validate the coarse path before smoothing. On allowed fallback, convert the revalidated coarse points to `SmoothedPathPoint` with `CoarsePathFallback`, re-run shared geometry analysis, and return `Fallback`, preserving the failed method diagnostics.
|
||||
Validate the full configuration and coarse path before constructing `SmoothingOptionsSnapshot` or starting finite retries; map every configuration-contract violation to `InvalidInput`. On allowed fallback, convert the revalidated coarse points to `SmoothedPathPoint` with `CoarsePathFallback`, re-run shared geometry analysis, and return `Fallback`, preserving the failed method diagnostics.
|
||||
|
||||
- [ ] **Step 4: Run all core smoothing verifications**
|
||||
|
||||
@@ -626,12 +753,14 @@ git add -- ClumsyPilot/ParkrobTrajplanner/PathSmoothing/Facade ClumsyPilot/tests
|
||||
git commit -m "feat: expose validated path smoothing service"
|
||||
```
|
||||
|
||||
### Task 9: Comparison metrics, isolation, and deterministic ranking
|
||||
### Task 10: Comparison metrics, isolation, and deterministic ranking
|
||||
|
||||
**Files:**
|
||||
- Create: `ClumsyPilot/ParkrobTrajplanner/PathSmoothing/Comparison/PathSmoothingComparisonRequest.cs`
|
||||
- Create: `ClumsyPilot/ParkrobTrajplanner/PathSmoothing/Comparison/PathSmoothingComparisonEntry.cs`
|
||||
- Create: `ClumsyPilot/ParkrobTrajplanner/PathSmoothing/Comparison/PathSmoothingComparisonResult.cs`
|
||||
- Create: `ClumsyPilot/ParkrobTrajplanner/PathSmoothing/Comparison/SmoothingTimingSummary.cs`
|
||||
- Create: `ClumsyPilot/ParkrobTrajplanner/PathSmoothing/Comparison/StableGeometryDigest.cs`
|
||||
- Create: `ClumsyPilot/ParkrobTrajplanner/PathSmoothing/Comparison/SmoothingMethodRanker.cs`
|
||||
- Create: `ClumsyPilot/ParkrobTrajplanner/PathSmoothing/Facade/PathSmoothingComparisonService.cs`
|
||||
- Test: `ClumsyPilot/tests/verify_path_smoothing_comparison.ps1`
|
||||
@@ -639,6 +768,8 @@ git commit -m "feat: expose validated path smoothing service"
|
||||
**Interfaces:**
|
||||
- Produces: `Compare(PathSmoothingComparisonRequest, CancellationToken)`.
|
||||
- Ranking order: feasible count; median variation energy; worst peak utilization; worst clearance loss; median length increase; median elapsed.
|
||||
- Timing protocol: one unmeasured warm-up plus five measured deterministic executions per scenario and method; rank by measured median.
|
||||
- `SmoothingTimingSummary` exposes a read-only five-value `MeasuredElapsedMilliseconds`, `MedianElapsedMilliseconds`, and `IsDeterministic`.
|
||||
|
||||
- [ ] **Step 1: Write failing comparison and ranking tests**
|
||||
|
||||
@@ -646,6 +777,8 @@ Create synthetic entries whose order changes at each tie-break level. Verify one
|
||||
|
||||
Also assert the result always contains one separately analyzed raw-path baseline plus exactly one entry for each requested method; the raw baseline is never treated as a candidate method in ranking.
|
||||
|
||||
For timing, assert the warm-up is excluded, exactly five samples remain, and a mismatch in status, point count, segment count, or stable geometry digest produces a non-deterministic diagnostic that excludes the method from recommendation.
|
||||
|
||||
- [ ] **Step 2: Run and confirm RED**
|
||||
|
||||
```powershell
|
||||
@@ -671,6 +804,8 @@ double Median(IReadOnlyList<double> values)
|
||||
|
||||
Use absolute deltas when a raw denominator has magnitude below `1e-12`. The comparison service must force `AllowFallbackToCoarsePath = false` so fallback cannot masquerade as method success.
|
||||
|
||||
Run each method once for warm-up and five times for measurement against the same immutable prepared input. Use the first measured result as the canonical comparison geometry only after all five measured outputs match its stable status and geometry digest. `StableGeometryDigest` writes status, segment metadata, enum values, and every double through `BitConverter.DoubleToInt64Bits` in fixed little-endian order, then computes SHA-256; do not use `GetHashCode()`. Store all five elapsed values plus their median; only the median participates in the final lexicographic timing tie-break.
|
||||
|
||||
- [ ] **Step 4: Run comparison and service tests**
|
||||
|
||||
```powershell
|
||||
@@ -688,7 +823,7 @@ git add -- ClumsyPilot/ParkrobTrajplanner/PathSmoothing/Comparison ClumsyPilot/P
|
||||
git commit -m "feat: compare and rank smoothing methods"
|
||||
```
|
||||
|
||||
### Task 10: Versioned fast fixtures and existing end-to-end scenarios
|
||||
### Task 11: Versioned fast fixtures and existing end-to-end scenarios
|
||||
|
||||
**Files:**
|
||||
- Create: `ClumsyPilot/ParkrobTrajplanner/PathSmoothing/Test/SmoothingScenarioFixture.cs`
|
||||
@@ -783,7 +918,7 @@ git add -- ClumsyPilot/ParkrobTrajplanner/PathSmoothing/Test ClumsyPilot/tests/g
|
||||
git commit -m "test: add path smoothing scenarios and fixtures"
|
||||
```
|
||||
|
||||
### Task 11: Shared figure model, IEEE SVG, and UTF-8 CSV
|
||||
### Task 12: Shared figure model, IEEE SVG, and UTF-8 CSV
|
||||
|
||||
**Files:**
|
||||
- Create: `ClumsyPilot/ParkrobTrajplanner/PathSmoothing/Visualization/IeeeFigureStyle.cs`
|
||||
@@ -796,6 +931,7 @@ git commit -m "test: add path smoothing scenarios and fixtures"
|
||||
**Interfaces:**
|
||||
- Consumes: immutable `PathSmoothingComparisonResult`, map, start/goal, scenario label.
|
||||
- Produces: one immutable figure model, UTF-8 SVG, and UTF-8-BOM CSV.
|
||||
- Portability boundary: text SVG is the editable master and requires exact fonts on the viewing machine; it is not claimed as a directly submittable IEEE vector file.
|
||||
|
||||
- [ ] **Step 1: Write failing style and serialization tests**
|
||||
|
||||
@@ -827,6 +963,8 @@ public const string LimitColor = "#CC79A7";
|
||||
|
||||
Allocate 60% width to panel `(a)`, split the right side between `(b)` curvature and `(c)` metrics, and compute one world-to-panel transform with equal X/Y scale.
|
||||
|
||||
Use `9 pt` for coordinate ticks, axis labels, legend, and table body; use `10 pt` for panel labels. Do not create any text smaller than `9 pt` at final physical size.
|
||||
|
||||
- [ ] **Step 4: Implement SVG and CSV**
|
||||
|
||||
SVG text must use explicit runs:
|
||||
@@ -838,7 +976,7 @@ SVG text must use explicit runs:
|
||||
CSV header order is fixed:
|
||||
|
||||
```text
|
||||
ScenarioId,Method,Status,PathLengthMeters,MaximumAbsoluteVehicleCurvaturePerMeter,RootMeanSquareVehicleCurvaturePerMeter,TotalAbsoluteCurvatureVariationPerMeter,CurvatureVariationEnergy,MinimumBodyClearanceMeters,ElapsedMilliseconds,RetryCount,AcceptedStrength
|
||||
ScenarioId,Method,Status,PathLengthMeters,MaximumAbsoluteVehicleCurvaturePerMeter,RootMeanSquareVehicleCurvaturePerMeter,TotalAbsoluteCurvatureVariationPerMeter,CurvatureVariationEnergy,MinimumBodyClearanceMeters,MedianElapsedMilliseconds,TimingSampleCount,IsDeterministic,RetryCount,AcceptedStrength
|
||||
```
|
||||
|
||||
- [ ] **Step 5: Run SVG/CSV and comparison checks**
|
||||
@@ -858,7 +996,7 @@ git add -- ClumsyPilot/ParkrobTrajplanner/PathSmoothing/Visualization ClumsyPilo
|
||||
git commit -m "feat: render ieee smoothing svg and metrics"
|
||||
```
|
||||
|
||||
### Task 12: Windows font validation and 300 dpi PNG export
|
||||
### Task 13: Windows font validation and 600 dpi PNG export
|
||||
|
||||
**Files:**
|
||||
- Modify: `ClumsyPilot/ClumsyPilot.csproj`
|
||||
@@ -873,6 +1011,7 @@ git commit -m "feat: render ieee smoothing svg and metrics"
|
||||
**Interfaces:**
|
||||
- Produces: atomic `.svg`, `.png`, `.csv` export; report failures do not mutate comparison results.
|
||||
- Runtime boundary: `SmoothingPngRenderer` is Windows-only; SVG/CSV remain usable without GDI+.
|
||||
- Submission boundary: conversion of the verified SVG master to font-embedded or outlined PDF/EPS is explicit external publishing work, not a hidden exporter side effect.
|
||||
|
||||
- [ ] **Step 1: Add the failing PNG/font verification**
|
||||
|
||||
@@ -880,8 +1019,8 @@ The script must assert:
|
||||
|
||||
```text
|
||||
PNG signature and CRC-valid chunks
|
||||
IHDR width=2148 and height=1560
|
||||
pHYs X=11811 and Y=11811 pixels/meter
|
||||
IHDR width=4296 and height=3120
|
||||
pHYs X=23622 and Y=23622 pixels/meter
|
||||
SimSun and Times New Roman were resolved by exact family name
|
||||
mixed sample "粗路径 κ(s) X (m) −π" produced non-empty glyph bounds
|
||||
missing-font test returns FontUnavailable
|
||||
@@ -926,7 +1065,7 @@ Return `FontUnavailable` before creating output files if either exact family is
|
||||
|
||||
- [ ] **Step 5: Render the shared model and write validated PNG**
|
||||
|
||||
Render at `2148 × 1560`, opaque white background, anti-aliased geometry, and no gradients/shadows. Convert bitmap pixels to RGBA and use the existing validated PNG path, extending it to insert a `pHYs` chunk with `11811` pixels/meter and correct CRC before `IDAT`.
|
||||
Render at `4296 × 3120`, opaque white background, anti-aliased geometry, and no gradients/shadows. Convert bitmap pixels to RGBA and use the existing validated PNG path, extending it to insert a `pHYs` chunk with `23622` pixels/meter and correct CRC before `IDAT`.
|
||||
|
||||
Export all three files to temporary siblings, validate each, then rename into place. On failure, remove only those exact temporary siblings.
|
||||
|
||||
@@ -948,7 +1087,7 @@ git add -- ClumsyPilot/ClumsyPilot.csproj ClumsyPilot/ParkrobTrajplanner/PathSmo
|
||||
git commit -m "feat: export ieee smoothing png reports"
|
||||
```
|
||||
|
||||
### Task 13: Module documentation, report batch entry, and full verification
|
||||
### Task 14: Module documentation, report batch entry, and full verification
|
||||
|
||||
**Files:**
|
||||
- Create: `ClumsyPilot/ParkrobTrajplanner/PathSmoothing/README.md`
|
||||
@@ -1028,7 +1167,7 @@ Expected: build exits 0 and every script prints its passed message with no termi
|
||||
powershell -ExecutionPolicy Bypass -File .\ClumsyPilot\tests\run_path_smoothing_comparison.ps1 -FixtureOnly
|
||||
```
|
||||
|
||||
Inspect `straight`, `rectangle-detour`, and `forward-reverse-switch` PNG/SVG files. Confirm four-method legend order, equal path axes, readable 8–10 pt text, no Chinese mojibake, no clipping/overlap, curvature limits, and infeasible markers where applicable.
|
||||
Inspect `straight`, `rectangle-detour`, and `forward-reverse-switch` PNG/SVG files. Confirm four-method legend order, equal path axes, readable 9–10 pt text, no Chinese mojibake, no clipping/overlap, curvature limits, and infeasible markers where applicable. Confirm the text SVG portability limitation and external PDF/EPS publishing step are documented.
|
||||
|
||||
- [ ] **Step 6: Commit**
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
粗路径由离散恒曲率运动原语拼接而成。它解决绕障拓扑、行驶方向和换向结构,但相邻原语之间的曲率可能跳变,不适合作为后续 SQP 的最终空间参考线。
|
||||
|
||||
本设计在 `CoarsePath` 之后增加独立的 `PathSmoothing` 模块。第一阶段先建设离线算法对比实验台,使用相同粗路径并行比较三次 B 样条、局部三次 Bézier 和分段五次多项式。实验台统一执行几何分析、安全复核、指标排序和 IEEE 风格绘图。算法成熟后,正式规划流程只调用选定的默认平滑方法。
|
||||
本设计在 `CoarsePath` 之后增加独立的 `PathSmoothing` 模块。第一阶段先建设离线算法对比实验台,使用相同粗路径独立比较三次 B 样条、局部三次 Bézier 和分段五次多项式;这里的“独立”不表示并发执行。实验台统一执行几何分析、安全复核、指标排序和 IEEE 风格绘图。算法成熟后,正式规划流程只调用选定的默认平滑方法。
|
||||
|
||||
## 2. 目标
|
||||
|
||||
@@ -233,9 +233,9 @@ EndsAtGearSwitch
|
||||
Method
|
||||
OutputSpacingMeters 默认 0.05
|
||||
MaximumCollisionCheckStepMeters 默认 0.025
|
||||
MinimumClearanceReserveMeters
|
||||
AllowFallbackToCoarsePath
|
||||
SmoothingStrength
|
||||
MinimumClearanceReserveMeters 默认 0.02
|
||||
AllowFallbackToCoarsePath 默认 true
|
||||
SmoothingStrength 默认 1.00
|
||||
RetryStrengthScales
|
||||
```
|
||||
|
||||
@@ -245,7 +245,20 @@ RetryStrengthScales
|
||||
1.00, 0.75, 0.50, 0.25
|
||||
```
|
||||
|
||||
每种算法拥有独立的强类型子配置,不能用无语义的字符串字典传参。
|
||||
每种算法拥有独立的强类型子配置,不能用无语义的字符串字典传参。第一版固定默认值如下:
|
||||
|
||||
```text
|
||||
CubicBSpline.EndpointTangentScale 1/3
|
||||
LocalCubicBezier.CornerHeadingThresholdRadians π/18
|
||||
LocalCubicBezier.MaximumWindowLengthMeters 0.60
|
||||
LocalCubicBezier.HandleLengthRatio 1/3
|
||||
PiecewiseQuintic.KnotSpacingMeters 0.50
|
||||
PiecewiseQuintic.MinimumKnotSpacingMeters 0.10
|
||||
```
|
||||
|
||||
公共请求在构造时复制这些配置;进入数值算法前再次转换成仅含只读标量的内部快照。算法不得硬编码或回读调用方可变配置。
|
||||
|
||||
所有配置数值必须有限;`OutputSpacingMeters`、`MaximumCollisionCheckStepMeters`、`SmoothingStrength`、控制比例及所有窗口/结点长度必须为正,`MinimumClearanceReserveMeters` 必须非负,转角阈值必须位于 `(0, π]`,且 `KnotSpacingMeters >= MinimumKnotSpacingMeters`。不满足时返回 `InvalidInput`,不得进入有限重试。
|
||||
|
||||
`MaximumCollisionCheckStepMeters` 默认值为当前粗路径默认安全精度 `0.025 m`。若上游粗规划采用了更小的检查步长,调用方必须传入相同或更小的值;平滑模块不能从未携带的粗规划配置中猜测该参数。
|
||||
|
||||
@@ -281,7 +294,9 @@ RetryStrengthScales
|
||||
|
||||
预处理器根据原路径的保守车体净空和 `MinimumClearanceReserveMeters` 计算每个样点允许的最大移动范围。该范围只用于减少平滑曲线切弯进入障碍物的概率,不构成安全证明。最终安全性只能由完整车体碰撞和扫掠复核确认。
|
||||
|
||||
算法生成候选时,每个求值输出点还必须相对同一参数处的原始插值参考点复核该范围:`max(0, reference.BodyClearance - MinimumClearanceReserveMeters)`。超限时该算法尝试必须失败并不得发布候选几何;禁止把单个求值点投影或硬裁剪回该范围,因为这会在原折点附近破坏曲线切线连续性。该候选可行性门槛不替代最终的完整车体碰撞和扫掠复核。
|
||||
算法生成候选时,每个求值输出点还必须相对同一原始弧长位置的插值参考点复核该范围:`max(0, reference.BodyClearance - MinimumClearanceReserveMeters)`。参数映射统一使用方向段局部原始弧长:完整方向段的归一化参数 `u∈[0,1]` 映射为 `s_ref=u×L_original`;局部窗口参数 `t∈[0,1]` 映射为 `s_ref=s_entry+t×(s_exit-s_entry)`;分段五次区间采用相同的结点弧长插值。禁止使用原始点索引比例代替弧长映射。
|
||||
|
||||
求值点超限属于可重试的几何不可行:该次尝试不得发布候选几何,但运行器必须继续下一个较低强度。禁止把单个求值点投影或硬裁剪回允许范围,因为这会在原折点附近破坏曲线切线连续性。该候选可行性门槛不替代最终的完整车体碰撞和扫掠复核。
|
||||
|
||||
## 9. 三种平滑方法
|
||||
|
||||
@@ -355,21 +370,25 @@ RetryStrengthScales
|
||||
|
||||
## 12. 有限安全回退
|
||||
|
||||
每种方法先按 `SmoothingStrength` 运行。候选不通过复核时,依次使用 `RetryStrengthScales` 降低平滑强度。
|
||||
每种方法先按 `SmoothingStrength` 运行。候选不通过复核或算法内的可动范围门槛时,依次使用 `RetryStrengthScales` 降低平滑强度。内部算法结果必须区分:
|
||||
|
||||
- `Success`:产生完整有限候选,进入统一分析和安全复核;
|
||||
- `RetryableInfeasible`:可动范围、局部几何约束或安全复核不满足,记录原因后尝试下一强度;
|
||||
- `Failed`:非法数值、奇异系数、输入契约错误或无法构造完整候选,立即停止该方法。
|
||||
|
||||
```text
|
||||
默认强度
|
||||
↓ 不可行
|
||||
↓ 可重试不可行
|
||||
0.75 倍
|
||||
↓ 不可行
|
||||
↓ 可重试不可行
|
||||
0.50 倍
|
||||
↓ 不可行
|
||||
↓ 可重试不可行
|
||||
0.25 倍
|
||||
↓ 不可行
|
||||
↓ 可重试不可行
|
||||
该方法标记 Infeasible
|
||||
```
|
||||
|
||||
重试次数、采用强度和每次失败原因必须进入诊断。达到有限次数后必须停止,不能无限调参。
|
||||
重试次数、采用强度和每次失败原因必须进入诊断。达到有限次数后必须停止,不能无限调参。算法返回 `Failed` 时不得用降低强度掩盖数值或契约错误。
|
||||
|
||||
正式单算法服务只有在 `AllowFallbackToCoarsePath = true` 且原粗路径重新通过完整安全复核时,才能返回 `FallbackToCoarsePath`。比较实验中的方法失败不能被回退结果伪装成该方法成功。
|
||||
|
||||
@@ -392,6 +411,10 @@ AcceptedStrength
|
||||
|
||||
曲率变化指标逐方向段计算后累加,不跨换向点产生虚假的曲率跳变。
|
||||
|
||||
正式单算法结果中的 `ComputationElapsed` 记录一次规范执行的耗时,不参与跨方法推荐。离线比较的耗时排序使用独立基准流程:每个场景和方法先预热 `1` 次,再计时 `5` 次;五次输出必须具有相同状态、路径点数和稳定几何摘要,否则该方法标记为非确定性诊断失败。稳定几何摘要按状态、方向段元数据和所有路径点字段的 IEEE 754 位模式顺序生成 SHA-256,不使用进程相关的 `GetHashCode()`。排名使用五次计时的中位数,预热和计时运行均不得改变正式比较结果。
|
||||
|
||||
比较条目另外保存 `MeasuredElapsedMilliseconds[5]`、`MedianElapsedMilliseconds`、`TimingSampleCount=5` 和 `IsDeterministic`;CSV 和排序使用 `MedianElapsedMilliseconds`,不能把正式单次 `ComputationElapsed` 混作基准中位数。
|
||||
|
||||
每个平滑结果还报告相对于原粗路径的:
|
||||
|
||||
```text
|
||||
@@ -472,7 +495,7 @@ forward-reverse-switch
|
||||
|
||||
路径图和曲率图使用相同的四方法顺序。某种方法产生完整但不可行的候选时,实验报告可以绘制其候选并在违规位置标记叉号,同时明确标注“不可行”。该候选只能存在于比较报告的只读调试数据中,不能进入正式 `PathSmoothingResult.Path`。
|
||||
|
||||
数值失败且没有完整候选时,保留图例和指标行,显示“无有效曲线”,不得伪造曲线。
|
||||
算法内可行性门槛或数值构造失败导致没有完整候选时,保留图例和指标行,显示“无有效曲线”,不得伪造曲线。
|
||||
|
||||
### 16.2 IEEE 风格版式
|
||||
|
||||
@@ -480,8 +503,8 @@ forward-reverse-switch
|
||||
|
||||
```text
|
||||
物理尺寸:7.16 × 5.2 in
|
||||
PNG:2148 × 1560 px
|
||||
分辨率:300 dpi
|
||||
PNG:4296 × 3120 px
|
||||
分辨率:600 dpi
|
||||
```
|
||||
|
||||
布局:
|
||||
@@ -543,19 +566,21 @@ IEEE 官方图形指南建议使用颜色和线型共同编码、保持字体和
|
||||
5. 字体缺失时返回明确的 `FontUnavailable` 导出失败,不能静默替换;
|
||||
6. SVG 使用 UTF-8 XML;
|
||||
7. CSV 使用带 BOM 的 UTF-8;
|
||||
8. PNG 写入并验证对应 300 dpi 的物理分辨率元数据;
|
||||
8. PNG 写入并验证对应 600 dpi 的物理分辨率元数据;
|
||||
9. 使用稳定英文文件名,中文只出现在图内和 CSV 内容中。
|
||||
|
||||
最终物理尺寸下建议:
|
||||
|
||||
```text
|
||||
坐标刻度:8 pt
|
||||
坐标刻度:9 pt
|
||||
坐标标题、图例和表格正文:9 pt
|
||||
分图编号:10 pt
|
||||
```
|
||||
|
||||
英文 Times New Roman 属于 IEEE 推荐字体。由于宋体不是 IEEE 通用英文字体清单的一部分,它只用于满足本项目中文图注需求;英文、数字和数学字符仍使用 Times New Roman。
|
||||
|
||||
字体检查只能保证生成机器正确渲染。文本型 SVG 是可编辑母版,仅保证在安装了 `SimSun` 和 `Times New Roman` 的环境中保持原排版;600 dpi PNG 是无需字体依赖的便携预览。若用于 IEEE 正式投稿,必须在模块外将已验证的 SVG 转换为 IEEE 接受的 PDF/EPS,并嵌入字体或将文字转换为轮廓;本阶段不把 SVG 声明为可直接投稿格式。
|
||||
|
||||
### 16.5 输出格式
|
||||
|
||||
每个场景输出:
|
||||
@@ -566,7 +591,7 @@ IEEE 官方图形指南建议使用颜色和线型共同编码、保持字体和
|
||||
<scenario-id>-metrics.csv
|
||||
```
|
||||
|
||||
SVG 是矢量母版,PNG 用于直接查看和现有工作流,CSV 保存每种方法的完整指标。报告输出属于生成产物,不提交到源码目录。
|
||||
SVG 是可编辑矢量母版,600 dpi PNG 用于无需字体依赖的直接查看和现有工作流,CSV 保存每种方法的完整指标。报告输出属于生成产物,不提交到源码目录。IEEE 投稿用 PDF/EPS 的字体嵌入或轮廓化转换属于显式发布步骤,不在本模块中静默完成。
|
||||
|
||||
绘图使用独立的不可变 `SmoothingFigureModel`。SVG 和 PNG 渲染器都消费该模型,以保证面板范围、曲线、颜色、字体和文本一致。
|
||||
|
||||
@@ -609,6 +634,9 @@ SVG 是矢量母版,PNG 用于直接查看和现有工作流,CSV 保存每
|
||||
- 换向点的位置、航向和顺序保持;
|
||||
- 输出点数和间距符合配置;
|
||||
- 重试强度严格递减且次数有限;
|
||||
- 可动范围超限进入下一强度,数值失败立即停止;
|
||||
- 非均匀原始采样仍按方向段局部弧长映射参考点;
|
||||
- 修改请求构造后的外部配置不影响内部算法快照;
|
||||
- 短段和退化控制点产生明确失败而非 NaN。
|
||||
|
||||
### 18.4 安全复核测试
|
||||
@@ -626,6 +654,7 @@ SVG 是矢量母版,PNG 用于直接查看和现有工作流,CSV 保存每
|
||||
- 三种方法接收同一份预处理输入;
|
||||
- 单个方法失败不影响其他方法;
|
||||
- 排序规则按固定字典序执行;
|
||||
- 每个方法预热一次、计时五次并使用中位数,非确定性输出不得参与推荐;
|
||||
- 没有可行方法时不推荐默认方法;
|
||||
- 快速夹具路径不调用 Hybrid A*;
|
||||
- 配置指纹变化会使夹具明确过期;
|
||||
@@ -639,7 +668,7 @@ SVG 是矢量母版,PNG 用于直接查看和现有工作流,CSV 保存每
|
||||
- `SimSun` 与 `Times New Roman` 检测;
|
||||
- `粗路径 κ(s) X (m) −π` 等代表性混合文本完整渲染;
|
||||
- SVG 为有效 UTF-8,包含预期字体和所有四种方法;
|
||||
- PNG 具有正确像素尺寸、PNG 结构、CRC 和 300 dpi 元数据;
|
||||
- PNG 具有 `4296 × 3120` 像素、正确 PNG 结构、CRC 和 600 dpi 元数据;
|
||||
- CSV 具有 UTF-8 BOM、稳定列顺序和不依赖区域设置的小数格式;
|
||||
- 不使用依赖平台抗锯齿细节的脆弱逐像素金图测试;
|
||||
- 至少对直线、绕障和换向三张代表图执行人工视觉检查,确认无乱码、遮挡、裁切和间距失衡。
|
||||
@@ -669,7 +698,7 @@ PathSmoothingService
|
||||
5. 不可行候选不会进入正式可执行路径。
|
||||
6. 八个快速夹具无需运行 Hybrid A* 即可完成三算法比较。
|
||||
7. 四个现有端到端场景能够从建图和 Hybrid A* 连接到平滑比较。
|
||||
8. 每个场景生成包含四路径、四曲率和指标表的 SVG、300 dpi PNG 与 UTF-8 CSV。
|
||||
8. 每个场景生成包含四路径、四曲率和指标表的 SVG、600 dpi PNG 与 UTF-8 CSV,并明确 SVG/PDF 的投稿边界。
|
||||
9. 图内中文使用宋体,英文、数字和数学字符使用 Times New Roman,代表性图无乱码、遮挡或裁切。
|
||||
10. 比较结果使用公开的字典序规则推荐方法;没有合格方法时明确不推荐。
|
||||
11. 输出可以作为后续 SQP 的空间参考路径输入,但不提前引入时间、速度或控制字段。
|
||||
|
||||
Reference in New Issue
Block a user