Example #1
0
def test_dynamoDB_backend(client):
    """Test DynamoDB backend."""
    client.return_value.Table = MockTable

    with MosaicBackend("dynamodb:///thiswaskylebarronidea:mosaic") as mosaic:
        assert mosaic._backend_name == "AWS DynamoDB"
        assert isinstance(mosaic, DynamoDBBackend)
        assert mosaic.quadkey_zoom == 7
        assert list(mosaic.metadata.dict(exclude_none=True).keys()) == [
            "mosaicjson",
            "version",
            "minzoom",
            "maxzoom",
            "quadkey_zoom",
            "bounds",
            "center",
        ]
        assert mosaic.assets_for_tile(150, 182, 9) == ["cog1.tif", "cog2.tif"]
        assert mosaic.assets_for_point(-73, 45) == ["cog1.tif", "cog2.tif"]

        info = mosaic.info()
        assert not info["quadkeys"]
        assert list(info.dict()) == [
            "bounds",
            "center",
            "minzoom",
            "maxzoom",
            "name",
            "quadkeys",
        ]

        info = mosaic.info(quadkeys=True)
        assert info["quadkeys"]

    with MosaicBackend("dynamodb:///thiswaskylebarronidea:mosaic2",
                       mosaic_def=mosaic_content) as mosaic:
        assert isinstance(mosaic, DynamoDBBackend)
        items = mosaic._create_items()
        assert len(items) == 10
        assert items[-1] == {
            "mosaicId": "mosaic2",
            "quadkey": "0302330",
            "assets": ["cog1.tif", "cog2.tif"],
        }
        mosaic._create_table()

    with MosaicBackend("dynamodb:///thiswaskylebarronidea:mosaic2",
                       mosaic_def=mosaic_content) as mosaic:
        items = mosaic._create_items()
        assert len(items) == len(mosaic.mosaic_def.tiles.items()) + 1
        assert "quadkey" in list(items[0])
        assert "mosaicId" in list(items[0])
        assert "bounds" in list(items[0])
        assert "center" in list(items[0])
Example #2
0
def test_http_backend(requests):
    """Test HTTP backend."""
    with open(mosaic_json, "r") as f:
        requests.get.return_value = MockResponse(f.read())
        requests.exceptions.HTTPError = HTTPError
        requests.exceptions.RequestException = RequestException

    with MosaicBackend("https://mymosaic.json") as mosaic:
        assert mosaic._backend_name == "HTTP"
        assert isinstance(mosaic, HttpBackend)
        assert (mosaic.mosaicid ==
                "24d43802c19ef67cc498c327b62514ecf70c2bbb1bbc243dda1ee075")
        assert mosaic.quadkey_zoom == 7
        assert list(mosaic.metadata.dict(exclude_none=True).keys()) == [
            "mosaicjson",
            "version",
            "minzoom",
            "maxzoom",
            "quadkey_zoom",
            "bounds",
            "center",
        ]
        assert mosaic.assets_for_tile(150, 182, 9) == ["cog1.tif", "cog2.tif"]
        assert mosaic.assets_for_point(-73, 45) == ["cog1.tif", "cog2.tif"]
    requests.get.assert_called_once()
    requests.mock_reset()

    with open(mosaic_json, "r") as f:
        requests.get.return_value = MockResponse(f.read())

    with pytest.raises(NotImplementedError):
        with MosaicBackend("https://mymosaic.json") as mosaic:
            mosaic.update()
        requests.get.assert_called_once()
        requests.mock_reset()

    with pytest.raises(NotImplementedError):
        with MosaicBackend("https://mymosaic.json",
                           mosaic_def=mosaic_content) as mosaic:
            mosaic.write()
        requests.get.assert_not_called()
        requests.mock_reset()

    with open(mosaic_gz, "rb") as f:
        requests.get.return_value = MockResponse(f.read())

    with MosaicBackend("https://mymosaic.json.gz") as mosaic:
        assert isinstance(mosaic, HttpBackend)
        assert (mosaic.mosaicid ==
                "24d43802c19ef67cc498c327b62514ecf70c2bbb1bbc243dda1ee075")
