refactor: extract PartGeometry from Helper
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -11,122 +11,6 @@ namespace OpenNest
|
|||||||
{
|
{
|
||||||
public static class Helper
|
public static class Helper
|
||||||
{
|
{
|
||||||
public static List<Line> GetPartLines(Part part, double chordTolerance = 0.001)
|
|
||||||
{
|
|
||||||
var entities = ConvertProgram.ToGeometry(part.Program);
|
|
||||||
var shapes = ShapeBuilder.GetShapes(entities.Where(e => e.Layer != SpecialLayers.Rapid));
|
|
||||||
var lines = new List<Line>();
|
|
||||||
|
|
||||||
foreach (var shape in shapes)
|
|
||||||
{
|
|
||||||
var polygon = shape.ToPolygonWithTolerance(chordTolerance);
|
|
||||||
polygon.Offset(part.Location);
|
|
||||||
lines.AddRange(polygon.ToLines());
|
|
||||||
}
|
|
||||||
|
|
||||||
return lines;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static List<Line> GetPartLines(Part part, PushDirection facingDirection, double chordTolerance = 0.001)
|
|
||||||
{
|
|
||||||
var entities = ConvertProgram.ToGeometry(part.Program);
|
|
||||||
var shapes = ShapeBuilder.GetShapes(entities.Where(e => e.Layer != SpecialLayers.Rapid));
|
|
||||||
var lines = new List<Line>();
|
|
||||||
|
|
||||||
foreach (var shape in shapes)
|
|
||||||
{
|
|
||||||
var polygon = shape.ToPolygonWithTolerance(chordTolerance);
|
|
||||||
polygon.Offset(part.Location);
|
|
||||||
lines.AddRange(GetDirectionalLines(polygon, facingDirection));
|
|
||||||
}
|
|
||||||
|
|
||||||
return lines;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static List<Line> GetOffsetPartLines(Part part, double spacing, double chordTolerance = 0.001)
|
|
||||||
{
|
|
||||||
var entities = ConvertProgram.ToGeometry(part.Program);
|
|
||||||
var shapes = ShapeBuilder.GetShapes(entities.Where(e => e.Layer != SpecialLayers.Rapid));
|
|
||||||
var lines = new List<Line>();
|
|
||||||
|
|
||||||
foreach (var shape in shapes)
|
|
||||||
{
|
|
||||||
// Add chord tolerance to compensate for inscribed polygon chords
|
|
||||||
// being inside the actual offset arcs.
|
|
||||||
var offsetEntity = shape.OffsetEntity(spacing + chordTolerance, OffsetSide.Left) as Shape;
|
|
||||||
|
|
||||||
if (offsetEntity == null)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var polygon = offsetEntity.ToPolygonWithTolerance(chordTolerance);
|
|
||||||
polygon.RemoveSelfIntersections();
|
|
||||||
polygon.Offset(part.Location);
|
|
||||||
lines.AddRange(polygon.ToLines());
|
|
||||||
}
|
|
||||||
|
|
||||||
return lines;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static List<Line> GetOffsetPartLines(Part part, double spacing, PushDirection facingDirection, double chordTolerance = 0.001)
|
|
||||||
{
|
|
||||||
var entities = ConvertProgram.ToGeometry(part.Program);
|
|
||||||
var shapes = ShapeBuilder.GetShapes(entities.Where(e => e.Layer != SpecialLayers.Rapid));
|
|
||||||
var lines = new List<Line>();
|
|
||||||
|
|
||||||
foreach (var shape in shapes)
|
|
||||||
{
|
|
||||||
var offsetEntity = shape.OffsetEntity(spacing + chordTolerance, OffsetSide.Left) as Shape;
|
|
||||||
|
|
||||||
if (offsetEntity == null)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var polygon = offsetEntity.ToPolygonWithTolerance(chordTolerance);
|
|
||||||
polygon.RemoveSelfIntersections();
|
|
||||||
polygon.Offset(part.Location);
|
|
||||||
lines.AddRange(GetDirectionalLines(polygon, facingDirection));
|
|
||||||
}
|
|
||||||
|
|
||||||
return lines;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns only polygon edges whose outward normal faces the specified direction.
|
|
||||||
/// </summary>
|
|
||||||
private static List<Line> 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<Line>();
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Finds the distance from a vertex to a line segment along a push axis.
|
/// 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.
|
/// Returns double.MaxValue if the ray does not hit the segment.
|
||||||
|
|||||||
126
OpenNest.Core/PartGeometry.cs
Normal file
126
OpenNest.Core/PartGeometry.cs
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using OpenNest.Converters;
|
||||||
|
using OpenNest.Geometry;
|
||||||
|
|
||||||
|
namespace OpenNest
|
||||||
|
{
|
||||||
|
public static class PartGeometry
|
||||||
|
{
|
||||||
|
public static List<Line> GetPartLines(Part part, double chordTolerance = 0.001)
|
||||||
|
{
|
||||||
|
var entities = ConvertProgram.ToGeometry(part.Program);
|
||||||
|
var shapes = ShapeBuilder.GetShapes(entities.Where(e => e.Layer != SpecialLayers.Rapid));
|
||||||
|
var lines = new List<Line>();
|
||||||
|
|
||||||
|
foreach (var shape in shapes)
|
||||||
|
{
|
||||||
|
var polygon = shape.ToPolygonWithTolerance(chordTolerance);
|
||||||
|
polygon.Offset(part.Location);
|
||||||
|
lines.AddRange(polygon.ToLines());
|
||||||
|
}
|
||||||
|
|
||||||
|
return lines;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<Line> GetPartLines(Part part, PushDirection facingDirection, double chordTolerance = 0.001)
|
||||||
|
{
|
||||||
|
var entities = ConvertProgram.ToGeometry(part.Program);
|
||||||
|
var shapes = ShapeBuilder.GetShapes(entities.Where(e => e.Layer != SpecialLayers.Rapid));
|
||||||
|
var lines = new List<Line>();
|
||||||
|
|
||||||
|
foreach (var shape in shapes)
|
||||||
|
{
|
||||||
|
var polygon = shape.ToPolygonWithTolerance(chordTolerance);
|
||||||
|
polygon.Offset(part.Location);
|
||||||
|
lines.AddRange(GetDirectionalLines(polygon, facingDirection));
|
||||||
|
}
|
||||||
|
|
||||||
|
return lines;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<Line> GetOffsetPartLines(Part part, double spacing, double chordTolerance = 0.001)
|
||||||
|
{
|
||||||
|
var entities = ConvertProgram.ToGeometry(part.Program);
|
||||||
|
var shapes = ShapeBuilder.GetShapes(entities.Where(e => e.Layer != SpecialLayers.Rapid));
|
||||||
|
var lines = new List<Line>();
|
||||||
|
|
||||||
|
foreach (var shape in shapes)
|
||||||
|
{
|
||||||
|
// Add chord tolerance to compensate for inscribed polygon chords
|
||||||
|
// being inside the actual offset arcs.
|
||||||
|
var offsetEntity = shape.OffsetEntity(spacing + chordTolerance, OffsetSide.Left) as Shape;
|
||||||
|
|
||||||
|
if (offsetEntity == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var polygon = offsetEntity.ToPolygonWithTolerance(chordTolerance);
|
||||||
|
polygon.RemoveSelfIntersections();
|
||||||
|
polygon.Offset(part.Location);
|
||||||
|
lines.AddRange(polygon.ToLines());
|
||||||
|
}
|
||||||
|
|
||||||
|
return lines;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<Line> GetOffsetPartLines(Part part, double spacing, PushDirection facingDirection, double chordTolerance = 0.001)
|
||||||
|
{
|
||||||
|
var entities = ConvertProgram.ToGeometry(part.Program);
|
||||||
|
var shapes = ShapeBuilder.GetShapes(entities.Where(e => e.Layer != SpecialLayers.Rapid));
|
||||||
|
var lines = new List<Line>();
|
||||||
|
|
||||||
|
foreach (var shape in shapes)
|
||||||
|
{
|
||||||
|
var offsetEntity = shape.OffsetEntity(spacing + chordTolerance, OffsetSide.Left) as Shape;
|
||||||
|
|
||||||
|
if (offsetEntity == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var polygon = offsetEntity.ToPolygonWithTolerance(chordTolerance);
|
||||||
|
polygon.RemoveSelfIntersections();
|
||||||
|
polygon.Offset(part.Location);
|
||||||
|
lines.AddRange(GetDirectionalLines(polygon, facingDirection));
|
||||||
|
}
|
||||||
|
|
||||||
|
return lines;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns only polygon edges whose outward normal faces the specified direction.
|
||||||
|
/// </summary>
|
||||||
|
private static List<Line> 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<Line>();
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -34,8 +34,8 @@ namespace OpenNest.Engine.BestFit
|
|||||||
var part2Template = Part.CreateAtOrigin(drawing, Part2Rotation);
|
var part2Template = Part.CreateAtOrigin(drawing, Part2Rotation);
|
||||||
|
|
||||||
var halfSpacing = spacing / 2;
|
var halfSpacing = spacing / 2;
|
||||||
var part1Lines = Helper.GetOffsetPartLines(part1, halfSpacing);
|
var part1Lines = PartGeometry.GetOffsetPartLines(part1, halfSpacing);
|
||||||
var part2TemplateLines = Helper.GetOffsetPartLines(part2Template, halfSpacing);
|
var part2TemplateLines = PartGeometry.GetOffsetPartLines(part2Template, halfSpacing);
|
||||||
|
|
||||||
var bbox1 = part1.BoundingBox;
|
var bbox1 = part1.BoundingBox;
|
||||||
var bbox2 = part2Template.BoundingBox;
|
var bbox2 = part2Template.BoundingBox;
|
||||||
|
|||||||
@@ -129,12 +129,12 @@ namespace OpenNest
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
movingLines ??= halfSpacing > 0
|
movingLines ??= halfSpacing > 0
|
||||||
? Helper.GetOffsetPartLines(moving, halfSpacing, direction, ChordTolerance)
|
? PartGeometry.GetOffsetPartLines(moving, halfSpacing, direction, ChordTolerance)
|
||||||
: Helper.GetPartLines(moving, direction, ChordTolerance);
|
: PartGeometry.GetPartLines(moving, direction, ChordTolerance);
|
||||||
|
|
||||||
obstacleLines[i] ??= halfSpacing > 0
|
obstacleLines[i] ??= halfSpacing > 0
|
||||||
? Helper.GetOffsetPartLines(obstacleParts[i], halfSpacing, opposite, ChordTolerance)
|
? PartGeometry.GetOffsetPartLines(obstacleParts[i], halfSpacing, opposite, ChordTolerance)
|
||||||
: Helper.GetPartLines(obstacleParts[i], opposite, ChordTolerance);
|
: PartGeometry.GetPartLines(obstacleParts[i], opposite, ChordTolerance);
|
||||||
|
|
||||||
var d = Helper.DirectionalDistance(movingLines, obstacleLines[i], direction);
|
var d = Helper.DirectionalDistance(movingLines, obstacleLines[i], direction);
|
||||||
if (d < distance)
|
if (d < distance)
|
||||||
|
|||||||
Reference in New Issue
Block a user