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

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 27 maggio 2012

Geometric Network

Una rete geometrica  è un oggetto per modellare una serie di feature interconnesse. Generalmente sono utilizzate per modellare le reti tecnologiche (elettrica, gas, acqua ecc.) e le reti naturali (corsi d’acqua).
Concettualmente le reti sono semplici.
Esse sono composte da due componenti fondamentali: edge e junction.
Le strade, le linee di trasmissione, le tubazioni, i corsi d’acqua sono esempi di edge mentre gli incroci stradali, i fusibili, gli interruttori, le valvole e le confluenze di corsi d’acqua sono esempi di junction.
Gli edge si connettono tramite le junction ed il flusso da un edge (automobili, elettroni, acqua) può essere trasferito ad un altro edge.


                                 Vista geografica                                                 Vista logica

Come si evince dalla vista geografica, una rete è composta da feature lineari attraverso la quali le risorse si spostano. Una rete contiene feature puntuali dove avviene il trasferimento di risorse come, ad esempio, da strade a stazioni ferroviarie o da una strada all’altra.
Invece dalla vista logica possiamo notare come la rete è composta di edge e junction. Il flusso di ‘risorse’ attraversa gli edge e gli edge si connettono tramite junction dove abbiamo il trasferimento da un edge ad un altro. Solo la connettività tra edge e junction è importante rispetto alla geometria della rete.
In ArcGIS più feature class possono partecipare insieme alla rete ma una feature class può partecipare ad una sola rete geometrica. Tutte le feature class devono appartenere allo stesso feature dataset. Ad esempio feature class che rappresentano linee di trasmissione, interruttori, fusibili e trasformatori possono essere parte della stessa rete. Poiché le feature hanno una geometria, e quindi possono essere georeferenziate, la rete è chiamata rete geometrica.
Le feature class, partecipando in una rete geometrica, rappresenteranno o le feature edge (linee) o le feature junction (punti).
Per ogni rete geometrica c’è una corrispondente rete logica che è una struttura dati che memorizza gli elementi edge e junction e li connette fra di loro. Questa struttura logica è automaticamente costruita e mantenuta dal momento che si crea la rete geometrica.


                                          Rete geometrica                                        Rete logica
Rete geometrica:
- collega insieme feature class per creare una rete;
- contiene feature edge e feature junction;
- tutte le modifiche e le visualizzazioni avvengono sulla rete geometrica;
- contiene tutti gli attributi, le relazioni e le regole di validazione.

Rete logica:
- struttura  dati che memorizza la connettività della rete;
- contiene elementi edge e junction;
- gli sviluppatori possono scrivere programmi che si occupano esclusivamente di rete logica;
- può essere analizzata o visualizzata come un insieme di tabelle;
- non contiene delle geometrie;
- i dati sono mantenuti automaticamente quando la rete geometrica viene modificata.



Utilizzando il metodo INetworkLoader3:: LoadNetwork () possiamo creare via codice la nostra rete geometrica.
La rete geometrica contiene le feature che partecipano alla rete.
Le feature class contengono o feature edge o feature junction.
La rete logica registra la connettività della rete. La tabella di connettività elenca tutte le junction adiacenti ad una data junction lungo l’edge che le connette.
Il cuore della rete logica è la tabella della connettività che registra come gli elementi sono connessi. Per ogni junction nella rete la tabella di connettività elenca gli edge adiacenti e le junction connesse agli estremi degli edge adiacenti.
Dato un elemento della rete utilizzando INetwork::CreateForwardStar() e specificando honorState = true (per farsi restituire gli elementi non disabilitati) possiamo, chiamando FindAdjacent(), determinare il numero degli elementi adiacenti; successivamente, chiamando i metodi relativi QueryAdjacent{Edge,Junction}(), possiamo prendere ogni elemento adiacente con il proprio relativo peso (vedi più avanti la definizione di peso)

INetSchema netSchema = geometryNetwork.Network as INetSchema
INetWeight junctionWeight = netSchema. get_WeightByName(“JunctionImpedance”);
INetWeight edgeFTWeight = netSchema. get_WeightByName(“FTEdgeImpedance”);
INetWeight edgeTFWeight = netSchema. get_WeightByName(“TFEdgeImpedance”);
IForwardStarGEN fs = geometryNetwork.Network.CreateForwardStar(true, junctionWeight, edgeFTWeight, edgeTFWeight, null);
Loop entireNetoworkIsTraversed
{
        int numAdjacent;
        fs.FindAdjacent(fromEIDEdge, atJuctionEID, ref numAdjacent);
        for (int i=0;i++; i<numAdjacent)
       {
            fs.QueryAdjacentEdge(i, ref adjEdgeEID, ref adjEdgeOrientation, ref adjEdgeWeightValue);
            fs.QueryAdjacentJunction(i, ref adjJunctionEID, ref adjJunctionWeightValue);
       }
}



