def _scaled_tile(self, tile, stop_zoom, rescaled_tiles): """ Try to load tile by loading, scaling and clipping tiles from zoom levels above or below. stop_zoom determines if tiles from above should be scaled up, or if tiles from below should be scaled down. Returns an empty Tile if tile zoom level is stop_zoom. """ if tile.coord in rescaled_tiles: return rescaled_tiles[tile.coord] # Cache tile in rescaled_tiles. We initially set source to a fixed # BlankImageSource and overwrite it if we actually rescaled the tile. tile.source = RESCALE_TILE_MISSING rescaled_tiles[tile.coord] = tile tile_bbox = self.grid.tile_bbox(tile.coord) current_zoom = tile.coord[2] if stop_zoom == current_zoom: return tile if stop_zoom > current_zoom: src_level = current_zoom + 1 else: src_level = current_zoom - 1 src_bbox, src_tile_grid, affected_tile_coords = self.grid.get_affected_level_tiles(tile_bbox, src_level) affected_tiles = TileCollection(affected_tile_coords) for t in affected_tiles: # Add sources of cached tiles, to avoid loading same tile multiple times # loading recursive. if t.coord in rescaled_tiles: t.source = rescaled_tiles[t.coord].source tile_collection = self._load_tile_coords( affected_tiles, rescale_till_zoom=stop_zoom, rescaled_tiles=rescaled_tiles, ) if tile_collection.blank: return tile tile_sources = [] for t in tile_collection: # Replace RESCALE_TILE_MISSING with None, before transforming tiles. tile_sources.append(t.source if t.source is not RESCALE_TILE_MISSING else None) tiled_image = TiledImage(tile_sources, src_bbox=src_bbox, src_srs=self.grid.srs, tile_grid=src_tile_grid, tile_size=self.grid.tile_size) tile.source = tiled_image.transform(tile_bbox, self.grid.srs, self.grid.tile_size, self.image_opts) if self.cache_rescaled_tiles: self.cache.store_tile(tile) return tile
def _image(self, query): try: src_bbox, tile_grid, affected_tile_coords = \ self.grid.get_affected_tiles(query.bbox, query.size, req_srs=query.srs) except NoTiles: raise BlankImage() except GridError as ex: raise MapBBOXError(ex.args[0]) num_tiles = tile_grid[0] * tile_grid[1] if self.max_tile_limit and num_tiles >= self.max_tile_limit: raise MapBBOXError( "too many tiles, max_tile_limit: %s, num_tiles: %s" % (self.max_tile_limit, num_tiles)) if query.tiled_only: if num_tiles > 1: raise MapBBOXError("not a single tile") bbox = query.bbox if not bbox_equals(bbox, src_bbox, abs((bbox[2] - bbox[0]) / query.size[0] / 10), abs((bbox[3] - bbox[1]) / query.size[1] / 10)): raise MapBBOXError("query does not align to tile boundaries") with self.tile_manager.session(): tile_collection = self.tile_manager.load_tile_coords( affected_tile_coords, with_metadata=query.tiled_only) if tile_collection.empty: raise BlankImage() if query.tiled_only: tile = tile_collection[0].source tile.image_opts = self.tile_manager.image_opts tile.cacheable = tile_collection[0].cacheable return tile tile_sources = [tile.source for tile in tile_collection] tiled_image = TiledImage(tile_sources, src_bbox=src_bbox, src_srs=self.grid.srs, tile_grid=tile_grid, tile_size=self.grid.tile_size) try: return tiled_image.transform(query.bbox, query.srs, query.size, self.tile_manager.image_opts) except ProjError: raise MapBBOXError("could not transform query BBOX") except IOError as ex: from mapproxy.source import SourceError raise SourceError("unable to transform image: %s" % ex)
def _image(self, query): try: src_bbox, tile_grid, affected_tile_coords = \ self.grid.get_affected_tiles(query.bbox, query.size, req_srs=query.srs) except NoTiles: raise BlankImage() except GridError as ex: raise MapBBOXError(ex.args[0]) num_tiles = tile_grid[0] * tile_grid[1] if self.max_tile_limit and num_tiles >= self.max_tile_limit: raise MapBBOXError("too many tiles") if query.tiled_only: if num_tiles > 1: raise MapBBOXError("not a single tile") bbox = query.bbox if not bbox_equals(bbox, src_bbox, abs((bbox[2]-bbox[0])/query.size[0]/10), abs((bbox[3]-bbox[1])/query.size[1]/10)): raise MapBBOXError("query does not align to tile boundaries") with self.tile_manager.session(): tile_collection = self.tile_manager.load_tile_coords(affected_tile_coords, with_metadata=query.tiled_only) if tile_collection.empty: raise BlankImage() if query.tiled_only: tile = tile_collection[0].source tile.image_opts = self.tile_manager.image_opts tile.cacheable = tile_collection[0].cacheable return tile tile_sources = [tile.source for tile in tile_collection] tiled_image = TiledImage(tile_sources, src_bbox=src_bbox, src_srs=self.grid.srs, tile_grid=tile_grid, tile_size=self.grid.tile_size) try: return tiled_image.transform(query.bbox, query.srs, query.size, self.tile_manager.image_opts) except ProjError: raise MapBBOXError("could not transform query BBOX") except IOError as ex: from mapproxy.source import SourceError raise SourceError("unable to transform image: %s" % ex)
class CacheMapLayer(MapLayer): def __init__(self, tile_manager, extent=None, image_opts=None, max_tile_limit=None): MapLayer.__init__(self, image_opts=image_opts) self.tile_manager = tile_manager self.grid = tile_manager.grid self.extent = extent or map_extent_from_grid(self.grid) self.res_range = merge_layer_res_ranges(self.tile_manager.sources) self.transparent = tile_manager.transparent self.max_tile_limit = max_tile_limit def get_map(self, query): self.check_res_range(query) if query.tiled_only: self._check_tiled(query) query_extent = MapExtent(query.bbox, query.srs) if not query.tiled_only and self.extent and not self.extent.contains( query_extent): if not self.extent.intersects(query_extent): raise BlankImage() size, offset, bbox = bbox_position_in_image( query.bbox, query.size, self.extent.bbox_for(query.srs)) if size[0] == 0 or size[1] == 0: raise BlankImage() src_query = MapQuery(bbox, size, query.srs, query.format) resp = self._image(src_query) result = SubImageSource(resp, size=query.size, offset=offset, image_opts=self.image_opts, cacheable=resp.cacheable) else: result = self._image(query) return result def _check_tiled(self, query): if query.format != self.tile_manager.format: raise MapError("invalid tile format, use %s" % self.tile_manager.format) if query.size != self.grid.tile_size: raise MapError("invalid tile size (use %dx%d)" % self.grid.tile_size) def _image(self, query): try: src_bbox, tile_grid, affected_tile_coords = \ self.grid.get_affected_tiles(query.bbox, query.size, req_srs=query.srs) except NoTiles: raise BlankImage() except GridError, ex: raise MapBBOXError(ex.args[0]) num_tiles = tile_grid[0] * tile_grid[1] if self.max_tile_limit and num_tiles >= self.max_tile_limit: raise MapBBOXError("to many tiles") if query.tiled_only: if num_tiles > 1: raise MapBBOXError("not a single tile") bbox = query.bbox if not bbox_equals(bbox, src_bbox, (bbox[2] - bbox[0] / query.size[0] / 10), (bbox[3] - bbox[1] / query.size[1] / 10)): raise MapBBOXError("query does not align to tile boundaries") with self.tile_manager.session(): tile_collection = self.tile_manager.load_tile_coords( affected_tile_coords, with_metadata=query.tiled_only) if tile_collection.empty: raise BlankImage() if query.tiled_only: tile = tile_collection[0].source tile.image_opts = self.tile_manager.image_opts tile.cacheable = tile_collection[0].cacheable return tile tile_sources = [tile.source for tile in tile_collection] tiled_image = TiledImage(tile_sources, src_bbox=src_bbox, src_srs=self.grid.srs, tile_grid=tile_grid, tile_size=self.grid.tile_size) try: return tiled_image.transform(query.bbox, query.srs, query.size, self.tile_manager.image_opts) except ProjError: raise MapBBOXError("could not transform query BBOX")