2011年4月25日月曜日

16 pgRouting in Debian6 9 - PHP を使ったサーバサイドスクリプト

8. Server side script with PHP
http://workshop.pgrouting.org/chapters/php_server.html

を参考に PHP を使ってルーティングの結果を Web クライアントに送るコードを作成します。
内容を訳してみます。

*****
次の工程が必要です。

* 開始点と終了点の座標の取得。
* 始点/終点ポイントに最も近いエッジを検索。
* このエッジの開始または終了の頂点(Dijkstra/A-Starの場合)またはルートの始点と終点のそれぞれ完全なエッジ(シューティングスター)のいずれかの取得。
* 最短経路データベースクエリの作成。
* クエリの結果をXMLへ、または、よりよい GeoJSON へ変換し Web クライアントに送り返す。

いくつかの PHP テンプレートで始めます。それから、このファイルを Apache でアクセス可能なディレクトリに配置します:
*****

上記に従って、Eclipse を起動して workspase を mapsite ディレクトリにし、 新規に routingproj プロジェクトを作成します。

1 Eclipse を起動し、Aptana Web パースペクティブで、ファイル->新規->新規プロジェクトをクリックします。
2 「プロジェクト」ウィンドウの「プロジェクト名」に「routingproj」と入力し「次へ」ボタンをクリックします。
3 「Project Template」で「完了」ボタンをクリックします。


PHP コードの作成を支援するため PDT をインストールします。

Eclipseのメインメニューより、「Help → Software Updates → Find and Install」から「使用可能なソフトウェア」ウィンドウの「作業対象」で「Helios - http://download.eclipse.org/releases/helios」を選択します。
「名前」に表示された「PHP 開発ツール (PDT) SDK フィーチャー 2.2.1.v20101001-2300-53184QAN4JBQgLYPWMLcXn6Na9Od」にチェックをつけ「次へ」ボタンをクリックします。
「インストール詳細」ウィンドウで「次へ」ボタンをクリックします。
「ライセンスのビュー」ウィンドウで、「使用条件に同意します」をチェックし「完了」ボタンをクリックします。


次の内容の pgrouting.php ファイルを routingproj/php フォルダに作成します。
(注釈:このコードは、データベースの接続と始点及び終点のデータを取り戻しています。)

<?php

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

// 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]);

?>


8.1. Closest edge の内容を訳してみます。

*****
通常、クライアントから取得される始点と終点は、エッジの始点または終点の頂点ではありません。Shooting Star アルゴリズムは、"エッジベース"なので、最も近い頂点に比べて最も近いエッジを探す方が便利です。 "頂点ベースの"アルゴリズム(Dijkstra、A-Star)では、選択されたエッジの任意の始点またはの終点を選択することができます。
*****

<?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;
}

?>

8.2. Routing query
(注釈:ルーティングクエリーの実行)

<?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);

?>

8.3. GeoJSON output の内容を訳してみます。

*****
OpenLayers は、直接 GeoJSON 形式を使用して線を描画することができます。なので、このスクリプトは、GeoJSON FeatureCollection オブジェクトを返します。:
*****

<?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(
'id' => $edge['id'],
'length' => $edge['length']
)
);

// 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 件のコメント: