diff --git a/WaferAlignment/Camera.cs b/WaferAlignment/Camera.cs
index 0b75418..81441cc 100644
--- a/WaferAlignment/Camera.cs
+++ b/WaferAlignment/Camera.cs
@@ -161,7 +161,6 @@ namespace WaferAlignment
_dev.MV_CC_SetEnumValue_NET("TriggerSource", (uint)MyCamera.MV_CAM_TRIGGER_SOURCE.MV_TRIGGER_SOURCE_SOFTWARE);
_dev.MV_CC_StartGrabbing_NET();
_dev.MV_CC_TriggerSoftwareExecute_NET();
- Thread.Sleep(100);
}
public void Stop()
@@ -195,7 +194,7 @@ namespace WaferAlignment
try
{
_startAcqToken.Cancel();
- Thread.Sleep(20);
+ Thread.Sleep(200);
_imageAcquisitionTask.Wait(_stopAcqToken.Token);
_imageAcquisitionTask.Dispose();
}
diff --git a/WaferAlignment/DataPostbox.cs b/WaferAlignment/DataPostbox.cs
index d814cad..ef69a56 100644
--- a/WaferAlignment/DataPostbox.cs
+++ b/WaferAlignment/DataPostbox.cs
@@ -16,7 +16,7 @@ namespace ConVX.VXData
///
/// 判断线程状态
///
- private AutoResetEvent _autoReset = null;
+ //private AutoResetEvent _autoReset = null;
///
/// 线程
///
@@ -53,7 +53,7 @@ namespace ConVX.VXData
public DataPostbox()
{
_queue = new ConcurrentQueue();
- _autoReset = new AutoResetEvent(false);//线程非终止状态
+ //_autoReset = new AutoResetEvent(false);//线程非终止状态
}
///
/// 启动派发
@@ -72,7 +72,7 @@ namespace ConVX.VXData
try
{
RuningToken.Cancel();
- _autoReset.Set();//为了避免线程正在执行或等待状态
+ //_autoReset.Set();//为了避免线程正在执行或等待状态
await _task;
}
catch (OperationCanceledException ex)
@@ -98,7 +98,7 @@ namespace ConVX.VXData
//}
_queue.Enqueue(envelope);
- _autoReset.Set();
+ //_autoReset.Set();
}
#endregion
@@ -110,7 +110,8 @@ namespace ConVX.VXData
{
if (_queue.IsEmpty)
{
- _autoReset.WaitOne();
+ //_autoReset.WaitOne();
+ Thread.Sleep(1);
}
else
{
diff --git a/WaferAlignment/FitCircleToolBlock.cs b/WaferAlignment/FitCircleToolBlock.cs
new file mode 100644
index 0000000..a1ab1a9
--- /dev/null
+++ b/WaferAlignment/FitCircleToolBlock.cs
@@ -0,0 +1,101 @@
+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;
+using System.Windows.Documents;
+
+namespace WaferAdjust
+{
+ public delegate void OnFitCircleResult(double x, double y, double r, 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["Radius"].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);
+ Run(image8Grey, pointInfos);
+ }
+ catch (Exception ex)
+ {
+ LogHelper.LogError("ScanToolBlock Run Error: " + ex.Message);
+ }
+ }
+ public void Run(CogImage8Grey image8Grey, List pointInfos)
+ {
+ try
+ {
+ 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/WaferAlignment/Form1.Designer.cs b/WaferAlignment/Form1.Designer.cs
index 80069f2..56f5ec1 100644
--- a/WaferAlignment/Form1.Designer.cs
+++ b/WaferAlignment/Form1.Designer.cs
@@ -68,6 +68,10 @@
this.nud_SizeX = new System.Windows.Forms.NumericUpDown();
this.btn_Action = new System.Windows.Forms.Button();
this.btn_ToZero = new System.Windows.Forms.Button();
+ this.textBox2 = new System.Windows.Forms.TextBox();
+ this.label1 = new System.Windows.Forms.Label();
+ this.textBox3 = new System.Windows.Forms.TextBox();
+ this.label2 = new System.Windows.Forms.Label();
((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit();
this.splitContainer1.Panel1.SuspendLayout();
this.splitContainer1.Panel2.SuspendLayout();
@@ -93,6 +97,10 @@
//
// splitContainer1.Panel2
//
+ this.splitContainer1.Panel2.Controls.Add(this.textBox2);
+ this.splitContainer1.Panel2.Controls.Add(this.label1);
+ this.splitContainer1.Panel2.Controls.Add(this.textBox3);
+ this.splitContainer1.Panel2.Controls.Add(this.label2);
this.splitContainer1.Panel2.Controls.Add(this.lbl_Time);
this.splitContainer1.Panel2.Controls.Add(this.txt_Time);
this.splitContainer1.Panel2.Controls.Add(this.lbl_Times);
@@ -167,7 +175,7 @@
// lbl_Times
//
this.lbl_Times.AutoSize = true;
- this.lbl_Times.Location = new System.Drawing.Point(234, 15);
+ this.lbl_Times.Location = new System.Drawing.Point(182, 17);
this.lbl_Times.Name = "lbl_Times";
this.lbl_Times.Size = new System.Drawing.Size(89, 12);
this.lbl_Times.TabIndex = 30;
@@ -175,7 +183,7 @@
//
// txt_Times
//
- this.txt_Times.Location = new System.Drawing.Point(326, 12);
+ this.txt_Times.Location = new System.Drawing.Point(274, 14);
this.txt_Times.Name = "txt_Times";
this.txt_Times.ReadOnly = true;
this.txt_Times.Size = new System.Drawing.Size(129, 21);
@@ -383,9 +391,9 @@
//
// btn_RunTest
//
- this.btn_RunTest.Location = new System.Drawing.Point(481, 12);
+ this.btn_RunTest.Location = new System.Drawing.Point(409, 14);
this.btn_RunTest.Name = "btn_RunTest";
- this.btn_RunTest.Size = new System.Drawing.Size(161, 23);
+ this.btn_RunTest.Size = new System.Drawing.Size(119, 23);
this.btn_RunTest.TabIndex = 9;
this.btn_RunTest.Text = "启动检测";
this.btn_RunTest.UseVisualStyleBackColor = true;
@@ -444,6 +452,7 @@
0,
0,
-2147483648});
+ this.nud_SizeY.ValueChanged += new System.EventHandler(this.nud_SizeY_ValueChanged);
//
// lbl_X
//
@@ -458,8 +467,13 @@
//
this.nud_SizeX.DecimalPlaces = 2;
this.nud_SizeX.Location = new System.Drawing.Point(80, 137);
+ this.nud_SizeX.Maximum = new decimal(new int[] {
+ 6,
+ 0,
+ 0,
+ 0});
this.nud_SizeX.Minimum = new decimal(new int[] {
- 100,
+ 8,
0,
0,
-2147483648});
@@ -471,6 +485,7 @@
0,
0,
0});
+ this.nud_SizeX.ValueChanged += new System.EventHandler(this.nud_SizeX_ValueChanged);
//
// btn_Action
//
@@ -484,7 +499,7 @@
//
// btn_ToZero
//
- this.btn_ToZero.Location = new System.Drawing.Point(17, 99);
+ this.btn_ToZero.Location = new System.Drawing.Point(17, 95);
this.btn_ToZero.Name = "btn_ToZero";
this.btn_ToZero.Size = new System.Drawing.Size(161, 23);
this.btn_ToZero.TabIndex = 0;
@@ -492,6 +507,42 @@
this.btn_ToZero.UseVisualStyleBackColor = true;
this.btn_ToZero.Click += new System.EventHandler(this.btn_ToZero_Click);
//
+ // textBox2
+ //
+ this.textBox2.Location = new System.Drawing.Point(534, 22);
+ this.textBox2.Name = "textBox2";
+ this.textBox2.Size = new System.Drawing.Size(55, 21);
+ this.textBox2.TabIndex = 33;
+ this.textBox2.Text = "82";
+ this.textBox2.TextChanged += new System.EventHandler(this.textBox2_TextChanged);
+ //
+ // label1
+ //
+ this.label1.AutoSize = true;
+ this.label1.Location = new System.Drawing.Point(532, 7);
+ this.label1.Name = "label1";
+ this.label1.Size = new System.Drawing.Size(53, 12);
+ this.label1.TabIndex = 34;
+ this.label1.Text = "相机计数";
+ //
+ // textBox3
+ //
+ this.textBox3.Location = new System.Drawing.Point(595, 22);
+ this.textBox3.Name = "textBox3";
+ this.textBox3.Size = new System.Drawing.Size(55, 21);
+ this.textBox3.TabIndex = 35;
+ this.textBox3.Text = "4096";
+ this.textBox3.TextChanged += new System.EventHandler(this.textBox3_TextChanged);
+ //
+ // label2
+ //
+ this.label2.AutoSize = true;
+ this.label2.Location = new System.Drawing.Point(593, 7);
+ this.label2.Name = "label2";
+ this.label2.Size = new System.Drawing.Size(41, 12);
+ this.label2.TabIndex = 36;
+ this.label2.Text = "总计数";
+ //
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
@@ -556,7 +607,10 @@
private System.Windows.Forms.DataGridViewTextBoxColumn Column4;
private System.Windows.Forms.Label lbl_Time;
private System.Windows.Forms.TextBox txt_Time;
-
+ private System.Windows.Forms.TextBox textBox2;
+ private System.Windows.Forms.Label label1;
+ private System.Windows.Forms.TextBox textBox3;
+ private System.Windows.Forms.Label label2;
}
}
diff --git a/WaferAlignment/Form1.cs b/WaferAlignment/Form1.cs
index 2b027bd..6accad2 100644
--- a/WaferAlignment/Form1.cs
+++ b/WaferAlignment/Form1.cs
@@ -19,6 +19,7 @@ using System.Windows.Forms;
using System.Xml.Serialization;
using System.Diagnostics;
using Cognex.VisionPro.PMAlign;
+using WaferAdjust;
namespace WaferAlignment
@@ -54,20 +55,12 @@ namespace WaferAlignment
///
string arAngle = "DB7.DBD76";//设置触发拍照的偏转角度
+ GetCircleToolBlock getCircleMachineToolBlock;
+ FitCircleToolBlock FitCircleMachineToolBlock;
+ TranslateCirclePoint translateCirclePoint;
+ CogGraphicCollection m_graphics;
+ CogGraphicCollection m_graphics2;
-
- string vppPath;
- CogToolBlock mTB;
- CogToolBlock mTB_1;
- CogToolBlock mTB_2;
-
-
- float R = 11.25F;//1024->12
- //CogImage8Grey OutputImg;
-
- //旋转中心的坐标应将标定的数据保存后获取
- double circleCenterX;
- double circleCenterY;
//XML文件读取与写入
ConfigStore _ConfigStore = new ConfigStore();
CenterOfRotation _center = new CenterOfRotation();
@@ -123,7 +116,6 @@ namespace WaferAlignment
_s7.SetValue(arSizeX, (float)0);
_s7.SetValue(arSizeY, (float)0);
_s7.SetValue(arSizeR, (float)0);
- _s7.SetValue(arAngle, Convert.ToSingle(R));//角度为10
lbl_CommunState.BackColor = Color.Lime;
lbl_CommunState.Text = "已连接";
}
@@ -150,9 +142,16 @@ namespace WaferAlignment
try
{
// 加载VPP文件
- vppPath = Path.Combine(System.AppDomain.CurrentDomain.SetupInformation.ApplicationBase, "vpp", "ToolBlock.vpp");
+ getCircleMachineToolBlock = new GetCircleToolBlock();
+ getCircleMachineToolBlock.OnGetCircleResult += GetCircleMachineToolBlock_OnGetCircleResult;
+ getCircleMachineToolBlock.OnGetNashResult += GetCircleMachineToolBlock_OnGetNashResult;
+ getCircleMachineToolBlock.OnToolReady += GetCircleMachineToolBlock_OnToolReady;
- mTB = CogSerializer.LoadObjectFromFile(vppPath) as CogToolBlock;
+ FitCircleMachineToolBlock = new FitCircleToolBlock();
+ FitCircleMachineToolBlock.OnFitCircleResult += FitCircleMachineToolBlock_OnFitCircleResult;
+ FitCircleMachineToolBlock.OnToolReady += FitCircleMachineToolBlock_OnToolReady;
+ translateCirclePoint = new TranslateCirclePoint();
+ m_graphics2 = new CogGraphicCollection();
}
catch (Exception ex)
{
@@ -171,15 +170,117 @@ namespace WaferAlignment
catch (Exception ex)
{
MessageBox.Show(ex.Message);
+ }
+ }
+ private void FitCircleMachineToolBlock_OnToolReady(bool ready)
+ {
+ LogHelper.LogInfo("FitCircleMachineToolBlock_OnToolReady");
+ }
+
+ private void FitCircleMachineToolBlock_OnFitCircleResult(double x, double y, double r, double rms)
+ {
+ TCP_X = x.ToString("F4");
+ TCP_Y = y.ToString("F4");
+ TCP_RMS = rms.ToString("F4");
+ TCP_R = r.ToString("F4");
+
+ deviationX = Math.Round((x - translateCirclePoint.GetRotateX()), 3);
+ deviationY = Math.Round((y - translateCirclePoint.GetRotateY()), 3);
+
+ AddPointMarker(m_graphics2, x, y);
+ AddPointMarker(m_graphics2, translateCirclePoint.GetRotateX(), translateCirclePoint.GetRotateY(), CogColorConstants.Red);
+
+ PointInfo nPoint = translateCirclePoint.GetNashPoint();
+ if (nPoint != null)
+ {
+ AddPointMarker(m_graphics2, nPoint.X, nPoint.Y, CogColorConstants.Yellow);
+ AddLineMarker(m_graphics2, x, y, x, y - r);
+ AddLineMarker(m_graphics2, x, y, nPoint.X, nPoint.Y, CogColorConstants.Yellow);
+ angle = GetCounterClockwiseAngle360(x, y, x, y - r, nPoint.X, nPoint.Y);
+ AddLabelMarker(m_graphics2, angle.ToString(), x, y, CogColorConstants.Yellow);
+ LogHelper.LogInfo($"nash degree:{angle}");
}
- // 指定XML文件路径
- string filePath = Path.Combine(System.AppDomain.CurrentDomain.SetupInformation.ApplicationBase, "vpp", "CenterOfRotation.xml"); //@"D:\晶圆寻边机\XML文件\CenterOfRotation.xml";
- _center = _ConfigStore.ReadConfigFromFile(_center.GetType(), filePath) as CenterOfRotation;
- circleCenterX = _center.Center_X;
- circleCenterY = _center.Center_Y;
+ LogHelper.LogInfo($"X:{x}, Y:{y}, RMS:{rms}");
+ LogHelper.LogInfo($"DiffX:{deviationX}, DiffY:{deviationY}, RMS:{rms}{Environment.NewLine}");
+ ImageDisplay(FitCircleMachineToolBlock.FitCircleImage);
+ ImageDisplay(m_graphics);
+ ImageDisplay(m_graphics2);
+ ImageDisplayFit();
}
+ private void AddPointMarker(CogGraphicCollection graphicCollection, double x, double y, CogColorConstants color = CogColorConstants.Green)
+ {
+ CogPointMarker marker = new CogPointMarker();
+ marker.X = x;
+ marker.Y = y;
+ marker.Color = color;
+ marker.Interactive = false;
+ graphicCollection.Add(marker);
+ }
+ private void AddLineMarker(CogGraphicCollection graphicCollection, double x1, double y1, double x2, double y2, CogColorConstants color = CogColorConstants.Green)
+ {
+ CogLineSegment line = new CogLineSegment();
+ line.SetStartEnd((int)x1, (int)y1, (int)x2, (int)y2);
+ line.Color = color;
+ line.Interactive = false;
+ graphicCollection.Add(line);
+ }
+ private void AddLabelMarker(CogGraphicCollection graphicCollection, string text, double x, double y, CogColorConstants color = CogColorConstants.Green)
+ {
+ CogGraphicLabel label = new CogGraphicLabel();
+ label.Text = text;
+ label.X = x;
+ label.Y = y;
+ label.Color = color;
+ graphicCollection.Add(label);
+ }
+ ///
+ /// 计算从 lineA 到 lineB 的逆时针有向角度(0-360度)
+ /// 坐标系:向右为正,向下为正(标准屏幕坐标系)
+ ///
+ public double GetCounterClockwiseAngle360(double x, double y, double x1, double y1, double x2, double y2)
+ {
+ // 2. 获取方向向量(dy 向下为正)
+ double dxA = x1 - x;
+ double dyA = y1 - y;
+
+ double dxB = x2 - x;
+ double dyB = y2 - y;
+
+ // 3. 将Y轴翻转,转换为标准数学坐标系(dy向上为正)
+ // 这样 Math.Atan2 返回的就是标准数学角度(逆时针为正)
+ double angleA = Math.Atan2(-dyA, dxA); // 注意:y取负号
+ double angleB = Math.Atan2(-dyB, dxB); // 注意:y取负号
+
+ // 4. 计算逆时针角度差(弧度)
+ double angleDiff = angleB - angleA;
+
+ // 5. 转换为角度并规范化为 [0, 360)
+ double angleDegrees = angleDiff * 180.0 / Math.PI;
+ angleDegrees = angleDegrees % 360.0;
+ if (angleDegrees < 0) angleDegrees += 360.0;
+
+ return Math.Round(angleDegrees, 3);
+ }
+ private void GetCircleMachineToolBlock_OnToolReady(bool ready)
+ {
+ LogHelper.LogInfo("GetCircleMachineToolBlock_OnToolReady");
+ }
+
+ private void GetCircleMachineToolBlock_OnGetNashResult(double x, double y)
+ {
+ translateCirclePoint.AddNashPoint(x, y);
+ LogHelper.LogInfo($"Update Nash X:{x}, Y:{y}");
+ }
+
+ private void GetCircleMachineToolBlock_OnGetCircleResult(double x, double y, double r)
+ {
+ translateCirclePoint.AddCircleCenter(x, y, r);
+ translateCirclePoint.AddCirclePoint(getCircleMachineToolBlock.PointInfos);
+ LogHelper.LogInfo($"X:{x}, Y:{y}, R:{r}");
+ }
+
///
/// 接收到TCP数据时,根据接收到的数据,进行不同操作
///
@@ -217,17 +318,11 @@ namespace WaferAlignment
_tcp.SendData(e.ClientIp, "DetectionTime:" + TCP_time + " " + "X:" + TCP_X + " " + "Y:" + TCP_Y + " " + "Angle:" + TCP_R + " " + "RMS:" + TCP_RMS);
}
}
-
-
}
void _cam_OutputImageEvent(Bitmap obj)
{
- lstNasR.Add((acqNum + 1) * R);
acqNum++;
- //lstNasR.Add((testNum) * R);
- //保存图像
- //SaveImage(new CogImage8Grey(obj));
ImageData.Mailing(new CogImage8Grey(obj));
Images.Add(new CogImage8Grey(obj));
@@ -235,10 +330,9 @@ namespace WaferAlignment
void ImageData_ErrorEvent(string obj)
{
- //throw new NotImplementedException();
+
}
-
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
try
@@ -300,7 +394,6 @@ namespace WaferAlignment
this.splitContainer1.Invoke(new Action(() => this.splitContainer1.Panel2.Enabled = true));
});
}
-
public string ToZero()
{
if (_s7 != null)
@@ -393,15 +486,7 @@ namespace WaferAlignment
}
}
- List lstRotation;
- List lstX;
- List lstY;
- List lstRadius;
- List lstNasX;
- List lstNasY;
- List lstNasR;
List Images;
-
int acqNum = 0;
int testNum = 0;
double angle = 0;
@@ -411,9 +496,11 @@ namespace WaferAlignment
private void btn_RunTest_Click(object sender, EventArgs e)
{
SavePath = Path.Combine(System.AppDomain.CurrentDomain.SetupInformation.ApplicationBase, "SaveImage", DateTime.Now.ToString("yyyyMMdd_HHmmss"));
-
+ m_cameraCount = Convert.ToDouble(textBox2.Text);
+ m_codeCount = Convert.ToDouble(textBox3.Text);
+ m_roateX = Convert.ToDouble(nud_SizeX.Value);
+ m_roateY = Convert.ToDouble(nud_SizeY.Value);
ClearDisplay();
- ////---------------------------------------
Task.Run(() =>
{
this.splitContainer1.Invoke(new Action(() => this.splitContainer1.Panel2.Enabled = false));
@@ -423,8 +510,6 @@ namespace WaferAlignment
this.splitContainer1.Invoke(new Action(() => this.splitContainer1.Panel2.Enabled = true));
});
-
- //---------------------------------------
}
public string RunTest()
@@ -436,7 +521,6 @@ namespace WaferAlignment
}
else
{
-
//R轴回0
if (_s7 != null)
{
@@ -480,13 +564,6 @@ namespace WaferAlignment
angle = 0;
acqNum = 0;
testNum = 0;
- lstRotation = new List();
- lstX = new List();
- lstY = new List();
- lstRadius = new List();
- lstNasX = new List();
- lstNasY = new List();
- lstNasR = new List();
Images = new List();
sw_1 = new Stopwatch();//检测时间
@@ -495,6 +572,7 @@ namespace WaferAlignment
deviationY = 0;
times = 0;
//启动拍照
+ translateCirclePoint.SetRotateXY(m_roateX, m_roateY, 360 * m_cameraCount / m_codeCount);
if (_s7 != null)
{
@@ -529,9 +607,7 @@ namespace WaferAlignment
}
}
//Thread.Sleep(100);
-
}
-
}
_cam.SoftwareGrab();
@@ -644,327 +720,62 @@ namespace WaferAlignment
return "NG_RUN";
}
}
-
+ private CogImage8Grey m_lastImage;
//所有点
// 调整vpp中CogCaliperTool工具数据需要同时调整Y值与 for (double i = Y; i < 12; i = i + 0.5)中12的值
private void MonitorSpot(CogImage8Grey outputImg)
{
sw_1 = new Stopwatch();//检测时间
sw_1.Start();
- //double Y = -17;
- //double X = 0;
- double X = -15;
- double Y = 0;
- CogImage8Grey inputImg = new CogImage8Grey();
- CogGraphicCollection graphics = new CogGraphicCollection();
- CogImage8Grey _OutputImg = new CogImage8Grey();
- inputImg = outputImg;
- mTB_1 = mTB.Tools["CogToolBlock1"] as CogToolBlock;
- mTB_2 = mTB.Tools["CogToolBlock2"] as CogToolBlock;
- mTB_1.Inputs["InputImage"].Value = inputImg;
- mTB_1.Run();
- _OutputImg = mTB_1.Outputs["OutputImage"].Value as CogImage8Grey;
+ translateCirclePoint.AddCircleIndex();
+ m_lastImage = outputImg;
+ getCircleMachineToolBlock.Run(outputImg);
- CogCaliperTool mCT = mTB_1.Tools["CogCaliperTool1"] as CogCaliperTool;
-
-
-
- //x′= cx + (x−cx)⋅cos(r)−(y−cy)⋅sin(r)
- //y′= cy + (x−cx)⋅sin(r) + (y−cy)⋅cos(r)
-
- int _count = 0;
-
- for (double i = X; i < 14; i = i + 0.5)
- {
- mCT.InputImage = _OutputImg;
- mCT.Region.CenterX = i;
- mCT.Run();
- _count = mCT.Results.Count;
-
- if (_count != 0)
- {
- Y = mCT.Results[0].Edge0.PositionY;
- //旋转角度
- double r = lstNasR[testNum] / 180 * Math.PI;
- //旋转移动到实际位置
- lstNasX.Add(i * Math.Cos(r) - Y * Math.Sin(r) + circleCenterX * (1 - Math.Cos(r)) + circleCenterY * Math.Sin(r));
- lstNasY.Add(i * Math.Sin(r) + Y * Math.Cos(r) - circleCenterX * Math.Sin(r) + circleCenterY * (1 - Math.Cos(r)));
-
- CogPointMarker marker_1 = new CogPointMarker();//圆
-
- marker_1.X = i;
- marker_1.Y = Y;
- marker_1.Color = CogColorConstants.Blue;
- marker_1.Interactive = false;
- graphics.Add(marker_1);
- }
- else
- {
- OKorNG = false;
- testNum++;
- return;
- }
- if (i == X)
- {
- double r = lstNasR[testNum] / 180 * Math.PI;
- lstX.Add(i * Math.Cos(r) - Y * Math.Sin(r) + circleCenterX * (1 - Math.Cos(r)) + circleCenterY * Math.Sin(r));
- lstY.Add(i * Math.Sin(r) + Y * Math.Cos(r) - circleCenterX * Math.Sin(r) + circleCenterY * (1 - Math.Cos(r)));
- }
-
- }
sw_1.Stop();
TimeSpan ts = sw_1.Elapsed;
- ImageDisplay(_OutputImg, graphics);
- DataDisplay(lstNasR[testNum], lstNasX[0], lstNasY[0], ts.TotalMilliseconds);
+ PointInfo pp = translateCirclePoint.GetFirstPoint();
+ if (pp != null)
+ DataDisplay(translateCirclePoint.GetCurrentDegree(), pp.X, pp.Y, ts.TotalMilliseconds);
+ else
+ DataDisplay(translateCirclePoint.GetCurrentDegree(), 0, 0, ts.TotalMilliseconds);
testNum++;
times += ts.TotalMilliseconds;
OKorNG = true;
}
- //比较半径和点间距,拟合圆
private void FitCircle()
{
if (OKorNG)
{
sw_2 = new Stopwatch();//检测时间
sw_2.Start();
- int Image_i = -1;
- // 调整vpp中CogCaliperTool工具数据需要同时调整step为x点数*2
- int step = 58;
- CogPMAlignTool mPM = mTB_2.Tools["CogPMAlignTool2"] as CogPMAlignTool;
+ LogHelper.LogInfo("转换机械坐标系下圆弧各点的原始坐标:\n");
+ var points = translateCirclePoint.DoTranslatePoint();
+ translateCirclePoint.DoTranslateNashPoint();
-
- CogImage8Grey outputImg = mTB_1.Outputs["OutputImage"].Value as CogImage8Grey;
- //添加找圆工具的 忽略点数 和 RMS偏差量
- CogFitCircleTool fitCircle_1 = new CogFitCircleTool();
- CogFitCircleTool fitCircle_2 = new CogFitCircleTool();
-
-
- CogGraphicCollection graphics = new CogGraphicCollection();
-
- fitCircle_1.InputImage = outputImg;
- for (int i = 0; i < lstX.Count; i++)
+ LogHelper.LogInfo("拟合机械坐标系下的圆中心:\n");
+ m_graphics = new CogGraphicCollection();
+ m_graphics2 = new CogGraphicCollection();
+ foreach (PointInfo pointInfo in points)
{
- fitCircle_1.RunParams.AddPoint(lstX[i], lstY[i]);
-
- //CogPointMarker marker_1 = new CogPointMarker();//圆
-
- //marker_1.X = lstNasX[i];
- //marker_1.Y = lstNasY[i];
- //marker_1.Color = CogColorConstants.White;
- //marker_1.Interactive = false;
- //graphics.Add(marker_1);
-
+ AddPointMarker(m_graphics, pointInfo.X, pointInfo.Y);
}
- //fitCircle_1.RunParams.NumToIgnore = 0;
- fitCircle_1.Run();
- if (fitCircle_1.Result != null)
- {
- double _RMS = fitCircle_1.Result.RMSError;
- CogCircle circle_1 = new CogCircle(fitCircle_1.Result.GetCircle());
- circle_1.Color = CogColorConstants.Cyan;
- circle_1.Interactive = false;
+ FitCircleMachineToolBlock.Run(m_lastImage, points);
- CogFitLineTool fitLine = new CogFitLineTool();
+ sw_2.Stop();
+ TimeSpan ts = sw_2.Elapsed;
- //晶圆圆心位置
- double _centerX = circle_1.CenterX;
- double _centerY = circle_1.CenterY;
- double _radius = circle_1.Radius;
+ times += ts.TotalMilliseconds;
+ TCP_time = ts.TotalMilliseconds.ToString();
-
- fitCircle_2.InputImage = outputImg;
-
- CogDistancePointPointTool pTp = new CogDistancePointPointTool();
- pTp.InputImage = outputImg;
- pTp.StartX = _centerX;
- pTp.StartY = _centerY;
- //double[] _DistanceMin = new double[lstNasX.Count];
- //int _distanceMin_i = 0;
- for (int i = 0; i < lstNasX.Count; i += step)
- {
-
- for (int j = i; j < i + step && j < lstNasX.Count; j++)
- {
- if (j < (i + step - 15))//忽略重合数据的末尾的15个点
- {
- pTp.EndX = lstNasX[j];
- pTp.EndY = lstNasY[j];
- pTp.Run();
- double Distance = pTp.Distance;
- if (Distance - _radius < 0.1 && Distance - _radius > -0.1)
- {
- fitCircle_2.RunParams.AddPoint(lstNasX[j], lstNasY[j]);
- CogPointMarker marker_1 = new CogPointMarker();//圆
-
- marker_1.X = lstNasX[j];
- marker_1.Y = lstNasY[j];
- marker_1.Color = CogColorConstants.Green;
- marker_1.Interactive = false;
- graphics.Add(marker_1);
- }
- else//忽略的点数
- {
- if (!(Distance - _radius < 1 && Distance - _radius > -1))
- {
- if (Image_i == -1)
- {
- Image_i = (int)(j / step);
- }
- }
-
-
- CogPointMarker marker_1 = new CogPointMarker();//圆
-
- marker_1.X = lstNasX[j];
- marker_1.Y = lstNasY[j];
- marker_1.Color = CogColorConstants.Yellow;
- marker_1.Interactive = false;
- graphics.Add(marker_1);
- }
- //_DistanceMin[i] = Distance;
- }
- else
- {
- CogPointMarker marker_1 = new CogPointMarker();//圆
-
- marker_1.X = lstNasX[j];
- marker_1.Y = lstNasY[j];
- marker_1.Color = CogColorConstants.Red;
- marker_1.Interactive = false;
- //graphics.Add(marker_1);
- }
- }
-
- }
- //忽略的拟合点数
- fitCircle_2.RunParams.NumToIgnore = 0;
- fitCircle_2.Run();
-
- double RMS = fitCircle_2.Result.RMSError;
- CogCircle circle_2 = new CogCircle(fitCircle_2.Result.GetCircle());
- circle_2.Color = CogColorConstants.Cyan;
- circle_2.Interactive = false;
- //晶圆圆心位置
- double centerX = circle_2.CenterX;
- double centerY = circle_2.CenterY;
- double radius = circle_2.Radius;
-
-
- double PM_X = 0;
- double PM_Y = 0;
- int _count = 0;
- if (Image_i != -1)
- {
- mTB_2.Inputs["InputImage"].Value = Images[Image_i];
- mTB_2.Run();
- _count = mPM.Results.Count;
-
- if (_count != 0)
- {
-
- double r = lstNasR[Image_i] / 180 * Math.PI;
- PM_X = mPM.Results[0].GetPose().TranslationX * Math.Cos(r) - mPM.Results[0].GetPose().TranslationY * Math.Sin(r) + circleCenterX * (1 - Math.Cos(r)) + circleCenterY * Math.Sin(r);
- PM_Y = mPM.Results[0].GetPose().TranslationX * Math.Sin(r) + mPM.Results[0].GetPose().TranslationY * Math.Cos(r) - circleCenterX * Math.Sin(r) + circleCenterY * (1 - Math.Cos(r));
-
- }
- }
- //_distanceMin_i = DistanceMin(_DistanceMin);
-
- ////纳什口
- //CogLine line_ = new CogLine();
- //line_.SetFromStartXYEndXY(centerX, centerY, lstNasX[_distanceMin_i], lstNasY[_distanceMin_i]);
- //line_.Color = CogColorConstants.Green;
- //line_.Interactive = false;
- //graphics.Add(line_);
- //纳什口
- CogLine line_ = new CogLine();
- line_.SetFromStartXYEndXY(centerX, centerY, PM_X, PM_Y);
- line_.Color = CogColorConstants.Green;
- line_.Interactive = false;
- graphics.Add(line_);
- //角度值为0
- CogLine line_0 = new CogLine();
- line_0.SetXYRotation(centerX, centerY, 0);
- line_0.Color = CogColorConstants.Blue;
- line_0.Interactive = false;
- graphics.Add(line_0);
- CogAngleLineLineTool llTool = new CogAngleLineLineTool();
- llTool.InputImage = outputImg;
- llTool.LineA = line_0;
- llTool.LineB = line_;
- llTool.Run();
- angle = CogMisc.RadToDeg(llTool.Angle);
-
- CogPointMarker marker_2 = new CogPointMarker();//圆心
-
- marker_2.X = centerX;
- marker_2.Y = centerY;
- marker_2.Color = CogColorConstants.Green;
- marker_2.Interactive = false;
- graphics.Add(marker_2);
-
- CogPointMarker marker_3 = new CogPointMarker();//旋转圆心
-
- marker_3.X = circleCenterX;
- marker_3.Y = circleCenterY;
- marker_3.Color = CogColorConstants.Orange;
- marker_3.Interactive = false;
- graphics.Add(marker_3);
- graphics.Add(circle_2);
-
-
- deviationX = centerX - circleCenterX;
- deviationY = centerY - circleCenterY;
-
- sw_2.Stop();
- TimeSpan ts = sw_2.Elapsed;
-
- times += ts.TotalMilliseconds;
-
-
- ImageDisplay(outputImg, graphics);
- TCP_time = ts.TotalMilliseconds.ToString();
- TCP_X = centerX.ToString("F4");
- TCP_Y = centerY.ToString("F4");
- TCP_RMS = RMS.ToString("F4");
- TCP_R = angle.ToString("F4");
- ResultDisplay(times, ts.TotalMilliseconds, centerX, centerY, radius, RMS, deviationX, deviationY, angle);
-
- OKorNG = true;
- }
- else
- {
- //MessageBox.Show("检测结果为空。");
- OKorNG = false;
- }
+ ResultDisplay(times, ts.TotalMilliseconds, TCP_X, TCP_Y, TCP_R, TCP_RMS, deviationX, deviationY, angle);
}
-
-
-
}
- //private int DistanceMin(double[] numbers)
- //{
- // double number = numbers[0];
- // int num1 = 0;
- // double num2 = ((IEnumerable)numbers).Sum() / (double)((IEnumerable)numbers).Count();
- // for (int index = 1; index < numbers.Length; ++index)
- // {
- // if (numbers[index] < number)
- // {
- // number = numbers[index];
- // num1 = index;
- // }
- // }
- // //return Math.Abs(number - num2) > 0.0 ? num1 : -1;
- // return num1;
- //}
-
- private void ResultDisplay(double Times,double Time, double X, double Y, double R, double RMS, double dX, double dY, double dR)
+ private void ResultDisplay(double Times,double Time, string X, string Y, string R, string RMS, double dX, double dY, double dR)
{
if (this.InvokeRequired)
{
@@ -1013,7 +824,6 @@ namespace WaferAlignment
return;
}
this.cogRecordDisplay1.StaticGraphics.AddList(graphics, "");
- this.cogRecordDisplay1.Fit(true);
}
private void ImageDisplay(CogImage8Grey img)
{
@@ -1023,9 +833,17 @@ namespace WaferAlignment
return;
}
this.cogRecordDisplay1.Image = img;
- this.cogRecordDisplay1.Fit(true);
+ cogRecordDisplay1.StaticGraphics.Clear();
+ }
+ private void ImageDisplayFit()
+ {
+ if (InvokeRequired)
+ {
+ BeginInvoke(new Action(() => ImageDisplayFit()));
+ return;
+ }
+ cogRecordDisplay1.Fit(true);
}
-
private void DataDisplay(double Rotation, double X, double Y, double Radius)
{
if (this.InvokeRequired)
@@ -1041,18 +859,6 @@ namespace WaferAlignment
}
string SavePath;
- private void SaveImage(ICogImage img)
- {
- if (!Directory.Exists(SavePath))
- {
- Directory.CreateDirectory(SavePath);
- }
- using (CogImageFile imgFile = new CogImageFile())
- {
- imgFile.Open(Path.Combine(SavePath, DateTime.Now.ToString("yyyyMMdd_HHmmss_fff") + ".bmp"), CogImageFileModeConstants.Write);
- imgFile.Append(img);
- }
- }
private void Save()
{
if (!Directory.Exists(SavePath))
@@ -1068,5 +874,27 @@ namespace WaferAlignment
}
}
}
+ private double m_cameraCount = 82;
+ private double m_codeCount = 4096;
+ private void textBox2_TextChanged(object sender, EventArgs e)
+ {
+ m_cameraCount = Convert.ToDouble(textBox2.Text);
+ }
+
+ private void textBox3_TextChanged(object sender, EventArgs e)
+ {
+ m_codeCount = Convert.ToDouble(textBox3.Text);
+ }
+ private double m_roateX = 1;
+ private double m_roateY = -1;
+ private void nud_SizeX_ValueChanged(object sender, EventArgs e)
+ {
+ m_roateX = Convert.ToDouble(nud_SizeX.Value);
+ }
+
+ private void nud_SizeY_ValueChanged(object sender, EventArgs e)
+ {
+ m_roateY = Convert.ToDouble(nud_SizeY.Value);
+ }
}
}
diff --git a/WaferAlignment/Form1.resx b/WaferAlignment/Form1.resx
index b3e563c..5714ba7 100644
--- a/WaferAlignment/Form1.resx
+++ b/WaferAlignment/Form1.resx
@@ -140,4 +140,16 @@
True
+
+ True
+
+
+ True
+
+
+ True
+
+
+ True
+
\ No newline at end of file
diff --git a/WaferAlignment/GetCircleToolBlock.cs b/WaferAlignment/GetCircleToolBlock.cs
new file mode 100644
index 0000000..2e92685
--- /dev/null
+++ b/WaferAlignment/GetCircleToolBlock.cs
@@ -0,0 +1,117 @@
+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);
+ public delegate void OnGetNashResult(double x, double y);
+ internal class GetCircleToolBlock
+ {
+ private CogToolBlock cogToolBlock;
+ private bool initialized = false;
+ public event OnToolReady OnToolReady;
+ public event OnGetCircleResult OnGetCircleResult;
+ public event OnGetNashResult OnGetNashResult;
+ 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));
+
+ if ((int)cogToolBlock.Outputs["Results_Count"].Value == 1)
+ {
+ OnGetNashResult?.Invoke(Math.Round((double)cogToolBlock.Outputs["TranslationX"].Value, 3),
+ Math.Round((double)cogToolBlock.Outputs["TranslationY"].Value, 3));
+ }
+ }
+ catch (Exception ex)
+ {
+ LogHelper.LogError(ex.Message + ex.StackTrace);
+ }
+ }
+ public void Run(Bitmap bmp)
+ {
+ try
+ {
+ CogImage8Grey image8Grey = new CogImage8Grey(bmp);
+ Run(image8Grey);
+ }
+ catch (Exception ex)
+ {
+ LogHelper.LogError("ScanToolBlock Run Error: " + ex.Message);
+ }
+ }
+ public void Run(CogImage8Grey image8Grey)
+ {
+ try
+ {
+ 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/WaferAlignment/LogHelper.cs b/WaferAlignment/LogHelper.cs
new file mode 100644
index 0000000..da64197
--- /dev/null
+++ b/WaferAlignment/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/WaferAlignment/Nlog.config b/WaferAlignment/Nlog.config
new file mode 100644
index 0000000..3635098
--- /dev/null
+++ b/WaferAlignment/Nlog.config
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/WaferAlignment/PointInfo.cs b/WaferAlignment/PointInfo.cs
new file mode 100644
index 0000000..4e3a830
--- /dev/null
+++ b/WaferAlignment/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/WaferAlignment/Rotation2D.cs b/WaferAlignment/Rotation2D.cs
new file mode 100644
index 0000000..d310406
--- /dev/null
+++ b/WaferAlignment/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/WaferAlignment/TranslateCirclePoint.cs b/WaferAlignment/TranslateCirclePoint.cs
new file mode 100644
index 0000000..c699d09
--- /dev/null
+++ b/WaferAlignment/TranslateCirclePoint.cs
@@ -0,0 +1,92 @@
+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;
+ PointInfo nashPoint;
+ PointInfo firstPoint;
+ public void SetRotateXY(double x, double y, double angle)
+ {
+ rotateX = x; rotateY = y;
+ totalPoints = new List();
+ totalCenters = new List();
+ circleIndex = 0;
+ perAngle = angle;
+ nashPoint = null;
+ firstPoint = null;
+ }
+ public double GetRotateX()
+ {
+ return rotateX;
+ }
+ public double GetRotateY()
+ {
+ return rotateY;
+ }
+ public void AddCirclePoint(List pointInfos)
+ {
+ if (pointInfos == null || pointInfos.Count == 0) return;
+ foreach (var item in pointInfos)
+ {
+ totalPoints.Add(new PointInfo(item.X, item.Y, circleIndex * perAngle));
+ }
+ firstPoint = pointInfos[0];
+ }
+ public PointInfo GetFirstPoint()
+ {
+ return firstPoint;
+ }
+ public void AddCircleIndex()
+ {
+ circleIndex++;
+ }
+ public double GetCurrentDegree()
+ {
+ return circleIndex * perAngle;
+ }
+ public void AddNashPoint(double x, double y)
+ {
+ nashPoint = new PointInfo(x, y, circleIndex * perAngle);
+ }
+ 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);
+ trans.Add(new PointInfo(res.x, res.y, item.Radius));
+ }
+ return trans;
+ }
+ public void DoTranslateNashPoint()
+ {
+ if (nashPoint == null)
+ return;
+
+ var res = Rotation2D.GetOriginalPointDegrees(nashPoint.X, nashPoint.Y,
+ rotateX, rotateY, nashPoint.Radius, true, false);
+
+ nashPoint = new PointInfo(res.x, res.y, nashPoint.Radius);
+ }
+ public PointInfo GetNashPoint()
+ {
+ return nashPoint;
+ }
+ }
+}
diff --git a/WaferAlignment/WaferAlignment.csproj b/WaferAlignment/WaferAlignment.csproj
index 66e7eaf..72ef79e 100644
--- a/WaferAlignment/WaferAlignment.csproj
+++ b/WaferAlignment/WaferAlignment.csproj
@@ -79,6 +79,9 @@
..\..\..\..\..\..\Program Files (x86)\MVS\Development\DotNet\win64\net40\MvCameraControl.Net.dll
+
+ ..\packages\NLog.6.0.6\lib\net46\NLog.dll
+
@@ -86,6 +89,7 @@
+
@@ -104,15 +108,21 @@
+
Form
Form1.cs
+
+
+
+
+
Form1.cs
@@ -126,6 +136,10 @@
Resources.resx
True
+
+ PreserveNewest
+
+
SettingsSingleFileGenerator
Settings.Designer.cs
diff --git a/WaferAlignment/packages.config b/WaferAlignment/packages.config
new file mode 100644
index 0000000..e772309
--- /dev/null
+++ b/WaferAlignment/packages.config
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file