ArcEngine空間查詢優化
阿新 • • 發佈:2018-12-06
開發環境: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介面。