mirror of
https://github.com/ajisaacs/OpenNest.git
synced 2026-11-11 08:41:09 -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.
298 lines
9.1 KiB
C#
298 lines
9.1 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Drawing;
|
|
using ACadSharp.Entities;
|
|
using CSMath;
|
|
using OpenNest.Geometry;
|
|
using OpenNest.Math;
|
|
|
|
namespace OpenNest.IO
|
|
{
|
|
internal static class Extensions
|
|
{
|
|
public static Vector ToOpenNest(this XY v)
|
|
{
|
|
return new Vector(v.X, v.Y);
|
|
}
|
|
|
|
public static Vector ToOpenNest(this XYZ v)
|
|
{
|
|
return new Vector(v.X, v.Y);
|
|
}
|
|
|
|
public static Geometry.Arc ToOpenNest(this ACadSharp.Entities.Arc arc)
|
|
{
|
|
var result = new Geometry.Arc(
|
|
arc.Center.X,
|
|
arc.Center.Y,
|
|
arc.Radius,
|
|
arc.StartAngle,
|
|
arc.EndAngle
|
|
)
|
|
{
|
|
Layer = arc.Layer.ToOpenNest(),
|
|
};
|
|
result.ApplyDxfProperties(arc);
|
|
return result;
|
|
}
|
|
|
|
public static Geometry.Circle ToOpenNest(this ACadSharp.Entities.Circle circle)
|
|
{
|
|
var result = new Geometry.Circle(circle.Center.X, circle.Center.Y, circle.Radius)
|
|
{
|
|
Layer = circle.Layer.ToOpenNest(),
|
|
};
|
|
result.ApplyDxfProperties(circle);
|
|
return result;
|
|
}
|
|
|
|
public static Geometry.Line ToOpenNest(this ACadSharp.Entities.Line line)
|
|
{
|
|
var result = new Geometry.Line(
|
|
line.StartPoint.X,
|
|
line.StartPoint.Y,
|
|
line.EndPoint.X,
|
|
line.EndPoint.Y
|
|
)
|
|
{
|
|
Layer = line.Layer.ToOpenNest(),
|
|
};
|
|
result.ApplyDxfProperties(line);
|
|
return result;
|
|
}
|
|
|
|
public static List<Geometry.Entity> ToOpenNest(this Spline spline)
|
|
{
|
|
var layer = spline.Layer.ToOpenNest();
|
|
var color = spline.ResolveColor();
|
|
var lineTypeName = spline.ResolveLineTypeName();
|
|
|
|
// Evaluate actual points on the spline curve (not control points)
|
|
List<XYZ> curvePoints;
|
|
try
|
|
{
|
|
curvePoints = spline.PolygonalVertexes(200);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
System.Diagnostics.Debug.WriteLine($"Spline curve evaluation failed: {ex.Message}");
|
|
curvePoints = null;
|
|
}
|
|
|
|
if (curvePoints == null || curvePoints.Count < 2)
|
|
{
|
|
// Fallback: use control points if evaluation fails
|
|
curvePoints = new List<XYZ>(spline.ControlPoints);
|
|
if (curvePoints.Count < 2)
|
|
return new List<Geometry.Entity>();
|
|
}
|
|
|
|
var points = new List<Vector>(curvePoints.Count);
|
|
foreach (var pt in curvePoints)
|
|
points.Add(pt.ToOpenNest());
|
|
|
|
var entities = SplineConverter.Convert(points, spline.IsClosed, tolerance: 0.001);
|
|
|
|
foreach (var entity in entities)
|
|
{
|
|
entity.Layer = layer;
|
|
entity.Color = color;
|
|
entity.LineTypeName = lineTypeName;
|
|
}
|
|
|
|
return entities;
|
|
}
|
|
|
|
public static List<Geometry.Line> ToOpenNest(this Polyline polyline)
|
|
{
|
|
var lines = new List<Geometry.Line>();
|
|
|
|
if (polyline.Vertices.Count == 0)
|
|
return lines;
|
|
|
|
var layer = polyline.Layer.ToOpenNest();
|
|
var color = polyline.ResolveColor();
|
|
var lineTypeName = polyline.ResolveLineTypeName();
|
|
var lastPoint = polyline.Vertices[0].Location.ToOpenNest();
|
|
|
|
for (var i = 1; i < polyline.Vertices.Count; i++)
|
|
{
|
|
var nextPoint = polyline.Vertices[i].Location.ToOpenNest();
|
|
|
|
lines.Add(
|
|
new Geometry.Line(lastPoint, nextPoint)
|
|
{
|
|
Layer = layer,
|
|
Color = color,
|
|
LineTypeName = lineTypeName,
|
|
}
|
|
);
|
|
|
|
lastPoint = nextPoint;
|
|
}
|
|
|
|
var isClosed =
|
|
(polyline.Flags & PolylineFlags.ClosedPolylineOrClosedPolygonMeshInM) != 0;
|
|
|
|
if (isClosed)
|
|
lines.Add(
|
|
new Geometry.Line(lastPoint, polyline.Vertices[0].Location.ToOpenNest())
|
|
{
|
|
Layer = layer,
|
|
Color = color,
|
|
LineTypeName = lineTypeName,
|
|
}
|
|
);
|
|
|
|
return lines;
|
|
}
|
|
|
|
public static List<Geometry.Line> ToOpenNest(this LwPolyline polyline)
|
|
{
|
|
var lines = new List<Geometry.Line>();
|
|
|
|
if (polyline.Vertices.Count == 0)
|
|
return lines;
|
|
|
|
var layer = polyline.Layer.ToOpenNest();
|
|
var color = polyline.ResolveColor();
|
|
var lineTypeName = polyline.ResolveLineTypeName();
|
|
var lastPoint = polyline.Vertices[0].ToOpenNest();
|
|
|
|
for (var i = 1; i < polyline.Vertices.Count; i++)
|
|
{
|
|
var nextPoint = polyline.Vertices[i].ToOpenNest();
|
|
|
|
lines.Add(
|
|
new Geometry.Line(lastPoint, nextPoint)
|
|
{
|
|
Layer = layer,
|
|
Color = color,
|
|
LineTypeName = lineTypeName,
|
|
}
|
|
);
|
|
|
|
lastPoint = nextPoint;
|
|
}
|
|
|
|
var isClosed = (polyline.Flags & LwPolylineFlags.Closed) != 0;
|
|
|
|
if (isClosed)
|
|
lines.Add(
|
|
new Geometry.Line(lastPoint, polyline.Vertices[0].ToOpenNest())
|
|
{
|
|
Layer = layer,
|
|
Color = color,
|
|
LineTypeName = lineTypeName,
|
|
}
|
|
);
|
|
|
|
return lines;
|
|
}
|
|
|
|
public static List<Geometry.Entity> ToOpenNest(
|
|
this ACadSharp.Entities.Ellipse ellipse,
|
|
double tolerance = 0.001
|
|
)
|
|
{
|
|
var center = new Vector(ellipse.Center.X, ellipse.Center.Y);
|
|
var majorAxis = new Vector(ellipse.MajorAxisEndPoint.X, ellipse.MajorAxisEndPoint.Y);
|
|
|
|
var startParam = ellipse.StartParameter;
|
|
var endParam = ellipse.EndParameter;
|
|
|
|
if (ellipse.Normal.Z < 0)
|
|
{
|
|
var newStart = OpenNest.Math.Angle.TwoPI - endParam;
|
|
var newEnd = OpenNest.Math.Angle.TwoPI - startParam;
|
|
startParam = newStart;
|
|
endParam = newEnd;
|
|
}
|
|
|
|
var semiMajor = System.Math.Sqrt(majorAxis.X * majorAxis.X + majorAxis.Y * majorAxis.Y);
|
|
var semiMinor = semiMajor * ellipse.RadiusRatio;
|
|
var rotation = PortableMath.Atan2(majorAxis.Y, majorAxis.X);
|
|
|
|
var layer = ellipse.Layer.ToOpenNest();
|
|
var color = ellipse.ResolveColor();
|
|
var lineTypeName = ellipse.ResolveLineTypeName();
|
|
|
|
var entities = EllipseConverter.Convert(
|
|
center,
|
|
semiMajor,
|
|
semiMinor,
|
|
rotation,
|
|
startParam,
|
|
endParam,
|
|
tolerance
|
|
);
|
|
|
|
foreach (var entity in entities)
|
|
{
|
|
entity.Layer = layer;
|
|
entity.Color = color;
|
|
entity.LineTypeName = lineTypeName;
|
|
}
|
|
|
|
return entities;
|
|
}
|
|
|
|
public static Geometry.Layer ToOpenNest(this ACadSharp.Tables.Layer layer)
|
|
{
|
|
return new Geometry.Layer(layer.Name)
|
|
{
|
|
Color = Color.FromArgb(layer.Color.R, layer.Color.G, layer.Color.B),
|
|
IsVisible = layer.IsOn,
|
|
LineTypeName = layer.LineType?.Name,
|
|
};
|
|
}
|
|
|
|
public static Color ResolveColor(this ACadSharp.Entities.Entity entity)
|
|
{
|
|
var color = entity.Color;
|
|
|
|
if (color.IsByLayer)
|
|
color = entity.Layer.Color;
|
|
|
|
return Color.FromArgb(color.R, color.G, color.B);
|
|
}
|
|
|
|
public static string ResolveLineTypeName(this ACadSharp.Entities.Entity entity)
|
|
{
|
|
var lt = entity.LineType;
|
|
|
|
if (
|
|
lt == null
|
|
|| string.Equals(lt.Name, "ByLayer", System.StringComparison.OrdinalIgnoreCase)
|
|
)
|
|
return entity.Layer.LineType?.Name ?? "Continuous";
|
|
|
|
return lt.Name;
|
|
}
|
|
|
|
public static void ApplyDxfProperties(
|
|
this Geometry.Entity target,
|
|
ACadSharp.Entities.Entity source
|
|
)
|
|
{
|
|
target.Color = source.ResolveColor();
|
|
target.LineTypeName = source.ResolveLineTypeName();
|
|
}
|
|
|
|
public static Vector ToOpenNest(this LwPolyline.Vertex v)
|
|
{
|
|
return new Vector(v.Location.X, v.Location.Y);
|
|
}
|
|
|
|
public static XY ToAcad(this Vector v)
|
|
{
|
|
return new XY(v.X, v.Y);
|
|
}
|
|
|
|
public static XYZ ToAcadXYZ(this Vector v)
|
|
{
|
|
return new XYZ(v.X, v.Y, 0);
|
|
}
|
|
}
|
|
}
|