Come già detto, in una rete geometrica possono partecipare più feature class . In questo esempio abbiamo una feature class junction (Cities) e due feature class edge (Major rails e Trunk routes).
La rete logica traccia gli ID delle feature. La rete logica, per ogni coppia di Id Feature class e OID della feature, crea un suo proprio Id interno (EID = Element ID). L’univocità è data da questa coppia perché possono partecipare più feature class e quindi il solo OID della feature non garantisce l’univocità dell’elemento. Internamente poi la struttura fa riferimento ad una chiave surrogata che fa riferimento alla coppia tramite l’EID (Element ID). Più avanti vedremo che occorrerà aggiungere un terzo Id per rendere unico l’elemento nelle tabelle che memorizzano la struttura logica.
Le feature class partecipano ad uno dei quattro ruoli seguenti: edge semplici, junction semplici, edge complesse e junction complesse. Inoltre ogni rete ha una feature class dove memorizza le junction orfane.



Una junction semplice ha una corrispondenza 1 a 1 tra la feature e l’elemento junction (EID).
Analogamente, un edge semplice ha una corrispondenza 1 a 1 tra la feature e l’elemento edge (EID). 
Dalla figura possiamo notare come ad esempio  la junction con id= j1 ha come riferimento l’EID =0.
Molte reti possono essere modellate con junction ed edge semplici mentre per alcune reti la corrispondenza 1 a 1 potrebbe essere troppo restrittiva. In questo caso le junction e gli edge complessi forniscono un grado di controllo superiore per potere così modellare queste realtà.
Per capire gli edge complessi vediamo un esempio: supponiamo di avere una condotta principale per la distribuzione dell’acqua che si estende per diverse centinaia di metri lungo una via. Lungo questa condotta sono presenti diverse prese che si connettono alle tubazioni di servizio degli edifici. Tutte le funzioni di gestione ed interrogazione dei dati necessitano di trattare questa condotta principale come una singola feature. Ma poiché le funzioni di analisi delle reti necessitano di un modello di flusso dalla condotta principale alle prese, la rete logica deve trattare le porzioni tra ogni presa, creando molte sezioni frammentate nella condotta principale che complicherebbero la manutenibilità e l’interrogazione dei dati.



In questo esempio c’è una condotta principale che serve due case; per avere flusso dalla condotta principale alle case occorre aggiungere due junction sulla condotta principale. Con gli edge semplici l’unico modo per aggiungere junction è dividere la condotta in tre edge separati perché gli edge semplici hanno una corrispondenza 1 a 1 con gli elementi edge.
Gli edge complessi risolvono il problema della frammentazione consentendo alle junction di essere poste lungo la condotta senza creare nuove feature di tipo edge.
Una rete geometrica con feature di tipo complesso crea molte edge per ogni feature. Quando si crea una rete geometrica specifichiamo se la feature class edge è di tipo semplice o complesso. Se è di tipo complesso poi la feature non sarà frammentata quando aggiungiamo una junction su di essa.



Per questa edge di tipo complesso la rete geometrica crea tre elementi edge da una feature edge assegnando un sub-ID per ogni feature.
Pertanto, per identificare univocamente un elemento, occorre conoscere la feature class ID, il feature ID e il sub-ID.
L’ID surrogato (Element ID = EID) farà riferimento a questa tripletta univoca all’interno della tabella Edge.

Con gli ArcObjects, ad esempio per determinare i tre id dato l’EID (element Id), possiamo utilizzare il metodo INetElements::QueryIDs:

INetElements netElements = geometricNetwork.Network as INetElements;
int featureClassID, featureID, subID;
netElements.QueryIDs(eid, esriElementType.esriETEdge, out featureClassID, out featureID, out subID);

Mentre per determinare l’EID di un edge più vicino ad un punto possiamo utilizzare il metodo IPointToEID::GetNearestEdge().
Mentre per determinare la junction più vicina ad un punto possiamo utilizzare il metodo IPointToEID::GetNearestJunction ().
Per quel che riguarda le junction complesse, il modo migliore per capire di cosa si tratta è immaginare un armadio elettrico in una rete elettrica. Un armadio elettrico può essere visto come una rete in miniatura costituita da proprie junction ed edge.



In una rete elettrica le junction complesse sono utilizzate per rappresentare interruttori complessi. In questo schema sono visualizzati due interruttori (SW1 e SW2) e due fusibili (F1 e F2).
Nella rete geometrica questo interruttore può essere rappresentato da un oggetto (SW-2) implementato come feature junction complessa, dove entrano ed escono due conduttori (c1,c2 e c3,c4).
Nella rete logica questo interruttore è modellato con 4 elementi edge e 5 elementi junction. Occorrerà scrivere del codice in una junction complessa per gestire gli elementi edge e junction nella rete logica.
Un altro esempio di junction complessa potrebbe essere una stazione di pompaggio in una rete di distribuzione dell’acqua.



