Size.Parse and ToString now use WxL format (width first) matching the
natural convention. Fixed the Plate(w,l) constructor which was swapping
args when creating Size. Fixed PlateView.DrawPlate and DrawControl
ZoomToArea which had width/length mapped to the wrong screen axes.
Simplified Console --size parsing to use Size.TryParse instead of manual
split with confusing PlateHeight/PlateWidth fields. Added Command-Line
Interface section to README documenting all console options.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Use pole-of-inaccessibility (polylabel) to place part labels at the
visual center of shapes instead of the first path vertex. Labels now
stay correctly positioned regardless of part rotation or shape.
Also adds project README and MIT license.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Extract direction helpers to Helper class (EdgeDistance, DirectionalGap,
DirectionToOffset, IsHorizontalDirection) and use them to skip parts not
ahead in the push direction or further than the current best distance.
Defer line computation until parts survive bounding box checks.
Co-Authored-By: Claude Opus 4.6 (1M context) <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>
Vector implements IEquatable<Vector> with proper GetHashCode for HashSet usage.
Polygon.FindCrossing uses bounding-box pruning to skip non-overlapping edge pairs.
Helper.DirectionalDistance deduplicates vertices via HashSet, sorts edges for
early-exit pruning, and adds a new array-based overload that avoids allocations.
PartBoundary sorts directional edges and exposes GetEdges for zero-alloc access.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace shape-list iteration with ShapeProfile.Perimeter in both
Part.Intersects and PartBoundary, simplifying the logic and ensuring
only the outermost contour is used for collision detection.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add G-code serialization via ToString() for debugging/ML workflows.
Fix Rotate(angle, origin) to propagate origin to sub-programs instead
of calling the single-argument overload.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Offset-only copies don't modify program codes, so sharing the instance
avoids expensive cloning during large pattern tiling.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add primitive-parameter RayEdgeDistance overload with AggressiveInlining,
merge Left/Right and Up/Down cases. Add DirectionalDistance overload that
accepts (dx, dy) translation without creating Line objects, and FlattenLines
for packing segments into flat arrays for GPU transfer.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Break deeply nested loop structure into focused helper methods,
reducing max nesting from 5 levels to 2. Uses GetRange/AddRange
for cleaner loop building.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Brings in the full NFP implementation: ConvexDecomposition, NoFitPolygon,
InnerFitPolygon, NfpCache, BottomLeftFill, SimulatedAnnealing optimizer,
and INestOptimizer interface. Resolves conflicts by keeping master's
progress reporting infrastructure alongside the new AutoNest methods,
and adapting RunAutoNest_Click to use NFP AutoNest with async/cancellation.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Shape.OffsetEntity computed joins between consecutive offset segments
but never joined the last segment back to the first, leaving the
closing corner with a straight line instead of a proper miter/arc.
Track the first entity and apply the same join logic after the loop.
Also wrap nest template loading in try-catch so a corrupt template
file doesn't crash the app on startup — falls back to default nest.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The exit point should be the corner farthest from the origin so the
perimeter (cut last) ends near the machine home. The mapping was
backwards — Q1 (origin bottom-left) was returning (0,0) instead of
(w,l).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Exit point from plate quadrant, nearest-neighbor cutout
sequencing via ShapeProfile + ClosestPointTo, contour type
detection, and normal angle computation.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
"Length" is more natural than "height" for flat plate materials.
Renames the field on OpenNest.Geometry.Size, Box.Height property,
and all references across 38 files.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
DXF files can have endpoint gaps at entity junctions that fall right at
the floating-point boundary of Tolerance.Epsilon (0.00001). This caused
shapes to not close, resulting in 0 area and 0% utilization in Best-Fit.
Added ChainTolerance (0.0001) for endpoint chaining in GetConnected and
Shape.IsClosed, keeping the tighter Epsilon for geometric precision.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>