diff --git a/OpenNest.Core/Geometry/Arc.cs b/OpenNest.Core/Geometry/Arc.cs
index faaa91e..dfd805f 100644
--- a/OpenNest.Core/Geometry/Arc.cs
+++ b/OpenNest.Core/Geometry/Arc.cs
@@ -185,6 +185,19 @@ namespace OpenNest.Geometry
return center == circle.Center;
}
+ ///
+ /// Returns the minimum number of segments needed so that the chord-to-arc
+ /// deviation (sagitta) does not exceed the given tolerance.
+ ///
+ public int SegmentsForTolerance(double tolerance)
+ {
+ if (tolerance >= Radius)
+ return 1;
+
+ var maxAngle = 2.0 * System.Math.Acos(1.0 - tolerance / Radius);
+ return System.Math.Max(1, (int)System.Math.Ceiling(System.Math.Abs(SweepAngle()) / maxAngle));
+ }
+
///
/// Converts the arc to a group of points.
///
diff --git a/OpenNest.Core/Geometry/Circle.cs b/OpenNest.Core/Geometry/Circle.cs
index fdada85..5d57e9e 100644
--- a/OpenNest.Core/Geometry/Circle.cs
+++ b/OpenNest.Core/Geometry/Circle.cs
@@ -122,6 +122,19 @@ namespace OpenNest.Geometry
return Center.DistanceTo(pt) <= Radius;
}
+ ///
+ /// Returns the minimum number of segments needed so that the chord-to-arc
+ /// deviation (sagitta) does not exceed the given tolerance.
+ ///
+ public int SegmentsForTolerance(double tolerance)
+ {
+ if (tolerance >= Radius)
+ return 3;
+
+ var maxAngle = 2.0 * System.Math.Acos(1.0 - tolerance / Radius);
+ return System.Math.Max(3, (int)System.Math.Ceiling(Angle.TwoPI / maxAngle));
+ }
+
public List ToPoints(int segments = 1000)
{
var points = new List();
diff --git a/OpenNest.Core/Geometry/Shape.cs b/OpenNest.Core/Geometry/Shape.cs
index f910a06..843485d 100644
--- a/OpenNest.Core/Geometry/Shape.cs
+++ b/OpenNest.Core/Geometry/Shape.cs
@@ -243,6 +243,49 @@ namespace OpenNest.Geometry
return polygon;
}
+ ///
+ /// Converts the shape to a polygon using a chord tolerance to determine
+ /// the number of segments per arc/circle.
+ ///
+ public Polygon ToPolygonWithTolerance(double tolerance)
+ {
+ var polygon = new Polygon();
+
+ foreach (var entity in Entities)
+ {
+ switch (entity.Type)
+ {
+ case EntityType.Arc:
+ var arc = (Arc)entity;
+ polygon.Vertices.AddRange(arc.ToPoints(arc.SegmentsForTolerance(tolerance)));
+ break;
+
+ case EntityType.Line:
+ var line = (Line)entity;
+ polygon.Vertices.AddRange(new[]
+ {
+ line.StartPoint,
+ line.EndPoint
+ });
+ break;
+
+ case EntityType.Circle:
+ var circle = (Circle)entity;
+ polygon.Vertices.AddRange(circle.ToPoints(circle.SegmentsForTolerance(tolerance)));
+ break;
+
+ default:
+ Debug.Fail("Unhandled geometry type");
+ break;
+ }
+ }
+
+ polygon.Close();
+ polygon.Cleanup();
+
+ return polygon;
+ }
+
///
/// Reverses the rotation direction of the shape.
///
diff --git a/OpenNest.Core/Helper.cs b/OpenNest.Core/Helper.cs
index a6b31f5..8a1a0b8 100644
--- a/OpenNest.Core/Helper.cs
+++ b/OpenNest.Core/Helper.cs
@@ -739,7 +739,7 @@ namespace OpenNest
return pts.Count > 0;
}
- private const int PushArcSegments = 36;
+ private const double PushChordTolerance = 0.08;
public static List GetPartLines(Part part)
{
@@ -749,7 +749,7 @@ namespace OpenNest
foreach (var shape in shapes)
{
- var polygon = shape.ToPolygon(PushArcSegments);
+ var polygon = shape.ToPolygonWithTolerance(PushChordTolerance);
polygon.Offset(part.Location);
lines.AddRange(polygon.ToLines());
}
@@ -770,7 +770,7 @@ namespace OpenNest
if (offsetEntity == null)
continue;
- var polygon = offsetEntity.ToPolygon(PushArcSegments);
+ var polygon = offsetEntity.ToPolygonWithTolerance(PushChordTolerance);
polygon.Offset(part.Location);
lines.AddRange(polygon.ToLines());
}