我从pgrouting-workshop文件开始,但是我无法使用多种方法获得准确的路径长度。
第一种方法是将从ajax调用返回的长度变量加到pgrouting.php脚本中。从路由db返回的长度似乎是从距离公式获得的:sqrt((x2-x1)^ 2 +(y2-y1)^ s)其中x坐标是经度,y坐标是纬度epsg:4326。由于经度和经度在投射到地球表面时长度不同,我不确定这个值有多好,但我是这个游戏的新手......
由于第一种方法没有提供准确的总距离,我决定只使用长度计算的半影公式来总结从ajax调用返回的每个段的长度。然而,我将这个长度与起始点和终点之间的“如乌鸦飞行”(ATCF)距离进行了比较,发现这个长度小于ATCF长度。因此,我将这些路径段中的每一个添加到openlayers中的单独矢量图层,并发现这些段不覆盖整个路径。特别是在路线的弯曲部分,有许多路段缺失。
然后我想,我只是通过获得一段的开头和前一段的结尾之间的距离来总结间隙。但是,我发现这些段不会按顺序返回。
我受到了阻碍。如何使用pgrouting获得准确的路径长度?这是我使用的html和php脚本:
路由-final05.html:
<html>
<head>
<title>A Basic GeoExt Page</title>
<script src="/scripts/openlayers/OpenLayers.js" type="text/javascript"></script>
<style type="text/css">
html, body { height: 100%; }
body {margin: 0px;}
#map {
width: 100%;
height: 90%;
}
</style>
<script src="DrawPoints.js" type="text/javascript"></script>
<script src="proj4js/lib/proj4js.js" type="text/javascript"></script>
<script type="text/javascript">
// global projection objects (uses the proj4js lib)
var epsg_4326 = new OpenLayers.Projection("EPSG:4326"),
epsg_900913 = new OpenLayers.Projection("EPSG:900913");
function pgrouting(layer, method) {
if (layer.features.length == 2)
{
route_layer.removeAllFeatures();
crow_layer.removeAllFeatures();
verify1_layer.removeAllFeatures();
verify2_layer.removeAllFeatures();
var startpoint = layer.features[0].geometry.clone();
startpoint.transform(epsg_900913, epsg_4326);
var finalpoint = layer.features[1].geometry.clone();
finalpoint.transform(epsg_900913, epsg_4326);
var result = {
startpoint: startpoint.x + " " + startpoint.y,
finalpoint: finalpoint.x + " " + finalpoint.y,
method: method,
};
// layer.removeFeatures(layer.features);
var params = OpenLayers.Util.getParameterString(result);
OpenLayers.loadURL("./php/pgrouting05.php?" + params,
'',
null,
drawRoute);
}
}
function init(){
map = new OpenLayers.Map('map', {
controls: [
new OpenLayers.Control.Navigation(),
new OpenLayers.Control.PanZoomBar(),
new OpenLayers.Control.LayerSwitcher({'ascending':true}),
//new OpenLayers.Control.Permalink(),
//new OpenLayers.Control.ScaleLine(),
//new OpenLayers.Control.Permalink('permalink'),
new OpenLayers.Control.MousePosition(),
new OpenLayers.Control.OverviewMap(),
new OpenLayers.Control.KeyboardDefaults(),
new OpenLayers.Control.Scale({'geodesic':true})
],
//numZoomLevels: 6,
maxResolution: 156543.0339,
units: 'm',
projection: new OpenLayers.Projection("EPSG:900913"),
// displayProjection: new OpenLayers.Projection("EPSG:4326"),
displayProjection: new OpenLayers.Projection("EPSG:900913"),
maxExtent: new OpenLayers.Bounds(-20037508.34, -20037508.34, 20037508.34, 20037508.34)
});
// TileLite by default mounts on localhost port 8000
var tiles_url = "http://localhost:8000/";
var tilelite_layer = new OpenLayers.Layer.OSM("Mapnik locally via TileLite", tiles_url + '${z}/${x}/${y}.png');
map.addLayer(tilelite_layer);
var lonLat = new OpenLayers.LonLat(-104.99323, 39.74259).transform(new OpenLayers.Projection("EPSG:4326"), new OpenLayers.Projection("EPSG:900913"));
map.setCenter (lonLat, 14);
// create the layer where the route will be drawn
route_layer = new OpenLayers.Layer.Vector("route", {
styleMap: new OpenLayers.StyleMap(new OpenLayers.Style({
strokeColor: "#ff9933",
strokeWidth: 3
}))
});
// create the layer where the "as the crow flies" route will be drawn
crow_layer = new OpenLayers.Layer.Vector("crow", {
styleMap: new OpenLayers.StyleMap(new OpenLayers.Style({
strokeColor: "#000000",
strokeWidth: 3
}))
});
// create a verification layer
verify1_layer = new OpenLayers.Layer.Vector("verify1", {
styleMap: new OpenLayers.StyleMap(new OpenLayers.Style({
strokeColor: "#FF0000",
strokeWidth: 3
}))
});
// create a verification layer
verify2_layer = new OpenLayers.Layer.Vector("verify2", {
styleMap: new OpenLayers.StyleMap(new OpenLayers.Style({
strokeColor: "#00FF00",
strokeWidth: 3
}))
});
// create the layer where the start and final points will be drawn
points_layer = new OpenLayers.Layer.Vector("points");
// when a new point is added to the layer, call the pgrouting function
points_layer.events.on({
featureadded: function() {
// pgrouting(store, points_layer, method.getValue());
pgrouting(points_layer, method);
}
});
// add the layers to the map
map.addLayers([points_layer, route_layer, crow_layer, verify1_layer, verify2_layer]);
// create the control to draw the points (see the DrawPoints.js file)
var draw_points = new DrawPoints(points_layer);
// create the control to move the points
var drag_points = new OpenLayers.Control.DragFeature(points_layer, {
autoActivate: true
});
// when a point is moved, call the pgrouting function
drag_points.onComplete = function() {
// pgrouting(store, points_layer, method.getValue());
// pgrouting(store, points_layer, method);
pgrouting(points_layer, method);
};
// add the controls to the map
map.addControls([draw_points, drag_points]);
method = "SPS";
}; // end init()
function change_method()
{
// console.log(document);
method = document.forms["f1"]["method_select"].value
pgrouting(points_layer, method);
// calc_dist();
}
function calc_dist()
{
console.log("entered calc_dist()")
console.log(map.layers[2])
console.log(map.layers[2].features[0])
}
function haversine_dist(lon1,lat1,lon2,lat2,unit)
{
var radius_km = 6371
var radius_mi = 3958.75
var dlat = (lat2-lat1)*Math.PI/180.0;
var dlon = (lon2-lon1)*Math.PI/180.0;
var a = Math.sin(dlat/2) * Math.sin(dlat/2) + Math.cos(lat1*Math.PI/180.0) * Math.cos(lat2*Math.PI/180.0) * Math.sin(dlon/2) * Math.sin(dlon/2)
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a))
if (unit == 'mi')
{
var d = radius_mi * c
}
else if (unit == 'km')
{
var d = radius_km * c
}
return d;
}
function drawRoute(response)
{
// interpret geojson data coming in from ajax response
var geojson_format900913 = new OpenLayers.Format.GeoJSON({
internalProjection: epsg_900913,
externalProjection: epsg_4326
});
var geojson_format4326 = new OpenLayers.Format.GeoJSON();
var geom4326 = geojson_format4326.read(response.responseText)
var geom900913 = geojson_format900913.read(response.responseText)
// console.log(geom900913);
// console.log(geom4326);
// add features
route_layer.addFeatures(geom900913);
// calculate distances between current segment start and previous segment end
var lon1,lat1,lon2,lat2,seg_len;
var pointList = [];
var p1,p2;
var dist2 = 0;
for (i=0;i<geom900913.length;i++)
{
if (i == 0)
{
var startpoint = points_layer.features[0].geometry.clone();
// var startpoint = points_layer.features[1].geometry.clone();
lon1 = startpoint.x;
lat1 = startpoint.y;
lon2 = geom900913[i].geometry.components[0].x;
lat2 = geom900913[i].geometry.components[0].y;
}
else
{
lon1 = geom900913[i-1].geometry.components[1].x
lat1 = geom900913[i-1].geometry.components[1].y
lon2 = geom900913[i].geometry.components[0].x
lat2 = geom900913[i].geometry.components[0].y
}
seg_len = haversine_dist(lon1,lat1,lon2,lat2,'mi');
if ( seg_len > 0 )
{
dist2 += seg_len;
var pointList = [];
var p1 = new OpenLayers.Geometry.Point(lon1,lat1);
var p2 = new OpenLayers.Geometry.Point(lon2,lat2);
pointList.push(p1);
pointList.push(p2);
var route_seg = new OpenLayers.Feature.Vector(
new OpenLayers.Geometry.LineString(pointList),null,null);
verify2_layer.addFeatures([route_seg]);
}
}
// verify2_layer.addFeatures(geom4326.transform(epsg_4326, epsg_900913));
var sp900913 = points_layer.features[0].geometry.clone();
var sp4326 = points_layer.features[0].geometry.clone();
sp4326.transform(epsg_900913, epsg_4326);
var fp900913 = points_layer.features[1].geometry.clone();
var fp4326 = points_layer.features[1].geometry.clone();
fp4326.transform(epsg_900913, epsg_4326);
// console.log(sp4326);
// console.log(fp4326);
var lengths = [];
var tot_length = 0.0;
// console.log(tot_length)
var lon1,lat1,lon2,lat2;
for (i=0;i<geom4326.length;i++)
{
// lengths.push(geom4326[i].data.length);
lon1 = geom4326[i].geometry.components[0].x
lat1 = geom4326[i].geometry.components[0].y
lon2 = geom4326[i].geometry.components[1].x
lat2 = geom4326[i].geometry.components[1].y
tot_length += parseFloat(haversine_dist(lon1,lat1,lon2,lat2,'mi'))
// console.log(tot_length)
var pointList = [];
var p1 = new OpenLayers.Geometry.Point(lon1,lat1).transform(epsg_4326, epsg_900913);
var p2 = new OpenLayers.Geometry.Point(lon2,lat2).transform(epsg_4326, epsg_900913);
pointList.push(p1);
pointList.push(p2);
// console.log(pointList)
var route_seg = new OpenLayers.Feature.Vector(
new OpenLayers.Geometry.LineString(pointList),null,null);
// console.log(crow_line)
verify1_layer.addFeatures([route_seg]);
}
// console.log(lengths);
// console.log("sum of the parts: " + tot_length);
// as the crow flies
lon1 = sp4326.x
lat1 = sp4326.y
lon2 = fp4326.x
lat2 = fp4326.y
var line_length_mi = haversine_dist(lon1,lat1,lon2,lat2,'mi')
var line_length_km = haversine_dist(lon1,lat1,lon2,lat2,'km')
// console.log("straight line dist: " + line_length);
document.getElementById("dist").innerHTML = "Distance: " + Math.round(tot_length*1000)/1000 + " miles"
document.getElementById("straight_dist").innerHTML = "As the crow flies: " + Math.round(line_length_mi*1000)/1000 + " miles, " + Math.round(line_length_km*1000)/1000 + " km"
var pointList = [];
pointList.push(new OpenLayers.Geometry.Point(sp900913.x,sp900913.y));
pointList.push(new OpenLayers.Geometry.Point(fp900913.x,fp900913.y));
// console.log(pointList)
var crow_line = new OpenLayers.Feature.Vector(
new OpenLayers.Geometry.LineString(pointList),null,null);
// console.log(crow_line)
crow_layer.addFeatures([crow_line]);
}
</script>
</head>
<body onload="init()">
<form name="f1">
<table width="100%">
<tr>
<td align="center">
<select name="method_select" onchange="change_method();">
<option value="SPD">Shortest Path Dijkstra</option>
<option value="SPA">Shortest Path A*</option>
<option value="SPS">Shortest Path Shooting*</option>
</select>
</td>
<td align="center">
<p id="dist"></p>
</td>
<td align="center">
<p id="straight_dist"></p>
</td>
</tr>
</table>
</form>
<div id="map" ></div>
<div id="gxmap"></div>
<div id="method"></div>
</body>
</html>
pgrouting.php(我这里没有改变任何内容,这是直接来自研讨会文件)
<?php
// Database connection settings
define("PG_DB" , "routing");
define("PG_HOST", "localhost");
define("PG_USER", "postgres");
define("PG_PORT", "5432");
define("TABLE", "ways");
//echo($_REQUEST)
// Retrieve start point
$start = preg_split('/ /',$_REQUEST['startpoint']);
$startPoint = array($start[0], $start[1]);
// Retrieve end point
//$end = split(' ',$_REQUEST['finalpoint']);
$end = preg_split('/ /',$_REQUEST['finalpoint']);
$endPoint = array($end[0], $end[1]);
//echo($end[0]);
?>
<?php
// Find the nearest edge
$startEdge = findNearestEdge($startPoint);
$endEdge = findNearestEdge($endPoint);
// FUNCTION findNearestEdge
function findNearestEdge($lonlat) {
// Connect to database
$con = pg_connect("dbname=".PG_DB." host=".PG_HOST." user=".PG_USER);
$sql = "SELECT gid, source, target, the_geom,
distance(the_geom, GeometryFromText(
'POINT(".$lonlat[0]." ".$lonlat[1].")', 4326)) AS dist
FROM ".TABLE."
WHERE the_geom && setsrid(
'BOX3D(".($lonlat[0]-0.1)."
".($lonlat[1]-0.1).",
".($lonlat[0]+0.1)."
".($lonlat[1]+0.1).")'::box3d, 4326)
ORDER BY dist LIMIT 1";
$query = pg_query($con,$sql);
$edge['gid'] = pg_fetch_result($query, 0, 0);
$edge['source'] = pg_fetch_result($query, 0, 1);
$edge['target'] = pg_fetch_result($query, 0, 2);
$edge['the_geom'] = pg_fetch_result($query, 0, 3);
// Close database connection
pg_close($con);
return $edge;
}
?>
<?php
// Select the routing algorithm
switch($_REQUEST['method']) {
case 'SPD' : // Shortest Path Dijkstra
$sql = "SELECT rt.gid, ST_AsGeoJSON(rt.the_geom) AS geojson,
length(rt.the_geom) AS length, ".TABLE.".gid
FROM ".TABLE.",
(SELECT gid, the_geom
FROM dijkstra_sp_delta(
'".TABLE."',
".$startEdge['source'].",
".$endEdge['target'].",
0.1)
) as rt
WHERE ".TABLE.".gid=rt.gid;";
break;
case 'SPA' : // Shortest Path A*
$sql = "SELECT rt.gid, ST_AsGeoJSON(rt.the_geom) AS geojson,
length(rt.the_geom) AS length, ".TABLE.".gid
FROM ".TABLE.",
(SELECT gid, the_geom
FROM astar_sp_delta(
'".TABLE."',
".$startEdge['source'].",
".$endEdge['target'].",
0.1)
) as rt
WHERE ".TABLE.".gid=rt.gid;";
break;
case 'SPS' : // Shortest Path Shooting*
$sql = "SELECT rt.gid, ST_AsGeoJSON(rt.the_geom) AS geojson,
length(rt.the_geom) AS length, ".TABLE.".gid
FROM ".TABLE.",
(SELECT gid, the_geom
FROM shootingstar_sp(
'".TABLE."',
".$startEdge['gid'].",
".$endEdge['gid'].",
0.1, 'length', true, true)
) as rt
WHERE ".TABLE.".gid=rt.gid;";
break;
} // close switch
// Connect to database
$dbcon = pg_connect("dbname=".PG_DB." host=".PG_HOST." user=".PG_USER);
// Perform database query
$query = pg_query($dbcon,$sql);
?>
<?php
// Return route as GeoJSON
$geojson = array(
'type' => 'FeatureCollection',
'features' => array()
);
// Add edges to GeoJSON array
while($edge=pg_fetch_assoc($query)) {
$feature = array(
'type' => 'Feature',
'geometry' => json_decode($edge['geojson'], true),
'crs' => array(
'type' => 'EPSG',
'properties' => array('code' => '4326')
),
'properties' => array(
//'osm_id' => $edge['osm_id'],
'length' => $edge['length']
//'x1' => $edge['x1']
)
);
// Add feature array to feature collection array
array_push($geojson['features'], $feature);
}
// Close database connection
pg_close($dbcon);
// Return routing result
header('Content-type: application/json',true);
echo json_encode($geojson);
?>
答案 0 :(得分:0)
我没有检查过pgRouting研讨会,但是“路由数据库返回的长度”可能是成本,因为从pgRouting SQL调用返回成本,请参阅docs。只有在pgRouting函数的SQL参数中使用实际长度作为成本时,成本值的总和才等于实际长度。
假设您的数据库中预先计算了正确的长度和使用长度作为成本,您可以使用第一种方法获得准确的长度。
如果length不等于cost,则可以使用结果的edge_id列,并以某种方式获取edge_id中具有id的所有方式的长度总和。这样的事情(未经测试):
SELECT sum(length) FROM my_ways WHERE id IN (
SELECT edge_id FROM shortest_path_astar("SQL", source, target, false, false)
) as edge_ids
P上。 S.我不知道您使用哪个应用程序来创建方法数据库,但我确信osm2po计算正确的方式。
答案 1 :(得分:0)
长度错误源于sql语句的这一部分:length(rt.the_geom) AS length
这应该更改为length
。我不确定length(rt.the_geom) AS length
是做什么的,但正如我在原始问题中所述,这似乎使用距离公式。
如果您使用geojson返回的路线段,路线中仍然存在间隙,但是与“描述的乌鸦飞行距离”相比,总路线距离(使用修改的长度)现在精确到8米以内在原始问题中(沿直线路线)。这必然意味着某些段的几何中的x和y值是错误的,从而导致间隙。