fix: allow line-on-line contact and remove extra spacing gap

- Part.Intersects: filter intersection points at a vertex of either
  shape (was both), so edge-touching parts are not flagged as overlapping
- NestEngineBase.HasOverlaps: use epsilon-based bounding box pre-filter
  consistent with FillExtents and Plate.HasOverlappingParts
- PartGeometry.GetOffsetPartLines: remove extra chordTolerance added to
  spacing offset — was causing 0.002" gap beyond the intended part spacing

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-28 15:36:35 -04:00
parent 61b917c398
commit abc707f1d9
3 changed files with 14 additions and 8 deletions
+4 -3
View File
@@ -177,15 +177,16 @@ namespace OpenNest
if (!perimeter1.Intersects(perimeter2, out var rawPts)) if (!perimeter1.Intersects(perimeter2, out var rawPts))
return false; return false;
// Exclude intersection points that coincide with vertices of BOTH // Exclude intersection points that coincide with a vertex of either
// perimeters — these are touch points (shared corners/endpoints), // perimeter — these are boundary contact points (shared corners,
// endpoints, or a corner touching an edge) with zero area overlap,
// not actual crossings where one shape enters the other's interior. // not actual crossings where one shape enters the other's interior.
var verts1 = CollectVertices(perimeter1); var verts1 = CollectVertices(perimeter1);
var verts2 = CollectVertices(perimeter2); var verts2 = CollectVertices(perimeter2);
foreach (var pt in rawPts) foreach (var pt in rawPts)
{ {
if (IsNearAnyVertex(pt, verts1) && IsNearAnyVertex(pt, verts2)) if (IsNearAnyVertex(pt, verts1) || IsNearAnyVertex(pt, verts2))
continue; continue;
pts.Add(pt); pts.Add(pt);
} }
+3 -3
View File
@@ -45,7 +45,7 @@ namespace OpenNest
var profile = new ShapeProfile( var profile = new ShapeProfile(
entities.Where(e => e.Layer != SpecialLayers.Rapid).ToList()); entities.Where(e => e.Layer != SpecialLayers.Rapid).ToList());
var lines = new List<Line>(); var lines = new List<Line>();
var totalSpacing = spacing + chordTolerance; var totalSpacing = spacing;
AddOffsetLines(lines, profile.Perimeter.OffsetOutward(totalSpacing), AddOffsetLines(lines, profile.Perimeter.OffsetOutward(totalSpacing),
chordTolerance, part.Location); chordTolerance, part.Location);
@@ -63,7 +63,7 @@ namespace OpenNest
var profile = new ShapeProfile( var profile = new ShapeProfile(
entities.Where(e => e.Layer != SpecialLayers.Rapid).ToList()); entities.Where(e => e.Layer != SpecialLayers.Rapid).ToList());
var lines = new List<Line>(); var lines = new List<Line>();
var totalSpacing = spacing + chordTolerance; var totalSpacing = spacing;
AddOffsetDirectionalLines(lines, profile.Perimeter.OffsetOutward(totalSpacing), AddOffsetDirectionalLines(lines, profile.Perimeter.OffsetOutward(totalSpacing),
chordTolerance, part.Location, facingDirection); chordTolerance, part.Location, facingDirection);
@@ -97,7 +97,7 @@ namespace OpenNest
var profile = new ShapeProfile( var profile = new ShapeProfile(
entities.Where(e => e.Layer != SpecialLayers.Rapid).ToList()); entities.Where(e => e.Layer != SpecialLayers.Rapid).ToList());
var lines = new List<Line>(); var lines = new List<Line>();
var totalSpacing = spacing + chordTolerance; var totalSpacing = spacing;
AddOffsetDirectionalLines(lines, profile.Perimeter.OffsetOutward(totalSpacing), AddOffsetDirectionalLines(lines, profile.Perimeter.OffsetOutward(totalSpacing),
chordTolerance, part.Location, facingDirection); chordTolerance, part.Location, facingDirection);
+7 -2
View File
@@ -2,6 +2,7 @@ using OpenNest.Engine;
using OpenNest.Engine.Fill; using OpenNest.Engine.Fill;
using OpenNest.Engine.Strategies; using OpenNest.Engine.Strategies;
using OpenNest.Geometry; using OpenNest.Geometry;
using OpenNest.Math;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
@@ -275,8 +276,12 @@ namespace OpenNest
{ {
var box2 = parts[j].BoundingBox; var box2 = parts[j].BoundingBox;
if (box1.Right < box2.Left || box2.Right < box1.Left || var overlapX = System.Math.Min(box1.Right, box2.Right)
box1.Top < box2.Bottom || box2.Top < box1.Bottom) - System.Math.Max(box1.Left, box2.Left);
var overlapY = System.Math.Min(box1.Top, box2.Top)
- System.Math.Max(box1.Bottom, box2.Bottom);
if (overlapX <= Tolerance.Epsilon || overlapY <= Tolerance.Epsilon)
continue; continue;
List<Vector> pts; List<Vector> pts;