-----------------------------------

Acquista i software ArcGIS tramite Studio A&T srl, rivenditore autorizzato dei prodotti Esri.

I migliori software GIS, il miglior supporto tecnico!

I migliori software GIS, il miglior supporto tecnico!
Azienda operante nel settore GIS dal 2001, specializzata nell’utilizzo della tecnologia ArcGIS e aderente ai programmi Esri Italia Business Network ed Esri Partner Network

-----------------------------------



domenica 13 giugno 2010

Singletons e System.__COMObject

Quando un ArcObject (basato su COM) in ambiente .NET viene istanziato via interop con la parola riservata 'new', viene preso un riferimento all'oggetto stesso tramite un wrapper .NET Framework fortemente tipizzato (runtime callable wrapper (RCW)). Un RCW è un oggetto gestito che può trattenere un oggetto COM in una applicazione .NET.

Vediamo un esempio:

IEnvelope env = new EnvelopeClass();


In questo caso, in fase di compilazione, il compilatore conosce il tipo esatto della variabile tramite Reflection e metadati ed a runtime utilizza questa informazione per sapere il tipo esatto della variabile.

Vediamo un altro esempio:

            IEnvelope a = axMapControl1.Extent;

            try
            {
                EnvelopeClass b = (EnvelopeClass)a;
            }
            catch (Exception ex)
            {
                System.Windows.Forms.MessageBox.Show(ex.Message);
            }


In questo caso, quando il codice è compilato, il compilatore sa solo che la proprietà Extent restituisce un oggetto che implementa l'interfaccia IEnvelope ma non può sapere il tipo della classe dell'oggetto. Sebbene possiamo sempre 'castare' ad interfacce che implementano Envelope, il runtime .NET 'wrappa' il riferimento all'oggetto COM tramite un RCW generico chiamato System.__ComObject.
Riprendendo l'esempio, se proviamo a 'castare' la variabile a in EnvelopeClass otterremmo un errore perchè non possiamo 'castare' da un System.__ComObject ad una classe.



Possiamo, come abbiato detto, castare mediante le interfacce che sono implementate dall'oggetto ma, come potete vedere, l'oggetto è un System.__ComObject.

Invece nel primo esempio che abbiamo visto l'rcw è fortemente tipizzato:




Vediamo ora cosa succede con gli oggetti Singleton.
Gli oggetti singleton supportano una sola istanza dell'oggetto (vedi post).
Dalla ArcGIS 9.x, gli oggetti singleton sono singletons per thread e non per processo (vedi post).

Anche qui vale quello che abbiamo detto precedentemente solo che, se dovessimo istanziare un nuovo oggetto, prenderemmo come riferimento l'istanza corrente.
Per esempio:
IWorkspaceFactory workspaceFactory = new AccessWorkspaceFactoryClass();

            IWorkspaceFactory workspaceFactory1 = new AccessWorkspaceFactoryClass();

            if (object.ReferenceEquals(workspaceFactory, workspaceFactory1))
                System.Windows.Forms.MessageBox.Show("workspaceFactory and workspaceFactory1: same reference");


            SpatialReferenceEnvironment spatialReferenceEnvironment = new SpatialReferenceEnvironmentClass();
            SpatialReferenceEnvironment spatialReferenceEnvironment1 = new SpatialReferenceEnvironmentClass();

            if (object.ReferenceEquals(spatialReferenceEnvironment, spatialReferenceEnvironment1))
                System.Windows.Forms.MessageBox.Show("spatialReferenceEnvironment and spatialReferenceEnvironment1: same reference");

