2017-12-06 16 views
1

enter image description here

PostGIS와를 사용하여 그림에서 점에서 두 개의 빨간색 경계선을 결정하는 빠른 방법이 있나요에서 다각형에 대한 탄젠트 (경계) 라인을 결정?

답변

1

예를 들어 사용자 지정 기능으로 here 알고리즘을 적용 할 수 있습니다. 아래는 PostgreSQL/PostGIS로 어떻게 변환 될 수 있는지에 대한 예제입니다 (구현에서는 테스트중인 폴리곤이 하나의 "구성 요소"로만 구성되어 있다고 가정합니다).

CREATE OR REPLACE FUNCTION ST_IsLeft(P0 geometry(POINT), P1 geometry(POINT), P2 geometry(POINT)) RETURNS float AS $$ 
BEGIN 
    RETURN (ST_X(P1) - ST_X(P0))*(ST_Y(P2) - ST_Y(P0)) - (ST_X(P2) - ST_X(P0))*(ST_Y(P1) - ST_Y(P0)); 
END 
$$ LANGUAGE PLPGSQL; 

CREATE OR REPLACE FUNCTION ST_IsAbove(P0 geometry(POINT), Vi geometry(POINT), Vj geometry(POINT)) RETURNS bool AS $$ 
BEGIN 
    RETURN (ST_IsLeft(P0, Vi, Vj) > 0); 
END 
$$ LANGUAGE PLPGSQL; 
CREATE OR REPLACE FUNCTION ST_IsBelow(P0 geometry(POINT), Vi geometry(POINT), Vj geometry(POINT)) RETURNS bool AS $$ 
BEGIN 
    RETURN (ST_IsLeft(P0, Vi, Vj) < 0); 
END 
$$ LANGUAGE PLPGSQL; 

CREATE OR REPLACE FUNCTION ST_TangentLine(P geometry(POINT), polygon geometry(POLYGON)) RETURNS SETOF geometry AS $$ 
DECLARE 
    boundary geometry; 
    Vi geometry; 
    Vr geometry; 
    Vl geometry; 
    N int; 
    i int; 
    ePrev float; 
    eNext float; 
BEGIN 
    N := ST_NPoints(polygon); 
    i := 0; 

    boundary := ST_Boundary(polygon); 

    Vr := ST_PointN(boundary, 1); 
    Vl := Vr; 

    ePrev := ST_IsLeft(ST_PointN(boundary, 1), ST_PointN(boundary, 2), P); 
    FOR i IN 2 .. (N-1) 
    LOOP 
     Vi := ST_PointN(boundary, i); 
     eNext := ST_IsLeft(Vi, ST_PointN(boundary, i+1), P); 

     IF ((ePrev <= 0) AND (eNext > 0)) THEN 
      IF (NOT ST_IsBelow(P, Vi, Vr)) THEN 
       Vr := Vi; 
      END IF; 
     ELSIF ((ePrev > 0) AND (eNext <= 0)) THEN 
      IF (NOT ST_IsAbove(P, Vi, Vl)) THEN 
       Vl := Vi; 
      END IF; 
     END IF; 
     ePrev := eNext; 
    END LOOP; 

    RETURN NEXT ST_MakeLine(P, Vl); 
    RETURN NEXT ST_MakeLine(P, Vr); 
END 
$$ LANGUAGE PLPGSQL; 

DROP TABLE IF EXISTS polygons; 
CREATE TABLE polygons(iid INTEGER, outline GEOMETRY); 
INSERT INTO polygons VALUES (1, ST_GeomFromText('POLYGON((0 0, 1 0, 1 1, 0 1, 0 0))')); 

SELECT iid, ST_AsText(ST_TangentLine(ST_MakePoint(-1, 0.5), outline)) FROM polygons; 

이 다음

iid |  st_astext 
-----+------------------------ 
    1 | LINESTRING(-1 0.5,0 1) 
    1 | LINESTRING(-1 0.5,0 0) 
+0

감사를 반환! 위의 코드에 작은 버그가 있었지만 수정했습니다. 이제 작동합니다. 고맙게도 알고리즘의 세부 사항에 대한 링크를 추가했습니다. 버그를 발견 한 방법입니다. –

+0

@TheunsHeydenrych 잡아 주셔서 감사합니다! 좀 더 철저히 테스트 했어야 했어! :) – ewcz