ArcGIS Engine中如何调用GP工具(一)

0
分享 2017-04-13
相信用过ArcGIS的用户都会有这样一个感受,那就是功能太强大了!尤其是其提供了超过900个地理处理(Geoprocessing,简称GP)工具,可以快速地实现数据分析、数据管理以及数据转换等功能。在ArcGIS Engine的开发过程中也必不可少的会遇到调用GP工具的问题,这也是用户问的最多的一类问题,那么ArcGIS Engine中如何调用GP工具?参数怎么写?有哪些注意事项?如何获取报错信息?今天,就把Engine中调用GP工具的相关问题总结一下,相信一定会让你有所收获。
一、如何调用GP工具?
调用GP工具的方式有两种:一种是使用Geoprocessing类,工具参数使用IVariantArray方式输入;另一种是使用Geoprocessor托管类,创建工具对象,参数作为该工具对象的属性输入。下面就分别来看下这两种调用方式的具体实现。
使用Geoprocessing类:
主要分为以下几步:
1,添加ESRI.ArcGIS.Geoprocessing引用,仅需要引用该类库 2,创建geoprocessor对象,注意这里的P是大写 3,如果调用自定义工具,需要添加自定义工具箱的路径 4,创建IVariantArray对象,用于存放工具参数 5,调用geoprocessor的Execute方法
下面来看具体代码(以调用Buffer工具为例):
A,调用系统工具:
IGeoProcessor2 gp = new GeoProcessorClass();
//设置gp.OverwriteOutput是指可以用一个输出执行多次工具
gp.OverwriteOutput = true;
IGeoProcessorResult result = new GeoProcessorResultClass();
// Create a variant array to hold the parameter values.
IVariantArray parameters = new VarArrayClass();
object sev = null;
try
{
// Populate the variant array with parameter values.
parameters.Add(FileGDBPath + "\\LotIds");
parameters.Add(FileGDBPath + "\\LotIds_Buffer");
parameters.Add("100 Feet");

// Execute the tool.
result = gp.Execute("Buffer_analysis", parameters, null);
// Print geoprocessring messages.
Console.WriteLine(gp.GetMessages(ref sev));
}
catch (Exception ex)
{
// Print a generic exception message.
Console.WriteLine(ex.Message);
// Print geoprocessing execution error messages.
Console.WriteLine(gp.GetMessages(ref sev));
}




B,调用自定义工具(Model中添加Buffer工具):
// Initialize the geoprocessor.
IGeoProcessor2 gp = new GeoProcessorClass();
// Add the BestPath toolbox.
gp.AddToolbox(tbxPath);
// Generate the array of parameters.
IVariantArray parameters = new VarArrayClass();
parameters.Add(FileGDBPath + "\\LotIds");
parameters.Add("100 Feet");
parameters.Add(FileGDBPath + "\\LotIds_Buffer2");
object sev = null;
try
{
// Execute the model tool by name.
gp.Execute("Model2", parameters, null);
Console.WriteLine(gp.GetMessages(ref sev));
}
catch (Exception ex)
{
// Print geoprocessing execution error messages.
Console.WriteLine(gp.GetMessages(ref sev));
}




总结下使用IVariantArray的注意事项:
1,执行工具时,传入的第一个参数Name为工具的语法名称,语法名称是工具名称_工具箱别名方式,以便唯一确定该工具。举个例子,比如Clip工具,Analysis和Data Management工具箱中都有Clip,这时通过工具的语法名称就可以区别,前者是Clip_analysis,后者是Clip_management。再比如用到的Buffer工具,不是直接传入”Buffer”,而是输入”Buffer_analysis”,具体可以打开该工具的Tool Help,Synatx关键字下面显示的即为工具的语法名称。

2,参数是有顺序的。其顺序以工具帮助中的参数顺序为准。因为ArcMap中有的工具界面的参数显示顺序与该Tool Help中的不一致。比如Buffer工具,工具界面如下:

其Tool Help中的参数顺序如下:

Method参数的顺序与工具界面中是不同的。再看下ArcMap中执行该工具成功后Results界面的内容,如图:

也验证了其顺序是与Tool Help中相一致的。
3,如果必写参数前有可选参数,那么可选参数也是要赋值的,如果想要略过该参数,则传入空字符串(即采用该参数的默认值),以保证参数的顺序是正确的。
4,调用自定义工具时,注意自定义工具的执行名称是Name而非Label,如下图:显示的名称为custom_BufferTool,但需要使用Name,即Model2,这是很多用户容易犯的错误,需要注意。

