• 欢迎访问开心洋葱网站,在线教程,推荐使用最新版火狐浏览器和Chrome浏览器访问本网站,欢迎加入开心洋葱 QQ群
  • 为方便开心洋葱网用户,开心洋葱官网已经开启复制功能!
  • 欢迎访问开心洋葱网站,手机也能访问哦~欢迎加入开心洋葱多维思维学习平台 QQ群
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏开心洋葱吧~~~~~~~~~~~~~!
  • 由于近期流量激增,小站的ECS没能经的起亲们的访问,本站依然没有盈利,如果各位看如果觉着文字不错,还请看官给小站打个赏~~~~~~~~~~~~~!

GeoHash PHP Class

PHP 开心洋葱 2144次浏览 0个评论

============================================================
GeoHash PHP Class

Provides a class for generating and decoding geohashes as
documented at http://en.wikipedia.org/wiki/Geohash

Developed by Paul Dixon and licenced for reuse via the
GNU General Public Licence – see LICENCE.txt for details
============================================================

UPDATES
——————————————————-
The latest version of this class is available from

Downloads

HISTORY
——————————————————-
0.10 – 27th Feb 2008 – First release

EXAMPLES
——————————————————-

$geohash=new Geohash();

#decode a hash
$coords=$geohash->decode(“mh7w”);
echo “Lat {$coords[0]} Long {$coords[1]}
“;

#encode a hash
$hash=$geohash->encode(-62.5, 23.4);
echo “Hash is $hash
“;

<?php
/**
 * Geohash generation class
 * http://blog.dixo.net/downloads/
 *
 * This file copyright (C) 2008 Paul Dixon (paul@elphin.com)
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 3
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */



/**
* Encode and decode geohashes
*
*/
class Geohash
{
	private $coding="0123456789bcdefghjkmnpqrstuvwxyz";
	private $codingMap=array();
	
	public function Geohash()
	{
		//build map from encoding char to 0 padded bitfield
		for($i=0; $i<32; $i++)
		{
			$this->codingMap[substr($this->coding,$i,1)]=str_pad(decbin($i), 5, "0", STR_PAD_LEFT);
		}
		
	}
	
