四 ArcEngine實現創建網絡數據集
ArcEngine創建網絡數據集的過程,與ArcMap設置的過程類似,主要通過六個步驟即可以實現。
1 定義網絡數據集對象,並設置基本屬性,包括網絡數據集名稱,空間參考,空間范圍等內容。
關鍵代碼如下:

1 /// <summary> 2 3 /// 創建網絡數據集對象 4 5 /// </summary> 6 7 /// <param name="featureDataset">包含網絡數據集的空間要素集</param> 8 9 /// <param name="NetworkName">網絡數據集名稱</param> 10 11 /// <returns>邊線網絡數據集</returns> 12 13 public IDENetworkDataset CreateNetworkDataset(IFeatureDataset featureDataset, string NetworkName) 14 15 { 16 17 if (string.IsNullOrEmpty(NetworkName)||null==featureDataset) 18 19 { 20 21 return null; 22 23 } 24 25 26 27 //定義邊線網絡數據集對象 28 29 IDENetworkDataset deNetworkDataset = new DENetworkDatasetClass(); 30 31 // 轉換為 IGeoDataset 接口 32 33 IGeoDataset geoDataset = (IGeoDataset)featureDataset; 34 35 36 37 // 設置數據集的空間參考和空間范圍 38 39 IDEGeoDataset deGeoDataset = (IDEGeoDataset)deNetworkDataset; 40 41 deGeoDataset.Extent = geoDataset.Extent; 42 43 deGeoDataset.SpatialReference = geoDataset.SpatialReference; 44 45 46 47 // 設置名稱 48 49 IDataElement dataElement = (IDataElement)deNetworkDataset; 50 51 dataElement.Name = NetworkName; 52 53 // 設置為可創建 54 55 pDENetworkDataset.Buildable = true; 56 57 //設置數據集類型 58 59 pDENetworkDataset.NetworkType = esriNetworkDatasetType.esriNDTGeodatabase; 60 61 62 63 return deNetworkDataset; 64 65 }
2 創建數據源對象;
關鍵代碼如下:

1 /// <summary> 2 3 /// 創建網絡源對象 4 5 /// </summary> 6 7 /// <param name="FeatureClassName">參與網絡數據集的空間要素類名稱</param> 8 9 /// <returns>源</returns> 10 11 public INetworkSource CreateEdgeFeatureNetworkSource(string FeatureClassName) 12 13 { 14 15 16 17 INetworkSource pEdgeNetworkSource = new EdgeFeatureSourceClass(); 18 19 pEdgeNetworkSource.Name = FeatureClassName; 20 21 //設置類型 22 23 pEdgeNetworkSource.ElementType = esriNetworkElementType.esriNETEdge; 24 25 26 27 return pEdgeNetworkSource; 28 29 }
3 設置數據源的屬性,主要包括連通性策略,源對象方向;
關鍵代碼如下:

1 /// <summary> 2 3 /// 設置源的連通性,不使用字段值設置 4 5 /// </summary> 6 7 /// <param name="pEdgeNetworkSource">源對象</param> 8 9 public void SetNetworkSourcewithoutSubtypes(INetworkSource pEdgeNetworkSource) 10 11 { 12 13 // 源的連通性 14 15 IEdgeFeatureSource pEdgeFeatureSource = (IEdgeFeatureSource)pEdgeNetworkSource; 16 17 //不使用子類 18 19 pEdgeFeatureSource.UsesSubtypes = false; 20 21 //分組 22 23 pEdgeFeatureSource.ClassConnectivityGroup = 1; 24 25 //使用節點參與 26 27 pEdgeFeatureSource.ClassConnectivityPolicy = esriNetworkEdgeConnectivityPolicy.esriNECPEndVertex; 28 29 } 30 31 32 33 /// <summary> 34 35 /// 設置源對象的方向 36 37 /// </summary> 38 39 /// <param name="StreetFieldName">道路屬性名</param> 40 41 /// <param name="EdgeNetworkSource">源對象</param> 42 43 private void SetNetworkSourceDirections(string StreetFieldName, INetworkSource EdgeNetworkSource) 44 45 { 46 47 // 創建道路名字段類對象 48 49 IStreetNameFields streetNameFields = new StreetNameFieldsClass(); 50 51 streetNameFields.Priority = 1; 52 53 // 設置名稱 54 55 streetNameFields.StreetNameFieldName = StreetFieldName; 56 57 58 59 //添加到集合中 60 61 IArray nsdArray = new ArrayClass(); 62 63 nsdArray.Add(streetNameFields); 64 65 66 67 //創建網絡方向對象 68 69 INetworkSourceDirections nsDirections = new NetworkSourceDirectionsClass(); 70 71 72 73 nsDirections.StreetNameFields = nsdArray; 74 75 76 77 //設置源對象的網絡方向 78 79 EdgeNetworkSource.NetworkSourceDirections = nsDirections; 80 81 } 82 83
4 設置網絡數據集的屬性,對應ArcMap創建網絡數據集的第六步設置;
關鍵代碼如下:

