User:Melnibon/FR:CartesPerso

From OpenStreetMap Wiki
Jump to navigation Jump to search

Extraction de cartes OSM

Cette activité est inspirée par les articles de Petrovsk http://wiki.openstreetmap.org/wiki/User:Petrovsk. Je stocke une copie locale de la base europe.osm, j'en choisis quelques extraits pour faire des cartes multicouches destinées à mon Garmin.

J'ai besoin de cartes pour une petite partie de la France, par exemple la Bretagne, le Languedoc, le Poitou, le Bugey et l'Auvergne. Il me faut des outils pour créer ces cartes compatibles Garmin et les maintenir à jour.

J'utilise les logiciels osmosis, srtm et la suite mkgmap sur une machine linux, mais c'est portable sur windows avec cygwin.

Gestion d'une copie locale de europe.osm

Le but était initialement de maintenir à jour une copie des données OSM. En fait, cette copie locale n'est absolument pas nécessaire une fois que les extraits sont faits. Elle n'est indispensable que pour ajouter une nouvelle zone. Sinon, ce sont les zones qui sont mises à jour et non pas toute l'europe. Donc finalement, cette partie ne sert pas à grand chose.

Pour faire ça, il faut installer osmosis et curl. Comme Petrovsk, j'ai créé un dossier DataSets pour stocker la base europe.

Voici le script qui me permet de récupérer europe.osm : GetEurope.sh

#!/bin/bash

# (c) Pierre Nerzic 02/2010, pierre.nerzic@free.fr

# obtenir la date du fichier au format YYYY-MM-DD_hh:mm:ss
curl -L -s -I "http://download.geofabrik.de/osm/europe.osm.bz2" | awk 'BEGIN{Mois["Jan"]="01";Mois["Feb"]="02";Mois["Mar"]="03";Mois["Apr"]="04";Mois["May"]="05";Mois["Jun"]="06";Mois["Jul"]="07";Mois["Aug"]="08";Mois["Sep"]="09";Mois["Oct"]="10";Mois["Nov"]="11";Mois["Dec"]="12";}/^Last-Modified:/ {date=$5"-"Mois[$4]"-"$3"_"$6 ; print date}' > europe.osm.txt

# noter la taille du fichier à récupérer
taille=`curl -L -s -I "http://download.geofabrik.de/osm/europe.osm.bz2" | tr -d '\015' | awk '/Content-Length:/{print $2}'`

# obtenir le contenu du fichier
if ! curl -L -O "http://download.geofabrik.de/osm/europe.osm.bz2"
then
    echo 'ERREUR: echec du téléchargement'
    mv europe.osm.bz2 INCOMPLET_europe.osm.bz2
    exit 1
fi

# vérifier la taille du fichier
recu=`stat -c '%s' europe.osm.bz2`
if test $recu -ne $taille
then
    echo "ERREUR: europe.osm.bz2 incomplet: reçu $recu or il faut $taille octets"
    mv europe.osm.bz2 INCOMPLET_europe.osm.bz2
    exit 1
fi

# configurer les mises à jour automatiques
rm -f configuration.txt  download.lock timestamp.txt
osmosis --read-change-interval-init initialDate=`cat europe.osm.txt`

cat >configuration.txt <<data
# The URL of the directory containing change files.
baseUrl=https://planet.openstreetmap.org/daily

# The length of an extraction interval in seconds (3600 = 1 hour).
intervalLength=86400

# Define the changeset filename format.  The format is {changeFileBeginFormat}-{changeFileEndFormat}.osc.gz
# Be careful to pick a format that won't result in duplicate names for the specified interval size.
# Change file begin format
changeFileBeginFormat=yyyyMMdd
changeFileEndFormat=yyyyMMdd

# Defines the maximum number of files to download in a single invocation.
# There will be approximately two threads created for every downloaded file.
# Setting this to 0 disables this feature.
maxDownloadCount = 20

data

echo "Tout va bien, europe.osm.bz2 fait $taille octets comme prévu"

Le gros souci est de pouvoir commencer et finir le téléchargement dans la même journée afin de mettre en place le système rci de osmosis.

Ensuite voici le script qui permet de mettre à jour europe.osm.bz2 : MajEurope.sh

#!/bin/bash

# (c) Pierre Nerzic 02/2010, pierre.nerzic@free.fr

# log
echo -n "MajCartes.sh : started $carte " ; date