	/**
	* Decode a geohash and return an array with decimal lat,long in it
	*/
	public function decode($hash)
	{
		//decode hash into binary string
		$binary="";
		$hl=strlen($hash);
		for($i=0; $i<$hl; $i++)
		{
			$binary.=$this->codingMap[substr($hash,$i,1)];
		}
		
		//split the binary into lat and log binary strings
		$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);
			
		}
		
		//now concert to decimal
		$lat=$this->binDecode($blat,-90,90);
		$long=$this->binDecode($blong,-180,180);
		
		//figure out how precise the bit count makes this calculation
		$latErr=$this->calcError(strlen($blat),-90,90);
		$longErr=$this->calcError(strlen($blong),-180,180);
				
		//how many decimal places should we use? There's a little art to
		//this to ensure I get the same roundings as geohash.org
		$latPlaces=max(1, -round(log10($latErr))) - 1;
		$longPlaces=max(1, -round(log10($longErr))) - 1;
		
		//round it
		$lat=round($lat, $latPlaces);
		$long=round($long, $longPlaces);
		
		return array($lat,$long);
	}

	
	/**
	* Encode a hash from given lat and long
	*/
	public function encode($lat,$long)
	{
		//how many bits does latitude need?	
		$plat=$this->precision($lat);
		$latbits=1;
		$err=45;
		while($err>$plat)
		{
			$latbits++;
			$err/=2;
		}
		
		//how many bits does longitude need?
		$plong=$this->precision($long);
		$longbits=1;
		$err=90;
		while($err>$plong)
		{
			$longbits++;
			$err/=2;
		}
		
		//bit counts need to be equal
		$bits=max($latbits,$longbits);
		
		//as the hash create bits in groups of 5, lets not
		//waste any bits - lets bulk it up to a multiple of 5
		//and favour the longitude for any odd bits
		$longbits=$bits;
		$latbits=$bits;
		$addlong=1;
		while (($longbits+$latbits)%5 != 0)
		{
			$longbits+=$addlong;
			$latbits+=!$addlong;
			$addlong=!$addlong;
		}
		
		
		//encode each as binary string
		$blat=$this->binEncode($lat,-90,90, $latbits);
		$blong=$this->binEncode($long,-180,180,$longbits);
		
		//merge lat and long together
		$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;
		}
		
		//convert binary string to hash
		$hash="";
		for ($i=0; $i<strlen($binary); $i+=5)
		{
			$n=bindec(substr($binary,$i,5));
			$hash=$hash.$this->coding[$n];
		}
		
		
		return $hash;
	}
	
	/**
	* What's the maximum error for $bits bits covering a range $min to $max
	*/
	private function calcError($bits,$min,$max)
	{
		$err=($max-$min)/2;
		while ($bits--)
			$err/=2;
		return $err;
	}
	
	/*
	* returns precision of number
	* precision of 42 is 0.5
	* precision of 42.4 is 0.05
	* precision of 42.41 is 0.005 etc
	*/
	private function precision($number)
	{
		$precision=0;
		$pt=strpos($number,'.');
		if ($pt!==false)
		{
			$precision=-(strlen($number)-$pt-1);
		}
		
		return pow(10,$precision)/2;
	}
	
	
	/**
	* create binary encoding of number as detailed in http://en.wikipedia.org/wiki/Geohash#Example
	* removing the tail recursion is left an exercise for the reader
	*/
	private function binEncode($number, $min, $max, $bitcount)
	{
		if ($bitcount==0)
			return "";
		
		#echo "$bitcount: $min $max<br>";
			
		//this is our mid point - we will produce a bit to say
		//whether $number is above or below this mid point
		$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);
	}
	

	/**
	* decodes binary encoding of number as detailed in http://en.wikipedia.org/wiki/Geohash#Example
	* removing the tail recursion is left an exercise for the reader
	*/
	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.php

<?php
/**
 * Geohash generation class test harness
 * http://blog.dixo.net/downloads/
 *
 * This file copyright (C) 2008 Paul Dixon (paul@elphin.com)
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 3
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */


require_once('geohash.class.php');

$geohash=new Geohash;

//these test hashes were made on geohash.org
//and test various combinations of precision
//and range
$tests=array(
	"ezs42"=>array(42.6,-5.6),
	"mh7w"=>array(-20, 50),
	"t3b9m"=>array(10.1, 57.2),
	"c2b25ps"=>array(49.26, -123.26),
	"80021bgm"=>array(0.005, -179.567),
	"k484ht99h2"=>array(-30.55555, 0.2),
	"8buh2w4pnt"=>array(5.00001, -140.6),
);


foreach($tests as $actualhash=>$coords)
{
	$computed_hash=$geohash->encode($coords[0], $coords[1]);
	
	echo "Encode {$coords[0]}, {$coords[1]} as $actualhash : ";
	if ($computed_hash==$actualhash)
	{
		echo "OK<br>";
	}
	else
	{
		echo "FAIL (got $computed_hash)<br>";
	}
	
	
	echo "<hr>";
	
	$computed_coords=$geohash->decode($actualhash);
	
	echo "Decode $actualhash as {$coords[0]}, {$coords[1]} : ";
	if (($computed_coords[0]==$coords[0]) && ($computed_coords[1]==$coords[1]))
	{
		echo "OK<br>";
	}
	else
	{
		echo "FAIL (got {$computed_coords[0]}, {$computed_coords[1]})<br>";
	}

	echo "<hr>";
}



?>


开心洋葱 , 版权所有丨如未注明 , 均为原创丨未经授权请勿修改 , 转载请注明GeoHash PHP Class
喜欢 (0)

您必须 登录 才能发表评论!

加载中……