Anche qui la stazione di pompaggio è una junction complessa composta da molte junction ed edge semplici.
Poiché è abbastanza complesso sviluppare una junction complessa (interface IComplexJunctionFeature) e visto che anche la stessa ESRI non lo consiglia, è possibile sfruttare le componenti del geodatabase per implementare funzionalità parziali come le class extension.
Abbiamo accennato alle junction orfane che sono create per definire i punti terminali degli edge che non sono identificati da un’altra feature class junction, durante la creazione o durante le modifiche in gestione della rete stessa.
La procedura di creazione della rete parte sempre creando le junction orfane da punti terminali di edge; successivamente la procedura confronta la posizione delle junction orfane con la posizione delle junction fornite dalle feature. Se viene trovata una junction (tramite la tolleranza impostata) la junction è utilizzata e la junction orfana viene scartata. Se non viene trovata nessuna junction, la junction orfana viene scritta nella feature class delle junction orfane. Se durante una sessione di editing creiamo una feature junction da sostituire ad una junction orfana creata durante il processo di costruzione della rete, la junction orfana è rimossa ed è sostituita dalla nuova feature junction.


Come possiamo notare, le junction orfane (in figura rappresentate con delle stelline) sono quelle junction che non sono rimpiazzate da feature junction (in questo caso da Cities) ma che vengono memorizzate in una feature class con il nome della rete geometrica seguita dal suffisso ‘_Junctions’.


Le reti ricadono in due contesti operativi: le reti tecnologiche e le reti di trasporto.
In una rete di trasporto ad esempio l’automobilista decide come muoversi attraverso la rete mentre in una rete tecnologica le ‘risorse’ che si muovono attraverso la rete (acqua, elettricità ecc) hanno un flusso ben definito. La rete impone la direzione di flusso configurando le sources (sorgenti), i sink (punti di scarico) e gli interruttori. Le reti tecnologiche hanno un flusso definito mentre le reti di trasporto non hanno un flusso definito.



                                           Rete di trasporto                            Rete tecnologica
In una rete tecnologica la direzione di flusso lungo gli edge è intrinsecamente parte della rete e quindi non è un qualcosa che viene calcolato di volta in volta e poi scartato.  Ad esempio, supponiamo di utilizzare la rete per prendere delle decisioni operative come chiudere un interruttore o aprire una valvola. E’ necessario conoscere il flusso presente al fine di prendere la giusta decisione e occorre sapere se la decisione si tradurrà nel flusso corretto. Le facilities nella rete che influenzano il flusso come sorgenti, punti di scarico, interruttori e valvole necessitano di essere conosciuti dalla rete e la direzione di flusso è sempre sincronizzata con queste strutture.
La rete geometrica dispone di un metodo che stabilisce la direzione di flusso. Questo metodo decide come le risorse si muovono nella rete basata sulla configurazione corrente delle sorgenti e dei punti di scarico e abilita lo stato di ogni feature.
Il risultato della direzione di flusso stabilita è la direzione di flusso delle risorse lungo gli edge o nella direzione di digitalizzazione della feature o nella direzione opposta.



Come possiamo notare, il flusso è verso il punto di scarico (sink) ma e1 ha il flusso contrario alla direzione di digitalizzazione mentre e3 e e2 hanno il flusso concorde con le feature.
Il metodo che stabilisce la direzione di flusso nella rete geometrica popola la proprietà Flow Direction di ogni elemento edge nella rete logica. Il flusso è Against (opposto alla direzione di digitalizzazione) o With (nello stesso senso di digitalizzazione). Questa informazione è utilizzata quando si visualizza il flusso sulla rete geometrica.
In una rete tecnologica le source e i sink sono utilizzati per determinare la direzione di flusso. Alcune feature class junction possono avere un ruolo ausiliario (ancillary) di sorgente o di punto di scarico. Una source è una junction dalla quale parte la risorsa (ad esempio una pompa). Un sink è una junction dove tutte le risorse terminano come ad esempio un impianto di trattamento delle acque. Quando si crea una rete geometrica, possiamo indicare o meno se in feature class junction abbiamo il ruolo di ancillary. Se è disponibile, l’utente può utilizzarlo per specificare se una junction all’interno della feature class è source o sink.



Il ruolo è memorizzato come attributo della feature class ed è accessibile dal metodo che stabilisce la direzione di flusso. Nell’attributo possiamo indicare Source, Sink o None (dominio nel geodatabase).
Tutte le feature che partecipano nella rete hanno uno stato Abilitato/Disabilitato. Le feature che hanno impostato disabilitato non partecipano nel flusso della rete: nessun flusso nella feature. Disabilitare le feature è utile per rappresentare valvole chiuse o interruttori elettrici aperti.
Quando si creerà via codice una feature occorre ricordarsi che, prima di creare la geometria e chiamare lo Store, se è presente il subtype, si dovrà impostare il metodo IRowSubtypes::SubtypeCode. Nell’InitDefaultValues saranno gestiti il ruolo ancillary e l’Enabled.
Le source, i sink e lo stato abilitato/disabilitato delle feature influenzano il flusso nella rete.