# effectuer la mise à jour automatique de la carte europe
cp timestamp.txt timestamp.txt.bak
if osmosis --rci --rx europe.osm.bz2 --ac --wx tmp.osm.bz2
then
    mv tmp.osm.bz2 europe.osm.bz2
    rm -f timestamp.txt.bak
else
    rm -f tmp.osm.bz2
    mv -f timestamp.txt.bak timestamp.txt
fi

# log
echo -n "MajCartes.sh : finished $carte " ; date

Je suis déçu par la mise à jour, en fait le temps pour mettre à jour est énorme, comparé au temps de téléchargement. Donc finalement, au lieu de mettre à jour europe.osm, je le retélécharge.

Définition d'extraits

Les extraits, Bretagne, Poitou, etc.. sont définis de la manière suivante. J'ai créé un dossier Cartes contenant deux sous-dossiers styles et typ décrits plus loin. Chaque zone est un sous-dossier contenant au départ un seul fichier appelé Limites. Voici un exemple avec ce que j'ai mis dans Bretagne/Limites

#!/bin/bash
left=-6
right=-1
top=49
bottom=46.8

Ce sont en fait les options de bounding box pour osmosis écrites sour la forme d'affectations bash. Attention à ne pas mettre un espace dans ces lignes.

Il y a un fichier comme ça pour chaque zone : Poitou/Limites, Languedoc/Limites...

L'étape suivante consiste à obtenir les données de ces cartes en faisant une extraction sur la base europe.osm. Voici le script bash qui fait ça. En plus d'extraire les données cartographiques osm, il construit les données de relief srtm : InitCartes.sh

#!/bin/bash

for carte in *
do
    # ne regarder que les dossiers, le nom du dossier = la carte à créer
    if test ! -d $carte -o ! -f $carte/Limites
    then
        continue
    fi

    cd $carte

    # lire les bornes de la carte
    . Limites

    # créer la carte
    osmosis --rx ../../DataSets/europe.osm.bz2 --bb left=$left right=$right top=$top bottom=$bottom --wx $carte.osm

    # configurer le système de mise à jour : recopier les fichiers de DataSets
    for fich in configuration.txt download.lock timestamp.txt
    do
        cp ../../DataSets/$fich .
    done

    # mettre à jour les lignes de niveau
    mono ../../bin/Srtm2Osm.exe -q -bounds1 $bottom $left $top $right -step 10 -cat 200 50 -large -corrxy 0.0005 0.0006 -o ${carte}-relief.osm
    rm -fr srtm

    cd ..
done

On obtient plusieurs fichiers dans chaque dossier en plus de Limites : les fichiers de osmosis pour gérer les mises à jour (configuration.txt, download.lock, timestamp.txt) et surtout les deux carte.osm et carte-relief.osm qui servent ensuite à créer les cartes pour le Garmin.

Il faut faire tourner ce script à chaque fois qu'on attend plus de 15 jours pour faire une mise à jour des données, voir le paragraphe suivant.

Script de création des cartes

Voici maintenant le script principal, le plus important. C'est lui qui met à jour les données des zones sélectionnées et qui crée les cartes complètes 3 couches pour le Garmin, voir http://wiki.openstreetmap.org/wiki/User:Petrovsk/FR:layered_Garmin_map : MajCartes.sh

#!/bin/bash

# (c) Pierre Nerzic 02/2010, pierre.nerzic@free.fr

# fonction pour initialiser le script de création des cartes
# $1 : nom de la carte, ex : Bretagne
InitMkGmapArgs()
{
    cat >mkgmap.args <<data
description="Open Street Maps"
country-name="France"
country-abbr="FR"
region-name="$1"

data
}

# fonction pour rajouter une zone de relief dans les paramètres de mkgmap
# $1 : nom de la carte, ex : Bretagne
RajouterZonesRelief()
{
    InitMkGmapArgs $1
    grep '^input-file:' template.args | while read inputfile zone
    do
        # éditer le script des cartes à trois couches
        cat >>mkgmap.args <<data
family-id=44
family-name="Altitude 10,50,200m"
draw-priority=50
transparent
remove-short-arcs
max-jobs=1
latin1
style-file=../styles/relief
input-file=$zone

data
    done
}

