User Tools

Site Tools


Sidebar

No ai soldati italiani all'estero

Indice

Eventi

Energia

Rigacci.Org usa energia elettrica da fonti rinnovabili, grazie al gruppo di acquisto Merci Dolci.

Merci Dolci - Energia Rinnovabile

Software libero!

Petizione contro i brevetti software

Faunalia: Soluzioni GIS professionali

Debian

www.gnu.org www.kernel.org

Altre libertà

MoVimento 5 Stelle Campi Bisenzio

tecnica:gps_cartografia_gis:osm_recipes

Ricette Mappe OpenStreetMap

In questa pagina alcune ricette utili per cucinare mappe OpenStreetMap da caricare su navigatore GPS. In particolare l'obiettivo è creare delle versioni ridotte compatibili con il Garmin eTrex 10, che ha capacità di memoria davvero ridotte (circa 7 Mb).

Tutti gli script qui descritti sono contenuti nell'archivio garmin-etrex10-map.tgz.

Spazio limitato: è necessario un compromesso

Per motivi di capienza sarà quindi necessario restringere l'estensione della mappa ad una sola regione (in questo esempio la Toscana), inoltre si dovrà optare per una mappa di tipo on-road (ad esempio per uso cicloturistico) oppure una off-road (per uso trekking o MTB). Nel primo caso si includerà solo la rete stradale ordinaria (da motorway a unclassified nella classificazione OSM), nel secondo caso quella off-road (footway, track e path nella classificazione OSM).

Cosa includere

  • Grafo stradale. Poiché l'eTrex-10 non è in grado di effettuare il routing, si è preservato solo il grafo stradale senza includere le informazioni relative ad esempio alla percorribilità, ai sensi unici, alle relazioni circa le restrizioni di svolta, ecc.
  • Waypoint. Si è inclusa una selezione di waypoint. Dalla categoria amenity di OSM: distributori di benzina, punti di ristoro (ristoranti, caffè), farmacie, ospedali. Dalla categoria tourism: strutture di ospitalità come alberghi, campeggi e rifugi montani. Alcune feature sono rappresentate nella mappa OSM come way invece che come node, cioè è stato mappato il contorno invece del singolo punto. La procedura individuata trasforma tale contorno in un singolo punto.
  • Centri abitati. Avere i centri abitati come waypoint è utile per effettuare ricerche e spostarsi velocemente sulla mappa del GPS.
  • Confini amministrativi. Si sono inclusi i confini delle regioni italiane soprattutto per fini “estetici”, poiché sono utili ad interpretare la mappa a livelli di zoom inferiori. I confini NON vengono utilizzati per l'indicizzazione degli indirizzi da utilizzare durante la ricerca degli stessi. L'aggiunta dei confini regionali ha ingrossato la mappa finale di circa 170 kb.

Confini regioni italiane da Istat

L'Istituto nazionale di statistica fornisce gratuitamente il file dei confini comunali e regionali, in formato Shapefile. Per effettuare le opportune manipolazioni abbiamo caricato il file in un database geografico PostgreSQL/PostGIS. Inoltre abbiamo utilizzato i tool GDAL/OGR e gpsbabel.

I pacchetti Debian da installare sono:

apt-get install postgis gdal-bin gpsbabel

Dalla pagina Archivio dei confini delle unità amministrative si è scaricato l'archivio più dettagliato nel formato UTM32N.

Queste sono le trasformazioni applicate al dataset originale:

  1. Rimozione dei “buchi”.
  2. Semplificazione, con errore massimo di 150 metri, per ridurre il numero dei vertici.
  3. Eliminazione dei poligoni più piccoli di una certa area.
  4. Riproiezione dal sistema UTM zone 32N (EPSG:32632) al WGS84 (EPSG:4326).
  5. Conversione del file GPX in file OSM.

Per la creazione di un database geografico consultare la pagina PostGIS su Debian. La conversione dello Shapefile in SLQ è ottenuta con:

shp2pgsql -s 32632 Reg_2016_WGS84.shp reg2016 > Reg_2016_WGS84.sql

