diff --git a/WaferAdjust.sln b/WaferAdjust.sln new file mode 100644 index 0000000..ec7b861 --- /dev/null +++ b/WaferAdjust.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.14.36623.8 d17.14 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WaferAdjust", "WaferAdjust\WaferAdjust.csproj", "{941B8ABC-436F-457D-95DA-A79E23C8CA5D}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {941B8ABC-436F-457D-95DA-A79E23C8CA5D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {941B8ABC-436F-457D-95DA-A79E23C8CA5D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {941B8ABC-436F-457D-95DA-A79E23C8CA5D}.Debug|x64.ActiveCfg = Debug|x64 + {941B8ABC-436F-457D-95DA-A79E23C8CA5D}.Debug|x64.Build.0 = Debug|x64 + {941B8ABC-436F-457D-95DA-A79E23C8CA5D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {941B8ABC-436F-457D-95DA-A79E23C8CA5D}.Release|Any CPU.Build.0 = Release|Any CPU + {941B8ABC-436F-457D-95DA-A79E23C8CA5D}.Release|x64.ActiveCfg = Release|x64 + {941B8ABC-436F-457D-95DA-A79E23C8CA5D}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/WaferAdjust/App.config b/WaferAdjust/App.config new file mode 100644 index 0000000..4bfa005 --- /dev/null +++ b/WaferAdjust/App.config @@ -0,0 +1,6 @@ + + + + + + diff --git a/WaferAdjust/CalibForm.Designer.cs b/WaferAdjust/CalibForm.Designer.cs new file mode 100644 index 0000000..aa94a2e --- /dev/null +++ b/WaferAdjust/CalibForm.Designer.cs @@ -0,0 +1,39 @@ +namespace WaferAlignment +{ + partial class CalibForm + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(800, 450); + this.Text = "CalibForm"; + } + + #endregion + } +} \ No newline at end of file diff --git a/WaferAdjust/CalibForm.cs b/WaferAdjust/CalibForm.cs new file mode 100644 index 0000000..726754e --- /dev/null +++ b/WaferAdjust/CalibForm.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace WaferAlignment +{ + public partial class CalibForm : Form + { + public CalibForm() + { + InitializeComponent(); + } + } +} diff --git a/WaferAdjust/FitCircle.cs b/WaferAdjust/FitCircle.cs new file mode 100644 index 0000000..4931634 --- /dev/null +++ b/WaferAdjust/FitCircle.cs @@ -0,0 +1,37 @@ +using Cognex.VisionPro; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace WaferAdjust +{ + public delegate void OnFitCircleResult(double x, double y, double rms); + internal class FitCircle + { + CogFitCircleTool fitCircleTool = new CogFitCircleTool(); + public event OnFitCircleResult OnFitCircleResult; + public void AddPoint(double x, double y) + { + fitCircleTool.RunParams.AddPoint(x, y); + } + public void Run(Bitmap bmp) + { + fitCircleTool.InputImage = new CogImage8Grey(bmp); + fitCircleTool.Run(); + if (fitCircleTool.Result != null) + { + CogCircle circle = new CogCircle(fitCircleTool.Result.GetCircle()); + OnFitCircleResult?.Invoke(circle.CenterX, circle.CenterY, fitCircleTool.Result.RMSError); + } + } + public void Init() + { + fitCircleTool?.Dispose(); + fitCircleTool = null; + fitCircleTool = new CogFitCircleTool(); + } + } +} diff --git a/WaferAdjust/FitCircleToolBlock.cs b/WaferAdjust/FitCircleToolBlock.cs new file mode 100644 index 0000000..8299586 --- /dev/null +++ b/WaferAdjust/FitCircleToolBlock.cs @@ -0,0 +1,88 @@ +using Cognex.VisionPro; +using Cognex.VisionPro.PMAlign; +using Cognex.VisionPro.ToolBlock; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace WaferAdjust +{ + public delegate void OnFitCircleResult(double x, double y, double rms); + internal class FitCircleToolBlock + { + private CogToolBlock cogToolBlock; + private bool initialized = false; + public event OnToolReady OnToolReady; + public event OnFitCircleResult OnFitCircleResult; + public CogImage8Grey FitCircleImage; + public void Initialize(string vpp) + { + try + { + if (cogToolBlock != null) + { + cogToolBlock.Ran -= CogToolBlock_Ran; + cogToolBlock.Dispose(); + cogToolBlock = null; + } + initialized = false; + cogToolBlock = CogSerializer.LoadObjectFromFile(vpp) as CogToolBlock; + cogToolBlock.Ran += CogToolBlock_Ran; + initialized = true; + OnToolReady?.Invoke(initialized); + LogHelper.LogInfo("FitCircleToolBlock initialized successfully: " + vpp); + } + catch (Exception ex) + { + LogHelper.LogError(ex.Message); + } + } + private void CogToolBlock_Ran(object sender, EventArgs e) + { + try + { + FitCircleImage = cogToolBlock.Outputs["OutputImage"].Value as CogImage8Grey; + OnFitCircleResult?.Invoke(Math.Round((double)cogToolBlock.Outputs["CenterX"].Value, 3), + Math.Round((double)cogToolBlock.Outputs["CenterY"].Value, 3), + Math.Round((double)cogToolBlock.Outputs["RMSError"].Value, 3)); + } + catch (Exception ex) + { + LogHelper.LogError(ex.Message + ex.StackTrace); + } + } + public void Run(Bitmap bmp, List pointInfos) + { + try + { + CogImage8Grey image8Grey = new CogImage8Grey(bmp); + cogToolBlock.Inputs["OutputImage"].Value = image8Grey; + CogFitCircleTool fitCircleTool = cogToolBlock.Tools["CogFitCircleTool1"] as CogFitCircleTool; + fitCircleTool.RunParams.NumPoints = 0; + foreach (var item in pointInfos) + fitCircleTool.RunParams.AddPoint(item.X, item.Y); + cogToolBlock.Run(); + } + catch (Exception ex) + { + LogHelper.LogError("ScanToolBlock Run Error: " + ex.Message); + } + } + public bool Ready() + { + return initialized; + } + public void Stop() + { + if (cogToolBlock != null) + { + cogToolBlock.Ran -= CogToolBlock_Ran; + cogToolBlock.Dispose(); + cogToolBlock = null; + } + } + } +} diff --git a/WaferAdjust/Form1.Designer.cs b/WaferAdjust/Form1.Designer.cs new file mode 100644 index 0000000..5dd5359 --- /dev/null +++ b/WaferAdjust/Form1.Designer.cs @@ -0,0 +1,481 @@ +namespace WaferAdjust +{ + partial class Form1 + { + /// + /// 必需的设计器变量。 + /// + private System.ComponentModel.IContainer components = null; + + /// + /// 清理所有正在使用的资源。 + /// + /// 如果应释放托管资源,为 true;否则为 false。 + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows 窗体设计器生成的代码 + + /// + /// 设计器支持所需的方法 - 不要 + /// 使用代码编辑器修改此方法的内容。 + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Form1)); + this.splitContainer1 = new System.Windows.Forms.SplitContainer(); + this.cogRecordDisplay1 = new Cognex.VisionPro.CogRecordDisplay(); + this.groupBox2 = new System.Windows.Forms.GroupBox(); + this.checkBox2 = new System.Windows.Forms.CheckBox(); + this.checkBox1 = new System.Windows.Forms.CheckBox(); + this.button7 = new System.Windows.Forms.Button(); + this.label9 = new System.Windows.Forms.Label(); + this.textBox10 = new System.Windows.Forms.TextBox(); + this.label8 = new System.Windows.Forms.Label(); + this.textBox9 = new System.Windows.Forms.TextBox(); + this.button6 = new System.Windows.Forms.Button(); + this.label7 = new System.Windows.Forms.Label(); + this.textBox8 = new System.Windows.Forms.TextBox(); + this.label6 = new System.Windows.Forms.Label(); + this.textBox7 = new System.Windows.Forms.TextBox(); + this.label5 = new System.Windows.Forms.Label(); + this.textBox6 = new System.Windows.Forms.TextBox(); + this.button5 = new System.Windows.Forms.Button(); + this.textBox2 = new System.Windows.Forms.TextBox(); + this.label1 = new System.Windows.Forms.Label(); + this.label4 = new System.Windows.Forms.Label(); + this.textBox3 = new System.Windows.Forms.TextBox(); + this.textBox5 = new System.Windows.Forms.TextBox(); + this.label2 = new System.Windows.Forms.Label(); + this.label3 = new System.Windows.Forms.Label(); + this.textBox4 = new System.Windows.Forms.TextBox(); + this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.button2 = new System.Windows.Forms.Button(); + this.button4 = new System.Windows.Forms.Button(); + this.button3 = new System.Windows.Forms.Button(); + this.textBox1 = new System.Windows.Forms.TextBox(); + this.button1 = new System.Windows.Forms.Button(); + this.richTextBox1 = new System.Windows.Forms.RichTextBox(); + ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit(); + this.splitContainer1.Panel1.SuspendLayout(); + this.splitContainer1.Panel2.SuspendLayout(); + this.splitContainer1.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.cogRecordDisplay1)).BeginInit(); + this.groupBox2.SuspendLayout(); + this.groupBox1.SuspendLayout(); + this.SuspendLayout(); + // + // splitContainer1 + // + this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill; + this.splitContainer1.FixedPanel = System.Windows.Forms.FixedPanel.Panel2; + this.splitContainer1.Location = new System.Drawing.Point(0, 0); + this.splitContainer1.Name = "splitContainer1"; + this.splitContainer1.Orientation = System.Windows.Forms.Orientation.Horizontal; + // + // splitContainer1.Panel1 + // + this.splitContainer1.Panel1.Controls.Add(this.cogRecordDisplay1); + // + // splitContainer1.Panel2 + // + this.splitContainer1.Panel2.Controls.Add(this.groupBox2); + this.splitContainer1.Panel2.Controls.Add(this.groupBox1); + this.splitContainer1.Panel2.Controls.Add(this.button3); + this.splitContainer1.Panel2.Controls.Add(this.textBox1); + this.splitContainer1.Panel2.Controls.Add(this.button1); + this.splitContainer1.Panel2.Controls.Add(this.richTextBox1); + this.splitContainer1.Size = new System.Drawing.Size(885, 806); + this.splitContainer1.SplitterDistance = 558; + this.splitContainer1.TabIndex = 1; + // + // cogRecordDisplay1 + // + this.cogRecordDisplay1.ColorMapLowerClipColor = System.Drawing.Color.Black; + this.cogRecordDisplay1.ColorMapLowerRoiLimit = 0D; + this.cogRecordDisplay1.ColorMapPredefined = Cognex.VisionPro.Display.CogDisplayColorMapPredefinedConstants.None; + this.cogRecordDisplay1.ColorMapUpperClipColor = System.Drawing.Color.Black; + this.cogRecordDisplay1.ColorMapUpperRoiLimit = 1D; + this.cogRecordDisplay1.Dock = System.Windows.Forms.DockStyle.Fill; + this.cogRecordDisplay1.DoubleTapZoomCycleLength = 2; + this.cogRecordDisplay1.DoubleTapZoomSensitivity = 2.5D; + this.cogRecordDisplay1.Location = new System.Drawing.Point(0, 0); + this.cogRecordDisplay1.MouseWheelMode = Cognex.VisionPro.Display.CogDisplayMouseWheelModeConstants.Zoom1; + this.cogRecordDisplay1.MouseWheelSensitivity = 1D; + this.cogRecordDisplay1.Name = "cogRecordDisplay1"; + this.cogRecordDisplay1.OcxState = ((System.Windows.Forms.AxHost.State)(resources.GetObject("cogRecordDisplay1.OcxState"))); + this.cogRecordDisplay1.Size = new System.Drawing.Size(885, 558); + this.cogRecordDisplay1.TabIndex = 0; + // + // groupBox2 + // + this.groupBox2.Controls.Add(this.checkBox2); + this.groupBox2.Controls.Add(this.checkBox1); + this.groupBox2.Controls.Add(this.button7); + this.groupBox2.Controls.Add(this.label9); + this.groupBox2.Controls.Add(this.textBox10); + this.groupBox2.Controls.Add(this.label8); + this.groupBox2.Controls.Add(this.textBox9); + this.groupBox2.Controls.Add(this.button6); + this.groupBox2.Controls.Add(this.label7); + this.groupBox2.Controls.Add(this.textBox8); + this.groupBox2.Controls.Add(this.label6); + this.groupBox2.Controls.Add(this.textBox7); + this.groupBox2.Controls.Add(this.label5); + this.groupBox2.Controls.Add(this.textBox6); + this.groupBox2.Controls.Add(this.button5); + this.groupBox2.Controls.Add(this.textBox2); + this.groupBox2.Controls.Add(this.label1); + this.groupBox2.Controls.Add(this.label4); + this.groupBox2.Controls.Add(this.textBox3); + this.groupBox2.Controls.Add(this.textBox5); + this.groupBox2.Controls.Add(this.label2); + this.groupBox2.Controls.Add(this.label3); + this.groupBox2.Controls.Add(this.textBox4); + this.groupBox2.Location = new System.Drawing.Point(358, 133); + this.groupBox2.Name = "groupBox2"; + this.groupBox2.Size = new System.Drawing.Size(515, 99); + this.groupBox2.TabIndex = 17; + this.groupBox2.TabStop = false; + this.groupBox2.Text = "标定后寻边测试"; + // + // checkBox2 + // + this.checkBox2.AutoSize = true; + this.checkBox2.Location = new System.Drawing.Point(269, 59); + this.checkBox2.Name = "checkBox2"; + this.checkBox2.Size = new System.Drawing.Size(78, 16); + this.checkBox2.TabIndex = 28; + this.checkBox2.Text = "y向上为正"; + this.checkBox2.UseVisualStyleBackColor = true; + // + // checkBox1 + // + this.checkBox1.AutoSize = true; + this.checkBox1.Checked = true; + this.checkBox1.CheckState = System.Windows.Forms.CheckState.Checked; + this.checkBox1.Location = new System.Drawing.Point(185, 59); + this.checkBox1.Name = "checkBox1"; + this.checkBox1.Size = new System.Drawing.Size(78, 16); + this.checkBox1.TabIndex = 27; + this.checkBox1.Text = "x向右为正"; + this.checkBox1.UseVisualStyleBackColor = true; + // + // button7 + // + this.button7.Location = new System.Drawing.Point(284, 76); + this.button7.Name = "button7"; + this.button7.Size = new System.Drawing.Size(75, 23); + this.button7.TabIndex = 26; + this.button7.Text = "求原始点"; + this.button7.UseVisualStyleBackColor = true; + this.button7.Click += new System.EventHandler(this.button7_Click); + // + // label9 + // + this.label9.AutoSize = true; + this.label9.Location = new System.Drawing.Point(428, 63); + this.label9.Name = "label9"; + this.label9.Size = new System.Drawing.Size(47, 12); + this.label9.TabIndex = 25; + this.label9.Text = "旋转点Y"; + // + // textBox10 + // + this.textBox10.Location = new System.Drawing.Point(430, 78); + this.textBox10.Name = "textBox10"; + this.textBox10.Size = new System.Drawing.Size(55, 21); + this.textBox10.TabIndex = 24; + this.textBox10.Text = "1"; + // + // label8 + // + this.label8.AutoSize = true; + this.label8.Location = new System.Drawing.Point(363, 63); + this.label8.Name = "label8"; + this.label8.Size = new System.Drawing.Size(47, 12); + this.label8.TabIndex = 23; + this.label8.Text = "旋转点X"; + // + // textBox9 + // + this.textBox9.Location = new System.Drawing.Point(365, 78); + this.textBox9.Name = "textBox9"; + this.textBox9.Size = new System.Drawing.Size(55, 21); + this.textBox9.TabIndex = 22; + this.textBox9.Text = "1"; + // + // button6 + // + this.button6.Location = new System.Drawing.Point(213, 76); + this.button6.Name = "button6"; + this.button6.Size = new System.Drawing.Size(75, 23); + this.button6.TabIndex = 21; + this.button6.Text = "求旋转点"; + this.button6.UseVisualStyleBackColor = true; + this.button6.Click += new System.EventHandler(this.button6_Click); + // + // label7 + // + this.label7.AutoSize = true; + this.label7.Location = new System.Drawing.Point(150, 63); + this.label7.Name = "label7"; + this.label7.Size = new System.Drawing.Size(29, 12); + this.label7.TabIndex = 20; + this.label7.Text = "角度"; + // + // textBox8 + // + this.textBox8.Location = new System.Drawing.Point(152, 78); + this.textBox8.Name = "textBox8"; + this.textBox8.Size = new System.Drawing.Size(55, 21); + this.textBox8.TabIndex = 19; + this.textBox8.Text = "1"; + // + // label6 + // + this.label6.AutoSize = true; + this.label6.Location = new System.Drawing.Point(78, 63); + this.label6.Name = "label6"; + this.label6.Size = new System.Drawing.Size(47, 12); + this.label6.TabIndex = 18; + this.label6.Text = "起始点Y"; + // + // textBox7 + // + this.textBox7.Location = new System.Drawing.Point(80, 78); + this.textBox7.Name = "textBox7"; + this.textBox7.Size = new System.Drawing.Size(55, 21); + this.textBox7.TabIndex = 17; + this.textBox7.Text = "1"; + // + // label5 + // + this.label5.AutoSize = true; + this.label5.Location = new System.Drawing.Point(10, 63); + this.label5.Name = "label5"; + this.label5.Size = new System.Drawing.Size(47, 12); + this.label5.TabIndex = 16; + this.label5.Text = "起始点X"; + // + // textBox6 + // + this.textBox6.Location = new System.Drawing.Point(12, 78); + this.textBox6.Name = "textBox6"; + this.textBox6.Size = new System.Drawing.Size(55, 21); + this.textBox6.TabIndex = 15; + this.textBox6.Text = "1"; + // + // button5 + // + this.button5.Location = new System.Drawing.Point(141, 35); + this.button5.Name = "button5"; + this.button5.Size = new System.Drawing.Size(212, 23); + this.button5.TabIndex = 6; + this.button5.Text = "拟合计算圆中心(机械坐标)"; + this.button5.UseVisualStyleBackColor = true; + this.button5.Click += new System.EventHandler(this.button5_Click); + // + // textBox2 + // + this.textBox2.Location = new System.Drawing.Point(369, 37); + this.textBox2.Name = "textBox2"; + this.textBox2.Size = new System.Drawing.Size(55, 21); + this.textBox2.TabIndex = 7; + this.textBox2.Text = "64"; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(367, 22); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(53, 12); + this.label1.TabIndex = 8; + this.label1.Text = "相机计数"; + // + // label4 + // + this.label4.AutoSize = true; + this.label4.Location = new System.Drawing.Point(78, 22); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(59, 12); + this.label4.TabIndex = 14; + this.label4.Text = "旋转中心Y"; + // + // textBox3 + // + this.textBox3.Location = new System.Drawing.Point(430, 37); + this.textBox3.Name = "textBox3"; + this.textBox3.Size = new System.Drawing.Size(55, 21); + this.textBox3.TabIndex = 9; + this.textBox3.Text = "4096"; + // + // textBox5 + // + this.textBox5.Location = new System.Drawing.Point(80, 37); + this.textBox5.Name = "textBox5"; + this.textBox5.Size = new System.Drawing.Size(55, 21); + this.textBox5.TabIndex = 13; + this.textBox5.Text = "1"; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(428, 22); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(41, 12); + this.label2.TabIndex = 10; + this.label2.Text = "总计数"; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(8, 22); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(59, 12); + this.label3.TabIndex = 12; + this.label3.Text = "旋转中心X"; + // + // textBox4 + // + this.textBox4.Location = new System.Drawing.Point(10, 37); + this.textBox4.Name = "textBox4"; + this.textBox4.Size = new System.Drawing.Size(55, 21); + this.textBox4.TabIndex = 11; + this.textBox4.Text = "1"; + // + // groupBox1 + // + this.groupBox1.Controls.Add(this.button2); + this.groupBox1.Controls.Add(this.button4); + this.groupBox1.Location = new System.Drawing.Point(438, 45); + this.groupBox1.Name = "groupBox1"; + this.groupBox1.Size = new System.Drawing.Size(340, 82); + this.groupBox1.TabIndex = 16; + this.groupBox1.TabStop = false; + this.groupBox1.Text = "九点标定"; + // + // button2 + // + this.button2.Location = new System.Drawing.Point(61, 40); + this.button2.Name = "button2"; + this.button2.Size = new System.Drawing.Size(212, 23); + this.button2.TabIndex = 3; + this.button2.Text = "拟合圆中心求旋转中心(相机坐标)"; + this.button2.UseVisualStyleBackColor = true; + this.button2.Click += new System.EventHandler(this.button2_Click); + // + // button4 + // + this.button4.Location = new System.Drawing.Point(61, 11); + this.button4.Name = "button4"; + this.button4.Size = new System.Drawing.Size(212, 23); + this.button4.TabIndex = 5; + this.button4.Text = "计算各图的圆中心(相机坐标)"; + this.button4.UseVisualStyleBackColor = true; + this.button4.Visible = false; + this.button4.Click += new System.EventHandler(this.button4_Click); + // + // button3 + // + this.button3.Location = new System.Drawing.Point(736, 16); + this.button3.Name = "button3"; + this.button3.Size = new System.Drawing.Size(137, 23); + this.button3.TabIndex = 4; + this.button3.Text = "清除所有的圆中心"; + this.button3.UseVisualStyleBackColor = true; + this.button3.Click += new System.EventHandler(this.button3_Click); + // + // textBox1 + // + this.textBox1.Location = new System.Drawing.Point(499, 16); + this.textBox1.Name = "textBox1"; + this.textBox1.Size = new System.Drawing.Size(231, 21); + this.textBox1.TabIndex = 2; + // + // button1 + // + this.button1.Location = new System.Drawing.Point(368, 16); + this.button1.Name = "button1"; + this.button1.Size = new System.Drawing.Size(103, 23); + this.button1.TabIndex = 1; + this.button1.Text = "选择图像文件夹"; + this.button1.UseVisualStyleBackColor = true; + this.button1.Click += new System.EventHandler(this.button1_Click); + // + // richTextBox1 + // + this.richTextBox1.Location = new System.Drawing.Point(12, 16); + this.richTextBox1.Name = "richTextBox1"; + this.richTextBox1.Size = new System.Drawing.Size(340, 216); + this.richTextBox1.TabIndex = 0; + this.richTextBox1.Text = ""; + // + // Form1 + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(885, 806); + this.Controls.Add(this.splitContainer1); + this.Name = "Form1"; + this.Text = "晶圆校准程序"; + this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.Form1_FormClosing); + this.Load += new System.EventHandler(this.Form1_Load); + this.splitContainer1.Panel1.ResumeLayout(false); + this.splitContainer1.Panel2.ResumeLayout(false); + this.splitContainer1.Panel2.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).EndInit(); + this.splitContainer1.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.cogRecordDisplay1)).EndInit(); + this.groupBox2.ResumeLayout(false); + this.groupBox2.PerformLayout(); + this.groupBox1.ResumeLayout(false); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.SplitContainer splitContainer1; + private Cognex.VisionPro.CogRecordDisplay cogRecordDisplay1; + private System.Windows.Forms.TextBox textBox1; + private System.Windows.Forms.Button button1; + private System.Windows.Forms.RichTextBox richTextBox1; + private System.Windows.Forms.Button button2; + private System.Windows.Forms.Button button3; + private System.Windows.Forms.Button button4; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.TextBox textBox3; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.TextBox textBox2; + private System.Windows.Forms.Button button5; + private System.Windows.Forms.Label label4; + private System.Windows.Forms.TextBox textBox5; + private System.Windows.Forms.Label label3; + private System.Windows.Forms.TextBox textBox4; + private System.Windows.Forms.GroupBox groupBox2; + private System.Windows.Forms.GroupBox groupBox1; + private System.Windows.Forms.Button button7; + private System.Windows.Forms.Label label9; + private System.Windows.Forms.TextBox textBox10; + private System.Windows.Forms.Label label8; + private System.Windows.Forms.TextBox textBox9; + private System.Windows.Forms.Button button6; + private System.Windows.Forms.Label label7; + private System.Windows.Forms.TextBox textBox8; + private System.Windows.Forms.Label label6; + private System.Windows.Forms.TextBox textBox7; + private System.Windows.Forms.Label label5; + private System.Windows.Forms.TextBox textBox6; + private System.Windows.Forms.CheckBox checkBox2; + private System.Windows.Forms.CheckBox checkBox1; + } +} + diff --git a/WaferAdjust/Form1.cs b/WaferAdjust/Form1.cs new file mode 100644 index 0000000..e0cef2d --- /dev/null +++ b/WaferAdjust/Form1.cs @@ -0,0 +1,322 @@ +using Cognex.VisionPro; +using Cognex.VisionPro.Caliper; +using Cognex.VisionPro.Dimensioning; +using Cognex.VisionPro.ImageFile; +using Cognex.VisionPro.ImageProcessing; +using Cognex.VisionPro.PMAlign; +using Cognex.VisionPro.ToolBlock; +using QWhale.Common; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Diagnostics; +using System.Drawing; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Windows.Forms; +using System.Windows.Interop; +using System.Xml.Serialization; + + +namespace WaferAdjust +{ + public partial class Form1 : Form + { + GetCircleToolBlock getCircleCameraToolBlock; + GetCircleToolBlock getCircleMachineToolBlock; + FitCircleToolBlock fitCircleCameraToolBlock; + FitCircleToolBlock FitCircleMachineToolBlock; + List m_circlePoints; + TranslateCirclePoint translateCirclePoint; + public Form1() + { + InitializeComponent(); + } + private void Form1_Load(object sender, EventArgs e) + { + try + { + getCircleCameraToolBlock = new GetCircleToolBlock(); + getCircleCameraToolBlock.OnGetCircleResult += GetCircleCameraToolBlock_OnGetCircleResult; + getCircleCameraToolBlock.OnToolReady += GetCircleCameraToolBlock_OnToolReady; + getCircleCameraToolBlock.Initialize("vpp\\GetCircleC.vpp"); + + fitCircleCameraToolBlock = new FitCircleToolBlock(); + fitCircleCameraToolBlock.OnFitCircleResult += FitCircleCameraToolBlock_OnFitCircleResult; + fitCircleCameraToolBlock.OnToolReady += FitCircleCameraToolBlock_OnToolReady; + fitCircleCameraToolBlock.Initialize("vpp\\FitCircleC.vpp"); + + getCircleMachineToolBlock = new GetCircleToolBlock(); + getCircleMachineToolBlock.OnGetCircleResult += GetCircleMachineToolBlock_OnGetCircleResult; + getCircleMachineToolBlock.OnToolReady += GetCircleMachineToolBlock_OnToolReady; + getCircleMachineToolBlock.Initialize("vpp\\GetCircleM.vpp"); + + FitCircleMachineToolBlock = new FitCircleToolBlock(); + FitCircleMachineToolBlock.OnFitCircleResult += FitCircleMachineToolBlock_OnFitCircleResult; + FitCircleMachineToolBlock.OnToolReady += FitCircleMachineToolBlock_OnToolReady; + FitCircleMachineToolBlock.Initialize("vpp\\FitCircleM.vpp"); + + translateCirclePoint = new TranslateCirclePoint(); + + m_graphics2 = new CogGraphicCollection(); + } + catch (Exception ex) + { + MessageBox.Show(ex.Message); + } + } + + private void FitCircleMachineToolBlock_OnToolReady(bool ready) + { + + } + + private void FitCircleMachineToolBlock_OnFitCircleResult(double x, double y, double rms) + { + CogPointMarker marker_1 = new CogPointMarker(); + + marker_1.X = x; + marker_1.Y = y; + marker_1.Color = CogColorConstants.Green; + marker_1.Interactive = false; + m_graphics2.Add(marker_1); + + CogPointMarker marker_2 = new CogPointMarker(); + + marker_2.X = Convert.ToDouble(textBox4.Text); + marker_2.Y = Convert.ToDouble(textBox5.Text); + marker_2.Color = CogColorConstants.Red; + marker_2.Interactive = false; + m_graphics2.Add(marker_2); + + ShowMessage($"{Environment.NewLine}X:{x}, Y:{y}, RMS:{rms}{Environment.NewLine}"); + ShowMessage($"{Environment.NewLine}DiffX:{x - Convert.ToDouble(textBox4.Text)}, DiffY:{y - Convert.ToDouble(textBox5.Text)}, RMS:{rms}{Environment.NewLine}"); + ImageDisplay(FitCircleMachineToolBlock.FitCircleImage); + ImageDisplay(m_graphics); + ImageDisplay(m_graphics2); + ImageDisplayFit(); + } + + private void GetCircleMachineToolBlock_OnToolReady(bool ready) + { + + } + + private void GetCircleMachineToolBlock_OnGetCircleResult(double x, double y, double r) + { + translateCirclePoint.AddCircleCenter(x, y, r); + translateCirclePoint.AddCirclePoint(getCircleMachineToolBlock.PointInfos); + ShowMessage($"X:{x}, Y:{y}, R:{r}{Environment.NewLine}"); + } + + private void FitCircleCameraToolBlock_OnToolReady(bool ready) + { + + } + + private void FitCircleCameraToolBlock_OnFitCircleResult(double x, double y, double rms) + { + CogPointMarker marker_1 = new CogPointMarker(); + + marker_1.X = x; + marker_1.Y = y; + marker_1.Color = CogColorConstants.Green; + marker_1.Interactive = false; + m_graphics2.Add(marker_1); + ShowMessage($"{Environment.NewLine}X:{x}, Y:{y}, RMS:{rms}{Environment.NewLine}"); + ImageDisplay(fitCircleCameraToolBlock.FitCircleImage); + ImageDisplay(m_graphics); + ImageDisplay(m_graphics2); + ImageDisplayFit(); + } + + private void GetCircleCameraToolBlock_OnToolReady(bool ready) + { + + } + + private void GetCircleCameraToolBlock_OnGetCircleResult(double x, double y, double r) + { + ShowMessage($"X:{x}, Y:{y}, R:{r}{Environment.NewLine}"); + m_circlePoints.Add(new PointInfo(x, y, r)); + } + + private void Form1_FormClosing(object sender, FormClosingEventArgs e) + { + + } + Bitmap m_lastBMP = null; + private string m_lastPath = ""; + private void button1_Click(object sender, EventArgs e) + { + richTextBox1.Clear(); + using (FolderBrowserDialog folderBrowserDialog = new FolderBrowserDialog()) + { + if (m_lastPath != "") + folderBrowserDialog.SelectedPath = m_lastPath; + if (folderBrowserDialog.ShowDialog() == DialogResult.OK) + { + m_lastPath = folderBrowserDialog.SelectedPath; + textBox1.Text = Path.GetFileName(m_lastPath); + } + else + { + m_lastPath = ""; + textBox1.Text = ""; + } + } + } + CogGraphicCollection m_graphics; + CogGraphicCollection m_graphics2; + private void button2_Click(object sender, EventArgs e) + { + if (!Directory.Exists(m_lastPath)) + return; + + ShowMessage("计算相机坐标系下各圆弧的圆中心:\n"); + m_circlePoints = new List(); + string[] files = Directory.GetFiles(m_lastPath, "*.bmp"); + foreach (string file in files) + { + Bitmap bmp = new Bitmap(file); + m_lastBMP = bmp; + getCircleCameraToolBlock.Run(bmp); + } + + if (m_circlePoints == null || m_circlePoints.Count < 4) + return; + if (m_lastBMP == null) + return; + ShowMessage("计算相机坐标系下各圆弧的圆中心拟合出的旋转中心:\n"); + var aa = m_circlePoints;//.OrderBy(x => x.Radius).Skip(2).Take(m_circlePoints.Count - 4).ToList(); + m_graphics = new CogGraphicCollection(); + foreach (PointInfo pointInfo in aa) + { + CogPointMarker marker_1 = new CogPointMarker();//圆 + + marker_1.X = pointInfo.X; + marker_1.Y = pointInfo.Y; + marker_1.Color = CogColorConstants.Green; + marker_1.Interactive = false; + m_graphics.Add(marker_1); + } + fitCircleCameraToolBlock.Run(m_lastBMP, aa); + } + private void ImageDisplay(CogImage8Grey img) + { + if (InvokeRequired) + { + BeginInvoke(new Action(() => ImageDisplay(img))); + return; + } + cogRecordDisplay1.Image = img; + cogRecordDisplay1.StaticGraphics.Clear(); + } + private void ImageDisplay(CogGraphicCollection graphics) + { + if (InvokeRequired) + { + BeginInvoke(new Action(() => ImageDisplay(graphics))); + return; + } + cogRecordDisplay1.StaticGraphics.AddList(graphics, ""); + } + private void ImageDisplayFit() + { + if (InvokeRequired) + { + BeginInvoke(new Action(() => ImageDisplayFit())); + return; + } + cogRecordDisplay1.Fit(true); + } + + private void button3_Click(object sender, EventArgs e) + { + m_graphics2?.Clear(); + } + public void ShowMessage(string message) + { + if (InvokeRequired) + { + BeginInvoke(new Action(ShowMessage), message); + return; + } + if (richTextBox1.Lines.Length > 2000) + richTextBox1.Clear(); + richTextBox1.AppendText(message); + richTextBox1.ScrollToCaret(); + } + + private void button4_Click(object sender, EventArgs e) + { + if (!Directory.Exists(m_lastPath)) + return; + ShowMessage("计算相机坐标系下各圆弧的圆中心:\n"); + m_circlePoints = new List(); + string[] files = Directory.GetFiles(m_lastPath, "*.bmp"); + foreach (string file in files) + { + Bitmap bmp = new Bitmap(file); + m_lastBMP = bmp; + getCircleCameraToolBlock.Run(bmp); + } + } + + private void button5_Click(object sender, EventArgs e) + { + if (!Directory.Exists(m_lastPath)) + return; + ShowMessage("读取机械坐标系下圆弧各点的坐标:\n"); + translateCirclePoint.SetRotateXY(Convert.ToDouble(textBox4.Text), Convert.ToDouble(textBox5.Text), 360 * Convert.ToDouble(textBox2.Text)/Convert.ToDouble(textBox3.Text)); + string[] files = Directory.GetFiles(m_lastPath, "*.bmp"); + foreach (string file in files) + { + Bitmap bmp = new Bitmap(file); + m_lastBMP = bmp; + translateCirclePoint.AddCircleIndex(); + getCircleMachineToolBlock.Run(m_lastBMP); + } + + ShowMessage("转换机械坐标系下圆弧各点的原始坐标:\n"); + var points = translateCirclePoint.DoTranslatePoint(); + + ShowMessage("拟合机械坐标系下的圆中心:\n"); + m_graphics = new CogGraphicCollection(); + m_graphics2 = new CogGraphicCollection(); + foreach (PointInfo pointInfo in points) + { + CogPointMarker marker_1 = new CogPointMarker();//圆 + + marker_1.X = pointInfo.X; + marker_1.Y = pointInfo.Y; + marker_1.Color = CogColorConstants.Green; + marker_1.Interactive = false; + m_graphics.Add(marker_1); + } + FitCircleMachineToolBlock.Run(m_lastBMP, points); + } + + private void button6_Click(object sender, EventArgs e) + { + var res = Rotation2D.RotatePointDegrees(Convert.ToDouble(textBox6.Text), Convert.ToDouble(textBox7.Text), + Convert.ToDouble(textBox4.Text), Convert.ToDouble(textBox5.Text), Convert.ToDouble(textBox8.Text), + checkBox1.Checked, checkBox2.Checked); + textBox9.Text = Math.Round(res.x, 3).ToString(); + textBox10.Text = Math.Round(res.y, 3).ToString(); + } + + private void button7_Click(object sender, EventArgs e) + { + var res = Rotation2D.GetOriginalPointDegrees(Convert.ToDouble(textBox9.Text), Convert.ToDouble(textBox10.Text), + Convert.ToDouble(textBox4.Text), Convert.ToDouble(textBox5.Text), Convert.ToDouble(textBox8.Text), + checkBox1.Checked, checkBox2.Checked); + textBox6.Text = Math.Round(res.x, 3).ToString(); + textBox7.Text = Math.Round(res.y, 3).ToString(); + } + } +} diff --git a/WaferAdjust/Form1.resx b/WaferAdjust/Form1.resx new file mode 100644 index 0000000..e66ae10 --- /dev/null +++ b/WaferAdjust/Form1.resx @@ -0,0 +1,131 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w + LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACFTeXN0 + ZW0uV2luZG93cy5Gb3Jtcy5BeEhvc3QrU3RhdGUBAAAABERhdGEHAgIAAAAJAwAAAA8DAAAAtwAAAAIB + AAAAAQAAAAAAAAAAAAAAAKIAAAAAAQAAeFsAAKw5AAATAAoKZAALAAAACwAAAAsA//8DAAAAAAADAAEA + AAAFAAAAAAAAAAAABQAAAAAAAAAAAAUAAAAAAAAA8D8TAAAAwAALAP//CwD//xMAAIAAAAMAAwAAAAsA + //8LAAAAAAAAAAAA4D8AAAAAAADgPwAAAAAAAOA/AAAAAAAA4D8BAAAAAQAAAAsA//8LAAAACwAAAAsA + //8L + + + \ No newline at end of file diff --git a/WaferAdjust/GetCircleToolBlock.cs b/WaferAdjust/GetCircleToolBlock.cs new file mode 100644 index 0000000..9de918e --- /dev/null +++ b/WaferAdjust/GetCircleToolBlock.cs @@ -0,0 +1,98 @@ +using Cognex.VisionPro; +using Cognex.VisionPro.Caliper; +using Cognex.VisionPro.ToolBlock; +using QWhale.Common; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace WaferAdjust +{ + public delegate void OnGetCircleResult(double x, double y, double r); + public delegate void OnToolReady(bool ready); + internal class GetCircleToolBlock + { + private CogToolBlock cogToolBlock; + private bool initialized = false; + public event OnToolReady OnToolReady; + public event OnGetCircleResult OnGetCircleResult; + public List PointInfos; + public void Initialize(string vpp) + { + try + { + if (cogToolBlock != null) + { + cogToolBlock.Ran -= CogToolBlock_Ran; + cogToolBlock.Dispose(); + cogToolBlock = null; + } + initialized = false; + PointInfos = new List(); + cogToolBlock = CogSerializer.LoadObjectFromFile(vpp) as CogToolBlock; + cogToolBlock.Ran += CogToolBlock_Ran; + initialized = true; + OnToolReady?.Invoke(initialized); + LogHelper.LogInfo($"{vpp} initialized successfully: " + vpp); + } + catch (Exception ex) + { + LogHelper.LogError(ex.Message); + } + } + private void CogToolBlock_Ran(object sender, EventArgs e) + { + try + { + CogFindCircleTool cogFindCircleTool = cogToolBlock.Tools["CogFindCircleTool1"] as CogFindCircleTool; + PointInfos.Clear(); + + if (cogFindCircleTool.Results != null) + { + foreach (CogFindCircleResult item in cogFindCircleTool.Results) + { + if (item.Found && item.Used) + PointInfos.Add(new PointInfo(item.X, item.Y, item.DistanceToCircle)); + } + } + + OnGetCircleResult?.Invoke(Math.Round((double)cogToolBlock.Outputs["CenterX"].Value, 3), + Math.Round((double)cogToolBlock.Outputs["CenterY"].Value, 3), + Math.Round((double)cogToolBlock.Outputs["Radius"].Value, 3)); + } + catch (Exception ex) + { + LogHelper.LogError(ex.Message + ex.StackTrace); + } + } + public void Run(Bitmap bmp) + { + try + { + CogImage8Grey image8Grey = new CogImage8Grey(bmp); + cogToolBlock.Inputs["OutputImage"].Value = image8Grey; + cogToolBlock.Run(); + } + catch (Exception ex) + { + LogHelper.LogError("ScanToolBlock Run Error: " + ex.Message); + } + } + public bool Ready() + { + return initialized; + } + public void Stop() + { + if (cogToolBlock != null) + { + cogToolBlock.Ran -= CogToolBlock_Ran; + cogToolBlock.Dispose(); + cogToolBlock = null; + } + } + } +} diff --git a/WaferAdjust/LogHelper.cs b/WaferAdjust/LogHelper.cs new file mode 100644 index 0000000..da64197 --- /dev/null +++ b/WaferAdjust/LogHelper.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using NLog; + +namespace WaferAdjust +{ + public class LogHelper + { + private static readonly ILogger Logger = LogManager.GetCurrentClassLogger(); + public static void LogInfo(string message) + { + Logger.Info(message); + } + public static void LogError(string message) + { + Logger.Error(message); + } + } +} diff --git a/WaferAdjust/Nlog.config b/WaferAdjust/Nlog.config new file mode 100644 index 0000000..3635098 --- /dev/null +++ b/WaferAdjust/Nlog.config @@ -0,0 +1,14 @@ + + + + + + + + + + \ No newline at end of file diff --git a/WaferAdjust/PointInfo.cs b/WaferAdjust/PointInfo.cs new file mode 100644 index 0000000..4e3a830 --- /dev/null +++ b/WaferAdjust/PointInfo.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace WaferAdjust +{ + internal class PointInfo + { + public double X; + public double Y; + public double Radius; + public PointInfo(double x, double y, double radius) + { + X = x; + Y = y; + Radius = radius; + } + } +} diff --git a/WaferAdjust/Program.cs b/WaferAdjust/Program.cs new file mode 100644 index 0000000..3c18c0d --- /dev/null +++ b/WaferAdjust/Program.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace WaferAdjust +{ + static class Program + { + /// + /// 应用程序的主入口点。 + /// + [STAThread] + static void Main() + { + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + Application.Run(new Form1()); + } + } +} diff --git a/WaferAdjust/Properties/AssemblyInfo.cs b/WaferAdjust/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..3253d90 --- /dev/null +++ b/WaferAdjust/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// 有关程序集的常规信息通过以下 +// 特性集控制。更改这些特性值可修改 +// 与程序集关联的信息。 +[assembly: AssemblyTitle("WaferAdjust")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("HP Inc.")] +[assembly: AssemblyProduct("WaferAdjust")] +[assembly: AssemblyCopyright("Copyright © HP Inc. 2024")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// 将 ComVisible 设置为 false 使此程序集中的类型 +// 对 COM 组件不可见。 如果需要从 COM 访问此程序集中的类型, +// 则将该类型上的 ComVisible 特性设置为 true。 +[assembly: ComVisible(false)] + +// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID +[assembly: Guid("1e41d94a-8082-46d2-83cd-92d60d48d97a")] + +// 程序集的版本信息由下面四个值组成: +// +// 主版本 +// 次版本 +// 生成号 +// 修订号 +// +// 可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值, +// 方法是按如下所示使用“*”: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/WaferAdjust/Properties/Resources.Designer.cs b/WaferAdjust/Properties/Resources.Designer.cs new file mode 100644 index 0000000..c84f52d --- /dev/null +++ b/WaferAdjust/Properties/Resources.Designer.cs @@ -0,0 +1,63 @@ +//------------------------------------------------------------------------------ +// +// 此代码由工具生成。 +// 运行时版本:4.0.30319.42000 +// +// 对此文件的更改可能会导致不正确的行为,并且如果 +// 重新生成代码,这些更改将会丢失。 +// +//------------------------------------------------------------------------------ + +namespace WaferAdjust.Properties { + using System; + + + /// + /// 一个强类型的资源类,用于查找本地化的字符串等。 + /// + // 此类是由 StronglyTypedResourceBuilder + // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。 + // 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen + // (以 /str 作为命令选项),或重新生成 VS 项目。 + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// 返回此类使用的缓存的 ResourceManager 实例。 + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("WaferAdjust.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// 重写当前线程的 CurrentUICulture 属性,对 + /// 使用此强类型资源类的所有资源查找执行重写。 + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + } +} diff --git a/WaferAdjust/Properties/Resources.resx b/WaferAdjust/Properties/Resources.resx new file mode 100644 index 0000000..af7dbeb --- /dev/null +++ b/WaferAdjust/Properties/Resources.resx @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/WaferAdjust/Properties/Settings.Designer.cs b/WaferAdjust/Properties/Settings.Designer.cs new file mode 100644 index 0000000..aed83d9 --- /dev/null +++ b/WaferAdjust/Properties/Settings.Designer.cs @@ -0,0 +1,26 @@ +//------------------------------------------------------------------------------ +// +// 此代码由工具生成。 +// 运行时版本:4.0.30319.42000 +// +// 对此文件的更改可能会导致不正确的行为,并且如果 +// 重新生成代码,这些更改将会丢失。 +// +//------------------------------------------------------------------------------ + +namespace WaferAdjust.Properties { + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.14.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default { + get { + return defaultInstance; + } + } + } +} diff --git a/WaferAdjust/Properties/Settings.settings b/WaferAdjust/Properties/Settings.settings new file mode 100644 index 0000000..3964565 --- /dev/null +++ b/WaferAdjust/Properties/Settings.settings @@ -0,0 +1,7 @@ + + + + + + + diff --git a/WaferAdjust/Rotation2D.cs b/WaferAdjust/Rotation2D.cs new file mode 100644 index 0000000..d310406 --- /dev/null +++ b/WaferAdjust/Rotation2D.cs @@ -0,0 +1,176 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace WaferAdjust +{ + /// + /// 二维坐标旋转计算器(支持自定义坐标系方向) + /// + public class Rotation2D + { + #region 正向旋转:求旋转后的坐标 + + /// + /// 点A绕点B逆时针旋转指定角度(角度制) + /// + /// 点A的X坐标 + /// 点A的Y坐标 + /// 旋转中心B的X坐标 + /// 旋转中心B的Y坐标 + /// 旋转角度(角度制,逆时针) + /// X轴正方向是否向右(默认true) + /// Y轴正方向是否向上(默认true) + /// 旋转后的点A'坐标 (x', y') + public static (double x, double y) RotatePointDegrees( + double ax, double ay, + double bx, double by, + double angleDegrees, + bool isRight = true, + bool isUp = true) + { + return RotatePointRadians(ax, ay, bx, by, + DegreesToRadians(angleDegrees), isRight, isUp); + } + + /// + /// 点A绕点B逆时针旋转指定角度(弧度制) + /// + /// 点A的X坐标 + /// 点A的Y坐标 + /// 旋转中心B的X坐标 + /// 旋转中心B的Y坐标 + /// 旋转角度(弧度制,逆时针) + /// X轴正方向是否向右(默认true) + /// Y轴正方向是否向上(默认true) + /// 旋转后的点A'坐标 (x', y') + public static (double x, double y) RotatePointRadians( + double ax, double ay, + double bx, double by, + double angleRadians, + bool isRight = true, + bool isUp = true) + { + // 1. 转换为标准数学坐标系(向右为正,向上为正) + double mathAx = isRight ? ax : -ax; + double mathAy = isUp ? ay : -ay; + double mathBx = isRight ? bx : -bx; + double mathBy = isUp ? by : -by; + + // 2. 在标准坐标系中执行旋转 + double cosR = Math.Cos(angleRadians); + double sinR = Math.Sin(angleRadians); + + double dx = mathAx - mathBx; + double dy = mathAy - mathBy; + + double rotatedDx = dx * cosR - dy * sinR; + double rotatedDy = dx * sinR + dy * cosR; + + double mathNewX = mathBx + rotatedDx; + double mathNewY = mathBy + rotatedDy; + + // 3. 转换回用户指定的坐标系 + double outputX = isRight ? mathNewX : -mathNewX; + double outputY = isUp ? mathNewY : -mathNewY; + + return (outputX, outputY); + } + + #endregion + + #region 反向旋转:求旋转前的原始坐标 + + /// + /// 已知旋转后的点A',求绕点B逆时针旋转前的原始点A(角度制) + /// + /// 旋转后的点A'的X坐标 + /// 旋转后的点A'的Y坐标 + /// 旋转中心B的X坐标 + /// 旋转中心B的Y坐标 + /// 旋转角度(角度制,逆时针) + /// X轴正方向是否向右(默认true) + /// Y轴正方向是否向上(默认true) + /// 原始的未旋转点A坐标 (x, y) + public static (double x, double y) GetOriginalPointDegrees( + double rotatedX, double rotatedY, + double bx, double by, + double angleDegrees, + bool isRight = true, + bool isUp = true) + { + return GetOriginalPointRadians(rotatedX, rotatedY, bx, by, + DegreesToRadians(angleDegrees), isRight, isUp); + } + + /// + /// 已知旋转后的点A',求绕点B逆时针旋转前的原始点A(弧度制) + /// + /// 旋转后的点A'的X坐标 + /// 旋转后的点A'的Y坐标 + /// 旋转中心B的X坐标 + /// 旋转中心B的Y坐标 + /// 旋转角度(弧度制,逆时针) + /// X轴正方向是否向右(默认true) + /// Y轴正方向是否向上(默认true) + /// 原始的未旋转点A坐标 (x, y) + public static (double x, double y) GetOriginalPointRadians( + double rotatedX, double rotatedY, + double bx, double by, + double angleRadians, + bool isRight = true, + bool isUp = true) + { + // 1. 转换为标准数学坐标系 + double mathRotatedX = isRight ? rotatedX : -rotatedX; + double mathRotatedY = isUp ? rotatedY : -rotatedY; + double mathBx = isRight ? bx : -bx; + double mathBy = isUp ? by : -by; + + // 2. 在标准坐标系中执行反向旋转 + double cosR = Math.Cos(angleRadians); + double sinR = Math.Sin(angleRadians); + + double dx = mathRotatedX - mathBx; + double dy = mathRotatedY - mathBy; + + // 反向旋转(相当于顺时针旋转) + double originalDx = dx * cosR + dy * sinR; + double originalDy = -dx * sinR + dy * cosR; + + double mathOriginalX = mathBx + originalDx; + double mathOriginalY = mathBy + originalDy; + + // 3. 转换回用户指定的坐标系 + double outputX = isRight ? mathOriginalX : -mathOriginalX; + double outputY = isUp ? mathOriginalY : -mathOriginalY; + + return (outputX, outputY); + } + + #endregion + + #region 辅助方法 + + /// + /// 角度转弧度 + /// + private static double DegreesToRadians(double degrees) + { + return degrees * Math.PI / 180.0; + } + + /// + /// 弧度转角度(公共方法,供外部使用) + /// + public static double RadiansToDegrees(double radians) + { + return radians * 180.0 / Math.PI; + } + + #endregion + } + +} diff --git a/WaferAdjust/TranslateCirclePoint.cs b/WaferAdjust/TranslateCirclePoint.cs new file mode 100644 index 0000000..8b3f7e8 --- /dev/null +++ b/WaferAdjust/TranslateCirclePoint.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace WaferAdjust +{ + internal class TranslateCirclePoint + { + private double rotateX; + private double rotateY; + List totalPoints; + List totalCenters; + private int circleIndex; + private double perAngle; + public void SetRotateXY(double x, double y, double angle) + { + rotateX = x; rotateY = y; + totalPoints = new List(); + totalCenters = new List(); + circleIndex = 0; + perAngle = angle; + } + public void AddCirclePoint(List pointInfos) + { + foreach (var item in pointInfos) + { + totalPoints.Add(new PointInfo(item.X, item.Y, circleIndex * perAngle)); + } + } + public void AddCircleIndex() + { + circleIndex++; + } + public void AddCircleCenter(double x, double y, double r) + { + totalCenters.Add(new PointInfo(x, y, r)); + } + public List DoTranslatePoint() + { + List trans = new List(); + foreach (var item in totalPoints) + { + var res = Rotation2D.GetOriginalPointDegrees(item.X, item.Y, + rotateX, rotateY, item.Radius, true, false); + Console.WriteLine($"{item.X} {item.Y} {item.Radius} ==> {res.x} {res.y}"); + trans.Add(new PointInfo(res.x, res.y, item.Radius)); + } + return trans; + } + } +} diff --git a/WaferAdjust/WaferAdjust.csproj b/WaferAdjust/WaferAdjust.csproj new file mode 100644 index 0000000..2c3ca24 --- /dev/null +++ b/WaferAdjust/WaferAdjust.csproj @@ -0,0 +1,148 @@ + + + + + Debug + AnyCPU + {941B8ABC-436F-457D-95DA-A79E23C8CA5D} + WinExe + Properties + WaferAdjust + WaferAdjust + v4.8 + 512 + true + + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + true + bin\x64\Debug\ + DEBUG;TRACE + full + x64 + 7.3 + prompt + true + + + bin\x64\Release\ + TRACE + true + pdbonly + x64 + 7.3 + prompt + true + + + + + + + + + + + + + + + + + + + + ..\packages\NLog.6.0.6\lib\net46\NLog.dll + + + + + + + + + + + + + + + + + + + + + + + + + + Form + + + Form1.cs + + + + + + + + + + Form1.cs + + + ResXFileCodeGenerator + Resources.Designer.cs + Designer + + + True + Resources.resx + True + + + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + True + Settings.settings + True + + + + + + + + \ No newline at end of file diff --git a/WaferAdjust/packages.config b/WaferAdjust/packages.config new file mode 100644 index 0000000..e772309 --- /dev/null +++ b/WaferAdjust/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file