File Coverage

blib/lib/Geo/JapanMesh.pm
Criterion Covered Total %
statement 113 120 94.1
branch 23 32 71.8
condition 5 13 38.4
subroutine 16 18 88.8
pod 6 6 100.0
total 163 189 86.2


line stmt bran cond sub pod time code
1             package Geo::JapanMesh;
2              
3 4     4   216718 use warnings;
  4         9  
  4         117  
4 4     4   22 use strict;
  4         8  
  4         111  
5 4     4   19 use Carp;
  4         13  
  4         313  
6              
7 4     4   3593 use version; our $VERSION = qv('0.0.2');
  4         10323  
  4         24  
8 4     4   379 use vars qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
  4         6  
  4         255  
9 4     4   20 use Exporter;
  4         7  
  4         7040  
10             @ISA = qw(Exporter);
11             @EXPORT = qw(latlng2japanmesh japanmesh2latlng japanmesh2rect);
12             @EXPORT_OK = qw(
13             latlng2iareamesh iareamesh2latlng iareamesh2rect
14             );
15             %EXPORT_TAGS = (
16             iareamesh => [qw(latlng2iareamesh iareamesh2latlng iareamesh2rect)],
17             japanmesh => [qw(latlng2japanmesh japanmesh2latlng japanmesh2rect)],
18             );
19              
20             # Export function for JapanMesh
21              
22             sub latlng2japanmesh {
23 15     15 1 19946 my $lat = shift;
24 15         20 my $lng = shift;
25 15   50     44 my $num = shift || 1;
26              
27 15 50       85 croak("Level number must be between 1 and 3") if ( $num !~ /^[1-3]$/ );
28              
29 15         31 my ( $slat, $slng ) = _latlng2msec( $lat, $lng );
30              
31 15         34 return _latlng2japanmesh( $slat, $slng, $num );
32             }
33              
34             sub japanmesh2latlng{
35 0     0 1 0 my @rect = japanmesh2rect(@_);
36 0         0 return @rect[4..6];
37             }
38              
39             sub japanmesh2rect {
40 3     3 1 13178 my $jmesh = shift;
41 3         18 my @res = grep { defined($_) } ( $jmesh =~ /(\d{2})(\d{2})\-?(?:(\d)(\d)\-?(?:(\d)(\d))?)?/ );
  18         30  
42            
43 3 50 33     32 croak("Maybe format is wrong: $jmesh") if ( @res < 2 || @res > 6 || @res % 2 != 0 );
      33        
44              
45 3         10 my ( $mny, $mnx, $mxy, $mxx, $lvl ) = _japanmesh2rect( @res );
46              
47 3         10 ( $mny, $mnx, $mxy, $mxx ) = _msec2latlng( $mny, $mnx, $mxy, $mxx );
48 3         8 my ( $cy, $cx ) = ( ( $mny + $mxy ) / 2, ( $mnx + $mxx ) / 2 );
49              
50 3         12 return ( $mny, $mnx, $mxy, $mxx, $cy, $cx, $lvl );
51             }
52              
53             # Export function for iAreaMesh
54              
55             sub latlng2iareamesh {
56 15     15 1 22 my $lat = shift;
57 15         19 my $lng = shift;
58 15   50     32 my $num = shift || 1;
59              
60 15 50       70 croak("Level number must be between 1 and 8") if ( $num !~ /^[1-8]$/ );
61              
62 15         26 my ( $slat, $slng ) = _latlng2msec( $lat, $lng );
63              
64 15 50       34 return _latlng2japanmesh( $slat, $slng, $num ) if ( $num < 3 );
65              
66 15         30 my ( $ret, $a, $b ) = _latlng2japanmesh( $slat, $slng, -2 );
67 15         46 $ret =~ s/\-//g;
68 15         48 return _latlng2iareamesh( $ret, $a, $b, $num - 2, 1 );
69             }
70              
71             sub iareamesh2latlng{
72 0     0 1 0 my @rect = iareamesh2rect(@_);
73 0         0 return @rect[4..6];
74             }
75              
76             sub iareamesh2rect {
77 341     341 1 968384 my $imesh = shift;
78 341         2218 my @res = grep { defined($_) } ( $imesh =~ /(\d{2})(\d{2})(?:(\d)(\d)(?:(\d{1,6}))?)?/ );
  1705         4405  
79              
80 341 50 33     2656 croak("Maybe format is wrong: $imesh") if ( @res < 2 || @res > 5 );
81              
82 341         1241 my ( $mny, $mnx, $mxy, $mxx, $lvl ) = _japanmesh2rect( splice( @res, 0, 4 ) );
83              
84 341 100       947 if ( @res ) {
85 340         975 ( $mny, $mnx, $mxy, $mxx, $lvl ) = _iareamesh2rect( $res[0], $mny, $mnx, 1 );
86             }
87              
88 341         993 ( $mny, $mnx, $mxy, $mxx ) = _msec2latlng( $mny, $mnx, $mxy, $mxx );
89 341         806 my ( $cy, $cx ) = ( ( $mny + $mxy ) / 2, ( $mnx + $mxx ) / 2 );
90              
91 341         2151 return ( $mny, $mnx, $mxy, $mxx, $cy, $cx, $lvl );
92             }
93              
94             # Internal function for Common Use
95              
96 30     30   46 sub _latlng2msec { map { $_ * 3600000 } @_; }
  60         171  
