Archivio

Posts Tagged ‘Leaflet’

OpenDistributoriCarburantiBot: come è fatto “dentro”


In questo post vedo di fornire qualche dettaglio su quelle che sono le caratteristiche e soluzioni tecniche che stanno alla base di OpenDistributoriCarburantiBot.

Non mi dilungo qui a spiegare nel dettaglio la piattaforma Telegram e la basi dei bot: rimando coloro che fossero interessati ad approfondire ad attingere dalle innumerevoli fonti presenti in rete.

Schematicamente l’architettura della soluzione è la seguente:

OpenDistributoriCarburantiBot

Nel diagramma sono citati i vari componenti del sistema che:

Si tratta di una soluzione che utilizza tutti software open source e attinge da servizi disponibili in rete.

Per una soluzione più scalabile è possibile passare ad utilizzare POSTGRESQL con la sua estensione POSTGIS, non cambiando la logica di funzionamento.

Nel diagramma sono anche illustrati i passi delle diverse operazioni coinvolte e precisamente:

  • giornalmente il sistema scarica dal MISE (0a) i dati e li memorizza sul db (0b)
    l’utente invia una richiesta dal proprio client (1)
  • il sistema recupera le richieste con un’operazione di getUpdates (2)
  • effettua le ricerche su DB (3)
  • nell’elaborazione della risposta invoca i servizi di Google Shortlink per abbreviare le url (4)
  • con un’operazione di sendMessage risponde (5)
  • Telegram inoltra la risposta al client (6)
  • l’utente può fruire dei diversi link contenuti nella risposta (7, 7a, 7b e 7c)

Il “cuore” del sistema sono i dati: questi sono tratti giornalmente dagli open del Ministero dello Sviluppo Economico (MISE).

I dati sono forniti nella forma di due file .csv che riportano le anagrafiche dei distributori ed i prezzi dei carburanti. Tra i dati delle anagrafiche dei distributori, informazione importante, sono disponibili anche le coordinate, espresse in latitudine e longitudine.

NOTA: negli esempi si suppone che il sw sia installato in /var/www/html/Telegram per cui la variabile <base_path> = /var/www/html/Telegram

Tutte le mattine, con un crontab schedulato, i dati sono prelevati via wget,

wget -U "Opera" -O <base_path>/OpenDistributoriCarburantiBot/Dati/prezzo_alle_8.csv http://www.sviluppoeconomico.gov.it/images/exportCSV/prezzo_alle_8.csv

wget -U "Opera" -O <base_path>/OpenDistributoriCarburantiBot/Dati/anagrafica_impianti_attivi.csv http://www.sviluppoeconomico.gov.it/images/exportCSV/anagrafica_impianti_attivi.csv

Si provvede ad eliminare la prima riga dei files

sed '1d' <base_path>/OpenDistributoriCarburantiBot/Dati/anagrafica_impianti_attivi.csv > <base_path>/OpenDistributoriCarburantiBot/Dati/anagrafica-temp.csv

sed '1d' <base_path>/OpenDistributoriCarburantiBot/Dati/prezzo_alle_8.csv > <base_path>/OpenDistributoriCarburantiBot/Dati/prezzo.csv

Nel file delle anagrafiche è necessario eliminare il carattere “doppi apici” che influisce negativamente nell’import in Spatialite

sed 's/"//g' <base_path>/OpenDistributoriCarburantiBot/Dati/anagrafica-temp.csv > <base_path>/OpenDistributoriCarburantiBot/Dati/anagrafica.csv

A questo punto è possibile creare il data base Spatialite ….

/usr/local/bin/spatialite <base_path>/OpenDistributoriCarburantiBot/Dati/PrezziCarburanti < <base_path>/OpenDistributoriCarburantiBot/Dati/CreaPrezziCarburanti.txt

….. con i seguenti dettagli …

CREATE TABLE anagrafica_impianti_attivi( idImpianto TEXT,
Gestore TEXT,
Bandiera TEXT,
Tipo Impianto TEXT,
Nome Impianto TEXT,
Indirizzo TEXT,
Comune TEXT,
Provincia TEXT,
Latitudine DOUBLE,
Longitudine DOUBLE );
CREATE TABLE prezzo_alle_8( idImpianto TEXT,
descCarburante TEXT,
prezzo TEXT,
isSelf TEXT,
dtComu TEXT );
.mode csv

.separator ;

.import <BASE_PATH>/OpenDistributoriCarburantiBot/Dati/anagrafica.csv anagrafica_impianti_attivi

SELECT AddGeometryColumn('anagrafica_impianti_attivi','geometry',4326,'POINT',2); UPDATE anagrafica_impianti_attivi SET geometry = GeomFromText('POINT('||"Longitudine"||' '||"Latitudine"||')',4326);

.import <BASE_PATH>/OpenDistributoriCarburantiBot/Dati/prezzo.csv prezzo_alle_8