Il primo passaggio è la rimozione dei “buchi” nei multipoligoni. La funzione da usare è ST_ExteriorRing(), che però deve essere applicata dopo aver scomposto i MULTIPOLYGON componenti con la funzione ST_Dump(). La geometria risultante è una LINESTRING che deve essere ricomposta in poligoni con ST_MakePolygon(). Il risultato viene salvato in una tabella temporanea reg2016_no_holes:

SELECT regione, ST_MakePolygon(ST_ExteriorRing((ST_Dump(geom)).geom)) AS geom
    INTO TABLE reg2016_no_holes FROM reg2016;

I passaggi successivi sono realizzati da una sola istruzione SQL, che viene eseguita dal tool ogr2ogr, in modo da salvare il risultato direttamente in un file GPX:

#!/bin/sh
SQL="SELECT regione AS name, ST_Transform(ST_Simplify(geom, 150), 4326) AS geom
     FROM reg2016_no_holes WHERE ST_Area(geom) > 11000000"
export GPX_USE_EXTENSIONS
ogr2ogr \
    -f "GPX" regioni.gpx \
    PG:"host=localhost user=username dbname=dbname password=MySecret" \
    -sql "$SQL" \
    -lco "FORCE_GPX_TRACK=YES" -nlt "MULTILINESTRING" -mapFieldType "Integer64=String"

Nell'istruzione SQL si utilizza ST_Simplfy() indicando un errore massimo di 150 metri (la proiezione dei dati Istat è in metri), la ST_Transform() per riproiettare le geometrie nel sistema WGS84, infine si impone una clausola con ST_Area() per togliere i poligoni (isole) che hanno una superficie inferiore agli 11 km quadrati.

Il passaggio finale viene fatto con il tool gpsbabel, consiste nel convertire il file GPX estratto dal database in un file OSM, utilizzabile in seguito da mkgmap. Durante la conversione vengono aggiunti ad ogni way i tag che indicano un confine regionale. Il file prodotto da gpsbabel ha purtroppo ha gli ID negativi ordinati in modo decrescente, questo impedisce a osmconvert (che verrà usato successivamente) di funzionare correttamente. Si usa un comando brutale sed per togliere il segno meno a tutti gli id e ref:

#!/bin/sh
gpsbabel -i gpx -f regioni.gpx \
    -o osm,created_by=,tag="boundary:administrative;admin_level:4" \
    -F regioni_bad_id.osm
cat regioni_bad_id.osm  | sed "s/id='-/id='/" | sed "s/ref='-/ref='/" > regioni.osm
rm regioni_bad_id.osm

FIXME Questa ricetta ha un problema teorico: gli ID trasformati in numeri positivi potrebbero andare in conflitto con gli ID degli oggetti scaricati dal database OpenStreetMap e quindi creare problemi al programma osmconvert. Esiste anche la funzione renumber del programma osmium (dal pacchetto osmium-tool), ma occorre la versione 1.8.0 da Debian stretch-backports e comunque non risolve il problema del potenziale conflitto.

Confine per l'estrazione dei dati

|Disegno del confine con JOSM Utilizzeremo il linguaggio Overpass API per estrarre i dati da OpenStreetMap. Per ogni richiesta forniremo il confine per l'estrazione sotto forma di vertici di un poligono grossolano (una trentina di vertici) che racchiude la regione desiderata.

Per disegnare i confini abbiamo utilizzato JOSM con questa procedura.

  1. Scaricato una porzione della mappa che includa un piccolo tratto del confine regionale.
  2. Dopo aver selezionato tale tratto di confine, dal tab Tags / Memberships si evidenzia la relazione boundary[4] Toscana, click destro, Download members. Vengono scaricate tutte le way che formano il confine reginale.
  3. Menu File, New Layer.
  4. Nel nuovo layer si disegna il poligono approssimato che racchiuda la regione.
  5. Click destro sul layer disegnato, Export to GPX.

