本文共 5683 字,大约阅读时间需要 18 分钟。
PgRouting是基于开源空间数据库PostGIS用于网络分析的扩展模块,最初它被称作pgDijkstra,因为它只是利用Dijkstra算法实现最短路径搜索,之后慢慢添加了其他的路径分析算法,如A算法,双向A算法,Dijkstra算法,双向Dijkstra算法,tsp货郎担算法等,然后被更名为pgRouting[1]。该扩展库依托PostGIS自身的gist索引,丰富的坐标系与图形类型,强大的几何处理能力,如空间查询,空间处理,线性参考等优势,能保障在较大数据级别下的网络分析效果更快更好。
PostGIS早已奠定了最优秀的开源空间数据库地位,在新时代GIS中的应用将会越来越普遍。其次,网络分析算法很多服务端语言如java,C#等虽能实现,但基于真实城市道路数据量较大且查询分析操作步骤复杂与数据库交互频繁,以这类服务端频繁访问数据库导致数据库开销压力较大,分析较慢,故选择PgRouting在数据库内部实现算法,提升分析效率。最后,路径分析不仅仅是最短路径,在实际应用中还有最短耗时,最近距离,道路对车辆类型限制,道路对速度限制等因素,交通事故、市政事故导致的交通障碍点等问题,所有的问题本质其实是对路径分析权重(Weight)的设置问题。windows安装过程比较简单,安装PostgreSQL,PostGIS一直Next即可,安装完自带PgRouting扩展,这里主要以Centos7介绍安装过程:
# 解压[root@localhost opt]# tar -zxvf pgrouting-2.4.1# 检查是否安装Cmake,未安装自行安装[root@localhost pgrouting-2.4.1]# cmake --help# 引入Postgres账户的环境变量[root@localhost pgrouting-2.4.1]# source /home/postgres/.bashrc# 安装CGAL #下载地址:https://github.com/CGAL/cgal#readme[root@localhost opt]# cd cgal-master[root@localhost cgal-master]# mkdir build[root@localhost cgal-master]# cd build[root@localhost build]# cmake ..[root@localhost build]# make & make install[root@localhost build]# cd /opt/pgrouting-2.4.1[root@localhost pgrouting-2.4.1]# mkdir build[root@localhost pgrouting-2.4.1]# cd build[root@localhost build]# cmake ..[root@localhost build]# make & make install
[root@localhost opt]# su - postgres[postgres@localhost ~]$ psqlpsql (9.6.1)Type "help" for help.postgres=# create database network;CREATE DATABASEpostgres=# \c networkYou are now connected to database "network" as user "postgres".network=# create extension postgis;CREATE EXTENSIONnetwork=# create extension pgrouting;CREATE EXTENSION
PgRouting需要使用道路线型数据,建立道路连通性topo关系。由于路网分析的特殊性,只支持LineString类型,不支持MultiLineString类型。测试数据从得来。
一般下载shp,使用PostGIS自带的shp2pgsql导入即可。其他格式可以使用osm2pgrouting工具,本文不做详述。笔者下载后,将路网数据使用ArcMap只截取了南京市范围内路网后,从epsg:4326转换成了epsg:3857坐标系,然后导入数据库,做测试数据。
[postgres@localhost ~]$ shp2pgsql -c -g geom -D -s 3857 -S -i -I /opt/roads.shp road | psql -d networkShapefile type: ArcPostgis type: LINESTRING[2]SETSETBEGINCREATE TABLEALTER TABLE addgeometrycolumn ----------------------------------------------------public.road.geom SRID:3857 TYPE:LINESTRING DIMS:2 (1 row)COPY 9731CREATE INDEXCOMMITANALYZE
关于shp2pgsql参数问题,参考。
注意:使用shp2pgsql工具,shp路径不要太深,不要有中文。对于含有中文乱码的,可使用-W gbk等转码。PgRouting提供pgr_createTopology方法,对道路数据创建拓扑关系,比如单一线要素,建立与其连通的source,tartget连通点。详细步骤如下:
#在network数据库中对导入的road表建立source,target字段network=# alter table road add column source int;ALTER TABLEnetwork=# alter table road add column target int;ALTER TABLE#创建连通性topo#road是表名称,geom是该表的图形字段名称,gid是改变的主键id。#一般我们使用shp2pgsql工具会自动创建gid为主键,geom为图形。#如果是自己其他形式建立的表,注意参数写自己对应的字段network=# SELECT pgr_createTopology('road', 0.00001, 'geom', 'gid');
正常情况下顺利完成以上步骤。
由于在网络分析中频繁读取source,target字段的topo关系值,为了提升查询效率,需要对这两个字段添加索引:network=# create index road_source_idx on road("source");network=# create index road_target_idx on road("target");
到此为止,全部数据准备工作已经完成了,查看本文用于测试路径分析的数据描述如下:
network=# \d road Table "public.road" Column | Type | Modifiers -----------+---------------------------+---------------------------------------------------- gid | integer | not null default nextval('road_gid_seq'::regclass) direction | character varying(1) | roadname | character varying(40) | oneway | character varying(50) | geom | geometry(LineString,3857) | source | integer | target | integer | Indexes: "road_pkey" PRIMARY KEY, btree (gid) "road_geom_idx" gist (geom) "road_source_idx" btree (source) "road_target_idx" btree (target)
由此看出,road表拥有主键索引,geom的gist索引,source,target节点处索引,还有一般性的道路名称字段,比较重要的是direction和oneway字段(有一个即可),这两个字段都是说明道路真实方向的。
direction | oneway | 含义 |
---|---|---|
0,1 | 空值 | 道路双向通行 |
2 | FT | 道路真实方向与数字化方向一致 |
3 | TF | 道路真实方向与数字化方向相反 |
4 | N | 道路禁止通行 |
在算法中分为有向图,无向图,图的path长度一般设置为权重,网络分析中,具体到比如交通领域,也分为双向通行道路,单向通行道路,交通事故导致的临时交通阻塞无法通行(障碍点),不同等级道路对车辆类型限制,比如高架,高速只允许机动车,乡间道路允许非机动车(条件限制因素),本节只是举个例子说明下不同的条件下如何设置通行成本权重:
update road set length=st_length(geom),rev_length=st_length(geom) where oneway is null;--采用真实地理距离是这样:update road set lenght=st_length(st_transform(geom),4326),true),rev_length=st_length((st_transform(geom),4326),true) where oneway is null;
#FT是道路方向与数字化方向一致,那么正向通行成本为道路长度,反向成本为正无穷(以极大值代替)update road set length=st_length(geom),rev_length=99999999999 where oneway='FT';update road set length=99999999999,rev_length=st_length(geom) where oneway='TF';
#假设gid=20的道路因事故,修路暂时不能通行update road set lenght=99999999999,rev_length=99999999999 where gid=20;
#假设道路表有字段restrict,该字段是array,记录了不可通行的车辆类型update road set lenght=99999999999,rev_length=99999999999 where 'lorry'=any(restrict);
言归正传,本文从入门角度只阐述最简单的单向,双向通行道路的例子,其他概不设置限制。
alter table road add column length numeric;alter table road add column rev_length numeric;update road set length=ST_Length(ST_TransForm(geom,4326),true),rev_length=ST_Length(ST_TransForm(geom,4326),true) where oneway is null;update road set length=st_length(ST_TransForm(geom,4326),true),rev_length=99999999999 where oneway='FT';update road set length=99999999999,rev_length=st_length(ST_TransForm(geom,4326),true) where oneway='TF';
select
转载地址:http://xyjaa.baihongyu.com/