using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using OTSModelSharp.ServiceCenter; using static OTSDataType.otsdataconst; using OTSDataType; using System.Diagnostics; using System.Drawing; using System.Threading; using OTSModelSharp.DTLBase; using OTSCLRINTERFACE; using OTSMeasureApp._0_OTSModel.Measure.ParamData; using System.Windows.Forms; using System.Data; namespace OTSModelSharp { using CHoleBSEImgsList = List; public class CSmplMeasure { protected static NLog.Logger log ; protected bool bSaveThreadWorking; protected System.Threading.Thread m_thread_ptr; protected COTSSample m_Sample; protected COTSSample m_HolePreviewSample; protected CMeasure m_pMsrThread; string m_strWorkingFolder; protected CSmplMsrResult m_pSampleRstFile; CHoleBSEImgsList m_listHoleBSEImg; protected ISemController m_SemHardwareMgr; protected IScanController m_ScanHardwareMgr; protected IEDSController m_EDSHardwareMgr; protected Queue fieldQueue=new Queue(); protected IClassifyEngine m_classifyEngine; public CSmplMeasure( string a_strWorkingFolder, COTSSample a_pSample) { m_Sample = a_pSample; log = NLog.LogManager.GetCurrentClassLogger(); var expC = m_Sample.GetMsrParams().GetXRayParam().GetAnalyExpCount(); var imgwidth = m_Sample.GetMsrParams().GetImageScanParam().GetImageResolutionSize().cx; var imgheight = m_Sample.GetMsrParams().GetImageScanParam().GetImageResolutionSize().cy; m_strWorkingFolder = a_strWorkingFolder; m_pSampleRstFile = new CSmplMsrResult( a_strWorkingFolder, a_pSample); m_SemHardwareMgr = SemController.GetSEMController(); m_ScanHardwareMgr = ScanController.GetScanController(); m_EDSHardwareMgr = EDSController.GetEDSController(imgwidth,imgheight,expC); m_listHoleBSEImg = new CHoleBSEImgsList(); m_Sample = a_pSample; } public void SetSample(COTSSample a_pSample) { m_Sample = a_pSample; m_pSampleRstFile.SetSample(a_pSample); } public COTSSample GetSample() { return m_Sample; } public void SetHolePreviewSample(COTSSample a_pSample) { m_HolePreviewSample = a_pSample; } public COTSSample GetHolePreviewSample() { return m_HolePreviewSample; } public void SetMsrThread(CMeasure mt) { m_pMsrThread = mt; } bool SetSEMDataMrs(COTSSample sample) { var pSEMDataMsr = sample.GetSEMDataMsr(); double dMag = pSEMDataMsr.GetMagnification(); double dWorkDis = pSEMDataMsr.GetWorkingDistance(); var pSEMCtrl = m_pMsrThread.GetSEMController(); pSEMCtrl.SetMagnification(dMag); pSEMCtrl.SetWorkingDistance(dWorkDis); return true; } bool SetSEMExteralOn() { var pSEMCtrl = m_SemHardwareMgr; log.Warn("Set Scan Exteral on!"); pSEMCtrl.SetScanExternal(true); return true; } // set SEM external off bool SetSEMExteralOff() { var pSEMCtrlPtr = m_SemHardwareMgr; log.Warn("Set SEM Exteral Off!"); pSEMCtrlPtr.SetScanExternal(false); return true; } bool SetBSEParam() { // get scan controller var pScanController = m_ScanHardwareMgr; // scan parameters var pMsrParam = m_Sample.GetMsrParams(); var pImgScanParam = pMsrParam.GetImageScanParam(); // get image size var nImageSizeId = pImgScanParam.GetImageResulotion(); int nResulotionId = RESOLUTION_ID_FIRST_TIE + (int)nImageSizeId; Size sizePixelImage = RESOLUTION_VALUE[nResulotionId]; // get dwell time OTS_IMAGE_SCANSPEED_OPTIONS nDwellTime = pImgScanParam.GetScanImageSpeed(); // convert dwell time to bruker dwell time (8, 16, 32) int nBrukerDwellTimeId; switch (nDwellTime) { case OTS_IMAGE_SCANSPEED_OPTIONS.low: nBrukerDwellTimeId = 1; break; case OTS_IMAGE_SCANSPEED_OPTIONS.meddium: nBrukerDwellTimeId = 2; break; case OTS_IMAGE_SCANSPEED_OPTIONS.high: nBrukerDwellTimeId = 3; break; default: nBrukerDwellTimeId = 1; break; } long nBrukerDwellTime = OTSDataType.otsdataconst.DWELLTIME_BRUKER_VALUES[nBrukerDwellTimeId]; if (!pScanController.Init()) { log.Error("SetBSEParam: failed to get scan control."); return false; } // set dwell time if (!pScanController.SetDwellTime(nBrukerDwellTime)) { log.Error("SetBSEParam: failed to set dwell time (%d) for bruker system.", nBrukerDwellTime); return false; } // set image size if (!pScanController.SetImageSize(sizePixelImage.Width,sizePixelImage.Height)) { // failed to set dwell time log.Error("SetBSEParam: failed to set dwell time (%d).", sizePixelImage.Height); return false; } return true; } bool SetHoleBSEParam(COTSSample sample) { // get SEM controller //var pSEMController = m_SemHardwareMgr; // get scan controller var pScanController = m_ScanHardwareMgr; // scan parameters var pMsrParam = sample.GetMsrParams(); var pImgScanParam = pMsrParam.GetImageScanParam(); // get image size var nImageSizeId = pImgScanParam.GetImageResulotion(); int nResulotionId = RESOLUTION_ID_FIRST_TIE + (int)nImageSizeId; Size sizePixelImage = RESOLUTION_VALUE[nResulotionId]; // get dwell time OTS_IMAGE_SCANSPEED_OPTIONS nDwellTime = pImgScanParam.GetScanImageSpeed(); // convert dwell time to bruker dwell time (6, 16, 32) long nBrukerDwellTime = DWELLTIME_BRUKER_VALUES[2];// choose the third option, so the dwell time will be 4 . there's no need to change here. it shoud be a const. if (!pScanController.Init()) { log.Error("SetBSEParam: failed to get scan control."); return false; } // set dwell time if (!pScanController.SetDwellTime(nBrukerDwellTime)) { log.Error("SetBSEParam: failed to set dwell time (%d) for bruker system.", nBrukerDwellTime); return false; } // set image size if (!pScanController.SetImageSize(sizePixelImage.Width/2, sizePixelImage.Height/2)) { // failed to set dwell time log.Error("SetBSEParam: failed to set ImageSize"); return false; } return true; } public void SetWorkingFolder(String a_strWorkingFolder) { // add "\\" at the string end if it is not "\\" if (a_strWorkingFolder.PadRight(1)!="\\") { a_strWorkingFolder += "\\"; } m_strWorkingFolder = a_strWorkingFolder + m_Sample.GetName() + "\\"; } bool CalculateUnMeasuredFieldsCenters(COTSSample sample, out List a_allpieldcenter, out List a_listUnMsrFieldCenter) { // sample measure parameters CMeasureParam pMsrParam = sample.GetMsrParams(); COTSImgScanPrm poImageScanParam = pMsrParam.GetImageScanParam(); COTSImageProcParam pImgProcParam = pMsrParam.GetImageProcessParam(); CSEMDataMsr poSEMDataMsr = m_Sample.GetSEMDataMsr(); CMsrSampleStatus pStatus = m_Sample.GetMsrStatus(); //CSEMDataMsr poSEMDataMsr = sample.GetSEMDataMsr(); //CMsrSampleStatus pStatus = sample.GetMsrStatus(); // measured field centers list List listCompletedCenter = pStatus.GetCompletedFieldsCenter(); // field centers list manager CFieldPositionMgr pFieldMgr = new CFieldPositionMgr(); // init field centers list manager if (!pFieldMgr.Init(sample.GetMsrDomain(), poImageScanParam, pImgProcParam, poSEMDataMsr, listCompletedCenter)) { log.Error("CalculateFieldsCenters: failed to init field centres list manager."); a_listUnMsrFieldCenter = new List(); a_allpieldcenter = new List(); return false; } // get field centers list a_listUnMsrFieldCenter = pFieldMgr.GetUnmeasuredFieldCentrePoints();// GetFieldCentrePoints(); a_allpieldcenter = pFieldMgr.GetFieldCentrePoints(); // ok, return TRUE return true; } protected bool IsAborted() { return m_pMsrThread.IsMeasureStopped(); } protected bool IsPaused() { //Debug.Assert(m_pMsrThread == null); var statu = m_pMsrThread.GetMsrThreadStatus(); if (statu.GetStatus() == OTS_MSR_THREAD_STATUS.PAUSED) { return true; } else { return false; } } bool IsSampleOver(COTSImgScanPrm a_pScanParam) { string sStopMode = a_pScanParam.GetStopMode(); int nStopField = a_pScanParam.GetStopParamFields(); // completed fields number CMsrSampleStatus pMsrSampleStatus = m_Sample.GetMsrStatus(); int nCompeltedField = pMsrSampleStatus.GetCompletedFields(); CMsrResultItems pMsrResults = m_Sample.GetMsrResults(); List listMsrResult = pMsrResults.GetResultItems(); int nNumParticle = 0; foreach (var pResult in listMsrResult) { if (pResult.GetTypeId() > (int)OTS_PARTCLE_TYPE.NOT_IDENTIFIED)//summarize the number of the identified particle in this condition { nNumParticle += (int)pResult.GetNumber(); } } TimeSpan timeSpan = pMsrSampleStatus.GetUsedTime(); int nDay = timeSpan.Days; int nHour = timeSpan.Hours; int nMin = timeSpan.Minutes; int nSec = timeSpan.Seconds; int nUsedTime = nSec + nMin * 60 + nHour * 3600 + nDay * 86400; int NMeasArea = (int)pMsrResults.GetMeasuredArea(); int nParticlAim = a_pScanParam.GetStopParamParticles(); int nMeasTimeAim = a_pScanParam.GetStopParamMeasTime(); int NMeasAreaAim = a_pScanParam.GetStopParamArea()*1000000 ; bool bRet = false; string[] str = sStopMode.Replace(" ", "").Split('+'); for(int i=0;i< str.Length;i++) { switch (int.Parse(str[i].Split(':')[0])-1) { case (int)OTS_MEASURE_STOP_MODE.CoverMode: // completed fields number if (nCompeltedField == m_Sample.GetFieldsData().Count) { bRet = true; } break; case (int)OTS_MEASURE_STOP_MODE.FieldMode: if (nCompeltedField >= nStopField) { bRet = true; } break; case (int)OTS_MEASURE_STOP_MODE.ParticleMode: if (nNumParticle >= nParticlAim) { bRet = true; } break; case (int)OTS_MEASURE_STOP_MODE.TimeMode: if (nUsedTime >= nMeasTimeAim) { bRet = true; } break; case (int)OTS_MEASURE_STOP_MODE.AreaMode: if (NMeasArea >= NMeasAreaAim) { bRet = true; } break; default: break; } } return bRet; } // move SEM to the point bool MoveSEMToPoint(System.Drawing.PointF a_poi) { // get SEM controller var pSEMController = m_SemHardwareMgr; PointF a_SEMpt = new Point(); CSEMStageData a_pCSEMStageData = m_pMsrThread.GetProjResultData().GetSEMStageData(); int hardWareDelay = a_pCSEMStageData.GetHardWareDelay(); if (!a_pCSEMStageData.ConvertOTSToSEMCoord(a_poi, ref a_SEMpt)) { return false; } log.Info("Begin to move SEM stage to OTScoord:" + a_poi.X + "," + a_poi.Y); log.Info("Begin to move SEM stage to " + a_SEMpt.X + "," + a_SEMpt.Y); // move SEM to the position (rotation 0) if (!pSEMController.MoveSEMToPoint(a_SEMpt.X, a_SEMpt.Y)) { log.Error("MoveSEMToPoint: failed to call MoveSEMToPoint method."); return false; } CMeasureParam pMsrParam = m_Sample.GetMsrParams(); if (pMsrParam.SlopParam.IsUsingSlopParam) { double wd = pMsrParam.SlopParam.GetWD(a_SEMpt); double originWd = 0; pSEMController.GetWorkingDistance(ref originWd); if ((wd - originWd) > 2) { log.Warn("Working Distance is invalid,outof the moving scope(2cm) wd=" + wd.ToString("F2")); } else { Thread.Sleep(hardWareDelay); pSEMController.SetWorkingDistance(wd); } } Thread.Sleep(hardWareDelay); return true; } // Acquire a BSE image CBSEImgClr AcquireABSEImage() { // BSE image CBSEImgClr pBSEImage = null; // get scan controller var pScanController = m_ScanHardwareMgr; pBSEImage = pScanController.AcquireBSEImage(); return pBSEImage; } public virtual void ClassifyFieldParticles(COTSFieldData curFldData) { return; } public virtual void ClassifyMergedParticles(List parts) { return; } private class SEMStateObject { private PointF pos; private double workingDistance; private CSEMDataGnr semdata; private COTSSample originalSample; private double magnification; public PointF Pos { get => pos; set => pos = value; } public double WorkingDistance { get => workingDistance; set => workingDistance = value; } public CSEMDataGnr Semdata { get => semdata; set => semdata = value; } public double Magnification { get => magnification; set => magnification = value; } public COTSSample OriginalSample { get => originalSample; set => originalSample = value; } } private class AutoResetSEMControl:IDisposable { CSmplMeasure sm; private SEMStateObject semState=null; public AutoResetSEMControl(CSmplMeasure s) { sm = s; } public SEMStateObject SemState { get => semState; set => semState = value; } public void Dispose() { if (semState != null) { sm.SetBSEParam(); sm.m_SemHardwareMgr.SetMagnification(semState.Magnification); sm.MoveSEMToPoint(semState.Pos); sm.m_SemHardwareMgr.SetWorkingDistance(semState.WorkingDistance); } sm.SetSEMExteralOff(); } } private bool GetSEMDataGnrFromHw(ref CSEMDataGnr SemDataGnr) { double kv = 0, brightness = 0, contrast = 0; var hw = SemController.GetSEMController(); hw.GetSemHighTension(ref kv); hw.GetSemBrightness(ref brightness); hw.GetSemContrast(ref contrast); SemDataGnr.SetValue(kv, brightness, contrast); return true; } public void DoMeasureForOneSample() { using (AutoResetSEMControl autoReset = new AutoResetSEMControl(this)) //when this method exit ,the SetSEMExternalOff and ResetScan will be called automatically. { // let the main thread to know that this sample measurement starts var pStatus = m_Sample.GetMsrStatus(); pStatus.SetStatus(OTS_MSR_SAMPLE_STATUS.INPROCESS); // set current time to current time pStatus.ComputeTime(OTS_MSR_TIME_TYPE.START); // let main App know that the sample begin to measure ST_MSTMsg MsgSmpStart = new ST_MSTMsg(); MsgSmpStart.iMsgType = ENUM_MSG_TYPE.MSAMPLESTATUS; MsgSmpStart.STMSampleStu.iMsrSampleStatu = OTS_MSR_SAMPLE_STATUS.INPROCESS; MsgSmpStart.STMSampleStu.cSampleName = m_Sample.GetName(); m_pMsrThread.SendMessageToMeasureApp(MsgSmpStart); log.Info(m_Sample.GetName() + " Measurement started!"); // get SEM controller to set magnification and working distance if (!SetSEMDataMrs(m_Sample)) { log.Error("DoMeasure: fail to set SEM data."); pStatus.SetStatus(OTS_MSR_SAMPLE_STATUS.FAILED); pStatus.ComputeTime(OTS_MSR_TIME_TYPE.STOPPED); return; } // set the BSE scan param if (!SetBSEParam()) { log.Error("DoMeasure: fail to set BSE param."); pStatus.SetStatus(OTS_MSR_SAMPLE_STATUS.FAILED); pStatus.ComputeTime(OTS_MSR_TIME_TYPE.STOPPED); return; } var pSEMDataGnr = new CSEMDataGnr(); log.Info("Get Kv, Brightness and Contrast!"); GetSEMDataGnrFromHw(ref pSEMDataGnr); m_pSampleRstFile.SetSEMGnr(pSEMDataGnr); // record SEM data COTSMsrPrjResultData pProjMgrFile = m_pMsrThread.GetProjResultData(); CSEMStageData pSEMStageData = pProjMgrFile.GetSEMStageData(); m_pSampleRstFile.SetSEMStageData(pSEMStageData); // record stage CStage pStage = pProjMgrFile.GetStage(); m_pSampleRstFile.SetSEMStage(pStage); //-----save the static measure result file data into xml file and the dynamic data of every field will be saved into sqlite database log.Info("Create result file!"); if (!m_pSampleRstFile.CreateResultFiles()) {// failed to call measure result file Save method log.Error("DoMeasure: failed to call measure result file Save method."); pStatus.SetStatus(OTS_MSR_SAMPLE_STATUS.FAILED); pStatus.ComputeTime(OTS_MSR_TIME_TYPE.STOPPED); return; } //------ var FldDatas = m_Sample.GetFieldsData(); if (m_EDSHardwareMgr.GetEDSType()==EDSTYPE.BRUKER && m_Sample.GetMsrParams().GetXRayParam().GetUseFilter()) { List KeyNameList = new List(); string DBAddress = Application.StartupPath + "\\Config\\SysData\\" + m_Sample.GetMsrParams().GetSTDName() + ".db"; SQLiteHelper sQLiteHelper = new SQLiteHelper(DBAddress);// KeyNameList = sQLiteHelper.GetDBKeyElementList("ClassifySTD", "KeyElementList"); m_EDSHardwareMgr.SetFilterKeyEleNames( KeyNameList);//will decide if do the quantification according to this keyelelist. } for (int i = 0; i < FldDatas.Count; ++i) {// check and break if stop button is clicked var curFld = FldDatas[i]; if (curFld.GetIsMeasureComplete()) { continue; } if (IsPaused()) {// measure stopped pStatus.SetStatus(OTS_MSR_SAMPLE_STATUS.PAUSED); // record end time pStatus.ComputeTime(OTS_MSR_TIME_TYPE.STOPPED); //must wait for the saving data thread finished,or we'll get null pointer exception when we stop the measure process. while (fieldQueue.Count() > 0) { Thread.Sleep(100); } SetSEMExteralOff(); // update thread measure status class, let the main thread know that this sample measurement stopped ST_MSTMsg MsgSmpStop = new ST_MSTMsg(); MsgSmpStop.iMsgType = ENUM_MSG_TYPE.MSAMPLESTATUS; MsgSmpStop.STMThreadStu.iMsrStatu = OTS_MSR_THREAD_STATUS.PAUSED; MsgSmpStop.STMSampleStu.iMsrSampleStatu = OTS_MSR_SAMPLE_STATUS.PAUSED; MsgSmpStop.STMThreadStu.csMsrEndTime = DateTime.Now.ToShortDateString(); MsgSmpStop.STMThreadStu.iMsrStatu = OTS_MSR_THREAD_STATUS.PAUSED; m_pMsrThread.SendMessageToMeasureApp(MsgSmpStop); while (IsPaused()) { Thread.Sleep(300); } } if (IsAborted()) {// measure stopped pStatus.SetStatus(OTS_MSR_SAMPLE_STATUS.STOPPED); // record end time pStatus.ComputeTime(OTS_MSR_TIME_TYPE.STOPPED); //must wait for the saving data thread finished,or we'll get null pointer exception when we stop the measure process. while (fieldQueue.Count() > 0) { Thread.Sleep(100); } break; } // check if sample measurement completes COTSImgScanPrm pScanParam = m_Sample.GetMsrParams().GetImageScanParam(); if (IsSampleOver(pScanParam)) { pStatus.SetStatus(OTS_MSR_SAMPLE_STATUS.SUCCESSED); pStatus.ComputeTime(OTS_MSR_TIME_TYPE.COMPLT); break; } // get a field center System.Drawing.PointF poiFieldCentre = curFld.GetOTSPosition(); // update thread measure status class, let the main thread know that starts a new field ST_MSTMsg MsgFieldStart = new ST_MSTMsg(); MsgFieldStart.iMsgType = ENUM_MSG_TYPE.MSAMPLERESULT; MsgFieldStart.STMSampleRetData.iRetDataType = MSAMPLE_RET.START_MSR_FIELD; MsgFieldStart.STMSampleRetData.SMsrField.FieldPos = new Point((int)poiFieldCentre.X,(int)poiFieldCentre.Y); m_pMsrThread.SendMessageToMeasureApp(MsgFieldStart); int fldNo = curFld.GetId(); log.Warn("Current field:" + fldNo.ToString()); // move SEM to the field center if (!MoveSEMToPoint(poiFieldCentre)) {// failed to move SEM to the position log.Error("DoMeasure: failed to move SEM to the field centre point."); pStatus.SetStatus(OTS_MSR_SAMPLE_STATUS.FAILED); // record end time pStatus.ComputeTime(OTS_MSR_TIME_TYPE.STOPPED); return; } log.Info("Begin to Acquire BSE image!"); // take BSE image for the fields CBSEImgClr pBSEImg = AcquireABSEImage(); // let the main thread to know that image process is completed if (pBSEImg == null) { log.Error("ImageProcess: can't get no background image."); pStatus.SetStatus(OTS_MSR_SAMPLE_STATUS.FAILED); return; } //BSEData ST_MSTMsg MsgFieldBSE = new ST_MSTMsg(); MsgFieldBSE.iMsgType = ENUM_MSG_TYPE.MSAMPLERESULT; MsgFieldBSE.STMSampleRetData.iRetDataType = MSAMPLE_RET.BSE_DATA; MsgFieldBSE.STMSampleRetData.BSEData.pos.X = (int)poiFieldCentre.X; MsgFieldBSE.STMSampleRetData.BSEData.pos.Y = (int)poiFieldCentre.Y; MsgFieldBSE.STMSampleRetData.BSEData.iBSEDataHeight = pBSEImg.GetHeight(); MsgFieldBSE.STMSampleRetData.BSEData.iBSEDataWidth = pBSEImg.GetWidth(); byte[] pImgData = pBSEImg.GetImageDataPtr(); MsgFieldBSE.STMSampleRetData.BSEData.lpBSEData = pImgData; m_pMsrThread.SendMessageToMeasureApp(MsgFieldBSE); log.Info("Acquire BSE image success! Processing image..."); // image process var rst = FieldImageProcess(curFld, pBSEImg); if (rst == true) { curFld.SetIsMeasureComplete(true); } else { return; } //start db save StartSaveFileThread(ref curFld); double measuredArea = 0; // this area should be the field area var a_pBSEImg = curFld.GetBSEImage(); double dPixelSize = curFld.GetPixelSize(); measuredArea = a_pBSEImg.GetHeight() * a_pBSEImg.GetWidth()* dPixelSize * dPixelSize + 0.5; //Get measured area CumulateFieldData(curFld.GetListAnalysisParticles(), measuredArea); log.Info("Send field data to screen!"); pStatus.AddCompletedFieldCenter(poiFieldCentre); //Field Data // record end time pStatus.ComputeTime(OTS_MSR_TIME_TYPE.STOPPED); ST_MSTMsg MsgFieldEnd = new ST_MSTMsg(); MsgFieldEnd.iMsgType = ENUM_MSG_TYPE.MSAMPLERESULT; MsgFieldEnd.STMSampleRetData.iRetDataType = MSAMPLE_RET.FIELD_DATA; MsgFieldEnd.STMSampleRetData.SFieldData.iCompleteFieldCount = pStatus.GetCompletedFields(); MsgFieldEnd.STMSampleRetData.SFieldData.iMeasureFieldCount = m_Sample.GetFieldsData().Count; MsgFieldEnd.STMSampleRetData.SFieldData.iSParticleCount = (int)curFld.GetListAnalysisParticles().Count; MsgFieldEnd.STMSampleRetData.SFieldData.FieldPos.X = Convert.ToInt32(poiFieldCentre.X); MsgFieldEnd.STMSampleRetData.SFieldData.FieldPos.Y = Convert.ToInt32(poiFieldCentre.Y); m_pMsrThread.SendMessageToMeasureApp(MsgFieldEnd); } while (bSaveThreadWorking)//wait untill all the field data has been saved. { Thread.Sleep(1000); log.Warn("db saving!"); } TheLastWorkOfSampleMeasure(); } } public void TheLastWorkOfSampleMeasure() { COTSSample theSample = m_Sample; var pStatus = theSample.GetMsrStatus(); //merging particles log.Info("Merging big particles which are crossing the field edge!"); CImageHandler imgpro = new CImageHandler(); int scanfldsize = theSample.GetSEMDataMsr().GetScanFieldSize(); List mergedParticles = new List(); double pixelSize = theSample.CalculatePixelSize(); imgpro.MergeBigBoundaryParticles(theSample.GetFieldsData(), pixelSize, scanfldsize, theSample.GetResolutionSize(), ref mergedParticles); CalculateMergedPartProperty(mergedParticles, pixelSize); ClassifyMergedParticles(mergedParticles); log.Info("begin merged particle data db saving..."); SaveMergedParticles(mergedParticles); pStatus.ComputeTime(OTS_MSR_TIME_TYPE.COMPLT); pStatus.SetStatus(OTS_MSR_SAMPLE_STATUS.SUCCESSED); // let main thread to know that this sample measurement completes ST_MSTMsg MsgSmplEnd = new ST_MSTMsg(); MsgSmplEnd.iMsgType = ENUM_MSG_TYPE.MSAMPLESTATUS; MsgSmplEnd.STMSampleStu.iMsrSampleStatu = OTS_MSR_SAMPLE_STATUS.SUCCESSED; MsgSmplEnd.STMSampleStu.cSampleName = theSample.GetName(); m_pMsrThread.SendMessageToMeasureApp(MsgSmplEnd); } public bool DoMEasureForReMeasure() { return true; } private void CalculateMergedPartProperty(List mergedParticles,double pixelSize) { var m_ImagePro = new CImageHandler(); foreach (COTSParticleClr part in mergedParticles) { m_ImagePro.CalParticleImageProp(part, pixelSize); } } public virtual bool FieldImageProcess(COTSFieldData curFldData, CBSEImgClr a_pBSEImg) { PointF fldCenter = curFldData.OTSPos; curFldData.SetBSEImage(a_pBSEImg); CSEMStageData a_pCSEMStageData = m_pMsrThread.GetProjResultData().GetSEMStageData(); PointF semPos = new Point(); a_pCSEMStageData.ConvertOTSToSEMCoord(fldCenter, ref semPos); curFldData.SetSemPos(semPos); //first step:remove background of the bse image and compound all the finded particles. log.Info("Begin to process image and get all particles!"); GetOriginalParticles(ref curFldData); // second step :filter the finded particles. log.Info("Begin to filter particles!"); FilterParticles(ref curFldData); CalculateParticleAbsolutPos(ref curFldData); log.Info("Begin to Calculate the image property of every particle!"); var analysisparts = curFldData.GetListAnalysisParticles(); curFldData.CalParticleImageProp(analysisparts);//calculate particle image property such as feret diameter, DMAX etc. COTSXRayParam pXRayParam = m_Sample.GetMsrParams().GetXRayParam(); if (pXRayParam.GetUsingXray() == true) { log.Info("Begin to collect particle's xray data!"); //Thread.Sleep(100); CollectParticlesXrayData(curFldData); //Thread.Sleep(100); } log.Info("Begin to classify particles! particle num:" + curFldData.GetListAnalysisParticles().Count); ClassifyFieldParticles(curFldData); m_Sample.GetMsrStatus().SetStatus(OTS_MSR_SAMPLE_STATUS.SUCCESSED); return true; } public void GetOriginalParticles(ref COTSFieldData curFldData) { // measure status //CMsrSampleStatus pStatus = m_Sample.GetMsrStatus(); // get image process parameter CMeasureParam pMsrParam = m_Sample.GetMsrParams(); COTSImageProcParam pImgProcessParam = pMsrParam.GetImageProcessParam(); var specialPartsparam = pMsrParam.GetSpecialGrayRangeParam(); var pixelsize = m_Sample.CalculatePixelSize(); if (specialPartsparam != null && specialPartsparam.GetIsToRun()) { List ranges = pMsrParam.GetSpecialGrayRangeParam().GetSpecialGreyRanges(); foreach (var grayRange in ranges) { CIntRangeClr range = new CIntRangeClr(grayRange.range.GetStart(), grayRange.range.GetEnd()); CDoubleRangeClr diaRange = new CDoubleRangeClr(grayRange.diameterRange.GetStart(), grayRange.diameterRange.GetEnd()); curFldData.GetPartsBySpecialGray(range, diaRange, pixelsize, grayRange.ifCollectXray); } } var ifCollectxray = pMsrParam.GetXRayParam().GetUsingXray(); // remove BES image background curFldData.RemoveImgBGAndGetParticles(pImgProcessParam, pixelsize, ifCollectxray); // check if this is an empty image if (curFldData.NoParticle()) { // empty fields log.Info("ImageProcess: empty field."); } return; } public void FilterParticles(ref COTSFieldData curFldData) { if (curFldData.NoAnalysisParticle()) { log.Warn("There's no analysis particles!"); return; } CMeasureParam pMsrParam = m_Sample.GetMsrParams(); COTSImageProcParam pImgProcessParam = pMsrParam.GetImageProcessParam(); double dPixelSize = m_Sample.CalculatePixelSize(); curFldData.InitParticles(pImgProcessParam, dPixelSize); var listXray = curFldData.GetAllParticles().OrderByDescending(x => x.GetActualArea()).ToList(); var listXray1 = new List(); var pXRayParam = pMsrParam.GetXRayParam(); if (listXray.Count > pXRayParam.GetXrayLimit()) { for (var i = 0; i < pXRayParam.GetXrayLimit(); i++) { listXray1.Add(listXray[i]); } } else { listXray1 = listXray; } curFldData.SetListAnalysisParticles(listXray1); log.Info("Analysis particles:"+ listXray1.Count); //2) according to the quantify threshold size value separate the analysis particles into two group :the bigparticles and the smallparticles. double quantifyThreshold = m_Sample.GetMsrParams().GetXRayParam().GetFeatureModeMinSize(); var smallparts = curFldData.ListSmallParticles; var bigparts = curFldData.ListBigParticles; foreach (var part in listXray1) { double equalCircleDiameter = Math.Sqrt(part.GetActualArea() / 3.14159) * 2f; if (equalCircleDiameter < quantifyThreshold) { smallparts.Add(part); } else { bigparts.Add(part); } } curFldData.ListSmallParticles = smallparts; curFldData.ListBigParticles = bigparts; //fld.SmallParticlePercentage=percentage; log.Info("SmallQuantifyParts (<" + quantifyThreshold.ToString("f2") + "): " + smallparts.Count); log.Info("BigQuantifyParts (>=" + quantifyThreshold.ToString("f2") + "): " + bigparts.Count); return; } public virtual void CollectParticlesXrayData(COTSFieldData curFldData) { // get x-ray parameters COTSXRayParam pXRayParam = m_Sample.GetMsrParams().GetXRayParam(); // calculate search x-ray acquire time uint nXRayAQTime; List smallparts = new List(); List bigparts = new List(); foreach (var p in curFldData.ListSmallParticles) { if (p.IsXrayParticle()) { smallparts.Add(p); } } foreach (var p in curFldData.ListBigParticles) { if (p.IsXrayParticle()) { bigparts.Add(p); } } curFldData.CreateXrayList(bigparts); // big particle using the full xray strategy. curFldData.CreateXrayList(smallparts); //small particle using the fast xray strategy if (bigparts.Count > 0) { var workmode = pXRayParam.GetScanMode(); // get x-ray list (analysis) by particle features if (workmode == OTS_X_RAY_SCAN_MODE.FeatureMode) { nXRayAQTime = (uint)pXRayParam.GetMidAnalyAQTime(); m_EDSHardwareMgr.GetXRayByFeatures(bigparts, nXRayAQTime, true); } else if(workmode==OTS_X_RAY_SCAN_MODE.PointMode) { nXRayAQTime = (uint)pXRayParam.GetMidAnalyAQTime(); m_EDSHardwareMgr.GetXRayByParts(bigparts, nXRayAQTime, true); } } if (smallparts.Count > 0) { nXRayAQTime = (uint)pXRayParam.GetFastXrayTime(); // get x-ray list (analysis) by points m_EDSHardwareMgr.GetXRayByParts(smallparts, nXRayAQTime, true); } return; } public void DoHolePreview() { using (AutoResetSEMControl autoReset = new AutoResetSEMControl(this)) { //----------memorize the state of sem var semstate = new SEMStateObject(); double dMagnification = m_Sample.GetSEMDataMsr().GetMagnification(); double wd = m_Sample.GetSEMDataMsr().GetWorkingDistance(); ISemController sem = m_SemHardwareMgr; double posX=0, posY=0,posR=0; sem.GetSemPositionXY(ref posX, ref posY, ref posR); CSEMStageData a_pCSEMStageData = m_pMsrThread.GetProjResultData().GetSEMStageData(); Point pos = new Point((int)posX, (int)posY); PointF otsPos = new Point(0, 0); if (!a_pCSEMStageData.ConvertSEMToOTSCoord(pos, ref otsPos)) { return; } semstate.Pos = otsPos; semstate.Magnification = dMagnification; semstate.WorkingDistance = wd; autoReset.SemState = semstate; //------------------------------------- // let the main thread to know that this sample measurement starts CMsrSampleStatus pStatus = m_HolePreviewSample.GetMsrStatus(); pStatus.SetStatus(OTS_MSR_SAMPLE_STATUS.INPROCESS); // set current time to current time pStatus.ComputeTime(OTS_MSR_TIME_TYPE.START); // let main App know that the sample begin to measure ST_MSTMsg MsgSmpStart=new ST_MSTMsg(); MsgSmpStart.iMsgType = ENUM_MSG_TYPE.MSAMPLESTATUS; MsgSmpStart.STMSampleStu.iMsrSampleStatu = OTS_MSR_SAMPLE_STATUS.INPROCESS; MsgSmpStart.STMSampleStu.cSampleName=m_Sample.GetName(); // get SEM controller to set magnification and working distance if (!SetSEMDataMrs(m_HolePreviewSample)) { log.Error("DoHolePreview: fail to set SEM data."); pStatus.SetStatus(OTS_MSR_SAMPLE_STATUS.FAILED); // record end time pStatus.ComputeTime(OTS_MSR_TIME_TYPE.STOPPED); return; } // set the BSE scan param if (!SetHoleBSEParam(m_HolePreviewSample)) { log.Error("DoHolePreview: fail to set BSE param."); pStatus.SetStatus(OTS_MSR_SAMPLE_STATUS.FAILED); // record end time pStatus.ComputeTime(OTS_MSR_TIME_TYPE.STOPPED); return; } // calculate field centers List listFieldCenter; List alllistFieldCenter ; if (!CalculateUnMeasuredFieldsCenters(m_HolePreviewSample, out alllistFieldCenter,out listFieldCenter)) {// failed to calculate field centers log.Error("DoHolePreview: failed to calculate field centers."); pStatus.SetStatus(OTS_MSR_SAMPLE_STATUS.FAILED); // record end time pStatus.ComputeTime(OTS_MSR_TIME_TYPE.STOPPED); return; } // go through each field int nNewFieldId = 0; for ( int i = 0; i < listFieldCenter.Count; ++i) {// check and break if stop button is clicked if (IsAborted()) {// measure stopped log.Trace("DoHolePreview: measure thread is stopped."); pStatus.SetStatus(OTS_MSR_SAMPLE_STATUS.STOPPED); // record end time pStatus.ComputeTime(OTS_MSR_TIME_TYPE.STOPPED); return; } // check if sample measurement completes COTSImgScanPrm pScanParam = m_Sample.GetMsrParams().GetImageScanParam(); int nTotalFieldSize = listFieldCenter.Count; // get a field center System.Drawing.Point poiFieldCentre = listFieldCenter[i]; // update thread measure status class, let the main thread know that starts a new field pStatus.ComputeTime(OTS_MSR_TIME_TYPE.STOPPED); ST_MSTMsg MsgFieldStart=new ST_MSTMsg(); MsgFieldStart.iMsgType = ENUM_MSG_TYPE.MSAMPLERESULT; MsgFieldStart.STMSampleRetData.iRetDataType = MSAMPLE_RET.START_MSR_FIELD; MsgFieldStart.STMSampleRetData.SMsrField.FieldPos = poiFieldCentre; m_pMsrThread.SendMessageToMeasureApp(MsgFieldStart); // move SEM to the field center if (!MoveSEMToPoint(poiFieldCentre)) {// failed to move SEM to the position log.Error("DoHolePreview: failed to move SEM to the field centre point."); pStatus.SetStatus(OTS_MSR_SAMPLE_STATUS.FAILED); // record end time pStatus.ComputeTime(OTS_MSR_TIME_TYPE.STOPPED); return; } // take BSE image for the fields CBSEImgClr pBSEIamge = AcquireABSEImage(); if (pBSEIamge==null) { // failed to acquire a BSE image log.Error("DoHolePreview: failed to acquire a BSE image."); pStatus.SetStatus(OTS_MSR_SAMPLE_STATUS.FAILED); // record end time pStatus.ComputeTime(OTS_MSR_TIME_TYPE.STOPPED); return; } //BSEData ST_MSTMsg MsgFieldBSE=new ST_MSTMsg(); MsgFieldBSE.iMsgType = ENUM_MSG_TYPE.MSAMPLERESULT; MsgFieldBSE.STMSampleRetData.iRetDataType = MSAMPLE_RET.BSE_DATA; MsgFieldBSE.STMSampleRetData.BSEData.pos = poiFieldCentre; MsgFieldBSE.STMSampleRetData.BSEData.iBSEDataHeight = pBSEIamge.GetHeight(); MsgFieldBSE.STMSampleRetData.BSEData.iBSEDataWidth = pBSEIamge.GetWidth(); byte[] pImgData = pBSEIamge.GetImageDataPtr(); MsgFieldBSE.STMSampleRetData.BSEData.lpBSEData = pImgData; m_pMsrThread.SendMessageToMeasureApp(MsgFieldBSE); if (pStatus.GetStatus() != OTS_MSR_SAMPLE_STATUS.INPROCESS) { // measurement failed or stopped log.Error("DoHolePreview: measurement failed or stopped."); pStatus.SetStatus(OTS_MSR_SAMPLE_STATUS.FAILED); // record end time pStatus.ComputeTime(OTS_MSR_TIME_TYPE.STOPPED); return; } //save the result to project file Rectangle oImageRect = (Rectangle)pBSEIamge.GetImageRect(); CHoleBSEImg pHoleBSEImg =new CHoleBSEImg(oImageRect,poiFieldCentre); pHoleBSEImg.SetImageData( pBSEIamge.GetImageDataPtr(),oImageRect.Width,oImageRect.Height); m_listHoleBSEImg.Add(pHoleBSEImg); // prepare for the next ++nNewFieldId; pStatus.ComputeTime(OTS_MSR_TIME_TYPE.STOPPED); ST_MSTMsg MsgFieldEnd=new ST_MSTMsg(); MsgFieldEnd.iMsgType = ENUM_MSG_TYPE.MSAMPLERESULT; MsgFieldEnd.STMSampleRetData.iRetDataType = MSAMPLE_RET.FIELD_DATA; MsgFieldEnd.STMSampleRetData.SFieldData.iCompleteFieldCount = (i + 1); MsgFieldEnd.STMSampleRetData.SFieldData.iMeasureFieldCount = listFieldCenter.Count; MsgFieldEnd.STMSampleRetData.SFieldData.iSParticleCount = 0; MsgFieldEnd.STMSampleRetData.SFieldData.FieldPos = poiFieldCentre; m_pMsrThread.SendMessageToMeasureApp(MsgFieldEnd); } pStatus.ComputeTime(OTS_MSR_TIME_TYPE.STOPPED); //calculate measure time pStatus.SetStatus(OTS_MSR_SAMPLE_STATUS.SUCCESSED); // let main thread to know that this sample measurement completes ST_MSTMsg MsgSmplEnd=new ST_MSTMsg(); MsgSmplEnd.iMsgType = ENUM_MSG_TYPE.MTHREADSTATUS; MsgSmplEnd.STMThreadStu.iMsrStatu = OTS_MSR_THREAD_STATUS.COMPLETED; m_pMsrThread.SendMessageToMeasureApp(MsgSmplEnd); } } // Cumulate field data info public virtual bool CumulateFieldData( List listParticles, double a_nMeasuredArea) { // get measure result items of the sample CMsrResultItems pMsrResults = m_Sample.GetMsrResults(); // cumulate field data info pMsrResults.CumulateMeasuredArea(a_nMeasuredArea); // cumulate ratio double dRatio = 10000 * pMsrResults.GetTotalParticleArea(); dRatio = dRatio / pMsrResults.GetMeasuredArea(); pMsrResults.SetRatio(dRatio); // go through the particles list foreach (COTSParticleClr pParticle in listParticles) { // create a measure result item pMsrResults.CumulateMeasureResult(pParticle); } // ok, return TRUE return true; } public bool SaveMergedParticles(List mergedParts) { CIncAFileMgr pDBFileMgr = m_pSampleRstFile.DBFileMgr; var mergedpartdb = pDBFileMgr.GetMergedParticleDB(); foreach (COTSParticleClr part in mergedParts) { mergedpartdb.SaveAParticle(part, part.GetXray(), (Point)part.GetAbsolutPos()); } CPosXrayDBMgr pXrayDBMgr = pDBFileMgr.GetPosXrayDBMgr(); CElementChemistryDB xraydb = pXrayDBMgr.GetElementChemistryDB(); List ches = new List(); foreach (COTSParticleClr part in mergedParts) { ches.Add(part.GetXray()); } xraydb.SaveElementChemistriesList(ches); return true; } public bool SaveFieldData(COTSFieldData fldData, string filedFileFoler) { string strFieldFileFolder = filedFileFoler; CBSEImageFileMgr pBSEImgFileMgr = new CBSEImageFileMgr(); pBSEImgFileMgr.SetBSEImg(fldData.GetBSEImage()); int nId = fldData.GetId(); string sFieldId; sFieldId = nId.ToString(); string strBSEFilePathname = strFieldFileFolder + "\\" + m_pSampleRstFile.SMPL_MSR_RESULT_FIELDS_BSE + sFieldId + pBSEImgFileMgr.BMP_IMG_FILE_EXT; if (!pBSEImgFileMgr.SaveIntoBitmap(strBSEFilePathname)) { log.Error("SaveFieldFiles: save BSE file failed."); return false; } // IncA Data list CIncAFileMgr pDBFileMgr = m_pSampleRstFile.DBFileMgr; pDBFileMgr.SaveStatusDataToDB(); var fldDB = pDBFileMgr.GetFieldDB(); log.Warn("Start saving particle data."); var fldcmd = fldDB.GetSavingAFieldcmdObj(fldData.GetId(), fldData.GetOTSPosition(), fldData.GetSemPos()); List> fldcmds = new List>(); fldcmds.Add(fldcmd); pDBFileMgr.ExecuteNonQueryBatch(ref fldcmds); //remomove the invalid particles var cmds = pDBFileMgr.GetSavingParticleDataToDBCmds(fldData.GetListAnalysisParticles(), fldData.GetOTSPosition()); pDBFileMgr.ExecuteNonQueryBatch(ref cmds); CPosXrayDBMgr PosXrayDBMgr = pDBFileMgr.GetPosXrayDBMgr(); var listAnalysisPosXray = new List(); foreach (var p in fldData.GetListXrayParticles()) { listAnalysisPosXray.Add(p.GetXray()); } var cmds1 = PosXrayDBMgr.GetSavingXrayCmds(listAnalysisPosXray, true); pDBFileMgr.ExecuteNonQueryBatch(ref cmds1); return true; } protected void SaveFieldMgrData() { while (bSaveThreadWorking) { while (fieldQueue.Count() > 0) { COTSFieldData f = fieldQueue.Dequeue(); //save to disk first ,then pop . if the size is 0,then we know all the saving work is done. SaveFieldData(f, m_pSampleRstFile.GetFieldFileSubFolderStr()); } if (fieldQueue.Count() == 0) { bSaveThreadWorking = false; //must set this flag,so the main thread can know this thread has exited. log.Warn("finished batch saving"); return; } } return; } protected void StartSaveFileThread(ref COTSFieldData a_pFieldMgr) { fieldQueue.Enqueue(a_pFieldMgr); if (fieldQueue.Count() > 0) //if there's data in the queue and the previous thread has finished then start a new thread. { if (bSaveThreadWorking == false) { bSaveThreadWorking = true; m_thread_ptr = new System.Threading.Thread(this.SaveFieldMgrData);//m_thread_ptr = shared_ptr(new thread(&CSmplMeasureInc::SaveFieldMgrData, this)); m_thread_ptr.IsBackground = true; m_thread_ptr.Start(); } } } public void ParticleSpecialTreatment(ref COTSFieldData fld) { //we adopt such a strategy here:if some particles satisfy the predefined condition then we go through the second collecting with max EDS time,so that we got a more acurate result. Dictionary mapPartXray = new Dictionary(); double edsTime = 0; //to store the EDSTime returned from the engine. var bigparts = fld.GetListXrayParticles(); var m_ClassifyEngine = new CClassifyEngine(); for (int i = 0; i < bigparts.Count(); i++) { var engine = m_ClassifyEngine.GetParticleEngine(m_Sample.GetMsrParams().GetSTDName()); var p = bigparts[i]; // there will be very less particle satisfied the condition ,so we use only one MaxEDS time,though we set MaxEDSTime for every rule separately .Here we store the last one. //if the particle satisfied the MaxEDS condition then we go through the second colleting.Here we record the particle and the EDSTime and the corresponding xray position. edsTime = engine.IfNeedMaxEDS(p); if (edsTime > 0) { mapPartXray[p] = i; } } List partsMax = new List(); if (mapPartXray.Count() > 0) { foreach (var p in mapPartXray) { partsMax.Add(p.Key); } List maxEDSXrays = new List(); m_EDSHardwareMgr.GetXRayByFeatures(partsMax, edsTime, true); } } public void CalculateParticleAbsolutPos(ref COTSFieldData curFldData) { double dPixelSize = m_Sample.CalculatePixelSize(); CSEMStageData pCSEMStageData = m_pMsrThread.GetProjResultData().GetSEMStageData(); foreach (var p in curFldData.GetListAnalysisParticles()) { //Point fldOtsPos = new Point((curFldData.OTSPos.X, curFldData.OTSPos.Y); PointF semP = new PointF(); ; Point semPos = new Point(); pCSEMStageData.ConvertOTSToSEMCoord(curFldData.OTSPos, ref semP); semPos.X = (int)semP.X; semPos.Y = (int)semP.Y; p.SetAbsolutPos(semPos); } } } }