97              
98 344     344   529 sub _msec2latlng { map { $_ / 3600000 } @_; }
  1376         2464  
99              
100             # Internal function for JapanMesh
101              
102             sub _latlng2japanmesh {
103 30     30   63 my $lat = shift;
104 30         29 my $lng = shift;
105 30         29 my $num = shift;
106              
107 30         49 my $p = int( $lat / 2400000 );
108 30         38 my $a = $lat - $p * 2400000;
109 30         37 my $s = int( $lng / 3600000 ) - 100;
110 30         46 my $c = $lng - ( $s + 100 ) * 3600000;
111              
112 30         116 my $ret = $p.$s;
113 30 100       77 return $ret if ( $num == 1 );
114              
115 25         33 my $q = int( $a / 300000 );
116 25         28 my $t = int( $c / 450000 );
117              
118 25         42 $ret .= "-$q$t";
119 25 100       62 return $ret if ( $num == 2 );
120              
121 20         26 my $b = $a - $q * 300000;
122 20         24 my $d = $c - $t * 450000;
123              
124 20 100       69 return ($ret, $b, $d) if ( $num == -2 );
125              
126 5         7 my $r = int( $b / 30000 );
127 5         11 my $u = int( $d / 45000 );
128              
129 5         9 $ret .= "-$r$u";
130 5 50       28 return $ret if ( $num == 3 );
131              
132 0         0 my $e = $b - $r * 30000;
133 0         0 my $f = $d - $u * 45000;
134              
135 0 0       0 return ($ret, $e, $f) if ( $num == -3 );
136             }
137              
138             sub _japanmesh2rect {
139 344     344   1130 my @codes = @_;
140              
141 344         639 my ( $mny, $mnx ) = ( 0.0, 100.0 * 3600000 );
142              
143 344         689 my ( $cy1, $cx1 ) = splice( @codes, 0, 2 );
144 344         1096 ( $mny, $mnx ) = ( $mny + $cy1 * 2400000, $mnx + $cx1 * 3600000 );
145 344         651 my ( $mxy, $mxx ) = ( $mny + 2400000, $mnx + 3600000 );
146              
147 344 100       826 return ( $mny, $mnx, $mxy, $mxx, 1 ) unless ( @codes );
148              
149 343         677 my ( $cy2, $cx2 ) = splice( @codes, 0, 2 );
150 343         779 ( $mny, $mnx ) = ( $mny + $cy2 * 300000, $mnx + $cx2 * 450000 );
151 343         554 ( $mxy, $mxx ) = ( $mny + 300000, $mnx + 450000 );
152              
153 343 100       1357 return ( $mny, $mnx, $mxy, $mxx, 2 ) unless ( @codes );
154              
155 1         2 my ( $cy3, $cx3 ) = @codes;
156 1         3 ( $mny, $mnx ) = ( $mny + $cy3 * 30000, $mnx + $cx3 * 45000 );
157 1         5 ( $mxy, $mxx ) = ( $mny + 30000, $mnx + 45000 );
158              
159 1         4 return ( $mny, $mnx, $mxy, $mxx, 3 );
160             }
161              
162             # Internal function for iAreaMesh
163              
164             sub _latlng2iareamesh {
165 75     75   88 my $ret = shift;
166 75         86 my $y = shift;
167 75         71 my $x = shift;
168 75         73 my $num = shift;
169 75         62 my $depth = shift;
170              
171 75         96 my $divy = 300000 / 2 ** $depth;
172 75         89 my $divx = 450000 / 2 ** $depth;
173              
174 75         89 my $rety = int( $y / $divy );
175 75         88 my $nxty = $y - $rety * $divy;
176 75         87 my $retx = int( $x / $divx );
177 75         77 my $nxtx = $x - $retx * $divx;
178              
179 75         99 $ret .= $retx + $rety * 2;
180              
181 75 100       277 return $depth >= $num ? $ret
182             : _latlng2iareamesh( $ret, $nxty, $nxtx, $num, $depth + 1 );
183              
184             }
185              
186             sub _iareamesh2rect {
187 1252     1252   3563 my ( $code, $mny, $mnx, $depth ) = @_;
188              
189 1252         1974 my $divy = 300000 / 2 ** $depth;
190 1252         1574 my $divx = 450000 / 2 ** $depth;
191              
192 1252         5684 my ( $this, $rest ) = $code =~ /^([0-3])(?:([0-3]+))?$/;
193              
194 1252 50       3734 croak("Maybe format is wrong") unless ( defined( $this ) );
195              
196 1252         2267 my $dy = int( $this / 2 );
197 1252         1466 my $dx = $this % 2;
198              
199 1252         3326 ( $mny, $mnx ) = ( $mny + $dy * $divy, $mnx + $dx * $divx );
200              
201 1252 100       12608 return _iareamesh2rect( $rest, $mny, $mnx, $depth + 1 ) if ( defined( $rest ) );
202              
203 340         496 my ( $mxy, $mxx ) = ( $mny + $divy, $mnx + $divx );
204              
205 340         1921 return ( $mny, $mnx, $mxy, $mxx, $depth + 2 );
206             }
207              
208             1; # Magic true value required at end of module
209             __END__