ArcGIS - Engine二次开发 - 提高篇 - 图文

更新时间:2024-06-18 07:20:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

ArcGIS Engine高级功能开发

ArcGIS Engine二次开发

——提高篇

ArcGIS Engine高级功能开发

1 缩略图(鹰眼)

鹰眼功能是GIS的主要功能之一,当地图范围很大时,它可以很好的为用户指明当前地图的范围。在本小节中我们将学习如何制作这种鹰眼。

1.1 添加控件

新建一个C#.Net项目,项目名称为OverView,将Form1的名字设置为MainForm,并添加ToolbarControl 、两个MapControl和LicenceControl等四个控件。布局如下图所示。左边的axMapControl1用于地图数据显示和操作,右边axMapControl2用于鹰眼显示。

图 1 界面布局

在ToolbarControl 加载添加数据按钮和地图浏览的功能按钮,如下图所示,并将ToolbarControl的伙伴控件设为axMapControl1。

图 2添加按钮

1.2 代码添加及解释

鹰眼用来显示主窗体当前视图范围在全景视图中的位置,在ArcMap中使用一个线框在鹰眼视图中标识。当主视图中的视图范围改变时,鹰眼中的线框随之改变,当拖动鹰眼视图中的红线框时,主视图中的视图范围也随之改变。 下面开始实现鹰眼功能,添加using ESRI.ArcGIS.Carto、using ESRI.ArcGIS.Geometry、 using ESRI.ArcGIS.Display三个引用。首先在axMapControl1中视图范围改变时鹰眼窗体要做出对应的响应,即绘制线框并显示,在OnExtentUpdated事件中添加代码如下:

private void axMapControl1_OnExtentUpdated(object sender,

ESRI.ArcGIS.Controls.IMapControlEvents2_OnExtentUpdatedEvent e) {

//创建鹰眼中线框

IEnvelope pEnv = (IEnvelope)e.newEnvelope;

IRectangleElement pRectangleEle = new RectangleElementClass(); IElement pEle = pRectangleEle as IElement; pEle.Geometry = pEnv;

//设置线框的边线对象,包括颜色和线宽 IRgbColor pColor = new RgbColorClass(); pColor.Red = 255; pColor.Green = 0; pColor.Blue = 0;

pColor.Transparency = 255; // 产生一个线符号对象

ILineSymbol pOutline = new SimpleLineSymbolClass(); pOutline.Width = 2; pOutline.Color = pColor;

// 设置颜色属性 pColor.Red = 255; pColor.Green = 0; pColor.Blue = 0;

pColor.Transparency = 0;

// 设置线框填充符号的属性

IFillSymbol pFillSymbol = new SimpleFillSymbolClass(); pFillSymbol.Color = pColor; pFillSymbol.Outline = pOutline;

IFillShapeElement pFillShapeEle = pEle as IFillShapeElement; pFillShapeEle.Symbol = pFillSymbol;

// 得到鹰眼视图中的图形元素容器

IGraphicsContainer pGra = axMapControl2.Map as IGraphicsContainer; IActiveView pAv = pGra as IActiveView;

// 在绘制前,清除 axMapControl2 中的任何图形元素 pGra.DeleteAllElements(); // 鹰眼视图中添加线框

pGra.AddElement((IElement)pFillShapeEle, 0); // 刷新鹰眼

pAv.PartialRefresh(esriViewDrawPhase.esriViewGraphics, null, null); }

当鼠标点击鹰眼窗体时,主窗体Extent随之改变。在axMapControl2的OnMouseDown事件中添加代码如下:

private void axMapControl2_OnMouseDown(object sender,

ESRI.ArcGIS.Controls.IMapControlEvents2_OnMouseDownEvent e) {

if (this.axMapControl2.Map.LayerCount != 0) {

// 按下鼠标左键移动矩形框 if (e.button == 1) {

IPoint pPoint = new PointClass(); pPoint.PutCoords(e.mapX, e.mapY);

IEnvelope pEnvelope = this.axMapControl1.Extent; pEnvelope.CenterAt(pPoint);

this.axMapControl1.Extent = pEnvelope;

this.axMapControl1.ActiveView.PartialRefresh(esriViewDrawPhase.esriViewGeography, null, null); }

// 按下鼠标右键绘制矩形框 else if (e.button == 2) {

IEnvelope pEnvelop = this.axMapControl2.TrackRectangle(); this.axMapControl1.Extent = pEnvelop;

this.axMapControl1.ActiveView.PartialRefresh(esriViewDrawPhase.esriViewGeography, null, null); } } }

当鼠标在鹰眼窗体移动时,主窗体Extent随之改变。在axMapControl2的OnMouseMove事件中添加代码如下:

private void axMapControl2_OnMouseMove(object sender, ESRI.ArcGIS.Controls.IMapControlEvents2_OnMouseMoveEvent e) {

// 如果不是左键按下就直接返回 if (e.button != 1) return;

IPoint pPoint = new PointClass(); pPoint.PutCoords(e.mapX, e.mapY); this.axMapControl1.CenterAt(pPoint);

this.axMapControl1.ActiveView.PartialRefresh(esriViewDrawPhase.esriViewGeography, null, null); }

