Bladeren bron

develop the algorithm that can identify the string like particles when do measurement.

gsp 2 maanden geleden
bovenliggende
commit
4f457acb8f

+ 4 - 4
Bin/x64/Debug/Config/SysData/OTSProgMgrParam.pmf

@@ -1,12 +1,12 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<XMLData RunMode="ProfessionalMode" SysType="BatteryCleannessA">
-  <Member RegName="GenParam" DefaultArea="1400" DefaultSampleName="Sample" DefaultShape="0" EngineType="2:InclutionPlusExpressionParse" MeasParamFileFolderName=".\Config\ProData\" MeasSwitch="true" PartSTDLibFolderName=".\Config\SysData\" PropertyDisplayMode="0" StdLibFileName="Cleanness_ND - 副本" SteelTechnology="0" />
+<XMLData RunMode="ProfessionalMode" SysType="IncA">
+  <Member RegName="GenParam" DefaultArea="1400" DefaultSampleName="Sample" DefaultShape="0" EngineType="0:InclustionEngine" MeasParamFileFolderName=".\Config\ProData\" MeasSwitch="true" PartSTDLibFolderName=".\Config\SysData\" PropertyDisplayMode="0" StdLibFileName="NoSTDDB" SteelTechnology="0" />
   <Member RegName="ImageProcParam" AutoBGRemoveType="0:MIDDLE" BGRemoveType="1:MANUAL" MatrixStep="0" OverlapParam="0" ParticleSelectionCondition="">
-    <Member RegName="BGGray" end="40" start="0" />
+    <Member RegName="BGGray" end="255" start="175" />
     <Member RegName="IncArea" end="10000" start="5" />
     <Member RegName="ParticleGray" end="255" start="0" />
   </Member>
-  <Member RegName="ImageScanParam" ImageResolution="4:_1536_1024" SatrtImageMode="0:Spiral" ScanImageSpeed="0:low" StopMode="0:CoverMode" StopParamArea="10" StopParamFields="100" StopParamMeasTime="360" StopParamParticles="5000" />
+  <Member RegName="ImageScanParam" ImageResolution="3:_1024_768" SatrtImageMode="0:Spiral" ScanImageSpeed="0:low" StopMode="0:CoverMode,2:FieldMode" StopParamArea="10" StopParamFields="2" StopParamMeasTime="360" StopParamParticles="5000" />
   <Member RegName="SpecialGrayParam" ToRun="false">
     <Collection RegName="GrayRangeList" />
   </Member>

+ 1 - 1
Bin/x64/Debug/Config/SysData/OTSReportMgrParam.rpf

@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<XMLData systype="BatteryCleannessA">
+<XMLData systype="IncA">
   <Member RegName="Scale" strValue="1000" />
   <Member RegName="DefaultComputedColName" strValue="ParticleCoordinate,Area,EquivalentCircleDiameter,MaxDiameter,MinDiameter,DiameterRatio,FerretDiameter,PERP,PERI,INSCR,MEAN,ELONG,ASPECT_ELONG,Orientation,XRayDataCount" />
   <Member RegName="ElementsColName" strValue="C,O,Al,Fe,F,Ti,Na,Mn,Mg" />

+ 4 - 1
OTSCPP/OTSClrInterface/CommonClr/OTSParticleClr.h

@@ -267,7 +267,10 @@ namespace OTSCLRINTERFACE {
 		}
 		void ClearSubParticles() { m_Particle->get()->ClearSubParticles(); }
 		void AddSubParticle(COTSParticleClr^ particle) { m_Particle->get()->AddSubParticle(particle->GetOTSParticlePtr()); }
-		
+		bool IsConnected(COTSParticleClr^ a_p, int fldwidth, int fldheight, int direction)
+		{
+			return m_Particle->get()->IsConnected(a_p->GetOTSParticlePtr().get(), fldwidth, fldheight, direction);
+		}
 
 	protected:		
 		COTSParticlePtr* m_Particle;

+ 1 - 1
OTSCPP/OTSImagePro/OTSImageProcess.cpp

@@ -1676,7 +1676,7 @@ namespace OTSIMGPROC
 		const int nLineType = 8;
 		// get rectangle of the particle
 		CRect rect = a_pOTSPart->GetParticleRect();
-		if (a_pOTSPart->GetActualArea() < 30 * a_PixelSize)// the particle is too small that openCV can't calculate a width value of it. Then we take the upright rect of the particle as it's minArea rect.
+		if (a_pOTSPart->GetActualArea() < 20 * a_PixelSize)// the particle is too small that openCV can't calculate a width value of it. Then we take the upright rect of the particle as it's minArea rect.
 		{
 			double w = 0, h = 0;
 			w = (double)rect.Width()*a_PixelSize;

+ 28 - 28
OTSCPP/OTSRptCalculate/GBCal/GBFieldData.cpp

@@ -330,7 +330,7 @@ namespace OTSGBCalculate
 				dLengthWidthRatio = 1 / dLengthWidthRatio;
 			}
 			GB_CHEMICAL_TYPE nChemicalType = GBParticle::IdentifyPartChemicalType(pParticle);