.quit

La logica di business è stata implementata in php sebbene questa non sia una scelta esclusiva od obbligata. E’ possibile scegliere linguaggi di programmazione diversi: nel mio caso è stata una scelta di opportunità visto che in PHP avevo la possibilità di trovare maggiore esempi e supporto.

Di potenziale interesse riporto come sono implementate le ricerche, ad esempio quella per i distributori di un comune

SELECT distr.Comune, distr.Gestore, distr.Indirizzo, distr.Bandiera, distr.Latitudine, distr.Longitudine, prz.descCarburante, prz.prezzo, prz.dtComu FROM anagrafica_impianti_attivi as distr JOIN prezzo_alle_8 as prz ON (prz.idImpianto = distr.IdImpianto) WHERE distr.Comune = :Comune ORDER BY prz.prezzo ASC

dove ovviamente il parametro :Comune sarà poi valorizzato dal nome del comune corrente indicato dall’utente.

Analogamente, una ricerca spaziale che individua i distributori di un certo carburante, nell’intorno di una certa distanza da un punto, caratterizzato da una determinata coppia di coordinate, sarà

SELECT distr.Comune, distr.Gestore, distr.Indirizzo, distr.Bandiera, distr.Latitudine, distr.Longitudine, prz.descCarburante, prz.prezzo, prz.dtComu, ST_Distance(distr.geometry, MakePoint('.$lon.', '.$lat.', 4326), 1) AS dist FROM anagrafica_impianti_attivi as distr JOIN prezzo_alle_8 as prz ON (prz.idImpianto = distr.IdImpianto) WHERE dist <= '.$dist.' AND prz.descCarburante = \''.$carburante.'\' ORDER BY prz.prezzo ASC, dist ASC

Ovviamente i risultati delle query sono poi parsificati opportunamente per andare a costruire il messaggio finale che arriverà sul dispositivo dell’utente finale.

Ecco come …..

try {
$stmt = $db->prepare($q);
$results = $stmt->execute();
$count = 0;
while (($row = $results->fetchArray(SQLITE3_ASSOC)) AND ($count < $limit_search)){
$data .= "Marca: ".$row['Bandiera'];
$data .= "\n";
$data .= "Carburante: ".$row['descCarburante'];
$data .= "\n";
$data .= "Prezzo: ".$row['prezzo'];
$data .= "\n";
$data .= "Data: ".$row['dtComu'];
$data .= "\n";

$longUrl = "http://www.openstreetmap.org/?mlat=".$row['Latitudine']."&mlon=".$row['Longitudine']."&zoom=18";
$shortUrl = CompactUrl($longUrl);
$data .= "Mappa: ".$shortUrl;
$data .= "\n";

$longUrl = $base_url."/Telegram/DistributoriCarburanti/RenderRoute.php?lat_from=".$lat."&lon_from=".$lon."&lat_to=".$row['Latitudine']."&lon_to=".$row['Longitudine']."&map_type=0";
$shortUrl = CompactUrl($longUrl);
$data .= "Descrizione Percorso: ".$shortUrl;
$data .= "\n";

$longUrl = $base_url."/Telegram/DistributoriCarburanti/RenderRoute.php?lat_from=".$lat."&lon_from=".$lon."&lat_to=".$row['Latitudine']."&lon_to=".$row['Longitudine']."&map_type=2";
$shortUrl = CompactUrl($longUrl);
$data .= "Percorso su mappa 2D: ".$shortUrl;
$data .= "\n";

$longUrl = $base_url."/Telegram/DistributoriCarburanti/RenderRoute.php?lat_from=".$lat."&lon_from=".$lon."&lat_to=".$row['Latitudine']."&lon_to=".$row['Longitudine']."&map_type=3";
$shortUrl = CompactUrl($longUrl);
$data .= "Percorso su mappa 3D: ".$shortUrl;
$data .= "\n";

$data .= "\n";
$count = $count + 1;
}
if ($count >= $limit_search){
$data .= "La ricerca ha prodotto troppi risultati !!! Si presentano solo i primi ".$limit_search.". Per maggiori dettagli provare a cambiare comune, tipo di carburante, posizione o raggio di ricerca";
$data .= "\n";
}
return $data;
}
catch(PDOException $e) {
print "Something went wrong or Connection to database failed! ".$e->getMessage();
}
}
}

I messaggi di Telegram non possono superare i 4096 caratteri e dovendo fornire le url per la visualizzazione dei dettagli del percorso o della sua rappresentazione su mappa, ho dovuto “restringere” le url stesse avvalendomi del servizio di Google URL Shortener.

Il tutto avviene invocando un’apposita funzione …