Dal file GPX creato è possibile estrarre le coordinate con un semplice script di shell (lo abbiamo chiamato bounds-gpx2txt):

#!/bin/sh
cat "bounds-toscana.gpx" \
    | grep '<trkpt' \
    | sed 's/.*lat="\([0-9\.]\+\)" lon="\([0-9\.]\+\)".*/\1 \2/' \
    | tr '\n' ' ' \
    | awk '{$1=$1};1'

Il risultato desiderato è semplicemente la sequenza delle coordinate lat lon di tutti i vertici separate da spazi:

44.381756 9.629437 44.488539 9.699057 44.569342 9.951234 ...

Grafo stradale da OSM

Per questa ricetta è necessario osmfilter, contenuto nel pacchetto Debian osmctools.

In un file che chiameremo query_way.xml si prepara la query Overpass per estrarre le way dalla zona desiderata:

<osm-script>
  <query type="way">
    <has-kv k="highway" regv="^motorway$|^trunk$|^primary$|^secondary$|^tertiary$|^unclassified$"/>
    <polygon-query bounds="44.381756 9.629437 44.488539 9.699057 44.569342 ..."/>
  </query>
  <union>
    <item />
    <recurse type="way-node"/>
  </union>
  <print mode="body"/>
</osm-script>

NOTA: all'espressione regolare regv è opportuno aggiungere anche tutte le highway di tipo *_link, ad esempio motorway_link, ecc. Vedere la classificazione delle highway.

Nell'opportuno linguaggio è scritto che devono essere estratte non solo le way con i relativi attributi, ma anche i node che costituiscono effettivamente la forma della strada, questo è il senso della ricorsione di tipo way-node. Il polygon-query è quello definito nel paragrafo precedente.

Per prelevare i grafo stradale è quindi sufficiente l'uso di wget:

wget --post-file="query_way.xml" -O "op_way.osm" "http://overpass-api.de/api/interpreter"

Infine usiamo osmfilter per ripulire il file, togliendo eventuali tag associati ai singoli nodi e mantenendo solo alcuni tag delle strade (i tag highway, name e ref):

osmfilter "op_way.osm" \
    --drop-node-tags="*=" --keep-way-tags="all highway= name= ref=" \
    --drop-author --fake-version --out-osm -o="f_way.osm"

Per ottenere il grafo delle strade off-road si utilizza una ricetta del tutto analoga, salvo che le highway da estrarre sono solo quelle di tipo footway, track e path, mentre i tag tag preservare sono highway, name, ref e tracktype.

Waypoint da OSM

L'estrazione di waypoint dalla mappa OSM presenta una difficoltà. Prendiamo ad esempio le farmacie: in alcuni casi saranno indicate sulla mappa OSM come node con il tag:amenity=pharmacy, in altri casi saranno invece disegnate come way (ad esempio per rappresentare l'edificio) e il tag amenity sarà applicato alla way invece che a un node. Per questo motivo abbiamo fatto l'estrazione degli waypoint con due query Overpass diverse.

Questa è la query amenity_node.xml per l'estrazione dei semplici nodi:

<osm-script>
  <query type="node">
    <has-kv k="amenity" regv="^restaurant$|^cafe$|^drinking_water$|^pharmacy$|^hospital$"/>
    <polygon-query bounds="44.3817 9.6294 44.4885 ..."/>
  </query>
  <print mode="body"/>
</osm-script>

Per estrarre le way si usa una query amenity_way.xml leggermente diversa:

<osm-script>
  <query type="way">
    <has-kv k="amenity" regv="^restaurant$|^cafe$|^pharmacy$|^hospital$"/>
    <polygon-query bounds="44.3817 9.6294 44.4885 ..."/>
  </query>
  <print mode="body" geometry="center"/>
</osm-script>

La differenza sta nell'aver aggiunto il modificatore geometry="center" nel print, in tal modo viene aggiunto all'elemento <way> un child <center>, mentre i nodi che compongono la way non saranno estratti. Bisognerà manipolare opportunamente il file per avere <node> al posto di <way>.

