Archivio

Posts Tagged ‘Open Data’

Quattro milioni di verbali (open …) su una mappa


Tra i vari canali social che seguo ho trovato in questi giorni questo bel riferimento, il progetto Infrazioni  ….

infrazioni

… che usando dati i open delle infrazioni stradali della città di Torino ha realizzato una bella web gis application interattiva con cui si possono visualizzare ed interrogare i dati (potete divertirvi a cercare i luoghi, e i periodi, ove si registrano il maggiore o minore numero di infrazioni per tipologia ….diciamo che chi è di Torino intuisce rapidamente la natura dei due grossi cerchi in alto a sinistra ed in basso a destra della mappa …. 🙂 ).

Al netto dell’interfaccia  (realizzata con MapBox …), che è sicuramente curata, con buone prestazioni e di facile utilizzo, il grosso valore aggiunto è il riuso di dati aperti messi a disposizione da parte di una P.A., rappresentando una bella sinergia, un approccio “win-win” che sempre di più si spera di vedere.

I dati delle infrazioni infatti sono disponibili open data sul portale degli open data del Comune di Torino (e disponibili per più anni, dal 2011 al 2015 …), ma questo non è l’unico dataset utilizzato, in quanto i dati sono stati relazionati sul territorio utilizzando i dati della toponomastica comunale, anch’essi disponibili sul medesimo portale (a tale proposito, come elemento di miglioramento, si potrebbe suggerire al Comune di Torino di integrare già dalla fonte, vale a dire dalle generazione del dato delle infrazioni, la relazione spaziale, diretta o indiretta, con ìl numero civico o l’incrocio corrispondente usando la propria toponomatica al fine di rendere  così i dati relazionati strettamente ed in modo tra loro coerente. Credo che questo avrebbe fatto risparmiare parecchio tempo ai realizzatori del progetto …. se poi proprio volessimo esagerare, avere i medesimi dati disponibili come open services …. male non farebbe …).

E’ comunque un esempio “virtuoso” di collaborazione tra P.A e “privati /cittadini” che vale la pena di segnalare ed applaudire …. bravi tutti!

Annunci

OpenDistributoriCarburantiBot: risparmiare sul pieno di carburante con Telegram

28 febbraio 2016 6 commenti

In questi ultimi tempi, su più fronti si sente parlare molto spesso di Telegram, non solo e non tanto come app di messaggistica (per certi versi in alternativa o in opposizione / concorrenza a WhatsApp), quanto per la possibilità offerta di poter realizzare delle chat automatiche (denominati “bot”), il cui scopo è quello di rispondere alle nostre domande, alle nostre richieste, e facilitare in generale operazioni varie.

Si và da esempi molto semplici, piccoli giochi, sino a cose più serie ed articolate. Riporto ad esempio:

  • @webcamstravelbot che fornisce l’elenco delle webcam intorno ad un punto di interesse
  • @escilaricettaBot che permette di ricercare ricette dato un certo ingrediente di interesse
  • @emergenzeprato_bot per le segnalazioni meteo a di rischio dell’area del comune di Prato
  • @divinacommediabot che permette di ricercare versi della Divina Commedia di Dante
  • @gttorari_bot con cui la compagnia dei trasporti pubblici di Torino informa i propri utenti dei passaggi degli autobus

…. sino ad arrivare, notizia proprio degli ultimi giorni, al canale @pgpompei attraverso il quale Papa Francesco fà arrivare giornalmente il Vangelo del giorno!!! Quindi davvero dal “sacro” al “profano” …..

Non mi dilungo qui a spiegare più nel dettaglio: su internet si trovano abbondanti informazioni sia sulla piattaforma sia su cosa sono questi bot, per cui rimando a queste fonti tutti coloro che fossero interessati ad approfondire.

Più che lo strumento di messagistica in sè, con le sue dichiarate caratteristiche peculiari di maggior sicurezza e rispetto della privacy (nel bene e nel male ….), rispetto ai suoi concorrenti, mi ha incuriosito la possibilità di realizzare queste chat automatiche e quindi, volendone approfondire l’argomento, ho deciso a provare a realizzarne una.

Mi mancava un caso d’uso che non fosse un classico “Hello World!” e che, ovviamente, avesse anche una sua componente “spaziale”.