Ogni feature class ha un attributo Enabled che memorizza lo stato abilitato/disabilitato. Nell’esempio gli edge tratteggiati sono disabilitati. Nella rete logica ogni elemento memorizza lo stato abilitato/disabilitato.
Quando le source, i sink e le feature disabilitate non danno abbastanza informazioni è possibile che la direzione di flusso non possa essere stabilita per ogni edge. Di conseguenza l’edge ha un flusso indeterminato.



In questo caso non è possibile determinare la direzione di flusso data dalla configurazione delle sorgenti, punti di scarico e feature abilitare. Nell'esempio è impossibile determinare il flusso tra l’edge e1 e l’edge e2 perché formano un ciclo. Se dovessimo cambiare la junction j2 a source il ciclo verrebbe interrotto. Nel campo Direzione di Flusso verrà scritto Indeterminate come direzione di flusso quando non è possibile stabilire il flusso.
Quando un flusso è isolato perché gli edge sono disconnessi dal resto della rete (che ha flusso) il flusso è detto: non inizializzato.



In questo esempio una valvola è stata disabilitata e così gli edge non raggiungibili sono disconnessi dal resto della rete.
Gli edge e le junction possono avere dei pesi associati.
I pesi sono utilizzati per memorizzare il costo di attraversamento di un edge o di una junction. La lunghezza di un edge è un esempio di peso. I pesi sono creati dai valori nei campi delle feature class edge e junction.



Gli edge e le junction feature possono avere più pesi associati (nell’esempio: diameter e length). I pesi sono memorizzati nella rete logica in modo che i programmi di analisi possano accedere più efficientemente. Quando un valore di un peso è modificato nella tabella della feature, esso è automaticamente aggiornato nella rete logica.


I pesi su differenti feature class possono essere raggruppati  in un singolo peso nella rete logica.



In questo esempio al peso di nome LengthLine sono associati i campi Shape_Lenght per le feature class swCasing, swCulvert, swOpenDrain, swVirtualDrainline e swGravityMain.
Per recuperare questa informazione con gli ArcObjects è possibile utilizzare il metodo INetSchema::get_WeightAssociations.

            INetSchema netSchema = (INetSchema)this.GeometricNetwork.Network;
            INetWeight netWeight;
            List<JsonObject> weights = new List<JsonObject>();
            for (int i = 0; i < netSchema.WeightCount; i++)
            {
                netWeight = netSchema.get_Weight(i);
                JsonObject weight = new JsonObject();
                weight.AddLong("id", (long)netWeight.WeightID);
                weight.AddString("name", netWeight.WeightName);
                weight.AddString("type", Enum.GetName(typeof(esriWeightType), netWeight.WeightType));
                weight.AddLong("bitGateSize", (long)netWeight.BitGateSize);
               
                List<JsonObject> weightAssociation = new List<JsonObject>();
                IEnumNetWeightAssociation enumNetWeightAssociation = netSchema.get_WeightAssociations(netWeight.WeightID);
                INetWeightAssociation netWeightAssociation = enumNetWeightAssociation.Next();
                while (netWeightAssociation != null)
                {
                    JsonObject joNetWeightAssociation = new JsonObject();
                    joNetWeightAssociation.AddString("fieldName", netWeightAssociation.FieldName);
                    joNetWeightAssociation.AddString("tableName", netWeightAssociation.TableName);
                    weightAssociation.Add(joNetWeightAssociation);
                    netWeightAssociation = enumNetWeightAssociation.Next();
                }
                weight.AddArray("weightAssociation", weightAssociation.ToArray());
                weights.Add(weight);
            }

Per i pesi devono essere indicati campi di tipo numerico.
In funzione del tipo di analisi che dovrà essere fatta si utilizzeranno i pesi appropriati.
E’ anche disponibile un tipo speciale di peso: il tipo bitgate. Il tipo bitgate è utile quando si desidera intercettare una serie di categorie di edge o junction, come ad esempio consentire il passaggio agli autoveicoli in una strada. Inoltre questo tipo di peso è utile perché l’informazione è fornita in modo compatto. Se, ad esempio, abbiamo un peso che ha un intervallo da 0 a 7 esso potrà essere memorizzato con 3 bit. Per reti molto grandi la compressione dei pesi potrà risultare molto importante traducendosi in velocità di accesso ai valori.


In questo esempio un peso bitgate è utilizzato per consentire o meno ad una serie di categorie di veicoli di attraversare ogni strada. Per Passenger autos e Heavy Truck è consentito il passaggio nell’edge e1 mentre per l’edge e2 non è consentito per Heavy Truck.
Come per la direzione di flusso che è relativa alla direzione di digitalizzazione della feature possiamo definire i pesi in funzione della direzione di digitalizzazione. Possiamo così avere un peso che rappresenta il costo di attraversamento nella direzione di digitalizzazione (“from-to”) ed un altro costo per attraversarlo nel senso opposto di digitalizzazione. Normalmente i pesi direzionali sono utilizzati nelle reti di trasporto dove il traffico si muove in entrambe le direzioni.
In ArcObjects per impostare due pesi differenti in funzione della direzione di digitalizzazione:

            INetSolverWeightsGEN netSolverWeights = traceFlowSolver as INetSolverWeightsGEN;
            INetwork network = this.geometricNetwork.Network;
            INetSchema netSchema = network as INetSchema;
            INetWeight netFromToEdgeWeight = netSchema.get_WeightByName("NameWeightFT");
            netSolverWeights.FromToEdgeWeight = netFromToEdgeWeight;
            INetWeight netToFromEdgeWeight = netSchema.get_WeightByName("NameWeightTF");
            netSolverWeights.ToFromEdgeWeight = netToFromEdgeWeight;

