test(expand): bound pinned relaxation passes

This commit is contained in:
aj committed 2026-10-13 21:31:57 -04:00
1 parent 4183af4142
commit cad1083287
2 files changed
+41

No files matched your search

@@ -623,6 +623,34 @@ public class ExpanderTests
Assert.Equal(0, wall.Location.X);
}
[Fact]
public void Separate_PinnedBetweenFixedParts_StopsAfterOneNoProgressPass()
{
var plate = MakePlate(20, 20, edge: 0);
var pinned = AddSquare(plate, 8, 8);
AddSquare(plate, 3.8, 8);
AddSquare(plate, 12.2, 8);
AddSquare(plate, 8, 3.8);
AddSquare(plate, 8, 12.2);
var passes = 0;
var initial = pinned.Location;
var (converged, poses, violations) = Expander.SeparateObserved(
new List<Part> { pinned }, plate, spacing: 1,
checkpoint =>
{
if (checkpoint == Expander.Checkpoint.AfterPairPass)
passes++;
}, maxIterations: 10000
);
Assert.False(converged);
Assert.NotEmpty(violations);
Assert.Equal(1, passes); // Not a MaxIterations spin or wall-clock assertion.
Assert.Equal(initial, poses[0]);
Assert.Equal(initial, pinned.Location);
}
[Fact]
public void Expand_WallsAndUnselectedPairs_StayExactlyAtClearance()
{
+13
View File
@@ -77,6 +77,7 @@ namespace OpenNest.Engine.Fill
{
AfterScratchMove,
AfterSuccessfulProbe,
AfterPairPass,
BeforeApply,
}
@@ -307,6 +308,15 @@ namespace OpenNest.Engine.Fill
return Separate(context, positions, spacing, maxIterations, token, null);
}
internal static (bool Converged, List<Vector> Positions, List<Violation> Violations) SeparateObserved(
List<Part> selected, Plate plate, double spacing,
Action<Checkpoint> observer, int maxIterations = 100,
CancellationToken token = default)
{
var context = SeparationContext.Prepare(selected, plate, token);
return Separate(context, context.Positions(), spacing, maxIterations, token, observer);
}
private static void Apply(List<Part> selected, List<Vector> from, List<Vector> to)
{
// Only movers occupy [0, selected.Count); walls never move.
@@ -435,6 +445,9 @@ namespace OpenNest.Engine.Fill
// the next pass. The final sweep remeasures all pairs.
}
observer?.Invoke(Checkpoint.AfterPairPass);
if (token.IsCancellationRequested)
return (false, start, violations);
if (moved < epsMove)
break;
}