PostGIS에서 비 노드 교차 문제를 해결하는 가장 좋은 방법은 무엇입니까?


38

PL/R함수를 사용하고 PostGIS있으며 점 집합 주위에 보로 노이 다각형을 생성 하고 있습니다. 내가 사용하는 기능은 여기 에 정의되어 있습니다 . 특정 데이터 세트에서이 함수를 사용하면 다음 오류 메시지가 나타납니다.

Error : ERROR:  R interpreter expression evaluation error
DETAIL:  Error in pg.spi.exec(sprintf("SELECT %3$s AS id,   
st_intersection('SRID='||st_srid(%2$s)||';%4$s'::text,'%5$s') 
AS polygon FROM %1$s WHERE st_intersects(%2$s::text,'SRID='||st_srid(%2$s)||';%4$s');",  
:error in SQL statement : Error performing intersection: TopologyException: found non-noded 
intersection between LINESTRING (571304 310990, 568465 264611) and LINESTRING (568465 
264611, 594406 286813) at 568465.05533706467 264610.82749605528
CONTEXT:  In R support function pg.spi.exec In PL/R function r_voronoi

오류 메시지의이 부분을 검사하면 다음과 같습니다.

Error performing intersection: TopologyException: found non-noded intersection between
LINESTRING (571304 310990, 568465 264611) and LINESTRING (568465 264611, 594406 286813) 
at 568465.05533706467 264610.82749605528

위의 문제는 다음과 같습니다.

여기에 이미지 설명을 입력하십시오

나는 처음에이 메시지가 동일한 포인트의 존재로 인해 발생할 수 있다고 생각 st_translate()하고 다음 방법으로 사용되는 함수를 사용 하여이 문제를 해결하려고 시도했습니다 .

ST_Translate(geom, random()*20, random()*20) as geom 

이것은 문제를 해결하지만 내 관심사는 지금 x / y 방향으로 ~ 20m까지 모든 포인트를 번역한다는 것입니다. 또한 적절한 번역 금액이 필요한지 알 수 없습니다. 예를 들어 시행 착오를 통해이 데이터 세트에서 a 20m * random number는 괜찮지 만 더 커야하는지 어떻게 알 수 있습니까?

위의 이미지를 바탕으로 문제는 알고리즘이 점을 다각형과 교차하려고하는 동안 점이 선과 교차한다는 것입니다. 점이 선과 교차하지 않고 다각형 내에 있는지 확인하기 위해 무엇을 해야하는지 잘 모르겠습니다. 이 줄에 오류가 발생했습니다.

"SELECT 
  %3$s AS id, 
  st_intersection(''SRID=''||st_srid(%2$s)||'';%4$s''::text,''%5$s'') AS polygon 
FROM 
  %1$s 
WHERE 
  st_intersects(%2$s::text,''SRID=''||st_srid(%2$s)||'';%4$s'');"

이 이전 질문 인 "노드가 아닌 교차로"란 무엇입니까? 이 문제를 더 잘 이해하려고 노력하고 최선의 해결 방법에 대한 조언을 부탁드립니다.


입력이 유효하지 않은 경우 ST_MakeValid ()를 실행하십시오. 그것들이 유효하다면, 엔트로피를 추가하는 것이 현재 사용 가능한 다음 트릭이며 아마도 마지막 트릭입니다.
Paul Ramsey

예, WHERE ST_IsValid(p.geom)처음에 포인트를 필터링하는 데 사용 하고 있습니다.
djq

답변:


30

내 경험상이 문제는 거의 항상 다음과 같은 원인으로 발생합니다.

  1. 좌표의 고정밀도 (43.231499999999996)
  2. 거의 일치하지만 동일하지 않은 라인

ST_Buffer솔루션 의 "너지"접근 방식을 사용하면 # 2를 피할 수 있지만 지오메트리를 1e-6 그리드에 스냅하는 것과 같이 이러한 근본적인 원인을 해결하기 위해 수행 할 수있는 모든 작업을 통해보다 쉽게 ​​생활 할 수 있습니다. 버퍼링 된 지오메트리는 일반적으로 오버랩 영역과 같은 중간 계산에 적합하지만 장기적으로는 근접하지만 문제가되지 않은 문제를 악화시킬 수 있으므로 유지에주의해야합니다.

PostgreSQL의 예외 처리 기능을 사용하면 래퍼 함수를 ​​작성하여 이러한 특별한 경우를 처리하고 필요할 때만 버퍼링 할 수 있습니다. ST_Intersection;에 대한 예는 다음과 같습니다 . 에 비슷한 기능을 사용합니다 ST_Difference. 빈 다각형의 버퍼링 및 잠재적 리턴이 상황에 적합한 지 결정해야합니다.

CREATE OR REPLACE FUNCTION safe_isect(geom_a geometry, geom_b geometry)
RETURNS geometry AS
$$
BEGIN
    RETURN ST_Intersection(geom_a, geom_b);
    EXCEPTION
        WHEN OTHERS THEN
            BEGIN
                RETURN ST_Intersection(ST_Buffer(geom_a, 0.0000001), ST_Buffer(geom_b, 0.0000001));
                EXCEPTION
                    WHEN OTHERS THEN
                        RETURN ST_GeomFromText('POLYGON EMPTY');
    END;
END
$$
LANGUAGE 'plpgsql' STABLE STRICT;

이 방법의 또 다른 이점은 실제로 문제를 일으키는 지오메트리를 정확하게 찾을 수 있다는 것입니다. 블록에 RAISE NOTICE문장을 추가 EXCEPTION하여 WKT를 출력하거나 문제를 추적하는 데 도움이되는 다른 문장을 추가하십시오 .


그것은 영리한 생각입니다. 교차점 문제는 공용체, 차이점, 버퍼 등을 조합하는 동안 나타나는 선 스트링에서 발생하는 것으로 나타났습니다.이 문자열은 모든 것을 버퍼링하거나 모든 것을 덤프하여 다각형 / Mutlipolygons를 선택하여 해결할 수 있습니다. 이것은 흥미로운 접근법입니다.
John Powell

지오메트리를 1e-6 그리드에 스냅하는 것을 언급했지만, 2의 거듭 제곱에 스냅하는 것이 더 나은지 궁금합니다. 부동 소수점 숫자를 사용하는 PostGIS (및 GEOS)이므로 10의 거듭 제곱으로 스냅하면 숫자가 유한 길이 이진 표현을 가질 수 없으므로 실제로 좌표를 크게 자르지 않을 수 있습니다. 그러나 2 ^ -16이라고 말하면 소수 부분을 2 바이트로 자르는 것이 보장됩니다. 아니면 내가 잘못 생각하고 있습니까?
jpmc26

12

많은 시행 착오를 통해 결국 non-noded intersection자체 교차로 문제에서 발생 한다는 것을 깨달았습니다 . 사용을 제안한 스레드를 사용 ST_buffer(geom, 0)하여 문제를 해결할 수 있음 을 발견했습니다 (전반적으로 훨씬 느리게 만듭니다). 그런 다음 ST_MakeValid()다른 기능을 사용하기 전에 형상에 직접 적용 하고 사용하려고했습니다 . 이것은 문제를 강력하게 해결하는 것으로 보입니다.

ipoint <- pg.spi.exec(
        sprintf(
            "SELECT 
                    %3$s AS id, 
                    st_intersection(ST_MakeValid(''SRID=''||st_srid(%2$s)||'';%4$s''::text), ST_MakeValid(''%5$s'', 0)) AS polygon 
            FROM %1$s 
            WHERE 
                ST_Intersects(ST_MakeValid(%2$s::text),ST_MakeValid(''SRID=''||st_srid(%2$s)||'';%4$s''));",
            arg1,
            arg2,
            arg3,
            curpoly,
            buffer_set$ewkb[1]
        )
    )

내 문제를 해결하는 유일한 접근 방법 인 것처럼 이것을 답변으로 표시했습니다.


11

나는이 같은 문제 (Postgres 9.1.4, PostGIS 2.1.1)에 부딪 쳤으며, 나를 위해 일한 유일한 것은 지오메트리를 매우 작은 버퍼로 감싸는 것입니다.

SELECT ST_Intersection(
    (SELECT geom FROM table1), ST_Union(ST_Buffer(geom, 0.0000001))
) FROM table2

ST_MakeValid나에게 효과가 없었고 ST_Node와 의 조합도 없었습니다 ST_Dump. 버퍼는 성능 저하를 초래하지는 않았지만 더 작게 만들면 노드되지 않은 교차 ​​오류가 계속 발생합니다.

추악하지만 작동합니다.

최신 정보:

ST_Buffer 전략은 잘 작동하는 것처럼 보이지만 지오메트리를 지리로 캐스팅 할 때 오류가 발생하는 문제가 발생했습니다. 예를 들어, 점이 원래 -90.0이고 0.0000001로 버퍼링 된 경우 이제 -90.0000001에 있으며 이는 유효하지 않은 지리입니다.

이것은 비록 것을 의미 ST_IsValid(geom)했다 t, ST_Area(geom::geography)반환 NaN많은 기능을.

노드가 아닌 교차로 문제를 피하기 위해 유효한 지리를 유지하면서 다음 ST_SnapToGrid과 같이 사용했습니다.

SELECT ST_Union(ST_MakeValid(ST_SnapToGrid(geom, 0.0001))) AS geom, common_id
    FROM table
    GROUP BY common_id;

6

postgis에서 ST_Node 는 교차점에서 일련의 선을 끊어야하므로 노드가없는 교차점 문제를 해결해야합니다. 이것을 ST_Dump감싸면 파선의 복합 배열이 생성됩니다.

약간 관련이있는 PostGIS : 고급 사용자위한 팁 프레젠테이션에는 이러한 종류의 문제와 해결책이 명확하게 설명되어 있습니다.


훌륭한 프레젠테이션입니다 (@PaulRamsey 덕분에). 어떻게 사용해야 ST_Node하고 ST_Dump? 나는 함수의이 부분 근처에서 그것들을 사용해야한다고 생각하지만 확실하지는 않다. st_intersection(''SRID=''||st_srid(%2$s)||'';%4$s''::text,''%5$s'')in
djq

흠 나는 두 선이 동일한 좌표를 가지고 있다는 것을 알지 못했습니다. 이 좌표를 플로팅하면 교차점이 약 18cm 떨어져 있습니다. 실제로 해결책이 아니라 관찰입니다.
WolfOdrade

st_node여기 에서 어떻게 사용하는지 완전히 명확하지는 않습니다. 이전에 사용할 수 st_intersection있습니까?
djq

1
프리젠 테이션을 더 이상 사용할 수 없습니다. ST_Clip (rast, polygon)을 시도 할 때도 같은 문제가 발생합니다
Jackie

1
@ Jackie : 나는 대답 : PostGIS : Tips for Power Users 에서 프레젠테이션에 대한 링크를 수정했습니다 .
Pete

1

내 경험상 다각형의 꼭짓점 좌표에서 높은 정밀도를 갖는 문제를 해결 한 St_SnapToGrid 함수를 non-noded intersection사용하여 오류 를 해결했습니다.

SELECT dissolve.machine, dissolve.geom FROM (
        SELECT machine, (ST_Dump(ST_Union(ST_MakeValid(ST_SnapToGrid(geom,0.000001))))).geom 
        FROM cutover_automatique
        GROUP BY machine) as dissolve
WHERE ST_isvalid(dissolve.geom)='t' AND ST_GeometryType(dissolve.geom) = 'ST_Polygon';
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.