用线切割线串吗?


10

我正在检查按点切割线串的最佳方法。

场景是:很多街道,需要用相交点切开的线段,例如:

例

我有

  • 线串(完全未切分)表

  • st_intersection点表

我需要获取由交点表剪切的独立线串段。

我正在使用PostGIS函数,并发现了几种方法,但是每种方法都给我带来了某种问题。

这是我已经测试过的:

1个

折线表:1行,st_memunion 1200行折点表:1700行(点)

不好的是:确实需要大量时间和内存刷新。无法同时创建多个表,导致内存无法处理。结果是脏乱的。而不是给我正确的行号,我需要稍后进行清理(在这里很好地解释了在相交点处分割线

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
);

这种方式/方法的来源:https : //stackoverflow.com/questions/25753348/how-do-i-divide-city-streets-by-intersection-using-postgis


2

相同的线/点表。仍然凌乱的结果,需要清理。仍然有很多时间来完成查询。

--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)
);

这种方式/方法的来源:在相交点处分割线


3

我也发现了这个功能:https : //github.com/Remi-C/PPPP_utilities/blob/master/postgis/rc_Split_Line_By_Points.sql

这样做的好处是它不会留下messy_result,因此我需要清理它。但是您确实需要两面都使用st_memunion(线表和点表)

有点:

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
);

但是获得结果也要花费很长时间。而且我还尝试使用更长的表(10,000行,14k点),但我刚遇到内存不足的问题。

我也尝试了Esri的ArcGIS,但结果也很糟糕...

那么,用PostGIS geom函数完成此任务的最佳方法是什么?

我的意思是,无需进入拓扑结构。

或您的最佳建议是什么?


1
具有很小公差的缓冲区点,擦除缓冲区内的折线,将新端点对齐。。
Michael Stimson

4
您应该将最终更新作为答案,因为它可以回答问题
raphael

自我回答问题很好,并且可以赢得您的声誉,以解锁该网站上的其他功能。
PolyGeo

Answers:


5

就是这样!

好的,我从Remi-C得到了很好的反馈,现在,它就像魅力一样工作:

有史以来最好的非拓扑解决方案..它的确非常快捷,方便(相信我,我测试了很多方法可以做到这一点):

--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);

而已!。


1

另外,我还添加了自己的方法,而不使用st_split():

对于每一行,我检查是否有一些交叉点。

如果是,我的模板将如下所示:

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

包含线ID和点与线相交的线长度的分数的表。

然后我将分数成对组合以创建新的切割线

要求:

  • 表“点”包含每行的端点。
  • 这些点与线完美相交。

查询:

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;

真好!谢谢!我也要检查这个
-vlasvlasvlas
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.