def test_smoothing_and_area( polygons, expected_area_before, expected_area_after, ): original_area = Polygons(polygons).estimated_area smoothed_area = Polygons(polygons).smooth.estimated_area assert close_enough(original_area, expected_area_before) assert close_enough(smoothed_area, expected_area_after) assert smoothed_area >= original_area
def test_remove_areas_too_small(): hackney_marshes_and_wcb = Polygons([HACKNEY_MARSHES, WHITECHAPEL_BUILDING]) hackney_marshes = Polygons([HACKNEY_MARSHES]) assert len(hackney_marshes_and_wcb) == 2 assert len(hackney_marshes_and_wcb.remove_too_small) == 1 assert ( hackney_marshes_and_wcb.remove_too_small.estimated_area, hackney_marshes_and_wcb.remove_too_small.perimeter_length, ) == ( hackney_marshes.estimated_area, hackney_marshes.perimeter_length, )
def test_bleed( polygons, expected_area_before, expected_area_after, ): area_polygons = Polygons(polygons) assert close_enough( area_polygons.estimated_area, expected_area_before, ) assert close_enough( area_polygons.bleed_by( Polygons.approx_bleed_in_degrees).estimated_area, expected_area_after, )
def test_perimeter_length(polygons, expected_perimeter_length_km): perimeter_length_km = (Polygons(polygons).perimeter_length * Polygons.approx_metres_to_degree / 1000) assert close_enough( perimeter_length_km, expected_perimeter_length_km, )
def test_custom_bleed( bleed_distance_in_m, expected_area_before, expected_area_after, ): area_polygons = Polygons([ISLE_OF_DOGS]) assert close_enough( area_polygons.estimated_area, expected_area_before, ) assert close_enough( area_polygons.bleed_by( bleed_distance_in_m / Polygons.approx_metres_to_degree).estimated_area, expected_area_after, )
def _add_electoral_wards(dataset_id): areas_to_add = [] for feature in geojson.loads(wd20_filepath.read_text())["features"]: ward_code = feature["properties"]["wd20cd"] ward_name = feature["properties"]["wd20nm"] ward_id = "wd20-" + ward_code print() # noqa: T001 print(ward_name) # noqa: T001 try: la_id = "lad20-" + ward_code_to_la_id_mapping[ward_code] feature, simple_feature = (polygons_and_simplified_polygons( feature["geometry"])) if feature: rtree_index.insert(ward_id, Rect(*Polygons(feature).bounds)) areas_to_add.append([ ward_id, ward_name, dataset_id, la_id, feature, simple_feature, estimate_number_of_smartphones_in_area(ward_code), ]) except KeyError: print("Skipping", ward_code, ward_name) # noqa: T001 rtree_index_path.open('wb').write(pickle.dumps(rtree_index)) repo.insert_broadcast_areas(areas_to_add, keep_old_polygons)
def polygons_and_simplified_polygons(feature): if keep_old_polygons: # cheat and shortcut out return [], [] polygons = Polygons(simplify_geometry(feature)) full_resolution = polygons.remove_too_small smoothed = full_resolution.smooth simplified = smoothed.simplify print( # noqa: T001 f' Original:{full_resolution.point_count: >5} points' f' Smoothed:{smoothed.point_count: >5} points' f' Simplified:{simplified.point_count: >4} points') point_counts.append(simplified.point_count) if simplified.point_count >= 200: raise RuntimeError( 'Too many points ' '(adjust Polygons.perimeter_to_simplification_ratio or ' 'Polygons.perimeter_to_buffer_ratio)') return ( full_resolution.as_coordinate_pairs_long_lat, simplified.as_coordinate_pairs_long_lat, )
def test_bounds(polygons, expected_bounds): min_x, min_y, max_x, max_y = Polygons(polygons).bounds expected_min_x, expected_min_y, expected_max_x, expected_max_y = expected_bounds assert close_enough(min_x, expected_min_x) assert close_enough(min_y, expected_min_y) assert close_enough(max_x, expected_max_x) assert close_enough(max_y, expected_max_y)
def test_buffer_distances( polygons, expected_buffer_out_metres, expected_buffer_in_metres, ): outward_metres = Polygons( polygons).buffer_outward_in_degrees * Polygons.approx_metres_to_degree inward_metres = Polygons( polygons).buffer_inward_in_degrees * Polygons.approx_metres_to_degree assert close_enough( outward_metres, expected_buffer_out_metres, ) assert close_enough( inward_metres, expected_buffer_in_metres, )
def simple_polygons_with_bleed(self): polygons = Polygons( list( itertools.chain(*(area.simple_polygons_with_bleed for area in self.areas)))) # If we’ve added multiple areas then we need to re-simplify the # combined shapes to keep the point count down return polygons.smooth.simplify if len(self.areas) > 1 else polygons
def create_broadcast(): check_service_has_permission( BROADCAST_TYPE, authenticated_service.permissions, ) if request.content_type != 'application/cap+xml': raise BadRequestError( message=f'Content type {request.content_type} not supported', status_code=415, ) cap_xml = request.get_data() if not validate_xml(cap_xml, 'CAP-v1.2.xsd'): raise BadRequestError( message='Request data is not valid CAP XML', status_code=400, ) broadcast_json = cap_xml_to_dict(cap_xml) validate(broadcast_json, post_broadcast_schema) polygons = Polygons( list( chain.from_iterable( (area['polygons'] for area in broadcast_json['areas'])))) broadcast_message = BroadcastMessage( service_id=authenticated_service.id, content=broadcast_json['content'], reference=broadcast_json['reference'], areas={ 'areas': [area['name'] for area in broadcast_json['areas']], 'simple_polygons': polygons.smooth.simplify.as_coordinate_pairs_long_lat, }, status=BroadcastStatusType.PENDING_APPROVAL, api_key_id=api_user.id, stubbed=authenticated_service.restricted # The client may pass in broadcast_json['expires'] but it’s # simpler for now to ignore it and have the rules around expiry # for broadcasts created with the API match those created from # the admin app ) dao_save_object(broadcast_message) current_app.logger.info( f'Broadcast message {broadcast_message.id} created for service ' f'{authenticated_service.id} with reference {broadcast_json["reference"]}' ) return jsonify(broadcast_message.serialize()), 201
def test_simplify( polygons, expected_point_count_before, expected_point_count_after, ): area_polygons = Polygons(polygons) assert area_polygons.point_count == expected_point_count_before assert area_polygons.simplify.point_count == expected_point_count_after assert close_enough( area_polygons.estimated_area, area_polygons.simplify.estimated_area, )
def test_bleed( polygons, expected_area_before, expected_area_after, ): area_polygons = Polygons(polygons) assert close_enough( area_polygons.estimated_area, expected_area_before, ) assert close_enough( area_polygons.bleed.estimated_area, expected_area_after, )
def polygons(self): 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)
def simple_polygons(self): return Polygons( BroadcastAreasRepository().get_simple_polygons_for_area(self.id))
def polygons(self): return Polygons( list(itertools.chain(*(area.polygons for area in self.areas))))
def test_smooth_joins_areas_in_close_proximity(polygons, expected_count_before, expected_count_after): area_polygons = Polygons(polygons) assert len(area_polygons) == expected_count_before assert len(area_polygons.smooth) == expected_count_after
def test_intersection_ratio(polygons_1, polygons_2, expected_intersection_percentage): percentage = Polygons(polygons_1).ratio_of_intersection_with( Polygons(polygons_2)) * 100 assert close_enough(percentage, expected_intersection_percentage)
def test_empty_bounds(): with pytest.raises(ValueError) as exception: Polygons([]).bounds assert str(exception.value) == "Can't determine bounds of empty Polygons"