在ArcGIS Engine的开发过程中也必不可少的会遇到调用GP工具的问题,调用GP工具的方式有两种:一种是使用Geoprocessing类;另一种是使用Geoprocessor托管类。两者也可能混合使用。
一、GP工具的调用方式
以调用系统工具Dissolve为例:
准备数据:
1、使用Geoprocessing类
工具参数使用IVariantArray方式输入;且参数是有顺序的,其顺序以工具帮助中的参数顺序为准。 如果想要略过某个参数,则传入空字符串(即采用该参数的默认值),以保证参数的顺序是正确的。工具的名称也要按照语法中的写。例如Dissove工具的名称为"Dissolve_management"。顺序写错导致执行失败。
private void Dissolve(IFeatureClass sourceFClass)
{
ESRI.ArcGIS.Geoprocessing.IGeoProcessor gp = new ESRI.ArcGIS.Geoprocessing.GeoProcessorClass();
gp.OverwriteOutput = true;
//除了使用IGeoProcessorResult接口获取GP处理结果外,还可以直接将GP的输出结果写入FeatureClass中,方便进行使用
ESRI.ArcGIS.Geoprocessing.IGeoProcessorResult result = new ESRI.ArcGIS.Geoprocessing.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("F:\\GIS测试数据\\新建文件地理数据库.gdb\\ABCD");//parameters.Add(sourceFClass);
parameters.Add("F:\\GIS测试数据\\新建文件地理数据库.gdb\\diss");
ESRI.ArcGIS.Geoprocessing.IGpValueTableObject pObject = new ESRI.ArcGIS.Geoprocessing.GpValueTableObjectClass(); //对多个字段进行融合添加
pObject.SetColumns(1);
pObject.AddRow("MC");
pObject.AddRow("DM");
parameters.Add(pObject); //等同于parameters.Add("MC;DM");
parameters.Add(""); //传入空值,保证顺序正确
parameters.Add("SINGLE_PART"); // 等同于parameters.Add("false");
// Execute the tool.
result = gp.Execute("Dissolve_management", parameters, null);
IFeatureClass dealFclss = gp.Open(result.ReturnValue) as IFeatureClass;
}
catch (Exception ex)
{
// geoprocessing execution error messages.
gp.GetMessages(ref sev); //不知为什么返回一直为null
ReturnMessages(gp);
}
}
2、使用Geoprocessor托管类
需要创建工具对象,参数作为该工具对象的属性输入。需要添加该工具的工具箱的引用,例如Dissolve工具需要添加ESRI.ArcGIS.DataManagementTools引用。
private void Dissolve(IFeatureClass sourceFClass)
{
ESRI.ArcGIS.Geoprocessor.Geoprocessor gp = new ESRI.ArcGIS.Geoprocessor.Geoprocessor();
gp.OverwriteOutput = true; //是否覆盖原文件
try
{
ESRI.ArcGIS.DataManagementTools.Dissolve diss = new ESRI.ArcGIS.DataManagementTools.Dissolve();
diss.in_features = "F:\\GIS测试数据\\新建文件地理数据库.gdb\\ABCD";//sourceFClass; 可以填写文件路径或则要素类
diss.out_feature_class = "F:\\GIS测试数据\\diss2.SHP";//"F:\\GIS测试数据\\新建文件地理数据库.gdb\\AC";
diss.multi_part = "false"; //Boolean只能填写"false"或"true"
diss.dissolve_field = "MC;DM";
gp.Execute(diss, null);
//IGeoProcessorResult result = (IGeoProcessorResult)gp.Execute(diss,null);
////除了使用IGeoProcessorResult接口获取GP处理结果外,还可以直接将GP的输出结果写入FeatureClass中,方便进行使用
//IFeatureClass dealFclss = gp.Open(result.ReturnValue) as IFeatureClass;
}
catch
{
ReturnMessages(gp);
}
}
工具执行后效果为:
二、GP工具参数写法的注意事项
1,如果GP工具的参数类型是要素类,要素图层,栅格数据,栅格图层的话,最好使用要素类或者栅格数据的绝对路径,这样最稳定。如果传入AO对象,比如IFeatureLayer、IFeatureClass、IRasterDataset、IRasterLayer等,不太稳定,有时可以成功,有时则失败,所以强烈推荐使用数据的绝对路径方式。还有一点需要注意就是要素类的路径中最好不要含有中文、空格等特殊字符、路径不要过长,并且需要对该数据具有读写权限。
2,如果要素类存储在SDE中,怎么写呢?可以使用该.sde连接文件的绝对路径+要素类名称的写法,比如: @”C:\Users\Feng\AppData\Roaming\ESRI\Desktop10.2\ArcCatalog\连接到 127.0.0.1.sde\SDE.diss”;当然这是使用的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界面复制其写法。
三、获取GP详细报错信息
方法就是把执行GP的语句放进try-catch-finally的结构体中;尝试获取具体的报错信息,如许可级别不够、参数错误等。
/// <summary>
/// 获取GP工具执行后信息
/// </summary>
/// <param name="gp">gp对象(工具调用者)</param>
/// <returns></returns>
private string ReturnMessages(object gpr)
{
string ms = "";
if (gpr is ESRI.ArcGIS.Geoprocessor.Geoprocessor gp)
{
if (gp.MessageCount > 0)
{
for (int Count = 0; Count <= gp.MessageCount - 1; Count++)
{
ms += "$" + gp.GetMessage(Count) + "\n\n";
}
}
}
else if(gpr is ESRI.ArcGIS.Geoprocessing.IGeoProcessor gp2)
{
if (gp2.MessageCount > 0)
{
for (int Count = 0; Count <= gp2.MessageCount - 1; Count++)
{
ms += "$" + gp2.GetMessage(Count) + "\n\n";
}
}
}
return ms;
}