Вирізання рядків з очками?


10

Я перевіряв найкращий спосіб вирізати рядки на очки.

Сценарій такий: багато вулиць, потрібні сегменти, розрізані точками перетину, такий:

приклад

я зрозумів, я отримав

  • рядок рядків (повна без очок)

  • таблиця точок перетину st_intersection

Мені потрібно отримати відрізки незалежних рядків рядків за таблицею точок перетину.

Я використовую функції PostGIS і знайшов кілька підходів, але кожен з них задає мені певну проблему.

Ось що я вже перевірив:

1

Таблиця рядків: 1 ряд, стільниця 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
);

джерело цього способу / підходу: /programming/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

що добре, що він не залишає брудний_результат, що тоді мені потрібно його почистити. Але вам потрібно 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 к. Рядків, 14 к. Пунктів), і я просто отримую проблеми з пам'яттю.

Я також спробував ArcGIS Esri з поганими результатами ...

Отже, який найкращий спосіб зробити це за допомогою функцій geom PostGIS?

Я маю на увазі, не вступаючи в топологію.

Або яка ваша найкраща рекомендація?


1
точки буфера з дуже малим допуском, стирайте полілінії всередині буферів, з'єднуйте нові кінцеві точки разом. .
Майкл Стімсон

4
Ви повинні поставити остаточне оновлення як відповідь, оскільки воно відповідає на запитання
raphael

Це чудово самостійно відповідати на запитання і може заробити вам репутацію, щоб розблокувати додаткову функціональність на цьому веб-сайті.
PolyGeo

Відповіді:


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       ]
...

Таблиця, яка містить ідентифікатор лінії та частку довжини лінії, де точка перетинає лінію.

Потім я комбіную фракцію по парі, щоб створити нові вирізані лінії

Вимоги:

  • У таблиці "точки" містяться кінцеві точки кожного рядка.
  • Точки ідеально перетинають лінії.

Запит:

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;

приємно! txs! погано перевіряю і цього
власвласвлас
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.