# fonction pour rajouter une zone de carte dans les paramètres de mkgmap
# $1 : nom de la carte, ex : Bretagne
RajouterZonesCarte()
{
    InitMkGmapArgs $1
    grep '^input-file:' template.args | while read inputfile zone
    do
        # éditer le script des cartes à trois couches
        cat >>mkgmap.args <<data
family-id=42
family-name="Carte de randonnée"
draw-priority=25
add-pois-to-areas
remove-short-arcs
max-jobs=1
latin1
generate-sea=extend-sea-sectors
style-file=../styles/p-map
input-file=$zone

data
    done
}

# fonction pour rajouter une zone de carte dans les paramètres de mkgmap
# $1 : nom de la carte, ex : Bretagne
RajouterZonesRoutage()
{
    InitMkGmapArgs $1
    grep '^input-file:' template.args | while read inputfile zone
    do
        cat >>mkgmap.args <<data
family-id=43
family-name="Carte de routage"
draw-priority=5
route
add-pois-to-areas
remove-short-arcs
max-jobs=1
latin1
style-file=../styles/routage
input-file=$zone

data
    done
}


n=63210
cartes=""
for carte in *
do
    # ne regarder que les dossiers qui contiennent Limites, le nom du dossier = le nom de la carte
    if test ! -d $carte -o ! -f $carte/Limites
    then
        continue
    fi

    cd $carte

    #### mettre à jour les données OSM

    # lire les bornes de la carte
    . Limites

    # mettre à jour le fichier $carte.osm
    echo ''
    echo -n "*** ${carte}: update         " ; date '+%T'
    if osmosis -q --rci --sc --simc --rx $carte.osm --s --ac --bb left=$left right=$right top=$top bottom=$bottom --wx tmp.osm
    then
        mv -f tmp.osm $carte.osm
    else
        rm -f tmp.osm
        exit 1
    fi

    #### créer la carte Garmin

    # séparer la carte de relief en morceaux et les rajouter dans les paramètres
    echo ''
    echo -n "*** ${carte}: split relief   " ; date '+%T'
    mapid=`printf '%05d' $n` ; n=$((n+1))
    mkdir -p tmp
    if ! java -Xmx1G -jar ../../bin/splitter.jar --cache=tmp --mapid=${mapid}001 ${carte}-relief.osm
    then
        echo "ERREUR: échec de la séparation de ${carte}-relief"
        exit 1
    fi
    RajouterZonesRelief $carte
    rm -fr tmp

    # générer l'image garmin du relief
    echo ''
    echo -n "*** ${carte}: mkgmap relief  " ; date '+%T'
    if java -Xmx1G -jar ../../bin/mkgmap.jar --gmapsupp -c mkgmap.args ../typ/44-contours.TYP
    then
        mv gmapsupp.img gmapsupp44.img
    else
        echo 'ERREUR: échec de mkgmap mkgmap44.args'
        exit 1
    fi


    # séparer la carte en morceaux et les rajouter dans les paramètres
    echo ''
    echo -n "*** ${carte}: split map      " ; date '+%T'
    mapid=`printf '%05d' $n` ; n=$((n+1))
    mkdir -p tmp
    if ! java -Xmx1G -jar ../../bin/splitter.jar --cache=tmp --mapid=${mapid}101 ${carte}.osm
    then
        echo "ERREUR: échec de la séparation de ${carte}"
        exit 1
    fi
    RajouterZonesCarte $carte
    rm -fr tmp

    # générer l'image garmin normale
    echo ''
    echo -n "*** ${carte}: mkgmap normale " ; date '+%T'
    if java -Xmx1G -jar ../../bin/mkgmap.jar --gmapsupp -c mkgmap.args ../typ/p-map.TYP
    then
        mv gmapsupp.img gmapsupp42.img
    else
        echo 'ERREUR: échec de mkgmap mkgmap42.args'
        exit 1
    fi

    # séparer la carte en morceaux et les rajouter dans les paramètres
    echo ''
    echo -n "*** ${carte}: split map      " ; date '+%T'
    mapid=`printf '%05d' $n` ; n=$((n+1))
    mkdir -p tmp
    if ! java -Xmx1G -jar ../../bin/splitter.jar --cache=tmp --mapid=${mapid}201 ${carte}.osm
    then
        echo "ERREUR: échec de la séparation de ${carte}"
        exit 1
    fi
    RajouterZonesRoutage $carte
    rm -fr tmp

    # générer l'image garmin de routage
    echo ''
    echo -n "*** ${carte}: mkgmap routage " ; date '+%T'
    if java -Xmx1G -jar ../../bin/mkgmap.jar --gmapsupp -c mkgmap.args
    then
        mv gmapsupp.img gmapsupp43.img
    else
        echo 'ERREUR: échec de mkgmap mkgmap43.args'
        exit 1
    fi

    # fusionner les trois couches
    echo ''
    echo -n "*** ${carte}: mkgmap fusion  " ; date '+%T'
    if java -Xmx1G -jar ../../bin/mkgmap.jar --gmapsupp gmapsupp44.img gmapsupp42.img gmapsupp43.img
    then
        cartes="${cartes} ${carte}/gmapsupp.img"
    else
        exit 1
    fi

    # nettoyage
    rm -fr 63[0-9][0-9][0-9][0-9][0-9][0-9].* osmmap.* areas.list *.args gmapsupp4?.img tmp

    # log
    echo ''
    echo -n "*** ${carte} : finished      " ; date '+%T'
    cd ..
