ArcGIS Runtime SDK for .NET 100.0中如何执行.gpk(二)

接上文,在编写代码之前我们先回忆一下ArcMap中执行该脚本工具的过程,首先我把一个Dem影像添加进来,然后我在该影像范围内使用人机交互的方式画了一条线,那么我们在Runtime中也可以采用该思路:即首先加载该Dem影像(为了画线时便于定位),然后map上画线作为输入inputLine。

1,首先加载本地Dem影像(这是100.0的新特性哦)并且显示到该区域。这里不做详细介绍,可参考下面代码:

//加载DEM并且缩放到该区域
            Map map = new Map(Basemap.CreateTopographic());
            string pathToRaster = @"D:\work\github\ExecuteGPK\LasVegasNED13_geoid1.tif";
            var myRaster = new Raster(pathToRaster);
            // create a RasterLayer using the Raster
            var newRasterLayer = new RasterLayer(myRaster);

            map.OperationalLayers.Add(newRasterLayer);
            Viewpoint viewPoint = new Viewpoint(36.131, -115.144, 800000);
            myMapView.Map = map;
            await myMapView.SetViewpointAsync(viewPoint, TimeSpan.FromSeconds(2));

2,开启LocalServer,LocalServer 是单实例对象( singleton object),也就是说整个工程中只有一个,因此我们可以添加全局变量:

private Esri.ArcGISRuntime.LocalServices.LocalServer _localServer;

接下来开启LocalServer:

 private async void StartLocalServer()
        {
            // Get the singleton LocalServer object using the static "Instance" property
            _localServer = Esri.ArcGISRuntime.LocalServices.LocalServer.Instance;

            // Handle the StatusChanged event to react when the server is started
            _localServer.StatusChanged += ServerStatusChanged;

            // Start the local server instance
            await _localServer.StartAsync();
        }

        private async void ServerStatusChanged(object sender, Esri.ArcGISRuntime.LocalServices.StatusChangedEventArgs e)
        {
            // Check if the server started successfully
            if (e.Status == Esri.ArcGISRuntime.LocalServices.LocalServerStatus.Started)
            {

            }
        }

ServerStatusChanged事件可以用来监测LocalServer的状态。

3,执行本地gpk,可按照下面步骤:

a,新建LocalGeoprocessingService对象,传入该.gpk所在路径,获取其full URL,之后的过程其实和执行在线GP服务一样;

b,创建GeoprocessingTask对象,传入刚刚获取到的URL;

c,创建GeoprocessingParameters对象,用于输入必要参数,注意需要设置GeoprocessingExecutionType为同步或者异步;

d,使用GeoprocessingTask.CreateJob获取GeoprocessingJob,该对象可以监听job的状态;

e,执行Job,如果执行成功的话会得到GeoprocessingResult,执行失败可以捕获异常信息;

f,最后通过GeoprocessingResult获取返回值。

4,重点讲下参数的构建,构建参数时需要确认参数类型,Runtime中支持的参数类型及说明如下表:

1
2

由上表可以看出如果是输入矢量要素的话需要使用FeatureRecordSetLayer这种类型,对应的Runtime参数类型就是GeoprocessingFeatures,这也是为什么我们要自定义脚本工具(而不是直接调用系统工具Interpolate Shape)并且输入参数类型指定为Feature Set的原因。

那么GeoprocessingFeatures如何构建呢?可以使用FeatureCollectionTable实现,下面是FeatureCollectionTable的帮助:

3

其AddFeatureAsync方法可以添加要素,CreateFeature()方法可以新建要素,返回Feature对象,接下来看下Feature类:

4

与ArcObjects的逻辑一致,可以为该Feature赋予几何和属性,那么怎么获取Geometry呢?这里我们直接屏幕画线,使用MapView.SketchEditor获取SketchEditor,然后使用StartAsync(SketchCreationMode, Boolean)里面指定SketchCreationMode.Polyline就可以直接画线了,画完双击结束后即可获取Geometry,赋给Feature.Geometry,最后通过FeatureCollectionTable.AddFeatureAsync将该Feature添加进来即可。

由于我们构建的gpk就需要这一个参数,因此参数就构建完了。不过还有一点需要注意,由于我们需要获取Z值,所以GeoprocessingParameters.ReturnZ属性需要设为true,此外,还可以设置输出要素的空间参考。

5,获取结果类型为GeoprocessingResult,可以根据输出的参数名称“outputLine”获取GeoprocessingFeatures对象,进而获取IFeatureSet,由于我们仅输入了一条线,因此输出只有一个Feature,获取到该Feature后可以获取其Geometry即为Polyline,为了检测Z值是否返回,我们获取输出线的起点Z值和终点Z值,最终以MessageBox方式弹出。