Notare che secondo le indicazioni del wiki il tag:amenity=drinking_water si applica solo ai nodi e non alle way, perciò non è stato ripetuto.

Con wget si scarica i due estratti da OpenStreetMap:

wget --post-file=amenity_node.xml -O "op_amenity_n.osm" "http://overpass-api.de/api/interpreter"
wget --post-file=amenity_way.xml  -O "op_amenity_w.osm" "http://overpass-api.de/api/interpreter"

Con lo script name_fix si assegna un tag name a tutti i nodi che non ce l'hanno, in modo che siano etichettati opportunamente nella lista che compare sul GPS. Ad esempio per una farmacia si usa name=pharmacy (forse si potrebbe fare anche con uno stile di mkgmap). Con questo passaggio dal file op_amenity_n.osm si ottiene il file op_amenity_n_fix.osm.

Per diminuire le dimensioni del file destinazione si rimuovono tutti i tag ad eccezione di amenity e name:

osmfilter "op_amenity_n_fix.osm" --keep-node-tags="all amenity= name=" \
    --drop-author --fake-version --out-osm -o="f_amenity_n.osm"

Per trasformare ogni way del file op_amenity_w.osm in un node si usa lo script way2node. Il risultato è il file f_amenity_w.osm.

Come si sono estratti gli opportuni oggetti amenity, si estraggono anche gli oggetti tourism. In particolare si sono estratti: hotel, motel, guest_house, chalet, hostel, alpine_hut, wilderness_hut, caravan_site e camp_site.

Centri abitati da OSM

L'estrazione dei centri abitati è del tutto simile a quella degli altri waypoint. La query Overpass deve selezionare i node con tag place e valore city, town oppure village. Anche in questo caso si aggiunge il tag nome nel caso che sia assente ed infine si rimuovono tutti i tag ad eccezione di name, place e population:

osmfilter "tmp/op_place_n_fix.osm" \
    --keep-node-tags="all name= place= population=" \
    --drop-author --fake-version --out-osm -o="tmp/f_place_n.osm"

Assemblare tutti i pezzi

Per combinare tutte le parti prodotte in precedenza si utilizza osmconvert contenuto nel pacchetto Debian osmctools:

osmconvert \
    "admin_boundaries.osm" \
    "tmp/f_track.osm" \
    "tmp/f_place_n.osm" \
    "tmp/f_amenity_n.osm" "tmp/f_amenity_w.osm" \
    "tmp/f_tourism_n.osm" "tmp/f_tourism_w.osm" \
    -o="etrex_map.osm"

Il risultato è un file sempre nel formato XML di OpenStreetMap.

mkgmap-splitter e mkgmap

--region-name Viene mostrato accanto al nome del centro abitato nella visualizzazione dell'elenco (altrimenti compare la stringa ABC). FIXME Forse esiste la possibilità di usare i confini amministrativi e l'indicizzazione degli indirizzi per associare il centro abitato al nome del comune che lo contiene?

Stile della mappa

Fondamentale lettura è il Conversion Style manual di mkgmap (qui una copia locale). Si deve anzitutto familiarizzare con alcuni concetti:

In genere una mappa Garmin contiene diversi livelli di rappresentazione: dal più dettagliato al più generico. Sullo schermo verrà visualizzato il livello opportuno in base alla scala (zoom), o più propriamente alla risoluzione. Quindi la scelta di quali elementi visualizzare a quali livelli di zoom viene effettuata al momento della creazione della mappa, utilizzando l'opportuno stile. In pratica un file mappa Garmin contiene al suo interno mappe diverse della stessa regione e l'apparecchio GPS sceglie automaticamente quale mostrare in base allo zoom. Ciò differisce sostanzialmente dall'applicare al volo uno stile di rendering basato sullo zoom.