下面代码用于实现axMapControl2与axMapControl1的数据的同步更新,获取主视图中视图范围最大的图层作为鹰眼中的视图。这个更新由两部分组成,一个是对axMapControl1添加地图文档(mxd文件)的响应,通过axMapControl1的OnMapReplace事件实现,一个是对axMapControl1添加单个图层的响应,通过axMapControl1的OnFullExtentUpdated事件实现。我们获取主视图中的视图范围最大的图层写成一个独立的函数,方便调用。

private ILayer GetOverviewLayer(IMap map) {

//获取主视图的第一个图层 ILayer pLayer = map.get_Layer(0);

//遍历其他图层,并比较视图范围的宽度,返回宽度最大的图层 ILayer pTempLayer = null;

for (int i = 1; i < map.LayerCount;i++ ) {

pTempLayer = map.get_Layer(i);

if (pLayer.AreaOfInterest.Width < pTempLayer.AreaOfInterest.Width) pLayer = pTempLayer; }

return pLayer; }

然后在axMapControl1的OnMapReplaced事件中调用。

private void axMapControl1_OnMapReplaced(object sender, IMapControlEvents2_OnMapReplacedEvent e) {

//获取鹰眼图层

this.axMapControl2.AddLayer(this.GetOverviewLayer(this.axMapControl1.Map)); // 设置 MapControl 显示范围至数据的全局范围

this.axMapControl2.Extent = this.axMapControl1.FullExtent; // 刷新鹰眼控件地图

this.axMapControl2.Refresh(); }

在axMapControl1的OnFullExtentUpdated添加代码,用于实现在主视图添加图层时,实

现对鹰眼视图的更新。代码如下:

private void axMapControl1_OnFullExtentUpdated(object sender, ESRI.ArcGIS.Controls.IMapControlEvents2_OnFullExtentUpdatedEvent e) {

//获取鹰眼图层

this.axMapControl2.AddLayer(this.GetOverviewLayer(this.axMapControl1.Map)); // 设置 MapControl 显示范围至数据的全局范围

this.axMapControl2.Extent = this.axMapControl1.FullExtent; // 刷新鹰眼控件地图

this.axMapControl2.Refresh(); }

本例的示例数据无特别要求,使用前面章节实例数据即可。运行程序,添加地图数据,可以在主视图进行相关操作,鹰眼视图同步响应,在鹰眼视图可以移动红线框可以同步更新主视图的视图范围,在鹰眼视图单击右键拉框可以重新绘制红线框,效果如下:

图 3鹰眼效果

1.3 MyGIS中添加鹰眼

在上一讲中的最后一节,我们创建了一个简单的GIS系统MyGIS,这里,我们讲鹰眼功能嵌入到我们的系统中。在这里我们对实现的思路做一个介绍,请您自己动手完善MyGIS。

首先需要修改一下MyGIS窗体的控件布局,我们讲鹰眼视图放到图层管理器的下方,需要在控件容器SpliterContainer1的Panel1中添加一个水平分隔的SpliterContainer,然后将图层管理器空间TOCControl和鹰眼视图MapControl分别置于上下的容器中,并将其属性Dock分别设为Fill。

另外,在此种窗体布局情况下,直接在TOCControl控件属性中设置伙伴控件无效,如

图所示。我们需要在MainForm的Load事件中为TOCControl设置伙伴控件为axMapControl1。添加代码如下:

private void Form1_Load(object sender, EventArgs e) {

//设置axTOCControl1的伙伴控件

this.axTOCControl1.SetBuddyControl(axMapControl1.Object); }

图 4 TOCControl控件属性中设置伙伴控件

然后依次添加本例中的代码,即可完成,运行效果如下图所示:

图 5 MyGIS中鹰眼的运行效果

1.4 小结

在本小节中,我们实现了鹰眼功能并讲鹰眼加入了MyGIS,这部分的重点是鹰眼视图和主视图之间的事件交互。推荐您仔细结合例子程序查看代码,如果需要获得进一步的信息,请查看帮助系统。如果您对这一小节的内容比较熟悉了,就可以开始学习本章最后一小节的内容了。在下一小节中,我们将尝试添加缓冲区分析功能。

ArcGIS Engine高级功能开发

2 缓冲区分析

缓冲区分析指为了识别某一地理实体或空间物体对其周围地物影响度而在其周围建立的具有一定宽度的区域,以确定哪些实体落在了被影响的区域范围之内。

缓冲区分析与缓冲区查询不同,缓冲区查询是不破坏原有空间目标的关系,只是检索到该缓冲区范围内涉及到的目标。而缓冲区分析是根据设定的距离条件对一类地物建立缓冲区多边形,存储到一个新的图层中。然后再将新的图层与需要进行缓冲区分析的图层进行叠置分析,得到所需要的结果。因此,缓冲区分析实际上进行了两步的操作,第一步是建立缓冲区图层,第二步是进行叠置剪裁分析。

