ArcEngine|实现拖框/圆/多边形放大缩小

所有的代码已经传到了我的GitHub,需要的请自取,GitHub项目地址:https://github.com/Weltra/T_ArcMap

问题分析

加载地图文档

加载地图文档的过程:先点击“打开”按钮,自动弹出电脑文件夹目录,再从中选取“.mxd”类型的地图文档;选中后点击确定,即可加载;加载时,地图内容显示在Map界面(利用MapControl控件),图层索引显示在TOC界面(利用TOCControl控件)。

放大

放大分为三种方法:矩形放大(拉框放大)、圆形放大、多边形放大。这四种方法看似不一样,但是其本质上都有相同点:放大后的视图为四种geometry的Envelope。因此放大时需要算出画出的几何图形的最小外包矩形即可作为最终视图的一部分。

缩小

与放大相似,首先判断是哪种缩小方法,判断后求出geometry的Envelope,接着计算缩小的比例和缩小后的视图中X、Y坐标的最大值和最小值,最后更新显示界面即可得到缩小后的视图结果。

WinForm界面搭建

设计Windows 窗体应用程序

新建项目

新建一个MapControl窗体应用程序项目(Engine):

image-20230308162214628

窗体设计

MapControl窗体已经自带了很多常用的控件,包括TOCControl,MapControl,LicenseControl等,可以在此基础上添加或进行相应的修改。

image-20230308200351511

读入.xmd文件功能

地图放大功能

在View选项内添加放大选项,并且在放大后增加:按矩形框放大、按圆形放大、按多边形放大三个选项。

image-20230308192901623

地图缩小功能

在View选项内添加缩小选项,并且在缩小后增加:按矩形框缩小、按圆形缩小、按多边形缩小三个选项。

image-20230308192801134

为控件绑定事件

axMapControl1绑定 OnMouseDown事件:

image-20230308165126626

为各个 ToolStripMenuItem添加 Click事件(以按矩形框缩小为例):

image-20230308165258205

添加功能

读入.xmd文件部分

使用 OpenFileDialog来过滤并读入文件,代码如下:

private void openXmlFileToolStripMenuItem_Click(object sender, EventArgs e)
        {
            IMapDocument pMxdMapDocument = new MapDocumentClass();
            OpenFileDialog pMxdOpenFileDialog = new OpenFileDialog();
            pMxdOpenFileDialog.Filter = "地图文档(*.mxd)|*.mxd";
            if (pMxdOpenFileDialog.ShowDialog() == DialogResult.OK)
            {
                string xjmxdFilePath = pMxdOpenFileDialog.FileName;
                if (axMapControl1.CheckMxFile(xjmxdFilePath))
                {
                    axMapControl1.Map.ClearLayers();
                    axMapControl1.LoadMxFile(xjmxdFilePath);
                }
            }
            axMapControl1.ActiveView.Refresh();
        }

为了使TOCControl中的数据能显示出来,需要将TOCControl控件和MapControl控件通过接口连接,连接方法如下:

image-20230308184758368

绘制图形缩小/放大部分

放大编程思路

首先定义放大的三种方法;接着在各种放大方法的按钮对应的代码中调用放大方法;然后再在OnMouseDowen事件中添加一个switch函数,选择对应的方法应当返回的geometry;最后判断Envelope的边界是否超过View的范围,如果没有超过,则进行放大操作。

缩小编程思路

首先利用switch语句判断缩小方法属于矩形缩小、圆形缩小和多边形缩小中的哪种;接着判断所画geometry是否为空,若为空,则返回空值,若非空则进行如下缩小操作:先算出缩小后视图的长和宽,其计算方法为:当前视图长或宽(当前视图长或宽/geometry的Envelope的长或宽),其中括号中的为缩小系数;接着计算出缩小后视图的x、y最小值:当前视图最小值-(geometry.Envelope的最小值-当前视图最小值)缩小系数;最后计算缩小后视图的最大值:最小值+缩小后视图的长或宽;最终更新视图即可得到缩小后的视图。

编程实现

首先定义一个 toolAction的变量来存储功能

private string toolAction;

在各个 ToolStripMenuItem_Click事件下编写功能,首先更改 toolAction变量的值,随后检查该功能是否被勾选,如果被勾选,则将 axMapControl1_OnMouseDown事件加入事件队列之中。

private void 按矩形框放大ToolStripMenuItem_Click(object sender, EventArgs e)
    {
        toolAction = "Rectangle Drag Zoom In";
        if(this.按矩形框放大ToolStripMenuItem.Checked)
        {
            按矩形框放大ToolStripMenuItem.Checked = false;
            this.axMapControl1.OnMouseDown -= new ESRI.ArcGIS.Controls.IMapControlEvents2_Ax_OnMouseDownEventHandler(this.axMapControl1_OnMouseDown);
        }
        else
        {
            按矩形框放大ToolStripMenuItem.Checked = true;
            this.axMapControl1.OnMouseDown += new ESRI.ArcGIS.Controls.IMapControlEvents2_Ax_OnMouseDownEventHandler(this.axMapControl1_OnMouseDown);
        }
    }

