GPU factory logic belongs with the GPU implementation, not the UI. Changed from internal to public and updated namespace to OpenNest.Gpu. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
206 lines
6.0 KiB
C#
206 lines
6.0 KiB
C#
using System.Collections.Generic;
|
|
using System.ComponentModel;
|
|
using System.Linq;
|
|
using System.Windows.Forms;
|
|
using OpenNest.Controls;
|
|
using OpenNest.Geometry;
|
|
using OpenNest.Gpu;
|
|
|
|
namespace OpenNest.Actions
|
|
{
|
|
[DisplayName("Clone Parts")]
|
|
public class ActionClone : Action
|
|
{
|
|
private readonly List<LayoutPart> parts;
|
|
|
|
private double lastScale;
|
|
|
|
public ActionClone(PlateView plateView, Drawing drawing)
|
|
: this(plateView, new List<Part> { new Part(drawing) })
|
|
{
|
|
}
|
|
|
|
public ActionClone(PlateView plateView, List<Part> partsToClone)
|
|
: base(plateView)
|
|
{
|
|
plateView.KeyDown += plateView_KeyDown;
|
|
plateView.MouseMove += plateView_MouseMove;
|
|
plateView.MouseDown += plateView_MouseDown;
|
|
plateView.Paint += plateView_Paint;
|
|
|
|
parts = new List<LayoutPart>();
|
|
lastScale = double.NaN;
|
|
|
|
for (int i = 0; i < partsToClone.Count; i++)
|
|
{
|
|
var part = LayoutPart.Create(partsToClone[i].Clone() as Part, plateView);
|
|
part.IsSelected = true;
|
|
parts.Add(part);
|
|
}
|
|
|
|
plateView.SelectedParts.Clear();
|
|
plateView.SelectedParts.AddRange(parts);
|
|
}
|
|
|
|
private void plateView_MouseDown(object sender, MouseEventArgs e)
|
|
{
|
|
switch (e.Button)
|
|
{
|
|
case MouseButtons.Left:
|
|
Apply();
|
|
break;
|
|
}
|
|
}
|
|
|
|
private void plateView_KeyDown(object sender, KeyEventArgs e)
|
|
{
|
|
switch (e.KeyCode)
|
|
{
|
|
case Keys.F1:
|
|
case Keys.Enter:
|
|
Apply();
|
|
break;
|
|
|
|
case Keys.F:
|
|
if ((Control.ModifierKeys & Keys.Control) == Keys.Control)
|
|
Fill();
|
|
break;
|
|
}
|
|
}
|
|
|
|
private void plateView_Paint(object sender, PaintEventArgs e)
|
|
{
|
|
if (plateView.ViewScale != lastScale)
|
|
{
|
|
parts.ForEach(p =>
|
|
{
|
|
p.Update(plateView);
|
|
p.Draw(e.Graphics);
|
|
});
|
|
}
|
|
else
|
|
{
|
|
parts.ForEach(p =>
|
|
{
|
|
if (p.IsDirty)
|
|
p.Update(plateView);
|
|
|
|
p.Draw(e.Graphics);
|
|
});
|
|
}
|
|
|
|
lastScale = plateView.ViewScale;
|
|
}
|
|
|
|
private void plateView_MouseMove(object sender, MouseEventArgs e)
|
|
{
|
|
var offset = plateView.CurrentPoint - parts.GetBoundingBox().Location;
|
|
parts.ForEach(p => p.Offset(offset));
|
|
plateView.Invalidate();
|
|
}
|
|
|
|
public override bool SurvivesPlateChange => true;
|
|
|
|
public override void OnPlateChanged()
|
|
{
|
|
plateView.SelectedParts.Clear();
|
|
plateView.SelectedParts.AddRange(parts);
|
|
}
|
|
|
|
public override void ConnectEvents()
|
|
{
|
|
plateView.KeyDown += plateView_KeyDown;
|
|
plateView.MouseMove += plateView_MouseMove;
|
|
plateView.MouseDown += plateView_MouseDown;
|
|
plateView.Paint += plateView_Paint;
|
|
|
|
plateView.SelectedParts.Clear();
|
|
plateView.SelectedParts.AddRange(parts);
|
|
}
|
|
|
|
public override void DisconnectEvents()
|
|
{
|
|
plateView.KeyDown -= plateView_KeyDown;
|
|
plateView.MouseMove -= plateView_MouseMove;
|
|
plateView.MouseDown -= plateView_MouseDown;
|
|
plateView.Paint -= plateView_Paint;
|
|
|
|
plateView.SelectedParts.Clear();
|
|
plateView.Invalidate();
|
|
}
|
|
|
|
public override void CancelAction()
|
|
{
|
|
}
|
|
|
|
public override bool IsBusy()
|
|
{
|
|
return false;
|
|
}
|
|
|
|
public void Apply()
|
|
{
|
|
if ((Control.ModifierKeys & Keys.Shift) == Keys.Shift)
|
|
{
|
|
switch (plateView.Plate.Quadrant)
|
|
{
|
|
case 1:
|
|
plateView.PushSelected(PushDirection.Left);
|
|
plateView.PushSelected(PushDirection.Down);
|
|
break;
|
|
|
|
case 2:
|
|
plateView.PushSelected(PushDirection.Right);
|
|
plateView.PushSelected(PushDirection.Down);
|
|
break;
|
|
|
|
case 3:
|
|
plateView.PushSelected(PushDirection.Right);
|
|
plateView.PushSelected(PushDirection.Up);
|
|
break;
|
|
|
|
case 4:
|
|
plateView.PushSelected(PushDirection.Left);
|
|
plateView.PushSelected(PushDirection.Up);
|
|
break;
|
|
}
|
|
}
|
|
|
|
parts.ForEach(p => plateView.Plate.Parts.Add(p.BasePart.Clone() as Part));
|
|
}
|
|
|
|
private void Fill()
|
|
{
|
|
var plate = plateView.Plate;
|
|
var engine = new NestEngine(plate);
|
|
engine.CreateEvaluator = GpuEvaluatorFactory.Create;
|
|
var groupParts = parts.Select(p => p.BasePart).ToList();
|
|
|
|
var bounds = plate.WorkArea();
|
|
|
|
if (plate.Parts.Count == 0)
|
|
{
|
|
engine.Fill(groupParts);
|
|
return;
|
|
}
|
|
|
|
var boxes = new List<Box>();
|
|
foreach (var part in plate.Parts)
|
|
boxes.Add(part.BoundingBox.Offset(plate.PartSpacing));
|
|
|
|
var pt = plateView.CurrentPoint;
|
|
var vertical = Helper.GetLargestBoxVertically(pt, bounds, boxes);
|
|
var horizontal = Helper.GetLargestBoxHorizontally(pt, bounds, boxes);
|
|
|
|
var bestArea = vertical;
|
|
if (horizontal.Area() > vertical.Area())
|
|
bestArea = horizontal;
|
|
|
|
if (bestArea == Box.Empty)
|
|
return;
|
|
|
|
engine.Fill(groupParts, bestArea);
|
|
}
|
|
}
|
|
}
|