当前位置: 首页 > news >正文

arcgis gp 选择图层_ArcGIS Engine实现图层间空间选择的优化策略

转自:https://github.com/xinying180/QueryByLayer

如果您是ArcGIS Engine开发人员,也许会有这样的困惑:为什么对两个要素图层进行空间选择,ArcMap中瞬间就出结果了,而Engine中则慢很多倍,尤其是当数据量大时,该速率甚至无法忍受。图层间如何实现高效的空间选择呢?相信阅读完下面的文章,答案会迎刃而解。

下面就带着问题来开始今天的讨论吧。

问题:

假如有一个居民点数据和一个建筑物数据,想要知道哪些居民点被建筑物所覆盖,如何实现?

答案:

ArcMap中如何实现?

ArcMap中实现此功能很简单,即使用菜单条上的Select By Location或者Select Layer By Location工具,数据(点要素类中含有600个点,面要素类中含有750个面)和结果如下图所示。

3645cc7ddd11fc7823330e8b5ba9b0d1.png

用时:0.06秒

ArcGIS Engine中如何实现呢?

ArcGIS Engine中(相信很多用户是不太喜欢直接调用GP工具的)如何实现该功能呢?一般情况下会考虑使用ISpatialFilter结合遍历面要素来实现:

ISpatialFilter可以进行空间查询和属性查询。其Geometry属性传入要查询的几何,仅可使用high-level geometry(如polygon、polyline、points、multipoints)、envelope和geometry bags,这里使用面要素的geometry;其GeometryField属性用于指定过滤所使用的几何字段,这里使用点要素类的几何字段pointFeatureClass.ShapeFieldName;其SpatialRel属性用于指定空间关系,公式为[query_geometry] [spatial_relationship] [feature],这里的query_geometry为面,feature为点要素,空间关系就应该是包含,所以应该使用esriSpatialRelContains(注意与ArcMap中有所区别,ArcMap中需设置空间关系为CompletelyWithin)。SubFields可以指定查询后返回的属性字段,以逗号分隔。如果不设置的话会默认为“*”,即返回所有字段。如果需要获取要素属性值得话,最好设置该字段,可以提高性能。当然如果不获取属性的话,那这个字段可设可不设,比如选择要素。此外,如果还想同时进行属性查询,直接设置WhereClause语句即可。主要代码:

//从MapControl中获取的点图层

IFeatureLayer pointFeatureLayer = axMapControl1.get_Layer(0) as IFeatureLayer;

IFeatureSelection pointFeatureSelection = pointFeatureLayer as IFeatureSelection;

//从MapControl中获取的面图层

IFeatureLayer polygonFeatureLayer = axMapControl1.get_Layer(1) as IFeatureLayer;

//循环遍历面要素类内部的面,逐一进行查询

IQueryFilter queryFilter = new QueryFilterClass();

//Search如果返回属性值的话设置SubFields会提高效率

queryFilter.SubFields = "Shape";

IFeatureCursor cursor = polygonFeatureLayer.Search(queryFilter, true);

IFeature polygonFeature = null;

while ((polygonFeature = cursor.NextFeature()) != null)

{

IGeometry queryGeometry = polygonFeature.Shape;

//构建空间查询

ISpatialFilter spatialFilter = new SpatialFilterClass();

spatialFilter.Geometry = queryGeometry;

spatialFilter.GeometryField = pointFeatureLayer.FeatureClass.ShapeFieldName;

spatialFilter.SpatialRel = esriSpatialRelEnum.esriSpatialRelContains; pointFeatureSelection.SelectFeatures(spatialFilter as IQueryFilter, esriSelectionResultEnum.esriSelectionResultAdd, false);

}

//释放游标

System.Runtime.InteropServices.Marshal.FinalReleaseComObject(cursor);

用时:1.45秒

怎么和ArcMap中效率差这么多啊,别急,下面就来看优化方法。

优化1:创建空间缓存

使用ISpatialCacheManager接口对要素类创建空间缓存,然后使用上面的方法遍历选择。如果对同一个范围进行多次空间查询的话,先构建空间缓存会提升效率,因为其降低了数据库的访问次数,比如下面场景,当然也很适用于我们的问题。

0c4085e6fe1efaedc4d19074cabf8671.png

使用方法就是打开进行查询的要素类,为该范围创建空间缓存,执行查询,最后释放缓存。主要代码:

//填充Spatial Cache

ISpatialCacheManager spatialCacheManager = (ISpatialCacheManager)(pointFeatureLayer as IDataset).Workspace;

IEnvelope cacheExtent = (pointFeatureLayer as IGeoDataset).Extent;

//检测是否存在缓存

if (!spatialCacheManager.CacheIsFull)

{

//不过不存在,则创建缓存

spatialCacheManager.FillCache(cacheExtent);

}

//执行空间查询操作,与上文一样

...

//清空空间缓存

spatialCacheManager.EmptyCache();

用时:0.45秒

