OSM, QGis, PostGIS et SFCGAL en pratique
←
→
Transcription du contenu de la page
Si votre navigateur ne rend pas la page correctement, lisez s'il vous plaît le contenu de la page ci-dessous
OSM, QGis, PostGIS et SFCGAL en pratique Comment, avec quatre outil Open Source, ré- Création de la base de format est facilement interpréta- soudre une question d’aménagement appar- ble : chaque nombre correspond données à l’altitude d’une des cases de emment anodine… mais pas autant que ça ! la grille dont les caractéristiques La question que nous allons réso- (taille du maillage et position udre consiste à évaluer la pente d’une des cases d’extrémité) sont moyenne, kilomètre par kilomètre, données dans l’en-tête : du tracé de l’extension de la ligne ncols 1000 L ’offre Open Source en TGV est-européenne, longue nrows 1000 géomatique, qu’elle concerne d’une trentaine de kilomètres, et xllcorner 974962.500000000000 les données (Open data ou réalisée partiellement en tunnel yllcorner 6750037.500000000000 Open Street Map) et les logiciels sous le massif vosgien. Nous cellsize 75.000000000000 (PostGIS, QGIS…), a atteint un considérerons les parties sous NODATA_value -99999 niveau de maturité qui permet tunnel comme étant horizontales désormais de résoudre des prob- (ce qui constitue une hypothèse Nous savons ainsi que le fichier lèmes assez délicats en quelques à peu près raisonnable, du moins élémentaire (ici, celui qui nous manipulations, pourvu que l’on en première approximation). intéresse, baptisé BDALTIr_2-0_ maîtrise correctement chacun MNT_EXT_0975_6900_ des outils (ce qui n’est pas La première étape consiste à LAMB93_IGN69_20110929. évident). Dans ce « mini-tutoriel », constituer une base de données asc) est composé d’une grille nous allons détailler comment (nommons la, par exemple de mille points par mille points, résoudre une problématique « LGV ») dans laquelle nous que les coordonnés précisées simple, calculer la pente moyenne allons stocker nos deux couches sont celles du point sud-ouest d’une voie ferrée, kilomètre par initiales : la BD Alti® 75 m et (ll : lower left) et que la maille kilomètre, en n’utilisant que des le tracé de la ligne issue des mesure, on le savait déjà, soix- ressources libres, à savoir la données OSM. ante-quinze mètres. Enfin la BD Alti® de l’IGN au pas de 75 m valeur prétexte, -99 999 (utilisée (disponible en téléchargement La BD Alti® 75 m, comme pour les points hors territoire), sur le site de l’Institut), le tracé précédemment signalé, est libre- n’a pas d’importance ici puisque issu de la base Open Street ment téléchargeable sur le site de l’intégralité de la dalle est située Map, et les logiciels QGis 2.2 l’IGN dans sa partie profession- en France. (dernière version publiée) ainsi nelle. Elle est fournie sous la forme que PostGIS 2.1 accompagné de dalles .ASC compressées, La deuxième étape consiste à de l’extension SFCGAL1. chacune d’environ 1 Mio. Le récupérer les données Open 1. SFCGAL est une bibliothèque d’interface entre PostGIS et la bibliothèque de « géométrie computationnelle » CGAL développée en grande partie par l’INRIA. Cette bibliothèque enrichit PostGIS de nouvelles fonctions inédites, particulièrement dans le domaine de la 3D, mais pas seulement. 30 Géomatique Expert|N° 97|Mars-Avril 2014
Street Map. Théoriquement, Le processus d’importation, que l’on souhaite extraire (points, ceci est directement faisable à depuis l’intégration de la fonc- lignes, polygones), et de sélec- l’intérieur de QGis en utilisant, tionnalité OSM dans le cœur de tionner les attributs (tags) que dans le menu Vecteur, l’entrée QGis, est assez complexe. Il faut l’on souhaite conserver (figure 3). OpenStreetMap Ö Télécharger utiliser d’abord la fonction Vecteur Dans le cas qui nous intéresse, ce des données. Malheureusement, Ö OpenStreetMap Ö Importer la sont les polylignes (tracés routiers la plupart du temps, cette topologie depuis un XML pour et ferrés) que nous allons extraire, option ne fonctionne pas (on créer, à partir des données OSM en sélectionnant les attributs obtient un message d’erreur). brutes (XML), un fichier compat- name, railway et tunnel. Le La façon la plus efficace, et la ible avec la base de données résultat est un maillage assez plus fiable, de télécharger ces SpatiaLite qu’utilise QGis pour dense de polylignes (car même données reste donc d’utiliser ses besoins propres. L’opération les tronçons sans attributs sont la partie cartographique du site prend un certain temps, variable extraits) visible figure 4. openstreetmap.fr, qui renvoie elle- selon l’importance des données même vers openstreetmap.org. et la puissance de la machine qui Là, sélectionner l’emprise d’intérêt exécute le script. Figure 3 : Après la sur le fond cartographique (ici, transformation grossièrement, un rectangle Après quelques minutes, on des données XML en tables englobant les villes de Metz, obtient un fichier .db en sortie qu’il SpatiaLite, la Nancy et Strasbourg) puis utiliser va falloir maintenant exploiter pour troisième fonc- tion Exporter le lien sur l’ « API passerelle », qui obtenir des couches affichables. la topologie permet de rapatrier des quantités Pour cela, la troisième fonction en SpatiaLite permet de créer de données plus importantes que Exporter la topologie en SpatiaLite une couche le site standard. permet de préciser le type d’objet géométrique et de sélectionner les champs à conserver. Figure 1 : Les fonctions d’import des données OSM sont toutes situées sous l’entrée OpenStreetMap du menu Vecteur. Figure 4 : Après importation, on se retrouve Figure 2 : QGis propose avec l’ensemble des données filaires. une fonction intégrée La consultation de la table des attributs de téléchargement permet de trouver la valeur des tags que des données OSM, l’on souhaite extraire. mais qui ne fonctionne malheureusement pas. Il nous faut maintenant extraire les données utiles dans ce réseau extrêmement dense. Comme on peut observer dans la table attributaire affichée figure 4, il semble que la ligne TGV soit, dans le champ railway, affublée de la valeur « construction ». Nous Géomatique Expert|N° 97|Mars-Avril 2014 31
allons donc générer une nouvelle À ce stade, il est expédient de du gestionnaire de bases de couche en sélectionnant par constituer un base de données données QGis, il faut auparavant attribut les tronçons portant le tag PostGIS et d’y injecter le tracé avoir défini les paramètres de railway:construction. Le résul- et le MNT (grâce aux fonctions connexion en cliquant sur l’icône tat correspond bien au futur tracé raster). On ne peut apparem- de chargement d’un couche de la ligne nouvelle (figure 5). ment pas créer directement PostGIS, ce qui ouvre le dialogue approprié. Une fois la connexion créée et vérifiée, on peut donc retourner dans le gestionnaire de base de données, sélectionner la nouvelle base et injecter directe- ment le tracé grâce à la fonction « importer une couche ou un fichier ». En revanche, le raster ne peut pas être stocké dans PostGIS depuis QGis, il faut donc b Figure 6 : Après sélection par attribut puis par rectangle englobant, on obtient l’extrait du tracé de la ligne LGV dans la zone d’intérêt. a Figure 5 : Sélection par attribut (icône dans le menu de la boîte d’affichage des données attributaires) de la valeur construction du champ railway. Nous créons donc une nouvelle couche sous forme de fichier Shapefile en utilisant l’option Sauvegarder la sélection sous. Nous la rechargeons, puis nous utilisons l’outil de sélection rectan- gulaire pour limiter le tracé à la seule portion où nous disposons des données d’altimétrie, puis nous sauvegardons de nouveau la sélection sous un nouveau fichier une nouvelle base de données utiliser l’utilitaire raster2pgsql, Shapefile (il est également possible PostGIS à l’intérieur de QGis, fourni avec PostGIS. Par exemple, de rassembler les deux sélections même en utilisant le gestionnaire sous Unix/Linux/OS X : en une seule pour aller plus vite). de bases de données. Il faut donc le faire, soit au travers de l’utilitaire Quand on examine le tracé de d’administration PGAdmin III, raster2pgsql -s 2154 -b 1 -c près, on s’aperçoit qu’il est en fait soit manuellement en ligne de -f geom -I -C BDALTIr_2-0_ MNT_EXT_0975_6900_LAMB93_ constitué des deux voies dessi- commande en tapant createdb IGN69_20110929.asc mnt | psql nées l’une à côté de l’autre. Ceci , puis en -d LGV va nous poser un souci, car il va injectant les différentes bases falloir gérer une géométrie de type nécessaires au bon fonctionne- multi- alors que nous souhaiteri- ment de la cartouche spatiale Il est conseillé d’utiliser un alias ons obtenir un tracé « simple ». (ne pas oublier, dans ce cas, ni dans la commande raster2pg- En outre, la couche comprend le module rtpostgis de gestion sql (le « mnt » juste avant le |) également deux raccordements des raster, ni le module sfcgal.) de façon à éviter de créer une d’accès que nous ne souhaitons Ici, nous choisirons LGV comme table portant le même nom que pas prendre en compte. Il va donc nom de base. Pour pouvoir le fichier, ce qui ne serait pas du falloir les éliminer. accéder à celle-ci à l’intérieur tout commode par la suite. 32 Géomatique Expert|N° 97|Mars-Avril 2014
« squelettisation », c’est-à-dire les axes rigides d’orientation. Le calcul met en jeu la bibliothèque CGAL et prend un certain temps (quelques minutes). Le résultat se présente sous la forme de l’axe central du corridor, et de multiples lignes qui connectent perpendiculairement cet axe aux limites du corridor aux endroits où celui-ci change de direction (figure 10). Figure 7 : Exemple de création d’une connexion PostGIS sur la base LGV nouvellement créée. CREATE TABLE squelette AS (SELECT ST_StraightSkeleton TTraitement it t dde lla ddonnée é est réalisable à l’aide des outils (geom) AS geom FROM boudin); Python fournis en standard avec de voie QGIS (menu Vecteur ÖOutils de Il faut donc se débarrasser de ces La donnée issue d’OSM néces- géotraitement), mais il vaut mieux segments perpendiculaires. Pour site encore quelques pré-traite- la conduire directement dans ce faire, nous allons dessiner un ments avant d’être utilisable. PostGIS. buffer autour de chaque segment. Tout d’abord, il faut éliminer les Seul celui qui entoure l’axe central tronçons partiellement hors-MNT, CREATE TABLE boudin AS (SELECT sera entièrement contenu dans puis les tronçons de raccorde- ST_Union(ST_Buffer (geom, 200)) le boudin que nous avons créé ment qui ne nous intéressent pas. AS geom FROM tracé); auparavant. Il suffit donc d’éliminer Pour cela, le plus aisé est d’utiliser les segments dont le buffer n’est QGis pour éditer la couche, de Le choix de deux cents mètres sélectionner manuellement les comme largeur du buffer est tronçons à ôter, puis de sauve- arbitraire, l’idée étant de retenir garder le résultat (figure 8). une valeur suffisante pour couvrir tous les écartements rencontrés. Il faut ensuite « fusionner » les deux Le résultat est visible figure 9. voies parallèles pour ne conserver que l’axe du tracé. Cette opéra- Il faut maintenant trouver le tion est un peu délicate et néces- moyen de recréer, à partir de site du doigté. Pour commencer, ce corridor, un axe central. il faut convertir les deux voies en Pour cela, la nouvelle fonction Figure 9 : Détail du corridor dessiné le long de la une sorte de « boudin » polygo- ST_StraightSkeleton issue voie grâce à la fusion des deux zones tampon. nal, en créant des buffers autour du module SFCGAL va nous de chacun des axes, puis en aider. Son rôle est, en partant les fusionnant. Cette opération d’un polygone, d’en calculer la Figure 10 : Résultat de la « squelletisa- tion ». L’axe central est relié à la péri- Figure 8 : tracé de la voie après phérie par des tronçons correspondant ajustements manuels aux « ruptures de pente » élémentaires. Géomatique Expert|N° 97|Mars-Avril 2014 33
pas entièrement contenu dans détaillé dans le cadre ci-après, le boudin, de regrouper tous prend comme paramètre la table les segments restants grâce à contenant la ligne à segmenter, la fonction ST_Union. Bémol et rend en sortie une nouvelle préliminaire toutefois : le résultat table baptisée du même nom de la requête précédente, donc affublé du suffixe _tronçons, la table squelette, est fourni constitué d’une série de tron- sous forme d’une géométrie çons élémentaires, chacun d’un Multi-. Il faut donc préalablement kilomètre de long. Moyennant la découper en tronçons élémen- des améliorations cosmétiques, taires, ce que fait la fonction il est possible de transmettre la ST_Dump (). longueur du tronçon élémentaire en paramètre et de se constituer CREATE TABLE axe AS (WITH sqlt ainsi une fonction très générique AS (SELECT (ST_Dump (geom)). de segmentation linéaire. geom AS geom FROM squelette) Figure 12 : Élimination de la « fourche » SELECT s.geom AS geom FROM en bout de ligne. CREATE OR REPLACE FUNCTION découpe sqlt AS s, boudin AS b WHERE (voie VARCHAR) RETURNS VOID AS $$ ST_Contains (b.geom, ST_Buffer Une fois ce petit nettoyage (s.geom, 30))); accompli, il faut regrouper tous DECLARE les segments en une ligne unique. pk INTEGER := 0; La clause WITH qui précède Pour cela, on va les réunir dans pkf DOUBLE PRECISION; la vraie requête de sélection une multi-géométrie grâce à la long DOUBLE PRECISION; réalise le découpage en tronçons, fonction ST_Union, puis on va tronçons qui sont ensuite triés « recoudre » tous les segments voie_t VARCHAR := voie || ‘_tronçons’; individuellement selon la méthode de cette multi-géométrie en une tmp RECORD; précédemment décrite. La valeur seule ligne grâce à la fonction du buffer, 30, est arbitraire : suff- ST_LineMerge. BEGIN isante pour éviter les éventuelles CREATE TABLE ligne AS (SELECT EXECUTE ‘SELECT CAST ((ST_Length ambiguïtés géométriques, mais ST_LineMerge (ST_Union (geom)) (geom) + 1) / 1000 AS INTEGER) évidemment inférieure à la largeur AS geom FROM axe); FROM ‘|| voie INTO long; du corridor (ici 200). Après cette RAISE NOTICE ‘Longueur du tracé : requête, on se retrouve dans la Il ne reste maintenant qu’une %’, long; situation de la figure 11. opération à réaliser, mais de taille. Il s’agit de découper ce nouveau EXECUTE ‘SELECT true FROM pg_ tables WHERE tablename = ‘’’ || tracé unique et « médian » en tron- voie_t || ‘’’’ INTO tmp; çons d’un kilomètre de longueur (PK). Il n’existe pas, à l’heure IF (tmp.bool) THEN actuelle, de fonction PostGIS qui EXECUTE ‘DROP TABLE “’ permette de réaliser cette opéra- || voie_t || ‘”’; tion (ST_Cut ? ST_Carve ?) END IF; En revanche, il est possible de EXECUTE ‘CREATE TABLE “’ réaliser une « extraction » entre || voie_t || ‘” (‘ || tel et tel PK en utilisant la fonction Figure 11 : Après élimination des segments ‘pk INTEGER,’ || « latéraux », il ne reste plus que l’axe du corridor. ST_Line_Substring (pk1, pk2) ‘pente DOUBLE PRECISION,’ || où les PK doivent être exprimés ‘geom GEOMETRY)’; L’extrémité ouest doit faire l’objet en fraction de la longueur totale d’un traitement particulier. On se (0,5 correspond, par exemple, FOR pk IN 0..long-1 LOOP trouve avec un phénomène « de au point situé à mi-chemin des RAISE NOTICE ‘Calcul du fourche » dû au fait que les deux extrémités). tronçon %’, pk; voies ne se terminent pas stricte- pkf := CAST (pk AS DOUBLE ment au même niveau. On élimine Il n’y a pas donc d’autre solu- PRECISION); cette fourche à la main avec les tion que d’écrire un script en EXECUTE ‘INSERT INTO “’ || outils d’édition de PostGIS déjà langage pl/pgsql pour réal- voie_t || ‘” SELECT ‘ évoqués. iser ce découpage. Ce dernier, || pk || ‘, 0, ‘ || 34 Géomatique Expert|N° 97|Mars-Avril 2014
‘(SELECT ST_LineSubstring de la ligne moins un (long-1), WITH moyennes AS (WITH zone (geom, ‘ || pkf / long et pour chacune d’entre-elles on AS (SELECT ST_DumpAsPolygons || ‘, ‘ || insère dans la table _tronçons la (pente, 1) AS mixed FROM pentes) (pkf + 1) / long || ‘) valeur courante du pk, 0 – valeur SELECT avg ((zone.mixed).val), FROM “’ || voie || ‘”)’; pk FROM zone, ligne_tronçons conventionnelle pour la pente – et WHERE ST_Intersects ((zone. enfin la géométrie correspondant mixed).geom, ligne_tronçons. END LOOP; à la section de ligne comprise geom) GROUP BY pk) UPDATE entre les PK pk et pk+1. ligne_tronçons SET pente = PERFORM Populate_geometry_ moyennes.avg FROM moyennes columns (); WHERE moyennes.pk = ligne_tron- çons.pk; Association finale END; $$ LANGUAGE plpgsql; Il ne reste plus qu’une opération Cette requête, passablement à réaliser : associer à chaque complexe, est composée en Cette fonction n’est pas aisée tronçon la valeur moyenne de réalité de deux sous-requêtes à comprendre, en raison de la pente correspondante. Pour de type WITH et d’une requête l’utilisation systématique de cela, il faut en premier… calculer principale de type UPDATE. La clauses EXECUTE qui permettent la pente ! Pour cela, nous dispo- plus imbriquée (WITH zone AS d’exécuter un texte comme s’il sons de la fonction ST_Slope qui (SELECT… FROM pentes)) s’agissait d’une requête SQL fait partie des fonctions offertes crée une table appelée zone directe. Cette syntaxe peu explic- par PGRaster. contenant la vectorisation de la ite est néanmoins nécessaire à couche raster pentes. Celle-ci partir du moment où l’on souhaite CREATE TABLE pentes AS (SELECT se compose d’une colonne de ST_Slope (geom, 1, ‘32BF’, réaliser une fonction flexible, qui ‘PERCENT’, 1.0, FALSE) AS pente type mixte (structure) composée puisse travailler sur une table au FROM mnt); d’un champ geom contenant nom quelconque. la géométrie et d’un champ Les différents paramètres passés val contenant la valeur du pixel Le bloc DECLARE sert à déclarer à la fonction ST_Slope, à part (donc ici la pente). Autrement dit, les variables qui seront utilisées la colonne géométrique, corre- dans la table zone, on trouve, par la suite. spondent à la bande (il n’y en a pour chaque valeur de la pente qu’une dans notre cas), le type de possible, un (multi-)polygone Les premières lignes du bloc codage utilisé pour représenter correspondant à la réunion de BEGIN calculent et affichent la l’altitude (ici : réels simple préci- tous les pavés de la grille ayant longueur de la ligne stockée dans sion), le type d’unité souhaité cette valeur. la table dont le nom est passé (degrés, radians ou ici pourcent- en paramètre, et l’affectent à la age), un facteur d’échelle et Cette table est utilisée dans la variable long. enfin un booléen qui indique s’il seconde prérequête WITH. faut interpoler là où les données Celle-ci isole toutes les intersec- La requête suivante regarde si manquent. tions entre les différents tronçons la table suffixée par _tronçons et les (multi-)polygones d’iso- existe déjà2. Si oui (dans ce cas, Il serait souhaitable de pouvoir pente, et, pour chaque intersec- la variable tmp.bool vaut TRUE), réaliser le calcul de la pente tion, note la valeur de pente et on l’efface. Puis, dans tous les moyenne en récupérant direct- le PK correspondants, avant de cas, on la crée (ou on la recrée), ement la valeur des cases moyenner les valeurs de pente en la structurant en trois champs : situées « en-dessous » de la par PK (avg ((zone. mixed). le PK, la pente et la géométrie du voie. Cela n’est malheureuse- val) … GROUP BY pk;), puis tronçon kilométrique. ment pas encore possible dans de stocker les résultats dans la cette version de PostGIS. Il faut table moyennes. Enfin, la boucle FOR réalise donc « contourner » cette impos- l’opération de découpage. La vari- sibilité en « vectorisant » la couche Juste avant la requête finale, on able pk prend toutes les valeurs raster grâce à la fonction ST_ se trouve donc avec une table entières entre 0 et la longueur DumpAsPolygon. moyenne contenant deux 2. La suite de quatre apostrophes ’’’’, un peu surprenante, correspond à un caractère ’ lui-même entre apostrophes. La norme SQL précise que si l’on souhaite placer une apostrophe dans une chaîne de caractères, qui doit être elle-même délimitée par des apostrophes, alors il faut redoubler l’apostrophe médiane. ’’’’ équivaut donc à ‘ ’’ ’. Géomatique Expert|N° 97|Mars-Avril 2014 35
Figure 13 : Résultat de l’affectation de la pente moyenne sous-tendant chaque tronçon kilométrique du tracé. champs, l’un donnant le PK, et correction et forcer la pente à zéro l’autre la pente moyenne à ce PK. sous les tunnels, il suffit de repérer Conclusion Il ne reste plus qu’à mettre à jour les tronçons qui intersectent les Nous avons donc parcouru rapi- l’information de pente stockée parties désignées comme tunnel, dement quelques unes des dans la table ligne_tronçons moyennant le fait que notre axe possibilités offertes par l’utilisation précédemment créée en effectuant se trouve légèrement décalé par conjointe des logiciels libres que une jointure par l’intermédiaire du rapport au tracé original (bi-voie). sont QGis et PostGIS avec les PK. Le résultat apparaît figure 13. différentes bibliothèques sur UPDATE ligne_tronçons SET pente lesquelles ils s’appuient : GDAL, = 0 FROM “LGV” WHERE ST_ Nouveau bémol toutefois : notre Intersects (ST_Buffer (ligne_ SFCGAL et CGAL. Dans un couche ne prend pas en compte tronçons.geom, 30), “LGV”.geom) prochain opus, nous nous inté- les passages sous les tunnels. AND “LGV”.tunnel ILIKE ‘yes’; resserons aux problématiques Cette information est contenue 3D et à l’installation du plug-in dans la table originale (tag tunnel La figure 14 montre le résultat final QGis baptisé Horao, également à la valeur yes). Pour effectuer la après reclassification du tronçon. développé par OSLandia. | Figure 14 : Prise en compte du passage en tunnel (pente nulle). On voit clairement que les tunnels correspondent à la traversée de la « Ligne bleue des Vosges ». 36 Géomatique Expert|N° 97|Mars-Avril 2014
Vous pouvez aussi lire