世界対応版(v2.01)で作成しました。
元になるjsがアップデートするとのことですのでまだお試し版です。
問題等ありましたら教えていただけると助かります。
2010/09/11追記
特定の値でloc2zoneがちょっとずれるバグがあるようです。
geohex2_coreのリファクタリングを取り込みつつ調査しています。
<?php /* GeoHex module for php */ /* DISCLAIMER OF WARRANTY BECAUSE THIS SOFTWARE IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE SOFTWARE "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH YOU. SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR, OR CORRECTION. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE SOFTWARE AS PERMITTED BY THE ABOVE LICENCE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE SOFTWARE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE SOFTWARE TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. */ /* GeoHex oliginaly written by @sa2da (http://geogames.net/, http://geohex.net/) in Javascript Ported to PHP by Mage Whopperat 2010.9.8 Copyright (C) 2009 sa2da (http://twitter.com/sa2da) License : CC-BY-SA-2.1-JP You can find the full legal code at http://creativecommons.org/licenses/by/2.1/jp/legalcode (Japanese) or in the local file cc-by-sa-2.1-legalcode.html. such like http://creativecommons.org/licenses/by-sa/3.0/legalcode (English) Here is only an abstract : You are free: to Share – to copy, distribute and transmit the work to Remix – to adapt the work Under the following conditions: Attribution – You must attribute the work in the manner specified by the author or licensor (but not in any way that suggests that they endorse you or your use of the work). Share Alike — If you alter, transform, or build upon this work, you may distribute the resulting work only under the same or similar license to this one. For any reuse or distribution, you must make clear to others the license terms of this work. The best way to do this is with a link to this (http://creativecommons.org/licenses/by-sa/3.0/) web page. Any of the above conditions can be waived if you get permission from the copyright holder. Nothing in this license impairs or restricts the author's moral rights. SPECIAL THANKS TO @_hfu_ for projection transform mathematical expression (http://twitter.com/_hfu_/status/23144088252) */ class GeoHex{ var $h_key = 'abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'; var $h_base = 20037508.34; var $h_deg; var $h_k; var $h_size; var $h_x; var $h_y; var $h_lon; var $h_lat; function __construct(){ $this->h_deg = pi()*(30/180); $this->h_k = tan($this->h_deg); } // this function only for downward compatibility function geohex2latlng( $code ){ return $ths->getZoneByCode($code); } // this function only for downward compatibility function latlng2geohex($lat, $lon, $level){ return $ths->getZoneByLocation($lat, $lon, $level); } function setHexSize($_level){ if($_level < 1 || $_level > 24){ return -1; } return $this->h_base/pow(2,$_level)/3; } function getZoneByLocation( $_lat, $_lon, $_level){ $this->h_size = $this->setHexSize($_level); if($this->h_size < 0){ die("invalid level error!"); } $level = $_level; list($lon_grid, $lat_grid) = $this->loc2xy($_lon,$_lat); $unit_x = 6* $this->h_size; $unit_y = $unit_x*$this->h_k; $h_pos_x = ($lon_grid + $lat_grid/$this->h_k)/$unit_x; $h_pos_y = ($lat_grid - $this->h_k*$lon_grid)/$unit_y; $h_x_0 = floor($h_pos_x); $h_y_0 = floor($h_pos_y); $h_x_q = floor(($h_pos_x - $h_x_0)*100)/100; $h_y_q = floor(($h_pos_y - $h_y_0)*100)/100; $this->h_x = round($h_pos_x); $this->h_y = round($h_pos_y); $h_max=round($this->h_base/$unit_x + $this->h_base/$unit_y); if($h_y_q>-$h_x_q+1){ if(($h_y_q<2*$h_x_q)&&($h_y_q>0.5*$h_x_q)){ $this->h_x = $h_x_0 + 1; $this->h_y = $h_y_0 + 1; } }else if($h_y_q<-$h_x_q+1){ if(($h_y_q>(2*h_x_q)-1)&&($h_y_q<(0.5*$h_x_q)+0.5)){ $this->h_x = $h_x_0; $this->h_y = $h_y_0; } } $this->h_lat = ($this->h_k*$this->h_x*$unit_x + $this->h_y*$unit_y)/2; $this->h_lon = ($this->h_lat - $this->h_y*$unit_y)/$this->h_k; list($z_loc_x, $z_loc_y) = $this->xy2loc($this->h_lon,$this->h_lat); if(($this->h_base - $this->h_lon) < $this->h_size){ $z_loc_x = 180; $h_xy = $this->h_x; $this->h_x = $this->h_y; $this->h_y = $h_xy; } $h_x_p =0; $h_y_p =0; if($this->h_x<0){ $h_x_p = 1;} if($this->h_y<0){ $h_y_p = 1;} $h_x_abs = abs($this->h_x)*2+$h_x_p; $h_y_abs = abs($this->h_y)*2+$h_y_p; $h_x_10000 = floor(($h_x_abs%77600000)/1296000); $h_x_1000 = floor(($h_x_abs%1296000)/216000); $h_x_100 = floor(($h_x_abs%216000)/3600); $h_x_10 = floor(($h_x_abs%3600)/60); $h_x_1 = floor(($h_x_abs%3600)%60); $h_y_10000 = floor(($h_y_abs%77600000)/1296000); $h_y_1000 = floor(($h_y_abs%1296000)/216000); $h_y_100 = floor(($h_y_abs%216000)/3600); $h_y_10 = floor(($h_y_abs%3600)/60); $h_y_1 = floor(($h_y_abs%3600)%60); $hl_key = $this->h_key; $h_code = "" . substr($hl_key, ($level%60), 1); if($h_max >=1296000/2) $h_code = $h_code . $hl_key[$h_x_10000] . $hl_key[$h_y_10000]; if($h_max >=216000/2) $h_code = $h_code . $hl_key[$h_x_1000] . $hl_key[$h_y_1000]; if($h_max >=3600/2) $h_code = $h_code . $hl_key[$h_x_100] . $hl_key[$h_y_100]; if($h_max >=60/2) $h_code = $h_code . $hl_key[$h_x_10] . $hl_key[$h_y_10]; $h_code = $h_code . $hl_key[$h_x_1] . $hl_key[$h_y_1]; return array( "lat" => $z_loc_y, "lon" => $z_loc_x, "x" => $this->h_x, "y" => $this->h_y, "code" => $h_code ); } function getZoneByCode($_code){ $c_length = strlen($_code); $zone = array(); $hl_key=$this->h_key; $level = strpos( $hl_key, $_code[0]); $scl = $level; $this->h_size = $this->h_base/pow(2,$level)/3; $unit_x = 6* $this->h_size; $unit_y = 6* $this->h_size* $this->h_k; $h_max=round($this->h_base/$unit_x + $this->h_base/$unit_y); $this->h_x=0; $this->h_y=0; if( $h_max >= (1296000/2)) { $this->h_x = strpos( $hl_key, $_code[1]) *1296000+strpos( $hl_key, $_code[3] )*216000+strpos( $hl_key, $_code[5] )*3600+strpos( $hl_key, $_code[7] )*60+strpos( $hl_key, $_code[9] ); $this->h_y = strpos( $hl_key, $_code[2] )*1296000+strpos( $hl_key, $_code[4] )*216000+strpos( $hl_key, $_code[6] )*3600+strpos( $hl_key, $_code[8] )*60+strpos( $hl_key, $_code[10] ); }else if($h_max >=(216000/2) ) { $this->h_x = strpos( $hl_key, $_code[1] )*216000+strpos( $hl_key, $_code[3] )*3600+strpos( $hl_key, $_code[5] )*60+strpos( $hl_key, $_code[7] ); $this->h_y = strpos( $hl_key, $_code[2] )*216000+strpos( $hl_key, $_code[4] )*3600+strpos( $hl_key, $_code[6] )*60+strpos( $hl_key, $_code[8] ); }else if($h_max >=3600/2){ $this->h_x = strpos( $hl_key, $_code[1] )*3600+strpos( $hl_key, $_code[3] )*60+strpos( $hl_key, $_code[5] ); $this->h_y = strpos( $hl_key, $_code[2] )*3600+strpos( $hl_key, $_code[4] )*60+strpos( $hl_key, $_code[6] ); }else if(h_max >=60/2){ $this->h_x = strpos( $hl_key, $_code[1] )*60+strpos( $hl_key, $_code[3] ); $this->h_y = strpos( $hl_key, $_code[2] )*60+strpos( $hl_key, $_code[4] ); }else{ $this->h_x = strpos( $hl_key, $_code[1] ); $this->h_y = strpos( $hl_key, $_code[2] ); } $this->h_x = ($this->h_x%2)?-($this->h_x-1)/2:$this->h_x/2; $this->h_y = ($this->h_y%2)?-($this->h_y-1)/2:$this->h_y/2; $h_lat_y = ($this->h_k*$this->h_x*$unit_x + $this->h_y*$unit_y)/2; $h_lon_x = ($h_lat_y - $this->h_y*$unit_y)/$this->h_k; list($this->h_lon, $this->h_lat ) = $this->xy2loc($h_lon_x,$h_lat_y); return array( "code" => $_code, "lat" => $this->h_lat, "lon" => $this->h_lon, "x" => $this->h_x, "y" => $this->h_y ); } function loc2xy($_lon, $_lat) { $x = $_lon*$this->h_base/180; $y = log(tan((90+$_lat)*pi()/360))/(pi()/180); $y = $y*$this->h_base/180; return array($x, $y); } function xy2loc($_x, $_y) { $lon=($_x/$this->h_base)*180; $lat=($_y/$this->h_base)*180; $lat=180/pi()*(2*atan(exp($lat*pi()/180))-pi()/2); return array($lon, $lat); } function _gh_strpos( $num ){ $hl_key = $this->h_key; return strpos($hl_key, $_code[$num]); } }/* class geohex */
使い方
//モジュールの読み込み require_once('geohex2.01.php'); // GeoHexオブジェクト生成 $ghx = &new GeoHex(); // 各計算 // 緯度経度からGeoHexコードを求める print $ghx->getZoneByLocation($latitude, $longitude, $level) ."\n"; // GeoHexコードから緯度経度に変換 print $ghx->getZoneByCode($geohex)."\n";