LoginSignup
4
6

More than 5 years have passed since last update.

メートル単位で半径を指定して円形のポリゴンをKMLで出力するAPI

Last updated at Posted at 2014-12-05

前提とする環境 PHP+PostgreSQL(PostGIS)

こちらの説明は以下の環境を前提としています。
・PHPが動作するWebサーバ(IIS,Apache,Nginx)など
・PostgreSQL(PostGISの拡張機能を利用します)

PostGISのインストール

PostgreSQL 9.1 以上のバージョンでは、PostGISの導入がSQLの実行だけで完了するため非常に簡単になりました。

CREATE EXTENSION postgis;

また、Amazon Web ServiceではRDSというPostgreSQLのデータベースをレンタルすることも可能です。

任意の半径のポリゴンをPostGISで作成する

GIS処理の基本

簡単ですが、PostgreSQLのGIS処理の概念を説明です。詳しくはドキュメントを御覧ください。

データ型

PostGISには空間情報を処理するために専用のデータ型が2つ有ります。
・平面データの geometry型
・球面データの geography型

今回は簡単かつ正確にメートル単位での円形を作成するために球面データを扱う、geography型を用います。

SQLによる円形ポリゴンの作成

PostGISの関数を活用して、緯度経度から点を作成し、点を円形のポリゴンに変換します。
複数の関数を組み合わせて処理するため、それぞれの関数毎にステップを踏んで説明致します。

今後はソースコードの中で、緯度をlat、経度をlonと表記します。

ステップ1 : 点データの作成

ST_Point関数を用いて、点データを作成します。

点の作成
 SELECT ST_POINT( lon, lat) ;

ステップ2 : 球面データ型へキャスト

ステップ1では平面データ型のgeometry型が生成されているので、geography関数を用いて球面データ型のgeography型へキャストします。

geometry型からgeography型へキャスト
 SELECT GEOGRAPHY( ST_POINT( lon, lat) );

ステップ3 : 点を円形に変換

点を円バッファに変換します。ST_Buffer( geography型 , 半径(メートル))関数を用いて、点データを円形のポリゴンデータに変換します。例では1,000m

ポイントデータからポリゴンデータに
 SELECT ST_Buffer( GEOGRAPHY( ST_POINT( lon, lat) ) , 1000 );

ステップ4 : KMLのポリゴンタグへ変換

ST_AsKMLを用いて、geography型からkmlのポリゴン形状の定義部分の文字列を出力します。

geography型からKML文字列へ変換
 SELECT ST_AsKML(ST_Buffer( GEOGRAPHY( ST_POINT( lon, lat) ) , 1000 ));

PHPによるAPI化

緯度経度と半径をパラメータとして取得し、動的に円形のポリゴンを出力するAPIを作成します。

入力パラメータ

  • lon : 経度
  • lat:緯度
  • r : 半径
  • color : 色 ( αbgr ) 今回は各値にデフォルト値を用意して、入力が無くても動作します。

URL例

http://ドメイン名/getcircle.php?lon=140.0&lat=36.6&r=300&440000ff

getcircle.php
<?php
//データベースへ接続
$conn_string = "host=localhost port=5432 dbname=database1 user=user1 password=*****";
$conn = pg_pconnect($conn_string);
if (!$conn) {
  echo "An error occurred.\n";
  exit;
}

//パラメータの取得
if(isset($_GET['lon']) ){
$lon = $_GET['lon'];
} else {
    $lon=139.989136553437;
}
if(isset($_GET['lat']) ){
$lat = $_GET['lat'];
}else {
    $lat = 35.65945922265559;
}
if(isset($_GET['r']) ){
$radius = $_GET['r'];
}else {
    $radius = 1000;

}
if(isset($_GET['o']) ){
$color = $_GET['o'];
}else {
 $color ="4cff7b00";
}

//SQLの作成
$sql ="SELECT ST_AsKML(ST_Buffer( GEOGRAPHY(ST_Point(".$lon.",".$lat.")) , ".$radius.")) AS p ;";
//検索実行
$result = pg_query($conn, $sql);
if (!$result) {
  echo "An error occurred.\n";
  exit;
}
//検索結果の取得
$row = pg_fetch_row($result);

//KML文字列の取得
$str = <<<EOD
<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2" xmlns:gx="http://www.google.com/kml/ext/2.2" xmlns:kml="http://www.opengis.net/kml/2.2" xmlns:atom="http://www.w3.org/2005/Atom">
<Document>
    <name></name>
    <Style id="s">
        <LineStyle>
            <color>{$color}</color>
        </LineStyle>
        <PolyStyle>
            <color>{$color}</color>
        </PolyStyle>
    </Style>
    <Placemark>
        <name>polygon</name>
        <styleUrl>#s</styleUrl>
        {$row[0]}
    </Placemark>
</Document>
</kml>
EOD;
header('Content-Type: application/vnd.google-earth.kml+xml kml');
header('Content-Disposition: attachment; filename="mar.kml"');
print $str;
?>
4
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
6