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>
This commit is contained in:
@@ -39,7 +39,30 @@ namespace OpenNest
|
||||
return lines;
|
||||
}
|
||||
|
||||
public static List<Line> GetOffsetPartLines(Part part, double spacing, double chordTolerance = 0.001)
|
||||
/// <summary>
|
||||
/// Returns the perimeter entities (Line, Arc, Circle) with spacing offset applied,
|
||||
/// without tessellation. Much faster than GetOffsetPartLines for parts with many arcs.
|
||||
/// </summary>
|
||||
public static List<Entity> GetOffsetPerimeterEntities(Part part, double spacing)
|
||||
{
|
||||
var geoEntities = ConvertProgram.ToGeometry(part.Program);
|
||||
var profile = new ShapeProfile(
|
||||
geoEntities.Where(e => e.Layer != SpecialLayers.Rapid).ToList());
|
||||
|
||||
var offsetShape = profile.Perimeter.OffsetOutward(spacing);
|
||||
if (offsetShape == null)
|
||||
return new List<Entity>();
|
||||
|
||||
// Offset the shape's entities to the part's location.
|
||||
// OffsetOutward creates a new Shape, so mutating is safe.
|
||||
foreach (var entity in offsetShape.Entities)
|
||||
entity.Offset(part.Location);
|
||||
|
||||
return offsetShape.Entities;
|
||||
}
|
||||
|
||||
public static List<Line> GetOffsetPartLines(Part part, double spacing, double chordTolerance = 0.001,
|
||||
bool perimeterOnly = false)
|
||||
{
|
||||
var entities = ConvertProgram.ToGeometry(part.Program);
|
||||
var profile = new ShapeProfile(
|
||||
@@ -50,9 +73,12 @@ namespace OpenNest
|
||||
AddOffsetLines(lines, profile.Perimeter.OffsetOutward(totalSpacing),
|
||||
chordTolerance, part.Location);
|
||||
|
||||
foreach (var cutout in profile.Cutouts)
|
||||
AddOffsetLines(lines, cutout.OffsetInward(totalSpacing),
|
||||
chordTolerance, part.Location);
|
||||
if (!perimeterOnly)
|
||||
{
|
||||
foreach (var cutout in profile.Cutouts)
|
||||
AddOffsetLines(lines, cutout.OffsetInward(totalSpacing),
|
||||
chordTolerance, part.Location);
|
||||
}
|
||||
|
||||
return lines;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user