在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); }