Alignement des nœuds de début et de fin de lignes sur d'autres lignes dans PostGIS

9

Il existe de nombreux exemples qui montrent comment accrocher des lignes à des points, mais je n'ai pas trouvé de moyen (rapide!) D'aligner les nœuds de début et de fin des chaînes de lignes sur les nœuds d'autres lignes.

Essentiellement, je veux «nettoyer» mon calque dans Postgis (2.0), en rapprochant des points presque similaires et en cousant de minuscules ouvertures entre les chaînes de lignes.

Peu importe que j'ajoute un autre nœud, que je déplace le premier / dernier nœud de l'une des lignes ou que je déplace les deux points au centre.

J'ai trouvé deux options, mais je ne sais pas comment commencer avec l'une ou l'autre:

La deuxième option semble faisable, mais toute aide sur la façon de suivre cette méthode serait grandement appréciée.

Jelmer Baas
la source

Réponses:

6

J'ai réussi à résoudre ce problème, sans utiliser les outils GRASS mentionnés ou les fonctions topologiques.

Fondamentalement, je prends tous les nœuds de début et de fin, les place dans une nouvelle table temporaire, place un tampon autour d'eux, union les objets tampon et déplace tous les nœuds trouvés dans chaque tampon vers le centroïde du tampon.

Une fois cela fait, je déplace les points de début et de fin d'origine vers le nouvel emplacement.

Plus facile que prévu et toujours rapide, mais je m'attendais à ce que PostGIS ait une fonction intégrée pour cela - ce serait encore plus rapide.

Edit: dans l'intérêt de redonner à la communauté, c'est mon code (assez merdique) pour l'instant.

drop table if exists nodes;
drop table if exists nodes2;
drop table if exists buffers;

-- Get Start and End nodes
select ST_StartPoint(wkb_geometry) startnode,  ST_EndPoint(wkb_geometry) endnode,    ogc_fid into nodes  from sourceTable;
-- Combine all nodes into one table for easier queries
select startnode node, ogc_fid into nodes2 from nodes;
insert into nodes2 select endnode node, ogc_fid from nodes;

-- Some indexes to speed everything up
CREATE INDEX nodesstart_idx ON nodes USING gist  (startnode);
CREATE INDEX nodesend_idx ON nodes USING gist  (endnode);
CREATE INDEX nodes2_idx ON nodes2 USING gist  (node);
CREATE INDEX nodes_ogcfid_idx ON nodes USING btree (ogc_fid ASC NULLS LAST);

-- Create buffers, combine them, split combined objects again
select (ST_Dump(ST_Union(ST_Buffer(node, 1)))).geom geom into buffers from nodes2;
CREATE INDEX buffers_idx ON buffers USING gist  (geom);

-- Update start/end nodes table
UPDATE nodes SET startnode = ST_Centroid((select geom from buffers WHERE geom && startnode));
UPDATE nodes SET endnode = ST_Centroid((select geom from buffers WHERE geom && endnode));
-- Update original points
update sourceTable set wkb_geometry = ST_SetPoint(
ST_SetPoint(wkb_geometry, 0, (select startnode from nodes where ogc_fid=sourceTable.ogc_fid)), 
ST_NumPoints(wkb_geometry) - 1, (select endnode from nodes where ogc_fid=sourceTable.ogc_fid));

DROP TABLE nodes;
DROP TABLE nodes2;
DROP TABLE buffers;
Jelmer Baas
la source
Cette réponse ressemble un peu à la suggestion "non topologique" de ma réponse. Il serait bon que vous donniez un vote positif ou que vous choisissiez la réponse. Voilà ce qui nourrit la communauté ici :)
katahdin
Tu as raison. J'ai voté pour votre réponse et modifierai ma réponse pour inclure mon code.
Jelmer Baas
4

Voici trois options. Si tout va bien on aidera.

v.clean

À l'aide des outils GRASS de QGIS, vous pouvez nettoyer la topologie d'un objet spatial. L'utilisateur @RK donne un bon ensemble d'instructions sur la façon de procéder dans une réponse à une question différente . L'avantage de GRASS est qu'il permet de déduire la topologie du fichier de formes. L'inconvénient de votre situation est que vos données ne sont pas dans un fichier de formes. Bien sûr, vous pouvez exporter les données de Postgres dans un fichier de formes à l'aide de l'outil "Ajouter une couche PostGIS", mais c'est une étape supplémentaire.

Fonctions PostGIS non topologiques

Dans PostGIS, vous pouvez utiliser les fonctions ST_EndPoint et ST_StartPoint pour obtenir le point de fin et de début d'une chaîne de lignes. Ensuite, en utilisant une combinaison de ST_DWithi n et ST_Distance , vous pouvez trouver le point de début ou de fin le plus proche sur une géométrie proche. Si vous avez beaucoup de points, ST_DWithin accélérera beaucoup la requête - en supposant que vous avez un index en place. À partir de là, vous devrez établir une règle qui définit les points à modifier et ceux qui sont fixes.

L'avantage ici est que vous n'avez pas à envoyer vos données à GRASS pour le nettoyage, mais il y a quelques pièges à surveiller.

Fonctions topologiques PostGIS

La question faisait référence aux fonctions topologiques de PostGIS. Cela fonctionne très bien, mais, comme le décrit le wiki , vous devez définir explicitement les arêtes, les nœuds et les faces. De toute évidence, ce sera un problème pour votre ensemble de données car vous avez des problèmes connus avec la topologie.

katahdin
la source
1

PostGIS a des fonctions de capture. Peut-être qu'elles aideront?

ST_Snap: Accrochez les segments et les sommets de la géométrie en entrée aux sommets d'une géométrie de référence.

ST_SnapToGrid: Accrochez tous les points de la géométrie en entrée sur une grille standard.

Jordan Arseno
la source
1
Merci, je connais ces fonctions. ST_Snap snaps TOUS les nœuds, je veux seulement le nœud de début et de fin. ST_SnapToGrid n'est pas vraiment adapté car il modifie toute la géométrie existante et a une chance de déplacer des nœuds plus proches, car ils tombent à peine dans un autre segment.
Jelmer Baas