refactor: use ShapeProfile perimeter for boundary and intersection

Replace shape-list iteration with ShapeProfile.Perimeter in both
Part.Intersects and PartBoundary, simplifying the logic and ensuring
only the outermost contour is used for collision detection.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-14 12:41:03 -04:00
parent 65ded42120
commit a9aaab8337
2 changed files with 29 additions and 31 deletions
+13 -19
View File
@@ -149,31 +149,25 @@ namespace OpenNest
pts = new List<Vector>(); pts = new List<Vector>();
var entities1 = ConvertProgram.ToGeometry(Program) var entities1 = ConvertProgram.ToGeometry(Program)
.Where(e => e.Layer != SpecialLayers.Rapid); .Where(e => e.Layer != SpecialLayers.Rapid)
.ToList();
var entities2 = ConvertProgram.ToGeometry(part.Program) var entities2 = ConvertProgram.ToGeometry(part.Program)
.Where(e => e.Layer != SpecialLayers.Rapid); .Where(e => e.Layer != SpecialLayers.Rapid)
.ToList();
var shapes1 = Helper.GetShapes(entities1); if (entities1.Count == 0 || entities2.Count == 0)
var shapes2 = Helper.GetShapes(entities2); return false;
shapes1.ForEach(shape => shape.Offset(Location)); var perimeter1 = new ShapeProfile(entities1).Perimeter;
shapes2.ForEach(shape => shape.Offset(part.Location)); var perimeter2 = new ShapeProfile(entities2).Perimeter;
for (int i = 0; i < shapes1.Count; i++) if (perimeter1 == null || perimeter2 == null)
{ return false;
var shape1 = shapes1[i];
for (int j = 0; j < shapes2.Count; j++) perimeter1.Offset(Location);
{ perimeter2.Offset(part.Location);
var shape2 = shapes2[j];
List<Vector> pts2;
if (shape1.Intersects(shape2, out pts2)) return perimeter1.Intersects(perimeter2, out pts);
pts.AddRange(pts2);
}
}
return pts.Count > 0;
} }
public double Left public double Left
+11 -7
View File
@@ -23,23 +23,27 @@ namespace OpenNest
public PartBoundary(Part part, double spacing) public PartBoundary(Part part, double spacing)
{ {
var entities = ConvertProgram.ToGeometry(part.Program); var entities = ConvertProgram.ToGeometry(part.Program)
var shapes = Helper.GetShapes(entities.Where(e => e.Layer != SpecialLayers.Rapid)); .Where(e => e.Layer != SpecialLayers.Rapid)
.ToList();
var definedShape = new ShapeProfile(entities);
var perimeter = definedShape.Perimeter;
_polygons = new List<Polygon>(); _polygons = new List<Polygon>();
foreach (var shape in shapes) if (perimeter != null)
{ {
var offsetEntity = shape.OffsetEntity(spacing, OffsetSide.Left) as Shape; var offsetEntity = perimeter.OffsetEntity(spacing, OffsetSide.Left) as Shape;
if (offsetEntity == null)
continue;
if (offsetEntity != null)
{
// Circumscribe arcs so polygon vertices are always outside // Circumscribe arcs so polygon vertices are always outside
// the true arc — guarantees the boundary never under-estimates. // the true arc — guarantees the boundary never under-estimates.
var polygon = offsetEntity.ToPolygonWithTolerance(PolygonTolerance, circumscribe: true); var polygon = offsetEntity.ToPolygonWithTolerance(PolygonTolerance, circumscribe: true);
polygon.RemoveSelfIntersections(); polygon.RemoveSelfIntersections();
_polygons.Add(polygon); _polygons.Add(polygon);
} }
}
PrecomputeDirectionalEdges( PrecomputeDirectionalEdges(
out _leftEdges, out _rightEdges, out _upEdges, out _downEdges); out _leftEdges, out _rightEdges, out _upEdges, out _downEdges);