Dopo qualche riflessione ed ipotesi mi sono ricordato di un bel lavoro fatto tempo fà da Stefano Sabatini (@__sabas) sui distributori di carburanti in Italia che mi sembrava fosse adatto allo scopo: dati “reali”, dati open, liberamente utilizzabili (licenza iodl 2.0), aggiornati giornalmente, con coordinate e quindi facilmente trasformabili in un dato spaziale per poi essere utilizzabili anche con funzionalità spaziali.

E’ così che è nata l’ipotesi, pian piano concretizzatasi, di OpenDistributoriCarburantiBot.

Questo bot permette di sapere, dato un comune italiano, quali sono i distributori di carburante che vi ricadono o, data una posizione georiferita, quali sono i distributori di carburante che ricadono nel suo intorno per una certa distanza (scelta tra 500, 1000, 2000 e 3000 metri).

I dati sono aggiornati giornalmente a partire dalle 08.30 attingendo direttamente dagli open del Ministero dello Sviluppo Economico (MISE).

E’ possibile selezionare il carburante di proprio interesse ed i risultati sono ordinati sulla base del prezzo: è quindi possibile individuare quelli più convenienti per le nostre esigenze.

A seconda del tipo di ricerca effettuata, e se si è fornita o meno la posizione georiferita, è possibile:

  • visualizzare su mappa OpenStreetMap la localizzazione del distributore
  • visualizzare la descrizione del percorso per raggiungere il distributore dalla posizione corrente
  • visualizzare, su mappa 2D, il percorso per raggiungere il distributore dalla posizione corrente
  • visualizzare, su mappa 3D, il percorso per raggiungere il distributore dalla posizione corrente. Per questa ultima funzionalità è necessario disporre di un web browser di ultima generazione che supporti webGL (le ultime versioni di Mozilla Firefox e Chrome sono già abilitate)

Il suo utilizzo è molto semplice: nel seguito vi illustro una sequenza di passi per il suo utilizzo e anche una breve sessione utente registrata in video.

Occorre ovviamente avere installato Telegram sul proprio smartphone, tablet o desktop (nota: la versione desktop è un pò limitata per le funzonalità supportate, ad esempio non è possibile fornire la propria posizione, o almeno io non ci sono riuscito): fatto questo è sufficiente ricercare “OpenDistributoriCarburantiBot” come illustrato

01

All’avvio viene visualizzato un messaggio di benvenuto con una una breve sintesi sulle sue caratteristiche.

02

Occorre avviare il bot se si intende utilizzarlo

04

In qualunque momento questo messaggio è nuovamente visualizzabile scrivendo il comando /start.

Sono disponibili anche altri due comandi, rispettivamente /info (per avere informazioni di dettagli tecnico)…

05

…. e /credits (per i doverosi e necessari ringraziamenti) ….

06

E possibile scrivere il nome di un comune italiano: il nome può essere scritto minuscolo o maiuscolo in modo indifferente. Sono trattati anche nomi di comuni con spazi ed apostrofi.

07

Per i comuni il cui nome contiene lettere accentate è necessario utilizzare gli apici

08

A questo punto occorre selezionare, dal menù visualizzato, il tipo di carburante e attendere il risultato della ricerca

09

Se la ricerca produce risultati questi sono ordinati per prezzo crescente e, per ogni risultato, è possibile visualizzare su una mappa OpenStreetMap la localizzazione del relativo distributore

10

11

L’indicazione del comune non è l’unica modalità di ricerca: è infatti possibile indicare le propria posizione corrente o di interesse cliccando sull’icona della graffetta che in queste videate compare in basso a destra e poi selezionare l’opzione ‘Posizione

12

13

A questo punto è necessario selezionare, dal menù visualizzato, il raggio di ricerca

14

A questo punto occorre selezionare, dal menù visualizzato, il tipo di carburante

15

In questo caso, se la ricerca produce risultati questi sono ordinati per prezzo crescente e, per ogni risultato, è possibile:

  • visualizzare su una mappa OpenStreetMap la localizzazione del relativo distributore
  • visualizzare la descrizione del percorso per raggiungere il distributore di interesse a partire dal punto di ricerca
  • visualizzare il percorso per raggiungere il distributore di interesse a partire dal punto di ricerca su una mappa OpenStreetMap bidimensionale
  • visualizzare il percorso per raggiungere il distributore di interesse a partire dal punto di ricerca su una mappa OpenStreetMap tridimensionale (OSM Buildings)

16

17

18

19

20

