postgis+geoserver最短路径

  • 1 安装软件
  • 2 数据预处理
  • 3 操作postgres
  • 4 操作Geoserver
  • 5 计算最短路径
  • 6 问题记录

1 安装软件

安装PostgreSQL与 postgis,以及geoserver。

2 数据预处理

对路网的shapefile数据进行处理:

1、打断相交线。
2、拓扑检查。

以上处理均可以在ArcMap中实现,在此不再详细列出操作步骤。注意如果不打断相交线或不进行拓扑检查,很有可能导致后面无法进行最短路径的计算,建议可以先用简单数据进行实验。

本实验所用的数据为自己绘制的简单数据,数据及属性表如下图所示 :

3 操作postgres

  1. 打开pgAdmin,新建名为simple_road的数据库。

  2. 在simple_road数据库上右键打开CREATE Script,对simple_road数据库增加如下的拓展:
CREATE EXTENSION postgis;
CREATE EXTENSION postgis_topology;
CREATE EXTENSION fuzzystrmatch;
CREATE EXTENSION postgis_tiger_geocoder;
CREATE EXTENSION pgRouting;
CREATE EXTENSION address_standardizer;
  1. 打开postgis shapefile import/export manager工具,进行如下图所示的4个步骤:

    (1)点击“view connection details”连接至postgres的simple_road数据库。

    (2)点击“add file”选择shapefile文件上传,注意设置SRID为4326,Geo_Colunm为geom。

    (3) 点击“options”进入设置,设置编码为“GBK”以支持中文字段,勾选三个选项,注意必须要勾选最后一个选项,将MULIPOLYLINE简化为POLYLINE。

    (4)点击“import”导入数据后,即可在postgres的simple_road数据库中查看到导入的数据。

  2. 继续在CREATE Script中输入代码进行以下的步骤:

(1) 添加路网线段的起止点,存储线段的首尾编号

ALTER TABLE simple_road ADD COLUMN source integer;
ALTER TABLE simple _road ADD COLUMN target integer;

(2)添加路网道路权重值

ALTER TABLE simple_road ADD COLUMN length double precision;

(3)为权重赋值,这里将路段的长度赋值给权重值

UPDATE simple_road SET length = ST_Length(geom);

(4) 回程成本设置,则可支持回程

ALTER TABLE simple_road ADD COLUMN reverse_cost double precision;
UPDATE simple_road SET reverse_cost = length;

(5) 创建拓扑结构(数据量较大时,这一步骤需要等待较长)

SELECT pgr_createTopology('province_road',0.0001, 'geom', 'gid');

(6) 为source和target字段创建索引

CREATE INDEX source_idx ON simple_road ("source");
CREATE INDEX target_idx ON simple_road ("target");

(7) 创建起点经度x1、起点纬度y1、终点经度x2、终点纬度y2

ALTER TABLE simple_road ADD COLUMN x1 double precision;
ALTER TABLE simple_road ADD COLUMN y1 double precision;
ALTER TABLE simple_road ADD COLUMN x2 double precision;
ALTER TABLE simple_road ADD COLUMN y2 double precision;

(8) 给x1、y1、x2、y2复制

UPDATE simple_road SET x1 =ST_x(ST_PointN(geom, 1));
UPDATE simple_road SET y1 =ST_y(ST_PointN(geom, 1));
UPDATE simple_road SET x2 =ST_x(ST_PointN(geom, ST_NumPoints(geom)));
UPDATE simple_road SET y2 =ST_y(ST_PointN(geom, ST_NumPoints(geom)));
  1. 计算任意两点间最短路径的主要思路为:

首先计算距离起点A和终点B最新的路网线段l1和l2,再使用pgr_dijkstra函数计算l1和l2的两线段端点之间的最短路径,也就是l1的起点和终点至l2的起点和终点四种情况的最短路径,求得这四种情况中线段长度最小的情况,然后再在l1求得离起点A最近的点C,以及在l2上离终点B最近的点D,并根据点C、D截取l1和l2,最后将起点A、点C、最短路径、点D、终点B进行拼接,就是起点A到终点B的最短路径。

输入以下代码创建pgr_fromAtoB函数:

-- Function: pgr_fromAtoB(character varying, double precision, double precision, double precision, double precision)
-- DROP FUNCTION pgr_fromAtoB(character varying, double precision, double precision, double precision, double precision);CREATE OR REPLACE FUNCTION pgr_fromAtoB(tbl character varying,startx double precision,starty double precision,endx double precision,endy double precision)RETURNS geometry AS
$BODY$  declare startpoint geometry; -- 起点endpoint geometry; -- 终点star_line geometry; -- 起点到最近线上点的线段end_line geometry; -- 终点到最近线上点的线段 v_startLine geometry;--离起点最近的线 v_endLine geometry;--离终点最近的线 v_startTarget integer;--距离起点最近线的终点 v_startSource 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_se geometry;--开始到结束v_shPath_es geometry;--结束到开始v_shPath geometry;--最终结果tempnode float;
begin--查询离起点最近的线 --4326坐标系--找起点10000000米范围内的最近线execute 'select geom, source, target  from ' ||tbl||' where ST_DWithin(geom,ST_Geometryfromtext(''point('||startx ||' ' || starty||')'',4326), 10000000)order by ST_Distance(geom,ST_GeometryFromText(''point('|| startx ||' '|| starty ||')'',4326))  limit 1'into v_startLine, v_startSource ,v_startTarget; --查询离终点最近的线 --找终点10000000米范围内的最近线execute 'select geom, source, target from ' ||tbl||' where ST_DWithin(geom,ST_Geometryfromtext(''point('|| endx || ' ' || endy ||')'',4326), 10000000)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; --raise notice '%',  v_startSource;  -- 12--raise notice '%',  v_endSource;     -- 3--raise notice '%',  v_startTarget;   -- 1--raise notice '%',  v_endTarget;   -- 6-- 从开始的起点到结束的起点最短路径execute 'SELECT st_linemerge(st_union(b.geom)) ' ||'FROM pgr_dijkstra( ''SELECT gid as id, source, target, length as cost FROM ' ||tbl|| '''::text,' ||'array['||v_startSource||'] , ' ||'array['||v_endSource||'] , false ) a, ' ||tbl|| ' b WHERE a.edge=b.gid' into v_res ; --从开始的终点到结束的起点最短路径execute 'SELECT st_linemerge(st_union(b.geom)) ' ||'FROM pgr_dijkstra( ''SELECT gid as id, source, target, length as cost FROM ' ||tbl|| '''::text,' ||'array['||v_startTarget||'] , ' ||'array['||v_endSource||'] , false ) a, ' ||tbl|| ' b WHERE a.edge=b.gid' into v_res_b ;--从开始的起点到结束的终点最短路径execute 'SELECT st_linemerge(st_union(b.geom)) ' ||'FROM pgr_dijkstra( ''SELECT gid as id, source, target, length as cost FROM ' ||tbl|| '''::text,' ||'array['||v_startSource||'] , ' ||'array['||v_endTarget||'] , false ) a, ' ||tbl|| ' b WHERE a.edge=b.gid' into v_res_c ;--从开始的终点到结束的终点最短路径execute 'SELECT st_linemerge(st_union(b.geom)) ' ||'FROM pgr_dijkstra( ''SELECT gid as id, source, target, length as cost FROM ' ||tbl|| '''::text,' ||'array['||v_startTarget||'] , ' ||'array['||v_endTarget||'] , false ) a, ' ||tbl|| ' b WHERE a.edge=b.gid' into v_res_d ;if(ST_Length(v_res) > ST_Length(v_res_b)) thenv_res = v_res_b;end if;if(ST_Length(v_res) > ST_Length(v_res_c)) thenv_res = v_res_c;end if;if(ST_Length(v_res) > ST_Length(v_res_d)) thenv_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_SetSRID( ST_MakePoint(startx , starty), 4326 )into startpoint;  select ST_SetSRID( ST_MakePoint(endx , endy), 4326 )into endpoint;  select ST_MakeLine( v_statpoint,startpoint) into star_line;   select ST_MakeLine( endpoint,v_endpoint) into end_line;   select st_linemerge(st_union(array[end_line,v_shPath,star_line])) into v_shPath;  return v_shPath; end; $BODY$LANGUAGE plpgsql VOLATILE STRICTCOST 100;
ALTER FUNCTION pgr_fromctod(character varying, double precision, double precision, double precision, double precision)OWNER TO postgres;

4 操作Geoserver

  1. 添加新的数据存储,类型为postgis数据库:


数据源名称为simple_road:

连接的数据库为simple_road,user和password为连接数据库的用户及密码:

其他选项为默认配置,点击最下方的“保存”按钮。

  1. 保存后,选择“配置新的SQL视图”,

    输入视图名称为“new”,SQL语句为
select * from pgr_fromAtoB('simple_road',%x1%, %y1%, %x2%, %y2%)


然后点击下方的“从SQL猜想的参数”,输入默认值为0,验证的正则表达式为*^-?[\d.]+$*

点击下方的“刷新”按钮,在新弹出的栏目中,选择类型为“LineString”,SRI为“4326”:

然后计算数据的边框:

最后点击保存即可。

5 计算最短路径

使用如下url即可获取计算得到的最短路径的geojson格式,其中,参数如下表所示:

参数示例 含义
test geoserver发布的postgis图层的工作区
typeName 工具区:视图名
viewparams x1、y1、x2、y2是最短路径分析的起点和终点,用“ ; ”隔开

http://localhost:8080/geoserver/test/wfs?service=WFS&version=1.1.0&request=GetFeature&typeName=test:new&outputformat=JSON&viewparams=x1:111.882740557158;y1:29.8983406704794;x2:113.047556556274;y2:29.0935587074538

6 问题记录

  1. 使用postgis shapefile import/export manager工具上传shapefile至数据库时,忘记设定SRID为4326。

  2. 网上很多帖子的计算最短路径的函数都存在问题:
    (1)本实验使用的pgrouting为3.0版本,其中pgr_dijkstra函数的参数都为4个,具体函数参数可以在postgres中查看。但是网上贴子中使用的pgr_dijkstra函数的参数都为5个,因此需要进行修改。可参考如下网址中对该函数的介绍,需要注意返回的结果也发生了变化,不再是id、id2等字段表示节点,而是node字段标识节点,edge字段表示边id。

    http://www.mamicode.com/info-detail-2781808.html
    

    (2) 使用时候发现st_linelocatepoint函数参数有时候会报错,报错结果如下图所示,查看使用该函数的传入参数,可以发现传入参数为multilinestring类型,而不是linestring类型。

    继续检查可以发现前面在执行pgr_dijkstra函数的时候,就已经返回了multilinestring,这是因为sql语句里面写了后面的group和order导致在使用st_linemerge并未合并线段,因此需要将所有的group和order删除。

    -- 改写前
    execute 'SELECT st_linemerge(st_union(b.geom)) ' ||
    'FROM pgr_dijkstra(
    ''SELECT gid as id, source, target, length as cost FROM ' ||tbl|| '''::text,' ||'array['||v_startSource||'] , ' ||'array['||v_endTarget||'] , false
    ) a, ' ||tbl|| ' b
    WHERE a.edge=b.gid
    GROUP by edge
    ORDER by edge' into v_res_c ;
    
    -- 改写后
    execute 'SELECT st_linemerge(st_union(b.geom)) ' ||
    'FROM pgr_dijkstra(
    ''SELECT gid as id, source, target, length as cost FROM ' ||tbl|| '''::text,' ||'array['||v_startSource||'] , ' ||'array['||v_endTarget||'] , false
    ) a, ' ||tbl|| ' b
    WHERE a.edge=b.gid' into v_res_c ;
    
  3. 在使用pgr_dijkstra函数计算完最短路径后,还需要在路径上截取起点至终点需要的部分,再将截取的结果与起点、终点拼接起来,得到最后最短路径的结果。必须要截取和拼接,否则返回结果是错误的。

  4. pgsql代码难以调试的时候,可以使用如下方法进行变量的输出,再某行代码查看输出结果,以判断错误。

     raise notice '%',  变量名
    
  5. 在geoserver发布新视图后,点击从数据计算边框的时候,经常会报错。这时候需要拉到页面底部查看错误,此时错误多维pgsql中的错误,可以根据该错误调整函数代码,重新定义函数。

