Postgis 自定义函数解决台风影响范围问题

冷暖自知 提交于 2020-11-19 14:07:13

最近在做船舶运输的相关服务,需要在地图上展示台风行进方向的扇形区域,以及该区域内的船舶,扇形区域的输入参数包括:

  1. 台风行进方向
  2. 扇形半径
  3. 行进方向夹角

由于postgis内置函数并未提供直接构造扇形的功能,所以只能自己实现。思路很简单,利用半径画圆,利用半径和夹角画三角形,利用postgis的重影函数,求得两个对象的重叠部分,即是我们需要的扇形,示意图如下:(需要注意的是,三角形的边长要放大,以免相交后圆弧部分被切掉,这里直接放大一倍)

Postgis 自定义函数解决台风影响范围问题

函数定义如下:

lon,lat代表圆心坐标,radius是扇形半径,drc是

CREATE OR REPLACE FUNCTION "sdc_dw"."fn_sdc_sector"("lon" numeric, "lat" numeric, "radius" numeric, "drc" numeric, "bdc" numeric)
  RETURNS "public"."geography" AS $BODY$
DECLARE
        circle geometry;
    trigle geometry;
    lon1   NUMERIC;
    lat1   NUMERIC;
    lon2   NUMERIC;
    lat2   NUMERIC;
    c1     NUMERIC;
    c2     NUMERIC;
    center TEXT;
    rate   NUMERIC;
        rate2  NUMERIC;
        rate3  NUMERIC;
BEGIN
    --纬度差一度约111/1.8527海里, 经度查一度约111/1.8527海里;
    rate = 111 / 1.8527;
        rate2 = cosd(lat)*0.93;
--      rate2 = 1;
        --半径扩大两倍画三角
        rate3 = 3;
    c1 = (drc + bdc) % 360;
    c2 = (drc - bdc + 360) % 360;
    IF
            c1 >= 0
            AND c1 < 90 THEN
        lon1 = lon + rate3 * radius * sind(c1) / (rate2 * rate);
        lat1 = lat + rate3 * radius * cosd(c1) / rate;

    END IF;
    IF
            c1 >= 90
            AND c1 < 180 THEN
        lon1 = lon + rate3 *  radius * cosd(c1 % 90) / (rate2 * rate);
        lat1 = lat - rate3 * radius * sind(c1 % 90) / rate;

    END IF;
    IF
            c1 >= 180
            AND c1 < 270 THEN
        lon1 = lon - rate3 *  radius * sind(c1 % 90) / (rate2 * rate);
        lat1 = lat - rate3 * radius * cosd(c1 % 90) / rate;

    END IF;
    IF
            c1 >= 270
            AND c1 < 360 THEN
        lon1 = lon - rate3 *  radius * cosd(c1 % 90) / (rate2 * rate);
        lat1 = lat + rate3 * radius * sind(c1 % 90) / rate;

    END IF;
    IF
            c2 >= 0
            AND c2 < 90 THEN
        lon2 = lon + rate3 *  radius * sind(c2) / (rate2 * rate);
        lat2 = lat + rate3 * radius * cosd(c2) / rate;

    END IF;
    IF
            c2 >= 90
            AND c2 < 180 THEN
        lon2 = lon + rate3 * radius * cosd(c2 % 90) / (rate2 * rate);
        lat2 = lat - rate3 * radius * sind(c2 % 90) / rate;

    END IF;
    IF
            c2 >= 180
            AND c2 < 270 THEN
        lon2 = lon - rate3 * radius * sind(c2 % 90) / (rate2 * rate);
        lat2 = lat - rate3 * radius * cosd(c2 % 90) / rate;

    END IF;
    IF
            c2 >= 270
            AND c2 < 360 THEN
        lon2 = lon - rate3 * radius * cosd(c2 % 90) / (rate2 * rate);
        lat2 = lat + rate3 * radius * sind(c2 % 90) / rate;

    END IF;
    IF
        lon1 > 180 THEN
        lon1 = 180 - lon1;

    END IF;
    IF
        lon2 > 180 THEN
        lon2 = 180 - lon2;

    END IF;
    IF
        lon1 < - 180 THEN
        lon1 = - 1 * lon1 - 180;

    END IF;
    IF
        lon2 < - 180 THEN
        lon2 = - 1 * lon2 - 180;

    END IF;
    IF
        lat1 > 90 THEN
        lat1 = 90 - lat1;

    END IF;
    IF
        lat2 > 90 THEN
        lat2 = 90 - lat2;

    END IF;
    IF
        lat1 < - 90 THEN
        lat1 = - 1 * lat1 - 90;

    END IF;
    IF
        lat2 < - 90 THEN
        lat2 = - 1 * lat2 - 90;
--
    END IF;
    center = 'POINT(lon lat)';
    center = REPLACE(center, 'lon', lon :: TEXT);
    center = REPLACE(center, 'lat', lat :: TEXT);
     circle = ST_Buffer(ST_GeomFromText(center,4326)::geography, radius*1.8527*1000) :: geography;
    trigle = ST_Polygon('LINESTRING(' || lon || ' ' || lat || ',' || lon1 || ' ' || lat1 || ',' || lon2 ||
                                        ' ' || lat2 || ',' || lon || ' ' || lat || ')', 4326) :: geography;
    RETURN ST_Intersection(circle, trigle);

END
$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!