Пример #1
0
def test_tiles_truncate():
    """Input is truncated"""
    assert list(
        mercantile.tiles(-181.0, 0.0, -170.0, 10.0, zooms=[2],
                         truncate=True)) == list(
                             mercantile.tiles(-180.0,
                                              0.0,
                                              -170.0,
                                              10.0,
                                              zooms=[2]))
Пример #2
0
def coords2png(lat0, lng0, lat1, lng1, out_file):
    # find desirable zoom level
    zoom = 0
    while True:
        tiles_list = list(mercantile.tiles(lng0, lat0, lng1, lat1, [zoom]))
        if len(tiles_list) > MAX_TILES:
            zoom -= 1
            break
        zoom += 1
    print('Zoom level %s' % zoom)

    # get tiles list
    tiles_list = list(mercantile.tiles(lng0, lat0, lng1, lat1, [zoom]))
    xs = [tile.x for tile in tiles_list]
    x0 = min(xs)
    x1 = max(xs)
    ys = [tile.y for tile in tiles_list]
    y0 = min(ys)
    y1 = max(ys)
    x_tiles = x1 - x0 + 1
    y_tiles = y1 - y0 + 1
    x_width = x_tiles * TILE_SIDE
    y_width = y_tiles * TILE_SIDE

    # create image
    img = Image.new("RGBA", (x_tiles * TILE_SIDE, y_tiles * TILE_SIDE),
                    (0, 0, 0, 0))
    for x in range(x0, x1 + 1):
        for y in range(y0, y1 + 1):
            print("processing tile %s, %s" % (x, y))
            tile = tile_image(zoom, x, y)
            tile_img = Image.open(io.BytesIO(tile))
            img.paste(tile_img, ((x - x0) * TILE_SIDE, (y - y0) * TILE_SIDE))

    # crop image
    top_left = mercantile.bounds(x0, y0, zoom)
    bottom_right = mercantile.bounds(x1, y1, zoom)
    img_lat1 = top_left.north
    img_lng0 = top_left.west
    img_lat0 = bottom_right.south
    img_lng1 = bottom_right.east
    img_lat_delta = img_lat1 - img_lat0
    img_lng_delta = img_lng1 - img_lng0
    pixel_lat_ratio = float(x_width) / img_lat_delta
    pixel_lng_ratio = float(y_width) / img_lng_delta
    left = int(abs(lng0 - img_lng0) * pixel_lng_ratio)
    right = x_width - int(abs(lng1 - img_lng1) * pixel_lng_ratio)
    top = int(abs(lat1 - img_lat1) * pixel_lat_ratio)
    bottom = y_width - int(abs(lat0 - img_lat0) * pixel_lat_ratio)
    img = img.crop((left, top, right, bottom))

    img.save(out_file, 'PNG')
Пример #3
0
def coords2png(lat0, lng0, lat1, lng1, out_file):
    # find desirable zoom level
    zoom = 0
    while True:
        tiles_list = list(mercantile.tiles(lng0, lat0, lng1, lat1, [zoom]))
        if len(tiles_list) > MAX_TILES:
            zoom -= 1
            break
        zoom += 1
    print('Zoom level %s' % zoom)
    
    # get tiles list
    tiles_list = list(mercantile.tiles(lng0, lat0, lng1, lat1, [zoom]))
    xs = [tile.x for tile in tiles_list]
    x0 = min(xs)
    x1 = max(xs)
    ys = [tile.y for tile in tiles_list]
    y0 = min(ys)
    y1 = max(ys)
    x_tiles = x1 - x0 + 1
    y_tiles = y1 - y0 + 1
    x_width = x_tiles * TILE_SIDE
    y_width = y_tiles * TILE_SIDE

    # create image
    img = Image.new("RGBA", (x_tiles * TILE_SIDE, y_tiles * TILE_SIDE), (0, 0, 0, 0))
    for x in range(x0, x1 + 1):
        for y in range(y0, y1 + 1):
            print("processing tile %s, %s" % (x, y))
            tile = tile_image(zoom, x, y)
            tile_img = Image.open(io.BytesIO(tile))
            img.paste(tile_img, ((x - x0) * TILE_SIDE, (y - y0) * TILE_SIDE))

    # crop image
    top_left = mercantile.bounds(x0, y0, zoom)
    bottom_right = mercantile.bounds(x1, y1, zoom)
    img_lat1 = top_left.north
    img_lng0 = top_left.west
    img_lat0 = bottom_right.south
    img_lng1 = bottom_right.east
    img_lat_delta = img_lat1 - img_lat0
    img_lng_delta = img_lng1 - img_lng0
    pixel_lat_ratio = float(x_width) / img_lat_delta
    pixel_lng_ratio = float(y_width) / img_lng_delta
    left = int(abs(lng0 - img_lng0) * pixel_lng_ratio)
    right = x_width - int(abs(lng1 - img_lng1) * pixel_lng_ratio)
    top = int(abs(lat1 - img_lat1) * pixel_lat_ratio)
    bottom = y_width - int(abs(lat0 - img_lat0) * pixel_lat_ratio)
    img = img.crop((left, top, right, bottom))
            
    img.save(out_file, 'PNG')
Пример #4
0
        def map_interacted(event):
            if event["type"] == "change" and event["name"] == "bounds":
                self.ht.value = f"{self.tile_id}, Map zoom: {int(a_map.zoom)}"
                self.slider.max = int(a_map.zoom) + self._max_zoom_delta

                m = event["owner"]
                ((south, west), (north, east)) = m.bounds

                b_poly = list(m.bounds_polygon)
                b_poly += [tuple(b_poly[0])]
                # m += Polyline(locations=b_poly)

                # Attention in the order of west, south, east, north!
                tiles = mercantile.tiles(west,
                                         south,
                                         east,
                                         north,
                                         zooms=self.level)

                features = [mercantile.feature(t) for t in tiles]
                self.gj.data = geojson.FeatureCollection(features=features)

                # Ipyleaflet buglet(?): This name is updated in the GeoJSON layer,
                # but not in the LayersControl!
                self.gj.name = f"Mercator"  # level {self.level}"

                self.gj.on_hover(hover)