缓冲区分析适用于点、线、面对象,如点状的居民点、线状的河流和面状的作物分布区等,只要地理实体能对周围一定区域形成影响即可使用这种分析方法。

图 6点、线、面的缓冲区分析

ArcGIS的ArcToolBox中的分析工具提供了缓冲区分析的功能,本节实习我们首先使用Geoprocessor方法实现一个简单的缓冲区分析功能,然后将缓冲区分析功能添加到我们的MyGIS项目中。

程序运行前首先需要在D盘下新建一个名为Temp的文件夹,存放叠置分析生成的文件。

2.1 Geoprocessor实现缓冲区分析

为了降低开发难度和提高开发效率,ArcGIS Engine中添加了GeoProcessor类,使用Geoprocessor能帮助用户直接实现一些简单的工具性的功能,所有在ArcToolBox中的功能,基本都可以用Geoprocessor编程实现。本节我们使用Geoprocessor实现缓冲区分析的功能。

2.1.1 添加控件

新建一个C#.Net项目,项目名称为Buffer,将Form1的名字设置为MainForm,并添加ToolbarControl 、MapControl、TOCControl、LicenceControl和Button等五个控件。并将ToolbarControl 、TOCControl的伙伴控件设为MapControl,Button控件的Name属性设定为btnBuffer,Text属性设定为“缓冲区分析”。控件布局效果如下图所示。

ArcGIS Engine高级功能开发

图 7控件布局效果

在ToolbarControl 加载添加数据按钮和地图浏览的功能按钮,如下图所示。

图 8添加按钮

2.1.2 代码添加及解释

首先添加如下四个命名空间的引用。

using ESRI.ArcGIS.Carto;

using ESRI.ArcGIS.Geoprocessor; using ESRI.ArcGIS.Geoprocessing; using ESRI.ArcGIS.esriSystem;

在使用Geoprocessor工具实现缓冲区分析时,需要首先定义一个Geoprocessor对象,因为命名空间“ESRI.ArcGIS.Geoprocessing”也包含Geoprocessor类,为了避免混淆,我们使用命

ArcGIS Engine高级功能开发

名空间来定义Geoprocessor,然后设置Geoprocessor中的环境参数,这里我们使用默认参数。

然后定义一个操作类Buffer,并设置参数,生成缓冲区的参数包含原始图层,缓冲半径和输出路径,最后使用已定义的Geoprocessor对象执行即可。双击“生成缓存区”按钮,添加代码如下:

private void btnBuffer_Click(object sender, EventArgs e) {

//判断MapControl中是否包含图层 if (this.axMapControl1.LayerCount == 0) return;

//获取MapControl中第一个图层

ILayer pLayer = this.axMapControl1.Map.get_Layer(0); //输出路径,可以自行指定

string strOutputPath = @\; //缓冲半径

double dblDistace = 1.0;

//获取一个geoprocessor的实例,避免与命名空间Geoprocessing中的Geoprocessor发生引用错误

ESRI.ArcGIS.Geoprocessor.Geoprocessor gp = new ESRI.ArcGIS.Geoprocessor.Geoprocessor();

//OverwriteOutput为真时,输出图层会覆盖当前文件夹下的同名图层 gp.OverwriteOutput = true; //创建一个Buffer工具的实例

ESRI.ArcGIS.AnalysisTools.Buffer buffer = new ESRI.ArcGIS.AnalysisTools.Buffer(pLayer, strOutputPath, dblDistace); //执行缓冲区分析

IGeoProcessorResult results = null;

results = gp.Execute(buffer, null) as IGeoProcessorResult;

//判断缓冲区是否成功生成

if (results.Status != esriJobStatus.esriJobSucceeded)

MessageBox.Show(\图层\ + pLayer.Name + \缓冲区生成失败!\); else {

MessageBox.Show(\缓冲区生成成功!\); //将生成图层加入MapControl

int index = strOutputPath.LastIndexOf(\);

this.axMapControl1.AddShapeFile(strOutputPath.Substring(0, index), strOutputPath.Substring(index)); } }

运行程序,添加一个图层(多个图层时本例中默认选择的图层为第一个图层),点击“生

ArcGIS Engine高级功能开发

成缓冲区”,运行结果如图。

图 9缓冲区生成效果

2.1.3 小结

本例中,我们使用Geoprocessor工具实现了缓冲区分析。从中我们可以得到Geoprocessor工具使用的一般方法,在使用Geoprocessor时,一般需先定义一个Geoprocessor对象,然后设置该对象的参数,如本例中的OverwriteOutput,再定义一个具体的操作类,如本例中的Buffer类,在设置完操作类的参数后,则通过Geoprocessor的Excute函数来执行。至此,我们已经实现了一个简单的缓冲区分析的功能,从中我们学习了Geoprocessor的使用方法。

下一节我们讲对缓冲区份分析功能做进一步的改进,使其具有更强的适用性,并将这个功能添加到MyGIS中。

2.2 MyGIS中添加缓冲区分析

