• 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。

  • 相关阅读:
    Spring编译AOP项目报错
    Intellij新建Spring项目引入用户目录下的Spring jar包
    python如何安装第三方库
    sizeof and strlen整理
    数轴上从左到右有n个点a[0],a[1]…,a[n-1],给定一根长度为L的绳子,求绳子最多能覆盖其中的几个点。要求算法复杂度为o(n)。
    百度笔试题--最长回文字串
    微软笔试题
    人群智商差不多,是什么引起了差距?
    低层次“努力学习”和学习的本质
    集成 solr6.5.1到 tomcat7(8) 中 (解决java.lang.NoSuchMethodError问题)
  • 原文地址:https://www.cnblogs.com/onsummer/p/6998121.html
Copyright © 2020-2023  润新知