Ed ecco ora in video come avviene dal vivo una sessione utente immaginandone la fruizione durante una gita nel territorio Albese:

Come detto in precedenza i dati sono giornalmente tratti direttamente dal Ministero dello Sviluppo Economico (MISE) a cui è demandato il livello di completezza e aggiornamento rispetto alle diverse realtà locali: devo dire che ho notato, almeno nelle zone che conosco, che, da quando ho iniziato a fare questo piccolo esperimento, aggiornamento e completezza sono in crescita.

Per concludere devo ringraziare tutti coloro da cui ho tratto spunti ed ispirazione, nonchè supporto diretto in varie forme, e quindi, sperando di non dimenticare nessuno direi:

  • Stefano Sabatini (@__sabas), per il suo lavoro iniziale da cui ho tratto spunto per l’idea
  • Matteo Tempestini (@il_tempe), Francesco “Piersoft” Paolicelli (@Piersoft) e Gabriele Grillo da cui ho tratto il codice inziale e per il loro supporto via mail
  • Alessandro Furieri, per il suo grandissimo lavoro su Spatialite, data base open source che ho usato come tool per memorizzare i dati georiferiti, e per il suo paziente supporto online
    Fabrizio Massara per la pazienza ed il suo supporto a 360° nonchè, per la condivisione del server su cui stà girando il codice del bot in produzione
  • mia moglie, per il tempo che le ho rubato per fare tutto ciò

Un ringraziamento particolare, perchè si è dimostrato un vero “signore” (merce rara …), lo devo a @Piersoft per la sua disponibilità a rinunciare a pubblicare un lavoro analogo in buona parte realizzato, pur di non “bruciarmi” la news ….. grazie mille!!!!

Per chi fosse interessato a maggiori dettagli tecnici per sapere “come è fatto dentro” rimando ad un altro post

A questo punto non resta quindi che iniziare a provare ad usare di OpenDistributoriCarburantiBot e vedere di iniziare a risparmiare facendo il pieno nei distributori più convenienti!

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.

Numeri civici Open Data in Italia: disponibile la release 3.0 della raccolta

27 settembre 2015 14 commenti

A febbraio 2015 ho pubblicato la seconda versione della raccolta di quelli che sono i numeri civici georiferiti open data disponibili nel panorama italiano.

E’ giunta quindi l’ora di un ulteriore aggiornamento, per cui ora è rendo disponibile la release 3.0 della raccolta stessa.

La raccolta è resa disponibile con licenza CC0 1.0 Universal: ovviamente per i singoli dataset restano valide le licenze originali che sono riportate nella raccolta stessa.

Con questo aggiornamento siamo arrivati a 188 dataset diversi : ci sono aree ancora completamente vuote, intere regioni in cui mancano dati, regioni per cui vi sono dati ridondanti, ecc … ma i numeri stanno crescendo

Ecco quali sono “release notes” di questa versione della raccolta:

  • verificati, per tutti i dataset già esistenti, i link di pubblicazione e download: nel tempo alcuni erano stati cambiati dagli Enti
  • verificate tutte le licenze d’uso: anche qui vi sono casi in cui le licenze sono state modificate
  • aggiunti nuovi dataset, in particolare:
    • Comune di Storo
    • Provincia Autonoma di Bolzano
    • Regione Piemonte
    • Regione Lombardia

La percentuale dei numeri civici resi disponibili come tali, e non “derivati” da altri tematismi,  sale dal 10% al 25 % sul totale delle informazioni raccolte e quindi un buon risultato in termini di crescita  (la prima versione vedeva una percentuale del 5%)

DistribuzioneCivici-V03

Come consueto i dati sono consultabili via web grazie ad un piccolo esempio in web mapping basato su HTML, Javascript e Leaflet.

CiviciItalia2

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

A differenza delle versioni precedenti della raccolta, viste le dimensioni raggiunte, non mi è più stato possibile rendere disponibile anche i dati in formato ESRI shapefile insieme al progetto QGIS di consultazione. Resta comunque possibile, per chi interessato, poter scaricare i singoli dataset in formato ESRI shapefile e convertiti un WGS84 utilizzando i link di download resi disponibili all’interno del file della raccolta stessa

Ricordo una breve nota tecnica: per rendere operativo lo sfondo OpenStreetMap è necessario che, qualora si operi su una rete locale, si verifichi la corretta configurazione del proxy, e che, nel QGIS utilizzato, sia presente ed attivo il plugin OpenLayers.

