Google Map Hack

来自Jack's Lab
跳转到: 导航, 搜索



1 概述

Google 的地图采用将地球圆表面投影成平面的方式进行贴图

假设 zoom = 18,则横坐标从左至右像素为 0 - 256*2^18(2的18次幂),也就是每增加一级,地图大小横纵坐标加倍,256为一个标准图片的大小。显示-180度到+180的范围,经度越大,x 越大

纵坐标从上到下像素为 0 - 256*2^18(2的18次幂)。显示+85到-85度的范围,纬度越小,y 越大

经度到像素 X 值:

 (long + 180) * (256L << zoom) / 360

像素 X 到经度:

 X * 360 / (256L << zoom) - 180

纬度到像素 Y:

double siny = Math.sin(lat * Math.PI / 180);
double y = Math.log((1 + siny) / (1 - siny));
Y = (128 << zoom) * (1 - y / (2 * Math.PI));


double y = 2 * Math.PI * (1 - Y / (128 << zoom));
double z = Math.pow(Math.E, y);
double siny = (z - 1) / (z + 1);
Lat = Math.asin(siny) * 180 / Math.PI;

2 矫正

3 Google Map Tile 下载


import cmath,urllib,os,math,random,sys,time,threading

class Cdt:
    def __str__(self):
        return '{x = %s,y = %s}'%(self.x,self.y)        

def createName(num,type):
    temp = '00000000'+str(hex(int(num)))[2:]
    return type + temp[::-1][0:8][::-1]

def getPixelFromCdt(x,y,z):
    pixel = Cdt()
    sinLatitude = cmath.sin(y * cmath.pi / 180)
    pixel.x = ((x + 180) / 360) * 256 * (2**z)
    temp = cmath.log((1+sinLatitude)/(1-sinLatitude))
    pixel.y = abs((0.5 - temp / (4 * cmath.pi))*256*(2**z))
    return pixel

def getTileFromPixel(pixel):
    tile = Cdt()
    tile.x = math.floor(pixel.x / 256)
    tile.y = math.floor(pixel.y / 256)
    return tile

def getTileFromCdt(x,y,z):
    return getTileFromPixel(getPixelFromCdt(x,y,z))

def downloadTile(remoteFile,localFile):

def createDir(dirPath):
    if not os.path.exists(dirPath):

def createRemoteUrl(x,y,z):
    port = str(random.randint(0,3))
    x = str(x)
    y = str(y)
    z = str(z)
    return 'http://mt'+port+''+x+'&s=&y='+y+'&z='+z

def createLocalFile(x,y,z,lvRange,cacheDir):
    i = int(z) - lvRange[0]
    l = ''
    if i < 10:
        l = 'L0' + str(i)
    elif i >= 10 and i <= lvRange[len(lvRange) - 1]:
        l = 'L' + str(i)
    r = createName(y,'R')
    c = createName(x,'C')
    return cacheDir + os.sep + l + os.sep + r + os.sep + c + '.png'

def createCacheDir(rowName,lv,row,xRange):
    for col in xRange:
        #localTile = rowName + os.sep + createName(col,'C') + '.png'
def createLvCache(extent,lv,dir):
    startTile = getTileFromCdt(extent[0],extent[1],lv)
    endTile = getTileFromCdt(extent[2],extent[3],lv)
    xRange = range(int(startTile.x),int(endTile.x))
    yRange = range(int(startTile.y),int(endTile.y))
    for row in yRange:
        rowName = dir + os.sep + createName(row,'R')     
def createCacheStruc(extent,lvRange,cacheDir):
    global tempTask
    count = 0
    print '创建Cache目录及计算tile数目...'
    for lv in lvRange:        
        lvName = 'L0' + str(count)#lvName:等级文件夹名        
        createDir(cacheDir +os.sep + lvName)#创建lv等级的文件夹,例如:lv01,lv02...
        createLvCache(extent,lv,cacheDir +os.sep + lvName)#创建完等级文件夹后,添加该等级的行文件夹,例如:R000001a0
        count += 1

def loadErrorFile(url):
    f = open(url+'bak')
    return f.readlines()

def loadTask(task,threadNum):
    global failureTask
    failureTask = []
    tasksize = len(task)
    threadTask = tasksize//int(threadNum)       #取整除 返回商的整数部分
    print '待下载Tile总计:%s,下载线程数:%s'%(tasksize,sys.argv[5])
    for i in range(len(task)):
        st = i * int(threadTask)
        ed = st + int(threadTask) + 1
        if ed > len(task) - 1:
            download = Download(task[st:len(task) - 1])
        download = Download(task[st:ed])
class Download(threading.Thread):
    sucessCount = 0
    failureCount = 0
    def __init__(self,tasks):
        self.tasks = tasks
        self.lock = threading.RLock()
    def run(self):        
        #log('start download',False)
        for task in self.tasks:
            valueAry = task.split(",")
            lv = valueAry[0]
            row = valueAry[1]
            col = valueAry[2]
            remoteFile = createRemoteUrl(col,row,lv)
            localFile = createLocalFile(col,row,lv,lvRange,cacheDir)
                Download.sucessCount += 1
                log('已经下载:%s / %s ,失败: %s / %s'%(Download.sucessCount,len(tempTask),Download.failureCount,len(failureTask)),False)
                logStr = '%s,%s,%s'%(lv,row,col)
                f = file(cacheDir+os.sep+'error.log','a')#在日志文件中打印失败记录
                Download.failureCount += 1
def log(event,b):
        logStr = str(event)
        if b:#在日志文件中打印消息
            f = file(cacheDir+os.sep+str(time.strftime('%Y%m%d%H'))+'.log','a')

if __name__ == '__main__':
    extent = sys.argv[1]
    maxLv = sys.argv[2]
    minLv = sys.argv[3]

    global extAry,lvRange,cacheDir,threadNum
    ext = [float(i) for i in extent.split(' ')]
    extAry = [ext[0],ext[3],ext[2],ext[1]]          #区域范围
    lvRange = range(int(minLv),int(maxLv) + 1)      #等级范围
    cacheDir = sys.argv[4]                          #下载目录
    threadNum = sys.argv[5]                         #下载线程

    if sys.argv[1] == 'loadError':
        errorTask = loadErrorFile(sys.argv[2]+os.sep+'error.log')
        createCacheStruc(extAry,lvRange,cacheDir)       #创建缓存目录结构
        loadTask(tempTask,threadNum)                    #下载


$ ./ "118.411792548134 31.5176549981089 119.43094617187 32.3386680868215" 16 10 /gmap/data 20

"118.411792548134 31.5176549981089 119.43094617187 32.3386680868215" 是待下载的区域范围

16 10 是下载的等级范围

/gmap/data 是存储目录

20 是线程数

4 World File Format

Subject 	World File Format 
Author 	A.J. Romanelli 
Date 	Apr 10, 2006 
Message 	The units of a world file are map units. For example, if the x/y values you enter are state-plane coordinates in feet, then your image will be referenced to state-plane feet, if the values you enter are utm meters, then your image will be referenced to that UTM zone. The values for the offsets and cell size need to be specified in the same units (e.g. if you are in state-plane use feet, if you are working in UTM use meters). 

From the MO help.... 

Vector data in MapLayers exists in a real-world or map coordinate system, measured, typically, in feet or meters. The x-coordinates increase from left to right and the y-coordinates increase from the bottom to the top. This is quite different from a raster image represented by an ImageLayer. A raster image is organized and measured by rows and columns. Each cell has a row number and a column number. If the origin is located in the upper left corner of the data, that cell would be identified as row 1, column 1. 

For MapLayers and ImageLayers to be displayed simultaneously, the rows and columns of the image must be mapped into the x,y plane of a map coordinate system. An image-to-world transformation that converts the image coordinates to map coordinates must be established. Some image formats store georeferencing information in the file header of the image or, in the case of images that do not contain this georeferencing information, facilities exist in other products available from ESRI, for creating a file that contains the necessary transformation parameters. The file that contains the transformation parameters is called a world file. The world file takes precedence over any header information. 

About the world file 

The image-to-world transformation is a six parameter affine transformation of the form: 

x' = Ax + By + C 
y' = Dx + Ey + F 


x' = calculated x-coordinate of the pixel on the map 
y' = calculated y-coordinate of the pixel on the map 
x = column number of a pixel in the image 
y = row number of a pixel in the image 
A = x-scale, dimension of a pixel in map units in the x-direction 
D,B = rotation terms. Note: Not supported for this release. 
E = y-scale (this value is always negative, because image space is top-down, whereas map space is bottom-up) 
C = translation term; x-Origin (x-coordinate of the center of the upper left pixel) 
F = translation term; y-Origin (y-coordinate of the center of the upper left pixel) 
The transformation parameters are stored in the world file, an ASCII format, in this order, A, D, B, E, C, F; for example: 

2.22123393184959 A 
0.00000000000000 D 
0.00000000000000 B 
-2.22123393184959 E 
10383.13600759092515 C 
11611.48117990907485 F 
Note that the parameter characters are included in the example for clarity. They do not actually appear in the file. 
If a world file is not present and there is no georeferencing information in the header of the image, a default mapping is still provided between image space and map space. MapObjects makes the origin of the image (-0.5, -0.5), and sets the X and Y scale factors both to 1.0 (as the center of the bottom right pixel should be at (0,0). 
If you want to display a non-georeferenced image on a portion of your map, supply the georeferencing world file yourself, and make sure it maps the image to the portion of the map that you want. 

World file naming conventions 

The world file associated with an image is named by following the conventions in the table below. For example, if you have an image that's stored in a file named myimage.bmp, then the world file associated with it must be named myimage.bmpw or myimage.bpw. 

If the file extension of the image is the world file extension must be 
bmp bmpw or bpw 
jpg; jpeg jpgw or jgw 
tif; tff; tiff tfw 
gis gsw 
lan lnw 
bil blw 
bip bpw 
bsq bqw 
sid sdw 
sun snw 
rs; ras rsw 
rlc rcw