def test_feature(): """TileSchema.feature should create proper geojson feature.""" tms = morecantile.tms.get("WebMercatorQuad") feat = tms.feature(morecantile.Tile(1, 0, 1)) assert feat["bbox"] assert feat["id"] assert feat["geometry"] assert len(feat["properties"].keys()) == 3 feat = tms.feature( morecantile.Tile(1, 0, 1), buffer=-10, precision=4, fid="1", props={"some": "thing"}, ) assert feat["bbox"] assert feat["id"] == "1" assert feat["geometry"] assert len(feat["properties"].keys()) == 4 with pytest.warns(UserWarning): feat = tms.feature( morecantile.Tile(1, 0, 1), projected=True, fid="1", props={"some": "thing"} ) assert feat["bbox"] assert feat["id"] == "1" assert feat["geometry"] assert len(feat["properties"].keys()) == 4
def test_tiles(): """Test tiles from bbox.""" tms = morecantile.tms.get("WebMercatorQuad") # replicate mercantile tests # https://github.com/mapbox/mercantile/blob/master/tests/test_funcs.py#L115-L178 bounds = (-105, 39.99, -104.99, 40) tiles = list(tms.tiles(*bounds, zooms=[14])) expect = [ morecantile.Tile(x=3413, y=6202, z=14), morecantile.Tile(x=3413, y=6203, z=14), ] assert sorted(tiles) == sorted(expect) # Single zoom bounds = (-105, 39.99, -104.99, 40) tiles = list(tms.tiles(*bounds, zooms=14)) expect = [ morecantile.Tile(x=3413, y=6202, z=14), morecantile.Tile(x=3413, y=6203, z=14), ] assert sorted(tiles) == sorted(expect) # Input is truncated assert list(tms.tiles(-181.0, 0.0, -170.0, 10.0, zooms=[2], truncate=True)) == list( tms.tiles(-180.0, 0.0, -170.0, 10.0, zooms=[2])) # Antimeridian-crossing bounding boxes are handled bounds = (175.0, 5.0, -175.0, 10.0) assert len(list(tms.tiles(*bounds, zooms=[2]))) == 2
def test_children(): """test children.""" tms = morecantile.tms.get("WebMercatorQuad") x, y, z = 243, 166, 9 children = tms.children(x, y, z) assert len(children) == 4 assert morecantile.Tile(2 * x, 2 * y, z + 1) in children assert morecantile.Tile(2 * x + 1, 2 * y, z + 1) in children assert morecantile.Tile(2 * x + 1, 2 * y + 1, z + 1) in children assert morecantile.Tile(2 * x, 2 * y + 1, z + 1) in children
async def tile( self, x: int, y: int, z: int, tile_size: int = 256, tms: TileMatrixSet = DEFAULT_TMS, resample_method: int = Image.NEAREST, ) -> np.ndarray: tile = morecantile.Tile(x=x, y=y, z=z) tile_bounds = tms.xy_bounds(tile) width = height = tile_size if self.cog.epsg != tms.crs: arr = await self._warped_read( tile_bounds, width, height, bounds_crs=tms.crs, resample_method=resample_method, ) else: arr = await self.cog.read(tile_bounds, shape=(width, height), resample_method=resample_method) return arr
async 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"), ) -> morecantile.Tile: """Tile parameters.""" return morecantile.Tile(x, y, z)
def get_web_optimized_params( src_dst, zoom_level_strategy: str = "auto", zoom_level: Optional[int] = None, aligned_levels: Optional[int] = None, tms: morecantile.TileMatrixSet = morecantile.tms.get("WebMercatorQuad"), ) -> Dict: """Return VRT parameters for a WebOptimized COG.""" if src_dst.crs != tms.rasterio_crs: with WarpedVRT(src_dst, crs=tms.rasterio_crs) as vrt: bounds = vrt.bounds aff = list(vrt.transform) else: bounds = src_dst.bounds aff = list(src_dst.transform) resolution = max(abs(aff[0]), abs(aff[4])) if zoom_level is None: # find max zoom (closest to the raster resolution) max_zoom = tms.zoom_for_res( resolution, max_z=30, zoom_level_strategy=zoom_level_strategy, ) else: max_zoom = zoom_level # defined the zoom level we want to align the raster aligned_levels = aligned_levels or 0 base_zoom = max_zoom - aligned_levels # find new raster bounds (bounds of UL tile / LR tile) ul_tile = tms._tile(bounds[0], bounds[3], base_zoom) w, _, _, n = tms.xy_bounds(ul_tile) # The output resolution should match the TMS resolution at MaxZoom vrt_res = tms._resolution(tms.matrix(max_zoom)) # Output transform is built from the origin (UL tile) and output resolution vrt_transform = Affine(vrt_res, 0, w, 0, -vrt_res, n) lr_tile = tms._tile(bounds[2], bounds[1], base_zoom) e, _, _, s = tms.xy_bounds( morecantile.Tile(lr_tile.x + 1, lr_tile.y + 1, lr_tile.z) ) vrt_width = max(1, round((e - w) / vrt_transform.a)) vrt_height = max(1, round((s - n) / vrt_transform.e)) return dict( crs=tms.rasterio_crs, transform=vrt_transform, width=vrt_width, height=vrt_height, )
def test_bounds(zoom: int): """Make sure mercantile and morecantile returns the same thing.""" # get random x,y index x = sample(range(0, tms.matrix(zoom).matrixWidth), 1)[0] y = sample(range(0, tms.matrix(zoom).matrixHeight), 1)[0] for a, b in zip( mercantile.xy_bounds(x, y, zoom), tms.xy_bounds(morecantile.Tile(x, y, zoom)) ): assert round(a - b, 7) == 0
def test_parent(): """test parent""" tms = morecantile.tms.get("WebMercatorQuad") parent = tms.parent(486, 332, 10) assert parent[0] == morecantile.Tile(243, 166, 9) with pytest.raises(InvalidZoomError): tms.parent(486, 332, 10, zoom=11) assert tms.parent(0, 0, 0) == []
def test_tiles(): """Test tiles from bbox.""" tms = morecantile.tms.get("WebMercatorQuad") # replicate mercantile tests # https://github.com/mapbox/mercantile/blob/master/tests/test_funcs.py#L115-L178 bounds = (-105, 39.99, -104.99, 40) tiles = list(tms.tiles(*bounds, zooms=[14])) expect = [ morecantile.Tile(x=3413, y=6202, z=14), morecantile.Tile(x=3413, y=6203, z=14), ] assert sorted(tiles) == sorted(expect) # Single zoom bounds = (-105, 39.99, -104.99, 40) tiles = list(tms.tiles(*bounds, zooms=14)) expect = [ morecantile.Tile(x=3413, y=6202, z=14), morecantile.Tile(x=3413, y=6203, z=14), ] assert sorted(tiles) == sorted(expect) # Input is truncated assert list(tms.tiles(-181.0, 0.0, -170.0, 10.0, zooms=[2], truncate=True)) == list( tms.tiles(-180.0, 0.0, -170.0, 10.0, zooms=[2])) # Antimeridian-crossing bounding boxes are handled bounds = (175.0, 5.0, -175.0, 10.0) assert len(list(tms.tiles(*bounds, zooms=[2]))) == 2 # Y is clamped to (0, 2 ** zoom - 1) tiles = list(tms.tiles(-180, -90, 180, 90, [1])) assert len(tiles) == 4 assert min(t.y for t in tiles) == 0 assert max(t.y for t in tiles) == 1 # tiles(bounds(tile)) gives the tile's children t = morecantile.Tile(x=3413, y=6202, z=14) res = list(tms.tiles(*tms.bounds(t), zooms=[15])) assert len(res) == 4
def test_tile_coordinates(): """Test coordinates to tile index utils.""" tms = morecantile.tms.get("WebMercatorQuad") assert tms.tile(-179, 85, 5) == (0, 0, 5) # Check equivalence between mercantile and morecantile # wlon, wlat = mercantile.xy(20.0, 15.0) assert tms.tile(20.0, 15.0, 5) == mercantile.tile(20.0, 15.0, 5) tms = morecantile.tms.get("WorldCRS84Quad") assert tms.tile(-39.8, 74.2, 4) == morecantile.Tile(12, 1, 4)
def geotiff_options( x: int, y: int, z: int, tilesize: int = 256, tms: morecantile.TileMatrixSet = default_tms, ) -> Dict: """GeoTIFF options.""" bounds = tms.xy_bounds(morecantile.Tile(x=x, y=y, z=z)) dst_transform = from_bounds(*bounds, tilesize, tilesize) return dict(crs=tms.crs, transform=dst_transform)
def test_InvertedLatLonGrids(): """Check Inverted LatLon grids.""" tms = morecantile.tms.get("NZTM2000") bound = tms.xy_bounds(morecantile.Tile(1, 2, 0)) assert bound == (1293760.0, 3118720.0, 3587520.0, 5412480.0) assert tms.xy_bbox == (274000.0, 3087000.0, 3327000.0, 7173000.0) tms = morecantile.tms.get("LINZAntarticaMapTilegrid") assert tms.xy_bbox == ( -918457.73, -22441670.269999996, 28441670.269999996, 6918457.73, )
def test_reader_tiles(rio): """Test STACReader.tile.""" rio.open = mock_rasterio_open tile = morecantile.Tile(z=9, x=289, y=207) with STACReader(STAC_PATH) as stac: with pytest.raises(InvalidAssetName): stac.tile(*tile, assets="B1") with pytest.raises(MissingAssets): stac.tile(*tile) data, mask = stac.tile(*tile, assets="B01") assert data.shape == (1, 256, 256) assert mask.shape == (256, 256) with STACReader(STAC_PATH) as stac: data, mask = stac.tile(*tile, expression="B01/B02") assert data.shape == (1, 256, 256) assert mask.shape == (256, 256) with STACReader(STAC_PATH) as stac: data, mask = stac.tile(*tile, assets=["B01", "B02"]) assert data.shape == (2, 256, 256) assert mask.shape == (256, 256) # This is possible but user should not to it ;-) # We are reading B01 and B02 and telling rasterio to return twice bidx 1. with STACReader(STAC_PATH) as stac: data, mask = stac.tile(*tile, assets=["B01", "B02"], indexes=(1, 1)) assert data.shape == (4, 256, 256) assert mask.shape == (256, 256) # Power User might use expression for each assets with STACReader(STAC_PATH) as stac: data, mask = stac.tile(*tile, assets=["B01", "B02"], asset_expression="b1/2") assert data.shape == (2, 256, 256) assert mask.shape == (256, 256) with STACReader(STAC_PATH, tms=morecantile.tms.get("WorldCRS84Quad")) as stac: data, mask = stac.tile(4, 1, 2, assets="B01") assert data.shape == (1, 256, 256) assert mask.shape == (256, 256)
def tile( self, tile_x: int, tile_y: int, tile_z: int, tilesize: int = 256, indexes: Optional[Sequence] = None, expression: Optional[str] = "", **kwargs: Any, ) -> Tuple[numpy.ndarray, numpy.ndarray]: """Read a TMS map tile from a COG.""" kwargs = {**self._kwargs, **kwargs} if isinstance(indexes, int): indexes = (indexes, ) if expression: indexes = parse_expression(expression) tile = morecantile.Tile(x=tile_x, y=tile_y, z=tile_z) if not self._tile_exists(tile): raise TileOutsideBounds( "Tile {}/{}/{} is outside image bounds".format( tile_z, tile_x, tile_y)) tile_bounds = self.tms.xy_bounds(*tile) tile, mask = reader.part( self.dataset, tile_bounds, tilesize, tilesize, dst_crs=self.tms.crs, indexes=indexes, **kwargs, ) if expression: blocks = expression.lower().split(",") bands = [f"b{bidx}" for bidx in indexes] tile = apply_expression(blocks, bands, tile) return tile, mask
async def tile( self, tile_x: int, tile_y: int, tile_z: int, tilesize: int = 256, indexes: Optional[Union[int, Sequence]] = None, expression: Optional[str] = "", # placeholder resampling_method: str = "nearest", ) -> TileResponse: """tile""" if isinstance(indexes, int): indexes = (indexes,) tile = morecantile.Tile(x=tile_x, y=tile_y, z=tile_z) tile_bounds = self.tms.xy_bounds(tile) # resampling_method -> resample_method resample_method = RESAMPLING[resampling_method] width = height = tilesize if self.epsg != self.tms.crs.to_epsg(): arr = await self._warped_read( tile_bounds, width, height, bounds_crs=self.tms.crs, resample_method=resample_method, ) else: arr = await self.read( tile_bounds, shape=(width, height), resample_method=resample_method ) # should be handled at read level if indexes: arr = arr[[r - 1 for r in indexes]] return TileResponse.from_array(arr)
def test_parent_multi(): """test parent""" tms = morecantile.tms.get("WebMercatorQuad") parent = tms.parent(486, 332, 10, zoom=8) assert parent[0] == morecantile.Tile(121, 83, 8)
def test_tiles_roundtrip_children(): """tiles(bounds(tile)) gives the tile's children""" tms = morecantile.tms.get("WebMercatorQuad") t = morecantile.Tile(x=3413, y=6202, z=14) res = list(tms.tiles(*tms.bounds(t), zooms=[15])) assert len(res) == 4
"""test masks.""" import os import morecantile import numpy import pytest from rasterio.coords import BoundingBox from rasterio.crs import CRS from rio_tiler.io import COGReader tiles = { "masked": morecantile.Tile(x=535, y=498, z=10), "boundless": morecantile.Tile(x=540, y=497, z=10), } equator = { "name": "equator", "bounds": BoundingBox(left=382792.5, bottom=362992.5, right=610507.5, top=595207.5), "crs": CRS.from_epsg(32632), } dataset = [ dict(equator, dtype="uint8", nodata_type="alpha"), dict(equator, dtype="uint8", nodata_type="nodata"), dict(equator, dtype="uint8", nodata_type="mask"), dict(equator, dtype="int8", nodata_type="alpha"), dict(equator, dtype="int8", nodata_type="nodata"),
assert tms.minzoom == 0 assert tms.maxzoom == 24 def test_tile_coordinates(): """Test coordinates to tile index utils.""" tms = morecantile.tms.get("WebMercatorQuad") assert tms.tile(-179, 85, 5) == (0, 0, 5) # Check equivalence between mercantile and morecantile # wlon, wlat = mercantile.xy(20.0, 15.0) assert tms.tile(20.0, 15.0, 5) == mercantile.tile(20.0, 15.0, 5) @pytest.mark.parametrize( "args", [(486, 332, 10), [(486, 332, 10)], [morecantile.Tile(486, 332, 10)]] ) def test_bounds(args): """ TileMatrixSet.bounds should return the correct coordinates. test form https://github.com/mapbox/mercantile/blob/master/tests/test_funcs.py """ expected = (-9.140625, 53.12040528310657, -8.7890625, 53.33087298301705) tms = morecantile.tms.get("WebMercatorQuad") bbox = tms.bounds(*args) for a, b in zip(expected, bbox): assert round(a - b, 7) == 0 assert bbox.left == bbox[0] assert bbox.bottom == bbox[1] assert bbox.right == bbox[2]
def test_tile_coordinates(): """Test coordinates to tile index utils.""" tms = morecantile.tms.get("WebMercatorQuad") assert tms.tile(-179, 85, 5) == (0, 0, 5) # Check equivalence between mercantile and morecantile # wlon, wlat = mercantile.xy(20.0, 15.0) assert tms.tile(20.0, 15.0, 5) == mercantile.tile(20.0, 15.0, 5) tms = morecantile.tms.get("WorldCRS84Quad") assert tms.tile(-39.8, 74.2, 4) == morecantile.Tile(12, 1, 4) @pytest.mark.parametrize( "args", [(486, 332, 10), [(486, 332, 10)], [morecantile.Tile(486, 332, 10)]]) def test_bounds(args): """ TileMatrixSet.bounds should return the correct coordinates. test form https://github.com/mapbox/mercantile/blob/master/tests/test_funcs.py """ expected = (-9.140625, 53.12040528310657, -8.7890625, 53.33087298301705) tms = morecantile.tms.get("WebMercatorQuad") bbox = tms.bounds(*args) for a, b in zip(expected, bbox): assert round(a - b, 7) == 0 assert bbox.left == bbox[0] assert bbox.bottom == bbox[1] assert bbox.right == bbox[2] assert bbox.top == bbox[3]
async def tile(self, tile_x: int, tile_y: int, tile_z: int, columns: str) -> bytes: """read vector tile""" tile = morecantile.Tile(tile_x, tile_y, tile_z) bbox = self.tms.xy_bounds(tile) return await self._tile_from_bbox(bbox, columns)
def test_nztm_quad_is_quad(): tms = morecantile.tms.get("NZTM2000Quad") bound = tms.xy_bounds(morecantile.Tile(0, 0, 0)) expected = (-3260586.7284, 419435.9938, 6758167.443, 10438190.1652) for a, b in zip(expected, bound): assert round(a - b, 4) == 0
def test_projtile(): """TileSchema._tile should return the correct tile.""" tms = morecantile.tms.get("WebMercatorQuad") assert tms._tile(1000, 1000, 1) == morecantile.Tile(1, 0, 1)
"""rio-tiler.tests.benchmarks.""" import morecantile from rasterio.coords import BoundingBox from rasterio.crs import CRS benchmark_tiles = { "north": { "full": morecantile.Tile(x=70, y=17, z=7), "masked": morecantile.Tile(x=69, y=16, z=7), "boundless": morecantile.Tile(x=68, y=17, z=7), }, "south": { "full": morecantile.Tile(x=124, y=108, z=7), "masked": morecantile.Tile(x=125, y=109, z=7), "boundless": morecantile.Tile(x=122, y=107, z=7), }, "equator": { "full": morecantile.Tile(x=537, y=499, z=10), "masked": morecantile.Tile(x=535, y=498, z=10), "boundless": morecantile.Tile(x=540, y=497, z=10), }, "dateline": { "full": morecantile.Tile(x=510, y=169, z=10), "masked": morecantile.Tile(x=510, y=168, z=10), "boundless": morecantile.Tile(x=509, y=171, z=10), }, } # LC08_L1TP_212004_20190816_20190902_01_T1 north = {