空间查询功能是通过用户选择(绘制)的空间几何体与当前地图中要素之间的几何关系进行空间查找。绘制的空间几何通常包括:点、线、圆形、矩形、多边形等;空间关系通常包括:空间相交、空间相接——共享空间边界、空间覆盖、空间跨越、空间包含于被包含等。ArcGIS Engine进行空间查询的步骤如下:
绘制空间几何体可以通过AxMapControl对象提供的如下图所示方法实现,四个方法返回类型均为IGeometery。
public void OnMouseDown(int button, int shift, double x, double y)
{
if (button != 1 || IsBusing)
{
return;
}
IGeometry pGeometry=axMapControl.TrackCircle();
}
注:若绘制的是点,则需要获取鼠标的点击位置创建点对象IPoint。通常在OnMouseDown事件中通过如下代码进行创建点对象
public void OnMouseDown(int button, int shift, double x, double y)
{
if (button != 1 || IsBusing)
{
return;
}
IPoint pt = new PointClass();
pt.PutCoords(x, y);
}
或者:
public void OnMouseDown(int button, int shift, double x, double y)
{
if (button != 1 || IsBusing)
{
return;
}
IPoint pt = axMapControl1.Activeview.ScreenDisplay.DisplayTransformation.ToMapPoint(x, y);
}
然后将IPoint转换为IGeomtry对象:IGeometry pGeometry=pt as IGeometry;
使用ISpatialFilter进行空间查询时需要对该对象的Geometry和SpatialRel属性进行赋值。Geometry属性的值来至于步骤1中所获取的,SpatialRel是定义查询的空间关系,由枚举esriSpatialRelEnum给出。
IFeatureLayer pFeatureLayer=axMapControl.get_Layer(1) as IFeatureLayer;
IFeatureClass pFeatureClass=pFeatureLayer.FeatureClass;
ISpatialFilter pSpatialFilter = new SpatialFilter();
pSpatialFilter.Geometry = pGeomentry;
//根据被选择要素的不同,设置不同的空间滤过关系
switch (pFeatureClass.ShapeType)
{
case esriGeometryType.esriGeometryPoint://查询的为点类型
pSpatialFilter.SpatialRel = esriSpatialRelEnum.esriSpatialRelContains;//空间包含
break;
case esriGeometryType.esriGeometryPolyline://查询要素类型为线类型时
pSpatialFilter.SpatialRel = esriSpatialRelEnum.esriSpatialRelCrosses;//空间跨越
break;
case esriGeometryType.esriGeometryPolygon://查询要素类型为面类型时
pSpatialFilter.SpatialRel = esriSpatialRelEnum.esriSpatialRelIntersects;//空间相交
break;
}
注:绘制空间几何为点类型时,在对pSpatialFilter的Geometry进行赋值时,并不会将IPoint转换后的IGeometry对象直接赋值给pSpatialFilter,因为在进行包含、相交等空间查询时,鼠标点击的点往往很难选中地图上的某些要素,难以得到预期的空间查询结果。通常的做法是对IPoint创建一个缓冲区,通过设置合适的容差,友好地进行相关空间查询。实现代码如下:
ITopologicalOperator pTOpo = pGeometry as ITopologicalOperator;
double length;
length = MapManager.ConvertPixelsToMapUnits(mActiveView, 10);
IGeometry pBuffer = pTOpo.Buffer(length);
IGeometry pNewGeometry = pBuffer.Envelope;
pSpatialFilter.Geometry=pNewGeometry;
其中ConvertPixelsToMapUnits()方法如下:
public static double ConvertPixelsToMapUnits(IActiveView pActiveView, double pixelUnits)
{
// Uses the ratio of the size of the map in pixels to map units to do the conversion
IPoint p1 = pActiveView.ScreenDisplay.DisplayTransformation.VisibleBounds.UpperLeft;
IPoint p2 = pActiveView.ScreenDisplay.DisplayTransformation.VisibleBounds.UpperRight;
int x1, x2, y1, y2;
//converts a point in map units to device coordinates.
pActiveView.ScreenDisplay.DisplayTransformation.FromMapPoint(p1, out x1, out y1);
pActiveView.ScreenDisplay.DisplayTransformation.FromMapPoint(p2, out x2, out y2);
double pixelExtent = x2 - x1;
double realWorldDisplayExtent = pActiveView.ScreenDisplay.DisplayTransformation.VisibleBounds.Width;
double sizeOfOnePixel = realWorldDisplayExtent / pixelExtent;
return pixelUnits * sizeOfOnePixel;
}
进行空间查询时,有两种方法:
①IFeatureSelection对象下的SelectFeatures()方法,该方法查询到的结果会高亮显示;
IFeatureSelection pFSelection = pFeatureLayer as IFeatureSelection;
//根据空间过滤关系选择要素
pFSelection.SelectFeatures(pSpatialFilter, esriSelectionResultEnum.esriSelectionResultNew, false);
//刷新视图
axMapControl.Activeview.PartialRefresh(esriViewDrawPhase.esriViewGraphicSelection, null, null);
②IFeatureClass对象下的Search()方法,该方法查询到的结果不会高亮显示;
IFeatureCursor pFeatureCursor = pFeatureClass.Search(pSpatialFilter, false);
通过IFeatureCursor接口提供的NextFeature()方法进行遍历。在步骤3的②中直接获取到IFeatureCursor对象,因此可以直接进行遍历;接下来重点看①:SelectFeatures()方法执行后的结果是根据空间关系将符合条件的要素选择出来并高亮显示,也就是说该方法执行后地图选择集中就已经有对象了,然后可已通过地图选择集
ICursor pCursor;
pSelectionset.Search(null, true, out pCursor);
IFeatureCursor pFeatCursor = pCursor as IFeatureCursor;
IFeature pFeature=pFeatCursor.NextFeature();//获取选择集中的第一个要素
while(pFeature!=null)
{
//这里已经获取了要素 然后可以访问要素的空间、属性等信息,然后进行信息可视化等
//代码略
pFeature=pFeatCursor.NextFeature();//获取选择集中的下一个要素
}