Example #3
0
def _point(
    mosaicid: str = None, lng: float = None, lat: float = None, url: str = None
) -> Tuple[str, str, str]:
    """Handle point requests."""
    if not mosaicid and not url:
        return ("NOK", "text/plain", "Missing 'MosaicID or URL' parameter")

    if not lat or not lng:
        return ("NOK", "text/plain", "Missing 'Lon/Lat' parameter")

    if isinstance(lng, str):
        lng = float(lng)

    if isinstance(lat, str):
        lat = float(lat)

    mosaic_path = _create_mosaic_path(mosaicid) if mosaicid else url
    with MosaicBackend(mosaic_path) as mosaic:
        assets = mosaic.point(lng, lat)
        if not assets:
            return (
                "EMPTY",
                "text/plain",
                f"No assets found for lat/lng ({lat}, {lng})",
            )

    with rasterio.Env(aws_session):
        meta = {
            "coordinates": [lng, lat],
            "values": [
                {"asset": assets[ix], "values": value}
                for ix, value in enumerate(multi_point(assets, coordinates=(lng, lat)))
            ],
        }
        return ("OK", "application/json", json.dumps(meta, separators=(",", ":")))
Example #4
0
 def info():
     """return info."""
     with MosaicBackend(self.src_path) as mosaic:
         info = mosaic.info(quadkeys=True).dict(exclude_none=True)
         bounds = info.pop("bounds", None)
         info.pop("center", None)
         return bbox_to_feature(bounds, properties=info)
Example #5
0
def create_from_features(
    features,
    output,
    minzoom,
    maxzoom,
    property,
    quadkey_zoom,
    min_tile_cover,
    tile_cover_sort,
    quiet,
):
    """Create mosaic definition file."""
    mosaicjson = MosaicJSON.from_features(
        list(features),
        minzoom,
        maxzoom,
        quadkey_zoom=quadkey_zoom,
        accessor=lambda feature: feature["properties"][property],
        minimum_tile_cover=min_tile_cover,
        tile_cover_sort=tile_cover_sort,
        quiet=quiet,
    )

    if output:
        with MosaicBackend(output, mosaic_def=mosaicjson) as mosaic:
            mosaic.write()
    else:
        click.echo(json.dumps(mosaicjson.dict(exclude_none=True)))
Example #6
0
 def shapes(qk: str = Query(...)):
     """return info."""
     x, y, z = mercantile.quadkey_to_tile(qk)
     with MosaicBackend(self.src_path) as mosaic:
         assets = mosaic.assets_for_tile(x, y, z)
         features = get_footprints(assets, max_threads=MAX_THREADS)
     return FeatureCollection(features=features)
Example #7
0
def _info(mosaicid: str = None, url: str = None) -> Tuple:
    """Handle /info requests."""
    if not mosaicid and not url:
        return ("NOK", "text/plain", "Missing 'MosaicID or URL' parameter")

    mosaic_path = _create_mosaic_path(mosaicid) if mosaicid else url
    with MosaicBackend(mosaic_path) as mosaic:
        meta = mosaic.metadata
        response = {
            "bounds": meta["bounds"],
            "center": meta["center"],
            "maxzoom": meta["maxzoom"],
            "minzoom": meta["minzoom"],
            "name": mosaicid or url,
        }

        if not mosaic_path.startswith("dynamodb://"):
            mosaic_quadkeys = set(mosaic._quadkeys)
            tile = mercantile.quadkey_to_tile(random.sample(mosaic_quadkeys, 1)[0])
            assets = mosaic.tile(*tile)
            with rasterio.open(assets[0]) as src_dst:
                layer_names = _get_layer_names(src_dst)
                dtype = src_dst.dtypes[0]

            response["quadkeys"] = list(mosaic_quadkeys)
            response["layers"] = layer_names
            response["dtype"] = dtype
        else:
            warnings.warn(
                "Cannot retrieve 'quadkeys,layers and dtype' from dynamoDB mosaic."
            )

        return ("OK", "application/json", json.dumps(response, separators=(",", ":")))
