Makina Blog
Draper des lignes sur un MNT avec PostGIS
Comment obtenir des géométries 3D en drapant des géométries sur un MNT avec PostGIS 2
Dans Geotrek les géométries des tronçons sont saisies en 2D, puis drapées en 3D, afin d'obtenir des informations relatives à l'altimétrie (pente, dénivelées, …)
Nous présentons ici les fonctions PostGIS utilisées pour y parvenir.
Charger le MNT
Si votre Modèle Numérique de Terrain (MNT) est compatible avec GDAL, vous pouvez alors charger le raster très facilement dans la base de données avec les commandes suivantes.
Reprojette vers le SRID spécifié, rogne sur l'étendue spécifiée, et écrit le résultat dans un fichier binaire:
gdalwarp -t_srs EPSG:32632 -te 289942 4845809 400671 4947295 dem_file.geotif output.bin
Découpe en tuiles de 100 pixels et convertit en instructions SQL:
raster2pgsql -c -C -I -M -t 100x100 output.bin mnt > output.sql
Charge le SQL dans la base :
psql -d yourdb < output.sql
Draper les géométries
Il y a pour le moins 3 stratégies pour draper les géométries vers la 3D.
En gardant la résolution des géométries
On obtient une altitude pour chaque point de la ligne.
Avantages: On garde le niveau de définition original (nombre de points)
Inconvénients: On perd potentiellement beaucoup d'information ("sauts")
WITH line AS -- Prendre une ligne arbitraire (SELECT 'SRID=32632;LINESTRING (348595 4889225,352577 4887465,354784 4883841)'::geometry AS geom), points2d AS -- Extraire ses points (SELECT (ST_DumpPoints(geom)).geom AS geom FROM line), cells AS -- Obtenir l'altitude pour chacun d'eux (SELECT p.geom AS geom, ST_Value(mnt.rast, 1, p.geom) AS val FROM mnt, points2d p WHERE ST_Intersects(mnt.rast, p.geom)), -- Instancier des points 3D points3d AS (SELECT ST_SetSRID(ST_MakePoint(ST_X(geom), ST_Y(geom), val), 32632) AS geom FROM cells) - Contruire la ligne 3D depuis les points 3D ELECT ST_MakeLine(geom) FROM points3d;
Selon la résolution du MNT
On obtient une altitude pour chaque cellule du raster.
Avantages: On profite au maximum des informations du MNT
Inconvénients: On augmente énormément la résolution des géométries, parfois pour rien.
WITH line AS -- Prendre une ligne arbitraire (SELECT 'SRID=32632;LINESTRING (348595 4889225,352577 4887465,354784 4883841)'::geometry AS geom), cells AS -- Obtenir l'altitude pour chaque cellule intersectée (SELECT ST_Centroid((ST_Intersection(mnt.rast, line.geom)).geom) AS geom, (ST_Intersection(mnt.rast, line.geom)).val AS val FROM mnt, line WHERE ST_Intersects(mnt.rast, line.geom)), -- Instancier des points 3D, dans l'ordre de la ligne points3d AS (SELECT ST_SetSRID(ST_MakePoint(ST_X(cells.geom), ST_Y(cells.geom), val), 32632) AS geom FROM cells, line ORDER BY ST_Distance(ST_StartPoint(line.geom), cells.geom)) - Construire la ligne 3D depuis les points 3D ELECT ST_MakeLine(geom) FROM points3d;
En échantillonnant
On obtient une altitude par pas de X unités (mètres).
Avantages: On controle la résolution des géométries obtenues
Inconvénients: Parfois difficile un bon compromis selon la longueur des géométries
WITH line AS -- Prendre une ligne arbitraire (SELECT 'SRID=32632;LINESTRING (348595 4889225,352577 4887465,354784 4883841)'::geometry AS geom), linemesure AS -- Ajouter une mesure pour découper selon un pas (ici, de 50) (SELECT ST_AddMeasure(line.geom, 0, ST_Length(line.geom)) as linem, generate_series(0, ST_Length(line.geom)::int, 50) as i FROM line), points2d AS (SELECT ST_GeometryN(ST_LocateAlong(linem, i), 1) AS geom FROM linemesure), cells AS -- Obtenir l'altitude pour chacun d'eux (SELECT p.geom AS geom, ST_Value(mnt.rast, 1, p.geom) AS val FROM mnt, points2d p WHERE ST_Intersects(mnt.rast, p.geom)), -- Instancier des points 3D points3d AS (SELECT ST_SetSRID(ST_MakePoint(ST_X(geom), ST_Y(geom), val), 32632) AS geom FROM cells) - Construire la ligne 3D ELECT ST_MakeLine(geom) FROM points3d;
En tant que fonction PostgreSQL
Il est possible d'enfermer tout ce code dans une fonction :
CREATE OR REPLACE FUNCTION drape(line geometry) RETURNS geometry AS $$ DECLARE line3d geometry; BEGIN WITH … … … … SELECT ST_MakeLine(geom) INTO geom3d FROM points3d; RETURN geom3d; END; $$ LANGUAGE plpgsql;
Et draper les géométries d'une table:
-- Ajouter une colonne ALTER TABLE yourtable ADD COLUMN geom_3d geometry(LineStringZ, 32632);
-- geom_3d avec la version drapée UPDATE yourtable SET geom_3d = drape(geom);
Formations associées
Formations Outils et bases de données
Formation PostgreSQL
Nantes Du 11 au 13 décembre 2024
Voir la formationFormations SIG / Cartographie
Formation PostGIS
À distance (FOAD) Du 9 au 13 décembre 2024
Voir la formationFormations SIG / Cartographie
Formation QGIS
À distance (FOAD) Du 2 au 6 décembre 2024
Voir la formationActualités en lien
Nouvelle Journée Technique du PRNSN : le numérique dans les pratiques sportives de nature
Le 27 novembre 2024, Montpellier accueille la 18e Journée technique du réseau national des sports de nature, organisée par le PRNSN.
Mini-guide à l’usage des collectivités : l’Open Data, entre nécessité et opportunité
Tout ce que vous avez toujours voulu savoir sur l’Open Data. Petit guide à destination des collectivités pour l’appréhender et se l’approprier.
Une rentrée riche autour de la donnée et des rencontres pour Makina Corpus Territoires
Chaque rentrée apporte son lot d’opportunités pour faire avancer les projets autour de la données au service des territoires. Le calendrier de Makina Corpus en la matière a été particulièrement dense en événements.