ArcGIS 網絡分析[8.3] 設置IDENetworkDataset的屬性及INetworkDataset的對比/創建網絡數據集


創建網絡數據集就得有各種數據和參數,這篇文章很長,慎入。

網絡分析依賴於網絡數據集的質量,這句話就在這里得到了驗證:復雜、精確定義。

本節目錄如下:

  • 1. INetworkDataset與IDENetworkDataset對比
  • 1.1 什么是INetworkDataset
  • 1.2 兩者對比
  • 2. 如何設置數據元素網絡數據集(IDENetworkDataset)的屬性以創建網絡數據集
  • 2.1 涉及的接口、類、枚舉
  • 2.2 創建數據元素網絡數據集(IDENetworkDataset)對象
  • 2.3 添加網絡源
  • 2.4 添加網絡屬性
  • 2.5 添加導航/方向
  • 2.6 為數據元素網絡數據集賦值並構建網絡數據集(INetworkDataset)

 

1. INetworkDataset與IDENetworkDataset的對比

挑簡單的先說,INetworkDataset與IDENetworkDataset的對比。

1.1 先說說INetworkDataset是個什么東西

網絡數據集是一個擁有網絡關系的要素類的容器。每個要素類都有自己的拓撲規則,每個網絡有可能有多個同樣拓撲規則的要素類。一個要素數據集可能有多個網絡數據集,但是一個要素類只能屬於一個網絡數據集或一個幾何網絡。一個屬於網絡數據集的要素類被稱為:網絡數據源,網絡數據集還擁有多個網絡屬性,這些屬性被用作解決網絡分析問題。

IDatasetContainer2接口用於創建或打開網絡數據集。INetworkBuild接口用作添加或刪除一個網絡數據集中的網絡數據源、網絡屬性,或者被用於構建網絡數據集。

再上一張INetworkDataset的屬性圖:

這些屬性全部都是只允許訪問的(都是get屬性)。

INetworkDataset更合適在分析部分解釋,它與INAContext有關。

1.2 二者對比

很容易與上一節的IDENetworkDataset做出對比,INetworkDataset更專注於處理與屬性、數據源的存取,而IDENetworkDataset更專注於數據的組織。

后者是數據的集合,是真正的網絡數據源、網絡屬性等的容器,而前者更合適稱為“分析對象”,它專注於網絡屬性和網絡數據源的訪問。

因為后者名中的“DE”就是DataElement的簡稱,所以IDENetworkDataset是“數據元素網絡數據集”。

2. 如何設置數據元素網絡數據集(IDENetworkDataset)的屬性以創建網絡數據集

再貼一張IDENetworkDataset的屬性圖(就上篇文章):

 

重點需要設置的屬性是:Attributes、Directions、Sources

這對應了桌面創建網絡數據集的三個重要步驟:網絡屬性、導航設置、網絡數據源。

其中網絡數據源又可分為三種:線要素、點要素、轉彎要素。

其他需要注意的屬性是:Buildable;

2.1 涉及的接口、類、枚舉

 

在接下來的介紹中,會用到的核心接口和類、枚舉先列出:

涉及的接口:共計18個

IDENetworkDataset、INetworkDataset、INetworkSource、INetworkAttribute、INetworkDirection、IEvaluatedNetworkAttribute、

INetworkSourceDirections、IStreetNameFields、IEdgeFeatureSource、INetworkFieldEvaluator、INetworkEvaluator、INetworkConstantEvaluator

IArray

INetworkBuild、IDEDataset、IDatasetContainer、IFeatureDatasetExtension、IFeatureDatasetExtensionContainer

涉及到的類:共計9個

DENetworkDatasetClass、StreetNameFieldsClass、NetworkSourceDirectionsClass

TurnFeatureSourceClass、EdgeFeatureSourceClass(INetworkSource的實現類)

EvaluatedNetworkAttributeClass、NetworkFieldEvaluatorClass、NetworkConstantEvaluatorClass

ArrayClass

涉及到的枚舉:共計6個

esriNetworkElementType、esriNetworkAttributeUnits、esriNetworkEdgeDirection、esriNetworkAttributeDataType、esriNetworkAttributeUsageType、esriNetworkEdgeConnectivityPolicy

別害怕,我會逐一解釋這些類對應桌面創建網絡數據集時,分別是什么。

2.2 創建一個IDENetworkDataset對象

為了創建一個裝着網絡數據集所有素材的“數據元素網絡數據集”,我們需要的東西是:一個IFeatureDataset(即桌面上的要素數據集)對象,網絡數據集的名稱。

