我在WebGIS最佳实践-2 在WebGIS程序中实现路径分析中提到过pgRouting,现在来看看这头小象能给我们带来些什么。
先上效果图给大家鼓鼓劲。:》
为了实现以上效果我用jsp和openlayers编写了服务端和客户端,但是本文的重点是介绍pgRouting所以不在这里详细介绍这些这些代码了,大家可以从下载包中找到这两个文件。要使用pgRouting得先安装,我假设大家已经安装了Postgresql和PostGIS。
从这里下载合适的二进制包,我下的是Windows版本,解压缩后把Lib下面的动态库复制到Postgresql的bin目录下,把Share\Contrib下面的sql文件复制到Postgresql的share\contrib目录下,然后重新启动Postgresql(这一步我不确定是否必要)。然后就可以进行路径搜素了,下面我们从数据准备开始,一步步得创建出完整可用的路网数据表。Let·s rock!
我们先要创建一个新数据库,就叫routing吧,我们会先让它支持pgRouting的函数然后给他增加一张表,一张路网表。随后我们会需要执行一些sql脚本,你可以用postgresql提供的小程序psql.exe来执行也可以用图形化工具pgAdmin来完成。我选择用psql。postgresql提供的程序createdb.exe可以帮助我们创建数据库,我们假设用户是postgres:
createdb -U postgres routing
然后让数据库支持PostGIS和pgRouting的函数和基础表
psql –U postgres –d routing –f postgis.sql psql –U postgres –d routing –f spatial_ref_sys.sql psql –U postgres –d routing –f routing_core.sql psql –U postgres –d routing –f routing_core_wrappers.sql psql –U postgres –d routing –f routing_topology.sql
其中,“postgis.sql,spatial_ref_sys.sql”可以在“<Postgresql的安装路径>\<version>\share\contrib\postgis<-1.4>”下面找到,到此数据库创建完成。
为了创建路网表,我们需要一些道路数据。可以从OpenStreetMap上免费获得XML格式的道路数据。由于我们平时更容易获得Shapefile格式的数据,所以我决定用shp来完成数据导入。从Geobase下载道路数据。这个网站提供加拿大全国的道路数据,选择British Columbia , Edition 8.0的Shapefile格式(nrn_rrn_bc_shp_en.zip)。解压缩,我们要使用的数据就在“NRN_BC_8_0_ROADSEG”中。这个表的字段很多,大家可以用熟悉的GIS数据处理工具删掉一些字段,当然不处理也没关系。
先用shp2psql.exe程序把shp文件装换成sql脚本
shp2pgsql -s 4326 NRN_BC_8_0_ROADSEG public.street_bc > street_bc.sql
如果一切顺利的话,我们会得到文件“street_bc.sql”,这是一个很大的文件。然后我们执行这个文件:
psql -U postgres -d routing -f street_bc.sql
下面创建路网的拓扑结构
psql –U postgres –d routing –c “alter table street_bc add “source” integer” psql –U postgres –d routing –c “alter table street_bc add “target” integer” psql –U postgres –d routing –c “select assign_vertex_id(“street_bc”,0.001,”the_geom”,”gid”)” psql –U postgres –d routing –c “alter table street_bc add “length” double precision” psql –U postgres –d routing –c “update routing set length=st_length(the_geom)”
到这里路网数据就做好了。来测试一下:
SELECT astext(st_transform(the_geom,900913)),l_stname_c as name FROM shortest_path('SELECT gid as id,source::integer,target::integer,length::double precision as cost FROM street_bc',158390, 63634, false, false),street_bc where edge_id = gid;