Example #8
0
def test_dynamoDB_backend(client):
    """Test DynamoDB backend."""
    client.return_value.Table = MockTable

    with MosaicBackend("dynamodb:///thiswaskylebarronidea:mosaic") as mosaic:
        assert mosaic._backend_name == "AWS DynamoDB"
        assert isinstance(mosaic, DynamoDBBackend)
        assert mosaic.quadkey_zoom == 7
        assert list(mosaic.metadata.dict(exclude_none=True).keys()) == [
            "mosaicjson",
            "version",
            "minzoom",
            "maxzoom",
            "quadkey_zoom",
            "bounds",
            "center",
        ]
        assert mosaic.assets_for_tile(150, 182, 9) == ["cog1.tif", "cog2.tif"]
        assert mosaic.assets_for_point(-73, 45) == ["cog1.tif", "cog2.tif"]

        info = mosaic.info()
        assert not info["quadkeys"]
        assert list(info.dict()) == [
            "bounds",
            "center",
            "minzoom",
            "maxzoom",
            "name",
            "quadkeys",
        ]

        info = mosaic.info(quadkeys=True)
        assert info["quadkeys"]
Example #9
0
def create(
    input_files,
    output,
    minzoom,
    maxzoom,
    quadkey_zoom,
    min_tile_cover,
    tile_cover_sort,
    threads,
    quiet,
):
    """Create mosaic definition file."""
    input_files = input_files.read().splitlines()
    mosaicjson = MosaicJSON.from_urls(
        input_files,
        minzoom=minzoom,
        maxzoom=maxzoom,
        quadkey_zoom=quadkey_zoom,
        minimum_tile_cover=min_tile_cover,
        tile_cover_sort=tile_cover_sort,
        max_threads=threads,
        quiet=quiet,
    )

    if output:
        with MosaicBackend(output, mosaic_def=mosaicjson) as mosaic:
            mosaic.write()
    else:
        click.echo(json.dumps(mosaicjson.dict(exclude_none=True)))
Example #10
0
def test_http_backend(requests):
    """Test HTTP backend."""
    with open(mosaic_json, "r") as f:
        requests.get.return_value = MockResponse(f.read())

    with MosaicBackend("https://mymosaic.json") as mosaic:
        assert isinstance(mosaic, HttpBackend)
        assert (mosaic.mosaicid ==
                "f39f05644731addf1d183fa094ff6478900a27912ad035ef570231b1")
        assert mosaic.quadkey_zoom == 7
        assert list(mosaic.metadata.keys()) == [
            "mosaicjson",
            "version",
            "minzoom",
            "maxzoom",
            "quadkey_zoom",
            "bounds",
            "center",
        ]
        assert mosaic.tile(150, 182, 9) == ["cog1.tif", "cog2.tif"]
        assert mosaic.point(-73, 45) == ["cog1.tif", "cog2.tif"]
    requests.get.assert_called_once()
    requests.mock_reset()

    with open(mosaic_json, "r") as f:
        requests.get.return_value = MockResponse(f.read())

    with pytest.raises(NotImplementedError):
        with MosaicBackend("https://mymosaic.json") as mosaic:
            mosaic.update()
        requests.get.assert_called_once()
        requests.mock_reset()

    with pytest.raises(NotImplementedError):
        with MosaicBackend("https://mymosaic.json",
                           mosaic_def=mosaic_content) as mosaic:
            mosaic.write()
        requests.get.assert_not_called()
        requests.mock_reset()

    with open(mosaic_gz, "rb") as f:
        requests.get.return_value = MockResponse(f.read())

    with MosaicBackend("https://mymosaic.json.gz") as mosaic:
        assert isinstance(mosaic, HttpBackend)
        assert (mosaic.mosaicid ==
                "f39f05644731addf1d183fa094ff6478900a27912ad035ef570231b1")
