在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);
-
}
(9)按位置选择
按位置选择工具的输入必须是要素图层;不可以是要素类。所在在调用工具之前,需要先使用MakeFeatureLayer来创建要素图,详见:
GP开发示例:数据库去重