def TileParams( z: int = Path(..., ge=0, le=30, description="Tiles's zoom level"), x: int = Path(..., description="Tiles's column"), y: int = Path(..., description="Tiles's row"), ) -> Tile: """Tile parameters.""" return Tile(x, y, z)
def tile_exists(self, tile_z: int, tile_x: int, tile_y: int) -> bool: """Check if a tile is inside a the dataset bounds.""" tile = Tile(x=tile_x, y=tile_y, z=tile_z) tile_bounds = self.tms.bounds(*tile) return ((tile_bounds[0] < self.bounds[2]) and (tile_bounds[2] > self.bounds[0]) and (tile_bounds[3] > self.bounds[1]) and (tile_bounds[1] < self.bounds[3]))
def tile_exists(self, tile_x: int, tile_y: int, tile_z: int) -> bool: """Check if a tile intersects the dataset bounds. Args: tile_x (int): Tile's horizontal index. tile_y (int): Tile's vertical index. tile_z (int): Tile's zoom level index. Returns: bool: True if the tile intersects the dataset bounds. """ # bounds in TileMatrixSet's CRS tile_bounds = self.tms.xy_bounds(Tile(x=tile_x, y=tile_y, z=tile_z)) if not self.tms.rasterio_crs == self.crs: # Transform the bounds to the dataset's CRS try: tile_bounds = transform_bounds( self.tms.rasterio_crs, self.crs, *tile_bounds, densify_pts=21, ) except: # noqa # HACK: gdal will first throw an error for invalid transformation # but if retried it will then pass. # Note: It might return `+/-inf` values tile_bounds = transform_bounds( self.tms.rasterio_crs, self.crs, *tile_bounds, densify_pts=21, ) # If tile_bounds has non-finite value in the dataset CRS we return True if not all(numpy.isfinite(tile_bounds)): return True return ( (tile_bounds[0] < self.bounds[2]) and (tile_bounds[2] > self.bounds[0]) and (tile_bounds[3] > self.bounds[1]) and (tile_bounds[1] < self.bounds[3]) )
def tile_exists(self, tile_z: int, tile_x: int, tile_y: int) -> bool: """Check if a tile is intersets the dataset bounds. Args: tile_x (int): Tile's horizontal index. tile_y (int): Tile's vertical index. tile_z (int): Tile's zoom level index. Returns: bool: True if the tile is intersets the dataset bounds. """ tile = Tile(x=tile_x, y=tile_y, z=tile_z) tile_bounds = self.tms.bounds(*tile) return ((tile_bounds[0] < self.bounds[2]) and (tile_bounds[2] > self.bounds[0]) and (tile_bounds[3] > self.bounds[1]) and (tile_bounds[1] < self.bounds[3]))
def tile( self, tile_x: int, tile_y: int, tile_z: int, tilesize: int = 256, indexes: Optional[Union[int, Sequence]] = None, expression: Optional[str] = "", **kwargs: Any, ) -> ImageData: """ Read a Mercator Map tile from a COG. Attributes ---------- tile_x: int Mercator tile X index. tile_y: int Mercator tile Y index. tile_z: int Mercator tile ZOOM level. tilesize: int, optional (default: 256) Output image size. indexes: int or sequence of int Band indexes (e.g. 1 or (1, 2, 3)) expression: str rio-tiler expression (e.g. b1/b2+b3) kwargs: dict, optional These will be passed to the 'rio_tiler.reader.part' function. Returns ------- data: numpy ndarray mask: numpy array """ kwargs = {**self._kwargs, **kwargs} if not self.tile_exists(tile_z, tile_x, tile_y): raise TileOutsideBounds( f"Tile {tile_z}/{tile_x}/{tile_y} is outside {self.filepath} bounds" ) if isinstance(indexes, int): indexes = (indexes,) if indexes and expression: warnings.warn( "Both expression and indexes passed; expression will overwrite indexes parameter.", ExpressionMixingWarning, ) if expression: indexes = parse_expression(expression) tile_bounds = self.tms.xy_bounds(*Tile(x=tile_x, y=tile_y, z=tile_z)) tile, mask = reader.part( self.dataset, tile_bounds, tilesize, tilesize, indexes=indexes, dst_crs=self.tms.crs, **kwargs, ) if expression: blocks = expression.lower().split(",") bands = [f"b{bidx}" for bidx in indexes] tile = apply_expression(blocks, bands, tile) return ImageData( tile, mask, bounds=tile_bounds, crs=self.tms.crs, assets=[self.filepath] )
def tile( self, tile_x: int, tile_y: int, tile_z: int, tilesize: int = 256, indexes: Optional[Union[int, Sequence]] = None, expression: Optional[str] = None, **kwargs: Any, ) -> ImageData: """Read a Web Map tile from a COG. Args: tile_x (int): Tile's horizontal index. tile_y (int): Tile's vertical index. tile_z (int): Tile's zoom level index. tilesize (int, optional): Output image size. Defaults to `256`. indexes (int or sequence of int, optional): Band indexes. expression (str, optional): rio-tiler expression (e.g. b1/b2+b3). kwargs (optional): Options to forward to the `rio_tiler.reader.part` function. Returns: rio_tiler.models.ImageData: ImageData instance with data, mask and tile spatial info. """ kwargs = {**self._kwargs, **kwargs} if not self.tile_exists(tile_z, tile_x, tile_y): raise TileOutsideBounds( f"Tile {tile_z}/{tile_x}/{tile_y} is outside {self.filepath} bounds" ) if isinstance(indexes, int): indexes = (indexes, ) if indexes and expression: warnings.warn( "Both expression and indexes passed; expression will overwrite indexes parameter.", ExpressionMixingWarning, ) if expression: indexes = parse_expression(expression) tile_bounds = self.tms.xy_bounds(*Tile(x=tile_x, y=tile_y, z=tile_z)) tile, mask = reader.part( self.dataset, tile_bounds, tilesize, tilesize, indexes=indexes, dst_crs=self.tms.crs, **kwargs, ) if expression: blocks = expression.lower().split(",") bands = [f"b{bidx}" for bidx in indexes] tile = apply_expression(blocks, bands, tile) return ImageData(tile, mask, bounds=tile_bounds, crs=self.tms.crs, assets=[self.filepath])
def validate_and_parse(cls, v) -> Tile: """Parse and return Morecantile Tile.""" z, x, y = list(map(int, v.split("-"))) return Tile(x, y, z)
def tile( self, tile_x: int, tile_y: int, tile_z: int, tilesize: int = 256, indexes: Optional[Indexes] = None, expression: Optional[str] = None, tile_buffer: Optional[NumType] = None, **kwargs: Any, ) -> ImageData: """Read a Web Map tile from a COG. Args: tile_x (int): Tile's horizontal index. tile_y (int): Tile's vertical index. tile_z (int): Tile's zoom level index. tilesize (int, optional): Output image size. Defaults to `256`. indexes (int or sequence of int, optional): Band indexes. expression (str, optional): rio-tiler expression (e.g. b1/b2+b3). tile_buffer (int or float, optional): Buffer on each side of the given tile. It must be a multiple of `0.5`. Output **tilesize** will be expanded to `tilesize + 2 * tile_buffer` (e.g 0.5 = 257x257, 1.0 = 258x258). kwargs (optional): Options to forward to the `COGReader.part` method. Returns: rio_tiler.models.ImageData: ImageData instance with data, mask and tile spatial info. """ if not self.tile_exists(tile_x, tile_y, tile_z): raise TileOutsideBounds( f"Tile {tile_z}/{tile_x}/{tile_y} is outside {self.input} bounds" ) tile_bounds = self.tms.xy_bounds(Tile(x=tile_x, y=tile_y, z=tile_z)) if tile_buffer is not None: if tile_buffer % 0.5: raise IncorrectTileBuffer( "`tile_buffer` must be a multiple of `0.5` (e.g: 0.5, 1, 1.5, ...)." ) x_res = (tile_bounds.right - tile_bounds.left) / tilesize y_res = (tile_bounds.top - tile_bounds.bottom) / tilesize # Buffered Tile Bounds tile_bounds = BoundingBox( tile_bounds.left - x_res * tile_buffer, tile_bounds.bottom - y_res * tile_buffer, tile_bounds.right + x_res * tile_buffer, tile_bounds.top + y_res * tile_buffer, ) # Buffered Tile Size tilesize += int(tile_buffer * 2) return self.part( tile_bounds, dst_crs=self.tms.rasterio_crs, bounds_crs=None, height=tilesize, width=tilesize, max_size=None, indexes=indexes, expression=expression, **kwargs, )