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
Example #2
0
    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'
        })
Example #7
0
    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')
Example #8
0
 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)
Example #9
0
    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)
Example #10
0
 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))
Example #11
0
 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)
Example #13
0
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)
Example #14
0
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
                }
            ),
        )
Example #19
0
 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))
Example #20
0
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
Example #21
0
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
Example #22
0
    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,
            })
Example #26
0
    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)