postgis+geoserver最短路径相关推荐

  1. postgis+geoserver+openlayers最短路径分析-学习记录bug

    学习postgis+geoserver+openlayers最短路径分析,记录遇到的奇奇怪怪的问题. 主要参考: https://www.cnblogs.com/giser-s/p/11599562. ...

  2. 用Postgis算最短路径(在任意位置选择起点终点)

    1.前言 阅读本文需要知道什么是shapfile,什么是路径分析,什么是GIS.相比Arcgis的路径分析功能,本文介绍的方法稍微复杂,需要注意的细节更多,但却是完全免费的.PostGis+QGIS+ ...

  3. 使用PostGIS+GeoServer+Openlayer+Vue构建简单的web地图应用

    一.将shx通过postgis导入 1.创建数据库 2.右键–>新建对象–>新建扩展 3.菜单栏点击插件–>打开postgis 也可通过开始菜单 注意点:文件路径不可有中文,文件格式 ...

  4. java gis 最短路径_用Postgis算最短路径(在任意位置选择起点终点)(下)

    今天将上一次路径绘制的坑(上次绘制的是子路径端点的连线)给填了,本文中我将实现一个输入起点和终点经纬度,输出完整路径(包含子路径端点间的真实弯曲情况,完美贴合真实路径)的函数,能够计算准确的路径长度. ...

  5. geoserver的api接口_geoserver api

    介绍了 Geoserver:2.1.3 Pyramid Plugin:2.7.4 FWTools:2.4.7 环境下的影像金字塔模型的发布过程. 使用Geoserver Pyramidal Plugi ...

  6. 开源方案搭建可离线的精美矢量切片地图服务-1.开篇(附成果演示地址)

    系列文章目录 开源方案搭建可离线的精美矢量切片地图服务-1.开篇(附成果演示地址) 开源方案搭建可离线的精美矢量切片地图服务-2.PostGIS+GeoServer矢量切片 开源方案搭建可离线的精美矢 ...

  7. 开源方案搭建可离线的精美矢量切片地图服务-3.Mapbox个性化地图定制入门

    系列文章目录 开源方案搭建可离线的精美矢量切片地图服务-1.开篇(附成果演示地址) 开源方案搭建可离线的精美矢量切片地图服务-2.PostGIS+GeoServer矢量切片 开源方案搭建可离线的精美矢 ...

  8. 开源方案搭建可离线的精美矢量切片地图服务-5.Mapbox离线项目实现

    系列文章目录 开源方案搭建可离线的精美矢量切片地图服务-1.开篇(附成果演示地址) 开源方案搭建可离线的精美矢量切片地图服务-2.PostGIS+GeoServer矢量切片 开源方案搭建可离线的精美矢 ...

  9. 开源方案搭建可离线的精美矢量切片地图服务-6.Mapbox之.pbf字体库

    系列文章目录 开源方案搭建可离线的精美矢量切片地图服务-1.开篇(附成果演示地址) 开源方案搭建可离线的精美矢量切片地图服务-2.PostGIS+GeoServer矢量切片 开源方案搭建可离线的精美矢 ...

最新文章

  1. 百度被曝将成立芯片公司!头部互联网玩家,为何纷纷入局造芯?
  2. python 清空所有对象_Python编程思想(7):列表的增删改操作
  3. 【转】解决:ORA-19602: cannot backup or copy active file in NOARCHIVELOG mode
  4. mysql逗号分隔正则查询_正则表达式在逗号分隔的列表中查找字符串和下一个字符-MySQL?...
  5. 选好财务软件做好企业管理
  6. Scala具体解释---------Scala是什么?可伸展的语言!
  7. c语言第六章条件型循环结构,C语言课件(第六章 循环结构)
  8. 求大素数 - 埃拉托斯特尼筛法
  9. SSAS的MDX中的计算成员和命名集
  10. 梯度下降算法以及线性回归模型
  11. yapi 权限_win10 x64下从0开始搭建YApi可视化接口管理平台
  12. 函数进阶---闭包/装饰器/迭代器/生成器---高级特性
  13. Webservice检查
  14. 课程《设计模式之美》笔记之关于面向对象与面向过程
  15. 银行测试汉字录入软件,小键盘数字练习软件(银行及各行业文员专用)
  16. 快速解决NVivo节点慢的问题!
  17. CM108AH和DP108/DP108T的区别
  18. 大数据工程师面临哪些行业机遇与挑战?
  19. 阿里云DMS添加ECS自建数据库
  20. 一般线性规划求最大值

热门文章

  1. 排查解决 - Linux无法访问百度(公网)?
  2. 如何调用百度卫星地图
  3. 等保2.0.第五章.网络安全产品与方案(中)
  4. 大学计算机类专业按成绩分,那个大学的计算机专业比较好
  5. 为什么要写博客,写博客有什么意义
  6. 云服务器nginx站点主页路径更改方法
  7. 使用socket.io实现强制踢出其他在线账号
  8. xilinx FPGA普通IO作PLL时钟输入
  9. windows下编程控制摄像头的详细介绍
  10. 开始读《Oracle Database 12c Security》