GeoHash

今天偶然看到一个Ruby的GeoHash库,功能非常简单,就是将经纬度坐标哈希成字符串,并且,利用这个字符串可以粗略地比较两点的距离。这个库的代码host在GitHub上,要安装,需要将github加入gem:
sudo gem sources -a http://gems.github.com
sudo gem install davotroy-geohash

用法,irb:
irb(main):001:0> require ‘rubygems’
=> true
irb(main):002:0> require ‘geohash’
=> true
irb(main):003:0> GeoHash.encode(32.168, 118.54)
=> “wtsr12n0nj”
irb(main):004:0> GeoHash.decode(‘wtsr12n0nj’)
=> [32.168, 118.54]

代码可以从github上获得
git clone git://github.com/davetroy/geohash.git

GeoHash的核心部分用C实现,仔细看一下可以发现是一个四叉树的结构:

[codesyntax lang="c"]
#define BASE32	"0123456789bcdefghjkmnpqrstuvwxyz"
static void encode_geohash(double latitude, double longitude, int precision, char *geohash) {
	int is_even=1, i=0;
	double lat[2], lon[2], mid;
	char bits[] = {16,8,4,2,1};
	int bit=0, ch=0;

	lat[0] = -90.0;  lat[1] = 90.0;
	lon[0] = -180.0; lon[1] = 180.0;

	while (i < precision) {
		if (is_even) {
 			mid = (lon[0] + lon[1]) / 2;
 			if (longitude > mid) {
				ch |= bits[bit];
				lon[0] = mid;
			} else
				lon[1] = mid;
		} else {
			mid = (lat[0] + lat[1]) / 2;
			if (latitude > mid) {
				ch |= bits[bit];
				lat[0] = mid;
			} else
				lat[1] = mid;
		}

		is_even = !is_even;
		if (bit < 4)
			bit++;
		else {
			geohash[i++] = BASE32[ch];
			bit = 0;
			ch = 0;
		}
	}
	geohash[i] = 0;
}

[/codesyntax]

可惜在学校的时候没有看到这么精致的代码。

This entry was written by Sunng , posted on Saturday September 19 2009at 09:09 pm , filed under 手艺 and tagged , . Bookmark the permalink . Post a comment below or leave a trackback: Trackback URL.

One Response to “GeoHash”

Leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

*
To prove you're a person (not a spam script), type the security word shown in the picture. Click on the picture to hear an audio file of the word.
Click to hear an audio file of the anti-spam word