Skip to content

Commit

Permalink
OGC Coverages: Content-Bbox & Content-Crs headers
Browse files Browse the repository at this point in the history
The main coverages endpoint now includes the required Content-Bbox
and Content-Crs headers in its response.
  • Loading branch information
pont-us committed Nov 24, 2023
1 parent 71dd987 commit 8c32ba6
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 14 deletions.
26 changes: 16 additions & 10 deletions xcube/webapi/ows/coverages/controllers.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ def get_coverage_data(
collection_id: str,
query: Mapping[str, Sequence[str]],
content_type: str,
) -> Optional[bytes]:
) -> tuple[Optional[bytes], list[float], pyproj.CRS]:
"""
Return coverage data from a dataset
Expand Down Expand Up @@ -183,11 +183,11 @@ def get_coverage_data(
netcdf={'netcdf', 'application/netcdf', 'application/x-netcdf'},
)
if content_type in media_types['tiff']:
return dataset_to_image(ds, 'tiff')
content = dataset_to_image(ds, 'tiff')
elif content_type in media_types['png']:
return dataset_to_image(ds, 'png')
content = dataset_to_image(ds, 'png')
elif content_type in media_types['netcdf']:
return dataset_to_netcdf(ds)
content = dataset_to_netcdf(ds)
else:
# It's expected that the caller (server API handler) will catch
# unhandled types, but we may as well do the right thing if any
Expand All @@ -199,6 +199,8 @@ def get_coverage_data(
[type_ for value in media_types.values() for type_ in value]
)
)
final_bbox = get_bbox_from_ds(ds)
return content, final_bbox, final_crs


def _assert_coverage_size_ok(ds):
Expand Down Expand Up @@ -317,12 +319,7 @@ def _apply_geographic_subsetting(
# 1. transform native extent to a whole-dataset bbox in subset_crs.
# We'll use this to fill in "full extent" values if geographic
# subsetting is only specified in one dimension.
h_dim = _get_h_dim(ds)
v_dim = _get_v_dim(ds)
full_bbox_native = list(
map(float, [ds[h_dim][0], ds[v_dim][0], ds[h_dim][-1], ds[v_dim][-1]])
)
_ensure_bbox_y_ascending(full_bbox_native)
full_bbox_native = get_bbox_from_ds(ds)
native_crs = get_crs_from_dataset(ds)
full_bbox_subset_crs = _transform_bbox(
full_bbox_native, native_crs, subset_crs
Expand Down Expand Up @@ -354,6 +351,8 @@ def _apply_geographic_subsetting(
bbox_native_crs = _transform_bbox(bbox_subset_crs, subset_crs, native_crs)

# 6. Apply the dataset-native bbox using sel.
h_dim = _get_h_dim(ds)
v_dim = _get_v_dim(ds)
ds = ds.sel(
indexers={
h_dim: slice(bbox_native_crs[0], bbox_native_crs[2]),
Expand All @@ -367,6 +366,13 @@ def _apply_geographic_subsetting(
return bbox_subset_crs, ds


def get_bbox_from_ds(ds: xr.Dataset):
h, v = ds[_get_h_dim(ds)], ds[_get_v_dim(ds)]
bbox = list(map(float, [h[0], v[0], h[-1], v[-1]]))
_ensure_bbox_y_ascending(bbox)
return bbox


def _find_geographic_parameters(
names: list[str],
) -> tuple[Optional[str], Optional[str]]:
Expand Down
9 changes: 8 additions & 1 deletion xcube/webapi/ows/coverages/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ async def get(self, collectionId: str):
# TODO: support covjson
]
content_type = negotiate_content_type(self.request, available_types)
content_bbox = content_crs = None
if content_type is None:
raise ApiError.UnsupportedMediaType(
f'Available media types: {", ".join(available_types)}\n'
Expand All @@ -90,10 +91,16 @@ async def get(self, collectionId: str):
elif content_type in {'application/json', 'json'}:
result = get_coverage_as_json(ds_ctx, collectionId)
else:
result = get_coverage_data(
result, content_bbox, content_crs = get_coverage_data(
ds_ctx, collectionId, self.request.query, content_type
)
# TODO Add Content-Bbox and Content-Crs headers
self.response.set_header(
'Content-Bbox', ','.join(map(str, content_bbox))
)
self.response.set_header(
'Content-Crs', f'[{content_crs.to_string()}]'
)
return await self.response.finish(result, content_type=content_type)


Expand Down
4 changes: 1 addition & 3 deletions xcube/webapi/ows/stac/controllers.py
Original file line number Diff line number Diff line change
Expand Up @@ -542,9 +542,7 @@ def _crs_to_uri_or_wkt(crs: pyproj.CRS) -> str:
auth_and_code = crs.to_authority()
if auth_and_code is not None:
authority, code = auth_and_code
# TODO check appropriate version for EPSG: 9.9.1 is available,
# but Testbed-19 participants seem to prefer 0.
version = dict(OGC='1.3', IAU='2015', EPSG='0').get(authority, '0')
version = 0 # per https://docs.ogc.org/pol/09-048r6.html#toc13
return (f'http://www.opengis.net/def/crs/'
f'{authority}/{version}/{code}')
else:
Expand Down

0 comments on commit 8c32ba6

Please sign in to comment.