I progetti QGIS sono stati realizzati con la versione 2.6.1 (Brigthon).

Segnalazioni di dati mancanti per aggiornare la raccolta sono particolarmente gradite …. grazie sin da ora!

Numeri civici Open Data in Italia: disponibile la release 2.0 della raccolta

4 febbraio 2015 10 commenti

A settembre 2014 ho pubblicato la prima versione della raccolta di quelli che sono i numeri civici georiferiti open data disponibili nel panorama italiano, ripromettendomi di rilasciare un aggiornamento ogni trimestre.

Un po’ in ritardo rispetto alle previsioni ma riesco a mantenere ora la promessa e quindi ecco pronta la release 2.0 della raccolta stessa (il totale di ciò che ho raccolto è reso liberamente disponibile nel rispetto delle licenze d’suo dei dati originali).

Quali sono le aggiunte? Non moltissime in termini di numero di Enti ma direi, discrete in termini di volumi di civici georiferiti aggiunti in quanto vanno ad aggiungersi ben 4 Regioni che hanno reso open data questo livello informativo.

L’elenco completo delle aggiunte di questa release è il seguente:

  • Comune di Rovereto
  • Comune di Verona
  • Regione Toscana
  • Regione Umbria
  • Regione Sicilia
  • Comune di Modena
  • Regione Sardegna
  • Comune di Verona
  • Comune di Biella
  • Provincia di Biella

Alcune di queste fonti informative sono già state oggetto di import nella base dati di OSM (Comune di Biella), per altre (Regione Sardegna), l’attività è, ad oggi, in corso e altre lo potrebbero diventare a seconda della compatibilità della licenza d’uso.

La percentuale dei numeri civici sale dal 5% al 10 % sul totale delle informazioni raccolte e quindi un buon risultato in termini di crescita.

TortaCivici2

I dati sono consultabili via web grazie ad un piccolo esempio in web mapping basato su HTML, Javascript e Leaflet.

DettaglioMappa

Analogamente alla release 1.0 tutti i dati sono anche resi consultabili, da un punto di vista geografico, usando il software open source QGIS, in due modalità:

Ricordo una breve nota tecnica: per rendere operativo lo sfondo OpenStreetMap è necessario che, qualora si operi su una rete locale, si verifichi la corretta configurazione del proxy, e che, nel QGIS utilizzato, sia presente ed attivo il plugin OpenLayers.

I progetti QGIS sono stati realizzati con la versione 2.6.1 (Brigthon).

La mappa nazionale inizia a riempirsi di pallini colorati come vedete sotto, anche se ci sono ancora parecchi buchi e regioni in cui, per il momento, non sono riuscito a rintracciare nulla per cui chiedo, a chiunque interessato, di farmi avere riferimenti utili così che possano essere inclusi nei successivi rilasci.

CiviciItalia2

Una nota doverosa, relativamente a questa release, sono i ringraziamenti a coloro che, in varia forma, mi hanno dato una mano con i loro contributi quindi procedo:

  • Giovanni Allegri (@_giohappy_), per i dati di Regione Toscana
  • Maurizio Napolitano (@napo), per i dati di Regione Umbria
  • Andrea Borruso (@aborruso), per l’ispirazione metodologica che ho utilizzato per i dati di Regione Sicilia
  • Francesco Fiermonte (@ffierm), per il tempo speso a farmi da “tester”

In conclusione una riflessione: questo lavoro mi costa fatica, tempo da dedicarci, ecc …., quindi ci tengo ma al tempo stesso sarei lieto di chiuderlo, definitivamente, nel momento in cui vi fosse la disponibilità dei civici georiferiti open data per come prevista nell’elenco dell’Agenda Digitale 2014: purtroppo al momento le date indicate sono state, più o meno ampiamente, disattese, …… ma resto fiducioso …… 🙂

 

Open data e Open service basati su standard: come ottenere lo shapefile dei Numeri Civici Open Data della Regione Sicilia partendo dai servizi resi disponibili


Tutto è nato da una mail di Andrea Borruso, apparsa sulla lista GFOSS proprio alla vigilia di Natale, in cui si annunciava, da parte della Regione Sicilia e per una serie di comuni, la disponibilità, in modalità WFS, di un dataset dei numeri civici georiferiti.

