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 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 __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 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 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 _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 _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_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_tile_tuple(): tp = TilePyramid("geodetic") a = tp.tile(5, 5, 5) assert tuple(a) == ( 5, 5, 5, )
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_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_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 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 __init__( self, pyramid_type, metatiling=1, tile_size=256, pixelbuffer=0 ): """Initialize.""" TilePyramid.__init__( self, pyramid_type, metatiling=metatiling, tile_size=tile_size) self.tile_pyramid = TilePyramid( pyramid_type, metatiling=metatiling, tile_size=tile_size) self.metatiling = metatiling if isinstance(pixelbuffer, int) and pixelbuffer >= 0: self.pixelbuffer = pixelbuffer else: raise ValueError("pixelbuffer has to be a non-negative int")
def test_tiles_from_point_batches(point): """Get tile from point.""" tp = TilePyramid("geodetic") zoom = 9 tiles = 0 gen = tp.tiles_from_geom(point, zoom, batch_by="row") assert isinstance(gen, GeneratorType) for row in gen: assert isinstance(row, GeneratorType) for tile in row: tiles += 1 assert isinstance(tile, Tile) assert tiles assert tiles == len(list(tp.tiles_from_geom(point, zoom)))
def test_tiles_from_linestring_batches(linestring): """Get tiles from LineString.""" tp = TilePyramid("geodetic") zoom = 9 tiles = 0 gen = tp.tiles_from_geom(linestring, zoom, batch_by="row") assert isinstance(gen, GeneratorType) for row in gen: assert isinstance(row, GeneratorType) for tile in row: tiles += 1 assert isinstance(tile, Tile) assert tiles assert tiles == len(list(tp.tiles_from_geom(linestring, zoom)))
def test_tiles_from_multipolygon_batches(multipolygon): """Get tiles from MultiPolygon.""" tp = TilePyramid("geodetic") zoom = 9 tiles = 0 gen = tp.tiles_from_geom(multipolygon, zoom, batch_by="row") assert isinstance(gen, GeneratorType) for row in gen: assert isinstance(row, GeneratorType) for tile in row: tiles += 1 assert isinstance(tile, Tile) assert tiles assert tiles == len(list(tp.tiles_from_geom(multipolygon, zoom)))
def test_tiles_from_linestring(linestring): """Get tiles from LineString.""" test_tiles = { (8, 58, 270), (8, 58, 271), (8, 58, 272), (8, 58, 273), (8, 59, 267), (8, 59, 268), (8, 59, 269), (8, 59, 270), } tp = TilePyramid("geodetic") linestring_tiles = {tile.id for tile in tp.tiles_from_geom(linestring, 8)} assert linestring_tiles == test_tiles
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 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 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 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 _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 get_best_zoom_level(input_file, tile_pyramid_type): """ Determine the best base zoom level for a raster. "Best" means the maximum zoom level where no oversampling has to be done. Parameters ---------- input_file : path to raster file tile_pyramid_type : ``TilePyramid`` projection (``geodetic`` or ``mercator``) Returns ------- zoom : integer """ tile_pyramid = TilePyramid(tile_pyramid_type) with rasterio.open(input_file, "r") as src: if not src.crs.is_valid: raise IOError("CRS could not be read from %s" % input_file) bbox = box( src.bounds.left, src.bounds.bottom, src.bounds.right, src.bounds.top) if src.crs != tile_pyramid.crs: segmentize = raster_file._get_segmentize_value( input_file, tile_pyramid) ogr_bbox = ogr.CreateGeometryFromWkb(bbox.wkb) ogr_bbox.Segmentize(segmentize) segmentized_bbox = loads(ogr_bbox.ExportToWkt()) bbox = segmentized_bbox xmin, ymin, xmax, ymax = reproject_geometry( bbox, src_crs=src.crs, dst_crs=tile_pyramid.crs).bounds else: xmin, ymin, xmax, ymax = bbox.bounds x_dif = xmax - xmin y_dif = ymax - ymin size = float(src.width + src.height) avg_resolution = ( (x_dif / float(src.width)) * (float(src.width) / size) + (y_dif / float(src.height)) * (float(src.height) / size) ) for zoom in range(0, 25): if tile_pyramid.pixel_x_size(zoom) <= avg_resolution: return zoom-1 raise ValueError("no fitting zoom level found")
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 __init__(self, mapchete_file, zoom=None, bounds=None): """ Initialize with a .mapchete file and optional zoom & bound parameters. """ try: self.config = get_clean_configuration( mapchete_file, zoom=zoom, bounds=bounds ) base_tile_pyramid = TilePyramid(str(self.config["output_srs"])) base_tile_pyramid.set_format(self.config["output_format"]) self.tile_pyramid = MetaTilePyramid( base_tile_pyramid, self.config["metatiling"] ) self.format = self.tile_pyramid.format except Exception as e: raise
def test_snap_bounds(): bounds = (0, 1, 2, 3) tp = TilePyramid("geodetic") zoom = 8 snapped = snap_bounds(bounds=bounds, tile_pyramid=tp, zoom=zoom) control = unary_union( [tile.bbox() for tile in tp.tiles_from_bounds(bounds, zoom)]).bounds assert snapped == control pixelbuffer = 10 snapped = snap_bounds(bounds=bounds, tile_pyramid=tp, zoom=zoom, pixelbuffer=pixelbuffer) control = unary_union([ tile.bbox(pixelbuffer) for tile in tp.tiles_from_bounds(bounds, zoom) ]).bounds assert snapped == control
def get_best_zoom_level(input_file, tile_pyramid_type): """ Determines the best base zoom level for a raster. "Best" means the maximum zoom level where no oversampling has to be done. """ tile_pyramid = TilePyramid(tile_pyramid_type) input_bbox = file_bbox(input_file, tile_pyramid) xmin, ymin, xmax, ymax = input_bbox.bounds with rasterio.open(input_file, "r") as src: x_dif = xmax - xmin y_dif = ymax - ymin size = float(src.width + src.height) avg_resolution = ( (x_dif / float(src.width)) * (float(src.width) / size) + (y_dif / float(src.height)) * (float(src.height) / size) ) for zoom in range(0, 25): if tile_pyramid.pixel_x_size(zoom) <= avg_resolution: return zoom-1 raise ValueError("no fitting zoom level found")
def main(): scriptdir = os.path.dirname(os.path.realpath(__file__)) # YAML configuration #=================== # Load source process from python file and initialize. mapchete_file = os.path.join(scriptdir, "example.mapchete") mapchete = Mapchete(MapcheteConfig(mapchete_file)) dummy1_abspath = os.path.join(scriptdir, "testdata/dummy1.tif") dummy2_abspath = os.path.join(scriptdir, "testdata/dummy2.tif") # Validate configuration constructor ## basic run through try: config = mapchete.config print "OK: basic configuraiton constructor run through" except: print "FAILED: basic configuraiton constructor run through" raise try: # Check configuration at zoom level 5 zoom5 = config.at_zoom(5) input_files = zoom5["input_files"] assert input_files["file1"] == None assert input_files["file2"] == dummy2_abspath assert zoom5["some_integer_parameter"] == 12 assert zoom5["some_float_parameter"] == 5.3 assert zoom5["some_string_parameter"] == "string1" assert zoom5["some_bool_parameter"] == True # Check configuration at zoom level 11 zoom11 = config.at_zoom(11) input_files = zoom11["input_files"] assert input_files["file1"] == dummy1_abspath assert input_files["file2"] == dummy2_abspath assert zoom11["some_integer_parameter"] == 12 assert zoom11["some_float_parameter"] == 5.3 assert zoom11["some_string_parameter"] == "string2" assert zoom11["some_bool_parameter"] == True except: print "FAILED: basic configuration parsing" print input_files raise else: print "OK: basic configuration parsing" ## read zoom level from config file mapchete_file = os.path.join(scriptdir, "testdata/zoom.mapchete") config = Mapchete(MapcheteConfig(mapchete_file)).config try: assert 5 in config.zoom_levels print "OK: read zoom level from config file" except: print "FAILED: read zoom level from config file" print mapchete_file raise ## read min/max zoom levels from config file mapchete_file = os.path.join(scriptdir, "testdata/minmax_zoom.mapchete") config = Mapchete(MapcheteConfig(mapchete_file)).config try: for zoom in [7, 8, 9, 10]: assert zoom in config.zoom_levels print "OK: read min/max zoom levels from config file" except: print "FAILED: read min/max zoom levels from config file" raise ## zoom levels override mapchete_file = os.path.join(scriptdir, "testdata/minmax_zoom.mapchete") config = Mapchete(MapcheteConfig(mapchete_file, zoom=[1, 4])).config try: for zoom in [1, 2, 3, 4]: assert zoom in config.zoom_levels print "OK: zoom levels override" except: print "FAILED: zoom levels override" raise ## read bounds from config file mapchete_file = os.path.join(scriptdir, "testdata/zoom.mapchete") config = Mapchete(MapcheteConfig(mapchete_file)).config try: test_polygon = Polygon([ [3, 1.5], [3, 2], [3.5, 2], [3.5, 1.5], [3, 1.5] ]) assert config.process_area(5).equals(test_polygon) print "OK: read bounds from config file" except: print "FAILED: read bounds from config file" print config.process_area(5), test_polygon raise ## override bounds mapchete_file = os.path.join(scriptdir, "testdata/zoom.mapchete") config = Mapchete(MapcheteConfig( mapchete_file, bounds=[3, 2, 3.5, 1.5] )).config try: test_polygon = Polygon([ [3, 1.5], [3, 2], [3.5, 2], [3.5, 1.5], [3, 1.5] ]) assert config.process_area(5).equals(test_polygon) print "OK: override bounds" except: print "FAILED: override bounds" print config.process_area(5) raise ## read bounds from input files mapchete_file = os.path.join(scriptdir, "testdata/files_bounds.mapchete") config = Mapchete(MapcheteConfig(mapchete_file)).config try: test_polygon = Polygon( [[3, 2], [4, 2], [4, 1], [3, 1], [2, 1], [2, 4], [3, 4], [3, 2]] ) assert config.process_area(10).equals(test_polygon) print "OK: read bounds from input files" except: print "FAILED: read bounds from input files" print config.process_area(10), test_polygon raise ## read .mapchete files as input files mapchete_file = os.path.join(scriptdir, "testdata/mapchete_input.mapchete") config = Mapchete(MapcheteConfig(mapchete_file)).config area = config.process_area(5) testpolygon = "POLYGON ((3 2, 3.5 2, 3.5 1.5, 3 1.5, 3 1, 2 1, 2 4, 3 4, 3 2))" try: assert area.equals(loads(testpolygon)) print "OK: read bounding box from .mapchete subfile" except: print "FAILED: read bounding box from .mapchete subfile" raise mapchete_file = os.path.join(scriptdir, "testdata/gtiff.mapchete") mapchete_file = os.path.join(scriptdir, "testdata/numpy.mapchete") mapchete = Mapchete(MapcheteConfig(mapchete_file)) # test io module testdata_directory = os.path.join(scriptdir, "testdata") outdata_directory = os.path.join(testdata_directory, "out") dummy1 = os.path.join(testdata_directory, "dummy1.tif") # dummy1 = os.path.join(testdata_directory, "sentinel2.tif") dummy2 = os.path.join(testdata_directory, "dummy2.tif") zoom = 8 tile_pyramid = TilePyramid("geodetic") dummy1_bbox = file_bbox(dummy1, tile_pyramid) tiles = tile_pyramid.tiles_from_geom(dummy1_bbox, zoom) resampling = "average" pixelbuffer=5 for tile in tiles: for band in read_raster_window( dummy1, tile, resampling=resampling, pixelbuffer=pixelbuffer ): try: assert band.shape == ( tile_pyramid.tile_size + 2 * pixelbuffer, tile_pyramid.tile_size + 2 * pixelbuffer ) print "OK: read data size" except: print "FAILED: read data size" outname = str(tile.zoom) + str(tile.row) + str(tile.col) + ".tif" outfile = os.path.join(outdata_directory, outname)
def main(args): parser = argparse.ArgumentParser() parser.add_argument("-d", "--debug", action="store_true") parsed = parser.parse_args(args) global debug debug = parsed.debug scriptdir = os.path.dirname(os.path.realpath(__file__)) testdata_directory = os.path.join(scriptdir, "testdata") outdata_directory = os.path.join(testdata_directory, "out") wgs84 = TilePyramid("geodetic") wgs84_meta = MetaTilePyramid(wgs84, 16) # TilePyramid #=========== # tiles per zoomlevel try: matrix_width = wgs84.matrix_width(5) matrix_height = wgs84.matrix_height(5) assert (matrix_width, matrix_height) == (64, 32) print "tiles per zoomlevel OK" except: print "tiles per zoomlevel FAILED" raise # top left coordinate try: tile = wgs84.tile(5, 3, 3) tl = (tile.left,tile.top) assert tl == (-163.125, 73.125) print "top left coordinate OK" except: print "top left coordinate FAILED" print tl raise # tile bounding box try: tile = wgs84.tile(5, 3, 3) bbox = tile.bbox() testpolygon = Polygon([[-163.125, 73.125], [-157.5, 73.125], [-157.5, 67.5], [-163.125, 67.5], [-163.125, 73.125]]) assert bbox.equals(testpolygon) print "tile bounding box OK" except: print "tile bounding box FAILED" raise # tile bounding box with buffer try: tile = wgs84.tile(5, 3, 3) bbox = tile.bbox(1) testpolygon = Polygon([[-163.14697265625, 73.14697265625], [-157.47802734375, 73.14697265625], [-157.47802734375, 67.47802734375], [-163.14697265625, 67.47802734375], [-163.14697265625, 73.14697265625]]) assert bbox.equals(testpolygon) print "tile bounding box with buffer OK" except: print "tile bounding box with buffer FAILED" print bbox raise # tile bounds try: tile = wgs84.tile(5, 3, 3) bounds = tile.bounds() testbounds = (-163.125, 67.5, -157.5, 73.125) assert bounds == testbounds print "tile bounds OK" except: print "tile bounds FAILED" raise # tile bounds buffer try: tile = wgs84.tile(5, 3, 3) bounds = tile.bounds(1) testbounds = (-163.14697265625, 67.47802734375, -157.47802734375, 73.14697265625) assert bounds == testbounds print "tile bounds with buffer OK" except: print "tile bounds wigh buffer FAILED" raise # test bounding box bbox_location = os.path.join(testdata_directory, "bbox.geojson") tiled_out = os.path.join(outdata_directory, "bbox_tiles.geojson") zoom = 5 testtiles = [(5, 5, 33), (5, 6, 33), (5, 7, 33), (5, 8, 33), (5, 9, 33), (5, 10, 33), (5, 5, 34), (5, 6, 34), (5, 7, 34), (5, 8, 34), (5, 9, 34), (5, 10, 34), (5, 5, 35), (5, 6, 35), (5, 7, 35), (5, 8, 35), (5, 9, 35), (5, 10, 35),(5, 5, 36), (5, 6, 36), (5, 7, 36), (5, 8, 36), (5, 9, 36), (5, 10, 36), (5, 5, 37), (5, 6, 37), (5, 7, 37), (5, 8, 37), (5, 9, 37), (5, 10, 37),(5, 5, 38), (5, 6, 38), (5, 7, 38), (5, 8, 38), (5, 9, 38), (5, 10, 38), (5, 5, 39), (5, 6, 39), (5, 7, 39), (5, 8, 39), (5, 9, 39), (5, 10, 39), (5, 5, 40), (5, 6, 40), (5, 7, 40), (5, 8, 40), (5, 9, 40), (5, 10, 40), (5, 5, 41), (5, 6, 41), (5, 7, 41), (5, 8, 41), (5, 9, 41), (5, 10, 41)] with fiona.open(bbox_location) as bbox_file: try: bbox_tiles = [ (tile.zoom, tile.row, tile.col) for tile in wgs84.tiles_from_bbox(bbox_file, zoom) ] assert len(set(bbox_tiles).symmetric_difference(set(testtiles))) == 0 print "bounding box OK" except: print "bounding box FAILED" raise if debug: ## write debug output schema = { 'geometry': 'Polygon', 'properties': {'col': 'int', 'row': 'int'} } try: os.remove(tiled_out) except: pass with fiona.open(tiled_out, 'w', 'GeoJSON', schema) as sink: for tile in bbox_tiles: zoom, row, col = tile feature = {} feature['geometry'] = mapping(wgs84.tile_bbox(zoom, row, col)) feature['properties'] = {} feature['properties']['col'] = col feature['properties']['row'] = row sink.write(feature) # tiles from Point point_location = os.path.join(testdata_directory, "point.geojson") tiled_out = os.path.join(outdata_directory, "point_tiles.geojson") zoom = 6 testtile = [(6, 14, 69)] with fiona.open(point_location) as point_file: point = shape(point_file[0]["geometry"]) try: point_tile = [ (tile.zoom, tile.row, tile.col) for tile in wgs84.tiles_from_geom(point, zoom) ] assert point_tile == testtile print "Point OK" except: print point_tile, testtile print "Point FAILED" raise if debug: ## write debug output schema = { 'geometry': 'Polygon', 'properties': {'col': 'int', 'row': 'int'} } try: os.remove(tiled_out) except: pass with fiona.open(tiled_out, 'w', 'GeoJSON', schema) as sink: zoom, row, col = point_tile[0] feature = {} feature['geometry'] = mapping(wgs84.tile_bbox(zoom, row, col)) feature['properties'] = {} feature['properties']['col'] = col feature['properties']['row'] = row sink.write(feature) # tiles from MultiPoint multipoint_location = os.path.join(testdata_directory, "multipoint.geojson") tiled_out = os.path.join(outdata_directory, "multipoint_tiles.geojson") zoom = 9 testtiles = [(9, 113, 553), (9, 118, 558)] with fiona.open(multipoint_location) as multipoint_file: multipoint = shape(multipoint_file[0]["geometry"]) try: multipoint_tiles = [ (tile.zoom, tile.row, tile.col) for tile in wgs84.tiles_from_geom(multipoint, zoom) ] assert multipoint_tiles == testtiles print "MultiPoint OK" except: print "MultiPoint FAILED" print multipoint_tiles print testtiles raise if debug: ## write debug output schema = { 'geometry': 'Polygon', 'properties': {'col': 'int', 'row': 'int'} } try: os.remove(tiled_out) except: pass with fiona.open(tiled_out, 'w', 'GeoJSON', schema) as sink: for tile in multipoint_tiles: zoom, row, col = tile feature = {} feature['geometry'] = mapping(wgs84.tile_bbox(zoom, row, col)) feature['properties'] = {} feature['properties']['col'] = col feature['properties']['row'] = row sink.write(feature) # tiles from LineString linestring_location = os.path.join(testdata_directory, "linestring.geojson") tiled_out = os.path.join(outdata_directory, "linestring_tiles.geojson") zoom = 6 testtiles = [(6, 14, 66), (6, 14, 67), (6, 14, 68), (6, 14, 69), (6, 14, 70), (6, 15, 70), (6, 15, 71), (6, 16, 71), (6, 16, 72), (6, 15, 73), (6, 16, 73), (6, 15, 74)] with fiona.open(linestring_location) as linestring_file: linestring = shape(linestring_file[0]["geometry"]) try: linestring_tiles = [ (tile.zoom, tile.row, tile.col) for tile in wgs84.tiles_from_geom(linestring, zoom) ] assert len(set(linestring_tiles).symmetric_difference(set(testtiles))) == 0 print "LineString OK" except: print "LineString FAILED" raise if debug: ## write debug output schema = { 'geometry': 'Polygon', 'properties': {'col': 'int', 'row': 'int'} } try: os.remove(tiled_out) except: pass with fiona.open(tiled_out, 'w', 'GeoJSON', schema) as sink: for tile in linestring_tiles: zoom, row, col = tile feature = {} feature['geometry'] = mapping(wgs84.tile_bbox(zoom, row, col)) feature['properties'] = {} feature['properties']['col'] = col feature['properties']['row'] = row sink.write(feature) # tiles from MultiLineString multilinestring_location = os.path.join(testdata_directory, "multilinestring.geojson") tiled_out = os.path.join(outdata_directory, "multilinestring_tiles.geojson") zoom = 6 testtiles = [(6, 14, 66), (6, 14, 67), (6, 14, 68), (6, 14, 69), (6, 14, 70), (6, 15, 70), (6, 15, 71), (6, 16, 71), (6, 16, 72), (6, 15, 73), (6, 16, 73), (6, 15, 74), (6, 21, 74), (6, 22, 74), (6, 24, 74), (6, 25, 74), (6, 28, 74), (6, 29, 74), (6, 20, 75), (6, 21, 75), (6, 22, 75), (6, 23, 75), (6, 24, 75), (6, 25, 75), (6, 26, 75), (6, 27, 75), (6, 28, 75), (6, 29, 75), (6, 30, 75), (6, 31, 75), (6, 25, 76)] with fiona.open(multilinestring_location) as multilinestring_file: multilinestring = shape(multilinestring_file[0]["geometry"]) try: multilinestring_tiles = [ (tile.zoom, tile.row, tile.col) for tile in wgs84.tiles_from_geom(multilinestring, zoom) ] assert len(set(multilinestring_tiles).symmetric_difference(set(testtiles))) == 0 print "MultiLineString OK" except: print "MultiLineString FAILED" raise if debug: ## write debug output schema = { 'geometry': 'Polygon', 'properties': {'col': 'int', 'row': 'int'} } try: os.remove(tiled_out) except: pass with fiona.open(tiled_out, 'w', 'GeoJSON', schema) as sink: for tile in multilinestring_tiles: zoom, row, col = tile feature = {} feature['geometry'] = mapping(wgs84.tile_bbox(zoom, row, col)) feature['properties'] = {} feature['properties']['col'] = col feature['properties']['row'] = row sink.write(feature) # tiles from Polygon polygon_location = os.path.join(testdata_directory, "polygon.geojson") tiled_out = os.path.join(outdata_directory, "polygon_tiles.geojson") zoom = 8 testtiles = [(8, 60, 269), (8, 61, 269), (8, 60, 270), (8, 61, 270), (8, 60, 271), (8, 61, 271), (8, 60, 272), (8, 61, 272), (8, 60, 273), (8, 61, 273), (8, 59, 274), (8, 60, 274), (8, 61, 274), (8, 58, 275), (8, 59, 275), (8, 60, 275), (8, 61, 275), (8, 58, 276), (8, 59, 276), (8, 60, 276), (8, 61, 276), (8, 62, 276), (8, 58, 277), (8, 59, 277), (8, 60, 277), (8, 61, 277), (8, 58, 278), (8, 59, 278), (8, 60, 278), (8, 61, 278), (8, 58, 279), (8, 59, 279), (8, 60, 279), (8, 61, 279), (8, 58, 280), (8, 59, 280), (8, 60, 280)] with fiona.open(polygon_location) as polygon_file: polygon = shape(polygon_file[0]["geometry"]) polygon_tiles = [ (tile.zoom, tile.row, tile.col) for tile in wgs84.tiles_from_geom(polygon, zoom) ] try: assert len(set(polygon_tiles).symmetric_difference(set(testtiles))) == 0 print "Polygon OK" except: print "Polygon FAILED" raise if debug: ## write debug output schema = { 'geometry': 'Polygon', 'properties': {'col': 'int', 'row': 'int'} } try: os.remove(tiled_out) except: pass with fiona.open(tiled_out, 'w', 'GeoJSON', schema) as sink: for tile in polygon_tiles: zoom, row, col = tile feature = {} feature['geometry'] = mapping(wgs84.tile_bbox(zoom, row, col)) feature['properties'] = {} feature['properties']['col'] = col feature['properties']['row'] = row sink.write(feature) # tiles from MultiPolygon multipolygon_location = os.path.join(testdata_directory, "multipolygon.geojson") tiled_out = os.path.join(outdata_directory, "multipolygon_tiles.geojson") zoom = 10 testtiles = [(10, 243, 1081), (10, 244, 1081), (10, 245, 1081), (10, 242, 1082), (10, 243, 1082), (10, 244, 1082), (10, 245, 1082), (10, 241, 1083), (10, 242, 1083), (10, 243, 1083), (10, 244, 1083), (10, 245, 1083), (10, 241, 1084), (10, 242, 1084), (10, 243, 1084), (10, 244, 1084), (10, 245, 1084), (10, 241, 1085), (10, 242, 1085), (10, 243, 1085), (10, 244, 1085), (10, 245, 1085), (10, 241, 1086), (10, 242, 1086), (10, 243, 1086), (10, 244, 1086), (10, 245, 1086), (10, 242, 1087), (10, 243, 1087), (10, 244, 1087), (10, 245, 1087), (10, 241, 1088), (10, 242, 1088), (10, 243, 1088), (10, 244, 1088), (10, 241, 1089), (10, 242, 1089), (10, 243, 1089), (10, 244, 1089), (10, 241, 1090), (10, 242, 1090), (10, 243, 1090), (10, 244, 1090), (10, 241, 1091), (10, 242, 1091), (10, 243, 1091), (10, 244, 1091), (10, 241, 1092), (10, 242, 1092), (10, 243, 1092), (10, 244, 1092), (10, 240, 1093), (10, 241, 1093), (10, 242, 1093), (10, 244, 1093), (10, 245, 1093), (10, 240, 1094), (10, 241, 1094), (10, 242, 1094), (10, 243, 1094), (10, 244, 1094), (10, 245, 1094), (10, 246, 1094), (10, 240, 1095), (10, 241, 1095), (10, 242, 1095), (10, 243, 1095), (10, 244, 1095), (10, 245, 1095), (10, 246, 1095), (10, 241, 1096), (10, 244, 1096), (10, 245, 1096), (10, 246, 1096), (10, 245, 1097), (10, 246, 1097)] with fiona.open(multipolygon_location) as multipolygon_file: multipolygon = shape(multipolygon_file[0]["geometry"]) multipolygon_tiles = [ (tile.zoom, tile.row, tile.col) for tile in wgs84.tiles_from_geom(multipolygon, zoom) ] try: assert len(set(multipolygon_tiles).symmetric_difference(set(testtiles))) == 0 print "MultiPolygon OK" except: print "MultiPolygon FAILED" raise if debug: ## write debug output schema = { 'geometry': 'Polygon', 'properties': {'col': 'int', 'row': 'int'} } try: os.remove(tiled_out) except: pass with fiona.open(tiled_out, 'w', 'GeoJSON', schema) as sink: for tile in multipolygon_tiles: zoom, row, col = tile feature = {} feature['geometry'] = mapping(wgs84.tile_bbox(zoom, row, col)) feature['properties'] = {} feature['properties']['col'] = col feature['properties']['row'] = row sink.write(feature) if debug: # writing output test files col, row = 2, 2 zoom = 5 metatiling = 2 wgs84_meta = MetaTilePyramid(wgs84, metatiling) antimeridian_location = os.path.join(testdata_directory, "antimeridian.geojson") with fiona.open(antimeridian_location) as antimeridian_file: geometries = [] for feature in antimeridian_file: geometries.append(shape(feature["geometry"])) antimeridian = cascaded_union(geometries) print "top left tile coordinates:" print "metaTilePyramid: %s" %([wgs84_meta.top_left_tile_coords(zoom, row, col)]) print "tile bounding box" print "metaTilePyramid: %s" %([mapping(wgs84.tile_bbox(zoom, row, col))]) print "tile bounds" print "metaTilePyramid: %s" %([wgs84_meta.tile_bounds(zoom, row, col)]) print "tiles from bbox" #print "metaTilePyramid: %s" %([wgs84_meta.tiles_from_bbox(antimeridian, zoom)]) print "tiles from geometry" ## write debug output tiled_out = os.path.join(outdata_directory, "tile_antimeridian_tiles.geojson") schema = { 'geometry': 'Polygon', 'properties': {'col': 'int', 'row': 'int'} } try: os.remove(tiled_out) except: pass tiles = wgs84.tiles_from_geom(antimeridian, zoom) print "TilePyramid: %s" %(len(tiles)) with fiona.open(tiled_out, 'w', 'GeoJSON', schema) as sink: for tile in tiles: zoom, row, col = tile feature = {} feature['geometry'] = mapping(wgs84.tile_bbox(zoom, row, col)) feature['properties'] = {} feature['properties']['col'] = col feature['properties']['row'] = row sink.write(feature) ## write debug output metatiled_out = os.path.join(outdata_directory, "metatile_antimeridian_tiles.geojson") schema = { 'geometry': 'Polygon', 'properties': {'col': 'int', 'row': 'int'} } try: os.remove(metatiled_out) except: pass metatiles = wgs84_meta.tiles_from_geom(antimeridian, zoom) print "metaTilePyramid: %s" %(len(metatiles)) with fiona.open(metatiled_out, 'w', 'GeoJSON', schema) as sink: for metatile in metatiles: zoom, row, col = metatile feature = {} feature['geometry'] = mapping(wgs84_meta.tile_bbox(zoom, row, col)) feature['properties'] = {} feature['properties']['col'] = col feature['properties']['row'] = row sink.write(feature) for metatiling in (1, 2, 4, 8, 16): wgs84_meta = MetaTilePyramid(wgs84, metatiling) for zoom in range(22): tilepyramid_width = wgs84.matrix_width(zoom) tilepyramid_height = wgs84.matrix_height(zoom) metatilepyramid_width = wgs84_meta.matrix_width(zoom) metatilepyramid_height = wgs84_meta.matrix_height(zoom) control_width = int(math.ceil( float(tilepyramid_width)/float(metatiling) )) control_height = int(math.ceil( float(tilepyramid_height)/float(metatiling) )) try: assert metatilepyramid_width == control_width assert metatilepyramid_height == control_height except: print "ERROR: metatile number" print "metatiling, zoom:", metatiling, zoom print "width:", metatilepyramid_width, control_width print "height:", metatilepyramid_height, control_height raise for metatiling in (1, 2, 4, 8, 16): wgs84_meta = MetaTilePyramid(wgs84, metatiling) for zoom in range(21): # check tuple assert isinstance(wgs84_meta.matrix_width(zoom), int) assert isinstance(wgs84_meta.matrix_height(zoom), int) # check metatile size metatile_x_size = round(wgs84_meta.metatile_x_size(zoom), ROUND) metatile_y_size = round(wgs84_meta.metatile_y_size(zoom), ROUND) # assert metatile size equals TilePyramid width and height at zoom 0 if zoom == 0: try: if metatiling == 1: assert (metatile_x_size * 2) == wgs84.x_size else: assert metatile_x_size == wgs84.x_size assert metatile_y_size == wgs84.y_size except: print "ERROR: zoom 0 metatile size not correct" print "metatiling, zoom:", metatiling, zoom print "metatile_x_size:", wgs84_meta.metatiling, metatile_x_size, wgs84.x_size print "metatile_y_size:", metatile_y_size, wgs84.y_size raise ## assert metatile size within TilePyramid bounds try: assert (metatile_x_size > 0.0) and ( metatile_x_size <= wgs84.x_size) assert (metatile_y_size > 0.0) and ( metatile_y_size <= wgs84.y_size) except: print "ERROR: metatile size" print zoom print "metatile_x_size:", metatile_x_size, wgs84_meta.x_size print "metatile_y_size:", metatile_y_size, wgs84_meta.x_size raise ## calculate control size from tiles tile_x_size = wgs84.tile_x_size(zoom) tile_y_size = wgs84.tile_y_size(zoom) we_control_size = round(tile_x_size * float(metatiling), ROUND) if we_control_size > wgs84.x_size: we_control_size = wgs84.x_size ns_control_size = round(tile_y_size * float(metatiling), ROUND) if ns_control_size > wgs84.y_size: ns_control_size = wgs84.y_size try: assert metatile_x_size == we_control_size assert metatile_y_size == ns_control_size except: print "ERROR: metatile size and control sizes" print "zoom, metatiling:", zoom, metatiling print metatile_x_size, we_control_size print metatile_y_size, ns_control_size raise # check metatile pixelsize (resolution) pixel_x_size = round(wgs84.pixel_x_size(zoom), ROUND) ctr_pixel_x_size = round(wgs84_meta.pixel_x_size(zoom), ROUND) pixel_y_size = round(wgs84.pixel_y_size(zoom), ROUND) ctr_pixel_y_size = round(wgs84_meta.pixel_y_size(zoom), ROUND) try: assert pixel_x_size == ctr_pixel_x_size assert pixel_y_size == ctr_pixel_y_size except: print "ERROR: metatile pixel size" print "zoom, metatiling:", zoom, metatiling print "pixel_x_size:", pixel_x_size, ctr_pixel_x_size print "pixel_y_size:", pixel_y_size, ctr_pixel_y_size raise if debug: fiji_borders = os.path.join(testdata_directory, "fiji.geojson") with fiona.open(fiji_borders, "r") as fiji: geometries = [] for feature in fiji: geometry = shape(feature['geometry']) geometries.append(geometry) union = cascaded_union(geometries) # tiles fiji_tiles = os.path.join(outdata_directory, "fiji_tiles.geojson") schema = { 'geometry': 'Polygon', 'properties': {'col': 'int', 'row': 'int'} } try: os.remove(fiji_tiles) except: pass metatiling = 4 zoom = 10 tiles = wgs84.tiles_from_geom(union, zoom) with fiona.open(fiji_tiles, 'w', 'GeoJSON', schema) as sink: for tile in tiles: zoom, row, col = tile feature = {} feature['geometry'] = mapping(wgs84.tile_bbox(zoom, row, col)) feature['properties'] = {} feature['properties']['col'] = col feature['properties']['row'] = row sink.write(feature) # metatiles fiji_metatiles = os.path.join(outdata_directory, "fiji_metatiles.geojson") schema = { 'geometry': 'Polygon', 'properties': {'col': 'int', 'row': 'int'} } try: os.remove(fiji_metatiles) except: pass wgs84_meta = MetaTilePyramid(wgs84, metatiling) metatiles = wgs84_meta.tiles_from_geom(union, zoom) with fiona.open(fiji_metatiles, 'w', 'GeoJSON', schema) as sink: for metatile in metatiles: zoom, row, col = metatile feature = {} feature['geometry'] = mapping(wgs84_meta.tile_bbox(zoom, row, col)) feature['properties'] = {} feature['properties']['col'] = col feature['properties']['row'] = row sink.write(feature) ## test get neighbors metatiling = 1 wgs84_meta = MetaTilePyramid(wgs84, metatiling) tile = wgs84_meta.tile(5, 4, 3) assert len(tile.get_neighbors()) == 8 ## test tile <--> metatile conversion metatile = [(10, 44, 33)] metatiling = 4 wgs84_meta = MetaTilePyramid(wgs84, metatiling) small_tile = wgs84_meta.tilepyramid.tile(10, 178, 133) test_metatile = [ (tile.zoom, tile.row, tile.col) for tile in wgs84_meta.tiles_from_bbox( small_tile.bbox(), 10 ) ] try: assert metatile == test_metatile print "OK: metatile <-> tile conversion" except: print metatile, test_metatile raise print "ERROR: metatile <-> tile conversion" # test mercator tile pyramid tile_pyramid = TilePyramid("mercator") assert tile_pyramid.srid == 3857 try: for zoom in range(15): assert ( (tile_pyramid.matrix_width(zoom), tile_pyramid.matrix_height(zoom) ) == (2**zoom, 2**zoom) ) print "OK: mercator tile matrix widths" except: print "ERROR: mercator tile matrix widths" from shapely.ops import transform from functools import partial import pyproj import mercantile example_tiles = [ (12, 1024, 512), (6, 32, 16), (0, 0, 0), ] for tile_idx in example_tiles: (zoom, row, col) = tile_idx mercantile_ul = Point( mercantile.ul(col, row, zoom).lng, mercantile.ul(col, row, zoom).lat, ) m_bounds = mercantile.bounds(col, row, zoom) mercantile_bbox = box(*m_bounds) project = partial( pyproj.transform, pyproj.Proj({"init": "epsg:3857"}), pyproj.Proj({"init": "epsg:4326"}) ) tilematrix_ul = transform( project, Point( Tile(tile_pyramid, zoom, row, col).left, Tile(tile_pyramid, zoom, row, col).top, ) ) tilematrix_bbox = transform( project, Tile(tile_pyramid, zoom, row, col).bbox() ) try: assert mercantile_ul.almost_equals( tilematrix_ul, decimal=GEOM_EQUALS_ROUND ) assert mercantile_bbox.almost_equals( tilematrix_bbox, decimal=GEOM_EQUALS_ROUND ) print "OK: mercator tile coordinates" except AssertionError: print "ERROR: mercator tile coordinates" print tile_idx, mercantile_ul, tilematrix_ul print tile_idx, mercantile_bbox, tilematrix_bbox tile_idx = (12, 1024, 512) tile = Tile(tile_pyramid, *tile_idx) for child in tile.get_children(): try: assert child.get_parent().id == tile.id print "OK: tile children and parent" except AssertionError: print child.parent.id, tile.id print "ERROR: tile children and parent" # get tiles over antimeridian: tile_pyramid = TilePyramid("geodetic") tile = tile_pyramid.tile(5, 0, 63) target_tiles = set( target_tile.id for target_tile in tile_pyramid.tiles_from_bounds(tile.bounds(256), 5) ) control_tiles = set( [ # tiles west of antimeridian (5, 0, 62), (5, 0, 63), (5, 1, 62), (5, 1, 63), # tiles east of antimeridian (5, 0, 0), (5, 1, 0) ] ) try: diff = control_tiles.difference(target_tiles) assert len(diff) == 0 print "OK: tiles over antimeridian" except AssertionError: print "ERROR: tiles over antimeridian" print diff tile = tile_pyramid.tile(5, 0, 0) target_tiles = set( target_tile.id for target_tile in tile_pyramid.tiles_from_bounds(tile.bounds(256), 5) ) control_tiles = set( [ # tiles west of antimeridian (5, 0, 63), (5, 1, 63), # tiles east of antimeridian (5, 0, 0), (5, 1, 0), (5, 0, 1), (5, 1, 1) ] ) try: diff = control_tiles.difference(target_tiles) assert len(diff) == 0 print "OK: tiles over antimeridian" except AssertionError: print "ERROR: tiles over antimeridian" print diff # get tiles over antimeridian: tile_pyramid = TilePyramid("mercator") tile = tile_pyramid.tile(5, 0, 31) target_tiles = set( target_tile.id for target_tile in tile_pyramid.tiles_from_bounds(tile.bounds(256), 5) ) control_tiles = set( [ # tiles west of antimeridian (5, 0, 30), (5, 0, 31), (5, 1, 30), (5, 1, 31), # tiles east of antimeridian (5, 0, 0), (5, 1, 0) ] ) try: diff = control_tiles.difference(target_tiles) assert len(diff) == 0 print "OK: tiles over antimeridian" except AssertionError: print "ERROR: tiles over antimeridian" print diff tile = tile_pyramid.tile(5, 0, 0) target_tiles = set( target_tile.id for target_tile in tile_pyramid.tiles_from_bounds(tile.bounds(256), 5) ) control_tiles = set( [ # tiles west of antimeridian (5, 0, 31), (5, 1, 31), # tiles east of antimeridian (5, 0, 0), (5, 1, 0), (5, 0, 1), (5, 1, 1) ] ) try: diff = control_tiles.difference(target_tiles) assert len(diff) == 0 print "OK: tiles over antimeridian" except AssertionError: print "ERROR: tiles over antimeridian" print diff # geometry over antimeridian tile_pyramid = TilePyramid("geodetic") geometry = loads("POLYGON ((184.375 90, 190 90, 180 84.375, 174.375 84.375, 184.375 90))") target_tiles = set( tile.id for tile in tile_pyramid.tiles_from_geom(geometry, 6) ) control_tiles = set( [ (6, 0, 127), (6, 1, 126), (6, 1, 127), (6, 0, 0), (6, 0, 1), (6, 0, 2), (6, 0, 3), (6, 1, 0), (6, 1, 1) ] ) try: diff = control_tiles.difference(target_tiles) assert len(diff) == 0 print "OK: geometry over antimeridian" except AssertionError: print "ERROR: geometry over antimeridian" print diff tile_pyramid = TilePyramid("mercator") geometry = loads("POLYGON ((-22037508.3427892 20037508.3427892, -20785164.07136488 20037508.3427892, -18785164.07136488 18785164.07136488, -20037508.3427892 18785164.07136488, -22037508.3427892 20037508.3427892))") target_tiles = set( tile.id for tile in tile_pyramid.tiles_from_geom(geometry, 6) ) tile_pyramid_bbox = box( tile_pyramid.left, tile_pyramid.bottom, tile_pyramid.right, tile_pyramid.top ) for tile in target_tiles: assert tile_pyramid.tile(*tile).bbox().within(tile_pyramid_bbox) control_tiles = set( [ # west of antimeridian (6, 0, 60), (6, 0, 61), (6, 0, 62), (6, 0, 63), (6, 1, 62), (6, 1, 63), # east of antimeridian (6, 0, 0), (6, 1, 0), (6, 1, 1) ] ) try: diff = control_tiles.difference(target_tiles) assert len(diff) == 0 print "OK: geometry over antimeridian" except AssertionError: print "ERROR: geometry over antimeridian" print target_tiles print diff # tile shapes tile_pyramid = TilePyramid("mercator") col, row = (0, 0) for zoom in range(10): tile = Tile(tile_pyramid, zoom, col, row) assert tile.shape() == (256, 256) metatile_pyramid = MetaTilePyramid(tile_pyramid, metatiles=8) control_shapes = [ (256, 256), (512, 512), (1024, 1024), (2048, 2048), (2048, 2048), (2048, 2048), (2048, 2048), (2048, 2048), (2048, 2048), (2048, 2048) ] for zoom, control_shape in zip(range(9), control_shapes): tile = Tile(metatile_pyramid, zoom, col, row) try: assert tile.shape() == control_shape print "OK: metatile shape at zoom ", zoom except AssertionError: print "ERROR: metatile shape at zoom", zoom print tile.id, tile.shape(), control_shape raise # tile shapes with pixelbuffer tile_pyramid = TilePyramid("mercator") test_tiles = [ (0, 0, 0), (1, 0, 0), # top left (2, 0, 1), # top middle (2, 0, 3), # top right (2, 3, 3), # bottom right (2, 3, 0), # bottom left (2, 3, 2), # bottom middle (2, 2, 0), # left middle (2, 2, 3), # right middle ] pixelbuffer = 2 tile_size = tile_pyramid.tile_size control_shapes = [ (tile_size, tile_size+2*pixelbuffer), (tile_size+1*pixelbuffer, tile_size+2*pixelbuffer), # top left (tile_size+1*pixelbuffer, tile_size+2*pixelbuffer), # top middle (tile_size+1*pixelbuffer, tile_size+2*pixelbuffer), # top right (tile_size+1*pixelbuffer, tile_size+2*pixelbuffer), # bottom right (tile_size+1*pixelbuffer, tile_size+2*pixelbuffer), # bottom left (tile_size+1*pixelbuffer, tile_size+2*pixelbuffer), # bottom middle (tile_size+2*pixelbuffer, tile_size+2*pixelbuffer), # left middle (tile_size+2*pixelbuffer, tile_size+2*pixelbuffer), # right middle ] for test_tile, control_shape in zip(test_tiles, control_shapes): tile = Tile(tile_pyramid, *test_tile) try: assert tile.shape(pixelbuffer) == control_shape print "OK: tile pixelbuffer shape for tile ", test_tile except AssertionError: print "ERROR: tile pixelbuffer shape for tile", test_tile print tile.id, tile.shape(pixelbuffer), control_shape # metatile shapes with pixelbuffer pixelbuffer = 2 metatiling = 8 metatile_pyramid = MetaTilePyramid(tile_pyramid, metatiles=metatiling) tile_size = tile_pyramid.tile_size test_tiles = [ (0, 0, 0), (1, 0, 0), (2, 0, 0), (3, 0, 0), (4, 0, 0), (5, 0, 0), # top left (5, 0, 1), # top middle (5, 0, 3), # top right (5, 3, 3), # bottom right (5, 3, 0), # bottom left (5, 3, 2), # bottom middle (5, 2, 0), # left middle (5, 2, 3), # right middle ] for test_tile in test_tiles: tile = Tile(metatile_pyramid, *test_tile) left, bottom, right, top = tile.bounds(pixelbuffer) control_shape = ( int(round((top-bottom)/tile.pixel_y_size)), int(round((right-left)/tile.pixel_x_size)) ) try: assert tile.shape(pixelbuffer) == control_shape print "OK: tile pixelbuffer shape for metatile ", test_tile except AssertionError: print "ERROR: tile pixelbuffer shape for metatile", test_tile print tile.id, tile.shape(pixelbuffer), control_shape """intersecting function""" try: # equal metatiling: tile = Tile(TilePyramid("geodetic", metatiling=1), 3, 4, 5) pyramid = TilePyramid("geodetic", metatiling=1) assert len(tile.intersecting(pyramid)) == 1 assert tile.intersecting(pyramid)[0].id == tile.id # different metatiling: tile = Tile(TilePyramid("geodetic", metatiling=1), 3, 4, 5) pyramid_metatiling = 2 pyramid = TilePyramid("geodetic", metatiling=pyramid_metatiling) assert len(tile.intersecting(pyramid)) == 1 intersect = tile.intersecting(pyramid)[0] assert tile.bbox().within(intersect.bbox()) tile = Tile(TilePyramid("geodetic", metatiling=8), 13, 4, 5) pyramid_metatiling = 2 pyramid = TilePyramid("geodetic", metatiling=pyramid_metatiling) assert len(tile.intersecting(pyramid)) == 16 for intersect in tile.intersecting(pyramid): assert intersect.bbox().within(tile.bbox()) tile_list = set( tile.id for tile in tile.intersecting(pyramid) ) reversed_list = set( tile.id for tile in pyramid.intersecting(tile) ) assert not len(tile_list.symmetric_difference(reversed_list)) print "OK: intersecting function" except: print "ERROR: intersecting function" raise """affine objects""" try: for metatiling in [1, 2, 4, 8, 16]: pyramid = TilePyramid("geodetic", metatiling=metatiling) for zoom in range(22): tile = pyramid.tile(zoom, 0, 0) assert tile.pixel_x_size == tile.pixel_y_size assert tile.affine()[0] == -tile.affine()[4] assert tile.affine(pixelbuffer=10)[0] == \ -tile.affine(pixelbuffer=10)[4] print "OK: Affine objects" except: print "ERROR: Affine objects" raise