1 /// <summary> 2 3 /// 網絡權重屬性設置,多個源參與同一個網絡數據集屬性的設置 4 5 /// </summary> 6 7 /// <param name=" SourceLst ">參與的所有源對象</param> 8 9 /// <param name="AttributeName">屬性名稱</param> 10 11 /// <param name="Expression">設置表達式</param> 12 13 /// <param name="PreLogic">設置邏輯表達式,可空</param> 14 15 /// <returns></returns> 16 17 private IEvaluatedNetworkAttribute CreateNetworkSourceAttribute(List<INetworkSource> SourceLst, string AttributeName, string Expression, string PreLogic) 18 19 { 20 21 //定義變量 22 23 IEvaluatedNetworkAttribute pEvalNetAttr; 24 25 INetworkAttribute2 pNetAttr2; 26 27 INetworkFieldEvaluator pNetFieldEval; 28 29 INetworkConstantEvaluator pNetConstEval; 30 31 32 33 pEvalNetAttr = new EvaluatedNetworkAttributeClass(); 34 35 pNetAttr2 = (INetworkAttribute2)pEvalNetAttr; 36 37 pNetAttr2.Name = AttributeName; 38 39 //計算類型 40 41 pNetAttr2.UsageType = esriNetworkAttributeUsageType.esriNAUTCost; 42 43 //數值類型 44 45 pNetAttr2.DataType = esriNetworkAttributeDataType.esriNADTDouble; 46 47 //單位類型 48 49 pNetAttr2.Units = esriNetworkAttributeUnits.esriNAUMeters; 50 51 pNetAttr2.UseByDefault = true; 52 53 54 55 //計算表達式 56 57 pNetFieldEval = new NetworkFieldEvaluatorClass(); 58 59 pNetFieldEval.SetExpression(Expression, PreLogic); 60 61 62 63 //參與的每個源的計算表達式設置 64 65 SourceLst.ForEach(pEdgeNetworkSource => 66 67 { 68 69 //正向計算表達式 70 71 pEvalNetAttr.set_Evaluator(pEdgeNetworkSource, esriNetworkEdgeDirection.esriNEDAlongDigitized, (INetworkEvaluator)pNetFieldEval); 72 73 //反向計算表達式 74 75 pEvalNetAttr.set_Evaluator(pEdgeNetworkSource, esriNetworkEdgeDirection.esriNEDAgainstDigitized, (INetworkEvaluator)pNetFieldEval); 76 77 78 79 }); 80 81 82 83 pNetConstEval = new NetworkConstantEvaluatorClass(); 84 85 pNetConstEval.ConstantValue = 0; 86 87 88 89 //設置邊,交匯點,轉彎的默認值為常數 90 91 pEvalNetAttr.set_DefaultEvaluator(esriNetworkElementType.esriNETEdge, 92 93 (INetworkEvaluator)pNetConstEval); 94 95 pEvalNetAttr.set_DefaultEvaluator(esriNetworkElementType.esriNETJunction, 96 97 (INetworkEvaluator)pNetConstEval); 98 99 pEvalNetAttr.set_DefaultEvaluator(esriNetworkElementType.esriNETTurn, 100 101 (INetworkEvaluator)pNetConstEval); 102 103 104 105 return pEvalNetAttr; 106 107 }
5 設置網絡數據集的方向;
關鍵代碼如下:

1 /// <summary> 2 3 /// 指定網絡數據集的方向屬性 4 5 /// </summary> 6 7 /// <param name="deNetworkDataset">網絡數據集</param> 8 9 /// <param name="UnitsType">單位類型</param> 10 11 /// <param name="LengthAttribute"> 創建的長度屬性的名稱</param> 12 13 /// <param name="TimeAttribute"> 創建的時間屬性名稱,可空</param> 14 15 /// <param name="RoadClassAttribute">創建的道路類型屬性名稱,可空</param> 16 17 public void SetNetworkDirction(IDENetworkDataset deNetworkDataset,esriNetworkAttributeUnits UnitsType, string LengthAttribute, string TimeAttribute, string RoadClassAttribute) 18 19 { 20 21 // 創建網絡方向對象 22 23 INetworkDirections networkDirections = new NetworkDirectionsClass(); 24 25 networkDirections.DefaultOutputLengthUnits = UnitsType; 26 27 28 29 //設置長度屬性 30 31 if (!string.IsNullOrEmpty(LengthAttribute)) 32 33 { 34 35 networkDirections.LengthAttributeName = LengthAttribute; 36 37 } 38 39 //設置時間屬性 40 41 if (!string.IsNullOrEmpty(TimeAttribute)) 42 43 { 44 45 networkDirections.TimeAttributeName = TimeAttribute; 46 47 } 48 49 //設置道路類型屬性 50 51 if (!string.IsNullOrEmpty(RoadClassAttribute)) 52 53 { 54 55 networkDirections.RoadClassAttributeName = RoadClassAttribute; 56 57 } 58 59 60 61 // 設置網絡數據集的方向屬性 62 63 deNetworkDataset.Directions = networkDirections; 64 65 }
6 建立網絡數據集;
關鍵代碼如下:

