zoukankan      html  css  js  c++  java
  • 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。

  • 相关阅读:
    CF763C Timofey and Remoduling
    CF762E Radio Stations
    CF762D Maximum Path
    CF763B Timofey and Rectangles
    URAL1696 Salary for Robots
    uva10884 Persephone
    LA4273 Post Offices
    SCU3037 Painting the Balls
    poj3375 Network Connection
    Golang zip压缩文件读写操作
  • 原文地址:https://www.cnblogs.com/onsummer/p/6998121.html
Copyright © 2011-2022 走看看