using OpenNest.CNC;
namespace OpenNest.Posts.Cincinnati;
///
/// Chooses the M47 head raise (ยง3.47) written before the rapid that leaves a feature.
///
internal static class CincinnatiHeadRaise
{
/// True when the feature just cut is a part exterior.
/// Travel to the next pierce; null when unknown.
///
/// True when Plan Cutting marked the rapid to raise the head over parts already cut
/// (): it always gets a raise the operator cannot skip.
///
/// The block to write, or null for no head raise.
internal static string Line(CincinnatiPostConfig config, bool isExterior, double? rapidDistance,
bool raised = false)
{
if (IsSafetyRapid(config, rapidDistance))
return SafetyLine(config);
if (raised)
return "M47";
var mode = isExterior ? config.ExteriorM47 : config.InteriorM47;
return mode switch
{
M47Mode.Always => "M47",
M47Mode.BlockDelete => "/M47",
M47Mode.Auto => IsLongRapid(config, rapidDistance) ? "M47" : "/M47",
_ => null,
};
}
///
/// True when the rapid is long enough to cross warped plate, so it takes the
/// safety head raise. Unknown travel never does.
///
internal static bool IsSafetyRapid(CincinnatiPostConfig config, double? rapidDistance) =>
config.SafetyHeadraiseDistance.HasValue
&& config.SafetyHeadraiseRapidDistance is { } threshold
&& rapidDistance is { } distance
&& distance > threshold;
internal static string SafetyLine(CincinnatiPostConfig config) =>
$"M47 P{config.SafetyHeadraiseDistance.Value} (Safety Headraise)";
// Unknown travel, or no threshold configured, always gets the full raise.
private static bool IsLongRapid(CincinnatiPostConfig config, double? rapidDistance) =>
config.M47OverrideDistanceThreshold is not { } threshold
|| rapidDistance is not { } distance
|| distance > threshold;
}