ArcEngine空间查询优化


开发环境:VS2013 + ArcEngine 10.4
开发背景:有两个图层,一个点图层,一个线图层,现在需要查询与线相交的点有哪些~大多数书上的方法如下:

        public void Method_A(IFeatureLayer pSourceFeatureLayer, IFeatureLayer pTargetFeatureLayer)
        {
            IQueryFilter pQueryFilter = new QueryFilter();
            pQueryFilter.AddField("Shape");

            // 源图层
            IFeatureClass pSourceFeatureClass = pSourceFeatureLayer.FeatureClass;
            IFeatureCursor pSourceFeatureCursor = pSourceFeatureClass.Search(pQueryFilter, true);
            IFeature pSourceFeature = pSourceFeatureCursor.NextFeature();
            if (pSourceFeature == null)
            {
                return;
            }

            // 目标图层
            IFeatureSelection pTargetFeatureSelection = pTargetFeatureLayer as IFeatureSelection;
            ISpatialFilter pSpatialFilter = new SpatialFilter();
            while (pSourceFeature != null)
            {
                pSpatialFilter.Geometry = pSourceFeature.ShapeCopy;
                pSpatialFilter.SpatialRel = esriSpatialRelEnum.esriSpatialRelIntersects;
                pTargetFeatureSelection.SelectFeatures(pSpatialFilter, esriSelectionResultEnum.esriSelectionResultAdd, false);
                pSourceFeature = pSourceFeatureCursor.NextFeature();
            }
            Marshal.ReleaseComObject(pSourceFeatureCursor);

            // 刷新视图
            axMapControl1.ActiveView.PartialRefresh(esriViewDrawPhase.esriViewGeoSelection, null, null);
        }

20毫秒!!!该方法的缺点:一旦数据量较大时,遍历次数较多,时间效率就会较低。我们可以回想一下,传统关系型数据库怎么优化查询?除了优化SQL,创建索引也是一个较好的方法,在ArcEngne中也同样可以创建空间索引,代码如下:

        public void Method_B(IFeatureLayer pSourceFeatureLayer, IFeatureLayer pTargetFeatureLayer)
        {
            IFeatureClass pSourceFeatureClass = pSourceFeatureLayer.FeatureClass;
            IGeoDataset pGeoDataset = pSourceFeatureClass as IGeoDataset;
            ISpatialReference pSpatialReference = pGeoDataset.SpatialReference;

            // 实体几何
            IGeometryBag pGeometryBag = new GeometryBag() as IGeometryBag;
            pGeometryBag.SpatialReference = pSpatialReference;
            IGeometryCollection pGeometryCollection = pGeometryBag as IGeometryCollection;

            // 要素游标
            IFeatureCursor pSourceFeatureCursor = pSourceFeatureClass.Search(null, true);
            IFeature pSourceFeature = pSourceFeatureCursor.NextFeature();
            if (pSourceFeature == null)
            {
                return;
            }

            // 添加实体
            object missing = Type.Missing;
            while (pSourceFeature != null)
            {
                pGeometryCollection.AddGeometry(pSourceFeature.ShapeCopy, ref missing, ref missing);
                pSourceFeature = pSourceFeatureCursor.NextFeature();
            }
            Marshal.ReleaseComObject(pSourceFeatureCursor);

            // 创建空间索引
            ISpatialIndex pSpatialIndex = pGeometryBag as ISpatialIndex;
            pSpatialIndex.AllowIndexing = true;
            pSpatialIndex.Invalidate();

            // 创建空间过滤器
            ISpatialFilter pSpatialFilter = new SpatialFilter();
            pSpatialFilter.Geometry = pGeometryBag;
            pSpatialFilter.SpatialRel = esriSpatialRelEnum.esriSpatialRelIntersects;

            // 刷新视图
            IFeatureSelection pTargetFeatureSelection = pTargetFeatureLayer as IFeatureSelection;
            pTargetFeatureSelection.SelectFeatures(pSpatialFilter, esriSelectionResultEnum.esriSelectionResultAdd, false);
            axMapControl1.ActiveView.PartialRefresh(esriViewDrawPhase.esriViewGeoSelection, null, null);
        }

15毫秒!!!这种方法已经能够满足大部分需求,但还有没有更快的方法?ArcEngine有一个IQueryByLayer接口,这个接口很有意思,首先贴上代码:

        public void Method_C(IFeatureLayer pSourceFeatureLayer, IFeatureLayer pTargetFeatureLayer)
        {
            IQueryByLayer pQueryByLayer = new QueryByLayer();
            pQueryByLayer.FromLayer = pTargetFeatureLayer;
            pQueryByLayer.ByLayer = pSourceFeatureLayer;
            pQueryByLayer.LayerSelectionMethod = esriLayerSelectionMethod.esriLayerSelectIntersect;
            pQueryByLayer.UseSelectedFeatures = false;

            // 刷新视图
            IFeatureSelection pFeatureSelection = pTargetFeatureLayer as IFeatureSelection;
            ISelectionSet pSelectionSet = pQueryByLayer.Select();
            pFeatureSelection.SelectionSet = pSelectionSet;
            axMapControl1.ActiveView.PartialRefresh(esriViewDrawPhase.esriViewGeoSelection, null, null);
        }

13毫秒!!!对于图层与图层之间的查询,这个方法速度最快~而且大家可以看一下IQueryByLayer的成员:

        // 摘要: 
        //     The type of selection method to be performed.
        [DispId(1610678275)]
        double BufferDistance { set; }
        //
        // 摘要: 
        //     The buffer units.
        [DispId(1610678276)]
        esriUnits BufferUnits { set; }
        //
        // 摘要: 
        //     The layer features will be selected from.
        [DispId(1610678273)]
        IFeatureLayer ByLayer { set; }
        //
        // 摘要: 
        //     Provides access to the methods and properties of QueryByLayer.
        [DispId(1610678272)]
        IFeatureLayer FromLayer { set; }
        //
        // 摘要: 
        //     The input layer that contains features to base the selection on.
        [DispId(1610678274)]
        esriLayerSelectionMethod LayerSelectionMethod { set; }
        //
        // 摘要: 
        //     The result type of the selection where it can be specified that the selection
        //     adds to a current selection etc.
        [DispId(1610678278)]
        esriSelectionResultEnum ResultType { set; }
        //
        // 摘要: 
        //     Indicates whether selected features will be used.
        [DispId(1610678277)]
        bool UseSelectedFeatures { set; }

        // 摘要: 
        //     Selects the features based on the input parameters and returns a selection
        //     set.
        ISelectionSet Select();

我们再来看一下ArcMap中的空间查询界面,如下图:
在这里插入图片描述
我们发现,IQueryByLayer接口中的BuferDistance对应“应用搜索距离”,BufferUnits对应搜索距离的单位,由于ArcGIS Desktop和ArcEngine都是基于ArcObjects,所以Desktop中的空间查询也是基于IQueryByLayer接口。

转载自:https://blog.csdn.net/HerryDong/article/details/82817022

You may also like...