Atelier initiation à OpenStreetMap et QGis

Du 17 au 20 juin dernier avait lieu le 48e colloque annuel de l’Association des cartothèques et archives cartographiques du Canada (ACACC).   Les organisateurs sont entrés en contact avec Mapgears pour organiser un atelier sur OpenStreetMap et QGis.   Le défi était tout de même relativement important pour plusieurs participants qui n'avaient pas encore eu la chance d'ouvrir le logiciel QGis.  Comme promis aux participants, voici donc les documents PDF de l'atelier.

Scribeui 0.7 beta

En 2013, Mapgears lance le projet ScribeUI destiné à simplifier la création de cartes pour le Web basé sur Mapserver et l'intégration du langage scribe pour mapserver.  L'objectif était vraiment simple: améliorer notre efficacité d'écriture d'un mapfile pour produire des cartes multiniveau tout en conservant la grande flexibilité de Mapserver.  La première version du projet était vraiment intéressante et on décide de faire un Google summer of code pour améliorer le design de l'outil.  Jessica Lapointe (de l'équipe Mapgears) avait d'ailleurs eu de bons mots à propos de son projet ScribeUI au GsoC 2013 provenant de la responsable de la fondation OSGeo.

Suite à des travaux importants réalisés chez Mapgears, je teste depuis plusieurs jours, une nouvelle version de ScribeUI et je suis vraiment épaté du résultat. Le projet n'est pas encore sur Github, mais il y sera prochainement.  On a remodelé l'interface, ajouté de nouvelles fonctions mais surtout changé le framework Flask pour Pyramid. L'application est maintenant beaucoup plus stable même si quelques petits bogues persistent. La bonne nouvelle est que Jessica Lapointe poursuivra bientôt les travaux entamés sur l'application beta pour améliorer l'utilisation générale du produit.

Personnellement, je ne peux plus me passer de l'outil pour produire des cartes web.  ScribeUI offre une méthode rapide, structurée et efficace pour faire un projet Web Mapping.  Combiné à Git, je peux transférer un projet d'une VM local à un serveur Cloud en quelques minutes, c'est vraiment pratique.

.

En plus de la syntaxe scribe très pratique, deux nouvelles fonctions vraiment cool arrivent avec cette version!  On a intégré un processus Git à la production carto avec ScribeUI. On se disait que produire une carte web est un peu comme faire de la programmation et que git mériterait d'être plus largement utilisé dans ce contexte.  C'est aussi une bonne pratique pour structurer le travail à faire, suivre l'évolution des versions de la carte et faciliter le transfert du projet cartographique d'un environnement à l'autre (DEV, TEST, PROD).  Directement dans l'application ScribeUI, on pourra maintenant, cloner puller et pusher toutes la config d'un projet carto sur un Git.  J'ai un projet complet (data et mapping ) pouvant être cloné ici : https://github.com/smercier/gitscribe.

