mirror of
https://github.com/ajisaacs/OpenNest.git
synced 2026-10-26 15:21:06 -04:00
feat(cutoffs): cut sheet-separating cut-offs after every part
This commit is contained in:
1 parent
b9a387b517
commit
ddd1e422be
10 files changed
+273
-26
No files matched your search
@@ -83,6 +83,16 @@ internal sealed class CuttingDependencyGraph
|
||||
{
|
||||
if (!nodes[cut].IsCutOff)
|
||||
continue;
|
||||
if (nodes[cut].SeparatesSheet)
|
||||
{
|
||||
// Cutting a line that splits the sheet comes after every part and every other
|
||||
// cutoff, so the head never travels back across the separated edge. Such a line
|
||||
// is continuous, so it passes through no part and needs no crossing edge.
|
||||
for (var other = 0; other < nodes.Count; other++)
|
||||
if (!nodes[other].SeparatesSheet)
|
||||
edges[cut].Add(other);
|
||||
continue;
|
||||
}
|
||||
var definition = nodes[cut].CutOff;
|
||||
for (var part = 0; part < nodes.Count; part++)
|
||||
{
|
||||
@@ -190,9 +200,10 @@ internal sealed class DependencyNode
|
||||
private LeadMaterialSnapshot material;
|
||||
|
||||
internal DependencyNode(bool isCutOff, CutOffDefinition cutOff, Box placedBounds, Box cleanBounds,
|
||||
Func<LeadMaterialSnapshot> materialFactory)
|
||||
Func<LeadMaterialSnapshot> materialFactory, bool separatesSheet = false)
|
||||
{
|
||||
IsCutOff = isCutOff;
|
||||
SeparatesSheet = isCutOff && separatesSheet;
|
||||
CutOff = cutOff;
|
||||
PlacedBounds = Copy(placedBounds);
|
||||
CleanBounds = cleanBounds == null ? null : Copy(cleanBounds);
|
||||
@@ -201,6 +212,8 @@ internal sealed class DependencyNode
|
||||
}
|
||||
|
||||
internal bool IsCutOff { get; }
|
||||
/// <summary>A cutoff whose placed program is one continuous cut across the whole sheet.</summary>
|
||||
internal bool SeparatesSheet { get; }
|
||||
internal CutOffDefinition CutOff { get; }
|
||||
internal Box PlacedBounds { get; }
|
||||
internal Box CleanBounds { get; }
|
||||
|
||||
@@ -147,12 +147,15 @@ public sealed class FixedProgramPlacement
|
||||
}
|
||||
return new(SourcePart, SourceOrdinal, Location, Rotation, LeadInsLocked, execution,
|
||||
OwnedProgramCopy.Copy(proposed, token), Prepared, Material, choices)
|
||||
{ SelectedProgram = selected, IsCutOff = IsCutOff };
|
||||
{ SelectedProgram = selected, IsCutOff = IsCutOff, SeparatesSheet = SeparatesSheet };
|
||||
}
|
||||
|
||||
/// <summary>A cutoff: always a fixed open-cut program, never material or regenerated.</summary>
|
||||
public bool IsCutOff { get; internal init; }
|
||||
|
||||
/// <summary>A cutoff that splits the whole sheet; it is cut after every other placement.</summary>
|
||||
public bool SeparatesSheet { get; internal init; }
|
||||
|
||||
public Part SourcePart { get; }
|
||||
public int SourceOrdinal { get; }
|
||||
public Vector Location { get; }
|
||||
|
||||
@@ -78,12 +78,15 @@ public static class CuttingPlanService
|
||||
var cut = ExecutionMotionReader.ReadSupported(source.Program, source.Location, request.StartPoint, token);
|
||||
if (!cut.HasCuttingContour)
|
||||
throw new ArgumentException("Placed cutoff program has no nonzero cutting motions.");
|
||||
nodes.Add(new(true, definitions.TryGetValue(source.BaseDrawing, out var definition)
|
||||
var defined = definitions.TryGetValue(source.BaseDrawing, out var definition);
|
||||
var separates = defined && CutOff.SeparatesSheet(source, definition,
|
||||
request.Plate.BoundingBox(includeParts: false));
|
||||
nodes.Add(new(true, defined
|
||||
? new(definition.Axis, definition.Position, definition.StartLimit, definition.EndLimit) : null,
|
||||
source.BoundingBox, null, null));
|
||||
source.BoundingBox, null, null, separates));
|
||||
placements.Add(new(source, index, source.Location, source.Rotation, source.LeadInsLocked,
|
||||
cut, OwnedProgramCopy.Copy(source.Program, token))
|
||||
{ IsCutOff = true });
|
||||
{ IsCutOff = true, SeparatesSheet = separates });
|
||||
continue;
|
||||
}
|
||||
var clean = ExecutionMotionReader.ReadSupported(source.BaseDrawing.Program, Vector.Zero, null, token);
|
||||
@@ -382,6 +385,10 @@ public static class CuttingPlanService
|
||||
{
|
||||
var part = snapshot.Placements[violation.Part];
|
||||
var prerequisite = snapshot.Placements[violation.Prerequisite];
|
||||
if (part.SeparatesSheet)
|
||||
return new(part.SourceOrdinal, part.SourcePart, prerequisite.SourceOrdinal, prerequisite.SourcePart, null,
|
||||
$"{subject} cuts the sheet-separating cutoff (part {part.SourceOrdinal + 1}) before part "
|
||||
+ $"{prerequisite.SourceOrdinal + 1}; every part and other cutoff must be cut before the sheet is separated.");
|
||||
var reason = prerequisite.IsCutOff ? "the cutoff crossing it" : "the part nested in its cutout";
|
||||
return new(part.SourceOrdinal, part.SourcePart, prerequisite.SourceOrdinal, prerequisite.SourcePart, null,
|
||||
$"{subject} cuts part {part.SourceOrdinal + 1} before {reason} (part {prerequisite.SourceOrdinal + 1}).");
|
||||
|
||||
@@ -34,16 +34,27 @@ namespace OpenNest.Engine.Sequencing
|
||||
|
||||
private static List<Part> OrderCutOffsFirst(List<Part> ordered, Plate plate)
|
||||
{
|
||||
var cuts = ordered.Select((part, index) => (Part: part, Index: index))
|
||||
.Where(item => item.Part.BaseDrawing.IsCutOff).ToList();
|
||||
if (cuts.Count == 0)
|
||||
return ordered;
|
||||
|
||||
var definitions = new Dictionary<Drawing, CutOff>(ReferenceEqualityComparer.Instance);
|
||||
foreach (var cutOff in plate.CutOffs)
|
||||
definitions[cutOff.Drawing] = cutOff;
|
||||
|
||||
var bounds = plate.BoundingBox(includeParts: false);
|
||||
|
||||
// A cutoff that splits the whole sheet goes after every part and other cutoff, so the
|
||||
// head never travels back across it. It passes through no part.
|
||||
var separating = ordered.Where(part => part.BaseDrawing.IsCutOff
|
||||
&& definitions.TryGetValue(part.BaseDrawing, out var definition)
|
||||
&& CutOff.SeparatesSheet(part, definition, bounds)).ToList();
|
||||
if (separating.Count > 0)
|
||||
{
|
||||
var last = new HashSet<Part>(separating, ReferenceEqualityComparer.Instance);
|
||||
ordered = ordered.Where(part => !last.Contains(part)).ToList();
|
||||
}
|
||||
|
||||
var cuts = ordered.Select((part, index) => (Part: part, Index: index))
|
||||
.Where(item => item.Part.BaseDrawing.IsCutOff).ToList();
|
||||
if (cuts.Count == 0)
|
||||
return ordered.Concat(separating).ToList();
|
||||
|
||||
var emitted = new bool[ordered.Count];
|
||||
var result = new List<Part>(ordered.Count);
|
||||
for (var i = 0; i < ordered.Count; i++)
|
||||
@@ -75,6 +86,7 @@ namespace OpenNest.Engine.Sequencing
|
||||
}
|
||||
}
|
||||
|
||||
result.AddRange(separating);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user