Skip to content

Commit

Permalink
Smarter bounding box generation for bounding box generation (#1086)
Browse files Browse the repository at this point in the history
* Be cleverer about bounding box calculations.

* Be cleverer about bounding box calculations.

* Mypy appeasement.
  • Loading branch information
SpacemanPaul authored Nov 15, 2024
1 parent 919a987 commit 6d731b0
Showing 1 changed file with 62 additions and 25 deletions.
87 changes: 62 additions & 25 deletions datacube_ows/index/postgis/product_ranges.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,25 +155,10 @@ def create_range_entry(layer: OWSNamedLayer, cache: dict[LayerSignature, list[st
# calculate bounding boxes
# Get extent polygon from materialised views

base_crs = CRS(layer.native_CRS)
base_extent = None
for product in layer.products:
prod_extent = layer.dc.index.products.spatial_extent(product, base_crs)
if prod_extent is None:
# Workaround - this should be handled in core.
prod_extent = layer.dc.index.products.spatial_extent(product)
if prod_extent is not None:
prod_extent = prod_extent.to_crs(base_crs)
if base_extent is None:
base_extent = prod_extent
else:
base_extent = base_extent | prod_extent
if base_extent is None:
click.echo(f"Layer {layer.name} has no extent in CRS {base_crs}. Skipping.")
all_bboxes = build_bboxes(layer)
if not all_bboxes:
return

all_bboxes = bbox_projections(base_extent, layer.global_cfg.crses)

conn.execute(text("""
UPDATE ows.layer_ranges
SET bboxes = :bbox,
Expand All @@ -197,6 +182,43 @@ def create_range_entry(layer: OWSNamedLayer, cache: dict[LayerSignature, list[st
conn.close()


def build_bboxes(layer: OWSNamedLayer) -> dict[str, dict[str, float]]:
# User native CRS for base extent, unless no spatial index for it, in which case
# use 4326 which always has a spatial index.
base_crs = CRS(layer.native_CRS)
if base_crs not in layer.dc.index.spatial_indexes():
base_crs = CRS("epsg:4326")
base_extent = extent_for_layer(layer, base_crs)
if base_extent is None:
click.echo(f"Layer {layer.name} has no extent in CRS {base_crs}. Skipping.")
return {}
result = {}
for crsid, crs in layer.global_config().crses.items():
if crs == base_crs:
result[crsid] = sanitise_bbox(base_extent.boundingbox)
elif crs in layer.dc.index.spatial_indexes():
extent = extent_for_layer(layer, crs)
if extent is None:
click.echo(f"Layer {layer.name} has no extent in CRS {crs}. Skipping.")
return {}
result[crsid] = sanitise_bbox(extent.boundingbox)
else:
extent = base_extent.to_crs(crs)
result[crsid] = sanitise_bbox(extent.boundingbox)
return result


def extent_for_layer(layer: OWSNamedLayer, crs: CRS) -> odc.geo.Geometry | None:
ext = None
for product in layer.products:
prod_extent = layer.dc.index.products.spatial_extent(product, crs)
if ext is None:
ext = prod_extent
else:
ext = ext | prod_extent
return ext


def bbox_projections(starting_box: odc.geo.Geometry, crses: dict[str, odc.geo.CRS]) -> dict[str, dict[str, float]]:
result = {}
for crsid, crs in crses.items():
Expand All @@ -206,14 +228,29 @@ def bbox_projections(starting_box: odc.geo.Geometry, crses: dict[str, odc.geo.CR


def sanitise_bbox(bbox: odc.geo.geom.BoundingBox) -> dict[str, float]:
def sanitise_coordinate(coord: float, fallback: float) -> float:
return coord if math.isfinite(coord) else fallback
return {
"top": sanitise_coordinate(bbox.top, float("9.999999999e99")),
"bottom": sanitise_coordinate(bbox.bottom, float("-9.999999999e99")),
"left": sanitise_coordinate(bbox.left, float("-9.999999999e99")),
"right": sanitise_coordinate(bbox.right, float("9.999999999e99")),
}
def sanitise_coordinate(coord: float, fallback: float, upper: bool) -> float:
if not math.isfinite(coord):
return fallback
elif upper and coord > fallback:
return fallback
elif not upper and coord < fallback:
return fallback
else:
return coord
if bbox.crs == CRS("epsg:4326"):
return {
"top": sanitise_coordinate(bbox.top, float("90.0"), True),
"bottom": sanitise_coordinate(bbox.bottom, float("-90.0"), False),
"left": sanitise_coordinate(bbox.left, float("-180"), False),
"right": sanitise_coordinate(bbox.right, float("9.999999999e99"), True),
}
else:
return {
"top": sanitise_coordinate(bbox.top, float("9.999999999e99"), True),
"bottom": sanitise_coordinate(bbox.bottom, float("-9.999999999e99"), False),
"left": sanitise_coordinate(bbox.left, float("-9.999999999e99"), False),
"right": sanitise_coordinate(bbox.right, float("9.999999999e99"), True),
}


def get_ranges(layer: OWSNamedLayer) -> LayerExtent | None:
Expand Down

0 comments on commit 6d731b0

Please sign in to comment.