On a ajouté un lien direct sur le fichier "readme.md" de votre projet pour favoriser le réflex de documentation. Deux clics suffisent pour éditer le "readme.md" de votre git avec la syntaxe mardown.  Pour ma part, c'est dans le readme que je documente les grandes lignes du makefile d'installation de données (quand c'est requis).

On a amélioré la coloration syntaxique et on pourra mieux apprécier la nouvelle option pour commenter de grande section de mapfile avec un code ouvrant (/*) et fermant  (*/) , ça j'aime VRAIMENT.  On a ajouté un lien direct sur l'aide en ligne(http://mapserver.org/mapfile/)  des mapfiles keywords en cliquant sur ALT et le keywords.

Écrire des mapfiles avec des variables et des codes de niveau de zoom, qui correspond bien plus à notre nouvelle réalité de production cartographique pour OpenLayers ou Leaflet.  Faire une carte avec les données OpenStreetMap devient soudainement bien plus plaisant.

L'autre fonction nouvellement ajoutée est un UI pour lancer des job Mapcache.  Le panorama permet de spécifier le Zoom levels à produire, le Metatile size, le Grid disponible et un Extent spécifique.  Ce dernier peut être dérivé du Map Extent de mapfile mais aussi à partir shapefile ou même d'une requête provenant d'un serveur Postgis.   L'intégration de nouvelles options sera documentée sur github.

J'ai aussi testé l'application avec des Mapfiles standard très volumineux (pour une carte maritime avec des données S-57) 5 mapfiles de 2000 lignes et plus dont un de 3042 lignes.  La navigation entre les groupes me permette de passer rapidement d'un include mapfile très rapidement et rend l'édition de la carte bien plus rapide.

À suivre donc, d'autres infos suivront prochainement.  Les idées ne manquent pas pour ce projet.

Plug-in Oracle pour Mapserver dans UbuntuGIS

Mapgears a réalisé un plug-in Oracle pour Mapserver et GDAL/OGR qui simplifie énormément la configuration d'une configuration Mapserver pour Oracle.

Installer le client Oracle

Oracle met à la disposition des organisations un portail regroupant une panoplie d’outils et de tutoriels logiciels Open Source d’Oracle. Grâce à ce portail, il est possible d’installer une version gratuite de la base de données Oracle et le client Oracle XE plus facilement sur un poste Linux.  Par contre, actuellement les packages de ce type d'installation datent de 2006 et il ne s'agit pas de la dernière version du client.  Ça fonctionne, mais l'option manque un peu de rigueur pour monter une infrastructure solide pour une organisation en mode "stable".

Pour permettre la connectivité entre Mapserver et Oracle, je recommande l'installation de la version du client Oracle officiellement supportée:  Oracle InstantClient.  Vous trouverez sur le site Web d'Oracle toutes les versions OS supportées.  Dans cette procédure, j'utilise les sources (dans fichier zip) et non les packages Redhat (rpm).  Pour télécharger les sources officielles, il faudra vous enregistrer sur le site Web d'Oracle et accepter les termes de la licence.  Par la suite, faire l'installation via la méthode suivante :

  • Télécharger les fichiers zip requis pour l'installation de la version Linux x86 InstantClient v 11.2. Les fichiers zip requis seront les suivants :
  1. Instant Client Package - Basic Lite ( instantclient-basic-linux-11.2.0.4.0.zip )
  2. Instant Client Package - SDK ( instantclient-sdk-linux-11.2.0.4.0.zip )
  3. Instant Client Package - SQL*Plus ( instantclient-sqlplus-linux-11.2.0.4.0.zip )
  • Pour installer le client, aucune installation n'est requise.  Il faut simplement dézipper les fichiers sources dans le répertoire de votre choix (/opt/ dans mon cas):
sudo unzip instantclient-sqlplus-linux-11.2.0.4.0.zip -d /opt/
sudo unzip instantclient-basic-linux-11.2.0.4.0.zip -d /opt/
sudo unzip instantclient-sdk-linux-11.2.0.4.0.zip -d /opt/
ls -l /opt/instantclient_11_2/
-rwxrwxr-x 1 root root     22004 Aug 25 11:18 adrci
-rw-rw-r-- 1 root root       437 Aug 25 11:18 BASIC_README
-rwxrwxr-x 1 root root     38461 Aug 25 11:18 genezi
-r-xr-xr-x 1 root root       368 Aug 25 11:18 glogin.sql
-rwxrwxr-x 1 root root  44316855 Aug 25 11:18 libclntsh.so.11.1
-r-xr-xr-x 1 root root   7098468 Aug 25 11:18 libnnz11.so
-rwxrwxr-x 1 root root   1881900 Aug 25 11:18 libocci.so.11.1
-rwxrwxr-x 1 root root 118729922 Aug 25 11:18 libociei.so
-r-xr-xr-x 1 root root    152585 Aug 25 11:18 libocijdbc11.so
-r-xr-xr-x 1 root root   1499831 Aug 25 11:18 libsqlplusic.so
-r-xr-xr-x 1 root root   1216654 Aug 25 11:18 libsqlplus.so
-r--r--r-- 1 root root   2091135 Aug 25 11:18 ojdbc5.jar
-r--r--r-- 1 root root   2739616 Aug 25 11:18 ojdbc6.jar
drwxrwxr-x 4 root root      4096 Aug 25 11:18 sdk
-r-xr-xr-x 1 root root      6913 Aug 25 11:18 sqlplus
-rw-rw-r-- 1 root root       441 Aug 25 11:18 SQLPLUS_README
-rwxrwxr-x 1 root root    160203 Aug 25 11:18 uidrvci
-rw-rw-r-- 1 root root     66779 Aug 25 11:18 xstreams.jar
  • Pour configurer le client par la méthode couramment utilisée par la majorité des organisations, on va créer l'arborescence de répertoires network et y ajouter un fichier tnsnames fourni par le DBA. ( cette étape est optionnelle)
sudo mkdir /opt/instantclient_11_2/network
sudo mkdir /opt/instantclient_11_2/network/admin
sudo vim /opt/instantclient_11_2/network/admin/tnsnames.ora
  • Pour avoir le runtime library path du le Client Oracle pour tous les utilisateurs, il est préférable d’ajouter un fichier de configuration dans le répertoire de chargement de librairie, pour que tous les logiciels puisent y accéder.
sudo vim /etc/ld.so.conf.d/oracle.conf
/opt/instantclient_11_2 ==>ligne à ajouter dans le fichier
sudo ldconfig
  • Validation de connexion direct (sans TNS)
sqlplus [utilisateur]/[mot_passe]@//[nom_server_ou_ip]:1521/[SID]
  • Validation de connexion (avec TNS)
sqlplus [utilisateur]@[SID]

Installer Mapserver et le plugin Oracle

Les instructions de base pour installer le plugin Oracle pour Mapserver sont maintenant documenté sur le Trac UbuntuGIS.
  • 1_ Connecter les packages privés de UbuntuGIS
sudo apt-get install python-software-properties
sudo add-apt-repository ppa:ubuntugis/ppa
sudo apt-get update
  • 2_ Installer Mapserver
sudo apt-get install cgi-mapserver mapserver-bin libmapcache mapcache-cgi mapcache-tools libapache2-mod-mapcache libmsplugin-oracle-src
  • 3_ Activer le plug-in Oracle pour Mapserver.  NOTE 1: on doit créer des liens symboliques avec les librairies requises par le plug-in.  Oracle ne respecte pas la nomenclature et les façons de faire Debian alors on doit s'adapter un peu.  NOTE 2: la variable d'environnement n'est pas requise pour rouler Mapserver une fois le plug-in activé, elle est seulement requise pour l'activation. NOTE 3: Attention, dans mon cas, je me suis retrouvé avec une librairie 11.1 dans un package annoncé 11.2! Je n’ai pas de félicitation à faire ici...
sudo ln -s /opt/instantclient_11_2/sdk/include/ /opt/instantclient_11_2/include

sudo ln -s /opt/instantclient_11_2/libocci.so.11.1 /opt/instantclient_11_2/libocci.so

sudo ln -s /opt/instantclient_11_2/libclntsh.so.11.1 /opt/instantclient_11_2/libclntsh.so

sudo ORACLE_HOME=/opt/instantclient_11_2 mapserver-oracle-build yes
  • 4_ Par la suite utiliser un répertoire relatif dans le paramètre PLUGIN du LAYER ou paramétriser le répertoire dans l'entête du mapfile avec "CONFIG MS_PLUGIN_DIR"
LAYER
  ...
  CONNECTIONTYPE PLUGIN
  PLUGIN "/usr/lib/msplugins/libmsplugin_oracle.so"
  DATA "GEOM FROM ZZ_EOLIENNES_P USING UNIQUE EOLIENNES_ID SRID 4326"
  ...
END
Note: jeu de données test

Rechercher des adresses dans Open Street Map

Un étudiant suisse m'a demandé de l'orienter dans sa recherche pour trouver des adresses dans Open Street Map.  Il avait chargé avec succès un fichier de données sources de la Suisse dans sa base de données Postgresql mais avait de la difficulté à trouver les adresses.

On ne trouve pas énormément d'adresses dans OSM car c'est une information très coûteuse à colliger, mais il y en a un peu.   Si vous utilisez l'utilitaire d'importation imposm,  pas de chance, les adresses ne sont pas récupérées par défaut.  Je n'ai jamais essayé, mais il faudrait probablement modifier le script python de paramétrage d'importation defaultmapping.py.   Ne vous en faire pas si vous trouvez la chose un peu compliquée à priori!  Ça l'est réellement et demande du temps pour assimiler l'ensemble des technicalités OSM!

Si vous utilisez l'utilitaire osm2pgsql, vous pouvez récupérer des adresses dans les buildings et les amenities, à condition d'avoir activé l'extension Hstore dans votre base de données, sans oublier de spécifier l'option --hstore dans votre ligne de commande osm2pgsql.  Cette option permet de charger dans la base de données tous les tags et pas seulement ceux spécifiés dans le fichier de style.  Comme j''aime avoir accès à TOUTES la base de données OSM, j'utilise toujours l'option --hstore.  J'ai regardé dans quelques villes en Suisse (dont Lausanne) et effectivement plusieurs bâtiments ont des adresses. Une fois les données chargées avec osm2pgsql et --hstore, voici le genre de requêtes SQL possibles

SELECT osm_id, name, building, shop, amenity,
     tags -> 'tourism'::text AS tourism,
     tags->'denomination' as denomination,
     tags->'religion' as religion,
     tags->'cuisine' as cuisine,
     CAST(tags->'addr:housenumber' as text)||' '||CAST(tags->'addr:street' as text) as address,
     tags->'addr:postcode' as postcode,
     tags->'addr:city' as city,
     tags->'building:levels' as building_levels,
     CASE WHEN ST_IsValid(way) = 'f' THEN           
ST_Buffer(ST_MakeValid(way),0) ELSE way END AS geometry
FROM osm_polygon
WHERE building IS NOT NULL;
Et dans la classe des amenities:
SELECT osm_id, name, amenity, '' as building, shop,
     tags -> 'tourism'::text AS tourism,
     tags->'denomination' as denomination,
     tags->'religion' as religion,
     tags->'cuisine' as cuisine,
     CAST(tags->'addr:housenumber' as text)||' '||CAST(tags->'addr:street' as text) as address,
     tags->'addr:postcode' as postcode,
     tags->'addr:city' as city,
     tags->'building:levels' as building_levels
FROM osm_point
WHERE amenity is not null
OR shop is not null ;
L'autre solution serait d'utiliser l'API Nominatim. Je n'ai pas encore fait d'essais sérieux avec ce service, ici au Canada, ce n'est pas fameux parce que le base de données OSM n'est pas assez complète  Pour terminer il y a aussi le projet OSRM qui pourrait aider à trouver une méthode d'extraction d'adresses.

Un essai avec Vagrant et osmbase

Update le 30 décembre 2013
Suite à un billet de @alanboudrault, sur l'utilisation d'un environnement virtuel pour développer avec Mapserver, j'ai testé l'utilisation de Vagrant pour améliorer notre processus interne de tests unitaires sur nos projets Open Street Map.   J'ai tout de suite aimé la simplicité de l'outil et la rapidité qu'il me donne pour monter un environnement jettable à l'aide de quelques lignes de commandes.  Il faut voir Vagrant comme un outil exploitant un moteur de machine virtuel comme Virtual Box ou VMware Fusion.  Sa force sera d'être rapidement configurable et réutilisable avec un Vagrantfile.

Considérons que vous avez déjà installé Vagrant et VirtualBox. Dans une fenêtre terminale (Mac, Ubuntu ou Windows), on commence par télécharger une box vagrant de type Ubuntu et on va l'initialiser:

mkdir vagrant
cd vagrant
vagrant box add precise32 http://files.vagrantup.com/precise32.box
vagrant init precise32

L'initiation de la VM avec Vagrant, vient de créer un fichier Vagrantfile.  Je garde ce config hyper simple pour l'instant. Il me permettra de me connecter au besoin sur ma VM avec pgAdmin au serveur "localhost" sur le port 5555, et d'accéder au serveur Web localhost via le port 8080 (  http://localhost:8080):

# -*- mode: ruby -*-
# vi: set ft=ruby :

Vagrant.configure("2") do |config|

# Every Vagrant virtual environment requires a box to build off of.
config.vm.box = "precise32"

# Create a forwarded port mapping which allows access to a specific port
# within the machine from a port on the host machine. In the example below,
# accessing "localhost:8080" will access port 80 on the guest machine.
config.vm.network :forwarded_port, guest: 5432, host: 5555
config.vm.network :forwarded_port, guest: 80, host: 8080
...
end
On va démarrer la VM et s'y connecter:
vagrant up
vagrant ssh
Utilisateur Windows: J'utilise ici un client ssh par défaut sur mon macbook. Pour les utilisateurs Windows, je conseille toujours d'utiliser le client ssh MobaXtrem parce qu'il est très pratique pour les moins habitués. L'utilitaire Putty peut aussi être utilisé. Vagrant donnera ce genre d'information (après vagrant up) pour faire la connexion avec MobaXtrem:
Host: 127.0.0.1
Port: 2222
Username: vagrant
Private key: C:/Documents and Settings/mapgears/.vagrant.d/insecure_private_key

J'utilise toujours le user par défaut de vagrant. Un fois connecté au serveur, configurer la langue du nouveau serveur dans le profile vagrant. Ça reste une étape toujours importante pour supporter convenablement les accents dans votre base de données Postgresql:

export LANGUAGE=en_CA.UTF-8
export LANG=en_CA.UTF-8
export LC_ALL=en_CA.UTF-8
sudo localedef -i en_CA -f UTF-8 en_CA
sudo locale-gen en_CA.UTF-8
sudo update-locale
sudo sudo dpkg-reconfigure locales
On doit maintenant faire la mise à jour du serveur avec un script VirtualBox et brancher le dépôt logiciels géomatiques UbuntuGIS (version precise):
sudo sh postinstall.sh
sudo apt-get update
sudo apt-get install python-software-properties
sudo add-apt-repository ppa:ubuntugis/ppa
sudo apt-get update
Installation de Postgresql/PostGIS
sudo apt-get install -y postgresql-9.1 postgresql-server-dev-9.1 postgresql-contrib-9.1 postgis
Installation d'outils
sudo apt-get install -y apache2 binutils gdal-bin checkinstall git vim screen make python-virtualenv python-pip python-all-dev osm2pgsql osmosis 
Installation Mapserver / Mapcache
sudo apt-get install -y cgi-mapserver mapserver-bin libmapcache mapcache-cgi mapcache-tools libapache2-mod-mapcache
sudo mkdir /tmp/ms_tmp
sudo chown www-data:www-data /tmp/ms_tmp
NOTE: Pour faire toutes les opérations en une seule étape, créer un fichier init.sh avec vi à l'aide de ce Gist init.sh

Par la suite on installe un nouvelle BD Postgresql/PostGIS OSM avec un encodage UTF-8 (voir ce billet pour instructions):

Ne reste plus qu'à faire un peu de magie avec ce repo osmbase. Le makefile contenu dans ce projet va télécharger les données requises et lancer imposm avec notre petit fichier OSM préféré de la Nouvelle-Calédonie pour construire ma carte QA et de plus j'active un environnement virtuel python. Enfin, simplement modifier les variables de départ du makefile pour vos besoins.

virtualenv venv
source venv/bin/activate
pip install imposm
git clone https://github.com/smercier/osmbase.git
cd osmbase
make
make imposm
Si l'installation se passe sans erreur, la URL suivante devrait fonctionner! http://localhost:8080/cgi-bin/mapserv?map=/home/vagrant/osmbase/osmbase.map&LAYERS=default&template=openlayers Une fois le QA terminé, on a qu'a détruire la VM et recommencer le processus à nouveau pour un autre besoin.  Très simple, j'aime vraiment :-)

GEOTRANSFORM et Mauve Nanane …

En début de semaine, j'ai pris connaissance des travaux de mon collègue @AlanBoudreault sur une nouvelle fonctionnalité vraiment intéressante qui sera ajoutée dans la version Mapserver 6.4.  Le RFC-89  ajoutera de nouvelles fonctions de simplification, qui seront effectuées directement par le moteur cartographique Mapserver sans intermédiaire.

J'en ai profité en même temps pour faire une critique cinglante (à l'interne mais c'était humoristique quand même  :-) ) sur l'horrible Mauve nanane du site Web officiel de mapserver.org. Je sais, tout est question de goût, reste que je pense qu'il y trop de mauve dans la mise en page et qu'on devrait faire disparaître tous ces en-têtes mauves qui me font toujours sursauter un peu.

Ce qui m'a valu un retour tout aussi cinglant de la part de bon ami @dmorissette, qui m'a proposé un nouveau titre pour mon blog! Pour ma défense, c'est un paramètre par défaut de mon thème WordPress, mais promis je vais chercher à solutionner ladite chose.

Une carte choroplèthe trigrid

Après avoir créé la carte sur les gaz à effet de serre, je voulais refaire l'expérience avec un grid en forme de triangle, sachant que l'utilisation d'un grid rectangulaire ou hexagonal donne un superbe effet pour cartographier une choroplèthe. Après quelques recherches, j'ai trouvé cet exemple qui s'approchait à ce que je voulais reproduire:

J'ai donc récupéré quelques données géométriques sur les divisions de recensement et des données statistiques sur le site Web de Statistique Canada pour créer une carte Choroplèthe selon les divisions de recensement canadiennes.

Après quelques manipulations dans QGis, j'arrive rapidement à créer une choroplèthe, tout ce qu'il y a de plus standard et habituelle (pour ne pas dire sans saveur ni odeur) basée sur une régression quantile en 5 classes:

Même que, pour mieux représenter la répartition de la population, je préfère utiliser un écoumène de Statistique Canada.  Ça donne un bien meilleur résultat et montre mieux l'occupation du territoire.

J'ai aussi testé une requête SQL proposée par @tokumin sur stackoverflow permettant de calculer directement dans Postgresql la même régression Quantile. Le résultat basé sur l'utilisation de la clause OVER (une windows function bien expliquée dans ce billet) est vraiment intéressant et donne un résultat presque identique à QGis.

SELECT ntile, avg(nb) AS avgAmount, max(nb) AS maxAmount,
       min(nb) AS  minAmount
FROM (SELECT nb, ntile(5) OVER (ORDER BY nb) AS ntile
FROM cdec_p_4326) x
GROUP BY ntile ORDER BY ntile<code>

-- ntile avgamount maxamount minamount
-- 1 11736.7796610169 18000 629
-- 2 23135.5593220339 31138 18036
-- 3 39888.5762711864 50512 31333
-- 4 72870.1206896552 104075 50900
-- 5 428264.25862069 2615060 105719</code>

Pour reproduire  l'effet désiré, j'ai placé dans une boucle la création de 8 triangles à l'aide de quelques formules mathématiques sur les triangles de cette façon:

Je répète ensuite la création de cet ensemble de triangles sur toute la largeur de l'étendue souhaitée et empile les uns par-dessus les autres, ce même ensemble de triangles, sur toute la hauteur voulue. Vous trouverez les quelques lignes de code SQL permettant de créer le trigrid avec Postgresql/PostGIS dans mon github.

À l'aide de cette suite d'instructions et de la fonction trigrid, on pourra créer deux classes d'entités géométriques permettant de préparer une carte choroplèthe trigrid :
-- créer une table tirgrid level 1
drop table trigrid_l1;
create table trigrid_l1(gid integer,tx integer, ty integer);
SELECT AddGeometryColumn ('','trigrid_l1','the_geom',4326,'POLYGON',2);
select trigrid (-150,36,100,44,0.13,4326,'trigrid_l1');
CREATE INDEX sidx_trigrid_l1 ON trigrid_l1 USING GIST ( the_geom );
CREATE UNIQUE INDEX idx_trigrid_l1 ON trigrid_l1 (gid);
select count(*) from trigrid_l1;
-- 605200

-- créer une table tirgrid level 2
drop table trigrid_l2;
create table trigrid_l2(gid integer,tx integer, ty integer);
SELECT AddGeometryColumn ('','trigrid_l2','the_geom',4326,'POLYGON',2);
select trigrid (-150,36,100,44,0.065,4326,'trigrid_l2');
CREATE INDEX sidx_trigrid_l2 ON trigrid_l2 USING GIST ( the_geom );
CREATE UNIQUE INDEX idx_trigrid_l2 ON trigrid_l2 (gid);
select count(*) from trigrid_l2;
-- 2410968

Enfin, pour simplifier la création de la thématique avec Mapserver, j'ai transféré ma classification quantile des divisions de recensement sur mes deux trigrid (level 1 et 2), par une association avec ce genre de requête:

ALTER table trigrid_l1 add column cls integer;
update trigrid_l1 SET cls=5 FROM cdec_p_4326 WHERE ST_Intersects( trigrid_l1.the_geom,cdec_p_4326.the_geom) and cdec_p_4326.nb >105719;
--
update trigrid_l1 SET cls=4 FROM cdec_p_4326 WHERE ST_Intersects( trigrid_l1.the_geom,cdec_p_4326.the_geom) and cdec_p_4326.nb >50900 and cdec_p_4326.nb ...
Au final, j'aime bien et ça donne un résultat pas mal intéressant! Essayez-le http://smercier.github.com/trigrid/trigrid.html!

Scribe – Une nouvelle façon de faire du mapfile

Créer une belle carte qui véhicule efficacement son message n'est pas chose facile. On dispose souvent d'une grande quantité de données qu'on ne souhaite pas afficher en tout temps ou qu'on souhaite afficher mais avec un style qui varie en fonction du niveau d'échelle. Lorsqu'on défini le style d'une carte, chaque petit détail est important. Le processus se fait généralement de facon itérative et implique beaucoup de modifications, à tous les niveaux d'échelle.

Dans Mapserver, la gestion de l'échelle se fait avec les tags MINSCALEDENOM et MAXSCALEDENOM au niveau du LAYER ou de la CLASS. Cela veut dire qu'aussitôt qu'un élément du style change pour un LAYER ou une CLASS donné, à un certain niveau d'échelle, un nouveau LAYER ou une nouvelle CLASS doit être créé. On se trouve ainsi a réécrire beaucoup de texte pour ne modifier peut-être qu'un seul paramètre. La tâche devient encore plus fastidieuse si on doit changer un paramètre (par exemple la couleur d'une route) définie dans 16 LAYERs différents.

"Scribe" est un outil en python que nous avons créé pour faciliter l'écriture d'un "mapfile" en utilisant des variables et des raccourcis pour la gestion des échelles via des niveaux (maintenant la norme).  Cette façon de faire s'apparente à "Basemaps" mais est plus simple d'utilisation et généralement moins verbeuse.

Gestion des niveaux d'échelle

LAYER {
    1-16 {
        NAME: 'land'
        TYPE: POLYGON
        @layerconfig
        DATA {
            1-4: '110m_physical/ne_110m_land'
            5-10: '50m_physical/ne_50m_land'
            11-16: '10m_physical/ne_10m_land'
        }
        CLASS {
            STYLE {
                COLOR {
                    1-6: '#EEECDF'
                    7-16: '#AAA89B'
                }
                OUTLINECOLOR: 200 200 200
                OUTLINEWIDTH: @land_ol_width
            }
         }
     }
 }

Dans l'exemple précédent, un LAYER appelé "land" est créé. Le tag "1-16" signifie que ce LAYER doit etre affiché des niveaux d'échelle 1 à 16. Le script traduit automatiquement ces niveaux en MINSCALEDENOM et MAXSCALEDENOM. De plus, les données utilisées (DATA) des niveaux 1 à 4 sont au 110m tandis qu'elles sont au 50m des niveaux 5 à 10 et au 10m des niveaux 11 à 16. La couleur (COLOR) elle aussi change en fonction de l'échelle. En utilisant cette nomenclature, il devient très facile de modifier un paramètre pour un ou plusieurs niveaux d'échelle sans avoir à réécrire beaucoup de texte ou à faire des modifications à plusieurs endroits.

Définition et utilisation de variables

"Scribe" ne permet pas seulement de gérer les échelles mais il permet aussi de définir des variables réutilisables. Dans l'exemple ci-haut, les variables "layerconfig" et "land_ol_width" sont appelées a l'aide d'un "@". Ces variables sont définies de la facon suivante:

VARIABLES {
    layerconfig {
        GROUP: 'default'
        STATUS: ON
        PROJECTION {{
            'init=epsg:4326'
        }}
        PROCESSING: 'LABEL_NO_CLIP=ON'
        PROCESSING: 'CLOSE_CONNECTION=DEFER'
     }
     land_ol_width: 1
 }

La variable "layerconfig" contient plusieurs paramètres utilisés dans la définition de presque tous les LAYERs. Ainsi, pour chaque nouveau LAYER, il suffit d'écrire "@layerconfig" pour que tous les paramètres entrent dans la définition du LAYER. L'autre variable 'land_ol_width' prend une valeur unique.

Il est à noter que dans la définition de la variable "layerconfig", PROJECTION est suivi de deux "{". Cette syntaxe permet de gérer les tags comme PROJECTION, METADATA, PATTERN etc qui ne contiennent aucun paramètre, seulement du texte.

Blocs de commentaires

"Scribe" permet également d'utiliser des blocs de commentaire, ce qui n'est pas possible dans Mapserver seulement. D'autres types de commentaire sur une seule ligne peuvent aussi être écrits et apparaîtront dans le "mapfile" résultant.

LAYER {
    1-16 {
        NAME: 'land'
        TYPE: POLYGON
        @layerconfig
        DATA {
            1-4: '110m_physical/ne_110m_land'
            5-10: '50m_physical/ne_50m_land'
            11-16: '10m_physical/ne_10m_land'
        }
        CLASS {
            STYLE {
                COLOR {
                    1-6: '#EEECDF'
                    7-16: '#AAA89B'
                }                
                ##Les commentaires précédés par ## apparaissent
                ##dans le mapfile résultant.
                ##Les blocs de commentaires entre /* */
                ## n'apparaissent pas dans le mapfile résultant.
                /*
                OUTLINECOLOR: 200 200 200
                OUTLINEWIDTH: @land_ol_width
                */                
             }
         }
     }
 }

Conclusion

Finalement, pour exécuter le script, il suffit d'utiliser une seule commande, configurable avec certaines options:

python scribe.py

Le résultat est un mapfile parfaitement indenté avec gestion des échelles et souvent beaucoup plus de ligne que ce qu'il a fallu écrire. "Scribe" représente donc une économie importante en temps et produire des cartes de qualité devient plus facile et agréable.

Il est fort probable que "Scribe" évoluera et que de nouvelles fonctionnalités s'ajouteront.

Pour plus d'information ou pour utiliser "Scribe", consulter l'adresse suivante :

https://github.com/solutionsmapgears/Scribe.git Pour tout commentaire ou pour rapporter un bug : Charles-Éric Bourget cbourget@mapgears.com

Cartographie d’un réseau routier avec MapServer: savoir gérer l’ordre d’affichage

Lorsqu’on veut cartographier un réseau routier, l’ordre d’affichage des routes est important pour que les voies les plus importantes ne soient pas coupées par des voies secondaires, par exemple.

Image 1 - résultat désiré

Image 2 - résultat brut

L'ordre d'affichage dépend de plusieurs facteurs.  Cet article explique le comportement de MapServer face à l'ordre d'affichage des entités géographiques afin de vous permettre d'obtenir un résultat "propre" dans l'affichage de votre réseau routier.  Il est important de noter que certaines des règles qui suivent ne s'appliquent qu'aux LAYERs de type LINE.

1) Premier lu - Premier dessiné

Le premier élément à considérer est, qu'à l'intérieur d'un même layer, les éléments sont dessinés selon l'ordre de lecture de la donnée indépendamment de la CLASS à laquelle ils appartiennent. En d'autres mots, le premier segment du réseau routier lu sera le premier dessiné. Il est donc nécessaire de classer la source. Par exemple, avec une BD Postgresql/PostGIS, on peut classer les données selon un z-index (z_order dans Open Street Map) et selon la longueur du segment :

DATA "geometry from (select osm_id, geometry, name, type
      from osm_roads
      where type in ('secondary', 'tertiary', 'residential')
      order by z_order asc, st_length(geometry) asc)
      as foo using unique osm_id using srid=900913"

Si vous utilisez un shapefile, l'utilitaire sortshp pourrait être très utile. 

NOTE: Cette règle s'applique à tous les types de layers.

2) Nombre de style dans la classe

Le nombre de STYLE dans une CLASS influence l'ordre d'affichage. Lorsqu'à l'intérieur d'un LAYER, des CLASS comprennent plus qu'un STYLE, le premier STYLE de chaque CLASS est dessiné avant de procéder au 2e STYLE des CLASS et ainsi de suite.

3) Outline en premier

Lorsque les premiers STYLE des CLASS comportent un OUTLINEWIDTH, les outlines de toutes les CLASS sont dessinés avant l'intérieur.  Cet aspet spécifique n'est pas le fruit du hasard et a été implanté dans la version 5.4 et documenté dans la RFC-49.

