路径分析—PostgreSQL+GeoServer+Openlayers(二)
阅读原文时间:2023年07月09日阅读:3

路径分析—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 中的函数时,由于不同版本下函数名写法会有些不一样,查看自己所用版本的文档。

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

  1、代码连接数据库查询

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

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

1)、创建数据源

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

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

新建图层

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

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

在 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 的使用参考这里。

实现效果