Style Definisce gli elementi della mappa OpenStreetMap che costituiranno la mappa Garmin e quali simboli Garmin verranno usati; non definisce la simbologia grafica della mappa. Esistono alcuni stili predefiniti: per ottenere il risultato desiderato sarà sufficiente in generale fare alcune modifiche allo stile default per definire quali oggetti saranno visualizzati e a quale scala
TYP files Definiscono la simbologia grafica della mappa: colori, spessori delle linee, ecc.
Resolution È un numero compreso fra 1 e 24. La mappa più dettagliata è alla risoluzione di 24. Al diminuire di uno step la risoluzione si dimezza; cioè se un oggetto occupa 10 unità alla risoluzione 24, occuperà 5 unità alla risoluzione di 23. Un determinato GPS utilizza una determinata risoluzione per ogni scala di visualizzazione. Ad esempio un Garmin Legend Cx usa la risoluzione 22 quando la scala di visualizzazione è su 500m-200m.
Level È un numero compreso fra 0 e 16 (in pratica non si usa mai oltre il 10). Il livello 0 è quello maggiormente dettagliato e viene usato a risoluzioni maggiori. Uno stile in genere definisce quanti livelli sono presenti nella mappa e a quali risoluzioni vanno utilizzati. Ad esempio lo stile default definisce 4 livelli (da 0 a 3) da usare alle risoluzioni 24, 22, 20 e 18.
Livelli diversi sono a tutti gli effetti mappe diverse: uno stesso oggetto fisico può essere rappresentato in modo del tutto diverso da un livello ad un altro, ad esempio una città può essere rappresentata da un poligono a livello 1 e con un singolo punto a livello 2.
Risoluzione mappa su eTrex 10
Resolution Scala
18 8 km
19 5 km
20 2 km
21 1.2 km
22 500 m
23 300 m
24 120 - 80 m

Lo stile "default"

Lo stile default è inglobato nell'eseguibile di mkgmap, quindi è necessario ispezionare i sorgenti. In particolare osserviamo i file options e lines.

In options si vede che la mappa contiene 4 livelli di dettaglio:

levels = 0:24, 1:22, 2:20, 3:18

In lines viene definito a quali risoluzioni compaiono le strade di tipo highway=footway, highway=path, highway=track e i confini amministrativi:

highway=footway|highway=path|highway=steps [0x16 road_class=0 road_speed=0 resolution 23]
highway=track [0x0a road_class=0 road_speed=1 resolution 22]
boundary=administrative & admin_level<3 [0x1e resolution 12]
boundary=administrative & admin_level<5 [0x1d resolution 19]
boundary=administrative & admin_level<7 [0x1c resolution 21]
boundary=administrative & admin_level<9 [0x1c resolution 22]
boundary=administrative [0x1c resolution 22]

Secondo le indicazioni OpenStreetMap l'admin_level per i confini amministrativi dell'Italia assume i valori: 2=Nazione, 4=Regione, 6=Provincia e 8=Comune. Questo significa che il confine regionale appare alla risoluzione 19 o superiore. Nello stile default il primo livello che visualizza tali confini (partendo da quello meno dettagliato, cioè con indice maggiore) è quindi il livello 2 che ha risoluzione 20. L'effetto pratico è che i confini regionali si vedono sul GPS con la mappa alla scala dei 2 km o inferiore (più ingrandita).

Personalizzazione dello stile "default"

Rispetto allo stile default si sono rese necessarie alcune modifiche per realizzare una mappa destinata all'escursionismo off-road:

  • I confini regionali devono essere sempre visibili (anche alla scala 800 km). Prepareremo quindi un livello #3 (il meno dettagliato) alla risoluzione 18.
  • Alcuni centri abitati compaiono alla scala 5 km. Il livello #2 verrà usato quindi alla risoluzione 19.
  • Le track e path devono essere visibili dalla scala 2 km. Per questo prepareremo un livello #1 (dettaglio intermedio) alla risoluzione 20.
  • Gli waypoint appaiono dalla scala 120-80 m. Si tratta del livello #0 (il più dettagliato) alla risoluzione 24.

Schematicamente:

Oggetto Visibile da Risoluzione Livello
Confini regionali 800 km 18 3
Centri abitati minori 5 km 19 2
Track e path 2 km 20 1
Waypoint 120-80 m 24 0