我們創建一個這樣的方法:

public IDENetworkDataset CreateDENetworkDataset(IFeatureDataset featureDataset, string networkName)
{
    IDENetworkDataset deNetworkDataset = new DENetworkDatasetClass();
// ...設置數據要素網絡數據集的必須參數

return deNetworkDataset;
}

注意,這個時候並不需要這個要素數據集中有要素數據。而在桌面軟件中基於要素數據集創建網絡數據集,是要求要素數據集中存在最基本的點線要素的。

那是因為,在AO中,要創建數據元素網絡數據集,只需要獲取IFeatureDataset即可,至於網絡數據集中的點、線、轉彎,則是下一步添加Sources(網絡數據源)的事情。

我直接給出數據元素網絡數據集必須設置的屬性,和分別來自哪些接口:

從上圖可以看出為了創建DENetworkDataset這個類的實例,默認使用IDENetworkDataset接口來定義變量。

需要給的默認屬性有:

IDENetworkDataset接口下的Buildable屬性、NetworkType屬性

IDEGeoDataset接口下的Extent屬性、SpatialReference屬性

IDataElement接口下的Name屬性

其中,Buildable設置為true,表示可以構建;

NetworkType設置為枚舉值esriNetworkDatasetType.esriNDTGeodatabase,表示是基於數據庫的網絡數據集;

Extent和SpatialReference屬性表示網絡數據集的地理外接矩形和空間參考系,可以從傳入的要素數據集的父級接口IGeoDataset中獲取。

Name表示網絡數據集的名稱,由傳入參數給定。

完整的方法如下:

/// <summary>
/// 創建IDENetworkDataset(數據元素網絡數據集)對象
/// </summary>
/// <param name="featureDataset">傳入:要素數據集</param>
/// <param name="NetworkName">傳入:網絡數據集名稱</param>
/// <returns>返回:數據元素網絡數據集</returns>
public IDENetworkDataset CreateDENetworkDataset(IFeatureDataset featureDataset, string NetworkName)
{
    //判斷傳入參數是否為空
    if (string.IsNullOrEmpty(NetworkName) || null == featureDataset)
    {
        return null;
    }

    // 若傳入參數不為空,實例化數據元素網絡數據集對象
    IDENetworkDataset deNetworkDataset = new DENetworkDatasetClass();
    // 設置數據集類型、可以被構建
    deNetworkDataset.Buildable = true;
    deNetworkDataset.NetworkType = esriNetworkDatasetType.esriNDTGeodatabase;

    // 設置數據集的空間參考、空間范圍
    IDEGeoDataset deGeoDataset = deNetworkDataset as IDEGeoDataset;
    IGeoDataset geoDataset = featureDataset as IGeoDataset;
    deGeoDataset.Extent = geoDataset.Extent;
    deGeoDataset.SpatialReference = geoDataset.SpatialReference;

    // 設置名稱
    IDataElement dataElement = deNetworkDataset as IDataElement;
    dataElement.Name = NetworkName;

    return deNetworkDataset;
}
創建IDENetworkDataset(數據元素網絡數據集)對象

可以直接封裝在一個類里。

2.3 添加Sources屬性(網絡數據源)——添加邊線與轉彎

涉及到的接口:INetworkSource、IEdgeFeatureSource、IJunctionFeatureSource、ITurnFeatureSource、IArray

涉及到的類:EdgeFeatureSourceClass、JunctionFeatureSourceClass、TurnFeatureSourceClass、ArrayClass

還記得桌面端如何設置網絡數據集的數據源嗎?

就勾選點、線、轉彎要素即可。

這里對應的EdgeFeatureSourceClass、JunctionFeatureSourceClass、TurnFeatureSourceClass,以及他們的接口,就是他們的編程中的類。

畫一張類圖吧:

通過實例化不同的INetworkSource對象,設置其連通性和名稱,再添加到IArray容器中,就可以給IDENetworkDataset的Sources屬性賦值啦!

看代碼:

#region 邊源創建
//創建邊源
INetworkSource edgeNetworkSource = new EdgeFeatureSourceClass();
edgeNetworkSource.Name = "Streets";//就是添加到網絡數據集的要素類的名稱
edgeNetworkSource.ElementType = esriNetworkElementType.esriNETEdge;
//設置邊源的連通性組
IEdgeFeatureSource edgeFeatureSource = edgeNetworkSource as IEdgeFeatureSource;
// 不使用子類
edgeFeatureSource .UsesSubtypes = false;
// 連通性組:只有1組
edgeFeatureSource .ClassConnectivityGroup = 1;
// 連通性設置為:任意節點
edgeFeatureSource .ClassConnectivityPolicy = esriNetworkEdgeConnectivityPolicy.esriNECPAnyVertex;
#endregion

