Skip to content

Instantly share code, notes, and snippets.

@dividuum
Last active August 29, 2015 14:22
Show Gist options
  • Save dividuum/2ee993f037c9e0cb3376 to your computer and use it in GitHub Desktop.
Save dividuum/2ee993f037c9e0cb3376 to your computer and use it in GitHub Desktop.
# fw@dividuum.de wrote this file. As long as you retain this notice you
# can do whatever you want with this stuff. If we meet some day, and you think
# this stuff is worth it, you can buy me a beer in return
import math
import traceback
import json
from cStringIO import StringIO
from PIL import Image
import requests
class Tileset(object):
def __init__(self, overviewer, config):
self._overviewer = overviewer
self._config = config
self._tilepath = config['path']
self._maxzoom = config['maxZoom']
self._imgext = config['imgextension']
self._northdir = config['north_direction']
def tile_path(self, tile_x, tile_y, zoom):
path = ""
tile_x, tile_y = int(tile_x), int(tile_y)
if zoom == 0:
path += "/base"
else:
for z in xrange(zoom - 1, -1, -1):
x = int(math.floor(tile_x / (2 ** z)) % 2)
y = int(math.floor(tile_y / (2 ** z)) % 2)
path += "/" + str(x + 2 * y)
return '/' + self._tilepath + path + "." + self._imgext + "?c=" + self._overviewer._cachetag
def world_to_pixel(self, x, y, z):
x, z = -z, x
x /= 16.0 # to chunk coord
z /= 16.0
col = x + z
row = z - x
return 192 * col, 96 * row + 12 * (256 - y)
def pixel_coord(self, x, y, z, zoom):
x, y = self.world_to_pixel(x, y, z)
x /= 2 ** (self._maxzoom - zoom)
y /= 2 ** (self._maxzoom - zoom)
return x, y
def pixel_to_tile(self, x, y, zoom):
x = x / 384. + (2 ** (zoom-1))
y = y / 384. + (2 ** (zoom-1))
return x, y
def surrounding_tiles(self, x, y, z, zoom, radius=1):
x, y = self.pixel_coord(x, y, z, zoom)
tx, ty = self.pixel_to_tile(x, y, zoom)
cx, cy = int(tx), int(ty)
def get_tiles():
for xx in xrange(radius*2+1):
for yy in xrange(radius*2+1):
yield xx, yy, self.tile_path(cx + -radius + xx, cy + -radius + yy, zoom)
return 384 * (radius + (tx - math.floor(tx))), 384 * (radius + (ty - math.floor(ty))), get_tiles()
def adjust_north(self, x, z):
if self._northdir == 0:
return z, -x
elif self._northdir == 1:
return x, z
elif self._northdir == 2:
return -z, x
elif self._northdir == 3:
return -x, -z
def snapshot(self, x, y, z, zoom=0, radius=2):
x, z = self.adjust_north(x, z)
center_x, center_y, tiles = self.surrounding_tiles(x, y, z, self._maxzoom + zoom, radius)
im = Image.new("RGB", (384 * (radius*2+1), 384 * (radius*2+1)), "#000")
for off_x, off_y, path in tiles:
tile = self._overviewer.get(path)
try:
tile_img = Image.open(StringIO(tile.content))
im.paste(tile_img, (384*off_x, 384*off_y))
except Exception:
traceback.print_exc()
im = im.crop((
int(center_x - radius*384),
int(center_y - radius*384),
int(center_x + radius*384),
int(center_y + radius*384),
))
return im
class Overviewer(object):
def __init__(self, base_url, proxy=None):
self._proxy = proxy
self._base_url = base_url
self._config = self.get_config()
self._cachetag = self._config['map']['cacheTag']
def get_config(self):
config = self.get("/overviewerConfig.js").content
prefix = 'var overviewerConfig = '
if not config.startswith(prefix):
raise ValueError("couldn't parse overviewerConfig.js")
return json.loads(config[len(prefix):-2])
def get_tileset(self, name):
for ts in self._config.get('tilesets', ()):
if ts['path'] == name:
return Tileset(self, ts)
def get(self, path):
print 'fetching ' + self._base_url + path
# implement caching here, if required. Or just use a proxy
return requests.get(self._base_url + path,
proxies = self._proxy,
)
if __name__ == "__main__":
ov = Overviewer('http://hcfactions.net/map')
ts = ov.get_tileset('normalrender')
ts.snapshot(0, 100, 0, radius=2, zoom=-1).save("spawn.jpg")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment