前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 ># 如何使用 ArcGIS Engine10.2 + C# VS2012 开发环境,实现鹰眼功能。

# 如何使用 ArcGIS Engine10.2 + C# VS2012 开发环境,实现鹰眼功能。

原创
作者头像
Abigail
发布2023-04-20 22:02:18
1.9K0
发布2023-04-20 22:02:18
举报
文章被收录于专栏:GIS二次开发基础

这是我的练习作业,我拿来回忆和复习。

鹰眼地图是一种在地图上显示一个小的缩略图,用来表示当前地图的范围和位置的工具。它可以让我们在查看细节的同时,也能看到整体的情况,方便我们进行导航和定位。它还可以让我们通过拖动或者缩放鹰眼地图上的矩形框,来改变主地图的视图范围,实现同步更新。👏

在本文中,我将介绍如何用C#语言和ArcGIS Engine的控件和类库,实现一个简单的鹰眼地图功能。我将分为以下几个步骤:

  • 创建一个Windows窗体应用程序,并添加两个MapControl控件,一个作为主地图,一个作为鹰眼地图。
  • 编写一个同步鹰眼地图的方法,用来根据主地图的数据和视图范围,更新鹰眼地图的内容和矩形框。
  • 编写一个绘制矩形框的方法,用来在鹰眼地图上绘制一个表示当前视图范围的矩形框,并设置其样式和颜色。
  • 编写一个获取颜色的方法,用来根据RGB值创建一个颜色对象。
  • 编写几个事件处理方法,用来响应主地图和鹰眼地图上的鼠标操作,并实现视图范围的变化和同步

创建一个Windows窗体应用程序,并添加两个MapControl控件,一个作为主地图,一个作为鹰眼地图:

接下来我们需要编写一个方法,定义一个 SynchronizeEagleEye 方法,用于同步鹰眼地图和主地图的图层和坐标系统,接着我们需要判断鹰眼地图是否有图层,如果有,就清除所有图层,以便重新添加。然后设置了鹰眼地图和主地图的空间参考一致,接着,我们需要遍历了主地图的所有图层,从最上面的图层开始,判断它们是否是组合图层或复合图层。如果是,就再遍历它们的子图层,判断它们是否是要素图层。如果是要素图层,并且不是点或多点类型的要素,如果不是组合图层或复合图层,就直接判断它们是否是要素图层,并且不是点或多点类型的要素,如果是,就将它们添加到鹰眼地图中。这样它们就可以在同一个坐标系统下显示,最后我们获取了主地图的当前范围,作为一个 IEnvelope 对象,并将其作为参数传递给 DrawRectangle 方法,用于在鹰眼地图上绘制一个矩形框,表示主地图的当前视图范围。我们可以将这个方法命名为SyncEagleEyeMap,具体代码如下:

代码语言:javascript
复制
        private void SynchronizeEagleEye()
        {
            //判断鹰眼地图是否有图层
            if (axMapControl2.LayerCount > 0)
            {
                axMapControl2.ClearLayers();
            }
            //设置鹰眼和主地图的坐标系统一致
            axMapControl2.SpatialReference = axMapControl1.SpatialReference;
            for (int i = axMapControl1.LayerCount - 1; i >= 0; i--)
            {
                //使鹰眼视图与数据视图的图层上下顺序保持一致
                ILayer pLayer = axMapControl1.get_Layer(i);
                if (pLayer is IGroupLayer || pLayer is ICompositeLayer)
                {
                    ICompositeLayer pCompositeLayer = (ICompositeLayer)pLayer;
                    for (int j = pCompositeLayer.Count - 1; j >= 0; j--)
                    {
                        ILayer pSubLayer = pCompositeLayer.get_Layer(j);
                        IFeatureLayer pFeatureLayer = pSubLayer as IFeatureLayer;
                        if (pFeatureLayer != null)
                        {
                            //由于鹰眼地图较小,所以过滤点图层不添加
                            if (pFeatureLayer.FeatureClass.ShapeType != esriGeometryType.esriGeometryPoint
                                && pFeatureLayer.FeatureClass.ShapeType != esriGeometryType.esriGeometryMultipoint)
                            {
                                axMapControl2.AddLayer(pLayer);
                            }
                        }
                    }
                }
                else
                {
                    IFeatureLayer pFeatureLayer = pLayer as IFeatureLayer;
                    if (pFeatureLayer != null)
                    {
                        if (pFeatureLayer.FeatureClass.ShapeType != esriGeometryType.esriGeometryPoint
                            && pFeatureLayer.FeatureClass.ShapeType != esriGeometryType.esriGeometryMultipoint)
                        {
                            axMapControl2.AddLayer(pLayer);
                        }
                    }
                }
                //设置鹰眼地图全图显示  
                axMapControl2.Extent = axMapControl1.FullExtent;
                pEnv = axMapControl1.Extent as IEnvelope;
                DrawRectangle(pEnv);
                axMapControl2.ActiveView.Refresh();
            }
        }

我们还需要定义一个 DrawRectangle 方法,用于在鹰眼地图上绘制一个矩形框,表示当前地图的视图范围,用DrawRectangle 方法接受一个 IEnvelope 参数,表示当前地图的视图范围的几何形状。在绘制前,先清除鹰眼地图中之前绘制的矩形框,以避免重叠和混乱。然后,创建了一个 IRectangleElement 对象,用于表示矩形框的元素,并将其几何形状设置为 IEnvelope 参数。接着,设置矩形框的样式,包括颜色、透明度、线宽等。你使用了一个 GetRgbColor 方法,用于根据三个整数参数返回一个 IRgbColor 对象。最后,将矩形框元素添加到鹰眼地图的图形容器中,并刷新视图,使其显示出来。代码如下:

代码语言:javascript
复制
        //在鹰眼地图上面画矩形框
        private void DrawRectangle(IEnvelope pEnvelope)
        {
            //在绘制前,清除鹰眼中之前绘制的矩形框
            IGraphicsContainer pGraphicsContainer = axMapControl2.Map as IGraphicsContainer;
            IActiveView pActiveView = pGraphicsContainer as IActiveView;
            pGraphicsContainer.DeleteAllElements();
            //得到当前视图范围
            IRectangleElement pRectangleElement = new RectangleElementClass();
            IElement pElement = pRectangleElement as IElement;
            pElement.Geometry = pEnvelope;
            //设置矩形框(实质为中间透明度面)
            IRgbColor pColor = new RgbColorClass();
            pColor = GetRgbColor(255, 0, 0);
            pColor.Transparency = 255;
            ILineSymbol pOutLine = new SimpleLineSymbolClass();
            pOutLine.Width = 2;
            pOutLine.Color = pColor;

            IFillSymbol pFillSymbol = new SimpleFillSymbolClass();
            pColor = new RgbColorClass();
            pColor.Transparency = 0;
            pFillSymbol.Color = pColor;
            pFillSymbol.Outline = pOutLine;
            //向鹰眼中添加矩形框
            IFillShapeElement pFillShapeElement = pElement as IFillShapeElement;
            pFillShapeElement.Symbol = pFillSymbol;
            pGraphicsContainer.AddElement((IElement)pFillShapeElement, 0);
            //刷新
            pActiveView.PartialRefresh(esriViewDrawPhase.esriViewGraphics, null, null);
        }
        //定义用于获取颜色的GetRgbColor方法
        private IRgbColor GetRgbColor(int intR, int intG, int intB)
        {
            IRgbColor pRgbColor = null;
            if (intR < 0 || intR > 255 || intG < 0 || intG > 255 || intB < 0 || intB > 255)
            {
                return pRgbColor;
            }
            pRgbColor = new RgbColorClass();
            pRgbColor.Red = intR;
            pRgbColor.Green = intG;
            pRgbColor.Blue = intB;
            return pRgbColor;
        }

我们需要在axMapControl1_OnMapReplaced ,axMapControl1_OnExtentUpdated,axMapControl2_OnMouseDown,axMapControl2_OnMouseMove,axMapControl2_OnMouseUp方法里处理鹰眼地图和主地图的交互事件。

axMapControl1_OnMapReplaced方法里我们要在主地图的地图对象被替换时触发的它,然后调用 SynchronizeEagleEye 方法,用于同步鹰眼地图和主地图的图层和坐标系统。代码如下:

代码语言:javascript
复制
        private void axMapControl1_OnMapReplaced(object sender, IMapControlEvents2_OnMapReplacedEvent e)
        {
            SynchronizeEagleEye();
        }

axMapControl1_OnExtentUpdated 方法是在主地图的视图范围被更新时触发的,它获取了主地图的当前范围,并将其作为参数传递给 DrawRectangle 方法,用于在鹰眼地图上绘制一个矩形框,表示主地图的当前视图范围。代码如下:

代码语言:javascript
复制
        private void axMapControl1_OnExtentUpdated(object sender, IMapControlEvents2_OnExtentUpdatedEvent e)
        {
            //得到当前视图范围
            pEnv = (IEnvelope)e.newEnvelope;
            DrawRectangle(pEnv);
        }

axMapControl2_OnMouseDown 方法是在鹰眼地图上按下鼠标时触发的,它根据鼠标的按键类型和位置执行不同的操作。表示如果按下鼠标左键,并且指针落在鹰眼地图的矩形框中,就标记为可移动,并记录点击的点的坐标,用于后续的拖动操作。如果按下鼠标右键,就在鹰眼地图上绘制一个新的矩形框,并将其范围和中心点应用到主地图上,用于改变主地图的视图范围。代码如下:

代码语言:javascript
复制
        private void axMapControl2_OnMouseDown(object sender, IMapControlEvents2_OnMouseDownEvent e)
        {
            if (axMapControl2.Map.LayerCount > 0)
            {
                //按下鼠标左键移动矩形框
                if (e.button == 1)
                {
                    //如果指针落在鹰眼的矩形框中,标记可移动
                    if (e.mapX > pEnv.XMin && e.mapY > pEnv.YMin && e.mapX < pEnv.XMax && e.mapY < pEnv.YMax)
                    {
                        bCanDrag = true;
                    }
                    pMoveRectPoint = new PointClass();
                    pMoveRectPoint.PutCoords(e.mapX, e.mapY);  //记录点击的第一个点的坐标
                }
                    //按下鼠标右键绘制矩形框
                else if (e.button == 2)
                {
                    IEnvelope pEnvelope = axMapControl2.TrackRectangle();

                    IPoint pTempPoint = new PointClass();
                    pTempPoint.PutCoords(pEnvelope.XMin + pEnvelope.Width / 2, pEnvelope.YMin + pEnvelope.Height / 2);
                    axMapControl1.Extent = pEnvelope;
                    //矩形框的高宽和数据试图的高宽不一定成正比,这里做一个中心调整
                    axMapControl1.CenterAt(pTempPoint);
                }
            }
        }

axMapControl2_OnMouseMove 方法是在鹰眼地图上移动鼠标时触发的,它根据鼠标的位置和按键状态执行不同的操作。如果鼠标移动到矩形框中,并且没有按下右键,就将鼠标指针换成小手,表示可以拖动矩形框。如果鼠标移动到矩形框中,并且按下了右键,就将鼠标指针换成默认样式,表示不能拖动矩形框。如果鼠标移动到矩形框外,就将鼠标指针换成默认样式。如果之前已经标记为可移动,并且按下了左键,就计算鼠标移动的距离,并根据偏移量改变矩形框的位置,同时也改变主地图的视图范围。代码如下:

代码语言:javascript
复制
        private void axMapControl2_OnMouseMove(object sender, IMapControlEvents2_OnMouseMoveEvent e)
        {
            if (pEnv == null) 
            {
                return;
            }
            if (e.mapX > pEnv.XMin && e.mapY > pEnv.YMin && e.mapX < pEnv.XMax && e.mapY < pEnv.YMax)
            {
                //如果鼠标移动到矩形框中,鼠标换成小手,表示可以拖动
                axMapControl2.MousePointer = esriControlsMousePointer.esriPointerHand;
                if (e.button == 2)  //如果在内部按下鼠标右键,将鼠标演示设置为默认样式
                {
                    axMapControl2.MousePointer = esriControlsMousePointer.esriPointerDefault;
                }
            }
            else
            {
                //在其他位置将鼠标设为默认的样式
                axMapControl2.MousePointer = esriControlsMousePointer.esriPointerDefault;
            }
            if (bCanDrag)
            {
                double Dx, Dy;  //记录鼠标移动的距离
                Dx = e.mapX - pMoveRectPoint.X;
                Dy = e.mapY - pMoveRectPoint.Y;
                pEnv.Offset(Dx, Dy); //根据偏移量更改 pEnv 位置
                pMoveRectPoint.PutCoords(e.mapX, e.mapY);
                DrawRectangle(pEnv);
                axMapControl1.Extent = pEnv;
            }
        }

axMapControl2_OnMouseUp 方法是在鹰眼地图上松开鼠标时触发的,它判断是否是左键点击,并且是否在矩形框中点击。如果是,就将主地图的中心点设置为点击的点。然后取消可移动的标记。

代码语言:javascript
复制
        private void axMapControl2_OnMouseUp(object sender, IMapControlEvents2_OnMouseUpEvent e)
        {
            //判断是否是左键点击
            if (e.button == 1 && pMoveRectPoint != null)
            {
                if (e.mapX == pMoveRectPoint.X && e.mapY == pMoveRectPoint.Y)
                {
                    axMapControl1.CenterAt(pMoveRectPoint);
                }
                bCanDrag = false;
            }
        }

最后我们需要定义了两个方法,分别是 CopyToPageLayout 和 axMapControl1_OnAfterScreenDraw。

CopyToPageLayout 方法用于将主地图的地图对象复制到页面布局控件中的地图对象,实现两个地图对象的同步。它使用了一个 IObjectCopy 接口,用于复制和覆盖对象。代码如下:

代码语言:javascript
复制
        private void CopyToPageLayout()
        {
            IObjectCopy pObjectCopy = new ObjectCopyClass();
            object copyFromMap = axMapControl1.Map;
            object copiedMap = pObjectCopy.Copy(copyFromMap);//复制地图到copiedMap中
            object copyToMap = axPageLayoutControl1.ActiveView.FocusMap;
            pObjectCopy.Overwrite(copiedMap, ref copyToMap); //复制地图
            axPageLayoutControl1.ActiveView.Refresh();
        }

axMapControl1_OnAfterScreenDraw 方法是在主地图的屏幕绘制完成后触发的,它用于将主地图的视图范围应用到页面布局控件中的地图的显示转换上,并刷新页面布局控件的视图。然后调用 CopyToPageLayout 方法,将主地图的内容复制到页面布局控件中。代码如下:

代码语言:javascript
复制
        private void axMapControl1_OnAfterScreenDraw(object sender, IMapControlEvents2_OnAfterScreenDrawEvent e)
        {
            //获取PageLayoutControl控件中的地图的活动视图
            IActiveView pActiveView = (IActiveView)axPageLayoutControl1.ActiveView.FocusMap;
            IDisplayTransformation displayTransformation = pActiveView.ScreenDisplay.DisplayTransformation;
            displayTransformation.VisibleBounds = axMapControl1.Extent;
            axPageLayoutControl1.ActiveView.Refresh();
            CopyToPageLayout();
        }

总结:我们基于 ArcGIS Engine10.2 + C# VS2012 开发环境实现了鹰眼功能。定义了多个方法,用于在主地图和鹰眼地图之间同步图层、坐标系统、视图范围和交互事件。使用了ArcObjects接口和类,如IGraphicsContainer、IRectangleElement、IRgbColor、ILineSymbol、IFillSymbol等,用于在鹰眼地图上绘制一个矩形框,表示主地图的当前视图范围。处理了鹰眼地图上的鼠标事件,如OnMouseDown、OnMouseMove、OnMouseUp等,用于移动或改变矩形框的位置和大小,并相应地改变主地图的视图范围。处理了主地图上的事件,如OnMapReplaced、OnExtentUpdated、OnAfterScreenDraw等,用于同步鹰眼地图和页面布局控件中的地图对象。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档