Пример #5
0
def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('path', type=str)
    parser.add_argument('out', type=str)
    parser.add_argument('--zoom', type=int, required=True)
    parser.add_argument('--ext', type=str, default='webp')
    args = parser.parse_args()

    os.makedirs(args.out, exist_ok=True)
    os.makedirs(os.path.join(args.out, str(args.zoom)), exist_ok=True)

    meta = tiler.bounds(args.path)
    bounds = meta['bounds']

    tiles = list(mercantile.tiles(*bounds + [[args.zoom]]))

    for x, y, z in tqdm(tiles, desc='Tiling', unit='tile', ascii=True):
        os.makedirs(os.path.join(args.out, str(z), str(x)), exist_ok=True)

        data, _ = tiler.tile(args.path, x, y, z)

        img = reshape_as_image(data)
        img = Image.fromarray(img, mode='RGB')
        img.save(os.path.join(args.out, str(z), str(x),
                              str(y) + '.' + args.ext),
                 optimize=True)
Пример #6
0
    def __init__(self):
        self.lat = 43.03350  # Координаты центра карты на старте. Задал координаты университета
        self.lon = 131.88928

        self.west = 131.8797
        self.south = 43.0227
        self.east = 131.9089
        self.north = 43.0373

        self.zoom = 16  # Масштаб карты на старте
        self.type = "map"  # Другие значения "sat", "sat,skl"

        self.tiles = list(mercantile.tiles(self.west, self.south, self.east, self.north, self.zoom))

        self.min_x = min([t.x for t in self.tiles])
        self.min_y = min([t.y for t in self.tiles])
        self.max_x = max([t.x for t in self.tiles])
        self.max_y = max([t.y for t in self.tiles])

        self.bounds = {
            "west": min([mercantile.bounds(t).west for t in self.tiles]),
            "east": max([mercantile.bounds(t).east for t in self.tiles]),
            "south": min([mercantile.bounds(t).south for t in self.tiles]),
            "north": max([mercantile.bounds(t).north for t in self.tiles]),
        }
Пример #7
0
def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('min_zoom',
                        type=int,
                        help='The minimum zoom level to include')
    parser.add_argument('max_zoom',
                        type=int,
                        help='The maximum zoom level to include')
    parser.add_argument(
        '--cities_url',
        default="https://mapzen.com/data/metro-extracts/cities-extractor.json",
        help='A GeoJSON URL with features to cover with tiles')
    parser.add_argument('--output_prefix',
                        default="output",
                        help='The path prefix to output coverage data to')
    args = parser.parse_args()

    cities_resp = requests.get(args.cities_url)
    cities_resp.raise_for_status()
    cities_data = cities_resp.json()

    for feature in cities_data:
        name = feature['id']
        bbox = feature['bbox']
        min_lon, min_lat, max_lon, max_lat = float(bbox['left']), float(
            bbox['bottom']), float(bbox['right']), float(bbox['top'])
        count = 0
        with open(os.path.join(args.output_prefix, '{}.csv'.format(name)),
                  'w') as f:
            for x, y, z in mercantile.tiles(
                    min_lon, min_lat, max_lon, max_lat,
                    range(args.min_zoom, args.max_zoom + 1)):
                f.write('{}/{}/{}\n'.format(z, x, y))
                count += 1
        print("Wrote out {} tiles to {}".format(count, f.name))
Пример #8
0
def _get_image(west, south, east, north, zoom):
    tiles = list(mercantile.tiles(west, south, east, north, zoom))
    tile_size = 256
    min_x = min_y = max_x = max_y = None

    for tile in tiles:
        min_x = min(min_x, tile.x) if min_x is not None else tile.x
        min_y = min(min_y, tile.y) if min_y is not None else tile.y
        max_x = max(max_x, tile.x) if max_x is not None else tile.x
        max_y = max(max_y, tile.y) if max_y is not None else tile.y

    out_img = PIL.Image.new('RGB', ((max_x - min_x + 1) * tile_size,
                                    (max_y - min_y + 1) * tile_size))

    lat_max = mercantile.bounds(max_x, min_y, zoom).north
    lat_min = mercantile.bounds(min_x, max_y, zoom).south
    lon_max = mercantile.bounds(max_x, max_y, zoom).east
    lon_min = mercantile.bounds(min_x, min_y, zoom).west

    results = []
    cnt = 0
    for tile in tiles:
        # print('Tile {}/{}'.format(cnt+1, len(tiles)))
        result = _download_tile(tile)
        results.append(result)
        cnt += 1

    for img, tile in results:
        left = tile.x - min_x
        top = tile.y - min_y
        bounds = (left * tile_size, top * tile_size, (left + 1) * tile_size,
                  (top + 1) * tile_size)
        out_img.paste(img, bounds)

    return out_img, lat_min, lat_max, lon_min, lon_max
Пример #9
0
    def polyfill(self, input_gdf, zoom_level):
        check_package('mercantile', is_optional=True)
        import mercantile

        if not hasattr(input_gdf, 'geometry'):
            raise ValueError('This dataframe has no valid geometry.')

        geometry_name = input_gdf.geometry.name

        dfs = []
        for _, row in input_gdf.iterrows():
            input_geometry = row[geometry_name]
            bounds = input_geometry.bounds
            tiles = mercantile.tiles(bounds[0], bounds[1], bounds[2],
                                     bounds[3], zoom_level)
            new_rows = []
            for tile in tiles:
                new_row = row.copy()
                new_geometry = box(*mercantile.bounds(tile))
                if new_geometry.intersects(input_geometry):
                    new_row[geometry_name] = new_geometry
                    new_row['quadkey'] = mercantile.quadkey(tile)
                    new_rows.append(new_row)
            dfs.append(DataFrame(new_rows))

        df = concat(dfs).reset_index(drop=True)

        return GeoDataFrame(df, geometry=geometry_name, crs='epsg:4326')
Пример #10
0
def _get_tiles(src_path, nb_tiles=5):
    with rasterio.open(src_path) as src_dst:
        bounds = warp.transform_bounds(
            src_dst.crs, "epsg:4326", *src_dst.bounds, densify_pts=21
        )
        minzoom, maxzoom = mercator.get_zooms(src_dst)

    while True:
        zoom = random.randint(maxzoom - 2, maxzoom)
        tiles = list(mercantile.tiles(*bounds, zoom))

        def _f(tile):
            x, y, z = tile
            ulx, uly = mercantile.ul(x, y, z)
            lrx, lry = mercantile.ul(x + 1, y + 1, zoom)
            return (
                (bounds[0] < ulx < bounds[2])
                and (bounds[1] < uly < bounds[3])
                and (bounds[0] < lrx < bounds[2])
                and (bounds[1] < lry < bounds[3])
            )

        tiles = list(filter(lambda x: _f(x), tiles))
        if not tiles:
            continue

        if len(tiles) > nb_tiles:
            return random.sample(tiles, nb_tiles)
        else:
            return tiles
