0

pgrouting-workshop ファイルから始めましたが、複数の方法を使用して正確なルート長を取得するのに問題があります。

最初の方法は、pgrouting.php スクリプトへの ajax 呼び出しから返された長さ変数を合計するだけです。ルーティング データベースから返される長さは、距離の式から取得されるようです: sqrt((x2-x1)^2 + (y2-y1)^s) ここで、x 座標は経度、y 座標は epsg:4326 の緯度です。緯度と経度は地表に投影したときの長さが違うので、この値の良し悪しはよくわかりませんが、このゲームは初めてなので...

この最初の方法では正確な合計距離が得られなかったため、長さの計算に haversine 式を使用して、ajax 呼び出しから返された各セグメントの長さを合計することにしました。しかし、この長さを「カラスが飛ぶように」(ATCF) 開始点と終了点の間の距離と比較したところ、この長さは ATCF の長さより短いことがわかりました。そこで、これらの各ルート セグメントを openlayers の個別のベクター レイヤーに追加したところ、これらのセグメントがルート全体をカバーしていないことがわかりました。特にルートの曲線部分では、多くのセグメントが欠落しています。

そこで、1 つのセグメントの開始点と前のセグメントの終了点の間の距離を取得して、ギャップを合計することにしました。ただし、これらのセグメントが順番どおりに返されないことがわかりました。

私は困惑しています。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);

?>
4

2 に答える 2

0

長さのエラーは、SQL ステートメントのこの部分に起因します。length(rt.the_geom) AS length これは、just に変更する必要がありますlength。何が何をするのかよくわかりませんlength(rt.the_geom) AS lengthが、最初の質問で述べたように、これは距離の式を使用しているようです。

geojson によって返されたルート セグメントを使用する場合、ルートにはまだギャップがありますが、ルートの合計距離 (変更された長さを使用) は、オリジナルで説明されている「カラスが飛ぶように距離」と比較すると、8 メートル以内の精度になりました。質問(直線ルートに沿って)。これは、一部のセグメントのジオメトリの x 値と y 値が正しくなく、ギャップが発生していることを意味しているに違いありません。

于 2013-09-18T23:00:30.600 に答える