路径规划PgRouting
2015年7月1日
1 目标:根据矢量路线图,进行路线规划计算。
输入起止点,生成路线规划的最短路径。
2方法:pgRouting。
目标:使用已有的成熟算法,利用postgresql中的postgis图层和postgis算法,进行路线规划。
原理:Dijkstra,A*(A Star)。
Dijkstra:从起点开始计算到各点的最短路径,逐个取出。找到最短路径。
参考:
http://baike.baidu.com/view/1712262.htm?fromtitle=Dijkstra%E7%AE%97%E6%B3%95&fromid=215612&type=syn
A*:与Dijkstra类似,从起点开始计算与各点的最短路径和终点的估计最短路径之和,逐个取出。找到最短路径。效率较高。
参考:http://www.jb51.cc/article/p-cknoyiud-yt.html
2.1 方法:安装
参考:http://www.xuebuyuan.com/1655300.html
2.1.1下载源程序
下载pgRouting,解压后复制到postgres的目录中,与原程序合并。
如果安装的postgis中已经包含pgRouting则不用再手动安装。
2.1.2添加postgis和pgRouting扩展
Create Extension Postgis;
Create Extension pgRouting;
参见:..\postgis\Postgis.docx中扩展安装方法
2.2 方法:准备规划数据
规则数据要求各个线路之间具有相互独立,在换乘站具有节点。
2.2.1创建换乘节点:在线路相交的位置生成节点。
2.2.1.1 使用Qgis生成一副简单的线路矢量图。
2.2.1.2 使用OpenJump进行交点分割。
参见:..\QGIS\编译过程\qgis应用\qgis应用-矢量操作.docx中OpenJump部分。
2.2.1.3 将数据导入postgis。
2.2.2构建拓扑关系:pgr_createTopology()。
拓扑关系:所有线段节点之间的相互关系。包括每一条线段的节点与其它节点之间的连接线起点、终点,且每条线段只使用一次。目的是路径的可达性基础数据。
起点:source。
终点:target。
2.2.2.1 添加起止点:
2.2.2.2 构建拓扑数据索引:默认创建source和target的btree索引。
如果没有创建,可以使用create index IndexName on TableName(“colName”);创建索引。
2.2.3添加每条线段的权重:cost
可以使用qgis或者直接在postgis中添加cost的字段(integer)并设置一些值。
2.3 方法:Dijkstra计算最短路径,pgr_dijkstra()。
dijstra算法需要提供每个元素的id,source,target,cost;路径起点,终点。
结果为id,起点,经过的边,cost数组。
将结果保存为新的表供使用。
示例:将结果保存为数据表
select seq,id1 asnode,id2 as edge,cost into dijkstra from pgr_dijkstra(
'select gid asid,cost::double precision from road_noded',1,8,false,false
);
示例:将结果保存为矢量表,并在qgis中显示。
参考:http://www.bubuko.com/infodetail-907849.html
create tabledijkstraResult as
select seq,a.cost,the_geom from pgr_dijkstra(
'select gid asid,
1,false) a
left join
road_noded b
on
a.id2=b.gid;
2.4 方法:A*计算最短路径
A*算法需要使用每个线段的起点x,y和终点x,y坐标。
添加线段起止点的x1,y1,x2,y2字段。
为每个字段赋值。
查询结果保存为新表。
示例:结果保存为数据表。
select seq,cost into astar from pgr_astar(
'select gid asid,cost::double precision,x1,y2 fromroad_noded',false
);
示例:结果保存为矢量表,并在Qgis中显示。
selectthe_geom,id,id1,id2,di.cost into astar2 from pgr_astar(
'select gid asid,false
) as di joinroad_noded pt on di.id2=pt.gid;
3 方法:发布WMS路径查询服务
3.1 生成最短路径查询函数:生成sql函数pgr_framAtoB()。
-- Function:pgr_fromatob(character varying,double precision,doubleprecision,double precision)
-- DROP FUNCTIONpgr_fromatob(character varying,double precision);
CREATE OR REPLACEFUNCTION pgr_fromatob(
IN tbl character varying,
IN x1 double precision,
IN y1 double precision,
IN x2 double precision,
IN y2 double precision,
OUT seq integer,
OUT gid integer,
OUT name text,
OUT heading double precision,
OUT cost double precision,
OUT geom geometry)
RETURNS SETOF record AS
$BODY$
DECLARE
sqltext;
recrecord;
source integer;
target integer;
point integer;
BEGIN
-- Find nearest node
EXECUTE 'SELECT id::integer FROM road_noded_vertices_pgr
ORDER BY the_geom <->ST_GeometryFromText(''POINT('
|| x1 || ' ' || y1 ||')'',4326) LIMIT 1' INTO rec;
source := rec.id;
EXECUTE 'SELECT id::integer FROMroad_noded_vertices_pgr
ORDER BY the_geom <->ST_GeometryFromText(''POINT('
|| x2 || ' ' || y2 ||')'',4326) LIMIT 1' INTO rec;
target := rec.id;
-- Shortest path query (TODO: limit extentby BBox)
seq := 0;
sql := 'SELECT gid,the_geom,name,
ST_Reverse(the_geom) ASflip_geom FROM ' ||
'pgr_dijkstra(''SELECTgid as id,source::int,target::int,'
||'cost::float AS cost FROM '
||quote_ident(tbl) || ''','
|| source ||',' || target
|| ',false) a,'
||quote_ident(tbl) || ' WHERE id2 = gid ORDER BY seq';
-- Remember start point
point := source;
FOR rec IN EXECUTE sql
LOOP
-- Flip geometry (if required)
IF ( point != rec.source ) THEN
rec.the_geom := rec.flip_geom;
point := rec.source;
ELSE
point := rec.target;
END IF;
-- Calculate heading (simplified)
EXECUTE 'SELECT degrees( ST_Azimuth(
ST_StartPoint(''' ||rec.the_geom::text || '''),
ST_EndPoint(''' ||rec.the_geom::text || ''') ) )'
INTO heading;
-- Return record
seq := seq + 1;
gid :=rec.gid;
name := rec.name;
cost := rec.cost;
geom := rec.the_geom;
RETURN NEXT;
END LOOP;
RETURN;
END;
$BODY$
LANGUAGE plpgsql VOLATILE STRICT
COST 100
ROWS 1000;
ALTER FUNCTIONpgr_fromatob(character varying,double precision)
OWNER TO postgres;
3.2 发布WMS的postgis sqlview
关于sqlview的使用,参见:GeoServer.docx中postgis参数WMS部分。
注意:发布要的图层要使用4326,使用其它srs不能正常显示???。
不要使用从数据计算范围,会报错。手动输入。
参考:http://lists.osgeo.org/pipermail/postgis-users/2014-January/038518.html
3.2.1设置sqlview的sql及相关属性。
SELECT ST_MakeLine(route.geom)FROM (
SELECT geom FROM pgr_fromAtoB('road_noded',%x1%,%y1%,%x2%,%y2%
) ORDER BY seq) AS route
3.2.2测试:使用layer preview显示openlayers,添加参数查看。
4方法:OpenLayers中使用最短路径
参考:http://workshop.pgrouting.org/chapters/ol3_client.html
4.1 构建WMS的viewparams参数。
//pgrouting test
var params = {
LAYERS: 'pgrouting:pgrouting',
FORMAT: 'image/png',
CRS:'EPSG:4326'
};
//add pgrouting
var viewparams = [
'x1:' +startPoint.getGeometry().getCoordinates()[0],'y1:' +startPoint.getGeometry().getCoordinates()[1],
'x2:' +destPoint.getGeometry().getCoordinates()[0],'y2:' +destPoint.getGeometry().getCoordinates()[1]
];
params.viewparams = viewparams.join(';');
4.2 示例:设置起止点,自动生成最短路径。
放大后如下图所示。
<!DOCTYPE HTML PUBLIC"-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<style>
.map2{height:400px;width:100%;}
</style>
<script src="D:/Data/test/openlayers/jquery-1.11.1.min.js"></script>
<link rel="stylesheet"href="D:/ProgramData/OpenLayers_SDK_v3.6.0/apidoc/styles/bootstrap.min.css">
<scriptsrc="D:/ProgramData/OpenLayers_SDK_v3.6.0/apidoc/scripts/bootstrap.min.js"></script>
<link rel="stylesheet" href="D:/ProgramData/OpenLayers_SDK_v3.6.0/css/ol.css"type="text/css">
<scriptsrc="D:/ProgramData/OpenLayers_SDK_v3.6.0/build/ol.js"></script>
<title>testOpenLayers</title>
</head>
<body>
<h2>Head Test OpenLayers</h2>
<div id="map2"class="map2">Map</div>
<script type="text/javascript">
/************************************/
//base map
map=new ol.Map
({
target:'map2',
layers:[new ol.layer.Image({source:newol.source.ImageWMS({
url:'http://localhost:8080/geoserver/testShp/wms',
params: {'LAYERS': 'states'},
serverType:'geoserver',
projection:ol.proj.get('EPSG:4326'),
})
})],
view:new ol.View
({
zoom:4,
projection: new ol.proj.get('EPSG:4326'),
center:[0,0]
})
});
var bounds=[-180,-10,10,60];
map.getView().fitExtent(bounds,map.getSize());
/************************************/
// The "start" and "destination" features.
var startPoint = new ol.Feature();
var destPoint = new ol.Feature();
startPoint.setGeometry(new ol.geom.Point([-3,1.6]));//([-3.8,0.67]));//([-3,1.6]));
destPoint.setGeometry(newol.geom.Point([-0.84,1.5]));//([-2.7,1.7]));
// The vector layer used to display the "start" and"destination" features.
var vectorLayer = new ol.layer.Vector({
source: new ol.source.Vector({
features: [startPoint,destPoint]
})
});
map.addLayer(vectorLayer);
//pgrouting test
var params = {
LAYERS: 'pgrouting:pgrouting',
CRS:'EPSG:4326'
};
//add pgrouting
var viewparams = [
'x1:' + startPoint.getGeometry().getCoordinates()[0],'y1:' + startPoint.getGeometry().getCoordinates()[1],
'x2:' + destPoint.getGeometry().getCoordinates()[0],'y2:'+ destPoint.getGeometry().getCoordinates()[1]
];
params.viewparams = viewparams.join(';');
//add result layer
result = new ol.layer.Image({
source: new ol.source.ImageWMS({
url:'http://localhost:8080/geoserver/pgrouting/wms',
params: params
})
});
map.addLayer(result);
</script>
</body>
</html>