Example #11
0
def _mvt(
    mosaicid: str = None,
    z: int = None,
    x: int = None,
    y: int = None,
    url: str = None,
    tile_size: Union[str, int] = 256,
    pixel_selection: str = "first",
    feature_type: str = "point",
    resampling_method: str = "nearest",
) -> Tuple:
    """Handle MVT requests."""
    from rio_tiler_mvt.mvt import encoder as mvtEncoder  # noqa

    if not mosaicid and not url:
        return ("NOK", "text/plain", "Missing 'MosaicID or URL' parameter")

    mosaic_path = _create_mosaic_path(mosaicid) if mosaicid else url
    with MosaicBackend(mosaic_path) as mosaic:
        assets = mosaic.tile(x, y, z)
        if not assets:
            return ("EMPTY", "text/plain", f"No assets found for tile {z}-{x}-{y}")

    if tile_size is not None and isinstance(tile_size, str):
        tile_size = int(tile_size)

    if pixel_selection == "last":
        pixel_selection = "first"
        assets = list(reversed(assets))

    with rasterio.Env(aws_session):
        pixsel_method = PIXSEL_METHODS[pixel_selection]
        tile, mask = mosaic_tiler(
            assets,
            x,
            y,
            z,
            cogeoTiler,
            tilesize=tile_size,
            pixel_selection=pixsel_method(),
            resampling_method=resampling_method,
        )
        if tile is None:
            return ("EMPTY", "text/plain", "empty tiles")

        with rasterio.open(assets[0]) as src_dst:
            band_descriptions = _get_layer_names(src_dst)

        return (
            "OK",
            "application/x-protobuf",
            mvtEncoder(
                tile,
                mask,
                band_descriptions,
                mosaicid or os.path.basename(url),
                feature_type=feature_type,
            ),
        )
Example #12
0
def _img(
    mosaicid: str = None,
    z: int = None,
    x: int = None,
    y: int = None,
    scale: int = 1,
    ext: str = None,
    url: str = None,
    pixel_selection: str = "first",
    resampling_method: str = "nearest",
) -> Tuple:
    """Handle tile requests."""
    if not mosaicid and not url:
        return ("NOK", "text/plain", "Missing 'MosaicID or URL' parameter")

    mosaic_path = _create_mosaic_path(mosaicid) if mosaicid else url
    with MosaicBackend(mosaic_path) as mosaic:
        assets = mosaic.tile(x, y, z)
        if not assets:
            return ("EMPTY", "text/plain", f"No assets found for tile {z}-{x}-{y}")

    tilesize = 256 * scale

    if pixel_selection == "last":
        pixel_selection = "first"
        assets = list(reversed(assets))

    with rasterio.Env(aws_session):
        pixsel_method = PIXSEL_METHODS[pixel_selection]
        tile, mask = mosaic_tiler(
            assets,
            x,
            y,
            z,
            usgs_tiler,
            tilesize=tilesize,
            pixel_selection=pixsel_method(),
            resampling_method=resampling_method,
        )

    if tile is None:
        return ("EMPTY", "text/plain", "empty tiles")

    if not ext:
        ext = "jpg" if mask.all() else "png"

    driver = "jpeg" if ext == "jpg" else ext
    options = img_profiles.get(driver, {})

    if ext == "tif":
        ext = "tiff"
        driver = "GTiff"
        options = geotiff_options(x, y, z, tilesize)

    return (
        "OK",
        f"image/{ext}",
        render(tile, mask, img_format=driver, **options),
    )
Example #13
0
def info(url: str) -> Tuple[str, str, str]:
    """Handle /info requests."""
    if url is None:
        return ("NOK", "text/plain", "Missing 'URL' parameter")

    with MosaicBackend(url) as mosaic:
        mosaic_def = dict(mosaic.mosaic_def)

    return ("OK", "application/json", json.dumps(mosaic_def))
