路径规划PgRouting
2015年7月1日
输入起止点,生成路线规划的最短路径。
目标:使用已有的成熟算法,利用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://blog.csdn.net/crayondeng/article/details/12342989
参考:http://www.xuebuyuan.com/1655300.html
下载pgRouting,解压后复制到postgres的目录中,与原程序合并。
如果安装的postgis中已经包含pgRouting则不用再手动安装。
Create Extension Postgis;
Create Extension pgRouting;
参见:..\postgis\Postgis.docx中扩展安装方法
规则数据要求各个线路之间具有相互独立,在换乘站具有节点。
参见:..\QGIS\编译过程\qgis应用\qgis应用-矢量操作.docx中OpenJump部分。
参见:..\postgis\Postgis.docx
拓扑关系:所有线段节点之间的相互关系。包括每一条线段的节点与其它节点之间的连接线起点、终点,且每条线段只使用一次。目的是路径的可达性基础数据。
起点:source。
终点:target。
如果没有创建,可以使用create index IndexName on TableName(“colName”);创建索引。
可以使用qgis或者直接在postgis中添加cost的字段(integer)并设置一些值。
dijstra算法需要提供每个元素的id,source,target,cost;路径起点,终点。
结果为id,起点,经过的边,cost数组。
将结果保存为新的表供使用。
示例:将结果保存为数据表
select seq,id1 asnode,id2 as edge,cost into dijkstra from pgr_dijkstra(
'select gid asid,source,target,cost::double precision from road_noded',1,8,false,false
);
示例:将结果保存为矢量表,并在qgis中显示。
参考:http://www.bubuko.com/infodetail-907849.html
create tabledijkstraResult as
select seq,id1 asnode ,id2 as edge,a.cost,the_geom from pgr_dijkstra(
'select gid asid,source,target,cost::double precision from road_noded',
1,8,false,false) a
left join
road_noded b
on
a.id2=b.gid;
A*算法需要使用每个线段的起点x,y和终点x,y坐标。
添加线段起止点的x1,y1,x2,y2字段。
为每个字段赋值。
查询结果保存为新表。
示例:结果保存为数据表。
select seq,id1 asnode,id2 as edge,cost into astar from pgr_astar(
'select gid asid,source,target,cost::double precision,x1,y1,x2,y2 fromroad_noded',1,8,false,false
);
示例:结果保存为矢量表,并在Qgis中显示。
selectthe_geom,id,id1,id2,di.cost into astar2 from pgr_astar(
'select gid asid,source,target,cost::double precision,x1,y1,x2,y2 fromroad_noded',1,8,false,false
) as di joinroad_noded pt on di.id2=pt.gid;
-- Function:pgr_fromatob(character varying, double precision, double precision, doubleprecision, double precision)
-- DROP FUNCTIONpgr_fromatob(character varying, double precision, double precision, doubleprecision, 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
sql text;
rec record;
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,a.cost, source, target,
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, 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, double precision, doubleprecision, double precision)
OWNER TO postgres;
关于sqlview的使用,参见:GeoServer.docx中postgis参数WMS部分。
注意:发布要的图层要使用4326,使用其它srs不能正常显示???。
不要使用从数据计算范围,会报错。手动输入。
参考:http://lists.osgeo.org/pipermail/postgis-users/2014-January/038518.html
SELECT ST_MakeLine(route.geom)FROM (
SELECT geom FROM pgr_fromAtoB('road_noded',%x1%, %y1%, %x2%, %y2%
) ORDER BY seq) AS route
在默认的url上添加查询参数,结果如下:
http://localhost:8080/geoserver/pgrouting/wms?service=WMS&version=1.1.0&request=GetMap&layers=pgrouting:pgrouting&styles=&bbox=-10.0,-10.0,10.0,10.0&width=768&height=768&srs=EPSG:4326&format=application/openlayers&viewparams=x1:-3;y1:1.6;x2:-2.7;y2:1.7
参考:http://workshop.pgrouting.org/chapters/ol3_client.html
//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(';');
放大后如下图所示。
<!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',
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(';');
//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>