ArcGIS Engine识别连续的多段线

版权声明:本文为博主原创文章,不需博主允许即可随意转载。 https://blog.csdn.net/a_dev/article/details/84581744

已知:

1.某一片区域内有多条管线段

2.每条管线段包含两个端点

3.两条管线段可通过一个端点进行连接

4.管线段之间可能存在交叉

数据如下:

我们要做的事情是,画一个范围,将范围内所有连续的管线段识别出来。

先制作一份测试数据:

对上图,我们预期得到的结果集合应该是这样的(不区分方向,即123与321视为同一条连续管线段):

扫描二维码关注公众号,回复: 5552334 查看本文章
{
	(123),
	(1245),
	(1246),
	(345),
	(346),
	(56),
	(78),
	(9)
}

算法中需要使用以下几个类来存储相应的变量:

/// <summary>
/// 要素图形信息
/// </summary>
public class FeatureShape
{
	/// <summary>
	/// 要素GLOBALID(唯一标识)
	/// </summary>
	public int ObjectID { get; set; }
	/// <summary>
	/// 要素几何图形
	/// </summary>
	public IGeometry Geometry { get; set; }
}

/// <summary>
/// 连接的线段要素对象
/// </summary>
public class ContinuousLine
{
	private List<FeatureShape> lineFeatures = null;
	public List<FeatureShape> Features
	{
		get
		{
			if (null == lineFeatures)
				lineFeatures = new List<FeatureShape>();
			return lineFeatures;
		}
		set => lineFeatures = value;
	}
	/// <summary>
	/// 重写ToString,将ObjectID输出(方便调试查看)
	/// </summary>
	/// <returns></returns>
	public override string ToString()
	{
		string s = "";
		if (null != lineFeatures && 0 < lineFeatures.Count)
		{
			lineFeatures.ForEach(e => s += $" {e.ObjectID}");
		}
		return s;
	}
}

/// <summary>
/// 连续线段信息
/// </summary>
public class LineSegmentInfo
{
	/// <summary>
	/// 是否为端点段(即至少有一端末与其他线段相连)
	/// </summary>
	public bool IsEnd { get; set; }
	/// <summary>
	/// 线要素对象信息
	/// </summary>
	public FeatureShape LineFeature { get; set; }
}

根据以上示例图形生成测试数据:

private FeatureShape GenerateTestFeature(int objectId, double x0, double y0, double x1, double y1)
{
	var aLineFeature = new FeatureShape()
	{
		ObjectID = objectId,
		Geometry = CreatePolyline(new PointClass() { X = x0, Y = y0 }, new PointClass() { X = x1, Y = y1 })
	};
	return aLineFeature;
}

private List<LineSegmentInfo> GenerateTestData()
{
	var lstResult = new List<LineSegmentInfo>
	{
		new LineSegmentInfo() { IsEnd = false, LineFeature = GenerateTestFeature(1, 1, 6, 2, 4) },
		new LineSegmentInfo() { IsEnd = false, LineFeature = GenerateTestFeature(2, 2, 4, 4, 4) },
		new LineSegmentInfo() { IsEnd = false, LineFeature = GenerateTestFeature(3, 4, 4, 6, 6) },
		new LineSegmentInfo() { IsEnd = false, LineFeature = GenerateTestFeature(4, 4, 4, 5, 2) },
		new LineSegmentInfo() { IsEnd = false, LineFeature = GenerateTestFeature(5, 5, 2, 5, 0) },
		new LineSegmentInfo() { IsEnd = false, LineFeature = GenerateTestFeature(6, 5, 2, 7, 3) },
		new LineSegmentInfo() { IsEnd = false, LineFeature = GenerateTestFeature(7, 1, 2, 3, 2) },
		new LineSegmentInfo() { IsEnd = false, LineFeature = GenerateTestFeature(8, 3, 2, 4, 0) },
		new LineSegmentInfo() { IsEnd = false, LineFeature = GenerateTestFeature(9, 2, 6, 4, 6) }
	};
	return lstResult;
}

我们设计的算法步骤如下:
1.根据区域,使用空间包含关系,查询所有管线段(示例中使用代码生成所有管线段)
2.识别出所有截止管线段(即至少有一个端点未连接其他管线段)
3.从每个截止管线段起,搜索连续的管线段(不区分方向)

