答案 0 :(得分: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)