mirror of
https://github.com/ajisaacs/OpenNest.git
synced 2026-11-12 07:51:11 -05:00
Geometry, nesting and import code now call PortableMath instead of System.Math for Sin, Cos, Tan, Atan, Atan2, Asin and Acos (Core, Engine, IO, Data; 269 calls in 64 files). A test fails if those projects call the runtime's trig again. With the runtime's trig, Windows and Linux disagreed in the last bit at non-quarter angles and the same job could nest differently: the learned-angle nests (a cross fixture) placed 23 parts in Strip on Windows and 28 on Linux. Now every Engine.Tests pin gives the same layout on both (3600 passing on Linux and on DesktopPC), Linux layouts are unchanged, and the learned-angle rows are re-pinned to the shared layouts, which pass the overlap and work-area checks, and run on every platform again. Fixes Project Memory 518f3b58.
79 lines
2.6 KiB
C#
79 lines
2.6 KiB
C#
using System.Linq;
|
|
using OpenNest.Converters;
|
|
using OpenNest.Geometry;
|
|
using OpenNest.Math;
|
|
|
|
namespace OpenNest.Engine.BestFit
|
|
{
|
|
public static class PolygonHelper
|
|
{
|
|
public static PolygonExtractionResult ExtractPerimeterPolygon(
|
|
Drawing drawing,
|
|
double halfSpacing
|
|
)
|
|
{
|
|
var entities = ConvertProgram
|
|
.ToGeometry(drawing.Program)
|
|
.ForNesting()
|
|
.ToList();
|
|
|
|
if (entities.Count == 0)
|
|
return new PolygonExtractionResult(null, Vector.Zero);
|
|
|
|
var definedShape = new ShapeProfile(entities);
|
|
var perimeter = definedShape.Perimeter;
|
|
|
|
if (perimeter == null)
|
|
return new PolygonExtractionResult(null, Vector.Zero);
|
|
|
|
// Circumscribe so the polygon never under-estimates the part (or its offset).
|
|
var polygon =
|
|
halfSpacing > 0
|
|
? ClipperBridge
|
|
.OffsetPerimeter(perimeter, halfSpacing, 0.01, circumscribe: true)
|
|
.LargestOuter()
|
|
: perimeter.ToPolygonWithTolerance(0.01, circumscribe: true);
|
|
|
|
if (polygon == null || polygon.Vertices.Count < 3)
|
|
return new PolygonExtractionResult(null, Vector.Zero);
|
|
|
|
// Normalize: move polygon to origin.
|
|
polygon.UpdateBounds();
|
|
var bb = polygon.BoundingBox;
|
|
polygon.Offset(-bb.Left, -bb.Bottom);
|
|
|
|
// No correction needed: BestFitFinder always pairs the same drawing with
|
|
// itself, so the polygon-to-part offset is identical for both parts and
|
|
// cancels out in the NFP displacement.
|
|
return new PolygonExtractionResult(polygon, Vector.Zero);
|
|
}
|
|
|
|
public static Polygon RotatePolygon(Polygon polygon, double angle, bool reNormalize = true)
|
|
{
|
|
if (angle.IsEqualTo(0))
|
|
return polygon;
|
|
|
|
var result = new Polygon();
|
|
var cos = PortableMath.Cos(angle);
|
|
var sin = PortableMath.Sin(angle);
|
|
|
|
foreach (var v in polygon.Vertices)
|
|
{
|
|
result.Vertices.Add(new Vector(v.X * cos - v.Y * sin, v.X * sin + v.Y * cos));
|
|
}
|
|
|
|
if (reNormalize)
|
|
{
|
|
// Re-normalize to origin.
|
|
result.UpdateBounds();
|
|
var bb = result.BoundingBox;
|
|
result.Offset(-bb.Left, -bb.Bottom);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
}
|
|
|
|
public record PolygonExtractionResult(Polygon Polygon, Vector Correction);
|
|
}
|