ZM_Geohash.php 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. <?php
  2. namespace common\library;
  3. class ZM_Geohash{
  4. private $coding="0123456789bcdefghjkmnpqrstuvwxyz";
  5. private $codingMap=array();
  6. public function getGeohash(){
  7. return $this->codingMap;
  8. }
  9. public function getDistance($lat1,$lng1,$lat2,$lng2)
  10. {
  11. //地球半径
  12. $R = 6378137;
  13. //将角度转为狐度
  14. $radLat1 = deg2rad($lat1);
  15. $radLat2 = deg2rad($lat2);
  16. $radLng1 = deg2rad($lng1);
  17. $radLng2 = deg2rad($lng2);
  18. //结果
  19. $s = acos(cos($radLat1)*cos($radLat2)*cos($radLng1-$radLng2)+sin($radLat1)*sin($radLat2))*$R;
  20. //精度
  21. $s = round($s* 10000)/10000;
  22. return round($s);
  23. }
  24. public function init_codingMap()
  25. {
  26. for($i=0; $i<32; $i++)
  27. {
  28. $this->codingMap[substr($this->coding,$i,1)]=str_pad(decbin($i), 5, "0", STR_PAD_LEFT);
  29. }
  30. }
  31. public function decode($hash)
  32. {
  33. $binary="";
  34. $hl=strlen($hash);
  35. for($i=0; $i<$hl; $i++){
  36. $binary.=$this->codingMap[substr($hash,$i,1)];
  37. }
  38. $bl=strlen($binary);
  39. $blat="";
  40. $blong="";
  41. for ($i=0; $i<$bl; $i++)
  42. {
  43. if ($i%2)
  44. $blat=$blat.substr($binary,$i,1);
  45. else
  46. $blong=$blong.substr($binary,$i,1);
  47. }
  48. $lat=$this->binDecode($blat,-90,90);
  49. $long=$this->binDecode($blong,-180,180);
  50. $latErr=$this->calcError(strlen($blat),-90,90);
  51. $longErr=$this->calcError(strlen($blong),-180,180);
  52. $latPlaces=max(1, -round(log10($latErr))) - 1;
  53. $longPlaces=max(1, -round(log10($longErr))) - 1;
  54. $lat=round($lat, $latPlaces);
  55. $long=round($long, $longPlaces);
  56. return array($lat,$long);
  57. }
  58. public function encode($lat,$long)
  59. {
  60. $plat=$this->precision($lat);
  61. $latbits=1;
  62. $err=45;
  63. while($err>$plat)
  64. {
  65. $latbits++;
  66. $err/=2;
  67. }
  68. $plong=$this->precision($long);
  69. $longbits=1;
  70. $err=90;
  71. while($err>$plong)
  72. {
  73. $longbits++;
  74. $err/=2;
  75. }
  76. $bits=max($latbits,$longbits);
  77. $longbits=$bits;
  78. $latbits=$bits;
  79. $addlong=1;
  80. while (($longbits+$latbits)%5 != 0)
  81. {
  82. $longbits+=$addlong;
  83. $latbits+=!$addlong;
  84. $addlong=!$addlong;
  85. }
  86. $blat=$this->binEncode($lat,-90,90, $latbits);
  87. $blong=$this->binEncode($long,-180,180,$longbits);
  88. $binary="";
  89. $uselong=1;
  90. while (strlen($blat)+strlen($blong))
  91. {
  92. if ($uselong)
  93. {
  94. $binary=$binary.substr($blong,0,1);
  95. $blong=substr($blong,1);
  96. }
  97. else
  98. {
  99. $binary=$binary.substr($blat,0,1);
  100. $blat=substr($blat,1);
  101. }
  102. $uselong=!$uselong;
  103. }
  104. $hash="";
  105. for ($i=0; $i<strlen($binary); $i+=5){
  106. $n=bindec(substr($binary,$i,5));
  107. $hash=$hash.$this->coding[$n];
  108. }
  109. return $hash;
  110. }
  111. private function calcError($bits,$min,$max)
  112. {
  113. $err=($max-$min)/2;
  114. while ($bits--)
  115. $err/=2;
  116. return $err;
  117. }
  118. private function precision($number)
  119. {
  120. $precision=0;
  121. $pt=strpos($number,'.');
  122. if ($pt!==false)
  123. {
  124. $precision=-(strlen($number)-$pt-1);
  125. }
  126. return pow(10,$precision)/2;
  127. }
  128. private function binEncode($number, $min, $max, $bitcount)
  129. {
  130. if ($bitcount==0)
  131. return "";
  132. $mid=($min+$max)/2;
  133. if ($number>$mid)
  134. return "1".$this->binEncode($number, $mid, $max,$bitcount-1);
  135. else
  136. return "0".$this->binEncode($number, $min, $mid,$bitcount-1);
  137. }
  138. private function binDecode($binary, $min, $max)
  139. {
  140. $mid=($min+$max)/2;
  141. if (strlen($binary)==0)
  142. return $mid;
  143. $bit=substr($binary,0,1);
  144. $binary=substr($binary,1);
  145. if ($bit==1)
  146. return $this->binDecode($binary, $mid, $max);
  147. else
  148. return $this->binDecode($binary, $min, $mid);
  149. }
  150. }?>