说完第一种方式的实现方法和注意事项,下面来看第二种调用方式:
使用Geoprocessor托管类:
主要分为以下几步:
1,添加ESRI.ArcGIS.Geoprocessor引用,如果想要获取执行结果result或者list datasets还需要引用ESRI.ArcGIS.Geoprocessing 2,除此之外,需要添加该工具所在工具箱的引用。比如使用Buffer工具,则需要添加ESRI.ArcGIS.AnalysisTools引用,使用IDW工具,则需要添加ESRI.ArcGIS.SpatialAnalystTools引用,以此类推。 3,创建geoprocessor对象 4,如果调用自定义工具,需要添加自定义工具箱的路径 5,创建工具对象(tool process object)并且设置参数 6,调用geoprocessor的Execute方法
下面来看具体代码(同样以调用Buffer工具为例):
A,调用系统工具:
// Create the geoprocessor. 
Geoprocessor GP = new Geoprocessor();
GP.OverwriteOutput = true;
// Create the tool process object.
ESRI.ArcGIS.AnalysisTools.Buffer bufferTool = new
ESRI.ArcGIS.AnalysisTools.Buffer();
// Set parameter values.
bufferTool.in_features = FileGDBPath + "\\LotIds";
bufferTool.out_feature_class = FileGDBPath + "\\LotIds_BufferSystem";
bufferTool.buffer_distance_or_field = "100 Feet";
object sev = null;
try
{
// Execute the tool.
GP.Execute(bufferTool, null);
Console.WriteLine(GP.GetMessages(ref sev));
}
catch (Exception ex)
{
// Print geoprocessing execution error messages.
Console.WriteLine(GP.GetMessages(ref sev));
}

}




B,调用自定义工具:
由于自定义工具箱没有任何托管类,因此,最简单的方式就是使用IVariantArray根据工具的Name执行(Geoprocessor对象的Execute方法实现了该重载)。
// Initialize the geoprocessor.
Geoprocessor GP = new Geoprocessor();
GP.OverwriteOutput = true;
// Add the BestPath toolbox.
GP.AddToolbox(tbxPath);
// Generate the array of parameters.
IVariantArray parameters = new VarArrayClass();
parameters.Add(FileGDBPath + "\\LotIds");
parameters.Add("100 Feet");
parameters.Add(FileGDBPath + "\\LotIds_BufferCustomArray2");
object sev = null;
try
{
// Execute the model tool by name.
GP.Execute("Model2", parameters, null);
Console.WriteLine(GP.GetMessages(ref sev));
}
catch (Exception ex)
{
// Print geoprocessing execution error messages.
//Console.WriteLine(GP.GetMessages(ref sev));
for (int i = 0; i < GP.MessageCount; i++)
Console.WriteLine(GP.GetMessage(i));
}

}




顺便提一下,如果就想用调用系统工具(比如工具变量.参数)的方法调用自定义工具,可以使用ArcGIS ToolBox Reference(如下图),将该自定义工具箱生成为dll,然后添加该引用后就可以正常使用了,不过10.4版本之后貌似没有ArcGIS Toolbox Reference了。

详细信息参考How to run a geoprocessing tool
Tips:调用GP工具时使用的是相同的框架,只需要改变其中的具体的工具及参数即可。
下面总结下各自的优缺点:
第一种方式:
优点:只需要添加Geoprocessing引用,所有工具都可以使用工具的语法名称来执行,无需添加该工具所在工具箱的引用,参数统一使用IVariantArray方式输入;
缺点:参数有严格顺序,必写参数前有可选参数也需要设置,顺序写错经常导致执行失败。
第二种方式:
优点:参数无顺序,仅根据工具对象的属性输入即可,可以只输入必写参数,参数环节不容易出错;
缺点:除添加Geoprocessor引用外,还需要知道工具所在的工具箱名称,添加其工具箱的引用,如果调用工具较多,可能需要添加很多引用。
介绍完调用GP工具的两种方式,接下来就是用户最关注的两部分内容了,一个是GP工具的参数如何写?有哪些注意事项;另一个就是假如工具执行失败了,如何获取详细的报错信息,比如怎么判断是参数错误还是许可错误。
二、GP工具参数写法的注意事项
1,如果GP工具的参数类型是要素类,要素图层,栅格数据,栅格图层的话,最好使用要素类或者栅格数据的绝对路径,这样最稳定。如果传入AO对象,比如IFeatureLayer、IFeatureClass、IRasterDataset、IRasterLayer等,不太稳定,有时可以成功,有时则失败,所以强烈推荐使用数据的绝对路径方式。还有一点需要注意就是要素类的路径中最好不要含有中文、空格等特殊字符、路径不要过程,并且需要对该数据具有读写权限。
2,如果要素类存储在SDE中,怎么写呢?可以使用该.sde连接文件的绝对路径+要素类名称的写法,比如: @”C:\Users\Xinying\AppData\Roaming\ESRI\Desktop10.3\ArcCatalog\Connection to 192.168.220.131.sde\SDE.polygon”;当然这是使用的ArcCatalog中自动生成的.sde文件,如果没有或者不想使用该连接文件的话也可以使用IWorkspaceFactory.Create()方法或者GP工具Create ArcSDE Connection File根据参数来创建.sde连接文件。
3,GP工具的参数不会写或者写法有误的处理技巧:可以先在ArcMap中使用相同参数执行该GP工具成功后,然后在菜单栏–>Geoprocessing–>Results中打开Results窗口,查看刚才执行成功的GP历史,在Inputs项中查看或直接复制各参数的填写方式到代码中即可。