我们在使用缓冲区分析时,需要设定原始的图层,缓冲半径以及生成缓冲区的保存路径。本节我们将在上一节的基础上进一步实现缓冲区分析,实现缓冲图层,缓冲半径和保存路径的可选设置。

2.2.1 添加控件

打开项目MyGIS,在MyGIS的主菜单添加一个新的菜单项“空间分析”,并添加子菜单“缓冲区分析”,Name属性修改为“menuBuffer”。

项目中添加一个新的窗体,名称为“BufferForm”,Name属性设为“缓冲区分析”,添加四个Label、一个ComboBox、两个TextBox、三个Button控件,控件属性设置如下:

表 1控件属性设置

控件类型

Name属性 Text属性 控件说明 ArcGIS Engine高级功能开发

Label Label Label Label lblUnit 选择图层: 缓冲半径: 地图单位 标示当前地图的地图单位 输出图层: ComboBox cboLayers 所有图层的名称 TextBox txtBufferDistance 1.0 生成缓冲区的缓冲半径 TextBox Button Button Button

txtOutputPath btnOutputLayer btnBuffer btnCancel … 分析 取消 缓冲区文件的输出路径,其ReadOnly属性设为True 选择缓冲区文件的输出路径 进行缓冲区分析 取消 2.2.2 代码添加及解释

该项目需添加如下引用:

using ESRI.ArcGIS.Controls; using ESRI.ArcGIS.Geoprocessor; using ESRI.ArcGIS.Carto;

using ESRI.ArcGIS.Geoprocessing; using ESRI.ArcGIS.esriSystem;

首先声明两个成员变量,用于保存地图数据和输出文件的路径。

//接收MapControl中的数据

private IHookHelper mHookHelper = new HookHelperClass(); //缓冲区文件输出路径 public string strOutputPath;

重写BufferForm的构造函数,添加一个参数,用于接收MapControl中的数据。

//重写构造函数,添加参数hook,用于传入MapControl中的数据 public BufferForm(object hook) {

InitializeComponent();

this.mHookHelper.Hook = hook; }

添加一个自定义函数,用于根据图层名称获取要素图层并返回。

private IFeatureLayer GetFeatureLayer(string layerName) {

IFeatureLayer pFeatureLayer = null; //遍历图层,获取与名称匹配的图层

ArcGIS Engine高级功能开发

for (int i = 0; i < this.mHookHelper.FocusMap.LayerCount; i++) {

ILayer pLayer = this.mHookHelper.FocusMap.get_Layer(i); if (pLayer.Name == layerName) {

pFeatureLayer = pLayer as IFeatureLayer; } }

if (pFeatureLayer != null) return pFeatureLayer; else

return null; }

BufferForm在载入时需要加载当前MapControl中的图层名称到cboLayers,读取当前地图的地图单位,设置缓冲区文件的默认输出路径,这里我们将默认输出路径设为“D:\\Temp\\”。

private void BufferForm_Load(object sender, EventArgs e) {

//传入数据为空时返回

if (null == mHookHelper || null == mHookHelper.Hook || 0 == mHookHelper.FocusMap.LayerCount) return;

//获取图层名称并加入cboLayers

for (int i = 0; i < this.mHookHelper.FocusMap.LayerCount; i++) {

ILayer pLayer = this.mHookHelper.FocusMap.get_Layer(i); cboLayers.Items.Add(pLayer.Name); }

//cboLayers控件中默认显示第一个选项 if (cboLayers.Items.Count > 0) cboLayers.SelectedIndex = 0;

//设置生成文件的默认输出路径和名称 string tempDir = @\;

txtOutputPath.Text = System.IO.Path.Combine(tempDir, ((string)cboLayers.SelectedItem + \));

//设置默认地图单位

lblUnits.Text = Convert.ToString(mHookHelper.FocusMap.MapUnits); }

ArcGIS Engine高级功能开发

双击路径设置按钮,进入代码编辑界面,添加如下代码:

private void btnOutputLayer_Click(object sender, EventArgs e) {

//定义输出文件路径

SaveFileDialog saveDlg = new SaveFileDialog(); //检查路径是否存在

saveDlg.CheckPathExists = true; saveDlg.Filter = \; //保存时覆盖同名文件

saveDlg.OverwritePrompt = true; saveDlg.Title = \输出路径\; //对话框关闭前还原当前目录 saveDlg.RestoreDirectory = true;

saveDlg.FileName = (string)cboLayers.SelectedItem + \;

//读取文件输出路径到txtOutputPath DialogResult dr = saveDlg.ShowDialog(); if (dr == DialogResult.OK)

txtOutputPath.Text = saveDlg.FileName; }

双击“分析”按钮,添加代码如下:

