For more information about the geohash algorithm and implementation of nearby sites (PHP version), see:
Principle and implementation of http://blog.csdn.net/wangxiafghj/article/details/9014363geohash algorithm
Http://blog.charlee.li/geohash-intro/ geohash: nearby location search with strings
A discussion on Geohash scheme for finding nearby points in http://blog.sina.com.cn/s/blog_7c05385f0101eofb.html
Study on xxx spherical distance and Geohash scheme in http://www.wubiao.info/372 searching
Formula for http://en.wikipedia.org/wiki/Haversine_formula Haversine formula spherical distance
Code implementation of http://www.codecodex.com/wiki/Calculate_Distance_Between_Two_Points_on_a_Globe spherical distance formula
Http://developer.baidu.com/map/jsdemo.htm#a6_1 spherical distance formula verification
Fast implementation of http://www.wubiao.info/470 Mysql or Mongodb LBS
Geohash has the following features:
First, geohash uses a string to represent the longitude and latitude coordinates. In some cases, indexes cannot be applied on both columns at the same time (for example, MySQL 4 and Google App Engine data layer). With geohash, you only need to apply indexes on one column.
Second, geohash represents not a vertex, but a rectangular area. For example, wx4425ec19 indicates a rectangular area. Users can publish address codes, indicating that they are located near Beihai Park, without exposing their precise coordinates, which helps privacy protection.
Third, the encoding prefix can indicate a larger region. For example, wx4g0ec1, whose prefix wx4g0e indicates a larger range including the encoded wx4g0ec1. This feature can be used to search nearby locations. First, geohash (for example, wx4g0ec1) is calculated based on the current coordinate of the user, and then the prefix is obtained for query (SELECT * FROM place WHERE geohash LIKE 'wx4g0e % ') to query all nearby locations.
Geohash is much more efficient than using longitude and latitude directly.
Geohash algorithm implementation (PHP version)
codingMap[substr($this->coding,$i,1)]=str_pad(decbin($i), 5, "0", STR_PAD_LEFT); } } public function decode($hash) { $binary=""; $hl=strlen($hash); for($i=0; $i<$hl; $i++) { $binary.=$this->codingMap[substr($hash,$i,1)]; } $bl=strlen($binary); $blat=""; $blong=""; for ($i=0; $i<$bl; $i++) { if ($i%2) $blat=$blat.substr($binary,$i,1); else $blong=$blong.substr($binary,$i,1); } $lat=$this->binDecode($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; $i
coding[$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); }} ?>
Test instance
The following outlets are closest to me: "; // start $ B _time = microtime (true); // solution A: directly use the database storage function to traverse the sorting. // solution B geohash is used to find the nearest node, then sort // The current geohash value $ n_geohash = $ geohash-> encode ($ n_latitude, $ n_longpolling); // nearby $ 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"], "longpolling" => $ row ["longpolling"], "name" => $ row ["RetailersName"],) ;}// calculate the actual distance from foreach ($ data as $ key => $ val) {$ distance = getDistance ($ n_latitude, $ n_longpolling, $ val ['latitude '], $ val ['longyun']); $ data [$ key] ['distance '] = $ distance; // sorting column $ sortdistance [$ key] = $ distance;} // array_multisort ($ sortdistance, SORT_ASC, $ data); // end $ e_time = microtime (true); echo "(computing time:"; echo $ e_time-$ B _time; echo "seconds)
"; // Var_dump ($ data); foreach ($ data as $ key => $ val) {echo"
"; Echo $ val ['distance ']. "Meters -------". $ val ['name'];} /*** @ desc calculate the distance * @ param float $ latitude value * @ param float $ longpolling longitude value */function getDistance ($ latitude1, $ longitude1, $ latitude2, $ longitude2) {$ earth_radius = 6371000; // approximate radius of earth in meters $ dLat = deg 2rad ($ latitude2-$ latitude1 ); $ dLon = deg 2rad ($ longitude2-$ longitude1);/* Using the Haversine formula http://en.wiki Pedia.org/wiki/Haversine_formula http://www.codecodex.com/wiki/Calculate_Distance_Between_Two_Points_on_a_Globe verification: Baidu map http://developer.baidu.com/map/jsdemo.htm#a6_1 calculate the distance */$ a = sin ($ dLat/2) * sin ($ dLat/2) + cos (deg 2rad ($ latitude1 )) * cos (deg 2rad ($ latitude2) * sin ($ dLon/2) * sin ($ dLon/2 ); $ c = 2 * asin (sqrt ($ a); $ d = $ earth_radius * $ c; return round ($ d); // rounding}?>