fix: improve overlap detection to ignore touch points and add bounding box pre-filtering
Part.Intersects now filters out intersection points that coincide with vertices of both perimeters (shared corners/endpoints), which are touch points rather than actual crossings. Plate.HasOverlappingParts adds a bounding box pre-filter requiring overlap region to exceed Epsilon in both dimensions before performing expensive shape intersection checks. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
using OpenNest.CNC;
|
using OpenNest.CNC;
|
||||||
using OpenNest.Converters;
|
using OpenNest.Converters;
|
||||||
using OpenNest.Geometry;
|
using OpenNest.Geometry;
|
||||||
|
using OpenNest.Math;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
@@ -173,7 +174,53 @@ namespace OpenNest
|
|||||||
perimeter1.Offset(Location);
|
perimeter1.Offset(Location);
|
||||||
perimeter2.Offset(part.Location);
|
perimeter2.Offset(part.Location);
|
||||||
|
|
||||||
return perimeter1.Intersects(perimeter2, out pts);
|
if (!perimeter1.Intersects(perimeter2, out var rawPts))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Exclude intersection points that coincide with vertices of BOTH
|
||||||
|
// perimeters — these are touch points (shared corners/endpoints),
|
||||||
|
// not actual crossings where one shape enters the other's interior.
|
||||||
|
var verts1 = CollectVertices(perimeter1);
|
||||||
|
var verts2 = CollectVertices(perimeter2);
|
||||||
|
|
||||||
|
foreach (var pt in rawPts)
|
||||||
|
{
|
||||||
|
if (IsNearAnyVertex(pt, verts1) && IsNearAnyVertex(pt, verts2))
|
||||||
|
continue;
|
||||||
|
pts.Add(pt);
|
||||||
|
}
|
||||||
|
|
||||||
|
return pts.Count > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<Vector> CollectVertices(Geometry.Shape shape)
|
||||||
|
{
|
||||||
|
var verts = new List<Vector>();
|
||||||
|
foreach (var entity in shape.Entities)
|
||||||
|
{
|
||||||
|
switch (entity)
|
||||||
|
{
|
||||||
|
case Geometry.Line line:
|
||||||
|
verts.Add(line.StartPoint);
|
||||||
|
verts.Add(line.EndPoint);
|
||||||
|
break;
|
||||||
|
case Geometry.Arc arc:
|
||||||
|
verts.Add(arc.StartPoint());
|
||||||
|
verts.Add(arc.EndPoint());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return verts;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsNearAnyVertex(Vector pt, List<Vector> vertices)
|
||||||
|
{
|
||||||
|
foreach (var v in vertices)
|
||||||
|
{
|
||||||
|
if (pt.X.IsEqualTo(v.X) && pt.Y.IsEqualTo(v.Y))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public double Left
|
public double Left
|
||||||
|
|||||||
@@ -601,10 +601,24 @@ namespace OpenNest
|
|||||||
for (var i = 0; i < realParts.Count; i++)
|
for (var i = 0; i < realParts.Count; i++)
|
||||||
{
|
{
|
||||||
var part1 = realParts[i];
|
var part1 = realParts[i];
|
||||||
|
var b1 = part1.BoundingBox;
|
||||||
|
|
||||||
for (var j = i + 1; j < realParts.Count; j++)
|
for (var j = i + 1; j < realParts.Count; j++)
|
||||||
{
|
{
|
||||||
var part2 = realParts[j];
|
var part2 = realParts[j];
|
||||||
|
var b2 = part2.BoundingBox;
|
||||||
|
|
||||||
|
// Skip pairs whose bounding boxes don't meaningfully overlap.
|
||||||
|
// Floating-point rounding can produce sub-epsilon overlaps for
|
||||||
|
// parts that are merely edge-touching, so require the overlap
|
||||||
|
// region to exceed Epsilon in both dimensions.
|
||||||
|
var overlapX = System.Math.Min(b1.Right, b2.Right)
|
||||||
|
- System.Math.Max(b1.Left, b2.Left);
|
||||||
|
var overlapY = System.Math.Min(b1.Top, b2.Top)
|
||||||
|
- System.Math.Max(b1.Bottom, b2.Bottom);
|
||||||
|
|
||||||
|
if (overlapX <= Math.Tolerance.Epsilon || overlapY <= Math.Tolerance.Epsilon)
|
||||||
|
continue;
|
||||||
|
|
||||||
if (part1.Intersects(part2, out var pts2))
|
if (part1.Intersects(part2, out var pts2))
|
||||||
pts.AddRange(pts2);
|
pts.AddRange(pts2);
|
||||||
|
|||||||
Reference in New Issue
Block a user