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

上一篇文章最后提到过GP工具的许可,这篇文章就详细讲解一下调用GP工具的许可问题,这也是Engine中调用GP工具出错最多的一类问题。除此之外,再介绍一下Engine中如何设置环境变量以及如何调用后台64位GP。首先看下最最重要的许可问题。

一、许可问题

ArcGIS按产品来说可以分为ArcGIS Desktop以及ArcGIS Engine(当然还包括ArcGIS Server、Portal for ArcGIS以及ArcGIS Runtime等,由于本文不涉及就不介绍了),这二者都是基于ArcObjects组件开发的产品。Desktop产品的许可分为三个级别,即Basic、Standard以及Advanced;Engine产品的许可分为两个级别,即Engine许可以及Engine + Geodatabase Update扩展许可(简称EngineGeoDB许可)。AO帮助中说明了Engine许可相当于Desktop的Basic许可级别,而EngineGeoDB许可则相当于Desktop的Standard许可级别。

ArcGIS Engine中如何调用GP工具(二)_第1张图片

Tips:至于Basic许可和Standard许可的区别(其实等同于Engine和EngineGeoDB许可的区别)可以参考Desktop help中ArcGIS for Desktop Basic and the geodatabase

为什么说上面一堆感觉无关主题的话呢,是因为每个GP工具都有其相应的许可级别,Basic级别能调用的工具用Engine许可就可以调用,Standard级别能调用的工具用EngineGeoDB许可就可以调用,而只有Advanced级别能调用的工具Engine产品是无法调用的。具体可以在ArcMap中打开该工具,点击GP对话框右下角的Tool Help,第一行就是该工具的License Level,如Buffer工具:

ArcGIS Engine中如何调用GP工具(二)_第2张图片

前面小方框中打钩就是说该许可级别可以调用,不打钩就是无法调用,而小方框中画黑色方框就是说使用过程中有限制,在工具帮助中会有相应说明,如:

ArcGIS Engine中如何调用GP工具(二)_第3张图片

也就是说如果要将line_side设为Left,Right等使用Engine许可或者EngineGDB许可是不行的。

再比如ExtractByMask工具,其License Level:

ArcGIS Engine中如何调用GP工具(二)_第4张图片

最下方一行有说明,该工具需要Spatial Analyst扩展许可。

ArcGIS Engine中如何调用GP工具(二)_第5张图片

也就是说Engine程序中需要检出Spatial Analyst扩展许可才能执行该工具。有两种方式检出扩展许可:

一是使用LicenseControl控件:

选中LicenseControl控件,右键选择属性,在弹出窗体右侧的Spatial Analyst方框处打钩;

二是使用AO代码检出扩展许可:

ao.CheckOutExtension(esriLicenseExtensionCode.esriLicenseExtensionCodeSpatialAnalyst);

再比如Erase工具:

ArcGIS Engine中如何调用GP工具(二)_第6张图片

只能Advanced许可才能调用,也就是Engine或EngineGeoDB许可无法调用该工具。但有的用户说了,我就想在程序中调用Erase工具怎么办?办法是有,但是有前提:首先机器上安装了Desktop产品,并且授权了Advanced许可;其次是程序界面不能使用MapControl、TOCControl、ToolBarControl等控件,原因在于任何接口都有其适用的产品,比如IMapControl控件,AO帮助中明确说明只能在ArcGIS Engine产品下使用:

ArcGIS Engine中如何调用GP工具(二)_第7张图片

所以如果想要调用Erase工具,而原有工程中使用了MapControl等控件的话,建议另外新建工程绑定Desktop产品(最好不要使用EngineOrDesktop,不然如果机子上安装了Engine会默认绑定Engine产品),代码中初始化Advanced许可,如下:

ESRI.ArcGIS.RuntimeManager.Bind(ESRI.ArcGIS.ProductCode.Engine);
ESRI.ArcGIS.esriSystem.IAoInitialize ao = new ESRI.ArcGIS.esriSystem.AoInitialize();            ao.Initialize(ESRI.ArcGIS.esriSystem.esriLicenseProductCode.esriLicenseProductCodeAdvanced);

这里做一下提醒:如果程序中初始化了Advanced许可,给客户部署时也要求部署机上有该许可。

