Tile Coordinates
March 29, 2024About 2 min
Tile Coordinates
import math
'''
The code of quad
-------
3 | 2
-------
0 | 1
-------
The first layer of the earth will be split into
| 0 | 1 |
---------------------------------------------------
The code of WMTS will start from the left-top corner.
The zero layer will split into
| 0-0-0 | 0-1-0 |
The first layer
| 1-0-0 | 1-1-0 | 1-2-0 | 1-3-0 |
---------------------------------
| 1-0-1 | 1-1-1 | 1-2-1 | 1-3-1 |
'''
class tile_util:
def __getGeojsonTemplate__(self, name):
return {
"type": "FeatureCollection",
"name": name,
"crs": {
"type": "name",
"properties": {
"name": "urn:ogc:def:crs:OGC:1.3:CRS84"
}
},
"features": []
}
def WMTS2Quad(self, ilayer, row, col):
'''
@desc Convert WMTS index into quad index
@param ilayer WMTS layer number (from 0)
@param row WMTS layer tiley number
@param col WMTS layer tilex number
@return The quad index correspond to wmts index
'''
offset = 180/2**ilayer
lat = 90 - (row+0.5)*offset
lng = (col+0.5)*offset - 180
return self.getTileQuad(lng, lat, ilayer+1)
def Quad2WMTS(self, quad):
'''
@desc Convert quad index into WMTS index
@parm quad quad index
@return The WMTS index (layer, col/x, row/y)
'''
tilew = 360/(2**len(quad))
centerx = 0
centery = 0
for i in range(len(quad)):
tilew = 360/(2**(i+1))
if i == 0:
if quad[i] == '0':
centerx = -90
centery = 0
else:
centerx = 90
centery = 0
else:
if quad[i] == '0':
centerx -= tilew/2
centery -= tilew/2
if quad[i] == '1':
centerx += tilew/2
centery -= tilew/2
if quad[i] == '2':
centerx += tilew/2
centery += tilew/2
if quad[i] == '3':
centerx -= tilew/2
centery += tilew/2
wmtsl = len(quad)-1
wmts_tilew = 180/(2**wmtsl)
#print(centerx, centery, wmts_tilew)
tilex = math.floor((centerx+180)/wmts_tilew)
tiley = math.floor(-(centery-90)/wmts_tilew)
return wmtsl, tilex, tiley
# Get the sub block list of quad until the specified level
def getWMTSSubTile(self, quad, level):
rc = list()
if len(quad) < level-1:
rc.extend(self.getWMTSSubTile(quad+'0', level))
rc.extend(self.getWMTSSubTile(quad+'1', level))
rc.extend(self.getWMTSSubTile(quad+'2', level))
rc.extend(self.getWMTSSubTile(quad+'3', level))
return rc
elif len(quad) >= level:
return rc
else:
return [quad + '0', quad + '1', quad + '2', quad + '3', ]
# Get the quad number on specified level according to latitude and longtitude.
def getTileQuad(self, lng, lat, level):
#level += 1 # Because of quad start from 0, thus the number of quad should plus 1
minx = -180
maxx = 180
miny = -90
maxy = 90
centerx = 0
centery = 0
tilew = 180
ret = ''
for l in range(level):
if l <= 0:
if lng <= 0:
centerx = -90
centery = 0
ret += '0'
else:
centerx = 90
centery = 0
ret += '1'
else:
if lng < centerx and lat < centery:
ret += '0'
centerx -= tilew/2
centery -= tilew/2
elif lng > centerx and lat < centery:
ret += '1'
centerx += tilew/2
centery -= tilew/2
elif lng > centerx and lat > centery:
ret += '2'
centerx += tilew/2
centery += tilew/2
else:
ret += '3'
centerx -= tilew/2
centery += tilew/2
tilew /= 2
return ret
def getBoundingBox(self, quad):
'''
Get the bounding box of quad block
'''
l, x, y = self.Quad2WMTS(quad)
tilew = 180/(2**l)
maxx = x*tilew + tilew - 180
minx = x*tilew + 0 -180
maxy = 90 - (y*tilew + 0)
miny = 90 - (y*tilew + tilew)
return minx, maxx, miny, maxy
def getGeojson(self, quad, targetLevel = None):
'''
Get the geojson of quad if the targetLevel is not specified.
Get the geojson for all sub block until targetLevel regard as quad as a base block
'''
rc = None
if targetLevel:
rc = self.__getGeojsonTemplate__(f'{quad}-{targetLevel}')
subs = self.getWMTSSubTile(quad, targetLevel)
for i in subs:
rc['features'].append(self.__getFeatureJson__(i))
else:
rc = self.__getGeojsonTemplate__(f'{quad}')
rc['features'].append(self.__getFeatureJson__(quad))
return rc
def __getFeatureJson__(self, quad):
'''
Get the geojson of quad
'''
ret = {
"type": "Feature",
"properties": dict(),
"geometry": {
"type": "Polygon",
"coordinates": list()
}
}
minx, maxx, miny, maxy = self.getBoundingBox(quad)
ret['geometry']['coordinates'].append( [[minx, miny], [minx, maxy], [maxx, maxy], [maxx, miny], [minx, miny]])
ret['properties']['quad'] = quad
ret['properties']['wmts'] = self.Quad2WMTS(quad)
return ret