Noktalı linestring kesimi?


10

Linestrings'i noktalarla kesmenin en iyi yolunu kontrol ediyordum.

Senaryo: birçok sokak, kesişme noktaları ile kesilen segmentlere ihtiyaç var, şöyle:

misal

Bende var

  • linestrings (noktalarla kesilmemiş) tablo

  • st_intersection puan tablosu

Kesişme noktaları tablosuyla kesilen bağımsız linestring segmentlerini almam gerekiyor.

PostGIS işlevlerini kullanıyorum ve çeşitli yaklaşımlar buldum, ancak her biri bana bir tür sorun veriyor.

İşte zaten test ettiklerim:

1

Çizgi tablosu: 1 satır, 1200 satır st_memunion Nokta tablosu: 1700 satır (puan)

Kötü olan: Gerçekten çok zaman ve bellek boşalması gerekiyor. Aynı anda birden fazla tablo oluşturulamıyor, çünkü bellek sadece işleyemiyor. Ve sonuç kirli ve dağınık. Bana doğru satır numarasını vermek yerine, daha sonra temizlemem gerekiyor (burada iyi açıklanmıştır Kavşak noktalarındaki çizgileri ayırın )

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

Bu yolun / yaklaşımın kaynağı: /programming/25753348/how-do-i-divide-city-streets-by-intersection-using-postgis


2

Aynı çizgiler / noktalar tablosu. Hala dağınık sonuçlar ve bunu temizlemek gerekiyor. Sorguyu bitirmek için hala çok zaman var.

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

Bu yolun / yaklaşımın kaynağı: Kavşak noktalarındaki çizgileri ayırın


3

Ayrıca bu işlevi buldum: https://github.com/Remi-C/PPPP_utilities/blob/master/postgis/rc_Split_Line_By_Points.sql

hangi bir messy_result bırakmaz iyi bir şey var o zaman onu temizlemek gerekir. Ancak her iki taraftan da st_memunion'a ihtiyacınız var (çizgiler tablosu ve puan tablosu)

Birazcık:

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

Ama aynı zamanda sonuçları almak için çok uzun saatler. Ve ayrıca daha uzun tablolarla (10k satır, 14k puan) denedim ve sadece bellek çıkışı sorunları alıyorum.

Ayrıca Esri'nin ArcGIS'ini de kötü sonuçlarla denedim ...

Peki, bunu PostGIS geom fonksiyonları ile yapmanın en iyi yolu nedir?

Yani, topolojiye adım atmadan.

Ya da en iyi tavsiyen nedir?


1
çok küçük bir toleransla tampon noktaları, tamponların içindeki çoklu çizgileri silin, yeni uç noktaları birbirine oturtun. .
Michael Stimson

4
Son güncellemeyi bir cevap olarak koymalısınız, çünkü soruyu cevaplıyor
raphael

Soruları kendi kendinize cevaplamak iyidir ve bu sitedeki ek işlevlerin kilidini açmak için size itibar kazandırabilir.
PolyGeo

Yanıtlar:


5

Bu yol!

Tamam, Remi-C'den harika bir geri bildirim aldım ve şimdi bu cazibe gibi çalışıyor:

Şimdiye kadarki en iyi topoloji çözümü .. GERÇEKTEN hızlı ve kolay çalışır (inan bana bunu yapmanın birçok yolunu test ettim):

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

Bu kadar!.


1

Ayrıca st_split () kullanmadan kendi yöntemimi de ekliyorum:

Her çizgi için bazı kesişen noktalar olup olmadığını kontrol ediyorum.

Evet ise benim cazibem şöyle görünecektir:

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

Bir noktanın çizgiyle kesiştiği çizgi kimliğini ve çizgi uzunluğunun kısmını içeren bir tablo.

Sonra kesimi çiftle birleştirerek yeni kesik çizgiler oluşturmak için

Recquirement:

  • "Noktalar" tablosu her satırın uç noktalarını içerir.
  • Noktalar çizgileri mükemmel bir şekilde keser.

Sorgu:

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;

Güzel! txs! Ben de bu bir kontrol
vlasvlasvlas
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.