Initial public release
GeoIntel release gates / Compile, test, contracts and builds (push) Successful in 1m49s
GeoIntel release gates / Python and npm vulnerability policy (push) Successful in 21s
GeoIntel release gates / Production AI image, SBOM and container scan (push) Successful in 5m39s
GeoIntel release gates / Deploy exact gated revision to Unraid (push) Failing after 58m43s
GeoIntel release gates / Compile, test, contracts and builds (push) Successful in 1m49s
GeoIntel release gates / Python and npm vulnerability policy (push) Successful in 21s
GeoIntel release gates / Production AI image, SBOM and container scan (push) Successful in 5m39s
GeoIntel release gates / Deploy exact gated revision to Unraid (push) Failing after 58m43s
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
"""A selection smaller than a raster cell must not silently read as zero.
|
||||
|
||||
``geometry_mask`` selects a cell when its *centre* falls inside the geometry.
|
||||
A rectangle smaller than one cell, or one that lands between four centres,
|
||||
therefore selects nothing at all — and the analysis returned zeros, which on
|
||||
screen is indistinguishable from "we looked and there is nothing here". On a
|
||||
100 m population raster a 40 m rectangle over a city block reported no
|
||||
inhabitants.
|
||||
|
||||
Selection now falls back to every touched cell and says that it did, so the
|
||||
value is readable as "at least one whole cell", not as an empty area.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import pytest
|
||||
|
||||
np = pytest.importorskip("numpy")
|
||||
rasterio = pytest.importorskip("rasterio")
|
||||
|
||||
from rasterio.transform import from_origin # noqa: E402 - optional rasterio gate precedes imports
|
||||
from shapely.geometry import box # noqa: E402 - optional rasterio gate precedes imports
|
||||
|
||||
from app.services.raster_cell_selection import select_cells # noqa: E402 - optional rasterio gate precedes service import
|
||||
|
||||
|
||||
# 100 m cells, origin at the top-left corner of a 3x3 grid.
|
||||
TRANSFORM = from_origin(200_000, 210_000, 100.0, 100.0)
|
||||
SHAPE = (3, 3)
|
||||
|
||||
|
||||
def test_a_normal_selection_uses_cell_centres() -> None:
|
||||
selection = select_cells(box(200_000, 209_700, 200_300, 210_000), out_shape=SHAPE, transform=TRANSFORM)
|
||||
|
||||
assert selection.mask.sum() == 9
|
||||
assert selection.mode == "cell_centre"
|
||||
assert selection.expanded_to_touched_cells is False
|
||||
assert selection.warning is None
|
||||
|
||||
|
||||
def test_a_rectangle_smaller_than_one_cell_still_returns_that_cell() -> None:
|
||||
selection = select_cells(box(200_010, 209_960, 200_050, 209_990), out_shape=SHAPE, transform=TRANSFORM)
|
||||
|
||||
assert selection.mask.sum() == 1
|
||||
assert selection.mode == "all_touched"
|
||||
assert selection.expanded_to_touched_cells is True
|
||||
assert "cel" in selection.warning
|
||||
|
||||
|
||||
def test_a_rectangle_between_four_cell_centres_returns_all_four() -> None:
|
||||
selection = select_cells(box(200_080, 209_880, 200_120, 209_920), out_shape=SHAPE, transform=TRANSFORM)
|
||||
|
||||
assert selection.mask.sum() == 4
|
||||
assert selection.expanded_to_touched_cells is True
|
||||
|
||||
|
||||
def test_a_selection_entirely_off_the_raster_selects_nothing() -> None:
|
||||
"""Falling back must not invent coverage where the geometry does not reach."""
|
||||
|
||||
selection = select_cells(box(300_000, 300_000, 300_100, 300_100), out_shape=SHAPE, transform=TRANSFORM)
|
||||
|
||||
assert selection.mask.sum() == 0
|
||||
assert selection.expanded_to_touched_cells is False
|
||||
assert selection.mode == "cell_centre"
|
||||
|
||||
|
||||
def test_the_warning_states_how_much_larger_the_analysed_area_is() -> None:
|
||||
selection = select_cells(
|
||||
box(200_010, 209_960, 200_050, 209_990),
|
||||
out_shape=SHAPE,
|
||||
transform=TRANSFORM,
|
||||
cell_area_m2=100.0 * 100.0,
|
||||
)
|
||||
|
||||
# One 100x100 m cell was analysed for a 40x30 m request.
|
||||
assert "1 rastercel" in selection.warning
|
||||
assert "1.0 ha" in selection.warning
|
||||
|
||||
|
||||
def test_the_mask_shape_always_matches_the_raster_window() -> None:
|
||||
selection = select_cells(box(200_010, 209_960, 200_050, 209_990), out_shape=SHAPE, transform=TRANSFORM)
|
||||
|
||||
assert selection.mask.shape == SHAPE
|
||||
assert selection.mask.dtype == np.bool_
|
||||
Reference in New Issue
Block a user