Archivio

Posts Tagged ‘SpatiaLite’

OpenDistributoriCarburantiBot: risparmiare sul pieno di carburante con Telegram

28 febbraio 2016 15 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”

28 febbraio 2016 4 commenti

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.

SpatiaLite su Android: disponibile!


Dopo averlo anticipato a Torino nel corso del GFOSS 2012, da oggi è disponibile SpatiaLite per Android !!

Questa distribuzione binaria si basa su SpatiaLite  3.0.1 (include anche PROJ 4.7.0 e GEOS 3.2.2), ed è rilasciata con licenza LGPLv3.

A questo punto esiste quindi una possibilità concreta di avere un vero e proprio RDBMS con estensione spaziale a disposizione per gli sviluppi su mobile. E questa possibilità è completamente open source.

Considerando questa notizia nel contesto in cui lo stesso SpatiaLite è stato individuato come soluzione per l’implementazione del nuovo standard OGC GeoPackage (GPKG) (il nuovo standard dovrebbe uscire nella sua versione definitiva a fine 2012 / inizio 2013 …. ), le prospettive sono quanto mai interessanti e rappresenta quindi una grande opportunità.

Fonte: GFOSS.it

GFOSS 2012 e OSMit 2012: un breve resoconto

18 novembre 2012 2 commenti

Ecco un breve resoconto della tre giorni torinese di GFOSS 2012 e OSMit 2012 a cui ho avuto modo di partecipare.

Molti partecipanti (oltre 170 iscritti ….), interventi interessanti, un buon “fervore” sulle tecnologie GIS open source.

Nel mondo del GIS desktop direi che praticamente tutte le presentazioni hanno fatto riferimento a QGIS con la quasi totale assenza di altri attori (ricordo forse una presentazione che citava gvSIG, nessuna menzione di soluzioni alternative quali Udig o altri ancora. Anche l’utilizzo di GRASS, pur presente in diverse presentazioni, avviene spesso mediato da QGIS): viene quindi confermata la tendenza che vede QGIS una sorta di must de facto in questo campo.

Per il tier rappresentato dal livello data base questo è ampiamente coperto da POSTGIS. Rientra logicamente in questa categoria SQLite anche se gioca un ruolo leggermente diverso e per il quale di prefigura un possibile nuovo utilizzo.

A livello di soluzioni server enterprise la presenza più significativa è invece stata quella di GeoServer, anche se in una presentazione è stato citato QGIS Server come soluzione adottata.

Sul fronte mobile mi sarei aspettato una maggior numero di interventi di natura tecnica (soluzioni, framework , ecc … ), mentre ricordo solo un paio di interventi, uno di Alessandro Furieri, di inquadramento generale e più orientato agli standard OGC da usare su soluzioni mobile, e uno di Andrea Antonello (molto interessante), sull’evoluzione del mobile negli anni e della piattaforma mobile con accenno a GeoPaparazzi. Lo stesso QGIS per Android è stato dichiarato segnare un po’ il passo.

Completamente assenti invece presentazioni o accenni alle soluzioni cloud che invece si stanno affacciando anche sul mondo GIS: non le usa ancora nessuno in Italia? Possibile?

Anche se non sono riuscito a seguire tutte le presentazioni provo a riassumere e riportare alcune delle cose più interessanti, ovviamente a mio personale giudizio.

Uno dei primi interventi è stato quello relativo a QGIS di Paolo Cavallini che ha illustrato oltre alle caratteristiche già note del prodotto, quelle che saranno le prossime news e anche delle anticipazioni su caratteristiche funzionali future. A livello di news abbiamo:

  • possibilità di usare scale di colore sia per dati vettoriali sia per dati raster
  • una ristrutturazione della modalità di trattare i dati raster
  • ricampionamento dei raster
  • potenziamento della console Python
  • integrazione di Atlas per fare serie di mappa
  • miglioramento del  supporto standard OGC

Per il futuro invece:

  • ristrutturazione simbologie
  • completamento etichette
  • ristrutturazione sito e documentazione
  • miglioramento integrazione SEXTANTE
  • 3D Globe
  • accesso ad ORACLE nativo
  • WFST per QGIS Server
  • supporto multithread

E’ confermato un rallentamento sulla parte QGIS per Android.