I servizi sono fruibili direttamente da client diversi, desktop, web, mobile, ecc …. che ovviamente supportino lo standard OGC WFS,  cosa oramai ampiamente diffusa, piuttosto facile da fare e alla portata di un’utenza, seppur tecnica, piuttosto ampia.

Con una chiamata standard è anche possibile avere l’elenco dei comuni per cui sono disponibili i dati dei numeri civici: la chiamata è la seguente:

ogrinfo -ro wfs:"http://map.sitr.regione.sicilia.it/ArcGIS/services/CART_2000/Numeri_Civici/GeoDataServer/WFSServer"

Bello ma, per il mio interesse cioè quello di raccogliere i civici open data disponibili sul panorama nazionale, mancava una visione di insieme che mi fornisse TUTTI i civici a livello regionale.

Ma, essendo tutto basato  su standard, si trattava solo di avere un po di voglia e tempo per fare un interessante (??? 🙂 ) esercizio informatico e “rinfrescare” alcune conoscenze messe un po’ da parte negli ultimi tempi.

Provo a riassumere quanto fatto, primo per mie note personali, ma anche perchè credo / spero possa interessare a chi voglia /debba poter replicare un’esigenza analoga.

Premetto che quello indicato NON è l’unico modo possibile per raggiungere l’obiettivo, ve ne possono essere diversi altri, anche più “eleganti”.

In tutto è organizzato in 3 passi logici.

Step 1: scaricare i dati collegandosi ai servizi

Nota organizzativa: gli eseguibili shell che illustro nel seguito operano nel rispetto di questa organizzazione su file system:

OrganizzazioneCartelle

I servizi sono esposti in WFS e quindi possono essere contattati via chiamata http ottendo in risposta, tra le altre cose, il dato in formato GML.

Purtroppo gli attuali servizi non permettono di ottenere i dati in formati diversi.

In questo caso, essendo 376 i comuni da scaricare, e quindi le chiamate da fare, ho creato un piccolo eseguibile shell, lanciabile da linea di comando, che, usando il comando CURL disponibile in ambiente Linux e/o Windows a seconda delle installazioni (nel mio caso ho utilizzato CygWin …), scaricherà, completamente, tutti i singoli GML, uno per ogni comune.

La chiamata, per un singolo comune è la seguente …

curl "http://map.sitr.regione.sicilia.it/ArcGIS/services/CART_2000/Numeri_Civici/GeoDataServer/WFSServer?SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME=CART_2000:NumeriCivici_81008_Erice&SRSNAME=EPSG:4326" -o CiviciComuniSicilia/GML/81008_Erice_4326.gml

Visto che i comuni erano molti ho realizzato un programmino shell, denominato DownloadCiviciByCurl.sh, reso parametrico ….

echo "Download civici $1 ......"
curl "http://map.sitr.regione.sicilia.it/ArcGIS/services/CART_2000/Numeri_Civici/GeoDataServer/WFSServer?SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME=CART_2000:NumeriCivici_$1&SRSNAME=EPSG:4326" -o CiviciComuniSicilia/GML/$1_4326.gml
echo "Sleeping for 30 sec: don't load too much the server ...."
sleep 30

il quale è poi richiamabile da un programmino di lancio denominato LauncherDownloadCiviciByCurl.sh

echo "Starting download civici Sicilia ......"
sleep 5
./DownloadCiviciByCurl.sh 81008_Erice
./DownloadCiviciByCurl.sh 83040_Limina
./DownloadCiviciByCurl.sh 87001_Aci_Bonaccorsi
......
......

da completare con l’elenco dei comuni ricavato dall’istruzione ogrinfo mostrata in precedenza.

I files .sh sono mantenuti nella cartella “Work”.

Ecco uno snapshot dell’esecuzione di questo primo passo …

DownloadCiviciSicilia

Step 2: convertire i dati in formato ESRI shapefile

Il mio obiettivo finale era quello di avere un unico file con tutti gli indirizzi georiferiti disponibili per la Regione Sicilia, e quindi dovevo in un qualche modo unire tra loro, geograficamente, i singoli files GML scaricati.

L’aggregazione geografica di più files GML non sembra sia possibile (dopo una veloce ricerca sul web …), e quindi ho deciso di convertire ogni singolo file GML in uno shapefile per poi unificali tra loro in uno step successivo.

Per eseguire l’operazione di cui sopra ovviamente il tool che meglio si adatta sono ancora le librerie GDAL con il seguente comando ogr2ogr