function CompactUrl($longUrl)
{
$apiKey = API;

$postData = array('longUrl' => $longUrl);
$jsonData = json_encode($postData);

$curlObj = curl_init();

curl_setopt($curlObj, CURLOPT_URL, 'https://www.googleapis.com/urlshortener/v1/url?key='.$apiKey.'&fields=id');
curl_setopt($curlObj, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curlObj, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($curlObj, CURLOPT_HEADER, 0);
curl_setopt($curlObj, CURLOPT_HTTPHEADER, array('Content-type:application/json'));
curl_setopt($curlObj, CURLOPT_POST, 1);
curl_setopt($curlObj, CURLOPT_POSTFIELDS, $jsonData);

$response = curl_exec($curlObj);

// Change the response json string to object
$json = json_decode($response);

curl_close($curlObj);
$shortLink = get_object_vars($json);

return $shortLink['id'];
}

Siccome tutte le comunicazioni sono “stateless”, mentre per alcuni passaggi necessitavo di mantenere traccia delle opzioni selezionate ai passi precedenti, ho implementato una piccola gestione di sessione sul db SQLite 3.

In questo modo aggiorno i dati quando necessario …

try {
$base_path = BASE_PATH;
//## Preparo di dati di sessione da memorizzare nel data base per il'id di chat ...
$session_data = array(
array('Chat_id' => $chat_id,
'Comune' => $comune,
'My_Lat' => $lat,
'My_Lon' => $lon,
'Search_Distance' => $search_distance
)
);
//## Accedo al db di sessione per memorizzare i dati per il'id di chat ...
$db_data_sessions = new SQLite3($base_path.'/DistributoriCarburanti/DataSessionsDB');
//## Accedo al db di sessione per eliminare i dati di sessione per di interesse per l'id di chat ...
$q="DELETE FROM data_sessions WHERE Chat_id = :Chat_id";
try {
$stmt = $db_data_sessions->prepare($q);
$stmt->bindvalue(':Chat_id', $chat_id, SQLITE3_TEXT);
$results = $stmt->execute();
}
catch(PDOException $e) {
print "Something went wrong or Connection to database failed! ".$e->getMessage();
}

//## Prepare INSERT statement to SQLite3 file db ...
$insert = "INSERT INTO data_sessions (Chat_id, Comune, My_Lat, My_Lon, Search_Distance) VALUES (:Chat_id, :Comune, :My_Lat, :My_Lon, :Search_Distance)";
$stmt = $db_data_sessions->prepare($insert);

//## Bind parameters to statement variables ...
$stmt->bindParam(':Chat_id', $Chat_id);
$stmt->bindParam(':Comune', $Comune);
$stmt->bindParam(':My_Lat', $My_Lat);
$stmt->bindParam(':My_Lon', $My_Lon);
$stmt->bindParam(':Search_Distance', $Search_Distance);

//## Loop thru all messages and execute prepared insert statement ...
foreach ($session_data as $data) {
//## Set values to bound variables ...
$Chat_id = $data['Chat_id'];
$Comune = $data['Comune'];
$My_Lat = $data['My_Lat'];
$My_Lon = $data['My_Lon'];
$Search_Distance = $data['Search_Distance'];

//## Execute statement ...
$stmt->execute();

$db_data_sessions = null;
}

}
catch(PDOException $e) {
print "Something went wrong or Connection to database failed! ".$e->getMessage();
}

ed in questo modo recupero i dati quando necessario ….

$db_data_sessions = new SQLite3($base_path.’/DistributoriCarburanti/DataSessionsDB’);
$q="SELECT ds.Chat_id, ds.Comune, ds.My_Lat, ds.My_Lon, ds.Search_Distance
FROM data_sessions as ds
WHERE ds.Chat_id = :Chat_id";
try {
$stmt = $db_data_sessions->prepare($q);
$stmt->bindvalue(':Chat_id', $chat_id, SQLITE3_TEXT);
$results = $stmt->execute();
while ($row = $results->fetchArray(SQLITE3_ASSOC)){
$comune = $row['Comune'];
$my_lat = $row['My_Lat'];
$my_lon = $row['My_Lon'];
$search_distance = $row['Search_Distance'];
}
}
catch(PDOException $e) {
print "Something went wrong or Connection to database failed! ".$e->getMessage();
}

Per il calcolo dei percorsi utilizzo il servizio di routing di MapQuest (rif. https://developer.mapquest.com/products/directions): tale servizio, gratuito sino a 15.000 chiamate al giorno (non credo di superare tali limite …. ne sarei piacevolmente stupito ….), si basa sui dati di OpenStreetMap e permette di ritornare sia la semplice descrizione testuale del percorso, sia i suoi dettagli geografici in formato JSON.

Ecco un esempio di chiamata ….

http://www.mapquestapi.com/directions/v2/route?key=YOUR_KEY_HERE&from=Lancaster,PA&to=York,PA&callback=renderNarrative

Il richiamo del servizio avviene via CURL

$url = 'http://open.mapquestapi.com/directions/v2/route?key=&outFormat=json&routeType=fastest&timeType=1&narrativeType=html&enhancedNarrative=true&shapeFormat=raw&generalize=0&locale=it_IT&unit=k&from='.$lat_from.','.$lon_from.'&to='.$lat_to.','.$lon_to.'&drivingStyle=2&highwayEfficiency=21.0';

//#Set CURL parameters
$ch = curl_init();
curl_setopt($ch, CURLOPT_AUTOREFERER, TRUE);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE);
curl_setopt($ch, CURLOPT_PROXY, '');
$data = curl_exec($ch);
curl_close($ch);

//#Convert to string (json) the route ...
$json = json_decode($data);

ed ecco come aggiungere il json del percorso sulla mappa Leaflet …..

var json_route = <?php echo json_encode($json); ?>;

//# Calculate the new map center based on the route bounding box ...
lng_ul = json_route.route.boundingBox.ul.lng;
lat_ul = json_route.route.boundingBox.ul.lat;
lng_lr = json_route.route.boundingBox.lr.lng;
lat_lr = json_route.route.boundingBox.lr.lat;
lng_center = (lng_lr - lng_ul)/2 + lng_ul;
lat_center = (lat_ul - lat_lr)/2 + lat_lr;


var map = L.map('map').setView([lat_center, lng_center], 15);

L.tileLayer('https://api.tiles.mapbox.com/v4/{id}
/{z}/{x}/{y}.png?access_token=’, {
maxZoom: 18,
attribution: 'Map data © OpenStreetMap contributors, ' +
'CC-BY-SA, ' +
'Imagery © Mapbox',
id: 'mapbox.light'
}).addTo(map);


the_coords = '';

for (i = 0; i < json_route.route.shape.shapePoints.length;
i++) {

if (i == 0) {
the_coords = the_coords + '[' + json_route.route.shape.shapePoints[i+1] + ',' + json_route.route.shape.shapePoints[i] + ']';
}
else {
if ((i % 2) == 0) {
the_coords = the_coords + ',[' + json_route.route.shape.shapePoints[i+1] + ',' + json_route.route.shape.shapePoints[i] + ']';
}
}
}

//# Create the lineString json (text) of the route ...
var my_lineString = '{\"type\": \"Feature\", \"properties\": {
}, \”geometry\”: {\”type\”: \”LineString\”, \”coordinates\”: [‘ + the_coords + ‘]}}’;