AccessWorkspaceFactoryClass e SpatialReferenceEnvironment sono singleton (vedi qui l'elenco degli oggetti singleton negli arcobjects).  In questo caso, dopo aver istanziato la classe, se la dovessimo reinstanziare, otterremmo lo stesso riferimento (verifica con il metodo ReferenceEquals). Non si può dire lo stesso di una classe non singleton. Env e env1 non rappresentano la stessa istanza:

IEnvelope env = new EnvelopeClass();
            IEnvelope env1 = new EnvelopeClass();
            if (object.ReferenceEquals(env, env1))
                System.Windows.Forms.MessageBox.Show("env and env1: same reference");
            else
                System.Windows.Forms.MessageBox.Show("env and env1: Not the same reference");

Con gli oggetti singleton, a differenza di quelli non singleton, potremmo incorrere nell'errore precentemente visto ("Impossibile eseguire il cast...") anche con un semplice new

IWorkspaceFactory workspaceFactory = new AccessWorkspaceFactoryClass();


Questo perchè è possibile che sia presente già la singola istanza come RCW non fortemente tipizzato e quindi il cast fallisce anche se si fa riferimento con un'interfaccia perchè il new tenta di 'castare' da RCW non tipizzato a RCW tipizzato e l'operazione fallisce. Ad esempio tools in ArcObjects scritti .NET da terze parti potrebbero 'wrappare' un oggetto in un generico wrapper causando l'errore.

In questo esempio non fallisce perchè supponiamo di trovarci nel caso in cui non siamo in presenza di una istanza già presente (AccessWorkspaceFactoryClass) e non tipizzata ( System.__ComObject ) e quindi il cast viene eseguito:

IWorkspaceFactory workspaceFactory = new AccessWorkspaceFactoryClass();
IWorkspaceFactory workspaceFactory1 = new AccessWorkspaceFactoryClass();


Per evitare comunque il possibile errore precedentemente descritto è buona regola utilizzare la classe Activator per assicurare che l'oggetto singleton sia wrappato con un rcw fortemente tipizzato quando fai riferimento ad esso per la prima volta. Usando il metodo CreateInstance della class Activator invece di usare il new, l'Activator è abilitato a prendere le informazioni (metadato) per eseguire il cast.

Type factoryType = Type.GetTypeFromProgID(
                  "esriDataSourcesGDB.AccessWorkspaceFactory");
            IWorkspaceFactory workspaceFactory = (IWorkspaceFactory)
              Activator.CreateInstance(factoryType);

martedì 8 giugno 2010

Realtà aumentata (augmented reality - AR)

In poche parole la realtà viene 'aumentata' mediante la sovrapposizione di informazioni (elementi virtuali, multimediali, dati geolocalizzati ecc.). Per dettagli vedere su wiki.

Provate a pensare alle possibili applicazioni: perchè non utilizzare le immagini che provengono direttamente dalla fotocamera del telefono ed arrichirle con informazioni? Vedi qui un esempio di navigatore satellitare che sfrutta l'AR o aiuta i militari a 'sistemare' i veicoli.


Per avere un esempio di AR su desktop computer, potete fare subito un test grazie al post di ESRI Lab dove viene effettuata una dimostrazione video di come integrare la realtà con una mappa SL.
Potete provare anche voi direttamente dal sito http://maps.esri.com/Labs4/ar/ dotandovi di una web cam e stampando il seguente marker.
Se volete sviluppare una vostra applicazione potete utilizzare Silverlight AR Toolkit

Per un esempio di AR su piattaforma mobile potete fare riferimento a questo link.
In questo caso è possibile utilizzare Layar (gira sia sotto Android che iPhone). Sviluppando la componente server-side è possibile pubblicare i propri contenuti in Layar.
Uno degli esempi di ESRI è ArcPhoto layer . Esso è stato sviluppato come estensione di ArcPhoto Desktop e ArcPhoto (visualizzazione di immagini memorizzate in un campo raster di un geodatabase)  e mostrate come 'cartelloni' sul device. Nel caso specifico, per aggiungere un' immagine, occorre inviare dal mobile un' email con allegata una foto georeferenziata . Essa sarà automaticamente inserita nel layer.

domenica 6 giugno 2010

Deferreds

Javascript non supporta il concetto di threads ma offre la possibilità di eseguire richieste asincrone con l'oggetto XMLHttpRequest e attraverso i ritardi con la funzione setTimeout.

Dojo mette a disposizione una classe chiamata Deferred che aiuta a gestire la complessità degli eventi asincroni astraendola con una interfaccia consistente.

Vediamo un esempio

 var d = new dojo.Deferred(/* Optional cancellation function goes here */);
  
                //aggiungi una funzione di callback
  
                d.addCallback(function(response) {
  
                  console.log("La response e': ", response);
  
                  return response +1;
  
                });
  
                //Aggiungi un'altra callback che viene eseguita dopo la precedente
  
                d.addCallback(function(response) {
  
                  console.log("La response e': ", response);
  
                  return response + 1;
  
                });
  
                d.addErrback(function(response) {
  
                  console.log("C'è un errore: ", response);
  
                  return response;
  
                });
  
                d.callback(100);  

Questo è quello che vedremo in console:


Deferreds consente di concatenare insieme multiple callback e errbacks così da essere eseguite in ordine sequenziale. Inoltre il Deferreds consente di fornire una funzione di annullamento così da eseguire un'operazione di abort in richieste asincrone.

Tutte le chiamate di input/output alla rete restitutiscono un Deferred perchè offre una maggiore flessibilità nella gestione delle chiamate asincrone.

Vediamo un esempio applicato ad una funzione XHR.

 var d = dojo.xhrGet({
  
        url : "/legend.json",
  
        handleAs : "json", 
  
                 load : function(response, ioArgs) {
  
                  return response; // passa al prossimo callback
  
                 },
  
                 error : function(response, ioArgs) {
  
                  return response; //passa al prossimo errback
  
                 }
  
                });
  
                //chiamato una volta che il load è completato
  
                d.addCallback(function(response) {
  
                      console.log("Il response 1 e': ", response);
  
                      //passato al prossimo callback
  
                   return response;
  
                });
  
                d.addCallback(function(response) {
  
                      console.log("Il response 2 e': ", response);
  
                   return response;
  
                });
  
                d.addErrback(function(response) {
  
                      console.log("C'è un errore: ", response);
  
                   return response;
  
                });  

Questo è il risultato in console:




Per annullare un'operazione asincrona 'iniettiamo' un deferred negli eventi load ed error:

 var d = new dojo.Deferred;
  
                     //aggiungi una funzione di callback
  
                     d.addCallback(function(response){
  
                          console.log("Callback 1: ", response);
  
                          return response;
  
                     });
  
                     //Aggiungi un'altra callback che viene eseguita dopo la precedente
  
                     d.addCallback(function(response){
  
                          console.log("Callback 2: ", response);
  
                          return response;
  
                     });
  
                     d.addErrback(function(response){
  
                          console.log("Errback 1: ", response);
  
                          return response;
  
                     });
  
                     d.addErrback(function(response){
  
                          console.log("Errback 2: ", response);
  
                          return response;
  
                     });
  
                     request = dojo.xhrGet({
  
                          url: "/legend.json",
  
                          handleAs: "json",
  
                          timeout: 5000,
  
                          load: function(response, ioArgs){
  
                               console.log("load: ", response);
  
                               d.callback(response, ioArgs);
  
                               return response; // passa al prossimo callback
  
                          },
  
                          error: function(response, ioArgs){
  
                               console.log("error: ", response);
  
                               d.errback(response, ioArgs);
  
                               return response; //passa al prossimo errback
  
                          }
  
                     });  

Se non annulliamo avremo:

se annulliamo con un: request.cancel() avremo



Infine vi segnalo il DeferredList che fa parte del core che facilita la gestione di multipli Deferreds.

Vediamo un esempio pratico con le API Javascript ESRI. Tenete presente che dalla versione 1.4 i task restituiscono un oggetto dojo.Deferred che permette di monitorare lo stato della richiesta e gestire la comunicazione di thread asincroni.

 var mapDeferred = esri.arcgis.utils.createMap(itemInfo, "map", {
  
       mapOptions: {
  
        slider: true
  
       },
  
       bingMapsKey: bingMapsKey,
  
 geometryServiceURL: "http://sampleserver3.arcgisonline.com/ArcGIS/rest/services/Geometry/GeometryServer"
  
  });
  
 mapDeferred.addCallback(function(response) {
  
       map = response.map;
  
       dojo.connect(dijit.byId('map'), 'resize', resizeMap);
  
 });
  
 mapDeferred.addErrback(function(error) {
  
      console.log("Map creation failed: ", dojo.toJson(error));
  
 });
  

Il metodo esri.arcgis.utils.createMap che crea una mappa utilizzando informazioni da arcgis.com restituisce un dojo.Deferred con response:
{
map: esri.Map,
itemInfo:{
item: Object,
itemData:Object
}
}

che utilizziamo per aggiungere una funzione di callback per, ad esempio, impostare il resize della mappa.