perf(fill): prepare overlap polygons once per check

Both HasOverlappingParts loops rebuilt each part's polygon from its
Program on every pair. PartOverlapChecker prepares each distinct Program
(reference identity) once and each part's world polygon once per call,
then uses the overlap-only Collision.HasOverlap. Loop order, bounding-box
prefilter, early exit and returned indices are unchanged; Part.Intersects
shares the material/polygon recipe and still returns crossing points.

Verification:
- Frozen LegacyPartOverlap differential (original Intersects and both
  loops): verdicts, indices and world polygons bit-identical across fill
  grids, patterns, touching/epsilon gaps, scribe/rapid/empty programs.
- Debug OverlapPolygonPreparations: 246 -> 1 and 64 -> 2 per check.
- Corpus job (169 parts, --engines Default --parallel 1, with 1a):
  median 18,885 -> 13,464 ms over 4+4 alternating runs, identical
  outcomes; serialized layout byte-identical to the base.
This commit is contained in:
aj
2026-09-27 13:34:04 -04:00
parent f44a1a3d2c
commit a27290a29c
9 changed files with 672 additions and 17 deletions
+7
View File
@@ -17,6 +17,7 @@ namespace OpenNest
private static long partBoundsUpdates;
private static long featureBitmaskCells;
private static long crossingPointScans;
private static long overlapPolygonPreparations;
public static long FindBestFits => Interlocked.Read(ref findBestFits);
public static long OffsetPerimeterEntities => Interlocked.Read(ref offsetPerimeterEntities);
@@ -26,6 +27,7 @@ namespace OpenNest
public static long PartBoundsUpdates => Interlocked.Read(ref partBoundsUpdates);
public static long FeatureBitmaskCells => Interlocked.Read(ref featureBitmaskCells);
public static long CrossingPointScans => Interlocked.Read(ref crossingPointScans);
public static long OverlapPolygonPreparations => Interlocked.Read(ref overlapPolygonPreparations);
[Conditional("DEBUG")]
public static void CountFindBestFits() => Interlocked.Increment(ref findBestFits);
@@ -52,6 +54,10 @@ namespace OpenNest
[Conditional("DEBUG")]
public static void CountCrossingPointScan() => Interlocked.Increment(ref crossingPointScans);
[Conditional("DEBUG")]
public static void CountOverlapPolygonPreparation() =>
Interlocked.Increment(ref overlapPolygonPreparations);
public static void Reset()
{
Interlocked.Exchange(ref findBestFits, 0);
@@ -62,6 +68,7 @@ namespace OpenNest
Interlocked.Exchange(ref partBoundsUpdates, 0);
Interlocked.Exchange(ref featureBitmaskCells, 0);
Interlocked.Exchange(ref crossingPointScans, 0);
Interlocked.Exchange(ref overlapPolygonPreparations, 0);
}
}
}