선 스트링의 가장 긴 세그먼트 제거 및 세그먼트 재결합
선 스트링에서 가장 긴 세그먼트를 제거하고 그 사이에 가장 짧은 세그먼트로 남아있는 두 세그먼트 그룹을 결합하려고합니다.
선 스트링과 가장 긴 세그먼트 사이에 ST_Difference
(도 ST_Split
작동 함)을 사용하는 것은 쉬웠으며, ST_ShorestLine
결과적으로 두 세그먼트 그룹을 결합하는 데 사용 했습니다.

그러나 주요 세그먼트가 선 스트링의 많은 세그먼트를 교차 할 때 가장 큰 문제를 발견했습니다. ST_Difference
또는 결과 ST_Split
가 두 개 이상의 세그먼트 그룹을 반환합니다 (점 유형 교차도 고려되기 때문).
이로 인해 그룹의 후속 결합이 어려워집니다.

나에게 도움이 될 수있는 것은 ST_Difference
or ST_Split
(또는 다른 함수 인 IDK)가 선 스트링 유형의 교차점 만 고려하지만 올바른 쿼리를 만들 수 없다는 것입니다.
아니면 가장 긴 세그먼트를 제거하고 두 개의 인접한 선 스트링을 다시 결합하는 더 쉬운 방법이 있을까요?
어떤 아이디어?
답변
다음은 솔루션의 첫 번째 부분입니다. SQL은 가장 긴 세그먼트의 양쪽 선 부분을 찾습니다.
WITH data(id, geom) AS (VALUES
( 1, 'LINESTRING (0 0, 1 1, 2.1 2, 3 3, 4 4)'::geometry )
),
longest AS (SELECT i AS iLongest, geom,
ST_Distance( ST_PointN( data.geom, s.i ),
ST_PointN( data.geom, s.i+1 ) ) AS dist
FROM data JOIN LATERAL (
SELECT i FROM generate_series(1, ST_NumPoints( data.geom )-1) AS gs(i)
) AS s(i) ON true
ORDER BY dist LIMIT 1
)
SELECT
CASE WHEN iLongest > 2 THEN ST_AsText( ST_MakeLine(
(ARRAY( SELECT (ST_DumpPoints(geom)).geom FROM longest))[1 : iLongest - 1]
)) ELSE null END AS line1,
CASE WHEN iLongest < ST_NumPoints(geom) - 1 THEN ST_AsText( ST_MakeLine(
(ARRAY( SELECT (ST_DumpPoints(geom)).geom FROM longest))[iLongest + 1: ST_NumPoints(geom)]
)) ELSE null END AS line2
FROM longest;
이 코드에서 유용한 패턴 :
JOIN LATERAL generate_series
선분 추출- 원래 라인의 섹션을 포함하는 하위 라인을 추출하기위한 배열 슬라이싱
(잠재적 인) 두 라인을 연결하기위한 전략이 명확하지 않기 때문에 구현되지 않았습니다.
이 SQL의 일부가 함수 (예 : ST_LineSlice
함수 및 ST_DumpSegments
함수-아마도 언젠가 PostGIS의 일부가 될 것임)에 의해 제공되는 경우 더 명확 할 것입니다.
선이 자기 교차하는 상황에 직면하게 될 사람들을 위해 Postgre / PostGIS SQL에 저의 독창적이고 재미있는 솔루션을 게시합니다.
따라서 초기 상황은 line (LineString EPSG : 4326)이라는 초기 테이블 인 그림에 표시됩니다.

새 원래 함수를 만들고 실행 요청을 시작합니다.
CREATE OR REPLACE FUNCTION ST_SelfIntersectingLineRectifier(
geom GEOMETRY
)
RETURNS GEOMETRY AS
$BODY$
WITH
tbla AS (SELECT (ST_Dump(geom)).geom geom),
tblb AS (SELECT ST_MakeLine(pt1, pt2) geom FROM (SELECT ST_PointN(geom, generate_series(1, ST_NPoints(geom)-1)) pt1,
ST_PointN(geom, generate_series(2, ST_NPoints(geom))) pt2 FROM tbla) AS geom),
tblc AS (SELECT DISTINCT ST_Union(a.geom) geom FROM tblb a, tblb b WHERE ST_Length(a.geom)<ST_Length(b.geom)),
tbld AS (SELECT DISTINCT (ST_Dump(ST_Difference(a.geom, b.geom))).geom geom FROM tblb a JOIN tblc b ON ST_Intersects(a.geom, b.geom)),
tble AS (SELECT ST_MakeLine(ST_LineSubstring(geom, 0.1, 0.9)) geom FROM tbld),
tblf AS (SELECT (a.geom) geom FROM tblb a JOIN tble b ON ST_Intersects(a.geom, b.geom)),
tblg AS (SELECT (a.geom) geom FROM tblf a WHERE NOT EXISTS (SELECT 1 FROM tbld b WHERE ST_Intersects(a.geom, ST_StartPoint(b.geom)))),
tblh AS (SELECT (a.geom) geom FROM tblb a JOIN tbld b ON ST_Touches(a.geom, b.geom) LIMIT 1),
tbli AS (SELECT ST_MakeLine(ST_EndPoint(a.geom), ST_EndPoint(b.geom)) geom FROM tblg a, tblh b)
SELECT ST_Union(geom) geom FROM (SELECT * FROM tblc UNION SELECT * FROM tbli) foo
$BODY$
LANGUAGE SQL
SELECT ST_SelfIntersectingLineRectifier(geom) geom FROM line
아래 그림에서 결과를 볼 수 있습니다.

스크립트는 ST_SelfIntersectingLineRectifier
이 문제를 분석적으로 해결하는 것은 실제로 정말 어렵지만 기하학적으로 해결하는 것은 매우 쉽습니다.
해결책을 찾는 데 도움이 될 절점 또는 선을 정의하는 것이 항상 중요합니다.
"처음에는 당신의 회의에 달려 갔지만 당신은 나를 당신에게서 도망 치도록 강요합니다 ..."🙂
www.DeepL.com/Translator 로 번역됨 (무료 버전)