Routing PHP script with XML output

Important

The content of this page is outdated and is for archiving purposes only.

PHP page template (basics)

We will use a PHP script to make the routing query and send the result back to the web client.

The following steps are necessary:

  • Retrieve the start and end point coordinates.
  • Find the closest edge to start/end point.
  • Take either the start or end vertex of this edge (for Dijkstra/ A-Star) or the complete edge (Shooting-Star) as start of the route and end respectively.
  • Make the Shortest Path database query.
  • Transform the query result to XML and send it back to the web client.
<?php

  // Database connection settings
  define("PG_DB"  , "routing");
  define("PG_HOST", "localhost");
  define("PG_USER", "postgres");
  define("PG_PORT", "5432");
  define("TABLE",   "victoria");

  $counter = $pathlength = 0;

  // Retrieve start point
  $start = split(' ',$_REQUEST['startpoint']);
  $startPoint = array($start[0], $start[1]);

  // Retrieve end point
  $end = split(' ',$_REQUEST['finalpoint']);
  $endPoint = array($end[0], $end[1]);

  /* ... */
?>

Select closest edge

Usually the start and end point, which we retrieved from the client, is not the start or end vertex of an edge. It is more convenient to look for the closest edge than for the closest vertex, because Shooting Star algorithm is “edge-based”. For “vertex-based” algorithms (Dijkstra, A-Star) we can choose arbitrary start or end of the selected edge.

<?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].")', 54004)) AS dist
                FROM ".TABLE."
                WHERE the_geom && setsrid(
                      'BOX3D(".($lonlat[0]-200)."
                             ".($lonlat[1]-200).",
                             ".($lonlat[0]+200)."
                             ".($lonlat[1]+200).")'::box3d, 54004)
                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;
  }
?>

Routing Query

<?php
  // Select the routing algorithm
  switch($_REQUEST['method']) {
?>

For Shortest Path Dijkstra

<?php
        case 'SPD' : // Shortest Path Dijkstra

          $sql = "SELECT rt.gid, AsText(rt.the_geom) AS wkt,
                       length(rt.the_geom) AS length, ".TABLE.".id
                    FROM ".TABLE.",
                        (SELECT gid, the_geom
                            FROM dijkstra_sp_delta(
                                '".TABLE."',
                                ".$startEdge['source'].",
                                ".$endEdge['target'].",
                                3000)
                         ) as rt
                    WHERE ".TABLE.".gid=rt.gid;";
          break;
?>

For Shortest Path A-Star

<?php
        case 'SPA' : // Shortest Path A*

          $sql = "SELECT rt.gid, AsText(rt.the_geom) AS wkt,
                         length(rt.the_geom) AS length, ".TABLE.".id
                      FROM ".TABLE.",
                          (SELECT gid, the_geom
                              FROM astar_sp_delta(
                                  '".TABLE."',
                                  ".$startEdge['source'].",
                                  ".$endEdge['target'].",
                                  3000)
                           ) as rt
                      WHERE ".TABLE.".gid=rt.gid;";
          break;
?>

For Shortest Path Shooting-Star

<?php
        case 'SPS' : // Shortest Path Shooting*

          $sql = "SELECT rt.gid, AsText(rt.the_geom) AS wkt,
                         length(rt.the_geom) AS length, ".TABLE.".id
                      FROM ".TABLE.",
                          (SELECT gid, the_geom
                              FROM shootingstar_sp(
                                  '".TABLE."',
                                  ".$startEdge['gid'].",
                                  ".$endEdge['gid'].",
                                  5000, 'length', true, true)
                           ) as rt
                      WHERE ".TABLE.".gid=rt.gid;";
          break;
?>

Query database

<?php
  } // 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);
?>

XML output

OpenLayers allows to draw lines directly using WKT (Well-Known Text) format. This makes the XML output short and simple:

<?php
  // Return route as XML
  $xml  = '<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>'."\n";
  $xml .= "<route>\n";

  // Add edges to XML file
  while($edge=pg_fetch_assoc($query)) {

        $pathlength += $edge['length'];

        $xml .= "\t<edge id='".++$counter."'>\n";
        $xml .= "\t\t<id>".$edge['id']."</id>\n";
        $xml .= "\t\t<wkt>".$edge['wkt']."</wkt>\n";
        $xml .= "\t\t<length>".round(($pathlength/1000),3)."</length>\n";
        $xml .= "\t</edge>\n";
  }

  $xml .= "</route>\n";

  // Close database connection
  pg_close($dbcon);

  // Return routing result
  header('Content-type: text/xml',true);
  echo $xml;
?>