using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using OpenNest.Geometry; namespace OpenNest; /// A detached mutable domain nest plus explicit requirement identity (never inferred from names). public sealed class MaterializedNestResult { internal MaterializedNestResult(Nest nest, Dictionary drawings) { Nest = nest; DrawingsByPartId = new ReadOnlyDictionary(drawings); } public Nest Nest { get; } public IReadOnlyDictionary DrawingsByPartId { get; } } /// Materializes a result from the same job. Geometry safety remains the solver's future validation boundary. public static class NestResultMaterializer { public static MaterializedNestResult Materialize(NestJob job, NestJobResult result) { ArgumentNullException.ThrowIfNull(job); ArgumentNullException.ThrowIfNull(result); var nest = new Nest(); var drawings = job.Parts.ToDictionary(p => p.Id, DrawingJobMapper.CreateDrawing, StringComparer.Ordinal); foreach (var drawing in drawings.Values) nest.Drawings.Add(drawing); foreach (var sheet in result.Plates) { var plate = DrawingJobMapper.CreatePlate(sheet.Stock); foreach (var pose in sheet.Placements) { if (!drawings.TryGetValue(pose.PartId, out var drawing)) throw new ArgumentException("Result contains a requirement not present in the job.", nameof(result)); // Do not use CreateAtOrigin: it normalizes bounds and would change the snapshot frame. var part = new Part(drawing); part.Rotate(pose.Rotation); part.Location = new Vector(pose.X, pose.Y); part.UpdateBounds(); // Quantity=1 is set before the only attachment; Plate's event owns Nested accounting. plate.Parts.Add(part); } nest.Plates.Add(plate); } return new MaterializedNestResult(nest, drawings); } }