• 路径分析—PostgreSQL+GeoServer+Openlayers(二)


    路径分析—QGIS+PostgreSQL+PostGIS+pgRouting(一)

    路径分析—PostgreSQL+GeoServer+Openlayers(二)

    前言

    上一篇文章中实现数据库层面的路径分析了,可以在数据库里面通过 SQL 查询到结果。

    本篇文章实现了从前端页面直接可视化操作点选起点、终点,并返回最短路径进行展示。

    一、数据库函数

    在 PostgreSQL 数据库中创建函数,该函数实现的功能是:传入表名、起点、终点经纬度、距离等参数,返回对应的最短距离 geometry。

    创建的函数具体如下:

    复制代码
    -- 删除已经存在的函数(可能会报错,报错的话注释)
    DROP FUNCTION pgr_fromAtoB(tbl varchar,startx float, starty float,endx float,endy float);
     
    -- tbl路网表名
    -- startx起点经度
    -- starty起点纬度
    -- endx终点经度
    -- endy终点纬度
    -- diatance 起点、终点到路径查询的距离
    CREATE OR REPLACE function pgr_fromAtoB(tbl varchar,startx float, starty float,endx float,endy float, distance float)
     
    --限制返回类型
    returns geometry as $body$
    declare
        v_startLine geometry;    -- 离起点最近的线 
        v_endLine geometry;        -- 离终点最近的线 
        
        v_startSource integer;    -- 距离起点最近线的起点
        v_startTarget integer;    -- 距离起点最近线的终点
        v_endSource integer;    -- 距离终点最近线的起点
        v_endTarget integer;    -- 距离终点最近线的终点
        
        v_statpoint geometry;    -- 在v_startLine上距离起点(传入的起点)最近的点 
        v_endpoint geometry;    -- 在v_endLine上距离终点(传入的终点)最近的点 
        
        v_res geometry;            -- 最短路径分析结果
        v_res_a geometry;
        v_res_b geometry;
        v_res_c geometry;
        v_res_d geometry; 
     
        v_perStart float;        -- v_statpoint在v_res上的百分比 
        v_perEnd float;            -- v_endpoint在v_res上的百分比 
        
        v_shPath_ss geometry;    --起点到最近距离点的线
        v_shPath_ee geometry;    --终点到最近距离点的线
        v_shPath geometry;        --最终结果
        
        tempnode float;      
    begin
     
        -- 4326坐标系
        -- 查询离起点最近的线 
        -- 找起点15米范围内的最近线
        execute 'select geom, source, target  from ' ||tbl||
                                ' where ST_DWithin(geom,ST_Geometryfromtext(''point('|| startx || ' ' || starty||')'',4326),'|| distance ||')
                                order by ST_Distance(geom,ST_GeometryFromText(''point('|| startx ||' '|| starty ||')'',4326))  limit 1'
                                into v_startLine, v_startSource ,v_startTarget;
                                
        -- 查询离终点最近的线 
        -- 找终点15米范围内的最近线
        execute 'select geom, source, target from ' ||tbl||
                                ' where ST_DWithin(geom,ST_Geometryfromtext(''point('|| endx || ' ' || endy ||')'',4326),'|| distance ||')
                                order by ST_Distance(geom,ST_GeometryFromText(''point('|| endx ||' ' || endy ||')'',4326))  limit 1'
                                into v_endLine, v_endSource,v_endTarget;
    
        -- 如果没找到最近的线,就返回null
        if (v_startLine is null) or (v_endLine is null) then 
            return null;
        end if ; 
    
        -- 分别找到路径上距离起点和终点最近的点
        select  ST_ClosestPoint(v_startLine, ST_Geometryfromtext('point('|| startx ||' ' || starty ||')',4326)) into v_statpoint; 
        select  ST_ClosestPoint(v_endLine, ST_GeometryFromText('point('|| endx ||' ' || endy ||')',4326)) into v_endpoint;
        
        -- 从开始的起点到结束的起点最短路径
        execute 'SELECT ST_Union(b.geom) ' ||
        'FROM pgr_dijkstra( 
        ''SELECT id, source, target, length as cost FROM ' || tbl ||''',' || v_startSource || ', ' || v_endSource || ' , false ) a LEFT JOIN '
        || tbl || ' b 
        ON a.edge=b.id' into v_res ;
        
        
        --从开始的终点到结束的起点最短路径
        execute 'SELECT ST_Union(b.geom) ' ||
        'FROM pgr_dijkstra( 
        ''SELECT id, source, target, length as cost FROM ' || tbl ||''',' || v_startTarget || ', ' || v_endSource || ' , false ) a LEFT JOIN '
        || tbl || ' b 
        ON a.edge=b.id' into v_res_b ;
        
        --从开始的起点到结束的终点最短路径
        execute 'SELECT ST_Union(b.geom) ' ||
        'FROM pgr_dijkstra( 
        ''SELECT id, source, target, length as cost FROM ' || tbl ||''',' || v_startSource || ', ' || v_endTarget || ' , false ) a LEFT JOIN '
        || tbl || ' b 
        ON a.edge=b.id' into v_res_c ;
        
        --从开始的终点到结束的终点最短路径
        execute 'SELECT ST_Union(b.geom) ' ||
        'FROM pgr_dijkstra( 
        ''SELECT id, source, target, length as cost FROM ' || tbl ||''',' || v_startTarget || ', ' || v_endTarget || ' , false ) a LEFT JOIN '
        || tbl || ' b 
        ON a.edge=b.id' into v_res_d ;
    
        if(ST_Length(v_res) > ST_Length(v_res_b)) then
           v_res = v_res_b;
        end if;
        
        if(ST_Length(v_res) > ST_Length(v_res_c)) then
           v_res = v_res_c;
        end if;
    
        if(ST_Length(v_res) > ST_Length(v_res_d)) then
           v_res = v_res_d;
        end if;
    
        -- 如果找不到最短路径,就返回null (根据实际情况是否需要)
    --     if(v_res is null) then 
    --        return null; 
    --     end if; 
     
        --将 v_res,v_startLine,v_endLine 进行拼接
        select  ST_LineMerge(ST_Union(array[v_res,v_startLine,v_endLine])) into v_res;
        -- 根据起点、终点最近距离点,找到在路径中的百分比
        select  ST_LineLocatePoint(v_res, v_statpoint) into v_perStart;
        select  ST_LineLocatePoint(v_res, v_endpoint) into v_perEnd;
    
        if(v_perStart > v_perEnd) then 
            tempnode =  v_perStart;
            v_perStart = v_perEnd;
            v_perEnd = tempnode;
        end if;
        
        --截取 v_res
        SELECT ST_LineSubstring(v_res,v_perStart, v_perEnd) into v_shPath;
        
        SELECT ST_MakeLine(ST_SetSRID(ST_Point( startx, starty),4326),v_statpoint) into v_shPath_ss;
        SELECT ST_MakeLine(ST_SetSRID(ST_Point( endx, endy),4326),v_endpoint) into v_shPath_ee;
        -- 将 v_shPath、v_shPath_ss、v_shPath_ee 拼接
        select  ST_LineMerge(ST_Union(array[v_shPath,v_shPath_ss,v_shPath_ee])) into v_shPath;
        
        return v_shPath; 
    end;
    $body$ LANGUAGE plpgsql VOLATILE STRICT;
    复制代码

    注意:

      在使用 PostGIS 中的函数时,由于不同版本下函数名写法会有些不一样,查看自己所用版本的文档。

    二、GeoServer SQL View 创建

    在创建完成数据库函数后,有两种方式可以调用:

      1、代码连接数据库查询

      2、GeoServer 中创建图层,以PostGIS为数据源,并创建 SQL View

    因为原先项目中已经有在用 GeoServer,所用直接选用方式2。

    1)、创建数据源

     里面的参数主要有:正常的数据源参数、数据库连接参数等

    2)、创建图层、编辑 SQL View

    新建图层

    编辑 SQL View,在编辑好查询语句后,参数、返回结果都可以自动读出。

     这样一个 PostGIS 数据源的图层就发布好了

    三、Openlayers 调用

    在 openlayers 中调用,主要就是WMS图层的调用,这里主要是参数的传递。

    下面就只贴出调用 WMS 图层,关于其他起始点点击、清空、分析等具体交互就不在这里。

    复制代码
          const params = {
            LAYERS: 'layername',
            VERSION: '1.1.0',
            REQUEST: 'GetMap',
            FORMAT: 'image/png'
          }
        // pathPoint 起点、终点坐标
          const viewparams = [`x1:${this.pathPoint[0][0]}`, `y1:${this.pathPoint[0][1]}`, `x2:${this.pathPoint[1][0]}`, `y2:${this.pathPoint[1][1]}`]
          params.viewparams = viewparams.join(';')
          this.pathLayer = new Image({
            source: new ImageWMS({
              url: `${GEOSERVER_URL}/wms`,
              params
            })
          })
          this.map.addLayer(this.pathLayer)
    复制代码

    这里用的是 ImageWMS。

    关于TileWMS 和 ImageWMS 的使用参考这里。

     

    实现效果

     

  • 相关阅读:
    做项目管理有且有必要了解并学习的重要知识--PMP项目管理
    Dubbo框架基本使用
    FFmpeg进阶:音视频滤镜概述
    PostgreSQL下载和安装教程
    字典常用方法
    NDK 是什么 | FFmpeg 5.0 编译 so 库
    Qt 窗口的尺寸
    如何使用ArcGIS Pro制作标准地图样式国界
    Java数据结构之哈希表
    SpringBoot 过滤器和拦截器
  • 原文地址:https://www.cnblogs.com/zhurong/p/16787057.html