private void 按矩形框缩小ToolStripMenuItem_Click(object sender, EventArgs e)
{
    toolAction = "Rectangle Drag Zoom Out";
    if (this.按矩形框缩小ToolStripMenuItem.Checked)
    {
        按矩形框缩小ToolStripMenuItem.Checked = false;
        this.axMapControl1.OnMouseDown -= new ESRI.ArcGIS.Controls.IMapControlEvents2_Ax_OnMouseDownEventHandler(this.axMapControl1_OnMouseDown);
    }
    else
    {
        按矩形框缩小ToolStripMenuItem.Checked = true;
        this.axMapControl1.OnMouseDown += new ESRI.ArcGIS.Controls.IMapControlEvents2_Ax_OnMouseDownEventHandler(this.axMapControl1_OnMouseDown);
    }
}

private void 按多边形放大ToolStripMenuItem_Click(object sender, EventArgs e)
{
    toolAction = "Geometry Drag Zoom In";
    if (按多边形放大ToolStripMenuItem.Checked)
    {
        按多边形放大ToolStripMenuItem.Checked = false;
        this.axMapControl1.OnMouseDown -= new ESRI.ArcGIS.Controls.IMapControlEvents2_Ax_OnMouseDownEventHandler(this.axMapControl1_OnMouseDown);
    }
    else
    {
        按多边形放大ToolStripMenuItem.Checked = true;
        this.axMapControl1.OnMouseDown += new ESRI.ArcGIS.Controls.IMapControlEvents2_Ax_OnMouseDownEventHandler(this.axMapControl1_OnMouseDown);
    }
}

private void 按多边形缩小ToolStripMenuItem_Click(object sender, EventArgs e)
{
    toolAction = "Geometry Drag Zoom Out";
    if (按多边形缩小ToolStripMenuItem.Checked)
    {
        按多边形缩小ToolStripMenuItem.Checked = false;
        this.axMapControl1.OnMouseDown -= new ESRI.ArcGIS.Controls.IMapControlEvents2_Ax_OnMouseDownEventHandler(this.axMapControl1_OnMouseDown);
    }
    else
    {
        按多边形缩小ToolStripMenuItem.Checked = true;
        this.axMapControl1.OnMouseDown += new ESRI.ArcGIS.Controls.IMapControlEvents2_Ax_OnMouseDownEventHandler(this.axMapControl1_OnMouseDown);
    }
}

private void 按圆形放大ToolStripMenuItem_Click(object sender, EventArgs e)
{
    toolAction = "Circle Drag Zoom In";
    if (按圆形放大ToolStripMenuItem.Checked)
    {
        按圆形放大ToolStripMenuItem.Checked = false;
        this.axMapControl1.OnMouseDown -= new ESRI.ArcGIS.Controls.IMapControlEvents2_Ax_OnMouseDownEventHandler(this.axMapControl1_OnMouseDown);
    }
    else
    {
        按圆形放大ToolStripMenuItem.Checked = true;
        this.axMapControl1.OnMouseDown += new ESRI.ArcGIS.Controls.IMapControlEvents2_Ax_OnMouseDownEventHandler(this.axMapControl1_OnMouseDown);
    }
}

private void 按圆形缩小ToolStripMenuItem_Click(object sender, EventArgs e)
{
    toolAction = "Circle Drag Zoom Out";
    if (按圆形缩小ToolStripMenuItem.Checked)
    {
        按圆形缩小ToolStripMenuItem.Checked = false;
        this.axMapControl1.OnMouseDown -= new ESRI.ArcGIS.Controls.IMapControlEvents2_Ax_OnMouseDownEventHandler(this.axMapControl1_OnMouseDown);
    }
    else
    {
        按圆形缩小ToolStripMenuItem.Checked = true;
        this.axMapControl1.OnMouseDown += new ESRI.ArcGIS.Controls.IMapControlEvents2_Ax_OnMouseDownEventHandler(this.axMapControl1_OnMouseDown);
    }
}

为了避免大量重复的代码块出现,因此需要写一个缩小外接矩形的方法,代码如下:

private IEnvelope zoom_out(IEnvelope pEnvelop2)
        {
            double x_scale = axMapControl1.Extent.Width / pEnvelop2.Width;//XY尺寸
            double y_scale = axMapControl1.Extent.Height / pEnvelop2.Width;
            //新窗口的高度宽度=原地图窗口*比例
            double width = axMapControl1.Extent.Width * x_scale;
            double height = axMapControl1.Extent.Width * y_scale;
            //找到窗口的最小值 即XY的最小值
            double x_min = pEnvelop2.XMin - (pEnvelop2.XMin - axMapControl1.Extent.XMin) * x_scale;
            double y_min = pEnvelop2.YMin - (pEnvelop2.YMin - axMapControl1.Extent.YMin) * y_scale;

            //取矩形框的取最大值
            double x_max = x_min + width;
            double y_max = y_min + height;

            //新的envelop
            pEnvelop2.PutCoords(x_min, y_min, x_max, y_max);
            return pEnvelop2;
        }

axMapControl1_OnMouseDown事件中,使用 switch case语句来实现不同的功能:

private void axMapControl1_OnMouseDown(object sender, IMapControlEvents2_OnMouseDownEvent e)
        {
            switch (toolAction)
            {
                case "Rectangle Drag Zoom In":
                    IEnvelope pEnvelop = axMapControl1.TrackRectangle();
                    if (pEnvelop == null | pEnvelop.IsEmpty || pEnvelop.Height == 0 || pEnvelop.Width == 0)//判断外接矩形是否为空
                    {
                        return;
                    }
                    axMapControl1.Extent = pEnvelop;
                    break;
                case "Rectangle Drag Zoom Out":
                    IEnvelope pEnvelop2 = axMapControl1.TrackRectangle();
                    if (pEnvelop2 == null || pEnvelop2.IsEmpty || pEnvelop2.Height == 0 || pEnvelop2.Width == 0)
                    {
                        return;
                    }
                    IEnvelope pEnvelop2_1 = zoom_out(pEnvelop2);
                    axMapControl1.Extent = pEnvelop2_1;
                    axMapControl1.Refresh();
                    break;
                case "Geometry Drag Zoom In":
                    IGeometry IG1 = axMapControl1.TrackPolygon();
                    IEnvelope pEnvelop3 = IG1.Envelope;
                    if (pEnvelop3 == null | pEnvelop3.IsEmpty || pEnvelop3.Height == 0 || pEnvelop3.Width == 0)//判断外接矩形是否为空
                    {
                        return;
                    }
                    axMapControl1.Extent = pEnvelop3;
                    break;
                case "Geometry Drag Zoom Out":
                    IGeometry IG2 = axMapControl1.TrackPolygon();
                    IEnvelope pEnvelop4 = IG2.Envelope;
                    if (pEnvelop4 == null | pEnvelop4.IsEmpty || pEnvelop4.Height == 0 || pEnvelop4.Width == 0)//判断外接矩形是否为空
                    {
                        return;
                    }
                    IEnvelope pEnvelop4_1 = zoom_out(pEnvelop4);
                    axMapControl1.Extent = pEnvelop4_1;
                    axMapControl1.Refresh();
                    break;
                case "Circle Drag Zoom In":
                    IGeometry IG3 = axMapControl1.TrackCircle();
                    IEnvelope pEnvelop5 = IG3.Envelope;
                    if (pEnvelop5 == null | pEnvelop5.IsEmpty || pEnvelop5.Height == 0 || pEnvelop5.Width == 0)//判断外接矩形是否为空
                    {
                        return;
                    }
                    axMapControl1.Extent = pEnvelop5;
                    break;
                case "Circle Drag Zoom Out":
                    IGeometry IG4 = axMapControl1.TrackCircle();
                    IEnvelope pEnvelop6 = IG4.Envelope;
                    if (pEnvelop6 == null | pEnvelop6.IsEmpty || pEnvelop6.Height == 0 || pEnvelop6.Width == 0)//判断外接矩形是否为空
                    {
                        return;
                    }
                    IEnvelope pEnvelop6_1 = zoom_out(pEnvelop6);
                    axMapControl1.Extent = pEnvelop6_1;
                    axMapControl1.Refresh();
                    break;
            }
        }

运行结果

读入.mxd文档

选择文件:

image-20230308200457835

读入.mxd文档的结果:

image-20230308200522576

按矩形框放大

拖拽一个矩形框:

image-20230308200634045

按矩形框放大结果:

image-20230308200745822

按矩形框缩小

拖拽一个矩形框:

image-20230308200830643

按矩形框缩小结果:

image-20230308200839799

按圆形放大

拖拽一个圆形

image-20230308201139223

按圆形放大结果

image-20230308201201930

按圆形缩小

拖拽一个圆形

image-20230308201652819

按圆形缩小结果

image-20230308201703715

按多边形放大

绘制一个多边形:

image-20230308201748591

按多边形放大结果:

image-20230308201830886

按多边形缩小

绘制一个多边形:

image-20230308202332895

按多边形缩小结果:

image-20230308202341683

分析

MapControl和TOCControl之间的关系,通过那个接口实现关联?

TOCControl控件相当于ArcMap中左侧的目录树,需要与一个“伙伴控件”协同工作,可以是MapControl、PageLayoutControl、SceneControl或者GlobeControl,通过 ITOCBuddy接口连接。

image-20230309122745759

伙伴控件的设置可通过TOCControl属性对话框或用SetBuddyControl方法通过编程设置,

private void Form1_Load(object sender, EventArgs e)
{
	axTOCControl1.SetBuddyControl(axMapControl1);
}

TOCControl控件支持 BuddySetBuddyControl()将MapControl设置为伙伴控件,使得两者可以协同工作。

posted @ 2023-03-15 11:30  Weltㅤ  阅读(391)  评论(0编辑  收藏  举报