Nous reprenons ici l’exemple traité dans l’article Éliminer les superpositions et les espaces entre polygones dans une couche(avec QGis et Postgis) pour voir le même type de solution quand vous ne disposez pas d’une base de données PostgreSQL/Postgis. Nous allons utiliser ici seulement les possibilités offertes par QGis en travaillant sur un format de données Geopackage.
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 le premier problème : Comment corriger la topologie de la couche lieux-dits en supprimant les superpositions de polygones et les espaces vides entre eux.
Pour le deuxième problème : Comment recréer une couche communes cohérente avec la nouvelle couche lieux-dits et se superposant exactement aux limites des lieux-dits, référez-vous à l’article cité plus haut (Éliminer les superpositions et les espaces entre polygones dans une couche(avec QGis et Postgis), car cette partie utilise simplement QGis et Geopackage.
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 ne nécessite pas d’une base de données PostgreSQL/Postgis. Par contre, étant donné quelques limitations de SQLite3 et un bug du DB Manager de QGis 3.30,on aura quelques manipulations supplémentaires. Il faut aussi s’attendre à avoir des temps de traitement longs, raison pour laquelle il n’est pas adapté au traitement de couches trop importantes.
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.
Choisissez un fichier en sortie permanent au format Geopackage, cela vous permettra de suivre la procédure de l’étape suivante directement 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- Ouvrez le DataBase Manager de QGis
Vous aurez la fenêtre du DB Manager
Si votre fichier geopackage n’apparaît pas dans les fichiers listés, cliquez-droit sur Geopackage->Nouvelle connexion et chargez -le.
Cliquez sur la couche bufferisée dans l’étape précedente, puis sur le Menu Base de données ->Fenêtre SQL.
3- Exécuter les lignes du script SQL
L’ensemble des lignes du script suivant correspondent aux tâches suivantes
- 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
- Pour finir, on ajoute au plus petit des deux polygones concernés par la superposition la partie superposée
Contrairement à la fenêtre SQL de pgAdmin et PostgreSQL/Postgis, dans la fenêtre SQL de DB Manager vous devez exécuter requête par requête.
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.
Voici les lignes du script:
Première requête (si vous avez déjà exécuté le script)
DROP TABLE IF EXISTS table_corrigee ;
Deuxième requête(si vous avez déjà exécuté le script)
DROP VIEW auto_jointure;
Troisième requête
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 ;
Quatrième requête
/*
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 sont 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);
Résolution des problèmes de DB Manager
Après l’exécution des requêtes, vous serez surpris de ne pas voir apparaître ni le stables ni les vues crées lors des scripts dans la liste des tables du Geopackage.
Et pourtant, si vous tapez une requête faisant référence aux tables des scripts, elles fonctionnent. Les tables sont bien quelque part, mais DB Manager ne les voit pas… C’est un bug, connu et reconnu, et…assumé! Comme les développeurs de QGis préparent un remplaçant de DB Manager, le Data Source Manager, ils n’ont pas l’intention de résoudre ce problème.
Bref!, si on ne peut pas résoudre le problème, on peut le contourner.
Avec le DB Manager nous allons créer une table, avec l’option standard
Et nous créons une table avec les mêmes champs que la couche bufferisée
Celle-ci apparaît dans la liste des tables du geopackage
Maintenant,il suffit de charger le résultat de notre script dans cette table « officielle » avec la requête SQL suivante:
insert into recup
select fid,geom,nom,commune from lieux_dits_corr
On charge cette nouvelle couche dans QGis:
Nous avons résolu le problème de cohérence topologique des lieux-dits.
Pour les puristes, une dernière explication du problème de l’affichage des tables dans DB Manager.
Le problème ne vient pas de QGIS, mais du standard de géopackage.
OGR (et qgis) ne recherchent que des tables dans la table gpkg_contents. Pour qu’elles soient donc visibles, il faut ajouter une nouvelle ligne dans ces tables :
INSERT INTO gpkg_contents (table_name, data_type) values (table_name,'attributes'). # attributes or features (if geometry); INSERT INTO gpkg_geometry (table_name, column_name, geometry_type_name, srs_id, z, m) (table_name, 'geom', 'Point', 4326, 1, 1); |
Mais on pourrait s’attendre à que dans ce cas, QGIS DB Manager exécute ces requêtes automatiquement.