mirror of
https://github.com/ajisaacs/OpenNest.git
synced 2026-10-03 13:42:20 -04:00
fix(irregular): keep exact bounds for line-only part outlines
Orientation bounds were padded by the arc chord tolerance even when the outline has no arcs, so a part that exactly fills the work area after rotation was rejected before packing. Pad only outlines with flattened arcs; footprints and NFPs still use the chord tolerance.
This commit is contained in:
1 parent
c7b4ba4457
commit
25755a8850
1 file changed
+16
-8
@@ -25,7 +25,11 @@ internal sealed class Orientation
|
||||
/// <summary>Chord deviation used for arcs; footprints are grown by it to stay conservative.</summary>
|
||||
public required double Tolerance { get; init; }
|
||||
|
||||
/// <summary>Outline bounds grown by the tolerance, so they contain the true perimeter.</summary>
|
||||
/// <summary>
|
||||
/// Outline bounds grown by the outline's actual flattening error, so they contain the true
|
||||
/// perimeter: by <see cref="Tolerance"/> when arcs were flattened, not at all for line-only
|
||||
/// outlines, whose vertices are exact. Footprints and NFPs still use <see cref="Tolerance"/>.
|
||||
/// </summary>
|
||||
public required double MinX { get; init; }
|
||||
public required double MinY { get; init; }
|
||||
public required double MaxX { get; init; }
|
||||
@@ -96,7 +100,7 @@ internal static class PartCatalog
|
||||
var outline = Polygonize(perimeter, angle, tolerance);
|
||||
if (outline.Count < 3)
|
||||
continue;
|
||||
orientations.Add(MakeOrientation(index, orientations.Count, angle, outline, tolerance));
|
||||
orientations.Add(MakeOrientation(index, orientations.Count, angle, outline, tolerance, perimeter));
|
||||
}
|
||||
|
||||
var area = orientations.Count == 0 ? 0 : System.Math.Abs(Clipper.Area(orientations[0].Outline));
|
||||
@@ -123,7 +127,7 @@ internal static class PartCatalog
|
||||
return null;
|
||||
var tolerance = type.Orientations[0].Tolerance;
|
||||
var outline = Polygonize(type.Perimeter, angle, tolerance);
|
||||
return outline.Count < 3 ? null : MakeOrientation(type.Index, index, angle, outline, tolerance);
|
||||
return outline.Count < 3 ? null : MakeOrientation(type.Index, index, angle, outline, tolerance, type.Perimeter);
|
||||
}
|
||||
|
||||
private static Shape? ReadPerimeter(PartGeometrySnapshot geometry) =>
|
||||
@@ -163,9 +167,13 @@ internal static class PartCatalog
|
||||
return path;
|
||||
}
|
||||
|
||||
private static Orientation MakeOrientation(int typeIndex, int index, double angle, PathD outline, double tolerance)
|
||||
private static Orientation MakeOrientation(int typeIndex, int index, double angle, PathD outline,
|
||||
double tolerance, Shape perimeter)
|
||||
{
|
||||
var bounds = Clipper.GetBounds(outline);
|
||||
// Only flattened arcs deviate from the true perimeter; line vertices are exact, so a
|
||||
// line-only part keeps its nominal material bounds and can fill its work area exactly.
|
||||
var padding = perimeter.Entities.All(e => e.Type == EntityType.Line) ? 0 : tolerance;
|
||||
return new Orientation
|
||||
{
|
||||
TypeIndex = typeIndex,
|
||||
@@ -173,10 +181,10 @@ internal static class PartCatalog
|
||||
Rotation = angle,
|
||||
Outline = outline,
|
||||
Tolerance = tolerance,
|
||||
MinX = bounds.left - tolerance,
|
||||
MinY = bounds.top - tolerance, // Clipper RectD: top is the minimum Y.
|
||||
MaxX = bounds.right + tolerance,
|
||||
MaxY = bounds.bottom + tolerance,
|
||||
MinX = bounds.left - padding,
|
||||
MinY = bounds.top - padding, // Clipper RectD: top is the minimum Y.
|
||||
MaxX = bounds.right + padding,
|
||||
MaxY = bounds.bottom + padding,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user