refactor: extract ShapeBuilder from Helper

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-15 17:41:40 -04:00
parent be318bc1c1
commit 7c4eac5460
13 changed files with 168 additions and 159 deletions

View File

@@ -9,7 +9,7 @@ namespace OpenNest.Converters
{
public static Program ToProgram(IList<Entity> geometry)
{
var shapes = Helper.GetShapes(geometry);
var shapes = ShapeBuilder.GetShapes(geometry);
if (shapes.Count == 0)
return null;

View File

@@ -65,7 +65,7 @@ namespace OpenNest
public void UpdateArea()
{
var geometry = ConvertProgram.ToGeometry(Program).Where(entity => entity.Layer != SpecialLayers.Rapid);
var shapes = Helper.GetShapes(geometry);
var shapes = ShapeBuilder.GetShapes(geometry);
if (shapes.Count == 0)
return;

View File

@@ -0,0 +1,150 @@
using System.Collections.Generic;
using System.Diagnostics;
using OpenNest.Math;
namespace OpenNest.Geometry
{
public static class ShapeBuilder
{
public static List<Shape> GetShapes(IEnumerable<Entity> entities)
{
var lines = new List<Line>();
var arcs = new List<Arc>();
var circles = new List<Circle>();
var shapes = new List<Shape>();
var entities2 = new Queue<Entity>(entities);
while (entities2.Count > 0)
{
var entity = entities2.Dequeue();
switch (entity.Type)
{
case EntityType.Arc:
arcs.Add((Arc)entity);
break;
case EntityType.Circle:
circles.Add((Circle)entity);
break;
case EntityType.Line:
lines.Add((Line)entity);
break;
case EntityType.Shape:
var shape = (Shape)entity;
shape.Entities.ForEach(e => entities2.Enqueue(e));
break;
default:
Debug.Fail("Unhandled geometry type");
break;
}
}
foreach (var circle in circles)
{
var shape = new Shape();
shape.Entities.Add(circle);
shape.UpdateBounds();
shapes.Add(shape);
}
var entityList = new List<Entity>();
entityList.AddRange(lines);
entityList.AddRange(arcs);
while (entityList.Count > 0)
{
var next = entityList[0];
var shape = new Shape();
shape.Entities.Add(next);
entityList.RemoveAt(0);
Vector startPoint = new Vector();
Entity connected;
switch (next.Type)
{
case EntityType.Arc:
var arc = (Arc)next;
startPoint = arc.EndPoint();
break;
case EntityType.Line:
var line = (Line)next;
startPoint = line.EndPoint;
break;
}
while ((connected = GetConnected(startPoint, entityList)) != null)
{
shape.Entities.Add(connected);
entityList.Remove(connected);
switch (connected.Type)
{
case EntityType.Arc:
var arc = (Arc)connected;
startPoint = arc.EndPoint();
break;
case EntityType.Line:
var line = (Line)connected;
startPoint = line.EndPoint;
break;
}
}
shape.UpdateBounds();
shapes.Add(shape);
}
return shapes;
}
internal static Entity GetConnected(Vector pt, IEnumerable<Entity> geometry)
{
var tol = Tolerance.ChainTolerance;
foreach (var geo in geometry)
{
switch (geo.Type)
{
case EntityType.Arc:
var arc = (Arc)geo;
if (arc.StartPoint().DistanceTo(pt) <= tol)
return arc;
if (arc.EndPoint().DistanceTo(pt) <= tol)
{
arc.Reverse();
return arc;
}
break;
case EntityType.Line:
var line = (Line)geo;
if (line.StartPoint.DistanceTo(pt) <= tol)
return line;
if (line.EndPoint.DistanceTo(pt) <= tol)
{
line.Reverse();
return line;
}
break;
}
}
return null;
}
}
}

View File

@@ -16,7 +16,7 @@ namespace OpenNest.Geometry
private void Update(List<Entity> entities)
{
var shapes = Helper.GetShapes(entities);
var shapes = ShapeBuilder.GetShapes(entities);
Perimeter = shapes[0];
Cutouts = new List<Shape>();

View File

@@ -11,147 +11,6 @@ namespace OpenNest
{
public static class Helper
{
public static List<Shape> GetShapes(IEnumerable<Entity> entities)
{
var lines = new List<Line>();
var arcs = new List<Arc>();
var circles = new List<Circle>();
var shapes = new List<Shape>();
var entities2 = new Queue<Entity>(entities);
while (entities2.Count > 0)
{
var entity = entities2.Dequeue();
switch (entity.Type)
{
case EntityType.Arc:
arcs.Add((Arc)entity);
break;
case EntityType.Circle:
circles.Add((Circle)entity);
break;
case EntityType.Line:
lines.Add((Line)entity);
break;
case EntityType.Shape:
var shape = (Shape)entity;
shape.Entities.ForEach(e => entities2.Enqueue(e));
break;
default:
Debug.Fail("Unhandled geometry type");
break;
}
}
foreach (var circle in circles)
{
var shape = new Shape();
shape.Entities.Add(circle);
shape.UpdateBounds();
shapes.Add(shape);
}
var entityList = new List<Entity>();
entityList.AddRange(lines);
entityList.AddRange(arcs);
while (entityList.Count > 0)
{
var next = entityList[0];
var shape = new Shape();
shape.Entities.Add(next);
entityList.RemoveAt(0);
Vector startPoint = new Vector();
Entity connected;
switch (next.Type)
{
case EntityType.Arc:
var arc = (Arc)next;
startPoint = arc.EndPoint();
break;
case EntityType.Line:
var line = (Line)next;
startPoint = line.EndPoint;
break;
}
while ((connected = GetConnected(startPoint, entityList)) != null)
{
shape.Entities.Add(connected);
entityList.Remove(connected);
switch (connected.Type)
{
case EntityType.Arc:
var arc = (Arc)connected;
startPoint = arc.EndPoint();
break;
case EntityType.Line:
var line = (Line)connected;
startPoint = line.EndPoint;
break;
}
}
shape.UpdateBounds();
shapes.Add(shape);
}
return shapes;
}
internal static Entity GetConnected(Vector pt, IEnumerable<Entity> geometry)
{
var tol = Math.Tolerance.ChainTolerance;
foreach (var geo in geometry)
{
switch (geo.Type)
{
case EntityType.Arc:
var arc = (Arc)geo;
if (arc.StartPoint().DistanceTo(pt) <= tol)
return arc;
if (arc.EndPoint().DistanceTo(pt) <= tol)
{
arc.Reverse();
return arc;
}
break;
case EntityType.Line:
var line = (Line)geo;
if (line.StartPoint.DistanceTo(pt) <= tol)
return line;
if (line.EndPoint.DistanceTo(pt) <= tol)
{
line.Reverse();
return line;
}
break;
}
}
return null;
}
internal static bool Intersects(Arc arc1, Arc arc2, out List<Vector> pts)
{
var c1 = new Circle(arc1.Center, arc1.Radius);
@@ -519,7 +378,7 @@ namespace OpenNest
public static List<Line> GetPartLines(Part part, double chordTolerance = 0.001)
{
var entities = ConvertProgram.ToGeometry(part.Program);
var shapes = GetShapes(entities.Where(e => e.Layer != SpecialLayers.Rapid));
var shapes = ShapeBuilder.GetShapes(entities.Where(e => e.Layer != SpecialLayers.Rapid));
var lines = new List<Line>();
foreach (var shape in shapes)
@@ -535,7 +394,7 @@ namespace OpenNest
public static List<Line> GetPartLines(Part part, PushDirection facingDirection, double chordTolerance = 0.001)
{
var entities = ConvertProgram.ToGeometry(part.Program);
var shapes = GetShapes(entities.Where(e => e.Layer != SpecialLayers.Rapid));
var shapes = ShapeBuilder.GetShapes(entities.Where(e => e.Layer != SpecialLayers.Rapid));
var lines = new List<Line>();
foreach (var shape in shapes)
@@ -551,7 +410,7 @@ namespace OpenNest
public static List<Line> GetOffsetPartLines(Part part, double spacing, double chordTolerance = 0.001)
{
var entities = ConvertProgram.ToGeometry(part.Program);
var shapes = GetShapes(entities.Where(e => e.Layer != SpecialLayers.Rapid));
var shapes = ShapeBuilder.GetShapes(entities.Where(e => e.Layer != SpecialLayers.Rapid));
var lines = new List<Line>();
foreach (var shape in shapes)
@@ -575,7 +434,7 @@ namespace OpenNest
public static List<Line> GetOffsetPartLines(Part part, double spacing, PushDirection facingDirection, double chordTolerance = 0.001)
{
var entities = ConvertProgram.ToGeometry(part.Program);
var shapes = GetShapes(entities.Where(e => e.Layer != SpecialLayers.Rapid));
var shapes = ShapeBuilder.GetShapes(entities.Where(e => e.Layer != SpecialLayers.Rapid));
var lines = new List<Line>();
foreach (var shape in shapes)

View File

@@ -11,7 +11,7 @@ namespace OpenNest
public static TimingInfo GetTimingInfo(Program pgm)
{
var entities = ConvertProgram.ToGeometry(pgm);
var shapes = Helper.GetShapes(entities.Where(entity => entity.Layer != SpecialLayers.Rapid));
var shapes = ShapeBuilder.GetShapes(entities.Where(entity => entity.Layer != SpecialLayers.Rapid));
var info = new TimingInfo { PierceCount = shapes.Count };
var last = entities[0];

View File

@@ -116,7 +116,7 @@ namespace OpenNest.Engine.BestFit
{
var entities = ConvertProgram.ToGeometry(drawing.Program)
.Where(e => e.Layer != SpecialLayers.Rapid);
var shapes = Helper.GetShapes(entities);
var shapes = ShapeBuilder.GetShapes(entities);
var points = new List<Vector>();

View File

@@ -103,7 +103,7 @@ namespace OpenNest.Engine.BestFit
{
var entities = ConvertProgram.ToGeometry(part.Program)
.Where(e => e.Layer != SpecialLayers.Rapid);
var shapes = Helper.GetShapes(entities);
var shapes = ShapeBuilder.GetShapes(entities);
shapes.ForEach(s => s.Offset(part.Location));
return shapes;
}
@@ -112,7 +112,7 @@ namespace OpenNest.Engine.BestFit
{
var entities = ConvertProgram.ToGeometry(part.Program)
.Where(e => e.Layer != SpecialLayers.Rapid);
var shapes = Helper.GetShapes(entities);
var shapes = ShapeBuilder.GetShapes(entities);
var points = new List<Vector>();
foreach (var shape in shapes)

View File

@@ -17,7 +17,7 @@ namespace OpenNest
var entities = ConvertProgram.ToGeometry(item.Drawing.Program)
.Where(e => e.Layer != SpecialLayers.Rapid);
var shapes = Helper.GetShapes(entities);
var shapes = ShapeBuilder.GetShapes(entities);
if (shapes.Count == 0)
return 0;
@@ -65,7 +65,7 @@ namespace OpenNest
var entities = ConvertProgram.ToGeometry(part.Program)
.Where(e => e.Layer != SpecialLayers.Rapid);
var shapes = Helper.GetShapes(entities);
var shapes = ShapeBuilder.GetShapes(entities);
foreach (var shape in shapes)
{

View File

@@ -258,7 +258,7 @@ namespace OpenNest.Gpu
{
var entities = ConvertProgram.ToGeometry(part.Program)
.Where(e => e.Layer != SpecialLayers.Rapid);
var shapes = Helper.GetShapes(entities);
var shapes = ShapeBuilder.GetShapes(entities);
var points = new List<Vector>();
foreach (var shape in shapes)

View File

@@ -47,7 +47,7 @@ namespace OpenNest.Gpu
{
var entities = ConvertProgram.ToGeometry(part.Program)
.Where(e => e.Layer != SpecialLayers.Rapid);
var shapes = Helper.GetShapes(entities);
var shapes = ShapeBuilder.GetShapes(entities);
var polygons = new List<Polygon>();
@@ -137,7 +137,7 @@ namespace OpenNest.Gpu
{
var entities = ConvertProgram.ToGeometry(drawing.Program)
.Where(e => e.Layer != SpecialLayers.Rapid);
var shapes = Helper.GetShapes(entities);
var shapes = ShapeBuilder.GetShapes(entities);
var polygons = new List<Polygon>();

View File

@@ -52,7 +52,7 @@ namespace OpenNest.Actions
{
var entities = ConvertProgram.ToGeometry(part.Program).Where(e => e.Layer == SpecialLayers.Cut).ToList();
entities.ForEach(entity => entity.Offset(part.Location));
var shapes = Helper.GetShapes(entities);
var shapes = ShapeBuilder.GetShapes(entities);
var shape = new Shape();
shape.Entities.AddRange(shapes);
ShapePartPairs.Add(new Pair() { Part = part, Shape = shape });

View File

@@ -134,7 +134,7 @@ namespace OpenNest
{
var result = new List<PointF[]>();
var entities = ConvertProgram.ToGeometry(BasePart.Program);
var shapes = Helper.GetShapes(entities.Where(e => e.Layer != SpecialLayers.Rapid));
var shapes = ShapeBuilder.GetShapes(entities.Where(e => e.Layer != SpecialLayers.Rapid));
foreach (var shape in shapes)
{