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.
122 lines
4.2 KiB
C#
122 lines
4.2 KiB
C#
using System.Collections.Generic;
|
|
using OpenNest.Geometry;
|
|
|
|
namespace OpenNest;
|
|
|
|
/// <summary>
|
|
/// Generates rectangular tabs on one side of the split edge (negative side).
|
|
/// The positive side remains a straight line. Tabs act as weld-gap spacers.
|
|
/// </summary>
|
|
public class WeldGapTabSplit : ISplitFeature
|
|
{
|
|
public string Name => "Weld-Gap Tabs";
|
|
|
|
public SplitFeatureResult GenerateFeatures(
|
|
SplitLine line,
|
|
double extentStart,
|
|
double extentEnd,
|
|
SplitParameters parameters
|
|
)
|
|
{
|
|
var extent = extentEnd - extentStart;
|
|
var tabCount = parameters.TabCount;
|
|
var tabWidth = parameters.TabWidth;
|
|
var tabHeight = parameters.TabHeight;
|
|
|
|
// Use custom positions if provided, otherwise evenly space
|
|
var tabCenters = new List<double>();
|
|
if (line.FeaturePositions.Count > 0)
|
|
{
|
|
tabCenters.AddRange(line.FeaturePositions);
|
|
}
|
|
else
|
|
{
|
|
var spacing = extent / (tabCount + 1);
|
|
for (var i = 0; i < tabCount; i++)
|
|
tabCenters.Add(extentStart + spacing * (i + 1));
|
|
}
|
|
|
|
var negEntities = new List<Entity>();
|
|
var isVertical = line.Axis == CutOffAxis.Vertical;
|
|
var pos = line.Position;
|
|
|
|
// Tabs protrude toward the negative side (lower coordinate on the split axis)
|
|
var tabDir = -1.0;
|
|
|
|
var cursor = extentStart;
|
|
|
|
for (var i = 0; i < tabCenters.Count; i++)
|
|
{
|
|
var tabCenter = tabCenters[i];
|
|
var tabStart = tabCenter - tabWidth / 2;
|
|
var tabEnd = tabCenter + tabWidth / 2;
|
|
|
|
if (isVertical)
|
|
{
|
|
if (tabStart > cursor + OpenNest.Math.Tolerance.Epsilon)
|
|
negEntities.Add(new Line(new Vector(pos, cursor), new Vector(pos, tabStart)));
|
|
|
|
negEntities.Add(
|
|
new Line(
|
|
new Vector(pos, tabStart),
|
|
new Vector(pos + tabDir * tabHeight, tabStart)
|
|
)
|
|
);
|
|
negEntities.Add(
|
|
new Line(
|
|
new Vector(pos + tabDir * tabHeight, tabStart),
|
|
new Vector(pos + tabDir * tabHeight, tabEnd)
|
|
)
|
|
);
|
|
negEntities.Add(
|
|
new Line(new Vector(pos + tabDir * tabHeight, tabEnd), new Vector(pos, tabEnd))
|
|
);
|
|
}
|
|
else
|
|
{
|
|
if (tabStart > cursor + OpenNest.Math.Tolerance.Epsilon)
|
|
negEntities.Add(new Line(new Vector(cursor, pos), new Vector(tabStart, pos)));
|
|
|
|
negEntities.Add(
|
|
new Line(
|
|
new Vector(tabStart, pos),
|
|
new Vector(tabStart, pos + tabDir * tabHeight)
|
|
)
|
|
);
|
|
negEntities.Add(
|
|
new Line(
|
|
new Vector(tabStart, pos + tabDir * tabHeight),
|
|
new Vector(tabEnd, pos + tabDir * tabHeight)
|
|
)
|
|
);
|
|
negEntities.Add(
|
|
new Line(new Vector(tabEnd, pos + tabDir * tabHeight), new Vector(tabEnd, pos))
|
|
);
|
|
}
|
|
|
|
cursor = tabEnd;
|
|
}
|
|
|
|
// Final segment from last tab to extent end
|
|
if (isVertical)
|
|
{
|
|
if (extentEnd > cursor + OpenNest.Math.Tolerance.Epsilon)
|
|
negEntities.Add(new Line(new Vector(pos, cursor), new Vector(pos, extentEnd)));
|
|
}
|
|
else
|
|
{
|
|
if (extentEnd > cursor + OpenNest.Math.Tolerance.Epsilon)
|
|
negEntities.Add(new Line(new Vector(cursor, pos), new Vector(extentEnd, pos)));
|
|
}
|
|
|
|
// Positive side: plain straight line (reversed direction)
|
|
var posEntities = new List<Entity>();
|
|
if (isVertical)
|
|
posEntities.Add(new Line(new Vector(pos, extentEnd), new Vector(pos, extentStart)));
|
|
else
|
|
posEntities.Add(new Line(new Vector(extentEnd, pos), new Vector(extentStart, pos)));
|
|
|
|
return new SplitFeatureResult(negEntities, posEntities);
|
|
}
|
|
}
|