Пример #11
0
def howmany(w, s, e, n, zoom, verbose=True, ll=False):
    """
    Number of tiles required for a given bounding box and a zoom level
    ...

    Arguments
    ---------
    w       : float
              West edge longitude
    s       : float
              South edge latitude
    e       : float
              East edge longitude
    n       : float
              Noth edge latitude
    zoom    : int
              Level of detail
    verbose : Boolean
              [Optional. Default=True] If True, print short message with
              number of tiles and zoom.
    ll      : Boolean
              [Optional. Default: False] If True, `w`, `s`, `e`, `n` are
              assumed to be lon/lat as opposed to Spherical Mercator.
    """
    if not ll:
        # Convert w, s, e, n into lon/lat
        w, s = _sm2ll(w, s)
        e, n = _sm2ll(e, n)
    if zoom == "auto":
        zoom = _calculate_zoom(w, s, e, n)
    tiles = len(list(mt.tiles(w, s, e, n, [zoom])))
    if verbose:
        print("Using zoom level %i, this will download %i tiles" %
              (zoom, tiles))
    return tiles
def get_tile_list(geom,
                  zoom=17):
    """Generate the Tile List for The Tasking List

    Parameters
    ----------
    geom: shapely geometry of area.

    zoom : int Zoom Level for Tiles
        One or more zoom levels.

    Yields
    ------
    list of tiles that intersect with

    """

    west, south, east, north = geom.bounds
    tiles = mercantile.tiles(west, south, east, north, zooms=zoom)
    tile_list = []

    for tile in tiles:

        tile_geom = geometry.shape(mercantile.feature(tile)['geometry'])

        if tile_geom.intersects(geom):

            tile_list.append(tile)

    return tile_list
Пример #13
0
def add_terrain():
    twin = load_config()

    bbox = twin["bbox"]
    package = Package(".")

    dl = gsi.Downloader(CACHE_DIR)  # TODO: Fix

    basemap_zoom = 18
    tiles = mercantile.tiles(*bbox, basemap_zoom)  # left, bottom, right, top
    tiles = list(tiles)

    spinner = Halo(text="", spinner="bouncingBar")
    spinner.start(
        "Installing {}".format(typer.style("terrain", fg=typer.colors.GREEN, bold=True))
    )

    filenames = dl.download_dem5a(tiles)
    merged = utils.geojson_merge(filenames)
    # print(merged.head())

    merged.to_file(package.assets.joinpath("merged_dem5a.geojson"), driver="GeoJSON")

    extract_meshed_level(merged, outfile=package.assets.joinpath("levelmap.json"))

    spinner.succeed()
    spinner.stop()
Пример #14
0
def main(args):

    if not args.zoom and args.type in ["geojson", "bbox"]:
        sys.exit("Zoom parameter is required")

    cover = []

    if args.type == "geojson":
        with open(args.input) as f:
            features = json.load(f)

        for feature in tqdm(features["features"], ascii=True, unit="feature"):
            cover.extend(map(tuple, burntiles.burn([feature], args.zoom).tolist()))

        cover = list(set(cover))  # tiles can overlap for multiple features; unique tile ids

    elif args.type == "bbox":
        west, south, east, north = map(float, args.input.split(","))
        cover = tiles(west, south, east, north, args.zoom)

    elif args.type == "dir":
        cover = [tile for tile, _ in tiles_from_slippy_map(args.input)]

    if os.path.dirname(args.out) and not os.path.isdir(os.path.dirname(args.out)):
        os.makedirs(os.path.dirname(args.out), exist_ok=True)

    with open(args.out, "w") as fp:
        csv.writer(fp).writerows(cover)
def pickle_task_distributor(pickle_filepath,
                            bucket_name,
                            output_picklepath,
                            zoom=3):
    """
    tile_task_distributor(pickle_filepath, data_type, bucket_name, output_picklepath, zoom=3)

    -----------------------------------------------------------------------
    Inputs:
    picke_data_path: (str) - the path of the .pickle data file
    bucket_name: (str) the AWS bucket name
    output_picklepath: (str) - the location where subsetted data are saved
    zoom: (int) - the zoom level to generate data 'tiles'

    -----------------------------------------------------------------------
    Output: Invokes process_pickle.py lambda function on AWS with fully specified event
    -----------------------------------------------------------------------
    Author: Michael Christensen
    Date Modified: 10/08/2018
    """

    pickle_data = s3.get_object(Bucket=bucket_name, Key=pickle_filepath)
    body_string = pickle_data['Body'].read()
    data = pickle.loads(body_string)

    lat = data['lat']
    lon = data['lon']

    tiles = mercantile.tiles(west=lon.min(),
                             south=lat.min(),
                             east=lon.max(),
                             north=lat.max(),
                             zooms=zoom)
    x, y, z = zip(*[t for t in tiles])

    #break into groups of 50
    group_size = 50
    tile_break_points = (list(range(0, len(x), group_size)))
    tile_break_points.append(len(x))

    # check that the event is valid format
    for break_indx in range(len(tile_break_points) - 1):
        # build payload for initiation of lambda function
        payload = {}
        payload['pickle_filepath'] = pickle_filepath
        payload['bucket_name'] = bucket_name
        payload['output_picklepath'] = output_picklepath
        payload['xyz_info'] = {
            'start_indx': tile_break_points[break_indx],
            'end_indx': tile_break_points[break_indx + 1]
        }
        payload['zoom'] = zoom

        # invoke process_tiles with appropriate payload
        try:
            response = lam.invoke(FunctionName='process_pickle',
                                  InvocationType='Event',
                                  Payload=json.dumps(payload))
        except Exception as e:
            raise e
Пример #16
0
    def _tile_coords(self, bounds):
        """ convert mercator bbox to tile index limits """
        tfm = partial(pyproj.transform, pyproj.Proj(init="epsg:3857"),
                      pyproj.Proj(init="epsg:4326"))
        bounds = ops.transform(tfm, box(*bounds)).bounds

        # because tiles have a common corner, the tiles that cover a
        # given tile includes the adjacent neighbors.
        # https://github.com/mapbox/mercantile/issues/84#issuecomment-413113791

        west, south, east, north = bounds
        epsilon = 1.0e-10
        if east != west and north != south:
            # 2D bbox
            # shrink the bounds a small amount so that
            # shapes/tiles round trip.
            west += epsilon
            south += epsilon
            east -= epsilon
            north -= epsilon

        params = [west, south, east, north, [self.zoom_level]]
        tile_coords = [(tile.x, tile.y) for tile in mercantile.tiles(*params)]
        xtiles, ytiles = zip(*tile_coords)
        minx = min(xtiles)
        miny = min(ytiles)
        maxx = max(xtiles)
        maxy = max(ytiles)
        return minx, miny, maxx, maxy
