關於如何根據幾何網路進行爆管分析
我的QQ是:732344647,加我記得寫備註~
之前寫過一篇關於如何建立集合網路流向的文章:如何建立幾何網路流向,在這篇文章之中只是介紹如何建立流向,並沒有介紹如何實現爆管分析的功能,我在網上也沒百度谷歌出相關程式碼(應該有我沒有找到吧),所以自己研究出來了,今天就分享給大家,並感謝給我找相關文獻的同門們以及那些分享經驗的大神們(本文實現程式碼並沒有根據流向來找到閥門,而是找到所有的相連,但是整體的實現思路不會錯,如果你需要根據流向來實現搜尋,還需要將流向設定好了以後進一步判斷,參考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;
}
———————————————————————————————————————-
這就是主要的流程邏輯與程式碼了,希望可以幫到大家,另外有什麼不足之處請大家不吝指教!