refactor(engine): share jobs placement identity and progress mechanics
This commit is contained in:
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
|
||||
@@ -13,7 +12,8 @@ namespace OpenNest.Engine.Jobs.Placement;
|
||||
/// <see cref="NestItem.Quantity"/> mutations never feed back into job accounting.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// A private <see cref="Drawing"/> per requirement is created once per solve and reused across every
|
||||
/// The identity/progress boundary mechanics live in <see cref="CandidatePlacementContext"/>: one
|
||||
/// private <see cref="Drawing"/> per requirement is created once per solve and reused across every
|
||||
/// candidate trial (the runner reuses one <see cref="IPlateNester"/> instance per job). This is safe
|
||||
/// because the engines mutate <see cref="NestItem.Quantity"/> (per-trial) and canonical-frame copies,
|
||||
/// never the shared <see cref="Drawing"/> or its <c>Quantity</c>. Identity is by Drawing reference,
|
||||
@@ -23,10 +23,7 @@ public sealed class DefaultPlateNester : IPlateNester
|
||||
{
|
||||
private readonly Func<Plate, DefaultNestEngine> engineFactory;
|
||||
private readonly OrderedPlateNester restrictedRotationNester = new();
|
||||
private readonly Dictionary<string, Drawing> drawingsById = new(StringComparer.Ordinal);
|
||||
private readonly Dictionary<Drawing, string> idByDrawing = new(
|
||||
ReferenceEqualityComparer.Instance
|
||||
);
|
||||
private readonly CandidatePlacementContext context = new();
|
||||
|
||||
public DefaultPlateNester()
|
||||
: this(static plate => new DefaultNestEngine(plate)) { }
|
||||
@@ -55,30 +52,9 @@ public sealed class DefaultPlateNester : IPlateNester
|
||||
return restrictedRotationNester.Place(request, progress, token);
|
||||
|
||||
var plate = DrawingJobMapper.CreatePlate(request.Stock);
|
||||
var items = new List<NestItem>(request.Parts.Count);
|
||||
foreach (var requirement in request.Parts)
|
||||
{
|
||||
if (!drawingsById.TryGetValue(requirement.Id, out var drawing))
|
||||
{
|
||||
drawing = DrawingJobMapper.CreateDrawing(requirement);
|
||||
drawingsById.Add(requirement.Id, drawing);
|
||||
idByDrawing.Add(drawing, requirement.Id);
|
||||
}
|
||||
|
||||
// Quantity is the request's remaining demand; the engine may mutate this per-trial item,
|
||||
// and that mutation is deliberately discarded — placement counts come from the result.
|
||||
items.Add(
|
||||
new NestItem
|
||||
{
|
||||
Drawing = drawing,
|
||||
Quantity = requirement.Quantity,
|
||||
Priority = requirement.Priority,
|
||||
StepAngle = DrawingJobMapper.LegacyStep(requirement.Rotation),
|
||||
RotationStart = requirement.Rotation.Start,
|
||||
RotationEnd = requirement.Rotation.End,
|
||||
}
|
||||
);
|
||||
}
|
||||
// Quantity is the request's remaining demand; the engine may mutate these per-trial items,
|
||||
// and that mutation is deliberately discarded — placement counts come from the result.
|
||||
var items = context.CreateItems(request.Parts);
|
||||
|
||||
var engine =
|
||||
engineFactory(plate)
|
||||
@@ -89,18 +65,6 @@ public sealed class DefaultPlateNester : IPlateNester
|
||||
if (parts == null)
|
||||
throw new InvalidOperationException("Engine returned null placements.");
|
||||
|
||||
var placements = new List<NestJobPlacement>(parts.Count);
|
||||
foreach (var part in parts)
|
||||
{
|
||||
if (part?.BaseDrawing == null || !idByDrawing.TryGetValue(part.BaseDrawing, out var id))
|
||||
throw new InvalidOperationException(
|
||||
"Placement does not reference a known requirement drawing."
|
||||
);
|
||||
placements.Add(
|
||||
new NestJobPlacement(id, 0, part.Location.X, part.Location.Y, part.Rotation)
|
||||
);
|
||||
}
|
||||
|
||||
return new PlateCandidate(placements);
|
||||
return new PlateCandidate(context.MapPlacements(parts));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user