Anche la presentazione di Andrea Aime su GeoServer ha illustrato quelle che saranno le future evoluzioni del prodotto e precisamente:

  • introduzione di linguaggi di scripting quali Python, Ruby, ecc .. per il  WPS
  • la possibilità di usare un solo geoserver per servizi diverse organizzazioni, enti, divisioni aziendali
  • supporto png 8 con canale alpha: immagini più piccole ma di qualità, come con il formato png24
  • supporto time ed elevation
  • rendering transformation: calcolo isolinee o heat maps fatte al volo durante il rendering
  • miglioramenti integrazione con GeoWebCache
  • supporto del WFS 2.0 (standard INSPIRE)  e supporto paginazione
  • supporto XSLT
  • chiamate asincrone su WPS

Si sta già lavorando sulla release 2.2.3 in cui si avranno:

  • Aggancio per autenticazione: LDAP o base dati e supporto diversi sistemi di autenticazione (CAS)
  • Configurazione di GeoServer  su database
  • GoeWebCache: possibilità di clustering
  • Catalogue server in geoserver

Nel futuro ci sono ipotesi di:

  • Supporto WCS 2.0
  • Supporto NoSQL DB

A livello di presentazioni di natura tecnologica interessante quella di Francesco Izzi del CNR su GeoPlatform, progetto nato nel 2010 e disponibile su github costituito da un client basato su GWT e uno strato di servizi Java. Al momento è alla versione 1.5.

Alessandro Furieri nel corso della sua presentazione ha annunciato che per l’implementazione del nuovo standard OGC GeoPackage (GPKG) la scelta è caduta su SpatiaLite e questa è sicuramente la notizia tecnologia di maggior interesse in prospettiva (il nuovo standard dovrebbe uscire nella sua versione definitiva a fine 2012 / inizio 2013)

A livello di presentazioni relativi a progetti sicuramente da citare è stato l’intervento di ISTAT a cura di Francesco Di Pede dal titolo “Censimento 2011: dal dato areale al dato puntuale. Numeri civici, edifici e popolazionein cui è stata messa enfasi sull’Anagrafe Nazionale delle Strade e Numeri Civici di sui tanto si sta parlando sul web in questo periodo. Sono stati presentati interessanti esempi di casi d’uso reali di questi  e altri dati georiferiti in possesso dell’ISTAT (vie, edifici, civici, ecc …). Purtroppo continua a  non essere chiarissimo quali, quanti e in quale modalità i dataset saranno resi disponibili, quindi se open data o meno.

Altra presentazione di progetto interessante è stata quella di Corrado D’Alessandro dal titolo Settimo Torinese con l’open source ottimizza la conoscenza del territorio. Il progetto è stato realizzato completamente con tecnologie open source e precisamente:

  • Postgis 2.0
  • QGIS Server 1.8
  • OpenLayers in QGIS client
  • GeoExt 3
  • PHP

La palma del miglior progetto presentato però mi sentirei di darla a quella de “Il portale delle reti tecnologiche di Regione Lombardia: un esempio di tecnologia aperta per la condivisione di informazioni e dati sulle reti tecnologiche” (rif. http://www.ors.regione.lombardia.it/cm/home.html  e http://195.254.250.104/gisclient/intro.php?topic=generic ), non tanto per la parte tecnologica, quanto per la completezza delle informazioni che sono rese disponibili dal progetto e consiglio chi interessato di provare a dargli un’occhiata.

Molto interessante anche il lavoro di ARPA Piemonte su “Acquisizione di misure nivologiche manuali georiferite tramite social media”, con un interessante utilizzo di Ushahidi, replicabile anche in altri contesti.

Nella giornata dedicata ad OSMIt le presentazioni più interessanti sono state quelle relative a:

  • Geographike che utilizza OSM per fare business con una replica della base dati di OSM per l’Italia aggiornata giornalmente (modalità documentata sul wiki di OSM). Le tecnologie usate sono POSTGIS come data base, Mapnik integrato con MapProxy per la distribuzione delle tiles: la documentazione tecnica è stato dichiarato che sarà resa pubblica.
  • Controllo dell’ortografia dei nomi delle strade realizzato da Daniele Forsi e disponibile via web www.forsi.it/osm/