mirror of
https://github.com/ajisaacs/OpenNest.git
synced 2026-10-17 22:01:38 -04:00
87 lines
3.5 KiB
C#
87 lines
3.5 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Threading;
|
|
|
|
namespace OpenNest.Engine.Jobs;
|
|
|
|
/// <summary>Alternate representation of checked physical sheets; never changes raw output.
|
|
/// Equality includes ordered requirement IDs and scalar bits, not instance indices.</summary>
|
|
internal static class RepeatedPlateGrouping
|
|
{
|
|
internal sealed record Group(NestJobPlateResult Sheet, int Quantity);
|
|
|
|
internal static IReadOnlyList<Group> Create(IReadOnlyList<NestJobPlateResult> sheets,
|
|
bool consolidate, CancellationToken token = default)
|
|
{
|
|
var groups = new List<Group>();
|
|
var firstByLayout = new Dictionary<NestJobPlateResult, int>(LayoutComparer.Instance);
|
|
foreach (var sheet in sheets)
|
|
{
|
|
token.ThrowIfCancellationRequested();
|
|
if (consolidate && sheet.Placements.Count > 0
|
|
&& firstByLayout.TryGetValue(sheet, out var first))
|
|
groups[first] = groups[first] with { Quantity = checked(groups[first].Quantity + 1) };
|
|
else
|
|
{
|
|
if (consolidate && sheet.Placements.Count > 0)
|
|
firstByLayout.Add(sheet, groups.Count);
|
|
groups.Add(new Group(sheet, 1));
|
|
}
|
|
}
|
|
return groups.AsReadOnly();
|
|
}
|
|
|
|
internal static bool SameStock(NestPlateStock a, NestPlateStock b) =>
|
|
string.Equals(a.Id, b.Id, StringComparison.Ordinal)
|
|
&& Bits(a.Size.Width) == Bits(b.Size.Width) && Bits(a.Size.Length) == Bits(b.Size.Length)
|
|
&& a.Quadrant == b.Quadrant && Bits(a.PartSpacing) == Bits(b.PartSpacing)
|
|
&& Bits(a.EdgeSpacing.Left) == Bits(b.EdgeSpacing.Left)
|
|
&& Bits(a.EdgeSpacing.Right) == Bits(b.EdgeSpacing.Right)
|
|
&& Bits(a.EdgeSpacing.Top) == Bits(b.EdgeSpacing.Top)
|
|
&& Bits(a.EdgeSpacing.Bottom) == Bits(b.EdgeSpacing.Bottom)
|
|
&& a.Quantity == b.Quantity
|
|
&& a.Cost.HasValue == b.Cost.HasValue
|
|
&& (!a.Cost.HasValue || Bits(a.Cost.Value) == Bits(b.Cost.Value));
|
|
|
|
private static long Bits(double value) => BitConverter.DoubleToInt64Bits(value);
|
|
|
|
private sealed class LayoutComparer : IEqualityComparer<NestJobPlateResult>
|
|
{
|
|
internal static readonly LayoutComparer Instance = new();
|
|
|
|
public bool Equals(NestJobPlateResult a, NestJobPlateResult b)
|
|
{
|
|
if (ReferenceEquals(a, b))
|
|
return true;
|
|
if (a == null || b == null || !SameStock(a.Stock, b.Stock)
|
|
|| a.Placements.Count != b.Placements.Count)
|
|
return false;
|
|
for (var i = 0; i < a.Placements.Count; i++)
|
|
{
|
|
var x = a.Placements[i];
|
|
var y = b.Placements[i];
|
|
if (!string.Equals(x.PartId, y.PartId, StringComparison.Ordinal)
|
|
|| Bits(x.X) != Bits(y.X) || Bits(x.Y) != Bits(y.Y)
|
|
|| Bits(x.Rotation) != Bits(y.Rotation))
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public int GetHashCode(NestJobPlateResult sheet)
|
|
{
|
|
// Hash only accelerates lookup; Equals checks every stock field and ordered pose.
|
|
var hash = new HashCode();
|
|
hash.Add(sheet.StockId, StringComparer.Ordinal);
|
|
foreach (var pose in sheet.Placements)
|
|
{
|
|
hash.Add(pose.PartId, StringComparer.Ordinal);
|
|
hash.Add(Bits(pose.X));
|
|
hash.Add(Bits(pose.Y));
|
|
hash.Add(Bits(pose.Rotation));
|
|
}
|
|
return hash.ToHashCode();
|
|
}
|
|
}
|
|
}
|