Commit Graph
26 Commits
Author SHA1 Message Date
ajandClaude Sonnet 5 a764a70e52 fix(engine): make canonical-frame fills orientation-invariant
Part.Rotation is cumulative, so rebinding canonical parts with
CreateAtOrigin(original, p.Rotation) double-counted the drawing's own
rotation, and FromCanonical rotated each part about its Location, which
moved it off its slot and out of the work area. Add
CanonicalFrame.RebindToOriginal (rotation = part - original program
rotation, footprint aligned to the canonical part) and use it in the
three places that duplicated the old logic.

The MBR only fixes the frame modulo 90 degrees and nest results are not
90-degree symmetric (an L gave 56/43/42/42 parts by orientation).
CanonicalAngle.Compute now picks one of the four orientations from the
centroid offset; symmetric shapes keep the MBR orientation.

Fixes the three NestInvarianceTests.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-21 11:07:44 -04:00
aj aec0523062 style: apply CSharpier formatting to all C# sources
Repo-wide sweep with the pinned CSharpier 1.3.0 tool. Whitespace and
line-wrapping only; OpenNest.Engine.Tests (109) and OpenNest.IO.Tests
pass after reformat, full solution builds 0 errors.

Added .csharpierignore so csproj/config XML keeps its existing layout
(CSharpier's XML wrapping churns attributes with zero benefit).

Formatting is now enforceable: dotnet csharpier check . passes.
2026-09-20 16:41:50 -04:00
aj 5b88d85937 fix(engine): isolate job identity and engine selection
Replace name-based quantity deduction with reference-based drawing
identity in the engine paths the whole-job runner reaches
(NestEngineBase fill/pack, StripNestEngine deduction, RemnantFiller
ledger, IterativeShrinkFiller leftovers). Add instance-scoped
PlateNesterFactory that resolves built-in strategies without touching
the global NestEngineRegistry. Add identity and engine-selection tests.

44 net8.0 tests pass in Debug and Release; no new warnings.
2026-09-17 15:35:59 -04:00
aj 199095ee43 fix(engine): canonicalize PlaceBestFitPairs builds to match BestFitCache frame 2026-04-23 08:22:20 -04:00
ajandClaude Opus 4.6 e93523d7a2 perf: optimize best fit computation and plate optimizer
- Try all valid best fit pairs instead of only the first when qty=2,
  picking the best via IsBetterFill comparer (fixes suboptimal plate
  selection during auto-nesting)
- Pre-compute best fits across all plate sizes once via
  BestFitCache.ComputeForSizes instead of per-size GPU evaluation
- Early exit plate optimizer when all items fit (salvage < 100%)
- Trim slide offset sweep range to 50% overlap to reduce candidates
- Use actual geometry (ray-arc/ray-circle intersection) instead of
  tessellated polygons for slide distance computation — eliminates
  the massive line count from circle/arc tessellation
- Add RayArcDistance and RayCircleDistance to SpatialQuery
- Add PartGeometry.GetOffsetPerimeterEntities for non-tessellated
  perimeter extraction
- Disable GPU slide computer (slower than CPU currently)
- Remove dead SelectBestFitPair virtual method and overrides

Reduces best fit computation from 7+ minutes to ~4 seconds for a
73x25" part with 30+ holes on a 48x96 plate.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 10:21:44 -04:00
ajandClaude Opus 4.6 f78cc78a65 fix: improve fill progress reporting and engine pipeline
- Strategies now promote results to IsOverallBest when they beat the
  pipeline best, so the UI updates immediately on improvement rather
  than waiting for each phase to complete
- PlateView only updates the main view on overall-best results, fixing
  intermediate angle-sweep layouts leaking to the plate display
- Skip Row/Column strategies for rectangle parts (redundant with Linear)
- Intercept Escape key at MainForm level via ProcessCmdKey so it always
  reaches the active PlateView regardless of focus state
- Restore keyboard focus to PlateView after fill progress form closes
- Remnant engines use SelectBestFitPair for orientation-aware pair
  selection; DefaultNestEngine tries both landscape and portrait pairs
- RemnantFiller preserves more parts during topmost-part removal

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 20:52:13 -04:00
ajandClaude Opus 4.6 b15375cca5 feat: capacity-based fill/pack split with best-fit pair placement
Change Nest() to decide fill vs pack based on total area coverage
instead of qty != 1. Items covering < 10% of the plate are packed,
so large parts get prime position and small low-qty parts fill gaps.

Qty=2 items are placed as interlocking best-fit pairs in remnant
spaces after the main pack phase, rather than as separate rectangles.

- Add ShouldFill() capacity-based heuristic
- Split pack phase: regular items pack first, then pairs
- Add PlaceBestFitPairs() for Phase 3 remnant pair placement

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 00:38:57 -04:00
ajandClaude Opus 4.6 05037bc928 feat: wire PartClassifier into engine and update angle selection
Replace RotationAnalysis.FindBestRotation with PartClassifier.Classify in
RunPipeline, propagate ClassificationResult through BuildAngles signatures and
FillContext.PartType, and rewrite AngleCandidateBuilder to dispatch on part type
(Circle=1 angle, Rectangle=2, Irregular=full sweep).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 22:19:20 -04:00
ajandClaude Opus 4.6 abc707f1d9 fix: allow line-on-line contact and remove extra spacing gap
- Part.Intersects: filter intersection points at a vertex of either
  shape (was both), so edge-touching parts are not flagged as overlapping
- NestEngineBase.HasOverlaps: use epsilon-based bounding box pre-filter
  consistent with FillExtents and Plate.HasOverlappingParts
- PartGeometry.GetOffsetPartLines: remove extra chordTolerance added to
  spacing offset — was causing 0.002" gap beyond the intended part spacing

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 15:36:35 -04:00
ajandClaude Opus 4.6 07d6f08e8b feat: engine-specific TrimAxis and rename ShrinkAxis.Height to Length
Make quantity trimming direction-aware: DefaultNestEngine uses TrimAxis
(virtual property on NestEngineBase) so HorizontalRemnantEngine removes
topmost parts instead of rightmost. Rename ShrinkAxis.Height → Length
for consistency with Width/Length naming used throughout the codebase.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 19:43:29 -04:00
ajandClaude Opus 4.6 ccd402c50f refactor: simplify NestProgress with computed properties and ProgressReport struct
Replace stored property setters (BestPartCount, BestDensity, NestedWidth,
NestedLength, NestedArea) with computed properties that derive values from
BestParts, with a lazy cache invalidated on setter. Add internal
ProgressReport struct to replace the 7-parameter ReportProgress signature.
Update all 13 callsites and AccumulatingProgress. Delete FormatPhaseName
in favor of NestPhase.ShortName() extension.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 19:44:45 -04:00
ajandClaude Sonnet 4.6 99546e7eef feat: add IFillComparer hooks to NestEngineBase
Add virtual comparer, direction, and angle-building hooks to NestEngineBase
so subclasses can override scoring and direction policy. Rewire IsBetterFill
to delegate to the comparer instead of calling FillScore directly.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-21 12:43:45 -04:00
ajandClaude Sonnet 4.6 c88cec2beb perf: remove no-op AutoNester.Optimize calls from fill pipelines
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 20:11:49 -04:00
ajandClaude Opus 4.6 cf1c5fe120 feat: integrate NFP optimization into nest engines and fill UI
Add Compactor.Settle and AutoNester.Optimize post-passes to
NestEngineBase.Nest, StripNestEngine, and PlateView.FillWithProgress
so all fill paths benefit from geometry-aware compaction.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 14:43:24 -04:00
ajandClaude Sonnet 4.6 e789fe312d feat(engine): add IsOverallBest flag to NestProgress
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-18 22:11:29 -04:00
ajandClaude Opus 4.6 0e1e619f0a refactor(engine): move fill and strategy code to dedicated namespaces
Move fill algorithms to OpenNest.Engine.Fill namespace:
FillLinear, FillExtents, PairFiller, ShrinkFiller, Compactor,
RemnantFiller, RemnantFinder, FillScore, Pattern, PatternTiler,
PartBoundary, RotationAnalysis, AngleCandidateBuilder, and
AccumulatingProgress.

Move strategy layer to OpenNest.Engine.Strategies namespace:
IFillStrategy, FillContext, FillStrategyRegistry, FillHelpers,
and all built-in strategy implementations.

Add using directives to all consuming files across Engine, UI,
MCP, and Tests projects.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 16:46:11 -04:00
ajandClaude Sonnet 4.6 4348e5c427 feat(engine): add NestPhase.Custom for plugin fill strategies
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-18 12:57:23 -04:00
aj 6e30e24957 feat(engine): add NestPhase.Extents enum value 2026-03-18 00:42:48 -04:00
ajandClaude Opus 4.6 5bb637f3e2 refactor(engine): use RemnantFiller in NestEngineBase.Nest
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 22:38:53 -04:00
ajandClaude Opus 4.6 c8587929b5 refactor(engine): extract PairFiller from DefaultNestEngine
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 22:31:51 -04:00
ajandClaude Sonnet 4.6 6419f6b8a2 feat: report ActiveWorkArea in NestProgress from ReportProgress
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-16 12:58:17 -04:00
ajandClaude Sonnet 4.6 4d30178752 refactor: replace ComputeRemainderWithin with RemnantFinder in Nest()
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-16 12:51:25 -04:00
ajandClaude Sonnet 4.6 2b578fa006 refactor: remove NestPhase.Remainder enum value and switch cases
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-16 12:50:48 -04:00
aj dd3a2b0e9a refactor: remove UsableRemnantArea from NestProgress and UI 2026-03-16 12:47:57 -04:00
ajandClaude Opus 4.6 48be4d5d46 feat: add virtual Nest method to NestEngineBase for polymorphic auto-nest
The auto-nest code paths (MainForm, MCP, Console) now call
engine.Nest(items, progress, token) instead of manually orchestrating
sequential fill+pack. The default implementation in NestEngineBase
does sequential FillExact+PackArea. StripNestEngine overrides with
its strip strategy. This makes the engine dropdown actually work.

Also consolidates ComputeRemainderWithin into NestEngineBase,
removing duplicates from MainForm and StripNestEngine.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 22:16:08 -04:00
ajandClaude Opus 4.6 1bcfe5d031 feat: add NestEngineBase abstract class, rename NestEngine to DefaultNestEngine
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 21:06:28 -04:00