Пример #17
0
def test_tiles_roundtrip(t):
    """tiles(bounds(tile)) gives the tile"""
    res = list(mercantile.tiles(*mercantile.bounds(t), zooms=[t.z]))
    assert len(res) == 1
    val = res.pop()
    assert val.x == t.x
    assert val.y == t.y
    assert val.z == t.z
Пример #18
0
 def get_intersected_tiles(self):
     zoom_range = range(app_settings.MIN_TILE_ZOOM, app_settings.MAX_TILE_ZOOM + 1)
     try:
         return [(tile.x, tile.y, tile.z)
                 for tile in tiles(*self.get_bounding_box(), zoom_range)]
     except ValueError:
         # TODO find why a ValueError is raised with some Point() geometries
         return []
Пример #19
0
def test_tiles_single_zoom():
    bounds = (-105, 39.99, -104.99, 40)
    tiles = list(mercantile.tiles(*bounds, zooms=14))
    expect = [
        mercantile.Tile(x=3413, y=6202, z=14),
        mercantile.Tile(x=3413, y=6203, z=14),
    ]
    assert sorted(tiles) == sorted(expect)
Пример #20
0
def bbox_to_quadkeys(bbox: list, zoom: int):
    """ Find all quadkeys in a bbox """
    tiles = mercantile.tiles(bbox[0], bbox[1], bbox[2], bbox[3], int(zoom))
    quadkeys = []
    for tile in tiles:
        quadkeys.append(mercantile.quadkey(tile))

    return quadkeys
Пример #21
0
def create_tiles_gdf(bounds: List[float],
                     quadkey_zoom: int) -> gpd.GeoDataFrame:
    """Create GeoDataFrame of all tiles within bounds at quadkey_zoom
    """
    features = [
        mercantile.feature(tile, props={'quadkey': mercantile.quadkey(tile)})
        for tile in mercantile.tiles(*bounds, quadkey_zoom)
    ]
    return gpd.GeoDataFrame.from_features(features, crs='EPSG:4326')
Пример #22
0
def write_tile_data():
    filename = args.output_filename
    with open(filename, "w", newline="") as data_file:
        writer = csv.writer(data_file)
        for tile in mercantile.tiles(args.minx, args.miny, args.maxx,
                                     args.maxy,
                                     range(args.minlevel, args.maxlevel)):
            bounds = mercantile.bounds(tile)
            writer.writerow(bounds)
Пример #23
0
    def handle(self, *args, **kwargs):
        tiles = []
        for service in Service.objects.all():
            extent = service.full_extent.project(WGS84)
            tiles += [
                (service.name, t) for t in
                mercantile.tiles(extent.xmin, extent.ymin, extent.xmax, extent.ymax, ZOOM_LEVELS, truncate=True)
            ]

        asyncio.get_event_loop().run_until_complete(self.fetch_tiles(tiles))
Пример #24
0
        def worker(path):

            raster = rasterio_open(path)
            w, s, e, n = transform_bounds(raster.crs, "EPSG:4326", *raster.bounds)
            transform, _, _ = calculate_default_transform(raster.crs, "EPSG:3857", raster.width, raster.height, w, s, e, n)
            tiles = [mercantile.Tile(x=x, y=y, z=z) for x, y, z in mercantile.tiles(w, s, e, n, args.zoom)]
            tiled = []

            for tile in tiles:

                try:
                    w, s, e, n = mercantile.xy_bounds(tile)

                    # inspired by rio-tiler, cf: https://github.com/mapbox/rio-tiler/pull/45
                    warp_vrt = WarpedVRT(
                        raster,
                        crs="epsg:3857",
                        resampling=Resampling.bilinear,
                        add_alpha=False,
                        transform=from_bounds(w, s, e, n, args.ts, args.ts),
                        width=math.ceil((e - w) / transform.a),
                        height=math.ceil((s - n) / transform.e),
                    )
                    data = warp_vrt.read(
                        out_shape=(len(raster.indexes), args.ts, args.ts), window=warp_vrt.window(w, s, e, n)
                    )
                    image = np.moveaxis(data, 0, 2)  # C,H,W -> H,W,C
                except:
                    sys.exit("Error: Unable to tile {} from raster {}.".format(str(tile), raster))

                tile_key = (str(tile.x), str(tile.y), str(tile.z))
                if not args.label and len(tiles_map[tile_key]) == 1 and is_border(image):
                    progress.update()
                    continue

                if len(tiles_map[tile_key]) > 1:
                    out = os.path.join(splits_path, str(tiles_map[tile_key].index(path)))
                else:
                    out = args.out

                x, y, z = map(int, tile)

                if not args.label:
                    ret = tile_image_to_file(out, mercantile.Tile(x=x, y=y, z=z), image)
                if args.label:
                    ret = tile_label_to_file(out, mercantile.Tile(x=x, y=y, z=z), palette, image)

                if not ret:
                    sys.exit("Error: Unable to write tile {} from raster {}.".format(str(tile), raster))

                if len(tiles_map[tile_key]) == 1:
                    progress.update()
                    tiled.append(mercantile.Tile(x=x, y=y, z=z))

            return tiled
Пример #25
0
def get_tiles(zoom, input, dst_crs="EPSG:3857"):
    print("getting tiles for", input)
    input = input.replace("s3://", "/vsicurl/http://s3.amazonaws.com/")
    with rasterio.drivers():
        with rasterio.open(input) as src:
            # Compute the geographic bounding box of the dataset.
            (west, east), (south, north) = transform(
                src.crs, "EPSG:4326", src.bounds[::2], src.bounds[1::2])

            # Initialize an iterator over output tiles.
            return mercantile.tiles(
                west, south, east, north, range(zoom, zoom + 1))
