mirror of
https://github.com/ajisaacs/OpenNest.git
synced 2026-10-16 03:11:37 -04:00
feat(core): resolve a fixed clamp rail onto nest plates
Add ClampRail: identical clamps (width along the edge, depth into the sheet) at X centers measured from the plate origin on the origin-side edge. It resolves onto any sheet size and quadrant without re-scaling: clamps wholly beyond the sheet are skipped, one still reaching onto it is clipped to it, and ids follow rail position (clamp-N) so a physical clamp keeps its id on every sheet. A plate can follow a rail (Plate.SetClampRail); its ClampZones are then derived and re-resolved whenever Size or Quadrant changes, because the clamps are fixed to the machine. Plates without a rail keep explicit zones unchanged. Nest.PlateDefaults.ClampRail is the template new plates follow, and Nest.SetClampRail applies a nest-wide rail to every plate (an empty rail removes it).
This commit is contained in:
1 parent
040776807a
commit
cc85a9e068
4 files changed
+491
-4
No files matched your search
@@ -0,0 +1,146 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OpenNest.Geometry;
|
||||
|
||||
namespace OpenNest
|
||||
{
|
||||
/// <summary>
|
||||
/// The machine's fixed clamp rail: identical rectangular clamps whose X centers are
|
||||
/// measured from the plate origin along the origin-side (operator) edge. Plates always
|
||||
/// start at the origin, so the same rail resolves onto every sheet size without
|
||||
/// re-scaling; a clamp whose footprint lies wholly beyond a sheet is skipped and one
|
||||
/// that still reaches onto it is kept, clipped to the sheet.
|
||||
/// </summary>
|
||||
public sealed class ClampRail : IEquatable<ClampRail>
|
||||
{
|
||||
public ClampRail(double width, double depth, IEnumerable<double> centers)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(centers);
|
||||
if (!double.IsFinite(width) || width <= 0)
|
||||
throw new ArgumentOutOfRangeException(
|
||||
nameof(width),
|
||||
"Clamp width must be finite and positive."
|
||||
);
|
||||
if (!double.IsFinite(depth) || depth <= 0)
|
||||
throw new ArgumentOutOfRangeException(
|
||||
nameof(depth),
|
||||
"Clamp depth must be finite and positive."
|
||||
);
|
||||
|
||||
var sorted = new SortedSet<double>();
|
||||
foreach (var center in centers)
|
||||
{
|
||||
if (!double.IsFinite(center) || center < 0)
|
||||
throw new ArgumentOutOfRangeException(
|
||||
nameof(centers),
|
||||
"Clamp centers must be finite and measured from the origin (zero or more)."
|
||||
);
|
||||
sorted.Add(center);
|
||||
}
|
||||
|
||||
Width = width;
|
||||
Depth = depth;
|
||||
Centers = sorted.ToArray();
|
||||
}
|
||||
|
||||
/// <summary>Clamp extent along the edge (X).</summary>
|
||||
public double Width { get; }
|
||||
|
||||
/// <summary>Clamp intrusion into the sheet from the origin-side edge (Y).</summary>
|
||||
public double Depth { get; }
|
||||
|
||||
/// <summary>Distinct clamp centers along X from the origin, ascending.</summary>
|
||||
public IReadOnlyList<double> Centers { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The zones this rail places on a sheet, in plate coordinates (the frame of
|
||||
/// <see cref="Plate.ClampZones"/>: origin at the sheet's lower-left corner). The
|
||||
/// quadrant locates the plate origin, and with it the origin-side edge, on the sheet.
|
||||
/// Ids are <c>clamp-N</c> by rail position, so one physical clamp keeps its id on
|
||||
/// every sheet even when others are skipped.
|
||||
/// </summary>
|
||||
public IReadOnlyList<ClampZone> ResolveFor(Size size, int quadrant)
|
||||
{
|
||||
var length = size.Length;
|
||||
var sheetWidth = size.Width;
|
||||
if (!(length > 0) || !(sheetWidth > 0) || !double.IsFinite(length) || !double.IsFinite(sheetWidth))
|
||||
return Array.Empty<ClampZone>();
|
||||
|
||||
var extendsLeft = quadrant is 2 or 3;
|
||||
var extendsDown = quadrant is 3 or 4;
|
||||
var depth = System.Math.Min(Depth, sheetWidth);
|
||||
var y = extendsDown ? sheetWidth - depth : 0;
|
||||
var half = Width / 2;
|
||||
|
||||
var zones = new List<ClampZone>(Centers.Count);
|
||||
for (var i = 0; i < Centers.Count; i++)
|
||||
{
|
||||
// Distances from the origin along the edge.
|
||||
var near = Centers[i] - half;
|
||||
var far = Centers[i] + half;
|
||||
if (near >= length)
|
||||
continue; // wholly beyond this sheet
|
||||
|
||||
var clipped = near < 0 || far > length;
|
||||
var start = near < 0 ? 0 : near;
|
||||
var extent = clipped ? System.Math.Min(far, length) - start : Width;
|
||||
if (!(extent > 0))
|
||||
continue;
|
||||
|
||||
// Plate coordinates are measured from the lower-left corner; a sheet extending
|
||||
// to -X from the origin has its origin edge at x = length.
|
||||
var x = extendsLeft ? length - (start + extent) : start;
|
||||
zones.Add(new ClampZone($"clamp-{i + 1}", new Box(x, y, extent, depth)));
|
||||
}
|
||||
|
||||
return zones;
|
||||
}
|
||||
|
||||
/// <summary>True when the plate's zones are exactly (ids and bits) this rail's for its sheet.</summary>
|
||||
public bool Matches(Plate plate)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(plate);
|
||||
return SameZones(plate.ClampZones, ResolveFor(plate.Size, plate.Quadrant));
|
||||
}
|
||||
|
||||
internal static bool SameZones(IList<ClampZone> current, IReadOnlyList<ClampZone> expected)
|
||||
{
|
||||
if (current.Count != expected.Count)
|
||||
return false;
|
||||
for (var i = 0; i < current.Count; i++)
|
||||
{
|
||||
var a = current[i];
|
||||
var b = expected[i];
|
||||
if (
|
||||
!string.Equals(a.Id, b.Id, StringComparison.Ordinal)
|
||||
|| a.Bounds.X != b.Bounds.X
|
||||
|| a.Bounds.Y != b.Bounds.Y
|
||||
|| a.Bounds.Length != b.Bounds.Length
|
||||
|| a.Bounds.Width != b.Bounds.Width
|
||||
)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool Equals(ClampRail other) =>
|
||||
other is not null
|
||||
&& Width.Equals(other.Width)
|
||||
&& Depth.Equals(other.Depth)
|
||||
&& Centers.SequenceEqual(other.Centers);
|
||||
|
||||
public override bool Equals(object obj) => Equals(obj as ClampRail);
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
var hash = HashCode.Combine(Width, Depth, Centers.Count);
|
||||
foreach (var center in Centers)
|
||||
hash = HashCode.Combine(hash, center);
|
||||
return hash;
|
||||
}
|
||||
|
||||
public override string ToString() =>
|
||||
$"ClampRail {Width:R} x {Depth:R} at [{string.Join(", ", Centers.Select(c => c.ToString("R")))}]";
|
||||
}
|
||||
}
|
||||
+25
-1
@@ -65,6 +65,21 @@ namespace OpenNest
|
||||
return plate;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Makes <paramref name="rail"/> this nest's machine clamp rail: new plates follow it
|
||||
/// (<see cref="PlateSettings.ClampRail"/>) and every existing plate re-resolves its
|
||||
/// zones from it. Null, or a rail without clamps, removes the rail and every plate's
|
||||
/// zones; the rail is nest-wide, so per-plate zones are replaced either way.
|
||||
/// </summary>
|
||||
public void SetClampRail(ClampRail rail)
|
||||
{
|
||||
if (rail != null && rail.Centers.Count == 0)
|
||||
rail = null;
|
||||
PlateDefaults.ClampRail = rail;
|
||||
foreach (var plate in Plates)
|
||||
plate.SetClampRail(rail);
|
||||
}
|
||||
|
||||
public void UpdateDrawingQuantities()
|
||||
{
|
||||
foreach (var drawing in Drawings)
|
||||
@@ -114,6 +129,12 @@ namespace OpenNest
|
||||
set { plate.PartSpacing = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The machine clamp rail new plates follow, or null for none. Set through
|
||||
/// <see cref="Nest.SetClampRail"/> to also update existing plates.
|
||||
/// </summary>
|
||||
public ClampRail ClampRail { get; set; }
|
||||
|
||||
public void SetFromExisting(Plate plate)
|
||||
{
|
||||
Quadrant = plate.Quadrant;
|
||||
@@ -124,7 +145,7 @@ namespace OpenNest
|
||||
|
||||
public Plate CreateNew()
|
||||
{
|
||||
return new Plate()
|
||||
var created = new Plate()
|
||||
{
|
||||
Size = Size,
|
||||
EdgeSpacing = EdgeSpacing,
|
||||
@@ -132,6 +153,9 @@ namespace OpenNest
|
||||
Quadrant = Quadrant,
|
||||
Quantity = 1,
|
||||
};
|
||||
if (ClampRail != null)
|
||||
created.SetClampRail(ClampRail);
|
||||
return created;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+54
-3
@@ -85,9 +85,20 @@ namespace OpenNest
|
||||
public Spacing EdgeSpacing;
|
||||
|
||||
/// <summary>
|
||||
/// The size of the plate.
|
||||
/// The size of the plate. A plate following a <see cref="ClampRail"/> re-resolves
|
||||
/// its clamp zones for the new size.
|
||||
/// </summary>
|
||||
public Size Size { get; set; }
|
||||
public Size Size
|
||||
{
|
||||
get { return size; }
|
||||
set
|
||||
{
|
||||
size = value;
|
||||
ResolveClampRail();
|
||||
}
|
||||
}
|
||||
|
||||
private Size size;
|
||||
|
||||
public CNC.CuttingStrategy.CuttingParameters CuttingParameters { get; set; }
|
||||
|
||||
@@ -122,6 +133,42 @@ namespace OpenNest
|
||||
|
||||
private void OnClampZonesChanged() => ClampZonesChanged?.Invoke(this, EventArgs.Empty);
|
||||
|
||||
/// <summary>
|
||||
/// The machine clamp rail this plate follows, or null when its
|
||||
/// <see cref="ClampZones"/> are explicit (engine sheets, files without a rail). While
|
||||
/// set, the zones are derived: re-resolved whenever <see cref="Size"/> or
|
||||
/// <see cref="Quadrant"/> changes, because the clamps are fixed to the machine.
|
||||
/// </summary>
|
||||
public ClampRail ClampRail { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Follows <paramref name="rail"/> and replaces the zones with its resolution for
|
||||
/// this sheet; null detaches and removes every zone. Unchanged zones raise no events.
|
||||
/// </summary>
|
||||
public void SetClampRail(ClampRail rail)
|
||||
{
|
||||
ClampRail = rail;
|
||||
ReplaceClampZones(
|
||||
rail == null ? Array.Empty<ClampZone>() : rail.ResolveFor(Size, Quadrant)
|
||||
);
|
||||
}
|
||||
|
||||
private void ResolveClampRail()
|
||||
{
|
||||
// Called from the constructor's Size assignment before the zone list exists.
|
||||
if (ClampRail != null)
|
||||
ReplaceClampZones(ClampRail.ResolveFor(Size, Quadrant));
|
||||
}
|
||||
|
||||
private void ReplaceClampZones(IReadOnlyList<ClampZone> zones)
|
||||
{
|
||||
if (ClampRail.SameZones(ClampZones, zones))
|
||||
return;
|
||||
ClampZones.Clear();
|
||||
foreach (var zone in zones)
|
||||
ClampZones.Add(zone);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Regenerates all cut-off drawings and materializes them as parts.
|
||||
/// Existing cut-off parts are removed first, then each cut-off is
|
||||
@@ -256,7 +303,11 @@ namespace OpenNest
|
||||
public int Quadrant
|
||||
{
|
||||
get { return quadrant; }
|
||||
set { quadrant = value <= 4 && value > 0 ? value : 1; }
|
||||
set
|
||||
{
|
||||
quadrant = value <= 4 && value > 0 ? value : 1;
|
||||
ResolveClampRail();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -0,0 +1,266 @@
|
||||
using OpenNest.Geometry;
|
||||
|
||||
namespace OpenNest.Tests;
|
||||
|
||||
/// <summary>
|
||||
/// The fixed machine clamp rail: X centers measured from the plate origin along the
|
||||
/// origin-side edge, resolved onto every sheet size without re-scaling (D2/D3).
|
||||
/// </summary>
|
||||
public class ClampRailTests
|
||||
{
|
||||
// The user's machine: ~8 clamps, 1.5" along the edge x 0.625" into the sheet.
|
||||
private static readonly double[] MachineCenters = { 6, 21, 36, 51, 66, 81, 96, 111 };
|
||||
|
||||
private static ClampRail Machine() => new(1.5, 0.625, MachineCenters);
|
||||
|
||||
// Plate(width, length): Width is the Y extent, Length the X extent along the clamp edge.
|
||||
private static Plate Sheet(double width, double length, int quadrant = 1) =>
|
||||
new(width, length) { Quadrant = quadrant };
|
||||
|
||||
[Theory]
|
||||
[InlineData(0, 0.625)]
|
||||
[InlineData(-1, 0.625)]
|
||||
[InlineData(double.NaN, 0.625)]
|
||||
[InlineData(double.PositiveInfinity, 0.625)]
|
||||
[InlineData(1.5, 0)]
|
||||
[InlineData(1.5, -0.5)]
|
||||
[InlineData(1.5, double.NaN)]
|
||||
public void NonPositiveOrNonFiniteSizesAreRejected(double width, double depth)
|
||||
{
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => new ClampRail(width, depth, new[] { 6.0 }));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(-0.5)]
|
||||
[InlineData(double.NaN)]
|
||||
[InlineData(double.PositiveInfinity)]
|
||||
public void CentersMustBeFiniteAndFromTheOrigin(double center)
|
||||
{
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => new ClampRail(1.5, 0.625, new[] { 6, center }));
|
||||
Assert.Throws<ArgumentNullException>(() => new ClampRail(1.5, 0.625, null!));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CentersAreSortedAndDistinct()
|
||||
{
|
||||
var rail = new ClampRail(1.5, 0.625, new[] { 36.0, 6, 21, 6 });
|
||||
Assert.Equal(new[] { 6.0, 21, 36 }, rail.Centers);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FullLengthSheetGetsEveryClampOnTheFrontEdge()
|
||||
{
|
||||
var zones = Machine().ResolveFor(new Size(60, 120), quadrant: 1);
|
||||
|
||||
Assert.Equal(8, zones.Count);
|
||||
for (var i = 0; i < zones.Count; i++)
|
||||
{
|
||||
Assert.Equal($"clamp-{i + 1}", zones[i].Id);
|
||||
Assert.Equal(MachineCenters[i] - 0.75, zones[i].Bounds.X);
|
||||
Assert.Equal(0, zones[i].Bounds.Y);
|
||||
Assert.Equal(1.5, zones[i].Bounds.Length);
|
||||
Assert.Equal(0.625, zones[i].Bounds.Width);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ShorterSheetSkipsClampsBeyondItWithoutRescaling()
|
||||
{
|
||||
// D2: a 60" sheet keeps the clamps at their table positions and drops the rest.
|
||||
var zones = Machine().ResolveFor(new Size(48, 60), quadrant: 1);
|
||||
|
||||
Assert.Equal(new[] { "clamp-1", "clamp-2", "clamp-3", "clamp-4" }, zones.Select(z => z.Id));
|
||||
Assert.Equal(new[] { 5.25, 20.25, 35.25, 50.25 }, zones.Select(z => z.Bounds.X));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ClampStraddlingTheSheetEndIsClippedNotDropped()
|
||||
{
|
||||
var rail = new ClampRail(1.5, 0.625, new[] { 59.5, 60.5, 60.75, 61 });
|
||||
|
||||
var zones = rail.ResolveFor(new Size(48, 60), quadrant: 1);
|
||||
|
||||
// 59.5 covers [58.75, 60]; 60.5 still reaches onto the sheet [59.75, 60];
|
||||
// 60.75 only touches the end and 61 lies wholly beyond it.
|
||||
Assert.Equal(new[] { "clamp-1", "clamp-2" }, zones.Select(z => z.Id));
|
||||
Assert.Equal(58.75, zones[0].Bounds.X);
|
||||
Assert.Equal(1.25, zones[0].Bounds.Length);
|
||||
Assert.Equal(59.75, zones[1].Bounds.X);
|
||||
Assert.Equal(0.25, zones[1].Bounds.Length);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ClampAtTheOriginAndDeepClampsAreClippedToTheSheet()
|
||||
{
|
||||
var rail = new ClampRail(1.5, 0.625, new[] { 0.25 });
|
||||
var origin = Assert.Single(rail.ResolveFor(new Size(48, 96), quadrant: 1));
|
||||
Assert.Equal(0, origin.Bounds.X);
|
||||
Assert.Equal(1.0, origin.Bounds.Length);
|
||||
|
||||
var deep = Assert.Single(new ClampRail(1.5, 10, new[] { 6.0 }).ResolveFor(new Size(4, 96), 1));
|
||||
Assert.Equal(4, deep.Bounds.Width);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(0, 96)]
|
||||
[InlineData(48, 0)]
|
||||
[InlineData(double.NaN, 96)]
|
||||
public void DegenerateSheetsGetNoZones(double width, double length)
|
||||
{
|
||||
Assert.Empty(Machine().ResolveFor(new Size(width, length), quadrant: 1));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(1)]
|
||||
[InlineData(2)]
|
||||
[InlineData(3)]
|
||||
[InlineData(4)]
|
||||
public void ZonesSitOnTheOriginEdgeMeasuredFromTheOriginInEveryQuadrant(int quadrant)
|
||||
{
|
||||
var plate = Sheet(48, 96, quadrant);
|
||||
plate.SetClampRail(new ClampRail(1.5, 0.625, new[] { 6.0 }));
|
||||
var zone = Assert.Single(plate.ClampZones);
|
||||
|
||||
// Plate coordinates start at the sheet's lower-left corner; translating by the
|
||||
// sheet's placement corner gives machine coordinates around the origin.
|
||||
var sheet = plate.BoundingBox(includeParts: false);
|
||||
var machine = zone.Bounds.Translate(sheet.X, sheet.Y);
|
||||
var awayFromOrigin = quadrant is 1 or 4 ? 1 : -1;
|
||||
var intoSheet = quadrant is 1 or 2 ? 1 : -1;
|
||||
|
||||
Assert.Equal(6.0, System.Math.Abs(machine.Center.X), 12);
|
||||
Assert.Equal(awayFromOrigin, System.Math.Sign(machine.Center.X));
|
||||
Assert.Equal(0.0, intoSheet > 0 ? machine.Bottom : machine.Top, 12);
|
||||
Assert.Equal(0.625, machine.Width);
|
||||
Assert.Equal(1.5, machine.Length, 12);
|
||||
Assert.True(zone.Bounds.Left >= 0 && zone.Bounds.Right <= 96 + 1e-9);
|
||||
Assert.True(zone.Bounds.Bottom >= 0 && zone.Bounds.Top <= 48 + 1e-9);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PlateFollowsItsRailWhenResizedOrRotated()
|
||||
{
|
||||
var plate = Sheet(48, 120);
|
||||
plate.SetClampRail(Machine());
|
||||
Assert.Equal(8, plate.ClampZones.Count);
|
||||
Assert.True(plate.ClampRail.Matches(plate));
|
||||
|
||||
plate.Size = new Size(48, 60);
|
||||
Assert.Equal(4, plate.ClampZones.Count);
|
||||
|
||||
// Rotating swaps the sheet's extents; the machine's clamps stay where they are.
|
||||
plate.Rotate90(RotationType.CW);
|
||||
Assert.Equal(new Size(60, 48), plate.Size);
|
||||
Assert.Equal(new[] { 5.25, 20.25, 35.25 }, plate.ClampZones.Select(z => z.Bounds.X));
|
||||
|
||||
plate.Quadrant = 2;
|
||||
Assert.True(plate.ClampRail.Matches(plate));
|
||||
Assert.Equal(48 - 6.75, plate.ClampZones[0].Bounds.X);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void UnchangedResolutionRaisesNoEvents()
|
||||
{
|
||||
var plate = Sheet(48, 120);
|
||||
plate.SetClampRail(Machine());
|
||||
var original = plate.ClampZones.ToList();
|
||||
var changes = 0;
|
||||
plate.ClampZonesChanged += (_, _) => changes++;
|
||||
|
||||
plate.Size = new Size(48, 120);
|
||||
plate.Quadrant = 1;
|
||||
plate.SetClampRail(Machine());
|
||||
|
||||
Assert.Equal(0, changes);
|
||||
Assert.Equal(original, plate.ClampZones); // same zone instances
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DetachingTheRailRemovesItsZones()
|
||||
{
|
||||
var plate = Sheet(48, 120);
|
||||
plate.SetClampRail(Machine());
|
||||
|
||||
plate.SetClampRail(null!);
|
||||
|
||||
Assert.Null(plate.ClampRail);
|
||||
Assert.Empty(plate.ClampZones);
|
||||
plate.Size = new Size(48, 96);
|
||||
Assert.Empty(plate.ClampZones);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PlatesWithoutARailKeepExplicitZonesThroughResizes()
|
||||
{
|
||||
var plate = Sheet(48, 96);
|
||||
plate.ClampZones.Add(new ClampZone("manual", new Box(5.25, 0, 1.5, 0.625)));
|
||||
|
||||
plate.Size = new Size(48, 120);
|
||||
plate.Quadrant = 3;
|
||||
|
||||
Assert.Equal("manual", Assert.Single(plate.ClampZones).Id);
|
||||
Assert.False(Machine().Matches(plate));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void NewPlatesFollowTheNestRailAtTheirOwnSize()
|
||||
{
|
||||
var nest = new Nest();
|
||||
nest.PlateDefaults.Size = new Size(48, 60);
|
||||
nest.SetClampRail(Machine());
|
||||
|
||||
var plate = nest.CreatePlate();
|
||||
|
||||
Assert.Same(nest.PlateDefaults.ClampRail, plate.ClampRail);
|
||||
Assert.Equal(4, plate.ClampZones.Count);
|
||||
plate.Size = new Size(60, 120);
|
||||
Assert.Equal(8, plate.ClampZones.Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void NestRailReplacesEveryPlatesZones()
|
||||
{
|
||||
var nest = new Nest();
|
||||
nest.PlateDefaults.Size = new Size(48, 120);
|
||||
var a = nest.CreatePlate();
|
||||
var b = nest.CreatePlate();
|
||||
b.Size = new Size(48, 60);
|
||||
b.ClampZones.Add(new ClampZone("manual", new Box(1, 0, 1, 1)));
|
||||
|
||||
nest.SetClampRail(Machine());
|
||||
Assert.Equal(8, a.ClampZones.Count);
|
||||
Assert.Equal(4, b.ClampZones.Count);
|
||||
Assert.DoesNotContain(b.ClampZones, z => z.Id == "manual");
|
||||
|
||||
// A rail without clamps is no rail: zones and the template are cleared everywhere.
|
||||
nest.SetClampRail(new ClampRail(1.5, 0.625, Array.Empty<double>()));
|
||||
Assert.Null(nest.PlateDefaults.ClampRail);
|
||||
Assert.All(nest.Plates, p => Assert.Empty(p.ClampZones));
|
||||
Assert.Empty(nest.CreatePlate().ClampZones);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RailZonesStayOutOfQuantityAndUtilization()
|
||||
{
|
||||
var drawing = new Drawing("part", new OpenNest.CNC.Program());
|
||||
var nest = new Nest();
|
||||
nest.Drawings.Add(drawing);
|
||||
nest.SetClampRail(Machine());
|
||||
var plate = nest.CreatePlate();
|
||||
|
||||
Assert.Equal(8, plate.ClampZones.Count);
|
||||
Assert.Empty(plate.Parts);
|
||||
Assert.Equal(0, plate.Utilization());
|
||||
nest.UpdateDrawingQuantities();
|
||||
Assert.Equal(0, drawing.Quantity.Nested);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RailsCompareByValue()
|
||||
{
|
||||
Assert.Equal(Machine(), new ClampRail(1.5, 0.625, MachineCenters.Reverse()));
|
||||
Assert.Equal(Machine().GetHashCode(), new ClampRail(1.5, 0.625, MachineCenters).GetHashCode());
|
||||
Assert.NotEqual(Machine(), new ClampRail(1.5, 0.5, MachineCenters));
|
||||
Assert.NotEqual(Machine(), new ClampRail(1.5, 0.625, MachineCenters.Take(7)));
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user