Files
OpenNest/OpenNest.Engine/Jobs/Adapters/DrawingJobMapper.cs
T
aj df2f1b796d fix(engine): keep every plate's clamp zones in the sheet frame
Plates the engine built from stock (DrawingJobMapper.CreatePlate, used
by the public result materializer, the layout check and the placement
fillers) stored placement-frame zones, while live plates store them
relative to the sheet's lower-left corner. The same Plate.ClampZones
therefore meant two frames: the new clamp cut checks double-translated
materialized plates in quadrants 2-4, and interactive fill and push on
live plates read sheet-frame zones as placement coordinates, so they
could put parts on clamps there.

Plates built from stock now keep the stock's input zones (sheet frame,
no lossy translate-and-back), and the layout check and interactive
clamp obstacles map through ClampZoneFrame.ToPlacement, which
reproduces the stock's placement zones bit for bit, so engine
placements and validation are unchanged.

Project Memory: opennest 14f93b26-2e41-41f1-b09f-87dc895bb4da
2026-10-13 18:15:49 -04:00

126 lines
4.4 KiB
C#

using System;
using System.Collections.Generic;
using OpenNest.CNC;
namespace OpenNest.Engine.Jobs.Adapters;
/// <summary>Explicit-ID input mapping and exact supported-geometry reconstruction. Never retains caller objects.</summary>
public static class DrawingJobMapper
{
public static NestJobPart FromDrawing(string partId, Drawing drawing, int quantity)
{
ArgumentNullException.ThrowIfNull(drawing);
var constraints = drawing.Constraints;
return new NestJobPart(
partId,
PartGeometrySnapshot.FromProgram(drawing.Program),
quantity,
drawing.Priority,
constraints == null
? RotationPolicy.Automatic
: RotationPolicy.FromLegacy(
constraints.StepAngle,
constraints.StartAngle,
constraints.EndAngle,
constraints.Allow180Equivalent
)
);
}
public static NestJobPart FromItem(string partId, NestItem item)
{
ArgumentNullException.ThrowIfNull(item);
ArgumentNullException.ThrowIfNull(item.Drawing);
return new NestJobPart(
partId,
PartGeometrySnapshot.FromProgram(item.Drawing.Program),
item.Quantity,
item.Priority,
RotationPolicy.FromLegacy(
item.StepAngle,
item.RotationStart,
item.RotationEnd,
item.Drawing.Constraints?.Allow180Equivalent ?? false
)
);
}
/// <summary>Available stock is explicit; the legacy plate repeat count is not inventory.</summary>
public static NestPlateStock FromPlate(string stockId, Plate plate, int? quantity)
{
ArgumentNullException.ThrowIfNull(plate);
return new NestPlateStock(
stockId,
plate.Size,
quantity,
plate.PartSpacing,
plate.EdgeSpacing,
plate.Quadrant,
cost: null,
clampZones: new List<ClampZone>(plate.ClampZones)
);
}
public static Program ToProgram(PartGeometrySnapshot geometry)
{
ArgumentNullException.ThrowIfNull(geometry);
var program = new Program(geometry.Mode);
foreach (var motion in geometry.Motions)
{
var code = motion.Type switch
{
CodeType.RapidMove => (Motion)new RapidMove(motion.X, motion.Y),
CodeType.LinearMove => new LinearMove(motion.X, motion.Y) { Layer = motion.Layer },
CodeType.ArcMove => new ArcMove(
motion.X,
motion.Y,
motion.CenterX,
motion.CenterY,
motion.Rotation
)
{
Layer = motion.Layer,
},
_ => throw new NotSupportedException("Unsupported snapshot motion."),
};
code.Suppressed = motion.Suppressed;
program.Codes.Add(code);
}
return program;
}
internal static Drawing CreateDrawing(NestJobPart part)
{
var drawing = new Drawing(part.Id, ToProgram(part.Geometry)) { Priority = part.Priority };
drawing.Quantity.Required = part.Quantity;
drawing.Constraints = new NestConstraints
{
StepAngle = LegacyStep(part.Rotation),
StartAngle = part.Rotation.Start,
EndAngle = part.Rotation.End,
Allow180Equivalent = part.Rotation.Allow180Equivalent,
};
return drawing;
}
// A fixed angle needs a nonzero legacy step so it is not misread as automatic.
internal static double LegacyStep(RotationPolicy policy) =>
policy.Kind == RotationPolicyKind.Fixed ? OpenNest.Math.Angle.TwoPI : policy.Step;
internal static Plate CreatePlate(NestPlateStock stock)
{
var plate = new Plate(stock.Size)
{
Quantity = 1,
PartSpacing = stock.PartSpacing,
EdgeSpacing = stock.EdgeSpacing,
Quadrant = stock.Quadrant,
};
// Every Plate stores zones in plate (sheet lower-left) coordinates; consumers map
// them into the placement frame through ClampZoneFrame, exactly as the stock did.
foreach (var zone in stock.SheetClampZones)
plate.ClampZones.Add(new ClampZone(zone.Id, zone.Bounds));
return plate;
}
}