ArcGIS_Engine二次开发——提高篇
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
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 (yerCount != 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 < yerCount;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.3MyGIS中添加鹰眼
在上一讲中的最后一节,我们创建了一个简单的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,这部分的重点是鹰眼视图和主视图之间的事件交互。
推荐您仔细结合例子程序查看代码,如果需要获得进一步的信息,请查看帮助系统。
如果您对这一小节的内容比较熟悉了,就可以开始学习本章最后一小节的内容了。
在下一小节中,我们将尝试添加缓冲区分析功能。
2缓冲区分析
缓冲区分析指为了识别某一地理实体或空间物体对其周围地物影响度而在其周围建立的具有一定宽度的区域,以确定哪些实体落在了被影响的区域范围之内。
缓冲区分析与缓冲区查询不同,缓冲区查询是不破坏原有空间目标的关系,只是检索到该缓冲区范围内涉及到的目标。
而缓冲区分析是根据设定的距离条件对一类地物建立缓冲区多边形,存储到一个新的图层中。
然后再将新的图层与需要进行缓冲区分析的图层进行叠置分析,得到所需要的结果。
因此,缓冲区分析实际上进行了两步的操作,第一步是建立缓冲区图层,第二步是进行叠置剪裁分析。
缓冲区分析适用于点、线、面对象,如点状的居民点、线状的河流和面状的作物分布区等,只要地理实体能对周围一定区域形成影响即可使用这种分析方法。
图6点、线、面的缓冲区分析
ArcGIS的ArcToolBox中的分析工具提供了缓冲区分析的功能,本节实习我们首先使用Geoprocessor方法实现一个简单的缓冲区分析功能,然后将缓冲区分析功能添加到我们的MyGIS项目中。
程序运行前首先需要在D盘下新建一个名为Temp的文件夹,存放叠置分析生成的文件。
2.1Geoprocessor实现缓冲区分析
为了降低开发难度和提高开发效率,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属性设定为“缓冲区分析”。
控件布局效果如下图所示。
图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类,为了避免混淆,我们使用命
名空间来定义Geoprocessor,然后设置Geoprocessor中的环境参数,这里我们使用默认参数。
然后定义一个操作类Buffer,并设置参数,生成缓冲区的参数包含原始图层,缓冲半径和输出路径,最后使用已定义的Geoprocessor对象执行即可。
双击“生成缓存区”按钮,添加代码如下:
private void btnBuffer_Click(object sender, EventArgs e)
{
//判断MapControl中是否包含图层
if (yerCount == 0)
return;
//获取MapControl中第一个图层
ILayer pLayer = this.axMapControl1.Map.get_Layer(0);
//输出路径,可以自行指定
string strOutputPath = @"D:\Buffer.shp";
//缓冲半径
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("图层" + + "缓冲区生成失败!");
else
{
MessageBox.Show("缓冲区生成成功!");
//将生成图层加入MapControl
int index = stIndexOf("\\");
this.axMapControl1.AddShapeFile(strOutputPath.Substring(0, index), strOutputPath.Substring(index));
}
}
运行程序,添加一个图层(多个图层时本例中默认选择的图层为第一个图层),点击“生
成缓冲区”,运行结果如图。
图9缓冲区生成效果
2.1.3小结
本例中,我们使用Geoprocessor工具实现了缓冲区分析。
从中我们可以得到Geoprocessor工具使用的一般方法,在使用Geoprocessor时,一般需先定义一个Geoprocessor 对象,然后设置该对象的参数,如本例中的OverwriteOutput,再定义一个具体的操作类,如本例中的Buffer类,在设置完操作类的参数后,则通过Geoprocessor的Excute函数来执行。
至此,我们已经实现了一个简单的缓冲区分析的功能,从中我们学习了Geoprocessor 的使用方法。
下一节我们讲对缓冲区份分析功能做进一步的改进,使其具有更强的适用性,并将这个功能添加到MyGIS中。
2.2MyGIS中添加缓冲区分析
我们在使用缓冲区分析时,需要设定原始的图层,缓冲半径以及生成缓冲区的保存路径。
本节我们将在上一节的基础上进一步实现缓冲区分析,实现缓冲图层,缓冲半径和保存路径的可选设置。
2.2.1添加控件
打开项目MyGIS,在MyGIS的主菜单添加一个新的菜单项“空间分析”,并添加子菜单“缓冲区分析”,Name属性修改为“menuBuffer”。
项目中添加一个新的窗体,名称为“BufferForm”,Name属性设为“缓冲区分析”,添加四个Label、一个ComboBox、两个TextBox、三个Button控件,控件属性设置如下:
表1控件属性设置
控件类型Name属性Text属性控件说明
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;
//遍历图层,获取与名称匹配的图层
for (int i = 0; i < yerCount; i++)
{
ILayer pLayer = this.mHookHelper.FocusMap.get_Layer(i);
if ( == 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 ==
yerCount)
return;
//获取图层名称并加入cboLayers
for (int i = 0; i < yerCount; i++)
{
ILayer pLayer = this.mHookHelper.FocusMap.get_Layer(i);
cboLayers.Items.Add();
}
//cboLayers控件中默认显示第一个选项
if (cboLayers.Items.Count > 0)
cboLayers.SelectedIndex = 0;
//设置生成文件的默认输出路径和名称
string tempDir = @"D:\Temp\";
txtOutputPath.Text = bine(tempDir, ((string)cboLayers.SelectedItem + "_buffer.shp"));
//设置默认地图单位
lblUnits.Text = Convert.ToString(mHookHelper.FocusMap.MapUnits);
}
双击路径设置按钮,进入代码编辑界面,添加如下代码:
private void btnOutputLayer_Click(object sender, EventArgs e)
{
//定义输出文件路径
SaveFileDialog saveDlg = new SaveFileDialog();
//检查路径是否存在
saveDlg.CheckPathExists = true;
saveDlg.Filter = "Shapefile (*.shp)|*.shp";
//保存时覆盖同名文件
saveDlg.OverwritePrompt = true;
saveDlg.Title = "输出路径";
//对话框关闭前还原当前目录
saveDlg.RestoreDirectory = true;
saveDlg.FileName = (string)cboLayers.SelectedItem + "_buffer.shp";
//读取文件输出路径到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)) ||
".shp" != System.IO.Path.GetExtension(txtOutputPath.Text))
{
MessageBox.Show("输出路径错误!");
return;
}
//判断图层个数
if (yerCount == 0)
return;
//获取图层
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("图层" + + "缓冲区生成失败!");
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;
//缓冲区图层载入到MapControl
int index = stIndexOf("\\");
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 工具开发空间分析功能的基本方法。
3叠置分析
叠置分析是GIS中一种常见的分析功能,它是将有关主题层组成的各个数据层面进行叠置产生一个新的数据层面,其结果综合了原来两个或多个层面要素所具有的属性,同时叠置分析不仅生成了新的空间关系,而且还将输入的多个数据层的属性联系起来产生了新的属性关系。
ArcGIS中的叠置分析包含Union(叠置求并)、Intersect(叠置求交)、Identify(叠置标识)、Erase(叠置擦除)、Symmetrical Difference(叠置相交取反)、Update(叠置更新)等。
这一小节,我们以叠置求交为例,介绍叠置分析的开发。
叠置求交是保留两个图层公共部分的空间图形,并综合两个叠加图层的属性。
如下图,反映了叠置求交的原理。
图11叠置求交示意图
本节实习将介绍这种方法实现缓冲区分析,我们首先使用Geoprocessor方法实现一个简单的缓冲区分析功能,然后将缓冲区分析功能添加到我们的MyGIS项目中。
同样,ArcGIS的ArcToolBox中的分析工具提供了缓冲区分析的功能,本节实习我们首先使用Geoprocessor方法实现一个简单的缓冲区分析功能,然后将缓冲区分析功能添加到我们的MyGIS项目中。
程序运行前首先需要在D盘下新建一个名为Temp的文件夹,存放叠置分析生成的文件。
3.1Geoprocessor实现叠置分析
叠置分析我们同样使用Geoprocessor工具来实现。
3.1.1添加控件
新建一个C#.Net项目,项目名称为OverLay,将Form1的名字设置为MainForm,并添加ToolbarControl 、MapControl、TOCControl、LicenceControl和Button等五个控件。
并将ToolbarControl 、TOCControl的伙伴控件设为MapControl,Button控件的Name属性设定为btnIntersect,Text属性设定为“叠置求交”。
控件布局效果如下图所示。
图12控件布局效果
在ToolbarControl 加载添加数据按钮和地图浏览的功能按钮,如下图所示。
图13添加按钮
3.1.2代码添加及解释
首先添加如下引用:
using ESRI.ArcGIS.Carto;
using ESRI.ArcGIS.AnalysisTools;
using ESRI.ArcGIS.Geoprocessor;
using ESRI.ArcGIS.Geoprocessing;
与缓冲区分析的实现类似,在使用Geoprocessor工具实现叠置分析时,需要首先定义一个Geoprocessor对象,因为命名空间“ESRI.ArcGIS.Geoprocessing”也包含Geoprocessor类,为了避免混淆,我们使用命名空间来定义Geoprocessor,然后设置Geoprocessor中的环境参数,这里我们使用默认参数。
然后定义一个操作类,这里为Intersect,然后设置其操作参数,这里我们仅设置输入的要素,最后使用已定义的Geoprocessor对象执行即可。
双击“生成缓存区”按钮,添加代码如下:
private void btnIntersect_Click(object sender, EventArgs e)
{
//添加两个以上图层时才允许叠置
if (yerCount < 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 = @"D:\Temp\";
string strOutputPath = strTempPath + + "_" + + "_Intersect.shp";
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("叠置求交失败!");
else
{
MessageBox.Show("叠置求交成功!");
int index = stIndexOf("\\");
this.axMapControl1.AddShapeFile(strOutputPath.Substring(0, index), strOutputPath.Substring(index));
}
}
运行程序,添加叠置分析的数据,至少为两个图层,点击“叠置求交”,运行结果如图。
图14叠置求交效果
3.1.3小结
学习完这一小节,细心的同学会发现使用Geoprocessor实现叠置分析与实现缓冲区分析的基本思路是一致的,只是不同的操作方法设置了不同的参数。
另外,注意在进行叠置分析时要通过IGpValueTableObject接口加载多个要素。
请您仔细体会缓冲区分析和叠置求交分析的实现过程的相似点与不同点。
下一小节我们将对叠置分析进行进一步学习,并将多种叠置分析功能添加到MyGIS中。
3.2MyGIS中添加叠置分析
这一小节我们将在上一节开发的叠置求交的基础上,实现叠置分析中三种最常用的叠置方式,Union(叠置求并)、Intersect(叠置求交)和Identify(叠置标识)。
Intersect(叠置求交)在上节已经介绍,下面简要介绍一下Union(叠置求并)和Identify(叠置标识)。
叠置求并(Union)保留了两个叠置图层的空间图形和属性信息,进行叠置求和的两个图层须是多边形图层。
输入图层的一个多边形被叠加图层中的多边形弧段分割成多个多边形,输出图层综合了两个图层的属性。
所有要素都将被写入到输出要素类,输出结果具有来自与其叠置的输入要素的属性。
图15叠置求并(Union)
Identify(叠置标识)是以输入图层为界,保留边界以内两个多变形的所有多边形,出入图层切割后的多边形也被赋予叠加图层的属性。
如下图所示。
图16叠置标识(Identify)
在通过ArcEngine中的Geoprocessor实现这三种叠置分析时,我们将实现输入图层和叠置图层的可选设置,叠置方式的可选设置,输出路径的可选设置。
3.2.1添加控件
打开项目MyGIS,在MyGIS的主菜单“空间分析”中添加子菜单“叠置分析”,Name 属性修改为“menuOverlay”。
项目中添加一个新的窗体,名称为“OverlayForm”,Name属性设为“叠置分析”,添加四个Label、一个ComboBox、四个TextBox、五个Button控件和一个GroupBox,控件属性设置如下:
表2控件属性设置
控件类型Name属性Text属性Readonly属性控件说明
Label 输入要素:
Label 叠置要素:
Label 叠置方式:
Label 输出图层:
TextBox txtInputFeat True 保存输入要素路径
TextBox txtOverlayFeat True 保存叠置要素路径
TextBox txtOutputPath True 叠置结果的输出路径
TextBox
txtMessage True 叠置分析处理过程消息,Multiline属性设为True,
3.2.2代码添加及解释
该工程需要添加如下引用:
using ESRI.ArcGIS.Controls;
using ESRI.ArcGIS.AnalysisTools;
using ESRI.ArcGIS.Geoprocessing;
首先声明一个成员变量,用于保存叠置分析输出文件的路径。
public string strOutputPath;
OverlayForm在载入时需要加载三种叠置方式到cboOverlay中,并且需要设置缓冲区文件的默认输出路径,这里我们将默认输出路径设为“D:\Temp\”。
private void OverlayForm_Load(object sender, EventArgs e)
{
//加载叠置方式
this.cboOverLay.Items.Add("求交(Intersect)");
this.cboOverLay.Items.Add("求并(Union)");
this.cboOverLay.Items.Add("标识(Identity)");
this.cboOverLay.SelectedIndex = 0;
//设置默认输出路径
string tempDir = @"D:\Temp\";
txtOutputPath.Text = tempDir;
}
双击输入要素的文件选择按钮,进入代码编辑界面,添加代码如下:
private void btnInputFeat_Click(object sender, EventArgs e)
{
//定义OpenfileDialog
OpenFileDialog openDlg = new OpenFileDialog();
openDlg.Filter = "Shapefile (*.shp)|*.shp";
openDlg.Title = "选择第一个要素";
//检验文件和路径是否存在
openDlg.CheckFileExists=true;
openDlg.CheckPathExists=true;
//初试化初试打开路径
openDlg.InitialDirectory = @"D:\Temp\";
//读取文件路径到txtFeature1中
if (openDlg.ShowDialog()==DialogResult.OK)
{
this.txtInputFeat.Text=openDlg.FileName;
}
}
类似的,双击叠置要素的文件选择按钮,添加代码如下;
private void btnOverlayFeat_Click(object sender, EventArgs e) {
//定义OpenfileDialog
OpenFileDialog openDlg = new OpenFileDialog();
openDlg.Filter = "Shapefile (*.shp)|*.shp";
openDlg.Title = "选择第二个要素";
//检验文件和路径是否存在
openDlg.CheckFileExists = true;
openDlg.CheckPathExists = true;
//初试化初试打开路径
openDlg.InitialDirectory = @"D:\Temp\";
//读取文件路径到txtFeature2中
if (openDlg.ShowDialog() == DialogResult.OK)
{
this.txtOverlayFeat.Text = openDlg.FileName;
}
}
双击输出图层的路径选择按钮,添加代码如下:
private void btnOutputLayer_Click(object sender, EventArgs e) {
//定义输出文件路径
SaveFileDialog saveDlg = new SaveFileDialog();
//检查路径是否存在
saveDlg.CheckPathExists = true;
saveDlg.Filter = "Shapefile (*.shp)|*.shp";
//保存时覆盖同名文件
saveDlg.OverwritePrompt = true;
saveDlg.Title = "输出路径";
//对话框关闭前还原当前目录
saveDlg.RestoreDirectory = true;
saveDlg.FileName = (string)cboOverLay.SelectedItem + ".shp";
//读取文件输出路径到txtOutputPath
DialogResult dr = saveDlg.ShowDialog();
if (dr == DialogResult.OK)
txtOutputPath.Text = saveDlg.FileName;
}
双击“分析”按钮,添加代码如下。
private void btnOverLay_Click(object sender, EventArgs e)
{
//判断是否选择要素
if (this.txtInputFeat.Text==""||this.txtInputFeat.Text==null||
this.txtOverlayFeat.Text==""||this.txtOverlayFeat.Text==null) {
txtMessage.Text="请设置叠置要素!";
return;
}
ESRI.ArcGIS.Geoprocessor.Geoprocessor gp = new
ESRI.ArcGIS.Geoprocessor.Geoprocessor();
//OverwriteOutput为真时,输出图层会覆盖当前文件夹下的同名图层
gp.OverwriteOutput = true;
//设置参与叠置分析的多个对象
object inputFeat = this.txtInputFeat.Text;
object overlayFeat = this.txtOverlayFeat.Text;
IGpValueTableObject pObject = new GpValueTableObjectClass();
pObject.SetColumns(2);
pObject.AddRow(ref inputFeat);
pObject.AddRow(ref overlayFeat);
//获取要素名称
string str = System.IO.Path.GetFileName(this.txtInputFeat.Text);
int index = stIndexOf(".");
string strName = str.Remove(index);
//设置输出路径
strOutputPath = txtOutputPath.Text;
//叠置分析结果
IGeoProcessorResult result = null;
//创建叠置分析实例,执行叠置分析
string strOverlay=cboOverLay.SelectedItem.ToString();
try
{
//添加处理过程消息
txtMessage.Text = "开始叠置分析……"+"\r\n";
switch (strOverlay)
{
case"求交(Intersect)":
Intersect intersectTool = new Intersect();
//设置输入要素
intersectTool.in_features = pObject;
//设置输出路径
strOutputPath += strName + "_"+ "_intersect.shp";
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 + "_" + "_union.shp";
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 + "_"+ "_identity.shp";
identityTool.out_feature_class = strOutputPath;
//执行标识运算
result = gp.Execute(identityTool, null) as IGeoProcessorResult;
break;
}
}
catch (System.Exception ex)
{
//添加处理过程消息
txtMessage.Text += "叠置分析过程出现错误:" + ex.Message+"\r\n";
}
//判断叠置分析是否成功
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设置
运行程序,点击菜单“叠置分析”,弹出叠置分析参数设置窗口,添加叠置分析要素文件,并设置输出路径如下。
图18叠置分析参数设置
点击分析,可得到如下结果。
图19叠置分析效果
3.2.3小结
本节我们系统讲解了叠置分析功能的开发并进一步完善了MyGIS系统。
当然,我们的工程中的叠置分析的功能还存在一些不足之处,比如叠置求交和叠置联合是针对两个或以上要素类进行的操作,我们这里仅实现了两个要素类的操作。
如果您有兴趣,可以自己动手进行扩展。
同时,您也可以尝试自己通过ArcEngine来实现ArcGIS中的其他分析操作,并添加到MyGIS中。
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控件属性设置
控件类型Name属性Text属性控件说明
Label 选择图层:
Label 编辑任务:
ComboBox cboLayers MapControl中的图层
ComboBox cboTasks 编辑的方式
Button btnRefreshLayers 更新图层cboLayers载入图层名称
Button btnStartEditing 开始编辑开始编辑状态。