9

これは、地理的位置を初めて見たものです。長い質問をお許しください。明確であることを願っています。

緯度と経度のレコードを保持するデータベースがあります。境界ボックスを形成する 4 つの 10 進座標を定義する PHP クラスを作成しようとしています (ボックス内のすべてのレコードを取得するため)。

ユーザーの場所からn km以内にある場所を知る必要があるだけです。ユーザーから場所までの距離は必要ありません。

私はこの答えの最初の部分に基づいています。

上記の回答の核心は次のとおりです。

直線で 10 km は次のとおりです。

on the latitude is equal to ~1'(minute)
on the longitude is equal to ~6'(minutes)

これを基礎として簡単な計算を行い、クエリで WHERE 句に追加して、緯度 1'、長さ 6' の仮定でバッファー ゾーンを追加することによって作成される「ボックス」の外側にある場所を削除します。

うーん、「簡単な計算をしてください」とパトリックは言います。数日後、私は正しく計算できませんでした。

私のクラスはそこにぶら下がっていて、10kmでうまくいくようです. ただし、他の距離では機能しません。

最初に秒に移動したので、10km は次のようになります。

on the latitude is equal to 60 seconds
on the longitude is equal to 360 seconds

これはうまくいきました。

しかし、私が試した5kmは次のとおりです。

on the latitude is equal to 30 seconds
on the longitude is equal to 180 seconds

これはうまくいきませんでした。

このアプローチが 5km (および私が試した他の距離) でうまくいかない理由を説明できますか?

以下は私のクラスコードです。明らかにスイッチはゴミです。どんな助けでも感謝します。

class coords 
{
/*
    Calculate a bounding box from a decimal coordinate and distance.
    The public vars are populated with minimum and maximum longitudes and latitudes which define the boundary.
*/
    public $dec_lat_min;
    public $dec_lat_max;
    public $dec_lng_min;
    public $dec_lng_max;

    function init($dec_lat, $dec_lng, $dist) 
    { 
        // This switch is a terrible way to allow multiple distances.

        // 10km = 1 min lat = 60 sec lat
        // 10km = 6 min lng = 360 sec lng

        // 5km = 30 sec lat
        // 5km = 180 sec lng

        // 1km = 6 sec lat
        // 1km = 36 sec lat

        // 500m = 3 sec lat
        // 500m = 18 sec lat

        switch($dist)
        {
            case 10: // 10km
                $sec_diff_lat = 60;
                $sec_diff_lng = 360;
                break;
            case 5: // 5km
                $sec_diff_lat = 30;
                $sec_diff_lng = 180;
                break;
            case 1: // 1km
                $sec_diff_lat = 6;
                $sec_diff_lng = 36;
                break;
            default: // 500m
                $sec_diff_lat = 3;
                $sec_diff_lng = 18;
                break;  
        }

        // Convert lat to DMS
        $dms_lat = $this->dec2dms($dec_lat);

        // Allow for western hemisphere (ie negative)
        $dms_lat['hem'] == '-' ? $h = -1 : $h = 1;

        // Populate min and max latitudes
        $this->dec_lat_min = $this->dms2dec($dms_lat['deg'],$dms_lat['min'],$dms_lat['sec']+(-1 * $sec_diff_lat * $h),$dms_lat['hem']);
        $this->dec_lat_max = $this->dms2dec($dms_lat['deg'],$dms_lat['min'],$dms_lat['sec']+($sec_diff_lat * $h),$dms_lat['hem']);

        $dms_lng = $this->dec2dms($dec_lng);

        $dms_lng['hem'] == '-' ? $h = -1 : $h = 1;

        $this->dec_lng_min = $this->dms2dec($dms_lng['deg'],$dms_lng['min'],$dms_lng['sec']+(-1 * $sec_diff_lng * $h),$dms_lng['hem']);
        $this->dec_lng_max = $this->dms2dec($dms_lng['deg'],$dms_lng['min'],$dms_lng['sec']+($sec_diff_lng * $h),$dms_lng['hem']);

    }

    function dec2dms($d) 
    {
        $d = (string)$d;

        // got dashes?
        if ($d[0] == "-") {
            $hem = '-';
            $dVal = substr($d,1);
        } else {
            $hem = '';
            $dVal = $d;
        }

        // degrees = degrees
        $dVals = explode('.', $dVal);
        $dmsDeg = $dVals[0];

        // * 60 = mins
        $dRemainder = ('0.'.$dVals[1]) * 60;
        $dmsMinVals = explode('.', $dRemainder);
        $dmsMin = $dmsMinVals[0];

        // * 60 again = secs
        $dMinRemainder = ('0.'.$dmsMinVals[1]) * 60;
        $dmsSec = round($dMinRemainder);

        return array("deg"=>$dmsDeg,"min"=>$dmsMin,"sec"=>$dmsSec, "hem"=>$hem);
    }

    function dms2dec($deg,$min,$sec,$hem) 
    {
        // find decimal latitude
        $d = $deg+((($min*60)+($sec))/3600);
        $d = $hem.$d;

        return $this->round100000($d);
    }

    function round100000($v) 
    {
        return round($v * 100000) / 100000;
    } 
}
4

2 に答える 2

1

直線で 10 km は: 経度で ~6 分に等しい

距離と経度の比率は一定ではなく、ユーザーの緯度に依存します。この関数を経度差に使用できます。

function distanceToLng($distance,$latDeg) {
    $latRad = $latDeg / 180 * M_PI;
    $R = 6371;
    return atan2(1*sin($distance/$R)*cos($latRad), cos($distance/$R) - sin($latRad)*sin($latRad)) * (180 / M_PI);
}

式はこの質問から取得されます。

次のようなものを使用して、特定の距離から緯度の差を計算できます。

$lngDeg = $distanceInKm/6371 * 180 / M_PI
于 2012-07-20T18:51:04.677 に答える
0

他の回答が指摘したように、ユーザーの緯度を考慮した Haversine Formula を本当に使用したいと考えています。

Haversine Formula: http://en.wikipedia.org/wiki/Haversine_formula

この他の回答には、PHP または SQL でこれを達成するための優れたリソースがたくさんあります。

MySQL 大圏距離 (Haversine 式)

于 2012-07-20T19:06:35.507 に答える