Пример #1
0
    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
Пример #2
0
    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)