无距离地理搜索

9
这是我第一次接触地理位置。请原谅我的长篇问题,希望它很清楚。
我有一个数据库,其中包含具有纬度和经度的记录。我正在尝试编写一个PHP类,定义四个小数坐标,形成一个边界框(然后检索框内的所有记录)。
我只需要知道哪些位置在用户位置附近的n公里范围内。我不需要知道用户到位置的距离。
我正在构建这个答案的第一部分。
上述答案的核心是:

10 km in a straight line is:

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

Using this as a basis, do some quick math and in your query add to the WHERE clause removing any locations that are outside the 'box' that is created by adding the buffer zone with the assumption of 1' lat & 6' long.

帕特里克说:“做些快速的数学计算。”我在几天后仍然没能正确地完成这个数学问题。

我的班级正在坚持下去,似乎可以运行10公里。然而,我无法使它适用于其他距离。

首先,我将距离转换为秒,那么10公里就是:

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

这个没问题。
但是,我接着尝试了“5km is:”。
on the latitude is equal to 30 seconds
on the longitude is equal to 180 seconds

这种方法不起作用。

您能解释一下为什么这种方法对5km(以及其他我尝试过的距离)无效吗?

以下是我的类代码。 显然,switch语句很糟糕。 感谢任何帮助。

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

1
+1 很好的问题/问题解释 - Manse
你能给一个表结构的例子吗? - Fluffeh
由于我正在进行实验,所以表格位于mySQL上:id(INT自动递增),description(文本),lng(FLOAT(10,6)),lat(FLOAT(10,6))。 - Polly
我没有选择这种方法。相反,我决定硬着头皮使用Postgres+Postgis,效果非常好。 - Polly
2个回答

1
10公里的直线距离大约相当于经度上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);
}

这个公式来自于this的问题。

你可以使用类似以下的方法计算给定距离的纬度差:

$lngDeg = $distanceInKm/6371 * 180 / M_PI

谢谢。我原本希望保持简单(和近似)。然而,现在我将拥抱数学并按照规范操作。 - Polly

0

非常感谢。您链接的页面有很棒的信息。 - Polly

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接