1package Geo::Coordinates::Converter::Format::IArea; 2use strict; 3use warnings; 4use base 'Geo::Coordinates::Converter::Format'; 5our $VERSION = '0.01'; 6use File::ShareDir 'dist_file'; 7use CDB_File; 8use Geo::Coordinates::Converter::iArea; 9 10sub name { 'iarea' } 11 12sub detect { 13 my($self, $point) = @_; 14 return unless Geo::Coordinates::Converter::iArea->get_center( $point->areacode ); 15 return $self->name; 16} 17 18# other(e.g. wgs84) to iarea 19sub from { 20 my ($self, $point) = @_; 21 22 my @mesh = _calc_meshcode($point); 23 if (my $areacode = $self->_meshcode2areacode(@mesh)) { 24 $point->areacode($areacode); 25 } 26 $point; 27} 28 29sub _meshcode2areacode { 30 my ($self, @mesh) = @_; 31 32 my $file = dist_file('Geo-Coordinates-Converter-iArea', 'meshcode2areacode.cdb'); 33 my $cdb = CDB_File->TIEHASH($file); 34 for my $meshcode (@mesh) { 35 if ($cdb->EXISTS($meshcode)) { 36 return $cdb->FETCH($meshcode); 37 } 38 } 39 return; 40} 41 42sub _calc_meshcode { 43 my $point = shift; 44 45 # normalize 46 $point = do { 47 my $geo = Geo::Coordinates::Converter->new(point => $point); 48 $geo->convert('degree', 'tokyo'); 49 }; 50 51 my ($lat,$lng) = map { int ($_ * 60 * 60 * 1000) } ($point->lat, $point->lng); 52 53 my $mesh; 54 my @mesh; 55 my $ab = int($lat / 2400000); 56 my $cd = int($lng / 3600000) - 100; 57 my $x1 = ($cd +100) * 3600000; 58 my $y1 = $ab * 2400000; 59 my $e = int(($lat - $y1) / 300000); 60 my $f = int(($lng - $x1) / 450000); 61 $mesh = $ab.$cd.$e.$f; 62 push @mesh, $mesh; 63 64 my $x2 = $x1 + $f * 450000; 65 my $y2 = $y1 + $e * 300000; 66 my $l3 = int(($lng - $x2) / 225000); 67 my $m3 = int(($lat - $y2) / 150000); 68 my $g = $l3 + $m3 * 2; 69 $mesh .= $g; 70 push @mesh, $mesh; 71 72 my $x3 = $x2 + $l3 * 225000; 73 my $y3 = $y2 + $m3 * 150000; 74 my $l4 = int(($lng - $x3) / 112500); 75 my $m4 = int(($lat - $y3) / 75000); 76 my $h = $l4 + $m4 * 2; 77 $mesh .= $h; 78 push @mesh, $mesh; 79 80 my $x4 = $x3 + $l4 * 112500; 81 my $y4 = $y3 + $m4 * 75000; 82 my $l5 = int(($lng - $x4) / 56250); 83 my $m5 = int(($lat - $y4) / 37500); 84 my $i = $l5 + $m5 * 2; 85 $mesh .= $i; 86 push @mesh, $mesh; 87 88 my $x5 = $x4 + $l5 * 56250; 89 my $y5 = $y4 + $m5 * 37500; 90 my $l6 = int(($lng - $x5) / 28125); 91 my $m6 = int(($lat - $y5) / 18750); 92 my $j = $l6 + $m6 * 2; 93 $mesh .= $j; 94 push @mesh, $mesh; 95 96 my $x6 = $x5 + $l6 * 28125; 97 my $y6 = $y5 + $m6 * 18750; 98 my $l7 = int(($lng - $x6) / 14062.5); 99 my $m7 = int(($lat - $y6) / 9375); 100 my $k = $l7 + $m7 * 2; 101 $mesh .= $k; 102 push @mesh, $mesh; 103 104 @mesh; 105} 106 107# iarea to other(e.g. wgs84) 108sub to { 109 my($self, $point) = @_; 110 111 my $area_geo = _get_center($point) || { lat => '0.000000', lng => '0.000000' }; 112 113 $point->lat($area_geo->{lat}); 114 $point->lng($area_geo->{lng}); 115 $point->datum('tokyo'); 116 117 $point; 118} 119 120sub _get_center { 121 my $point = shift; 122 my $center = Geo::Coordinates::Converter::iArea->get_center( $point->areacode ); 123 +{ lat => $center->lat, lng => $center->lng }; 124} 125 126sub Geo::Coordinates::Converter::Point::areacode { 127 return $_[0]->{'areacode'} if @_ == 1; 128 return $_[0]->{'areacode'} = $_[1] if @_ == 2; 129 shift->{'areacode'} = \@_; 130} 131 132sub Geo::Coordinates::Converter::areacode { 133 my $self = shift; 134 my $point = shift || $self->current; 135 $point->areacode; 136} 137 1381; 139__END__ 140 141=for stopwords aaaatttt dotottto gmail DoCoMo MOVA csv FOMA kazuhiro osawa areacode 142 143=head1 NAME 144 145Geo::Coordinates::Converter::Format::IArea - get center point from iArea 146 147=head1 SYNOPSIS 148 149=over 4 150 151=item GET CENTER POINT FROM AREA CODE 152 153 use Geo::Coordinates::Converter; 154 use Geo::Coordinates::Converter::iArea; 155 156 my $geo = Geo::Coordinates::Converter->new( format => 'iarea', areacode => '00205' ); 157 my $point = $geo->convert('degree' => 'wgs84'); 158 print "lat: ", $point->lat, " lng: ", $point->lng, "\n"; 159 # => lat: 42.859220 lng: 141.492367 160 161=item GET AREACODE FROM LOCATION POINT 162 163 use Geo::Coordinates::Converter; 164 use Geo::Coordinates::Converter::iArea; 165 166 my $geo = Geo::Coordinates::Converter->new( format => 'degree', datum => 'tokyo', lat => '42.859220', lng => '141.492367' ); 167 my $point = $geo->convert('iarea'); 168 print $point->areacode, "\n"; 169 # => 00205 170 171=item INTEGRATE WITH HTTP::MobileAgent::Plugin::Locator 172 173 use Geo::Coordinates::Converter; 174 use Geo::Coordinates::Converter::iArea; 175 use CGI; 176 use HTTP::MobileAgent; 177 use HTTP::MobileAgent::Plugin::Locator; 178 179 my $q = CGI->new(); 180 my $agent = HTTP::MobileAgent->new(); 181 my $orig_point = $agent->get_location($q); 182 my $geo = Geo::Coordinates::Converter->new( point => $orig_point->clone ); 183 my $point = $geo->convert('iarea'); 184 print $point->areacode, "\n"; 185 # => 00205 186 187=back 188 189=head1 DESCRIPTION 190 191Geo::Coordinates::Converter::Format::IArea is utilities for DoCoMo iArea. 192 193easy to get the center point of area. 194 195=head1 ADDITIONAL METHODS FOR Geo::Coordinates::Converter core. 196 197=over 4 198 199=item Geo::Coordinates::Converter->areacode() 200 201areacode accessor 202 203=item Geo::Coordinates::Converter::Point->areacode() 204 205areacode accessor 206 207=back 208 209=head1 INTERNAL METHODS 210 211=over 4 212 213=item name 214 215=item detect 216 217=item from 218 219=item to 220 221DO NOT USE DIRECTLY 222 223=back 224 225=head1 AUTHOR 226 227Kazuhiro Osawa, Tokuhiro Matsuno 228 229=head1 SEE ALSO 230 231C<Geo::Coordinates::Converter::iArea>, L<Location::Area::DoCoMo::iArea> 232 233=head1 LICENSE 234 235This library is free software; you can redistribute it and/or modify 236it under the same terms as Perl itself. 237 238=cut 239