Couper des linestrings avec des points?


10

Je vérifiais la meilleure façon de couper les linestrings par points.

Le scénario est: beaucoup de rues, ont besoin des segments coupés par des points d'intersection, genre de ceci:

exemple

j'ai eu

  • linestrings (plein non coupé par points) table

  • Table des points st_intersection

J'ai besoin que les segments de chaîne de lignes indépendants soient coupés par la table des points d'intersection.

J'utilise les fonctions PostGIS et j'ai trouvé plusieurs approches, mais chacune d'elles me pose un problème.

Voici ce que j'ai déjà testé:

1

Tableau des lignes: 1 ligne, st_memunion de 1200 lignes Tableau des points: 1700 lignes (points)

Ce qui est mauvais: prend vraiment beaucoup de temps et de mémoire. Impossible de créer plusieurs tables en même temps car la mémoire ne peut tout simplement pas la gérer. Et le résultat est sale et désordonné. Au lieu de me donner le bon numéro de ligne, et je dois le nettoyer plus tard (bien expliqué ici Fractionner les lignes aux points d'intersection )

CREATE TABLE lines_with_messy_result AS (
SELECT
((ST_DUMP(ST_SPLIT(a.geom,b.ix))).geom) as geom
FROM st_union_lines a
INNER JOIN lots_of_points b
ON ST_INTERSECTS(a.geom, b.ix)
);

--then need to clean this up
create table lines_segments_cleaned as (
SELECT DISTINCT ON (ST_AsBinary(geom)) 
geom 
FROM 
lines_with_messy_result
);

source de cette voie / approche: /programming/25753348/how-do-i-divide-city-streets-by-intersection-using-postgis


2

Même tableau de lignes / points. Résultats toujours en désordre et besoin de nettoyer cela. Encore beaucoup de temps pour terminer la requête.

--messy table    
Create table messy_lines_segments as 
Select 
row_number() over() as id,
(st_dump(st_split(input.geom, blade.ix))).geom as geom
from st_union_lines input
inner join lots_of_points blade on st_intersects(input.geom, blade.ix);

--then cleaning the messy table
delete from messy_lines_segments a
where exists 
(
select 1 from messy_lines_segments b where a.id != b.id and st_coveredby(b.geom,a.geom)
);

source de cette voie / approche: lignes de séparation aux points d'intersection


3

J'ai également trouvé cette fonction: https://github.com/Remi-C/PPPP_utilities/blob/master/postgis/rc_Split_Line_By_Points.sql

ce qui a la bonne chose qu'il ne laisse pas de résultat désordonné alors j'ai besoin de le nettoyer. Mais vous avez besoin de st_memunion des deux côtés (tableau des lignes et tableau des points)

Il est une sorte de:

create table osm.calles_cortadas_03segmentos_sanluis as (
SELECT result.geom
FROM 
osm.calles_cortadas_01uniones_sanluis AS line, 
osm.calles_cortadas_00intersecciones_sanluis AS point,
rc_split_line_by_points(
input_line:=line.geom
,input_points:=point.ix
,tolerance:=4
) AS result
);

Mais ses heures sont également extrêmement longues pour obtenir les résultats. Et j'ai aussi essayé avec des tables plus longues (10k lignes, 14k points) et j'ai juste des problèmes de mémoire

J'ai aussi essayé ArcGIS d'Esri avec aussi de mauvais résultats ...

Alors, quelle est la meilleure façon de faire cela avec les fonctions Geom de PostGIS?

Je veux dire, sans entrer dans la topologie.

Ou quelle est votre meilleure recommandation?


1
tampons avec une très petite tolérance, effacez les polylignes à l'intérieur des tampons, enclenchez les nouveaux points d'extrémité ensemble. .
Michael Stimson

4
Vous devriez mettre la dernière mise à jour comme réponse, car elle répond à la question
raphael

Il est correct de répondre à vos questions par vous-même et de gagner de la réputation pour débloquer des fonctionnalités supplémentaires sur ce site.
PolyGeo

Réponses:


5

Ceci est le chemin!

Ok, j'ai reçu un excellent retour de Remi-C et maintenant cela fonctionne comme un charme:

La meilleure solution non topologique de tous les temps .. elle fonctionne VRAIMENT rapidement et facilement (croyez-moi, j'ai testé de nombreuses façons de le faire):

--please add this function:
https://github.com/Remi-C/PPPP_utilities/blob/master/postgis/rc_split_multi.sql

-- please create a universal sequence for unique id multipurpose
CREATE SEQUENCE select_id
  INCREMENT 1
  MINVALUE 1
  MAXVALUE 9223372036854775807
  START 1
  CACHE 1
  CYCLE;



-- lines (non st_unioned linestrings, with gist index) : linetable
-- points (non st_unioned points, with gist index) : pointtable

-- first, lines with cuts (pointtable)
create table segment_lines_00 as (
WITH points_intersecting_lines AS( 
   SELECT lines.id AS lines_id, lines.geom AS line_geom,  ST_Collect(points.ix) AS blade
   FROM 
   linetable as lines, 
   pointtable as points
   WHERE st_dwithin(lines.geom, points.ix, 4) = true
   GROUP BY lines.id, lines.geom
)
SELECT lines_id, rc_Split_multi(line_geom, blade, 4)
FROM points_intersecting_lines
);
CREATE INDEX ON segment_lines_00 USING gist(rc_split_multi);


-- then, segments cutted by points
create table segment_lines_01 as (
select 
(ST_Dump(rc_split_multi)).geom as geom,  nextval('SELECT_id'::regclass) AS gid  from segment_lines_00
);
CREATE INDEX ON segment_lines_01 USING gist(geom);

C'est ça!.


1

J'ajoute également, en plus, ma propre méthode, sans utiliser st_split ():

Pour chaque ligne, je vérifie s'il y a des points d'intersection.

Si oui, ma tentation ressemblera à ceci:

[line_id, fraction]
[1      , 0       ]
[1      , 0.3     ]
[1      , 1       ]
[2      , 0       ]
[2      , 0.88    ]
[2      , 1       ]
...

Une table qui contient l'ID de la ligne et la fraction de la longueur de la ligne où un point coupe la ligne.

Ensuite, je combine la fraction par paire pour créer les nouvelles lignes coupées

Recquirement:

  • Le tableau "points" contient les points d'extrémité de chaque ligne.
  • Les points coupent parfaitement les lignes.

La requête:

DROP TABLE IF EXISTS temptable;

CREATE TABLE temptable as 
(
    SELECT ST_LineLocatePoint(a.geom,b.geom) as fraction,a.id, a.geom as shape
    FROM lines a, points b
    WHERE st_intersects(a.geom,b.geom)
    UNION
    SELECT 1 as fraction ,a.id, a.geom as shape -- It avoid to get an incomplete line when the original line is circular
    FROM lines a
    ORDER BY a.id, fraction -- important to keep the same order
);

ALTER TABLE temptable  ADD COLUMN gid SERIAL PRIMARY KEY;

DROP TABLE IF EXISTS LINE_SPLIT;
CREATE TABLE LINE_SPLIT AS
(
SELECT b.fend,a.*, ST_LineSubstring(a.shape,a.fstart,b.fend) as geom
FROM
    (
    SELECT *, fraction as fstart FROM temptable
    LIMIT (SELECT COUNT(*) FROM temptable)-1
    ) a,
    (
    SELECT fraction as fend,gid-1 as gid FROM temptable
    OFFSET 1
    ) b
WHERE a.gid = b.gid
AND a.fstart < b.fend
);

ALTER TABLE LINE_SPLIT DROP COLUMN IF EXISTS shape;
DROP TABLE IF EXISTS temptable;

agréable! txs! mal vérifier celui-ci aussi
vlasvlasvlas
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.