最新ICS工厂有一项incam脚本新需求,这里介绍5种解决方法解决
需求如下图所示:绿色所圈处是是需求出的中心点(图形间距一致归为一类并计算中心点坐标)
前题条件:
1.一个SET里面可能有多个CAM,存在CAM1,CAM2,CAM3
2.每个CAM与CAM这最小间距不是固定值
对方法求解前;对此数据存储结构列出来:
/// <summary> /// Mod_step 坐标data类型 存放PNL中的子板排放坐标位置 /// </summary> public class Mod_Sr_data { public string step_name { get; set; } public gPoint ps; public int angle { get; set; } public bool mirror { get; set; } public gPoint min; public gPoint max; public gPoint size { get { return new gPoint(Math.Abs(this.min.x - this.max.x), Math.Abs(this.min.y - this.max.y)); } } public gPoint center { get { return new gPoint((this.max.x + this.min.x) / 2, (this.max.y + this.min.y) / 2); } } }
方法一:矩阵排序分组法求解
第一步:分别进行X与Y排列,如下图所示
第二步,求出X最近距离,与Y最近距离
第三步, 通过X与Y最近距离求出,间距分组ID号
第四步,通过间距分组ID号,遍历分组
第五步,通过每个分组求出中心点
缺点:只能支持矩阵排列(X数*Y数=PCS总数),X或Y间距全部需保持一致,最小左下角相连PCS最少2个,不支持PCS旋转
代码实现:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
private static void SetCenterAddPad1() { step gstep = new step(g.JOB); gProfile profile = g.getProfile(g.STEP, g.JOB); List<Mod_Sr_data> sr_dataList = gstep.get_step_Sr_data(g.STEP); List<Mod_Sr_data> sr_dataList_y_Order = sr_dataList.OrderBy(tt => tt.min.y).ThenBy(tt => tt.min.x).ToList(); List<Mod_Sr_data> sr_dataList_x_Order = sr_dataList.OrderBy(tt => tt.min.x).ThenBy(tt => tt.min.y).ToList(); List<int> x_CountList = new List<int>(); x_CountList.Add(0); List<int> y_CountList = new List<int>(); y_CountList.Add(0); double tempDi = 0; double minDi = 0; bool isMinDi = false; int tempCount = 0; for (int i = 0; i < sr_dataList_y_Order.Count - 1; i++) { if (Math.Abs(sr_dataList_y_Order[i + 1].min.y - sr_dataList_y_Order[i].min.y) > 0.1) break; tempDi = Math.Abs(sr_dataList_y_Order[i + 1].min.x - sr_dataList_y_Order[i].min.x); if (!isMinDi) { minDi = tempDi; isMinDi = true; x_CountList[tempCount] = i + 1; } else { if ((Math.Abs(minDi - tempDi) < 0.001)) { x_CountList[tempCount] = i + 1; } else { tempCount++; x_CountList.Add(i + 1); } } } isMinDi = false; tempCount = 0; for (int i = 0; i < sr_dataList_x_Order.Count - 1; i++) { if (Math.Abs(sr_dataList_x_Order[i + 1].min.x - sr_dataList_x_Order[i].min.x) > 0.1) break; tempDi = Math.Abs(sr_dataList_x_Order[i + 1].min.y - sr_dataList_x_Order[i].min.y); if (!isMinDi) { minDi = tempDi; isMinDi = true; y_CountList[tempCount] = i + 1; } else { if ((Math.Abs(minDi - tempDi) < 0.001)) { y_CountList[tempCount] = i + 1; } else { tempCount++; y_CountList.Add(i + 1); } } } int x_Count = x_CountList.Max(tt => tt) + 1; int y_Count = y_CountList.Max(tt => tt) + 1; List<Mod_Sr_data>[] sr_dataListGroup = new List<Mod_Sr_data>[(x_CountList.Count * y_CountList.Count)]; for (int i = 0; i < sr_dataListGroup.Count(); i++) { sr_dataListGroup[i] = new List<Mod_Sr_data>(); } for (int i = 0; i < sr_dataList_y_Order.Count; i++) { int x_index = i % x_Count; int y_index = i / x_Count; for (int j = 0; j < x_CountList.Count; j++) { if (x_index <= x_CountList[j]) { x_index = j; break; } } for (int j = 0; j < y_CountList.Count; j++) { if (y_index <= y_CountList[j]) { y_index = j; break; } } int index = y_index * x_CountList.Count + x_index; sr_dataListGroup[index].Add(sr_dataList_y_Order[i]); } List<gPoint> gpointList = new List<gPoint>(); foreach (var item in sr_dataListGroup) { double xVal = item.Sum(tt => tt.center.x) / item.Count; double yVal = item.Sum(tt => tt.center.y) / item.Count; gpointList.Add(new gPoint(xVal, yVal)); } add add_ = new add(); add_.pad(gpointList.ToArray(), 500); }
方法二:坐标对号入坑法(类拟桶排序算法思想上改进)
第一步:分别进行X与Y排列
第二步,求出X最近距离,与Y最近距离
第三步, 建二维数组准备挖坑了(X与Y尺寸依据旋转时X与Y互换)
第四步,遍历数据填入到对应的坑位
第五步,通过二维的坑位依次对比最近距离X与Y进行划分数据分组
第五步,通过每个分组求出中心点
缺点:只能支持矩阵排列(中心可以缺少PCS),X或Y间距全部需保持一致,
代码实现,未完待完善
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
private void SetCenterAddPad2() { step gstep = new step(g.JOB); gProfile profile = g.getProfile(g.STEP, g.JOB); List<Mod_Sr_data> sr_dataList = gstep.get_step_Sr_data(g.STEP); List<Mod_Sr_data> sr_dataList_y_Order = sr_dataList.OrderBy(tt => tt.min.y).ThenBy(tt => tt.min.x).ToList(); List<Mod_Sr_data> sr_dataList_x_Order = sr_dataList.OrderBy(tt => tt.min.x).ThenBy(tt => tt.min.y).ToList(); double tempDi = 0; double yDi = 10000; double xDi = 10000; for (int i = 0; i < sr_dataList_y_Order.Count - 1; i++) { tempDi = Math.Abs(sr_dataList_y_Order[i + 1].min.y - sr_dataList_y_Order[i].min.y); if (tempDi > 0.01 && yDi > tempDi) yDi = tempDi; } for (int i = 0; i < sr_dataList_x_Order.Count - 1; i++) { tempDi = Math.Abs(sr_dataList_x_Order[i + 1].min.x - sr_dataList_x_Order[i].min.x); if (tempDi > 0.01 && xDi > tempDi) xDi = tempDi; } int x_array, y_array; double xWidth, yHeigth; double PcsAng = Math.Abs(sr_dataList[0].angle - 180); if (89 < PcsAng && PcsAng < 91) { x_array = (int)Math.Ceiling(profile.Prof.size.y / sr_dataList[0].size.y); y_array = (int)Math.Ceiling(profile.Prof.size.x / sr_dataList[0].size.x); xWidth = sr_dataList[0].size.y; yHeigth = sr_dataList[0].size.x; } else { x_array = (int)Math.Ceiling(profile.Prof.size.x / sr_dataList[0].size.x); y_array = (int)Math.Ceiling(profile.Prof.size.y / sr_dataList[0].size.y); xWidth = sr_dataList[0].size.x; yHeigth = sr_dataList[0].size.y; } Mod_Sr_data[,] sr_dataArray = new Mod_Sr_data[x_array, y_array]; for (int i = 0; i < sr_dataList_y_Order.Count; i++) { int x_index = (int)Math.Floor((sr_dataList_y_Order[i].min.x - profile.Prof.min.x) / xWidth); int y_index = (int)Math.Floor((sr_dataList_y_Order[i].min.y - profile.Prof.min.y) / yHeigth); sr_dataArray[x_index, y_index] = sr_dataList_y_Order[i]; } List<int> x_CountList = new List<int>(); x_CountList.Add(0); List<int> y_CountList = new List<int>(); y_CountList.Add(0); for (int i = 0; i < x_array-1; i++) { for (int j = 0; j < y_array-1; j++) { var aa = sr_dataArray[i, j]; } } }
方法三:最近邻聚类算法
方法四:递归最左下角坐标定原点,进行相等距离求解
方法五:扩边求解