Dai sorgenti di mkgmap si è estratta tutta la directory mkgmap-r3741/resources/styles/default/, quindi si sono modificati due file:

  • styles/default/options
  • styles/default/lines

Nel primo si definiscono i livelli di dettaglio e la relativa risoluzione:

levels = 0:24, 1:20, 2:19, 3:18

Nel secondo si definisce a quale risoluzione far comparire i vari oggetti:

highway=footway|highway=path|highway=steps [0x16 road_class=0 road_speed=0 resolution 20]
highway=track [0x0a road_class=0 road_speed=1 resolution 20]
...
boundary=administrative & admin_level<3 [0x1e resolution 12] # admin_level:2 Nazione
boundary=administrative & admin_level<5 [0x1d resolution 18] # admin_level:4 Regione
boundary=administrative & admin_level<7 [0x1c resolution 21] # admin_level:6 Provincia
boundary=administrative & admin_level<9 [0x1c resolution 22] # admin_level:8 Comune

Personalizzazione del simbolismo (file TYP)

Ogni GPS Garmin ha un simbolismo predefinito che definisce l'aspetto grafico per ogni oggetto mappa. Ad esempio una highway=track della mappa OSM viene convertita in un oggetto Garmin line Type=0x00a, che viene mostrata sul display dell'eTrex 10 con un certo spessore e colore.

Nella mappa compilata con mkgmap è possibile definire delle personalizzazioni rispetto al simbolismo predefinito. Abbiamo sfruttato questa possibilità per modificare l'aspetto delle linee Type=0x00a e Type=0x016 (track e path rispettivamente) in modo che fossero più sottili e non confondessero il display alla scala dei 2 km.

Per ottenere il risultato è sufficiente creare un file my_etrex10.txt con questo contenuto:

[_id]
ProductCode=0x1
FID=9999
[end]

[_line]
Type=0x00a
;GRMN_TYPE: Roads/UNPAVED_ROAD/Gravel or dirt road/Non NT, NT
UseOrientation=Y
Xpm="32 1 2  1"
"! c #000000"
"  c none"
"!!!!!!  !!!!!!  !!!!!!  !!!!!!  "
;12345678901234567890123456789012
String1=0x04,Track
ExtendedLabels=N
[end]

[_line]
Type=0x016
;GRMN_TYPE: Roads/TRAIL/Walkway or trail/Non NT, NT
UseOrientation=Y
Xpm="32 1 2  1"
"! c #808080"
"  c none"
"!!!!  !!!!  !!!!  !!!!  !!!!  !!"
;12345678901234567890123456789012
String1=0x04,Path
ExtendedLabels=N
[end]

La riga Xpm definisce il bitmap in termini di larghezza, altezza, colori e caratteri per pixel. Le righe successive definiscono il colore rappresentato da ciascun carattere (il punto esclamativo è nero o grigio, lo spazio è trasparente), infine il bitmap vero e proprio che nel nostro caso è una matrice di 32×1 caratteri.

NOTA BENE: Con mkgmap versione svn3741 non è più necessario compilare il file TYP, è possibile utilizzare direttamente il testo sorgente.

Per ulteriori dettagli vedere:

Compilazione della mappa con stile e simbolismo personalizzato

Durante l'invocazione di mkgmap è sufficiente passare il riferimento alla directory con lo stile modificato e al file con le modifiche al simbolismo per ottenere la mappa desiderata (il file TYP viene compilato al volo):

mkgmap \
    --reduce-point-density=4 --unicode \
    --description="Trekking map for eTrex-10" \
    --style-file='./styles/default/' \
    --country-name='Italy' --country-abbr='I' \
    --region-name='Toscana' \
    --family-id=9999 \
    --gmapsupp 63240*.osm.pbf \
    ./typ/my_etrex10.txt
tecnica/gps_cartografia_gis/osm_recipes.txt · Last modified: 2018/05/05 23:20 by niccolo