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展示代码下载

     

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

     

  • 相关阅读:
    我的WCF之旅(1):创建一个简单的WCF程序
    与众不同 windows phone (15) Media(媒体)之后台播放音频
    与众不同 windows phone (14) Media(媒体)之音频播放器, 视频播放器, 与 Windows Phone 的音乐和视频中心集成
    与众不同 windows phone (10) Push Notification(推送通知)之推送 Tile 通知, 推送自定义信息
    与众不同 windows phone (17) Graphic and Animation(画图和动画)
    与众不同 windows phone (5) Chooser(选择器)
    与众不同 windows phone (26) Contacts and Calendar(联系人和日历)
    与众不同 windows phone (7) Local Database(本地数据库)
    与众不同 windows phone (19) Device(设备)之陀螺仪传感器, Motion API
    与众不同 windows phone (16) Media(媒体)之编辑图片, 保存图片到相册, 与图片的上下文菜单“应用程序...”和“共享...”关联, 与 Windows Phone 的图片中心集成
  • 原文地址:https://www.cnblogs.com/liongis/p/7692477.html
Copyright © 2011-2022 走看看