1 /// <summary> 2 3 /// 根據網絡節點信息,創建網絡數據集對象 4 5 /// </summary> 6 7 /// <param name="_pFeatureDataset">包含網絡數據集的空間數據集</param> 8 9 /// <param name="_pDENetDataset">源網絡</param> 10 11 /// <returns></returns> 12 13 public INetworkDataset CreateBuildingDataset(IFeatureDataset _pFeatureDataset, IDENetworkDataset2 _pDENetDataset) 14 15 { 16 17 IFeatureDatasetExtensionContainer pFeatureDatasetExtensionContainer = (IFeatureDatasetExtensionContainer)_pFeatureDataset; 18 19 IFeatureDatasetExtension pFeatureDatasetExtension = pFeatureDatasetExtensionContainer.FindExtension(esriDatasetType.esriDTNetworkDataset); 20 21 IDatasetContainer2 pDatasetContainer2 = (IDatasetContainer2)pFeatureDatasetExtension; 22 23 IDEDataset pDENetDataset = (IDEDataset)_pDENetDataset; 24 25 26 27 //創建網絡數據集 28 29 INetworkDataset pNetworkDataset = (INetworkDataset)pDatasetContainer2.CreateDataset(pDENetDataset); 30 31 32 33 return pNetworkDataset; 34 35 } 36 37 38 39 /// <summary> 40 41 /// 生成網絡數據集 42 43 /// </summary> 44 45 /// <param name="networkDataset">網絡數據集</param> 46 47 /// <param name="geoDataset">空間數據集</param> 48 49 public bool BuildNetwork(INetworkDataset networkDataset, featureDataset) 50 51 { 52 53 // 空間數據集轉換為IGeoDataset 接口 54 55 IGeoDataset geoDataset = (IGeoDataset)featureDataset; 56 57 58 59 if (null==geoDataset) 60 61 { 62 63 return false; 64 65 } 66 67 68 69 INetworkBuild networkBuild = (INetworkBuild)networkDataset; 70 71 //構建網絡數據集 72 73 networkBuild.BuildNetwork(geoDataset.Extent); 74 75 76 77 return true; 78 79 }
五 遇到的難題與解決過程
ArcEngine創建網絡數據集過程中,遇到一些問題,主要是兩部分原因,一是擴展許可問題,二是屬性值設置的問題。
1 擴展許可問題:
項目開發過程中,注意到了許可初始化的問題,通過代碼實現ArcEngine許可初始化。但是,在IDatasetContainer2接口執行CreateDataset方法時,報錯"異常來自HRESULT:0x80040220”。
該異常產生的原因是,由於網絡數據集創建功能接口的實現,需要ArcEngine擴展許可初始化,即調用IAoInitialize 接口的CheckOutExtension方法,注冊空間分析的擴展許可。
2 屬性值設置問題:
1)官網的樣例代碼對於創建網絡數據集屬性接口IEvaluatedNetworkAttribute時,都是針對當個參與源對象INetworkSource進行設置的。如果多個源對象參與設置同一個IEvaluatedNetworkAttribute接口設置時,需要遍歷每個源對象進行設置。
關鍵代碼段如下:
//參與的每個源的計算表達式設置
SourceLst.ForEach(pEdgeNetworkSource =>
{
//正向計算表達式
pEvalNetAttr.set_Evaluator(pEdgeNetworkSource, esriNetworkEdgeDirection.esriNEDAlongDigitized, (INetworkEvaluator)pNetFieldEval);
//反向計算表達式
pEvalNetAttr.set_Evaluator(pEdgeNetworkSource, esriNetworkEdgeDirection.esriNEDAgainstDigitized, (INetworkEvaluator)pNetFieldEval);
});
2)創建的網絡數據集屬性IEvaluatedNetworkAttribute,是用在設置網絡數據集的方向屬性,需要保證名稱一致。
例如,定義了名稱為“Length”的IEvaluatedNetworkAttribute對象,在設置網絡數據集的長度屬性為該定義的對象時,需要把INetworkDirections接口的LengthAttributeName屬性設置為“Length”。這樣,網絡數據集在計算長度屬性時,根據已定義的接口計算。否則,會報錯“The network attribute name is invalid”。
未完待續......