PHP中经纬度坐标距离计算及查询示例代码

超酷的站长 2024-12-17 10:53:11编程技术
182

在地理信息系统(GIS)和位置服务中,计算两点之间的距离是一个常见的需求。PHP作为一种广泛使用的服务器端脚本语言,提供了多种方法来计算经纬度坐标之间的距离。本文将详细介绍如何在PHP中计算两个经纬度坐标之间的距离,并提供示例代码,帮助开发者在实际项目中高效地实现这一功能。

经纬度坐标.webp

1. 前言

想要测试本文提供的几个功能函数,可以使用下面这个数据表结构及其数据

CREATE TABLE `user` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '用户id',
`name` varchar(60) DEFAULT NULL COMMENT '昵称',
`longitude` varchar(64) DEFAULT NULL COMMENT '经度',
`latitude` varchar(64) DEFAULT NULL COMMENT '纬度',
`remark` varchar(50) DEFAULT NULL COMMENT '备注',
`distance` varchar(20) DEFAULT NULL COMMENT '距离',
PRIMARY KEY (`id`)
) ENGINE=InnoDB COMMENT='用户表';
INSERT INTO `user` (`name`, `longitude`, `latitude`, `remark`, `distance`) VALUES ('中海九号公馆', '113.899529', '22.60063', '深圳市宝安区中海九号公馆', '3.66km');
INSERT INTO `user` (`name`, `longitude`, `latitude`, `remark`, `distance`) VALUES ('平峦山公园', '113.876462', '22.608322', '深圳市宝安区平峦山公园', '2.88km');
INSERT INTO `user` (`name`, `longitude`, `latitude`, `remark`, `distance`) VALUES ('铁仔山公园', '113.86359', '22.592355', '深圳市宝安区铁仔山公园', '1.16km');
INSERT INTO `user` (`name`, `longitude`, `latitude`, `remark`, `distance`) VALUES ('宝安公园', '113.902671', '22.58621', '深圳市宝安区宝安公园', '3.45km');

本文内容测试各个功能函数时,使用的当前位置坐标均为:

// 深圳市宝安区西乡街道九方广场
$longitude = '113.869205';//经度
$latitude = '22.583286';//纬度

2. 计算经纬度坐标间的距离

计算经纬度坐标间的距离 功能函数 (前四个参数为两组经纬度坐标)

/**
* 计算经纬度坐标间的距离
* @param $lng1 经度
* @param $lat1 纬度
* @param $lng2 经度
* @param $lat2 纬度
* @param $lang 语言
*/
function get_distance($lng1, $lat1, $lng2, $lat2, $lang = 'en')
{
// 地球的近似半径(单位:米)
$earthRadius = 6367000;
// 将这些度数转换为弧度以使用公式
$lat1 = ($lat1 * pi()) / 180;
$lng1 = ($lng1 * pi()) / 180;
$lat2 = ($lat2 * pi()) / 180;
$lng2 = ($lng2 * pi()) / 180;
// 使用 Haversine 公示计算距离
// http://en.wikipedia.org/wiki/Haversine_formula
$calcLongitude = $lng2 - $lng1;
$calcLatitude = $lat2 - $lat1;
$stepOne = pow(sin($calcLatitude / 2), 2) + cos($lat1) * cos($lat2) * pow(sin($calcLongitude / 2), 2);
$stepTwo = 2 * asin(min(1, sqrt($stepOne)));
// 两个经纬度坐标的距离(单位: 米)
$calculatedDistance = round($earthRadius * $stepTwo);
// 距离单位
$language = [
'en' => ['m' => 'm', 'km' => 'km'],
'cn' => ['m' => '米', 'km' => '公里'],
];
if (!isset($language[$lang])) throw new \Exception('不支持的语言:' . $lang);
foreach ($language[$lang] as $key => $value) $$key = $value;
// 两个坐标间的距离,单位:米
$distance = round($calculatedDistance);
// 距离单位转换:超出 1000m 时单位转为km
if ($distance < 1000) {
$distance .= $m;
} else {
$distance = floatval(number_format($distance / 1000, 2)) . $km;
}
return $distance; // 返回单位转换后的距离
}

使用示例:

我在 九方广场,手机上的高德地图导航至 中海九号公馆 显示的距离为 3.6公里,计算结果还是很准确的

// 深圳市宝安区西乡街道九方广场: 113.869205, 22.583286
// 深圳市宝安区西乡街道中海九号公馆: 113.899529, 22.60063
$distance = get_distance(113.869205, 22.583286, 113.899529, 22.60063);
echo $distance; //3.66km

3. 根据经纬度坐标距离排序

项目中经常有距离显示数据的场景,根据距离排序,越近越靠前显示;比如: 店铺地址、房源信息等。代码示例:

// 当前坐标
$longitude = '113.869205';
$latitude = '22.583286';
// 数据库中经纬度字段分别为:longitude、latitude
$field = '*,( 2 * 6378.137 * ASIN( SQRT( POW( SIN( PI() * (' . $longitude . ' - longitude) / 360 ), 2 ) + COS(PI() * ' . $latitude . ' / 180) * COS(latitude * PI() / 180) * POW( SIN( PI() * (' . $latitude . ' - latitude) / 360 ), 2 ) ) ) ) AS juli';
// 根据距离升序查询(越近越靠前)
$order = 'juli asc,id desc';
// 查询数据
Db::name('user')->field($field)->order($order)->select();

4. 经纬度范围查询

经纬度范围计算 功能函数

/**
* 经纬度范围计算
* @param $longitude 经度
* @param $latitude 纬度
* @param $radius 半径(米)
* @return array
*/
function get_around($longitude, $latitude, $radius)
{
$PI = 3.14159265;
$degree = (24901 * 1609) / 360.0;
$dpmLat = 1 / $degree;
$radiusLat = $dpmLat * $radius;
$minLat = $latitude - $radiusLat;
$maxLat = $latitude + $radiusLat;
$mpdLng = $degree * cos($latitude * ($PI / 180));
$dpmLng = 1 / $mpdLng;
$radiusLng = $dpmLng * $radius;
$minLng = $longitude - $radiusLng;
$maxLng = $longitude + $radiusLng;
return compact('minLat', 'maxLat', 'minLng', 'maxLng');
}

使用示例

查询 3 公里内的数据。首先,根据当前位置获取 3 公里内的经纬度范围,然后带上查询条件查询数据库即可

$longitude = 113.869205; //经度
$latitude = 22.583286; //纬度
$radius = 3000; //单位:米
// 经纬度范围
$around = get_around($longitude, $latitude, $radius);
// 构造查询条件
// 数据库经纬度字段分别为:longitude,latitude
$where = [
['longitude', '>=', $around['minLng']],
['longitude', '<=', $around['maxLng']],
['latitude', '>=', $around['minLat']],
['latitude', '<=', $around['maxLat']],
];
// 按照经纬度范围查询数据
// 建议使用 where 的闭包查询(TP6.0)
// 因为闭包可以生成以下SQL,标明这几个查询条件是一个整体,便于后期维护
// SQL语句示例: SELECT * FROM `user` WHERE ( 经纬度查询条件 ) and 其他条件
$data = Db::name('user')
->where(function ($query) use ($where) {
$query->where($where);
})
->select();

总结

通过对PHP中经纬度坐标距离计算的详细解析,我们了解了多种计算方法及其应用场景。Haversine公式是最常用的方法,能够精确计算地球表面上两点之间的大圆距离。本文提供的示例代码展示了如何使用Haversine公式在PHP中计算两点之间的距离,并结合数据库查询实现了实际应用中的距离筛选功能。通过本文的学习,开发者可以掌握在PHP中处理经纬度坐标距离计算的方法,提高地理信息系统的开发效率和准确性。希望本文的内容能为读者在实际项目中提供有价值的参考和帮助。

php 经纬度 坐标
THE END
蜜芽
故事不长,也不难讲,四字概括,毫无意义。

相关推荐

PHP生成随机用户名的几种方法及示例代码
​在Web开发中,用户名的生成是一个常见的需求。为了确保用户名的唯一性和安全性,随机生成用户名成为了一种常见的做法。PHP作为一种流行的服务器端脚本语言,提供了多种方法...
2024-12-26 编程技术
235

PHP实现ICP网站备案查询API接口示例代码分享
在当今互联网环境中,ICP备案信息对于网站运营至关重要。ICP备案不仅是中国法律法规的要求,也是保障互联网信息安全的重要手段。为了方便网站管理员和开发者快速查询ICP备案信...
2024-12-26 编程技术
253

PHP使用GD库实现webp转jpg的示例代码及方法详解
PHP的GD库是一个强大的图像处理工具,可以轻松实现这一转换。本文将详细介绍如何使用PHP的GD库将WebP图像转换为JPEG格式,并提供示例代码,帮助开发者在实际项目中高效地实现...
2024-12-17 编程技术
207

PHP获取本机ip地址实例代码详解
在Web开发中,获取客户端的IP地址是一个常见的需求。无论是用于日志记录、用户行为分析,还是安全防护,了解客户端的IP地址都是非常有用的。本文ZHANID工具网将详细介绍如何使...
2024-12-13 编程技术
225

PHP调用API接口详解:从基础到实践
无论是构建微服务架构,还是与其他系统进行数据交换,API接口都是不可或缺的一部分。本文将详细介绍如何使用PHP调用API接口,涵盖三种常用的方法:curl库、file_get_contents...
2024-12-12 编程技术
206

PHP为任意网站生成网站地图(sitemap)代码分享
网站地图(Sitemap)是搜索引擎优化(SEO)的重要组成部分。它帮助搜索引擎更好地理解网站的结构和内容,从而提高网站的可见性和排名。对于使用PHP开发的网站来说,生成网站地图代...
2024-11-16 编程技术
308