private void btnBuffer_Click(object sender, EventArgs e) {

//缓冲距离

double bufferDistance; //输入的缓冲距离转换为double

double.TryParse(txtBufferDistance.Text.ToString(),out bufferDistance);

//判断输出路径是否合法

if (!System.IO.Directory.Exists(System.IO.Path.GetDirectoryName(txtOutputPath.Text)) || \ != System.IO.Path.GetExtension(txtOutputPath.Text)) {

MessageBox.Show(\输出路径错误!\); return; }

//判断图层个数

if (mHookHelper.FocusMap.LayerCount == 0) return; //获取图层

ArcGIS Engine高级功能开发

IFeatureLayer pFeatureLayer = GetFeatureLayer((string)cboLayers.SelectedItem); if (null == pFeatureLayer) {

MessageBox.Show(\图层\ + (string)cboLayers.SelectedItem + \不存在!\\r\\n\); return; }

//获取一个geoprocessor的实例

Geoprocessor gp = new Geoprocessor();

//OverwriteOutput为真时,输出图层会覆盖当前文件夹下的同名图层 gp.OverwriteOutput = true; //缓冲区保存路径

strOutputPath = txtOutputPath.Text; //创建一个Buffer工具的实例

ESRI.ArcGIS.AnalysisTools.Buffer buffer = new

ESRI.ArcGIS.AnalysisTools.Buffer(pFeatureLayer, strOutputPath, bufferDistance.ToString()); //执行缓冲区分析

IGeoProcessorResult results = null;

results = (IGeoProcessorResult)gp.Execute(buffer, null); //判断缓冲区是否成功生成

if (results.Status != esriJobStatus.esriJobSucceeded)

MessageBox.Show(\图层\ + pFeatureLayer.Name + \缓冲区生成失败!\); else {

this.DialogResult = DialogResult.OK; MessageBox.Show(\缓冲区生成成功!\); } }

双击“取消”按钮,添加代码如下:

private void btnCancel_Click(object sender, EventArgs e) {

this.Dispose(); }

进入MyGIS的主窗体,双击菜单中的“缓冲区分析”,添加代码如下:

BufferForm bufferForm = new BufferForm(this.axMapControl1.Object); if (bufferForm.ShowDialog() == DialogResult.OK) {

//获取输出文件路径

string strBufferPath = bufferForm.strOutputPath;

ArcGIS Engine高级功能开发

//缓冲区图层载入到MapControl

int index = strBufferPath.LastIndexOf(\);

this.axMapControl1.AddShapeFile(strBufferPath.Substring(0, index), strBufferPath.Substring(index)); }

至此,代码编辑完成,运行程序,添加数据usa.mxd,选择图层wind,设置缓冲区半径为0.8,点击“分析”,效果如下图所示。

图 10缓冲区分析效果

如果运行过程中出现错误“正试图在 OS 加载程序锁内执行托管代码。不要尝试在 DllMain 或映像初始化函数内运行托管代码,这样做会导致应用程序挂起。”,请采用如下方法解决:

把vs2005菜单的 调试->异常->Managed Debuggin Assistants->LoaderLock 的选中状态去掉即可!如果异常(exception)这一项没有的话,在工具---自定义---命令选项卡,选择左边“调试”,找到右边“异常”拖到菜单上。

2.2.3 小结

缓冲区分析是GIS空间分析的基本功能,这一节我们完成了缓冲区分析的功能,实现了缓冲区分析文件、缓冲半径和输出路径的可选设置,希望您仔细体会并掌握Geoprocessor工具开发空间分析功能的基本方法。

ArcGIS Engine高级功能开发

3 叠置分析

叠置分析是GIS中一种常见的分析功能,它是将有关主题层组成的各个数据层面进行叠置产生一个新的数据层面,其结果综合了原来两个或多个层面要素所具有的属性,同时叠置分析不仅生成了新的空间关系,而且还将输入的多个数据层的属性联系起来产生了新的属性关系。

ArcGIS中的叠置分析包含Union(叠置求并)、Intersect(叠置求交)、Identify(叠置标识)、Erase(叠置擦除)、Symmetrical Difference (叠置相交取反)、Update(叠置更新)等。这一小节,我们以叠置求交为例,介绍叠置分析的开发。叠置求交是保留两个图层公共部分的空间图形,并综合两个叠加图层的属性。如下图,反映了叠置求交的原理。

图 11叠置求交示意图

本节实习将介绍这种方法实现缓冲区分析,我们首先使用Geoprocessor方法实现一个简单的缓冲区分析功能,然后将缓冲区分析功能添加到我们的MyGIS项目中。

同样,ArcGIS的ArcToolBox中的分析工具提供了缓冲区分析的功能,本节实习我们首先使用Geoprocessor方法实现一个简单的缓冲区分析功能,然后将缓冲区分析功能添加到我们的MyGIS项目中。

程序运行前首先需要在D盘下新建一个名为Temp的文件夹,存放叠置分析生成的文件。

3.1 Geoprocessor实现叠置分析

叠置分析我们同样使用Geoprocessor工具来实现。

3.1.1 添加控件

新建一个C#.Net项目,项目名称为OverLay,将Form1的名字设置为MainForm,并添加ToolbarControl 、MapControl、TOCControl、LicenceControl和Button等五个控件。并将ToolbarControl 、TOCControl的伙伴控件设为MapControl,Button控件的Name属性设定为btnIntersect,Text属性设定为“叠置求交”。控件布局效果如下图所示。

