mirror of
https://github.com/ajisaacs/OpenNest.git
synced 2026-11-03 13:31:39 -05:00
A quantity-limited fill trimmed the parts farthest along the trim axis, which could take one half from each of two pairs. TrimToCount now finds interlocked pairs and keeps or drops them whole (from d1d68a91), so the spare space stays one usable cell. After a fill, leftovers now run in two orders, pack-first and pairs-first, and the strategy's comparer keeps the better whole layout, so its ranking of this step cannot get worse. Even quantities go in as best-fit pairs, may turn a quarter when unrestricted, are tried in every remnant and are ranked with the layout around them. Each placed pair slides left and down against true outlines to take the space its bounding box could not. On compare.nest Vertical Remnant goes from 6665.1 to 5862.6 and Lattice from 7200 to 5915.8. Nine characterization pins change from the trim with counts unchanged; the fill pins now also check layout validity. Vertical Remnant's golden layout shortens from 28 to 26. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
43 lines
2.0 KiB
C#
43 lines
2.0 KiB
C#
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using OpenNest.Geometry;
|
|
using OpenNest.Math;
|
|
|
|
namespace OpenNest.Engine.Fill
|
|
{
|
|
/// <summary>
|
|
/// Finds the interlocked pairs in a fill pattern. Separate parts keep spacing apart, so only
|
|
/// an interlocked pair's bounding boxes overlap; each part pairs with the one it overlaps most.
|
|
/// </summary>
|
|
internal static class InterlockedPairs
|
|
{
|
|
/// <returns>Each part's partner index, or -1 for a part outside any pair.</returns>
|
|
internal static int[] Partners(IReadOnlyList<Box> boxes)
|
|
{
|
|
var partner = Enumerable.Repeat(-1, boxes.Count).ToArray();
|
|
var overlaps = new List<(double Area, int A, int B)>();
|
|
// Sweep by left edge: once a box starts past this one's right edge, so do the rest.
|
|
var byLeft = Enumerable.Range(0, boxes.Count).OrderBy(i => boxes[i].Left).ThenBy(i => i).ToArray();
|
|
for (var m = 0; m < byLeft.Length; m++)
|
|
for (var n = m + 1; n < byLeft.Length && boxes[byLeft[n]].Left < boxes[byLeft[m]].Right; n++)
|
|
{
|
|
var i = System.Math.Min(byLeft[m], byLeft[n]);
|
|
var j = System.Math.Max(byLeft[m], byLeft[n]);
|
|
var a = boxes[i];
|
|
var b = boxes[j];
|
|
var length = System.Math.Min(a.Right, b.Right) - System.Math.Max(a.Left, b.Left);
|
|
var width = System.Math.Min(a.Top, b.Top) - System.Math.Max(a.Bottom, b.Bottom);
|
|
if (length > Tolerance.Epsilon && width > Tolerance.Epsilon)
|
|
overlaps.Add((length * width, i, j));
|
|
}
|
|
foreach (var (_, a, b) in overlaps.OrderByDescending(o => o.Area).ThenBy(o => o.A).ThenBy(o => o.B))
|
|
if (partner[a] < 0 && partner[b] < 0)
|
|
{
|
|
partner[a] = b;
|
|
partner[b] = a;
|
|
}
|
|
return partner;
|
|
}
|
|
}
|
|
}
|