Cắt linestrings với điểm?


10

Tôi đã kiểm tra cách tốt nhất để cắt linestrings bằng điểm.

Kịch bản là: rất nhiều đường phố, cần các đoạn được cắt bởi các điểm giao nhau, loại này:

thí dụ

tôi đã nhận

  • bảng linestrings (đầy đủ không bị cắt bởi điểm)

  • bảng điểm st_intersection

Tôi cần phải lấy các đoạn linestring độc lập được cắt bởi bảng điểm giao nhau.

Tôi đang sử dụng các chức năng của PostGIS và đã tìm thấy một số cách tiếp cận, nhưng mỗi một trong số chúng đều mang đến cho tôi một số vấn đề.

Đây là những gì tôi đã thử nghiệm:

1

Bảng dòng: 1 hàng, st_memunion gồm 1200 dòng Bảng điểm: 1700 hàng (điểm)

Điều tồi tệ: thực sự tốn rất nhiều thời gian và bộ nhớ. Không thể tạo nhiều bảng cùng một lúc khiến bộ nhớ không thể xử lý được. Và kết quả là bẩn và lộn xộn. Thay vì cho tôi số hàng chính xác và tôi cần dọn sạch nó sau (giải thích rõ ở đây Chia dòng tại các điểm giao nhau )

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

nguồn của cách này / cách tiếp cận: /programming/25753348/how-do-i-divide-city-streets-by-intersection-USE-postgis


2

Bảng dòng / điểm giống nhau. Vẫn còn kết quả lộn xộn và cần phải làm sạch này. Vẫn còn nhiều thời gian để hoàn thành truy vấn.

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

nguồn của cách này / cách tiếp cận: Chia dòng tại các điểm giao nhau


3

Tôi cũng tìm thấy chức năng này: https://github.com/Remi-C/PPPP_utilities/blob/master/postgis/rc_Split_Line_By_Points.sql

có một điều tốt là nó không để lại một mớ hỗn độn mà sau đó tôi cần phải dọn dẹp nó. Nhưng bạn cần st_memunion từ cả hai phía (bảng dòng và bảng điểm)

Đó là loại:

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

Nhưng nó cũng siêu giờ để nhận được kết quả. Và tôi cũng đã thử với các bảng dài hơn (10k dòng, 14k điểm) và tôi chỉ nhận được các vấn đề về bộ nhớ.

Tôi cũng đã thử ArcGIS của Esri với kết quả rất tệ ...

Vậy, cách tốt nhất để thực hiện điều này với các hàm geom của PostGIS là gì?

Ý tôi là, không bước vào cấu trúc liên kết.

Hoặc đề nghị tốt nhất của bạn là gì?


1
điểm đệm với dung sai rất nhỏ, xóa các polylines bên trong bộ đệm, gắn các điểm cuối mới lại với nhau. .
Michael Promotionson

4
Bạn nên đặt bản cập nhật cuối cùng làm câu trả lời, vì nó trả lời câu hỏi
raphael

Bạn có thể tự trả lời các câu hỏi và có thể giúp bạn có được danh tiếng để mở khóa chức năng bổ sung trên trang web này.
PolyGeo

Câu trả lời:


5

Đây là cách!

Ok, tôi đã nhận được một phản hồi tuyệt vời từ Remi-C và bây giờ điều này hoạt động như sự quyến rũ:

Giải pháp phi cấu trúc tốt nhất từ ​​trước đến nay .. nó thực sự hoạt động nhanh chóng và dễ dàng (tin tôi đi, tôi đã thử nghiệm rất nhiều cách để làm điều này):

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

Đó là nó!.


1

Ngoài ra, tôi cũng thêm phương thức của riêng mình mà không sử dụng st_split ():

Đối với mỗi dòng tôi kiểm tra nếu có một số điểm giao nhau.

Nếu có, cám dỗ của tôi sẽ như thế này:

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

Một bảng có chứa ID dòng và một phần của độ dài dòng trong đó một điểm giao nhau với dòng.

Sau đó, tôi kết hợp phân số theo cặp để tạo ra các đường cắt mới

Yêu cầu:

  • Bảng "điểm" chứa các điểm cuối của mỗi dòng.
  • Các điểm giao nhau hoàn hảo các dòng.

Truy vấn:

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;

đẹp! txs! tôi cũng sẽ kiểm tra cái này
vlasvlasvlas
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.