Example #14
0
def wmts(
    request: Request,
    tile_format: ImageType = Query(
        ImageType.png, description="Output image type. Default is png."
    ),
    tile_scale: int = Query(
        1, gt=0, lt=4, description="Tile size scale. 1=256x256, 2=512x512..."
    ),
    mosaic_path: str = Depends(MosaicPath),
):
    """OGC WMTS endpoint."""
    endpoint = request.url_for("read_mosaicjson")

    kwargs = dict(request.query_params)
    kwargs.pop("tile_format", None)
    kwargs.pop("tile_scale", None)
    qs = urlencode(list(kwargs.items()))

    tms = morecantile.tms.get("WebMercatorQuad")
    with MosaicBackend(mosaic_path) as mosaic:
        minzoom = mosaic.mosaic_def.minzoom
        maxzoom = mosaic.mosaic_def.maxzoom
        bounds = mosaic.mosaic_def.bounds

    media_type = ImageMimeTypes[tile_format.value].value

    tileMatrix = []
    for zoom in range(minzoom, maxzoom + 1):
        matrix = tms.matrix(zoom)
        tm = f"""
                <TileMatrix>
                    <ows:Identifier>{matrix.identifier}</ows:Identifier>
                    <ScaleDenominator>{matrix.scaleDenominator}</ScaleDenominator>
                    <TopLeftCorner>{matrix.topLeftCorner[0]} {matrix.topLeftCorner[1]}</TopLeftCorner>
                    <TileWidth>{matrix.tileWidth}</TileWidth>
                    <TileHeight>{matrix.tileHeight}</TileHeight>
                    <MatrixWidth>{matrix.matrixWidth}</MatrixWidth>
                    <MatrixHeight>{matrix.matrixHeight}</MatrixHeight>
                </TileMatrix>"""
        tileMatrix.append(tm)

    tile_ext = f"@{tile_scale}x.{tile_format.value}"
    return templates.TemplateResponse(
        "wmts.xml",
        {
            "request": request,
            "endpoint": endpoint,
            "bounds": bounds,
            "tileMatrix": tileMatrix,
            "tms": tms,
            "title": "Cloud Optimized GeoTIFF",
            "query_string": qs,
            "tile_format": tile_ext,
            "media_type": media_type,
        },
        media_type=MimeTypes.xml.value,
    )
Example #15
0
def update(input_files, input_mosaic, min_tile_cover, add_first, threads, quiet):
    """Update mosaic definition file."""
    input_files = input_files.read().splitlines()
    features = get_footprints(input_files, max_threads=threads)
    with MosaicBackend(input_mosaic) as mosaic:
        mosaic.update(
            features,
            add_first=add_first,
            minimum_tile_cover=min_tile_cover,
            quiet=quiet,
        )
Example #16
0
async def mosaic_point(
    lon: float = Path(..., description="Longitude"),
    lat: float = Path(..., description="Latitude"),
    bidx: Optional[str] = Query(
        None, title="Band indexes", description="comma (',') delimited band indexes",
    ),
    expression: Optional[str] = Query(
        None,
        title="Band Math expression",
        description="rio-tiler's band math expression (e.g B1/B2)",
    ),
    mosaic_path: str = Depends(MosaicPath),
):
    """Get Point value for a MosaicJSON."""
    indexes = tuple(int(s) for s in re.findall(r"\d+", bidx)) if bidx else None

    timings = []
    headers: Dict[str, str] = {}

    with utils.Timer() as t:
        with MosaicBackend(mosaic_path) as mosaic:
            assets = mosaic.point(lon, lat)

    timings.append(("Read-mosaic", t.elapsed))

    # Rio-tiler provides a helper function (``rio_tiler.reader.multi_point``) for reading a point from multiple assets
    # using an external threadpool.  For similar reasons as described below, we will transcribe the rio-tiler code to
    # use the default executor provided by the event loop.
    futures = [
        run_in_threadpool(
            _read_point, asset, lon, lat, indexes=indexes, expression=expression
        )
        for asset in assets
    ]

    values = []
    with utils.Timer() as t:
        async for fut in _process_futures(
            futures, concurrency=int(os.getenv("MOSAIC_CONCURRENCY", 10))
        ):
            try:
                values.append(await fut)
            except Exception:
                continue

    timings.append(("Read-tiles", t.elapsed))

    if timings:
        headers["X-Server-Timings"] = "; ".join(
            ["{} - {:0.2f}".format(name, time * 1000) for (name, time) in timings]
        )

    return {"coordinates": [lon, lat], "values": values}
