关于如何根据几何网络进行爆管分析
之前写过一篇关于如何建立集合网络流向的文章: 如何建立几何网络流向,在这篇文章之中只是介绍如何建立流向,并没有介绍如何实现爆管分析的功能,我在网上也没百度谷歌出相关代码(应该有我没有找到吧),所以自己研究出来了,今天就分享给大家,并感谢给我找相关文献的同门们以及那些分享经验的大神们(本文实现代码并没有根据流向来找到阀门,而是找到所有的相连,但是整体的实现思路不会错,如果你需要根据流向来实现搜索,还需要将流向设置好了以后进一步判断,参考API以后相信根据本文你可以进一步完善)。
———————————————————————————————————————-
首先,我并不会将所有的代码都写出来,但是会介绍最关键的流程与主要代码。
1–找到目标数据的 几何网络。因为我们是在这个数据基础上进行分析的,就是QI到这个接口 INetworkCollection,通过ArcGIS API的帮助文档,我们可以发现类FeatureDataset实现了这个接口,所以思路就是从操作的图层之中尽享QI转换过去就可以了;
iFeatureLayer = iLayer as IFeatureLayer;
iFeatureDataset = iFeaLayer.FeatureClass.FeatureDataset;
iNetCollec = iDataset as INetworkCollection;
2-找到Edge边。因为爆管分析是我们需要先选中我们确定的已经的爆管的管道,所以需要根据鼠标点击数据找到那条边;这里主要用到了 IPointToEID接口的GetNearestEdge方法获取到当前的爆管位置
3-找到Edge首末节点。根据第二步找到Edge以后得到的是该边的EID,在几何网络之中会根据Feature重新生成一个EID对应每个要素;所以我们可以使用 INetTopologyEditGEN接口的GetFromToJunctionEIDs方法找到首末节点的EID
4–判断首末节点是否为阀门(爆管分析就是要关闭连通的阀门),如果是阀门,那么这个节点相连的边线就不用继续搜索了,否则根据该节点的EID继续往下搜索所有相连的边线Edges;这里我们使用队列Enqueue数据结构来处理节点EID,所有检索到的非节点的EID全部保存在队列之中,因为队列是先进先出的,而且出列的同时会返回该出列值,适用于当前的数据结构,而检索到的所有Edges全部保存在字典Dictionary之中,其中Key是连接节点,而Value是与该点连接Edges;这样,当我们从队列中取出非阀门节点的EID的时候就可以去字典中找到相连的Edge,然后根据这条连接边继续寻找节点,直到队列为空为止。
这一步相对较为复杂,所以会将所有代码全部贡献出来
while (true)
{
dictionary.Clear();
//判断2个起始节点是否为阀门
if (IsWaterValue(fromFuncEID, iGeoNetwork) && IsWaterValue(toFuncEID, iGeoNetwork))//首尾皆为阀门
{
g_WaterValues.Add(GetFeatureByEID(fromFuncEID, iGeoNetwork)); g_WaterValues.Add(GetFeatureByEID(toFuncEID, iGeoNetwork));
break;//跳出
}
else if (IsWaterValue(fromFuncEID, iGeoNetwork) && !IsWaterValue(toFuncEID, iGeoNetwork))//起点是阀门
{
g_WaterValues.Add(GetFeatureByEID(fromFuncEID, iGeoNetwork));
juncQueue.Enqueue(toFuncEID);
dictionary.Add(toFuncEID, nearestEdgeEID);
}
else if (!IsWaterValue(fromFuncEID, iGeoNetwork) && IsWaterValue(toFuncEID, iGeoNetwork))//终点是阀门
{
g_WaterValues.Add(GetFeatureByEID(toFuncEID, iGeoNetwork));
juncQueue.Enqueue(fromFuncEID);
dictionary.Add(fromFuncEID, nearestEdgeEID);
}
else//都不是阀门
{
juncQueue.Enqueue(fromFuncEID);
juncQueue.Enqueue(toFuncEID);
dictionary.Add(fromFuncEID, nearestEdgeEID);
dictionary.Add(toFuncEID, nearestEdgeEID);
}
IForwardStarGEN iForwardStarGEN = iGeoNetwork.Network.CreateForwardStar(true, null, null, null, null) as IForwardStarGEN;//这个接口主要负责根据EID查找连通的要素EID
while (juncQueue.Count != 0)//判断队列是否为空,递归...
{
int adgacentEdgesCount = 0;//指定的搜索节点连接的除源edge以外的邻接边线个数
int eid = (int)juncQueue.Dequeue();//队列移除eid并获取eid
iForwardStarGEN.FindAdjacent(dictionary[eid], eid, out adgacentEdgesCount);//首次判断使用起始边线作为输入参数
if (adgacentEdgesCount != 0)//如果邻接线为0
{
int[] refEdgesEIDs = new int[adgacentEdgesCount];//查询到的边线集合
bool[] refReverseOrirntation = new bool[adgacentEdgesCount];//默认为false
object[] refWeightValue = new object[adgacentEdgesCount];
iForwardStarGEN.QueryAdjacentEdges(ref refEdgesEIDs, ref refReverseOrirntation, ref refWeightValue);//获得与指定节点的边线EID集合
//遍历边线集合
for (int i = 0; i < refEdgesEIDs.Length; i++)
{
int adgacentJunc;
object weight;
iForwardStarGEN.QueryAdjacentJunction(i, out adgacentJunc, out weight);
//判断这个输出的节点EID是否为阀门
if (IsWaterValue(adgacentJunc, iGeoNetwork))
{//如果是阀门加入到集合中
g_WaterValues.Add(GetFeatureByEID(adgacentJunc, iGeoNetwork));
}
else
{
if (!dictionary.ContainsKey(adgacentJunc))//因为没有设置流向,所以是双向查找,所以要判断是否已经查过了
{
dictionary.Add(adgacentJunc, refEdgesEIDs[i]); //成对添加到字典中去
juncQueue.Enqueue(adgacentJunc);//如果不是阀门,那么将该节点加入到队列中去
}
}
}
}
}
//最后需要break
break;
}
———————————————————————————————————————-
这就是主要的流程逻辑与代码了,希望可以帮到大家,另外有什么不足之处请大家不吝指教!