ArcGIS Engine高级功能开发

图 12控件布局效果

在ToolbarControl 加载添加数据按钮和地图浏览的功能按钮,如下图所示。

图 13添加按钮

3.1.2 代码添加及解释

首先添加如下引用:

using ESRI.ArcGIS.Carto; using ESRI.ArcGIS.AnalysisTools; using ESRI.ArcGIS.Geoprocessor; using ESRI.ArcGIS.Geoprocessing;

ArcGIS Engine高级功能开发

与缓冲区分析的实现类似,在使用Geoprocessor工具实现叠置分析时,需要首先定义一个Geoprocessor对象,因为命名空间“ESRI.ArcGIS.Geoprocessing”也包含Geoprocessor类,为了避免混淆,我们使用命名空间来定义Geoprocessor,然后设置Geoprocessor中的环境参数,这里我们使用默认参数。然后定义一个操作类,这里为Intersect,然后设置其操作参数,这里我们仅设置输入的要素,最后使用已定义的Geoprocessor对象执行即可。双击“生成缓存区”按钮,添加代码如下:

private void btnIntersect_Click(object sender, EventArgs e) {

//添加两个以上图层时才允许叠置 if (this.axMapControl1.LayerCount < 2) return;

ESRI.ArcGIS.Geoprocessor.Geoprocessor gp = new ESRI.ArcGIS.Geoprocessor.Geoprocessor();

//OverwriteOutput为真时,输出图层会覆盖当前文件夹下的同名图层 gp.OverwriteOutput=true;

//创建叠置分析实例

Intersect intersectTool = new Intersect(); //获取MapControl中的前两个图层

ILayer pInputLayer1 = this.axMapControl1.get_Layer(0); ILayer pInputLayer2 = this.axMapControl1.get_Layer(1); //转换为object类型

object inputfeature1 = pInputLayer1; object inputfeature2 = pInputLayer2; //设置参与叠置分析的多个对象

IGpValueTableObject pObject = new GpValueTableObjectClass(); pObject.SetColumns(2);

pObject.AddRow(ref inputfeature1); pObject.AddRow(ref inputfeature2); intersectTool.in_features = pObject; //设置输出路径

string strTempPath = @\;

string strOutputPath = strTempPath + pInputLayer1.Name + \ + pInputLayer2.Name + \;

intersectTool.out_feature_class=strOutputPath; //执行叠置分析

IGeoProcessorResult result = null;

result = gp.Execute(intersectTool, null) as IGeoProcessorResult;

//判断叠置分析是否成功

if (result.Status != ESRI.ArcGIS.esriSystem.esriJobStatus.esriJobSucceeded) MessageBox.Show(\叠置求交失败!\);

ArcGIS Engine高级功能开发

//设置输出路径

strOutputPath = txtOutputPath.Text;

//叠置分析结果

IGeoProcessorResult result = null;

//创建叠置分析实例,执行叠置分析

string strOverlay=cboOverLay.SelectedItem.ToString(); try {

//添加处理过程消息

txtMessage.Text = \开始叠置分析……\+\; switch (strOverlay) {

case \求交(Intersect)\:

Intersect intersectTool = new Intersect(); //设置输入要素

intersectTool.in_features = pObject; //设置输出路径

strOutputPath += strName + \ + \; intersectTool.out_feature_class = strOutputPath; //执行求交运算

result = gp.Execute(intersectTool, null) as IGeoProcessorResult; break; case \求并(Union)\:

Union unionTool = new Union(); //设置输入要素

unionTool.in_features = pObject; //设置输出路径

strOutputPath += strName + \ + \; unionTool.out_feature_class = strOutputPath; //执行联合运算

result = gp.Execute(unionTool, null) as IGeoProcessorResult; break;

case \标识(Identity)\:

Identity identityTool = new Identity(); //设置输入要素

identityTool.in_features = inputFeat; identityTool.identity_features = overlayFeat; //设置输出路径

strOutputPath += strName + \ + \; identityTool.out_feature_class = strOutputPath; //执行标识运算

result = gp.Execute(identityTool, null) as IGeoProcessorResult;

ArcGIS Engine高级功能开发

break; } }

catch (System.Exception ex) {

//添加处理过程消息

txtMessage.Text += \叠置分析过程出现错误:\ + ex.Message+\; }

//判断叠置分析是否成功

if (result.Status != ESRI.ArcGIS.esriSystem.esriJobStatus.esriJobSucceeded) txtMessage.Text+=\叠置失败!\; else {

this.DialogResult = DialogResult.OK;

txtMessage.Text += \叠置成功!\; } }

细心的同学可能会发现,Union和Intersect设置输入要素和叠置要素的方式是一致的,它们是将两种要素读入到IGpValueTableObject中,然后赋值给in_features,而Identity工具是针对in_features和 identity_features分别赋值。因为在ArcGIS的叠置分析中Union和Intersect两种工具可以针对两个以上的图层进行叠置运算,而Identity工具是针对两个要素的运算,其实质是使用叠置要素对输入要素进行更新的一个过程。

