Files
OpenNest/OpenNest.WinForms.Tests/TabbedCutoutFillTests.cs
T
ajandClaude Opus 5.5 3672697cb2 fix(ui): fill tabbed cutouts as one hole
A cutout cut in pieces around tabs is a set of open cut figures. Filling the
cut outline closed each piece with a chord, drawing a slanted bridge across
the hole. The fill path now rejoins open figures across their tab gaps, and
parts with open cuts use it for drawing, hit-testing and the lead-in overlay.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 23:40:11 -04:00

89 lines
3.0 KiB
C#

using System.Drawing;
using System.Drawing.Drawing2D;
using OpenNest.CNC;
using OpenNest.Geometry;
namespace OpenNest.WinForms.Tests;
public class TabbedCutoutFillTests
{
[Theory]
[InlineData(Mode.Absolute)]
[InlineData(Mode.Incremental)]
public void CutoutCutAroundTabsFillsAsOneHole(Mode mode)
{
// A 4x4 cutout cut in two pieces with lead-ins/outs, leaving 0.2 tabs on its left and
// right edges, inside a closed 10x10 perimeter.
var program = new CNC.Program(Mode.Absolute);
program.Codes.AddRange(new ICode[]
{
new RapidMove(3.2, 5.3),
new LinearMove(3, 5.1) { Layer = LayerType.Leadin },
new LinearMove(3, 7),
new LinearMove(7, 7),
new LinearMove(7, 5.1),
new LinearMove(6.8, 5.3) { Layer = LayerType.Leadout },
new RapidMove(6.8, 4.7),
new LinearMove(7, 4.9) { Layer = LayerType.Leadin },
new LinearMove(7, 3),
new LinearMove(3, 3),
new LinearMove(3, 4.9),
new LinearMove(3.2, 4.7) { Layer = LayerType.Leadout },
new RapidMove(0, 0),
new LinearMove(10, 0),
new LinearMove(10, 10),
new LinearMove(0, 10),
new LinearMove(0, 0),
});
program.Mode = mode;
program.GetDisplayPaths(Vector.Zero, out var cut, out var lead, out var etch, out var hasOpenCuts);
using (cut)
using (lead)
using (etch)
using (var fill = program.GetFillPath(Vector.Zero))
{
Assert.True(hasOpenCuts);
// Filling the cut outline closes each piece with a chord and fills the band between them.
Assert.True(Covers(cut, 5, 5));
Assert.False(Covers(fill, 5, 5));
Assert.False(Covers(fill, 4, 6.5));
Assert.False(Covers(fill, 6, 3.5));
Assert.True(Covers(fill, 1, 5));
Assert.True(Covers(fill, 8.5, 8.5));
}
}
[Fact]
public void ClosedContoursReportNoOpenCuts()
{
var program = new CNC.Program(Mode.Absolute);
program.Codes.AddRange(new ICode[]
{
new RapidMove(0, 0),
new LinearMove(10, 0),
new LinearMove(10, 10),
new LinearMove(0, 0),
new RapidMove(6, 3),
new ArcMove(6, 3, 5, 3),
});
program.GetDisplayPaths(Vector.Zero, out var cut, out var lead, out var etch, out var hasOpenCuts);
cut.Dispose();
lead.Dispose();
etch.Dispose();
Assert.False(hasOpenCuts);
}
// GraphicsPath.IsVisible tests on a one-unit pixel grid, so scale up before hit-testing.
private static bool Covers(GraphicsPath path, double x, double y)
{
using var scaled = (GraphicsPath)path.Clone();
using var scale = new Matrix();
scale.Scale(1000, 1000);
scaled.Transform(scale);
return scaled.IsVisible((float)(x * 1000), (float)(y * 1000));
}
}