Example #17
0
def update_mosaicjson(body: UpdateMosaicJSON):
    """Update an existing MosaicJSON"""
    mosaic_path = MosaicPath(body.url)
    with MosaicBackend(mosaic_path) as mosaic:
        features = get_footprints(body.files, max_threads=body.max_threads)
        try:
            mosaic.update(features, add_first=body.add_first, quiet=True)
        except NotImplementedError:
            raise BadRequestError(
                f"{mosaic.__class__.__name__} does not support update operations"
            )
        return mosaic.mosaic_def
Example #18
0
def npy_tiles(
    url: str,
    z: int,
    x: int,
    y: int,
    scale: int = 1,
    bands: str = None,
    expr: str = None,
    pixel_selection: str = "first",
) -> Tuple[str, str, BinaryIO]:
    """Handle tile requests."""
    if url is None:
        return ("NOK", "text/plain", "Missing 'URL' parameter")

    with MosaicBackend(url) as mosaic:
        assets = mosaic.tile(x, y, z)

    if not assets:
        return ("EMPTY", "text/plain", f"No assets found for tile {z}-{x}-{y}")

    tilesize = 256 * scale

    pixel_selection = pixSel[pixel_selection]
    if expr is not None:
        results = mosaic_tiler(
            assets,
            x,
            y,
            z,
            expressionTiler,
            pixel_selection=pixel_selection(),
            expr=expr,
            tilesize=tilesize,
        )

    elif bands is not None:
        results = mosaic_tiler(
            assets,
            x,
            y,
            z,
            landsatTiler,
            pixel_selection=pixel_selection(),
            bands=tuple(bands.split(",")),
            tilesize=tilesize,
        )
    else:
        return ("NOK", "text/plain", "No bands nor expression given")

    sio = io.BytesIO()
    numpy.save(sio, results)
    sio.seek(0)
    return ("OK", "application/x-binary", sio.getvalue())
Example #19
0
def _add(body: str, url: str) -> Tuple:
    mosaic_definition = MosaicJSON(**json.loads(body))
    with MosaicBackend(url, mosaic_def=mosaic_definition) as mosaic:
        mosaic.write()

    return (
        "OK",
        "application/json",
        json.dumps({
            "id": url,
            "status": "READY"
        }, separators=(",", ":")),
    )
Example #20
0
def _add(body: str, mosaicid: str) -> Tuple:
    if _aws_head_object(_create_mosaic_path(mosaicid), client=s3_client):
        return ("NOK", "text/plain", f"Mosaic: {mosaicid} already exist.")

    mosaic_definition = MosaicJSON(**json.loads(body))
    with MosaicBackend(
        _create_mosaic_path(mosaicid), mosaic_def=mosaic_definition
    ) as mosaic:
        mosaic.write()

    return (
        "OK",
        "application/json",
        json.dumps({"id": mosaicid, "status": "READY"}, separators=(",", ":")),
    )
Example #21
0
def mosaicjson_info(mosaic_path: str = Depends(MosaicPath)):
    """
    Read MosaicJSON info

    Ref: https://github.com/developmentseed/cogeo-mosaic-tiler/blob/master/cogeo_mosaic_tiler/handlers/app.py#L164-L198
    """
    with MosaicBackend(mosaic_path) as mosaic:
        meta = mosaic.metadata
        response = {
            "bounds": meta["bounds"],
            "center": meta["center"],
            "maxzoom": meta["maxzoom"],
            "minzoom": meta["minzoom"],
            "name": mosaic_path,
            "quadkeys": list(mosaic.mosaic_def.tiles),
        }
        return response
Example #22
0
def create_mosaicjson(body: CreateMosaicJSON):
    """Create a MosaicJSON"""
    mosaic = MosaicJSON.from_urls(
        body.files,
        minzoom=body.minzoom,
        maxzoom=body.maxzoom,
        max_threads=body.max_threads,
    )
    mosaic_path = MosaicPath(body.url)
    with MosaicBackend(mosaic_path, mosaic_def=mosaic) as mosaic:
        try:
            mosaic.write()
        except NotImplementedError:
            raise BadRequestError(
                f"{mosaic.__class__.__name__} does not support write operations"
            )
        return mosaic.mosaic_def
