Find nearby Dot Geohash algorithm and implementation (PHP version)

Source: Internet
Author: User
Tags cos
Reference Documentation:

Http://blog.csdn.net/wangxiafghj/article/details/9014363geohash algorithm principle and realization method
Http://blog.charlee.li/geohash-intro/geohash: Using strings to search for nearby locations
Http://blog.sina.com.cn/s/blog_7c05385f0101eofb.html find nearby points--geohash scenario discussion
http://www.wubiao.info/372 Find nearby xxx spherical distance and Geohash scheme discussion
Http://en.wikipedia.org/wiki/Haversine_formula haversine Formula Spherical distance formula
Http://www.codecodex.com/wiki/Calculate_Distance_Between_Two_Points_on_a_Globe Spherical distance Formula code implementation
Http://developer.baidu.com/map/jsdemo.htm#a6_1 Spherical Distance Formula verification
http://www.wubiao.info/470 Mysql or Mongodb lbs fast implementation solution


Geohash has the following features:

First, Geohash uses a string to represent the longitude and latitude two coordinates. In some cases, you can't apply an index on two columns at the same time (for example, a version prior to MySQL 4, a data layer for Google APP engine, etc.), using Geohash to apply an index on only one column.

Second, Geohash represents not a point, but a rectangular area. For example, the code WX4G0EC19, which represents a rectangular region. Users can publish address codes to show that they are located near Beihai Park without exposing their precise coordinates, which helps protect privacy.

Third, the prefix of the encoding can represent a larger area. For example, WX4G0EC1, whose prefix wx4g0e represents a larger range including encoded WX4G0EC1. This feature can be used to search nearby locations. You can query all nearby locations by first calculating geohash (for example, WX4G0EC1) based on the user's current coordinates and then querying by its prefix (SELECT * from places WHERE geohash like ' wx4g0e% ').

Geohash is much more efficient than using latitude and longitude 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);        The 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 (ten, $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 example

 
The following outlets closest to me: "; Start $b_time = Microtime (true); Plan A, directly using the database storage function, traverse sort//scheme B geohash find nearby, then sort//Current Geohash value $n _geohash = $geohash->encode ($n _latitude, $n _longitude ); 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 "]," longitude "and" longitude "," name "+ $row [" Retailersname "],);}} Calculate the actual distance foreach ($data as $key + $val) {$distance = Getdistance ($n _latitude, $n _longitude, $val [' latitude '], $val [' Longitude ']); $data [$key] [' distance '] = $distance; Row sequence $sortdistance [$key] = $distance;} Distance sort Array_multisort ($sortdistance, SORT_ASC, $data); End $e_time = Microtime (true); echo "(Computation time:"; Echo $e _time-$b _time; echo "seconds)
"; Var_dump ($data); foreach ($data as $key = + $val) {echo "
"Echo $val [' distance ']." M-------". $val [' name '];} /*** @desc calculates distance according to latitude and longitude between two points * @param float $latitude latitude value * @param float $longitude Longitude value */function getdistance ($latitude 1, $lo Ngitude1, $latitude 2, $longitude 2) {$earth _radius = 6371000; Approximate radius of earth in Meters$dlat = Deg2rad ($latitude 2-$latitude 1); $dLon = Deg2rad ($longitude 2-$longitude 1) ; /* Using the Haversine formula Http://en.wikipedia.org/wiki/Haversine_formula http://www.codecodex.co M/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 (Deg2rad ($latitude 1)) * cos (Deg2rad ($latitude 2)) * SI N ($dLon/2) * sin ($dLon/2); $c = 2 * ASIN (SQRT ($a)); $d = $earth _radius * $c; return round ($d); Rounding}?>
  • Contact Us

    The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

    If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.