done

# fusionner toutes les cartes gmapsupp.img en une seule
echo ''
echo -n "*** ${cartes}: final merge      " ; date '+%T'
echo $cartes
java -Xmx1G -jar ../bin/mkgmap.jar --gmapsupp $cartes
rm -f osmmap.*

Ce script utilise osmosis, splitter et mkgmap. Ils sont installés dans un répertoire bin situé au dessus des cartes. On peut changer ces chemins en éditant le script. Je vais sans doute déplacer tout ce paquet de logiciels vers /usr quand ça sera stable.

Il est assez compliqué à cause des particularités des logiciels employés. Le principe est d'abord de mettre à jour les données OSM de la zone. Il faut évidemment avoir fait tourner InitCartes.sh avant (le script du § prédédent). Ensuite, il répète le même processus trois fois : une fois pour chaque couche relief, carte et routage, séparer les données .osm en zones pas trop grandes puis lancer mkgmap sur chaque zone. A la fin, il fusionne les cartes obtenues en une seule carte.

Parmi les particularités des logiciels (mkgmap), il faut par exemple avoir des numéros mapid complètement différents entre les couches et entre les zones. Pour cela, les cartes sont nommées 632100NN pour les zones de relief, 632101NN pour la carte normale et 632102NN pour la carte de routage. Le nombre NN varie selon le pavé découpé par le splitter.

Un autre aspect est celui des identifiants des cartes family-id. Ces identifiants 42, 43 et 44 sont liés au fichier de style typ utilisé par le Garmin pour dessiner les cartes. Pour avoir des styles différents, il faut des identifiants différents et qu'ils correspondent aux styles. Les contours sont définis par le style 44-contours.typ, le routage est le n°43 et la carte normale de style p-map a pour identifiant 42.

Tout à la fin, on obtient un et un seul fichier gmapsupp.img qu'il suffit de copier dans le dossier Garmin du GPS. Il y a aussi un gmapsupp.img dans chaque zone de carte. Il permet de ne charger que la carte utile si on ne veut qu'une seule zone.

Styles pour les cartes

J'utilise le style p-map proposés par Petrovsk http://wiki.openstreetmap.org/wiki/User:Petrovsk/FR:My_Garmin_map_styles#P-Map et je l'ai un peu modifié pour faire mieux apparaître les sentiers et chemins de randonnée, à la fois l'apparence dans le fichier typ et la gestion dans le fichier p-map/lines (j'ai changé les niveaux de zoom auxquels apparaissent ces voies). Comme je les modifie encore très souvent, presqu'à chaque sortie, je préfère ne pas les fournir ici pour l'instant.

J'ai un souci avec ces styles, je n'arrive pas à remplir les zones vides en blanc (ou autre) afin de ne pas voir les cartes qui sont dessous. Plus précisément, le Garmin affiche trois couches superposées, exactement comme http://wiki.openstreetmap.org/wiki/User:Petrovsk/FR:layered_Garmin_map. D'abord les courbes de niveau ; ce sont des lignes et des textes, il n'y a pas de polygones de remplissage. Cette couche est définie transparente. En dessous, la carte normale de style p-map modifié, et tout en dessous, il y a la carte de routage dans le style standard Garmin mais simplifiée et pas destinée à être vue. Le problème est que la couche du milieu n'est pas entièrement opaque et laisse voir la couche de routage sous-jacente. Il faudrait un fond de remplissage là où il n'y a pas de polygones. Je ne sais pas comment faire ça avec mkgmap, si vous savez le faire écrivez-moi un petit message sur ma boite http://www.openstreetmap.org/user/melnibon, merci.