Si vous avez l’occasion de travailler avec les données cadastrales correspondantes aux Lieux-dits vous constaterez que la cohérence spatiale (topologie) n’est pas respectée:
En effet, chaque lieu-dit a comme limite le bord du chemin attenant, ce qui laisse des espaces vides là où les chemins se trouvent. Si dans certains cas ceci n’est pas un problème, il le devient quand vous ajoutez la couche « Communes » (du même cadastre) à votre carte:
A cette échelle cela ne fait pas très propre, mais si on zoome c’est encore pire
Et si on considère la couche lieux-dits elle-même, on trouve des anomalies topologiques nombreuses:
Nous allons voir ici comment résoudre les deux problèmes:
- Comment corriger la topologie de la couche lieux-dits en supprimant les superpositions de polygones et les espaces vides entre eux;
- Comment recréer une couche communes cohérente avec la nouvelle couche lieux-dits et se superposant exactement aux limites des lieux-dits.
L’exemple ci-après a été réalisé avec les données du cadastre officiel du Département 71, téléchargées à partir du lien https://cadastre.data.gouv.fr/data/etalab-cadastre/2023-01-01/shp/departements/71/
Comment corriger la topologie de la couche lieux-dits
La solution proposée ici nécessite une base de données PostgreSQL avec Postgis. Il est possible de l’adapter à SQLite pour utiliser un fichier geopackage et le DB Manager de QGis. Mais il faut s’attendre à avoir des temps de traitement très longs et à contourner quelques carences et bugs. Nous verrons ici la meilleure des solutions, mais nous présentons la solution avec Geopackage dans un autre article.
1-Créer une couche avec un buffer autour des lieux-dits
Pour gérer les espaces entre polygones, même si certains outils d’accrochage permettent de traiter certains problèmes, il n’en reste pas moins que la solution la plus simple et radicale est de construire un buffer autour des polygones de manière à transformer les espaces vides en superpositions. Dans le cas des lieux-dits, les espaces vides sont de l’ordre de 10m. Nous construisons un buffer de 6m autour des lieux-dits ce qui donnera une superposition de l’ordre de 2-3 mètres minimum.
Choisissez un fichier en sortie permanent au format Geopackage, cela vous permettra de suivre la procédure de l’étape suivante sans modification.
Le résultat de la couche tampon est le suivant:
Nous n’avons plus à gérer des espaces entre les polygones, nous avons seulement des superpositions.
2- Chargez la couche lieux-dits dans PostgreSQL
Vous pouvez suivre le détail de comment charger la couche dans l’article Comment charger un geopackage dans Postgis avec QGis . Vous utilisez la même procédure pour charger des shapefiles.
Et vous retrouvez votre table dans PostreSQL avec pgAdmin
3- Exécuter le script SQL
Nous allons utiliser un seul script pour faire l’ensemble du travail:
- On crée une vue avec deux collections de géométries. Au départ ce sont les polygones des lieux-dits en double exemplaire
- On garde dans une première collection les parties des polygones qui ne se superposent pas avec d’autres
- On garde dans la deuxième collection les parties superposées
- On ajoute au plus petit des deux polygones concernés par la superposition la partie superposée
Voici le script:
DROP TABLE IF EXISTS table_corrigee ;
CREATE OR REPLACE VIEW auto_jointure AS SELECT
tampon.id as id,
tampon.nom as "nom",
tampon.commune as "commune",
-- on récupère tous les polygones de la table tampon dans deux collections : une où on aura les géométries complètes et une autre où on aura les parties superposées. Pour l'instant les deux collections contiennent les géométries complètes.
ST_Union(tampon.geom) AS full_geom,
ST_Union(tampon_bis.geom) AS shared_geom
FROM tampon ,tampon AS tampon_bis
WHERE
--on vérifie la validité des polygones comme précaution
ST_IsValid(tampon.geom) AND ST_IsValid(tampon_bis.geom)
--on filtre pour conserver les polygones qui s'intersectent
AND ST_intersects(tampon.geom,tampon_bis.geom)
--on élimine les polygones en intersection avec eux mêmes
AND tampon.id <> tampon_bis.id
--pour une intersection de 2 polygones, on garde que le plus petit
AND ST_Area(tampon_bis.geom) < ST_Area(tampon.geom)
--puisque l'on fait des "unions”, il faut effectuer un regroupement sur les autres attributs
GROUP BY tampon.id,tampon."nom" , tampon.commune ;
/*
On va créer une table qui va contenir le résultat final : la première étape consiste à enlever toutes les zones de superposition. La deuxième étape consiste à ajouter les zones de superposition au polygone le plus petit des deux. Les trous créés par la première étape sont bouchés par cette deuxième étape. Les polygones finaux soint jointifs, sans superposition ni espace.
*/
CREATE TABLE table_corrigee AS SELECT
id,
"nom",
commune,
/* On soustrait les intersections à la couche contenant tous les polygones; on supprime ainsi les parties en conflits*/
ST_Multi(ST_Difference(full_geom,shared_geom)) as geom,
ST_Area(full_geom) as area
FROM auto_jointure
WHERE ST_IsValid(full_geom) AND ST_IsValid(shared_geom)
/*On doit ensuite rajouter les intersections que l'on vient de soustraire pour remplir les espaces crées.*/
UNION
SELECT
id,
"nom",
commune,
geom,
ST_Area(geom)
FROM tampon
WHERE id NOT IN (SELECT id FROM auto_jointure);
/*On redéfinit ensuite une clé primaire pour que QGIS puisse charger la couche.*/
ALTER TABLE table_corrigee ADD CONSTRAINT pk_table_corrigee PRIMARY KEY (id);
Pour adapter le script à votre cas, vous devez remplacer avec un traitement de texte les éléments suivants:
- toutes les occurrences de tampon par le nom de votre table contenant les lieux_dits bufferisés,
- toutes les occurrences de table_corrigee par le nom de la table résultat que vous souhaitez,
- et vérifiez si l’identifiant de votre table bufferisée est bien id. Par défaut il peut être nommé fid. Dans ce cas remplacez aussi toutes les occurrences de id par fid.
On charge cette nouvelle couche dans QGis:
Nous avons résolu le problème de cohérence topologique des lieux-dits.
Comment recréer une couche communes cohérente avec la nouvelle couche lieux-dits
Si nous superposons à notre nouvelle couche les limites communales du cadastre, nous pouvons constater que celles-ci ne sont pas cohérentes avec nos nouveaux lieux-dits, tout comme elles ne le sont pas avec les lieux-dits d’origine.
Pour obtenir des limites communales cohérentes il suffirait de regrouper les lieux-dits par commune. Le problème est que toute les surfaces communales ne sont pas divisées en lieux-dits. On a donc des « trous » dans la couche lieux-dits qui sont tout à fait normaux.
Pour pouvoir construire des communes complètes, il faut tout d’abord créer les polygones manquants des lieux-dits, en lui affectant le code commune correspondant, puis, seulement en regroupant les lieux-dits par l’attribut commune.
1-Création des polygones manquants
Tout d’abord on va créer une nouvelle couche de polygones, emprise, avec un seul polygone qui entoure complètement notre couche de lieux-dits.
On utilise alors le traitement « Différence » pour ne garder que les zones d’emprise qui ne correspondent pas aux lieux-dits existants dans notre table_corrigée:
Vous pouvez laisser les sorties des traitements en couches temporaires car vous n’aurez pas d’autre utilité après le résultat final.
Le résultat de la différence est:
Le résultat est un seul multipolygone.. Nous devons, avant de continuer, passer cette couche de multipolygone en polygones simples, pour pouvoir supprimer le contour de la zone.
On utilise le traitement de morceaux multiples à morceaux uniques
Une fois le traitement effectué, on passe le résultat en mode édition, on sélectionne le polygone extérieur
Et on le supprime:
Nous avons donc maintenant, une couche Géométries simples qui contient tous les endroits où il n’y a pas de lieux-dits et une couche de lieux-dits corrigés. Nous fusionnons les deux couches en une couche qui n’aura plus de trous:
Il nous reste à régler le problème des attributs des polygones n’étant pas des lieux-dits. Il faut qu’ils aient un attribut contenant le code commune, pour que le regroupement par commune puisse avoir lieu.
Nous allons utiliser la couche communes du cadastre et effectuer une jointure par localisation avec la nouvelle couche fusionnée.
Nous avons maintenant la table jointe:
Sur cette image, vous avez les cinq premiers enregistrements qui correspondent à des zones qui ne sont pas des lieux-dits. L’attribut Commune qui nous intéresse pour l’étape suivante n’est pas renseigné. par contre, l’attribut id2 qui vient de la jointure par localisation avec la couche communes est bien renseigné.
On ouvre la table en mode édition. On sélectionne avec une expression les enregistrements qui n’ont pas l’attribut commune renseigné, puis on ouvre la calculatrice de champs et on fait une mise à jour du champ commune avec le contenu de id2.
Maintenant on peut regrouper les lieux-dits par commune pour obtenir notre couche communes cohérente avec les lieux-dits.
On utilise le traitement Regrouper, avec la couche issue de la jointure que nous venons de modifier.
On a donc nos nouvelles communes. Il nous reste une dernière opération à faire. Comme dans toute opération de regroupement, le résultat affiche des petites scories qu’on doit éliminer:
Pour cela nous utilisons le traitement Supprimer les trous.
N’oubliez pas d’enregistrer le résultat dans un fichier permanent, ce serait dur d’être obligé de tout refaire!
On peut maintenant comparer le résultat de notre nouvelle couche communes avec la couche d’origine
Bonjour,
Merci pour ce tuto très complet.
Avez-vous contrôlé que le résultat du script SQL
génère bien une vraie topologie de nœuds une fois la gestion des recouvrements réalisée à savoir qu’un polygone A partage bien les mêmes nœuds qu’un polygone B en voisinage.
Il existe de nombreuses possibilités de traiter les recouvrements interne à une couche mais certaines ne donne pas le résultat escompté.
Exemple : plugin « clipper » de QGIS dont le résultat donne des polygones encore en recouvrement lorsque l’on fait une « sélection par localisation » après le découpage.
Merci et encore bravo pour le tuto
Dans PostGIS, il existe trois types de représentations pour les données vectorielles. Il y a le modèle géométrique (le plus courant), où chaque géométrie est une unité séparée. Dans le modèle géométrique, les éléments partagés, tels que les limites des surfaces, sont dupliqués dans chaque géométrie. Il y a le modèle géographique qui, à l’instar du modèle géométrique, traite chaque parcelle d’espace comme une unité distincte et dont les frontières sont dupliquées, mais qui considère ces unités dans un espace sphéroïdal. Enfin, il y a le modèle topologique, qui emprunte à la géométrie la vue en 2D du monde, mais avec une différence essentielle. Dans le modèle topologique, les frontières et les zones partagées sont stockées une fois dans la base de données et liées aux géométries qui partagent la frontière. Ces géométries dont les bords sont liés sont appelées « topogeoms ».
Le rsultat du script s’inscrit dans le cadre du modèle géométrique. Mais votre remarque est très pertinente. D’ici la semaine prochaine je publierai une suite pour passer le résultat dans un modèle topologique dans Postgis.
Encore merci!
Un grand merci à vous d’avoir pris le temps de répondre à ma question, c’est très clair et contribue à la bonne compréhension des différents types de représentation en base PostGIS.
Bonne journée.