def get_tile(self, layer_id): """ Returns a tile for rendering. If the tile does not exists, higher level tiles are searched and warped to lower level if found. """ # Get tile indices from request tilex = int(self.kwargs.get('x')) tiley = int(self.kwargs.get('y')) tilez = int(self.kwargs.get('z')) # Loop through zoom levels to search for a tile result = None for zoom in range(tilez, -1, -1): # Compute multiplier to find parent raster multiplier = 2 ** (tilez - zoom) # Fetch tile tile = RasterTile.objects.filter( tilex=tilex / multiplier, tiley=tiley / multiplier, tilez=zoom, rasterlayer_id=layer_id ) if tile.exists(): # Extract raster from tile model result = tile[0].rast # If the tile is a parent of the original, warp it to the # original request tile. if zoom < tilez: # Compute bounds, scale and size of child tile bounds = tile_bounds(tilex, tiley, tilez) tilesize = int(getattr(settings, 'RASTER_TILESIZE', WEB_MERCATOR_TILESIZE)) tilescale = tile_scale(tilez) # Warp parent tile to child tile result = result.warp({ 'width': tilesize, 'height': tilesize, 'scale': [tilescale, -tilescale], 'origin': [bounds[0], bounds[3]], }) break return result
def create_tiles(self, zoom): """ Create tiles for this raster at the given zoomlevel. This routine first snaps the raster to the grid of the zoomlevel, then creates the tiles from the snapped raster. """ # Compute the tile x-y-z index range for the rasterlayer for this zoomlevel bbox = self.rasterlayer.extent() indexrange = tiler.tile_index_range(bbox, zoom) # Compute scale of tiles for this zoomlevel tilescale = tiler.tile_scale(zoom) # Count the number of tiles that are required to cover the raster at this zoomlevel nr_of_tiles = (indexrange[2] - indexrange[0] + 1) * (indexrange[3] - indexrange[1] + 1) # Create destination raster file self.log("Snapping dataset to zoom level {0}".format(zoom)) bounds = tiler.tile_bounds(indexrange[0], indexrange[1], zoom) sizex = (indexrange[2] - indexrange[0] + 1) * self.tilesize sizey = (indexrange[3] - indexrange[1] + 1) * self.tilesize dest_file = os.path.join(self.tmpdir, "djangowarpedraster" + str(zoom) + ".tif") snapped_dataset = self.dataset.warp( { "name": dest_file, "origin": [bounds[0], bounds[3]], "scale": [tilescale, -tilescale], "width": sizex, "height": sizey, } ) self.log("Creating {0} tiles for zoom {1}.".format(nr_of_tiles, zoom)) counter = 0 for tilex in range(indexrange[0], indexrange[2] + 1): for tiley in range(indexrange[1], indexrange[3] + 1): # Log progress counter += 1 if counter % 250 == 0: self.log("{0} tiles created at zoom {1}".format(counter, zoom)) # Calculate raster tile origin bounds = tiler.tile_bounds(tilex, tiley, zoom) # Construct band data arrays pixeloffset = ((tilex - indexrange[0]) * self.tilesize, (tiley - indexrange[1]) * self.tilesize) band_data = [ { "data": band.data(offset=pixeloffset, size=(self.tilesize, self.tilesize)), "nodata_value": band.nodata_value, } for band in snapped_dataset.bands ] # Add tile data to histogram if zoom == self.max_zoom: self.push_histogram(band_data) # Warp source raster into this tile (in memory) dest = GDALRaster( { "width": self.tilesize, "height": self.tilesize, "origin": [bounds[0], bounds[3]], "scale": [tilescale, -tilescale], "srid": WEB_MERCATOR_SRID, "datatype": snapped_dataset.bands[0].datatype(), "bands": band_data, } ) # Store tile RasterTile.objects.create(rast=dest, rasterlayer=self.rasterlayer, tilex=tilex, tiley=tiley, tilez=zoom) # Store histogram data if zoom == self.max_zoom: bandmetas = RasterLayerBandMetadata.objects.filter(rasterlayer=self.rasterlayer) for bandmeta in bandmetas: bandmeta.hist_values = self.hist_values[bandmeta.band].tolist() bandmeta.save() # Remove snapped dataset self.log("Removing snapped dataset.", zoom=zoom) snapped_dataset = None os.remove(dest_file)