Nella rete geometrica la connettività è basata sulla coincidenza geometrica ed è sempre attiva.
Nella maggior parte delle reti non tutti gli edge possono logicamente connettersi a tutti i tipi di junction.
Analogamente, non tutti i tipi di edge possono connettersi logicamente a tutti gli altri tipi di edge attraverso tutti i tipi di junction. Ad esempio in un rete di distribuzione dell'acqua un tubo (edge) con diametro 10 pollici può connettersi ad un altro (edge) di 8 pollici attraverso un riduttore (junction).
Le regole di connettività vincolano il tipo di feature che può connettersi ad un altro tipo e il numero di feature di un particolare tipo che può connettersi a feature di un altro tipo. Stabilire queste regole con altre regole tipo i domini può garantire una maggiore integrità dei dati della rete nel geodatabase. A richiesta, è possibile validare feature selezionate e generare un report che indicherà le feature nella rete che violano le regole di connettività e le altre regole.

Regole:

Edge-junction: una regola di connettività che stabilisce che un edge di tipo A può connettersi ad una junction di tipo B;
edge-edge: una regola di connettività che stabilisce che un edge di tipo A può connettersi ad un edge di tipo B attraverso una junction di tipo C. Le regole edge-edge coinvolgono sempre un tipo di junction;
tipo di junction di default: due tipi di edge possono connettersi attraverso più di un tipo di junction. E’ possibile impostare quale tipo di junction è utilizzato di default per connettere due tipi di edge. Il tipo di junction è il tipo di junction di default;
cardinalità edge-junction: una regola che consente ad un edge di tipo A di connettersi ad una junction di tipo B. Di default un qualsiasi numero di edge di tipo A può connettersi ad una singola junction di tipo B. Possiamo però vincolare questo numero. Possiamo in pratica indicare l’intervallo di numero (ad esempio minimo 2 e massimo 5) di edge di tipo A che può connettersi ad una junction di tipo B. Se ci saranno meno di 2 o più di 5 edge la regola di connettività sarà violata. In modo analogo possiamo restringere il numero di junction di tipo C che può connettersi a qualsiasi junction di tipo D.



In ArcGIS la configurazione di queste regole è impostata nella sezione Connectivity. In questo esempio impostiamo una regola edge-edge dove il tipo swGravityMain della feature class swGravityMain (edge) può connettersi ad un edge delle stesso tipo tramite la junction di tipo swManhole e swInlet delle rispettive feature class. Poiché per queste feature class (swGravityMain, swManhole, swInlet) non è stato definito nessun subtype la regola è possibile definirla per l’unico subtype definito cioè la feature class stessa. Possiamo notare anche è stato definito il tipo di junction di default (swManhole) da utilizzare quando si connettono due edge del tipo swGravityMain della feature class swGravityMain.



In questo caso vediamo una impostazione edge-junction dove un edge di tipo swGravityMain della feature class swGravityMain (edge) può connettersi ad un tipo swInlet della feature class swInlet. Il numero di swGravityMain che possono connettersi a questo tipo di junction è minimo 2 e massimo 5 mentre un edge di questo tipo può avere connesso minimo 1 e massimo 2 junction di tipo swInlet. E’ chiaro che per valori superiori di junction è possibile solo con edge di tipo complesso perché edge di tipo semplice hanno al massimo due junction connesse dello stesso tipo.
Per migliorare la qualità del dato e per verificare eventuali anomalie nella rete è possibile, tramite la nuova extension Data Reviewer per ArcGIS 10, controllare anche problematiche relative alla rete geometrica. Vi segnalo questi due post dal blog ESRI:
http://blogs.esri.com/esri/arcgis/2012/05/09/data-reviewer-and-the-geometric-network/
http://blogs.esri.com/esri/arcgis/2012/05/17/data-reviewer-advanced-checks-and-the-geometric-network/
In ArcGIS l’analisi di rete è definita come una procedura che permette di navigare attraverso la connettività della rete per ottenere risultati di un certo significato, come ad esempio trovare tutti gli elementi a monte di un punto o determinare il percorso minimo tra due punti.
Un programma che fa analisi di rete è chiamato solver, perché risolve un problema come ad esempio isolare un flusso chiudendo una serie di valvole.
In questo solver di isolamento del flusso gli input dovrebbero essere la rete logica, l’edge da isolare e la serie di junction che sono le valvole. L’output dovrebbe essere il minimo set di valvole da chiudere per isolare il flusso dell’edge. La sola restrizione riguardo gli input e gli output del solver è che l’input includa sempre una rete logica.
I solver hanno un’interfaccia utente per poter specificare gli input e poter vedere i risultati di output.



