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中支援的引數型別及說明如下表:
由上表可以看出如果是輸入向量要素的話需要使用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,有興趣的同學可以下載。