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
{
class OTSIncAReportFun
{
#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;
//新版排序图窗体对象
//private Control_DrawDistrbutionSortImage m_Control_DrawdistrbutionsortImage = null;
//全局对象,为了能够快速的获取到xray数据,而做为一个临时变量进行保存,使用前应该判断是否为空
public List m_list_OTSField = 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;
//国际化
//Language lan = new Language();
//Hashtable table;
#endregion
#region 构造函数
///
/// 构造函数,接收新版分布图和排序图的构造函数
///
///
///
public OTSIncAReportFun( ResultFile result)
{
resultFile = result;
m_cfun =new ServiceInterface.SemController();
log = NLog.LogManager.GetCurrentClassLogger();
//table = lan.GetNameTable("OTSIncAReportFun");
}
#endregion
#region 封装自定义方法
///
/// 通过传入的各field物理坐标列表,和单个field的屏幕分辨率,及单个的field的物理坐标,来获取当前field在整个image中的屏幕像素坐标偏移,并且是OTS向上为正做了Y轴相反运算
///
///
///
///
///
///
///
public Point GetFieldPhysicsConvertToScreen(List in_list_point, int in_screen_width, int in_screen_height, Point in_physics_point)
{
//先确定单个物理坐标的宽和高
Rectangle rect_onefield_wl = GetOneFieldWidthAndHeight(in_list_point);
//找出最小的x,y用来做偏移运算
int i_offset_x = 1000000000;
int i_offset_y = 1000000000;
//先取出最小的x,y
for (int i = 0; i < in_list_point.Count; i++)
{
if (i_offset_x > in_list_point[i].X)
{
i_offset_x = in_list_point[i].X;
}
if (i_offset_y > in_list_point[i].Y)
{
i_offset_y = in_list_point[i].Y;
}
}
List list_point = new List();
//将各Field的OTS坐标与屏幕左上角的坐标进行相减,取出与屏幕左上角的偏移量,也就是取出了屏幕坐标
int index = 0;
for (int i = 0; i < in_list_point.Count; i++)
{
list_point.Add(new Point(in_list_point[i].X - i_offset_x, in_list_point[i].Y - i_offset_y));
//根据物理坐标的对应关系,找到了在数组中的位置,下面将用该位置对应得出像素坐标的位置,并进行返回
if (in_list_point[i] == in_physics_point)
{
index = i;
}
}
//再将物理像素list_point换算成像素list_point,再用index定位
for (int i = 0; i < list_point.Count; i++)
{
//将单个物理像素变换成屏幕像素分辨率
int i_bs_x = 0;
int i_bs_y = 0;
if (rect_onefield_wl.Width != 0)
i_bs_x = list_point[i].X / rect_onefield_wl.Width;
if (rect_onefield_wl.Height != 0)
i_bs_y = list_point[i].Y / rect_onefield_wl.Height;
//再将屏幕像素分辨率按倍数赋值给list_point
//考虑到OTS坐标整体是Y轴向上为正,所以这里需要根据总高,减y轴就是向上为正
list_point[i] = new Point(in_screen_width * i_bs_x, in_screen_height * i_bs_y);
}
#region Y轴向上为正转换---------------------------------------------------------------------------------------
//但上面由于相减,会出现y轴为负的情况,所以这里要根据Y轴是否出现负值,再次做偏移运算
//找到最小的y轴,也就是 [Y轴偏移量]
int i_offset_y_second = 100000000;
//找到最大的Y轴,用于做相反运算,Y轴向上
int i_screen_y = -100000000;
for (int i = 0; i < list_point.Count; i++)
{
if (i_offset_y_second > list_point[i].Y)
{
i_offset_y_second = list_point[i].Y;//这个偏移Y就是最小的Y,可能是负数,也可能是0
}
if (i_screen_y < list_point[i].Y)
{
i_screen_y = list_point[i].Y;
}
}
//对Y轴进行反转,OTS坐标向屏幕坐标转换
for (int i = 0; i < list_point.Count; i++)
{
list_point[i] = new Point(list_point[i].X, i_screen_y - list_point[i].Y);
}
//再将所有的Field与这个 [Y轴偏移量] 相加,防止OTS向上为正转换屏幕坐标,造成的Y轴为负的情况
for (int i = 0; i < list_point.Count; i++)
{
list_point[i] = new Point(list_point[i].X, list_point[i].Y + Math.Abs(i_offset_y_second));
}
#endregion Y轴向上为正转换结束--------------------------------------------------------------------------
return list_point[index];
}
///
/// 根据type,从三种分类的分析库中提取当前分析物的颜色
///
///
///
///
public Color GetColorBySTDTypeIDForBSEAndSorImage(string in_cotssampleclr, int in_stdtypeid)
{
Color ret_c = new Color();
if (in_stdtypeid < 1000)
{
OTSSysSTDMgrClass osc = new OTSSysSTDMgrClass();
//小于1000,使用系统默认分类
ret_c = osc.GetColorByEnum(in_stdtypeid);
}
else if (in_stdtypeid >= 1000)
{
//大于等于1000,并且小于10000时,使用用户标准库来分析夹杂物名称
if (!in_cotssampleclr.Contains("#"))
{
ret_c = DrawFunction.colorHx16toRGB("#" + in_cotssampleclr);//接收必须是#000000的格式
}
else
{
ret_c = DrawFunction.colorHx16toRGB(in_cotssampleclr);//接收必须是#000000的格式
}
}
return ret_c;
}
///
/// 计算像素总画面Image大小,及进行物理坐标与分辨率坐标的换算操作 传入物理坐标,及宽高,来
///
/// 传入的物理坐标数组
/// 单个field宽
/// 单个field高
///
public Rectangle ConvertAndGetMaxRect(List in_list_point, int in_width, int in_height)
{
//首先要能确定下来,单个物理坐标的宽和高--------------------------------
int i_wl_width = 0;
int i_wl_height = 0;
Rectangle ls_r = GetOneFieldWidthAndHeight(in_list_point);
i_wl_width = ls_r.Width;
i_wl_height = 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 < in_list_point.Count(); i++)
{
Point ls_point = in_list_point[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 (in_list_point.Count > 0)
{
ret_rectangle = new Rectangle(0, 0, point_x_max, point_y_max);
}
//这样返回是物理坐标的总大小,应该返回像素坐标大小才对
return ret_rectangle;
}
///
/// 计算单个field的物理大小 传入field的list,还有测量结果管理类对象,在无法计算出单file的物理大小的情况下,到这里取再计算得出
///
///
public Rectangle GetOneFieldWidthAndHeight(List in_list_point)
{
int i_wl_width_max = -10000000;
int i_wl_height_max = -10000000;
int i_wl_width_max2 = -10000000;
int i_wl_height_max2 = -10000000;
//先找出最大的值,
for (int i = 0; i < in_list_point.Count(); i++)
{
if (i_wl_width_max < in_list_point[i].X)
i_wl_width_max = in_list_point[i].X;
if (i_wl_height_max < in_list_point[i].Y)
i_wl_height_max = in_list_point[i].Y;
}
//再找出第二大的值
for (int i = 0; i < in_list_point.Count(); i++)
{
if (i_wl_width_max2 < in_list_point[i].X && i_wl_width_max != in_list_point[i].X)
i_wl_width_max2 = in_list_point[i].X;
if (i_wl_height_max2 < in_list_point[i].Y && i_wl_height_max != in_list_point[i].Y)
i_wl_height_max2 = in_list_point[i].Y;
}
//需要针对第二大的值,获取时进行判断,感觉这里应该如果并未找到第二大的值的情况下,赋于0值,便于以后进行计算
if (i_wl_width_max2 == -10000000)
i_wl_width_max2 = 0;
if (i_wl_height_max2 == -10000000)
i_wl_height_max2 = 0;
Rectangle ret_rect = new Rectangle(0, 0, i_wl_width_max - i_wl_width_max2, i_wl_height_max - i_wl_height_max2);
//如果最后计算出的宽高有0则重新到测量数据中获取---------------------------------------
if (ret_rect.Width == 0 || ret_rect.Height == 0)
{
//到参数中去取单个宽
double d_onefilesize_width = Convert.ToDouble(((Dictionary)resultFile.ResultInfo["SEMStageData"])["scanFieldSize"]);
//然后再用单个宽去计算出高是多少
double d_onefilesize_height = 0;
if (d_onefilesize_width != 0)
d_onefilesize_height = (d_onefilesize_width / 4) * 3;
ret_rect.Width = (int)d_onefilesize_width;
ret_rect.Height = (int)d_onefilesize_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 (m_list_OTSField == null)
return;
Particle particle = m_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));
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].OTS_RECT.X), Convert.ToInt32(in_list_dfield[i].OTS_RECT.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(DParticle 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;
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(DParticle 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;
}
}
#region //--------------------------------------颗粒排序图相关部份---------------------------------------------------------------------
///
/// 根据传入的fieldid和tagid返回该颗粒的OTS坐标
///
///
///
///
public Point GetOTSPointFromOld_list_sortparticledistribution(int in_fieldid, int in_tagid, Control_DrawDistrbutionSortImage in_control_drawdistrbutionsortimage)
{
Point ret_point = new Point(0, 0);
if (m_list_OTSField != null)
{
Field field = m_list_OTSField.Find(x => x.FieldID == in_fieldid);
ret_point = new Point() { X = field.FieldPosX, Y = field.FieldPosY };
}
return ret_point;
}
#endregion
}
}