1
Q
점
A
답변
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)
감사를 반환! 위의 코드에 작은 버그가 있었지만 수정했습니다. 이제 작동합니다. 고맙게도 알고리즘의 세부 사항에 대한 링크를 추가했습니다. 버그를 발견 한 방법입니다. –
@TheunsHeydenrych 잡아 주셔서 감사합니다! 좀 더 철저히 테스트 했어야 했어! :) – ewcz