有一点很重要放在最后:一个程序中只能使用一种方式初始化一次许可。什么意思呢?包含两层意思:一是LicenseControl控件(左侧单选,右侧多选)和AO代码初始化许可两种方式只能选择一种,不然如果两种方法都用了但初始化的许可不一样,程序无法判断到底使用什么许可;二是不要初始化多次许可,比如初始化过一次Engine许可,后来又初始化了EngineGeoDB许可,同样,程序中也无法判断。举个例子,比如用户调用SimplifyLine_cartography工具(该工具Basic许可无法调用),一直报没有许可错误,但是用户一口咬定就是初始化的EngineGeoDB许可,那怎么还会报许可错误呢,查找原因就是因为其初始化了两次许可,而且还不一样导致。

二、如何设置环境变量?

GP工具有些通用的属性,当一个工具执行时,当前环境中的某些设置被当作全局输入参数,例如Extent、输出数据的坐标系、新生成栅格数据的像元大小等等,都可以在环境变量中设置。

1,设置环境变量

所有环境变量名称都用string表示,并且不区分大小写,即”workspace”和”Workspace”均可。下面是一些常用变量的写法:

设置workspace:

gp.SetEnvironmentValue("workspace", @"C:\data\saltlake.gdb");

设置extent:

gp.SetEnvironmentValue("extent", "-3532000, -911000, -3515000, -890000");

设置输出坐标系:

gp.SetEnvironmentValue("outputCoordinateSystem", @"…\NAD 1983 UTM Zone 11N.prj");
或者
gp.SetEnvironmentValue("outputCoordinateSystem",   "PROJCS['NAD_1983_UTM_Zone_11N',GEOGCS['GCS_North_American_1983',DATUM['D_North_American_1983',SPHEROID['GRS_1980',6378137.0,298.257222101]],PRIMEM['Greenwich',0.0],UNIT['Degree',0.0174532925199433]],PROJECTION['Transverse_Mercator'],PARAMETER['False_Easting',500000.0],PARAMETER['False_Northing',0.0],PARAMETER['Central_Meridian',-117.0],PARAMETER['Scale_Factor',0.9996],PARAMETER['Latitude_Of_Origin',0.0],UNIT['Meter',1.0]]");

设置Mask:

gp.SetEnvironmentValue("mask", @"E:\ZhuXinying\testData\Data.gdb\polygonMask");

2,获取当前环境变量的值并重置到原始状态

// Get the cell size environment value.
object env = gp.GetEnvironmentValue("cellsize");
// Reset the environment values to their defaults.
gp.ResetEnvironments();

3,将设置的环境变量保存为.xml,后续使用的话可以直接加载:

gp.SetEnvironmentValue("workspace", @"C:/data/mydata.gdb");
gp.SetEnvironmentValue("extent", "-3532000, -911000, -3515000, -890000");
// Save environment settings to an XML file.
string settingsFile = @"C:\sdk\MyCustomSettings.xml";
gp.SaveSettings(settingsFile);
// Load previously saved environment settings.
gp.LoadSettings(settingsFile);
object sExtent = gp.GetEnvironmentValue("workspace");

详细信息可以参考Using environment settings

三、如何调用后台GP?

不知您是否注意到ArcGIS Engine安装光盘里有这样一个安装包:

ArcGIS Engine中如何调用GP工具(二)_第8张图片

这个安装包就是Engine的后台64位GP工具包,该包是在ArcGIS Engine 10.1 SP1中开始出现的,只能安装在64位机子上,安装后会在Engine的安装目录下多一个bin64的目录(后台执行应该使用的是这里的dll),在使用Geoprocessor.ExecuteAsync异步执行GP工具时调用。

相关事件:

1,ExecuteAsync方法是提交工具到当前进程已存在的geoprocessing队列中,当后台执行到这个工具时会触发ToolExecuting事件,这时该工具的IGeoProcessorResults.Status属性变为esriJobStatus.esriJobWaiting。该事件所有工具都会触发。

2,在工具执行过程中能触发MessagesCreated和ProgressChanged事件,这些事件依赖于所使用的工具以及工具处理的数据量。

3,当工具执行完成时触发ToolExecuted事件,该事件所有工具执行结束时都会触发。

4,模型工具可以看作单一工具,触发ToolExecuting以及ToolExecuted事件,MessagesCreated事件描述模型中每一个工具的进度。

5,工具可以在任何时刻取消,调用IGeoProcessorResult2.Canael()即可,取消后其状态变为esriJobStatus.esriJobCancelled。当工具执行失败时,返回esriJobStatus.esriJobFail。

下面看下具体实现:

Geoprocessor gp = new Geoprocessor();
gp.OverwriteOutput = true;
gp.ToolExecuting += new EventHandler.ArcGIS.Geoprocessor.ToolExecutingEventArgs>(gpToolExecuting);
gp.ProgressChanged += new EventHandler.ArcGIS.Geoprocessor.ProgressChangedEventArgs>(gpProgressChanged);
//Register to receive the geoprocessor event when the tools have completed execution.
gp.ToolExecuted += new EventHandler.ArcGIS.Geoprocessor.ToolExecutedEventArgs>(gpToolExecuted);

