PostGIS 结合Openlayers以及Geoserver实现最短路径分析(二)
前文讲述了怎么用ArcMap制作了测试数据,并导入了PostGIS,接下来我们需要结合PgRouting插件,对入库的数据再进行一下处理。
0、引入扩展包
postgis
pgrouting
postgis_topology
fuzzystrmatch
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: public.pgr_shortestpath(character varying, double precision, double precision, double precision, double precision)
-- DROP FUNCTION public.pgr_shortestpath(character varying, double precision, double precision, double precision, double precision);
CREATE OR REPLACE FUNCTION public.pgr_shortestpath(
tbl character varying,
startx double precision,
starty double precision,
endx double precision,
endy double precision)
RETURNS geometry
LANGUAGE 'plpgsql'
COST 100
VOLATILE STRICT
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 ;
raise notice '%', v_startLine;
raise notice '%', v_endLine;
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
--从开始的起点到结束的起点最短路径
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进行拼接
raise notice '%', v_res;
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$;
ALTER FUNCTION public.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中发布数据并调用
6、后续补充
在代码中提到做ST_Distance时,分别查询了四次查询:
--从开始的起点到结束的起点最短路径
--从开始的终点到结束的起点最短路径
--从开始的起点到结束的终点最短路径
--从开始的终点到结束的终点最短路径
原来在做的时候不是很理解为什么要做这四次查询,是否多余。后来在做带路径的最短路径查询时,有点心得。

实际查询的是A到C,A到D,B到C,B到D
如果不做这步的话,取任意点做路径,万一取到BC或者BD,其实就变成同一个线段了,没有意义了
PostGIS 结合Openlayers以及Geoserver实现最短路径分析(二)的更多相关文章
- PostGIS 结合Openlayers以及Geoserver实现最短路径分析(三)
接上篇,前面在ArcMap中和Postgis中将数据都已经进行了预处理. 接下来回到Geoserver中,进行数据发布. 1.新建工作区 2.填写完工作区信息 3.打开数据存储,添加新的数据存储 4. ...
- PostGIS 结合Openlayers以及Geoserver实现最短路径分析(一)
环境: Win10 ArcMap10.4(用于数据处理) postgresql9.4 postgis2.2.3 pgRouting2.3(postgresql插件) ##附上本文配套素材下载地址:ht ...
- postgresql+postgis+pgrouting实现最短路径查询(2)---openlayers+geoserver实现最短路径
自己的最短路径实现基本上是按照参考博文的1.2和3进行的,实现的时候也是问题不断,只能是一个一个解决. 问题1:自己发布的geoserver服务无法和OSM底图叠加到一起. 解决:参考博文2提到发布服 ...
- Arcgis Engine最短路径分析
ArcEngine 最短路径分析(源码) using System; using ESRI.ArcGIS.Carto; using ESRI.ArcGIS.Geometry; using ESRI ...
- ArcGIS API for JavaScript 4.2学习笔记[27] 网络分析之最短路径分析【RouteTask类】
要说网页端最经典的GIS应用,非网络分析莫属了. 什么?你没用过?百度高德谷歌地图的路线分析就是活生生的例子啊!只不过它们是根据大实际背景优化了结果显示而已. 这个例子使用RouteTask进行网络分 ...
- arcgis api 3.x for js 入门开发系列十三地图最短路径分析(附源码下载)
前言 关于本篇功能实现用到的 api 涉及类看不懂的,请参照 esri 官网的 arcgis api 3.x for js:esri 官网 api,里面详细的介绍 arcgis api 3.x 各个类 ...
- 以Network Dataset(网络数据集)方式实现的最短路径分析
转自原文 以Network Dataset(网络数据集)方式实现的最短路径分析 构建网络有两种方式,分别是网络数据集NetworkDataset和几何网络Geometric Network,这个网络结 ...
- OpenLayers 3+Geoserver+PostGIS实现点击查询
WebGIS开发中,点击查询是最经常使用的一种查询方式,在ArcGIS api 中.这样的查询叫IdentifyTask,主要作用是前台提交參数.交ArcServer查询分析返回. 本文从开源框架的角 ...
- Oracle spatial、openlayers、geoserver开发地理信息系统总结
感谢开源,使用OpenLayers+Geoserver的地理信息系统开发很简单,完全可以套用开发MIS系统的经验,我这里总结为三个步骤: 1.数据准备 2.数据发布 3.数据展现 我将按照这个思路来介 ...
随机推荐
- 百万年薪python之路 -- 装饰器
装饰器 1.1 开放封闭原则 开放封闭原则具体定义是这样: 1.对扩展是开放的 我们说,任何一个程序,不可能在设计之初就已经想好了所有的功能并且未来不做任何更新和修改.所以我们必须允许代码扩展.添加新 ...
- 百万年薪python之路 -- 迭代器
3.1 可迭代对象 3.1.1 可迭代对象定义 **在python中,但凡内部含有 _ _ iter_ _方法的对象,都是可迭代对象**. 3.1.2 查看对象内部方法 该对象内部含有什么方法除了看源 ...
- Sublime Text 3 安装 Package Control 结果返回 275309,找不到 Install Package
打开 Preferences->Settings , 查看 ignored-packages 数组中是否有 Package Control,如果有,删除即可.
- Docker在Linux上 基本使用
简介 Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器上,也可以实现虚拟化,容器是完全使用沙箱机制,相互之间不会有任 ...
- 第二十九章 System V共享内存
共享内存数据结构 共享内存函数 shmget int shmget(key_t key, size_t size, int shmflg); 功能: 用于创建共享内存 参数: key : 这个共享内存 ...
- Vue躬行记(6)——内容分发
Vue提供了一种内容分发技术,可将父组件中的内容传递给子组件的模板,实现方式参照了Web组件规范草案. 一.插槽 Vue内置了一个<slot>元素,能作为插槽(slot)存在,而插槽内可包 ...
- 雷神领域(并查集真是个好东西)并查集+流氓dp
考场上,整整看了半个小时以上的题目!!! 化简题意: 给定一个全0矩阵,一些坐标点(x,y)为1,当三个点可以构成一个直角三角形时(直角边长为整数)拓展为一个矩形,之后从(0,0)出发,求最多的占用行 ...
- Apache服务及个人用户主页功能和密码验证
Apache服务程序中有个默认未开启的个人用户主页功能,能够为所有系统内的用户生成个人网站,确实很实用哦 第1步:开启个人用户主页功能: 1.vim /etc/httpd/conf.d/userdir ...
- C语言程序设计100例之(6):数字反转
例6 数字反转 题目描述 给定一个整数,请将该数各个位上数字反转得到一个新数.新数也应满足整数的常见形式,即除非给定的原数为零,否则反转后得到的新数的最高位数字不应为零(参见样例2). 输入格式 ...
- Java传参-基本数据类型和引用数据类型作为参数的区别(值传递)
java中的方法可以传递参数,参数的传递方法就是值传递. 参数有形参和实参,定义方法时写的参数叫形参,真正调用方法时,传递的参数叫实参. 调用方法时,会把实参传递给形参,方法内部其实是在使用形参. 所 ...