mirror of
https://github.com/ajisaacs/OpenNest.git
synced 2026-11-14 12:35:07 -05:00
Round holes are cut as sub-programs, which are never marked because they may be shared, so the safest-route fallback could not raise the head for the rapid into a hole: on interlocked layouts every such crossing stayed a finding and the plan stayed unverified. A HEAD RAISE marker may now sit directly before a sub-program call, raising the call's arrival rapid. - Motion reader: a marked call raises its first rapid; each sub-program motion records the part's own call that runs it. - RaisedRapids marks the call when the crossing rapid is its arrival. - Cincinnati CL keeps the marker with its hole call and writes M47 before it; part sub-program dedupe now tells marked programs apart. - CI Fiber raises before the hole's first G0. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
76 lines
2.6 KiB
C#
76 lines
2.6 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using OpenNest.Diagnostics;
|
|
using OpenNest.Geometry;
|
|
|
|
namespace OpenNest.CNC.CuttingPlanning;
|
|
|
|
/// <summary>Owned value motions; no references to live programs, instructions or settings.</summary>
|
|
public sealed class OwnedExecution
|
|
{
|
|
internal OwnedExecution(IEnumerable<ExecutionMotion> motions)
|
|
{
|
|
Motions = Array.AsReadOnly(motions.ToArray());
|
|
}
|
|
|
|
public IReadOnlyList<ExecutionMotion> Motions { get; }
|
|
public Vector DeparturePoint => Motions[^1].End;
|
|
public bool HasCuttingContour => Motions.Any(move => !move.Rapid
|
|
&& move.Layer is LayerType.Cut or LayerType.Display
|
|
&& move.Length > PostVerificationGeometry.Epsilon);
|
|
|
|
public double RapidDistanceFrom(Vector arrival)
|
|
{
|
|
PostVerificationGeometry.Validate(arrival);
|
|
var total = 0.0;
|
|
for (var index = 0; index < Motions.Count; index++)
|
|
{
|
|
var move = Motions[index];
|
|
if (move.Rapid && (index == 0 ? arrival : move.Start) is { } start)
|
|
total += start.DistanceTo(move.End);
|
|
}
|
|
return total;
|
|
}
|
|
}
|
|
|
|
/// <summary>An immutable motion value; native line/arc geometry stays private to Core.</summary>
|
|
public sealed class ExecutionMotion
|
|
{
|
|
internal ExecutionMotion(Vector? start, Vector end, bool rapid, LayerType layer,
|
|
PostVerificationGeometry.Curve curve, bool headRaised = false, int? code = null, int? callCode = null)
|
|
{
|
|
Start = start;
|
|
End = end;
|
|
Rapid = rapid;
|
|
Layer = layer;
|
|
Curve = curve;
|
|
HeadRaised = headRaised;
|
|
Code = code;
|
|
CallCode = callCode;
|
|
}
|
|
|
|
public Vector? Start { get; }
|
|
public Vector End { get; }
|
|
public bool Rapid { get; }
|
|
public LayerType Layer { get; }
|
|
|
|
/// <summary>A rapid made with the head raised over parts already cut (<see cref="HeadRaise"/>).</summary>
|
|
public bool HeadRaised { get; }
|
|
|
|
/// <summary>
|
|
/// The index of the code this motion runs in the read program's own codes; null for a motion
|
|
/// inside a sub-program and for the rapid a program that opens with a cut is given.
|
|
/// </summary>
|
|
public int? Code { get; }
|
|
|
|
/// <summary>
|
|
/// For a motion inside a sub-program, the index of the read program's own call that runs it;
|
|
/// null for the program's own motions.
|
|
/// </summary>
|
|
internal int? CallCode { get; }
|
|
public double Length => Curve?.Length ?? 0;
|
|
internal PostVerificationGeometry.Curve Curve { get; }
|
|
internal ExecutionMotion WithStart(Vector? start) => new(start, End, Rapid, Layer, Curve, HeadRaised, Code, CallCode);
|
|
}
|