Exemple: mapfile incorrect

CLASS  # routes secondaires
  EXPRESSION /secondary/
  STYLE
    WIDTH 12
    COLOR 255 0 0 # rouge
    OUTLINEWIDTH 2
    OUTLINECOLOR 153 111 57 # brun
  END
  STYLE
    WIDTH 11
    COLOR 223 197 124 # orange
  END
END

CLASS # routes tertaires
  EXPRESSION /tertiary/
  STYLE
    WIDTH 11
    OUTLINEWIDTH 1
    OUTLINECOLOR 193 188 157 # gris
    COLOR 255 253 139 # jaune
  END
END

CLASS # routes résidentielles
  STYLE
    WIDTH 11
    OUTLINEWIDTH 1
    OUTLINECOLOR 103 181 157  # vert
  END
  STYLE
    WIDTH 11
    COLOR  238 225 226  # rose
  END
END

En considérant que la source a été triée dans cet ordre: résidentielles, tertiaires, secondaires, l'ordre d'affichage se déroule comme suit:

  1. Outline (vert) des routes résidentielles
  2. Outline (gris) des routes tertiaires
  3. Outline (brun) des routes secondaires
  4. Premier style (uniquement un outline) des routes résidentielles
  5. L'unique style (jaune) des routes tertiaires
  6. Premier style (rouge) des routes secondaires
  7. Deuxième style (rose) des routes résidentielles
  8. Deuxième style (orange) des routes secondaires
 

