Files
OpenNest/OpenNest.Engine/BestFit/GpuDistanceComputer.cs
AJ Isaacs 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

62 lines
2.2 KiB
C#

using OpenNest.Geometry;
using System.Collections.Generic;
namespace OpenNest.Engine.BestFit
{
public class GpuDistanceComputer : IDistanceComputer
{
private readonly ISlideComputer _slideComputer;
public GpuDistanceComputer(ISlideComputer slideComputer)
{
_slideComputer = slideComputer;
}
public double[] ComputeDistances(
List<Line> stationaryLines,
List<Line> movingTemplateLines,
SlideOffset[] offsets)
{
var stationarySegments = SpatialQuery.FlattenLines(stationaryLines);
var movingSegments = SpatialQuery.FlattenLines(movingTemplateLines);
var count = offsets.Length;
var flatOffsets = new double[count * 2];
var directions = new int[count];
for (var i = 0; i < count; i++)
{
flatOffsets[i * 2] = offsets[i].Dx;
flatOffsets[i * 2 + 1] = offsets[i].Dy;
directions[i] = DirectionVectorToInt(offsets[i].DirX, offsets[i].DirY);
}
return _slideComputer.ComputeBatchMultiDir(
stationarySegments, stationaryLines.Count,
movingSegments, movingTemplateLines.Count,
flatOffsets, count, directions);
}
public double[] ComputeDistances(
List<Entity> stationaryEntities,
List<Entity> movingEntities,
SlideOffset[] offsets)
{
// GPU path doesn't support native entities yet — fall back to CPU.
var cpu = new CpuDistanceComputer();
return cpu.ComputeDistances(stationaryEntities, movingEntities, offsets);
}
/// <summary>
/// Maps a unit direction vector to a PushDirection int for the GPU interface.
/// Left=0, Down=1, Right=2, Up=3.
/// </summary>
private static int DirectionVectorToInt(double dirX, double dirY)
{
if (dirX < -0.5) return (int)PushDirection.Left;
if (dirX > 0.5) return (int)PushDirection.Right;
if (dirY < -0.5) return (int)PushDirection.Down;
return (int)PushDirection.Up;
}
}
}