using OTSIncAReportApp.DataOperation.DataAccess; using OTSIncAReportApp.DataOperation.Model; using OTSIncAReportApp.SysMgrTools; using OTSIncAReportGraph.Class; using OTSIncAReportGraph.Controls; using System; using System.Collections; using System.Collections.Generic; using System.Data; using System.Diagnostics; using System.Drawing; using System.Drawing.Drawing2D; using System.Linq; namespace OTSIncAReportGraph.OTSIncAReportGraphFuncation { public class OTSImageDisHelp { #region 枚举定义 /// /// 样品台X轴方向 /// enum OTS_X_AXIS_DIRECTION { LEFT_TOWARD = 0, RIGHT_TOWARD = 1 } /// /// 样品台Y轴方向 /// enum OTS_Y_AXIS_DIRECTION { UP_TOWARD = 0, DOWN_TOWARD = 1 } #endregion #region 定义变量 private ResultFile resultFile = null; //记录field列表的原值 public List m_original_list_dfield = null; //记录原值,颗粒和线段 public List m_original_list_baseobject = null; NLog.Logger log; //field的数量 public int m_field_count = 0; //particle的数量 public int m_particle_count = 0; //加载使用的时间 public string m_time_str = ""; //加载使用时间计算时间段2 public string m_time_str2 = ""; //电镜设置对象 public ServiceInterface.SemController m_cfun = null; //是否已经连接到了电镜 public bool m_SEMConnectionState = false; //连接到电镜的ID号 public int m_SEM_ID = 0; #endregion #region 构造函数 public OTSImageDisHelp( ResultFile result) { m_original_list_dfield = new List(); m_original_list_baseobject = new List(); resultFile = result; m_cfun =new ServiceInterface.SemController(); log = NLog.LogManager.GetCurrentClassLogger(); } #endregion #region 封装自定义方法 public Point GetOTSCoordLeftBottomPoint(List allFldPos) { //the ots coordinate system is always positive on the right and up direction.So the leftbottom point would be the smallest point. //找出最小的x,y用来做偏移运算 int i_offset_x = 1000000000; int i_offset_y = 1000000000; //先取出最小的x,y for (int i = 0; i < allFldPos.Count; i++) { if (i_offset_x > allFldPos[i].X) { i_offset_x = allFldPos[i].X; } if (i_offset_y > allFldPos[i].Y) { i_offset_y = allFldPos[i].Y; } } return new Point(i_offset_x, i_offset_y); } public Point ConvertPhysicalCoordinateToScreenCoord(Point otsleftBottomPoint,double pixelSize, Point currenFldPos)//ots coordinate equals to the physical coordinate. { var OTSPoint=new Point(currenFldPos.X - otsleftBottomPoint.X, currenFldPos.Y - otsleftBottomPoint.Y); var screenPoint = new Point((int)(Convert.ToDouble(OTSPoint.X)/pixelSize), (int)(Convert.ToDouble(OTSPoint.Y)/pixelSize)); return screenPoint; } public Rectangle ConvertAndGetMaxRect(List inPoints, int in_width, int in_height) { //首先要能确定下来,单个物理坐标的宽和高-------------------------------- int i_wl_width = 0; int i_wl_height = 0; RectangleF ls_r = GetPhysicalFieldWidthAndHeight(inPoints,in_width,in_height); i_wl_width = (int)ls_r.Width; i_wl_height = (int)ls_r.Height; //----------------------------------------------------------------------------- int point_x_min = 10000000; int point_x_max = -10000000; int point_y_min = 10000000; int point_y_max = -10000000; for (int i = 0; i < inPoints.Count(); i++) { Point ls_point = inPoints[i]; //取出正数最大x if (ls_point.X > point_x_max) point_x_max = ls_point.X; if (ls_point.Y > point_y_max) point_y_max = ls_point.Y; if (ls_point.X < point_x_min) point_x_min = ls_point.X; if (ls_point.Y < point_y_min) point_y_min = ls_point.Y; } //然后分别用最大值+abs(最小值),就是x,和y轴的总长值 point_x_max = point_x_max - point_x_min; point_y_max = point_y_max - point_y_min; //该算法有个问题,就是不能直观的得到整个范围的大小,要除以倍数再补1能补充缺少的一个field视域********** point_x_max = ((point_x_max / i_wl_width) + 1) * i_wl_width; point_y_max = ((point_y_max / i_wl_height) + 1) * i_wl_height; //将物理宽高,变换成分辨率宽高 if (i_wl_width != 0) point_x_max = (point_x_max / i_wl_width) * in_width; else point_x_max = 0; if (i_wl_height != 0) point_y_max = (point_y_max / i_wl_height) * in_height; else point_y_max = 0; Rectangle ret_rectangle = new Rectangle(0, 0, 0, 0); //判断一下防止出错,只有在有数据的情况下,进行赋值才行 if (inPoints.Count > 0) { ret_rectangle = new Rectangle(0, 0, point_x_max, point_y_max); } //这样返回是物理坐标的总大小,应该返回像素坐标大小才对 return ret_rectangle; } /// /// 计算单个field的物理大小 传入field的list,还有测量结果管理类对象,在无法计算出单field的物理大小的情况下,到这里取再计算得出 /// /// public RectangleF GetPhysicalFieldWidthAndHeight(List points,int imageWidth,int imageHeight) { int width_max = -10000000; int height_max = -10000000; int width_max2 = -10000000; int height_max2 = -10000000; //先找出最大的值, for (int i = 0; i < points.Count(); i++) { if (width_max < points[i].X) width_max = points[i].X; if (height_max < points[i].Y) height_max = points[i].Y; } //再找出第二大的值 for (int i = 0; i < points.Count(); i++) { if (width_max2 < points[i].X && width_max != points[i].X) width_max2 = points[i].X; if (height_max2 < points[i].Y && height_max != points[i].Y) height_max2 = points[i].Y; } //需要针对第二大的值,获取时进行判断,感觉这里应该如果并未找到第二大的值的情况下,赋于0值,便于以后进行计算 if (width_max2 == -10000000) width_max2 = 0; if (height_max2 == -10000000) height_max2 = 0; RectangleF ret_rect = new RectangleF(0, 0, width_max - width_max2, height_max - height_max2); //如果最后计算出的宽高有0则重新到测量数据中获取--------------------------------------- if (ret_rect.Width == 0 || ret_rect.Height == 0) { //到参数中去取单个宽 double d_scanFieldSize_width = Convert.ToDouble(((Dictionary)resultFile.ResultInfo["SEMStageData"])["scanFieldSize"]); //然后再用单个宽去计算出高是多少 double d_scanFieldSize_height = 0; if (d_scanFieldSize_width != 0) d_scanFieldSize_height = (d_scanFieldSize_width / Convert.ToDouble(imageWidth)) * imageHeight; ret_rect.Width = (int)d_scanFieldSize_width; ret_rect.Height = (int)d_scanFieldSize_height; } ///-----------because all the fields 's height/width=0.75 so here we make an enforce. gsp add at 2019/10/31 ///sometimes the gbfields are not conform to this for the cuting and merging operation. //if (ret_rect.Height / ret_rect.Width != 0.75f) //{ // ret_rect = new Rectangle(ret_rect.X, ret_rect.Y, ret_rect.Width, (int)(ret_rect.Width * 0.75f)); //} return ret_rect; } #endregion #region 电镜操作相关方法 /// /// 连接电镜,分布图使用 /// public void ConnectToSEM() { log.Trace("(Connection_ForDrawDistrbutionImageAndBSE)" + "Connect to SEM"); if (!m_SEMConnectionState) { //和电镜建立通讯连接 m_SEMConnectionState = m_cfun.Connect(); log.Trace("(Connection_ForDrawDistrbutionImageAndBSE)" + "Connect to SEM" + ":--" + m_SEMConnectionState + "---"); } else { log.Trace("(Connection_ForDrawDistrbutionImageAndBSE)" + ":allready connected, state:" + m_SEMConnectionState); //断开电镜连接 } } public void DisConnectSEM() { m_SEMConnectionState = false; m_cfun.DisConnect(); } /// /// 移动电镜到指定的X,Y坐标上,R坐标使用原先的值进行移动 /// /// /// public void MoveSemToPointXY(double in_PositionX, double in_PositionY) { log.Trace("Begin MoveSemToPointXY:(" +in_PositionX.ToString()+","+in_PositionY.ToString()+")"); //首先获取电镜当前的位置,并记录原R值 double ls_PositionX = 0; double ls_PositionY = 0; double ls_PositionR = 0; if (m_SEMConnectionState) { m_cfun.GetSemPositionXY(ref ls_PositionX, ref ls_PositionY, ref ls_PositionR); } else { log.Error("Failed to GetSemPositionXY"); return; } if (m_SEMConnectionState) { m_cfun.MoveSEMToPoint(new Point((int)in_PositionX, (int)in_PositionY), ls_PositionR); } } #endregion #region //--------------------------------------颗粒分布图相关部份--------------------------------------------------------------------- /// /// 传入颗粒的tagid和fieldid,来获取该颗粒下对应的xray数据 /// /// /// /// /// public void GetXrayByParticleTagIDAndFieldID_ForDrawDistrbutionImageAndBSE(int in_clr_tagid, int in_clr_fieldid, out uint[] Search_xray, out uint[] Analysis_xray, out int xray_id, out List list_celementchemistryclr) { Search_xray = new uint[2000]; Analysis_xray = new uint[2000]; xray_id = 0; list_celementchemistryclr = new List(); //防止为空校验判断 if (resultFile.List_OTSField == null) return; Particle particle = resultFile.List_OTSField.Find(x => x.FieldID == in_clr_fieldid).ParticleList.Find(x => x.ParticleId == in_clr_tagid); var tmpPart = new ParticleData(resultFile.FilePath).GetParticleXrayDataByFidAndPid(Convert.ToString(particle.FieldId), Convert.ToString(particle.XrayId)); if (tmpPart != null) { particle.XRayData = tmpPart.XRayData; if (particle.XrayId > -1) { for (int i = 0; i < 2000; i++) { Analysis_xray[i] = BitConverter.ToUInt32(particle.XRayData, i * 4); } Search_xray = Analysis_xray; xray_id = particle.XrayId; list_celementchemistryclr = particle.ElementList; } } } /// /// 传入所有的物理field坐标点,和单个物理field的宽高,返回所有field的左上角位置,和整个field组成的rect大小 /// /// /// /// /// public Rectangle GetWlRectTopLeftAndRect(List in_list_point, int in_width, int in_height) { //分别获取整个rect的xy最小值和最大值 int i_rect_x_min = 100000000; int i_rect_y_min = 100000000; int i_rect_x_max = -100000000; int i_rect_y_max = -100000000; for (int i = 0; i < in_list_point.Count; i++) { if (i_rect_x_min > in_list_point[i].X) i_rect_x_min = in_list_point[i].X; if (i_rect_y_min > in_list_point[i].Y) i_rect_y_min = in_list_point[i].Y; if (i_rect_x_max < in_list_point[i].X) i_rect_x_max = in_list_point[i].X; if (i_rect_y_max < in_list_point[i].Y) i_rect_y_max = in_list_point[i].Y; } Rectangle ret_rect = new Rectangle(i_rect_x_min, i_rect_y_min, i_rect_x_max - i_rect_x_min, i_rect_y_max - i_rect_y_min); return ret_rect; } /// /// 根据Field的ID,来获取Field列表中对应FIeld的OTS 坐标 /// /// /// public Point GetOTSPointByFieldID(List in_list_dfield, int in_fieldid) { Point ret_point = new Point(0, 0); for (int i = 0; i < in_list_dfield.Count; i++) { //这里TagID先代表的是底层返回的ID if (in_list_dfield[i].FieldID == in_fieldid.ToString()) { ret_point = new Point(Convert.ToInt32(in_list_dfield[i].OTSCoordinatePos.X), Convert.ToInt32(in_list_dfield[i].OTSCoordinatePos.Y)); } } return ret_point; } /// /// 将OTS坐标转换为Sem 坐标 /// /// /// public Point ChangeOTSToSemCoord(Point POTSCoord) { //first if m_semstagedata is null to get stage inforation Convert.ToDouble(((Dictionary)resultFile.ResultInfo["SEMStageData"])["scanFieldSize"]); //after obtaining stage info,calc stage point data Point ret_SEM_point = new Point(); // get center point, um long xStart = Convert.ToInt64(((Dictionary)((Dictionary)((Dictionary)resultFile.ResultInfo["SEMStageData"])["Members"])["XAxis"])["start"]); long xEnd = Convert.ToInt64(((Dictionary)((Dictionary)((Dictionary)resultFile.ResultInfo["SEMStageData"])["Members"])["XAxis"])["end"]); long xCenter = (xStart + xEnd) / 2; long yStart = Convert.ToInt64(((Dictionary)((Dictionary)((Dictionary)resultFile.ResultInfo["SEMStageData"])["Members"])["YAxis"])["start"]); long yEnd = Convert.ToInt64(((Dictionary)((Dictionary)((Dictionary)resultFile.ResultInfo["SEMStageData"])["Members"])["YAxis"])["end"]); long yCenter = (yStart + yEnd) / 2; // delte = SEM - OTSa long deltex = xCenter - 0; long deltey = yCenter - 0; int xdir = Convert.ToInt32(((Dictionary)resultFile.ResultInfo["SEMStageData"])["xAxisDir"]); int ydir = Convert.ToInt32(((Dictionary)resultFile.ResultInfo["SEMStageData"])["yAxisDir"]); if (xdir == (int)OTS_X_AXIS_DIRECTION.LEFT_TOWARD) { ret_SEM_point.X = -1 * (POTSCoord.X - Convert.ToInt32(deltex)); } else if (xdir == (int)OTS_X_AXIS_DIRECTION.RIGHT_TOWARD) { ret_SEM_point.X = POTSCoord.X + Convert.ToInt32(deltex); } if (ydir == (int)OTS_Y_AXIS_DIRECTION.UP_TOWARD) { ret_SEM_point.Y = POTSCoord.Y + Convert.ToInt32(deltey); } else if (ydir == (int)OTS_Y_AXIS_DIRECTION.DOWN_TOWARD) { ret_SEM_point.Y = -1 * (POTSCoord.Y - Convert.ToInt32(deltey)); } return ret_SEM_point; } #endregion /// /// 判断该点是否在多边形的范围内 /// /// /// /// public bool WhetherInRange(DisplayParticle Part,/*PointF[] inPoints,*/ Point WhetherPoint) { var rect = Part.Rect; if ((rect.Left < WhetherPoint.X && WhetherPoint.X < rect.Right) && (rect.Top < WhetherPoint.Y && WhetherPoint.Y < rect.Bottom)) { var itm = (BaseObject)Part; itm.GPath = Part.GetRegionFromDSegments(); PointF[] inPoints = itm.GPath.PathPoints; bool b_inrange = false; GraphicsPath myGraphicsPath = new GraphicsPath(); Region myRegion = new Region(); myGraphicsPath.Reset(); myGraphicsPath.AddPolygon(inPoints); myRegion.MakeEmpty(); myRegion.Union(myGraphicsPath); //返回判断点是否在多边形里 b_inrange = myRegion.IsVisible(WhetherPoint); return b_inrange; } else { return false; } } public bool WhetherInRange(RectangleF rec,PointF[] inPoints, Point WhetherPoint) { var rect = rec; if ((rect.Left < WhetherPoint.X && WhetherPoint.X < rect.Right) && (rect.Top < WhetherPoint.Y && WhetherPoint.Y < rect.Bottom)) { //var itm = (BaseObject)Part; //PointF[] inPoints = itm.GPath.PathPoints; bool b_inrange = false; GraphicsPath myGraphicsPath = new GraphicsPath(); Region myRegion = new Region(); myGraphicsPath.Reset(); myGraphicsPath.AddPolygon(inPoints); myRegion.MakeEmpty(); myRegion.Union(myGraphicsPath); //返回判断点是否在多边形里 b_inrange = myRegion.IsVisible(WhetherPoint); return b_inrange; } else { return false; } } /// /// 判断该点是否在多边形的范围内的float版本重载 /// /// /// /// public bool WhetherInRange(DisplayParticle Part,/* PointF[] inPoints, */PointF WhetherPoint) { var rect = Part.Rect; if ((rect.Left < WhetherPoint.X && WhetherPoint.X < rect.Right) && (rect.Top < WhetherPoint.Y && WhetherPoint.Y < rect.Bottom)) { var itm = (BaseObject)Part; PointF[] inPoints = itm.GPath.PathPoints; bool b_inrange = false; GraphicsPath myGraphicsPath = new GraphicsPath(); Region myRegion = new Region(); myGraphicsPath.Reset(); myGraphicsPath.AddPolygon(inPoints); myRegion.MakeEmpty(); myRegion.Union(myGraphicsPath); //返回判断点是否在多边形里 b_inrange = myRegion.IsVisible(WhetherPoint); return b_inrange; } else { return false; } } } }