Example #23
0
def _wmts(
    mosaicid: str = None,
    url: str = None,
    tile_format: str = "png",
    tile_scale: int = 1,
    title: str = "Cloud Optimizied GeoTIFF Mosaic",
    **kwargs: Any,
) -> Tuple:
    """Handle /wmts requests."""
    if not mosaicid and not url:
        return ("NOK", "text/plain", "Missing 'MosaicID or URL' parameter")

    if tile_scale is not None and isinstance(tile_scale, str):
        tile_scale = int(tile_scale)

    if not mosaicid:
        kwargs.update(dict(url=url))
        host = app.host
    else:
        host = f"{app.host}/{mosaicid}"

    query_string = urllib.parse.urlencode(list(kwargs.items()))
    query_string = query_string.replace(
        "&", "&amp;"
    )  # & is an invalid character in XML
    kwargs.pop("SERVICE", None)
    kwargs.pop("REQUEST", None)

    mosaic_path = _create_mosaic_path(mosaicid) if mosaicid else url
    with MosaicBackend(mosaic_path) as mosaic:
        meta = mosaic.metadata

        return (
            "OK",
            "application/xml",
            wmts_template(
                host,
                query_string,
                minzoom=meta["minzoom"],
                maxzoom=meta["maxzoom"],
                bounds=meta["bounds"],
                tile_scale=tile_scale,
                tile_format=tile_format,
                title=title,
            ),
        )
Example #24
0
def find_assets(x, y, z, mosaic_url, tile_size):
    """Find assets for input

    Args:
        - x: OSM tile index
        - y: OSM tile index
        - z: OSM tile index
        - mosaic_url: either url to MosaicJSON file, or the strings "terrarium" or "geotiff" to load terrarium or geotiff tiles from AWS Terrain Tiles
        - tile_size, one of 256, 258, 512, 514
    """
    if mosaic_url == 'terrarium':
        return _find_terrarium_assets(x, y, z, tile_size)

    if mosaic_url == 'geotiff':
        return _find_geotiff_assets(x, y, z, tile_size)

    with MosaicBackend(mosaic_url) as mosaic:
        return mosaic.tile(x, y, z)
Example #25
0
def mosaic_tilejson(
    request: Request,
    tile_scale: int = Query(
        1, gt=0, lt=4, description="Tile size scale. 1=256x256, 2=512x512..."
    ),
    tile_format: Optional[ImageType] = Query(
        None, description="Output image type. Default is auto."
    ),
    mosaic_path: str = Depends(MosaicPath),
):
    """Create TileJSON"""
    kwargs = {"z": "{z}", "x": "{x}", "y": "{y}", "scale": tile_scale}
    if tile_format:
        kwargs["format"] = tile_format
    tile_url = request.url_for("mosaic_tile", **kwargs).replace("\\", "")
    with MosaicBackend(mosaic_path) as mosaic:
        tjson = TileJSON(**mosaic.metadata, tiles=[tile_url])
    return tjson
Example #26
0
def _geojson(mosaicid: str = None, url: str = None) -> Tuple:
    """Handle /geojson requests."""
    if not mosaicid and not url:
        return ("NOK", "text/plain", "Missing 'MosaicID or URL' parameter")

    mosaic_path = _create_mosaic_path(mosaicid) if mosaicid else url
    with MosaicBackend(mosaic_path) as mosaic:
        geojson = {
            "type": "FeatureCollection",
            "features": [
                mercantile.feature(
                    mercantile.quadkey_to_tile(qk), props=dict(files=files)
                )
                for qk, files in mosaic.mosaic_def.tiles.items()
            ],
        }

    return ("OK", "application/json", json.dumps(geojson, separators=(",", ":")))