可见,创建空间缓存后效率有所提升,但与ArcMap中调用GP相比,效率还差了几乎一个数量级。怎么办?

细心的你也许会发现上述方法之所以慢,是因为执行了多次SelectFeatures方法,如果只执行一次,肯定会快很多。而我们开始介绍ISpatialFilter的Geometry属性时提到过,Geometry可以传入GeometryBag,那么GeometryBag是什么呢?GeometryBag是Geometry的集合,可以往里添加N个Geometry,好吧,既然GeometryBag是个集合,那我们就可以把遍历的面都添加进去,这样就可以只执行一次SelectFeatures,很显然可以提高效率。不过使用GeometryBag时有一点需要注意:必须为其设置空间参考,因为添加Geometry(即使原本有空间参考)到GeometryBag中时会丢失空间参考。此外,如果为该GeometryBag创建空间索引会提高效率。主要代码:

//构建GeometryBag

IGeometryBag geometryBag = new GeometryBagClass();

IGeometryCollection geometryCollection = (IGeometryCollection)geometryBag;

IGeoDataset geoDataset = (IGeoDataset)polygonFeatureLayer;

ISpatialReference spatialReference = geoDataset.SpatialReference;

//一定要给GeometryBag赋空间参考

geometryBag.SpatialReference = spatialReference;

IQueryFilter queryFilter = new QueryFilterClass();

//Search如果返回属性值的话设置SubFields会提高效率

queryFilter.SubFields = "Shape";

//遍历面要素类,逐一获取Geometry并添加到GeometryBag中

IFeatureCursor cursor = polygonFeatureLayer.Search(queryFilter, true);

IFeature polygonFeature = null;

while ((polygonFeature = cursor.NextFeature()) != null)

{

geometryCollection.AddGeometry(polygonFeature.ShapeCopy);

}

//为GeometryBag生成空间索引,以提高效率

ISpatialIndex spatialIndex = (ISpatialIndex)geometryBag;

spatialIndex.AllowIndexing = true;

spatialIndex.Invalidate();

//构建空间查询

ISpatialFilter spatialFilter = new SpatialFilterClass();

spatialFilter.Geometry = geometryBag;

spatialFilter.GeometryField = pointFeatureLayer.FeatureClass.ShapeFieldName;

spatialFilter.SpatialRel = esriSpatialRelEnum.esriSpatialRelContains;

//选择的话可以不设置SubFields

pointFeatureSelection.SelectFeatures(spatialFilter as IQueryFilter, esriSelectionResultEnum.esriSelectionResultAdd, false);

用时:0.045秒

喜大普奔!该方法居然比ArcMap中直接调用GP还要快?!可是我觉得代码稍显复杂,有没有更简化而且高效的方法呢?(居然还想要自行车…)

IQueryByLayer接口就是用来进行图层间空间选择的!!!其FromLayer属性是指对哪个图层进行选择,这里即为点图层;其ByLayer属性是指查询几何所在的图层,即面图层;其LayerSelectionMethod就是两个图层间的空间关系,这里是esriLayerSelectCompletelyWithin(细心的同学注意到了吧,空间关系和ArcMap中使用的一模一样,ArcMap甚有可能就是用的该接口);此外还有一个UseSelectedFeatures属性很重要,我开始没有设置,结果导致程序一直报下面的错误:

bd250c128aaa23f46b5fc5a6b34c4ed5.png

该属性是说ByLayer中是否进行了选择,如果面图层中没有选中要素的话,一定要设置为该属性为false,如果设为true或者不设置都会报这个错。但是,如果面图层中进行了选中,想用选中的面进行空间查询,就要将其设为true了,如果设为false是按整个面要素类进行查询的,如果不设置是按选中的面进行查询的,所以我认为该属性的默认值为true,但AO帮助中并没有说明。主要代码:

//从MapControl中获取的点图层

IFeatureLayer pointFeatureLayer = axMapControl1.get_Layer(0) as IFeatureLayer;

IFeatureSelection pointFeatureSelection = pointFeatureLayer as IFeatureSelection;

//从MapControl中获取的面图层

IFeatureLayer polygonFeatureLayer = axMapControl1.get_Layer(1) as IFeatureLayer;

//构建QueryByLayer

IQueryByLayer queryByLayer = new QueryByLayerClass();

queryByLayer.FromLayer = pointFeatureLayer;

queryByLayer.ByLayer = polygonFeatureLayer;

queryByLayer.LayerSelectionMethod = esriLayerSelectionMethod.esriLayerSelectCompletelyWithin;

//该参数需要设置

queryByLayer.UseSelectedFeatures = false;

ISelectionSet selectionSet = queryByLayer.Select();

pointFeatureSelection.SelectionSet = selectionSet;

axMapControl1.Refresh();

用时:0.038秒

这种方法的代码比上面那种简单的多,而且用时也更少,这就是我认为既简单又高效的方法。由上可见,ArcGIS Engine中进行图层间的空间选择,方法使用正确了,确实会与ArcMap效率相当,甚至还要更快哦!

