📄 maptilecacher.perl
字号:
#!/usr/bin/perl# version 1.21# created by MichaelAtUVa# updated by Cristian Streng based on suggestions by n95_rit, Kozawa, denilsonsa, CrazyTerabyte and others#Externalsuse Math::Trig;use POSIX;#Caching Variables$numZoomLevels = 17;$dir_TopLevel = "MGMapsCache";$file_CacheConf = "cache.conf";$cache_Version = 3;$tiles_per_file = 1;$hashSize = 97;# Sleep$sleepTime = 0;$sleepEvery = 10000;print <<EOF;*** MGMaps Tile Cacher ***EOF#OS Specific Variables $wget = "wget -Y off -nv -O TempTile ";$linuxDirDivider = "\/"; $linuxMoveCommand = "mv"; $linuxDeleteCommand = "rm";$windowsDirDivider = "\\"; $windowsMoveCommand = "move"; $windowsDeleteCommand = "del";print "Detected OS: $^O\n";if($^O ge "linux" || $^O ge "cygwin" ) { $systemDirDivider = $linuxDirDivider; $systemMoveCommand = $linuxMoveCommand; $systemDeleteCommand = $linuxDeleteCommand; $systemRefererParam = "--referer=http://maps.google.com/ ";}elsif($^O ge "MSWin"){ $systemDirDivider = $windowsDirDivider; $systemMoveCommand = $windowsMoveCommand; $systemDeleteCommand = $windowsDeleteCommand; $systemRefererParam = "--referer=http://maps.google.com/ ";}if($^O eq "darwin"){ $systemDirDivider = $linuxDirDivider; $systemMoveCommand = $linuxMoveCommand; $systemDeleteCommand = $linuxDeleteCommand; $wget = "curl -# -o TempTile "; $systemRefererParam = "-e http://maps.google.com/ "; }$file_CacheConf = $dir_TopLevel.$systemDirDivider.$file_CacheConf;# Main# Read and/or write configurationif (-d $dir_TopLevel == FALSE) { system("mkdir $dir_TopLevel");}# Search for version number$configured = 0;if (-f $file_CacheConf != FALSE) { open(F, "<".$file_CacheConf) or die("Cannot read cache config file"); $line = <F>; @splits = split('=', $line); if (int($splits[1]) > 2) { $line = <F>; @splits = split('=', $line); $tiles_per_file = int($splits[1]); $configured = 1; } else { print "Older version of MGMapsCache found, please (re)move it.\n"; exit; } close(F);}# Ask for configurationif ($configured == 0) { # read configuration print "Cache configuration file does not exist, configuring...\n\n"; do { print "Map tiles per file (a power of two, 1-4096, default $tiles_per_file): "; chomp($tpf = <>); if ($tpf eq "") { $tpf = $tiles_per_file; break; } $tpf = int($tpf); if ($tpf == 0) { $tpf = $tiles_per_file; } # power of two } while (($tpf & -$tpf) != $tpf); $tiles_per_file = $tpf; open(F, ">".$file_CacheConf) or die("Cannot write cache config file"); print F "version=".$cache_Version."\n"; print F "tiles_per_file=".$tiles_per_file."\n"; close(F);}else { print "Storing $tiles_per_file tiles per file.\n\n";}$tiles_per_file_log = 0;$tpf = $tiles_per_file;while ($tpf > 1) { $tiles_per_file_log++; $tpf>>=1;}$tpfy = $tiles_per_file_log>>1;$tpfx = 1<<($tpfy + ($tiles_per_file_log&1));$tpfy = 1<<$tpfy;print <<EOF;Please choose map type by entering the associated keyword (case sensitive)...GoogleMap - Google Road MapsGoogleSat - Google Satellite ImagesGoogleHybrid - Google Satellite Images with Road Maps OverlayedGoogleChina - Google Road Maps (China)YahooMap - Yahoo Rood MapsYahooSat - Yahoo Satellite ImagesYahooHybrid - Yahoo Satellite Images with Road Maps OverlayedAskDotComMap - Ask.com Road MapsAskDotComSat - Ask.com Aerial ImagesAskDotComHybrid - Ask.com Aerial Images with LabelsMicrosoftMap - Microsoft Road MapsMicrosoftSat - Microsoft Aerial ImagesMicrosoftHybrid - Microsoft Aerial Images with Road Maps OverlayedOpenStreetMap - OpenStreetMap.org MapsEOFprint "Choice: ";do { $MapType = <>; $MapType =~ s/^\s+//; $MapType =~ s/\s+$//;} while ($MapType eq "");# TODO make it case insensitiveprint "Enter Zoom Level (0-23): ";chomp($zoomLevel = <>);$zoomLevel = $numZoomLevels-$zoomLevel;print "\nEnter coordinates in decimal degrees format... 38.031078, -78.481529 \n";print "Top left (latitude, longitude): ";($topLeftTileX, $topLeftTileY) = convertCoordindates2Tiles(split(/,/,<>,2), $zoomLevel);print "Bottom right (latitude, longitude): ";($bottomRightTileX, $bottomRightTileY) = convertCoordindates2Tiles(split(/,/,<>,2), $zoomLevel);my $bound = 1<<($numZoomLevels-$zoomLevel);# swap coords if not in correct orderif ($topLeftTileX > $bottomRightTileX) { $t = $topLeftTileX; $topLeftTileX = $bottomRightTileX; $bottomRightTileX = $t; }if ($topLeftTileY > $bottomRightTileY) { $t = $topLeftTileY; $topLeftTileY = $bottomRightTileY; $bottomRightTileY = $t; }# out of map?if ($topLeftTileX < 0) { $topLeftTileX = 0; }if ($bottomRightTileX >= $bound) { $bottomRightTileX = $bound-1; }if ($topLeftTileY < 0) { $topLeftTileY = 0; }if ($bottomRightTileY >= $bound) { $bottomRightTileY = $bound-1; }# still swapped coords? (we're entirely out of the map)if ($topLeftTileX > $bottomRightTileX or $topLeftTileY > $bottomRightTileY) { print "\n*** No map tiles to download ***\n"; exit;}$numTiles = (abs($topLeftTileX-$bottomRightTileX)+1)*(abs($topLeftTileY-$bottomRightTileY)+1);$numTiles *= (index($MapType,"Hybrid") != -1) ? 2 : 1;$zl = $numZoomLevels-$zoomLevel;print <<EOF;Ready to cache $numTiles tiles...Type: $MapTypeZoom: $zlPress enter to continue.EOF$_ = <>;print "*** Caching Started ***\n\n";my $tileCount = 0;my $actualTileCount = 0;downloadTiles($MapType, $topLeftTileX, $topLeftTileY, $bottomRightTileX, $bottomRightTileY);print "\n*** Caching Complete ***\n";exit;#MapTileCacher Subroutinessub convertCoordindates2Tiles { my $lat = shift; my $long = shift; my $z = shift; my $pixelsPerTile = 256; my $mapsize = 2**(($numZoomLevels + (log($pixelsPerTile)/log(2)))-$z); my $origin = $mapsize / 2; my $longdeg = abs(-180 - $long); my $longppd = $mapsize / 360; my $longppdrad = $mapsize/(2*pi); my $pixelx = $longdeg * $longppd; my $longtiles = $pixelx / $pixelsPerTile; my $tilex = cast2Integer($longtiles); my $e = sin($lat*(1/180.*pi)); if ($e>0.9999) { $e=0.9999; } if ($e<-0.9999) { $e=-0.9999; } my $pixely = $origin + 0.5*log((1+$e)/(1-$e)) * (-$longppdrad); my $tiley = cast2Integer($pixely / $pixelsPerTile); return ($tilex, $tiley);}sub downloadTiles{ my $MapType = shift; my $topLeftTileX = shift; my $topLeftTileY = shift; my $bottomRightTileX = shift; my $bottomRightTileY = shift; if(index($MapType,"Hybrid") != -1) { my $MapSource = substr($MapType,0,index($MapType,"Hybrid")); downloadTiles($MapSource . "Sat", $topLeftTileX, $topLeftTileY, $bottomRightTileX, $bottomRightTileY); downloadTiles($MapSource . "Hyb", $topLeftTileX, $topLeftTileY, $bottomRightTileX, $bottomRightTileY); } else { for ($y = $topLeftTileY; $y <= $bottomRightTileY; $y++) { for ($x = $topLeftTileX; $x <= $bottomRightTileX; $x++) { $tileCount++; # avoid sleeping for #0 if ((($actualTileCount+1) % $sleepEvery) == 0) { print "* Sleeping $sleepTime seconds\n"; sleep($sleepTime); } my $localFileName = $dir_TopLevel . $systemDirDivider . $MapType . "_" .($numZoomLevels-$zoomLevel); if ($tiles_per_file == 1) { $localFileName .= $systemDirDivider . (($x*256+$y)%$hashSize) . $systemDirDivider . "$x\_$y"; } else { $localFileName .= $systemDirDivider . int($x/$tpfx) . "_" . int($y/$tpfy); } $localFileName .= ".mgm"; $dx = $x % $tpfx; $dy = $y % $tpfy; my $url = getTileURL($MapType,$x,$y); $found = checkCached($localFileName,$dx,$dy); if($found == 0) { my $referer = (index($MapType,"Google") != -1) ? $systemRefererParam : ""; $wgetFileCommand = $wget . $referer. "\"" . $url . "\"" ; print "* Downloading tile $tileCount of $numTiles from $url\n"; if (index($MapType,"Sat") != -1) {$actualTileCount++;} system($wgetFileCommand); cacheDownloadedTile("TempTile",$localFileName,$dx,$dy); } else {print "* Skipping tile $tileCount of $numTiles from $url (already cached).\n";} } } }}# check if the map tile is already cached in $localFilename as ($dx,$dy)sub checkCached{ my $localFileName = shift; my $dx = shift; my $dy = shift; local $buf = ''; if (-f $localFileName == FALSE) { return 0; } # if the file exists and we have 1 tile/file, don't verify anything else elsif ($tiles_per_file == 1) { return 1; } sysopen(FD, $localFileName, O_RDONLY); binmode(FD); sysread(FD, $buf, 6*$tiles_per_file+2); $num = (ord(substr($buf,0,1))<<8)+ord(substr($buf,1,1)); for (my $i=0; $i<$num; $i++) { if (ord(substr($buf,2+$i*6,1)) == $dx && ord(substr($buf,2+$i*6+1,1)) == $dy) { close(FD); return 1; } } close(FD); return 0;}sub cacheDownloadedTile{ my $tempTile = shift; my $localFileName = shift; my $dx = shift; my $dy = shift; local $buf = ''; if(-s $tempTile) { my $dir_TopLevel; my $dir_TypeZoomLevel; my $dir_HashLevel; if ($tiles_per_file == 1) { ($dir_TopLevel, $dir_TypeZoomLevel, $dir_HashLevel) = split(($systemDirDivider eq "\\") ? "$systemDirDivider$systemDirDivider" : "$systemDirDivider",$localFileName); } else { ($dir_TopLevel, $dir_TypeZoomLevel) = split(($systemDirDivider eq "\\") ? "$systemDirDivider$systemDirDivider" : "$systemDirDivider",$localFileName); } $dir_TypeZoomLevel = $dir_TopLevel . $systemDirDivider . $dir_TypeZoomLevel; if(-d $dir_TypeZoomLevel == FALSE){system("mkdir $dir_TypeZoomLevel");} if ($tiles_per_file == 1) { $dir_HashLevel = $dir_TypeZoomLevel . $systemDirDivider . $dir_HashLevel; if(-d $dir_HashLevel == FALSE){system("mkdir $dir_HashLevel");} system("$systemMoveCommand $tempTile $localFileName"); print "\tTile cached at $localFileName\n"; return; } # append to the file, write info and offset to header my $num = 0; my $ofs = $tiles_per_file*6+2; $existed = ((-f $localFileName != FALSE) ? 1 : 0); sysopen($fh, $localFileName, O_RDWR|O_CREAT); binmode($fh); if ($existed == 1) { sysread($fh, $buf, $ofs); $num = (ord(substr($buf,0,1))<<8)+ord(substr($buf,1,1)); $ofs = (ord(substr($buf,2+$num*6-6+2,1))<<24)+ (ord(substr($buf,2+$num*6-6+3,1))<<16)+ (ord(substr($buf,2+$num*6-6+4,1))<<8)+ ord(substr($buf,2+$num*6-6+5,1)); } else { $buf = chr(0) x $ofs; syswrite($fh, $buf, $ofs); } my $totalsize = 0; sysseek($fh, $ofs, 0); sysopen(F2, $tempTile, O_RDONLY); binmode(F2); while ((my $read = sysread(F2, $buf, 4096)) > 0) { $totalsize += $read; syswrite($fh, $buf, $read); } close(F2); # new offset $totalsize += $ofs; # update header - number of tiles $buf = "" . chr(($num+1)>>8) . chr(($num+1)&255); sysseek($fh, 0, 0); syswrite($fh, $buf, 2); # update header - new tile data $buf = "" . chr($dx) . chr($dy) . chr($totalsize>>24) . chr(($totalsize>>16)&255) . chr(($totalsize>>8)&255) . chr($totalsize&255); sysseek($fh, 6*$num+2, 0); syswrite($fh, $buf, 6); close($fh); # delete temp tile system("$systemDeleteCommand $tempTile"); # system("$systemMoveCommand $tempTile $localFileName"); print "\tTile cached at $localFileName\n" } else {system("$systemDeleteCommand $tempTile"); print "\tERROR: Requested tile did not exist.\n"}}sub getTileURL{ my $MapType = shift; my $x = shift; my $y = shift; my $url = ""; if($MapType eq "GoogleMap" || $MapType eq "GoogleHyb") { $url = "http://mt" . (($x+$y)%4) . ".google.com/mt?n=404&v="; $url .= ($MapType eq "GoogleMap") ? "w2.56" : "w2t.57"; $url .= "&x=$x&y=$y&zoom=$zoomLevel"; } elsif($MapType eq "GoogleChina") { $url = "http://mapgoogle.mapabc.com/googlechina/maptile?v=w2.56"; $url .= "&x=$x&y=$y&zoom=$zoomLevel"; } elsif($MapType eq "GoogleSat") { my @goolgeSatURLLetters = ("q", "r", "t", "s" ); $url = "http://kh" . (($x+$y)%4) . ".google.com/kh?n=404&v=18&t=t"; for($i=$numZoomLevels-$zoomLevel-1; $i >= 0; $i--) { $url .= $goolgeSatURLLetters[((($y >> $i) & 1) << 1) + (($x >> $i) & 1)]; } } elsif(index($MapType,"Yahoo") != -1) { $url = ($MapType eq "YahooMap") ? "http://png.maps.yimg.com/png?t=m&v=3.52" : ($MapType eq "YahooSat") ? "http://aerial.maps.yimg.com/tile?t=a&v=1.7" : "http://aerial.maps.yimg.com/png?t=h&v=2.2"; $url .= "&x=$x&y=" . (((1 << ($numZoomLevels-$zoomLevel)) >> 1)-1-$y) . "&z=" . ($zoomLevel+1); } elsif(index($MapType,"Microsoft") != -1) { $url = ($MapType eq "MicrosoftMap") ? "http://r" : ($MapType eq "MicrosoftSat") ? "http://a" : "http://h"; $url .= ((($y & 1) << 1) + ($x & 1)) . ".ortho.tiles.virtualearth.net/tiles/"; $url .= ($MapType eq "MicrosoftMap") ? "r" : ($MapType eq "MicrosoftSat") ? "a" : "h"; for($i=$numZoomLevels-$zoomLevel-1; $i >= 0; $i--) { $url = $url . ((((($y >> $i) & 1) << 1) + (($x >> $i) & 1))); } $url .= ($MapType eq "MicrosoftMap") ? ".png?g=72" : ".jpeg?g=72"; } elsif(index($MapType,"AskDotCom") != -1) { $url = ($zoomLevel > 6) ? "http://mapstatic" : "http://mapcache"; $url .= (($x+$y)%4 + 1) . ".ask.com/"; $url .= ($MapType eq "AskDotComMap") ? "map" : ($MapType eq "AskDotComSat") ? "sat" : "mapt"; $url .= "/" . ($zoomLevel+2) . "/"; $url .= ($x-((1<<($numZoomLevels-$zoomLevel))>>1)) . "/" . ($y-((1<<($numZoomLevels-$zoomLevel))>>1)); $url .= "?partner=&tc=28"; } elsif(index($MapType,"OpenStreetMap") != -1) { $url = "http://tile.openstreetmap.org/" . ($numZoomLevels-$zoomLevel) . "/" . $x . "/" . $y . ".png"; } return $url}#Utility Subroutinessub cast2Integer { my $f = shift; if ($f < 0) {return ceil($f);} else {return floor($f);}}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -