mirror of
https://github.com/ajisaacs/OpenNest.git
synced 2026-11-08 14:55:45 -05:00
The first fill of a new drawing was blamed on the best-fit pair search, but on the reported nest that search takes ~3.4 s. The time goes to FillLinear.FillGrid, run thousands of times by the Pairs, Row/Column and Linear strategies: pattern copy-distance slides and the grid overlap check. Every change keeps the output bit for bit (part poses compared on the benchmark nest; best-fit results unchanged). - ConvexDecomposition.Triangulate: unlink clipped vertices from a circular list instead of List.RemoveAt, and remember why a vertex failed the ear test (same neighbors, same blocking vertex still present) instead of retesting it after every ear. Compared bitwise against a frozen pre-change copy, including the blocker-clipped case. - Collision: skip triangles whose box misses the other triangulation's union box (exact: min/max and monotone subtraction), reuse each triangle's open vertices, and let the overlap-only path stop at its first region when there are no holes. Check still returns every region. - SpatialQuery.ExtractEntityVertices presizes its set; FillLinear extracts each entity list's vertices once per copy-distance search rather than once per pair. - StripeFiller converges its stripe angles and tiles its grids in parallel. Dedup claims, cached remnant fills, ranking and progress stay in candidate order, and grids are tiled only for configurations a claim can still win (GridDedup.Contains), so results and reports do not depend on the thread count. - LinearFillStrategy fills its angles in parallel through FillHelpers.BestOverAnglesInParallel; angle results, ranking and progress stay in order. Benchmark (one drawing, 60x120, 0.25 spacing, cleared plate, interleaved runs): FillItem Lattice 291/317 s -> 164/153 s, 132 parts both; PairFiller alone 48 s -> 38-42 s. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
59 lines
2.0 KiB
C#
59 lines
2.0 KiB
C#
using System.Collections.Generic;
|
|
using OpenNest.Engine.Fill;
|
|
using OpenNest.Math;
|
|
|
|
namespace OpenNest.Engine.Strategies
|
|
{
|
|
public class LinearFillStrategy : IFillStrategy
|
|
{
|
|
public string Name => "Linear";
|
|
public NestPhase Phase => NestPhase.Linear;
|
|
public int Order => 400;
|
|
|
|
public List<Part> Fill(FillContext context)
|
|
{
|
|
var angles = context.SharedState.TryGetValue("AngleCandidates", out var cached)
|
|
? (List<double>)cached
|
|
: new List<double> { 0, Angle.HalfPI };
|
|
|
|
var workArea = context.WorkArea;
|
|
var comparer = context.Policy?.Comparer ?? new DefaultFillComparer();
|
|
var preferred = context.Policy?.PreferredDirection;
|
|
|
|
// Each angle's fill is independent; its angle result is recorded in angle order.
|
|
return FillHelpers.BestOverAnglesInParallel(
|
|
context,
|
|
angles,
|
|
angle =>
|
|
{
|
|
var engine = new FillLinear(workArea, context.Plate.PartSpacing)
|
|
{
|
|
Label = "Linear",
|
|
};
|
|
return FillHelpers.FillWithDirectionPreference(
|
|
dir => engine.Fill(context.Item.Drawing, angle, dir),
|
|
preferred,
|
|
comparer,
|
|
workArea
|
|
);
|
|
},
|
|
(angle, result) =>
|
|
{
|
|
if (result != null && result.Count > 0)
|
|
{
|
|
context.AngleResults.Add(
|
|
new AngleResult
|
|
{
|
|
AngleDeg = Angle.ToDegrees(angle),
|
|
Direction = preferred ?? NestDirection.Horizontal,
|
|
PartCount = result.Count,
|
|
}
|
|
);
|
|
}
|
|
},
|
|
"Linear"
|
|
);
|
|
}
|
|
}
|
|
}
|