总结一下:

本文仅以图层间的空间选择为例进行了优化,其实在进行空间查询时也可以采用文中的思想,比如:

1, 对同一区域进行多次查询时可以使用ISpatialCacheManager创建空间缓存; 2, 要使用多个geometry进行空间查询时,使用GeometryBag会提高效率; 3, 图层间的查询也是可以转化为空间选择的,使用IQueryByLayer接口获取ISelectionSet,进而获取到所有的要素; 4, 多次使用IRelationalOperator或者ITopologicalOperator接口进行空间关系的判断时也可以使用GeometryBag,但具体需要看所使用的方法是否支持GeometryBag。

Demo

使用ArcGIS Engine 10.5,Visual Studio 2015编写,创建了MapControlApplication模版工程,然后添加菜单栏,分别使用了上面提到的方法进行测试。界面为:

d4c960cf029ed0dba377428ea0df39c7.png

*Tips:*测试时是直接加载的已有mxd,然后获取的图层,如果直接从数据源获取要素类,然后创建图层,再查询会相对慢些。

工程下载地址:

http://download.csdn.net/detail/dreamgis/9817708

相关文章:

  • mysql 8安装 windows xp_Windows XP下安装和配置Apache2.2.22服务器+PHP5+Mysql5
  • python怎么强制转换_Python如何实现强制数据类型转换
  • 正向生成数据库mysql_数据库表反向生成 Django ORM inspectdb
  • java 泛型定义_Java中泛型定义的含义
  • 字符串转数组java_java数组与字符串相互转换、整型与字符串相互转换【详解】...
  • 简单描述mysql视图的概念_介绍mysql中视图的概念及操作
  • java web 与asp.net_JavaWeb与Asp.net工作原理比较分析
  • java 对象序列化磁盘_java对象的序列化以及反序列化详解
  • java --help_java help
  • java linux 接口_理解Java中的接口
  • java dns 缓存_Java DNS解析缓存的过期策略配置
  • java 二叉树图形_java实现二叉树以及实例
  • java tree的使用_Java TreeSet的使用
  • java矩形_JAVA实现矩形(长方形)的周长面积计算
  • phymeleaf 除取整_【Bug档案01】Spring Boot的控制器+thymeleaf模板 -使用中出现静态资源加载路径不当的问题 -解决时间:3h...
  • 「前端」从UglifyJSPlugin强制开启css压缩探究webpack插件运行机制
  • Apache Spark Streaming 使用实例
  • ECMAScript入门(七)--Module语法
  • Java读取Properties文件的六种方法
  • JDK9: 集成 Jshell 和 Maven 项目.
  • Js基础——数据类型之Null和Undefined
  • PAT A1050
  • Redis中的lru算法实现
  • v-if和v-for连用出现的问题
  • vue从创建到完整的饿了么(18)购物车详细信息的展示与删除
  • weex踩坑之旅第一弹 ~ 搭建具有入口文件的weex脚手架
  • 短视频宝贝=慢?阿里巴巴工程师这样秒开短视频
  • 关于字符编码你应该知道的事情
  • 前端技术周刊 2019-02-11 Serverless
  • 日剧·日综资源集合(建议收藏)
  • 设计模式走一遍---观察者模式
  • 使用Envoy 作Sidecar Proxy的微服务模式-4.Prometheus的指标收集
  • 无服务器化是企业 IT 架构的未来吗?
  • Spark2.4.0源码分析之WorldCount 默认shuffling并行度为200(九) ...
  • ​​​​​​​​​​​​​​汽车网络信息安全分析方法论
  • ​configparser --- 配置文件解析器​
  • ​linux启动进程的方式
  • (2)(2.4) TerraRanger Tower/Tower EVO(360度)
  • (4)(4.6) Triducer
  • (windows2012共享文件夹和防火墙设置
  • (zhuan) 一些RL的文献(及笔记)
  • (阿里云万网)-域名注册购买实名流程
  • (附源码)计算机毕业设计ssm高校《大学语文》课程作业在线管理系统
  • (附源码)计算机毕业设计SSM教师教学质量评价系统
  • (七)Java对象在Hibernate持久化层的状态
  • (十二)python网络爬虫(理论+实战)——实战:使用BeautfulSoup解析baidu热搜新闻数据
  • .java 9 找不到符号_java找不到符号
  • .NET Core 项目指定SDK版本
  • .NET Framework 的 bug?try-catch-when 中如果 when 语句抛出异常,程序将彻底崩溃
  • .NET Micro Framework初体验(二)
  • .NET 中创建支持集合初始化器的类型
  • /dev/VolGroup00/LogVol00:unexpected inconsistency;run fsck manually
  • /etc/sudoers (root权限管理)
  • [android学习笔记]学习jni编程
  • [AUTOSAR][诊断管理][ECU][$37] 请求退出传输。终止数据传输的(上传/下载)