From d64f07ad9c6882b01b59a707c62c61721f4b9769 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 15 Jul 2026 19:01:11 +0200 Subject: [PATCH] Normalize DHMV tile mosaic resolution --- .../app/services/dhmv_acquisition_service.py | 35 +++++++++++++------ 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/backend/app/services/dhmv_acquisition_service.py b/backend/app/services/dhmv_acquisition_service.py index 818c282c..e410e019 100644 --- a/backend/app/services/dhmv_acquisition_service.py +++ b/backend/app/services/dhmv_acquisition_service.py @@ -349,7 +349,7 @@ class DhmvAcquisitionService: ) @staticmethod - def _mosaic_geotiffs(coverages: list[bytes]) -> bytes: + def _mosaic_geotiffs(coverages: list[bytes], expected_resolution_m: float | None = None) -> bytes: if len(coverages) == 1: return coverages[0] try: @@ -367,20 +367,35 @@ class DhmvAcquisitionService: sources = [] try: sources = [memory.open() for memory in memories] - crs_values = {str(source.crs) for source in sources} - band_counts = {source.count for source in sources} - resolutions = { - (round(abs(float(source.res[0])), 6), round(abs(float(source.res[1])), 6)) - for source in sources - } - if crs_values != {DhmvAcquisitionService.SOURCE_CRS} or band_counts != {1} or len(resolutions) != 1: + target_resolution = float(expected_resolution_m or abs(float(sources[0].res[0]))) + invalid_crs = [index for index, source in enumerate(sources) if source.crs is None or source.crs.to_epsg() != 31370] + invalid_bands = [index for index, source in enumerate(sources) if source.count != 1] + invalid_resolution = [ + { + "tile_index": index, + "resolution": [abs(float(source.res[0])), abs(float(source.res[1]))], + } + for index, source in enumerate(sources) + if not all( + math.isclose(abs(float(value)), target_resolution, rel_tol=0.02, abs_tol=0.05) + for value in source.res + ) + ] + if invalid_crs or invalid_bands or invalid_resolution: raise AppError( code="DHMV_TILE_MISMATCH", - message="DHMV coverage tiles do not share one CRS, band layout and resolution", + message="DHMV coverage tiles do not match the governed CRS, band layout and resolution", + details={ + "invalid_crs_tile_indexes": invalid_crs, + "invalid_band_tile_indexes": invalid_bands, + "invalid_resolution_tiles": invalid_resolution, + "expected_resolution_m": target_resolution, + }, status_code=502, ) mosaic, transform = merge( sources, + res=(target_resolution, target_resolution), nodata=DhmvAcquisitionService.NODATA, dtype="float32", ) @@ -456,7 +471,7 @@ class DhmvAcquisitionService: coverage_hash.update(coverage_content) content_types.append(content_type) coverages.append(coverage_content) - return DhmvAcquisitionService._mosaic_geotiffs(coverages), { + return DhmvAcquisitionService._mosaic_geotiffs(coverages, prepared["resolution_m"]), { "tile_count": len(request_urls), "request_urls": request_urls, "response_content_types": content_types,