Commit Graph

62 Commits

Author SHA1 Message Date
7f96d632f3 fix: correct NFP polygon computation and inflation direction
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>
2026-03-20 23:24:04 -04:00
bc78ddc49c perf: use convex hull NFP to avoid Clipper2 union bottleneck
ConvexMinkowskiSum is O(n+m) with no boolean geometry ops.
The concave Minkowski path was doing triangulation + pairwise
sums + Clipper2 Union, which hung at 100% CPU for complex parts.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 20:54:19 -04:00
b7c7cecd75 feat: wire NfpSlideStrategy into BestFitFinder pipeline
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>
2026-03-20 20:09:48 -04:00
5f4288a786 feat: add NfpSlideStrategy for NFP-based best-fit candidate generation
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 20:03:52 -04:00
71f28600d1 refactor: extract PolygonHelper from AutoNester for shared polygon operations
Creates PolygonHelper.cs in OpenNest.Engine.BestFit with ExtractPerimeterPolygon
(returning PolygonExtractionResult with polygon + correction vector) and RotatePolygon.
AutoNester.ExtractPerimeterPolygon and RotatePolygon become thin delegates.
Adds MakeSquareDrawing/MakeLShapeDrawing to TestHelpers and 6 PolygonHelperTests.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 19:56:20 -04:00
708d895a04 perf: remove automatic angle sweep in linear fill
Remove NeedsSweep that triggered a 5-degree sweep (36 angles) when
the work area was narrower than the part. Position matters more than
angle for narrow areas, and the base angles (bestRotation + 90deg)
cover the useful cases. ForceFullSweep still works for training.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 14:43:38 -04:00
3756ea255e fix(test): plate size 2026-03-20 00:32:45 -04:00
6d66636e3d refactor: replace ShrinkFiller shrink loop with TrimToCount
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 00:06:58 -04:00
85278bbb75 feat: add ShrinkFiller.TrimToCount for axis-aware edge trimming
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 00:03:57 -04:00
e969260f3d refactor(engine): introduce PairFillResult and remove FillRemainingStrip
PairFiller now returns PairFillResult (Parts + BestFits) instead of
using a mutable BestFits property. Extracted EvaluateCandidates,
TryReduceWorkArea, and BuildTilingAngles for clarity. Simplified the
candidate loop by leveraging FillScore comparison semantics.

