PostGIS 结合Openlayers以及Geoserver实现最短路径分析(二)
时间:2019-09-30
本文章向大家介绍PostGIS 结合Openlayers以及Geoserver实现最短路径分析(二),主要包括PostGIS 结合Openlayers以及Geoserver实现最短路径分析(二)使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
前文讲述了怎么用ArcMap制作了测试数据,并导入了PostGIS,接下来我们需要结合PgRouting插件,对入库的数据再进行一下处理。
1、在pgAdmin中,执行下面的sql语句
--添加起点字段source ALTER TABLE zy ADD COLUMN source integer;
--添加终点字段target ALTER table zy add column target integer;
--添加道路权重值字段 ALTER TABLE zy ADD COLUMN length double precision;
--建立拓扑关系,这里会为source和target字段赋值(表明,阈值,要素字段名,主键id) SELECT pgr_createTopology('zy', 0.00001, 'geom', 'gid');
###这里在创建完拓扑,source和target赋值了以后,可以给上一篇文章中创建的点图层预留的Id字段赋值了(参看第5步)
--为source和target字段创建索引(加快查询速度) CREATE INDEX source_idx ON zy("source"); CREATE INDEX target_idx ON zy("target");
--添加线段端点坐标 ALTER TABLE ZY ADD COLUMN x1 double precision; --创建起点经度x1 ALTER TABLE ZY ADD COLUMN y1 double precision; --创建起点纬度y1 ALTER TABLE ZY ADD COLUMN x2 double precision; --创建起点经度x2 ALTER TABLE ZY ADD COLUMN y2 double precision; --创建起点经度y2 --给x1、y1、x2、y2赋值 UPDATE ZY SET x1 =ST_x(ST_PointN(geom, 1)); UPDATE ZY SET y1 =ST_y(ST_PointN(geom, 1)); UPDATE ZY SET x2 =ST_x(ST_PointN(geom, ST_NumPoints(geom))); UPDATE ZY SET y2 =ST_y(ST_PointN(geom, ST_NumPoints(geom)));
--为length赋值(以长度作为权重) UPDATE zy SET length =st_length(geom);
--将长度值赋给reverse_cost,作为路线选择标准(消耗) ALTER TABLE zy ADD COLUMN reverse_cost double precision; UPDATE zy SET reverse_cost = st_length(geom);
2、测试数据,如果执行下面的语句有结果,则表示数据预处理成功
--通过起点号、终点号查询最短路径 --source为线表起点字段名称 --target为线表终点字段名称 --起点终点前后顺序无固定要求 --length为长度字段,也可以使用自己的评价体系 --1、9为测试使用起点号\终点号 --zy表名 --id1经过节点号 --id2经过路网线的gid SELECT seq, id1 AS node, id2 AS edge, cost FROM pgr_dijkstra(' SELECT gid AS id, source::integer, target::integer, length::double precision AS cost FROM zy', 1, 4, false, false);
3、创建最短路径查询函数(核心)
-- Function: pgr_shortestpath(character varying, double precision, double precision, double precision, double precision)
-- DROP FUNCTION pgr_shortestpath(character varying, double precision, double precision, double precision, double precision);
CREATE OR REPLACE FUNCTION pgr_shortestpath(
tbl character varying, startx double precision, starty double precision, endx double precision, endy double precision) RETURNS geometry AS $BODY$
declare 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 --查询离起点最近的线 --3857坐标系 --找起点15米范围内的最近线 execute 'select geom, source, target from ' ||tbl|| ' where ST_DWithin(geom,ST_Geometryfromtext(''point('||startx ||' ' || starty||')'',3857),15) order by ST_Distance(geom,ST_GeometryFromText(''point('|| startx ||' '|| starty ||')'',3857)) 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 ||')'',3857),15) order by ST_Distance(geom,ST_GeometryFromText(''point('|| endx ||' ' || endy ||')'',3857)) 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 ||')',3857)) into v_statpoint; select ST_ClosestPoint(v_endLine, ST_GeometryFromText('point('|| endx ||' ' || endy ||')',3857)) into v_endpoint; -- ST_Distance (下面是否可以直接用pgr_dijkstra函数,不做端点判断,待研究) --从开始的起点到结束的起点最短路径 execute 'SELECT st_linemerge(st_union(b.geom)) ' || 'FROM pgr_kdijkstraPath( ''SELECT gid as id, source, target, length as cost FROM ' || tbl ||''',' ||v_startSource|| ', ' ||'array['||v_endSource||'] , false, false ) a, ' ||tbl|| ' b WHERE a.id3=b.gid GROUP by id1 ORDER by id1' into v_res ; --从开始的终点到结束的起点最短路径 execute 'SELECT st_linemerge(st_union(b.geom)) ' || 'FROM pgr_kdijkstraPath( ''SELECT gid as id, source, target, length as cost FROM ' || tbl ||''',' ||v_startTarget|| ', ' ||'array['||v_endSource||'] , false, false ) a, ' ||tbl|| ' b WHERE a.id3=b.gid GROUP by id1 ORDER by id1' into v_res_b ; --从开始的起点到结束的终点最短路径 execute 'SELECT st_linemerge(st_union(b.geom)) ' || 'FROM pgr_kdijkstraPath( ''SELECT gid as id, source, target, length as cost FROM ' || tbl ||''',' ||v_startSource || ', ' ||'array['||v_endTarget||'] , false, false ) a, ' || tbl || ' b WHERE a.id3=b.gid GROUP by id1 ORDER by id1' into v_res_c ; --从开始的终点到结束的终点最短路径 execute 'SELECT st_linemerge(st_union(b.geom)) ' || 'FROM pgr_kdijkstraPath( ''SELECT gid as id, source, target, length as cost FROM ' || tbl ||''',' ||v_startTarget || ', ' ||'array['||v_endTarget||'] , false, false ) a, ' || tbl || ' b WHERE a.id3=b.gid GROUP by id1 ORDER by id1' 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; raise notice '%', v_res; select ST_Line_Locate_Point(v_res, v_statpoint) into v_perStart; select ST_Line_Locate_Point(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_Line_SubString(v_res,v_perStart, v_perEnd) into v_shPath; raise notice '%', v_shPath; return v_shPath; end; $BODY$ LANGUAGE plpgsql VOLATILE STRICT COST 100; ALTER FUNCTION pgr_shortestpath(character varying, double precision, double precision, double precision, double precision) OWNER TO postgres;
4、测试
在调用函数做测试的时候,遇到ST_Line_Locate_Point时报错:“line_locate_point : 1st arg isnt a line”,查资料解释说是函数第一个参数格式应该是LineString,我检查了一下我的v_res格式,是MultiLineString所以报错。(参考了https://www.jianshu.com/p/4b9d22406bce,在此谢谢作者大大,很详细)
知道原因以后怎么解决呢?还是个头疼的问题。我把查询出来的MultiLineString放到ArcMap中,图形化的显示出来,发现这两段竟然是不连通的两端,最后分析应该是数据不连通导致的,两点间查不到结果,没有最短路径。
在ArcMap中利用网络分析工具(networkAnalyse tool)试了一下也不行,果然是这原因,后来换了两个连通的点查询结果就没问题,所以函数没有问题,结果控制一下就行。
5、至此数据预处理结束了,接下来在下一篇中介绍Geoserver中发布数据并调用
原文地址:https://www.cnblogs.com/giser-s/p/11611655.html
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 微信小程序发送订阅消息的方法(php 为例)
- Laravel5.5 动态切换多语言的操作方式
- Laravel 实现添加多语言提示信息
- Laravel监听数据库访问,打印SQL的例子
- PHP Swoole异步读取、写入文件操作示例
- PHP调用QQ互联接口实现QQ登录网站功能示例
- laravel解决迁移文件一次删除创建字段报错的问题
- laravel 错误处理,接口错误返回json代码
- Thinkphp 3.2框架使用Redis的方法详解
- Laravel validate error处理,ajax,json示例
- PHP 图片合成、仿微信群头像的方法示例
- python写文件时覆盖原来的实例方法
- Laravel 解决419错误 -ajax请求错误的问题(CSRF验证)
- PHP判断当前使用的是什么浏览器(推荐)
- PHP 计算两个时间段之间交集的天数示例