#region 邊源的方向

IStreetNameFields streetNameFields = new StreetNameFieldsClass();
streetNameFields.Priority = 1;
streetNameFields.StreetNameFieldName = "FULL_NAME";

INetworkSourceDirections nsDirections = new NetworkSourceDirectionsClass();
IArray nsdArray = new ArrayClass();
nsdArray.Add(streetNameFields);
nsDirections.StreetNameFields = nsdArray;
edgeNetworkSource.NetworkSourceDirections = nsDirections;

deNetworkDataset.SupportsTurns = true;

#endregion

#region 轉彎源創建

INetworkSource turnNetworkSource = new TurnFeatureSourceClass();
turnNetworkSource.Name = "ParisTurns";//就是添加到網絡數據集的要素類的名稱
turnNetworkSource.ElementType = esriNetworkElementType.esriNETTurn;

#endregion

#region 添加到IArray中
IArray sourceArray = new ArrayClass();
sourceArray.Add(edgeNetworkSource);
sourceArray.Add(turnNetworkSource);
#endregion
邊源與轉彎源創建與添加

可以包裝成一個或者兩個方法,傳入參數即為網絡數據集創建的所在要素數據集中的要素類的名稱(string)。

返回一個IArray對象,此IArray對象即可賦值給IDENetworkDataset.Sources屬性。

2.4 添加Attributes屬性(網絡屬性)——以長度或時間為單位的屬性為例(成本屬性)

涉及的接口:INetworkAttribute3、IEvaluatedNetworkAttribute

涉及的類:NetworkAttributeClass、EvaluatedNetworkAttributeClass、NetworkConstantEvaluatorClass、NetworkFieldEvaluatorClass、NetworkScriptEvaluatorClass

這一步比較復雜。回憶一下在桌面軟件中是如何設置網絡屬性的?

對,要添加一個網絡屬性,要設置其類型(成本、限制等),要設置其單位,要設置各個要素給網絡屬性的賦值(字段、腳本等),十分復雜。

在這里,網絡屬性是INetworkAttribute3接口的變量,而網絡屬性的具體數據則由IEvaluatedNetworkAttribute去組織和存放,后者,叫作數據組織器。

這對接口的作用頗似INetworkDataset和IDENetworkDataset。

來看類圖:

將IEdgeNetworkSourceClass(即網絡邊源)和字段賦值器、常量賦值器賦予給網絡屬性賦值器的Evaluator和DefaultEvaluator兩個屬性(圖中藍色方框),由於EvaluatedNetworkAttributeClass實現了兩個接口,而這兩個屬性是這個類中IEvaluatedNetworkAttribute接口的一個屬性,所以將EvaluatedNetworkAttributeClass對象添加至IArray接口的對象中,即可對IDENetworkDataset的Attributes屬性進行賦值。

那么有人會想問了,什么是字段賦值器呢?什么是常量賦值器?什么是字段賦值器?

在10.4中,原本“賦值器”就被翻譯成了“評估者(Evaluator)”。其實就是賦值器(EvaluatedNetworkAttributeClass)。

在這里,作為長度屬性,它的評估者(賦值器),指定了“道路數據集”這個邊源(IEdgeNetworkSource)后,類型(=INetworkFieldEvaluator、INetworkConstantEvaluator)就可以是“字段”、“常量”等。其值就由具體的賦值器的類的SetExpression方法決定。

見代碼:

//網絡屬性:Meters
//  網絡屬性類型:成本
//  網絡屬性數據類型:Double(雙精度)
//  網絡屬性單位:米
//  默認啟用:否
//  網絡數據源賦值器:
//     數據源Streets:字段 -[Meters]
//     數據源Streets:字段 -[Meters]
//  默認網絡屬性值:
//     默認邊:常量-0
//     默認交點:常量-0
//     默認轉彎:常量-0

IArray attributeArray = new ArrayClass();

