From 232bba172860e05ff791862d1424607eb6708a89 Mon Sep 17 00:00:00 2001 From: <> Date: Thu, 31 Aug 2023 13:48:00 +0000 Subject: [PATCH] Deployed 4b9da63 with MkDocs version: 1.5.2 --- .nojekyll | 0 404.html | 599 ++ advanced/custom_search/custom_search.md | 90 + advanced/custom_search/index.html | 742 ++ advanced/custom_tilejson/custom_tilejson.md | 166 + advanced/custom_tilejson/index.html | 823 ++ advanced/geojson_crop/geojson_crop.md | 132 + advanced/geojson_crop/index.html | 791 ++ advanced/metadata/index.html | 822 ++ advanced/metadata/metadata.md | 117 + advanced/mosaic_list/index.html | 685 ++ advanced/mosaic_list/mosaic_list.md | 30 + assets/images/favicon.png | Bin 0 -> 1870 bytes assets/javascripts/bundle.5a2dcb6a.min.js | 29 + assets/javascripts/bundle.5a2dcb6a.min.js.map | 8 + .../javascripts/extra/bundle.5f09fbc3.min.js | 18 + .../extra/bundle.5f09fbc3.min.js.map | 8 + assets/javascripts/lunr/min/lunr.ar.min.js | 1 + assets/javascripts/lunr/min/lunr.da.min.js | 18 + assets/javascripts/lunr/min/lunr.de.min.js | 18 + assets/javascripts/lunr/min/lunr.du.min.js | 18 + assets/javascripts/lunr/min/lunr.es.min.js | 18 + assets/javascripts/lunr/min/lunr.fi.min.js | 18 + assets/javascripts/lunr/min/lunr.fr.min.js | 18 + assets/javascripts/lunr/min/lunr.hi.min.js | 1 + assets/javascripts/lunr/min/lunr.hu.min.js | 18 + assets/javascripts/lunr/min/lunr.it.min.js | 18 + assets/javascripts/lunr/min/lunr.ja.min.js | 1 + assets/javascripts/lunr/min/lunr.jp.min.js | 1 + assets/javascripts/lunr/min/lunr.ko.min.js | 1 + assets/javascripts/lunr/min/lunr.multi.min.js | 1 + assets/javascripts/lunr/min/lunr.nl.min.js | 18 + assets/javascripts/lunr/min/lunr.no.min.js | 18 + assets/javascripts/lunr/min/lunr.pt.min.js | 18 + assets/javascripts/lunr/min/lunr.ro.min.js | 18 + assets/javascripts/lunr/min/lunr.ru.min.js | 18 + .../lunr/min/lunr.stemmer.support.min.js | 1 + assets/javascripts/lunr/min/lunr.sv.min.js | 18 + assets/javascripts/lunr/min/lunr.ta.min.js | 1 + assets/javascripts/lunr/min/lunr.th.min.js | 1 + assets/javascripts/lunr/min/lunr.tr.min.js | 18 + assets/javascripts/lunr/min/lunr.vi.min.js | 1 + assets/javascripts/lunr/min/lunr.zh.min.js | 1 + assets/javascripts/lunr/tinyseg.js | 206 + assets/javascripts/lunr/wordcut.js | 6708 +++++++++++++++++ .../workers/search.16e2a7d4.min.js | 48 + .../workers/search.16e2a7d4.min.js.map | 8 + assets/stylesheets/extra.0d2c79a8.min.css | 1 + assets/stylesheets/extra.0d2c79a8.min.css.map | 1 + assets/stylesheets/main.975780f9.min.css | 1 + assets/stylesheets/main.975780f9.min.css.map | 1 + assets/stylesheets/palette.2505c338.min.css | 1 + .../stylesheets/palette.2505c338.min.css.map | 1 + benchmark.html | 292 + contributing/contributing.md | 23 + contributing/index.html | 679 ++ img/favicon.ico | Bin 0 -> 3350 bytes img/logo.png | Bin 0 -> 4240 bytes index.html | 912 +++ index.md | 118 + intro/index.html | 997 +++ intro/intro.md | 233 + item_endpoints/index.html | 1393 ++++ item_endpoints/item_endpoints.md | 405 + mosaic_endpoints/index.html | 1222 +++ mosaic_endpoints/mosaic_endpoints.md | 351 + notebooks/demo/demo.ipynb | 691 ++ notebooks/demo/index.html | 3058 ++++++++ release-notes/index.html | 1335 ++++ release-notes/release-notes.md | 262 + search/search_index.json | 1 + sitemap.xml | 73 + sitemap.xml.gz | Bin 0 -> 337 bytes tiler_factories/index.html | 852 +++ tiler_factories/tiler_factories.md | 85 + tms_endpoints/index.html | 811 ++ tms_endpoints/tms_endpoints.md | 77 + 77 files changed, 26187 insertions(+) create mode 100644 .nojekyll create mode 100644 404.html create mode 100644 advanced/custom_search/custom_search.md create mode 100644 advanced/custom_search/index.html create mode 100644 advanced/custom_tilejson/custom_tilejson.md create mode 100644 advanced/custom_tilejson/index.html create mode 100644 advanced/geojson_crop/geojson_crop.md create mode 100644 advanced/geojson_crop/index.html create mode 100644 advanced/metadata/index.html create mode 100644 advanced/metadata/metadata.md create mode 100644 advanced/mosaic_list/index.html create mode 100644 advanced/mosaic_list/mosaic_list.md create mode 100644 assets/images/favicon.png create mode 100644 assets/javascripts/bundle.5a2dcb6a.min.js create mode 100644 assets/javascripts/bundle.5a2dcb6a.min.js.map create mode 100644 assets/javascripts/extra/bundle.5f09fbc3.min.js create mode 100644 assets/javascripts/extra/bundle.5f09fbc3.min.js.map create mode 100644 assets/javascripts/lunr/min/lunr.ar.min.js create mode 100644 assets/javascripts/lunr/min/lunr.da.min.js create mode 100644 assets/javascripts/lunr/min/lunr.de.min.js create mode 100644 assets/javascripts/lunr/min/lunr.du.min.js create mode 100644 assets/javascripts/lunr/min/lunr.es.min.js create mode 100644 assets/javascripts/lunr/min/lunr.fi.min.js create mode 100644 assets/javascripts/lunr/min/lunr.fr.min.js create mode 100644 assets/javascripts/lunr/min/lunr.hi.min.js create mode 100644 assets/javascripts/lunr/min/lunr.hu.min.js create mode 100644 assets/javascripts/lunr/min/lunr.it.min.js create mode 100644 assets/javascripts/lunr/min/lunr.ja.min.js create mode 100644 assets/javascripts/lunr/min/lunr.jp.min.js create mode 100644 assets/javascripts/lunr/min/lunr.ko.min.js create mode 100644 assets/javascripts/lunr/min/lunr.multi.min.js create mode 100644 assets/javascripts/lunr/min/lunr.nl.min.js create mode 100644 assets/javascripts/lunr/min/lunr.no.min.js create mode 100644 assets/javascripts/lunr/min/lunr.pt.min.js create mode 100644 assets/javascripts/lunr/min/lunr.ro.min.js create mode 100644 assets/javascripts/lunr/min/lunr.ru.min.js create mode 100644 assets/javascripts/lunr/min/lunr.stemmer.support.min.js create mode 100644 assets/javascripts/lunr/min/lunr.sv.min.js create mode 100644 assets/javascripts/lunr/min/lunr.ta.min.js create mode 100644 assets/javascripts/lunr/min/lunr.th.min.js create mode 100644 assets/javascripts/lunr/min/lunr.tr.min.js create mode 100644 assets/javascripts/lunr/min/lunr.vi.min.js create mode 100644 assets/javascripts/lunr/min/lunr.zh.min.js create mode 100644 assets/javascripts/lunr/tinyseg.js create mode 100644 assets/javascripts/lunr/wordcut.js create mode 100644 assets/javascripts/workers/search.16e2a7d4.min.js create mode 100644 assets/javascripts/workers/search.16e2a7d4.min.js.map create mode 100644 assets/stylesheets/extra.0d2c79a8.min.css create mode 100644 assets/stylesheets/extra.0d2c79a8.min.css.map create mode 100644 assets/stylesheets/main.975780f9.min.css create mode 100644 assets/stylesheets/main.975780f9.min.css.map create mode 100644 assets/stylesheets/palette.2505c338.min.css create mode 100644 assets/stylesheets/palette.2505c338.min.css.map create mode 100644 benchmark.html create mode 100644 contributing/contributing.md create mode 100644 contributing/index.html create mode 100644 img/favicon.ico create mode 100644 img/logo.png create mode 100644 index.html create mode 100644 index.md create mode 100644 intro/index.html create mode 100644 intro/intro.md create mode 100644 item_endpoints/index.html create mode 100644 item_endpoints/item_endpoints.md create mode 100644 mosaic_endpoints/index.html create mode 100644 mosaic_endpoints/mosaic_endpoints.md create mode 100644 notebooks/demo/demo.ipynb create mode 100644 notebooks/demo/index.html create mode 100644 release-notes/index.html create mode 100644 release-notes/release-notes.md create mode 100644 search/search_index.json create mode 100644 sitemap.xml create mode 100644 sitemap.xml.gz create mode 100644 tiler_factories/index.html create mode 100644 tiler_factories/tiler_factories.md create mode 100644 tms_endpoints/index.html create mode 100644 tms_endpoints/tms_endpoints.md diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 0000000..e69de29 diff --git a/404.html b/404.html new file mode 100644 index 0000000..dbc4531 --- /dev/null +++ b/404.html @@ -0,0 +1,599 @@ + + + +
+ + + + + + + + + + + + + +Even though TiTiler.PgSTAC
includes default FastAPI application,
+it also can be used like a library if you want to extend or
+override default behavior.
Let's look at one such example. Imagine that we use JSON Web Token (JWT) +based approach for authorization and every token contains information +about area a user has access to:
+{
+ "sub": "1234567890",
+ "name": "John Doe",
+ "iat": 1516239022,
+ "scope": "zone_A"
+}
+
We want our application to take this information into account while +registering a search query. It can be done in the following way:
+from contextlib import asynccontextmanager
+
+from typing import Tuple
+import json
+import jwt
+from fastapi import FastAPI
+from fastapi.security.utils import get_authorization_scheme_param
+from starlette.requests import Request
+from titiler.pgstac.factory import MosaicTilerFactory
+from titiler.pgstac.model import RegisterMosaic, Metadata, PgSTACSearch
+from titiler.pgstac.db import close_db_connection, connect_to_db
+
+@asynccontextmanager
+async def lifespan(app: FastAPI):
+ """FastAPI Lifespan."""
+ # Create Connection Pool
+ await connect_to_db(app, settings=postgres_settings)
+ yield
+ # Close the Connection Pool
+ await close_db_connection(app)
+
+app = FastAPI(lifespan=lifespan)
+
+AREAS = {
+ "zone_A": {"type": "Point", "coordinates": [-41.93, -12.76]},
+ "zone_B": {"type": "Point", "coordinates": [2.15, 41.39]},
+}
+
+
+def search_factory(request: Request, body: RegisterMosaic) -> Tuple[PgSTACSearch, Metadata]:
+ authorization = request.headers.get("Authorization")
+ scheme, token = get_authorization_scheme_param(authorization)
+ payload = jwt.decode(token, algorithms=["HS256"], key="your-256-bit-secret")
+
+ search = body.dict(exclude_none=True, exclude={"metadata"}, by_alias=True)
+ search["filter"] = {
+ "op": "and",
+ "args": [
+ {
+ "op": "s_intersects",
+ "args": [{"property": "geometry"}, AREAS[payload["scope"]]],
+ },
+ search["filter"],
+ ],
+ }
+
+ return model.PgSTACSearch(**search), body.metadata
+
+
+mosaic = MosaicTilerFactory(search_dependency=search_factory)
+app.include_router(mosaic.router)
+
Checking:
+$ curl -s -X 'POST' \
+ 'http://localhost:8081/register' \
+ -H 'accept: application/json' \
+ -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyLCJzY29wZSI6InpvbmVfQSJ9.BelzluX7v7kYObix2KSyy1T5gEOQYQn_pyNO5Ri0gWo' \
+ -H 'Content-Type: application/json' \
+ -d '{"filter":{"op":"and","args":[{"op":"=","args":[{"property":"collection"},"l1"]}]}}' | jq '.searchid'
+"bbc3c8f4c392436f74de6cd0308469f6"
+
+$ curl -X 'GET' \
+ 'http://localhost:8081/bbc3c8f4c392436f74de6cd0308469f6/info' \
+ -H 'accept: application/json'
+{"hash":"bbc3c8f4c392436f74de6cd0308469f6","search":{"filter":{"op":"and","args":[{"op":"s_intersects","args":[{"property":"geometry"},{"type":"Point","coordinates":[-41.93,-12.76]}]},{"op":"and","args":[{"op":"=","args":[{"property":"collection"},"l1"]}]}]}},"_where":"( ( st_intersects(geometry, '0101000020E6100000D7A3703D0AF744C085EB51B81E8529C0'::geometry) and ( (collection_id = 'l1') ) ) ) ","orderby":"datetime DESC, id DESC","lastused":"2022-02-23T13:00:04.090757+00:00","usecount":3,"metadata":{"type":"mosaic"}}
+
Goal: enable users to select a predefined configuration stored in the mosaic Metadata.
+import sys
+from typing import Optional
+from dataclasses import dataclass
+
+from morecantile import TileMatrixSet
+from titiler.core.resources.enums import ImageType
+from titiler.core.models.mapbox import TileJSON
+from titiler.pgstac import factory as TitilerPgSTACFactory
+from titiler.pgstac.dependencies import PgSTACParams
+
+from fastapi import Depends, Query
+
+from starlette.requests import Request
+
+if sys.version_info >= (3, 9):
+ from typing import Annotated # pylint: disable=no-name-in-module
+else:
+ from typing_extensions import Annotated
+
+
+@dataclass
+class MosaicTilerFactory(TitilerPgSTACFactory.MosaicTilerFactory):
+ """Custom factory."""
+
+ def _tilejson_routes(self) -> None:
+ """Custom TileJSON endpoint."""
+
+ @self.router.get(
+ "/{searchid}/tilejson.json",
+ response_model=TileJSON,
+ responses={200: {"description": "Return a tilejson"}},
+ response_model_exclude_none=True,
+ )
+ @self.router.get(
+ "/{searchid}/{tileMatrixSetId}/tilejson.json",
+ response_model=TileJSON,
+ responses={200: {"description": "Return a tilejson"}},
+ response_model_exclude_none=True,
+ )
+ def tilejson(
+ request: Request,
+ searchid=Depends(self.path_dependency),
+ tileMatrixSetId: Annotated[ # type: ignore
+ Literal[tuple(self.supported_tms.list())],
+ f"Identifier selecting one of the TileMatrixSetId supported (default: '{self.default_tms}')",
+ ] = self.default_tms,
+ layer: Annotated[
+ str,
+ Query(description="Name of default configuration"),
+ ] = None,
+ tile_format: Annotated[
+ Optional[ImageType],
+ Query(
+ description="Default will be automatically defined if the output image needs a mask (png) or not (jpeg).",
+ ),
+ ] = None,
+ tile_scale: Annotated[
+ Optional[int],
+ Query(
+ gt=0, lt=4, description="Tile size scale. 1=256x256, 2=512x512..."
+ ),
+ ] = None,
+ minzoom: Annotated[
+ Optional[int],
+ Query(description="Overwrite default minzoom."),
+ ] = None,
+ maxzoom: Annotated[
+ Optional[int],
+ Query(description="Overwrite default maxzoom."),
+ ] = None,
+ layer_params=Depends(self.layer_dependency),
+ dataset_params=Depends(self.dataset_dependency),
+ pixel_selection=Depends(self.pixel_selection_dependency),
+ buffer: Annotated[
+ Optional[float],
+ Query(
+ gt=0,
+ title="Tile buffer.",
+ description="Buffer on each side of the given tile. It must be a multiple of `0.5`. Output **tilesize** will be expanded to `tilesize + 2 * buffer` (e.g 0.5 = 257x257, 1.0 = 258x258).",
+ ),
+ ] = None,
+ post_process=Depends(self.process_dependency),
+ rescale=Depends(self.rescale_dependency),
+ color_formula: Annotated[
+ Optional[str],
+ Query(
+ title="Color Formula",
+ description="rio-color formula (info: https://github.com/mapbox/rio-color)",
+ ),
+ ] = None,
+ colormap=Depends(self.colormap_dependency),
+ render_params=Depends(self.render_dependency),
+ pgstac_params: PgSTACParams = Depends(),
+ backend_params=Depends(self.backend_dependency),
+ reader_params=Depends(self.reader_dependency),
+ ):
+ """Return TileJSON document for a SearchId."""
+ with request.app.state.dbpool.connection() as conn:
+ with conn.cursor(row_factory=class_row(model.Search)) as cursor:
+ cursor.execute(
+ "SELECT * FROM searches WHERE hash=%s;",
+ (searchid,),
+ )
+ search_info = cursor.fetchone()
+ if not search_info:
+ raise KeyError(f"search {searchid} not found")
+
+ route_params = {
+ "searchid": search_info.id,
+ "z": "{z}",
+ "x": "{x}",
+ "y": "{y}",
+ "tileMatrixSetId": tileMatrixSetId,
+ }
+ if tile_scale:
+ route_params["scale"] = tile_scale
+ if tile_format:
+ route_params["format"] = tile_format.value
+
+ tiles_url = self.url_for(request, "tile", **route_params)
+
+ qs_key_to_remove = [
+ "tilematrixsetid",
+ "tile_format",
+ "tile_scale",
+ "minzoom",
+ "maxzoom",
+ "layer",
+ ]
+ qs = [
+ (key, value)
+ for (key, value) in request.query_params._list
+ if key.lower() not in qs_key_to_remove
+ ]
+
+ if layer:
+ config = search_info.defaults.get(layer)
+ if not config:
+ raise HTTPException(status_code=404, detail=f"Invalid {layer} configuration.")
+
+ # This assume the default configuration follows the endpoint expected format
+ # as `"true_color": [("assets", "B4"), ("assets", "B3"), ("assets", "B2")]`
+ qs = QueryParams(config)
+
+ if qs:
+ tiles_url += f"?{urlencode(qs)}"
+
+ minzoom = _first_value([minzoom, search_info.metadata.minzoom], tms.minzoom)
+ maxzoom = _first_value([maxzoom, search_info.metadata.maxzoom], tms.maxzoom)
+ bounds = _first_value(
+ [search_info.input_search.get("bbox"), search_info.metadata.bounds],
+ tms.bbox,
+ )
+ return {
+ "bounds": bounds,
+ "minzoom": minzoom,
+ "maxzoom": maxzoom,
+ "name": search_info.metadata.name or search_info.id,
+ "tiles": [tiles_url],
+ }
+
Starting with version 0.1.0a7
we've added a feature()
method to the Mosaic backend which enable reading geojson defined shape for a mosaic (used for the /statistics
endpoint).
Here is how you can customize MosaicTilerFactory
to add a proper feature endpoint which return an image to the MosaicTilerFactory
.
Important
+The feature
method could need to open a lot of items/assets to construct the image, which can impact the performance.
import os
+import sys
+from typing import Optional
+from dataclasses import dataclass
+
+from geojson_pydantic import Feature
+from rio_tiler.constants import MAX_THREADS
+
+from titiler.core.factory import img_endpoint_params
+from titiler.core.resources.enums import ImageType, OptionalHeader
+from titiler.pgstac import factory as TitilerPgSTACFactory
+from titiler.pgstac.dependencies import PgSTACParams
+
+from fastapi import Body, Depends, Query
+
+from starlette.requests import Request
+from starlette.responses import Response
+
+if sys.version_info >= (3, 9):
+ from typing import Annotated # pylint: disable=no-name-in-module
+else:
+ from typing_extensions import Annotated
+
+
+@dataclass
+class MosaicTilerFactory(TitilerPgSTACFactory.MosaicTilerFactory):
+ """Custom endpoints factory."""
+
+ def register_routes(self) -> None:
+ """This Method register routes to the router."""
+ super().register_routes()
+
+ # POST endpoints
+ @self.router.post(
+ "/{searchid}/feature", **img_endpoint_params,
+ )
+ @self.router.post(
+ "/{searchid}/feature.{format}", **img_endpoint_params,
+ )
+ def geojson_crop(
+ request: Request,
+ geojson: Annotated[
+ Feature,
+ Body(description="GeoJSON Feature."),
+ ],
+ searchid=Depends(self.path_dependency),
+ format: Annotated[
+ ImageType,
+ "Default will be automatically defined if the output image needs a mask (png) or not (jpeg).",
+ ] = None,
+ layer_params=Depends(self.layer_dependency),
+ dataset_params=Depends(self.dataset_dependency),
+ pixel_selection=Depends(self.pixel_selection_dependency),
+ buffer: Annotated[
+ Optional[float],
+ Query(
+ gt=0,
+ title="Tile buffer.",
+ description="Buffer on each side of the given tile. It must be a multiple of `0.5`. Output **tilesize** will be expanded to `tilesize + 2 * buffer` (e.g 0.5 = 257x257, 1.0 = 258x258).",
+ ),
+ ] = None,
+ post_process=Depends(self.process_dependency),
+ rescale=Depends(self.rescale_dependency),
+ color_formula: Annotated[
+ Optional[str],
+ Query(
+ title="Color Formula",
+ description="rio-color formula (info: https://github.com/mapbox/rio-color)",
+ ),
+ ] = None,
+ colormap=Depends(self.colormap_dependency),
+ render_params=Depends(self.render_dependency),
+ pgstac_params: PgSTACParams = Depends(),
+ backend_params=Depends(self.backend_dependency),
+ reader_params=Depends(self.reader_dependency),
+ env=Depends(self.environment_dependency),
+ ):
+ """Create image from a geojson feature."""
+ threads = int(os.getenv("MOSAIC_CONCURRENCY", MAX_THREADS))
+
+ with rasterio.Env(**self.gdal_config):
+ with self.reader(
+ searchid,
+ reader_options={**reader_params},
+ **backend_params,
+ ) as src_dst:
+ image, assets = src_dst.feature(
+ geojson.dict(exclude_none=True),
+ pixel_selection=pixel_selection.method(),
+ threads=threads,
+ max_size=max_size,
+ **layer_params,
+ **dataset_params,
+ **pgstac_params,
+ )
+
+ if post_process:
+ image = post_process(image)
+
+ if rescale:
+ image.rescale(rescale)
+
+ if color_formula:
+ image.apply_color_formula(color_formula)
+
+ if colormap:
+ image = image.apply_colormap(colormap)
+
+ if not format:
+ format = ImageType.jpeg if image.mask.all() else ImageType.png
+
+ content = image.render(
+ img_format=format.driver,
+ **format.profile,
+ **render_params,
+ )
+
+ headers: Dict[str, str] = {}
+ if OptionalHeader.x_assets in self.optional_headers:
+ ids = [x["id"] for x in assets]
+ headers["X-Assets"] = ",".join(ids)
+
+ return Response(content, media_type=format.mediatype, headers=headers)
+
TiTiler-PgSTAC
uses PgSTAC search to host mosaic parameters for performance purposes. To help users we added the possibility to add metadata
to search entries and in TiTiler-PgSTAC
we introduced a non-official
specification to help user storing meaningful informations.
{
+ // OPTIONAL. Default: "mosaic" (No other value accepted for now). Describe the `type` of metadata.
+ "type": "mosaic",
+
+ // OPTIONAL. Default: null.
+ // The maximum extent of available map tiles. The bounds are represented in WGS:84
+ // latitude and longitude values, in the order left, bottom, right, top.
+ // Values may be integers or floating point numbers.
+ "bounds": [ -180, -85.05112877980659, 180, 85.0511287798066 ],
+
+ // OPTIONAL. Default: null.
+ // An integer specifying the minimum zoom level.
+ "minzoom": 0,
+
+ // OPTIONAL. Default: null.
+ // An integer specifying the maximum zoom level. MUST be >= minzoom.
+ "maxzoom": 11,
+
+ // OPTIONAL. Default: null. The name can contain any legal character.
+ "name": "compositing",
+
+ // OPTIONAL. Default: null. An array of available assets.
+ "assets": ["image", "cog"],
+
+ // OPTIONAL. Default: null. A set of `defaults` configuration to be forwarded to the /tiles endpoints.
+ "defaults": {
+ "true_color": {
+ "assets": ["B4", "B3", "B2"],
+ "color_formula": "Gamma RGB 3.5 Saturation 1.7 Sigmoidal RGB 15 0.35",
+ },
+ "ndvi": {
+ "expression": "(B4-B3)/(B4+B3)",
+ "rescale": "-1,1",
+ "colormap_name": "viridis"
+ }
+ }
+}
+
Important
+/mosaic/register
endpoint, {"type": "mosaic"}
will be set by defaultcurl -X 'POST' 'http://127.0.0.1:8081/mosaic/register' -H 'accept: application/json' -H 'Content-Type: application/json' -d '{"filter": {"op": "=", "args": [{"property": "collection"}, "landsat-c2l2-sr"]}, "metadata": {"name": "landsat mosaic"}}'
+>> {
+ "searchid": "d7fcdefd0457c949ea7a6192bc2c7122",
+ "links": [
+ {
+ "rel": "metadata",
+ "type": "application/json",
+ "href": "http://127.0.0.1:8081/mosaic/d7fcdefd0457c949ea7a6192bc2c7122/info"
+ },
+ {
+ "rel": "tilejson",
+ "type": "application/json",
+ "href": "http://127.0.0.1:8081/mosaic/d7fcdefd0457c949ea7a6192bc2c7122/tilejson.json"
+ }
+ ]
+}
+
+curl http://127.0.0.1:8081/mosaic/d7fcdefd0457c949ea7a6192bc2c7122/info | jq '.search.metadata'
+>> {
+ "type": "mosaic",
+ "name": "landsat mosaic"
+}
+
curl -X 'POST' 'http://127.0.0.1:8081/mosaic/register' -H 'accept: application/json' -H 'Content-Type: application/json' -d '{"collections": ["noaa-emergency-response"], "bbox": [-87.0251, 36.0999, -85.4249, 36.2251], "filter-lang": "cql-json", "metadata": {"bounds": [-87.0251, 36.0999, -85.4249, 36.2251], "minzoom": 14, "maxzoom": 18, "assets": ["cog"], "defaults": {"true_color": {"bidx": [1, 2, 3]}}}}'
+>> {
+ "searchid":"4b0db3dbd1858d54a3a55f84de97d1ca",
+ "links":[
+ {
+ "rel": "metadata",
+ "type": "application/json",
+ "href": "http://127.0.0.1:8081/mosaic/4b0db3dbd1858d54a3a55f84de97d1ca/info"
+ },
+ {
+ "rel": "tilejson",
+ "type": "application/json",
+ "href": "http://127.0.0.1:8081/mosaic/4b0db3dbd1858d54a3a55f84de97d1ca/tilejson.json"
+ }
+ ]
+}
+
+curl http://127.0.0.1:8081/mosaic/4b0db3dbd1858d54a3a55f84de97d1ca/info | jq '.search.metadata'
+>> {
+ "type": "mosaic",
+ "bounds": [
+ -87.0251,
+ 36.0999,
+ -85.4249,
+ 36.2251
+ ],
+ "minzoom": 14,
+ "maxzoom": 18,
+ "assets": [
+ "cog"
+ ],
+ "defaults": {
+ "true_color": {
+ "bidx": [
+ 1,
+ 2,
+ 3
+ ]
+ }
+ }
+}
+
Starting with titiler-pgstac>=0.2.0
, we've added a /mosaic/list
endpoint to be able to list all registered mosaics. When we add a mosaic via /mosaic/register
we add a specific metadata.type: "mosaic"
to the pgstac search
entry, which is then used by the /mosaic/list
endpoint to filter the pgstac searches
.
In order to make the mosaic list performant, users might want to alter their PgSTAC database to add an index
+$ psql
+postgis=# SET schema 'pgstac';
+>> SET
+
+postgis=# CREATE INDEX IF NOT EXISTS searches_mosaic ON searches ((true)) WHERE metadata->>'type'='mosaic';
+>> NOTICE: relation "searches_mosaic" already exists, skipping
+>> CREATE INDEX
+
+postgis=# SELECT
+ indexname,
+ indexdef
+FROM
+ pg_indexes
+WHERE
+ tablename = 'searches';
+
+>> indexname | indexdef
+>> -----------------+---------------------------------------------------------------------------------------------------------------------------
+>> searches_pkey | CREATE UNIQUE INDEX searches_pkey ON pgstac.searches USING btree (hash)
+>> searches_mosaic | CREATE INDEX searches_mosaic ON pgstac.searches USING btree ((true)) WHERE ((metadata ->> 'type'::text) = 'mosaic'::text)
+
ref: github.com/developmentseed/eoAPI/blob/master/stack/handlers/db_handler.py#L204-L213
+ + + + + + +\n {translation(\"search.result.term.missing\")}: {...missing}\n
\n }\n