1. 前言
想要测试本文提供的几个功能函数,可以使用下面这个数据表结构及其数据
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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' ); |
本文内容测试各个功能函数时,使用的当前位置坐标均为:
1 2 3 | // 深圳市宝安区西乡街道九方广场 $longitude = '113.869205' ; //经度 $latitude = '22.583286' ; //纬度 |
2. 计算经纬度坐标间的距离
计算经纬度坐标间的距离 功能函数 (前四个参数为两组经纬度坐标)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | /** * 计算经纬度坐标间的距离 * @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 公示计算距离 $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 |
使用示例:
我在 九方广场,手机上的高德地图导航至 中海九号公馆 显示的距离为 3.6公里,计算结果还是很准确的
1 2 3 4 | // 深圳市宝安区西乡街道九方广场: 113.869205, 22.583286 // 深圳市宝安区西乡街道中海九号公馆: 113.899529, 22.60063 $distance = get_distance(113.869205, 22.583286, 113.899529, 22.60063); echo $distance ; //3.66km |
3. 根据经纬度坐标距离排序
项目中经常有距离显示数据的场景,根据距离排序,越近越靠前显示;比如: 店铺地址、房源信息等。代码示例:
1 2 3 4 5 6 7 8 9 | // 当前坐标 $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. 经纬度范围查询
经纬度范围计算 功能函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | /** * 经纬度范围计算 * @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 公里内的经纬度范围,然后带上查询条件查询数据库即可
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | $longitude = 113.869205; //经度 $latitude = 22.583286; //纬度 $radius = 3000; //单位:米 // 经纬度范围 $around = get_around( $longitude , $latitude , $radius ); // 构造查询条件 // 数据库经纬度字段分别为:longitude,latitude $where = [ [ 'longitude' , '>=' , $around [ 'minLng' ]], [ 'longitude' , '=' , $around [ 'minLat' ]], [ 'latitude' , 'where( function ( $query ) use ( $where ) { $query ->where( $where ); }) ->select(); |
到此这篇关于PHP中经纬度坐标相关计算方法小结的文章就介绍到这了,更多相关PHP经纬度坐标计算内容请搜索IT俱乐部以前的文章或继续浏览下面的相关文章希望大家以后多多支持IT俱乐部!