fix(ui): cache offset paths and scale temp parts on zoom
Cache offset polygon geometry on LayoutPart so DrawOffset no longer recomputes the expensive offset pipeline every paint cycle. The costly OffsetEntity/ToPolygonWithTolerance/RemoveSelfIntersections chain now runs only when rotation, spacing, or tolerance actually changes. Also update temporary parts in UpdateMatrix() so preview parts during nesting scale correctly with zoom. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -12,7 +12,6 @@ using System.Windows.Forms;
|
||||
using OpenNest.Actions;
|
||||
using OpenNest.CNC;
|
||||
using OpenNest.Collections;
|
||||
using OpenNest.Converters;
|
||||
using OpenNest.Forms;
|
||||
using OpenNest.Geometry;
|
||||
using OpenNest.Math;
|
||||
@@ -512,37 +511,17 @@ namespace OpenNest.Controls
|
||||
{
|
||||
using (var offsetPen = new Pen(Color.FromArgb(120, 255, 100, 100)))
|
||||
{
|
||||
for (int i = 0; i < parts.Count; i++)
|
||||
for (var i = 0; i < parts.Count; i++)
|
||||
{
|
||||
var part = parts[i].BasePart;
|
||||
var entities = ConvertProgram.ToGeometry(part.Program);
|
||||
var shapes = Helper.GetShapes(entities.Where(e => e.Layer != SpecialLayers.Rapid));
|
||||
var layoutPart = parts[i];
|
||||
|
||||
foreach (var shape in shapes)
|
||||
{
|
||||
var offsetEntity = shape.OffsetEntity(Plate.PartSpacing, OffsetSide.Left) as Shape;
|
||||
if (layoutPart.IsDirty)
|
||||
layoutPart.Update(this);
|
||||
|
||||
if (offsetEntity == null)
|
||||
continue;
|
||||
layoutPart.UpdateOffset(Plate.PartSpacing, OffsetTolerance, Matrix);
|
||||
|
||||
var polygon = offsetEntity.ToPolygonWithTolerance(OffsetTolerance);
|
||||
polygon.RemoveSelfIntersections();
|
||||
polygon.Offset(part.Location);
|
||||
|
||||
if (polygon.Vertices.Count < 2)
|
||||
continue;
|
||||
|
||||
var pts = new PointF[polygon.Vertices.Count];
|
||||
|
||||
for (int j = 0; j < pts.Length; j++)
|
||||
pts[j] = new PointF((float)polygon.Vertices[j].X, (float)polygon.Vertices[j].Y);
|
||||
|
||||
var path = new GraphicsPath();
|
||||
path.AddLines(pts);
|
||||
path.Transform(Matrix);
|
||||
g.DrawPath(offsetPen, path);
|
||||
path.Dispose();
|
||||
}
|
||||
if (layoutPart.OffsetPath != null)
|
||||
g.DrawPath(offsetPen, layoutPart.OffsetPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1090,6 +1069,7 @@ namespace OpenNest.Controls
|
||||
{
|
||||
base.UpdateMatrix();
|
||||
parts.ForEach(p => p.Update(this));
|
||||
temporaryParts.ForEach(p => p.Update(this));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
using System.Drawing;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Linq;
|
||||
using System.Windows.Forms;
|
||||
using OpenNest.Controls;
|
||||
using OpenNest.Converters;
|
||||
using OpenNest.Geometry;
|
||||
|
||||
namespace OpenNest
|
||||
@@ -17,6 +20,11 @@ namespace OpenNest
|
||||
private Brush brush;
|
||||
private Pen pen;
|
||||
|
||||
private List<PointF[]> _offsetPolygonPoints;
|
||||
private double _cachedOffsetSpacing;
|
||||
private double _cachedOffsetTolerance;
|
||||
private double _cachedOffsetRotation = double.NaN;
|
||||
|
||||
public readonly Part BasePart;
|
||||
|
||||
static LayoutPart()
|
||||
@@ -92,6 +100,8 @@ namespace OpenNest
|
||||
g.DrawString(id, programIdFont, Brushes.Black, pt.X, pt.Y);
|
||||
}
|
||||
|
||||
public GraphicsPath OffsetPath { get; private set; }
|
||||
|
||||
public void Update(DrawControl plateView)
|
||||
{
|
||||
Path = GraphicsHelper.GetGraphicsPath(BasePart.Program, BasePart.Location);
|
||||
@@ -99,6 +109,86 @@ namespace OpenNest
|
||||
IsDirty = false;
|
||||
}
|
||||
|
||||
public void UpdateOffset(double spacing, double tolerance, Matrix matrix)
|
||||
{
|
||||
if (_offsetPolygonPoints == null ||
|
||||
spacing != _cachedOffsetSpacing ||
|
||||
tolerance != _cachedOffsetTolerance ||
|
||||
BasePart.Rotation != _cachedOffsetRotation)
|
||||
{
|
||||
_offsetPolygonPoints = ComputeOffsetPolygons(spacing, tolerance);
|
||||
_cachedOffsetSpacing = spacing;
|
||||
_cachedOffsetTolerance = tolerance;
|
||||
_cachedOffsetRotation = BasePart.Rotation;
|
||||
}
|
||||
|
||||
RebuildOffsetPath(matrix);
|
||||
}
|
||||
|
||||
public void InvalidateOffset()
|
||||
{
|
||||
_offsetPolygonPoints = null;
|
||||
}
|
||||
|
||||
private List<PointF[]> ComputeOffsetPolygons(double spacing, double tolerance)
|
||||
{
|
||||
var result = new List<PointF[]>();
|
||||
var entities = ConvertProgram.ToGeometry(BasePart.Program);
|
||||
var shapes = Helper.GetShapes(entities.Where(e => e.Layer != SpecialLayers.Rapid));
|
||||
|
||||
foreach (var shape in shapes)
|
||||
{
|
||||
var offsetEntity = shape.OffsetEntity(spacing, OffsetSide.Left) as Shape;
|
||||
|
||||
if (offsetEntity == null)
|
||||
continue;
|
||||
|
||||
var polygon = offsetEntity.ToPolygonWithTolerance(tolerance);
|
||||
polygon.RemoveSelfIntersections();
|
||||
|
||||
if (polygon.Vertices.Count < 2)
|
||||
continue;
|
||||
|
||||
var pts = new PointF[polygon.Vertices.Count];
|
||||
|
||||
for (var j = 0; j < pts.Length; j++)
|
||||
pts[j] = new PointF((float)polygon.Vertices[j].X, (float)polygon.Vertices[j].Y);
|
||||
|
||||
result.Add(pts);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private void RebuildOffsetPath(Matrix matrix)
|
||||
{
|
||||
OffsetPath?.Dispose();
|
||||
|
||||
if (_offsetPolygonPoints == null || _offsetPolygonPoints.Count == 0)
|
||||
{
|
||||
OffsetPath = null;
|
||||
return;
|
||||
}
|
||||
|
||||
var path = new GraphicsPath();
|
||||
var dx = (float)BasePart.Location.X;
|
||||
var dy = (float)BasePart.Location.Y;
|
||||
|
||||
foreach (var pts in _offsetPolygonPoints)
|
||||
{
|
||||
var offsetPts = new PointF[pts.Length];
|
||||
|
||||
for (var i = 0; i < pts.Length; i++)
|
||||
offsetPts[i] = new PointF(pts[i].X + dx, pts[i].Y + dy);
|
||||
|
||||
path.AddLines(offsetPts);
|
||||
path.StartFigure();
|
||||
}
|
||||
|
||||
path.Transform(matrix);
|
||||
OffsetPath = path;
|
||||
}
|
||||
|
||||
public static LayoutPart Create(Part part, PlateView plateView)
|
||||
{
|
||||
var layoutPart = new LayoutPart(part);
|
||||
|
||||
Reference in New Issue
Block a user