4,如果工具中需要输入多个要素类,参数怎么写?比如Intersect_analysis工具,如果对两个要素类求交可以这么写:intersect.in_features = @”C:\Users\a\Desktop\test\1.shp;C:\Users\a\Desktop\test\2.shp”; 其实在Result界面有其分隔符的写法即分号。其它工具也类似,比如:Reclassify工具,其映射参数可以这样写reclassify.remap = “589 1070 1;1070 1555 2;1555 2169 3;2169 3311 4”; 不同类别用分号隔开,同一类别的最大最小值用空格隔开。再比如Clip_management工具,其范围可以这样写clip.rectangle = “-117.35334730268 33.8297125828826 -116.792366370644 34.4768962586111”;中间用空格隔开。再强调一下:最保险并且准确的就是ArcMap执行成功后,在Results界面复制其写法。
5,如果涉及到空间参考的话也可以直接复制:
Project.Output_Coordinate_System = "PROJCS['CGCS2000_3_Degree_GK_CM_108E',GEOGCS['GCS_China_Geodetic_Coordinate_System_2000',DATUM['D_China_2000',SPHEROID['CGCS2000',6378137.0,298.257222101]],PRIMEM['Greenwich',0.0],UNIT['Degree',0.0174532925199433]],PROJECTION['Gauss_Kruger'],PARAMETER['False_Easting',500000.0],PARAMETER['False_Northing',0.0],PARAMETER['Central_Meridian',108.0],PARAMETER['Scale_Factor',1.0],PARAMETER['Latitude_Of_Origin',0.0],UNIT['Meter',1.0]]";

三、如何获取详细报错信息
方法就是把执行GP的语句放进try-catch-finally的结构体中,并用IGeoProcessor.GetMessage();尝试获取具体的报错信息,如许可级别不够、参数错误等。
举个例子,比如上面执行Buffer工具时,不小心把bufferTool.buffer_distance_or_field = “100 Feet”; 参数写成了“‘100 Feet’”,如果通过最开始那种写法是获取不了任何报错信息的,如下图,输出错误信息为null:

但是如果这样写:
try
{
IGeoProcessorResult2 result = GP.Execute(bufferTool, null) as IGeoProcessorResult2;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "GP Error");
}
finally
{
System.Text.StringBuilder sb = new System.Text.StringBuilder();
for (int i = 0; i < GP.MessageCount; i++)
sb.AppendLine(GP.GetMessage(i));
if (sb.Capacity > 0) MessageBox.Show(sb.ToString(), "GP Messages");
}




则可以获取下面信息:

会提示用户是参数无效,并且告诉用户是 ‘100 Feet’ 这个参数有误,有了这个信息就很方便我们回去查找到这个参数进而进行修改了。
再比如说如果对线要素类做缓冲区,ArcMap中可以设置在线的左侧或右侧缓冲以及端点处是圆头还是平头缓冲,这样的话Engine许可就用不了了,具体见该工具的Tool Help:

那如果程序中初始化的Engine许可,就会报没有license错误,如下图:

很方便定位问题所在。
Demo
使用ArcGIS Engine 10.5,Visual Studio 2013编写,界面为:

工程下载地址:
GP_ArcGISEngine
文章来源:http://blog.csdn.net/xinying180/article/details/70158549

5 个评论

很好地参考资料,今天才从网上找到,没想到您已经转过来了
mark
你好,请问gp工具该如何释放那,我利用循环调用dissolve工具,但是会堵塞,利用releaseComObject的方式会出现异常,该怎么办那?
GP只需要初始化一次的,没必要执行一个GP就初始化一次
感谢您的回答,并且解决了问题,发现每次都是您在回答我们的问题 非常感谢,希望自己也可以学到更多

要回复文章请先登录注册