Files
OpenNest/OpenNest.Core/Geometry/ShapeProfile.cs
T
aj aec0523062 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.
2026-09-20 16:41:50 -04:00

94 lines
2.6 KiB
C#

using System.Collections.Generic;
using System.Linq;
namespace OpenNest.Geometry
{
public class ShapeProfile
{
public ShapeProfile(Shape shape)
{
Update(shape.Entities);
}
public ShapeProfile(List<Entity> entities)
{
Update(entities);
}
private void Update(List<Entity> entities)
{
var shapes = ShapeBuilder.GetShapes(entities);
Perimeter = shapes[0];
Cutouts = new List<Shape>();
for (var i = 1; i < shapes.Count; i++)
{
var bb = shapes[i].BoundingBox;
var perimBB = Perimeter.BoundingBox;
if (bb.Width * bb.Length > perimBB.Width * perimBB.Length)
{
Cutouts.Add(Perimeter);
Perimeter = shapes[i];
}
else
{
Cutouts.Add(shapes[i]);
}
}
}
public Shape Perimeter { get; set; }
public List<Shape> Cutouts { get; set; }
/// <summary>
/// Ensures CNC-standard winding: perimeter CW (kerf left = outward),
/// cutouts CCW (kerf left = inward). Reverses contours in-place as needed.
/// </summary>
public void NormalizeWinding()
{
EnsureWinding(Perimeter, RotationType.CW);
foreach (var cutout in Cutouts)
EnsureWinding(cutout, RotationType.CCW);
}
/// <summary>
/// Returns the entities in normalized winding order (perimeter first, then cutouts).
/// </summary>
public List<Entity> ToNormalizedEntities()
{
NormalizeWinding();
var result = new List<Entity>(Perimeter.Entities);
foreach (var cutout in Cutouts)
result.AddRange(cutout.Entities);
return result;
}
/// <summary>
/// Convenience method: builds a ShapeProfile from raw entities,
/// normalizes winding, and returns the corrected entity list.
/// </summary>
public static List<Entity> NormalizeEntities(IEnumerable<Entity> entities)
{
var cloned = entities.CloneAll();
var profile = new ShapeProfile(cloned);
return profile.ToNormalizedEntities();
}
private static void EnsureWinding(Shape shape, RotationType desired)
{
var poly = shape.ToPolygon();
if (poly != null && poly.Vertices.Count >= 3 && poly.RotationDirection() != desired)
{
shape.Reverse();
}
}
}
}