相应的代码,第一步,我们已经得到了管线段集合,第二步,就是识别出其中的截止管线段,代码如下:

private void IdentifyEndLine(ref List<LineSegmentInfo> lstLineSegmentInfo)
{
	for (int i = 0; i < lstLineSegmentInfo.Count; i++)
	{
		var nCount = -1;
		var pPointCollection = lstLineSegmentInfo[i].LineFeature.Geometry as IPointCollection;
		if (null != pPointCollection && 0 < pPointCollection.PointCount)
		{
			for (int j = 0; j < pPointCollection.PointCount; j++)
			{
				var nTempCount = GetTouchFeatureCount(pPointCollection.Point[j] as IRelationalOperator, lstLineSegmentInfo[i].LineFeature.ObjectID, lstLineSegmentInfo);
				if (nCount < 0 || nTempCount < nCount)
					nCount = nTempCount;
			}
		}
		if (0 == nCount)
			lstLineSegmentInfo[i].IsEnd = true;
	}
}

private int GetTouchFeatureCount(IRelationalOperator pRelationalOperator, int nOwnOid, List<LineSegmentInfo> lstLineSegmentInfo)
{
	var nCount = 0;
	if (null != pRelationalOperator && null != lstLineSegmentInfo && 0 < lstLineSegmentInfo.Count)
	{
		foreach (var aLineSegment in lstLineSegmentInfo)
		{
			if (aLineSegment.LineFeature.ObjectID == nOwnOid)
				continue;
			if (pRelationalOperator.Touches(aLineSegment.LineFeature.Geometry))
				nCount++;
		}
	}
	return nCount;
}

第三步,我们要循环各个截止管线段,搜索连续管线段,结果存放在如下变量中:

private List<ContinuousLine> m_lstContinuousLine;

循环吧:

foreach (var item in lstSegment)
{
	if (item.IsEnd)
	{
		GetContinuousLine(lstSegment, item.LineFeature, null, null, ref m_lstContinuousLine);
	}
}

算法其实是一个递归:

