× [PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。 |
Geohashエンコード、デコード関数を書いてみた。
Geohash文字列を緯度と経度の区間に変換:geohash_decode_interval Geohash文字列を緯度と経度に変換:geohash_decode 緯度と経度をGeohash文字列に変換:geohash_encode Geohash文字列から、隣接する領域((2n+1)^2-1個)のGeohash文字列を返す:geohash_neighbour //integer to base32 function int_2_base32($v_in){ $v = (int)$v_in; if($v < 0 || $v > 31) return false; $base32 = '0123456789bcdefghjkmnpqrstuvwxyz'; $str = substr($base32, $v, 1); return $str; } //base32 to integer function base32_2_int($str_in){ if(strlen($str_in) != 1) return false; $str = $str_in; $base32 = '0123456789bcdefghjkmnpqrstuvwxyz'; $v = strpos($base32, $str); return $v; // not found: false } //geohash string to intervals of latitude, longitude function geohash_decode_interval($geohash_in){ $geohash = $geohash_in; $ary_lat = array(-90.0, 90.0); $ary_lon = array(-180.0, 180.0); $lat_r = 90.0; $lon_r = 180.0; $len = strlen($geohash); if($len == 0) return false; //error $ary_mask = array(16,8,4,2,1); $is_even = true; for($i=0; $i<$len; $i++){ $str = substr($geohash, $i, 1); $v = base32_2_int($str); if($v === false) return false; //error foreach($ary_mask as $mask){ if($is_even){ $lon_r /= 2; if($v & $mask){ $ary_lon = array(($ary_lon[0] + $ary_lon[1])/2, $ary_lon[1]); } else{ $ary_lon = array($ary_lon[0], ($ary_lon[0] + $ary_lon[1])/2); } } else{ $lat_r /= 2; if($v & $mask){ $ary_lat = array(($ary_lat[0] + $ary_lat[1])/2, $ary_lat[1]); } else{ $ary_lat = array($ary_lat[0], ($ary_lat[0] + $ary_lat[1])/2); } } $is_even = !$is_even; } } return array($ary_lat, $ary_lon); } //geohash string to latitude, longitude function geohash_decode($geohash_in){ $ary_tmp = geohash_decode_interval($geohash_in); if($ary_tmp == false) return false; list($ary_lat, $ary_lon) = $ary_tmp; $places_lat = max(1, -round(log10($ary_lat[1] - $ary_lat[0]))) - 1; $places_lon = max(1, -round(log10($ary_lon[1] - $ary_lon[0]))) - 1; $lat = round(($ary_lat[0] + $ary_lat[1]) / 2, $places_lat); $lon = round(($ary_lon[0] + $ary_lon[1]) / 2, $places_lon); return array($lat, $lon); } //latitude, longitude to geohash string function geohash_encode($lat_in, $lon_in, $len_in=11){ $lat = (float)$lat_in; $lon = (float)$lon_in; if($lat < -90 || $lat > 90 || $lon < -180 || $lon > 180) return false; $len = (int)$len_in; if($len <= 0) return false; $ary_lat = array(-90.0, 90.0); $ary_lon = array(-180.0, 180.0); $cnt = 0; $str_bin = ""; while($cnt <= $len * 5){ $lon_c = ($ary_lon[0] + $ary_lon[1]) / 2; if($lon < $lon_c){ $str_bin .= "0"; $ary_lon[1] = $lon_c; } else{ $str_bin .= "1"; $ary_lon[0] = $lon_c; } $lat_c = ($ary_lat[0] + $ary_lat[1]) / 2; if($lat < $lat_c){ $str_bin .= "0"; $ary_lat[1] = $lat_c; } else{ $str_bin .= "1"; $ary_lat[0] = $lat_c; } $cnt++; } $str_geohash = ""; for($i=0; $i<$len; $i++){ $str_sub = substr($str_bin, $i*5, 5); $str_geohash .= int_2_base32(bindec($str_sub)); } return $str_geohash; } //return geohash strings of neighbours function geohash_neighbour($geohash_in, $range_in=1){ $geohash = $geohash_in; $len = strlen($geohash); $range = (int)$range_in; if($range < 1) return false; //error $ary_tmp = geohash_decode_interval($geohash); if($ary_tmp == false) return false; //error list($ary_lat, $ary_lon) = $ary_tmp; $delta_lat = $ary_lat[1] - $ary_lat[0]; $delta_lon = $ary_lon[1] - $ary_lon[0]; $lat = ($ary_lat[0] + $ary_lat[1]) / 2; $lon = ($ary_lon[0] + $ary_lon[1]) / 2; $ary_geohash = array(); for($i=-1*$range; $i<=1*$range; $i++){ for($j=-1*$range; $j<=1*$range; $j++){ if($i == 0 && $j == 0) continue; $lat_tmp = $lat + $delta_lat * $i; if($lat_tmp < -90.0) $lat_tmp += 180.0; else if($lat_tmp > 90.0) $lat_tmp -= 180.0; $lon_tmp = $lon + $delta_lon * $j; if($lon_tmp < -180.0) $lon_tmp += 360.0; else if($lon_tmp > 180.0) $lon_tmp -= 360.0; $str_tmp = geohash_encode($lat_tmp, $lon_tmp, $len); if($str_tmp == false) return false; //error $ary_geohash[] = $str_tmp; } } return $ary_geohash; } 参考: http://blog.masuidrive.jp/index.php/2010/01/13/geohash/trackback/ http://en.wikipedia.org/wiki/Geohash ベタベタな書き方ですが・・・ PR |
|
ホーム |
|
|
トラックバックURL
|
| ホーム |
|