#!/usr/bin/python import os,sys,getopt,time,random,math,urllib def usage(): text = " Usage: " + sys.argv[0] + """ [options] [ACTION] Actions: sat -- Gets you the satellite map map -- Gets you the default map Options: -x n : Google maps x tile number at current zoom level. -y n : Google maps y tile number at current zoom level. -w n : How many tiles around the center in the x direction -h n : How many tiles around the center in the y direction -z n : Zoom level 0-8 -d : Default values of the above variables are used. -a "address ": If address is a valid address that can be found using google maps, the code will find a nearby x,y tile to start grabbing tiles. Example: gmaps.py -d Uses the default for everything. gmaps.py -z 0 Uses the default except the zoom value is set to zero. gmaps.py -a "32311" Uses the zip code 32311 as center with default values. To test: If the command below does not work on a machine, you will either need to get a new machine/IP or tweak the code. wget "http://kh2.google.com/kh?n=404&v=12&t=tqstqtrqtqtqtq" Version 0.001-maps.py Copyleft 2006, Piyush Kumar (Google Keyword: "Piyush") """ print text def address2latlong(laddress): # Encode query string into URL url = 'http://maps.google.com/?q=' + urllib.quote(laddress) + '&output=js' print '\nGoogle Maps Query: %s' % (url) # Get XML location xml = urllib.urlopen(url).read() lat,lng = 0.0,0.0 if '' in xml: print '\nGoogle cannot interpret the address.' sys.exit(1) else: # Strip lat/long coordinates from XML center = xml[xml.find('{center')+10:xml.find('}',xml.find('{center'))] center = center.replace('lat:','').replace('lng:','') lat,lng = center.split(',') url = 'http://maps.google.com/maps?q=%s+%s' % (lat,lng) return float(lat),float(lng) # Given pixel address from the full map at zoom level Z, return the # latitude and longitude of that address. def pixel2coord(x, y, z): eps = 0.000001 TileWidth=256; zoomlevels=17; mapsize= 1 << int(zoomlevels + math.log(TileWidth,2)- z ) origin = mapsize/2.0; longdpp=360.0/mapsize; long=-180.0+float(x)*TileWidth*longdpp; latpprad=mapsize/(math.pi*2.0); e=(y*TileWidth-origin)/(-1.0*latpprad); if e > math.pi: e = math.pi - eps; elif e < (-1.0*math.pi): e = (-1.0*math.pi)+eps; lat=(2.0*math.atan(math.exp(e))-(math.pi/2.0))*180.0/math.pi; #print "Longitude = " + str(long) + "\t Latitude = " + str(lat) return long, lat; def myint(f): if (f < 0): return math.ceil(f) else: return math.floor(f) def coord2tile( mlat, mlong, mz ): # Given coordinates and zoom level, return the address of the tile which # contains them, as well as their pixel address on the full map. pi = math.pi tw = 256 zoomlevels = 17 #print "Longitude = " + str(mlong) + "\t Latitude = " + str(mlat) mapsize= 1 << int(zoomlevels + math.log(tw,2)- mz ) origin = mapsize/2.0; longdeg = math.fabs(-180.0 - mlong); longppd = mapsize / 360.0; longppdrad = mapsize/(2.0*pi); pixelx = longdeg * longppd; longtiles = pixelx / float(tw); tilex = myint(longtiles); e = math.sin(mlat*(pi/180.0)); if (e>0.9999): e=0.9999 if (e<-0.9999): e=-0.9999 pixely = origin + 0.5*math.log((1+e)/(1-e)) * (-longppdrad); tiley = myint(pixely / tw); pixely = int(pixely); pixelx = int(pixelx); return tilex, tiley, pixelx, pixely def quadtree(x,y, zoom): out = [] m = {(0,0):'q', (0,1):'t', (1,0):'r', (1,1):'s'} for i in range(17-zoom): x, rx = divmod(x, 2) y, ry = divmod(y, 2) out.insert(0, m[(rx,ry)]) return 't' + ''.join(out) def xyzoom(quad): x, y, z = 0, 0, 17 m = {'q':(0,0), 't':(0,1), 'r':(1,0), 's':(1,1)} for c in quad[1:]: x = x*2 + m[c][0] y = y*2 + m[c][1] z -= 1 return x, y, z class progressbarClass: def __init__(self, finalcount, progresschar=None): import sys self.finalcount=finalcount self.blockcount=0 # # See if caller passed me a character to use on the # progress bar (like "*"). If not use the block # character that makes it look like a real progress # bar. # if not progresschar: self.block=chr(178) else: self.block=progresschar # # Get pointer to sys.stdout so I can use the write/flush # methods to display the progress bar. # self.f=sys.stdout # # If the final count is zero, don't start the progress gauge # if not self.finalcount : return self.f.write('\n------------------ Progress -------------------1\n') self.f.write(' 1 2 3 4 5 6 7 8 9 0\n') self.f.write('----0----0----0----0----0----0----0----0----0----0\n') return def progress(self, count): # # Make sure I don't try to go off the end (e.g. >100%) # count=min(count, self.finalcount) # # If finalcount is zero, I'm done # if self.finalcount: percentcomplete=int(round(100*count/self.finalcount)) if percentcomplete < 1: percentcomplete=1 else: percentcomplete=100 #print "percentcomplete=",percentcomplete blockcount=int(percentcomplete/2) #print "blockcount=",blockcount if blockcount > self.blockcount: for i in range(self.blockcount,blockcount): self.f.write(self.block) self.f.flush() if percentcomplete == 100: self.f.write("\n") self.blockcount=blockcount return if __name__ == "__main__": if (len(sys.argv) < 2): usage() sys.exit() try: opts, args = getopt.getopt(sys.argv[1:], "dx:dy:dz:dw:dh:da:") except getopt.GetoptError: usage() sys.exit(2) # default values to be set here. sx = 34840 sy = 53888 zoom = 0 w = 10 h = 10 laddress='' # Parse arguments. for opt, arg in opts: if opt in ("-x"): sx = int(arg) elif opt == '-y': sy = int(arg) elif opt == '-z': zoom = int(arg) elif opt == '-w': w = int(arg) elif opt == '-h': h = int(arg) elif opt == '-a': laddress = str(arg) if laddress != '': mlat,mlong = address2latlong(laddress) print 'Address lookup returned (lat , long) = (' + str(mlat)+','+str(mlong)+')' sx,sy,px,py = coord2tile( mlat, mlong, zoom ) print 'Getting Tiles (x , y) = (' + str(sx)+','+str(sy)+')' type = 2 # Usual google maps output if len(args) > 0: if args[0] in ("hyb"): type = 0 elif args[0] in ("sat"): type = 1 elif args[0] in ("map"): type = 2 print "\nDownloading tiles..." pb=progressbarClass(h*w) count = 0 for yd in range(0,h): for xd in range(0,w): x=int(sx+xd-w/2); y=int(sy+yd-h/2); localnem = "tile"+str(x)+","+str(y)+".gif"; mlong, mlat = pixel2coord(x,y,zoom) tx,ty,tpx,tpy = coord2tile( mlat, mlong, zoom ) #print "Getting tile : ("+str(x)+","+str(y)+")" + str(pixel2coord(x,y,zoom)) #print "Back conversion = " + str(tx) + " , " + str(ty) + " , " + str(tpx) + " , " + str(tpy) #sys.exit(1) if type == 2: # http://mt0.google.com/mt?n=404&v=w2.29&x=68&y=104&zoom=9 req="http://mt0.google.com/"; nem="mt?n=404&v=w2.29&x="+str(x)+"&y="+str(y)+"&zoom="+str(zoom); url = req+nem # on cygwin if sys.platform == "cygwin": nem="mt@n=404&v=w2.29&x="+str(x)+"&y="+str(y)+"&zoom="+str(zoom); elif type == 1: # http://kh2.google.com/kh?n=404&v=12&t=tqstqtrqtqtqtq req="http://kh0.google.com/" nem="kh?n=404&v=12&t="+quadtree(x,y, zoom) url = req+nem # on cygwin if sys.platform == "cygwin": nem="kh@n=404&v=12&t="+quadtree(x,y, zoom) cmd1 = "wget --quiet \""+url+"\" "; cmd2="mv \"" +nem+ '\" '+localnem; #print cmd1 #print cmd2 #sys.exit(1) os.system(cmd1) os.system(cmd2) count += 1 pb.progress(count) time.sleep(float(random.randint(0,20)) * 0.01) # concatenate horizontal maps # convert tile005000.gif -page +129+0 tile006000.gif -page +258+0 tile007000.gif -mosaic o.gif for yd in range(0,h): cmd3 = "convert " for xd in range(0,w): x=int(sx+xd-w/2); y=int(sy+yd-h/2); localnem = "tile"+str(x)+","+str(y)+".gif "; xsh = xd*128; ysh = yd*128; cmd3 += localnem ; cmd3 += "+append tmp"+str(yd)+".gif"; print cmd3; os.system(cmd3) # concatenate horizontal strips cmd4 = "convert "; for yd in range(0,h): localnem = "tmp"+str(yd)+".gif "; cmd4 += localnem; cmd4 += "-append output.gif"; print cmd4 os.system(cmd4);