POC for HRRR data
This commit is contained in:
Родитель
d2b46c9ae8
Коммит
db28c1439c
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -1,15 +1,21 @@
|
|||
import dataclasses
|
||||
import logging
|
||||
from typing import Annotated, Optional
|
||||
from typing import Annotated, Literal, Optional, List, Type
|
||||
from urllib.parse import quote_plus, urljoin
|
||||
|
||||
import fastapi
|
||||
from pydantic import conint
|
||||
import pystac
|
||||
from fastapi import Body, Depends, Query, Request, Response
|
||||
from fastapi import Body, Depends, Path, Query, Request, Response
|
||||
from fastapi.templating import Jinja2Templates
|
||||
from geojson_pydantic.features import Feature
|
||||
from html_sanitizer.sanitizer import Sanitizer
|
||||
from starlette.responses import HTMLResponse
|
||||
from titiler.core.dependencies import CoordCRSParams, DstCRSParams
|
||||
from titiler.core.dependencies import (
|
||||
CoordCRSParams,
|
||||
DstCRSParams,
|
||||
DefaultDependency,
|
||||
)
|
||||
from titiler.core.factory import MultiBaseTilerFactory, img_endpoint_params
|
||||
from titiler.core.resources.enums import ImageType
|
||||
from titiler.pgstac.dependencies import get_stac_item
|
||||
|
@ -29,6 +35,26 @@ except ImportError:
|
|||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@dataclasses.dataclass
|
||||
class SubdatasetParams(DefaultDependency):
|
||||
"""Assets, Expression and Asset's band Indexes parameters."""
|
||||
|
||||
subdataset_name: Annotated[
|
||||
Optional[str],
|
||||
Query(
|
||||
title="Subdataset name",
|
||||
description="The name of a subdataset within the asset.",
|
||||
),
|
||||
] = None
|
||||
subdataset_bands: Annotated[
|
||||
Optional[List[int]],
|
||||
Query(
|
||||
title="Subdataset bands",
|
||||
description="The name of a subdataset within the asset.",
|
||||
),
|
||||
] = None
|
||||
|
||||
|
||||
def ItemPathParams(
|
||||
request: Request,
|
||||
collection: str = Query(..., description="STAC Collection ID"),
|
||||
|
@ -44,7 +70,91 @@ templates = Jinja2Templates(
|
|||
)
|
||||
|
||||
|
||||
pc_tile_factory = MultiBaseTilerFactory(
|
||||
@dataclasses.dataclass
|
||||
class MyMultiBaseTilerFactory(MultiBaseTilerFactory):
|
||||
subdataset_dependency: Type[DefaultDependency] = SubdatasetParams
|
||||
private_router: fastapi.APIRouter = dataclasses.field(
|
||||
default_factory=fastapi.APIRouter
|
||||
)
|
||||
|
||||
def tile(self): # noqa: C901
|
||||
"""Register /tiles endpoint."""
|
||||
|
||||
@self.router.get(r"/tiles/{z}/{x}/{y}", **img_endpoint_params, deprecated=True)
|
||||
@self.router.get(
|
||||
r"/tiles/{z}/{x}/{y}.{format}", **img_endpoint_params, deprecated=True
|
||||
)
|
||||
@self.router.get(
|
||||
r"/tiles/{z}/{x}/{y}@{scale}x", **img_endpoint_params, deprecated=True
|
||||
)
|
||||
@self.router.get(
|
||||
r"/tiles/{z}/{x}/{y}@{scale}x.{format}",
|
||||
**img_endpoint_params,
|
||||
deprecated=True,
|
||||
)
|
||||
@self.router.get(r"/tiles/{tileMatrixSetId}/{z}/{x}/{y}", **img_endpoint_params)
|
||||
@self.router.get(
|
||||
r"/tiles/{tileMatrixSetId}/{z}/{x}/{y}.{format}", **img_endpoint_params
|
||||
)
|
||||
@self.router.get(
|
||||
r"/tiles/{tileMatrixSetId}/{z}/{x}/{y}@{scale}x", **img_endpoint_params
|
||||
)
|
||||
@self.router.get(
|
||||
r"/tiles/{tileMatrixSetId}/{z}/{x}/{y}@{scale}x.{format}",
|
||||
**img_endpoint_params,
|
||||
)
|
||||
def tile(
|
||||
request: Request,
|
||||
z: Annotated[
|
||||
int,
|
||||
Path(
|
||||
description="Identifier (Z) selecting one of the scales defined in the TileMatrixSet and representing the scaleDenominator the tile.",
|
||||
),
|
||||
],
|
||||
x: Annotated[
|
||||
int,
|
||||
Path(
|
||||
description="Column (X) index of the tile on the selected TileMatrix. It cannot exceed the MatrixHeight-1 for the selected TileMatrix.",
|
||||
),
|
||||
],
|
||||
y: Annotated[
|
||||
int,
|
||||
Path(
|
||||
description="Row (Y) index of the tile on the selected TileMatrix. It cannot exceed the MatrixWidth-1 for the selected TileMatrix.",
|
||||
),
|
||||
],
|
||||
tileMatrixSetId: Annotated[
|
||||
Literal[tuple(self.supported_tms.list())],
|
||||
f"Identifier selecting one of the TileMatrixSetId supported (default: '{self.default_tms}')",
|
||||
] = self.default_tms,
|
||||
scale: Annotated[
|
||||
conint(gt=0, le=4), "Tile size scale. 1=256x256, 2=512x512..."
|
||||
] = 1,
|
||||
format: Annotated[
|
||||
ImageType,
|
||||
"Default will be automatically defined if the output image needs a mask (png) or not (jpeg).",
|
||||
] = None,
|
||||
src_path=Depends(self.path_dependency),
|
||||
layer_params=Depends(self.layer_dependency),
|
||||
dataset_params=Depends(self.dataset_dependency),
|
||||
tile_params=Depends(self.tile_dependency),
|
||||
post_process=Depends(self.process_dependency),
|
||||
rescale=Depends(self.rescale_dependency),
|
||||
color_formula=Depends(self.color_formula_dependency),
|
||||
colormap=Depends(self.colormap_dependency),
|
||||
render_params=Depends(self.render_dependency),
|
||||
reader_params=Depends(self.reader_dependency),
|
||||
env=Depends(self.environment_dependency),
|
||||
subdataset_params=Depends(self.subdataset_dependency),
|
||||
):
|
||||
endpoint = get_endpoint_function(
|
||||
self.private_router, path="/tiles/{z}/{x}/{y}", method=request.method
|
||||
)
|
||||
return endpoint(z, x, y, tileMatrixSetId, scale, format, src_path, layer_params, dataset_params, tile_params, post_process, rescale, color_formula, colormap, render_params, reader_params, env)
|
||||
|
||||
|
||||
|
||||
pc_tile_factory = MyMultiBaseTilerFactory(
|
||||
reader=ItemSTACReader,
|
||||
path_dependency=ItemPathParams,
|
||||
colormap_dependency=PCColorMapParams,
|
||||
|
@ -52,6 +162,15 @@ pc_tile_factory = MultiBaseTilerFactory(
|
|||
router_prefix=get_settings().item_endpoint_prefix,
|
||||
# We remove the titiler default `/map` viewer
|
||||
add_viewer=False,
|
||||
private_router=MultiBaseTilerFactory(
|
||||
reader=ItemSTACReader,
|
||||
path_dependency=ItemPathParams,
|
||||
colormap_dependency=PCColorMapParams,
|
||||
reader_dependency=ReaderParams,
|
||||
router_prefix=get_settings().item_endpoint_prefix,
|
||||
# We remove the titiler default `/map` viewer
|
||||
add_viewer=False,
|
||||
).router
|
||||
)
|
||||
|
||||
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import logging
|
||||
import time
|
||||
import urllib.parse
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Any, Dict, List, Optional, Tuple, Type
|
||||
from typing import Any, Dict, List, Optional, Set, Tuple, Type
|
||||
|
||||
import attr
|
||||
import morecantile
|
||||
|
@ -12,6 +13,7 @@ from geojson_pydantic import Polygon
|
|||
from rio_tiler.errors import InvalidAssetName, MissingAssets, TileOutsideBounds
|
||||
from rio_tiler.models import ImageData
|
||||
from rio_tiler.mosaic import mosaic_reader
|
||||
from rio_tiler.io.stac import DEFAULT_VALID_TYPE
|
||||
from rio_tiler.types import AssetInfo
|
||||
from starlette.requests import Request
|
||||
from titiler.core.dependencies import DefaultDependency
|
||||
|
@ -46,6 +48,9 @@ class ItemSTACReader(PgSTACReader):
|
|||
# We make request an optional attribute to avoid re-writing
|
||||
# the whole list of attribute
|
||||
request: Optional[Request] = attr.ib(default=None)
|
||||
include_asset_types: Set[str] = attr.ib(
|
||||
default=DEFAULT_VALID_TYPE | {"application/wmo-GRIB2"}
|
||||
)
|
||||
|
||||
def _get_asset_info(self, asset: str) -> AssetInfo:
|
||||
"""return asset's url."""
|
||||
|
@ -57,7 +62,19 @@ class ItemSTACReader(PgSTACReader):
|
|||
if render_config and render_config.requires_token:
|
||||
asset_url = pc.sign(asset_url)
|
||||
|
||||
info["url"] = asset_url
|
||||
vrt_params = {}
|
||||
|
||||
if subdataset_name := self.request.query_params.get("subdataset_name"):
|
||||
vrt_params["sd_name"] = subdataset_name
|
||||
|
||||
if subdataset_bands := self.request.query_params.getlist("subdataset_bands"):
|
||||
vrt_params["bands"] = ",".join([str(band) for band in subdataset_bands])
|
||||
|
||||
if vrt_params:
|
||||
params = urllib.parse.urlencode(vrt_params, safe=",")
|
||||
asset_url = f"vrt:///vsicurl/{asset_url}?{params}"
|
||||
|
||||
info = AssetInfo(url=asset_url)
|
||||
return info
|
||||
|
||||
|
||||
|
@ -90,7 +107,6 @@ class MosaicSTACReader(pgstac_mosaic.CustomSTACReader):
|
|||
if render_config and render_config.requires_token:
|
||||
asset_url = pc.sign(asset_url)
|
||||
|
||||
info = AssetInfo(url=asset_url)
|
||||
if "file:header_size" in self.input["assets"][asset]:
|
||||
info["env"] = {
|
||||
"GDAL_INGESTED_BYTES_AT_OPEN": self.input["assets"][asset][
|
||||
|
@ -98,6 +114,19 @@ class MosaicSTACReader(pgstac_mosaic.CustomSTACReader):
|
|||
]
|
||||
}
|
||||
|
||||
vrt_params = {}
|
||||
|
||||
if subdataset_name := self.request.query_params.get("subdataset_name"):
|
||||
vrt_params["sd_name"] = subdataset_name
|
||||
|
||||
if subdataset_bands := self.request.query_params.getlist("subdataset_bands"):
|
||||
vrt_params["bands"] = ",".join([str(band) for band in subdataset_bands])
|
||||
|
||||
if vrt_params:
|
||||
params = urllib.parse.urlencode(vrt_params, safe=",")
|
||||
asset_url = f"vrt:///vsicurl/{asset_url}?{params}"
|
||||
|
||||
info = AssetInfo(url=asset_url)
|
||||
return info
|
||||
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче