ホームページ  >  記事  >  バックエンド開発  >  PHPで近くにいる人の検索を実装する方法

PHPで近くにいる人の検索を実装する方法

藏色散人
藏色散人オリジナル
2020-10-22 09:56:492564ブラウズ

php メソッドで近くにいる人の検索を実装します。最初に経度と緯度の範囲を計算する関数を宣言し、次にこの経度と緯度の範囲内の条件を満たすすべてのレコードをデータベースから検索し、最後に経度をクエリします。 「$radius」の緯度と範囲内の発電所の詳細な住所で十分です。

PHPで近くにいる人の検索を実装する方法

# 推奨: 「

PHP ビデオ チュートリアル

最近のプロジェクトでは、ユーザーの現在位置の経度と緯度に基づいて、ユーザーから 10 キロメートル以内にいる人々にクエリを実行する必要があります。この関数は、それほど技術的な実装ではありません (もちろん、When the function についてのみ参照します)。内容自体もデータ量も少ないので、そこから派生する他の問題は長らく含まれていません)が、いろいろ検討した結果、記録することにしました。

今後、APPサーバー開発でもWEB開発でも、お客様からそのような機能を求められることが多くなるので、その原理をしっかりとマスターする必要があります。

[問題提起]

この問題についてどのように考えるべきでしょうか? 「現在のユーザーの経度と緯度はすでにわかっているので、データベースからユーザーの経度と緯度をクエリし、それらを 1 つずつ計算して、資格のあるユーザーをすべて除外します。」## と言いたい友人もいるかもしれません。

#私はかつて、データベースの感情を考慮せずに、それを当然のこととして考えていました。10 万レベル、100 万レベルのデータベースを運用している場合、そのようなアプローチによって引き起こされる問題は壊滅的なものになります。毛糸にしましょうか?

[実装アイデア]

まず、次のように考える必要があります。ユーザーの現在位置の経度、緯度と、検索する範囲がわかったので、次のように考えることができます。範囲を計算しますか?つまり、中心点と半径をもとに、条件を満たす経度と緯度の最大値と最小値を計算します。

[具体的な実装]

したがって、ここで、独自に考えて完成させたい友人は、これ以上読まないでください。

この機能の実装原理については上で説明しましたが、その後、具体的な実装手順について説明します。

最初に、緯度と経度の範囲を計算する関数を宣言します。

/**
 * 根据经纬度和半径计算出范围
 * @param string $lat 纬度
 * @param String $lng 经度
 * @param float $radius 半径
 * @return Array 范围数组
 */private function calcScope($lat, $lng, $radius) {
    $degree = (24901*1609)/360.0;    $dpmLat = 1/$degree;    $radiusLat = $dpmLat*$radius;    $minLat = $lat - $radiusLat;       // 最小纬度
    $maxLat = $lat + $radiusLat;       // 最大纬度

    $mpdLng = $degree*cos($lat * (PI/180));    $dpmLng = 1 / $mpdLng;    $radiusLng = $dpmLng*$radius;    $minLng = $lng - $radiusLng;      // 最小经度
    $maxLng = $lng + $radiusLng;      // 最大经度

    /** 返回范围数组 */
    $scope = array(        'minLat'    =>  $minLat,        'maxLat'    =>  $maxLat,        'minLng'    =>  $minLng,        'maxLng'    =>  $maxLng
        );    return $scope;
}

返される配列には、$radius 範囲内の条件を満たす最大および最小の緯度と経度が含まれます。

範囲を取得したので、この経度と緯度の範囲内の条件を満たすすべてのレコードをデータベースから検索できます:

/**
 * 根据经纬度和半径查询在此范围内的所有的
 * @param  String $lat    纬度
 * @param  String $lng    经度
 * @param  float $radius 半径
 * @return Array         计算出来的结果
 */public function searchByLatAndLng($lat, $lng, $radius) {
    $scope = $this->calcScope($lat, $lng, $radius);     // 调用范围计算函数,获取最大最小经纬度
    /** 查询经纬度在 $radius 范围内的电站的详细地址 */
    $sql = &#39;SELECT `字段` FROM `表名` WHERE `Latitude` < &#39;.$scope[&#39;maxLat&#39;].&#39; and `Latitude` > &#39;.$scope[&#39;minLat&#39;].&#39; and `Longitude` < &#39;.$scope[&#39;maxLng&#39;].&#39; and `Longitude` > &#39;.$scope[&#39;minLng&#39;];    $stmt = self::$db->query($sql);    $res = $stmt->fetchAll(PDO::FETCH_ASSOC);       // 获取查询结果并返回
    return $res;
}

[拡張]

これまで、近くの人々を計算する方法はすでにわかっていましたが、実際のニーズでは、現在の中心点から各人物の実際の距離を計算する必要があることがよくあります。

次に、方法を見てみましょう:

/**
 * 获取两个经纬度之间的距离
 * @param  string $lat1 纬一
 * @param  String $lng1 经一
 * @param  String $lat2 纬二
 * @param  String $lng2 经二
 * @return float  返回两点之间的距离 */public function calcDistance($lat1, $lng1, $lat2, $lng2) {    /** 转换数据类型为 double */
    $lat1 = doubleval($lat1);    $lng1 = doubleval($lng1);    $lat2 = doubleval($lat2);    $lng2 = doubleval($lng2);    /** 以下算法是 Google 出来的,与大多数经纬度计算工具结果一致 */
    $theta = $lng1 - $lng2;    $dist = sin(deg2rad($lat1)) * sin(deg2rad($lat2)) +  cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * cos(deg2rad($theta));    $dist = acos($dist);    $dist = rad2deg($dist);    $miles = $dist * 60 * 1.1515;    return ($miles * 1.609344);
}

条件を満たすすべての近くの人の経度と緯度を事前に計算しました。その後、各人の経度と緯度を現在の経度と組み合わせることができます。中心点 経度と緯度をパラメータとして関数に渡し、最終的に各資格者と中心点との距離を計算します。

プログラムの厳密性を確保するために、次の説明をしなければなりません:

緯度と経度の範囲の計算方法は Baidu で見つかりました。現在、標準的な計算ツールはありません。が見つかったので、このアルゴリズムは検証できませんが、ほとんどの投稿は基本的にこの計算方法を使用しています。

緯度経度距離の計算方法はGoogleで見つけたもので、計算結果はほとんどの計算ツールと同様です。なぜGoogleで検索したかというと、Baiduで色々な計算方法を調べたのですが、満足のいく結果が得られなかったからです。

半径と緯度経度によって範囲を計算する場合、半径の単位は m で、距離を計算する場合、結果は km になります。したがって、単位の変更には注意してください。
私はまだ検証を試みており、より正確な計算結果を得るために専門家の助けを求めています。

以上がPHPで近くにいる人の検索を実装する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。