def _call_fut(self, shape, bounds): from tilequeue.process import Context from vectordatasource.transform import rank_features props = dict(foo='bar') feature = shape, props, 1 feature_layer = dict( features=[feature], layer_datum=dict(name='layer-name'), ) params = dict( source_layer='layer-name', rank_key='rank', items_matching=dict(foo='bar'), ) ctx = Context( feature_layers=[feature_layer], nominal_zoom=0, unpadded_bounds=bounds, params=params, resources=None, log=None, ) rank_features(ctx) rank = props.get('rank') return rank
def test_boundary_difference_exception(self): from vectordatasource.transform import admin_boundaries from tilequeue.process import Context from shapely.geometry.linestring import LineString from shapely.geometry import box from collections import namedtuple shape = LineString([[0, 0], [1, 1]]) props1 = {'id': 1, 'kind': 'foo', 'maritime_boundary': False} props2 = {'id': 2, 'kind': 'foo', 'maritime_boundary': False} fid = None bounds = (0, 0, 1, 1) # it turns out to be difficult to make a simple, canned example of # geometries which will cause a TopologicalError. instead, this fake # geometry class will cause Shapely to throw AttributeError whenever # it's used in a geometric operation, as it doesn't have the _geom # attribute used to store a pointer to GEOS' native object. class FakeGeom(namedtuple("FakeGeom", "geom_type envelope")): def difference(self, other_shape): from shapely.geometry import GeometryCollection return GeometryCollection([]) fake_geom = FakeGeom("LineString", box(*bounds)) feature_layers = [ dict( layer_datum=dict( is_clipped=True, area_threshold=0, simplify_before_intersect=True, simplify_start=0, name='foo', ), padded_bounds={'line': bounds}, features=[ (shape, props1, fid), # the fake geometry here causes an exception to be thrown, as # if the operation failed. (fake_geom, props2, fid), ], ) ] nominal_zoom = 0 unpadded_bounds = bounds params = dict( simplify_before=16, base_layer='foo', ) resources = None ctx = Context(feature_layers, nominal_zoom, unpadded_bounds, params, resources) # the test is simply that an exception isn't thrown. admin_boundaries(ctx)
def test_transform_adds_layer(self): """ Tests that the "$layer" pseudo-property is being injected by the add_collision_rank post-processor. We use the $-prefix so that it doesn't clash with the "layer" property, which represents something close to z-order for features. """ from ModestMaps.Core import Coordinate from shapely.geometry import Point from tilequeue.process import Context from tilequeue.tile import coord_to_bounds from tilequeue.tile import num2deg from vectordatasource.collision import CollisionRanker from vectordatasource.transform import add_collision_rank z, x, y = (16, 0, 0) ranker = CollisionRanker([ {"$layer": "foo"}, ]) shape = Point(*num2deg(x + 0.5, y + 0.5, z)) feature_layers = [ dict( layer_datum=dict(name='foo'), features=[ (shape, {}, 1), ], ), ] nominal_zoom = z padded_bounds = coord_to_bounds(Coordinate(zoom=z, column=x, row=y)) params = {} resources = {'ranker': ranker} ctx = Context( feature_layers, nominal_zoom, padded_bounds, params, resources, log=None, ) # NOTE: modifies layers in-place, doesn't return anything add_collision_rank(ctx) # we should have assigned the collision rank because of the # $layer match _, props, _ = feature_layers[0]['features'][0] self.assertEqual(props.get('collision_rank'), 1)
def _call_fut(self, feature_layers, zoom): from tilequeue.process import Context from vectordatasource.transform import drop_features_mz_min_pixels params = dict(property='mz_min_pixels', source_layers=('layer-name', )) ctx = Context( feature_layers=feature_layers, nominal_zoom=zoom, params=params, unpadded_bounds=None, resources=None, ) result = drop_features_mz_min_pixels(ctx) return result
def _call_fut(self, feature_layers, zoom): from tilequeue.process import Context from ModestMaps.Core import Coordinate from vectordatasource.transform import drop_features_mz_min_pixels params = dict(property='mz_min_pixels', source_layers=('layer-name', )) ctx = Context( feature_layers=feature_layers, tile_coord=Coordinate(column=1, row=1, zoom=zoom), params=params, unpadded_bounds=None, resources=None, ) result = drop_features_mz_min_pixels(ctx) return result
def _assert_no_id_in_props(self, features, merge_fn): from tilequeue.process import Context layer_name = 'layername' feature_layer = dict( features=features, layer_datum=dict(name=layer_name), ) feature_layers = [feature_layer] ctx = Context(feature_layers=feature_layers, nominal_zoom=0, unpadded_bounds=None, params=dict(source_layer=layer_name), resources=None) merged_feature_layer = merge_fn(ctx) merged_features = merged_feature_layer['features'] self.assertEquals(1, len(merged_features)) merged_feature = merged_features[0] props = merged_feature[1] self.assertTrue('id' not in props)
def test_simplify_and_clip(self): from vectordatasource.transform import simplify_and_clip from tilequeue.process import Context from shapely.geometry.linestring import LineString shape = LineString([[0, 0], [0.5, 2], [1, 1]]) props = {} fid = None bounds = (0, 0, 1, 1) feature_layers = [ dict( layer_datum=dict( is_clipped=True, area_threshold=0, simplify_before_intersect=True, simplify_start=0, ), padded_bounds={'line': bounds}, features=[(shape, props, fid)], ) ] nominal_zoom = 0 unpadded_bounds = bounds params = dict(simplify_before=16, ) resources = None ctx = Context(feature_layers, nominal_zoom, unpadded_bounds, params, resources, log=None) simplify_and_clip(ctx) self.assertEquals(1, len(ctx.feature_layers)) feature_layer = ctx.feature_layers[0] self.assertEquals(1, len(feature_layer['features'])) out_shape, out_props, out_fid = feature_layer['features'][0] self.assertEquals('LineString', out_shape.type)
def test_no_merge_preserve_props(self): import shapely.geometry from tilequeue.process import Context from vectordatasource.transform import merge_polygon_features buildings = [] for i in (0, 100): id = i + 1 points = [ (1 + i, 1 + i), (10 + i, 10 + i), (1 + i, 10 + i), (1 + i, 1 + i), ] shape = shapely.geometry.Polygon(points) props = dict( id=id, kind='building', unique_value='value-%d' % id, ) building = shape, props, id buildings.append(building) layer_name = 'buildings' feature_layer = dict( features=buildings, layer_datum=dict(name=layer_name), ) feature_layers = [feature_layer] ctx = Context(feature_layers=feature_layers, nominal_zoom=0, unpadded_bounds=None, params=dict(source_layer=layer_name), resources=None, log=None) merged_feature_layer = merge_polygon_features(ctx) merged_features = merged_feature_layer['features'] self.assertEquals(2, len(merged_features)) for f in merged_features: props = f[1] self.assertTrue('id' in props)
def _call_fut(self, building_shapes, building_part_shapes): from tilequeue.process import Context building_features = [] building_id = 1 for building_shape in building_shapes: building_props = dict( id=building_id, kind='building', ) building_feature = building_shape, building_props, building_id building_features.append(building_feature) building_id += 1 part_features = [] building_part_id = building_id for part_shape in building_part_shapes: part_props = dict( id=building_part_id, kind='building_part', ) part_feature = part_shape, part_props, building_part_id part_features.append(part_feature) building_part_id += 1 building_features = building_features + part_features building_feature_layer = dict( features=building_features, layer_datum=dict(name='buildings'), ) feature_layers = [building_feature_layer] ctx = Context(feature_layers=feature_layers, nominal_zoom=0, unpadded_bounds=None, params=dict(source_layer='buildings'), resources=None, log=None) from vectordatasource.transform import buildings_unify buildings_unify(ctx) return building_feature_layer['features']