// 實例化一個網絡屬性賦值器,並轉化為INetworkAttribute2身份
// 並設置網絡屬性名稱、網絡屬性類型、網絡數據類型、網絡屬性單位和是否默認啟用
IEvaluatedNetworkAttribute metersAttribute = new EvaluatedNetworkAttributeClass ();
INetworkAttribute2 metersNetworkAttribute2 = (INetworkAttribute2) metersAttribute;
metersNetworkAttribute2.Name = "Meters";
metersNetworkAttribute2.UsageType = esriNetworkAttributeUsageType.esriNAUTCost;
metersNetworkAttribute2.DataType = esriNetworkAttributeDataType.esriNADTDouble;
metersNetworkAttribute2.Units = esriNetworkAttributeUnits.esriNAUMeters;
metersNetworkAttribute2.UseByDefault = false;

// 創建一個字段賦值器,將其身份轉化為INetworkEvaluator,將傳入的網絡邊源進行屬性賦值
INetworkFieldEvaluator metersNetworkFieldEvaluator = new NetworkFieldEvaluatorClass();
INetworkEvaluator metersNetworkEvaluator = (INetworkEvaluator) metersNetworkFieldEvaluator;
metersNetworkFieldEvaluator.SetExpression("[Meters]", "");
metersAttribute.set_Evaluator(edgeNetworkSource, esriNetworkEdgeDirection.esriNEDAlongDigitized, etersNetworkEvaluator);
metersAttribute.set_Evaluator(edgeNetworkSource, esriNetworkEdgeDirection.esriNEDAgainstDigitized, metersNetworkEvaluator);

// 創建一個常量字段賦值器,將其身份轉化為INetworkEvaluator,將網絡屬性的默認值給定
INetworkConstantEvaluator metersNetworkConstantEvaluator = new NetworkConstantEvaluatorClass();
INetworkEvaluator metersConstantNetworkEvaluator = (INetworkEvaluator)metersNetworkConstantEvaluator;
metersNetworkConstantEvaluator.ConstantValue = 0;
metersAttribute.set_DefaultEvaluator(esriNetworkElementType.esriNETEdge, metersConstantNetworkEvaluator);
metersAttribute.set_DefaultEvaluator(esriNetworkElementType.esriNETJunction, metersConstantNetworkEvaluator);
metersAttribute.set_DefaultEvaluator(esriNetworkElementType.esriNETTurn, metersConstantNetworkEvaluator);

// 將IEvaluatedNetworkAttribute對象添加到IArray對象中,完成網絡屬性的添加
attributeArray.Add(metersAttribute);
成本類型-長度屬性
// 網絡屬性Minutes:
// 屬性類型:成本
// 屬性數據類型:雙精度(double)
// 屬性單位:分鍾
// 是否默認啟用:是
// 網絡數據源屬性賦值器:
//     網絡數據源Streets(From-To):字段 - [FT_Minutes]
//     網絡數據源Streets(To-From):字段 - [FT_Minutes]
// 默認網絡屬性值:
//     邊的默認值:常量 - 0;
//     交匯點的默認值:常量 - 0;
//     轉彎的默認值:常量 - 0;

// 創建一個網絡屬性賦值器,並轉化為網絡屬性接口,設置其名稱、網絡屬性類型、網絡數據類型、單位、默認是否啟用
IEvaluatedNetworkAttribute minutesAttribute = new EvaluatedNetworkAttributeClass();
INetworkAttribute2 minutesNetworkAttribute2 = (INetworkAttribute2) minutesAttribute;
                   minutesNetworkAttribute2.Name = "Minutes";
                   minutesNetworkAttribute2.UsageType = esriNetworkAttributeUsageType.esriNAUTCost;
                   minutesNetworkAttribute2.DataType = esriNetworkAttributeDataType.esriNADTDouble;
                   minutesNetworkAttribute2.Units = esriNetworkAttributeUnits.esriNAUMinutes;
                   minutesNetworkAttribute2.UseByDefault = true;

// 創建網絡字段賦值器,並轉化為網絡賦值器,前者賦值表達式,后者給邊源賦予網絡字段賦值器
INetworkFieldEvaluator ftMinutesNetworkFieldEvaluator = new NetworkFieldEvaluatorClass();
INetworkFieldEvaluator tfMinutesNetworkFieldEvaluator = new NetworkFieldEvaluatorClass();
                       ftMinutesNetworkFieldEvaluator.SetExpression("[FT_Minutes]", "");
                       tfMinutesNetworkFieldEvaluator.SetExpression("[TF_Minutes]", "");
