diff --git a/integration-test/1687-fewer-places-at-low-zoom.py b/integration-test/1687-fewer-places-at-low-zoom.py new file mode 100644 index 000000000..714e5debb --- /dev/null +++ b/integration-test/1687-fewer-places-at-low-zoom.py @@ -0,0 +1,45 @@ +# -*- encoding: utf-8 -*- +from . import FixtureTest + + +class LowZoomPlacesTest(FixtureTest): + + def test_zoom_1(self): + import dsl + + z, x, y = (3, 7, 3) + + self.generate_fixtures( + dsl.way(607976629, dsl.tile_centre_shape(z, x, y), { + "min_zoom": 1, + "__ne_max_zoom": 10, + "__ne_min_zoom": 3, + "area": 0, + "place": "country", + "name": "Guam", + "population": 185427, + "source": "openstreetmap.org", + }), + ) + + # should exist at zoom 3 (the min zoom from NE) + self.assert_has_feature( + z, x, y, 'places', { + 'id': 607976629, + 'kind': 'country', + 'name': 'Guam', + }) + + # should exist at zoom 2 (one past the min zoom) + self.assert_has_feature( + z-1, x//2, y//2, 'places', { + 'id': 607976629, + 'kind': 'country', + 'name': 'Guam', + }) + + # should not exist at zoom 1 + self.assert_no_matching_feature( + z-2, x//4, y//4, 'places', { + 'id': 607976629, + }) diff --git a/queries.yaml b/queries.yaml index ab015e8c5..abe6c5d0f 100644 --- a/queries.yaml +++ b/queries.yaml @@ -596,6 +596,12 @@ post_process: params: layer: places + # after we have the NE min zoom, drop features which we won't be displaying + # at this zoom. + - fn: vectordatasource.transform.min_zoom_filter + params: + layers: [places] + - fn: vectordatasource.transform.overlap params: base_layer: buildings diff --git a/vectordatasource/transform.py b/vectordatasource/transform.py index 022ef5a23..f15ff8dd1 100644 --- a/vectordatasource/transform.py +++ b/vectordatasource/transform.py @@ -7336,6 +7336,32 @@ def max_zoom_filter(ctx): return None +def min_zoom_filter(ctx): + """ + For features with a min_zoom, remove them if it's > nominal zoom + 1. + """ + + params = _Params(ctx, 'min_zoom_filter') + layers = params.required('layers', typ=list) + nominal_zoom = ctx.nominal_zoom + + for layer_name in layers: + layer = _find_layer(ctx.feature_layers, layer_name) + + features = layer['features'] + new_features = [] + + for feature in features: + _, props, _ = feature + min_zoom = props.get('min_zoom') + if min_zoom is not None and min_zoom <= nominal_zoom + 1: + new_features.append(feature) + + layer['features'] = new_features + + return None + + def tags_set_ne_min_max_zoom(ctx): """ Override the min zoom and max zoom properties with __ne_* variants from