- quando pubblichiamo un toolbox, tutti i tools nel toolbox diventano task di geoprocessing nel servizio di geoprocessing;
- quando pubblichiamo un documento di mappa, tutti i layer di tool nel documento di mappa diventano task di geoprocessing del servizio di geoprocessing di ArcGIS Server. I layer di tool sono creati trascinando i tool nella tabella dei contenuti (TOC) di ArcMap;
- quando pubblichiamo un documento di mappa contenente layer di tool, possiamo anche specificare se desideriamo che il documento di mappa diventi un servizio di mappa da utilizzare per generare l'output dei task. Un servizio di mappa che genera gli output dei task è chiamato result map service.
I servizi di geoprocessing possono avere un result map service per creare un'immagine della mappa come risultato dei task. Le immagini sono facili da gestire, trasferire e visualizzare su web.
Le immagini della mappa sono create dal servizio di mappa di ArcGIS Server e sono il risultato della pubblicazione del documento mappa (.mxd). Ma perchè creare un'immagine come risultato del task?
I motivi possono essere molteplici:
- il risultato del task potrebbe essere potenzialmente un dataset di grosse dimensioni;
- il tipo di dato restituito in output potrebbe non essere supportato dal client (esempio raster in ArcGIS Explorer). In questo caso utilizziamo il result map service per visualizzare l'output;
- desideriamo proteggere i dati del dataset e consentiamo solo la visualizzazione dei risultati;
- abbiamo una complessa cartografia da visualizzare ed il client non ha le capabilities per poterlo fare;
- abbiamo la necessità di visualizzare immagini in report (ad esempio in report services);
- per generare tematizzazioni lato server.
Quando utilizziamo i result map service è importante sottolineare che avremo due servizi: il servizio di geoprocessing e il result map service. Questi due servizi sono eseguiti indipendentemente l'uno dall'altro. Quando si invoca il task, ArcGIS Server esegue prima il task di geoprocessing e poi esegue il result map service per generare l'output del servizio di geoprocessing utilizzando la mappa del result map service. Questo significa che l'output dei task nel servizio di geoprocessing deve essere un dataset su disco e non un dataset in memoria perchè il result map service deve poter accedere al dato elaborato (GPRasterDataLayer o GPFeatureRecordSetLayer).
Uno degli errori più comuni è quello però di utilizzare il result map service come servizio di base della mappa dell'applicazione. L'utente clicca ad esempio su una particella, il nostro task ci restituisce la particella selezionata con un colore in funzione, ad esempio di un attributo. A questo punto, perchè non utilizzare il result map service come servizio di base della mappa? Lo abbiamo già a disposizione senza dover creare un altro servizio di mappa.
I motivi sono due:
- quando un result map service è aggiunto ad una applicazione, tutti i layer del servizio sono disponibili alla visualizzazione. Questi layer includono i layer di tool di geoprocessing utilizzati per la generazione dell'output, layer che possono contenere dati sensibili o layer utilizzati dal servizio di geoprocessing ma che non ha senso visualizzare per l'utente (tipo i layer di tool);
- le mappe di base sono multiscala e multirisoluzione (costruite per mostrare dettagli alle grandi scale e generalizzazioni alle piccole scale). Creare mappe di base multiscala e multirisoluzione che vengono generate velocemente è una caratteristica che il nostro result map service non necessita di avere poichè il suo lavoro è quello di generare un output.
Passiamo ora ad un esempio pratico.
Creiamo un modello che calcola le service area (utilizziamo i dati di questo esempio):
Come potete vedere, abbiamo come input i valori di break (impostiamo un default: 1 2 3) e la posizione, mentre come output la service area.
E' importante salvare l'output su disco poichè successivamente il servizio di mappa ArcGIS Server dovrà utilizzarlo per generare la mappa.
Quando il task del servizio di geoprocessing viene invocato, ArcGIS Server imposta al volo la variabile %scratchworkspace% al percorso fisico della cartella di nome 'scratch' contenuta all'interno della cartella univoca del job generato. Ogni volta che si esegue un task, una cartella univoca di job è creata all'interno della cartella del servizio contenuta all'interno della cartella 'jobs' di arcgis server. Qui sotto è illustrato lo schema delle cartelle e dei file gestiti da ArcGIS Server durante la creazione dei job.
Pertanto abbiamo la possibilità di memorizzare l'output in un file geodatabase già pronto creato dal sistema (scratch.gdb) o salvarlo nella cartella scratch come file (ad esempio come shapefile).
Nel primo caso il percorso di output sarà:
%scratchworkspace%\scratch.gdb\SAPolygon
Nel secondo caso sarà:
%scratchworkspace%\SAPolygon.shp
Optiamo per il primo caso e quindi nel modello impostiamo per l'ouput:
A questo punto creiamo la mappa che utilizzeremo come result map service. Trasciniamo nella TOC (tabella dei contenuti) di ArcMap il tool e carichiamo il network dataset utilizzato per il calcolo della service area. E' importante caricare in mappa il network dataset perchè utilizzare layer come sorgenti migliora le prestazioni del modello. Difatti, se si dovesse fare riferimento ad un network dataset su disco ogni volta che viene eseguito il task, il sistema dovrebbe leggere la struttura dei file; mentre, se è già caricato, vengono sfruttate la lettura iniziale e le proprietà del dataset in cache.
Ora, dal menu di Geoprocessing di ArcMap, occorre selezionare Enviroments ... ed impostare nella sezione Workspace il valore per la proprietà 'Scratch Workspace'. E' importante indicare una cartella dove l'utente SOC abbia i privilegi per leggere; poichè, una volta eseguito il modello per creare il layer di output, il documento di mappa verrà pubblicato ed i layer in esso contenuti dovranno essere accessibili.
In questo esempio ho creato nella cartella 'Progetti' (dove l'utente SOC può leggere) una cartella 'Test' con all'interno una cartella di nome 'Scratch' che a sua volta contiene un file geodatabase di nome 'scratch', così il modello potrà trovare il file geodatabase (visto come ho impostato l'output nel modello).
A questo punto eseguiamo il modello da ArcMap: selezioniamo il layer di tool dalla TOC e clicchiamo con il tasto destro del mouse, dal context menu visualizzato selezioniamo la voce Open.
Viene così aperta la maschera di input del modello che ci consente di selezionare un punto sulla mappa e generare la service area.
A questo punto selezioniamo il tool sulla mashera e clicchiamo un punto sulla mappa. Il modello verrà eseguito e verrà creata la feature class nel file geodatabase indicato in output (la variabile %scratchworkspace% viene risolta da quello che è stato impostato in Enviroments in ArcMap).
Una volta generate le service area, possiamo creare la nostra legenda direttamente in ArcMap o fare riferimento direttamente ad un layer, se nel modello abbiamo impostato il Layer Symbology dell'output.
Infine creiamo il servizio di mappa dall'mxd indicando nelle capabilities anche Geoprocessing. Verranno creati, come precedentemente detto, due servizi.
Se diamo un'occhiata alle proprietà del servizio di geoprocessing, noteremo che la proprietà Result Map Service punta al servizio di mappa DrivePolygon.
Ora vediamo come chiamare il task da client. In questo esempio utilizziamo le API Javascript ma potete utilizzare gli analoghi metodi per Flex e Silverlight.
Con il metodo getResultImageLayer ci facciamo restituire l'output del task come immagine che carichiamo come layer sulla mappa.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=7,IE=9" />
<!--The viewport meta tag is used to improve the presentation and behavior of the samples
on iOS devices-->
<meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no"/>
<title>Service Area Task</title>
<link rel="stylesheet" type="text/css" href="http://serverapi.arcgisonline.com/jsapi/arcgis/2.4/js/dojo/dijit/themes/claro/claro.css">
<script type="text/javascript" src="http://serverapi.arcgisonline.com/jsapi/arcgis/?v=2.4"></script>
<script type="text/javascript">
dojo.require("esri.map");
dojo.require("esri.tasks.gp");
var map, gp;
var driveTimes = "1 2 3";
/*Initialize map, GP and image params*/
function init() {
var startExtent = new esri.geometry.Extent({ "xmin": -122.673387, "ymin": 37.635131, "xmax": -122.157408, "ymax": 37.918426, "spatialReference": { "wkid": 4326} });
map = new esri.Map("mapDiv", { extent: startExtent });
var imageParameters = new esri.layers.ImageParameters();
imageParameters.format = "jpeg"; //set the image type to PNG24, note default is PNG8.
//Takes a URL to a non cached map service.
var dynamicMapServiceLayer = new esri.layers.ArcGISTiledMapServiceLayer("http://server.arcgisonline.com/ArcGIS/rest/services/ESRI_StreetMap_World_2D/MapServer", { "imageParameters": imageParameters });
map.addLayer(dynamicMapServiceLayer);
gp = new esri.tasks.Geoprocessor("http://localhost/ArcGIS/rest/services/DrivePolygon/GPServer/PolygonDriver");
gp.setOutputSpatialReference({ wkid: 4326 });
dojo.connect(map, "onClick", computeServiceArea);
}
function computeServiceArea(evt) {
map.graphics.clear();
var pointSymbol = new esri.symbol.SimpleMarkerSymbol();
pointSymbol.setOutline = new esri.symbol.SimpleLineSymbol(esri.symbol.SimpleLineSymbol.STYLE_SOLID, new dojo.Color([255, 0, 0]), 1);
pointSymbol.setSize(5);
pointSymbol.setColor(new dojo.Color([0, 255, 0, 0.25]));
var graphic = new esri.Graphic(evt.mapPoint, pointSymbol);
map.graphics.add(graphic);
var features = [];
features.push(graphic);
var featureSet = new esri.tasks.FeatureSet();
featureSet.features = features;
var params = { "Input_locations": featureSet, "Default_break_values": driveTimes };
gp.submitJob(params, completeCallback, statusCallback);
}
function statusCallback(jobInfo) {
console.log(jobInfo.jobStatus);
}
function completeCallback(jobInfo) {
var imageParams = new esri.layers.ImageParameters();
imageParams.imageSpatialReference = map.spatialReference;
gp.getResultImageLayer(jobInfo.jobId, "SAPolygons", imageParams, function (gpLayer) {
gpLayer.setOpacity(0.5);
map.addLayer(gpLayer)
});
}
dojo.addOnLoad(init);
</script>
</head>
<body class="claro">
<div id="mapDiv" style="width:800px; height:600px; border:1px solid #000;"></div>
Zoom in to a US city and single click the map. A service area GP task will be executed synchronously and on
completion the results will be drawn as graphic features to the map. The drive time polygons are 1, 2,
and 3 minutes.
</body>
</html>
Come possiamo vedere da Fiddler alla riga 21 viene invocato il job, dalla 22 alla 26 viene controllato se il job ha terminato con successo ed infine alla riga 27 viene fatta la richiesta dell'immagine del job.
Come possiamo vedere nel dettaglio la richiesta REST dell'immagine è:
In sintesi, all'url del geoprocessing si appendono 'jobs', l'id del job, 'results' ed il nome del parametro di output e si concatenano i parametri di export map per l'immagine.