下面就把这一部分的代码汇总一下:

 StartLocalServer();
            LocalGeoprocessingService localServiceGP = new LocalGeoprocessingService(@"D:\work\github\ExecuteGPK\InterpolateShape.gpk");
            localServiceGP.ServiceType = GeoprocessingServiceType.SynchronousExecute;
            // Handle the status changed event to check when it's loaded
            localServiceGP.StatusChanged += async (svc, args) =>
            {
                // If service started successfully, create a gp task
                if (args.Status == LocalServerStatus.Started)
                {
                    // Get the URL for the specific geoprocessing tool
                    var gpSvcUrl = (svc as LocalGeoprocessingService).Url.AbsoluteUri + "/InterpolateShape";
                    // Create the geoprocessing task
                    GeoprocessingTask gpRouteTask = new GeoprocessingTask(new Uri(gpSvcUrl));
                    GeoprocessingParameters para = new GeoprocessingParameters(GeoprocessingExecutionType.SynchronousExecute);
                    // Create the schema for a lines table (one text field to contain a name attribute)
                    var inputFeatures = new FeatureCollectionTable(new List<Field>(), GeometryType.Polyline, myMapView.SpatialReference);
                    Feature inputFeature = inputFeatures.CreateFeature();
                    var geometry = await myMapView.SketchEditor.StartAsync(SketchCreationMode.Polyline, false);
                    inputFeature.Geometry = geometry;
                    await inputFeatures.AddFeatureAsync(inputFeature);          

                    para.Inputs.Add("inputLine", new GeoprocessingFeatures(inputFeatures));
                    para.ReturnZ = true;
                    para.OutputSpatialReference = myMapView.SpatialReference;

                    GeoprocessingJob routeJob = gpRouteTask.CreateJob(para);

                    try
                    {
                        // Execute analysis and wait for the results
                        GeoprocessingResult geoprocessingResult = await routeJob.GetResultAsync();
                        GeoprocessingFeatures resultFeatures = geoprocessingResult.Outputs["outputLine"] as GeoprocessingFeatures;
                        IFeatureSet interpolateShapeResult = resultFeatures.Features;
                        Esri.ArcGISRuntime.Geometry.Polyline elevationLine = interpolateShapeResult.First().Geometry as Esri.ArcGISRuntime.Geometry.Polyline;
                        MapPoint startPoint = elevationLine.Parts[0].Points[0];
                        int count = elevationLine.Parts[0].PointCount;
                        MapPoint stopPoint = elevationLine.Parts[0].Points[count - 1];
                        double chazhi = stopPoint.Z - startPoint.Z;
                        MessageBox.Show("终点的Z值为: " + stopPoint.Z.ToString() + ",起点的Z值为: " + startPoint.Z.ToString());
                    }
                    catch (Exception ex)
                    {
                        if (routeJob.Status == JobStatus.Failed && routeJob.Error != null)
                            MessageBox.Show("Executing geoprocessing failed. " + routeJob.Error.Message, "Geoprocessing error");
                        else
                            MessageBox.Show("An error occurred. " + ex.ToString(), "Sample error");
                    }
                    // Create parameters, run the task, process results, etc.
                    // ...
                }
            };
            // Start the local geoprocessing service
            await localServiceGP.StartAsync();

界面为:

5

结果为:

6

三、遇到的问题与技巧

遇到的问题

发布过GP服务的用户都知道,GP服务的执行方式有两种:即同步和异步:

7

同样执行gpk也是如此,上面代码中有一点不知道您注意到没有,那就是LocalGeoprocessingService.ServiceType属性,这里指定的是GeoprocessingServiceType.SynchronousExecute也就是同步执行。悲剧的是我开始没加这句代码(其实也不怪我,Runtime的官网示例中也没有这句代码而且也没有地方有相关说明),后面参数处使用GeoprocessingParameters para = new GeoprocessingParameters(GeoprocessingExecutionType.SynchronousExecute);会报错:

8

那就改成异步执行吧,使用GeoprocessingExecutionType.AsynchronousSubmit,这次没有报错,但输出线要素的Z值始终是0!崩溃了,好在后来看到LocalGeoprocessingService.ServiceType属性,设置为同步后,参数处也设为同步就执行成功了。后来想尝试一下异步执行,于是将ServiceType设为异步,参数也设为异步,但始终得到的Z值为0,不知道为什么,如果大家异步执行这个工具成功了的话欢迎给我留言!

帮助中同步异步参数的详细说明

技巧

localServer会把gpk发布成本地的GP Service,如下图:

9

这时我们可以在浏览器中输入该URL,跟在线的GP Service类似,这里我将服务类型设为了异步,然后点击提交:、

10

输入inputLine的Json格式,执行:

11

生成的结果:

12

如果这里是可以成功的,那么我们在程序中参数构建正确了也应该是可以成功的,但如果这里都无法执行成功,那就别指望在Runtime中执行成功了,所以建议如果大家执行gpk失败了,可以在这里测试一下。

执行成功后,在那个临时目录下(注意,如果LocalServer关闭了,这个临时目录就销毁了)找到该outputLine是有Z值的。也就是说异步是正常的,但是为什么我的Runtime程序中获取的Z值就是0呢?我也是醉了。

LocalServer所支持的工具列表

好吧,就啰嗦到这吧,希望您看完后能对Desktop中如何制作gpk以及ArcGIS Runtime for .NET 100.0中如何执行gpk有个初步认识,测试工程和测试数据已上传至百度云盘了,链接:http://pan.baidu.com/s/1jIIE5Ps 密码:lixo,有兴趣的同学可以下载。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值