Source code for mapshader.mercator

import math


def invert_y_tile(y, z):
    """
    Convert from TMS to Google tile y coordinate, and vice versa
    """
    return (2 ** z) - 1 - y


[docs]class MercatorTileDefinition(object): """ Implementation of mercator tile source. In general, tile sources are used as a required input for ``TileRenderer``. Parameters ---------- x_range : tuple Full extent of x dimension in data units. y_range : tuple Full extent of y dimension in data units. min_zoom : int A minimum zoom level for the tile layer. This is the most zoomed-out level. max_zoom : int A maximum zoom level for the tile layer. This is the most zoomed-in level. x_origin_offset : int An x-offset in plot coordinates. y_origin_offset : int An y-offset in plot coordinates. initial_resolution : int Resolution (plot_units / pixels) of minimum zoom level of tileset projection. None to auto-compute. format : int An y-offset in plot coordinates. Returns ------- tileScheme: MercatorTileDefinition """
[docs] def __init__(self, x_range, y_range, tile_size=256, min_zoom=0, max_zoom=30, x_origin_offset=20037508.34, y_origin_offset=20037508.34, initial_resolution=156543.03392804097): self.x_range = x_range self.y_range = y_range self.tile_size = tile_size self.min_zoom = min_zoom self.max_zoom = max_zoom self.x_origin_offset = x_origin_offset self.y_origin_offset = y_origin_offset self.initial_resolution = initial_resolution self._resolutions = [self._get_resolution(z) for z in range(self.min_zoom, self.max_zoom+1)]
def to_ogc_tile_metadata(self, output_file_path): """ Create OGC tile metadata XML """ pass def to_esri_tile_metadata(self, output_file_path): """ Create ESRI tile metadata JSON """ pass def is_valid_tile(self, x, y, z): if x < 0 or x >= math.pow(2, z): return False if y < 0 or y >= math.pow(2, z): return False return True # TODO ngjit? def _get_resolution(self, z): return self.initial_resolution / (2 ** z) def get_resolution_by_extent(self, extent, height, width): x_rs = (extent[2] - extent[0]) / width y_rs = (extent[3] - extent[1]) / height return [x_rs, y_rs] def get_level_by_extent(self, extent, height, width): x_rs = (extent[2] - extent[0]) / width y_rs = (extent[3] - extent[1]) / height resolution = max(x_rs, y_rs) # TODO: refactor this... i = 0 for r in self._resolutions: if resolution > r: if i == 0: return 0 if i > 0: return i - 1 i += 1 return (i-1) def pixels_to_meters(self, px, py, level): res = self._get_resolution(level) mx = (px * res) - self.x_origin_offset my = (py * res) - self.y_origin_offset return (mx, my) def meters_to_pixels(self, mx, my, level): res = self._get_resolution(level) px = (mx + self.x_origin_offset) / res py = (my + self.y_origin_offset) / res return (px, py) def pixels_to_tile(self, px, py, level): tx = math.ceil(px / self.tile_size) tx = tx if tx == 0 else tx - 1 ty = max(math.ceil(py / self.tile_size) - 1, 0) # convert from TMS y coordinate return (int(tx), invert_y_tile(int(ty), level)) def pixels_to_raster(self, px, py, level): map_size = self.tile_size << level return (px, map_size - py) def meters_to_tile(self, mx, my, level): px, py = self.meters_to_pixels(mx, my, level) return self.pixels_to_tile(px, py, level) def get_tiles_by_extent(self, extent, level): # unpack extent and convert to tile coordinates xmin, ymin, xmax, ymax = extent # note y coordinates are reversed since they are in opposite direction to meters txmin, tymax = self.meters_to_tile(xmin, ymin, level) txmax, tymin = self.meters_to_tile(xmax, ymax, level) # TODO: vectorize? tiles = [] for ty in range(tymin, tymax + 1): for tx in range(txmin, txmax + 1): if self.is_valid_tile(tx, ty, level): t = (tx, ty, level, self.get_tile_meters(tx, ty, level)) tiles.append(t) return tiles def get_tile_meters(self, tx, ty, level): ty = invert_y_tile(ty, level) # convert to TMS for conversion to meters xmin, ymin = self.pixels_to_meters(tx * self.tile_size, ty * self.tile_size, level) xmax, ymax = self.pixels_to_meters( (tx + 1) * self.tile_size, (ty + 1) * self.tile_size, level, ) return (xmin, ymin, xmax, ymax)