如何使用PHP,MySQL从一组坐标(经度和纬度)中查找最近的位置

本文概述

  • 1.了解我们的标记数据库
  • 2.了解我们需要做什么
  • 3.准备最近的位置查询
  • 4.测试查询
如今, 许多应用程序提供的最流行的功能之一就是可以在给定自定义位置(你当前的位置, 可能指定纬度和经度)的情况下从数据库中找到最近的寄存器。例如, 在房地产业务中, 这是一个非常有用的实现, 如果你可以简单地将自己放置在城市中心(例如纽约), 该应用程序将允许你在地图上显示最近的可用房屋/公寓。半径为50/100公里:
如何使用PHP,MySQL从一组坐标(经度和纬度)中查找最近的位置 这个想法本身很酷, 对吧?显然, 我们没有包括Google Maps中的地点, 这意味着这些标记显然是我们的, 它们存储在我们自己的数据库中。在本文中, 我们将向你解释如何从MySQL的坐标集合中知道最近的位置。
1.了解我们的标记数据库 首先, 你显然需要在数据库中存储位置, 在我们的情况下, 我们将拥有非常简单的数据库结构, 因此每个人都可以轻松理解它。可以使用以下查询创建数据库:
CREATE TABLE `markers` (`id` bigint(20) NOT NULL, `lat` decimal(10, 8) NOT NULL, `lng` decimal(11, 8) NOT NULL, `name` varchar(255) CHARACTER SET utf8 NOT NULL) ENGINE=InnoDB DEFAULT CHARSET=utf8;

它仅存储由名称标识的标记, 并包含纬度和经度的坐标。它包含以下数据:
如何使用PHP,MySQL从一组坐标(经度和纬度)中查找最近的位置 如果我们使用JavaScript在Google地图中放置上述位置的标记:
var markers = [{"id": "1", "lat": "4.66455174", "lng": "-74.07867091", "name": "Bogot\u00e1"}, {"id": "2", "lat": "6.24478548", "lng": "-75.57050110", "name": "Medell\u00edn"}, {"id": "3", "lat": "7.06125013", "lng": "-73.84928550", "name": "Barrancabermeja"}, {"id": "4", "lat": "7.88475514", "lng": "-72.49432589", "name": "C\u00facuta"}, {"id": "5", "lat": "3.48835279", "lng": "-76.51532198", "name": "Cali"}, {"id": "6", "lat": "4.13510880", "lng": "-73.63690401", "name": "Villavicencio"}, {"id": "7", "lat": "6.55526689", "lng": "-73.13373892", "name": "San Gil"}]; function setMarkers(map) {var image = {url: 'https://developers.google.com/maps/documentation/javascript/examples/full/images/beachflag.png', size: new google.maps.Size(20, 32), origin: new google.maps.Point(0, 0), anchor: new google.maps.Point(0, 32)}; for (var i = 0; i < markers.length; i++) {var marker = markers[i]; var marker = new google.maps.Marker({position: {lat: parseFloat(marker.lat), lng: parseFloat(marker.lng)}, map: map, icon: image, shape: {coords: [1, 1, 1, 20, 18, 20, 18, 1], type: 'poly'}, title: marker.name}); }}

我们将在地图中获得以下输出:
如何使用PHP,MySQL从一组坐标(经度和纬度)中查找最近的位置 【如何使用PHP,MySQL从一组坐标(经度和纬度)中查找最近的位置】现在, 一切正常, 地图正常, 标记在正确的位置, 但是现在, 我们需要根据我们的位置(Bucaramanga)和特定的距离半径对它们进行过滤。我们不会在本文中介绍如何使用JavaScript过滤它们, 而仅在服务器端进行过滤, 因此你可以自行决定如何稍后在前端中显示它们。
2.了解我们需要做什么 首先, 我们需要了解我们将在数据库中进行理论上的操作。以下模式展示了我们需要完成以完成任务的两个问题, 其中包括我们将搜索一个圆形区域, 该圆形区域由我们将其称为搜索半径的某个距离定义:
如何使用PHP,MySQL从一组坐标(经度和纬度)中查找最近的位置 知道初始位置和其他坐标之间的距离是未知的:
  • 我们如何从起点定义搜索半径?
  • 我们如何知道位置在搜索半径内?
好吧, 基本上, 要定义搜索半径, 你将是一个定义该距离的纯数字值的用户, 例如, 我们将使用150公里!对于我们的初始点, 我们将使用本示例中哥伦比亚布卡拉曼加市的坐标:
  • 拉特:7.08594109039762
  • lng:286.95225338731285
3.准备最近的位置查询 现在, 要回答我们先前提出的第二个问题:” 如何知道某个位置何时在搜索半径内?” , 只要初始点(红色标记, 布卡拉曼加)与位置(“ 某些标志” )小于定义的搜索半径(150)。那么, 我们如何找到位置与初始点之间的距离?为此, 我们将需要找到坐标之间的距离。这是通过大量的数学运算完成的, 在本文中我们将不做解释, 因为否则它会变得很无聊, 因此, 我们可以使用PHP函数来恢复它, 这更有趣:
< ?php /** * Method to find the distance between 2 locations from its coordinates. * * @param latitude1 LAT from point A * @param longitude1 LNG from point A * @param latitude2 LAT from point A * @param longitude2 LNG from point A * * @return Float Distance in Kilometers. */function getDistanceBetweenPointsNew($latitude1, $longitude1, $latitude2, $longitude2, $unit = 'Mi') {$theta = $longitude1 - $longitude2; $distance = sin(deg2rad($latitude1)) * sin(deg2rad($latitude2)) + cos(deg2rad($latitude1)) * cos(deg2rad($latitude2)) * cos(deg2rad($theta)); $distance = acos($distance); $distance = rad2deg($distance); $distance = $distance * 60 * 1.1515; switch($unit) { case 'Mi': break; case 'Km' : $distance = $distance * 1.609344; }return (round($distance, 2)); }

这就是我们基本上要做的, 以便从它们的坐标知道2个位置之间的距离, 例如Bucaramanga之间的距离:
  • 拉特:7.08594109039762
  • lng:286.95225338731285
和库库塔:
  • 拉特:7.88475514
  • lng:-72.49432589
将会:
// Outputs: 107.76, distance in km between the given coordinatesecho getDistanceBetweenPointsNew(7.08594109039762, 286.95225338731285, 7.88475514, -72.49432589, 'Km');

了解了这一点, 我们将对SQL进行相同的操作, 这将在查询中为我们提供一个新列, 即距离, 该列包含来自给定坐标的值。如果你以公里或英里为单位, 则实现此目的的SQL查询将有所不同:
A.搜索公里
--- Where: --- $LATITUDE = the latitude of the start point e.g 7.08594109039762; --- $LONGITUDE = the longitude of the start point e.g 286.95225338731285; --- $DISTANCE_KILOMETERS = your radius of search in Kilometers e.g 150SELECT * FROM (SELECT *, (((acos(sin(( $LATITUDE * pi() / 180))*sin(( `latitud_fieldname` * pi() / 180)) + cos(( $LATITUDE * pi() /180 ))*cos(( `latitud_fieldname` * pi() / 180)) * cos((( $LONGITUDE - `longitude_fieldname`) * pi()/180)))) * 180/pi()) * 60 * 1.1515 * 1.609344)as distance FROM `myTable`) myTableWHERE distance < = $DISTANCE_KILOMETERSLIMIT 15;

B.英里搜索
--- Where: --- $LATITUDE = the latitude of the start point e.g 7.08594109039762; --- $LONGITUDE = the longitude of the start point e.g 286.95225338731285; --- $DISTANCE_MILES = your radius of search in Miles e.g 150SELECT * FROM (SELECT *, (((acos(sin(( $LATITUDE * pi() / 180))*sin(( `latitud_fieldname` * pi() / 180)) + cos(( $LATITUDE * pi() /180 ))*cos(( `latitud_fieldname` * pi() / 180)) * cos((( $LONGITUDE - `longitude_fieldname`) * pi()/180)))) * 180/pi()) * 60 * 1.1515)as distance FROM `myTable`) myTableWHERE distance < = $DISTANCE_MILESLIMIT 15;

4.测试查询 现在我们有了搜索半径距离, 我们最终可以测试查询以替换值并简单地运行它(在屏幕快照中, 我们使用140.85而不是150, 但基本相同):
如何使用PHP,MySQL从一组坐标(经度和纬度)中查找最近的位置 现在, 使用给定的值, 我们的查询总共以图形和数学方式完全匹配了3个与搜索匹配的位置。你最终可以使用PHP运行查询, 以根据需要处理结果:
< ?php$servername = "localhost"; $username = "root"; $password = ""; $dbname = "test"; // Create connection$conn = new mysqli($servername, $username, $password, $dbname); mysqli_set_charset($conn, "utf8"); // Check connectionif ($conn-> connect_error) {die("Connection failed: " . $conn-> connect_error); }// Bucaramanga Coordinates$lat = 7.08594109039762; $lon = 286.95225338731285; // Only show places within 100km$distance = 150; $lat = mysqli_real_escape_string($conn, $lat); $lon = mysqli_real_escape_string($conn, $lon); $distance = mysqli_real_escape_string($conn, $distance); $query = < < < EOFSELECT * FROM (SELECT *, (((acos(sin(( $lat * pi() / 180))*sin(( `lat` * pi() / 180)) + cos(( $lat * pi() /180 ))*cos(( `lat` * pi() / 180)) * cos((( $lon - `lng`) * pi()/180)))) * 180/pi()) * 60 * 1.1515 * 1.609344)as distance FROM `markers`) markersWHERE distance < = $distanceLIMIT 15; EOF; $result = $conn-> query($query); if ($result-> num_rows > 0) {// output data of each rowwhile($row = $result-> fetch_assoc()) {echo $row["name"] . "< br> "; }}// Outputs:// Barrancabermeja// Cúcuta// San Gil

编码愉快!

    推荐阅读