using System.Collections.Generic;
using System.Linq;
using OpenNest.Geometry;
using OpenNest.Math;
namespace OpenNest.Engine.Fill
{
///
/// 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.
///
internal static class InterlockedPairs
{
/// Each part's partner index, or -1 for a part outside any pair.
internal static int[] Partners(IReadOnlyList 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;
}
}
}