Loading files
This file is pinned to the selected release. Download the original to open it in your design tool.
using ClipperLib;
using GerberLibrary;
using GerberLibrary.Core;
using GerberLibrary.Core.Primitives;
using OpenTK;
using OpenTK.Graphics.OpenGL;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Xml.Serialization;
namespace GerberCombinerBuilder
{
public partial class GerberPanelize : Form
{
GerberPanelizerParent ParentFrame;
Thread ExportThread;
String ExportFolder;
Progress ProgressDialog;
bool MouseCapture = false;
PointD DragStartCoord = new PointD();
PointD DragInstanceOriginalPosition = new PointD();
PointD ContextStartCoord = new PointD();
bool Panning = false;
PointD PanStartPoint = new PointD(0, 0);
// Selection
public List<AngledThing> SelectedInstances = new List<AngledThing>();
private Dictionary<AngledThing, PointD> DragOriginalPositions = new Dictionary<AngledThing, PointD>();
private bool IsBoxSelecting = false;
private PointD BoxSelectStart = new PointD();
private PointD BoxSelectCurrent = new PointD();
private float DrawingScale;
public double Zoom = 1;
public double TargetZoom = 1;
public PointD CenterPoint = new PointD(0, 0);
// Undo/Redo
public List<string> UndoStack = new List<string>();
public List<string> RedoStack = new List<string>();
private string PendingUndoState = null;
enum SnapMode
{
Mil100,
Mil50,
MM1,
MM05,
Off
}
SnapMode CurrentSnapMode = SnapMode.Off;
public string LoadedFile = "";
private AngledThing HoverShape = null;
public GerberPanel ThePanel = new GerberPanel();
Treeview TV;
public AngledThing SelectedInstance;
InstanceDialog ID;
public GerberPanelize(GerberPanelizerParent Host, Treeview tv, InstanceDialog id)
{
ParentFrame = Host;
Gerber.ArcQualityScaleFactor = 20;
InitializeComponent();
glControl1.MouseWheel += glControl1_MouseWheel;
RotateLeftHover.Visible = false;
RotateRightHover.Visible = false;
UpdateAutoProcessButton();
UpdateSnapBox(SnapMode.MM1);
// AddGerberFolder(@"C:\Projects\Circuits\50pcs 5x5cm green 1.6mm - goaoma");
// TheSet.Tabs.Add(new BreakTab() { Radius = 5, Angle = 10, Center = new PointF(50,50) });
TV = tv;
ID = id;
TV.BuildTree(this, ThePanel.TheSet);
DrawingScale = Math.Min(glControl1.Width, glControl1.Height) / 110.0f;
ZoomToFit();
BuildTitle();
// LoadFile(@"C:\Projects\Circuits\panelsets\RackPanel-Frame\innerframetest.gerberset");
}
void BuildTitle()
{
this.Text = "Set: " + BaseName;
}
//private void pictureBox1_Paint(object sender, PaintEventArgs e)
//{
// e.Graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.High;
// e.Graphics.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
// e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
// Aspect = pictureBox1.Width / pictureBox1.Height;
// DrawingScale = Math.Min(pictureBox1.Width, pictureBox1.Height) / 110.0f;
// e.Graphics.TranslateTransform(0, pictureBox1.Height);
// e.Graphics.ScaleTransform(DrawingScale, -DrawingScale);
// e.Graphics.TranslateTransform(5, 5);
// ThePanel.DrawBoardBitmap(1.0f / DrawingScale, new GraphicsGraphicsInterface(e.Graphics), pictureBox1.Width, pictureBox1.Height, SelectedInstance);
// // e.Graphics.DrawImage(BoardBitmap, 0, 0, pictureBox1.Width, pictureBox1.Height);
//}
PointD MMToMouse(PointD MM)
{
PointD P = new PointD(MM.X, MM.Y);
P.X -= (float)CenterPoint.X;
P.Y -= (float)CenterPoint.Y;
P.X *= (float)Zoom;
P.Y *= (float)Zoom;
P.Y *= -1;
P.X += glControl1.Width / 2;
P.Y += glControl1.Height / 2;
return P;
}
PointD MouseToMM(PointD Mouse)
{
PointD P = new PointD(Mouse.X, Mouse.Y);
P.X -= glControl1.Width / 2;
P.Y -= glControl1.Height / 2;
P.Y *= -1;
P.X /= (float)Zoom;
P.Y /= (float)Zoom;
P.X += (float)CenterPoint.X;
P.Y += (float)CenterPoint.Y;
return P;
}
public void UpdateHoverControls()
{
return;
// todo -> redo these in pure GL.. windows controls interfere too much with the drawing resulting in glitches.
if (SelectedInstance != null)
{
GerberInstance GI = SelectedInstance as GerberInstance;
if (GI == null)
{
RotateLeftHover.Visible = false;
RotateRightHover.Visible = false;
}
else
{
RotateLeftHover.Visible = true;
RotateRightHover.Visible = true;
var TL = MMToMouse(GI.BoundingBox.TopLeft);
var BR = MMToMouse(GI.BoundingBox.BottomRight);
int W = RotateLeftHover.Width;
int H = RotateLeftHover.Height;
RotateLeftHover.Top = Math.Max(0, Math.Min(glControl1.Height - H, (int)(TL.Y - RotateLeftHover.Height)));
RotateLeftHover.Left = Math.Max(0, Math.Min(glControl1.Width - W, (int)(TL.X - RotateLeftHover.Width)));
RotateRightHover.Top = Math.Max(0, Math.Min(glControl1.Height - H, (int)(TL.Y - RotateLeftHover.Height)));
RotateRightHover.Left = Math.Max(0, Math.Min(glControl1.Width - W, (int)(BR.X + 1)));
}
}
else
{
RotateLeftHover.Visible = false;
RotateRightHover.Visible = false;
}
}
internal void SetSelectedInstance(AngledThing gerberInstance)
{
SelectedInstance = gerberInstance;
UpdateHoverControls();
ID.UpdateBoxes(this);
Redraw(false);
}
private string BaseName = "Untitled";
private bool ShapeMarkedForUpdate = true;
private bool ForceShapeUpdate = false;
internal void Redraw(bool refreshshape = true, bool force = false)
{
if (SuspendRedraw) return;
if (force) ForceShapeUpdate = true;
if (refreshshape)
{
ShapeMarkedForUpdate = true;
ProcessButton.Enabled = true;
}
glControl1.Invalidate();
}
private void Form1_SizeChanged(object sender, EventArgs e)
{
UpdateScrollers();
Redraw(false);
}
private void loadToolStripMenuItem_Click(object sender, EventArgs e)
{
if (openFileDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
string filename = openFileDialog1.FileName;
LoadFile(filename);
}
}
public void LoadFile(string filename)
{
LoadedFile = filename;
ThePanel.LoadFile(new StandardConsoleLog(), filename);
ThePanel.UpdateShape(new StandardConsoleLog());
TV.BuildTree(this, ThePanel.TheSet);
ZoomToFit();
Redraw(false);
BaseName = Path.GetFileNameWithoutExtension(filename);
BuildTitle();
}
private void saveToolStripMenuItem_Click(object sender, EventArgs e)
{
if (saveFileDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
string FileName = saveFileDialog1.FileName;
SaveFile(FileName);
}
}
private void newToolStripMenuItem_Click(object sender, EventArgs e)
{
SelectedInstance = null;
HoverShape = null;
ThePanel = new GerberPanel();
TV.BuildTree(this, ThePanel.TheSet);
Redraw(true);
}
private void AddTab(PointD center)
{
var BT = ThePanel.AddTab(MouseToMM(center));
TV.BuildTree(this, ThePanel.TheSet);
SetSelectedInstance(BT);
Redraw(true);
}
public void exportAllGerbersToolStripMenuItem_Click(object sender, EventArgs e)
{
try
{
folderBrowserDialog2.SelectedPath = ThePanel.TheSet.LastExportFolder;
}
catch (Exception)
{
}
if (folderBrowserDialog2.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
ExportFolder = folderBrowserDialog2.SelectedPath;
ProgressDialog = new Progress(this);
ProgressDialog.Show();
Enabled = false;
ParentFrame.Enabled = false;
ExportThread = new Thread(new ThreadStart(ExportThreadFunc));
ExportThread.Start();
}
}
public class ProgressForward : GerberLibrary.ProgressLog
{
public Progress parent;
public ProgressForward(Progress p)
{
parent = p;
}
public override void AddString(string text, float progress = -1)
{
parent.AddString(text, progress);
}
}
public void ExportThreadFunc()
{
ThePanel.SaveGerbersToFolder(BaseName, ExportFolder, new ProgressForward(ProgressDialog), ThePanel.TheSet.CopyOutlineToTopSilkscreen,true,true, true, BaseName+"_combined");
}
internal void ProcessDone()
{
this.Enabled = true;
ParentFrame.Enabled = true;
ProgressDialog.Close();
ProgressDialog.Dispose();
ProgressDialog = null;
}
private void GerberPanelize_Activated(object sender, EventArgs e)
{
ID.UpdateBoxes(this);
TV.BuildTree(this, ThePanel.TheSet);
ParentFrame.ActivatePanelizer(this);
}
private void GerberPanelize_FormClosed(object sender, FormClosedEventArgs e)
{
ParentFrame.RemovePanelizer();
}
private void GerberPanelize_Load(object sender, EventArgs e)
{
this.WindowState = FormWindowState.Maximized;
}
internal void AddInstance(string path, PointD coord)
{
SetSelectedInstance(ThePanel.AddInstance(path, MouseToMM(coord)));
CheckAndResizeCanvas();
TV.BuildTree(this, ThePanel.TheSet);
Redraw(true);
}
internal void RemoveInstance(AngledThing angledThing)
{
if (SelectedInstance == angledThing)
{
SetSelectedInstance(null);
}
if (HoverShape == angledThing)
{
HoverShape = null;
}
ThePanel.RemoveInstance(angledThing);
TV.BuildTree(this, ThePanel.TheSet);
ThePanel.UpdateShape(new StandardConsoleLog());
Redraw(true, true);
}
internal void SaveFile(string FileName)
{
ThePanel.SaveFile(FileName);
BaseName = Path.GetFileNameWithoutExtension(FileName);
BuildTitle();
LoadedFile = FileName;
}
private void DoMouseDown(MouseEventArgs e)
{
if (e.Button == MouseButtons.Middle)
{
Panning = true;
PanStartPoint = new PointD(e.X, e.Y);
}
if (e.Button == System.Windows.Forms.MouseButtons.Left)
{
var clickedInstance = ThePanel.FindOutlineUnderPoint(MouseToMM(new PointD(e.X, e.Y)));
if (clickedInstance != null)
{
if (ModifierKeys.HasFlag(Keys.Control))
{
if (SelectedInstances.Contains(clickedInstance))
{
SelectedInstances.Remove(clickedInstance);
SelectedInstance = SelectedInstances.LastOrDefault(); // or null
MouseCapture = false; // Don't drag if deselecting
}
else
{
SelectedInstances.Add(clickedInstance);
SelectedInstance = clickedInstance;
MouseCapture = true;
}
}
else
{
if (!SelectedInstances.Contains(clickedInstance))
{
SelectedInstances.Clear();
SelectedInstances.Add(clickedInstance);
}
// If it IS contained, we keep selection to allow dragging multiple
SelectedInstance = clickedInstance;
MouseCapture = true;
}
if (MouseCapture)
{
DragStartCoord = new PointD(e.X, e.Y);
DragOriginalPositions.Clear();
foreach(var inst in SelectedInstances)
{
DragOriginalPositions[inst] = new PointD(inst.Center.X, inst.Center.Y);
}
DragInstanceOriginalPosition = SelectedInstance.Center; // Legacy support
// Capture state for Undo if we actually move
try {
PendingUndoState = SerializeState();
} catch(Exception) { PendingUndoState = null; }
}
SetSelectedInstance(SelectedInstance);
}
else // Clicked on empty space
{
if (!ModifierKeys.HasFlag(Keys.Control))
{
SelectedInstances.Clear();
SetSelectedInstance(null);
}
IsBoxSelecting = true;
BoxSelectStart = new PointD(e.X, e.Y);
BoxSelectCurrent = new PointD(e.X, e.Y);
}
}
if (e.Button == System.Windows.Forms.MouseButtons.Right)
{
SelectedInstance = ThePanel.FindOutlineUnderPoint(MouseToMM(new PointD(e.X, e.Y)));
ContextStartCoord = new PointD(e.X, e.Y);
if (SelectedInstance != null)
{
if (!SelectedInstances.Contains(SelectedInstance))
{
SelectedInstances.Clear();
SelectedInstances.Add(SelectedInstance);
SetSelectedInstance(SelectedInstance);
}
contextMenuStrip2.Show(this, e.Location);
}
else
{
addInstanceToolStripMenuItem.DropDownItems.Clear();
foreach (var a in ThePanel.TheSet.LoadedOutlines)
{
addInstanceToolStripMenuItem.DropDownItems.Add(a, null, addinstance);
}
contextMenuStrip1.Show(this, e.Location);
}
SetSelectedInstance(SelectedInstance);
}
}
private void addinstance(object sender, EventArgs e)
{
ToolStripDropDownItem TSDDI = sender as ToolStripDropDownItem;
AddInstance(TSDDI.Text, ContextStartCoord);
//Console.WriteLine(sender.GetType().ToString());
}
private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
{
DoMouseUp(e);
}
private void DoMouseUp(MouseEventArgs e)
{
if (Panning && e.Button == MouseButtons.Middle)
{
Panning = false;
}
if (IsBoxSelecting && e.Button == MouseButtons.Left)
{
IsBoxSelecting = false;
// Calculate box in MM
PointD StartMM = MouseToMM(BoxSelectStart);
PointD EndMM = MouseToMM(BoxSelectCurrent);
double minX = Math.Min(StartMM.X, EndMM.X);
double maxX = Math.Max(StartMM.X, EndMM.X);
double minY = Math.Min(StartMM.Y, EndMM.Y);
double maxY = Math.Max(StartMM.Y, EndMM.Y);
Bounds selectionBounds = new Bounds();
selectionBounds.FitPoint(minX, minY);
selectionBounds.FitPoint(maxX, maxY);
if (!ModifierKeys.HasFlag(Keys.Control))
{
SelectedInstances.Clear();
}
foreach(var inst in ThePanel.TheSet.Instances)
{
if (selectionBounds.Contains(inst.Center))
{
if (!SelectedInstances.Contains(inst)) SelectedInstances.Add(inst);
}
}
foreach(var tab in ThePanel.TheSet.Tabs)
{
if (selectionBounds.Contains(tab.Center))
{
if (!SelectedInstances.Contains(tab)) SelectedInstances.Add(tab);
}
}
SelectedInstance = SelectedInstances.LastOrDefault();
SetSelectedInstance(SelectedInstance);
Redraw(false);
return; // Early return to skip Drag logic
}
if (MouseCapture)
{
MouseCapture = false;
PointD Delta = new PointD(e.X, e.Y) - DragStartCoord;
if (Delta.Length() == 0)
{
// Clicked, not dragged.
PendingUndoState = null; // discard
// Clicked, not dragged. Logic handled in MouseDown mostly.
// But if we were clicking on an already selected item without control, we might want to clear others?
// Standard behavior:
// Click on selected item -> MouseDown: keeps others selected (in case of drag).
// MouseUp: if no drag, clear others?
if (!ModifierKeys.HasFlag(Keys.Control))
{
if(SelectedInstance != null && SelectedInstances.Count > 1) {
SelectedInstances.Clear();
SelectedInstances.Add(SelectedInstance);
SetSelectedInstance(SelectedInstance);
}
}
Redraw(false);
}
else
{
// Dragged - Commit Undo
if (PendingUndoState != null)
{
UndoStack.Add(PendingUndoState);
if (UndoStack.Count > 20) UndoStack.RemoveAt(0);
RedoStack.Clear();
PendingUndoState = null;
}
// Dragged
bool fullRedraw = false;
foreach(var inst in SelectedInstances)
{
var GI = inst as GerberInstance;
if (GI != null)
{
GI.RebuildTransformed(ThePanel.GerberOutlines[GI.GerberPath], ThePanel.TheSet.ExtraTabDrillDistance);
fullRedraw = true;
}
if (inst is BreakTab)
{
fullRedraw = true;
}
}
if (SelectedInstance != null) ID.UpdateBoxes(this);
Redraw(fullRedraw);
}
}
}
PointD LastMouseMove = new PointD(0, 0);
public bool SuspendRedraw = false;
private void DoMouseMove(MouseEventArgs e)
{
LastMouseMove = new PointD(e.X, e.Y);
if (Panning)
{
PointD Current = new PointD(e.X, e.Y);
PointD Delta = Current - PanStartPoint;
CenterPoint.X -= Delta.X / Zoom;
CenterPoint.Y += Delta.Y / Zoom;
PanStartPoint = Current;
Redraw(false);
UpdateScrollers();
return;
}
if (IsBoxSelecting)
{
BoxSelectCurrent = new PointD(e.X, e.Y);
Redraw(false);
return;
}
if (MouseCapture && SelectedInstances.Count > 0)
{
PointD Delta = new PointD(e.X, e.Y) - DragStartCoord;
Delta.X /= Zoom;
Delta.Y /= -Zoom;
foreach(var inst in SelectedInstances)
{
if (DragOriginalPositions.ContainsKey(inst))
{
inst.Center = Snap(DragOriginalPositions[inst] + Delta);
}
}
if (SelectedInstance != null) {
UpdateHoverControls();
}
Redraw(false);
}
else
{
var newHoverShape = ThePanel.FindOutlineUnderPoint(MouseToMM(new PointD(e.X, e.Y)));
if (newHoverShape != HoverShape)
{
HoverShape = newHoverShape;
Redraw(false);
}
}
}
public double SnapDistance()
{
switch (CurrentSnapMode)
{
case SnapMode.MM1: return 1;
case SnapMode.MM05: return 0.5;
case SnapMode.Mil50: return 50 * (25.4 / 1000.0);
case SnapMode.Mil100: return 100 * (25.4 / 1000.0);
};
return -1;
}
public PointD Snap(PointD inp)
{
if (CurrentSnapMode == SnapMode.Off) return inp;
double multdiv = 1;
switch (CurrentSnapMode)
{
case SnapMode.MM1: break;
case SnapMode.MM05: multdiv = 2; break;
case SnapMode.Mil50: multdiv = 0.254 / 2.0; break;
case SnapMode.Mil100: multdiv = 0.254; break;
};
PointD Res = new PointD();
Res.X = Math.Floor(inp.X * multdiv) / multdiv;
Res.Y = Math.Floor(inp.Y * multdiv) / multdiv;
return Res;
}
private void deleteToolStripMenuItem_Click(object sender, EventArgs e)
{
if (SelectedInstance != null) RemoveInstance(SelectedInstance);
}
private void addBreakTabToolStripMenuItem_Click(object sender, EventArgs e)
{
AddTab(ContextStartCoord);
}
private void milToolStripMenuItem1_Click(object sender, EventArgs e)
{
UpdateSnapBox(SnapMode.Mil50);
}
private void UpdateSnapBox(SnapMode Mode)
{
string name = "none";
switch (Mode)
{
case SnapMode.Mil100: name = "100 mil"; break;
case SnapMode.Mil50: name = "50 mil"; break;
case SnapMode.MM1: name = "1mm"; break;
case SnapMode.MM05: name = "0.5mm"; break;
case SnapMode.Off: name = "off"; break;
}
CurrentSnapMode = Mode;
Redraw(false);
toolStripDropDownButton1.Text = "Snap: " + name;
}
private void milToolStripMenuItem_Click(object sender, EventArgs e)
{
UpdateSnapBox(SnapMode.Mil100);
}
private void mmToolStripMenuItem_Click(object sender, EventArgs e)
{
UpdateSnapBox(SnapMode.MM1);
}
private void mmToolStripMenuItem1_Click(object sender, EventArgs e)
{
UpdateSnapBox(SnapMode.MM05);
}
private void offToolStripMenuItem_Click(object sender, EventArgs e)
{
SnapOff();
}
private void SnapOff()
{
UpdateSnapBox(SnapMode.Off);
}
public void ZoomToFit()
{
if (ThePanel.TheSet.Width > 0 && ThePanel.TheSet.Height > 0 && glControl1.Width > 0 && glControl1.Height > 0)
{
double A1 = (ThePanel.TheSet.Width + 8) / (ThePanel.TheSet.Height + 8);
double A2 = glControl1.Width / glControl1.Height;
Zoom = Math.Min(glControl1.Width / (ThePanel.TheSet.Width + 8), glControl1.Height / (ThePanel.TheSet.Height + 8));
TargetZoom = Zoom;
CenterPoint.X = ThePanel.TheSet.Width / 2;
CenterPoint.Y = ThePanel.TheSet.Height / 2;
}
else
{
Zoom = 1;
TargetZoom = 1;
CenterPoint = new PointD(0, 0);
}
UpdateScrollers();
}
private void UpdateScrollers()
{
double hratio = glControl1.Width / (ThePanel.TheSet.Width * Zoom);
double vratio = glControl1.Height / (ThePanel.TheSet.Height * Zoom);
if (hratio > 1)
{
hScrollBar1.Visible = false;
}
else
{
double scrollablemm = (1 - hratio) * (ThePanel.TheSet.Width + 6);
// Console.WriteLine("{0} mm in X", scrollablemm);
hScrollBar1.Maximum = (int)Math.Ceiling(scrollablemm);
hScrollBar1.LargeChange = 1;
hScrollBar1.Minimum = 0;
hScrollBar1.Value = 0;
hScrollBar1.Update();
hScrollBar1.Visible = true;
}
if (vratio > 1)
{
vScrollBar1.Visible = false;
}
else
{
double scrollablemm = (1 - vratio) * (ThePanel.TheSet.Height + 6);
// Console.WriteLine("{0} mm in Y", scrollablemm);
vScrollBar1.LargeChange = 1;
vScrollBar1.Visible = true;
vScrollBar1.Maximum = (int)Math.Ceiling(scrollablemm);
vScrollBar1.Minimum = 0;
vScrollBar1.Value = 0;
}
}
public bool AutoUpdate = false;
private void glControl1_Paint(object sender, PaintEventArgs e)
{
if (ShapeMarkedForUpdate && (AutoUpdate || ForceShapeUpdate))
{
//Console.WriteLine("updating shape..");
ThePanel.UpdateShape(new StandardConsoleLog()); // check if needed?
ShapeMarkedForUpdate = false;
ForceShapeUpdate = false;
}
glControl1.MakeCurrent();
DrawingScale = Math.Min(glControl1.Width, glControl1.Height) / (float)(Math.Max(ThePanel.TheSet.Height, ThePanel.TheSet.Width) + 10);
GraphicsInterface GI = (GraphicsInterface)new GLGraphicsInterface(0, 0, glControl1.Width, glControl1.Height);
GL.MatrixMode(MatrixMode.Projection);
GL.LoadIdentity();
GL.Ortho(-glControl1.Width / 2, glControl1.Width / 2, glControl1.Height / 2, -glControl1.Height / 2, -100, 100);
GL.MatrixMode(MatrixMode.Modelview);
GL.LoadIdentity();
GL.Viewport(0, 0, glControl1.Width, glControl1.Height);
GL.Clear(ClearBufferMask.ColorBufferBit);
GI.ScaleTransform((float)Zoom, -(float)Zoom);
GI.TranslateTransform(-(float)(CenterPoint.X), -(float)(CenterPoint.Y));
GL.Disable(EnableCap.DepthTest);
GL.Enable(EnableCap.Blend);
GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha);
GL.Hint(HintTarget.LineSmoothHint, HintMode.Nicest);
GL.Hint(HintTarget.PointSmoothHint, HintMode.Nicest);
ThePanel.DrawBoardBitmap(1.0f, GI, glControl1.Width, glControl1.Height, SelectedInstance, HoverShape, SnapDistance(), Zoom);
// Highlight other selected instances
foreach(var inst in SelectedInstances)
{
if (inst != SelectedInstance)
{
ThePanel.RenderInstance(GI, DrawingScale, Color.Black, inst, false, true, false, Zoom);
}
}
if (IsBoxSelecting)
{
GL.MatrixMode(MatrixMode.Modelview);
GL.LoadIdentity();
// Coordinates are in screen space centered? No, Ortho was set to centered.
// Ortho is (-w/2, w/2, h/2, -h/2)
// Mouse coordinates are (0..w, 0..h) from top left?
// WinForms mouse: 0,0 is top left.
// GL Ortho: 0,0 is center. Y is up.
// Need to map Mouse to GL.
double x1 = BoxSelectStart.X - glControl1.Width / 2.0;
double y1 = (BoxSelectStart.Y - glControl1.Height / 2.0);
double x2 = BoxSelectCurrent.X - glControl1.Width / 2.0;
double y2 = (BoxSelectCurrent.Y - glControl1.Height / 2.0);
GL.Enable(EnableCap.Blend);
GL.Color4(0.0f, 0.5f, 1.0f, 0.3f);
GL.Begin(PrimitiveType.Quads);
GL.Vertex2(x1, y1);
GL.Vertex2(x2, y1);
GL.Vertex2(x2, y2);
GL.Vertex2(x1, y2);
GL.End();
GL.Color4(0.0f, 0.5f, 1.0f, 0.8f);
GL.LineWidth(1.0f);
GL.Begin(PrimitiveType.LineLoop);
GL.Vertex2(x1, y1);
GL.Vertex2(x2, y1);
GL.Vertex2(x2, y2);
GL.Vertex2(x1, y2);
GL.End();
}
glControl1.SwapBuffers();
}
private void glControl1_MouseDown(object sender, MouseEventArgs e)
{
DrawingScale = Math.Min(glControl1.Width, glControl1.Height) / 110.0f;
DoMouseDown(e);
}
private void glControl1_MouseMove(object sender, MouseEventArgs e)
{
DrawingScale = Math.Min(glControl1.Width, glControl1.Height) / 110.0f;
DoMouseMove(e);
}
private void glControl1_MouseUp(object sender, MouseEventArgs e)
{
DrawingScale = Math.Min(glControl1.Width, glControl1.Height) / 110.0f;
DoMouseUp(e);
}
private void exportBoardImageToolStripMenuItem_Click(object sender, EventArgs e)
{
if (SelectedInstance == null) return;
if (SelectedInstance.GetType() == typeof(GerberInstance))
{
string path = (SelectedInstance as GerberInstance).GerberPath;
try
{
System.Windows.Forms.SaveFileDialog OFD = new System.Windows.Forms.SaveFileDialog();
OFD.DefaultExt = "";
if (OFD.ShowDialog() != System.Windows.Forms.DialogResult.OK) return;
Console.WriteLine("path selected: {0}", path);
GerberImageCreator GIC = new GerberImageCreator();
foreach (var a in Directory.GetFiles(path, "*.*"))
{
GIC.AddBoardToSet(a, new StandardConsoleLog());
}
GIC.WriteImageFiles(OFD.FileName);
}
catch (Exception)
{
}
}
}
public void glControl1_DragDrop(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(DataFormats.FileDrop))
{
Point DropPointPre = glControl1.PointToClient(new Point(e.X, e.Y));
var DropPoint = MouseToMM(new PointD(DropPointPre.X, DropPointPre.Y));
string[] D = e.Data.GetData(DataFormats.FileDrop) as string[];
foreach (string S in D)
{
if (File.Exists(S) && (Path.GetExtension(S).ToLower() == ".gerberset" || Path.GetExtension(S).ToLower() == ".xml"))
{
LoadFile(S);
return;
}
if (Directory.Exists(S) || (File.Exists(S) && (Path.GetExtension(S).ToLower() == ".zip" || Path.GetExtension(S).ToLower() == "zip")))
{
Console.WriteLine("Adding dropped folder: {0}", S);
if (BaseName == "Untitled") BaseName = Path.GetFileNameWithoutExtension(S);
var R = ThePanel.AddGerberFolder(new StandardConsoleLog(), S);
foreach (var s in R)
{
GerberInstance GI = new GerberInstance() { GerberPath = s };
GI.Center = DropPoint;
ThePanel.TheSet.Instances.Add(GI);
SelectedInstance = GI;
}
}
else
{
Console.WriteLine("Dropped item {0} is not a folder! ignoring!", S);
}
}
ThePanel.UpdateShape(new StandardConsoleLog());
CheckAndResizeCanvas();
TV.BuildTree(this, ThePanel.TheSet);
ZoomToFit();
Redraw(true, true);
}
}
private void glControl1_DragEnter(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(DataFormats.FileDrop))
{
e.Effect = DragDropEffects.Copy;
}
else
{
e.Effect = DragDropEffects.None;
}
}
private void naiveRectanglePackerToolStripMenuItem_Click(object sender, EventArgs e)
{
ThePanel.RectanglePack();
Redraw(true);
}
private void maxRectsToolStripMenuItem_Click(object sender, EventArgs e)
{
ThePanel.MaxRectPack();
Redraw(true);
}
private void panelPropertiesToolStripMenuItem_Click(object sender, EventArgs e)
{
PanelProperties PP = new PanelProperties(ThePanel);
PP.ShowDialog();
Redraw(true);
}
private void deleteAllBreaktabsWithErrorsToolStripMenuItem_Click(object sender, EventArgs e)
{
ThePanel.RemoveAllTabs(true);
Redraw(true);
}
private void insertBoardJoinToolStripMenuItem_Click_1(object sender, EventArgs e)
{
AddTab(new PointD(0, 0));
}
private void toolStripMenuItem1_Click(object sender, EventArgs e)
{
ThePanel.BuildAutoTabs(new StandardConsoleLog());// GenerateTabLocations();
Redraw(true);
}
private void toolStripMenuItem2_Click(object sender, EventArgs e)
{
ThePanel.RemoveAllTabs(false);
Redraw(true);
}
private void toolStripMenuItem3_Click(object sender, EventArgs e)
{
ThePanel.RemoveAllTabs(true);
Redraw(true);
}
private void addGerberFolderToolStripMenuItem1_Click(object sender, EventArgs e)
{
if (folderBrowserDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
var R = ThePanel.AddGerberFolder(new StandardConsoleLog(),folderBrowserDialog1.SelectedPath);
foreach (var s in R)
{
GerberInstance GI = new GerberInstance() { GerberPath = s };
ThePanel.TheSet.Instances.Add(GI);
SelectedInstance = GI;
}
CheckAndResizeCanvas();
TV.BuildTree(this, ThePanel.TheSet);
Redraw(true);
}
}
private void mergeOverlappingBreaktabsToolStripMenuItem_Click(object sender, EventArgs e)
{
ThePanel.MergeOverlappingTabs();
Redraw(true);
}
private void doItAllToolStripMenuItem_Click(object sender, EventArgs e)
{
ThePanel.RemoveAllTabs();
ThePanel.GenerateTabLocations();
ThePanel.RemoveAllTabs(true);
ThePanel.MergeOverlappingTabs();
Redraw(true);
}
private void zoomToFitToolStripMenuItem_Click(object sender, EventArgs e)
{
ZoomToFit();
Redraw(false);
}
private void scale11ToolStripMenuItem_Click(object sender, EventArgs e)
{
Zoom1to1();
Redraw(false);
}
private void zoomInToolStripMenuItem_Click(object sender, EventArgs e)
{
ZoomIn();
}
public void ZoomIn()
{
TargetZoom *= 1.5;
StartZoomAnimation(glControl1.Width / 2, glControl1.Height / 2);
}
private void zoomOutToolStripMenuItem_Click(object sender, EventArgs e)
{
ZoomOut();
}
public void ZoomOut()
{
TargetZoom *= 0.6;
StartZoomAnimation(glControl1.Width / 2, glControl1.Height / 2);
}
private void Zoom1to1()
{
using (Graphics g = Graphics.FromHwnd(IntPtr.Zero))
{
try
{
var dx = g.DpiX;
var dy = g.DpiY;
Zoom = 1 * dx / 25.4;
CenterPoint.X = ThePanel.TheSet.Width / 2;
CenterPoint.Y = ThePanel.TheSet.Height / 2;
}
catch (Exception)
{
Zoom = 1;
CenterPoint = new PointD(0, 0);
}
}
}
private void vScrollBar1_Scroll(object sender, ScrollEventArgs e)
{
//Console.Write("newval: {0}", vScrollBar1.Value);
CenterPoint.Y = -vScrollBar1.Value + (vScrollBar1.Maximum / 2) + ThePanel.TheSet.Height / 2;
Redraw(false);
}
private void hScrollBar1_Scroll(object sender, ScrollEventArgs e)
{
// Console.Write("newval: {0}", hScrollBar1.Value);
CenterPoint.X = hScrollBar1.Value - (hScrollBar1.Maximum / 2) + ThePanel.TheSet.Width / 2;
Redraw(false);
}
private void generateSilkscreenLayerOffsetArtToolStripMenuItem_Click(object sender, EventArgs e)
{
if (SelectedInstance == null) return;
if (SelectedInstance.GetType() == typeof(GerberInstance))
{
string path = (SelectedInstance as GerberInstance).GerberPath;
GerberLibrary.ArtWork.Functions.CreateArtLayersForFolder(new StandardConsoleLog(), path, GerberLibrary.ArtWork.ArtLayerStyle.CheckerField);
}
}
private void glControl1_KeyDown(object sender, KeyEventArgs e)
{
switch (e.KeyCode)
{
case Keys.T:
AddTab(LastMouseMove);
break;
case Keys.Delete:
if (SelectedInstance != null)
{
RemoveInstance(SelectedInstance);
}
break;
case Keys.Add:
case Keys.Oemplus:
Zoom *= 1.05;
UpdateScrollers();
Redraw(false);
break;
case Keys.OemMinus:
case Keys.Subtract:
Zoom *= 0.95;
UpdateScrollers();
Redraw(false);
break;
case Keys.R:
if (HoverShape != null && HoverShape is BreakTab)
{
var BT = HoverShape as BreakTab;
BT.Radius -= 0.25f;
if (BT.Radius < 0.5f) BT.Radius = 0.5f;
Redraw(true);
}
else if (SelectedInstance != null && SelectedInstance is BreakTab)
{
var BT = SelectedInstance as BreakTab;
BT.Radius -= 0.25f;
if (BT.Radius < 0.5f) BT.Radius = 0.5f;
Redraw(true);
}
break;
case Keys.Y:
if (HoverShape != null && HoverShape is BreakTab)
{
var BT = HoverShape as BreakTab;
BT.Radius += 0.25f;
Redraw(true);
}
else if (SelectedInstance != null && SelectedInstance is BreakTab)
{
var BT = SelectedInstance as BreakTab;
BT.Radius += 0.25f;
Redraw(true);
}
break;
default:
if (SelectedInstance != null)
{
switch (e.KeyCode)
{
case Keys.Up:
SelectedInstance.Center.Y -= (float)SnapDistance();
Redraw(true);
break;
case Keys.Down:
SelectedInstance.Center.Y += (float)SnapDistance();
Redraw(true);
break;
case Keys.Left:
SelectedInstance.Center.X -= (float)SnapDistance();
Redraw(true);
break;
case Keys.Right:
SelectedInstance.Center.X += (float)SnapDistance();
Redraw(true);
break;
}
}
break;
}
}
private void generateArtOffsetCurvesToolStripMenuItem_Click(object sender, EventArgs e)
{
if (SelectedInstance == null) return;
if (SelectedInstance.GetType() == typeof(GerberInstance))
{
string path = (SelectedInstance as GerberInstance).GerberPath;
GerberLibrary.ArtWork.Functions.CreateArtLayersForFolder(new StandardConsoleLog(), path, GerberLibrary.ArtWork.ArtLayerStyle.OffsetCurves_GoldfishBoard);
}
}
private void generateArtFieldLinesToolStripMenuItem_Click(object sender, EventArgs e)
{
if (SelectedInstance == null) return;
if (SelectedInstance.GetType() == typeof(GerberInstance))
{
string path = (SelectedInstance as GerberInstance).GerberPath;
GerberLibrary.ArtWork.Functions.CreateArtLayersForFolder(new StandardConsoleLog(), path, GerberLibrary.ArtWork.ArtLayerStyle.FlowField);
}
}
private void addInstanceToolStripMenuItem_Click(object sender, EventArgs e)
{
ZoomToFit();
}
private void generateArtReactedBlobsToolStripMenuItem_Click(object sender, EventArgs e)
{
if (SelectedInstance == null) return;
if (SelectedInstance.GetType() == typeof(GerberInstance))
{
string path = (SelectedInstance as GerberInstance).GerberPath;
GerberLibrary.ArtWork.Functions.CreateArtLayersForFolder(new StandardConsoleLog(), path, GerberLibrary.ArtWork.ArtLayerStyle.ReactDiffuse);
}
}
private void generateArtPrototypeStripToolStripMenuItem_Click(object sender, EventArgs e)
{
if (SelectedInstance == null) return;
if (SelectedInstance.GetType() == typeof(GerberInstance))
{
string path = (SelectedInstance as GerberInstance).GerberPath;
GerberLibrary.ArtWork.Functions.CreateArtLayersForFolder(new StandardConsoleLog(), path, GerberLibrary.ArtWork.ArtLayerStyle.PrototypeEdge);
}
}
private void ProcessButton_Click_1(object sender, EventArgs e)
{
if (ShapeMarkedForUpdate)
{
ThePanel.UpdateShape(new StandardConsoleLog()); ShapeMarkedForUpdate = false;
Redraw(false);
ProcessButton.Enabled = false;
}
}
private void GerberPanelize_Resize(object sender, EventArgs e)
{
//ZoomToFit();
}
void UpdateAutoProcessButton()
{
if (AutoUpdate)
{
AutoUpdate = false;
AutoProcess.BackColor = Color.FromKnownColor(KnownColor.Control);
if (ShapeMarkedForUpdate)
{
ProcessButton.Enabled = true;
}
}
else
{
AutoUpdate = true;
if (ShapeMarkedForUpdate)
{
ThePanel.UpdateShape(new StandardConsoleLog()); ShapeMarkedForUpdate = false;
Redraw(false);
}
ProcessButton.Enabled = false;
AutoProcess.BackColor = Color.Gold;
}
}
private void AutoProcess_Click(object sender, EventArgs e)
{
UpdateAutoProcessButton();
}
private void CheckAndResizeCanvas()
{
double maxX = ThePanel.TheSet.Width;
double maxY = ThePanel.TheSet.Height;
bool changed = false;
foreach (var i in ThePanel.TheSet.Instances)
{
var bb = i.BoundingBox;
if (bb.BottomRight.X > maxX) { maxX = bb.BottomRight.X + 2; changed = true; }
if (bb.TopLeft.X > maxX) { maxX = bb.TopLeft.X + 2; changed = true; }
if (bb.BottomRight.Y > maxY) { maxY = bb.BottomRight.Y + 2; changed = true; }
if (bb.TopLeft.Y > maxY) { maxY = bb.TopLeft.Y + 2; changed = true; }
}
if (changed)
{
ThePanel.TheSet.Width = maxX;
ThePanel.TheSet.Height = maxY;
UpdateScrollers();
Redraw(true);
}
}
private void RotateRightHover_Click(object sender, EventArgs e)
{
}
private void RotateLeftHover_Click(object sender, EventArgs e)
{
}
private void glControl1_MouseWheel(object sender, MouseEventArgs e)
{
if (e.Delta != 0)
{
double det = e.Delta > 0 ? 1.5 : 0.6;
TargetZoom *= det;
StartZoomAnimation(e.X, e.Y);
}
}
private void StartZoomAnimation(int mouseX, int mouseY)
{
ZoomAnimationCenter = new PointD(mouseX - glControl1.Width / 2, (mouseY - glControl1.Height / 2) * -1);
ZoomAnimationTimer.Enabled = true;
}
// Clipboard
public void CopySelection()
{
if (SelectedInstances.Count == 0) return;
ClipboardData data = new ClipboardData();
foreach(var inst in SelectedInstances)
{
if (inst is GerberInstance) data.Instances.Add(inst as GerberInstance);
if (inst is BreakTab) data.Tabs.Add(inst as BreakTab);
}
try
{
XmlSerializer serializer = new XmlSerializer(typeof(ClipboardData));
using (StringWriter writer = new StringWriter())
{
serializer.Serialize(writer, data);
Clipboard.SetText(writer.ToString());
}
}
catch(Exception e) { Console.WriteLine("Copy failed: " + e.Message); }
}
public void PasteSelection()
{
if (!Clipboard.ContainsText()) return;
try
{
PushUndo();
string xml = Clipboard.GetText();
XmlSerializer serializer = new XmlSerializer(typeof(ClipboardData));
using (StringReader reader = new StringReader(xml))
{
ClipboardData data = (ClipboardData)serializer.Deserialize(reader);
SelectedInstances.Clear();
foreach(var inst in data.Instances)
{
inst.Center.X += 5;
inst.Center.Y += 5;
// We need to re-link or re-load the outlines?
// GerberInstance has GerberPath
// We need to ensure loaded outlines has it?
// Actually, if we just add it to Instances, UpdateShape will handle it if LoadedOutlines has it.
// Assuming the file is still loaded.
if (!ThePanel.TheSet.LoadedOutlines.Contains(inst.GerberPath))
{
ThePanel.TheSet.LoadedOutlines.Add(inst.GerberPath);
// We might need to actually reload the file content if it's not in GerberOutlines?
// But ThePanel.TheSet.LoadedOutlines is just a list of strings.
// ThePanel.AddGerberFolder loads it.
// If we paste from same session, current loaded outlines is fine.
// If we paste from another session/instance, we might be missing the file?
// For now assume same session or path valid.
}
ThePanel.TheSet.Instances.Add(inst);
SelectedInstances.Add(inst);
}
foreach(var tab in data.Tabs)
{
tab.Center.X += 5;
tab.Center.Y += 5;
ThePanel.TheSet.Tabs.Add(tab);
SelectedInstances.Add(tab);
}
SelectedInstance = SelectedInstances.LastOrDefault();
SetSelectedInstance(SelectedInstance);
ThePanel.UpdateShape(new StandardConsoleLog());
Redraw(true);
}
}
catch(Exception e) { Console.WriteLine("Paste failed: " + e.Message); }
}
public void CutSelection()
{
CopySelection();
DeleteSelection();
}
public void DeleteSelection()
{
if (SelectedInstances.Count == 0) return;
PushUndo();
foreach(var inst in SelectedInstances)
{
if (inst is GerberInstance) ThePanel.TheSet.Instances.Remove(inst as GerberInstance);
if (inst is BreakTab) ThePanel.TheSet.Tabs.Remove(inst as BreakTab);
}
SelectedInstances.Clear();
SelectedInstance = null;
SetSelectedInstance(null);
ThePanel.UpdateShape(new StandardConsoleLog());
Redraw(true);
}
// Undo/Redo Logic
public void PushUndo()
{
try {
UndoStack.Add(SerializeState());
if (UndoStack.Count > 20) UndoStack.RemoveAt(0);
RedoStack.Clear();
} catch { }
}
public void PerformUndo()
{
if (UndoStack.Count == 0) return;
string state = UndoStack.Last();
UndoStack.RemoveAt(UndoStack.Count - 1);
RedoStack.Add(SerializeState());
RestoreState(state);
Redraw(true);
}
public void PerformRedo()
{
if (RedoStack.Count == 0) return;
string state = RedoStack.Last();
RedoStack.RemoveAt(RedoStack.Count - 1);
UndoStack.Add(SerializeState());
RestoreState(state);
Redraw(true);
}
private string SerializeState()
{
XmlSerializer serializer = new XmlSerializer(typeof(GerberLayoutSet));
using (StringWriter writer = new StringWriter())
{
serializer.Serialize(writer, ThePanel.TheSet);
return writer.ToString();
}
}
private void RestoreState(string state)
{
XmlSerializer serializer = new XmlSerializer(typeof(GerberLayoutSet));
using (StringReader reader = new StringReader(state))
{
GerberLayoutSet set = (GerberLayoutSet)serializer.Deserialize(reader);
ThePanel.TheSet = set;
// We need to restore selected instances references?
// IDs? They are new objects.
SelectedInstances.Clear();
SelectedInstance = null;
SetSelectedInstance(null);
ThePanel.UpdateShape(new StandardConsoleLog());
}
}
public class ClipboardData
{
public List<GerberInstance> Instances = new List<GerberInstance>();
public List<BreakTab> Tabs = new List<BreakTab>();
}
private void autofitCanvasToolStripMenuItem_Click(object sender, EventArgs e)
{
AutofitDialog D = new AutofitDialog(this);
D.Show();
}
public void PerformAutofit(double margin, double moat)
{
PushUndo();
if (ThePanel.TheSet.Instances.Count == 0) return;
double minX = double.MaxValue;
double minY = double.MaxValue;
double maxX = double.MinValue;
double maxY = double.MinValue;
foreach (var inst in ThePanel.TheSet.Instances)
{
var bb = inst.BoundingBox;
if (bb.TopLeft.X < minX) minX = bb.TopLeft.X;
if (bb.BottomRight.X > maxX) maxX = bb.BottomRight.X;
if (bb.TopLeft.Y < minY) minY = bb.TopLeft.Y;
if (bb.BottomRight.Y > maxY) maxY = bb.BottomRight.Y;
}
// Also check tabs if they are stored separately in the set (though typically they are attached to instances or in a separate list)
// Looking at GerberPanel.cs, Tabs are property of GerberInstance, but can also be added to TheSet?
// Actually BreakTabs are added to TheSet.Tabs? No, TheSet is GerberPanelSet?
// In GerberPanel.cs: public BreakTab AddTab(PointD center) { ... TheSet.Tabs.Add(BT); ... }
// So we must check ThePanel.TheSet.Tabs as well.
foreach (var tab in ThePanel.TheSet.Tabs)
{
// BreakTab has Center and Radius. Bounds are Center +/- Radius.
// Assuming BreakTab : AngledThing
double r = tab.Radius;
if (tab.Center.X - r < minX) minX = tab.Center.X - r;
if (tab.Center.X + r > maxX) maxX = tab.Center.X + r;
if (tab.Center.Y - r < minY) minY = tab.Center.Y - r;
if (tab.Center.Y + r > maxY) maxY = tab.Center.Y + r;
}
double targetX = margin + moat;
double targetY = margin + moat;
double shiftX = targetX - minX;
double shiftY = targetY - minY;
foreach (var inst in ThePanel.TheSet.Instances)
{
inst.Center.X += (float)shiftX;
inst.Center.Y += (float)shiftY;
}
foreach (var tab in ThePanel.TheSet.Tabs)
{
tab.Center.X += (float)shiftX;
tab.Center.Y += (float)shiftY;
}
double contentWidth = maxX - minX;
double contentHeight = maxY - minY;
double totalPadding = 2 * (margin + moat);
ThePanel.TheSet.Width = contentWidth + totalPadding;
ThePanel.TheSet.Height = contentHeight + totalPadding;
ThePanel.UpdateShape(new StandardConsoleLog());
CheckAndResizeCanvas(); // Ensure consistency
UpdateScrollers();
CenterPoint = new PointD(ThePanel.TheSet.Width / 2, ThePanel.TheSet.Height / 2);
ZoomToFit();
Redraw(true, true);
}
PointD ZoomAnimationCenter;
private void ZoomAnimationTimer_Tick(object sender, EventArgs e)
{
double diff = TargetZoom - Zoom;
if (Math.Abs(diff) < 0.001)
{
Zoom = TargetZoom;
ZoomAnimationTimer.Enabled = false;
}
else
{
var OldZoom = Zoom;
Zoom += diff * 0.2;
// var det = Zoom / LastScale;
// The shift in centerpoint needed to keep the mouse fixed on the same world coordinate is:
// Shift = MouseScreenRel * (1/OldZoom - 1/NewZoom)
double Factor = (1.0 / OldZoom - 1.0 / Zoom);
CenterPoint.X += ZoomAnimationCenter.X * Factor;
CenterPoint.Y += ZoomAnimationCenter.Y * Factor;
}
UpdateScrollers();
Redraw(false);
}
}
}
5203ce801This file is pinned to the selected release. Download the original to open it in your design tool.