-			if (dLengthWidthRatio >= 3)//长宽比大于3的颗粒,根据化学元素不同,分为A类和C类
+			if (dLengthWidthRatio >= 3)
 			{
 				//A or C class
 				
@@ -351,7 +351,7 @@ namespace OTSGBCalculate
 				}
 
 			}
-			else//长宽比小于3的颗粒,有3种情况,一种是串条状的B类颗粒,一种是单独的D类颗粒,如果费雷特直径大于13则为DS类颗粒
+			else
 			{
 				
 				// B, or D or DS				
@@ -384,7 +384,7 @@ namespace OTSGBCalculate
 		for (auto gbp : listAGBparts)
 		{
 			gbp->myType = GB_CLASSIFY_TYPE::A_TYPE;
-			//计算颗粒宽度是属于细系粗系还是超尺寸
+			
 			GB_WIDTH_TYPE wt = gbp->CaculateLevelWidth(GB_CLASSIFY_TYPE::A_TYPE);
 			gbp->myWidth = wt;
 			switch (wt)
@@ -403,7 +403,7 @@ namespace OTSGBCalculate
 		//process C class
 		CGBParticleList listCGBparts;
 		ConnectStringParts(listCparts, listCGBparts);
-		//计算颗粒宽度是属于细系粗系还是超尺寸
+	
 		for (auto gbp : listCGBparts)
 		{
 			gbp->myType = GB_CLASSIFY_TYPE::C_TYPE;
@@ -437,7 +437,7 @@ namespace OTSGBCalculate
 					{*/
 						pGBParticle->myType = GB_CLASSIFY_TYPE::D_TYPE;//no matter what chemical it contains,as long as the aspect ratio is less than 3,then it's a D type.
 
-						//计算颗粒宽度是属于细系粗系还是超尺寸
+						
 						GB_WIDTH_TYPE wt = pGBParticle->CaculateLevelWidth( GB_CLASSIFY_TYPE::D_TYPE);
 						pGBParticle->myWidth = wt;
 						switch (wt)
@@ -504,7 +504,7 @@ namespace OTSGBCalculate
 						pGBParticle->myType = GB_CLASSIFY_TYPE::B_TYPE;
 						
 
-						//计算颗粒宽度是属于细系粗系还是超尺寸
+						
 						GB_WIDTH_TYPE wt = pGBParticle->CaculateLevelWidth( GB_CLASSIFY_TYPE::B_TYPE);
 						pGBParticle->myWidth = wt;
 						switch (wt)
@@ -602,7 +602,7 @@ namespace OTSGBCalculate
 		{
 			if (p->myOTSParts.size() == 1)//it's a isolated part
 			{
-				//获取最小外接矩形的宽和高
+				
 				auto p1 = p->myOTSParts[0];
 				double h = p1->GetDMax();
 				double w = p1->GetDMin();
@@ -613,7 +613,7 @@ namespace OTSGBCalculate
 					dLengthWidthRatio = 1 / dLengthWidthRatio;
 				}
 
-				if (dLengthWidthRatio < 3)//长宽比小于3的颗粒,且为孤立的颗粒,根据是否含硫化物,分为D类和DSulfide类,如果费雷特直径大于13 归为DS类
+				if (dLengthWidthRatio < 3)//when aspect<3,is isolate,if contain S then it's DSulfide,else it's D,if the feret>13,then it's DS.
 				{
 					double dFeretDiameter = p1->GetFeretDiameter();
 					if (dFeretDiameter >= 13)
@@ -668,7 +668,7 @@ namespace OTSGBCalculate
 		{
 			if (p->myOTSParts.size() == 1)//it's a isolated part
 			{
-				//获取最小外接矩形的宽和高
+				
 				auto p1 = p->myOTSParts[0];
 				double h = p1->GetDMax();
 				double w = p1->GetDMin();
@@ -679,7 +679,7 @@ namespace OTSGBCalculate
 					dLengthWidthRatio = 1 / dLengthWidthRatio;
 				}
 
-				if (dLengthWidthRatio < 3)//长宽比小于3的颗粒,且为孤立的颗粒,根据是否含硫化物,分为D类和DSulfide类,如果费雷特直径大于13 归为DS类
+				if (dLengthWidthRatio < 3)
 				{
 					double dFeretDiameter = p1->GetFeretDiameter();
 					if (dFeretDiameter >= 13)
@@ -733,7 +733,7 @@ namespace OTSGBCalculate
 		{
 			if (p->myOTSParts.size() == 1)//it's a isolated part
 			{
-				//获取最小外接矩形的宽和高
+				
 				auto p1 = p->myOTSParts[0];
 				double h = p1->GetDMax();
 				double w = p1->GetDMin();
@@ -744,7 +744,7 @@ namespace OTSGBCalculate
 					dLengthWidthRatio = 1 / dLengthWidthRatio;
 				}
 
-				if (dLengthWidthRatio < 3)//长宽比小于3的颗粒,且为孤立的颗粒,根据是否含硫化物,分为D类和DSulfide类,如果费雷特直径大于13 归为DS类
+				if (dLengthWidthRatio < 3)
 				{
 					double dFeretDiameter = p1->GetFeretDiameter();
 					if (dFeretDiameter >= 13)
@@ -836,7 +836,7 @@ namespace OTSGBCalculate
 			{
 				continue;
 			}
-			//获取最大长度和最小宽度
+			
 			double h = pParticle->GetDMax();
 			double w = pParticle->GetDMin();
 			double dLengthWidthRatio = h / w;
@@ -847,7 +847,7 @@ namespace OTSGBCalculate
 			GB_CHEMICAL_TYPE nChemicalType = GBParticle::IdentifyPartChemicalType(pParticle);
 			CGBParticlePtr gbp = CGBParticlePtr(new GBParticle());
 			gbp->myOTSParts.push_back(pParticle);
-			if (dLengthWidthRatio >= 3)//长宽比大于3的颗粒,根据化学元素不同,分为A类和C类
+			if (dLengthWidthRatio >= 3)
 			{
 				//A or C class
 				
@@ -855,7 +855,7 @@ namespace OTSGBCalculate
 				if (nChemicalType == GB_CHEMICAL_TYPE::CHE_S)
 				{
 					// A					
-					//计算颗粒宽度是属于细系粗系还是超尺寸
+					
 					GB_WIDTH_TYPE wt = gbp->CaculateLevelWidth(GB_CLASSIFY_TYPE::A_TYPE);
 					if (wt == GB_WIDTH_TYPE::THIN || wt == GB_WIDTH_TYPE::WIDE || wt == GB_WIDTH_TYPE::SUPER)
 					{
@@ -867,7 +867,7 @@ namespace OTSGBCalculate
 				else if (nChemicalType == GB_CHEMICAL_TYPE::CHE_O)
 				{
 					// C				
-					//计算颗粒宽度是属于细系粗系还是超尺寸
+					
 					GB_WIDTH_TYPE wt = gbp->CaculateLevelWidth( GB_CLASSIFY_TYPE::C_TYPE);
 					if (wt == GB_WIDTH_TYPE::THIN || wt == GB_WIDTH_TYPE::WIDE || wt == GB_WIDTH_TYPE::SUPER)
 					{
@@ -876,7 +876,7 @@ namespace OTSGBCalculate
 					
 				}
 			}
-			else//长宽比小于3的颗粒,有3种情况,一种是串条状的B类颗粒,一种是单独的D类颗粒,如果费雷特直径大于13则为DS类颗粒
+			else//when aspect<3,three cases,one is string B type,one is the single D type part,if the feret diameter >13 then is DS type.
 			{
 				// B, or D or DS
 				
@@ -907,7 +907,7 @@ namespace OTSGBCalculate
 				{
 					pGBParticle->myType = GB_CLASSIFY_TYPE::D_TYPE;
 
-					//计算颗粒宽度是属于细系粗系还是超尺寸
+					//calculate the GB_WIDTH_TYPE
 					GB_WIDTH_TYPE wt = pGBParticle->CaculateLevelWidth( GB_CLASSIFY_TYPE::D_TYPE);
 
 
@@ -917,12 +917,12 @@ namespace OTSGBCalculate
 					}
 					
 				}
-				else//找到了相邻接的颗粒,不是孤立的则为B类
+				else//find adjacent part ,then it is B type.
 				{
-					pGBParticle->myType = GB_CLASSIFY_TYPE::B_TYPE;//把类型设为有效类型
+					pGBParticle->myType = GB_CLASSIFY_TYPE::B_TYPE;
 					
 
-					//计算颗粒宽度是属于细系粗系还是超尺寸
+					//calculate the GB_WIDTH_TYPE
 					GB_WIDTH_TYPE wt = pGBParticle->CaculateLevelWidth( GB_CLASSIFY_TYPE::B_TYPE);
 					if (wt == GB_WIDTH_TYPE::THIN || wt == GB_WIDTH_TYPE::WIDE || wt == GB_WIDTH_TYPE::SUPER)
 					{
@@ -969,7 +969,7 @@ namespace OTSGBCalculate
 			{
 				continue;
 			}
-			//获取最大长度和最小宽度
+			
 			double h = pParticle->GetDMax();
 			double dLengthWidthRatio = h / w;
 			if (dLengthWidthRatio < 1)
@@ -977,7 +977,7 @@ namespace OTSGBCalculate
 				dLengthWidthRatio = 1 / dLengthWidthRatio;
 			}
 			GB_CHEMICAL_TYPE nChemicalType = GBParticle::IdentifyPartChemicalType(pParticle);
-			if (dLengthWidthRatio >= 3)//长宽比大于3的颗粒,根据化学元素不同,分为A类和C类
+			if (dLengthWidthRatio >= 3)//when aspect>3 ,according to the chemical ,classify them to A or C.
 			{
 				//A or C class
 				if (nChemicalType == GB_CHEMICAL_TYPE::CHE_S)
@@ -992,7 +992,7 @@ namespace OTSGBCalculate
 				}
 
 			}
-			else//长宽比小于3的颗粒,有3种情况,一种是串条状的B类颗粒,一种是单独的D类颗粒,如果费雷特直径大于13则为DS类颗粒
+			else//when aspect<3,three cases,one is string B type,one is the single D type part,if the feret diameter >13 then is DS type.
 			{
 
 				// B, or D or DS				
@@ -1112,12 +1112,12 @@ namespace OTSGBCalculate
 					}
 					double dd = 0, ds = 0;
 					ds = abs(ptParticleCenter.x - ptBParticleCenter.x);
-					if (ds < 15)//认为两个颗粒在一条竖直线上,但不在一起
+					if (ds < 15)//consider these two parts are on the same vertical line 
 					{
 						if (Bottom >= TopB)//current particle is on the above
 						{
 							dd = Bottom - TopB;
-							if (dd < 40)//认为这两个颗粒在一个串条上
+							if (dd < 40)//consider these two parts are in the same string
 							{
 								return true;
 							}
@@ -1143,11 +1143,11 @@ namespace OTSGBCalculate
 					return false;
 				});
 
-			if (adjacentPart == listStringparts.end())//没找到
+			if (adjacentPart == listStringparts.end())//don't find
 			{
 			
 			}
-			else//找到了相邻接的颗粒,
+			else//find adjacent part
 			{
 				pParticle->connectParticles.push_back( *adjacentPart);
 				adjacentPart->get()->connectParticles .push_back( pParticle);

+ 4 - 1
OTSIncAMeasureApp/0-OTSModel/OTSDataType/COTSField.cs

@@ -132,7 +132,10 @@ namespace OTSDataType
             m_listAnalysisParticles = value;
         }
 
-
+        public void SetListAllParticles(List<COTSParticleClr> value)
+        {
+            m_listAllParticles = value;
+        }
 
         public COTSField(PointF centerPoint, double a_dPixelSize)
         {

+ 275 - 6
OTSIncAMeasureApp/1-OTSMeasure/Measure/1-OTSInclution/SmplMeasureInclution.cs

@@ -1,8 +1,11 @@
 using OTSCLRINTERFACE;
+using OTSCommon.DBOperate.Model;
 using OTSDataType;
+using OTSMeasureApp._0_OTSModel.OTSDataType;
 using OTSModelSharp.ServiceCenter;
 using System;
 using System.Collections.Generic;
+using System.Drawing;
 using System.Linq;
 using static OTSDataType.otsdataconst;
 
@@ -52,14 +55,14 @@ namespace OTSModelSharp
             }
 
         }
-      
+
 
         public bool ClassifyIncAParticle(COTSParticleClr particle, string libname)// classify particles
         {
 
             int steelTech = (int)m_Sample.GetMsrParams().GetSteelTechnology();
             particle.SetType((int)OTS_PARTICLE_TYPE.NOT_IDENTIFIED);
-            if (m_Sample.GetMsrParams().GetEngineType()==OTS_CLASSIFY_ENGINE_TYPE.InclutionPlusExpressionParse)
+            if (m_Sample.GetMsrParams().GetEngineType() == OTS_CLASSIFY_ENGINE_TYPE.InclutionPlusExpressionParse)
             {
 
                 if (libname != "NoSTDDB")
@@ -78,7 +81,7 @@ namespace OTSModelSharp
                 }
 
             }
-            else if(m_Sample.GetMsrParams().GetEngineType() == OTS_CLASSIFY_ENGINE_TYPE.ExpressionParse)
+            else if (m_Sample.GetMsrParams().GetEngineType() == OTS_CLASSIFY_ENGINE_TYPE.ExpressionParse)
             {
                 if (libname != "NoSTDDB")
                 {
@@ -88,7 +91,7 @@ namespace OTSModelSharp
 
                 }
             }
-            else if(m_Sample.GetMsrParams().GetEngineType() == OTS_CLASSIFY_ENGINE_TYPE.SpectrumMatch)
+            else if (m_Sample.GetMsrParams().GetEngineType() == OTS_CLASSIFY_ENGINE_TYPE.SpectrumMatch)
             {
                 if (libname != "NoSTDDB")
                 {
@@ -97,7 +100,7 @@ namespace OTSModelSharp
                     engine.ClassifyBySpectrum(particle);
                 }
             }
-            else if(m_Sample.GetMsrParams().GetEngineType() == OTS_CLASSIFY_ENGINE_TYPE.InclustionEngine)
+            else if (m_Sample.GetMsrParams().GetEngineType() == OTS_CLASSIFY_ENGINE_TYPE.InclustionEngine)
             {
                 IClassifyEngine engine;
                 engine = m_classifyEngine.GetIncClassifyEngine();
@@ -108,6 +111,9 @@ namespace OTSModelSharp
         }
         public override void CollectParticlesXrayData(COTSField curFldData)
         {
+
+            LinkParticlesByGB30834Standard(curFldData);
+            //collect the particles xray data
             base.CollectParticlesXrayData(curFldData);
             var parts = curFldData.GetListAnalysisParticles();
             string libname = m_Sample.GetMsrParams().GetSTDName();
@@ -135,14 +141,277 @@ namespace OTSModelSharp
                     }
                 }
             }
-            
+
 
         }
+        class COTSLinkedParticle
+        {
+            public COTSLinkedParticle(COTSParticleClr mypart)
+            {
+                _myPart = mypart;
+            }
+
+            private bool _merged=false;
+           
+            private COTSParticleClr _myPart;
+
+
+            private List<COTSLinkedParticle> _linkedParts = new List<COTSLinkedParticle>();
+            public void AddLinkedParticle(COTSLinkedParticle part)
+            {
+                if (!_linkedParts.Contains(part))
+                {
+                    _linkedParts.Add(part);
+                }
+            }
+            public List<COTSLinkedParticle> GetLinkedParticles() { return _linkedParts; }
+            public COTSParticleClr MyPart { get => _myPart; set => _myPart = value; }
+            public bool IsMerged { get => _merged; set => _merged = value; }
+
+            internal void MergeLinkedParticles()
+            {
+                List<COTSSegmentClr > segs= new List<COTSSegmentClr>();
+                int l=0, t=0, r=0, b = 0;
+                foreach (var seg in _myPart.GetFeature().GetSegmentsList())
+                {
+                    segs.Add(seg);
+                }
+                _myPart.GetOTSRect(ref l, ref t, ref r, ref b);
+                Rectangle rec =(Rectangle)_myPart.GetParticleRect();
+                int l1 = 0, t1 = 0, r1 = 0, b1 = 0;
+                COTSParticleClr biggestPart = _myPart;
+                foreach (var p in _linkedParts)
+                {
+                   
+                    p.MyPart.GetOTSRect(ref l1,ref t1, ref r1, ref b1);
+                    if (l1 < l) l = l1;
+                    if(t1 > t) t = t1;
+                    if(r1 > r) r = r1;
+                    if (b1 < b) b = b1;
+                  if(p.MyPart.GetActualArea() > biggestPart.GetActualArea())
+                    {
+                        biggestPart = p.MyPart;
+                    }
+
+
+                    foreach (var seg in p.MyPart.GetFeature().GetSegmentsList())
+                    {
+                        if (!segs.Contains(seg))
+                        {
+                            segs.Add(seg);
+                        }
+                    }
+                }
+                _myPart.SetOTSRect(l, t, r, b);
+             
+                _myPart.GetFeature().SetSegmentsList(segs,true);
+                _myPart.CalCoverRectFromSegment();
+                _myPart.SetXRayPos(biggestPart.GetXRayPos());
+
+            }
+        }
+        private void LinkParticlesByGB30834Standard(COTSField curFldData)
+        {
+            var parts = curFldData.GetAllParticles();
+            
+            if (parts.Count == 0)
+            {
+                return;
+            }
+            List<COTSLinkedParticle> linkedParticles = new List<COTSLinkedParticle>();
+            foreach (var part in parts)
+            {
+                COTSLinkedParticle linkedParticle = new COTSLinkedParticle(part);
+                linkedParticles.Add(linkedParticle);
+            }
+
+            for (int i = 0; i < linkedParticles.Count; i++)
+            {
+                var part = linkedParticles[i];
+                int l = 0, r = 0, t = 0, b = 0;
+                part.MyPart.GetOTSRect(ref l, ref t, ref r, ref b);
+                COTSRect partrect = new COTSRect(l, t, r, b);
+                //PointF centerPoint = partrect.GetCenterPoint();
+
+                Point centerPoint =(Point) part.MyPart.GetXRayPos();
+                for (int j = i + 1; j < linkedParticles.Count; j++)
+                {
+                    var part1 = linkedParticles[j];
+                 
+
+                    part1.MyPart.GetOTSRect(ref l, ref t, ref r, ref b);
+                  COTSRect  partrect1 = new COTSRect(l, t, r, b);
+                    //PointF centerPoint1 = partrect1.GetCenterPoint();
+                    Point centerPoint1 = (Point)part1.MyPart.GetXRayPos();
+                    double d = Math.Sqrt(Math.Pow(centerPoint.X - centerPoint1.X, 2) + Math.Pow(centerPoint.Y - centerPoint1.Y, 2));
+
+                    if (Math.Abs(part.MyPart.GetAveGray() - part1.MyPart.GetAveGray()) > 10 )
+                    {
+                        // If the average gray values are not similar, do not link them
+                        continue;
+                    }
+                    if (d - part.MyPart.GetDMAX() / 2 - part1.MyPart.GetDMAX() / 2 < 40 && d > part.MyPart.GetDMAX() / 2+part1.MyPart.GetDMAX()/2)
+                    {
+                        double aspect1 = part.MyPart.GetDMAX() / part.MyPart.GetDMIN();
+                        double aspect2 = part1.MyPart.GetDMAX() / part.MyPart.GetDMIN();
+                        var angle1 = part.MyPart.GetORIENTATION();
+                        var angle2= part1.MyPart.GetORIENTATION();
+                        if (aspect1 > 2 && aspect2 > 2)
+                        {
+
+                            // If the aspect ratio of both particles is greater than 2 and their orientations are similar, link them
+                            var angle = calculateTwoPointAngle(centerPoint, centerPoint1);
+                            if (Math.Abs(angle - angle1) < 5 && Math.Abs(angle - angle2) < 5)
+                            {
+
+                                part.AddLinkedParticle(part1);
+                                part1.AddLinkedParticle(part);
+                                continue;
+                            }
+                            else
+                            {
+                                continue;
+                            }
+
 
 
 
 
 
+                        }
+                        else if (aspect1 > 2 && aspect2 < 2)
+                        {
+                            var angle = calculateTwoPointAngle(centerPoint, centerPoint1);
+                            if (Math.Abs(angle - angle1) < 5)
+                            {
+
+                                part.AddLinkedParticle(part1);
+                                part1.AddLinkedParticle(part);
+                                continue;
+                            }
+                            else
+                            {
+                                continue;
+                            }
+
+
+                        }
+                        else if (aspect1 < 2 && aspect2 > 2)
+                        {
+                            var angle = calculateTwoPointAngle(centerPoint, centerPoint1);
+                            if (Math.Abs(angle - angle2) < 5)
+                            {
+
+                                part.AddLinkedParticle(part1);
+                                part1.AddLinkedParticle(part);
+                                continue;
+                            }
+                            else
+                            {
+                                continue;
+                            }
 
+                        }
+                        else if (aspect1 <= 2 && aspect2 <=2)
+                        {
+                            if (Math.Abs(part.MyPart.GetActualArea() - part1.MyPart.GetActualArea()) < 10)
+                            {
+
+                                // Link the particles  
+                                part.AddLinkedParticle(part1);
+                                part1.AddLinkedParticle(part);
+                                continue;
+                            }
+                            else
+                            {
+                                // If the areas are not similar, do not link them
+                                continue;   
+                            } 
+                           
+
+                        }
+                           
+                    }
+                }
+
+
+            }
+
+
+
+            //DFS all the linked particles
+            Stack<COTSLinkedParticle> partStack=new Stack<COTSLinkedParticle>();
+           
+            List<COTSParticleClr> mergedParts = new List<COTSParticleClr>();
+            List<COTSParticleClr> finalOTSParts = new List<COTSParticleClr>();
+            foreach (var pParticle in linkedParticles)
+            {
+                if (!pParticle.IsMerged)
+                {
+                    COTSLinkedParticle finalpart = new COTSLinkedParticle(pParticle.MyPart);
+                    foreach (var connP in pParticle.GetLinkedParticles())
+                    {
+                        if (!connP.IsMerged)
+                        {
+                            partStack.Push(connP);
+                        }
+                    }
+                   
+                    while (partStack.Count > 0)
+                    {
+                        COTSLinkedParticle currpart = partStack.Pop();
+                        currpart.IsMerged = true;
+                       finalpart.AddLinkedParticle(currpart);
+                        if (currpart.GetLinkedParticles().Count>0)
+                        {
+                            foreach (var connP in currpart.GetLinkedParticles())
+                            {
+                                if (!connP.IsMerged)
+                                {
+                                    partStack.Push(connP);
+                                }
+                            }
+                           
+                        }
+                       
+                    }
+                    if (finalpart.GetLinkedParticles().Count > 1)
+                    {
+                        //merge the particles
+                        finalpart.MergeLinkedParticles();
+                        mergedParts.Add(finalpart.MyPart);
+                    }
+                    else
+                    {
+                        finalOTSParts.Add(finalpart.MyPart); // If no linked particles, just add the original particle
+                    }
+
+
+                }
+
+            }
+            
+            
+            curFldData.CalParticleImageProp(mergedParts);   
+            finalOTSParts.AddRange(mergedParts);           
+            curFldData.SetListAnalysisParticles(finalOTSParts);
+
+        }
+
+        public  double calculateTwoPointAngle(PointF p1, PointF p2)
+        {
+            if (p1.Y > p2.Y)
+            {
+                PointF temp = p1;
+                p1 = p2;
+                p2 = temp;
+            }
+            double angle = Math.Atan2(p2.Y - p1.Y, p2.X - p1.X) * 180 / Math.PI;
+            if (angle < 0)
+            {
+                angle += 360;
+            }
+            return angle;
+        }
     }
 }

+ 1 - 0
OTSIncAReportApp/1-UI/Control_Graph/Controls/Control_DrawDistrbutionImageAndBSE.cs

@@ -316,6 +316,7 @@ namespace OTSIncAReportGraph.Controls
                 {
 
                     df = new DisplayRectangle(fieldlist[i], fieldSize.Width,fieldSize.Height, sampleResultFile.GetPixelSize(), offset_point);
+                   df.InitParticleData();
                     df.ContentColor = Color.Black;
                     m_list_allDfield.Add(df);
                 }

+ 36 - 24
OTSIncAReportApp/2-CommonFunction/CommonClass/DisplayParticle.cs

@@ -1,9 +1,11 @@
-using OTSCommon.DBOperate.Model;
+using DevExpress.Utils.Extensions;
+using OTSCommon.DBOperate.Model;
 
 using OTSIncAReportGraph.Class;
 using OTSMeasureApp._0_OTSModel.OTSDataType;
 using System;
 using System.Collections.Generic;
+using System.Diagnostics;
 using System.Drawing;
 using System.Drawing.Drawing2D;
 using System.Linq;
@@ -78,7 +80,7 @@ namespace OTSIncAReportGraph
         private SegmentShowMode show_mode = SegmentShowMode.DRAWPARTICLEIMAGE;//绘线,绘点,默认绘点,意思为默认显示BSE原图像
         private Bitmap m_BSEimage;
         private Bitmap m_Colorimage;
-
+        private Bitmap originalFieldImage;
         private string m_sort_type = "从大到小";
         private float m_f_size = 0;
         private string m_str_lj = "颗粒粒级";
@@ -141,44 +143,63 @@ namespace OTSIncAReportGraph
             this.Color = DrawFunction.GetColorBySTDTypeIDForBSEAndSorImage(part.TypeColor, part.TypeId);
 
         }
-        public DisplayParticle(Particle particle,PointF FieldLeftTop,Bitmap originalFieldImage/*,Bitmap fieldParticleImage*/)
+        public DisplayParticle(Particle particle,PointF FieldLeftTop,Bitmap a_originalFieldImage/*,Bitmap fieldParticleImage*/)
         {
          
             m_id = System.Guid.NewGuid();
             objParticleData = particle;
+            originalFieldImage = a_originalFieldImage;
             this.Color = DrawFunction.GetColorBySTDTypeIDForBSEAndSorImage(particle.TypeColor, particle.TypeId);
 
 
+           
+
+
+           SetPaintState(PaintState.PAINT);
+ 
+            m_Globalrect.X = particle.RectLeft + FieldLeftTop.X;
+            m_Globalrect.Y = particle.RectTop + FieldLeftTop.Y;
+            m_Globalrect.Width = particle.RectWidth;
+            m_Globalrect.Height = particle.RectHeight;
+
+        
+
+        }
+        public void InitImageData()
+        {
             List<Segment> list_seg;
-            list_seg = particle.SegmentList;
+            list_seg = objParticleData.SegmentList;
 
-          
-            this.m_BSEimage = new Bitmap(particle.RectWidth+1, particle.RectHeight+1);
-            this.m_Colorimage = new Bitmap(particle.RectWidth+1, particle.RectHeight+1);
+
+            this.m_BSEimage = new Bitmap(objParticleData.RectWidth + 1, objParticleData.RectHeight + 1);
+            this.m_Colorimage = new Bitmap(objParticleData.RectWidth + 1, objParticleData.RectHeight + 1);
             //再循环取出里面所有的segment
             foreach (Segment seg in list_seg)
             {
-               
+
 
                 #region 
 
                 //合成图像完成,开始抠取像素-----------------------------------------------------------------
 
-             
+
 
                 for (int m = 0; m < seg.Length; m++)
                 {
-                   
-                    int lsjs_x = seg.Start+ m;
+
+                    int lsjs_x = seg.Start + m;
 
                     int lsjs_y = seg.Height;
 
                     var pixelColor = originalFieldImage.GetPixel(lsjs_x, lsjs_y);
 
-                     lsjs_x = seg.Start - particle.RectLeft + m;
-
-                     lsjs_y = seg.Height - particle.RectTop;
+                    lsjs_x = seg.Start - objParticleData.RectLeft + m;
 
+                    lsjs_y = seg.Height - objParticleData.RectTop;
+                    //Debug.Assert(lsjs_x > -1);
+                    //Debug.Assert(lsjs_y > -1);
+                    //Debug.Assert(lsjs_x < m_BSEimage.Width);
+                    //Debug.Assert(lsjs_y< m_BSEimage.Height);
 
                     m_BSEimage.SetPixel(lsjs_x, lsjs_y, pixelColor);//ls_list_colors[m]
                     m_Colorimage.SetPixel(lsjs_x, lsjs_y, m_color);
@@ -187,19 +208,10 @@ namespace OTSIncAReportGraph
 
                 #endregion //------------------------------------------------------------------------------
 
-               
-
-            }
 
 
-           SetPaintState(PaintState.PAINT);
- 
-            m_Globalrect.X = particle.RectLeft + FieldLeftTop.X;
-            m_Globalrect.Y = particle.RectTop + FieldLeftTop.Y;
-            m_Globalrect.Width = particle.RectWidth;
-            m_Globalrect.Height = particle.RectHeight;
+            }
 
-        
 
         }
         public bool WhetherInRange(Point WhetherPoint)

+ 35 - 17
OTSIncAReportApp/2-CommonFunction/CommonClass/DisplayRectangle.cs

@@ -1,4 +1,5 @@
-using OTSCommon.DBOperate.Model;
+using DevExpress.Drawing.Internal.Fonts.Interop;
+using OTSCommon.DBOperate.Model;
 using OTSIncAReportGraph.Class;
 using OTSMeasureApp._0_OTSModel.OTSDataType;
 using System;
@@ -12,6 +13,12 @@ namespace OTSIncAReportGraph
 
     public class DisplayRectangle
     {
+        Field m_field;
+        float m_FieldWidth;
+        float m_FieldHeight;
+        double m_pixelSize; //像素大小,单位um
+        Point m_screenPos; //屏幕位置
+
         Guid  m_id;
         Color disColor;
         string m_fieldid;
@@ -53,7 +60,11 @@ namespace OTSIncAReportGraph
         {
          
             m_list_dparticle = new List<DisplayParticle>();
-       
+       m_field = fld;
+            m_FieldWidth = fldwidth;
+            m_FieldHeight = fldheight;
+            m_pixelSize = pixelSize; //像素大小,单位um
+            m_screenPos = new Point((int)screenPos.X, (int)screenPos.Y);
             m_id = System.Guid.NewGuid();
             Point thisfield_point = new Point() { X = fld.FieldPosX, Y = fld.FieldPosY };
            
@@ -68,39 +79,46 @@ namespace OTSIncAReportGraph
             double bottom = OTSCoordinatePos.Y - fldheight * pixelSize / 2;
             myOTSRect.SetRectData( (float)left,(float)top,(float)right,(float)bottom);
 
+           
+
+
+
+
+
+        }
+        public void InitParticleData()
+        {
             //先获取该Field中的所有Particle
             List<Particle> list_particle;
-            list_particle = fld.ParticleList;
-           
+            list_particle = m_field.ParticleList;
+
             //然后将取出的数据,转换成Bitmap对象
-            m_originalImage = DrawFunction.ReadImageFile(fld.FieldImageName);
+            m_originalImage = DrawFunction.ReadImageFile(m_field.FieldImageName);
 
-            Bitmap dpImage = new Bitmap((int)fldwidth, (int)fldheight);
+            Bitmap dpImage = new Bitmap((int)m_FieldWidth, (int)m_FieldHeight);
+            var ltPoint = new PointF(m_screenPos.X - m_FieldWidth / 2, m_screenPos.Y - m_FieldHeight / 2);
             //再循环计算所有的Particle对象
             foreach (Particle particle in list_particle)
             {
                 //分布图排列图无效颗粒不显示
-                if (particle.TypeId == (int)RemoveParticleType.INVALID|| particle.TypeId == (int)RemoveParticleType.LOW_COUNT)
+                if (particle.TypeId == (int)RemoveParticleType.INVALID || particle.TypeId == (int)RemoveParticleType.LOW_COUNT)
                 {
                     continue;
                 }
 
                 //创建DParticle颗粒
                 DisplayParticle dp = new DisplayParticle(particle, ltPoint, m_originalImage/*,dpImage*/);
-                double partLeft=dp.objParticleData.RectLeft*pixelSize+myOTSRect.GetTopLeft().X;
-                double partRight = partLeft+dp.objParticleData.RectWidth*pixelSize;
-                double partTop = myOTSRect.GetTopLeft().Y - dp.objParticleData.RectTop * pixelSize;
-                double partBottom = partTop - dp.objParticleData.RectHeight * pixelSize;
-                dp.OTSRect.SetRectData((float )partLeft, (float)partTop, (float)partRight, (float)partBottom);
+                dp.InitImageData();
+                double partLeft = dp.objParticleData.RectLeft * m_pixelSize + myOTSRect.GetTopLeft().X;
+                double partRight = partLeft + dp.objParticleData.RectWidth * m_pixelSize;
+                double partTop = myOTSRect.GetTopLeft().Y - dp.objParticleData.RectTop * m_pixelSize;
+                double partBottom = partTop - dp.objParticleData.RectHeight * m_pixelSize;
+                dp.OTSRect.SetRectData((float)partLeft, (float)partTop, (float)partRight, (float)partBottom);
 
                 m_list_dparticle.Add(dp);
-          
-
-            }
-
-
 
 
+            }
 
         }