Exemple: mapfile correct

CLASS  # routes secondaires
  EXPRESSION /secondary/
  STYLE
    WIDTH 12
    COLOR 255 0 0 # rouge
    OUTLINEWIDTH 2
    OUTLINECOLOR 153 111 57 # brun
  END
  STYLE
    WIDTH 11
    COLOR 223 197 124 # orange
  END
END

CLASS # routes tertaires
  EXPRESSION /tertiary/
  STYLE
    WIDTH 11
    OUTLINEWIDTH 1
    OUTLINECOLOR 193 188 157 # gris
  END
  STYLE
    WIDTH 11
    COLOR 255 253 139 # jaune
  END
END

CLASS # routes résidentielles
  STYLE
    WIDTH 11
    OUTLINEWIDTH 1
    OUTLINECOLOR 103 181 157  # vert
  END
  STYLE
    WIDTH 11
    COLOR  238 225 226  # rose
  END
END

619 fonctions avancées d’analyses spatiales

QGis n'est pas un outil très utilisé au Québec, par contre les Analystes en Géomatique doivent absolument y jeter un oeil.  Nous utilisons QGis dans la très grande majorité de nos projets chez Solutions Mapgears.  Je n'avais pas encore regardé ce que pouvait offrir l'extension Sextante (aussi disponible sous ArcGIS et gvSIG), probablement parce que ma todolist est un peu trop longue! Bref, ce post d'Oslandia n'avait pas eu encore de suite.

Incroyable, mais on retrouve dans la toolbox de l'extension, pas moins de 619 géoalgorithmes!  GDAL, GRASS, SAGA, OTB(télédétection), R (statistique)....     Vrai que l'interface utilisateur de GRASS n'est pas très sexy, mais on pourra quand découvrir sa puissance via la liste interminable de fonctions dans le toolbar Sextante.  De plus, l'outil dispose d'un "Modeler" mais là vraiment je peux pas en dire plus je ne l'ai pas testé ...

J'ai aussi découvert l'outil d'analyses géoscientifiques System for Automated Geoscientific Analyses (SAGA) un logiciel FOSS.  Le plugin Sextante propose 279 algo de cette plateforme. Le développement semble avoir cessé en 2007, par contre l'outil est le fruit de plusieurs années de développement et vaux vraiment la peine d'être examiné. À mettre sur votre todolist donc!