geohash实现附近的工作室,php函数实现-tp5
2023-03-07 09:47:15 时间
geohash简介:
geohash是一种地址编码,它能把二维的经纬度编码成一维的字符串。
geohash有以下几个特点:
首先,geohash用一个字符串表示经度和纬度两个坐标。某些情况下无法在两列上同时应用索引 (例如MySQL 4之前的版本,Google App Engine的数据层等),利用geohash,只需在一列上应用索引即可。
其次,geohash表示的并不是一个点,而是一个矩形区域。比如编码wx4g0ec19,它表示的是一个矩形区域。 使用者可以发布地址编码,既能表明自己位于北海公园附近,又不至于暴露自己的精确坐标,有助于隐私保护。
第三,编码的前缀可以表示更大的区域。例如wx4g0ec1,它的前缀wx4g0e表示包含编码wx4g0ec1在内的更大范围。 这个特性可以用于附近地点搜索。首先根据用户当前坐标计算geohash(例如wx4g0ec1)然后取其前缀进行查询 (SELECT * FROM place WHERE geohash LIKE ‘wx4g0e%’),即可查询附近的所有地点。Geohash比直接用经纬度的高效很多。
用途:
移动互联网,lbs可以说是一个基础应用,geohash对于解决附近地点搜索提供了一个有效的解决方案。
相关函数
/********** geohash是一种地址编码,它能把二维的经纬度编码成一维的字符串。
* 得到编码
* $latitude //纬度
* $longitude //经度
* $precision //精密度, 默认是12
* @return string
*/
function encode_geohash($latitude, $longitude, $deep)
{
$BASE32 = '0123456789bcdefghjkmnpqrstuvwxyz';
$bits = array(16,8,4,2,1);
$lat = array(-90.0, 90.0);
$lon = array(-180.0, 180.0);
$bit = $ch = $i = 0;
$is_even = 1;
$i = 0;
$geohash = '';
while($i < $deep)
{
if ($is_even)
{
$mid = ($lon[0] + $lon[1]) / 2;
if($longitude > $mid)
{
$ch |= $bits[$bit];
$lon[0] = $mid;
}else{
$lon[1] = $mid;
}
} else{
$mid = ($lat[0] + $lat[1]) / 2;
if($latitude > $mid)
{
$ch |= $bits[$bit];
$lat[0] = $mid;
}else{
$lat[1] = $mid;
}
}
$is_even = !$is_even;
if ($bit < 4)
$bit++;
else {
$i++;
$geohash .= $BASE32[$ch];
$bit = 0;
$ch = 0;
}
}
return $geohash;
}
/******geohash解码
* @param $geohash
* @return array
*/
function decode_geohash($geohash)
{
$geohash = strtolower($geohash);
$BASE32 = '0123456789bcdefghjkmnpqrstuvwxyz';
$bits = array(16,8,4,2,1);
$lat = array(-90.0, 90.0);
$lon = array(-180.0, 180.0);
$hashlen = strlen($geohash);
$is_even = 1;
for($i = 0; $i < $hashlen; $i++ )
{
$of = strpos($BASE32,$geohash[$i]);
for ($j=0; $j<5; $j++) {
$mask = $bits[$j];
if ($is_even) {
$lon[!($of&$mask)] = ($lon[0] + $lon[1])/2;
} else {
$lat[!($of&$mask)] = ($lat[0] + $lat[1])/2;
}
$is_even = !$is_even;
}
}
$point = array( 0 => ($lat[0] + $lat[1]) / 2, 1 => ($lon[0] + $lon[1]) / 2);
return $point;
}
/**
* 计算两个经纬度距离
* @param $lat1 纬度
* @param $lng1 经度
* @param $lat2 纬度
* @param $lng2 经度
*/
function get_distance($lat1, $lng1, $lat2, $lng2){
$earthRadius = 6367000; //approximate radius of earth in meters
$lat1 = ($lat1 * pi() ) / 180;
$lng1 = ($lng1 * pi() ) / 180;
$lat2 = ($lat2 * pi() ) / 180;
$lng2 = ($lng2 * pi() ) / 180;
$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 = $earthRadius * $stepTwo;
return round($calculatedDistance);
}
实际场景,附近的工作室
代码示例
$latitude=$this->request->param('latitude',39.4);//纬度
$longitude=$this->request->param('longitude',116);//经度
if(!$longitude||!$latitude){
$this->error('位置参数不全');
}
$now_geohash=encode_geohash($latitude, $longitude, $deep=3);//当前位置的区域码,码位数越短范围越大,可以通过增大deep的值来缩小搜索范围
$list=Db::name('studio')->where('geohash','like',$now_geohash.'%')->page($page,100)->field('id,name,createtime,geohash,latitude,longitude')->select();
配合数据就达到了搜索附近工作室的效果
小技巧,工作室入住的时候存经纬度,同时生成geohash码,存的时候位数保留最长
关于geohash原理参考此篇文档 http://blog.mryxh.cn/291.html
未经允许不得转载:肥猫博客 » geohash实现附近的工作室,php函数实现-tp5
相关文章
- Hystrix熔断、限流与服务保护详解
- hystrix熔断、降级使用示例
- SAP QM 事务代码QA11界面里的‘To Reserves’栏位
- 干货分享-Adobe illustrator箭头通行图标怎么制作【附带安装包】
- SAP QM不常用功能之Automatic Usage Decision
- 易点易动为金融行业提供固定资产管理解决方案
- 【蓝桥杯2022省赛】备赛蓝桥杯经典动态规划。背包问题、背包与魔法、李白打酒加强版
- 干货分享-Adobe Illustrator文字内发光效果怎么制作(附带安装包、学习教程)
- Ningx - 源码安装Nginx已经编译时error解决办法
- 办公软件 2023 office
- 家用吸氧机出氧浓度的检测氧气传感器KE-25F3
- AI干货-Adobe illustrator怎么快速把图形一分为二【附安装包】
- 视频号小店新订单如何实时同步企业微信
- 币安暂停美元转账出入金!
- 优思学院|管理体系你就只知道ISO?太落伍了!
- 什么是SmartArt ? 如何在ONLYOFFICE使用它
- AI干货-Adobe illustrator羽毛状的线条如何绘制【附安装包】
- 涡轮盘的激光熔覆修复及涡轮叶片激光熔覆修复工艺
- 冬季如何做好高速激光熔覆设备的防冻措施
- 激光熔覆层裂纹产生的原因