using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using OTSModelSharp.ServiceInterface; using static OTSDataType.otsdataconst; using OTSDataType; using System.Diagnostics; using System.Drawing; using System.Threading; using OTSModelSharp.DTLBase; using OTSCLRINTERFACE; using OTSModelSharp.ServiceCenter; using OTSMeasureApp._0_OTSModel.Measure.ParamData; namespace OTSModelSharp { using CHoleBSEImgsList = List; class CSmplMeasure { protected static NLog.Logger log ; protected bool bSaveThreadWorking; protected System.Threading.Thread m_thread_ptr; protected COTSSample m_Sample; protected CMeasure m_pMsrThread; string m_strWorkingFolder; protected CSmplMsrResult m_pSampleRstFile; CHoleBSEImgsList m_listHoleBSEImg; //CFunExportClass loger; protected SemController m_SemHardwareMgr; protected ScanController m_ScanHardwareMgr; protected EDSController m_EDSHardwareMgr; protected Queue fieldQueue=new Queue(); protected COTSFieldData curFldData; protected IClassifyEngine m_classifyEngine; public CSmplMeasure() { log = NLog.LogManager.GetCurrentClassLogger(); m_pSampleRstFile = new CSmplMsrResult(); m_SemHardwareMgr = SemController.GetSEMController(); m_ScanHardwareMgr = ScanController.GetScanController(); m_EDSHardwareMgr = EDSController.GetEDSController(); m_listHoleBSEImg = new CHoleBSEImgsList(); } public CSmplMeasure( string a_strWorkingFolder, COTSSample a_pSample) { log = NLog.LogManager.GetCurrentClassLogger(); m_strWorkingFolder = a_strWorkingFolder; m_pSampleRstFile = new CSmplMsrResult( a_strWorkingFolder, a_pSample);// new CSmplMsrResultFile(m_strWorkingFolder,a_pSample); m_SemHardwareMgr = SemController.GetSEMController(); m_ScanHardwareMgr = ScanController.GetScanController(); m_EDSHardwareMgr = EDSController.GetEDSController(); m_listHoleBSEImg = new CHoleBSEImgsList(); m_Sample = a_pSample; } public void SetSample(COTSSample a_pSample) { m_Sample = a_pSample; m_pSampleRstFile.SetSample(a_pSample); } public void SetMsrThread(CMeasure mt) { m_pMsrThread = mt; } bool SetSEMDataMrs() { var pSEMDataMsr = m_Sample.GetSEMDataMsr(); //ASSERT(pSEMDataMsr); double dMag = pSEMDataMsr.GetMagnification(); double dWorkDis = pSEMDataMsr.GetWorkingDistance(); //CSemBasePtr pSEMCtrlPtr = GetSEMControl(); var pSEMCtrl = m_pMsrThread.GetSEMController(); // get SEM controller if (!pSEMCtrl.IsConnected()) { if (!pSEMCtrl.Connect()) { log.Error("SetSEMDataMrs: can't connect SEM."); return false; } } log.Info("set magnification:" + dMag.ToString()); log.Info("set Working Distance:" + dWorkDis.ToString()); pSEMCtrl.SetMagnification(dMag); pSEMCtrl.SetWorkingDistance(dWorkDis); return true; } bool SetSEMExteralOn() { var pSEMCtrl = m_SemHardwareMgr; // get SEM controller if (!pSEMCtrl.IsConnected()) { if (!pSEMCtrl.Connect()) { log.Error("SetSEMExteralOn: can't connect SEM."); return false; } } log.Warn("Set Scan Exteral on!"); pSEMCtrl.SetScanExternal(true); return true; } // set SEM external off bool SetSEMExteralOff() { var pSEMCtrlPtr = m_SemHardwareMgr; // get SEM controller if (!pSEMCtrlPtr.IsConnected()) { if (!pSEMCtrlPtr.Connect()) { log.Error("SetSEMExteralOff: can't connect SEM."); return false; } } log.Warn("Set SEM Exteral Off!"); pSEMCtrlPtr.SetScanExternal(false); return true; } bool SetBSEParam() { // get SEM controller var pSEMController = m_SemHardwareMgr; // 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 SEM controller if (!pSEMController.IsConnected()) { if (!pSEMController.Connect()) { log.Error("SetBSEParam: can't connect SEM."); return false; } } // get dwell time OTS_IMAGE_SCANSPEED_OPTIONS nDwellTime = pImgScanParam.GetScanImageSpeed(); // convert dwell time to bruker dwell time (8, 16, 32) int nBrukerDwellTimeId=3; switch (nDwellTime) { case OTS_IMAGE_SCANSPEED_OPTIONS.low: nBrukerDwellTimeId = 3; break; case OTS_IMAGE_SCANSPEED_OPTIONS.meddium: nBrukerDwellTimeId = 4; break; case OTS_IMAGE_SCANSPEED_OPTIONS.high: nBrukerDwellTimeId = 5; break; default: nBrukerDwellTimeId = 3; 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() { // get SEM controller var pSEMController = m_SemHardwareMgr; // 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 SEM controller if (!pSEMController.IsConnected()) { if (!pSEMController.Connect()) { log.Error("SetBSEParam: can't connect SEM."); return false; } } // 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 dwell time (%d).", sizePixelImage.Height); 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(out List a_allpieldcenter,out List a_listFieldCenter) { // sample measure parameters CSampleParam pMsrParam = m_Sample.GetMsrParams(); COTSImgScanPrm poImageScanParam = pMsrParam.GetImageScanParam(); CSEMDataMsr poSEMDataMsr = m_Sample.GetSEMDataMsr(); CMsrSampleStatus pStatus = m_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(m_Sample.GetMsrArea(), poImageScanParam, poSEMDataMsr, listCompletedCenter)) { log.Error("CalculateFieldsCenters: failed to init field centres list manager."); a_listFieldCenter = new List(); a_allpieldcenter = new List(); return false; } // get field centers list a_listFieldCenter = pFieldMgr.GetUnmeasuredFieldCentrePoints();// GetFieldCentrePoints(); a_allpieldcenter = pFieldMgr.GetFieldCentrePoints(); // ok, return TRUE return true; } protected bool IsAborted() { //Debug.Assert(m_pMsrThread == null); return m_pMsrThread.IsMeasureStopped(); } bool IsSampleOver(COTSImgScanPrm a_pScanParam, int a_nTotalFields) { int nStopMode = (int)a_pScanParam.GetStopMode(); int nStopField = a_pScanParam.GetStopParamFields(); // completed fields number CMsrSampleStatus pMsrSampleStatus = m_Sample.GetMsrStatus(); int nCompeltedField = pMsrSampleStatus.GetCompletedFields(); CMsrDisplayResults 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 nParticlAim = a_pScanParam.GetStopParamParticles(); int nMeasTimeAim = a_pScanParam.GetStopParamMeasTime(); bool bRet = true; switch (nStopMode) { case (int)OTS_MEASURE_STOP_MODE.CoverMode: // completed fields number if (nCompeltedField < a_nTotalFields) { bRet = false; } break; case (int)OTS_MEASURE_STOP_MODE.FieldMode: if (nCompeltedField < nStopField) { bRet = false; } break; case (int)OTS_MEASURE_STOP_MODE.ParticleMode: if (nNumParticle < nParticlAim) { bRet = false; } break; case (int)OTS_MEASURE_STOP_MODE.TimeMode: if (nUsedTime < nMeasTimeAim) { bRet = false; } break; default: break; } return bRet; } // move SEM to the point bool MoveSEMToPoint(System.Drawing.Point a_poi) { // get SEM controller var pSEMController = m_SemHardwareMgr; Point a_SEMpt = new Point(); CSEMStageData a_pCSEMStageData = m_pMsrThread.GetProjResultData().GetSEMStageData(); int hardWareDelay = a_pCSEMStageData.GetHardWareDelay(); if (!a_pCSEMStageData.ConverOTSToSEMPoint(a_poi, ref a_SEMpt)) { return false; } if (!pSEMController.IsConnected()) { if (!pSEMController.Connect()) { log.Error("MoveSEMToPoint: can't connect SEM."); return false; } } 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)) { log.Error("MoveSEMToPoint: failed to call MoveSEMToPoint method."); return false; } 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(0, 0, 2); return pBSEImage; } //public virtual bool FieldImageProcess(Point fldCenter, CBSEImgClr imageData) //{ // return true; //} public virtual void ClassifyFieldParticles() { return; } public virtual void ClassifyMergedParticles(List parts) { return; } private class AutoResetSEMControl:IDisposable { CSmplMeasure sm; public AutoResetSEMControl(CSmplMeasure s) { sm = s; } public void Dispose() { sm.SetSEMExteralOff(); } } 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()) { 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!"); m_SemHardwareMgr.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); // calculate field centers List umMeasuredlistFieldCenter; List alllistFieldCenter; if (!CalculateUnMeasuredFieldsCenters(out alllistFieldCenter,out umMeasuredlistFieldCenter)) {// failed to calculate field centers log.Error("DoMeasure: failed to calculate field centers."); pStatus.SetStatus(OTS_MSR_SAMPLE_STATUS.FAILED); // record end time pStatus.ComputeTime(OTS_MSR_TIME_TYPE.STOPPED); return; } //-----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; } //------ int nNewFieldId = 0; int numOfAllFields = pStatus.GetCompletedFields() + umMeasuredlistFieldCenter.Count;// int completedFields = pStatus.GetCompletedFields(); log.Info("Unmeasured fields:" + umMeasuredlistFieldCenter.Count); for (int i = 0; i < (int)umMeasuredlistFieldCenter.Count; ++i) {// check and break if stop button is clicked 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); } return; } // check if sample measurement completes COTSImgScanPrm pScanParam = m_Sample.GetMsrParams().GetImageScanParam(); int nTotalFieldSize = (int)umMeasuredlistFieldCenter.Count; if (IsSampleOver(pScanParam, numOfAllFields)) { pStatus.ComputeTime(OTS_MSR_TIME_TYPE.STOPPED); break; } // get a field center System.Drawing.Point poiFieldCentre = umMeasuredlistFieldCenter[i]; // 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 = poiFieldCentre; m_pMsrThread.SendMessageToMeasureApp(MsgFieldStart); int fldNo = completedFields + i + 1; 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 = poiFieldCentre.X; MsgFieldBSE.STMSampleRetData.BSEData.pos.Y = 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); // get a new field id log.Info("Acquire BSE image success! Processing image..."); // image process var rst = FieldImageProcess(poiFieldCentre, pBSEImg); if (rst == true) { // add the field into the field m_pSampleRstFile.AddAField(curFldData); } ++nNewFieldId; double measuredArea = 0; // this area should be the field area var a_pBSEImg = curFldData.GetBSEImage(); double dPixelSize = m_Sample.CalculatePixelSize(); measuredArea = a_pBSEImg.GetHeight() * a_pBSEImg.GetWidth()* dPixelSize * dPixelSize + 0.5; //Get measured area if (!CumulateFieldData(curFldData.GetListAnalysisParticles(), measuredArea)) { // failed to call SaveFieldFile method log.Error("ImageProcess: call CumulateFieldData method."); pStatus.SetStatus(OTS_MSR_SAMPLE_STATUS.FAILED); return; } log.Info("Send field data to screen!"); // completed fields pStatus.SetCompletedFields(pStatus.GetCompletedFields() + 1); // completed fieldCenter List listCpltedCenter = pStatus.GetCompletedFieldsCenter(); listCpltedCenter.Add(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 = numOfAllFields; MsgFieldEnd.STMSampleRetData.SFieldData.iSParticleCount = (int)curFldData.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!"); } //merging particles log.Info("Merging big particles which are crossing the field edge!"); CImageHandler imgpro = new CImageHandler(); int scanfldsize = m_Sample.GetSEMDataMsr().GetScanFieldSize(); List mergedParticles = new List(); double pixelSize = m_Sample.CalculatePixelSize(); imgpro.MergeBigBoundaryParticles(m_pSampleRstFile.GetFieldData(), pixelSize, scanfldsize, m_Sample.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 = m_Sample.GetName(); m_pMsrThread.SendMessageToMeasureApp(MsgSmplEnd); } } private void CalculateMergedPartProperty(List mergedParticles,double pixelSize) { var m_ImagePro = new CImageHandler(); foreach (COTSParticleClr part in mergedParticles) { m_ImagePro.CalParticleImageProp(part, pixelSize); } } public bool FieldImageProcess(Point fldCenter, CBSEImgClr a_pBSEImg) { int nNewFieldId; nNewFieldId = m_pSampleRstFile.GetIdForANewField(); // create a field curFldData = new COTSFieldData(a_pBSEImg, m_Sample.CalculatePixelSize()); curFldData.SetId(nNewFieldId); curFldData.SetOTSPosition(fldCenter); CSEMStageData a_pCSEMStageData = m_pMsrThread.GetProjResultData().GetSEMStageData(); Point semPos = new Point(); a_pCSEMStageData.ConverOTSToSEMPoint(fldCenter, ref semPos); curFldData.SemPos = 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(); // second step :filter the finded particles. log.Info("Begin to filter particles!"); FilterParticles(curFldData); CalculateParticleAbsolutPos(); 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(); // save field files m_Sample.GetMsrStatus().SetStatus(OTS_MSR_SAMPLE_STATUS.SUCCESSED); StartSaveFileThread(curFldData); return true; } public void GetOriginalParticles() { // measure status CMsrSampleStatus pStatus = m_Sample.GetMsrStatus(); // get image process parameter CSampleParam pMsrParam = m_Sample.GetMsrParams(); COTSImageProcParam pImgProcessParam = pMsrParam.GetImageProcessParam(); var specialPartsparam = pMsrParam.GetSpecialGrayRangeParam(); var pixelsize = m_Sample.CalculatePixelSize(); if (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(COTSFieldData fld) { if (fld.NoAnalysisParticle()) { log.Warn("There's no analysis particles!"); return; } CSampleParam 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 saperate the analysis particles into two group :the bigparticles and the smallparticles. double quantifyThreshold = m_Sample.GetMsrParams().GetXRayParam().GetFeatureModeMinSize(); var smallparts = fld.ListSmallParticles; var bigparts = fld.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); } } fld.ListSmallParticles = smallparts; fld.ListBigParticles = bigparts; //fld.SmallParticlePercentage=percentage; log.Info("SmallQuantifyParts (<" + quantifyThreshold.ToString("f2") + "): " + smallparts.Count); log.Info("BigQuantifyParts (>=" + quantifyThreshold.ToString("f2") + "): " + bigparts.Count); return; } public void CollectParticlesXrayData(COTSFieldData fld) { // 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 fld.ListSmallParticles) { if (p.IsXrayParticle()) { smallparts.Add(p); } } foreach (var p in fld.ListBigParticles) { if (p.IsXrayParticle()) { bigparts.Add(p); } } var pStatus = m_Sample.GetMsrStatus(); 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 { nXRayAQTime = (uint)pXRayParam.GetMidAnalyAQTime(); m_EDSHardwareMgr.GetXRayByPoints(bigparts, nXRayAQTime, true); } } if (smallparts.Count > 0) { nXRayAQTime = (uint)pXRayParam.GetFastXrayTime(); // get x-ray list (analysis) by points m_EDSHardwareMgr.GetXRayByPoints(smallparts, nXRayAQTime, true); } return; } public void DoHolePreview(int a_nHoleID) { using (AutoResetSEMControl autoReset = new AutoResetSEMControl(this)) { // let the main thread to know that this sample measurement starts CMsrSampleStatus 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(); // get SEM controller to set magnification and working distance if (!SetSEMDataMrs()) { 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()) { log.Error("DoMeasure: fail to set BSE param."); pStatus.SetStatus(OTS_MSR_SAMPLE_STATUS.FAILED); // record end time pStatus.ComputeTime(OTS_MSR_TIME_TYPE.STOPPED); return; } // check if measurement is aborted if (IsAborted()) {// measurement aborted log.Trace("DoHolePreview: measurement aborted before get SEM condition."); pStatus.SetStatus(OTS_MSR_SAMPLE_STATUS.STOPPED); // record end time pStatus.ComputeTime(OTS_MSR_TIME_TYPE.STOPPED); return; } // calculate field centers List listFieldCenter=new List(); List alllistFieldCenter = new List(); // listFieldCenter.clear(); if (!CalculateUnMeasuredFieldsCenters(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; if (IsSampleOver(pScanParam, nTotalFieldSize)) { pStatus.ComputeTime(OTS_MSR_TIME_TYPE.STOPPED); break; } // 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(); // memset(&MsgFieldBSE, 0, sizeof(ST_MSTMsg)); MsgFieldBSE.iMsgType = ENUM_MSG_TYPE.MSAMPLERESULT; MsgFieldBSE.STMSampleRetData.iRetDataType = MSAMPLE_RET.BSE_DATA; MsgFieldBSE.STMSampleRetData.BSEData.pos = poiFieldCentre; //MsgFieldBSE.STMSampleRetData.BSEData.pos.y = poiFieldCentre.y; 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,a_nHoleID, poiFieldCentre); pHoleBSEImg.SetImageData( pBSEIamge.GetImageDataPtr(),oImageRect.Width,oImageRect.Height); m_listHoleBSEImg.Add(pHoleBSEImg); COTSMsrPrjResultData pProjMgrFile = m_pMsrThread.GetProjResultData(); pProjMgrFile.SetHoleBESImgList(m_listHoleBSEImg,true); // 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); //break; } 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 CMsrDisplayResults 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; } // hole BSE images list void SetHoleBESImgList(CHoleBSEImgsList a_listHoleBSEImg, bool a_bClear/* = TRUE*/) {// clear the hole BSE image list if necessary if (a_bClear) { m_listHoleBSEImg.Clear(); } // go through the input list foreach (var pHoleBSEImg in a_listHoleBSEImg) {// add the new hole BSE image into HoleBSEImage list m_listHoleBSEImg.Add(pHoleBSEImg); } } 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) { //loger.Warn("begin bitmap saving..."); 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.SemPos); List> fldcmds = new List>(); fldcmds.Add(fldcmd); pDBFileMgr.ExecuteNonQueryBatch(ref fldcmds); //remomove the invalid particles var cmds = pDBFileMgr.GetSavingIncADataToDBCmds(curFldData.GetListAnalysisParticles(), fldData.GetOTSPosition()); pDBFileMgr.ExecuteNonQueryBatch(ref cmds); CPosXrayDBMgr PosXrayDBMgr = pDBFileMgr.GetPosXrayDBMgr(); var listAnalysisPosXray = new List(); foreach (var p in curFldData.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(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(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(); //std.map mapPartXray = new std.map(); 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() { 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); Point semPos = new Point(); pCSEMStageData.ConverOTSToSEMPoint(fldOtsPos, ref semPos); p.SetAbsolutPos(semPos); } } } }