mirror of
https://github.com/ajisaacs/OpenNest.git
synced 2026-10-25 09:21:06 -04:00
fix(io): keep a sheet's own clamp rail and its removals through save and reload
Commit can attach the stock's rail to a sheet whose nest has no (or another) default rail, but only the default rail was saved and the reader re-attached sheets only to it, so the removed clamp and its time vanished on reload. A sheet following a rail other than the default now saves it in an optional per-plate clampRail (read leniently, omitted otherwise), and the reader re-attaches the sheet to it. PM 22daec3d-dabb-4aae-95f7-c1d090d5dcdf
This commit is contained in:
1 parent
4226c0f902
commit
d9273c889f
5 files changed
+58
-12
No files matched your search
@@ -424,6 +424,32 @@ public class ClampRailPersistenceTests
|
||||
Assert.Contains("\"removedClamps\"", ReadNestJson(RemovedClamp3Nest()), StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
// PM 22daec3d: a sheet following a rail other than the nest default keeps its rail,
|
||||
// removed clamps and removal time through save/reload.
|
||||
[Fact]
|
||||
public void SheetRailDifferentFromTheDefaultsSurvivesReload()
|
||||
{
|
||||
var nest = new Nest("no-default-rail");
|
||||
nest.PlateDefaults.Size = new Size(48, 120);
|
||||
var plate = nest.CreatePlate();
|
||||
plate.SetClampRail(Machine(), new[] { "clamp-3" });
|
||||
|
||||
var reopened = Assert.Single(RoundTrip(nest).Plates);
|
||||
|
||||
Assert.Equal(Machine(), reopened.ClampRail);
|
||||
Assert.Equal(new[] { "clamp-3" }, reopened.RemovedClamps);
|
||||
Assert.Equal(ClampRail.DefaultRemovalMinutes, reopened.ClampRemovalMinutes);
|
||||
Assert.Null(RoundTrip(nest).PlateDefaults.ClampRail);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SheetsFollowingTheDefaultRailWriteNoPerSheetRail()
|
||||
{
|
||||
var json = ReadNestJson(RemovedClamp3Nest());
|
||||
var root = JsonNode.Parse(json)!;
|
||||
Assert.Null(root["plates"]![0]!["clampRail"]);
|
||||
}
|
||||
|
||||
/// <summary>Removes a named property wherever it appears in the document, simulating a
|
||||
/// key an older writer never emitted. Rebuilds via <see cref="JsonNode"/> so the result
|
||||
/// is always valid JSON regardless of whether the property was first, last or only one
|
||||
|
||||
@@ -214,6 +214,15 @@ namespace OpenNest.IO
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
[JsonConverter(typeof(LenientStringListConverter))]
|
||||
public List<string> RemovedClamps { get; init; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// The machine clamp rail this sheet follows, written only when it is not the
|
||||
/// nest's default rail (otherwise the sheet re-attaches to that one on load).
|
||||
/// Read leniently like <see cref="PlateDefaultsDto.ClampRail"/>.
|
||||
/// </summary>
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
[JsonConverter(typeof(LenientClampRailConverter))]
|
||||
public ClampRailDto ClampRail { get; init; }
|
||||
}
|
||||
|
||||
public record ClampZoneDto
|
||||
|
||||
@@ -452,8 +452,10 @@ namespace OpenNest.IO
|
||||
.Where(id => !string.IsNullOrEmpty(id))
|
||||
.ToHashSet(StringComparer.Ordinal)
|
||||
?? new HashSet<string>();
|
||||
if (clampRail != null && clampRail.Matches(plate, removedClamps))
|
||||
plate.SetClampRail(clampRail, removedClamps);
|
||||
// A sheet saved with its own rail (not the nest default) follows that one.
|
||||
var plateRail = ReadClampRail(p.ClampRail) ?? clampRail;
|
||||
if (plateRail != null && plateRail.Matches(plate, removedClamps))
|
||||
plate.SetClampRail(plateRail, removedClamps);
|
||||
|
||||
for (var partIndex = 0; partIndex < p.Parts.Count; partIndex++)
|
||||
{
|
||||
|
||||
@@ -135,15 +135,7 @@ namespace OpenNest.IO
|
||||
Right = pd.EdgeSpacing.Right,
|
||||
Bottom = pd.EdgeSpacing.Bottom,
|
||||
},
|
||||
ClampRail = pd.ClampRail == null
|
||||
? null
|
||||
: new ClampRailDto
|
||||
{
|
||||
Width = pd.ClampRail.Width,
|
||||
Depth = pd.ClampRail.Depth,
|
||||
Centers = pd.ClampRail.Centers.ToList(),
|
||||
RemovalMinutes = pd.ClampRail.RemovalMinutes,
|
||||
},
|
||||
ClampRail = ToDto(pd.ClampRail),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -222,6 +214,17 @@ namespace OpenNest.IO
|
||||
&& rail.Matches(plate);
|
||||
}
|
||||
|
||||
private static ClampRailDto ToDto(ClampRail rail) =>
|
||||
rail == null
|
||||
? null
|
||||
: new ClampRailDto
|
||||
{
|
||||
Width = rail.Width,
|
||||
Depth = rail.Depth,
|
||||
Centers = rail.Centers.ToList(),
|
||||
RemovalMinutes = rail.RemovalMinutes,
|
||||
};
|
||||
|
||||
/// <summary>Numeric suffix of a rail clamp id ("clamp-3" -> 3), for a natural sort of
|
||||
/// <see cref="PlateDto.RemovedClamps"/> instead of lexical ("clamp-10" before "clamp-2").
|
||||
/// A non-matching id sorts last by its own ordinal text.</summary>
|
||||
@@ -343,6 +346,10 @@ namespace OpenNest.IO
|
||||
.OrderBy(ClampIndex)
|
||||
.ThenBy(id => id, StringComparer.Ordinal)
|
||||
.ToList(),
|
||||
// Only a rail other than the nest default needs saving per sheet.
|
||||
ClampRail = Equals(plate.ClampRail, nest.PlateDefaults.ClampRail)
|
||||
? null
|
||||
: ToDto(plate.ClampRail),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@@ -86,7 +86,9 @@ Auto Nest removed clamps as a last resort lists their rail ids in an optional
|
||||
`removedClamps` array (omitted when none were removed); its `clamps` already
|
||||
exclude them, and it follows the rail minus those ids. A malformed
|
||||
`removedClamps` value reads as none removed (non-string entries are skipped);
|
||||
the saved `clamps` load either way.
|
||||
the saved `clamps` load either way. A plate that follows a rail other than the nest's default
|
||||
saves it in its own optional `clampRail` (same shape), so its removal state and
|
||||
time survive a reload; plates following the default rail omit it.
|
||||
|
||||
An empty plate (no parts, no cut-offs) is omitted from the file unless that
|
||||
would lose clamp zones: it is omitted like any other empty plate only when a
|
||||
|
||||
Reference in new issue
Block a user