ogr2ogr -f "ESRI Shapefile" 81008_Erice_4326 CiviciComuniSicilia/GML/81008_Erice_4326.gml

Nel preparare questa trasformazione mi sono accorto che lo shapefile prodotto risultava privo del file di proiezione (.prj), e quindi, con una seconda operazione ogr2ogr ho provveduto ad aggiungere allo shapefile prodotto, il file .prj relativo al sistema di riferimento che volevo utilizzare (EPSG: 4326)

ogr2ogr -a_srs EPSG:4326 CiviciComuniSicilia/Shapefile/NumeriCivici_81008_Erice.shp 81008_Erice_4326/NumeriCivici_81008_Erice.shp

Anche in questo caso  ho poi realizzato un programmino shell, denominato ConvertShapefile.sh, reso parametrico ….

echo Convert $1 civici GML into ESRI shapefile .....
ogr2ogr -f "ESRI Shapefile" $1_4326 CiviciComuniSicilia/GML/$1_4326.gml
echo Adding .prj to $1 civici shapefile .....
ogr2ogr -a_srs EPSG:4326 CiviciComuniSicilia/Shapefile/NumeriCivici_%1.shp $1_4326/NumeriCivici_$1.shp
echo Delete temporary files .....
rm -R $1_4326

il quale è poi richiamabile da un programmino di lancio denominato LauncherConvertShapefile.sh …

echo "Starting converting civici Sicilia in shapefiles ......"
./ConvertShapefile.bat 81008_Erice
./ConvertShapefile.bat 83040_Limina
./ConvertShapefile.bat 87001_Aci_Bonaccorsi
......
......

I files .sh sono mantenuti nella cartella “Work”.

Ecco lo snapshot dell’esecuzione di questo secondo passo …

ConvertShapefile

Step 3: creare un unico shapefile di dati

A questo punto non restava che “fondere” insieme i vari shapefile dei singoli comuni in un unico shapefile a livello regionale.

Anche qui viene in aiuto la libreria GDAL con le ogr2ogr che permettono di effettuare questa operazione eseguendo un semplice ciclo: anche in questo caso ho racchiuso il tutto in un programmino shell che ho nominato UnionShapefileComuni.sh

#!/bin/bash
for f in `ls *.shp`
do
echo "Append shapefile " $f " ....."
ogr2ogr -update -append civici_sicilia.shp $f -f "ESRI Shapefile" -nln civici_sicilia
done

Il file .sh è mantenuto nella cartella “Shapefile”.

Ecco uno snapshot dell’esecuzione di questo terzo passo …

Append

Ed ecco che il gioco è fatto, replicabile e, volendo,  completamente automatizzabile mettendo i vari passi in un unico shell.

Il risultato è il seguente:

Sicilia1

Sicilia2

L’intero dataset è scaricabile e disponibile nel rispetto delle licenze originali dei dati di partenza (CC-BY SA).

Come detto in precedenza quello descritto non è l’unico metodo ma ve ne possono essere molti altri, anche più eleganti: ne cito uno, illustrato da Andrea Borruso, che mi sembra di particolare interesse e che si basa sul fatto che i servizi della Regione Sicilia sono contattabili anche via REST, e quindi, partedo da questo,  si potrebbe replicare l’esperienza fatta da Maurizio Napolitano nel caso di Regione Umbria.

Un primo utilizzo delle informazioni che ho aggreato? Per visualizzare i dati delle mia raccolta degli indirizzi georiferiti open data in Italia (di cui stò preparando la nuova release … stay tuned!!!): portando i dati su un db POSTGIS e poi usando TileMill ho prodotto i tiles che permettono di visualizzare rapidamente l’intero dataset insieme a tutti gli altri raccolti a livello nazionale.

Spero che queste info possano essere utili.

OSM & Pubblica Amministrazione: non è proprio collaborazione stretta ma i punti di contatto aumentano


Negli ultimi tempi chi segue un po’ le vicende e le attività su OpenStreetMap, e in generale i temi degli open  data (georiferiti), ha potuto notare che c’è stato un bel fiorire di iniziative che, a partire dai dati resi disponibili dalle P.A. e con licenze compatibili alla ODbL (Open Data Commons Open Database License), hanno portato ad incrementare i dati presenti nel data base di OSM

Cito i casi di:

