2011年03月20日

GeoHex V3をPerlに移植 @ ウェブ

大量あるデータを処理して、位置情報を簡単に扱えるようにGeoHexの書式に変換してみた。

元々のGeoHexがJavascriptなので、node.jsでテキストを処理しようかと思ったのですが、1行毎に処理する方法が分からず断念し、Perlで処理する事に決め、GeoHex V3を書き換えてみた。実は、書き換えている途中でV3のPerl版がGitHubに有る事を知ったのですが、必要な部分の8割ほど移植済みだったので、そのまま作る事に。

で、実際に作ってみたのですが、計算の精度の問題なのか、位置がずれる。色々確認してみて、これは簡単に解決出来そうにないので、結局、途中で止めました。経度緯度からGeoHexの文字列に変換するコードしかありませんが、ソースコードを下に貼り付けておきます。場所によってはずれてしまうので、多分実用になりません。

これ以上時間は掛けられないので、今度時間がある時にでも、既にあったPerl版を試してみます。オフィシャルなサイトでV3のPerl版があると書かれてないので、もしかするとダメなのかな。使えるならば、使わせて貰います。

GeoHex V3公開しました。 | geogames.net
>>関連リンク


#!/usr/bin/perl

### GeoHex by @sa2da (http://geogames.net) is licensed under Creative Commons BY-SA 2.1 Japan License. ###

use Math::Trig;
use POSIX qw(floor);

my @h_key   = split//,"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";

$h_base = 20037508.34;
$h_deg = pi()*(30.0/180.0);
$h_k = tan($h_deg);

sub calcHexSize() {
	$level	= $_[0];
	return $h_base / 3.0 ** ($level+1);
}

sub getZoneByLocation() {
	my ($lat, $lon,$level) = @_;	
	$level+=2;
	my $h_size = &calcHexSize($level);

	my($lon_grid,$lat_grid) = &loc2xy($lon,$lat);


	my $unit_x = 6.0 * $h_size;
	my $unit_y = 6.0 * $h_size * $h_k;
	my $h_pos_x = ($lon_grid + $lat_grid / $h_k) / $unit_x;
	my $h_pos_y = ($lat_grid - $h_k * $lon_grid) / $unit_y;
	my $h_x_0 = floor($h_pos_x);
	my $h_y_0 = floor($h_pos_y);
	my $h_x_q = $h_pos_x - $h_x_0; 
	my $h_y_q = $h_pos_y - $h_y_0;
	my $h_x = &round($h_pos_x);
	my $h_y = &round($h_pos_y);

	if ($h_y_q > (-1 * $h_x_q) + 1.0) {
		if(($h_y_q < 2.0 * $h_x_q) && ($h_y_q > 0.5 * $h_x_q)){
			$h_x = $h_x_0 + 1.0;
			$h_y = $h_y_0 + 1.0;
		}
	} elsif ($h_y_q < (-1 * $h_x_q) + 1.0) {
		if (($h_y_q > (2.0 * $h_x_q) - 1.0) && ($h_y_q < (0.5 * $h_x_q) + 0.5)){
			$h_x = $h_x_0;
			$h_y = $h_y_0;
		}
	}

	my $h_lat = ($h_k * $h_x * $unit_x + $h_y * $unit_y) / 2;
	my $h_lon = ($h_lat - $h_y * $unit_y) / $h_k;


	my($z_loc_x,$z_loc_y) = &xy2loc($h_lon,$h_lat);
	if($h_base - $h_lon < $h_size){
		$z_loc_x = 180;
		my $h_xy = $h_x;
		$h_x = $h_y;
		$h_y = $h_xy;
	}

	my $h_code ="";
	my @code3_x =();
	my @code3_y =();
	my $code3 ="";
	my $code9="";
	my $mod_x = $h_x;
	my $mod_y = $h_y;


	for($i = 0;$i <= $level ; $i++){
	  my $h_pow = 3**($level-$i);
	  if($mod_x >= &ceil($h_pow/2)){
	    $code3_x[$i] =2;
	    $mod_x -= $h_pow;
	  }elsif($mod_x <= -1 * &ceil($h_pow/2)){
	    $code3_x[$i] =0;
	    $mod_x += $h_pow;
	  }else{
	    $code3_x[$i] =1;
	  }
	  if($mod_y >= &ceil($h_pow/2)){
	    $code3_y[$i] =2;
	    $mod_y -= $h_pow;
	  }elsif($mod_y <= -1 * &ceil($h_pow/2)){
	    $code3_y[$i] =0;
	    $mod_y += $h_pow;
	  }else{
	    $code3_y[$i] =1;
	  }
	}
    foreach my $i ( 0..$level ) {
	  $code3 .= "" . $code3_x[$i] . $code3_y[$i];

	  $code9 .= &parseInt($code3,3);
	  $h_code .= $code9;
	  $code9="";
	  $code3="";
	}
	
	$h_2 = substr($h_code,3);
	$h_1 = substr($h_code,0,3);
	$h_a1 = floor($h_1/30.0);
	$h_a2 = $h_1 % 30;
	$h_code = $h_key[$h_a1] .$h_key[$h_a2] . $h_2;


	$level-=2;
	print $h_k."\t".$h_code."\n"

	return $h_code;
}

sub loc2xy() {
	my ($lon,$lat) = @_;

	$x = $lon * $h_base / 180;
	$y = log(tan((90 + $lat) * pi / 360)) / (pi / 180);
	$y *= $h_base / 180;
	return ($x,$y);
}

sub xy2loc() {
	my ($x,$y) = @_;
	my $lon = ($x / $h_base) * 180;
	my $lat = ($y / $h_base) * 180;
	$lat = 180 / pi * (2 * atan(exp($lat * pi / 180)) - pi/ 2);
	
	return ($lon,$lat );
}

sub round(){
	return int($_[0]+0.5);
}

sub ceil(){
	return int($_[0]+0.99);
}

sub parseInt(){
	my($str,$number) = @_;
	
	$len = length($str);
	return $str if($len == 1);
	
	$multiplier = $len-1;
	$resulut = 0;
	for($i=0 ;$i< $len ;$i++,$multiplier--){
		$place = substr($str,$i,1);
		$resulut += $place*($number**$multiplier);
	}
	return 	$resulut;
}

閲覧数: 2546 / はてなブックマークusers

関連商品

amazon.co.jp・詳細ページへ

blog comments powered by Disqus

関連日記

アマゾン広告

この日記ページは閲覧数などの条件に応じて、閲覧制限を行っています。他からリンクしていただいても、そのリンクから辿った閲覧者が当ページの内容をご覧頂けない場合があります。ご了承下さい。

▼日記検索

Mac

Shade

3D

Flash

ゲーム

ウェブ

音楽

映画

デジカメ

Windows

Linux

携帯電話

テレビ

広島

電子工作

iOS

▼ 最近のトラックバック

▼ランキング

▼関連サイト