INetworkEvaluator ftMinutesNetworkEvaluator = (INetworkEvaluator) ftMinutesNetworkFieldEvaluator;
INetworkEvaluator tfMinutesNetworkEvaluator = (INetworkEvaluator) tfMinutesNetworkFieldEvaluator;
minutesAttribute.set_Evaluator(edgeNetworkSource, esriNetworkEdgeDirection.esriNEDAlongDigitized, ftMinutesNetworkEvaluator);
minutesAttribute.set_Evaluator(edgeNetworkSource, esriNetworkEdgeDirection.esriNEDAgainstDigitized, tfMinutesNetworkEvaluator);

// 創建網絡常量賦值器,並轉化為網絡賦值器,前者給默認值這個屬性賦予默認值,后者給邊源賦予默認值
INetworkConstantEvaluator minutesNetworkConstantEvaluator = new NetworkConstantEvaluatorClass();
                          minutesNetworkConstantEvaluator.ConstantValue = 0;
INetworkEvaluator minutesConstantNetworkEvaluator = (INetworkEvaluator) minutesNetworkConstantEvaluator;
minutesAttribute.set_DefaultEvaluator(esriNetworkElementType.esriNETEdge, minutesConstantNetworkEvaluator);
minutesAttribute.set_DefaultEvaluator(esriNetworkElementType.esriNETJunction, minutesConstantNetworkEvaluator);
minutesAttribute.set_DefaultEvaluator(esriNetworkElementType.esriNETTurn, minutesConstantNetworkEvaluator);

// 添加網絡屬性到IArray對象中
attributeArray.Add(minutesAttribute);
成本類型-時間屬性

兩段代碼均可包裝成C#的方法,參數可以傳遞需要賦值的字段名(string)、網絡邊源等,等下一篇博客將重點進行代碼梳理。

兩段代碼的最后一步,均為添加IEvaluatedNetworkAttribute的對象到IArray數組中,而這個IArray數組正是IDENetworkDataset.Attributes所需的。

2.5 設置Directions屬性(導航或方向)

涉及到的接口:INetworkDirections

涉及到的類:NetworkDirectionsClass

導航就比較容易了,導航需要的是:一個網絡邊源(其要素類必須有一個文本類型的字段),一個成本類型單位為長度類型的網絡屬性。

直接看代碼,這個沒什么問題:

/// <summary>
///  指定網絡數據集的導航屬性
/// </summary>
/// <param name="deNetworkDataset">數據元素網絡數據集</param>
/// <param name="UnitsType">單位類型</param>
/// <param name="LengthAttribute"> 創建的長度屬性的名稱</param>
/// <param name="TimeAttribute"> 創建的時間屬性名稱,可空</param>
/// <param name="RoadClassAttribute">創建的道路類型屬性名稱,可空</param>
public void SetNetworkDirction(IDENetworkDataset deNetworkDataset, esriNetworkAttributeUnits UnitsType, string LengthAttribute, string TimeAttribute, string RoadClassAttribute)
{
    // 創建INetworkDirections對象
    INetworkDirections networkDirections = new NetworkDirectionsClass();
    networkDirections.DefaultOutputLengthUnits = UnitsType;

    //設置長度屬性
    if (!string.IsNullOrEmpty(LengthAttribute))
    {
        networkDirections.LengthAttributeName = LengthAttribute;
    }
    //設置時間屬性
    if (!string.IsNullOrEmpty(TimeAttribute))
    {
        networkDirections.TimeAttributeName = TimeAttribute;
    }
    //設置道路類型屬性
    if (!string.IsNullOrEmpty(RoadClassAttribute))
    {
        networkDirections.RoadClassAttributeName = RoadClassAttribute;
    }
    // 設置網絡數據集的方向屬性
    deNetworkDataset.Directions = networkDirections;
}

這一步對應桌面創建網絡數據集的這一步:

2.6 創建並構建INetworkDataset對象(大功告成!)

只能通過IDatasetContainer.CreateDataset()方法創建,傳入的參數是IDEDataset類型的變量,返回的是IDataset對象。

這一步,也是最后的一步,將數據集合(DENetworkDataset)轉化為分析對象(NetworkDataset)。

當然別忘了構建一下~

直接上代碼:

創建並構建網絡數據集

創建成功的結果如下:

我傳的網絡數據集名稱為STH_ND,結果就如上圖咯。

3. 流程圖

這是我做過最復雜的AO開發了,涉及到的類和接口實在太龐大...趁年輕多搞搞,提升一下邏輯組織能力。

在后階段的整合中,我會給出一個實例,就用本篇的各種方法,包裝成一個工具類,並完整地對比桌面創建網絡數據集做一個demo。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM