本文概述
如今, 许多应用程序提供的最流行的功能之一就是可以在给定自定义位置(你当前的位置, 可能指定纬度和经度)的情况下从数据库中找到最近的寄存器。例如, 在房地产业务中, 这是一个非常有用的实现, 如果你可以简单地将自己放置在城市中心(例如纽约), 该应用程序将允许你在地图上显示最近的可用房屋/公寓。半径为50/100公里:
这个想法本身很酷, 对吧?显然, 我们没有包括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;
它仅存储由名称标识的标记, 并包含纬度和经度的坐标。它包含以下数据:
如果我们使用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
});
}
}
我们将在地图中获得以下输出:
现在, 一切正常, 地图正常, 标记在正确的位置, 但是现在, 我们需要根据我们的位置(Bucaramanga)和特定的距离半径对它们进行过滤。我们不会在本文中介绍如何使用JavaScript过滤它们, 而仅在服务器端进行过滤, 因此你可以自行决定如何稍后在前端中显示它们。
2.了解我们需要做什么
首先, 我们需要了解我们将在数据库中进行理论上的操作。以下模式展示了我们需要完成以完成任务的两个问题, 其中包括我们将搜索一个圆形区域, 该圆形区域由我们将其称为搜索半径的某个距离定义:
知道初始位置和其他坐标之间的距离是未知的:
- 我们如何从起点定义搜索半径?
- 我们如何知道位置在搜索半径内?
好吧, 基本上, 要定义搜索半径, 你将是一个定义该距离的纯数字值的用户, 例如, 我们将使用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 coordinates
echo 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 150
SELECT * 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`
) myTable
WHERE distance <= $DISTANCE_KILOMETERS
LIMIT 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 150
SELECT * 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`
) myTable
WHERE distance <= $DISTANCE_MILES
LIMIT 15;
4.测试查询
现在我们有了搜索半径距离, 我们最终可以测试查询以替换值并简单地运行它(在屏幕快照中, 我们使用140.85而不是150, 但基本相同):
现在, 使用给定的值, 我们的查询总共以图形和数学方式完全匹配了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 connection
if ($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 = <<<EOF
SELECT * 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`
) markers
WHERE distance <= $distance
LIMIT 15;
EOF;
$result = $conn->query($query);
if ($result->num_rows > 0) {
// output data of each row
while($row = $result->fetch_assoc()) {
echo $row["name"] . "<br>";
}
}
// Outputs:
// Barrancabermeja
// Cúcuta
// San Gil
编码愉快!
评论前必须登录!
注册