Memotong linestrings dengan poin?

10

Saya sedang memeriksa cara terbaik untuk memotong linestrings dengan poin.

Skenarionya adalah: banyak jalan, perlu bagian dipotong oleh titik potong, semacam ini:

contoh

saya mendapatkan

  • tabel linestrings (penuh tanpa poin)

  • tabel poin st_intersection

Saya perlu memotong segmen linestring independen oleh tabel titik persimpangan.

Saya menggunakan fungsi PostGIS, dan menemukan beberapa pendekatan, tetapi masing-masing dari mereka telah memberi saya semacam masalah.

Inilah yang sudah saya uji:

1

Tabel baris: 1 baris, st_memunion dari 1200 baris Tabel poin: 1700 baris (poin)

Yang buruk: benar-benar membutuhkan banyak waktu dan memori memerah. Tidak dapat membuat beberapa tabel sekaligus karena memori tidak bisa menanganinya. Dan hasilnya kotor dan berantakan. Alih-alih memberi saya nomor baris yang benar, dan saya perlu membersihkannya nanti (dijelaskan dengan baik di sini, Pisahkan garis pada titik persimpangan )

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

sumber cara / pendekatan ini: /programming/25753348/how-do-i-divide-city-streets-by-intersection-using-postgis


2

Tabel garis / titik yang sama. Masih berantakan hasilnya dan perlu dibersihkan ini. Masih banyak waktu untuk menyelesaikan kueri.

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

sumber cara / pendekatan ini: Membagi garis pada titik persimpangan


3

Saya juga menemukan fungsi ini: https://github.com/Remi-C/PPPP_utilities/blob/master/postgis/rc_Split_Line_By_Points.sql

yang memiliki hal baik yang tidak meninggalkan messy_result itu maka saya perlu membersihkannya. Tapi Anda perlu st_memunion dari kedua sisi (tabel garis dan tabel poin)

Ini semacam:

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

Tapi ini juga jam yang sangat lama untuk mendapatkan hasil. Dan saya juga mencoba dengan tabel yang lebih panjang (garis 10k, poin 14k) dan saya hanya mendapatkan masalah memori.

Saya juga mencoba Esri's ArcGIS dengan hasil yang juga buruk ...

Jadi, apa cara terbaik untuk menyelesaikan ini dengan fungsi geom PostGIS?

Maksudku, tanpa melangkah ke topologi.

Atau apa rekomendasi terbaik Anda?

vlasvlasvlas
sumber
1
titik penyangga dengan toleransi yang sangat kecil, hapus polyline di dalam buffer, pasang titik akhir yang baru bersama-sama. .
Michael Stimson
4
Anda harus meletakkan pembaruan terakhir sebagai jawaban, karena itu menjawab pertanyaan
raphael
Tidak apa-apa untuk menjawab pertanyaan sendiri dan dapat memberi Anda reputasi untuk membuka kunci fungsi tambahan di situs ini.
PolyGeo

Jawaban:

5

Ini jalannya!

Ok, saya mendapat tanggapan yang bagus dari Remi-C dan sekarang ini berfungsi seperti pesona:

Solusi non-topologi terbaik yang pernah ada .. ini BENAR-BENAR bekerja dengan cepat dan mudah (percayalah saya telah menguji banyak cara untuk melakukan ini):

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

Itu dia!.

vlasvlasvlas
sumber
1

Saya juga menambahkan, sebagai tambahan, metode saya sendiri, tanpa menggunakan st_split ():

Untuk setiap baris saya periksa apakah ada beberapa titik berpotongan.

Jika ya godaan saya akan terlihat seperti ini:

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

Tabel yang berisi ID garis dan sebagian kecil dari panjang garis tempat sebuah titik memotong garis.

Lalu saya menggabungkan fraksi demi pasangan untuk membuat garis terpotong baru

Penerimaan:

  • Tabel "poin" berisi titik akhir dari setiap baris.
  • Titik-titik tersebut dengan sempurna memotong garis.

Kueri:

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;
Obchardon
sumber
bagus! txs! sakit memeriksa yang satu ini juga
vlasvlasvlas