Skip to content

Commit

Permalink
tile generation algo added
Browse files Browse the repository at this point in the history
  • Loading branch information
itzmeanjan committed Apr 12, 2019
1 parent 09e3bde commit ed6b06c
Showing 1 changed file with 61 additions and 68 deletions.
129 changes: 61 additions & 68 deletions map_tile_renderer.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
try:
from xml.etree.ElementTree import SubElement, parse as parse_xml
from mapnik import Map, load_map, render_to_file, Box2d
from os import unlink
from sys import argv
from os.path import exists
from os import getcwd, unlink, mkdir
from os.path import exists, join
from subprocess import run
from tile_extent_determinator import get_tile_extent, tiles_required_at_certain_zoom_level
from tile_extent_determinator import get_tile_extent
except ImportError as e:
print('[!]Module Unavailable : {}'.format(str(e)))
exit(1)
Expand All @@ -16,100 +16,93 @@
def format_style_sheet(xml_doc, layer_name, element_name, element_attrs, element_text, target_xml):
# formats template XML stylesheet during runtime.
et = parse_xml(xml_doc) # parsing XML document
target_elem = None
for i in et.getroot().findall('Layer'):
# iterates over all available layers in XML and selects one using layer_name attribute
if(i.attrib.get('name') == layer_name):
# iterates over all available layers in XML and selects those which is mentioned in layer_name parameter
if(not layer_name):
break # if layer_name is exhausted, just break loop
if(i.attrib.get('name') in layer_name):
# remove that layer which is found and to be processed
layer_name.remove(i.attrib.get('name'))
target_elem = i.find('Datasource') # this is our target element
break # in case of success, just break loop
if(not target_elem):
# if something goes wrong with target Layer Name, denote failure
return False
# creating a new element, which is child of our target `Datasource` element
subelement = SubElement(target_elem, element_name)
subelement.text = element_text # setting text for newly added element
subelement.set(*element_attrs) # sets attribute of new element
if(not target_elem):
# if something goes wrong with target Layer Name, denote failure
return False
# creating a new element, which is child of our target `Datasource` element
subelement = SubElement(target_elem, element_name)
subelement.text = element_text # setting text for newly added element
subelement.set(*element_attrs) # sets attribute of new element
if(exists(target_xml)):
unlink(target_xml)
et.write(target_xml) # writes to another XML stylesheet
return True


def tile_generator(x_val, y_val, zoom_lvl, degree_along_x, degree_along_y, num_of_tiles_to_start_with, tile_width, tile_height, style_sheet, output_file):
num_of_tiles = tiles_required_at_certain_zoom_level(
num_of_tiles_to_start_with, zoom_lvl)
print('[+]No.of tiles required => {}'.format(num_of_tiles))
extent = get_tile_extent(zoom_lvl, (-180, +90), tile_width, tile_height,
degree_along_x, degree_along_y).get('{},{}'.format(x_val, y_val), [])
print(extent)
return True
if(not extent):
def tile_generator(zoom_lvl, tile_width, tile_height, style_sheet, target_storage_path):
print('\t[+]Generating tiles in zoom level -- {}'.format(zoom_lvl))
tiles = get_tile_extent(zoom_lvl, (-180, +90), tile_width, tile_height,
360, 180)
if(not tiles):
return False
map_obj = Map(tile_width, tile_height,
'+proj=longlat +datum=WGS84 +no_defs ')
if(not format_style_sheet(style_sheet, 'layer1', 'Parameter', [
'name', 'extent'], 'something', 'tmp.xml')):
return False
load_map(map_obj, 'tmp.xml') # loads XML style sheet
map_obj.zoom_to_box(Box2d(*extent))
render_to_file(map_obj, output_file, 'png')
for key, value in tiles.items():
map_obj = Map(tile_width, tile_height,
'+proj=longlat +datum=WGS84 +no_defs ')
if(not format_style_sheet(style_sheet, ['layer1'], 'Parameter', [
'name', 'extent'], '{}, {}, {}, {}'.format(*value), 'tmp.xml')):
return False
print(
'\t\t[+]Rendering tile {} - {} - {} ...'.format(zoom_lvl, *key.split(',')))
load_map(map_obj, 'tmp.xml') # loads generated XML style sheet
map_obj.zoom_to_box(Box2d(*value))
render_to_file(map_obj, join(target_storage_path, '{}_{}_{}.png'.format(
zoom_lvl, *key.split(','))), 'png')
# removes temporary XML file, which was generated from template XML
unlink('tmp.xml')
return True


