กำลังตัดจุดเชื่อมต่อด้วยคะแนนหรือไม่


10

ฉันกำลังตรวจสอบวิธีที่ดีที่สุดในการตัดการเชื่อมต่อตามจุด

สถานการณ์คือ: ถนนจำนวนมากต้องแบ่งส่วนตามจุดตัดกันแบบนี้:

ตัวอย่าง

ฉันได้

  • ตารางการเคลื่อนไหว (เต็มจุดโดยไม่ได้คะแนน)

  • ตารางคะแนน st_intersection

ฉันต้องได้รับการตัดส่วนที่เป็นอิสระโดยตารางจุดตัด

ฉันใช้ฟังก์ชั่น PostGIS และพบวิธีการต่าง ๆ แต่ทุกคนมีปัญหาบางอย่างให้ฉัน

นี่คือสิ่งที่ฉันทดสอบแล้ว:

1

ตารางเส้น: 1 แถว, st_memunion ของ 1200 บรรทัดตารางจุด: 1,700 แถว (คะแนน)

มีอะไรที่ไม่ดี: ใช้เวลาและหน่วยความจำอย่างมาก ไม่สามารถสร้างหลายตารางพร้อมกันทำให้หน่วยความจำไม่สามารถจัดการได้ และผลลัพธ์ก็สกปรกและยุ่งเหยิง แทนที่จะให้หมายเลขแถวที่ถูกต้องกับฉันและฉันจำเป็นต้องทำความสะอาดในภายหลัง (อธิบายอย่างดีที่นี่แยกบรรทัดที่จุดตัดกัน )

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

ซึ่งมีสิ่งที่ดีที่ไม่ทิ้ง 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
);

แต่ก็เป็นชั่วโมงที่ยาวเป็นพิเศษในการรับผลลัพธ์ และฉันก็ลองกับตารางที่ยาวขึ้น (เส้น 10k, 14k คะแนน) และฉันเพิ่งได้รับปัญหาหน่วยความจำ

ฉันยังลอง ArcGIS ของ Esri ด้วยเช่นกัน ...

ดังนั้นวิธีที่ดีที่สุดในการทำให้สิ่งนี้สำเร็จด้วยฟังก์ชั่น Geom ของ PostGIS คืออะไร

ฉันหมายถึงโดยไม่ต้องก้าวเข้าสู่โทโพโลยี

หรือคำแนะนำที่ดีที่สุดของคุณคืออะไร


1
จุดบัฟเฟอร์ด้วยความอดทนน้อยมากลบ polylines ภายในบัฟเฟอร์สแน็ปอินจุดสิ้นสุดใหม่เข้าด้วยกัน .
Michael Stimson

4
คุณควรใส่การอัปเดตครั้งสุดท้ายเป็นคำตอบเนื่องจากตอบคำถาม
ฟาเอล

เป็นการตอบคำถามตัวเองและสามารถสร้างชื่อเสียงให้คุณเพื่อปลดล็อคการใช้งานเพิ่มเติมในเว็บไซต์นี้
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       ]
...

ตารางที่มี ID บรรทัดและส่วนของความยาวบรรทัดที่มีจุดตัดกับเส้น

จากนั้นฉันก็รวมเศษส่วนทีละคู่เพื่อสร้างเส้นตัดใหม่

Recquirement:

  • ตาราง "คะแนน" มีจุดสิ้นสุดของแต่ละบรรทัด
  • จุดตัดกับเส้นอย่างสมบูรณ์

แบบสอบถาม:

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! ไม่ตรวจสอบอันนี้ด้วย
vlasvlasvlas
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.