Пример #26
0
def find_tiles(geometry, min_zoom, max_zoom):
    assert min_zoom <= max_zoom, 'min zoom must be <= max zoom'

    selected_tiles = []

    bound_tiles = mercantile.tiles(*geometry.bounds,
                                   zooms=range(min_zoom, max_zoom + 1))
    for tile in bound_tiles:
        if box(*mercantile.bounds(tile)).intersects(geometry):
            selected_tiles.append(tile)

    return selected_tiles
Пример #27
0
    def _download_image(self):
        """
        return glued tiles as PIL image
        :param west: west longitude in degrees
        :param south: south latitude in degrees
        :param east: east longitude in degrees
        :param north: north latitude in degrees
        :param zoom: wanted size
        :return: Image
        """
        tiles = list(
            mercantile.tiles(self._west, self._south, self._east, self._north,
                             self.zoom))

        min_x = min_y = max_x = max_y = None

        for tile in tiles:
            min_x = min(min_x, tile.x) if min_x is not None else tile.x
            min_y = min(min_y, tile.y) if min_y is not None else tile.y
            max_x = max(max_x, tile.x) if max_x is not None else tile.x
            max_y = max(max_y, tile.y) if max_y is not None else tile.y

        out_img = PIL.Image.new('RGB', ((max_x - min_x + 1) * self.TILE_SIZE,
                                        (max_y - min_y + 1) * self.TILE_SIZE))

        pool = multiprocessing.Pool(self.pool_workers)
        results = pool.map(self._download_tile, tiles)
        pool.close()
        pool.join()

        for img, tile in results:
            left = tile.x - min_x
            top = tile.y - min_y
            bounds = (left * self.TILE_SIZE, top * self.TILE_SIZE,
                      (left + 1) * self.TILE_SIZE, (top + 1) * self.TILE_SIZE)
            out_img.paste(img, bounds)

        tiles_bounding = list(mercantile.xy_bounds(t) for t in tiles)
        min_mercator_lng = min(t.left for t in tiles_bounding)
        max_mercator_lng = max(t.right for t in tiles_bounding)
        min_mercator_lat = min(t.bottom for t in tiles_bounding)
        max_mercator_lat = max(t.top for t in tiles_bounding)

        kx = out_img.size[0] / (max_mercator_lng - min_mercator_lng)
        ky = out_img.size[1] / (max_mercator_lat - min_mercator_lat)

        self._image = out_img
        self._left = min_mercator_lng
        self._right = max_mercator_lng
        self._top = max_mercator_lat
        self._bottom = min_mercator_lat
        self._kx = kx
        self._ky = ky
Пример #28
0
        def worker(path):

            raster = rasterio_open(path)
            w, s, e, n = transform_bounds(raster.crs, "EPSG:4326", *raster.bounds)
            tiles = [mercantile.Tile(x=x, y=y, z=z) for x, y, z in mercantile.tiles(w, s, e, n, args.zoom)]
            tiled = []

            for tile in tiles:

                if cover and tile not in cover:
                    continue

                w, s, e, n = mercantile.xy_bounds(tile)

                warp_vrt = WarpedVRT(
                    raster,
                    crs="epsg:3857",
                    resampling=Resampling.bilinear,
                    add_alpha=False,
                    transform=from_bounds(w, s, e, n, width, height),
                    width=width,
                    height=height,
                )
                data = warp_vrt.read(out_shape=(len(raster.indexes), width, height), window=warp_vrt.window(w, s, e, n))
                image = np.moveaxis(data, 0, 2)  # C,H,W -> H,W,C

                tile_key = (str(tile.x), str(tile.y), str(tile.z))
                if (
                    not args.label
                    and len(tiles_map[tile_key]) == 1
                    and is_nodata(image, args.nodata, args.nodata_threshold, args.keep_borders)
                ):
                    progress.update()
                    continue

                if len(tiles_map[tile_key]) > 1:
                    out = os.path.join(splits_path, str(tiles_map[tile_key].index(path)))
                else:
                    out = args.out

                x, y, z = map(int, tile)

                if not args.label:
                    tile_image_to_file(out, mercantile.Tile(x=x, y=y, z=z), image)
                if args.label:
                    tile_label_to_file(out, mercantile.Tile(x=x, y=y, z=z), palette, image)

                if len(tiles_map[tile_key]) == 1:
                    progress.update()
                    tiled.append(mercantile.Tile(x=x, y=y, z=z))

            return tiled
Пример #29
0
    def handle(self, *args, **options):
        for layer in Layer.objects.all():
            if options['verbosity'] >= 1:
                self.stdout.write(f'Generating {layer.name} tiles cache')
            bbox = layer.features.aggregate(bbox=Extent('geom'))['bbox']
            if bbox:
                vtile = VectorTile(layer)
                zoom_range = range(
                    layer.layer_settings_with_default('tiles', 'minzoom'),
                    layer.layer_settings_with_default('tiles', 'maxzoom') + 1)

                for tile in tiles(*bbox, zoom_range):
                    vtile.get_tile(tile.x, tile.y, tile.z)
Пример #30
0
 def _tile_coords(self, bounds):
     """ Convert tile coords mins/maxs to lng/lat bounds """
     tfm = partial(pyproj.transform, pyproj.Proj(init="epsg:3857"),
                   pyproj.Proj(init="epsg:4326"))
     bounds = ops.transform(tfm, box(*bounds)).bounds
     params = list(bounds) + [[self.zoom_level]]
     tile_coords = [(tile.x, tile.y) for tile in mercantile.tiles(*params)]
     xtiles, ytiles = zip(*tile_coords)
     minx = min(xtiles)
     maxx = max(xtiles)
     miny = min(ytiles)
     maxy = max(ytiles)
     return minx, miny, maxx, maxy
