Wire IDistanceComputer into RotationSlideStrategy, replacing inline
CPU/GPU branching. BestFitFinder constructs the appropriate implementation.
Replace PushDirection enum with direction vectors in BuildOffsets.
Rename IBestFitStrategy.Type and PairCandidate.StrategyType to StrategyIndex
for clarity (JSON field name unchanged for backward compatibility).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Three bugs fixed in NfpSlideStrategy pipeline:
1. NoFitPolygon.Reflect() incorrectly reversed vertex order. Point
reflection (negating both axes) is a 180° rotation that preserves
winding — the Reverse() call was converting CCW to CW, producing
self-intersecting bowtie NFPs.
2. PolygonHelper inflation used OffsetSide.Left which is inward for
CCW perimeters. Changed to OffsetSide.Right for outward inflation
so NFP boundary positions give properly-spaced part placements.
3. Removed incorrect correction vector — same-drawing pairs have
identical polygon-to-part offsets that cancel out in the NFP
displacement.
Also refactored NfpSlideStrategy to be immutable (removed mutable
cache fields, single constructor with required data, added Create
factory method). BestFitFinder remains on RotationSlideStrategy
as default.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
NFP strategy has coordinate correction issues causing overlaps.
The slide-based approach is fast and accurate — keeping it as default.
NfpSlideStrategy and PolygonHelper remain in the codebase for future use.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace RotationSlideStrategy with NfpSlideStrategy in BuildStrategies,
and add integration tests covering the end-to-end FindBestFits pipeline.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The BestFitFilter's aspect ratio cap of 5.0 was rejecting valid pair
candidates needed for narrow plates (e.g. 60x6.5, aspect 9.2) and
remainder strips on normal plates. Three fixes:
- BestFitFinder: derive MaxAspectRatio from the plate's own aspect
ratio so narrow plates don't reject all elongated pairs
- SelectPairCandidates: search the full unfiltered candidate list
(not just Keep=true) in strip mode, so pairs rejected by aspect
ratio for the main plate can still be used for narrow remainder
strips
- BestFitCache.Populate: skip caching empty result lists so stale
pre-computed data from nest files doesn't prevent recomputation
Also fixes console --size parsing to use LxW format matching
Size.Parse convention, and includes prior engine refactoring
(sequential fill loops, parallel FillPattern, pre-sorted edge
arrays in RotationSlideStrategy).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Thread ISlideComputer through BestFitCache → BestFitFinder →
RotationSlideStrategy. RotationSlideStrategy now collects all offsets
across 4 push directions and dispatches them in a single batch (GPU or
CPU fallback). Also improves rotation angle extraction: uses raw geometry
(line endpoints + arc cardinal extremes) instead of tessellation to avoid
flooding the hull with near-duplicate edge angles, and adds a 5-degree
deduplication threshold.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Narrow remnant strips now get more parts by:
- Sweeping rotations every 5° when the strip is narrower than the part
- Including all pairs that fit the strip width (not just top 50 by area)
- Placing individual parts from incomplete pattern copies that still fit
- Using finer polygon tolerance (0.01) for hull edge angle detection
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>