mirror of
https://github.com/ajisaacs/OpenNest.git
synced 2026-11-07 10:45:44 -05:00
Expensive alloy jobs (N26-295, 310 stainless) could not fit their last PT42 at full part spacing; the plate was squeezed to 0.2 spacing with a part 0.14 from the edge. Parts whose straight edges face each other one kerf apart are cut on the same centerline, saving the spacing along each shared edge. Plate.CommonLines holds groups of parts and the kerf they were joined at. Shared spans are derived from the placed clean perimeters, never stored, so a moved member breaks its group instead of leaving a stale span. Plate > Arrange > Join Common Line slides the selected parts together at the plate's kerf; Remove Common Line ungroups them. The plate draws shared spans as a dashed centerline. Both spacing checks hold group members to the kerf instead of the part spacing, and a new pre-post Common lines check reports broken groups, a changed kerf, and leads that run into a partner. Groups persist as part positions in an optional commonLines array that older readers ignore. This first slice still cuts every shared edge twice; single-pass cutting through Plan Cutting and the posts comes next. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
52 lines
2.5 KiB
C#
52 lines
2.5 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
|
|
namespace OpenNest
|
|
{
|
|
/// <summary>
|
|
/// Parts placed exactly one kerf apart along collinear straight edges, so one centerline cut
|
|
/// makes both edges (see docs/common-line-cutting.md). Membership is by reference; the shared
|
|
/// spans are derived from the parts' placed geometry (<see cref="CommonLineGeometry"/>), never
|
|
/// stored, so a moved member breaks the group rather than leaving a stale span behind.
|
|
/// </summary>
|
|
public sealed class CommonLineGroup
|
|
{
|
|
private readonly List<Part> members;
|
|
|
|
/// <exception cref="ArgumentOutOfRangeException">The kerf is not finite and positive.</exception>
|
|
/// <exception cref="ArgumentException">Fewer than two distinct parts, a null part or a cut-off.</exception>
|
|
public CommonLineGroup(IEnumerable<Part> members, double kerf)
|
|
{
|
|
ArgumentNullException.ThrowIfNull(members);
|
|
if (!double.IsFinite(kerf) || kerf <= 0)
|
|
throw new ArgumentOutOfRangeException(nameof(kerf), kerf, "A common line needs a finite, positive kerf.");
|
|
var distinct = new List<Part>();
|
|
foreach (var part in members)
|
|
{
|
|
if (part == null)
|
|
throw new ArgumentException("A common-line group cannot hold a null part.", nameof(members));
|
|
if (part.BaseDrawing?.IsCutOff == true)
|
|
throw new ArgumentException("A cut-off cannot share a common line.", nameof(members));
|
|
if (!distinct.Any(existing => ReferenceEquals(existing, part)))
|
|
distinct.Add(part);
|
|
}
|
|
if (distinct.Count < 2)
|
|
throw new ArgumentException("A common-line group needs at least two parts.", nameof(members));
|
|
this.members = distinct;
|
|
Kerf = kerf;
|
|
}
|
|
|
|
/// <summary>The parts in the group, in the order they were joined.</summary>
|
|
public IReadOnlyList<Part> Members => members;
|
|
|
|
/// <summary>The gap the members were placed at: the kerf width when the group was made.</summary>
|
|
public double Kerf { get; }
|
|
|
|
public bool Contains(Part part) => members.Any(member => ReferenceEquals(member, part));
|
|
|
|
/// <summary>Drops a member (a part removed from the plate); true when it was one.</summary>
|
|
internal bool Remove(Part part) => members.RemoveAll(member => ReferenceEquals(member, part)) > 0;
|
|
}
|
|
}
|