def polygon2mbtiles(infile, optsin = {}): """Take an Area of Interest (AOI) polygon, return an MBtiles file.""" # DEBUGGING OPTS #print('\noptsin from command line: {}\n'.format(optsin)) opts = set_defaults(optsin) # DEBUGGING OPTS #print('\nopts after setting defaults: {}\n'.format(opts)) (basename, extension) = os.path.splitext(infile) csvfile = '{}_{}.csv'.format(basename, opts['tileserver']) foldername = '{}_{}'.format(basename, opts['tileserver']) print('\nCreating the CSV list of tiles in {}\n'.format(csvfile)) # DEBUGGING OPTS print(opts) create_tile_list(infile, opts) print('Downloading the tiles into {}\n'.format(foldername)) opts['csvinfile'] = csvfile download_all_tiles_in_csv(csvfile, opts) print('Converting all tiles to JPEG format to save space.') convert_and_compress_tiles(foldername) print('Writing the actual MBTiles file {}{}'.format(foldername, '.mbtiles')) opts['tiledir'] = foldername write_mbtiles(foldername, opts)
def create_tile_list(infile, optsin={}): """Read a polygon file and create a set of output files to create tiles""" #print('\nThe opts received by create_tile_list are:{}'.format(type(optsin))) #print('\nThe opts received by create_tile_list are:\n{}\n'.format(optsin)) opts = set_defaults(optsin) url_template = (opts['url_template'] if opts['url_template'] else url_template_from_file(opts['tileserver'])) #print(url_template) #print('\nThe opts returned by set_defaults are:{}'.format(type(opts))) #print('\nThe opts returned by set_defaults are:\n{}\n'.format(opts)) (infilename, extension) = os.path.splitext(infile) minzoom = opts['minzoom'] maxzoom = opts['maxzoom'] tileserver = opts['tileserver'] if opts['tileserver'] else 'from_url' # Create the main output file which will contain the URL list outfile = '{}_{}.csv'.format(infilename, tileserver) if os.path.exists(outfile): os.remove(outfile) writer = csv.writer(open(outfile, 'w'), delimiter=';') writer.writerow(['wkt', 'Tilex', 'TileY', 'TileZ', 'URL']) (xmin, xmax, ymin, ymax) = get_extent(infile, extension) geomcollection = get_geomcollection(infile, extension) for zoom in range(int(minzoom), int(maxzoom) + 1): # get coordinate address of upper left left tile pixel = lat_long_zoom_to_pixel_coords(ymax, xmin, zoom) tile = pixel_coords_to_tile_address(pixel[0], pixel[1]) tileX_left = tile[0] tileY_top = tile[1] # get coordinate address of lower right tile pixel = lat_long_zoom_to_pixel_coords(ymin, xmax, zoom) tile = pixel_coords_to_tile_address(pixel[0], pixel[1]) tileX_right = tile[0] tileY_bottom = tile[1] for tileY in range(tileY_top, tileY_bottom + 1): for tileX in range(tileX_left, tileX_right + 1): inter = intersect(tileX, tileY, zoom, geomcollection) if inter: wkt_outline = '\"{}\"'.format(inter) URL = tile_coords_to_url(int(tileX), int(tileY), int(zoom), url_template) writer.writerow( [wkt_outline, str(tileX), str(tileY), str(zoom), URL]) print('\nInput file: ' + infile) print('Zoom levels: {} to {}'.format(str(minzoom), str(maxzoom))) print('Output files:\n{}\n'.format(outfile)) print()
def write_mbtiles(tiledir, optsin = {}): """Take a folder of tiles in Slippy Map-style schema, return an MBtiles file.""" opts = set_defaults(optsin) outfile = tiledir + '.mbtiles' if os.path.exists(outfile): os.remove(outfile) sqlite_file = outfile db = sqlite3.connect(sqlite_file) cursor = db.cursor() cursor.execute(''' CREATE TABLE tiles (zoom_level INTEGER, tile_column INTEGER, tile_row INTEGER, tile_data BLOB);''') cursor.execute(''' CREATE UNIQUE INDEX tile_index on tiles (zoom_level, tile_column, tile_row);''') image_files = scandir(tiledir) image_file_type = '' maxz = 0 # Max zoom will be incremented when we actually find tiles minz = 23 # As above but decrementing # Set initial bounds at opposite sides of their global extents (left, bottom, right, top) = (180.0, 85.05113, -180.0, -85.05113) (centerlon, centerlat) = ('','') for image_file in image_files: (image_filename, image_ext) = os.path.splitext(image_file) # Don't add the file to the tileset if it's not an image if(image_ext == '.png' or image_ext == '.jpeg' or image_ext == '.jpg'): # Save a string with the filetype (extension) for use in metadata table #TODO: check if there are multiple file types and throw an error if so image_file_type = image_ext.replace('.','') image_blob = open(image_file, "rb").read() (z, x, tiley) = path_to_zxy(image_filename) # MBTiles spec Y is upside down - subtract the tile y from max tile y y = int(math.pow(2.0, float(z)) - float(tiley) - 1.0) cursor.execute(''' INSERT INTO tiles (zoom_level, tile_column, tile_row, tile_data) VALUES(?,?,?,?) ''',(z,x,y,sqlite3.Binary(image_blob))) db.commit() # Update min and max zoom levels and bounds for use in metadata table maxz = z if int(z) > int(maxz) else maxz # Will end at correct max zoom minz = z if int(z) < int(minz) else minz # As above for min zoom (left, bottom, right, top) = increment_bounds(z, x, tiley, left, bottom, right, top) centerlon = float(right) - float(left) centerlat = float(top) - float(bottom) cursor.execute('CREATE TABLE metadata (name TEXT, value TEXT);') tilesetmetadata = [('name', tiledir), ('type', opts['type']), ('description', opts['description']), ('attribution', opts['attribution']), ('version', opts['version']), ('format', image_file_type), ('bounds', '{},{},{},{}'.format(left, bottom, right, top)), # Don't include center as it crashes the Mapbox Android driver #('center', '{},{}'.format(centerlon, centerlat)), ('minzoom', minz), ('maxzoom', maxz)] cursor.executemany( '''INSERT INTO metadata (name, value) VALUES(?,?)''',tilesetmetadata) db.commit() db.close()