另外,Identity工具需要本机中具有ArcInfo级别的Licence权限,如果你的当前电脑没有安装ArcInfo,请在实现的过程中将Identity的相关代码进行屏蔽,如果装有ArcInfo,在运行程序之前,首先需要打开ArcGIS LicenceManager的服务。我们通过以下方式设置Licence权限。 进入到MyGIS的MainForm窗体的设计器界面,右键单击LicenceControl,选择菜单中的“属性”选项。选择Products中的ArcInfo选项。

图 17 LicenceControl设置

ArcGIS Engine高级功能开发

运行程序,点击菜单“叠置分析”,弹出叠置分析参数设置窗口,添加叠置分析要素文件,并设置输出路径如下。

图 18叠置分析参数设置

点击分析,可得到如下结果。

图 19叠置分析效果

3.2.3 小结

本节我们系统讲解了叠置分析功能的开发并进一步完善了MyGIS系统。当然,我们的工程中的叠置分析的功能还存在一些不足之处,比如叠置求交和叠置联合是针对两个或以上要素类进行的操作,我们这里仅实现了两个要素类的操作。如果您有兴趣,可以自己动手进行扩展。同时,您也可以尝试自己通过ArcEngine来实现ArcGIS中的其他分析操作,并添加到MyGIS中。

ArcGIS Engine高级功能开发

ArcGIS Engine高级功能开发

4 地图编辑

地图编辑功能涉及到比较复杂的地图与鼠标的交互以及事件的响应,ArcGIS提供了强大的地图编辑的相关功能。本节我们将尝试实现一些简单的地图编辑功能,包括点、线、面要素形状的创建和移动。通过本节希望你能掌握ArcEngine实现地图编辑的机制以及常用的地图编辑的接口。

4.1 添加控件

新建一个C#.Net项目,项目名称为OverLay,将Form1的名字设置为MainForm,Text属性设为“地图编辑”,并添加ToolbarControl 、MapControl、TOCControl、LicenceControl、四个Button、两个ComboBox、两个Label和一个GroupBox等控件。

将ToolbarControl 、TOCControl的伙伴控件设为MapControl,ToolbarControl 加载添加数据按钮和地图浏览的功能按钮。控件布局效果如下图所示。

图 20界面效果

控件属性设置如下:

表 3控件属性设置

控件类型 Label Label Name属性 Text属性 选择图层: 编辑任务: 控件说明 MapControl中的图层 编辑的方式 cboLayers载入图层名称 开始编辑状态 ComboBox cboLayers ComboBox cboTasks Button Button

btnRefreshLayers 更新图层 btnStartEditing 开始编辑

ArcGIS Engine高级功能开发

Button Button GroupBox

btnSave btnStopEditing 保存 结束编辑 地图编辑 保存编辑 结束编辑状态 控件容器 4.2 添加引用和代码

ArcEngine中的地图编辑使用IWorkspaceEdit接口来进行编辑状态的管理,在需要对指定的工作空间进行编辑时,首先使用IWorkspaceEdit获取该工作空间的数据,然后使用StartEditing方法开始编辑状态,StartEditOperation方法打开具体编辑的操作,编辑完成后,使用StopEditOperation方法关闭编辑操作,使用StopEditing方法关闭编辑状态,完成编辑。

在本例中,我们实现了新的点线面要素的创建和移动的功能,涉及到了比较复杂的鼠标与地图间的交互,这个功能的实现中,IDisplayFeedback是一个十分关键的接口,它具有涉及创建要素,移动要素、编辑节点等31个实现类,能够实现鼠标与地图交互中的事件的追踪,返回新的几何对象。

本例的实现,我们首先来添加一个编辑类,将涉及到的编辑的相关方法抽象到这个类中。在项目中添加“Edit”类。添加如下引用。

using System.Windows.Forms; using ESRI.ArcGIS.Carto; using ESRI.ArcGIS.Geodatabase; using ESRI.ArcGIS.Geometry; using ESRI.ArcGIS.Display;

定义如下成员变量。

private bool mIsEditing; //编辑状态 private bool mHasEditing; //是否编辑 private IFeatureLayer mCurrentLayer; //当前编辑图层 private IWorkspaceEdit mWorkspaceEdit; //编辑工作空间 private IMap mMap; //地图

private IDisplayFeedback mDisplayFeedback; //用于鼠标与控件进行可视化交互 private IFeature mPanFeature; //移动的要素

带参数的构造函数和默认构造函数如下:

public Edit(IFeatureLayer editLayer, IMap map) {

mCurrentLayer = editLayer; this.mMap = map; }

///

/// 默认构造函数 /// public Edit()

ArcGIS Engine高级功能开发

{ }

添加编辑状态相关属性和方法。

///

/// 返回编辑状态 /// /// public bool IsEditing() {

return mIsEditing; }

///

/// 是否编辑 /// /// public bool HasEdited() {

return mHasEditing; }

///

/// 开始编辑 ///

public void StartEditing() {

//获取要素工作空间

IFeatureClass pFeatureClass = mCurrentLayer.FeatureClass; IWorkspace pWorkspace = (pFeatureClass as IDataset).Workspace; mWorkspaceEdit = pWorkspace as IWorkspaceEdit; if (mWorkspaceEdit == null) return; //开始编辑

if (!mWorkspaceEdit.IsBeingEdited()) {

mWorkspaceEdit.StartEditing(true); mIsEditing = true; } }

///

/// 保存编辑 ///

/// public void SaveEditing(bool save)

ArcGIS Engine高级功能开发

{

if (!save) {

mWorkspaceEdit.StopEditing(false); }

else if (save && mHasEditing && mIsEditing) {

mWorkspaceEdit.StopEditing(true); }

mHasEditing = false; }

///

/// 停止编辑 ///

///

this.SaveEditing(save); mIsEditing = false; }

下面添加鼠标与地图的交互事件,包括创建要素时鼠标的MouseDown事件、MouseMove事件和DoubleClick事件,移动要素时鼠标的PanMouseDown事件、MouseMove事件和MouseUp事件。

创建要素时首先在MouseDown事件中获取鼠标点击的点位,若图层为点图层,则直接创建要素,若为线图层或面图层,则作为第一个节点,以后每次点击都会添加一个节点,直到双击鼠标完成要素的创建。创建要素时的MouseDown事件在这里定义为CreateMouseDown。代码如下:

public void CreateMouseDown(double mapX, double mapY) {

//鼠标点击位置

IPoint pPoint = new PointClass(); pPoint.PutCoords(mapX, mapY);

INewLineFeedback pNewLineFeedback; INewPolygonFeedback pNewPolygonFeedback; //判断编辑状态 if (mIsEditing) {

//针对线和多边形,判断交互状态,第一次时要初始化,再次点击则直接添加节点 if(mDisplayFeedback==null) {

//根据图层类型创建不同要素

ArcGIS Engine高级功能开发

switch (mCurrentLayer.FeatureClass.ShapeType) {

case esriGeometryType.esriGeometryPoint: //添加点要素 AddFeature(pPoint); break;

case esriGeometryType.esriGeometryPolyline:

mDisplayFeedback = new NewLineFeedbackClass(); //获取当前屏幕显示

mDisplayFeedback.Display = ((IActiveView)this.mMap).ScreenDisplay; pNewLineFeedback = mDisplayFeedback as INewLineFeedback; //开始追踪

pNewLineFeedback.Start(pPoint); break;

case esriGeometryType.esriGeometryPolygon:

mDisplayFeedback = new NewPolygonFeedbackClass();

mDisplayFeedback.Display = ((IActiveView)this.mMap).ScreenDisplay; pNewPolygonFeedback = mDisplayFeedback as INewPolygonFeedback;

//开始追踪

pNewPolygonFeedback.Start(pPoint); break; } }

else //第一次之后的点击则添加节点 {

if (mDisplayFeedback is INewLineFeedback) {

pNewLineFeedback = mDisplayFeedback as INewLineFeedback; pNewLineFeedback.AddPoint(pPoint); }

else if (mDisplayFeedback is INewPolygonFeedback) {

pNewPolygonFeedback = mDisplayFeedback as INewPolygonFeedback; pNewPolygonFeedback.AddPoint(pPoint); } } } }

MouseMove事件在创建要素时和移动要素时可以共用,代码如下:

public void MouseMove(double mapX, double mapY)

ArcGIS Engine高级功能开发

{

if (mDisplayFeedback == null) return;

//获取鼠标移动点位,并移动至当前点位 IPoint pPoint = new PointClass(); pPoint.PutCoords(mapX, mapY); mDisplayFeedback.MoveTo(pPoint); }

创建要素时的DoubleClick事件代码如下:

public void CreateDoubleClick(double mapX, double mapY) {

if (mDisplayFeedback == null) return;

IGeometry pGeometry=null; IPoint pPoint = new PointClass(); pPoint.PutCoords(mapX, mapY);

INewLineFeedback pNewLineFeedback; INewPolygonFeedback pNewPolygonFeedback; IPointCollection pPointCollection; //判断编辑状态 if (mIsEditing) {

if (mDisplayFeedback is INewLineFeedback) {

pNewLineFeedback = mDisplayFeedback as INewLineFeedback; //添加点击点

pNewLineFeedback.AddPoint(pPoint); //结束Feedback

IPolyline pPolyline = pNewLineFeedback.Stop(); pPointCollection = pPolyline as IPointCollection; //至少两点时才创建线要素

if (pPointCollection.PointCount < 2)

MessageBox.Show(\至少需要两点才能建立线要素!\, \提示\); else

pGeometry = pPolyline as IGeometry; }

else if (mDisplayFeedback is INewPolygonFeedback) {

pNewPolygonFeedback = mDisplayFeedback as INewPolygonFeedback; //添加点击点

pNewPolygonFeedback.AddPoint(pPoint);

本文来源:https://www.bwwdw.com/article/fsl3.html

Top