mirror of
https://github.com/GSA/notifications-admin.git
synced 2026-09-10 10:03:21 -04:00
Update utils to do linear transformation of polygons
Brings in https://github.com/alphagov/notifications-utils/pull/889/files At the moment, we are not doing any transformation of features before applying geometric algorithms to them. This is, in effect, assuming that the earth is flat. This new version of utils implements the transformation of our polygons to a Cartesian plane. In other words, it converts them from being defined in spherical degrees to metres. For the admin app this means we need to convert places where the code expects things to be measured in degrees to work in metres instead.
This commit is contained in:
@@ -7,6 +7,8 @@ from notifications_utils.serialised_model import SerialisedModelCollection
|
||||
from rtreelib import Rect
|
||||
from werkzeug.utils import cached_property
|
||||
|
||||
from app.formatters import square_metres_to_square_miles
|
||||
|
||||
from .populations import CITY_OF_LONDON
|
||||
from .repo import BroadcastAreasRepository, rtree_index
|
||||
|
||||
@@ -55,13 +57,13 @@ class BaseBroadcastArea(ABC):
|
||||
|
||||
@cached_property
|
||||
def simple_polygons_with_bleed(self):
|
||||
return self.simple_polygons.bleed_by(self.estimated_bleed_in_degrees)
|
||||
return self.simple_polygons.bleed_by(self.estimated_bleed_in_m)
|
||||
|
||||
@cached_property
|
||||
def phone_density(self):
|
||||
if not self.polygons.estimated_area:
|
||||
return 0
|
||||
return self.count_of_phones / self.polygons.estimated_area
|
||||
return self.count_of_phones / square_metres_to_square_miles(self.polygons.estimated_area)
|
||||
|
||||
@property
|
||||
def estimated_bleed_in_m(self):
|
||||
@@ -72,14 +74,10 @@ class BaseBroadcastArea(ABC):
|
||||
range masts, so the typical bleed will be high (up to 5,000m).
|
||||
'''
|
||||
if self.phone_density < 1:
|
||||
return Polygons.approx_bleed_in_degrees * Polygons.approx_metres_to_degree
|
||||
return Polygons.approx_bleed_in_m
|
||||
estimated_bleed = 5_900 - (math.log(self.phone_density, 10) * 1_250)
|
||||
return max(500, min(estimated_bleed, 5000))
|
||||
|
||||
@property
|
||||
def estimated_bleed_in_degrees(self):
|
||||
return self.estimated_bleed_in_m / Polygons.approx_metres_to_degree
|
||||
|
||||
|
||||
class BroadcastArea(BaseBroadcastArea, SortableMixin):
|
||||
|
||||
@@ -123,7 +121,7 @@ class BroadcastArea(BaseBroadcastArea, SortableMixin):
|
||||
def count_of_phones(self):
|
||||
if self.id.endswith(CITY_OF_LONDON.WARDS):
|
||||
return CITY_OF_LONDON.DAYTIME_POPULATION * (
|
||||
self.polygons.estimated_area / CITY_OF_LONDON.AREA_SQUARE_MILES
|
||||
self.polygons.estimated_area / CITY_OF_LONDON.AREA_SQUARE_METRES
|
||||
)
|
||||
if self.sub_areas:
|
||||
return sum(area.count_of_phones for area in self.sub_areas)
|
||||
@@ -169,7 +167,10 @@ class CustomBroadcastArea(BaseBroadcastArea):
|
||||
return Polygons(
|
||||
# Polygons in the DB are stored with the coordinate pair
|
||||
# order flipped – this flips them back again
|
||||
Polygons(self._polygons).as_coordinate_pairs_lat_long
|
||||
[
|
||||
[[lat, long] for long, lat in polygon]
|
||||
for polygon in self._polygons
|
||||
]
|
||||
)
|
||||
|
||||
simple_polygons = polygons
|
||||
|
||||
Reference in New Issue
Block a user