ArcGIS Engine中的视图(IActiveView)控制着主程序窗口,二维中的常用视图有Map(数据视图)和PageLayout(布局视图)。IActiveView.ScreenDisplay属性即IScreenDisplay接口用来控制屏幕上图形的显示。ScreenDisplay允许用户创建任意数量的缓存,图像不是直接绘制在屏幕上的,而是先绘制在缓存中,然后再将缓存绘制到屏幕上。当程序窗口需要重绘时,不是直接从数据库中获取数据,而是从缓存中获取,从而提高绘制的性能。
通常情况下,Map对象有三个缓存:一是为所有图层生成一个缓存;二是如果Map中存在注记和Graphics的话,为其生成一个缓存;三是如果Map中有要素选择集,也会为其生成一个缓存。不过单个图层也可以创建其专属的缓存,这时Map将为该图层创建一个独立的缓存,而其余的所有图层则放在一个缓存里。接下来就看一下ArcGIS Engine中的刷新方法,以Map为例。
全局刷新,即重绘地图中的所有内容,是效率最低的一种刷新方法。当数据量大时非常耗时。所以除非绝对必要,一般推荐使用IActiveView.PartialRefresh方法。当然如果是涉及全部显示范围的更新就需要使用Refresh,比如平移、缩放、全图等操作。
部分刷新,可以人为指定重绘地图中的部分内容,该方法效率高,推荐使用。下表说明了部分刷新的参数以及Map或PageLayout中刷新的内容:
刷新所有图层使用:
activeView.PartialRefresh(esriViewGeography, null, null);
刷新单个图层使用:
activeView.PartialRefresh(esriViewDrawPhase.esriViewGeography, layer,null);
刷新单个图层中的某个区域使用:
activeView.PartialRefresh(esriViewDrawPhase.esriViewGeography, layer, envelope);
刷新图层中的选中要素使用:
activeView.PartialRefresh(esriViewDrawPhase.esriViewGeoSelection, null, null);
Tips: 测试只执行一次刷新即可,而ArcObjects帮助中说需要调用两次,一次在选择前,一次在选择后。
刷新整个Element图层或者label使用:
activeView.PartialRefresh(esriViewDrawPhase.esriViewGraphics, null, null);
刷新一个Element使用:
activeView.PartialRefresh(esriViewDrawPhase.esriViewGraphics, element, null);
刷新选中的Element使用:
activeView.PartialRefresh(esriViewDrawPhase.esriViewGraphicSelection, null, null);
Invalidate方法允许刷新显示中的指定区域,该方法不推荐用户使用,因为需要手动控制绘图缓存,对用户来说该方法不是最优的,推荐使用PartialRefresh。使用方法可以参考ArcObjects帮助:How to add display caching
此外,当地图刷新时会触发IActiveViewEvents.AfterDraw事件,其esriViewDrawPhase参数会返回当前的DrawPhase,其绘图阶段先后依次是esriViewInitialized、esriViewBackground、esriViewGeography、esriViewGraphics、esriViewGeoSelection、esriViewForeground,通过刷新阶段的先后顺序可以实现自定义功能。
坐标转换主要使用IDisplayTransformation接口,可以通过IScreenDisplay. DisplayTransformation属性获取。
1, 屏幕坐标转为地理坐标
public IPoint GetMapCoordinatesFromScreenCoordinates(IPoint screenPoint, IActiveView activeView)
{
if (screenPoint == null || screenPoint.IsEmpty || activeView == null)
{
return null;
}
IScreenDisplay screenDisplay = activeView.ScreenDisplay;
IDisplayTransformation displayTransformation = screenDisplay.DisplayTransformation;
return displayTransformation.ToMapPoint((System.Int32)screenPoint.X, (System.Int32)screenPoint.Y);
}
2, 地理坐标转为屏幕坐标
public IPoint GetScreenCoordinatesFromMapCoorindates(IPoint mapPoint, IActiveView activeView)
{
if (mapPoint == null || mapPoint.IsEmpty || activeView == null)
{
return null;
}
IScreenDisplay screenDisplay = activeView.ScreenDisplay;
IDisplayTransformation displayTransformation = screenDisplay.DisplayTransformation;
System.Int32 x;
System.Int32 y;
displayTransformation.FromMapPoint(mapPoint, out x, out y);
IPoint returnPoint = new PointClass();
returnPoint.PutCoords(x, y);
return returnPoint;
}
相较而言,PageLayout中页面坐标与地理坐标的转换就复杂一些,需要获取屏幕坐标作为中间变量:
1, 页面坐标到地理坐标的转换分两步:
(1)将IPageLayout转为IActiveView,IActiveView.ScreenDisplay.DisplayTransformation.FromMapPoint(); 将页面坐标转为屏幕坐标;
(2)将FocusMap转为IActiveView,IActiveView.ScreenDisplay.DisplayTransformation.ToMapPoint(); 将屏幕坐标转为地理坐标。
2, 地理坐标转换为页面坐标也是分两步:
(1)将FocusMap转为IActiveView,IActiveView.ScreenDisplay.DisplayTransformation.FromMapPoint();将地理坐标转为屏幕坐标;
(2)将IPageLayout转为IActiveView,IActiveView.ScreenDisplay.DisplayTransformation.ToMapPoint();将屏幕坐标转为页面坐标。
此外,其IDisplayTransformation.FromPoints方法可以将point(1/72 inch) distance转为map distance;IDisplayTransformation.ToPoints方法可以将map distance转为point distance。