def test_successful_merge(self): from ModestMaps.Core import Coordinate from shapely.geometry import LineString from tilequeue.tile import coord_to_bounds import dsl z, x, y = 9, 145, 201 bounds = coord_to_bounds(Coordinate(zoom=z, column=x, row=y)) mid_x = (bounds[2] - bounds[0]) / 2.0 + bounds[0] mid_y = (bounds[3] - bounds[1]) / 2.0 + bounds[1] ls1 = LineString([(mid_x-0.01, mid_y-0.01), (mid_x, mid_y)]) ls2 = LineString([(mid_x, mid_y), (mid_x+0.01, mid_y+0.01)]) props = dict(waterway=u'river', name=u'foo') self.generate_fixtures( dsl.way(1, ls1, props), dsl.way(2, ls2, props), ) self.assert_n_matching_features( z, x, y, 'water', { 'name': 'foo', 'kind': 'river', 'label_placement': type(None), }, 1) with self.features_in_tile_layer(z, x, y, 'water') as features: for f in features: if 'label_placement' in f['properties']: continue assert f['geometry']['type'] == 'LineString' assert len(f['geometry']['coordinates']) == 2
def test_road_no_repeated_points(self): from ModestMaps.Core import Coordinate from tilequeue.tile import coord_to_bounds z, x, y = 16, 17885, 27755 coord = Coordinate(zoom=z, column=x, row=y) bounds = coord_to_bounds(coord) # have to reorder the bounds from conventional order to the unusual # scheme that overpass expects (south,west,north,east). bbox = "%f,%f,%f,%f" % (bounds[1], bounds[0], bounds[3], bounds[2]) overpass = "******" query = "way(" + bbox + ")[highway]%3B>%3B" self.load_fixtures([overpass + query]) num_tested = 0 with self.features_in_tile_layer(z, x, y, 'roads') as features: for feature in features: gtype = feature['geometry']['type'] if gtype == 'LineString': self._assert_no_repeated_points( feature['geometry']['coordinates']) num_tested += 1 elif gtype == 'MultiLineString': for linestring in feature['geometry']['coordinates']: self._assert_no_repeated_points(linestring) num_tested += 1 self.assertTrue(num_tested != 0, "Expected at least one testable feature.")
def test_building_part(self): import dsl from tilequeue.tile import coord_to_bounds from shapely.geometry import box from ModestMaps.Core import Coordinate z, x, y = (16, 0, 0) bounds = coord_to_bounds(Coordinate(zoom=z, column=x, row=y)) shape = box(*bounds) self.generate_fixtures( dsl.way(1, shape, {'landuse': 'park', 'source': 'openstreetmap.org'}), dsl.way(2, shape, {'building': 'yes', 'source': 'openstreetmap.org'}), dsl.way(3, shape, {'building:part': 'yes', 'source': 'openstreetmap.org'}), ) self.assert_has_feature( z, x, y, 'buildings', {'id': 2, 'kind': 'building', 'landuse_kind': 'park'}) self.assert_has_feature( z, x, y, 'buildings', {'id': 3, 'kind': 'building_part', 'landuse_kind': 'park'})
def test_water_labels(self): import dsl from tilequeue.tile import coord_to_bounds from shapely.geometry import LineString from ModestMaps.Core import Coordinate z, x, y = (16, 2**15, 2**15) bounds = coord_to_bounds(Coordinate(zoom=z, column=x, row=y)) dx = bounds[2] - bounds[0] dy = bounds[3] - bounds[1] shape = LineString([ [bounds[0] + 0.01 * dx, bounds[1] + 0.01 * dy], [bounds[2] - 0.01 * dx, bounds[3] - 0.01 * dy], ]) self.generate_fixtures( dsl.way(1, shape, { 'waterway': 'river', 'name': 'Foo', 'source': u'openstreetmap.org', }), ) with self.features_in_tile_layer(z, x, y, 'water') as features: self.assertTrue(len(features) == 1) # when "download fixtures" phase is run, this won't be true. but # the preceding assertion will have been short-circuited to true, # so we guard the rest of the assertions here. if len(features) == 1: self.assertTrue( features[0]['geometry']['type'] == 'LineString')
def test_road_no_repeated_points(self): from ModestMaps.Core import Coordinate from tilequeue.tile import coord_to_bounds z, x, y = 16, 17885, 27755 coord = Coordinate(zoom=z, column=x, row=y) bounds = coord_to_bounds(coord) # have to reorder the bounds from conventional order to the unusual # scheme that overpass expects (south,west,north,east). bbox = "%f,%f,%f,%f" % (bounds[1], bounds[0], bounds[3], bounds[2]) overpass = "******" query = "way(" + bbox + ")[highway]%3B>%3B" self.load_fixtures([overpass + query]) num_tested = 0 with self.features_in_tile_layer(z, x, y, 'roads') as features: for feature in features: gtype = feature['geometry']['type'] if gtype == 'LineString': self._assert_no_repeated_points( feature['geometry']['coordinates']) num_tested += 1 elif gtype == 'MultiLineString': for linestring in feature['geometry']['coordinates']: self._assert_no_repeated_points(linestring) num_tested += 1 self.assertTrue(num_tested != 0, "Expected at least one testable feature.")
def test_building_part(self): import dsl from tilequeue.tile import coord_to_bounds from shapely.geometry import box from ModestMaps.Core import Coordinate z, x, y = (16, 0, 0) bounds = coord_to_bounds(Coordinate(zoom=z, column=x, row=y)) shape = box(*bounds) self.generate_fixtures( dsl.way(1, shape, { 'landuse': 'park', 'source': 'openstreetmap.org' }), dsl.way(2, shape, { 'building': 'yes', 'source': 'openstreetmap.org' }), dsl.way(3, shape, { 'building:part': 'yes', 'source': 'openstreetmap.org' }), ) self.assert_has_feature(z, x, y, 'buildings', { 'id': 2, 'kind': 'building', 'landuse_kind': 'park' }) self.assert_has_feature(z, x, y, 'buildings', { 'id': 3, 'kind': 'building_part', 'landuse_kind': 'park' })
def test_water_labels(self): import dsl from tilequeue.tile import coord_to_bounds from shapely.geometry import LineString from ModestMaps.Core import Coordinate z, x, y = (16, 2**15, 2**15) bounds = coord_to_bounds(Coordinate(zoom=z, column=x, row=y)) dx = bounds[2] - bounds[0] dy = bounds[3] - bounds[1] shape = LineString([ [bounds[0] + 0.01 * dx, bounds[1] + 0.01 * dy], [bounds[2] - 0.01 * dx, bounds[3] - 0.01 * dy], ]) self.generate_fixtures( dsl.way( 1, shape, { 'waterway': 'river', 'name': 'Foo', 'source': u'openstreetmap.org', }), ) with self.features_in_tile_layer(z, x, y, 'water') as features: self.assertTrue(len(features) == 1) # when "download fixtures" phase is run, this won't be true. but # the preceding assertion will have been short-circuited to true, # so we guard the rest of the assertions here. if len(features) == 1: self.assertTrue( features[0]['geometry']['type'] == 'LineString')
def test_convert_coord(self): from tilequeue.tile import coord_to_bounds from ModestMaps.Core import Coordinate coord = Coordinate(zoom=14, column=4824, row=6160) bounds = coord_to_bounds(coord) exp_bounds = (-74.00390625, 40.69729900863674, -73.98193359375, 40.713955826286046) self.assertEqual(exp_bounds, bounds)
def test_junction_x(self): from tilequeue.tile import coord_to_bounds from shapely.geometry import LineString, asShape from ModestMaps.Core import Coordinate import dsl z, x, y = (12, 2048, 2048) minx, miny, maxx, maxy = coord_to_bounds( Coordinate(zoom=z, column=x, row=y)) midx = 0.5 * (minx + maxx) midy = 0.5 * (miny + maxy) road_props = dict( highway='residential', source='openstreetmap.org', ) # make a tile with 4 roads in an X shape, as below. # # \ / # 1 2 # \/ # /\ # 3 4 # / \ # # these should get merged into two lines 1->4 & 2->3. self.generate_fixtures( dsl.way(1, LineString([[minx, maxy], [midx, midy]]), road_props), dsl.way(2, LineString([[maxx, maxy], [midx, midy]]), road_props), dsl.way(3, LineString([[minx, miny], [midx, midy]]), road_props), dsl.way(4, LineString([[maxx, miny], [midx, midy]]), road_props), ) with self.features_in_tile_layer(z, x, y, 'roads') as features: # multilinestrings which contain lines which cross (as in the X # above) are "non-simple", and many geometry operations start by # forcing multilinestrings to be simple. we don't want this, as # it introduces an extra coordinate where the lines cross. # instead, we split into features which are individually simple, # which means we'll need 2 in this example. self.assertTrue(len(features) == 2) # when the test suite runs in "download only mode", an empty # set of features is passed into this block. the assertion # is shorted out, so we need this additional check which is # trivially satisfied in the case we're doing real testing. if len(features) == 2: for i in (0, 1): # the shapes should be single linestrings in this example. shape = asShape(features[i]['geometry']) self.assertTrue(shape.geom_type == 'LineString') # consisting of _only two_ points. (i.e: one didn't get # inserted into the middle) self.assertTrue(len(shape.coords) == 2)
def test_tiles_for_coord(self): from ModestMaps.Core import Coordinate from tilequeue.tile import coord_to_bounds from tilequeue.tile import tile_generator_for_single_bounds coord = Coordinate(1, 1, 1) bounds = coord_to_bounds(coord) tile_generator = tile_generator_for_single_bounds(bounds, 1, 1) tiles = list(tile_generator) self.assertEqual(1, len(tiles))
def test_tiles_for_coord(self): from ModestMaps.Core import Coordinate from tilequeue.tile import coord_to_bounds from tilequeue.tile import tile_generator_for_single_bounds coord = Coordinate(1, 1, 1) bounds = coord_to_bounds(coord) tile_generator = tile_generator_for_single_bounds(bounds, 1, 1) tiles = list(tile_generator) self.assertEqual(1, len(tiles))
def test_junction_x(self): from tilequeue.tile import coord_to_bounds from shapely.geometry import LineString, asShape from ModestMaps.Core import Coordinate import dsl z, x, y = (12, 2048, 2048) minx, miny, maxx, maxy = coord_to_bounds( Coordinate(zoom=z, column=x, row=y)) midx = 0.5 * (minx + maxx) midy = 0.5 * (miny + maxy) road_props = dict( highway='residential', source='openstreetmap.org', ) # make a tile with 4 roads in an X shape, as below. # # \ / # 1 2 # \/ # /\ # 3 4 # / \ # # these should get merged into two lines 1->4 & 2->3. self.generate_fixtures( dsl.way(1, LineString([[minx, maxy], [midx, midy]]), road_props), dsl.way(2, LineString([[maxx, maxy], [midx, midy]]), road_props), dsl.way(3, LineString([[minx, miny], [midx, midy]]), road_props), dsl.way(4, LineString([[maxx, miny], [midx, midy]]), road_props), ) with self.features_in_tile_layer(z, x, y, 'roads') as features: # multilinestrings which contain lines which cross (as in the X # above) are "non-simple", and many geometry operations start by # forcing multilinestrings to be simple. we don't want this, as # it introduces an extra coordinate where the lines cross. # instead, we split into features which are individually simple, # which means we'll need 2 in this example. self.assertTrue(len(features) == 2) # when the test suite runs in "download only mode", an empty # set of features is passed into this block. the assertion # is shorted out, so we need this additional check which is # trivially satisfied in the case we're doing real testing. if len(features) == 2: for i in (0, 1): # the shapes should be single linestrings in this example. shape = asShape(features[i]['geometry']) self.assertTrue(shape.geom_type == 'LineString') # consisting of _only two_ points. (i.e: one didn't get # inserted into the middle) self.assertTrue(len(shape.coords) == 2)
def tile_box(z, x, y): """ Returns a Shapely Polygon which covers the tile. """ from tilequeue.tile import coord_to_bounds from shapely.geometry import box from ModestMaps.Core import Coordinate bounds = coord_to_bounds(Coordinate(zoom=z, column=x, row=y)) return box(*bounds)
def tile_box(z, x, y): """ Returns a Shapely Polygon which covers the tile. """ from tilequeue.tile import coord_to_bounds from shapely.geometry import box from ModestMaps.Core import Coordinate bounds = coord_to_bounds(Coordinate(zoom=z, column=x, row=y)) return box(*bounds)
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 _load_query(self, z, x, y, tag): from ModestMaps.Core import Coordinate from tilequeue.tile import coord_to_bounds coord = Coordinate(zoom=z, column=x, row=y) bounds = coord_to_bounds(coord) # have to reorder the bounds from conventional order to the unusual # scheme that overpass expects (south,west,north,east). bbox = "%f,%f,%f,%f" % (bounds[1], bounds[0], bounds[3], bounds[2]) overpass = "******" query = "way(" + bbox + ")[" + tag + "];>;" self.load_fixtures([overpass + query])
def _load_query(self, z, x, y, tag): from ModestMaps.Core import Coordinate from tilequeue.tile import coord_to_bounds coord = Coordinate(zoom=z, column=x, row=y) bounds = coord_to_bounds(coord) # have to reorder the bounds from conventional order to the unusual # scheme that overpass expects (south,west,north,east). bbox = "%f,%f,%f,%f" % (bounds[1], bounds[0], bounds[3], bounds[2]) overpass = "******" query = "way(" + bbox + ")[" + tag + "]%3B>%3B" self.load_fixtures([overpass + query])
def _setup(self, z, x, y, left_id, right_id): from tilequeue.tile import coord_to_bounds from shapely.geometry import LineString from ModestMaps.Core import Coordinate import dsl minx, miny, maxx, maxy = coord_to_bounds( Coordinate(zoom=z, column=x, row=y)) # move the coordinate points slightly out of the tile, so that we # don't get borders along the sides of the tile. w = maxx - minx h = maxy - miny minx -= 0.5 * w miny -= 0.5 * h maxx += 0.5 * w maxy += 0.5 * h self.generate_fixtures( dsl.way( 1, LineString([ [minx, miny], [minx, maxy], [maxx, maxy], [minx, miny], ]), { 'boundary': 'administrative', 'admin_level': '2', 'id': left_id, 'name': 'Left', 'mz_boundary_from_polygon': True, # need this for hack } ), dsl.way( 2, LineString([ [minx, miny], [maxx, maxy], [maxx, miny], [minx, miny], ]), { 'boundary': 'administrative', 'admin_level': '2', 'id': right_id, 'name': 'Right', 'mz_boundary_from_polygon': True, # need this for hack } ), )
def test_convert_coord(self): from tilequeue.tile import coord_to_bounds from ModestMaps.Core import Coordinate coord = Coordinate(zoom=14, column=4824, row=6160) bounds = coord_to_bounds(coord) exp_bounds = (-74.00390625, 40.69729900863674, -73.98193359375, 40.713955826286046) self.assertEqual(tuple, type(bounds)) self.assertEqual(len(exp_bounds), len(bounds)) for i in range(0, len(exp_bounds)): exp = exp_bounds[i] act = bounds[i] self.assertAlmostEqual( exp, act, msg="Expected %r but got %r at index %d" % (exp, act, i))
def tile_diagonal(z, x, y): """ Returns a Shapely LineString which goes from the lower left of the tile to the upper right. """ from tilequeue.tile import coord_to_bounds from shapely.geometry import LineString from ModestMaps.Core import Coordinate bounds = coord_to_bounds(Coordinate(zoom=z, column=x, row=y)) shape = LineString([ [bounds[0], bounds[1]], [bounds[2], bounds[3]], ]) return shape
def tile_diagonal(z, x, y): """ Returns a Shapely LineString which goes from the lower left of the tile to the upper right. """ from tilequeue.tile import coord_to_bounds from shapely.geometry import LineString from ModestMaps.Core import Coordinate bounds = coord_to_bounds(Coordinate(zoom=z, column=x, row=y)) shape = LineString([ [bounds[0], bounds[1]], [bounds[2], bounds[3]], ]) return shape
def _setup(self, z, x, y, left_props, right_props): from tilequeue.tile import coord_to_bounds from shapely.geometry import LineString from ModestMaps.Core import Coordinate import dsl minx, miny, maxx, maxy = coord_to_bounds( Coordinate(zoom=z, column=x, row=y)) # move the coordinate points slightly out of the tile, so that we # don't get borders along the sides of the tile. w = maxx - minx h = maxy - miny minx -= 0.5 * w miny -= 0.5 * h maxx += 0.5 * w maxy += 0.5 * h self.generate_fixtures( dsl.way( 1, LineString([ [minx, miny], [minx, maxy], [maxx, maxy], [minx, miny], ]), left_props, ), dsl.way( 2, LineString([ [minx, miny], [maxx, maxy], [maxx, miny], [minx, miny], ]), right_props, ), )
def test_sevier_lake(self): import dsl from tilequeue.tile import coord_to_bounds from shapely.geometry import Polygon from ModestMaps.Core import Coordinate z, x, y = (16, 12164, 25088) bounds = coord_to_bounds(Coordinate(zoom=z, column=x, row=y)) # lower right triangle of the tile box, so that part of the # boundary is definitely within the tile, not just at the edges. shape = Polygon([ [bounds[0], bounds[1]], [bounds[2], bounds[3]], [bounds[2], bounds[1]], [bounds[0], bounds[1]], ]) self.generate_fixtures( # https://www.openstreetmap.org/way/99982115 dsl.way(99982115, shape, { 'intermittent': 'yes', 'name': 'Sevier Lake', 'natural': 'water', 'source': 'openstreetmap.org', 'wikidata': 'Q81246', }), ) self.assert_has_feature( z, x, y, 'water', { 'id': 99982115, 'intermittent': True, 'kind': 'water', 'boundary': True, })
def test_roads_merged(self): from collections import defaultdict from shapely.geometry import asShape from tilequeue.tile import coord_to_bounds from shapely.geometry import LineString from ModestMaps.Core import Coordinate import dsl z, x, y = 8, 41, 99 bounds = coord_to_bounds(Coordinate(zoom=z, column=x, row=y)) def _line(frac): return LineString([ [bounds[0] + frac * (bounds[2] - bounds[0]), bounds[1]], [bounds[0] + frac * (bounds[2] - bounds[0]), bounds[3]], ]) # count the unique parameters - there should only be one, indicating # that the roads have been merged. self.generate_fixtures( dsl.way(1, _line(0.1), { 'highway': 'motorway', 'source': 'openstreetmap.org', }), dsl.way(2, _line(0.2), { 'highway': 'motorway', 'source': 'openstreetmap.org', }), dsl.way(3, _line(0.3), { 'highway': 'primary', 'source': 'openstreetmap.org', }), dsl.way(4, _line(0.4), { 'highway': 'primary', 'source': 'openstreetmap.org', }), dsl.way(5, _line(0.5), { 'highway': 'trunk', 'source': 'openstreetmap.org', }), dsl.way(6, _line(0.6), { 'highway': 'trunk', 'source': 'openstreetmap.org', }), ) with self.features_in_tile_layer(z, x, y, 'roads') as roads: features = defaultdict(list) for road in roads: props = frozenset(_freeze(road['properties'])) geom = asShape(road['geometry']) for f in features[props]: if f.disjoint(geom): self.assertTrue( False, 'Duplicate properties %r in roads layer for ' 'disjoint geometries (%r & %r), but ' 'properties should be unique or geometries ' 'intersecting.' % (road['properties'], f.wkt, geom.wkt)) features[props].append(geom)
def _check(self, aerodrome_type, runway_kind_detail): import dsl from tilequeue.tile import coord_to_bounds from shapely.geometry import LineString from shapely.geometry import CAP_STYLE from ModestMaps.Core import Coordinate z, x, y = (16, 0, 0) bounds = coord_to_bounds(Coordinate(zoom=z, column=x, row=y)) # runway line that runs from a quarter to three quarters of the # tile diagonal. this is so that we can buffer it without it # going outside the tile boundary. runway_line = LineString([ [bounds[0] + 0.25 * (bounds[2] - bounds[0]), bounds[1] + 0.25 * (bounds[3] - bounds[1])], [bounds[0] + 0.75 * (bounds[2] - bounds[0]), bounds[1] + 0.75 * (bounds[3] - bounds[1])], ]) # runway polygon which has the runway line as a centreline. runway_poly = runway_line.buffer( 0.1 * (bounds[2] - bounds[0]), # width 1/10th of a tile cap_style=CAP_STYLE.flat, ) self.generate_fixtures( dsl.way(1, dsl.tile_box(z, x, y), { 'aeroway': 'aerodrome', 'aerodrome:type': aerodrome_type, 'name': 'Fake Aerodrome', 'source': 'openstreetmap.org', }), # runway line dsl.way(2, runway_line, { 'aeroway': 'runway', 'source': 'openstreetmap.org', }), # runway polygon dsl.way(3, runway_poly, { 'area:aeroway': 'runway', 'source': 'openstreetmap.org', }) ) # runway line ends up in roads layer self.assert_has_feature( z, x, y, 'roads', { 'id': 2, 'kind': 'aeroway', 'kind_detail': 'runway', 'aerodrome_kind_detail': runway_kind_detail, }) # runway polygon is in landuse self.assert_has_feature( z, x, y, 'landuse', { 'id': 3, 'kind': 'runway', 'kind_detail': runway_kind_detail, })
def test_junction_hash(self): from tilequeue.tile import coord_to_bounds from shapely.geometry import LineString, asShape from ModestMaps.Core import Coordinate import dsl z, x, y = (12, 2048, 2048) minx, miny, maxx, maxy = coord_to_bounds( Coordinate(zoom=z, column=x, row=y)) midl = minx + (maxx - minx) / 3 midr = minx + 2 * (maxx - minx) / 3 midd = miny + (maxy - miny) / 3 midu = miny + 2 * (maxy - miny) / 3 road_props = dict( highway='residential', source='openstreetmap.org', ) # make a tile with 4 roads in a # shape, as below. # # | | # 1 2 # | | # --7--+--8--+--9-- # | | # 3 4 # | | # -10--+-11--+-12-- # | | # 5 6 # | | # # these should get merged into two features, one with 1->3->5 and # 2->4->6 and the other with 7->8->9 and 10->11->12. self.generate_fixtures( dsl.way(1, LineString([[midl, maxy], [midl, midu]]), road_props), dsl.way(2, LineString([[midr, maxy], [midr, midu]]), road_props), dsl.way(3, LineString([[midl, midu], [midl, midd]]), road_props), dsl.way(4, LineString([[midr, midu], [midr, midd]]), road_props), dsl.way(5, LineString([[midl, midd], [midl, miny]]), road_props), dsl.way(6, LineString([[midr, midd], [midr, miny]]), road_props), dsl.way(7, LineString([[minx, midu], [midl, midu]]), road_props), dsl.way(8, LineString([[minx, midd], [midl, midd]]), road_props), dsl.way(9, LineString([[midl, midu], [midr, midu]]), road_props), dsl.way(10, LineString([[midl, midd], [midr, midd]]), road_props), dsl.way(11, LineString([[midr, midu], [maxx, midu]]), road_props), dsl.way(12, LineString([[midr, midd], [maxx, midd]]), road_props), ) class ApproxCoordSet(object): def __init__(self, coords, tolerance): self.coords = coords self.tolerance = tolerance def check_and_remove(self, item): x, y = item for ex, ey in self.coords: if abs(x - ex) < self.tolerance and \ abs(y - ey) < self.tolerance: self.coords.remove((ex, ey)) return True return False # scale from the coordinates within the tile to the coords in the # generated tile. scale = 20026376.39 / 180.0 tolerance = scale * 1.0e-4 with self.features_in_tile_layer(z, x, y, 'roads') as features: self.assertTrue( len(features) == 2, "expected 2 features, got %d" % (len(features), )) expected_coords = ApproxCoordSet([ (midl * scale, maxy * scale), (midl * scale, miny * scale), (midr * scale, maxy * scale), (midr * scale, miny * scale), (minx * scale, midu * scale), (minx * scale, midd * scale), (maxx * scale, midu * scale), (maxx * scale, midd * scale), ], tolerance) if len(features) == 2: for i in (0, 1): # the shapes should be multilinestrings with two lines. shape = asShape(features[i]['geometry']) self.assertTrue(shape.geom_type == 'MultiLineString') self.assertTrue( len(shape.geoms) == 2, "expected 2 geometries in the MultiLineString, but " "there are %d" % (len(shape.geoms), )) for line_i in (0, 1): # each line should consist of only two points line = shape.geoms[line_i] self.assertTrue( len(line.coords) == 2, "expected 2 points, but line has %d" % (len(line.coords), )) for coord_i in (0, 1): coord = line.coords[coord_i] self.assertTrue( expected_coords.check_and_remove(coord), "%r not in expected set %r" % (coord, expected_coords.coords))
def test_non_maritime_boundary(self): from tilequeue.tile import coord_to_bounds from shapely.geometry import LineString from ModestMaps.Core import Coordinate import dsl z, x, y = (8, 44, 88) left_props = { 'source': 'openstreetmap.org', 'boundary': 'administrative', 'admin_level': '2', 'name': 'Country 1', 'mz_boundary_from_polygon': True, # need this for hack } right_props = { 'source': 'openstreetmap.org', 'boundary': 'administrative', 'admin_level': '2', 'name': 'Country 2', 'mz_boundary_from_polygon': True, # need this for hack } minx, miny, maxx, maxy = coord_to_bounds( Coordinate(zoom=z, column=x, row=y)) # move the coordinate points slightly out of the tile, so that we # don't get borders along the sides of the tile. w = maxx - minx h = maxy - miny minx -= 0.5 * w miny -= 0.5 * h maxx += 0.5 * w maxy += 0.5 * h self.generate_fixtures( dsl.way(1, dsl.tile_box(z, x, y), { 'source': 'tilezen.org', 'maritime_boundary': True, 'min_zoom': 0, 'kind': 'maritime', }), dsl.way( 1, LineString([ [minx, miny], [minx, maxy], [maxx, maxy], [minx, miny], ]), left_props, ), dsl.way( 2, LineString([ [minx, miny], [maxx, maxy], [maxx, miny], [minx, miny], ]), right_props, ), ) self.assert_has_feature( z, x, y, 'boundaries', { 'kind': 'country', 'maritime_boundary': type(None), 'collision_rank': 807, })
def _check(self, aerodrome_type, runway_kind_detail): import dsl from tilequeue.tile import coord_to_bounds from shapely.geometry import LineString from shapely.geometry import CAP_STYLE from ModestMaps.Core import Coordinate z, x, y = (16, 0, 0) bounds = coord_to_bounds(Coordinate(zoom=z, column=x, row=y)) # runway line that runs from a quarter to three quarters of the # tile diagonal. this is so that we can buffer it without it # going outside the tile boundary. runway_line = LineString([ [ bounds[0] + 0.25 * (bounds[2] - bounds[0]), bounds[1] + 0.25 * (bounds[3] - bounds[1]) ], [ bounds[0] + 0.75 * (bounds[2] - bounds[0]), bounds[1] + 0.75 * (bounds[3] - bounds[1]) ], ]) # runway polygon which has the runway line as a centreline. runway_poly = runway_line.buffer( 0.1 * (bounds[2] - bounds[0]), # width 1/10th of a tile cap_style=CAP_STYLE.flat, ) self.generate_fixtures( dsl.way( 1, dsl.tile_box(z, x, y), { 'aeroway': 'aerodrome', 'aerodrome:type': aerodrome_type, 'name': 'Fake Aerodrome', 'source': 'openstreetmap.org', }), # runway line dsl.way(2, runway_line, { 'aeroway': 'runway', 'source': 'openstreetmap.org', }), # runway polygon dsl.way(3, runway_poly, { 'area:aeroway': 'runway', 'source': 'openstreetmap.org', })) # runway line ends up in roads layer self.assert_has_feature( z, x, y, 'roads', { 'id': 2, 'kind': 'aeroway', 'kind_detail': 'runway', 'aerodrome_kind_detail': runway_kind_detail, }) # runway polygon is in landuse self.assert_has_feature(z, x, y, 'landuse', { 'id': 3, 'kind': 'runway', 'kind_detail': runway_kind_detail, })
def test_junction_hash(self): from tilequeue.tile import coord_to_bounds from shapely.geometry import LineString, asShape from ModestMaps.Core import Coordinate import dsl z, x, y = (12, 2048, 2048) minx, miny, maxx, maxy = coord_to_bounds( Coordinate(zoom=z, column=x, row=y)) midl = minx + (maxx - minx) / 3 midr = minx + 2 * (maxx - minx) / 3 midd = miny + (maxy - miny) / 3 midu = miny + 2 * (maxy - miny) / 3 road_props = dict( highway='residential', source='openstreetmap.org', ) # make a tile with 4 roads in a # shape, as below. # # | | # 1 2 # | | # --7--+--8--+--9-- # | | # 3 4 # | | # -10--+-11--+-12-- # | | # 5 6 # | | # # these should get merged into two features, one with 1->3->5 and # 2->4->6 and the other with 7->8->9 and 10->11->12. self.generate_fixtures( dsl.way(1, LineString([[midl, maxy], [midl, midu]]), road_props), dsl.way(2, LineString([[midr, maxy], [midr, midu]]), road_props), dsl.way(3, LineString([[midl, midu], [midl, midd]]), road_props), dsl.way(4, LineString([[midr, midu], [midr, midd]]), road_props), dsl.way(5, LineString([[midl, midd], [midl, miny]]), road_props), dsl.way(6, LineString([[midr, midd], [midr, miny]]), road_props), dsl.way(7, LineString([[minx, midu], [midl, midu]]), road_props), dsl.way(8, LineString([[minx, midd], [midl, midd]]), road_props), dsl.way(9, LineString([[midl, midu], [midr, midu]]), road_props), dsl.way(10, LineString([[midl, midd], [midr, midd]]), road_props), dsl.way(11, LineString([[midr, midu], [maxx, midu]]), road_props), dsl.way(12, LineString([[midr, midd], [maxx, midd]]), road_props), ) class ApproxCoordSet(object): def __init__(self, coords, tolerance): self.coords = coords self.tolerance = tolerance def check_and_remove(self, item): x, y = item for ex, ey in self.coords: if abs(x - ex) < self.tolerance and \ abs(y - ey) < self.tolerance: self.coords.remove((ex, ey)) return True return False # scale from the coordinates within the tile to the coords in the # generated tile. scale = 20026376.39 / 180.0 tolerance = scale * 1.0e-4 with self.features_in_tile_layer(z, x, y, 'roads') as features: self.assertTrue(len(features) == 2, "expected 2 features, got %d" % (len(features),)) expected_coords = ApproxCoordSet([ (midl * scale, maxy * scale), (midl * scale, miny * scale), (midr * scale, maxy * scale), (midr * scale, miny * scale), (minx * scale, midu * scale), (minx * scale, midd * scale), (maxx * scale, midu * scale), (maxx * scale, midd * scale), ], tolerance) if len(features) == 2: for i in (0, 1): # the shapes should be multilinestrings with two lines. shape = asShape(features[i]['geometry']) self.assertTrue(shape.geom_type == 'MultiLineString') self.assertTrue( len(shape.geoms) == 2, "expected 2 geometries in the MultiLineString, but " "there are %d" % (len(shape.geoms),)) for line_i in (0, 1): # each line should consist of only two points line = shape.geoms[line_i] self.assertTrue( len(line.coords) == 2, "expected 2 points, but line has %d" % (len(line.coords),)) for coord_i in (0, 1): coord = line.coords[coord_i] self.assertTrue( expected_coords.check_and_remove(coord), "%r not in expected set %r" % (coord, expected_coords.coords))
def test_non_maritime_boundary(self): from tilequeue.tile import coord_to_bounds from shapely.geometry import LineString from ModestMaps.Core import Coordinate import dsl z, x, y = (8, 44, 88) left_props = { 'source': 'openstreetmap.org', 'boundary': 'administrative', 'admin_level': '2', 'name': 'Country 1', } right_props = { 'source': 'openstreetmap.org', 'boundary': 'administrative', 'admin_level': '2', 'name': 'Country 2', } minx, miny, maxx, maxy = coord_to_bounds( Coordinate(zoom=z, column=x, row=y)) # move the coordinate points slightly out of the tile, so that we # don't get borders along the sides of the tile. w = maxx - minx h = maxy - miny minx -= 0.5 * w miny -= 0.5 * h maxx += 0.5 * w maxy += 0.5 * h self.generate_fixtures( dsl.way( 1, dsl.tile_box(z, x, y), { 'source': 'tilezen.org', 'maritime_boundary': True, 'min_zoom': 0, 'kind': 'maritime', }), dsl.way( 1, LineString([ [minx, miny], [minx, maxy], [maxx, maxy], [minx, miny], ]), left_props, ), dsl.way( 2, LineString([ [minx, miny], [maxx, maxy], [maxx, miny], [minx, miny], ]), right_props, ), ) self.assert_has_feature( z, x, y, 'boundaries', { 'kind': 'country', 'maritime_boundary': type(None), 'collision_rank': 807, })
def test_roads_merged(self): from collections import defaultdict from shapely.geometry import asShape from tilequeue.tile import coord_to_bounds from shapely.geometry import LineString from ModestMaps.Core import Coordinate import dsl z, x, y = 8, 41, 99 bounds = coord_to_bounds(Coordinate(zoom=z, column=x, row=y)) def _line(frac): return LineString([ [bounds[0] + frac * (bounds[2] - bounds[0]), bounds[1]], [bounds[0] + frac * (bounds[2] - bounds[0]), bounds[3]], ]) # count the unique parameters - there should only be one, indicating # that the roads have been merged. self.generate_fixtures( dsl.way(1, _line(0.1), { 'highway': 'motorway', 'source': 'openstreetmap.org', }), dsl.way(2, _line(0.2), { 'highway': 'motorway', 'source': 'openstreetmap.org', }), dsl.way(3, _line(0.3), { 'highway': 'primary', 'source': 'openstreetmap.org', }), dsl.way(4, _line(0.4), { 'highway': 'primary', 'source': 'openstreetmap.org', }), dsl.way(5, _line(0.5), { 'highway': 'trunk', 'source': 'openstreetmap.org', }), dsl.way(6, _line(0.6), { 'highway': 'trunk', 'source': 'openstreetmap.org', }), ) with self.features_in_tile_layer(z, x, y, 'roads') as roads: features = defaultdict(list) for road in roads: props = frozenset(_freeze(road['properties'])) geom = asShape(road['geometry']) for f in features[props]: if f.disjoint(geom): self.assertTrue( False, 'Duplicate properties %r in roads layer for ' 'disjoint geometries (%r & %r), but ' 'properties should be unique or geometries ' 'intersecting.' % (road['properties'], f.wkt, geom.wkt)) features[props].append(geom)