Skip to content

Instantly share code, notes, and snippets.

@cjhanks
Created April 7, 2016 23:23
Show Gist options
  • Save cjhanks/dd6bec4ddbbc3f74b75597609c471b63 to your computer and use it in GitHub Desktop.
Save cjhanks/dd6bec4ddbbc3f74b75597609c471b63 to your computer and use it in GitHub Desktop.
Python3 QuadKey/Tiling
from math import (
pi,
cos,
sin,
log,
atan,
exp
)
__EARTH_RADIUS = 6378137
__MIN_LAT = -85.05112878
__MAX_LAT = +85.05112878
__MIN_LON = -180.0
__MAX_LON = +180.0
def __clamp(n: float, min_value: float, max_value: float) -> float:
assert min_value <= max_value
return min(max(n, min_value), max_value)
def __map_size(level_of_detail: int) -> int:
return (256 << level_of_detail)
def ground_resolution(latitude: float, level_of_detail: int) -> float:
latitude = __clamp(latitude, __MIN_LAT, __MAX_LAT)
return (cos(latitude * pi / 180)
* 2
* pi
* __EARTH_RADIUS
/ __map_size(level_of_detail))
def map_scale(
latitude: float,
longitude: float,
level_of_detail: int,
screen_dpi: int) -> float:
return ground_resolution(
latitude,
level_of_detail) * screen_dpi / 0.254
def pixel_xy_to_latlon(
pixel_x: int,
pixel_y: int,
level_of_detail: int) -> (int, int):
map_size = __map_size(level_of_detail)
x = (__clamp(pixel_x, 0, map_size - 1) / map_size) - 0.5
y = 0.5 - (__clamp(pixel_y, 0, map_size - 1) / map_size)
return (
90 - 360 * atan(exp(-y * 2 * pi)) / pi,
360 * x
)
def latlon_to_pixel_xy(
latitude: float,
longitude: float,
level_of_detail: int) -> (int, int):
latitude = __clamp(latitude, __MIN_LAT, __MAX_LAT)
longitude = __clamp(longitude, __MIN_LON, __MAX_LON)
x = (longitude + 180) / 360
sin_latitude = sin(latitude * pi / 180)
y = 0.5 - log((1 + sin_latitude)
/ (1 - sin_latitude)) / (4 * pi)
map_size = __map_size(level_of_detail)
return (
int(__clamp(x * map_size + 0.5, 0, map_size - 1)),
int(__clamp(y * map_size + 0.5, 0, map_size - 1)),
)
def pixel_xy_to_tile_xy(
pixel_x: int,
pixel_y: int) -> (int, int):
return (
pixel_x / 256,
pixel_y / 256,
)
def tile_xy_to_pixel_xy(
tile_x: int,
tile_y: int) -> (int, int):
return (
tile_x * 256,
tile_y * 256,
)
def tile_xy_to_quadkey(
tile_x: int,
tile_y: int,
level_of_detail: int) -> str:
quad_key = ''
for i in range(level_of_detail, 0, -1):
digit = 0
mask = 1 << (i - 1)
if (tile_x & mask) != 0:
digit += 1
if (tile_y & mask) != 0:
digit += 2
quad_key += str(digit)
return quad_key
def quadkey_to_tile_xy(quad_key: str):
tile_x = 0
tile_y = 0
level_of_detail = len(quad_key)
for i in range(level_of_detail, 0, -1):
mask = 1 << (i - 1)
c = quad_key[level_of_detail - i]
if c == '0':
pass
elif c == '1':
tile_x |= mask
elif c == '2':
tile_y |= mask
elif c == '3':
tile_x |= mask
tile_y |= mask
else:
raise RuntimeError('Invalid quad key character: %s' % c)
return (
tile_x,
tile_y,
level_of_detail,
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment