zoukankan      html  css  js  c++  java
  • GeoServer+PostgreSQL+PostGIS+pgRouting实现最短路径查询

    一、软件安装

    GeoServer下载地址:

    http://geoserver.org/download/

    PostgreSQL下载地址:

    https://www.postgresql.org/download/

    paAdmin3下载地址:

    https://www.pgadmin.org/download/pgadmin-3-windows/

    PostGIS下载地址:

    http://postgis.net/windows_downloads/

    pgRouting已经包含在安装程序中。

    所有下载程序如下:

     

    安装过程不再详述。

     

    二、数据制作

    我使用的是ArcMap来绘制路网数据,也可以使用其它的GIS软件,但好像没有这么方便,地理坐标系使用GCS_WGS_1984,编号为:4326。

     

    注意:所有线段连接的地方都需要断开,这样便于以后的分析。

     

    三、数据处理

    使用paAdmin3连接PostgreSQL,并执行以下语句,在新的空间数据库里添加空间扩展:

    CREATE EXTENSION postgis;

    CREATE EXTENSION pgrouting;

    CREATE EXTENSION postgis_topology;

    CREATE EXTENSION fuzzystrmatch;

    CREATE EXTENSION postgis_tiger_geocoder;

    CREATE EXTENSION address_standardizer;

    制作完路网数据后,需要使用 来把路网数据导入到PostgreSQL中去。

     

    点击“View connection details....”在弹出的窗口中填入PostgreSQL的账号和密码,以及Database。

    连接成功后,需要设置一下“Optionns...”

     

    需要使用GBK编码,并勾选最下面一个选项。

    添加路网数据,并设置SRID为:4326

     

    导入完成后,会在数据库中创建一个对应的表:

     

    在查询表中分别执行下列SQL,对表结构进行修改:

    1.修改表结构

    --添加起点id

    ALTER TABLE public.road_xblk ADD COLUMN source integer;

    --添加终点id

    ALTER TABLE public.road_xblk ADD COLUMN target integer;

    --添加道路权重值

    ALTER TABLE public.road_xblk ADD COLUMN length double precis

     

    2.创建拓扑结构                  

    --为sampledata表创建拓扑布局,即为source和target字段赋值

    SELECT pgr_createTopology('public.road_xblk',0.0001, 'geom', 'gid');

     

    3.创建索引

    --为source和target字段创建索引

    CREATE INDEX source_idx ON road_xblk("source");

    CREATE INDEX target_idx ON road_xblk("target");

     

    4.给长度赋值

    --为length赋值

    update road_xblk set length =st_length(geom);

    --为road_xblk表添加reverse_cost字段并用length的值赋值

    ALTER TABLE road_xblk ADD COLUMN reverse_cost double precision;

    UPDATE road_xblk SET reverse_cost =length;

     

    5.创建最短路径函数

    ---创建查询随意两点之前的最短路径的函数

      1 DROP FUNCTION pgr_fromAtoB(tbl varchar,startx float, starty float,endx float,endy float);
      2 
      3 CREATE OR REPLACE function pgr_fromAtoB(tbl varchar,startx float, starty float,endx float,endy float)  
      4 
      5 returns geometry as 
      6 
      7 $body$  
      8 
      9 declare 
     10 
     11     v_startLine geometry;--离起点最近的线 
     12 
     13     v_endLine geometry;--离终点最近的线 
     14 
     15      
     16 
     17     v_startTarget integer;--距离起点最近线的终点
     18 
     19     v_startSource integer;
     20 
     21     v_endSource integer;--距离终点最近线的起点
     22 
     23     v_endTarget integer;
     24 
     25  
     26 
     27     v_statpoint geometry;--在v_startLine上距离起点最近的点 
     28 
     29     v_endpoint geometry;--在v_endLine上距离终点最近的点 
     30 
     31      
     32 
     33     v_res geometry;--最短路径分析结果
     34 
     35     v_res_a geometry;
     36 
     37     v_res_b geometry;
     38 
     39     v_res_c geometry;
     40 
     41     v_res_d geometry; 
     42 
     43  
     44 
     45     v_perStart float;--v_statpoint在v_res上的百分比 
     46 
     47     v_perEnd float;--v_endpoint在v_res上的百分比 
     48 
     49  
     50 
     51     v_shPath_se geometry;--开始到结束
     52 
     53     v_shPath_es geometry;--结束到开始
     54 
     55     v_shPath geometry;--最终结果
     56 
     57     tempnode float;      
     58 
     59 begin
     60 
     61     --查询离起点最近的线 
     62 
     63     execute 'select geom, source, target  from ' ||tbl||
     64 
     65                             ' where ST_DWithin(geom,ST_Geometryfromtext(''point('||         startx ||' ' || starty||')'',4326),15)
     66 
     67                             order by ST_Distance(geom,ST_GeometryFromText(''point('|| startx ||' '|| starty ||')'',4326))  limit 1'
     68 
     69                             into v_startLine, v_startSource ,v_startTarget; 
     70 
     71      
     72 
     73     --查询离终点最近的线 
     74 
     75     execute 'select geom, source, target from ' ||tbl||
     76 
     77                             ' where ST_DWithin(geom,ST_Geometryfromtext(''point('|| endx || ' ' || endy ||')'',4326),15)
     78 
     79                             order by ST_Distance(geom,ST_GeometryFromText(''point('|| endx ||' ' || endy ||')'',4326))  limit 1'
     80 
     81                             into v_endLine, v_endSource,v_endTarget; 
     82 
     83  
     84 
     85     --如果没找到最近的线,就返回null 
     86 
     87     if (v_startLine is null) or (v_endLine is null) then 
     88 
     89         return null; 
     90 
     91     end if ; 
     92 
     93  
     94 
     95     select  ST_ClosestPoint(v_startLine, ST_Geometryfromtext('point('|| startx ||' ' || starty ||')',4326)) into v_statpoint; 
     96 
     97     select  ST_ClosestPoint(v_endLine, ST_GeometryFromText('point('|| endx ||' ' || endy ||')',4326)) into v_endpoint; 
     98 
     99    
    100 
    101    -- ST_Distance 
    102 
    103      
    104 
    105     --从开始的起点到结束的起点最短路径 
    106 
    107     execute 'SELECT st_linemerge(st_union(b.geom)) ' ||
    108 
    109     'FROM pgr_kdijkstraPath( 
    110 
    111     ''SELECT gid as id, source, target, length as cost FROM ' || tbl ||''',' 
    112 
    113     ||v_startSource || ', ' ||'array['||v_endSource||'] , false, false 
    114 
    115     ) a, ' 
    116 
    117     || tbl || ' b 
    118 
    119     WHERE a.id3=b.gid   
    120 
    121     GROUP by id1   
    122 
    123     ORDER by id1' into v_res ;
    124 
    125    
    126 
    127     --从开始的终点到结束的起点最短路径
    128 
    129     execute 'SELECT st_linemerge(st_union(b.geom)) ' ||
    130 
    131     'FROM pgr_kdijkstraPath( 
    132 
    133     ''SELECT gid as id, source, target, length as cost FROM ' || tbl ||''',' 
    134 
    135     ||v_startTarget || ', ' ||'array['||v_endSource||'] , false, false 
    136 
    137     ) a, ' 
    138 
    139     || tbl || ' b 
    140 
    141     WHERE a.id3=b.gid   
    142 
    143     GROUP by id1   
    144 
    145     ORDER by id1' into v_res_b ;
    146 
    147  
    148 
    149     --从开始的起点到结束的终点最短路径
    150 
    151     execute 'SELECT st_linemerge(st_union(b.geom)) ' ||
    152 
    153     'FROM pgr_kdijkstraPath( 
    154 
    155     ''SELECT gid as id, source, target, length as cost FROM ' || tbl ||''',' 
    156 
    157     ||v_startSource || ', ' ||'array['||v_endTarget||'] , false, false 
    158 
    159     ) a, ' 
    160 
    161     || tbl || ' b 
    162 
    163     WHERE a.id3=b.gid   
    164 
    165     GROUP by id1   
    166 
    167     ORDER by id1' into v_res_c ;
    168 
    169  
    170 
    171     --从开始的终点到结束的终点最短路径
    172 
    173     execute 'SELECT st_linemerge(st_union(b.geom)) ' ||
    174 
    175     'FROM pgr_kdijkstraPath( 
    176 
    177     ''SELECT gid as id, source, target, length as cost FROM ' || tbl ||''',' 
    178 
    179     ||v_startTarget || ', ' ||'array['||v_endTarget||'] , false, false 
    180 
    181     ) a, ' 
    182 
    183     || tbl || ' b 
    184 
    185     WHERE a.id3=b.gid   
    186 
    187     GROUP by id1   
    188 
    189     ORDER by id1' into v_res_d ;
    190 
    191  
    192 
    193     if(ST_Length(v_res) > ST_Length(v_res_b)) then
    194 
    195        v_res = v_res_b;
    196 
    197     end if;
    198 
    199    
    200 
    201     if(ST_Length(v_res) > ST_Length(v_res_c)) then
    202 
    203        v_res = v_res_c;
    204 
    205     end if;
    206 
    207    
    208 
    209     if(ST_Length(v_res) > ST_Length(v_res_d)) then
    210 
    211        v_res = v_res_d;
    212 
    213     end if;
    214 
    215              
    216 
    217  
    218 
    219     --如果找不到最短路径,就返回null 
    220 
    221     --if(v_res is null) then 
    222 
    223     --    return null; 
    224 
    225     --end if; 
    226 
    227      
    228 
    229     --将v_res,v_startLine,v_endLine进行拼接 
    230 
    231     select  st_linemerge(ST_Union(array[v_res,v_startLine,v_endLine])) into v_res;
    232 
    233  
    234 
    235     select  ST_Line_Locate_Point(v_res, v_statpoint) into v_perStart; 
    236 
    237     select  ST_Line_Locate_Point(v_res, v_endpoint) into v_perEnd; 
    238 
    239         
    240 
    241     if(v_perStart > v_perEnd) then 
    242 
    243         tempnode =  v_perStart;
    244 
    245         v_perStart = v_perEnd;
    246 
    247         v_perEnd = tempnode;
    248 
    249     end if;
    250 
    251         
    252 
    253     --截取v_res 
    254 
    255     SELECT ST_Line_SubString(v_res,v_perStart, v_perEnd) into v_shPath;
    256 
    257  
    258 
    259     return v_shPath; 
    260 
    261  
    262 
    263 end; 
    264 
    265 $body$ 
    266 
    267 LANGUAGE plpgsql VOLATILE STRICT;

    四、数据发布

    数据准备完成后,就需要用GeoServer来进行发布:

    启动GeoServer,在浏览器中输入,http://localhost:8080/geoserver/web/,登录到GeoServer。

    1.创建工作区

     

    添加xblk名称的工作区。

    2.添加数据存储:

     

    填入对应的连接信息:

     

    3.添加图层:

     

    注意红框中的内容。

    4.添加路径查询服务,添加图层,选择“配置新的SQL视图”:

     

     

    视图名称:navigation

    SQL语句:

    SELECT * FROM pgr_fromAtoB('road_xblk', %x1%, %y1%, %x2%, %y2%)

    验证的正则表达式:^-?[d.]+$

    类型:LingString

    SRID:4326

    点击保存后,填入SRS,并自动计算范围:

     

     

     

    五、结果展示

    使用OpenLayer进行结果展示,代码请直接下载,结果如下:

     

    OpenLayer展示代码下载

     

    说明:这个最短路径的算法有一定的问题,在特定的条件下,查找的不一定是最短的路径,需要对数据进行再处理,或者对算法进行优化。

     

  • 相关阅读:
    《ElasticSearch6.x实战教程》之准备工作、基本术语
    《ElasticSearch6.x实战教程》正式推出
    【好书推荐】《剑指Offer》之硬技能(编程题12~16)
    synchronized凭什么锁得住?
    synchronized到底锁住的是谁?
    Java面试宝典(2020版)
    50道Redis面试题及答案整理,史上最全!
    MySQL面试题及答案整理,史上最全!
    Github 上优秀的 Java 项目推荐
    100道MySQL常见面试题总结
  • 原文地址:https://www.cnblogs.com/liongis/p/7692477.html
Copyright © 2011-2022 走看看