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,
    )
예제 #6
0
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)
예제 #7
0
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
예제 #11
0
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,
    )
예제 #13
0
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,
    )
예제 #14
0
 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)
예제 #15
0
 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"