diff --git a/OpenNest.Core/Helper.cs b/OpenNest.Core/Helper.cs index 385379e..c694c29 100644 --- a/OpenNest.Core/Helper.cs +++ b/OpenNest.Core/Helper.cs @@ -739,7 +739,7 @@ namespace OpenNest return pts.Count > 0; } - private const double PushChordTolerance = 0.03; + private const double PushChordTolerance = 0.01; public static List GetPartLines(Part part) { @@ -757,6 +757,22 @@ namespace OpenNest return lines; } + public static List GetPartLines(Part part, PushDirection facingDirection) + { + var entities = ConvertProgram.ToGeometry(part.Program); + var shapes = GetShapes(entities.Where(e => e.Layer != SpecialLayers.Rapid)); + var lines = new List(); + + foreach (var shape in shapes) + { + var polygon = shape.ToPolygonWithTolerance(PushChordTolerance); + polygon.Offset(part.Location); + lines.AddRange(GetDirectionalLines(polygon, facingDirection)); + } + + return lines; + } + public static List GetOffsetPartLines(Part part, double spacing) { var entities = ConvertProgram.ToGeometry(part.Program); @@ -780,6 +796,65 @@ namespace OpenNest return lines; } + public static List GetOffsetPartLines(Part part, double spacing, PushDirection facingDirection) + { + var entities = ConvertProgram.ToGeometry(part.Program); + var shapes = GetShapes(entities.Where(e => e.Layer != SpecialLayers.Rapid)); + var lines = new List(); + + foreach (var shape in shapes) + { + var offsetEntity = shape.OffsetEntity(spacing + PushChordTolerance, OffsetSide.Left) as Shape; + + if (offsetEntity == null) + continue; + + var polygon = offsetEntity.ToPolygonWithTolerance(PushChordTolerance); + polygon.Offset(part.Location); + lines.AddRange(GetDirectionalLines(polygon, facingDirection)); + } + + return lines; + } + + /// + /// Returns only polygon edges whose outward normal faces the specified direction. + /// + private static List GetDirectionalLines(Polygon polygon, PushDirection facingDirection) + { + if (polygon.Vertices.Count < 3) + return polygon.ToLines(); + + var sign = polygon.RotationDirection() == RotationType.CCW ? 1.0 : -1.0; + var lines = new List(); + var last = polygon.Vertices[0]; + + for (int i = 1; i < polygon.Vertices.Count; i++) + { + var current = polygon.Vertices[i]; + var dx = current.X - last.X; + var dy = current.Y - last.Y; + + bool keep; + + switch (facingDirection) + { + case PushDirection.Left: keep = -sign * dy > 0; break; + case PushDirection.Right: keep = sign * dy > 0; break; + case PushDirection.Up: keep = -sign * dx > 0; break; + case PushDirection.Down: keep = sign * dx > 0; break; + default: keep = true; break; + } + + if (keep) + lines.Add(new Line(last, current)); + + last = current; + } + + return lines; + } + /// /// Finds the distance from a vertex to a line segment along a push axis. /// Returns double.MaxValue if the ray does not hit the segment. @@ -803,7 +878,9 @@ namespace OpenNest var ix = p1.X + t * (p2.X - p1.X); var dist = vertex.X - ix; // positive if edge is to the left - return dist > Tolerance.Epsilon ? dist : double.MaxValue; + if (dist > Tolerance.Epsilon) return dist; + if (dist >= -Tolerance.Epsilon) return 0; // touching + return double.MaxValue; // edge is behind vertex } case PushDirection.Right: @@ -817,7 +894,9 @@ namespace OpenNest var ix = p1.X + t * (p2.X - p1.X); var dist = ix - vertex.X; - return dist > Tolerance.Epsilon ? dist : double.MaxValue; + if (dist > Tolerance.Epsilon) return dist; + if (dist >= -Tolerance.Epsilon) return 0; // touching + return double.MaxValue; // edge is behind vertex } case PushDirection.Down: @@ -832,7 +911,9 @@ namespace OpenNest var iy = p1.Y + t * (p2.Y - p1.Y); var dist = vertex.Y - iy; - return dist > Tolerance.Epsilon ? dist : double.MaxValue; + if (dist > Tolerance.Epsilon) return dist; + if (dist >= -Tolerance.Epsilon) return 0; // touching + return double.MaxValue; // edge is behind vertex } case PushDirection.Up: @@ -846,7 +927,9 @@ namespace OpenNest var iy = p1.Y + t * (p2.Y - p1.Y); var dist = iy - vertex.Y; - return dist > Tolerance.Epsilon ? dist : double.MaxValue; + if (dist > Tolerance.Epsilon) return dist; + if (dist >= -Tolerance.Epsilon) return 0; // touching + return double.MaxValue; // edge is behind vertex } default: @@ -872,6 +955,9 @@ namespace OpenNest { var d = RayEdgeDistance(movingLine.StartPoint, stationaryLines[j], direction); if (d < minDist) minDist = d; + + d = RayEdgeDistance(movingLine.EndPoint, stationaryLines[j], direction); + if (d < minDist) minDist = d; } } @@ -886,13 +972,16 @@ namespace OpenNest { var d = RayEdgeDistance(stationaryLine.StartPoint, movingLines[j], opposite); if (d < minDist) minDist = d; + + d = RayEdgeDistance(stationaryLine.EndPoint, movingLines[j], opposite); + if (d < minDist) minDist = d; } } return minDist; } - private static PushDirection OppositeDirection(PushDirection direction) + public static PushDirection OppositeDirection(PushDirection direction) { switch (direction) { diff --git a/OpenNest/Controls/PlateView.cs b/OpenNest/Controls/PlateView.cs index d2d0429..d5938a4 100644 --- a/OpenNest/Controls/PlateView.cs +++ b/OpenNest/Controls/PlateView.cs @@ -792,9 +792,11 @@ namespace OpenNest.Controls var stationaryLines = new List>(stationaryParts.Count); var stationaryBoxes = new List(stationaryParts.Count); + var opposite = Helper.OppositeDirection(direction); + foreach (var part in stationaryParts) { - stationaryLines.Add(Helper.GetPartLines(part.BasePart)); + stationaryLines.Add(Helper.GetPartLines(part.BasePart, opposite)); stationaryBoxes.Add(part.BoundingBox); } @@ -805,8 +807,8 @@ namespace OpenNest.Controls { // Get offset lines for the moving part. var movingLines = Plate.PartSpacing > 0 - ? Helper.GetOffsetPartLines(selected.BasePart, Plate.PartSpacing) - : Helper.GetPartLines(selected.BasePart); + ? Helper.GetOffsetPartLines(selected.BasePart, Plate.PartSpacing, direction) + : Helper.GetPartLines(selected.BasePart, direction); var movingBox = selected.BoundingBox;