Пример #31
0
def area(config, storage, dbname, host, port, username, connections,
         chunk_size, min_zoom, max_zoom, bbox):
    '''Generates tiles for an area'''
    # Get the directory the config is in
    full_path = os.path.join(os.getcwd(), config)
    root_path = os.path.dirname(full_path)
    config_path = os.path.relpath(full_path, root_path)

    filesystem = fs.osfs.OSFS(root_path)

    config = tilekiln.config.Config(
        filesystem.open(config_path).read(), filesystem)
    dbinfo = {
        "dbname": dbname,
        "host": host,
        "port": port,
        "username": username
    }

    min_zoom = min_zoom or config.minzoom
    max_zoom = max_zoom or config.maxzoom
    zoom_levels = [z for z in range(min_zoom, max_zoom + 1)]

    bounding_box = tuple(map(float, bbox.split(',')))
    if len(bounding_box) != 4:
        raise ValueError(f'Provided bounding box: "{bbox}" is invalid.' +
                         ' It should have 4 elements separated by commas.')
    if any([
            bounding_box[0] < -180,
            bounding_box[0] > 180,
            bounding_box[2] < -180,
            bounding_box[2] > 180,
    ]):
        raise ValueError(
            'Longitude cannot be lower than -180 or higher than 180.')
    if any([
            bounding_box[1] < -90, bounding_box[1] > 90, bounding_box[3] < -90,
            bounding_box[3] > 90
    ]):
        raise ValueError(
            'Latitude cannot be lower than -90 or higher than 90.')

    tiles = [(tile.z, tile.x, tile.y)
             for tile in mercantile.tiles(*bounding_box, zoom_levels)]

    # Apply some heuristics to guess a chunk size
    if chunk_size is None:
        chunk_size = int(min(max(len(tiles) / (2 * connections), 10), 50000))

    kiln = tilekiln.kiln.Kiln(config, dbinfo, storage)
    kiln.generate_tiles(tiles, connections, chunk_size)
Пример #32
0
    def calculate_zoom(self):
        # maximum number of needed tiles for thumbnail of given width and height
        max_tiles = (ceil(self.thumbnail_width / self.tile_size) +
                     1) * (ceil(self.thumbnail_height / self.tile_size) + 1)

        # zoom for which there are less needed tiles than max_tiles
        zoom = 0
        for z in range(1, 16):
            if len(list(mercantile.tiles(*self._mercantile_bbox,
                                         z))) > max_tiles:
                break
            else:
                zoom = max(zoom, z)
        return zoom
Пример #33
0
def seed_inputs(bounds, zooms):
    for tile in mercantile.tiles(*bounds, zooms=zooms):
        s = tile_url(strava, tile), tile_path(os.path.join(tiledir, 'strava'), tile, 'png')
        v = tile_url(osm_vect, tile), tile_path(os.path.join(tiledir, 'osm'), tile, 'json')
        save_tile(*s)
        save_tile(*v)
Пример #34
0
def mbtiles(ctx, files, output, overwrite, title, description,
            layer_type, img_format, tile_size, zoom_levels, image_dump,
            num_workers, src_nodata, dst_nodata, resampling, rgba):
    """Export a dataset to MBTiles (version 1.1) in a SQLite file.

    The input dataset may have any coordinate reference system. It must
    have at least three bands, which will be become the red, blue, and
    green bands of the output image tiles.

    An optional fourth alpha band may be copied to the output tiles by
    using the --rgba option in combination with the PNG format. This
    option requires that the input dataset has at least 4 bands.

    If no zoom levels are specified, the defaults are the zoom levels
    nearest to the one at which one tile may contain the entire source
    dataset.

    If a title or description for the output file are not provided,
    they will be taken from the input dataset's filename.

    This command is suited for small to medium (~1 GB) sized sources.

    Python package: rio-mbtiles (https://github.com/mapbox/rio-mbtiles).
    """
    output, files = resolve_inout(files=files, output=output,
                                  overwrite=overwrite)
    inputfile = files[0]

    log = logging.getLogger(__name__)

    with ctx.obj['env']:

        # Read metadata from the source dataset.
        with rasterio.open(inputfile) as src:

            validate_nodata(dst_nodata, src_nodata, src.profile.get('nodata'))
            base_kwds = {'dst_nodata': dst_nodata, 'src_nodata': src_nodata}

            if src_nodata is not None:
                base_kwds.update(nodata=src_nodata)

            if dst_nodata is not None:
                base_kwds.update(nodata=dst_nodata)

            # Name and description.
            title = title or os.path.basename(src.name)
            description = description or src.name

            # Compute the geographic bounding box of the dataset.
            (west, east), (south, north) = transform(
                src.crs, 'EPSG:4326', src.bounds[::2], src.bounds[1::2])

        # Resolve the minimum and maximum zoom levels for export.
        if zoom_levels:
            minzoom, maxzoom = map(int, zoom_levels.split('..'))
        else:
            zw = int(round(math.log(360.0 / (east - west), 2.0)))
            zh = int(round(math.log(170.1022 / (north - south), 2.0)))
            minzoom = min(zw, zh)
            maxzoom = max(zw, zh)

        log.debug("Zoom range: %d..%d", minzoom, maxzoom)

        if rgba:
            if img_format == 'JPEG':
                raise click.BadParameter("RGBA output is not possible with JPEG format.")
            else:
                count = 4
        else:
            count = 3

        # Parameters for creation of tile images.
        base_kwds.update({
            'driver': img_format.upper(),
            'dtype': 'uint8',
            'nodata': 0,
            'height': tile_size,
            'width': tile_size,
            'count': count,
            'crs': TILES_CRS})

        img_ext = 'jpg' if img_format.lower() == 'jpeg' else 'png'

        # Initialize the sqlite db.
        if os.path.exists(output):
            os.unlink(output)

        # workaround for bug here: https://bugs.python.org/issue27126
        sqlite3.connect(':memory:').close()

        conn = sqlite3.connect(output)
        cur = conn.cursor()
        cur.execute(
            "CREATE TABLE tiles "
            "(zoom_level integer, tile_column integer, "
            "tile_row integer, tile_data blob);")
        cur.execute(
            "CREATE TABLE metadata (name text, value text);")

        # Insert mbtiles metadata into db.
        cur.execute(
            "INSERT INTO metadata (name, value) VALUES (?, ?);",
            ("name", title))
        cur.execute(
            "INSERT INTO metadata (name, value) VALUES (?, ?);",
            ("type", layer_type))
        cur.execute(
            "INSERT INTO metadata (name, value) VALUES (?, ?);",
            ("version", "1.1"))
        cur.execute(
            "INSERT INTO metadata (name, value) VALUES (?, ?);",
            ("description", description))
        cur.execute(
            "INSERT INTO metadata (name, value) VALUES (?, ?);",
            ("format", img_ext))
        cur.execute(
            "INSERT INTO metadata (name, value) VALUES (?, ?);",
            ("bounds", "%f,%f,%f,%f" % (west, south, east, north)))

        conn.commit()

        # Create a pool of workers to process tile tasks.
        pool = Pool(num_workers, init_worker,
                    (inputfile, base_kwds, resampling), 100)

        # Constrain bounds.
        EPS = 1.0e-10
        west = max(-180 + EPS, west)
        south = max(-85.051129, south)
        east = min(180 - EPS, east)
        north = min(85.051129, north)

        # Initialize iterator over output tiles.
        tiles = mercantile.tiles(
            west, south, east, north, range(minzoom, maxzoom + 1))

        for tile, contents in pool.imap_unordered(process_tile, tiles):

            if contents is None:
                log.info("Tile %r is empty and will be skipped", tile)
                continue

            # MBTiles have a different origin than Mercantile/tilebelt.
            tiley = int(math.pow(2, tile.z)) - tile.y - 1

            # Optional image dump.
            if image_dump:
                img_name = '%d-%d-%d.%s' % (
                    tile.x, tiley, tile.z, img_ext)
                img_path = os.path.join(image_dump, img_name)
                with open(img_path, 'wb') as img:
                    img.write(contents)

            # Insert tile into db.
            cur.execute(
                "INSERT INTO tiles "
                "(zoom_level, tile_column, tile_row, tile_data) "
                "VALUES (?, ?, ?, ?);",
                (tile.z, tile.x, tiley, sqlite3.Binary(contents)))

            conn.commit()

        conn.close()