//# Create le lineString json (object) of the route ...
var lineString = JSON.parse(my_lineString);

//# add the lineString json (object) of the route to the map ...
L.geoJson(lineString).addTo(map);

Per la rappresentazione su mappa 3D l’approccio è del tutto analogo, con una unica eccezione: non essendo possibile sovrapporre alla mappa OSM Buildings un oggetto Linestring il percorso viene trasformato in un oggetto poligonale calcolandone un piccolo buffer di 1 metro. Il calcolo del buffer avviene avvalendosi della libreria Turf.js (rif. http://turfjs.org/).

Ecco come avviene il tutto ….

//# Extract the route coordinates ...
the_coords = '';

for (i = 0; i < json_route.route.shape.shapePoints.length; i++) {
if (i == 0) {
the_coords = the_coords + '[' + json_route.route.shape.shapePoints[i+1] + ',' + json_route.route.shape.shapePoints[i] + ']';
}
else {
if ((i % 2) == 0) {
the_coords = the_coords + ',[' + json_route.route.shape.shapePoints[i+1] + ',' + json_route.route.shape.shapePoints[i] + ']';
}
}
}

//# Create the lineString json (text) of the route ...
var my_lineString = '{\”type\”: \”Feature\”, \”properties\”: {}, \”geometry\”: {\”type\”: \”LineString\”, \”coordinates\”: [‘ + the_coords + ‘]}}’;

//# Create le lineString json (object) of the route ...
var lineString = JSON.parse(my_lineString);

//# Set the unit measure and calculate the buffer using Turf.js ....
var unit = 'meters';
var buffered = turf.buffer(lineString, 1, unit);
var result = turf.featurecollection([buffered]);

//# Convert to string the buffered json ....
var my_json = JSON.parse(JSON.stringify(result));

//# Create an empty Polygon json to put in OSM Building map ....
var geojson_route = {
type: 'FeatureCollection',
features: [{
type: 'Feature',
properties: {
color: '#FF0080',
roofColor: '#ff99cc',
height: 0,
minHeight: 0
},
geometry: {
type: 'Polygon',
coordinates: [
[
]
]
}
}]
};

//# Add the coordinates at the Polygon json bringing them from the buffered json ....
for (var i = 0; i < my_json.features[0].features[0].geometry.coordinates[0].length; i++) {
geojson_route.features[0].geometry.coordinates[0][i] = my_json.features[0].features[0].geometry.coordinates[0][i];
}

//# Add the Polygon json to the map ....
osmb.addGeoJSON(geojson_route);

//# Refresh of the map to show the labels ...
map.setPosition(map.getPosition());

Ovviamente per maggiori dettagli mi potete contattare direttamente.

Annunci

Numeri civici Open Data in Italia (hashtag #IndirizzatiItalia!): un po’ di dettaglio tecnico

24 settembre 2014 3 commenti

Nel post relativo all’annuncio  di Numeri Civici Open Data in Italia (hashtag #IndirizzatiItalia!) non mi sono dilungato nei dettagli tecnici per non appesantire: ora, per chi interessato, fornisco qui alcune informazioni.

Nel documento è possibile trovare, per ogni livello informativo:

  • i riferimenti relativi al nome dell’Ente che lo mette a disposizione in modalità open data
  • la sua url di pubblicazione
  • la sua url di download
  • il riferimento della licenza d’uso del dato
  • la url di download al dato trasformato in formato ESRI shapefile (senza alterazione della struttura dati), con sistema di riferimento WGS84

I dati sono anche resi consultabili, da un punto di vista geografico, usando il software open source QGIS, in due modalità:

Una breve nota tecnica: è necessario, per la consultazione di livelli informativi del Geoportale Nazionale, che, qualora si operi su una rete locale, si verifichi la corretta configurazione del  proxy, e, per rendere operativo lo sfondo OpenStreetMap, che, nel QGIS utilizzato, sia presente ed attivo il plugin OpenLayers. I progetti QGIS sono stati realizzati con la versione 2.0.1 (Dufour).

Per una consultazione web ho invece realizzato un piccolo esempio in web mapping basato su HTML, Javascript e Leaflet.

DettaglioMappa

L’applicazione permette di:

  • localizzare l’area di interesse per indirizzo o nome della località
  • attivare / disattivare i layer di interesse (il dettaglio dell’indirizzo <via> <civico> è fornito solo alle scale di maggior dettaglio)
  • interrogare interattivamente il livello informativo “Civici Geoportale Nazionale – (WFS)”

Visto che nell’applicazione di web mapping non era possibile elencare i più di 100 livelli informativi, questi sono stati raggruppati per Regione e/o Ente realizzando per ognuno di essi un singolo catalogo raster TMS usando come soluzione TileMill.

Per rendere più veloce la produzione dei vari cataloghi i dati, dopo essere stati trasformati in formato ESRI Shapefile e riportati in WGS84 (EPSG 4326), sono stati caricati in POSTGIS.

Sono anche disponibili due livelli informativi tratti dai geoservizi OGC offerti dal Geoportale Nazionale, il servizio WMS dei civici aggiornamento 2012 e il corrispettivo servizio WFS che permette l’interrogazione interattiva dei singoli numeri civici (funzionalità disponibile solo alle scale di maggior dettaglio onde evitare, da un lato, di richiedere un numero di features eccessivo al server del Geoportale Nazionale, e dall’altro di appesantire la fase di rendering sul browser).

Ovviamente sono disponibili diversi livelli informativi di sfondo (baselayer).

La modalità di pubblicazione in web mapping adottata, sebbene funzionale, ha il vantaggio di essere semplice e non richiede particolari necessità infrastrututrali, è sufficente un web server e un po’ di spazio disco. Al tempo stesso ha, indubbiamente dei limiti, il primo tra tutti è che la sua “semplicità” porta a perdere il livello di dettaglio dei dati raccolti, rendendoli disponibili solo in forma aggregata e come cataloghi raster TMS.

Una soluzione più “enterprise” richiede una disponibilità di un minimo di infrastruttura che al momento non ho adottato non disponendone. Non per questo non ho individuato una possibile soluzione che permetta, da un lato, di mantenere il dettaglio del dato  e al tempo stesso permetta di garantire sia buone prestazioni in consultazione sia l’interoperabilità.

Tale soluzione è basata su una pila tecnologica completamente open source (quindi facilmente replicabile da chi interessato …), che comprende:

Questa rappresenta “una” scelta, non l’unica adottabile nel panorama del mondo gis open source come pure nell’ambito del mondo gis bastao su soluzioni proprietarie.

Implementativamente e per ragioni di praticità, ho utilizzato OpenGeoSuite 4.0.2 (usando una installazione di default, senza alcun parametro di ottimizzazione …), su un quadcore Intel con 8Gbyte di RAM e Windows 7 Enterprise: ovviamente questa non è da considerarsi una configurazione adatta per un ipotetico ambiente di produzione.

Mentre la scelta di POSTGIS come data base spaziale direi che è quasi “inequivocabile”, la scelta di GeoServer è stata indirizzata dal fatto che, oltre ad essere un ottimo gis server, ha una caratteristica che, nel caso specifico dei dati che si dovevano trattare, tornava molto utile, vale a dire la capacità di implementare un point clustering server side per facilitare la consultazione di layer con un gran numero di punti che, altrimenti, dovrebbero essere renderizzati sul client, con prestazioni non accettabili.

Il tutto, come valore aggiunto, realizzato usando modalità standard, vale a dire uno stile SLD, ed esponendo il layer in interoperabilità secondo i consueti standard OGC (WMS e WFS).

NOTA: l’esempio di stile SLD fornito dal tutorial Buondless non permette di interrogare i singoli punti e quindi ho dovuto leggermente modificarlo e lo rendo liberamente scaricabile.

Volendo approfondire questa funzionalità ho quindi adottato questa soluzione.

Ecco un video in cui, usando GeoExplorer (integrato in OpenGeoSuite …), è possibile consultare tutti i 149 layer messi a disposizione

 mentre ecco un video in cui, alcuni dei layer dei civici puntuali sono consultati come layer WMS da un client QGIS

dimostrando quindi come, se ce ne fosse ancora bisogno, grazie all’adozione di servizi GIS esposti secondo standard di interoperabilità e con architetture in grado di scalare opportunamente sia possibile offrire dati geografici a diversi fruitori, sia gis desktop (commerciali e non), sia web browser (usando librerie open source quali OpenLayers, Leaflet, ecc .. , ma anche usando soluzioni commerciali), sia mobile, ma a questo punto diventa un puro esercizio informatico che non ha grande valore aggiunto quindi mi fermo qui.

Numeri civici Open Data in Italia (hashtag #IndirizzatiItalia!): ce ne sono? Quanti sono? Chi li mette a disposizione? Dove sono?

24 settembre 2014 4 commenti

Spesso a volentieri, seguendo le varie discussioni legate al geocoding di informazioni sulla base dell’indirizzo, si argomenta sulle potenzialità di georeferenziare oggetti sfruttando questa possibilità che, indubbiamente, permette di localizzare sul territorio molte informazioni.

Diversi sono gli sforzi di sensibilizzazione in tal senso: ultimi in ordine di tempo, la lettera aperta al Presidente del Consiglio Matteo Renzi sulla geo-localizzazione per i servizi ai cittadini  e il white paper sulla geo-localizzazione per i servizi ai cittadini, la cui stesura è in corso in modo collaborativo e sul quale, nel corso della prossima conferenza AM/FM il 25 Settembre a Roma, si terrà un convegno.

Argomento altamente dibattuto quindi la georeferenziazione per indirizzo ….. ma spesso se ne parla senza citare (o porre l’enfasi che si dovrebbe ….), quello che è l’elemento essenziale la cui disponibilità rende il tutto disponibile e fattibile, cioè l’indirizzo georiferito, al quale è poi possibile associare gli elementi che si intende localizzare / posizionare sul territorio stesso.

Per “indirizzo georiferito” si intende non tanto l’indirizzo espresso nei termini <via><n° civico>, con cui poi si effetta il geocoding usando strumenti e librerie commerciali e/o open source, ma, bensì, la coppia di coordinate che caratterizzano quell’indirizzo sul territorio.

  • Queste informazioni ci sono da qualche parte?
  • Sono liberamente disponibili / utilizzabili?
  • Quanti ce ne sono di liberamente disponibili / utilizzabili?
  • In quale modalità?
  • Quali Enti li stanno mettendo a disposizione?
  • Dove e come sono distribuiti sul territorio Nazionale?

Queste sono solo alcune delle domande che, personalmente, mi sono posto e a cui ho provato a cercare di dare una risposta.

Risposta sicuramente non esaustiva e definitiva, ma che al tempo stesso può essere un punto di partenza da integrare / arricchire con l’obiettivo di avere finalmente contezza di ciò di cui si stà parlando in modo oggettivo e tangibile rendendo queste informazioni disponibili nel loro insieme.

La mia ricerca è partita da quanto mette a disposizione per questa tematica OpenStreet Map con i suoi dati liberamente scaricabili. La situazione, come è normale attendersi per una comunità mondiale che si basa sul crowdmapping, è “a macchia di leopardo” , in special modo in Italia.

Ho poi proseguito sfogliando i vari geoportali e portali open data delle diverse Regioni, Province e Comuni Italiani per vedere se e quali di questi Enti mettessero a disposizioni i dati dei numeri civici georiferiti.

Con un po di pazienza sono arrivato al termine della mia ricerca ed il risultato non è stato esaltante.

Solo i seguenti Enti amministrativi mettono a disposizione questo livello informativo in modo esplicito:

  • Comune Anzola dell’Emilia
  • Comune di Torino
  • Comune di Bologna
  • Comune di Trento
  • Comune di Cesena
  • Comune di Rimini
  • Comune di Pavia
  • Regione Friuli Venezia Giulia

(NOTA: a questa lista va aggiunta la Regione Toscana che, il 22/09/14, ha dato notizia della disponibilità dei dati del proprio database topografico alla scala 1:2000, tra i cui livelli sono presenti  anche i numeri civici. News troppo a ridosso della pubblicazione di questo post per cui non ho avuto ancora il tempo di raccogliere ed integrare questi dati).

Una prima considerazione, oltre al plauso dovuto per la disponibilità offerta all’utenza per questi dati: se lo hanno fatto loro vuol dire che …. SI …. PUO’ …. FARE!!!

Un po’ poco però se lo immaginiamo rispetto al panorama nazionale.

Allora ho allargato un po’ la mia ricerca andando a cercare anche ciò che fosse stato reso disponibile come informazioni, legate a livelli informativi puntuali, che tipicamente avessero un indirizzo georiferito (se hanno un indirizzo ciò significa che questo esiste sul territorio ….)

Questa ricerca ha richiesto, ovviamente, molto più tempo, ma alla fine ha permesso di incrementare, sino agli attuali 149, il numero dei tematismi con indirizzi georiferiti potenzialmente disponibili  e, come effetto collaterale, anche individuare una serie di tipologie di livelli informativi che “tipicamente” sono messi a disposizione come open data georiferito, la cui distribuzione è la seguente:

DistribuzioneTipologieSi noti come la tipologia dei numeri civici veri e propri rappresenti “solo” il 5% del totale delle informazioni raccolte.

Il totale di ciò che ho raccolto è reso liberamente disponibile nel rispetto delle licenze d’suo dei dati originali.

Nel documento è possibile trovare, per ogni livello informativo:

  • i riferimenti relativi al nome dell’Ente che lo mette a disposizione in modalità open data
  • la sua url di pubblicazione
  • la sua url di download
  • il riferimento della licenza d’uso del dato
  • la url di download al dato trasformato in formato ESRI shapefile (senza alterazione della struttura dati), con sistema di riferimento WGS84

I dati sono anche resi consultabili, da un punto di vista geografico, usando il software open source QGIS, in due modalità:

Una breve nota tecnica: è necessario, per la consultazione di livelli informativi del Geoportale Nazionale, che, qualora si operi su una rete locale, si verifichi la corretta configurazione del  proxy, e, per rendere operativo lo sfondo OpenStreetMap, che, nel QGIS utilizzato, sia presente ed attivo il plugin OpenLayers. I progetti QGIS sono stati realizzati con la versione 2.0.1 (Dufour).

Per una consultazione web ho invece realizzato un piccolo esempio in web mapping basato su HTML, Javascript e Leaflet.

DettaglioMappa

Nel caso dell’applicazione web, per ragioni di semplificazione, i dati disponibili sono stati “aggregati” per Regione e/o Ente.

L’applicazione permette di:

  • localizzare l’area di interesse per indirizzo o nome della località
  • attivare / disattivare i layer di interesse (il dettaglio dell’indirizzo <via> <civico> è fornito solo alle scale di maggior dettaglio)
  • interrogare interattivamente il livello informativo “Civici Geoportale Nazionale – (WFS)”

Per tutti i dettagli tecnici di approfondimento si rimanda al post relativo.

Questa è una semplice raccolta di informazioni “as-is” mirata a dare un quadro d’insieme a livello nazionale della libera disponibilità di questa tipologia di informazioni, e nulla è stato fatto per armonizzare tra di loro i dati o per controllarne la qualità, sia della georeferenziazione, sia dell’informazione associata: è possibili quindi, anzi direi che è praticamente certo, che vi siano livelli informativi diversi che riportino il medesimo indirizzo localizzato sul territorio in punti diversi. Questo è sicuramente un lavoro che sarebbe di gran valore aggiunto ma che va oltre gli scopi e le finalità di questo post.

Cosa si potrebbe fare a questo punto? Beh tantissime cose, a partire dall’ampliare la disponibilità di questo tipo di dato da parte sia della P.A. Locale (Regioni, Province e Comuni), seguendo l’esempio di quelle che lo hanno già fatto, ma anche da parte della P.A centrale, con il completamento e la disponibilità aperta del Anagrafe delle Strade e dei Numeri Civici (ma ovviamente con la georeferenziazione dei civici ….. non come recentemente è stato fatto da ISTAT …:-) …), che era stato annunciato nel Decreto Digitalia, rinominato “Ulteriori misure urgenti per la crescita del Paese” (D.L. n.179 del 18 ottobre 2012) e di cui non si più saputo molto a 2 anni di distanza.

L’informazione georiferita, e quindi anche, ed in particolare direi, quella georiferita o georiferibile per indirizzo, può infatti essere considerata un fattore importante anche come elemento di crescita per lo sviluppo del Paese, argomento ultimamente ampiamente dibattuto nel contesto nazionale: se ne sono accorte (anni fa direi ….), realtà commerciali mondiali quali Google e la stessa Apple (con meno successo … ),  e quindi potrebbe esserlo, con i dovuti rapporti di scala, anche per il panorama Italiano, iniziando a vedere le informazioni georiferite come “infrastruttura” per i servizi futuri, ma con orizzonti che devono essere brevissimi.

Il dato disponibile in modalità open e con licenza compatibile, potrebbe poi andare ad integrare  e completare la copertura del livello di civici per OpenStreetMap in Italia (che al momento non è esaltante e non paragonabile ad altre realtà europee quali, ad esmepio. la Germania … ),  rendendo ancora più ampia la diffusione su larga scala di questo livello informativo anche oltre i confini nazionali. Come esempio di campo di applicazione si pensi ad esempio ai diversi motori di calcolo percorsi open source già oggi disponibili  (OpenTriplanner, OSRM, Graphopper, ecc …), che si basano su dati OSM e che non hanno nulla da invidiare (anzi in alcuni casi e per alcune caratteristiche a volte si dimostrano anche migliori … ).

Per evitare che questo lavoro resti una mera “fotografia” ad oggi, ma abbia una sua vita ed evoluzione, mi propongo di mantenerne un aggiornamento più o meno trimestrale, continuando a monitorare ogni annuncio utile che mi possa permettere di individuare nuove disponibilità (ovviamente chi interessato e a conoscenza di dati che non compaiono ancora nella raccolta me lo può segnalare liberamente, e sarà mia cura andarli ad integrare e rendere disponibili, nella medesima modalità, in versioni successive della stessa), poi …. non pongo limiti!.

Chiudo con i dovuti e necessari ringraziamenti a tutti coloro a cui, in varia modalità ho “rotto” un po’ le scatole nell’arco temporale (più lungo del previsto ma il tempo è sempre poco ….), che ha richiesto questo lavoro: a tutti un grazie per il tempo, poco o tanto non importa, che hanno speso per rispondere alle mie domande e per il supporto fornito. Cito i nomi sparsi ……. @napo, @simonecortesi@sbiribizio, @aborruso, @Piersoft, @ffierm, Diego.

P.S: Last but not least … un ringraziamento particolare, con menzione, a mia moglie Mary per la pazienza e per il tempo che un po’ le ho rubato.

GeoSpatial Data Version Control: GitHub permette di vedere l’evoluzione di un file geojson nel tempo


Come già accennato in un precedente post, GitHub può essere utilizzato come repository per geodati memorizzando dati geografici in formato GeoJSON e di visualizzandoli utilizzando Leaflet.

Da oggi è disponibile una nuova features: quella di vedere l’evoluzione di un file geojson nel tempo confrontando tra loro le modifiche del dato

GitHubHistory

E’ anche possibile tra l’altro customizzare le features specificandone proprietà come colore di reimpimento, opacità, ecc …

Fonte: GitHub Blog
.

Categorie:Progetti Tag:, ,

GitHub visualizza GeoJSON usando Leaflet


Le possibilità offerte da GitHub di essere utilizzato come repository per geodati oggi si sono ampliate di una nuova feature:  memorizzare dati geografici in formato GeoJSON e di visualizzarli utilizzando Leaflet.

Chicago-GitHub

La notizia è molto interessante e, sebbene con dei limiti tutti da verificare in relazione alle dimensioni dei GeoJSON supportati, apre importanti prospettive.

Ricordo che la stessa OpenGeo con GeoGit sta lavorando sull’utilizzo di GitHub per provare ad affontare il tema della creazione e gestione dei dati geografici con gli stessi principi collaborativi con cui viene trattata la gestione del codice sorgente, e che la città di Chicago sta già utilizzando la piattaforma per condividere alcuni dei suoi open data georiferiti con gli utenti.

Fonte: GitHub Blog

Mappa del Trentino: un esempio di un uso sinergico di dati open


E’ stata pubblicata la mappa web e mobile della Provincia Autonoma di Trento da parte di WebMapp.

MappaTrentino

Si tratta di un bell’esempio di come si possano ottenere eccelenti risultati utilizzando dati e tools open source.

I tre organismi produttori dei principali dati utilizzati per costruire la carta sono infatti:

I software opensource utilizzati sono stati:

La mappa delle Trentino è distribuita con licenza Creative Commons Attribuzione-Non commerciale-Condividi allo stesso modo 3.0 Italia

Ottima iniziativa e bell’esempio da seguire!

Erzgebirgsbahn utilizza OpenStreetMap


In un precedente post avevo riportato come la città di Linz visualizzasse in tempo reale i dati dei suoi trasporti pubblici utilizzando OpenStreetMap come mappa di riferimento.

Ecco ora un secondo caso: Erzgebirgsbahn visualizza la posizione corrente dei suoi treni su una mappa basata su OSM eLeaflet (il sito è in tedesco ….)

Treni

Fonte: OSM-Talk