fix(map): make area analysis scale-aware
This commit is contained in:
@@ -73,6 +73,63 @@ export function selectionAreaSquareMetres(bbox: VectorSelectionBBox | null): num
|
||||
return Math.max(0, widthMetres * heightMetres)
|
||||
}
|
||||
|
||||
export interface SelectionDimensions {
|
||||
widthMetres: number
|
||||
heightMetres: number
|
||||
areaSquareMetres: number
|
||||
}
|
||||
|
||||
export type SelectionAnalysisScale = 'detail' | 'regional' | 'overview'
|
||||
|
||||
export function selectionDimensions(bbox: VectorSelectionBBox): SelectionDimensions {
|
||||
const middleLatitudeRadians = ((bbox.min_y + bbox.max_y) / 2) * (Math.PI / 180)
|
||||
const widthMetres = Math.max(0, (bbox.max_x - bbox.min_x) * 111_320 * Math.cos(middleLatitudeRadians))
|
||||
const heightMetres = Math.max(0, (bbox.max_y - bbox.min_y) * 110_574)
|
||||
return {
|
||||
widthMetres,
|
||||
heightMetres,
|
||||
areaSquareMetres: widthMetres * heightMetres,
|
||||
}
|
||||
}
|
||||
|
||||
export function selectionAnalysisScale(bbox: VectorSelectionBBox): SelectionAnalysisScale {
|
||||
const { widthMetres, heightMetres } = selectionDimensions(bbox)
|
||||
const longestSide = Math.max(widthMetres, heightMetres)
|
||||
if (longestSide <= 20_000) return 'detail'
|
||||
if (longestSide <= 50_000) return 'regional'
|
||||
return 'overview'
|
||||
}
|
||||
|
||||
export function splitSelectionBbox(
|
||||
bbox: VectorSelectionBBox,
|
||||
maxTileSideMetres = 18_000,
|
||||
maxTiles = 16,
|
||||
): VectorSelectionBBox[] {
|
||||
const { widthMetres, heightMetres } = selectionDimensions(bbox)
|
||||
const columns = Math.max(1, Math.ceil(widthMetres / maxTileSideMetres))
|
||||
const rows = Math.max(1, Math.ceil(heightMetres / maxTileSideMetres))
|
||||
if (columns * rows > maxTiles) {
|
||||
throw new Error(
|
||||
`De selectie vereist ${columns * rows} detailpartities; maximaal ${maxTiles} zijn toegestaan.`,
|
||||
)
|
||||
}
|
||||
const longitudeStep = (bbox.max_x - bbox.min_x) / columns
|
||||
const latitudeStep = (bbox.max_y - bbox.min_y) / rows
|
||||
const tiles: VectorSelectionBBox[] = []
|
||||
for (let row = 0; row < rows; row += 1) {
|
||||
for (let column = 0; column < columns; column += 1) {
|
||||
tiles.push({
|
||||
min_x: bbox.min_x + longitudeStep * column,
|
||||
min_y: bbox.min_y + latitudeStep * row,
|
||||
max_x: column === columns - 1 ? bbox.max_x : bbox.min_x + longitudeStep * (column + 1),
|
||||
max_y: row === rows - 1 ? bbox.max_y : bbox.min_y + latitudeStep * (row + 1),
|
||||
crs: 'EPSG:4326',
|
||||
})
|
||||
}
|
||||
}
|
||||
return tiles
|
||||
}
|
||||
|
||||
export function bboxesEqual(left: VectorSelectionBBox | null, right: VectorSelectionBBox | null): boolean {
|
||||
if (!left || !right) {
|
||||
return false
|
||||
|
||||
Reference in New Issue
Block a user