Voglio dare un contributo alla comprensione dell'uso degli style di mkgmap.
La cosa più difficile e meno documentata sono le relazioni.
Partendo dal file relations dello style default di mkgmap ho costruito questo style, che è quello che uso attualmente.
# -------------------------------------------------------------------
# This is the mkgmap style file for applying rules on
# OSM relations. Usually you will set tags on the
# elements that make up the relation, and the tags will be
# processed by the rules defined in the "points" or "lines" files.
# Any line prefaced with # is a comment and will not be applied.
# Each line is a rule, of the generalised format:
# OSM_tag(s)_to_match [Garmin_type_code resolution]
# See
http://wiki.openstreetmap.org/wiki/Mkgmap/help/style_rules
# and
http://wiki.openstreetmap.org/wiki/Mkgmap/help/Custom_styles
# for more information.
# Symbol ${} address relation tag and $() relation members tag
# Boundary relations
(type=boundary | type=multipolygon) & boundary=administrative & name=*
{
# Append the name of the boundary relation to the attribute
# mkgmap:boundary_name of the member nodes recursively
apply {
set mkgmap:boundary_name='$(mkgmap:boundary_name):${name}' | '${name}';
}
# Prevent other relation processing
delete type; delete boundary; delete name;
}
# Route relations
type=route & route=* & (name=* | ref=*)
{
# If name is missing use ref as name
add name='${ref}';
# Append the type, name and ref of the route relation to the
# attributes route_* of the member nodes recursively
# (even to members of subrelations with role tag).
apply {
set route='$(route),${route}' | '${route}';
set route_name='$(route_name),${name}' | '${name}';
set route_ref='$(route_ref),${ref}' | '${ref}';
# Style syntax test:
# If subrelations with role tag exist, copy the name to them too
set mkgmap:name='${name}';
apply role=* {
set route_name='$(route_name),${mkgmap:name}' | '${mkgmap:name}';
}
delete mkgmap:name;
}
# We could want to copy the route relation name to unnamed ways
apply role=way { add name='${name}' }
# Prevent other relation processing
delete type; delete route; delete name; delete ref;
}
Ho inserito dei commenti che spiegano cosa produce il codice.
Comunque faccio una descrizione passo-passo per i meno esperti.
# Boundary relations
la riga seguente cerca le le relazioni che hanno il tag type impostato a boundary oppure multipolygon, il tag boundary = ad administrative ed anche il tag name definito (se una relazione non possiede anche uno solo di questi tag non viene selezionata e nulla viene eseguito)
(type=boundary | type=multipolygon) & boundary=administrative & name=*
questa prima parentesi, con la corrispondente di chiusura, elenca il blocco delle azioni eseguite sui dati della relazione
{
il comando apply seguente ha la funzione di esplorare la lista dei membri della relazione (linee, poligoni e punti), applicando a ciascuno di essi le azioni che il suo blocco {} contiene.
In questo caso viene estratto il nome della relazione, che viene concatenato a quello delle eventuali altre che hanno quel membro e che già sono state analizzate.
# Append the name of the boundary relation to the attribute
# mkgmap:boundary_name of the member nodes recursively
apply {
Vediamo come descrivendo il codice seguente.
set mkgmap:boundary_name='$(mkgmap:boundary_name):${name}' | '${name}';
La variabile mkgmap:boundary_name è un tag che è posseduto dal membro della relazione e non dalla relazione (i tag definiti dentro l'apply divengono proprietà dei membri della relazione). Il codice sostituibile $() opera sui tag dei membri della relazione e invece ${} su quelli della relazione (quindi su quelli assegnati fuori dall'apply).
La concatenazione viene eseguita attaccando a destra della stringa finale (contenuta in mkgmap:boundary_name) in successione i nomi delle varie relazioni elaborate (contenuto in ${name}). La parte dopo l'or (il |) gestisce l'inizio della procedura, quando mkgmap:boundary_name non è ancora definita.
Questo tag mkgmap:boundary_name lo potremo usare quando elaboreremo i comandi per i punti, le linee ed i poligoni (nei files points, lines e polygons)
}
Poi vengono cancellati i tag della relazione in modo che essa non possa essere processata ancora, ad esempio in un eventuale style collegato (io collego il mio al default di mkgmap)
# Prevent other relation processing
delete type; delete boundary; delete name;
}
A questo punto la rimanente parte del codice, che opera sulla relazione di tipo route, è più chiara:
selezioniamo solo le relazioni di tipo route (type=route) e che hanno impostati i tag route (route=*) e o il nome o il ref
# Route relations
type=route & route=* & (name=* | ref=*)
{
qui lo dice il commento
# If name is missing use ref as name
add name='${ref}';
# Append the type, name and ref of the route relation to the
# attributes route_* of the member nodes recursively
# (even to members of subrelations with role tag).
apply {
Vengono concatenati in tre tag assegnati ai membri (route, route_name e route_ref) i tipi di route, i nomi ed i ref delle relazioni successivamente elaborate.
Anche questi tag li potremo poi usare nei comandi per punti, linee e poligoni (nei files points, lines e polygons).
set route='$(route),${route}' | '${route}';
set route_name='$(route_name),${name}' | '${name}';
set route_ref='$(route_ref),${ref}' | '${ref}';
La parte seguente è una prova, essa concatena il nome della relazione principale nel tag route_name dei membri della sottorelazione a patto che la sottorelazione abbia il tag role impostato (role=*) (apply role= è un comando non documentato).
Per fare questo si crea un tag temporaneo (mkgmap:name), proprietà del membro della relazione principale.
Tag temporaneo perché viene poi cancellato.
# Style syntax test:
# If subrelations with role tag exist, copy the name to them too
set mkgmap:name='${name}';
la variabile temporanea mkgmap:name prende il valore del nome della relazione principale, ma appartiene al membro della relazione principale
L'apply seguente agisce solo sulle sottorelazioni (una relazione che è anche membro di un'altra relazione), ma solo su quelle che hanno il tag role impostato.
apply role=* {
set route_name='$(route_name),${mkgmap:name}' | '${mkgmap:name}';
Nella concatenazione precedente route_name è un tag assegnato al membro (della sottorelazione), mentre abbiamo visto che mkgmap:name appartiene al membro della relazione principale, che in questo caso è la sottorelazione in esame e ${mkgmap:name} ne estrae il contenuto, che è il nome della relazione principale.
Quindi il risultato è che alla fine il tag route_name dei membri della sottorelazione riceve la concatenazione dei nomi delle successive relazioni principali elaborate.
}
delete mkgmap:name;
}
Altra prova per gestire le sottorelazioni di tipo way.
# We could want to copy the route relation name to unnamed ways
apply role=way { add name='${name}' }
I membri senza nome della sottorelazione ne prendono il nome (add crea name solo se già non esiste, mentre usando set si sovrascrive),
infatti il tag name appartiene ai membri della sottorelazione, mentre ${name} estrae in questo caso il nome della sottorelazione
# Prevent other relation processing
delete type; delete route; delete name; delete ref;
}
Per usare i tag definiti sopra, si possono inserire comandi appositi nei files degli elementi.
Ad esempio il file lines del default contiene
# The following boundary styles are after the highway rules because ways
# are frequently tagged with both and we want the highway to take priority.
boundary=administrative { name '${mkgmap:boundary_name}' }
boundary=administrative & admin_level<3 [0x1e resolution 16]
...........................
che definisce il nome del boundary selezionato usando il valore del tag mkgmap:boundary_name, che è stato definito in relations.
Mentre nel file lines del mio style uso gli altri tag definiti in relations:
# Route
Se una highway è anche una route, lo evidenzio attivando una apposita grafica (codice 0x10700).
Il continue consente l'elaborazione successiva dell'elemento da parte di altra rules (come noto la presenza del campo [] termina l'elaborazione dell'elemento corrente).
highway=* & route=* [0x10700 continue resolution 24]
Le successive rules modificano il contenuto del tag name dell'elemento highway aggiungendo a destra i contenuti dei tag route_name e route_ref, anch'essi definiti in relations.
# Set highway name to include the route_name if there is one
highway=* & route_name=* { set name='${name} ${route_name}' | '${route_name}' }
# Set highway name to include the route_ref if there is one
highway=* & route_ref=* { set name='${name} ${route_ref}' | '${route_ref}' }