using System.Collections.Generic; using OpenNest.Geometry; namespace OpenNest; /// /// 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. /// 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(); 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(); 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(); 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); } }