// Create a variant array to hold the parameter values.
IVariantArray parameters = new VarArrayClass();
// Populate the variant array with parameter values.
parameters.Add(FileGDBPath + "\\testPoint_10w");
parameters.Add(FileGDBPath + "\\testPoint_10w_Copy");
IGeoProcessorResult2 gpResult = gp.ExecuteAsync("CopyFeatures_management", parameters) as
                IGeoProcessorResult2;
public void gpToolExecuting(object sender, ToolExecutingEventArgs e)
{
  IGeoProcessorResult2 result = e.GPResult as IGeoProcessorResult2;
            //Determine if this is the tool to handle this event.
            if (result.Process.Tool.Name.Equals("CopyFeatures_management") && result.GetInput(0)
                .GetAsText().Equals(FileGDBPath + "\\testPoint_10w") && result.GetOutput(0)
                .GetAsText().Equals(FileGDBPath + "\\testPoint_10w_Copy"))
            {
                //Application specific code.
            }
        }
 public void gpProgressChanged(object sender, ESRI.ArcGIS.Geoprocessor.ProgressChangedEventArgs e)
        {
            System.Windows.Forms.ProgressBar progressBar = progressBar1;
            IGeoProcessorResult2 gpResult = (IGeoProcessorResult2)e.GPResult;
            switch (e.ProgressChangedType)
            {
                case (ProgressChangedType.Show):
                    //The tool that is running reports progress or has stopped reporting progress; make the 
                    // progress bar visible if appropriate. 
                    //progressBar.Visible = e.Show;
                    break;
                case (ProgressChangedType.Message):
                    //The application does not use these, since a tool being used reports percentage progress.
                    break;
                case (ProgressChangedType.Percentage): progressBar.Value = (int)
                    e.ProgressPercentage;
                    break;
                default:
                    throw new ApplicationException(
                        "unexpected ProgressChangedEventsArgs.ProgressChangedType");
                    break;
            }
        }
public void gpToolExecuted(object sender, ToolExecutedEventArgs e)
        {
            IGeoProcessorResult2 result = e.GPResult as IGeoProcessorResult2;
            if (result.Status.Equals(esriJobStatus.esriJobSucceeded))
            {
                //Check that there are no information or warning messages.
                if (result.MaxSeverity == 0)
                {
                    //Get the return value.
                    object returnValue = result.ReturnValue;
                    //Application specific code, 
                    //for example, find the layer to which this return value corresponds.
                }
                else
                {
                    //Application specific code.
                }
                myWatch.Stop();
                string time = myWatch.Elapsed.TotalSeconds.ToString();
                MessageBox.Show(time + " Seconds"); 
            }
            else
            {
                //Get all messages.
                IGPMessages msgs = result.GetResultMessages();
                for (int i = 0; i < result.MessageCount; i++)
                {
                    IGPMessage2 msg = msgs.GetMessage(i) as IGPMessage2;
                    //Application specific code.
                }
            }
        }

再来测试下对相同数据前台执行Copy Features工具和后台执行Copy Features工具的用时对比:

10万个点:前台用时13.26秒,后台用时13.42秒

100万个点:前台用时1分55秒,后台用时1分50秒

最后总结一下调用后台GP的优势:

1,后台GP执行时,用户界面是可响应的,可以执行工具的同时与MapControl进行交互。如果一个GP工具花费很长时间,而用户界面不可能一直无响应,这时使用后台GP就比较好。

2,由于ArcGIS Engine 是32位应用程序,因此,最大只能利用4G内存,如果数据量大或者计算复杂会导致内存超过4G或接近这个数,那么在32位下可能会出错,但是如果安装了64位的后台GP工具包,则不会有这个限制。

3,如果处理小数据量数据用不用后台GP差别不大,但是处理数据量大的话,调用后台GP处理速度更快。

4,不过也有一些限制,如不支持mdb数据、不能调用Geodatabase administration toolset里的工具、操作SDE数据时需要安装64位客户端等,具体可以参考Desktop帮助:Background Geoprocessing (64-bit)

Demo

使用ArcGIS Engine 10.5,Visual Studio 2013编写,界面为:

ArcGIS Engine中如何调用GP工具(二)_第9张图片

工程下载地址:

GP_ArcGISEngine

你可能感兴趣的:(ArcEngine)