Example #27
0
def to_geojson(input, collect):
    """Read MosaicJSON document and create GeoJSON features."""
    features = []
    with MosaicBackend(input) as mosaic:
        for qk, assets in mosaic.mosaic_def.tiles.items():
            tile = mercantile.quadkey_to_tile(qk)

            west, south, east, north = mercantile.bounds(tile)

            geom = {
                "type":
                "Polygon",
                "coordinates": [[
                    [west, south],
                    [west, north],
                    [east, north],
                    [east, south],
                    [west, south],
                ]],
            }
            feature = {
                "type": "Feature",
                "id": str(tile),
                "geometry": geom,
                "properties": {
                    "nb_assets": len(assets),
                    "assets": assets
                },
            }

            if collect:
                features.append(feature)
            else:
                click.echo(json.dumps(feature))

        if collect and features:
            click.echo(
                json.dumps({
                    "type": "FeatureCollection",
                    "features": features
                }, ))
Example #28
0
def _tilejson(
    mosaicid: str = None,
    url: str = None,
    tile_scale: int = 1,
    tile_format: str = None,
    **kwargs: Any,
) -> Tuple:
    """Handle /tilejson.json requests."""
    if not mosaicid and not url:
        return ("NOK", "text/plain", "Missing 'MosaicID or URL' parameter")

    if not mosaicid:
        kwargs.update(dict(url=url))
        host = app.host
    else:
        host = f"{app.host}/{mosaicid}"

    if tile_format in ["pbf", "mvt"]:
        tile_url = f"{host}/{{z}}/{{x}}/{{y}}.{tile_format}"
    elif tile_format in ["png", "jpg", "webp", "tif", "npy"]:
        tile_url = f"{host}/{{z}}/{{x}}/{{y}}@{tile_scale}x.{tile_format}"
    else:
        tile_url = f"{host}/{{z}}/{{x}}/{{y}}@{tile_scale}x"

    qs = urllib.parse.urlencode(list(kwargs.items()))
    if qs:
        tile_url += f"?{qs}"

    mosaic_path = _create_mosaic_path(mosaicid) if mosaicid else url
    with MosaicBackend(mosaic_path) as mosaic:
        meta = mosaic.metadata
        response = {
            "bounds": meta["bounds"],
            "center": meta["center"],
            "maxzoom": meta["maxzoom"],
            "minzoom": meta["minzoom"],
            "name": mosaicid or url,
            "tilejson": "2.1.0",
            "tiles": [tile_url],
        }
    return ("OK", "application/json", json.dumps(response, separators=(",", ":")))
Example #29
0
def create(
    input_files,
    output,
    minzoom,
    maxzoom,
    quadkey_zoom,
    min_tile_cover,
    tile_cover_sort,
    threads,
    name,
    description,
    attribution,
    quiet,
):
    """Create mosaic definition file."""
    input_files = [file.strip() for file in input_files if file.strip()]
    mosaicjson = MosaicJSON.from_urls(
        input_files,
        minzoom=minzoom,
        maxzoom=maxzoom,
        quadkey_zoom=quadkey_zoom,
        minimum_tile_cover=min_tile_cover,
        tile_cover_sort=tile_cover_sort,
        max_threads=threads,
        quiet=quiet,
    )

    if name:
        mosaicjson.name = name
    if description:
        mosaicjson.description = description
    if attribution:
        mosaicjson.attribution = attribution

    if output:
        with MosaicBackend(output, mosaic_def=mosaicjson) as mosaic:
            mosaic.write(overwrite=True)
    else:
        click.echo(mosaicjson.json(exclude_none=True))
Example #30
0
def create_from_features(
    features,
    output,
    minzoom,
    maxzoom,
    property,
    quadkey_zoom,
    min_tile_cover,
    tile_cover_sort,
    name,
    description,
    attribution,
    quiet,
):
    """Create mosaic definition file."""
    mosaicjson = MosaicJSON.from_features(
        list(features),
        minzoom,
        maxzoom,
        quadkey_zoom=quadkey_zoom,
        accessor=lambda feature: feature["properties"][property],
        minimum_tile_cover=min_tile_cover,
        tile_cover_sort=tile_cover_sort,
        quiet=quiet,
    )

    if name:
        mosaicjson.name = name
    if description:
        mosaicjson.description = description
    if attribution:
        mosaicjson.attribution = attribution

    if output:
        with MosaicBackend(output, mosaic_def=mosaicjson) as mosaic:
            mosaic.write(overwrite=True)
    else:
        click.echo(mosaicjson.json(exclude_none=True))