private void GetContinuousLine(List<LineSegmentInfo> lstSegment, FeatureShape currentLineFeature, 
 ContinuousLine currentContinuousLine, List<FeatureShape> lstIgnored, ref List<ContinuousLine> lstResult)
{
	if (null == lstSegment || 0 == lstSegment.Count)
		return;
	if (null == lstResult)
		lstResult = new List<ContinuousLine>();

	foreach (var aSegment in lstSegment)
	{
		if (null != lstIgnored && 0 < lstIgnored.Count)
		{
			if (lstIgnored.Contains(aSegment.LineFeature))
			{
				continue;
			}
		}
		if (null != currentContinuousLine && 0 < currentContinuousLine.Features.Count)
		{
			if (currentContinuousLine.Features.Contains(aSegment.LineFeature))
			{
				continue;
			}
		}

		if (null == currentLineFeature)
		{
			if (!aSegment.IsEnd)
			{
				continue;
			}
			else
			{
				GetContinuousLine(lstSegment, aSegment.LineFeature, null, null, ref lstResult);
				break;
			}
		}

		if (aSegment.LineFeature.ObjectID != currentLineFeature.ObjectID)
		{
			continue;
		}

		if (aSegment.IsEnd)
		{
			if (null == currentContinuousLine || 0 == currentContinuousLine.Features.Count)
			{
				var lstConnected = GetConnectedLineFeature(aSegment.LineFeature, lstSegment, lstIgnored);
				if (0 < lstConnected.Count)
				{
					var aNewCurrentContinuous = new ContinuousLine();
					if (null != currentContinuousLine && 0 < currentContinuousLine.Features.Count)
					{
						currentContinuousLine.Features.ForEach(e => aNewCurrentContinuous.Features.Add(e));
					}
					aNewCurrentContinuous.Features.Add(aSegment.LineFeature);
					foreach (var aConnected in lstConnected)
					{
						if (aNewCurrentContinuous.Features.Contains(aConnected))
							continue;
						var lstNewIgnored = new List<FeatureShape>();
						foreach (var item in lstConnected)
						{
							if (item.ObjectID == aConnected.ObjectID)
								continue;
							if (aNewCurrentContinuous.Features.Contains(item))
								continue;
							lstNewIgnored.Add(item);
						}
						GetContinuousLine(lstSegment, aConnected, aNewCurrentContinuous, lstNewIgnored, ref lstResult);
					}
				}
				else
				{
					var aNewContinuousLine = new ContinuousLine() { Features = new List<FeatureShape>() { aSegment.LineFeature } };
					if (!ContainsContinuousLine(aNewContinuousLine, ref lstResult))
						lstResult.Add(aNewContinuousLine);
				}
			}
			else
			{
				var aNewContinuousLine = new ContinuousLine();
				currentContinuousLine.Features.ForEach(e => aNewContinuousLine.Features.Add(e));
				aNewContinuousLine.Features.Add(aSegment.LineFeature);
				if (!ContainsContinuousLine(aNewContinuousLine, ref lstResult))
					lstResult.Add(aNewContinuousLine);
				break;
			}
		}
		else
		{
			var lstConnected = GetConnectedLineFeature(aSegment.LineFeature, lstSegment, lstIgnored);
			var aNewCurrentContinuous = new ContinuousLine();
			if (null != currentContinuousLine && 0 < currentContinuousLine.Features.Count)
			{
				currentContinuousLine.Features.ForEach(e => aNewCurrentContinuous.Features.Add(e));
			}
			aNewCurrentContinuous.Features.Add(aSegment.LineFeature);
			foreach (var aConnected in lstConnected)
			{
				if (currentContinuousLine.Features.Contains(aConnected))
					continue;
				var lstNewIgnored = new List<FeatureShape>();
				foreach (var item in lstConnected)
				{
					if (item.ObjectID == aConnected.ObjectID)
						continue;
					if (currentContinuousLine.Features.Contains(item))
						continue;
					lstNewIgnored.Add(item);
				}
				GetContinuousLine(lstSegment, aConnected, aNewCurrentContinuous, lstNewIgnored, ref lstResult);
			}
		}
	}
}




private bool ContainsContinuousLine(ContinuousLine continuousLine, ref List<ContinuousLine> lstLine)
{
	var bContains = true;
	if (null == lstLine || 0 >= lstLine.Count)
	{
		if (null != continuousLine)
		{
			bContains = false;
		}
	}
	else
	{
		if (null == continuousLine || 0 >= continuousLine.Features.Count)
		{
			bContains = false;
		}
		else
		{
			bContains = false;
			foreach (var aLine in lstLine)
			{
				if (aLine.Features.Count != continuousLine.Features.Count)
				{
					continue;
				}
				if (continuousLine.Features.All(aLine.Features.Contains) && aLine.Features.All(continuousLine.Features.Contains))
				{
					bContains = true;
					break;
				}
			}
		}
	}
	return bContains;
}



private List<FeatureShape> GetConnectedLineFeature(FeatureShape lineFeature, List<LineSegmentInfo> lstLineSegment, List<FeatureShape> lstIgnored = null)
{
	var lstResult = new List<FeatureShape>();
	if (null != lineFeature && null != lineFeature.Geometry && null != lstLineSegment && 0 < lstLineSegment.Count)
	{
		var pRelOperator = lineFeature.Geometry as IRelationalOperator;
		foreach (var aLineSegment in lstLineSegment)
		{
			if (aLineSegment.LineFeature.ObjectID == lineFeature.ObjectID)
				continue;
			var bIgnore = false;
			if (null != lstIgnored && 0 < lstIgnored.Count)
			{
				foreach (var aLineFeature in lstIgnored)
				{
					if (aLineSegment.LineFeature.ObjectID == aLineFeature.ObjectID)
					{
						bIgnore = true;
						break;
					}
				}
			}
			if (!bIgnore)
			{
				if (pRelOperator.Touches(aLineSegment.LineFeature.Geometry))
					lstResult.Add(aLineSegment.LineFeature);
			}
		}
	}
	return lstResult;
}

代码跑起来,监视变量,发现结果正是我们想要的:

猜你喜欢

转载自blog.csdn.net/a_dev/article/details/84581744
今日推荐