路径分析—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。
实现效果
手机扫一扫
移动阅读更方便
你可能感兴趣的文章