fix(map): exclude high-resolution rasters from overview
This commit is contained in:
@@ -10990,3 +10990,20 @@ Remaining in this pass:
|
||||
- run the complete readiness gate, deploy the immutable revision and repeat
|
||||
both the large overview rectangle and a regional partitioned rectangle in
|
||||
the live browser.
|
||||
|
||||
## 2026-07-21 - Persisted raster scale guard
|
||||
|
||||
Live verification of the first scale-aware release showed that on-demand
|
||||
provider fan-out was resolved, but already persisted 5 m terrain and flood
|
||||
rasters could still enter a Belgium-scale analysis. The shared selection guard
|
||||
now applies the same real pixel budgets to persisted rasters: country-scale
|
||||
overview analysis keeps PostGIS vector and national statistical sources, while
|
||||
high-resolution rasters require detail or safely bounded regional extent.
|
||||
|
||||
Validation:
|
||||
|
||||
- frontend typecheck, 29 unit tests and the production build passed;
|
||||
- the map acquisition, component-boundary and density regression contracts
|
||||
passed (12 tests);
|
||||
- live redeployment and a repeated Belgium-scale rectangle follow on the
|
||||
immutable patch revision.
|
||||
|
||||
@@ -34,6 +34,7 @@ import {
|
||||
normalizeBboxFromCorners,
|
||||
operationalScopeProjectLabel,
|
||||
parseBboxInput,
|
||||
persistedDatasetSupportsSelection,
|
||||
productCoversZones,
|
||||
readablePropertyName,
|
||||
resultCountLabel,
|
||||
@@ -1154,7 +1155,8 @@ export function MapWorkspace({
|
||||
if (boundedThemes.has(theme.id)) {
|
||||
return true
|
||||
}
|
||||
if (!themeDatasetMap[theme.id]) {
|
||||
const dataset = themeDatasetMap[theme.id]
|
||||
if (!dataset || !persistedDatasetSupportsSelection(dataset, mapSelectionBbox)) {
|
||||
return false
|
||||
}
|
||||
const coverageTheme = COVERAGE_THEME_BY_MAP_THEME[theme.id]
|
||||
@@ -1830,7 +1832,7 @@ export function MapWorkspace({
|
||||
const availableThemes: Array<MapThemeQuery<DataThemeId>> = []
|
||||
for (const theme of DATA_THEMES) {
|
||||
const dataset = themeDatasetMap[theme.id]
|
||||
if (dataset) {
|
||||
if (dataset && persistedDatasetSupportsSelection(dataset, bbox)) {
|
||||
availableThemes.push({
|
||||
themeId: theme.id,
|
||||
dataset,
|
||||
@@ -1865,7 +1867,12 @@ export function MapWorkspace({
|
||||
setMapAnalysisDurationMs(null)
|
||||
setSelectionBbox(bbox)
|
||||
const tasks: Array<Promise<unknown>> = [loadAllThemeResults(bbox, areaId)]
|
||||
if (activeThemeAvailable && !regionalPartitionedThemeActive && !onDemandThemeActive) {
|
||||
const activeDatasetSupportsSelection = !activeThemeDataset
|
||||
|| persistedDatasetSupportsSelection(activeThemeDataset, bbox)
|
||||
if (
|
||||
activeThemeAvailable && !regionalPartitionedThemeActive && !onDemandThemeActive
|
||||
&& activeDatasetSupportsSelection
|
||||
) {
|
||||
tasks.push(onRunMapSelectionExtract(bbox, areaId))
|
||||
}
|
||||
if (analysisMode === 'evolution' && earlierDatasetId && laterDatasetId) {
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
isSelectionBoundedDataset,
|
||||
normalizeBboxFromCorners,
|
||||
parseBboxInput,
|
||||
persistedDatasetSupportsSelection,
|
||||
productCoversZones,
|
||||
resultMetricLabel,
|
||||
selectedAreaCoverageZones,
|
||||
@@ -138,4 +139,22 @@ describe('map workspace selection guards', () => {
|
||||
}
|
||||
expect(() => splitSelectionBbox(selection)).toThrow('detailpartities')
|
||||
})
|
||||
|
||||
it('keeps persisted high-resolution rasters out of overview selections', () => {
|
||||
const overview: VectorSelectionBBox = {
|
||||
min_x: 2.5,
|
||||
min_y: 49.5,
|
||||
max_x: 6.4,
|
||||
max_y: 51.5,
|
||||
crs: 'EPSG:4326',
|
||||
}
|
||||
expect(persistedDatasetSupportsSelection(
|
||||
{ dataset_type: 'raster', source_name: 'digitaal_vlaanderen_dhmv' },
|
||||
overview,
|
||||
)).toBe(false)
|
||||
expect(persistedDatasetSupportsSelection(
|
||||
{ dataset_type: 'vector', source_name: 'statbel' },
|
||||
overview,
|
||||
)).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -100,6 +100,23 @@ export function selectionAnalysisScale(bbox: VectorSelectionBBox): SelectionAnal
|
||||
return 'overview'
|
||||
}
|
||||
|
||||
export function persistedDatasetSupportsSelection(
|
||||
dataset: { dataset_type: string; source_name?: string | null },
|
||||
bbox: VectorSelectionBBox,
|
||||
): boolean {
|
||||
if (dataset.dataset_type !== 'raster') return true
|
||||
const scale = selectionAnalysisScale(bbox)
|
||||
if (scale === 'overview') return false
|
||||
const dimensions = selectionDimensions(bbox)
|
||||
if (dataset.source_name === 'digitaal_vlaanderen_dhmv' || dataset.source_name === 'vmm_flood_hazard') {
|
||||
return dimensions.areaSquareMetres <= 280_000_000
|
||||
}
|
||||
if (dataset.source_name === 'department_omgeving_thematic_raster') {
|
||||
return dimensions.areaSquareMetres <= 2_800_000_000
|
||||
}
|
||||
return scale === 'detail'
|
||||
}
|
||||
|
||||
export function splitSelectionBbox(
|
||||
bbox: VectorSelectionBBox,
|
||||
maxTileSideMetres = 18_000,
|
||||
|
||||
Reference in New Issue
Block a user