Пример #35
0
def tiles(ctx, zoom, input, seq):
    """Lists Web Mercator tiles at ZOOM level intersecting
    GeoJSON [west, south, east, north] bounding boxen, features, or
    collections read from stdin. Output is a JSON
    [x, y, z] array.

    Input may be a compact newline-delimited sequences of JSON or
    a pretty-printed ASCII RS-delimited sequence of JSON (like
    https://tools.ietf.org/html/rfc8142 and
    https://tools.ietf.org/html/rfc7159).

    Example:

    $ echo "[-105.05, 39.95, -105, 40]" | mercantile tiles 12

    Output:

    [852, 1550, 12]
    [852, 1551, 12]
    [853, 1550, 12]
    [853, 1551, 12]

    """
    src = iter(normalize_input(input))
    first_line = next(src)

    # If input is RS-delimited JSON sequence.
    if first_line.startswith(u'\x1e'):
        def feature_gen():
            buffer = first_line.strip(u'\x1e')
            for line in src:
                if line.startswith(u'\x1e'):
                    if buffer:
                        yield json.loads(buffer)
                    buffer = line.strip(u'\x1e')
                else:
                    buffer += line
            else:
                yield json.loads(buffer)
    else:
        def feature_gen():
            yield json.loads(first_line)
            for line in src:
                yield json.loads(line)

    source = feature_gen()
    # Detect the input format
    for obj in source:
        if isinstance(obj, list):
            bbox = obj
            if len(bbox) == 2:
                bbox += bbox
            if len(bbox) != 4:
                raise click.BadParameter(
                    "{0}".format(bbox), param=input, param_hint='input')
        elif isinstance(obj, dict):
            if 'bbox' in obj:
                bbox = obj['bbox']
            else:
                box_xs = []
                box_ys = []
                for feat in obj.get('features', [obj]):
                    lngs, lats = zip(*list(coords(feat)))
                    box_xs.extend([min(lngs), max(lngs)])
                    box_ys.extend([min(lats), max(lats)])
                bbox = min(box_xs), min(box_ys), max(box_xs), max(box_ys)
        west, south, east, north = bbox
        epsilon = 1.0e-10

        if east != west and north != south:
            # 2D bbox
            # shrink the bounds a small amount so that
            # shapes/tiles round trip.
            west += epsilon
            south += epsilon
            east -= epsilon
            north -= epsilon

        for tile in mercantile.tiles(
                west, south, east, north, [zoom], truncate=False):
            vals = (tile.x, tile.y, zoom)
            output = json.dumps(vals)
            if seq:
                click.echo(u'\x1e')
            click.echo(output)
Пример #36
0
def tiles(ctx, zoom, input, bounding_tile, with_bounds, seq, x_json_seq):
    """Lists Web Mercator tiles at ZOOM level intersecting
    GeoJSON [west, south, east, north] bounding boxen, features, or
    collections read from stdin. Output is a JSON
    [x, y, z [, west, south, east, north -- optional]] array.

    Example:

    $ echo "[-105.05, 39.95, -105, 40]" | mercantile tiles 12

    Output:

    [852, 1550, 12]
    [852, 1551, 12]
    [853, 1550, 12]
    [853, 1551, 12]

    """
    verbosity = ctx.obj['verbosity']
    logger = logging.getLogger('mercantile')
    try:
        src = click.open_file(input).readlines()
    except IOError:
        src = [input]

    src = iter(src)
    first_line = next(src)

    # If input is RS-delimited JSON sequence.
    if first_line.startswith(u'\x1e'):
        def feature_gen():
            buffer = first_line.strip(u'\x1e')
            for line in src:
                if line.startswith(u'\x1e'):
                    if buffer:
                        yield json.loads(buffer)
                    buffer = line.strip(u'\x1e')
                else:
                    buffer += line
            else:
                yield json.loads(buffer)
    else:
        def feature_gen():
            yield json.loads(first_line)
            for line in src:
                yield json.loads(line)

    try:
        source = feature_gen()
        # Detect the input format
        for obj in source:
            if isinstance(obj, list):
                bbox = obj
                if len(bbox) == 2:
                    bbox += bbox
                if len(bbox) != 4:
                    raise ValueError("Invalid input.")
            elif isinstance(obj, dict):
                if 'bbox' in obj:
                    bbox = obj['bbox']
                else:
                    box_xs = []
                    box_ys = []
                    for feat in obj.get('features', [obj]):
                        lngs, lats = zip(*list(coords(feat)))
                        box_xs.extend([min(lngs), max(lngs)])
                        box_ys.extend([min(lats), max(lats)])
                    bbox = min(box_xs), min(box_ys), max(box_xs), max(box_ys)
            west, south, east, north = bbox
            if bounding_tile:
                vals = mercantile.bounding_tile(
                    west, south, east, north, truncate=False)
                output = json.dumps(vals)
                if seq:
                    click.echo(u'\x1e')
                click.echo(output)
            else:
                # shrink the bounds a small amount so that
                # shapes/tiles round trip.
                epsilon = 1.0e-10
                west += epsilon
                south += epsilon
                east -= epsilon
                north -= epsilon
                for tile in mercantile.tiles(
                        west, south, east, north, [zoom], truncate=False):
                    vals = (tile.x, tile.y, zoom)
                    if with_bounds:
                        vals += mercantile.bounds(tile.x, tile.y, zoom)
                    output = json.dumps(vals)
                    if seq:
                        click.echo(u'\x1e')
                    click.echo(output)

        sys.exit(0)
    except Exception:
        logger.exception("Failed. Exception caught")
        sys.exit(1)
Пример #37
0
def mbtiles(ctx, files, output_opt, title, description, layer_type,
            img_format, zoom_levels, image_dump, num_workers):
    """Export a dataset to MBTiles (version 1.1) in a SQLite file.

    The input dataset may have any coordinate reference system. It must
    have at least three bands, which will be become the red, blue, and
    green bands of the output image tiles.

    If no zoom levels are specified, the defaults are the zoom levels
    nearest to the one at which one tile may contain the entire source
    dataset.

    If a title or description for the output file are not provided,
    they will be taken from the input dataset's filename.

    This command is suited for small to medium (~1 GB) sized sources.

    Python package: rio-mbtiles (https://github.com/mapbox/rio-mbtiles).
    """

    verbosity = (ctx.obj and ctx.obj.get('verbosity')) or 1
    logger = logging.getLogger('rio')

    output, files = resolve_inout(files=files, output=output_opt)
    inputfile = files[0]

    with rasterio.drivers(CPL_DEBUG=verbosity > 2):

        # Read metadata from the source dataset.
        with rasterio.open(inputfile) as src:

            # Name and description.
            title = title or os.path.basename(src.name)
            description = description or src.name

            # Compute the geographic bounding box of the dataset.
            (west, east), (south, north) = transform(
                src.crs, 'EPSG:4326', src.bounds[::2], src.bounds[1::2])

        # Resolve the minimum and maximum zoom levels for export.
        if zoom_levels:
            minzoom, maxzoom = map(int, zoom_levels.split('..'))
        else:
            zw = int(round(math.log(360.0/(east-west), 2.0)))
            zh = int(round(math.log(170.1022/(north-south), 2.0)))
            minzoom = min(zw, zh)
            maxzoom = max(zw, zh)
        logger.debug("Zoom range: %d..%d", minzoom, maxzoom)

        # Parameters for creation of tile images.
        base_kwds = {
            'driver': img_format.upper(),
            'dtype': 'uint8',
            'nodata': 0,
            'height': 256,
            'width': 256,
            'count': 3,
            'crs': 'EPSG:3857'}

        img_ext = 'jpg' if img_format.lower() == 'jpeg' else 'png'

        # Initialize the sqlite db.
        if os.path.exists(output):
            os.unlink(output)
        conn = sqlite3.connect(output)
        cur = conn.cursor()
        cur.execute(
            "CREATE TABLE tiles "
            "(zoom_level integer, tile_column integer, "
            "tile_row integer, tile_data blob);")
        cur.execute(
            "CREATE TABLE metadata (name text, value text);")

        # Insert mbtiles metadata into db.
        cur.execute(
            "INSERT INTO metadata (name, value) VALUES (?, ?);",
            ("name", title))
        cur.execute(
            "INSERT INTO metadata (name, value) VALUES (?, ?);",
            ("type", layer_type))
        cur.execute(
            "INSERT INTO metadata (name, value) VALUES (?, ?);",
            ("version", "1.1"))
        cur.execute(
            "INSERT INTO metadata (name, value) VALUES (?, ?);",
            ("description", description))
        cur.execute(
            "INSERT INTO metadata (name, value) VALUES (?, ?);",
            ("format", img_ext))
        cur.execute(
            "INSERT INTO metadata (name, value) VALUES (?, ?);",
            ("bounds", "%f,%f,%f,%f" % (west, south, east, north)))

        conn.commit()

        # Create a pool of workers to process tile tasks.
        pool = Pool(num_workers, init_worker, (inputfile, base_kwds), 100)

        # Constrain bounds.
        EPS = 1.0e-10
        west = max(-180+EPS, west)
        south = max(-85.051129, south)
        east = min(180-EPS, east)
        north = min(85.051129, north)

        # Initialize iterator over output tiles.
        tiles = mercantile.tiles(
            west, south, east, north, range(minzoom, maxzoom+1))

        for tile, contents in pool.imap_unordered(process_tile, tiles):

            # MBTiles has a different origin than Mercantile/tilebelt.
            tiley = int(math.pow(2, tile.z)) - tile.y - 1

            # Optional image dump.
            if image_dump:
                img_name = '%d-%d-%d.%s' % (
                    tile.x, tiley, tile.z, img_ext)
                img_path = os.path.join(image_dump, img_name)
                with open(img_path, 'wb') as img:
                    img.write(contents)

            # Insert tile into db.
            cur.execute(
                "INSERT INTO tiles "
                "(zoom_level, tile_column, tile_row, tile_data) "
                "VALUES (?, ?, ?, ?);",
                (tile.z, tile.x, tiley, buffer(contents)))

            conn.commit()

        conn.close()
Пример #38
0
def test_tiles_single_zoom():
    bounds = (-105, 39.99, -104.99, 40)
    tiles = list(mercantile.tiles(*bounds, zooms=14))
    expect = [mercantile.Tile(x=3413, y=6202, z=14),
              mercantile.Tile(x=3413, y=6203, z=14)]
    assert sorted(tiles) == sorted(expect)
Пример #39
0
def test_tiles_truncate():
    """Input is truncated"""
    assert list(mercantile.tiles(-181.0, 0.0, -170.0, 10.0, zooms=[2], truncate=True)) \
        == list(mercantile.tiles(-180.0, 0.0, -170.0, 10.0, zooms=[2]))
Пример #40
0
def test_tiles_antimerdian_crossing_bbox():
    """Antimeridian-crossing bounding boxes are handled"""
    bounds = (175.0, 5.0, -175.0, 10.0)
    assert len(list(mercantile.tiles(*bounds, zooms=[2]))) == 2
Пример #41
0
def test_global():
    assert len(list(mercantile.tiles(-180, -90, 180, 90, [1], truncate=True))) == 4
Пример #42
0
def test_global_tiles_clamped():
    """Y is clamped to (0, 2 ** zoom - 1)"""
    tiles = list(mercantile.tiles(-180, -90, 180, 90, [1]))
    assert len(tiles) == 4
    assert min(t.y for t in tiles) == 0
    assert max(t.y for t in tiles) == 1
Пример #43
0
def seed_outputs(bounds, zooms):
    for tile in mercantile.tiles(*bounds, zooms=zooms):
        print(tile)
        render_offroad_tile(tile)