style: apply CSharpier formatting to all C# sources
Repo-wide sweep with the pinned CSharpier 1.3.0 tool. Whitespace and line-wrapping only; OpenNest.Engine.Tests (109) and OpenNest.IO.Tests pass after reformat, full solution builds 0 errors. Added .csharpierignore so csproj/config XML keeps its existing layout (CSharpier's XML wrapping churns attributes with zero benefit). Formatting is now enforceable: dotnet csharpier check . passes.
This commit is contained in:
@@ -129,14 +129,28 @@ public sealed class CincinnatiFeatureWriter
|
||||
var sb = new StringBuilder();
|
||||
|
||||
// Kerf compensation on first cutting move (skip for etch)
|
||||
if (!ctx.IsEtch && !kerfEmitted && _config.KerfCompensation == KerfMode.ControllerSide)
|
||||
if (
|
||||
!ctx.IsEtch
|
||||
&& !kerfEmitted
|
||||
&& _config.KerfCompensation == KerfMode.ControllerSide
|
||||
)
|
||||
{
|
||||
sb.Append(_config.DefaultKerfSide == KerfSide.Left ? "G41 " : "G42 ");
|
||||
kerfEmitted = true;
|
||||
}
|
||||
|
||||
var xCoord = FormatCoordWithVars(linear.EndPoint.X + offset.X, "X", linear.VariableRefs, ctx);
|
||||
var yCoord = FormatCoordWithVars(linear.EndPoint.Y + offset.Y, "Y", linear.VariableRefs, ctx);
|
||||
var xCoord = FormatCoordWithVars(
|
||||
linear.EndPoint.X + offset.X,
|
||||
"X",
|
||||
linear.VariableRefs,
|
||||
ctx
|
||||
);
|
||||
var yCoord = FormatCoordWithVars(
|
||||
linear.EndPoint.Y + offset.Y,
|
||||
"Y",
|
||||
linear.VariableRefs,
|
||||
ctx
|
||||
);
|
||||
sb.Append($"G1 X{xCoord} Y{yCoord}");
|
||||
|
||||
// Feedrate — etch always uses process feedrate
|
||||
@@ -155,7 +169,11 @@ public sealed class CincinnatiFeatureWriter
|
||||
var sb = new StringBuilder();
|
||||
|
||||
// Kerf compensation on first cutting move (skip for etch)
|
||||
if (!ctx.IsEtch && !kerfEmitted && _config.KerfCompensation == KerfMode.ControllerSide)
|
||||
if (
|
||||
!ctx.IsEtch
|
||||
&& !kerfEmitted
|
||||
&& _config.KerfCompensation == KerfMode.ControllerSide
|
||||
)
|
||||
{
|
||||
sb.Append(_config.DefaultKerfSide == KerfSide.Left ? "G41 " : "G42 ");
|
||||
kerfEmitted = true;
|
||||
@@ -163,8 +181,18 @@ public sealed class CincinnatiFeatureWriter
|
||||
|
||||
// G2 = CW, G3 = CCW
|
||||
var gCode = arc.Rotation == RotationType.CW ? "G2" : "G3";
|
||||
var xCoord = FormatCoordWithVars(arc.EndPoint.X + offset.X, "X", arc.VariableRefs, ctx);
|
||||
var yCoord = FormatCoordWithVars(arc.EndPoint.Y + offset.Y, "Y", arc.VariableRefs, ctx);
|
||||
var xCoord = FormatCoordWithVars(
|
||||
arc.EndPoint.X + offset.X,
|
||||
"X",
|
||||
arc.VariableRefs,
|
||||
ctx
|
||||
);
|
||||
var yCoord = FormatCoordWithVars(
|
||||
arc.EndPoint.Y + offset.Y,
|
||||
"Y",
|
||||
arc.VariableRefs,
|
||||
ctx
|
||||
);
|
||||
sb.Append($"{gCode} X{xCoord} Y{yCoord}");
|
||||
|
||||
// Convert absolute center to incremental I/J
|
||||
@@ -175,8 +203,7 @@ public sealed class CincinnatiFeatureWriter
|
||||
// Feedrate — etch always uses process feedrate, cut uses layer/radius-based
|
||||
var radius = currentPos.DistanceTo(arc.CenterPoint);
|
||||
var isFullCircle = IsFullCircle(currentPos, arc.EndPoint);
|
||||
var feedVar = ctx.IsEtch ? "#148"
|
||||
: GetArcFeedrate(arc.Layer, radius, isFullCircle);
|
||||
var feedVar = ctx.IsEtch ? "#148" : GetArcFeedrate(arc.Layer, radius, isFullCircle);
|
||||
if (feedVar != lastFeedVar)
|
||||
{
|
||||
sb.Append($" F{feedVar}");
|
||||
@@ -211,14 +238,20 @@ public sealed class CincinnatiFeatureWriter
|
||||
/// the sheet width/length variables.
|
||||
/// Inline variables fall through to literal formatting.
|
||||
/// </summary>
|
||||
private string FormatCoordWithVars(double value, string axis,
|
||||
Dictionary<string, string> variableRefs, FeatureContext ctx)
|
||||
private string FormatCoordWithVars(
|
||||
double value,
|
||||
string axis,
|
||||
Dictionary<string, string> variableRefs,
|
||||
FeatureContext ctx
|
||||
)
|
||||
{
|
||||
// User-defined variable references take priority
|
||||
if (variableRefs != null
|
||||
if (
|
||||
variableRefs != null
|
||||
&& variableRefs.TryGetValue(axis, out var varName)
|
||||
&& ctx.UserVariableMapping != null
|
||||
&& ctx.UserVariableMapping.TryGetValue((ctx.DrawingId, varName), out var varNum))
|
||||
&& ctx.UserVariableMapping.TryGetValue((ctx.DrawingId, varName), out var varNum)
|
||||
)
|
||||
{
|
||||
return $"#{varNum}";
|
||||
}
|
||||
@@ -268,7 +301,12 @@ public sealed class CincinnatiFeatureWriter
|
||||
return Vector.Zero;
|
||||
}
|
||||
|
||||
private void WriteRapidToPierce(TextWriter writer, FeatureContext ctx, Vector piercePoint, Vector offset)
|
||||
private void WriteRapidToPierce(
|
||||
TextWriter writer,
|
||||
FeatureContext ctx,
|
||||
Vector piercePoint,
|
||||
Vector offset
|
||||
)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
|
||||
@@ -311,15 +349,18 @@ public sealed class CincinnatiFeatureWriter
|
||||
{
|
||||
LayerType.Leadin => "#126",
|
||||
LayerType.Leadout => "#129",
|
||||
_ => "#148"
|
||||
_ => "#148",
|
||||
};
|
||||
}
|
||||
|
||||
private string GetArcFeedrate(LayerType layer, double radius, bool isFullCircle)
|
||||
{
|
||||
if (layer == LayerType.Leadin) return "#127";
|
||||
if (layer == LayerType.Leadout) return "#129";
|
||||
if (isFullCircle) return "[#148*#128]";
|
||||
if (layer == LayerType.Leadin)
|
||||
return "#127";
|
||||
if (layer == LayerType.Leadout)
|
||||
return "#129";
|
||||
if (isFullCircle)
|
||||
return "[#148*#128]";
|
||||
return GetArcCutFeedrate(radius);
|
||||
}
|
||||
|
||||
|
||||
@@ -19,8 +19,10 @@ public sealed class CincinnatiPartSubprogramWriter
|
||||
private readonly CoordinateFormatter _fmt;
|
||||
private readonly Dictionary<int, int> _holeSubprograms;
|
||||
|
||||
public CincinnatiPartSubprogramWriter(CincinnatiPostConfig config,
|
||||
Dictionary<int, int> holeSubprograms = null)
|
||||
public CincinnatiPartSubprogramWriter(
|
||||
CincinnatiPostConfig config,
|
||||
Dictionary<int, int> holeSubprograms = null
|
||||
)
|
||||
{
|
||||
_config = config;
|
||||
_featureWriter = new CincinnatiFeatureWriter(config);
|
||||
@@ -32,8 +34,15 @@ public sealed class CincinnatiPartSubprogramWriter
|
||||
/// Writes a complete part sub-program for the given normalized program.
|
||||
/// The program coordinates must already be normalized to origin (0,0).
|
||||
/// </summary>
|
||||
public void Write(TextWriter w, Program normalizedProgram, string drawingName,
|
||||
int subNumber, string cutLibrary, string etchLibrary, double sheetDiagonal)
|
||||
public void Write(
|
||||
TextWriter w,
|
||||
Program normalizedProgram,
|
||||
string drawingName,
|
||||
int subNumber,
|
||||
string cutLibrary,
|
||||
string etchLibrary,
|
||||
double sheetDiagonal
|
||||
)
|
||||
{
|
||||
var allFeatures = FeatureUtils.SplitByRapids(normalizedProgram.Codes);
|
||||
if (allFeatures.Count == 0)
|
||||
@@ -58,9 +67,7 @@ public sealed class CincinnatiPartSubprogramWriter
|
||||
continue;
|
||||
}
|
||||
|
||||
var featureNumber = i == 0
|
||||
? _config.FeatureLineNumberStart
|
||||
: 1000 + i + 1;
|
||||
var featureNumber = i == 0 ? _config.FeatureLineNumberStart : 1000 + i + 1;
|
||||
var cutDistance = FeatureUtils.ComputeCutDistance(codes);
|
||||
|
||||
var ctx = new FeatureContext
|
||||
@@ -75,7 +82,7 @@ public sealed class CincinnatiPartSubprogramWriter
|
||||
IsEtch = isEtch,
|
||||
LibraryFile = isEtch ? etchLibrary : cutLibrary,
|
||||
CutDistance = cutDistance,
|
||||
SheetDiagonal = sheetDiagonal
|
||||
SheetDiagonal = sheetDiagonal,
|
||||
};
|
||||
|
||||
_featureWriter.Write(w, ctx);
|
||||
@@ -84,15 +91,20 @@ public sealed class CincinnatiPartSubprogramWriter
|
||||
w.WriteLine($"M99 (END OF {drawingName})");
|
||||
}
|
||||
|
||||
private void WriteHoleSubprogramCall(TextWriter w, SubProgramCall call,
|
||||
int featureIndex, bool isLastFeature)
|
||||
private void WriteHoleSubprogramCall(
|
||||
TextWriter w,
|
||||
SubProgramCall call,
|
||||
int featureIndex,
|
||||
bool isLastFeature
|
||||
)
|
||||
{
|
||||
var postSubNum = _holeSubprograms != null && _holeSubprograms.TryGetValue(call.Id, out var num)
|
||||
? num : call.Id;
|
||||
var postSubNum =
|
||||
_holeSubprograms != null && _holeSubprograms.TryGetValue(call.Id, out var num)
|
||||
? num
|
||||
: call.Id;
|
||||
|
||||
var featureNumber = featureIndex == 0
|
||||
? _config.FeatureLineNumberStart
|
||||
: 1000 + featureIndex + 1;
|
||||
var featureNumber =
|
||||
featureIndex == 0 ? _config.FeatureLineNumberStart : 1000 + featureIndex + 1;
|
||||
|
||||
var sb = new StringBuilder();
|
||||
if (_config.UseLineNumbers)
|
||||
@@ -138,8 +150,10 @@ public sealed class CincinnatiPartSubprogramWriter
|
||||
/// Scans all plates and builds a mapping of unique part geometries to sub-program numbers,
|
||||
/// along with their normalized programs for writing.
|
||||
/// </summary>
|
||||
internal static (Dictionary<(int, long), int> mapping, List<(int subNum, string name, Program program)> entries)
|
||||
BuildRegistry(IEnumerable<Plate> plates, int startNumber)
|
||||
internal static (
|
||||
Dictionary<(int, long), int> mapping,
|
||||
List<(int subNum, string name, Program program)> entries
|
||||
) BuildRegistry(IEnumerable<Plate> plates, int startNumber)
|
||||
{
|
||||
var mapping = new Dictionary<(int, long), int>();
|
||||
var entries = new List<(int, string, Program)>();
|
||||
@@ -149,7 +163,8 @@ public sealed class CincinnatiPartSubprogramWriter
|
||||
{
|
||||
foreach (var part in plate.Parts)
|
||||
{
|
||||
if (part.BaseDrawing.IsCutOff) continue;
|
||||
if (part.BaseDrawing.IsCutOff)
|
||||
continue;
|
||||
var key = SubprogramKey(part);
|
||||
if (!mapping.ContainsKey(key))
|
||||
{
|
||||
@@ -180,8 +195,10 @@ public sealed class CincinnatiPartSubprogramWriter
|
||||
/// Scans all parts across all plates and builds a nest-level registry of unique
|
||||
/// hole sub-programs. Deduplicates by comparing sub-program code content.
|
||||
/// </summary>
|
||||
internal static (Dictionary<int, int> modelToPostMapping, List<(int subNum, Program program)> entries)
|
||||
BuildHoleRegistry(IEnumerable<Plate> plates, int startNumber)
|
||||
internal static (
|
||||
Dictionary<int, int> modelToPostMapping,
|
||||
List<(int subNum, Program program)> entries
|
||||
) BuildHoleRegistry(IEnumerable<Plate> plates, int startNumber)
|
||||
{
|
||||
var mapping = new Dictionary<int, int>();
|
||||
var entries = new List<(int, Program)>();
|
||||
@@ -192,11 +209,14 @@ public sealed class CincinnatiPartSubprogramWriter
|
||||
{
|
||||
foreach (var part in plate.Parts)
|
||||
{
|
||||
if (part.BaseDrawing.IsCutOff) continue;
|
||||
if (part.BaseDrawing.IsCutOff)
|
||||
continue;
|
||||
foreach (var code in part.Program.Codes)
|
||||
{
|
||||
if (code is not SubProgramCall call) continue;
|
||||
if (mapping.ContainsKey(call.Id)) continue;
|
||||
if (code is not SubProgramCall call)
|
||||
continue;
|
||||
if (mapping.ContainsKey(call.Id))
|
||||
continue;
|
||||
|
||||
var canonical = ProgramToCanonical(call.Program);
|
||||
if (contentIndex.TryGetValue(canonical, out var existingNum))
|
||||
@@ -226,7 +246,9 @@ public sealed class CincinnatiPartSubprogramWriter
|
||||
if (code is LinearMove lm)
|
||||
sb.Append($"L{lm.EndPoint.X:F6},{lm.EndPoint.Y:F6},{(int)lm.Layer}");
|
||||
else if (code is ArcMove am)
|
||||
sb.Append($"A{am.EndPoint.X:F6},{am.EndPoint.Y:F6},{am.CenterPoint.X:F6},{am.CenterPoint.Y:F6},{(int)am.Rotation},{(int)am.Layer}");
|
||||
sb.Append(
|
||||
$"A{am.EndPoint.X:F6},{am.EndPoint.Y:F6},{am.CenterPoint.X:F6},{am.CenterPoint.Y:F6},{(int)am.Rotation},{(int)am.Layer}"
|
||||
);
|
||||
else if (code is RapidMove rm)
|
||||
sb.Append($"R{rm.EndPoint.X:F6},{rm.EndPoint.Y:F6}");
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace OpenNest.Posts.Cincinnati
|
||||
G91,
|
||||
|
||||
/// <summary>Use machine coordinate system.</summary>
|
||||
G53
|
||||
G53,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -29,7 +29,7 @@ namespace OpenNest.Posts.Cincinnati
|
||||
LibraryFile,
|
||||
|
||||
/// <summary>Explicitly define G89 parameters in the program.</summary>
|
||||
Explicit
|
||||
Explicit,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -41,7 +41,7 @@ namespace OpenNest.Posts.Cincinnati
|
||||
ControllerSide,
|
||||
|
||||
/// <summary>Pre-applied to part geometry during post-processing.</summary>
|
||||
PreApplied
|
||||
PreApplied,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -53,7 +53,7 @@ namespace OpenNest.Posts.Cincinnati
|
||||
Left,
|
||||
|
||||
/// <summary>Kerf applied to the right side of the cut.</summary>
|
||||
Right
|
||||
Right,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -71,7 +71,7 @@ namespace OpenNest.Posts.Cincinnati
|
||||
Auto,
|
||||
|
||||
/// <summary>Do not use M47.</summary>
|
||||
None
|
||||
None,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -86,7 +86,7 @@ namespace OpenNest.Posts.Cincinnati
|
||||
EndOfSheet,
|
||||
|
||||
/// <summary>Pallet exchange at start and end of sheet.</summary>
|
||||
StartAndEnd
|
||||
StartAndEnd,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -132,7 +132,9 @@ namespace OpenNest.Posts.Cincinnati
|
||||
|
||||
[Category("2. Subprograms")]
|
||||
[DisplayName("Use Part Subprograms")]
|
||||
[Description("Use M98 sub-programs for part geometry. Reduces output size for repeated parts.")]
|
||||
[Description(
|
||||
"Use M98 sub-programs for part geometry. Reduces output size for repeated parts."
|
||||
)]
|
||||
public bool UsePartSubprograms { get; set; } = false;
|
||||
|
||||
[Category("2. Subprograms")]
|
||||
@@ -247,13 +249,31 @@ namespace OpenNest.Posts.Cincinnati
|
||||
|
||||
[Category("9. Feedrates")]
|
||||
[DisplayName("Arc Feedrate Ranges")]
|
||||
[Description("Radius-based arc feedrate ranges. Matched from smallest to largest MaxRadius.")]
|
||||
public List<ArcFeedrateRange> ArcFeedrateRanges { get; set; } = new()
|
||||
{
|
||||
new() { MaxRadius = 0.125, FeedratePercent = 0.25, VariableNumber = 123 },
|
||||
new() { MaxRadius = 0.750, FeedratePercent = 0.50, VariableNumber = 124 },
|
||||
new() { MaxRadius = 4.500, FeedratePercent = 0.80, VariableNumber = 125 }
|
||||
};
|
||||
[Description(
|
||||
"Radius-based arc feedrate ranges. Matched from smallest to largest MaxRadius."
|
||||
)]
|
||||
public List<ArcFeedrateRange> ArcFeedrateRanges { get; set; } =
|
||||
new()
|
||||
{
|
||||
new()
|
||||
{
|
||||
MaxRadius = 0.125,
|
||||
FeedratePercent = 0.25,
|
||||
VariableNumber = 123,
|
||||
},
|
||||
new()
|
||||
{
|
||||
MaxRadius = 0.750,
|
||||
FeedratePercent = 0.50,
|
||||
VariableNumber = 124,
|
||||
},
|
||||
new()
|
||||
{
|
||||
MaxRadius = 4.500,
|
||||
FeedratePercent = 0.80,
|
||||
VariableNumber = 125,
|
||||
},
|
||||
};
|
||||
|
||||
[Category("A. Variables")]
|
||||
[DisplayName("User Variable Start")]
|
||||
@@ -272,7 +292,9 @@ namespace OpenNest.Posts.Cincinnati
|
||||
|
||||
[Category("B. Libraries")]
|
||||
[DisplayName("Material Libraries")]
|
||||
[Description("Material-to-library mapping for cut operations. Maps (material, thickness, gas) to a G89 library file.")]
|
||||
[Description(
|
||||
"Material-to-library mapping for cut operations. Maps (material, thickness, gas) to a G89 library file."
|
||||
)]
|
||||
public List<MaterialLibraryEntry> MaterialLibraries { get; set; } = new();
|
||||
|
||||
[Category("B. Libraries")]
|
||||
@@ -282,7 +304,9 @@ namespace OpenNest.Posts.Cincinnati
|
||||
|
||||
[Category("B. Libraries")]
|
||||
[DisplayName("Selected Library")]
|
||||
[Description("Overrides Material/Thickness/Gas auto-resolution. Pick an existing entry from Material Libraries, or leave blank to auto-resolve.")]
|
||||
[Description(
|
||||
"Overrides Material/Thickness/Gas auto-resolution. Pick an existing entry from Material Libraries, or leave blank to auto-resolve."
|
||||
)]
|
||||
[TypeConverter(typeof(MaterialLibraryNameConverter))]
|
||||
public string SelectedLibrary { get; set; } = "";
|
||||
|
||||
@@ -292,10 +316,13 @@ namespace OpenNest.Posts.Cincinnati
|
||||
return "";
|
||||
|
||||
return MaterialLibraries
|
||||
.Where(e => string.Equals(e.Material, materialName, StringComparison.OrdinalIgnoreCase))
|
||||
.OrderBy(e => System.Math.Abs(e.Thickness - thickness))
|
||||
.Select(e => e.Library)
|
||||
.FirstOrDefault() ?? "";
|
||||
.Where(e =>
|
||||
string.Equals(e.Material, materialName, StringComparison.OrdinalIgnoreCase)
|
||||
)
|
||||
.OrderBy(e => System.Math.Abs(e.Thickness - thickness))
|
||||
.Select(e => e.Library)
|
||||
.FirstOrDefault()
|
||||
?? "";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -325,7 +352,7 @@ namespace OpenNest.Posts.Cincinnati
|
||||
Percentages,
|
||||
|
||||
/// <summary>Radius-range-based variables: F #varNum based on radius range.</summary>
|
||||
Variables
|
||||
Variables,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -9,12 +9,15 @@ using OpenNest.CNC;
|
||||
|
||||
namespace OpenNest.Posts.Cincinnati
|
||||
{
|
||||
public sealed class CincinnatiPostProcessor : IConfigurablePostProcessor, IPostProcessorNestAware, IMaterialProvidingPostProcessor
|
||||
public sealed class CincinnatiPostProcessor
|
||||
: IConfigurablePostProcessor,
|
||||
IPostProcessorNestAware,
|
||||
IMaterialProvidingPostProcessor
|
||||
{
|
||||
private static readonly JsonSerializerOptions JsonOptions = new()
|
||||
{
|
||||
WriteIndented = true,
|
||||
Converters = { new JsonStringEnumConverter() }
|
||||
Converters = { new JsonStringEnumConverter() },
|
||||
};
|
||||
|
||||
public string Name => "Cincinnati CL-707";
|
||||
@@ -30,8 +33,8 @@ namespace OpenNest.Posts.Cincinnati
|
||||
if (Config?.MaterialLibraries == null)
|
||||
return System.Array.Empty<string>();
|
||||
|
||||
return Config.MaterialLibraries
|
||||
.Select(e => e.Material)
|
||||
return Config
|
||||
.MaterialLibraries.Select(e => e.Material)
|
||||
.Where(s => !string.IsNullOrWhiteSpace(s));
|
||||
}
|
||||
|
||||
@@ -83,9 +86,7 @@ namespace OpenNest.Posts.Cincinnati
|
||||
var vars = CreateVariableManager();
|
||||
|
||||
// 2. Filter to non-empty plates
|
||||
var plates = nest.Plates
|
||||
.Where(p => p.Parts.Count > 0)
|
||||
.ToList();
|
||||
var plates = nest.Plates.Where(p => p.Parts.Count > 0).ToList();
|
||||
|
||||
// 3. Register user variables from drawing programs
|
||||
var userVarMapping = RegisterUserVariables(vars, plates);
|
||||
@@ -97,36 +98,55 @@ namespace OpenNest.Posts.Cincinnati
|
||||
|
||||
// Resolve cut library from nest material/thickness for preamble
|
||||
var firstPlate = plates.FirstOrDefault();
|
||||
var initialCutLibrary = resolver.ResolveCutLibrary(nest.Material?.Name ?? "", nest.Thickness, gas);
|
||||
var initialCutLibrary = resolver.ResolveCutLibrary(
|
||||
nest.Material?.Name ?? "",
|
||||
nest.Thickness,
|
||||
gas
|
||||
);
|
||||
|
||||
// 5. Build part sub-program registry (if enabled)
|
||||
Dictionary<(int, long), int> partSubprograms = null;
|
||||
List<(int subNum, string name, Program program)> subprogramEntries = null;
|
||||
|
||||
if (Config.UsePartSubprograms)
|
||||
(partSubprograms, subprogramEntries) = CincinnatiPartSubprogramWriter.BuildRegistry(plates, Config.PartSubprogramStart);
|
||||
(partSubprograms, subprogramEntries) = CincinnatiPartSubprogramWriter.BuildRegistry(
|
||||
plates,
|
||||
Config.PartSubprogramStart
|
||||
);
|
||||
|
||||
// 5b. Build hole sub-program registry (SubProgramCalls across all parts)
|
||||
var holeStartNumber = Config.PartSubprogramStart
|
||||
+ (subprogramEntries?.Count ?? 0);
|
||||
var (holeMapping, holeEntries) = CincinnatiPartSubprogramWriter.BuildHoleRegistry(plates, holeStartNumber);
|
||||
var holeStartNumber = Config.PartSubprogramStart + (subprogramEntries?.Count ?? 0);
|
||||
var (holeMapping, holeEntries) = CincinnatiPartSubprogramWriter.BuildHoleRegistry(
|
||||
plates,
|
||||
holeStartNumber
|
||||
);
|
||||
|
||||
// 6. Create writers
|
||||
var preamble = new CincinnatiPreambleWriter(Config);
|
||||
var sheetWriter = new CincinnatiSheetWriter(Config, vars,
|
||||
holeMapping.Count > 0 ? holeMapping : null);
|
||||
var sheetWriter = new CincinnatiSheetWriter(
|
||||
Config,
|
||||
vars,
|
||||
holeMapping.Count > 0 ? holeMapping : null
|
||||
);
|
||||
|
||||
// 7. Build material description from nest
|
||||
var material = nest.Material;
|
||||
var materialDesc = material != null
|
||||
? $"{material.Name}{(string.IsNullOrEmpty(material.Grade) ? "" : $", {material.Grade}")}"
|
||||
: "";
|
||||
var materialDesc =
|
||||
material != null
|
||||
? $"{material.Name}{(string.IsNullOrEmpty(material.Grade) ? "" : $", {material.Grade}")}"
|
||||
: "";
|
||||
|
||||
// 8. Write to stream
|
||||
using var writer = new StreamWriter(outputStream, Encoding.UTF8, 1024, leaveOpen: true);
|
||||
|
||||
// Main program
|
||||
preamble.WriteMainProgram(writer, nest.Name ?? "NEST", materialDesc, plates, initialCutLibrary);
|
||||
preamble.WriteMainProgram(
|
||||
writer,
|
||||
nest.Name ?? "NEST",
|
||||
materialDesc,
|
||||
plates,
|
||||
initialCutLibrary
|
||||
);
|
||||
|
||||
// Variable declaration subprogram
|
||||
preamble.WriteVariableDeclaration(writer, vars);
|
||||
@@ -137,25 +157,50 @@ namespace OpenNest.Posts.Cincinnati
|
||||
var plate = plates[i];
|
||||
var layoutIndex = i + 1;
|
||||
var subNumber = Config.SheetSubprogramStart + i;
|
||||
var cutLibrary = resolver.ResolveCutLibrary(nest.Material?.Name ?? "", nest.Thickness, gas);
|
||||
sheetWriter.Write(writer, plate, nest.Name ?? "NEST", layoutIndex, subNumber,
|
||||
cutLibrary, etchLibrary, partSubprograms, userVarMapping);
|
||||
var cutLibrary = resolver.ResolveCutLibrary(
|
||||
nest.Material?.Name ?? "",
|
||||
nest.Thickness,
|
||||
gas
|
||||
);
|
||||
sheetWriter.Write(
|
||||
writer,
|
||||
plate,
|
||||
nest.Name ?? "NEST",
|
||||
layoutIndex,
|
||||
subNumber,
|
||||
cutLibrary,
|
||||
etchLibrary,
|
||||
partSubprograms,
|
||||
userVarMapping
|
||||
);
|
||||
}
|
||||
|
||||
// Part sub-programs (if enabled)
|
||||
if (subprogramEntries != null)
|
||||
{
|
||||
var partSubWriter = new CincinnatiPartSubprogramWriter(Config,
|
||||
holeMapping.Count > 0 ? holeMapping : null);
|
||||
var sheetDiagonal = firstPlate != null
|
||||
? System.Math.Sqrt(firstPlate.Size.Width * firstPlate.Size.Width
|
||||
+ firstPlate.Size.Length * firstPlate.Size.Length)
|
||||
: 100.0;
|
||||
var partSubWriter = new CincinnatiPartSubprogramWriter(
|
||||
Config,
|
||||
holeMapping.Count > 0 ? holeMapping : null
|
||||
);
|
||||
var sheetDiagonal =
|
||||
firstPlate != null
|
||||
? System.Math.Sqrt(
|
||||
firstPlate.Size.Width * firstPlate.Size.Width
|
||||
+ firstPlate.Size.Length * firstPlate.Size.Length
|
||||
)
|
||||
: 100.0;
|
||||
|
||||
foreach (var (subNum, name, pgm) in subprogramEntries)
|
||||
{
|
||||
partSubWriter.Write(writer, pgm, name, subNum,
|
||||
initialCutLibrary, etchLibrary, sheetDiagonal);
|
||||
partSubWriter.Write(
|
||||
writer,
|
||||
pgm,
|
||||
name,
|
||||
subNum,
|
||||
initialCutLibrary,
|
||||
etchLibrary,
|
||||
sheetDiagonal
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -163,16 +208,26 @@ namespace OpenNest.Posts.Cincinnati
|
||||
if (holeEntries.Count > 0)
|
||||
{
|
||||
var holeSubWriter = new CincinnatiPartSubprogramWriter(Config);
|
||||
var sheetDiagonal = firstPlate != null
|
||||
? System.Math.Sqrt(firstPlate.Size.Width * firstPlate.Size.Width
|
||||
+ firstPlate.Size.Length * firstPlate.Size.Length)
|
||||
: 100.0;
|
||||
var sheetDiagonal =
|
||||
firstPlate != null
|
||||
? System.Math.Sqrt(
|
||||
firstPlate.Size.Width * firstPlate.Size.Width
|
||||
+ firstPlate.Size.Length * firstPlate.Size.Length
|
||||
)
|
||||
: 100.0;
|
||||
|
||||
foreach (var (subNum, pgm) in holeEntries)
|
||||
{
|
||||
CincinnatiPartSubprogramWriter.EnsureLeadingRapid(pgm);
|
||||
holeSubWriter.Write(writer, pgm, "HOLE", subNum,
|
||||
initialCutLibrary, etchLibrary, sheetDiagonal);
|
||||
holeSubWriter.Write(
|
||||
writer,
|
||||
pgm,
|
||||
"HOLE",
|
||||
subNum,
|
||||
initialCutLibrary,
|
||||
etchLibrary,
|
||||
sheetDiagonal
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -186,13 +241,17 @@ namespace OpenNest.Posts.Cincinnati
|
||||
}
|
||||
|
||||
private Dictionary<(int drawingId, string varName), int> RegisterUserVariables(
|
||||
ProgramVariableManager vars, List<Plate> plates)
|
||||
ProgramVariableManager vars,
|
||||
List<Plate> plates
|
||||
)
|
||||
{
|
||||
var mapping = new Dictionary<(int drawingId, string varName), int>();
|
||||
var nextNumber = Config.UserVariableStart;
|
||||
|
||||
// Track global variables by name so they share a single number
|
||||
var globalNumbers = new Dictionary<string, int>(System.StringComparer.OrdinalIgnoreCase);
|
||||
var globalNumbers = new Dictionary<string, int>(
|
||||
System.StringComparer.OrdinalIgnoreCase
|
||||
);
|
||||
|
||||
// Collect unique drawings from all plates
|
||||
var seenDrawings = new HashSet<int>();
|
||||
@@ -285,19 +344,31 @@ namespace OpenNest.Posts.Cincinnati
|
||||
private ProgramVariableManager CreateVariableManager()
|
||||
{
|
||||
var vars = new ProgramVariableManager();
|
||||
vars.GetOrCreate("ProcessFeedrate", 148); // Set by G89, no expression
|
||||
vars.GetOrCreate("ProcessFeedrate", 148); // Set by G89, no expression
|
||||
vars.GetOrCreate("LeadInFeedrate", 126, $"[#148*{Config.LeadInFeedratePercent}]");
|
||||
vars.GetOrCreate("LeadInArcLine2Feedrate", 127, $"[#148*{Config.LeadInArcLine2FeedratePercent}]");
|
||||
vars.GetOrCreate("CircleFeedrate", 128, Config.CircleFeedrateMultiplier.ToString("0.#"));
|
||||
vars.GetOrCreate(
|
||||
"LeadInArcLine2Feedrate",
|
||||
127,
|
||||
$"[#148*{Config.LeadInArcLine2FeedratePercent}]"
|
||||
);
|
||||
vars.GetOrCreate(
|
||||
"CircleFeedrate",
|
||||
128,
|
||||
Config.CircleFeedrateMultiplier.ToString("0.#")
|
||||
);
|
||||
vars.GetOrCreate("LeadOutFeedrate", 129, $"[#148*{Config.LeadOutFeedratePercent}]");
|
||||
|
||||
if (Config.ArcFeedrate == ArcFeedrateMode.Variables)
|
||||
{
|
||||
foreach (var range in Config.ArcFeedrateRanges)
|
||||
{
|
||||
var name = $"ArcFeedR{range.MaxRadius.ToString("0.###", System.Globalization.CultureInfo.InvariantCulture)}";
|
||||
vars.GetOrCreate(name, range.VariableNumber,
|
||||
$"[#148*{range.FeedratePercent.ToString("0.##", System.Globalization.CultureInfo.InvariantCulture)}]");
|
||||
var name =
|
||||
$"ArcFeedR{range.MaxRadius.ToString("0.###", System.Globalization.CultureInfo.InvariantCulture)}";
|
||||
vars.GetOrCreate(
|
||||
name,
|
||||
range.VariableNumber,
|
||||
$"[#148*{range.FeedratePercent.ToString("0.##", System.Globalization.CultureInfo.InvariantCulture)}]"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,12 +23,24 @@ public sealed class CincinnatiPreambleWriter
|
||||
/// Writes the main program header block.
|
||||
/// </summary>
|
||||
/// <param name="initialLibrary">Resolved G89 library file for the initial process setup.</param>
|
||||
public void WriteMainProgram(TextWriter w, string nestName, string materialDescription,
|
||||
List<Plate> plates, string initialLibrary)
|
||||
public void WriteMainProgram(
|
||||
TextWriter w,
|
||||
string nestName,
|
||||
string materialDescription,
|
||||
List<Plate> plates,
|
||||
string initialLibrary
|
||||
)
|
||||
{
|
||||
w.WriteLine(CoordinateFormatter.Comment($"NEST {nestName}"));
|
||||
w.WriteLine(CoordinateFormatter.Comment($"CONFIGURATION - {_config.ConfigurationName}"));
|
||||
w.WriteLine(CoordinateFormatter.Comment(DateTime.Now.ToString("MM-dd-yyyy hh:mm:ss tt", System.Globalization.CultureInfo.InvariantCulture)));
|
||||
w.WriteLine(
|
||||
CoordinateFormatter.Comment(
|
||||
DateTime.Now.ToString(
|
||||
"MM-dd-yyyy hh:mm:ss tt",
|
||||
System.Globalization.CultureInfo.InvariantCulture
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
if (!string.IsNullOrEmpty(materialDescription))
|
||||
w.WriteLine(CoordinateFormatter.Comment($"Material = {materialDescription}"));
|
||||
@@ -45,7 +57,10 @@ public sealed class CincinnatiPreambleWriter
|
||||
|
||||
w.WriteLine("M42");
|
||||
|
||||
if (_config.ProcessParameterMode == G89Mode.LibraryFile && !string.IsNullOrEmpty(initialLibrary))
|
||||
if (
|
||||
_config.ProcessParameterMode == G89Mode.LibraryFile
|
||||
&& !string.IsNullOrEmpty(initialLibrary)
|
||||
)
|
||||
w.WriteLine($"G89 P{initialLibrary}");
|
||||
|
||||
w.WriteLine($"M98 P{_config.VariableDeclarationSubprogram} (Variable Declaration)");
|
||||
@@ -61,9 +76,8 @@ public sealed class CincinnatiPreambleWriter
|
||||
var subNum = _config.SheetSubprogramStart + i;
|
||||
var qty = System.Math.Max(plates[i].Quantity, 1);
|
||||
var lParam = qty > 1 ? $" L{qty}" : "";
|
||||
var sheetLabel = qty > 1
|
||||
? $"LAYOUT {layoutNumber} - {qty} SHEETS"
|
||||
: $"LAYOUT {layoutNumber}";
|
||||
var sheetLabel =
|
||||
qty > 1 ? $"LAYOUT {layoutNumber} - {qty} SHEETS" : $"LAYOUT {layoutNumber}";
|
||||
w.WriteLine($"N{layoutNumber} M98 P{subNum}{lParam} ({sheetLabel})");
|
||||
}
|
||||
|
||||
|
||||
@@ -19,8 +19,11 @@ public sealed class CincinnatiSheetWriter
|
||||
private readonly CincinnatiFeatureWriter _featureWriter;
|
||||
private readonly Dictionary<int, int> _holeSubprograms;
|
||||
|
||||
public CincinnatiSheetWriter(CincinnatiPostConfig config, ProgramVariableManager vars,
|
||||
Dictionary<int, int> holeSubprograms = null)
|
||||
public CincinnatiSheetWriter(
|
||||
CincinnatiPostConfig config,
|
||||
ProgramVariableManager vars,
|
||||
Dictionary<int, int> holeSubprograms = null
|
||||
)
|
||||
{
|
||||
_config = config;
|
||||
_vars = vars;
|
||||
@@ -38,10 +41,17 @@ public sealed class CincinnatiSheetWriter
|
||||
/// Optional mapping of (drawingId, rotationKey) to sub-program number.
|
||||
/// When provided, non-cutoff parts are emitted as M98 calls instead of inline features.
|
||||
/// </param>
|
||||
public void Write(TextWriter w, Plate plate, string nestName, int layoutIndex, int subNumber,
|
||||
string cutLibrary, string etchLibrary,
|
||||
public void Write(
|
||||
TextWriter w,
|
||||
Plate plate,
|
||||
string nestName,
|
||||
int layoutIndex,
|
||||
int subNumber,
|
||||
string cutLibrary,
|
||||
string etchLibrary,
|
||||
Dictionary<(int, long), int> partSubprograms = null,
|
||||
Dictionary<(int drawingId, string varName), int> userVarMapping = null)
|
||||
Dictionary<(int drawingId, string varName), int> userVarMapping = null
|
||||
)
|
||||
{
|
||||
if (plate.Parts.Count == 0)
|
||||
return;
|
||||
@@ -59,8 +69,12 @@ public sealed class CincinnatiSheetWriter
|
||||
w.WriteLine($"( Layout {layoutIndex} )");
|
||||
w.WriteLine($"( SHEET NAME = {_fmt.FormatCoord(width)} X {_fmt.FormatCoord(length)} )");
|
||||
w.WriteLine($"( Total parts on sheet = {partCount} )");
|
||||
w.WriteLine($"#{_config.SheetWidthVariable}={_fmt.FormatCoord(width)} (SHEET WIDTH FOR CUTOFFS)");
|
||||
w.WriteLine($"#{_config.SheetLengthVariable}={_fmt.FormatCoord(length)} (SHEET LENGTH FOR CUTOFFS)");
|
||||
w.WriteLine(
|
||||
$"#{_config.SheetWidthVariable}={_fmt.FormatCoord(width)} (SHEET WIDTH FOR CUTOFFS)"
|
||||
);
|
||||
w.WriteLine(
|
||||
$"#{_config.SheetLengthVariable}={_fmt.FormatCoord(length)} (SHEET LENGTH FOR CUTOFFS)"
|
||||
);
|
||||
|
||||
// 2. Coordinate setup
|
||||
w.WriteLine("M42");
|
||||
@@ -76,23 +90,40 @@ public sealed class CincinnatiSheetWriter
|
||||
w.WriteLine("GOTO1( Goto Feature )");
|
||||
|
||||
// 3. Order parts: non-cutoff sorted by Bottom then Left, cutoffs last
|
||||
var nonCutoffParts = plate.Parts
|
||||
.Where(p => !p.BaseDrawing.IsCutOff)
|
||||
var nonCutoffParts = plate
|
||||
.Parts.Where(p => !p.BaseDrawing.IsCutOff)
|
||||
.OrderBy(p => p.Bottom)
|
||||
.ThenBy(p => p.Left)
|
||||
.ToList();
|
||||
|
||||
var cutoffParts = plate.Parts
|
||||
.Where(p => p.BaseDrawing.IsCutOff)
|
||||
.ToList();
|
||||
var cutoffParts = plate.Parts.Where(p => p.BaseDrawing.IsCutOff).ToList();
|
||||
|
||||
var allParts = nonCutoffParts.Concat(cutoffParts).ToList();
|
||||
|
||||
// 4. Emit parts
|
||||
if (partSubprograms != null)
|
||||
WritePartsWithSubprograms(w, allParts, cutLibrary, etchLibrary, sheetDiagonal, width, length, partSubprograms, userVarMapping);
|
||||
WritePartsWithSubprograms(
|
||||
w,
|
||||
allParts,
|
||||
cutLibrary,
|
||||
etchLibrary,
|
||||
sheetDiagonal,
|
||||
width,
|
||||
length,
|
||||
partSubprograms,
|
||||
userVarMapping
|
||||
);
|
||||
else
|
||||
WritePartsInline(w, allParts, cutLibrary, etchLibrary, sheetDiagonal, width, length, userVarMapping);
|
||||
WritePartsInline(
|
||||
w,
|
||||
allParts,
|
||||
cutLibrary,
|
||||
etchLibrary,
|
||||
sheetDiagonal,
|
||||
width,
|
||||
length,
|
||||
userVarMapping
|
||||
);
|
||||
|
||||
// 5. Footer
|
||||
w.WriteLine("M42");
|
||||
@@ -101,11 +132,17 @@ public sealed class CincinnatiSheetWriter
|
||||
w.WriteLine($"M99 (END OF {nestName}.{layoutIndex:D3})");
|
||||
}
|
||||
|
||||
private void WritePartsWithSubprograms(TextWriter w, List<Part> allParts,
|
||||
string cutLibrary, string etchLibrary, double sheetDiagonal,
|
||||
double plateWidth, double plateLength,
|
||||
private void WritePartsWithSubprograms(
|
||||
TextWriter w,
|
||||
List<Part> allParts,
|
||||
string cutLibrary,
|
||||
string etchLibrary,
|
||||
double sheetDiagonal,
|
||||
double plateWidth,
|
||||
double plateLength,
|
||||
Dictionary<(int, long), int> partSubprograms,
|
||||
Dictionary<(int drawingId, string varName), int> userVarMapping)
|
||||
Dictionary<(int drawingId, string varName), int> userVarMapping
|
||||
)
|
||||
{
|
||||
var lastPartName = "";
|
||||
var featureIndex = 0;
|
||||
@@ -124,8 +161,15 @@ public sealed class CincinnatiSheetWriter
|
||||
|
||||
if (hasSubprogram)
|
||||
{
|
||||
WriteSubprogramCall(w, part, subNum, featureIndex, partName,
|
||||
isSafetyHeadraise, isLastPart);
|
||||
WriteSubprogramCall(
|
||||
w,
|
||||
part,
|
||||
subNum,
|
||||
featureIndex,
|
||||
partName,
|
||||
isSafetyHeadraise,
|
||||
isLastPart
|
||||
);
|
||||
featureIndex++;
|
||||
}
|
||||
else
|
||||
@@ -146,9 +190,10 @@ public sealed class CincinnatiSheetWriter
|
||||
continue;
|
||||
}
|
||||
|
||||
var featureNumber = featureIndex == 0
|
||||
? _config.FeatureLineNumberStart
|
||||
: 1000 + featureIndex + 1;
|
||||
var featureNumber =
|
||||
featureIndex == 0
|
||||
? _config.FeatureLineNumberStart
|
||||
: 1000 + featureIndex + 1;
|
||||
|
||||
var cutDistance = FeatureUtils.ComputeCutDistance(codes);
|
||||
|
||||
@@ -170,7 +215,7 @@ public sealed class CincinnatiSheetWriter
|
||||
DrawingId = part.BaseDrawing.Id,
|
||||
IsCutOff = part.BaseDrawing.IsCutOff,
|
||||
PlateWidth = plateWidth,
|
||||
PlateLength = plateLength
|
||||
PlateLength = plateLength,
|
||||
};
|
||||
|
||||
_featureWriter.Write(w, ctx);
|
||||
@@ -182,17 +227,23 @@ public sealed class CincinnatiSheetWriter
|
||||
}
|
||||
}
|
||||
|
||||
private void WriteSubprogramCall(TextWriter w, Part part, int subNum,
|
||||
int featureIndex, string partName, bool isSafetyHeadraise, bool isLastPart)
|
||||
private void WriteSubprogramCall(
|
||||
TextWriter w,
|
||||
Part part,
|
||||
int subNum,
|
||||
int featureIndex,
|
||||
string partName,
|
||||
bool isSafetyHeadraise,
|
||||
bool isLastPart
|
||||
)
|
||||
{
|
||||
// Safety headraise before rapid to new part
|
||||
if (isSafetyHeadraise && _config.SafetyHeadraiseDistance.HasValue)
|
||||
w.WriteLine($"M47 P{_config.SafetyHeadraiseDistance.Value} (Safety Headraise)");
|
||||
|
||||
// Rapid to part position (bounding box lower-left)
|
||||
var featureNumber = featureIndex == 0
|
||||
? _config.FeatureLineNumberStart
|
||||
: 1000 + featureIndex + 1;
|
||||
var featureNumber =
|
||||
featureIndex == 0 ? _config.FeatureLineNumberStart : 1000 + featureIndex + 1;
|
||||
|
||||
var sb = new StringBuilder();
|
||||
if (_config.UseLineNumbers)
|
||||
@@ -217,14 +268,20 @@ public sealed class CincinnatiSheetWriter
|
||||
w.WriteLine("M47");
|
||||
}
|
||||
|
||||
private void WriteHoleSubprogramCall(TextWriter w, SubProgramCall call, int featureIndex, bool isLastFeature)
|
||||
private void WriteHoleSubprogramCall(
|
||||
TextWriter w,
|
||||
SubProgramCall call,
|
||||
int featureIndex,
|
||||
bool isLastFeature
|
||||
)
|
||||
{
|
||||
var postSubNum = _holeSubprograms != null && _holeSubprograms.TryGetValue(call.Id, out var num)
|
||||
? num : call.Id;
|
||||
var postSubNum =
|
||||
_holeSubprograms != null && _holeSubprograms.TryGetValue(call.Id, out var num)
|
||||
? num
|
||||
: call.Id;
|
||||
|
||||
var featureNumber = featureIndex == 0
|
||||
? _config.FeatureLineNumberStart
|
||||
: 1000 + featureIndex + 1;
|
||||
var featureNumber =
|
||||
featureIndex == 0 ? _config.FeatureLineNumberStart : 1000 + featureIndex + 1;
|
||||
|
||||
// Shift the local origin to the hole center via G52 (manual §1.52).
|
||||
// G52 does not move the nozzle, so the sub-program's first rapid
|
||||
@@ -247,10 +304,16 @@ public sealed class CincinnatiSheetWriter
|
||||
w.WriteLine("M47");
|
||||
}
|
||||
|
||||
private void WritePartsInline(TextWriter w, List<Part> allParts,
|
||||
string cutLibrary, string etchLibrary, double sheetDiagonal,
|
||||
double plateWidth, double plateLength,
|
||||
Dictionary<(int drawingId, string varName), int> userVarMapping)
|
||||
private void WritePartsInline(
|
||||
TextWriter w,
|
||||
List<Part> allParts,
|
||||
string cutLibrary,
|
||||
string etchLibrary,
|
||||
double sheetDiagonal,
|
||||
double plateWidth,
|
||||
double plateLength,
|
||||
Dictionary<(int drawingId, string varName), int> userVarMapping
|
||||
)
|
||||
{
|
||||
// Split and classify features, ordering etch before cut per part
|
||||
var features = new List<(Part part, List<ICode> codes, bool isEtch)>();
|
||||
@@ -279,9 +342,7 @@ public sealed class CincinnatiSheetWriter
|
||||
continue;
|
||||
}
|
||||
|
||||
var featureNumber = i == 0
|
||||
? _config.FeatureLineNumberStart
|
||||
: 1000 + i + 1;
|
||||
var featureNumber = i == 0 ? _config.FeatureLineNumberStart : 1000 + i + 1;
|
||||
|
||||
var cutDistance = FeatureUtils.ComputeCutDistance(codes);
|
||||
|
||||
@@ -303,12 +364,11 @@ public sealed class CincinnatiSheetWriter
|
||||
DrawingId = part.BaseDrawing.Id,
|
||||
IsCutOff = part.BaseDrawing.IsCutOff,
|
||||
PlateWidth = plateWidth,
|
||||
PlateLength = plateLength
|
||||
PlateLength = plateLength,
|
||||
};
|
||||
|
||||
_featureWriter.Write(w, ctx);
|
||||
lastPartName = partName;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -13,7 +13,8 @@ namespace OpenNest.Posts.Cincinnati
|
||||
|
||||
public string FormatCoord(double value)
|
||||
{
|
||||
return System.Math.Round(value, _accuracy)
|
||||
return System
|
||||
.Math.Round(value, _accuracy)
|
||||
.ToString(_format, System.Globalization.CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
|
||||
@@ -52,7 +52,9 @@ public static class FeatureUtils
|
||||
/// <summary>
|
||||
/// Classifies features as etch or cut and orders etch features before cut features.
|
||||
/// </summary>
|
||||
public static List<(List<ICode> codes, bool isEtch)> ClassifyAndOrder(List<List<ICode>> features)
|
||||
public static List<(List<ICode> codes, bool isEtch)> ClassifyAndOrder(
|
||||
List<List<ICode>> features
|
||||
)
|
||||
{
|
||||
var result = new List<(List<ICode>, bool)>();
|
||||
var etch = new List<List<ICode>>();
|
||||
@@ -157,27 +159,33 @@ public static class FeatureUtils
|
||||
return 0.0;
|
||||
|
||||
// Full circle: start ≈ end
|
||||
if (Tolerance.IsEqualTo(startPos.X, arc.EndPoint.X)
|
||||
&& Tolerance.IsEqualTo(startPos.Y, arc.EndPoint.Y))
|
||||
if (
|
||||
Tolerance.IsEqualTo(startPos.X, arc.EndPoint.X)
|
||||
&& Tolerance.IsEqualTo(startPos.Y, arc.EndPoint.Y)
|
||||
)
|
||||
return 2.0 * System.Math.PI * radius;
|
||||
|
||||
var startAngle = System.Math.Atan2(
|
||||
startPos.Y - arc.CenterPoint.Y,
|
||||
startPos.X - arc.CenterPoint.X);
|
||||
startPos.X - arc.CenterPoint.X
|
||||
);
|
||||
var endAngle = System.Math.Atan2(
|
||||
arc.EndPoint.Y - arc.CenterPoint.Y,
|
||||
arc.EndPoint.X - arc.CenterPoint.X);
|
||||
arc.EndPoint.X - arc.CenterPoint.X
|
||||
);
|
||||
|
||||
double sweep;
|
||||
if (arc.Rotation == RotationType.CW)
|
||||
{
|
||||
sweep = startAngle - endAngle;
|
||||
if (sweep <= 0) sweep += 2.0 * System.Math.PI;
|
||||
if (sweep <= 0)
|
||||
sweep += 2.0 * System.Math.PI;
|
||||
}
|
||||
else
|
||||
{
|
||||
sweep = endAngle - startAngle;
|
||||
if (sweep <= 0) sweep += 2.0 * System.Math.PI;
|
||||
if (sweep <= 0)
|
||||
sweep += 2.0 * System.Math.PI;
|
||||
}
|
||||
|
||||
return radius * sweep;
|
||||
|
||||
@@ -18,11 +18,13 @@ namespace OpenNest.Posts.Cincinnati
|
||||
|
||||
if (config?.MaterialLibraries != null)
|
||||
{
|
||||
names.AddRange(config.MaterialLibraries
|
||||
.Select(e => e.Library)
|
||||
.Where(s => !string.IsNullOrWhiteSpace(s))
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.OrderBy(s => s, StringComparer.OrdinalIgnoreCase));
|
||||
names.AddRange(
|
||||
config
|
||||
.MaterialLibraries.Select(e => e.Library)
|
||||
.Where(s => !string.IsNullOrWhiteSpace(s))
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.OrderBy(s => s, StringComparer.OrdinalIgnoreCase)
|
||||
);
|
||||
}
|
||||
|
||||
return new StandardValuesCollection(names);
|
||||
|
||||
@@ -25,9 +25,10 @@ public sealed class MaterialLibraryResolver
|
||||
return EnsureLibExtension(_selectedLibrary);
|
||||
|
||||
var entry = _materialLibraries.FirstOrDefault(e =>
|
||||
string.Equals(e.Material, materialName, StringComparison.OrdinalIgnoreCase) &&
|
||||
System.Math.Abs(e.Thickness - thickness) <= ThicknessTolerance &&
|
||||
string.Equals(e.Gas, gas, StringComparison.OrdinalIgnoreCase));
|
||||
string.Equals(e.Material, materialName, StringComparison.OrdinalIgnoreCase)
|
||||
&& System.Math.Abs(e.Thickness - thickness) <= ThicknessTolerance
|
||||
&& string.Equals(e.Gas, gas, StringComparison.OrdinalIgnoreCase)
|
||||
);
|
||||
|
||||
return EnsureLibExtension(entry?.Library ?? "");
|
||||
}
|
||||
@@ -35,7 +36,8 @@ public sealed class MaterialLibraryResolver
|
||||
public string ResolveEtchLibrary(string gas)
|
||||
{
|
||||
var entry = _etchLibraries.FirstOrDefault(e =>
|
||||
string.Equals(e.Gas, gas, StringComparison.OrdinalIgnoreCase));
|
||||
string.Equals(e.Gas, gas, StringComparison.OrdinalIgnoreCase)
|
||||
);
|
||||
|
||||
return EnsureLibExtension(entry?.Library ?? "");
|
||||
}
|
||||
|
||||
@@ -8,8 +8,10 @@ namespace OpenNest.Posts.Cincinnati
|
||||
public string Classify(double contourLength, double sheetDiagonal)
|
||||
{
|
||||
var ratio = contourLength / sheetDiagonal;
|
||||
if (ratio >= FastThreshold) return "FAST";
|
||||
if (ratio <= SlowThreshold) return "SLOW";
|
||||
if (ratio >= FastThreshold)
|
||||
return "FAST";
|
||||
if (ratio <= SlowThreshold)
|
||||
return "SLOW";
|
||||
return "MEDIUM";
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user