def test_intersecting(): """Get intersecting Tiles from other TilePyramid.""" tp_source = TilePyramid("geodetic", metatiling=2) tp_target = TilePyramid("geodetic") tile = tp_source.tile(5, 2, 2) test_tiles = {(5, 4, 4), (5, 5, 4), (5, 4, 5), (5, 5, 5)} intersecting_tiles = {t.id for t in tile.intersecting(tp_target)} assert test_tiles == intersecting_tiles
def test_init(): """Initialize TilePyramids.""" for tptype in ["geodetic", "mercator"]: assert TilePyramid(tptype) with pytest.raises(ValueError): TilePyramid("invalid") with pytest.raises(ValueError): TilePyramid() assert hash(TilePyramid(tptype))
def test_metatiling(): """Metatiling setting.""" for metatiling in [1, 2, 4, 8, 16]: assert TilePyramid("geodetic", metatiling=metatiling) try: TilePyramid("geodetic", metatiling=5) raise Exception() except ValueError: pass
def test_tiles_from_point(point): """Get tile from point.""" for metatiling in [1, 2, 4, 8, 16]: tp = TilePyramid("geodetic", metatiling=metatiling) tile_bbox = next(tp.tiles_from_geom(point, 6)).bbox() assert point.within(tile_bbox) tp = TilePyramid("geodetic") with pytest.raises(ValueError): next(tp.tiles_from_geom(Point(-300, 100), 6))
def test_simple_shapes(): """Without metatiling & buffer.""" # default tile = TilePyramid("geodetic").tile(0, 0, 0) assert tile.width == tile.height == 256 assert tile.shape() == (256, 256) # 512x512 tile = TilePyramid("geodetic", tile_size=512).tile(0, 0, 0) assert tile.width == tile.height == 512 assert tile.shape() == (512, 512)
def test_intersect(): """Get intersecting Tiles.""" # same metatiling tp = TilePyramid("geodetic") intersect_tile = TilePyramid("geodetic").tile(5, 1, 1) control = {(5, 1, 1)} test_tiles = {tile.id for tile in tp.intersecting(intersect_tile)} assert control == test_tiles # smaller metatiling tp = TilePyramid("geodetic") intersect_tile = TilePyramid("geodetic", metatiling=2).tile(5, 1, 1) control = {(5, 2, 2), (5, 2, 3), (5, 3, 3), (5, 3, 2)} test_tiles = {tile.id for tile in tp.intersecting(intersect_tile)} assert control == test_tiles # bigger metatiling tp = TilePyramid("geodetic", metatiling=2) intersect_tile = TilePyramid("geodetic").tile(5, 1, 1) control = {(5, 0, 0)} test_tiles = {tile.id for tile in tp.intersecting(intersect_tile)} assert control == test_tiles intersect_tile = TilePyramid("geodetic").tile(4, 12, 31) control = {(4, 6, 15)} test_tiles = {tile.id for tile in tp.intersecting(intersect_tile)} assert control == test_tiles # different CRSes tp = TilePyramid("geodetic") intersect_tile = TilePyramid("mercator").tile(5, 1, 1) try: test_tiles = {tile.id for tile in tp.intersecting(intersect_tile)} raise Exception() except ValueError: pass
def test_get_neighbors(grid_definition_proj): """Get Tile neighbors.""" tp = TilePyramid("geodetic") # default tile = tp.tile(8, 100, 100) # 8 neighbors test_neighbors = {(8, 101, 100), (8, 100, 101), (8, 99, 100), (8, 100, 99), (8, 99, 101), (8, 101, 101), (8, 101, 99), (8, 99, 99)} neighbors = {t.id for t in tile.get_neighbors()} assert test_neighbors == neighbors # 4 neighbors test_neighbors = {(8, 101, 100), (8, 100, 101), (8, 99, 100), (8, 100, 99)} neighbors = {t.id for t in tile.get_neighbors(connectedness=4)} assert test_neighbors == neighbors # over antimeridian tile = tp.tile(3, 1, 0) # 8 neighbors test_neighbors = {(3, 0, 0), (3, 1, 1), (3, 2, 0), (3, 1, 15), (3, 0, 1), (3, 2, 1), (3, 2, 15), (3, 0, 15)} neighbors = {t.id for t in tile.get_neighbors()} assert test_neighbors == neighbors # 4 neighbors test_neighbors = {(3, 0, 0), (3, 1, 1), (3, 2, 0), (3, 1, 15)} neighbors = {t.id for t in tile.get_neighbors(connectedness=4)} assert test_neighbors == neighbors # tile has exactly two identical neighbors tile = tp.tile(0, 0, 0) test_tile = [(0, 0, 1)] neighbors = [t.id for t in tile.get_neighbors()] assert test_tile == neighbors # tile is alone at current zoom level tp = TilePyramid("geodetic", metatiling=2) tile = tp.tile(0, 0, 0) neighbors = [t.id for t in tile.get_neighbors()] assert neighbors == [] # wrong connectedness parameter try: tile.get_neighbors(connectedness="wrong_param") raise Exception() except ValueError: pass # neighbors on non-global tilepyramids tp = TilePyramid(grid_definition_proj) zoom = 5 max_col = tp.matrix_width(zoom) - 1 tile = tp.tile(zoom=zoom, row=3, col=max_col) # don't wrap around antimeridian, i.e. there are no tile neighbors assert len(tile.get_neighbors()) == 5
def test_tiles_from_bounds(grid_definition_proj): # global pyramids tp = TilePyramid("geodetic") parent = tp.tile(8, 5, 5) from_bounds = set([t.id for t in tp.tiles_from_bounds(parent.bounds(), 9)]) children = set([t.id for t in parent.get_children()]) assert from_bounds == children # non-global pyramids tp = TilePyramid(grid_definition_proj) parent = tp.tile(8, 0, 0) from_bounds = set([t.id for t in tp.tiles_from_bounds(parent.bounds(), 9)]) children = set([t.id for t in parent.get_children()]) assert from_bounds == children
def test_custom(grid_definition_proj, grid_definition_epsg): for grid_def in [grid_definition_proj, grid_definition_epsg]: tp = TilePyramid(grid_def, metatiling=8) tp_dict = tp.to_dict() assert isinstance(tp_dict, dict) tp2 = TilePyramid.from_dict(tp_dict) assert tp == tp2
def __init__(self, output_params): """Initialize.""" self.pixelbuffer = output_params["pixelbuffer"] self.pyramid = TilePyramid(output_params["type"], metatiling=output_params["metatiling"]) self.crs = self.pyramid.crs self.srid = self.pyramid.srid
def _run_bbox_bounds(zoom, row, col, command=None, grid="geodetic", metatiling=1, pixelbuffer=0, tile_size=256, output_format="WKT"): tile = TilePyramid(grid, metatiling=metatiling, tile_size=tile_size).tile(zoom, row, col) result = CliRunner().invoke(tmx, [ "--pixelbuffer", str(pixelbuffer), "--metatiling", str(metatiling), "--grid", grid, "--tile_size", str(tile_size), "--output_format", output_format, command, str(zoom), str(row), str(col) ]) assert result.exit_code == 0 if command == "bounds": assert result.output.strip() == " ".join( map(str, tile.bounds(pixelbuffer))) elif output_format == "WKT": assert wkt.loads(result.output.strip()).almost_equals( tile.bbox(pixelbuffer)) elif output_format == "GeoJSON": assert shape(geojson.loads(result.output.strip())).almost_equals( tile.bbox(pixelbuffer))
def test_tiles_from_bounds_batch_by_row_both_antimeridian_bounds(): tp = TilePyramid("geodetic") bounds = (-185, 0, 185, 95) zoom = 8 tiles = tp.tiles_from_bounds(bounds, zoom, batch_by="row") assert isinstance(tiles, GeneratorType) assert list(tiles) previous_row = None tiles = 0 for tile_row in tp.tiles_from_bounds(bounds, zoom, batch_by="row"): assert isinstance(tile_row, GeneratorType) previous_tile = None for tile in tile_row: tiles += 1 if previous_row is None: if previous_tile is not None: assert tile.col == previous_tile.col + 1 else: if previous_tile is not None: assert tile.col == previous_tile.col + 1 assert tile.row == previous_tile.row assert tile.row == previous_row + 1 previous_tile = tile previous_row = tile.row assert tiles == len(list(tp.tiles_from_bounds(bounds, zoom)))
def params_to_dump(params): # in case GridDefinition was not yet initialized if isinstance(params["type"], str): tp = TilePyramid(params["type"]) params.update(type=tp.grid) return dict(pyramid=dict( grid=dict( type=params["type"].type, shape=list(params["type"].shape), bounds=list(params["type"].bounds), left=params["type"].left, bottom=params["type"].bottom, right=params["type"].right, top=params["type"].top, is_global=params["type"].is_global, srid=params["type"].srid, crs=params["type"].crs.to_string(), ), metatiling=params.get("metatiling", 1), pixelbuffer=params.get("pixelbuffer", 0), ), driver={ k: v for k, v in params.items() if k not in ["path", "type", "pixelbuffer", "metatiling"] })
def _run_tiles(zoom, bounds, grid="geodetic", metatiling=1, pixelbuffer=0, tile_size=256, output_format="WKT"): left, bottom, right, top = bounds tiles = list( TilePyramid(grid, metatiling=metatiling, tile_size=tile_size).tiles_from_bounds(bounds, zoom)) result = CliRunner().invoke(tmx, [ "--pixelbuffer", str(pixelbuffer), "--metatiling", str(metatiling), "--grid", grid, "--tile_size", str(tile_size), "--output_format", output_format, "tiles", str(zoom), str(left), str(bottom), str(right), str(top) ]) assert result.exit_code == 0 if output_format == "Tile": assert result.output.count('\n') == len(tiles) elif output_format == "WKT": assert result.output.count('\n') == len(tiles) elif output_format == "GeoJSON": features = geojson.loads(result.output.strip())["features"] assert len(features) == len(tiles)
def count_tiles(geometry, pyramid, minzoom, maxzoom, init_zoom=0): """ Count number of tiles intersecting with geometry. Parameters ---------- geometry : shapely geometry pyramid : TilePyramid minzoom : int maxzoom : int init_zoom : int Returns ------- number of tiles """ if not 0 <= init_zoom <= minzoom <= maxzoom: raise ValueError("invalid zoom levels given") # tile buffers are not being taken into account unbuffered_pyramid = TilePyramid(pyramid.grid, tile_size=pyramid.tile_size, metatiling=pyramid.metatiling) # make sure no rounding errors occur geometry = geometry.buffer(-0.000000001) return _count_tiles([ unbuffered_pyramid.tile(*tile_id) for tile_id in product([init_zoom], range(pyramid.matrix_height(init_zoom)), range(pyramid.matrix_width(init_zoom))) ], geometry, minzoom, maxzoom)
def test_shape_error(grid_definition_epsg): """Raise error when shape aspect ratio is not bounds apsect ratio.""" grid_definition_epsg.update( bounds=(2426378.0132, 1528101.2618, 6293974.6215, 5446513.5222) ) with pytest.raises(ValueError): TilePyramid(grid_definition_epsg)
def _run_tile(zoom, point, grid="geodetic", metatiling=1, pixelbuffer=0, tile_size=256, output_format="WKT"): x, y, = point tile = TilePyramid(grid, metatiling=metatiling, tile_size=tile_size).tile_from_xy(x, y, zoom) result = CliRunner().invoke(tmx, [ "--pixelbuffer", str(pixelbuffer), "--metatiling", str(metatiling), "--grid", grid, "--tile_size", str(tile_size), "--output_format", output_format, "tile", str(zoom), str(x), str(y) ]) assert result.exit_code == 0 if output_format == "Tile": assert result.output.strip() == " ".join(map(str, tile.id)) elif output_format == "WKT": assert wkt.loads(result.output.strip()).almost_equals( tile.bbox(pixelbuffer)) elif output_format == "GeoJSON": feature = geojson.loads(result.output.strip())["features"][0] assert shape(feature["geometry"]).almost_equals(tile.bbox(pixelbuffer))
def test_tiles_from_polygon(polygon): """Get tiles from Polygon.""" test_tiles = { (9, 116, 544), (9, 116, 545), (9, 116, 546), (9, 117, 540), (9, 117, 541), (9, 117, 542), (9, 117, 543), (9, 117, 544), (9, 117, 545), (9, 118, 536), (9, 118, 537), (9, 118, 538), (9, 118, 539), (9, 118, 540), (9, 118, 541), (9, 119, 535), (9, 119, 536), (9, 119, 537), (9, 119, 538), } tp = TilePyramid("geodetic") polygon_tiles = {tile.id for tile in tp.tiles_from_geom(polygon, 9)} assert polygon_tiles == test_tiles
def test_tiles_from_bounds_batch_by_column(): tp = TilePyramid("geodetic") bounds = (0, 0, 90, 90) zoom = 8 tiles = tp.tiles_from_bounds(bounds, zoom, batch_by="column") assert isinstance(tiles, GeneratorType) assert list(tiles) previous_column = None tiles = 0 for tile_column in tp.tiles_from_bounds(bounds, zoom, batch_by="column"): assert isinstance(tile_column, GeneratorType) previous_tile = None for tile in tile_column: tiles += 1 if previous_column is None: if previous_tile is not None: assert tile.row == previous_tile.row + 1 else: if previous_tile is not None: assert tile.row == previous_tile.row + 1 assert tile.col == previous_tile.col assert tile.col == previous_column + 1 previous_tile = tile previous_column = tile.col assert tiles == len(list(tp.tiles_from_bounds(bounds, zoom)))
def bounds(ctx, tile): """Print Tile bounds.""" click.echo("%s %s %s %s" % TilePyramid( ctx.obj["grid"], tile_size=ctx.obj["tile_size"], metatiling=ctx.obj["metatiling"], ).tile(*tile).bounds(pixelbuffer=ctx.obj["pixelbuffer"]))
def tiles(ctx, bounds, zoom): """Print Tiles from bounds.""" tiles = TilePyramid( ctx.obj["grid"], tile_size=ctx.obj["tile_size"], metatiling=ctx.obj["metatiling"], ).tiles_from_bounds(bounds, zoom=zoom) if ctx.obj["output_format"] == "Tile": for tile in tiles: click.echo("%s %s %s" % tile.id) elif ctx.obj["output_format"] == "WKT": for tile in tiles: click.echo(tile.bbox(pixelbuffer=ctx.obj["pixelbuffer"])) elif ctx.obj["output_format"] == "GeoJSON": click.echo("{\n" ' "type": "FeatureCollection",\n' ' "features": [') # print tiles as they come and only add comma if there is a next tile try: tile = next(tiles) while True: gj = " %s" % geojson.Feature( geometry=tile.bbox(pixelbuffer=ctx.obj["pixelbuffer"]), properties=dict(zoom=tile.zoom, row=tile.row, col=tile.col), ) try: tile = next(tiles) click.echo(gj + ",") except StopIteration: click.echo(gj) raise except StopIteration: pass click.echo(" ]\n" "}")
def test_deprecated(): tp = TilePyramid("geodetic") assert tp.type assert tp.srid assert tp.tile_x_size(0) assert tp.tile_y_size(0) assert tp.tile_height(0) assert tp.tile_width(0)
def test_tile_tuple(): tp = TilePyramid("geodetic") a = tp.tile(5, 5, 5) assert tuple(a) == ( 5, 5, 5, )
def test_tiles_from_bounds(grid_definition_irregular): bounds = (755336.179, 300068.615, 791558.022, 319499.955) bbox = box(*bounds) tp = TilePyramid(grid_definition_irregular, metatiling=4) tiles_bounds = list(tp.tiles_from_bounds(bounds, 0)) tiles_bbox = list(tp.tiles_from_bbox(bbox, 0)) tiles_geom = list(tp.tiles_from_geom(bbox, 0)) assert set(tiles_bounds) == set(tiles_bbox) == set(tiles_geom)
def __init__(self, tile, pixelbuffer=0): """Initialize.""" if isinstance(tile, BufferedTile): tile = TilePyramid(tile.tp.grid, tile_size=tile.tp.tile_size, metatiling=tile.tp.metatiling).tile(*tile.id) Tile.__init__(self, tile.tile_pyramid, tile.zoom, tile.row, tile.col) self._tile = tile self.pixelbuffer = pixelbuffer
def test_get_parent(): """Get parent Tile.""" tp = TilePyramid("geodetic") # default tile = tp.tile(8, 100, 100) assert tile.get_parent().id == (7, 50, 50) # from top of pyramid tile = tp.tile(0, 0, 0) assert tile.get_parent() is None
def __init__(self, output_params, readonly=False): """Initialize.""" self.pixelbuffer = output_params["pixelbuffer"] self.pyramid = TilePyramid(output_params["type"], metatiling=output_params["metatiling"]) self.crs = self.pyramid.crs self.srid = self.pyramid.srid self._bucket = None if not readonly: write_output_metadata(output_params)
def test_tile_compare(): tp = TilePyramid("geodetic") a = tp.tile(5, 5, 5) b = tp.tile(5, 5, 5) c = tp.tile(5, 5, 6) assert a == b assert a != c assert b != c assert a != "invalid type" assert len(set([a, b, c])) == 2
def bbox(ctx, tile): """Print Tile bounding box as geometry.""" geom = (TilePyramid( ctx.obj["grid"], tile_size=ctx.obj["tile_size"], metatiling=ctx.obj["metatiling"], ).tile(*tile).bbox(pixelbuffer=ctx.obj["pixelbuffer"])) if ctx.obj["output_format"] in ["WKT", "Tile"]: click.echo(geom) elif ctx.obj["output_format"] == "GeoJSON": click.echo(geojson.dumps(geom))
def snap_bounds(ctx, bounds, zoom): """nap bounds to tile grid.""" click.echo("%s %s %s %s" % tilematrix.snap_bounds( bounds=bounds, tile_pyramid=TilePyramid( ctx.obj["grid"], tile_size=ctx.obj["tile_size"], metatiling=ctx.obj["metatiling"], ), zoom=zoom, pixelbuffer=ctx.obj["pixelbuffer"], ))