In ArcGIS Desktop abbiamo a disposizione la toolbar Utility Network Analyst dove abbiamo a disposizione una serie di Trace solver nel Trace Task che eseguono alcune analisi di rete. Per analisi non presenti in lista è possibile crearsene di personalizzate utilizzando gli ArcObjects.
In questo caso occorrerà implementare le interfacce ITraceTask e ITraceTaskResults.
Nel  dettaglio:
ITraceTask::OnCreate()
Logica eseguita quando il trace task è caricato in ArcMap
ITraceTask::get_Name()
Nome del trace task visualizzato nella toolbar Utility Network Analyst
ITraceTask::get_EnableSolve()
Logica eseguita quando il pulsante Solve sarà abilitato. Essendo eseguito frequentemente, inserire logica molto leggera.
ITraceTask::OnTraceExecution()
-Logica eseguita quando il pulsante Solve viene cliccato
ITraceTaskResults::get_Result{Edges/Junctions}()
Lista di elementi della rete nel risultato
Tramite l’oggetto UtilityNetworkAnalysisExt è possibile recuperare tutte le impostazioni presenti nella toolbar dell’Utility Network Analyst. Questo oggetto è utile per trasferire tutte le impostazioni dell’utente al solver che si vuole implementare.
Un riferimento a questo oggetto è passato quando si chiama l’ITraceTask::OnCreate
Qui potete vedere un esempio di custom trace.
Il netflag è una posizione sulla rete. I solver utilizzano i netflag per rappresentare oggetti del mondo reale come posti da visitare nella determinazione di un percorso minimo, punti di partenza per un tracing, posizioni di servizi e così via. Ci sono due tipi di netflag: edgeflag e junctionflag. Le proprietà del netflag includono l’ID della feature class, il feature ID (l’identificatore univoco all’interno della feature class), e il sub-ID (utilizzato per gli edge complessi per identificare il singolo elemento della feature edge complessa), altrimenti è 0 per le junction e gli edge semplici. Attenzione che i valori di sub-ID non necessariamente corrispondono all’ordine degli elementi edge nella feature ed inoltre non sono necessariamente consecutivi.
Per identificare l’EID possiamo utilizzare IComplexNetworkFeature::FindEdgeEID() o l’oggetto PointToEID.
Per convertire l’EID (identificatore elemento) a classeFC/Id Feature/SubID possiamo utilizzare come già detto:

INetElements netElements = geometryNetwork.Network as INetElements;
netElements.QueryIDs(inputEID, esriETEdge, ref outputClassID, ref outputFeatureID, ref outputSubID)

Una junctionFlag contiene queste stesse tre proprietà. Un edgeFlag ha inoltre la percentuale lungo l’elemento edge sul quale giace. Questo significa che un edgeflag può cadere dovunque lungo l’edge, da 0% (From Junction) a 100% (To junction).



INetFlag netFlag = new EdgeFlagClass() as INetFlag;
netFlag.UserClassID = fc.FeatureClassID;
netFlag.UserID = feature.OID;
netFlag.SubID = 0;  //(edge semplice)
IEdgeFlag edgeFlag = netFlag as IEdgeFlag;
edgeFlag.Position = 0.5;


Le barrier sono utilizzate dal solver per rappresentare elementi disabilitati della rete logica. Le barriere sono equivalenti a quando si imposta a disabilitato lo stato Enabled di un elemento; l’unica differenza è che le barriere non sono memorizzate nella rete logica ma sono solo riconosciute ed utilizzate dal solver. In pratica le barriere servono per disabilitare temporaneamente gli elementi. Ci sono quattro metodi per catturare e rappresentare le barriere per un solver: barriere semplici, feature selezionate, feature class e pesi filtrati.

Barriere semplici: le barriere semplici sono una collezione di edge e junction. ArcGIS ti lascia interattivamente creare barrier semplici con un tool di inserimento di barriere;
Feature selezionate: ArcMap ha tool per selezionare le feature. Il solver può poi utilizzare le feature selezionate per utilizzarle come barriere o meno



Il solver agirà solamente sulle feature selezionate mentre quelle non selezionate fungeranno da barriere. Se si seleziona Unselected features avverrà il contrario ovvero il solver agirà solo su quelle non selezionate e quelle selezionate fungeranno da barriere;
Feature Class: Un’intera feature class può essere utilizzata come barriera o meno. Questo è uno short-cut di selezionare tutte le feature di una feature class ed usare quelle selezionate come barriere



In questo caso abbiamo disabilitato la feature class Storm Open Drains e Storm Gravity Mains
Via codice utilizzeremo:
                                netSolver.DisableElementClass(fc.FeatureClassID);

