idgf
This commit is contained in:
parent
fbfebc651c
commit
aab85fe32e
33 changed files with 2016 additions and 283 deletions
|
|
@ -27,7 +27,7 @@ from .output import (
|
|||
to_wgs84_geojson_multi,
|
||||
write_district_geojson,
|
||||
)
|
||||
from .process_oa import _extract_polygonal, process_oa
|
||||
from .process_oa import MIN_GEOM_AREA, _extract_polygonal, process_oa
|
||||
from .uprn import get_oa_uprns, load_uprns
|
||||
from .voronoi import _equal_split_fallback, compute_voronoi_regions
|
||||
|
||||
|
|
@ -341,6 +341,65 @@ class TestVoronoiDeduplication:
|
|||
assert "B" in result, "Postcode B missing with int64 coords"
|
||||
|
||||
|
||||
class TestVoronoiCoincidentClusterNotCrushed:
|
||||
"""3+ postcodes at one coordinate must each keep a real cell.
|
||||
|
||||
Pre-fix, the first coincident postcode stayed unjittered at the exact
|
||||
cluster centre; with other seeds in the OA its Voronoi cell was squeezed
|
||||
below MIN_GEOM_AREA, so _clean_polygonal dropped that active postcode
|
||||
downstream. The fix spreads coincident postcodes onto a small regular
|
||||
polygon (equal wedges), so none is crushed.
|
||||
"""
|
||||
|
||||
def test_coincident_cluster_plus_outer_seed_no_postcode_crushed(self):
|
||||
# A block of flats: 4 distinct postcodes share one building coordinate,
|
||||
# plus one other postcode elsewhere in the OA. Pre-fix, the centre seed's
|
||||
# cell collapsed to ~0.0001 m^2 (< MIN_GEOM_AREA) and the postcode was
|
||||
# dropped; every postcode must now keep a non-degenerate cell.
|
||||
boundary = box(0, 0, 1000, 1000)
|
||||
points = np.array(
|
||||
[
|
||||
[500, 500], # A — coincident
|
||||
[500, 500], # B — coincident
|
||||
[500, 500], # C — coincident
|
||||
[500, 500], # D — coincident
|
||||
[100, 100], # OUT — elsewhere in the OA
|
||||
],
|
||||
dtype=np.float64,
|
||||
)
|
||||
postcodes = ["A", "B", "C", "D", "OUT"]
|
||||
result = compute_voronoi_regions(points, postcodes, boundary)
|
||||
for pc in postcodes:
|
||||
assert pc in result, f"Postcode {pc} was dropped"
|
||||
assert result[pc].area > MIN_GEOM_AREA, (
|
||||
f"Postcode {pc} cell {result[pc].area} <= MIN_GEOM_AREA"
|
||||
)
|
||||
|
||||
def test_coincident_cluster_partitions_into_fair_wedges(self, square_boundary):
|
||||
# N postcodes sharing one coordinate split the surrounding area into
|
||||
# roughly equal wedges (regular-polygon seeds), none degenerate.
|
||||
points = np.array([[500050, 180050]] * 5, dtype=np.float64)
|
||||
postcodes = ["A", "B", "C", "D", "E"]
|
||||
result = compute_voronoi_regions(points, postcodes, square_boundary)
|
||||
fair_share = square_boundary.area / len(postcodes)
|
||||
for pc in postcodes:
|
||||
assert pc in result, f"Postcode {pc} was dropped"
|
||||
# Each wedge is a meaningful fraction of its fair share (not crushed).
|
||||
assert result[pc].area > 0.3 * fair_share, (
|
||||
f"Postcode {pc} cell {result[pc].area} far below fair share {fair_share}"
|
||||
)
|
||||
|
||||
def test_two_coincident_split_is_fair(self, square_boundary):
|
||||
"""Regression: two postcodes at one coordinate split ~50/50."""
|
||||
points = np.array([[500050, 180050], [500050, 180050]], dtype=np.float64)
|
||||
postcodes = ["A", "B"]
|
||||
result = compute_voronoi_regions(points, postcodes, square_boundary)
|
||||
assert "A" in result and "B" in result
|
||||
total = result["A"].area + result["B"].area
|
||||
assert result["A"].area / total > 0.4
|
||||
assert result["B"].area / total > 0.4
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Bug 4: Voronoi collinear fallback gives everything to first postcode
|
||||
# ---------------------------------------------------------------------------
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue