package MT::Plugin::Locations; use MT::Template::Context; use Image::Info qw(image_info dim); use HTML::LinkExtor; use File::Spec; MT::Template::Context->add_container_tag(Locations => sub { &locations }); MT::Template::Context->add_tag(Location => sub { &location }); sub locations { my ($ctx, $args, $cond) = @_; my $builder = $ctx->stash('builder'); my $tokens = $ctx->stash('tokens'); my $entry = $ctx->stash('entry'); my $site_url = $ctx->stash('blog')->site_url; my $site_path = $ctx->stash('blog')->site_path; my %loc; my $res = ''; my ($lat, $lon); my $text = $entry->text; my $le = HTML::LinkExtor->new; $le->parse($text); foreach my $link ($le->links) { if (($link->[0] eq 'img')&&($link->[1] eq 'src')) { my $imgsrc = $link->[2]; $imgsrc =~ s/^$site_url//; unless ($imgsrc =~ '^https?://') { my $imgfile = File::Spec->catfile($site_path, $imgsrc); if ($args->{debug}) { $ctx->stash('debug_img', $imgfile); defined(my $out = $builder->build($ctx, $tokens, $cond)) or return $ctx->error($ctx->errstr); $res .= $out; } if (-e $imgfile) { my $info = image_info($imgfile); my @lats = $info->{GPSLatitude}; my @lons = $info->{GPSLongitude}; if ((ref $lats[0])&&(ref $lons[0])) { my $lat = $lats[0][0]/($lats[0][1]||1) + $lats[0][2]/($lats[0][3]||1)/60 + $lats[0][4]/($lats[0][5]||1)/3600; my $lon = $lons[0][0]/($lons[0][1]||1) + $lons[0][2]/($lons[0][3]||1)/60 + $lons[0][4]/($lons[0][5]||1)/3600; my $datum = 0; $datum = 1 if ($info->{GPSMapDatum} eq 'TOKYO'); $loc{"$lat,$lon,$datum"}++ } } } } } foreach (split(/\n/, $text)) { my ($lat, $lon); my $datum = 0; if (/http:\/\/www\.at\-navi\.com\/.*?lat=.?([0-9]+)\.([0-9]+)\.(([0-9]+)\.?([0-9]+)).*/) { $lat = (/http:\/\/www\.at\-navi\.com\/.*?lat=[^0-9]?([0-9]+)\.([0-9]+)\.(([0-9]+)\.?([0-9]+)).*/) ? $1 + $2/60 + $3/3600 : undef; $lon = (/http:\/\/www\.at\-navi\.com\/.*?lon=[^0-9]?([0-9]+)\.([0-9]+)\.(([0-9]+)\.?([0-9]+)).*/) ? $1 + $2/60 + $3/3600 : undef; } elsif (/http:\/\/walk\.eznavi\.jp\/map\/\?.*?lat=[^0-9]?([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+).*/) { $lat = (/http:\/\/walk\.eznavi\.jp\/map\/\?.*?lat=[^0-9]?([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+).*/) ? $1 + $2/60 + ($3 + $4/100)/3600 : undef; $lon = (/http:\/\/walk\.eznavi\.jp\/map\/\?.*?lon=[^0-9]?([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+).*/) ? $1 + $2/60 + ($3 + $4/100)/3600 : undef; $datum = (/http:\/\/walk\.eznavi\.jp\/map\/\?.*?datum=([0-9])/) ? $1 : undef; } elsif (/http:\/\/walk\.eznavi\.jp\/map\/\?.*?lat=.?([0-9]+)\.([0-9]+).*/) { $lat = (/http:\/\/walk\.eznavi\.jp\/map\/\?.*?lat=[^0-9]?(([0-9]+)\.([0-9]+)).*/) ? $1 : undef; $lon = (/http:\/\/walk\.eznavi\.jp\/map\/\?.*?lon=[^0-9]?(([0-9]+)\.([0-9]+)).*/) ? $1 : undef; $datum = (/http:\/\/walk.eznavi.jp\/map\/\?.*?datum=([0-9])/) ? $1 : undef; } elsif (/http:\/\/www\.gpspowered\.jp\/.*?pos=N([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)E([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+).*/) { $lat = (/http:\/\/www\.gpspowered\.jp\/.*?pos=N([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+).*/) ? $1 + $2/60 + ($3 + $4/100)/3600 : undef; $lon = (/http:\/\/www\.gpspowered\.jp\/.*?pos=.*E([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+).*/) ? $1 + $2/60 + ($3 + $4/100)/3600 : undef; } elsif (/http:\/\/.*mapfan\.com\/.*\?MAP=[EN]([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)[EN]([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)/) { $lat = (/http:\/\/.*mapfan\.com\/.*\?.*MAP=.*N([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)/) ? $1 + $2/60 + ($3 + $4/100)/3600 : undef; $lon = (/http:\/\/.*mapfan\.com\/.*\?.*MAP=.*E([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)/) ? $1 + $2/60 + ($3 + $4/100)/3600 : undef; $datum = 1; } elsif (/http:\/\/www\.mapion\.co\.jp\/.*\?.*nl=([0-9]+)\/([0-9]+)\/([0-9]+)\.([0-9]+)/) { $lat = (/http:\/\/www\.mapion\.co\.jp\/.*\?.*nl=([0-9]+)\/([0-9]+)\/([0-9]+)\.([0-9]+)/) ? $1 + $2/60 + ($3 + $4/100)/3600 : undef; $lon = (/http:\/\/www\.mapion\.co\.jp\/.*\?.*el=([0-9]+)\/([0-9]+)\/([0-9]+)\.([0-9]+)/) ? $1 + $2/60 + ($3 + $4/100)/3600 : undef; $datum = 1; } $loc{"$lat,$lon,$datum"}++ if ($lon && $lat); } foreach (keys %loc) { my ($lat, $lon, $datum) = split(/\,/); $ctx->stash('latitude', $lat); $ctx->stash('longitude', $lon); $ctx->stash('datum', $datum); defined(my $out = $builder->build($ctx, $tokens, $cond)) or return $ctx->error($ctx->errstr); $res .= $out; } $res; } sub location { my ($ctx, $args) = @_; my $lat = $ctx->stash('latitude'); my $lon = $ctx->stash('longitude'); my $datum = $ctx->stash('datum') || 0; my $coordinate = $args->{coordinate} || ''; my $frmt = $args->{'format'} || ''; my $res = ''; if ($args->{debug}) { my $img = $ctx->stash('debug_img'); $res .= <<"EOD"; EOD } if ($lat && $lon) { ($lon, $lat) = geoconv($lon, $lat, $args->{datum}) if ($args->{datum} != $datum); ($lat, $lon) = (deg2dms($lat), deg2dms($lon)) if ($frmt eq 'dms'); if ($coordinate eq 'latitude') { $res .= $lat; } elsif ($coordinate eq 'longitude') { $res .= $lon; } else { $res .= "$lat,$lon"; } } $res; } sub geoconv { my ($lon, $lat, $datum) = @_; my ($b, $l, $h) = ($lat, $lon, 0); $b = dms2deg($b) if ($b =~ /([0-9]+)\.([0-9]+)\.(([0-9]+)\.?([0-9]+))/); $l = dms2deg($l) if ($l =~ /([0-9]+)\.([0-9]+)\.(([0-9]+)\.?([0-9]+))/); # 直交座標経由の測地系変換 # Nowral PXI07463@nifty.ne.jp # 99/9/10 # # 定数 my $pi = 4 * atan2(1,1); # 円周率 my $rd = $pi / 180; # [ラジアン/度] # 変換したい座標 # (Tokyo) # 緯度 35°20′39.984328″ # 経度 138°35′08.086122″ # 高さ 697.681000 [m] #$b = 35 + 20/60 + 39.984328/3600; # 緯度 [度] #$l = 138 + 35/60 + 8.086122/3600; # 経度 [度] #$h = 697.681000; # 高さ [m] #print "変換前\n緯度: ",°2dms($b),"\n経度: ",°2dms($l),"\n高さ: $h\n\n"; # データム諸元 # 変換元 # (WGS 84) $a = 6378137.0; # 6378137; # 赤道半径 $f = 1 / 298.257223563; # 1 / 298.257223; # 扁平率 $e2 = 2*$f - $f*$f; # 第1離心率 # 変換先 # (Tokyo) $a_ = 6378137.0 - 739.845; # 6377397.155; $f_ = 1/298.257223563 - 0.000010037483; # 1 / 299.152813; $e2_ = 2*$f_ - $f_*$f_; # 並行移動量 [m] # e.g. $x_ = $x + $dx etc. #$dx = -148; #$dy = +507; #$dz = +681; # JGD2000 #my $dx = -146.414; #my $dy = +507.337; #my $dz = +680.507; # 変換 if ($datum == 1) { # TOKYO97 my $dx = +146.336; my $dy = -506.832; my $dz = -680.254; my ($x, $y, $z) = &llh2xyz($b, $l, $h, $a, $e2); ($b, $l, $h) = &xyz2llh($x+$dx, $y+$dy, $z+$dz, $a_, $e2_); } else { # WGS-84 my $dx = -146.336; my $dy = +506.832; my $dz = +680.254; my ($x, $y, $z) = &llh2xyz($b, $l, $h, $a_, $e2_); ($b, $l, $h) = &xyz2llh($x+$dx, $y+$dy, $z+$dz, $a, $e2); } return ($l, $b); # 変換された座標 #print "変換後\n緯度: ",$b,"\n経度: ",$l,"\n高さ: $h\n\n"; #&MacPerl'Quit(2); #die "The Unhappy End"; } sub llh2xyz { # 楕円体座標 -> 直交座標 my($b, $l, $h, $a, $e2) = @_; my($sb, $cb, $rn, $x, $y, $z); my $pi = 4 * atan2(1,1); # 円周率 my $rd = $pi / 180; # [ラジアン/度] $b *= $rd; $l *= $rd; $sb = sin($b); $cb = cos($b); $rn = $a / sqrt(1-$e2*$sb*$sb); $x = ($rn+$h) * $cb * cos($l); $y = ($rn+$h) * $cb * sin($l); $z = ($rn*(1-$e2)+$h) * $sb; ($x, $y, $z); } sub xyz2llh { # 直交座標 -> 楕円体座標 my($x, $y, $z, $a, $e2) = @_; my($bda, $p, $t, $st, $ct, $b, $l, $sb, $rn, $h); $bda = sqrt(1-$e2); # b/a my $pi = 4 * atan2(1,1); # 円周率 my $rd = $pi / 180; # [ラジアン/度] $p = sqrt($x*$x+$y*$y); $t = atan2($z, $p*$bda); $st = sin($t); $ct = cos($t); $b = atan2($z+$e2*$a/$bda*$st*$st*$st, $p-$e2*$a*$ct*$ct*$ct); $l = atan2($y, $x); $sb = sin($b); $rn = $a / sqrt(1-$e2*$sb*$sb); $h = $p/cos($b) - $rn; ($b/$rd, $l/$rd, $h); } sub deg2dms { my($d) = @_; my($m, $s, $sf); $sf = int($d*360000 + 0.5); $s = $sf / 100 % 60; $m = $sf / 6000 % 60; $d = int($sf/360000); $sf %= 100; sprintf("%d\.%d\.%d\.%d", $d, $m, $s, $sf); } sub dms2deg { my $dms = shift; my $deg = $1 + $2/60 + $3/3600 if ($dms =~ /([0-9]+)\.([0-9]+)\.(([0-9]+)\.?([0-9]+))/); return $deg; }