Filtri di pesi: possiamo specificare un peso e un range di valori e questi pesi si attuano come barriere o meno. Filtri di pesi si realizzano come per le feature selezionate. Ad esempio supponiamo di avere un attributo che indica il tipo di tubo ( A o B). Se desideriamo utilizzare il tipo di tubo A nel solver, possiamo selezionare il tipo B e trattarli come barriere. Se questo attributo era anche un peso, possiamo specificare il filtro di pesi dove solo i valori di uno sono utilizzati. Utilizzare il filtro di pesi è più veloce che selezionare le feature perché l’accesso ai valori dei pesi è più veloce dell’accesso agli attributi.



In questo caso sono stati impostati due range per i pesi LengthLine: 10-20 e 40-80. Pertanto il solver utilizzerà gli edge che rientrano in questi range e gli altri fungeranno da barriere.

            INetWeight netJunctionFilterWeight = netSchema.get_WeightByName("junctionWeight");
            netSolverWeights.JunctionFilterWeight = netJunctionFilterWeight;
            bool juncApplyNotOperator = true;
            netSolverWeights.SetFilterType(esriElementType.esriETJunction, esriWeightFilterType.esriWFRange, juncApplyNotOperator);
            int juncFilterRangeCount = 1;
            object[] juncFromValues = new object[juncFilterRangeCount];
            object[] juncToValues = new object[juncFilterRangeCount];
            juncFromValues[0] = 10;
            juncToValues[0] = 20;
            netSolverWeights.SetFilterRanges(esriElementType.esriETJunction, ref juncFromValues, ref juncToValues);
            INetWeight netFromToEdgeFilterWeight = netSchema.get_WeightByName("LengthLine ");
            netSolverWeights.FromToEdgeFilterWeight = netFromToEdgeFilterWeight;
            INetWeight netToFromEdgeFilterWeight = netSchema.get_WeightByName("LengthLine ");
            netSolverWeights.ToFromEdgeFilterWeight = netToFromEdgeFilterWeight;
            bool edgeApplyNotOperator = false;
            netSolverWeights.SetFilterType(esriElementType.esriETEdge, esriWeightFilterType.esriWFRange, edgeApplyNotOperator);
            int edgeFilterRangeCount = 2;
            object[] edgeFromValues = new object[edgeFilterRangeCount];
            object[] edgeToValues = new object[edgeFilterRangeCount];
            edgeFromValues[0] = 10;
            edgeToValues[0] = 20;
            edgeFromValues[1] = 40;
            edgeToValues[1] = 80;
            netSolverWeights.SetFilterRanges(esriElementType.esriETEdge, ref edgeFromValues, ref edgeToValues);


Tracing significa seguire il flusso nella rete fino a quando sono soddisfatte certe condizioni. Quando l’analisi può essere espressa in termini, ad esempio, di: "cerca a monte fino a trovare il primo punto di scarico" o "cerca a monte fino a trovare tutte le valvole", stai certamente pensando ad un solver per trovare la tua risposta.





Per utilizzare questi solver (trace upstream, trace downstream, find common ancestors, find UpstreamAccumulation e Find Path Upstream) è necessario avere la direzione di flusso.

Trace Upstream:  il trace è in senso contrario al flusso da una certa origine (netflag) fino a fermarsi per barriere, sink o fine della rete.
Normalmente questo trace viene utilizzato per trovare possibili punti di sversamento di inquinanti da una stazione di monitoraggio, determinare le valvole da chiudere per isolare edge o determinare statistiche di flusso per un determinato punto;
Trace Downstream: il trace è nel senso del flusso da un’origine (netflag) fino a fermarsi per barriere o sink.
Normalmente utilizzato per determinare la distanza dal sink;
Find Common Ancestors:  da ogni netflag traccia nel senso contrario al flusso fino al source o alla barriera e poi trova le feature (ancestors) comuni a tutte i trace. Normalmente utilizzato per determinare i comuni interruttori o trasformatori;
Find Upstream Accumulation: traccia tutti gli elementi a monte da un’origine (netflag) e restituisce il numero totale questi elementi. Utilizzato per determinare statistiche da un punto e trovare il numero di facilities a monte di una stazione di monitoraggio;
Find Path Upstream: trova un percorso tra un netflag nel senso contrario al flusso alla sorgente. Utilizzato come controllo per determinare la qualità e la consistenza della rete o per trovare il punto di scarico di un inquinante da una stazione di monitoraggio.


Per utilizzare questi solver non è necessario avere la direzione di flusso:





Find connected: trova tutti gli elementi che sono connessi al netflag. Gli elementi connessi sono riferiti alla componente connessa. Utilizzato per verificare la qualità e la consistenza del dato e trovare le componenti connesse;
Find Path: trova un percorso tra due netflag indipedentemente dalla direzione di flusso. Determina  il percorso  minimo minimizzando un peso fornito dall’utente, altrimenti restituisce il numero di elementi attraversati. Utilizzato come controllo per determinare la qualità e la consistenza della rete, controllare la connettività tra due punti o per trovare il percorso con minor costo;
Find Loops: trova tutti i loop indipendentemente dalla direzione di flusso. Il netflag è utilizzato per identificare quale componente utilizzare. Utilizzato come controllo per determinare la qualità e la consistenza della rete o per trovare cause di flusso indeterminato;
Find disconnected: trova tutti gli elementi che non possono essere raggiunti dal netflag. Utilizzato come controllo per determinare la qualità e la consistenza della rete o per trovare le componenti disconnesse.
In questa figura vediamo come si presenta in ArcGIS l’esecuzione del solver Find Path tra due flagEdge rappresentati da quadrati verdi.



