BLOG

距離を計算して近くの○○を表示させる

| JavaScriptWordPress

今いる場所を取得できるようになってから、近くの〇〇などの表示が便利ですよね。

僕も検索で、「近くのコンビニ」なんて言ったりします。

ってことで今回は距離を計算して近くの〇〇を表示したったです。

距離の計算方法

ざっくりと距離を計算する方法として

  • Lambert-Andoyer
    測地線航海算法を利用した計算。計算時間は最もかかるが一番正確。
  • Hubenyの公式
    赤道が膨らん考慮されているが、距離が離れると誤差がひどくなる
  • Haversineの公式
    球面三角法を利用した計算。球であることが前提で、楕円ではないので地球にあてはめると誤差が出る。

というのがあるそうです。
今回はHubenyの公式を使ってやってみます。
地図ソフト等でも使われているので結構信頼できるんじゃないかなと思います。

/*
 * Hubenyの公式
 * @param   float   $lat1       始点緯度
 * @param   float   $lon1       始点経度
 * @param   float   $lat2       終点緯度
 * @param   float   $lon2       終点経度
 * @return  float               距離(Km)
 */

function d_hubeny($lat1, $lng1, $lat2, $lng2) {
    $radlat  = deg2rad(abs($lat1 - $lat2));
    $radlng  = deg2rad(abs($lng1 - $lng2));
    $average = deg2rad($lat1 + (($lat2 - $lat1) / 2));
    $meridian = 0;
    $prime    = 0;

    $temp     = 1.0 - 0.00669438 * pow(sin($average),2);
    $meridian = 6335439.0 / sqrt(pow($temp,3));
    $prime    = 6378137.0 / sqrt($temp);

    return round(sqrt(pow($meridian*$radlat,2) + pow($prime*cos($average)*$radlng,2)),3) / 1000;
}

これはこのまま使ったらいいと思います。
なのであとは始点と終点の2点の経度緯度を送ってやれば距離がでます。

近いお店を取得する

ってことで、今回はWordPressでお店を登録していてAというお店の近くのお店を取得するみたいなことをやってみたいと思います。

// 基準(始点)のお店の経度緯度を取得
$lat = get_post_meta($post->ID,'Map_lat',true);
$lng = get_post_meta($post->ID,'Map_lng',true);

$shopitems = get_posts(
    array(
        'post_type' => 'shop', // ショップ用のカスタム投稿
        'posts_per_page' => -1, // 全ポストを取得
    )
);

foreach( $shopitems as $key => $val ) {
    // POSTの経度緯度(終点)を取得
    $shopLat = get_post_meta($val->ID,'Map_lat',true);
    $shopLng = get_post_meta($val->ID,'Map_lng',true);

    // 距離を取得
    $distance = d_hubeny($lat, $lng, $shopLat, $shopLng);
    // 取得した距離を挿入
    $shopitems[$key]->distance = $distance;
}

// 距離でソートを行う
// ソートを基準を設定
foreach ($shopitems as $key => $val) {
    $dist[$key] = $val->distance;
}
// ソートする
array_multisort($dist, SORT_ASC, $shopitems);
// 近くの8件のショップを表示するときは
$spotitems = array_slice($spotitems, 0, 8);

あとは表示するためにforeachで回してのコードを書くだけですね。

距離(10km以内とか)で取得する

距離(10km以内)で店を取得したい場合はforeachで距離を取得してるときに10km以上の場合は消しちゃう感じにして消したところを詰めてソートするって感じでしょうか。

// これ以前は上のと一緒です。

foreach( $shopitems as $key => $val ) {
    // POSTの経度緯度(終点)を取得
    $shopLat = get_post_meta($val->ID,'Map_lat',true);
    $shopLng = get_post_meta($val->ID,'Map_lng',true);

    // 距離を取得
    $distance = d_hubeny($lat, $lng, $shopLat, $shopLng);
    if($distance > 10) {
        unset($shopitems[$key]); // 10km以上の場合は要素を消しちゃう
    } else {
        $shopitems[$key]->distance = $distance;
    }
}

// 消した要素を詰める
$shopitems = array_values($shopitems);

// これ以降も一緒。

JavaScriptを使って現在地の経度緯度を取得する

ちなみに近くので場所を取得はJavaScriptを使ったほうが簡単みたいです。

if (navigator.geolocation) {
    navigator.geolocation.getCurrentPosition( function( position ) {
        lat = position.coords.latitude;
      lng = position.coords.longitude;
    });
    return [lat, lng];
}

こういう感じで取得できるようなのでこの値をPHPに渡して始点にすれば現在地からの近くのお店を取得できますね。
思ってる以上に簡単ですよね。

PAGE TOP