def input_validator():
# validates input, which was provided during invokation of function
zoom_lvl, x_val, y_val, num_of_tiles_to_start_with, style_sheet, image_file = argv[1:]
max_zoom_lvl = argv[1]
try:
zoom_lvl = int(zoom_lvl)
x_val = int(x_val)
y_val = int(y_val)
num_of_tiles_to_start_with = int(num_of_tiles_to_start_with)
max_zoom_lvl = int(max_zoom_lvl)
except ValueError as e:
print('[!]Error : {}'.format(str(e)))
return ()
if(zoom_lvl < 0 or zoom_lvl > 10):
print('[!]Zoom level value should be in range of 0 to 10')
return ()
t = True
i = 0
while(t):
tmp = 2**i
if(tmp == num_of_tiles_to_start_with):
t = False
if(tmp > num_of_tiles_to_start_with):
t = False
i = -1
i += 1
if(i < 1):
print('[!]Minimum number of tiles required to cover World at zoomed out condition needs to be 2^x where x=0,1,2,3 ....\n')
return ()
if(not exists(style_sheet) or not style_sheet.endswith('.xml')):
print('[!]Style Sheet not available !\n')
return ()
return (zoom_lvl, x_val, y_val, num_of_tiles_to_start_with, style_sheet, image_file)
return None
if(max_zoom_lvl < 0 or max_zoom_lvl > 10):
print('[!]Max Zoom level value should be in range of 0 to 10')
return None
for i in range(max_zoom_lvl+1):
if(not exists('map_tile_renderer_style_sheet_{}.xml'.format(i))):
print('[!]Style Sheet not available for zoom-level -- {} !\n'.format(i))
return None
return max_zoom_lvl


def main(tile_width, tile_height):
if(len(argv) != 7):
print('[+]Usage : ./{} zoom-level x-value y-value number-of-tiles-to-start-with style-sheet image-file-name\n\t[*] zoom-level = 0 to 10\n\t[*] number-of-tiles-to-start-with = 2^x , where x= 0,1,2,3 .... \n'.format(argv[0]))
def app(tile_width, tile_height):
if(len(argv) != 2):
print(
'[+]Usage : ./{} max-zoom-level \n\t[*] max-zoom-level = 0 to 10\n'.format(argv[0]))
return
try:
# if some argument is not okay, it'll fail simply
zoom_lvl, x_val, y_val, num_of_tiles_to_start_with, style_sheet, image_file = input_validator()
except ValueError:
# if command line input argument is not okay, it'll fail simply
max_zoom_lvl = input_validator()
if(not max_zoom_lvl):
return
print('[+]Generating tile ({},{}) with zoom level {} ...'.format(x_val, y_val, zoom_lvl))
if(not tile_generator(x_val, y_val, zoom_lvl, 360, 180, num_of_tiles_to_start_with, tile_width, tile_height, style_sheet, image_file)):
print('[!]Illegal Tile extent value !')
target_storage_path = join(getcwd(), 'tiles')
if(not exists(target_storage_path)):
mkdir(target_storage_path)
print('[+]Generating all tiles with max zoom level {} ...'.format(max_zoom_lvl))
for i in range(max_zoom_lvl+1):
if(not tile_generator(i, tile_width, tile_height, 'map_tile_renderer_style_sheet_{}.xml'.format(i), target_storage_path)):
print('\t[!]Illegal Tile extent value !')
return
print('[+]Success')
return


if __name__ == '__main__':
run('clear')
try:
main(256, 144)
app(256, 128)
except KeyboardInterrupt:
print('\n[!]Terminated')
finally:
Expand Down

0 comments on commit ed6b06c

Please sign in to comment.