mirror of
https://github.com/ajisaacs/OpenNest.git
synced 2026-10-10 02:04:13 -04:00
fix(cutting): find nested parts from material bounds
The containment prefilter used the inner part's whole clean-program bounds, which include rapid endpoints and scribe marks. A remote rapid or mark could push those bounds outside the host and drop a genuine inner-before-host prerequisite. Candidate pairs now use the material extent only (cut and display motions); containment is still proven on native material.
This commit is contained in:
1 parent
b9b475ab77
commit
e43a7c99d0
2 files changed
+38
-2
No files matched your search
@@ -97,8 +97,11 @@ public static class CuttingPlanService
|
||||
// Exact placed/proposed payloads still use lossless OwnedProgramCopy.
|
||||
var ownedClean = (Program)source.BaseDrawing.Program.Clone();
|
||||
ownedClean.Rotate(source.Rotation - source.BaseDrawing.Program.Rotation);
|
||||
var cleanBounds = ownedClean.BoundingBox();
|
||||
cleanBounds.Offset(source.Location);
|
||||
// Material extent only: remote rapids and scribe marks must not widen it, or a
|
||||
// genuine insert could fail the containment prefilter.
|
||||
var cleanBounds = ExecutionMotionReader.ReadSupported(ownedClean, source.Location, null, token).Motions
|
||||
.Where(m => !m.Rapid && m.Layer is LayerType.Cut or LayerType.Display && m.Curve != null)
|
||||
.Select(m => m.Curve.ToEntity().BoundingBox).ToList().GetBoundingBox();
|
||||
var location = source.Location;
|
||||
if (request.ConfirmedParameters != null)
|
||||
{
|
||||
|
||||
@@ -137,6 +137,22 @@ public class CuttingDependencyTests
|
||||
Assert.Contains("nested in its cutout", finding.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Dependencies_NonmaterialMotionsCannotHideANestedPart()
|
||||
{
|
||||
// Same insert as above plus a remote rapid and scribe mark: material is unchanged, so
|
||||
// the inner-before-host prerequisite must not depend on whole-program bounds.
|
||||
var (plate, host, inner) = NestedPlate(Marked(Rectangle(2.7, 2.7, 0.6, 0.6)));
|
||||
var snapshot = CuttingPlanService.Capture(new CuttingPlanRequest(plate));
|
||||
Assert.Null(snapshot.Findings.FirstOrDefault()?.Message);
|
||||
Assert.True(inner.BoundingBox.Left < host.BoundingBox.Left);
|
||||
|
||||
Assert.Equal(new[] { 1 }, snapshot.Dependencies.PrerequisitesOf(0));
|
||||
var result = CuttingPlanService.Plan(snapshot);
|
||||
Assert.True(result.Status == CuttingPlanStatus.Ready, Describe(result));
|
||||
Assert.Equal(new[] { inner, host }, result.ProposedOrder.Select(o => o.SourcePart));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Capture_PartStraddlingAHostCutoutEdge_IsAmbiguousContainment()
|
||||
{
|
||||
@@ -234,6 +250,23 @@ public class CuttingDependencyTests
|
||||
return (plate, host, inner);
|
||||
}
|
||||
|
||||
// Prefixes a remote rapid and scribe mark to both the clean and placed programs.
|
||||
private static Part Marked(Part part)
|
||||
{
|
||||
static Program Prefix(Program source)
|
||||
{
|
||||
var program = new Program();
|
||||
program.Codes.Add(new RapidMove(-20, -20));
|
||||
program.Codes.Add(new LinearMove(-19, -20) { Layer = LayerType.Scribe });
|
||||
program.Codes.AddRange(source.Codes);
|
||||
return program;
|
||||
}
|
||||
|
||||
var marked = new Part(new Drawing("same", Prefix(part.BaseDrawing.Program)), part.Location);
|
||||
Assert.True(marked.RestoreLeadInProgram(Prefix(part.Program), false));
|
||||
return marked;
|
||||
}
|
||||
|
||||
// A U-shaped part open at the top between x 3 and 7, lead on its right edge.
|
||||
private static Part Pocketed()
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user