接上文,在编写代码之前我们先回忆一下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中支持的参数类型及说明如下表:
由上表可以看出如果是输入矢量要素的话需要使用FeatureRecordSetLayer这种类型,对应的Runtime参数类型就是GeoprocessingFeatures,这也是为什么我们要自定义脚本工具(而不是直接调用系统工具Interpolate Shape)并且输入参数类型指定为Feature Set的原因。
那么GeoprocessingFeatures如何构建呢?可以使用FeatureCollectionTable实现,下面是FeatureCollectionTable的帮助:
其AddFeatureAsync方法可以添加要素,CreateFeature()方法可以新建要素,返回Feature对象,接下来看下Feature类:
与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();
界面为:
结果为:
三、遇到的问题与技巧
遇到的问题
发布过GP服务的用户都知道,GP服务的执行方式有两种:即同步和异步:
同样执行gpk也是如此,上面代码中有一点不知道您注意到没有,那就是LocalGeoprocessingService.ServiceType属性,这里指定的是GeoprocessingServiceType.SynchronousExecute也就是同步执行。悲剧的是我开始没加这句代码(其实也不怪我,Runtime的官网示例中也没有这句代码而且也没有地方有相关说明),后面参数处使用GeoprocessingParameters para = new GeoprocessingParameters(GeoprocessingExecutionType.SynchronousExecute);会报错:
那就改成异步执行吧,使用GeoprocessingExecutionType.AsynchronousSubmit,这次没有报错,但输出线要素的Z值始终是0!崩溃了,好在后来看到LocalGeoprocessingService.ServiceType属性,设置为同步后,参数处也设为同步就执行成功了。后来想尝试一下异步执行,于是将ServiceType设为异步,参数也设为异步,但始终得到的Z值为0,不知道为什么,如果大家异步执行这个工具成功了的话欢迎给我留言!
技巧
localServer会把gpk发布成本地的GP Service,如下图:
这时我们可以在浏览器中输入该URL,跟在线的GP Service类似,这里我将服务类型设为了异步,然后点击提交:、
输入inputLine的Json格式,执行:
生成的结果:
如果这里是可以成功的,那么我们在程序中参数构建正确了也应该是可以成功的,但如果这里都无法执行成功,那就别指望在Runtime中执行成功了,所以建议如果大家执行gpk失败了,可以在这里测试一下。
执行成功后,在那个临时目录下(注意,如果LocalServer关闭了,这个临时目录就销毁了)找到该outputLine是有Z值的。也就是说异步是正常的,但是为什么我的Runtime程序中获取的Z值就是0呢?我也是醉了。
好吧,就啰嗦到这吧,希望您看完后能对Desktop中如何制作gpk以及ArcGIS Runtime for .NET 100.0中如何执行gpk有个初步认识,测试工程和测试数据已上传至百度云盘了,链接:http://pan.baidu.com/s/1jIIE5Ps 密码:lixo,有兴趣的同学可以下载。