Oltre a queste esperienze, che rappresentano se vogliamo un effetto collaterale, non direttamente strutturato, della pubblicazione di open data georiferiti, spicca sicuramente l’iniziativa di Regione Toscana che, sulla falsariga dell’accordo stabilito qualche anno fa con GFOSS.it nell’ambito del software open source in campo GIS, per prima in Italia su scala regionale, ha recentemente messo a disposizione come Open Data la produzione regionale della sua banca dati topografica in scala 1:2.000.

In tale iniziativa viene sottolineata la ferma intenzione di aprire un dialogo ed una collaborazione stretta con OpenStreetMap, con l’obiettivo di veicolare i dati della Regione Toscana (strade, civici, edifici, copertura del suolo, idrografia, toponimi, ecc.) all’interno di OSM, facendone crescere la qualità nell’ambito del territorio toscano e fornendo quindi, anche tramite la mappa pubblica, un servizio migliore al territorio regionale.

I dati messi potenzialente a disposizione sono molti: si parla, per ciascun comune, di oltre 90 livelli informativi in formato ESRI shapefiles.

La Regione ha dimostrato ampia disponibilità permettendo di estendere la possibilità di portare in OSM anche i dati dei livelli informativi di strade e civici.

Sembra quindi che per la prima volta, sul panorama nazionale, qualcosa si stia muovendo nella forma di una collaborazione strutturata ed ufficiale: si spera, e sarebbe auspicabile, che quanto fatto da Regione Toscana costituisca ben presto una best practise seguita da altre P.A.

Non sullo stesso livello di impatto ma iniziativa comunque ufficiale è anche la seconda edizione del Piemonte Visual Contest organizzato dal Consiglio Regionale del Piemonte, dal Consorzio TOP-IX , dal CSI Piemonte e altri, che per il 2015 è incentrato con un mappathon su OSM, segnale anche questo di un occhio di riguardo e di attenzione da  parte di una pubblica amministrazione nei confronti della realtà costituita da questa comunità mondiale.

Tutti gli esempi di cui sopra sono riferiti al flusso di dati “dalla P.A verso il  mondo OSM“, mentre meno battuta è ancora la strada inversa che permetterebbe, una volta aperta, di innescare invece aspetti decisamente interessanti.

In questo senso si iniziano però a smuovere un po’ le acque: andando oltre lo stretto rapporto OSM – PA ed iniziando ad affrontare le problematiche di un ciclo virtuoso di collaborazione  tra “neo-geografia” e la modalità classica della produzione dei dati geografici da parte della P.A, occorre citare il workshop sul tema dei dati geografici armonizzati che si è tenuto ad ASITA e che è stato sintetizzato nel post di Massimo Zotti sul “Collaudo collaborativo dei dati geografici“.

Nell’ambito del workshop si è discusso sull’adottare nuovi modelli di produzione e aggiornamento dei dati geografici, basati su servizi web centralizzati invece che sulle tradizionali  produzioni distribuite su client stand-alone e sul ripensamento dei processi della Pubblica Amministrazione secondo il  paradigma della neogeografia, che prevede il coinvolgimento degli  utilizzatori del dato geografico fin dalle prima fasi della sua produzione.

Mentre il ragionamento di cui sopra si svolge più su un piano organizzativo e di processo, occorre evidenziare che anche da un punto di vista prettamente tecnico iniziano ad affacciarsi tecnologie che potrebbero essere abilitanti: già da tempo i principali produttori commerciali di software GIS  propongono soluzioni per il version control dei dati spaziali ed ora anche le comunità software del mondo gis open source stanno presentando analoghe soluzioni. L’ultima nata in questo campo che sembra essere piuttosto promettente è Versio un distribuited version control per dati spaziali che viene proposto da Boundless.

Sembra quindi che ci siano convergenze e humus fertile per far maturare, o almeno intraprendere, iniziative volte ad una collaborazione fattiva e proficua tra il mondo della  VGI (Volunteered Geographic Information) o neo-geography, e di OMS in particolare, ed il mondo dei “authoritative data” offerti e gestiti dalla P.A.

Di lavoro da fare ce nè ancora molto ma se non si inizia sicuramente non lo si riesce a portare a termine ed invece, forse, si stanno finalmente muovendo i primi passi: se son rose fioriranno come si suol dire e, almeno personalmente, spero di vederle presto spuntare fiorite da qualche parte!!!