您好,欢迎访问一九零五行业门户网

查找附近网点geohash算法及实现 (PHP版本)

参考文档:
http://blog.csdn.net/wangxiafghj/article/details/9014363geohash  算法原理及实现方式
http://blog.charlee.li/geohash-intro/  geohash:用字符串实现附近地点搜索
http://blog.sina.com.cn/s/blog_7c05385f0101eofb.html    查找附近点--geohash方案讨论
http://www.wubiao.info/372        查找附近的xxx 球面距离以及geohash方案探讨
http://en.wikipedia.org/wiki/haversine_formula       haversine formula球面距离公式
http://www.codecodex.com/wiki/calculate_distance_between_two_points_on_a_globe   球面距离公式代码实现
http://developer.baidu.com/map/jsdemo.htm#a6_1   球面距离公式验证  
http://www.wubiao.info/470     mysql or mongodb lbs快速实现方案
geohash有以下几个特点:
首先,geohash用一个字符串表示经度和纬度两个坐标。某些情况下无法在两列上同时应用索引 (例如mysql 4之前的版本,google app engine的数据层等),利用geohash,只需在一列上应用索引即可。
其次,geohash表示的并不是一个点,而是一个矩形区域。比如编码wx4g0ec19,它表示的是一个矩形区域。 使用者可以发布地址编码,既能表明自己位于北海公园附近,又不至于暴露自己的精确坐标,有助于隐私保护。
第三,编码的前缀可以表示更大的区域。例如wx4g0ec1,它的前缀wx4g0e表示包含编码wx4g0ec1在内的更大范围。 这个特性可以用于附近地点搜索。首先根据用户当前坐标计算geohash(例如wx4g0ec1)然后取其前缀进行查询 (select * from place where geohash like 'wx4g0e%'),即可查询附近的所有地点。
geohash比直接用经纬度的高效很多。
geohash算法实现(php版本)
coding,$i,1)]=str_pad(decbin($i), 5, 0, str_pad_left); } } public function decode($hash) { $binary=; $hl=strlen($hash); for($i=0; $icodingmap[substr($hash,$i,1)]; } $bl=strlen($binary); $blat=; $blong=; for ($i=0; $ibindecode($blat,-90,90); $long=$this->bindecode($blong,-180,180); // $lat=$this->bindecode($blat,2,54); // $long=$this->bindecode($blong,72,136); $laterr=$this->calcerror(strlen($blat),-90,90); $longerr=$this->calcerror(strlen($blong),-180,180); $latplaces=max(1, -round(log10($laterr))) - 1; $longplaces=max(1, -round(log10($longerr))) - 1; $lat=round($lat, $latplaces); $long=round($long, $longplaces); return array($lat,$long); } public function encode($lat,$long) { $plat=$this->precision($lat); $latbits=1; $err=45; while($err>$plat) { $latbits++; $err/=2; } $plong=$this->precision($long); $longbits=1; $err=90; while($err>$plong) { $longbits++; $err/=2; } $bits=max($latbits,$longbits); $longbits=$bits; $latbits=$bits; $addlong=1; while (($longbits+$latbits)%5 != 0) { $longbits+=$addlong; $latbits+=!$addlong; $addlong=!$addlong; } $blat=$this->binencode($lat,-90,90, $latbits); $blong=$this->binencode($long,-180,180,$longbits); $binary=; $uselong=1; while (strlen($blat)+strlen($blong)) { if ($uselong) { $binary=$binary.substr($blong,0,1); $blong=substr($blong,1); } else { $binary=$binary.substr($blat,0,1); $blat=substr($blat,1); } $uselong=!$uselong; } $hash=; for ($i=0; $icoding[$n]; } return $hash; } private function calcerror($bits,$min,$max) { $err=($max-$min)/2; while ($bits--) $err/=2; return $err; } private function precision($number) { $precision=0; $pt=strpos($number,'.'); if ($pt!==false) { $precision=-(strlen($number)-$pt-1); } return pow(10,$precision)/2; } private function binencode($number, $min, $max, $bitcount) { if ($bitcount==0) return ; $mid=($min+$max)/2; if ($number>$mid) return 1.$this->binencode($number, $mid, $max,$bitcount-1); else return 0.$this->binencode($number, $min, $mid,$bitcount-1); } private function bindecode($binary, $min, $max) { $mid=($min+$max)/2; if (strlen($binary)==0) return $mid; $bit=substr($binary,0,1); $binary=substr($binary,1); if ($bit==1) return $this->bindecode($binary, $mid, $max); else return $this->bindecode($binary, $min, $mid); }} ?>
测试实例
encode($n_latitude,$n_longitude); //附近$n = 3;$like_geohash = substr($n_geohash, 0, $n); $sql = 'select * from retailersinfotable where geohash like '.$like_geohash.'%'; $query = mysql_query($sql); if(mysql_num_rows($query)) { while($row=mysql_fetch_array($query)) { $data[] = array ( latitude =>$row[latitude], longitude=>$row[longitude], name =>$row[retailersname], ); }} //算出实际距离 foreach($data as $key=>$val){ $distance = getdistance($n_latitude,$n_longitude,$val['latitude'],$val['longitude']); $data[$key]['distance'] = $distance; //排序列 $sortdistance[$key] = $distance;} //距离排序array_multisort($sortdistance,sort_asc,$data); //结束$e_time = microtime(true); echo (计算耗时: ;echo $e_time - $b_time; echo 秒)
; //var_dump($data); foreach($data as $key=>$val){ echo ; echo $val['distance']. 米-------.$val['name'];} /*** @desc 根据两点间的经纬度计算距离* @param float $latitude 纬度值* @param float $longitude 经度值*/function getdistance($latitude1, $longitude1, $latitude2, $longitude2) { $earth_radius = 6371000; //approximate radius of earth in meters $dlat = deg2rad($latitude2 - $latitude1); $dlon = deg2rad($longitude2 - $longitude1); /* using the haversine formula http://en.wikipedia.org/wiki/haversine_formula http://www.codecodex.com/wiki/calculate_distance_between_two_points_on_a_globe 验证:百度地图 http://developer.baidu.com/map/jsdemo.htm#a6_1 calculate the distance */ $a = sin($dlat/2) * sin($dlat/2) + cos(deg2rad($latitude1)) * cos(deg2rad($latitude2)) * sin($dlon/2) * sin($dlon/2); $c = 2 * asin(sqrt($a)); $d = $earth_radius * $c; return round($d); //四舍五入} ?>
其它类似信息

推荐信息