Removed FillRemainingStrip and all its helpers (FindPlacedEdge,
BuildRemainingStrip, BuildRotationSet, FindBestFill, TryFewerRows,
RemainderPatterns) from FillLinear — these were a major bottleneck in
strip nesting, running expensive fills on undersized remnant strips.
ShrinkFiller + RemnantFiller already handle space optimization, making
the remainder strip fill redundant.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 15:53:23 -04:00
c31ef9f80c test(engine): add multi-item, leftover, unlimited qty, and cancellation tests for IterativeShrinkFiller
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-19 10:34:12 -04:00
ef737ffa6d feat(engine): add IterativeShrinkFiller with dual-direction shrink selection
Introduces IterativeShrinkFiller.Fill, which composes RemnantFiller and
ShrinkFiller by wrapping the caller's fill function in a closure that tries
both ShrinkAxis.Height and ShrinkAxis.Width and picks the better FillScore.
Adds IterativeShrinkResult (Parts + Leftovers). Covers null/empty inputs and
single-item placement with three passing xUnit tests.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-19 10:30:10 -04:00
9a58782c46 merge: resolve conflicts from remote nesting progress changes
Kept using OpenNest.Api in Timing.cs and EditNestForm.cs alongside
remote's reorganized usings and namespace changes.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 09:35:25 -04:00
f13443b6b3 feat(api): add NestRunner with multi-plate loop
Stateless orchestrator that takes a NestRequest and returns a NestResponse.
Imports DXFs, builds NestItems, runs the engine in a multi-plate loop until
all parts are placed, computes timing, and returns utilization metrics.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 08:37:44 -04:00
a7688f4c9d feat(api): add NestResponse with SaveAsync/LoadAsync
Adds NestResponse type to OpenNest.Api with SaveAsync/LoadAsync for .nestquote format — a ZIP containing request.json, response.json (metrics), and an embedded nest.nest.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-19 08:33:35 -04:00
84679b40ce feat(api): add NestStrategy, NestRequestPart, NestRequest
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-19 08:26:51 -04:00
b6bd7eda6e refactor: move CutParameters to OpenNest.Api namespace with new properties
Relocates CutParameters from OpenNest namespace to OpenNest.Api, adds
LeadInLength and PostProcessor properties, and provides a typed Default
factory. Updates Timing.cs, the WinForms project reference, and the three
consuming forms to resolve the type from the new namespace.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-19 08:25:32 -04:00
cfe8a38620 chore: add OpenNest.Api project skeleton
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-19 08:23:07 -04:00
62f00055b7 Reapply "refactor(compactor): deduplicate Push — PushDirection delegates to Vector overload"
This reverts commit e695e29355.
2026-03-18 20:26:14 -04:00
e695e29355 Revert "refactor(compactor): deduplicate Push — PushDirection delegates to Vector overload"
This reverts commit 9012a9fc1c.
2026-03-18 20:24:33 -04:00
9012a9fc1c refactor(compactor): deduplicate Push — PushDirection delegates to Vector overload
Also fix missing using for FillHelpers in FillLinear and FillExtents,
and update callers (CompactorTests, PatternTileForm) for the new
Vector parameter.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 20:23:50 -04:00
794ef16629 test: add Compactor safety-net tests before refactor
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 20:17:06 -04:00
1d9bcc63d2 chore: sort using directives
Auto-formatter reordering of using statements across the solution.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 16:47:42 -04:00
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
442501828a test(io): add DXF roundtrip tests
Verifies export-then-reimport preserves geometry for lines,
circles, arcs, mixed entities, and rectangle bounding boxes.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 14:53:58 -04:00
202f49f368 test(engine): add FillStrategyRegistry and pipeline tests
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-18 13:08:13 -04:00
0ac7b9babd fix(test): rename misleading test method name
Tile_CellLargerThanPlate_ReturnsSingleCell -> ReturnsEmpty

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 09:46:26 -04:00
f336af5d65 feat(engine): add PatternTiler for unit cell tiling across plates 2026-03-18 09:43:45 -04:00
7a19b78d31 feat(engine): implement FillExtents horizontal column repetition
Replace RepeatColumns stub with real implementation: compacts a test column
left against column 1 to derive the copy distance, tiles further columns at
that interval, and clips partial columns to the work area bounds. Adds 4 new
FillExtentsTests covering multi-column fill, rect shapes, non-zero-origin
work areas, and cancellation.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-18 00:50:16 -04:00
31b293324d feat(engine): implement FillExtents iterative height adjustment
Replace AdjustColumn stub with a convergence loop that distributes the
remaining gap between the topmost part and the work area top edge across
all pairs. TryAdjustPair/TryShiftDirection try shifting part2 up (or down
as fallback) and compact left, rejecting moves that widen the pair.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-18 00:48:41 -04:00
7bc9f134f6 feat(engine): add FillExtents scaffold with pair construction and column tiling
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-18 00:45:55 -04:00
bfd740c81e feat(core): add FlangeShape with JSON preset loading
FlangeShape generates an outer circle with evenly-spaced bolt holes
on a bolt circle pattern. ShapeDefinition.LoadFromJson<T>() provides
generic JSON loading for any shape — no separate preset classes needed.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 11:36:26 -04:00
dde07fc256 merge: resolve polylabel conflicts, keep remote version with hole support
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 09:02:30 -04:00
6e5471271d feat(core): add RoundedRectangleShape
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 08:07:22 -04:00
0651f185e3 feat(core): add OctagonShape
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 08:06:21 -04:00
33377291a6 feat(core): add TShape
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 08:06:08 -04:00
dfd5a15274 feat(core): add TrapezoidShape
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 08:04:15 -04:00
09a7608bcb feat(core): add IsoscelesTriangleShape
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 08:03:14 -04:00
92d2d6d2bc feat(core): add RightTriangleShape
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 08:02:18 -04:00
641734ba70 feat(core): add RingShape
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 08:00:11 -04:00
5d0de4a1b1 feat(core): add CircleShape
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 07:59:26 -04:00
f92d09a863 feat(core): add RectangleShape
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 07:58:37 -04:00
29d58cc8af test(engine): add integration smoke tests for engine refactor
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 22:39:51 -04:00
319eace472 refactor(engine): extract RemnantFiller for iterative remnant filling
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 22:33:00 -04:00
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
a7f27480e9 refactor(engine): extract AngleCandidateBuilder from DefaultNestEngine
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 22:29:52 -04:00
094b1e9f00 refactor(engine): extract ShrinkFiller from StripNestEngine
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 22:28:24 -04:00
31dbbbeedc refactor(engine): extract AccumulatingProgress from StripNestEngine
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 22:26:53 -04:00
909b697b78 test(geometry): add PolyLabel tests for L, C, triangle, thin rect, hole
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 20:42:49 -04:00
44657a86b8 feat(geometry): add PolyLabel algorithm with square test
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 20:40:25 -04:00