In ArcObjects deve essere utilizzato l’oggetto TraceFlowSolver:

                ITraceFlowSolverGEN traceFlowSolver = new TraceFlowSolverClass() as ITraceFlowSolverGEN;
                INetSolver netSolver = traceFlowSolver as INetSolver;
                INetwork network = this.geometricNetwork.Network;
                netSolver.SourceNetwork = network;

Passiamo i netflag come array al TraceFlowSolver (in questo caso un solo EdgeFlag):

                    INetFlag netFlag = new EdgeFlagClass();
                    netFlag.UserClassID = featureClassID;
                    netFlag.UserID = featureID;
                    netFlag.UserSubID = subID;
                    IEdgeFlag[] edgeFlags = new IEdgeFlag[1];
                    edgeFlags[0] = netFlag;
                    traceFlowSolver.PutEdgeOrigins(ref edgeFlags);
                    traceFlowSolver.TraceIndeterminateFlow = false;
                    IEnumNetEID junctionEIDs = null;
                    IEnumNetEID edgeEIDs = null;

In questo caso utilizziamo un FindFlowElements:

                   traceFlowSolver.FindFlowElements(flowMethod, flowElements, out junctionEIDs, out edgeEIDs);

Per farsi restituire i dati utilizziamo l’EIDHelper.
Con l’EIDHelper possiamo anche farci restituire solo le features che ricadono in un certo Envelope (IEIDHelper::putref_DisplayEnvelope()) e aggiungere solo i campi degli attributi che ci interessano (IEIDHelper::AddField())
       
            IEIDHelper eidHelper = new EIDHelperClass();
            eidHelper.GeometricNetwork = this.geometricNetwork;
            eidHelper.ReturnGeometries = true;
            eidHelper.ReturnFeatures = true;
            //risultati da FindFlowEelements tramite l’enumeratore che implementa IEnumNetEID
            IEnumEIDInfo enumEIDinfo = eidHelper.CreateEnumEIDInfo(edgeEIDs);
            enumEIDinfo.Reset();
            IEIDInfo eidInfo = enumEIDinfo.Next();
            while (eidInfo != null)
            {
                IFeatureClass featureClass = eidInfo.Feature.Class as IFeatureClass;
                IFeature feature = eidInfo.Feature;
                int featureClassID = featureClass.FeatureClassID;
…..
                eidInfo = enumEIDinfo.Next();
            }

Scegliere quali attributi utilizzare come pesi nella rete logica dipende dal solver che verrà utilizzato. Il solver stesso non necessita di pesi poiché risolve utilizzando solo la connettività nella rete logica. Ma se abbiamo un solver che restituisce tutte le junction che condividono edge con una determinata caratteristica, allora ha senso specificare questa caratteristica come peso. Inoltre, come già detto, i filtri di pesi, se definiti, possono vincolare il trace, visto che hanno lo stessa funzione di una selezione di feature ma risultano essere più performanti perché definiti direttamente nella rete logica.
Inoltre, tramite i pesi è possibile gestire le gerarchie e le classificazioni dei modi di attraversare la rete (pesi bitgate).
Per il trace ci sono buone notizie in vista della 10.1 perché anche il trace di reti geometriche ora è esposto tramite Geoprocessing (http://resourcesbeta.arcgis.com/en/help/main/10.1/index.html#/Geometric_Network_Trace/0154000005s0000000/) e quindi ci permetterà di creare i nostri modelli ed esporli direttamente via ArcGIS server tramite Geoprocessing service.
Se invece desiderate utilizzare una SOE che effettua il trace ed utilizzarla con un web client ESRI potete scaricare da arcgis.com a questo link.



Il Team Water di ESRI ha sviluppato una toolbar per la gestione di reti tecnologiche (acqua, fognatura ecc.) che potete scaricare da questo link.
In questo post abbiamo parlato delle reti geometriche utilizzate per reti tecnologiche o reti naturali (corsi d’acqua) dove abbiamo visto come è ben definita una direzione lungo gli edge. La risorsa nella rete (ad esempio acqua di un corso d’acqua) non può scegliere la direzione di flusso se non vincolata da fattori esterni: gravità, pressione acqua, elettromagnetismo. Un ingegnere può controllare il flusso della risorsa controllando i fattori esterni che si attuano sulla risorsa.
In una rete di trasporti come quella stradale, pedonale, o rete ferroviaria è consentito il transito in entrambe le direzioni. Chi utilizza la rete, per esempio un automobilista sulla strada, generalmente è libero di decidere in che direzione muoversi per andare in una certa destinazione. In questo caso è possibile utilizzare in ArcGIS l’estensione Network Analyst che gestisce le reti di trasporto mediante l’utilizzo di network dataset.