在ArcEngine时,GP无疑是GIS开发者的神器。自ArcEngine9.2开始新增一个程序集ESRI.ArcGIS.Geoprocessor,它能调用包含扩展模块在内的所有Geoprocessing工具。关于GP的使用问题,做如下总结:
1.许可问题
大家都知道,AE二次开发有两种许可定义方式:一是直接拖放License控件,右键设置其属性,另一种方式是使用IAoInitialize接口实现。但两者只需一种即可,建议使用后者。Program.cs文件Main函数中初始代码示例:
//绑定Runtime
if (!RuntimeManager.Bind(ProductCode.Engine))
{
if (!RuntimeManager.Bind(ProductCode.Desktop))
{
MessageBox.Show("不能绑定ArcGIS Runtime,应用程序即将关闭!");
return;
}
}
//初始化Advanced许可,还有Standard,Engine,Basic等
esriLicenseStatus licenseStatus = esriLicenseStatus.esriLicenseUnavailable;
IAoInitialize m_AoInitialize = new AoInitialize();
licenseStatus = m_AoInitialize.Initialize(esriLicenseProductCode.esriLicenseProductCodeAdvanced);
//检查扩展模块功能
licenseStatus = m_AoInitialize.CheckOutExtension(esriLicenseExtensionCode.esriLicenseExtensionCodeSpatialAnalyst);
2.概念区分
Geoprocessor与Geoprocessing有什么区别?
Geoprocessing是GIS三大视角之一,能够通过分析处理已存在的数据,在新的数据集中产生结果。可以简单地理解为ToolBoxs中的工具。
Geoprocessor是ArcEngine9.2新增的一个基于NET Framework2.0的托管类,所有的Geoprocessing工具,包括扩展工具,都是由Geoprocessor对象调用运行,Geoprocessor能够通过设置不同的环境参数,简化执行Geoprocessing工具的过程,并返回相应的处理结果。(来看《插件式GIS应用框架的设计与实现——基于C#和ArcGIS Engine9.2》,这是一本不错的书!)
所以,一般地,在进行开发调用GP之前要添加Geoprocessor和Geoprocessing两个引用:
using ESRI.ArcGIS.Geoprocessor;
using ESRI.ArcGIS.Geoprocessing;
3.寻找工具
在哪里去寻找我们需要的工具呢?
第一步,首先在ToolBox里找到要使用的工具,最好利用该工具测试一下实验数据,确保其正确性。工具右键属性可看到其英文名称。
第二步,去ESRI帮助中查找工具参数。在其中我们可以看到有哪些参数,分别是什么类型、含义,如果不知道怎么填写,可参考Python例子。
工具名称及对应命名空间:
工具名称 |
命名空间 |
3D Analyst tools |
ESRI.ArcGIS.Analyst3DTools |
Analysis tools |
ESRI.ArcGIS.AnalysisTools |
Conversion tools |
ESRI.ArcGIS.ConversionTools |
Data Management tools |
ESRI.ArcGIS.DataManagementTools |
Cartography tools |
ESRI.ArcGIS.CartographyTools |
Coverage tools |
ESRI.ArcGIS.CoverageTools |
Geocoding tools |
ESRI.ArcGIS.GeocodingTools |
Geostatistical Analyst tools |
ESRI.ArcGIS.GeostatisticalAnalystTools |
Linear Referencing tools |
ESRI.ArcGIS.LinearReferencingAnalystTools |
Multidimension tools |
ESRI.ArcGIS.MultidimensionTools |
Network Analyst tools |
ESRI.ArcGIS.NetworkAnalystTools |
Samples |
ESRI.ArcGIS.SamplesTools |
Spatial Analyst tools |
ESRI.ArcGIS.SpatialAnalystTools |
Spatial Statistics tools |
ESRI.ArcGIS.SpatialStatisticsTools |
第三步,查看它在哪个工具大类下,添加对应的引用,设置参数,调试运行即可。下表是EsriLicenseProduct,关于扩展许可详见esriLicenseExtensionCode
许可 |
代码 |
描述 |
esriLicenseProductCodeEngine |
10 |
Engine Product Code |
esriLicenseProductCodeEngineGeoDB |
20 |
Engine Enterprise GeoDatabase |
esriLicenseProductCodeArcServer |
30 |
ArcServer Product Code |
esriLicenseProductCodeBasic |
40 |
Basic Product Code |
esriLicenseProductCodeStandard |
50 |
Standard Product Code |
esriLicenseProductCodeAdvanced |
60 |
Advanced Product Code |
4.调用方式
以使用Buffer为例,调用GP实现缓冲区分析的方式:
方式一:实例化GP对象
//初始化GP
Geoprocessor GP = new Geoprocessor();
//初始化Buffer
ESRI.ArcGIS.AnalysisTools.Buffer buffer = new ESRI.ArcGIS.AnalysisTools.Buffer();
buffer.in_features = @"D\data\temp.gdb\road";
buffer.out_feature_class = @"D\data\temp.gdb\road_bf30";
buffer.buffer_distance_or_field = 30; //默认单位
//执行工具
GP.Execute(buffer, null);
方式二:VariantArray传递参数
Geoprocessor GP = new Geoprocessor();
GP.AddToolbox(@"C:\Program Files (x86)\ArcGIS\Desktop10.1\ArcToolbox\Toolboxes\Analysis Tools.tbx");
//使用IVariantArray传递参数
IVariantArray array = new VarArrayClass();
array.Add(@"D\data\temp.gdb\road");
array.Add(@"D\data\temp.gdb\road_bf30");
array.Add(30);
GP.Execute("Buffer", array, null);
当然,定义GP对象也有两种方法:一是通过引用ESRI.ArcGIS.Geoprocessing命名空间,使用IGeoProcessor2接口定义,注意其中的P是大写;二是使用Geoprocessor类。
private static IGeoProcessor2 GP = new GeoProcessorClass(); // using ESRI.ArcGIS.Geoprocessing;
private static Geoprocessor GP = new Geoprocessor(); // using ESRI.ArcGIS.Geoprocessor;
5.调试函数
如果参数设置正确,能够输出想要的结果,如果设置错误,则不能输入结果,也不知哪里错了,这是写了一个调试的函数。
/// <summary>
/// 执行GP
/// </summary>
/// <param name="mGP">GP对象</param>
/// <param name="process">GP工具</param>
/// <param name="TC"></param>
/// <returns>处理结果</returns>
public static IGeoProcessorResult Execute(Geoprocessor mGP, IGPProcess process, ITrackCancel TC)
{
tGeoResult = null;
mGP.OverwriteOutput = true; // 是否覆盖
try
{
tGeoResult = (IGeoProcessorResult)mGP.Execute(process, null);
ReturnMessages(mGP);
}
catch (System.Exception ex)
{
MessageBox.Show(ex.Message+"\n\n"+ex.StackTrace);
ReturnMessages(mGP); //当调试正确后注释本行
}
return tGeoResult;
}
private static void ReturnMessages(Geoprocessor gp)
{
string ms = "";
if (gp.MessageCount > 0)
{
for (int Count = 0; Count <= gp.MessageCount - 1; Count++)
{
ms +="$"+ gp.GetMessage(Count) + "\n\n";
}
}
MessageBox.Show(ms);
}
修改GP的执行:
//执行工具
Execute(GP,buffer,null); // GP.Execute(buffer, null);
6.运行结果
除了使用IGeoProcessorResult接口获取GP处理结果外,还可以直接将GP的输出结果写入FeatureClass中,方便进行使用。
IGeoProcessorResult的一个重要属性是ReturnValue,用于返回执行结果,使用示例:
IGeoProcessorResult result=Execute(GP,buffer,null);
IFeatureClass mFeatureClass=GP.Open(result.ReturnValue);
7.设置环境
每个GP工具都有自己的执行参数,其中有些参数是很工具都有的,如容差、输入、输出位置都是有的,像ArcMap中一样,在进行地理处理前要进行环境的设置。
使用setEnvironmentValue方法来设置环境变量的值,使用getEnvironmentValue方法来获取当前环境变量的值。例如:
//获取和设置环境:单元格大小
String env = (String) gp.getEnvironmentValue("cellsize");
GP.setEnvironmentValue("cellsize", Double.valueOf(10.0));
// 设置输出坐标系统
gp.setEnvironmentValue("outputCoordinateSystem", "c:/Program Files/ArcGIS/Coordinate Systems/Projected Coordinate Systems/UTM/Nad 1983/NAD 1983 UTM Zone 21N.prj");
// 重置
GP.resetEnvironments();
8.批量处理
GeoProcessor类为我们提供了一些提取数据的方法,即通过list来获取数据库中数据名称,结果是字符串,通过获取的路径再进行GP调用等操作:
listDatasets (string wildCard, string datasetType)
listFeatureClasses (string wildCard, string featureType, string dataset)
listRasters (string wildCard, string rasterType)
listTables (string wildCard, string tableType)
listToolboxes(string wildCard)
listWorkspaces (string wildCard, string workspaceType)
/// <summary>
/// 要素筛选
/// </summary>
/// <param name="filePath">数据库位置</param>
/// <param name="featureType">文件类型,可填写Point,Polyline,Polygon等</param>
/// <param name="wildCard">扩展通配符</param>
/// <param name="dataset">要素集</param>
/// <returns></returns>
public static List<string> FeatureClassFilter(string filePath,string wildCard, string featureType,string dataset)
{
lstWorkspace.Clear();
GP.SetEnvironmentValue("workspace", filePath);
IGpEnumList featureClasses = GP.ListFeatureClasses(wildCard,featureType,dataset);
string featureClass = featureClasses.Next();
while(featureClass!="")
{
lstWorkspace.Add(featureClass.ToString());
featureClass = featureClasses.Next();
}
return lstWorkspace;
}
调用方法:
FeatureClassFilter(@"D\data\temp.gdb", "P*", "poInt", "net");
此句的含义是遍历获取temp.gdb中net数据集下名为p开头的点层要素。
当然也可以通过IGPUtilities类直接打开要素层或要素类等。
IFeatureClass mFeatureClass=gpUtilities.OpenFeatureClassFromString(dataPath);
9.注意事项
(1)数据的测试
GP工具对输入、输出参数要求严格,因此首先要保证数据没有问题,可以先在ArcGIS中调用ArcToolBox进行操作,如果能正常执行,则说明数据基本没有问题。除数据本身名,还要注意数据的命名(不要出现中文的符号)、使用权限等问题。
(2)参数有多个值的设置
有的GP工具有多个输入,如联合(Union),如将数据库中的P1和P2进行联合操作,其输入要素要用分号隔开。
union.in_features = @"D\temp.gdb\P1;D\temp.gdb\P2";
如果已设置GP的默认数据库,可直接写成如下形式:
union.in_features = " P1; P2";
(3)"重分类"分类表设置
有的GP工具参数比较特殊,需要进行特别处理,可参考帮助文档中Python示例,如重分类工具,其重分类表参数设置如下:
Reclassify rc = new Reclassify();
rc.reclass_field = "Value";
rc.remap = "0.0 2.0 1; 2.0 2.5 2; 2.5 3.0 3 ";
……
即将原来的0-2重分类为1,原来2-2.5重分类为2,原来2.5-3重分类为3,同一类别的上限和下限用空格隔开,不同类别用分号隔开。
(4)"添加XY数据"的查找
我们经常将文本文件中的坐标数据转到ArcMap中的点,需要使用 "添加xy数据"工具,通常会选择"文件"-"添加数据"-"添加XY数据",这时,它属性哪个工具箱的呢?可以通过搜索的功能来查找它应该引用的类库。它在ToolBox中叫"创建XY事件图层"。当然,有些工具ToolBox是没有的,再怎么搜索也找不到,如"文件"-"共享为"-"服务"。
(5)"添加XY数据"的输出
工具"添加XY数据"的输出比较特殊,由此工具创建的是临时图层,需要保存,在ArcMap中右键导出结果即可,在ArcEngine中调用GP工具CopyFeatures(复制要素),FeatureToPoint(要素转点)或FeatureClassToFeatureClass(要素类转要素类)可导出为对应的图层。
(6)OpenRasterLayerFromString
IGPUtilities接口的OpenRasterLayerFromString函数总是不能得到结果,所以,只能使用IWorkspaceFactory接口来打开数据库中的栅格数据。示例代码:
/// <summary>
/// 打开栅格
/// </summary>
/// <param name="path">文件路径</param>
/// <param name="name">文件名</param>
/// <returns>栅格图层</returns>
public static IRasterLayer GetRater(string path, string name)
{
IWorkspaceFactory mWSF = new RasterWorkspaceFactoryClass();
IRasterWorkspace mRasterWorkspace = mWSF.OpenFromFile(path, 0) as IRasterWorkspace;
IRasterDataset mRasterDataset = mRasterWorkspace.OpenRasterDataset(name);
//创建rasterlayer从RasterDataset
IRasterLayer mRasterLayer = new RasterLayerClass();
mRasterLayer.CreateFromDataset(mRasterDataset);
return mRasterLayer;
}
(7)参数值的灵活设置
在使用ArcMap中的工具时,有的工具参数需要灵活的设置,不能固化。
如做缓冲区分析,缓冲的半径为图层范围最大值,不同的图层,其值则不相同,所以,读取到变量中,再进行缓冲区分析。
private void BufferBounding500()
{
//读取范围,设置半径
IGeoDataset pGeodataset = gpUtilities.OpenFeatureClassFromString(gdbPath + filename+"_xy") as IGeoDataset;
IEnvelope pEnvelope = pGeodataset.Extent;
double distance = Max(pEnvelope.XMax - pEnvelope.XMin, pEnvelope.YMax - pEnvelope.YMin);
//缓冲区分析
ESRI.ArcGIS.AnalysisTools.Buffer bf = new ESRI.ArcGIS.AnalysisTools.Buffer();
bf.in_features = gdbPath + fileName + "_sp";
bf.buffer_distance_or_field = distance + " Degrees"; //注意设置缓冲半径的单位
bf.out_feature_class = gdbPath + fileName + "_bf500";
RunGPTool(GP, bf, null);
}
再如,做Kriging插值时,其参数"输出单元格大小"默认情况下是插值点范围的最大值除以250,但在实际中,这样的插值结果显示效果不很理想,因此,一般都是改为除以2500才比较合适。当然输出单元格大小越小,使用的内存和耗时就更多!
(8)裁剪栅格的范围参数
裁剪栅格Clip的rectangle参数需要设置为输出范围图层的四至。
private void ClipRaster()
{
IGeoDataset pGeodataset = gpUtilities.OpenFeatureClassFromString(gdbPath + fileName + "_ clip") as IGeoDataset;
IEnvelope pEnvelope = pGeodataset.Extent;
//顺序:X 最小值、Y 最小值、X 最大值和 Y 最大值
string strEnvelope = pEnvelope.XMin.ToString() + "" + pEnvelope.YMin.ToString() + "" + pEnvelope.XMax.ToString() + "" + pEnvelope.YMax.ToString();
ESRI.ArcGIS.DataManagementTools.Clip cp = new ESRI.ArcGIS.DataManagementTools.Clip();
cp.in_raster = gdbPath + fileName + "_krg";
cp.in_template_dataset = gdbPath + fileName + "_ clip";
cp.rectangle = strEnvelope;
cp.clipping_geometry = "true";
cp.out_raster = gdbPath + fileName + "_re";
RunGPTool(GP, cp, null);
}