def flip_quadkey(q, flip): lng, lat = quadkey_to_centroid(q) z = len(q) if flip[0]: lng = -lng if flip[1]: lat = -lat tile = mercantile.tile(lng, lat, z) return mercantile.quadkey(tile)
def quadkey(ctx, input): """Takes [x, y, z] tiles or quadkeys as input and writes quadkeys or a [x, y, z] tiles to stdout, respectively. 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). $ echo "[486, 332, 10]" | mercantile quadkey Output: 0313102310 $ echo "0313102310" | mercantile quadkey Output: [486, 332, 10] """ src = normalize_input(input) try: for line in iter_lines(src): if line[0] == '[': tile = json.loads(line)[:3] output = mercantile.quadkey(tile) else: tile = mercantile.quadkey_to_tile(line) output = json.dumps(tile) click.echo(output) except ValueError: raise click.BadParameter( "{0}".format(input), param=input, param_hint='input')
def cl_post_prediction(self, payload: Dict[str, Any], chips: List[dict], prediction_id: str, inferences: List[str]) -> Dict[str, Any]: payload = json.dumps(payload) r = requests.post(self.prediction_endpoint + ":predict", data=payload) r.raise_for_status() preds = r.json()["predictions"] pred_list = []; for i in range(len(chips)): pred_dict = {} for j in range(len(preds[i])): pred_dict[inferences[j]] = preds[i][j] body = { "geom": shapely.geometry.mapping(box(*chips[i].get('bounds'))), "predictions": pred_dict, "prediction_id": prediction_id } if chips[i].get('x') is not None and chips[i].get('y') is not None and chips[i].get('z') is not None: body['quadkey'] = mercantile.quadkey(chips[i].get('x'), chips[i].get('y'), chips[i].get('z')) pred_list.append(body) return { "predictionId": prediction_id, "predictions": pred_list }
def quadkey(ctx, input): """Takes a [x, y, z] tile or a quadkey as input and writes a quadkey or a [x, y, z] tile to stdout, respectively. $ echo "[486, 332, 10]" | mercantile quadkey Output: 0313102310 $ echo "0313102310" | mercantile quadkey Output: [486, 332, 10] """ src = normalize_input(input) try: for line in iter_lines(src): if line[0] == '[': tile = json.loads(line)[:3] output = mercantile.quadkey(tile) else: tile = mercantile.quadkey_to_tile(line) output = json.dumps(tile) click.echo(output) except ValueError: raise click.BadParameter("{0}".format(input), param=input, param_hint='input')
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')
def cl_post_prediction(self, payload: Dict[str, Any], tiles: List[Tile], prediction_id: str, inferences: List[str]) -> Dict[str, Any]: payload = json.dumps(payload) r = requests.post(self.prediction_endpoint + ":predict", data=payload) r.raise_for_status() preds = r.json()["predictions"] pred_list = [] for i in range(len(tiles)): pred_dict = {} for j in range(len(preds[i])): pred_dict[inferences[j]] = preds[i][j] pred_list.append({ "quadkey": mercantile.quadkey(tiles[i].x, tiles[i].y, tiles[i].z), "predictions": pred_dict, "prediction_id": prediction_id }) return {"predictionId": prediction_id, "predictions": pred_list}
def quadkey(ctx, input): """Takes a [x, y, z] tile or a quadkey as input and writes a quadkey or a [x, y, z] tile to stdout, respectively. $ echo "[486, 332, 10]" | mercantile quadkey Output: 0313102310 $ echo "0313102310" | mercantile quadkey Output: [486, 332, 10] """ src = normalize_input(input) try: for line in iter_lines(src): if line[0] == '[': tile = json.loads(line)[:3] output = mercantile.quadkey(tile) else: tile = mercantile.quadkey_to_tile(line) output = json.dumps(tile) click.echo(output) except ValueError: raise click.BadParameter( "{0}".format(input), param=input, param_hint='input')
def quadkey(ctx, input): """Takes [x, y, z] tiles or quadkeys as input and writes quadkeys or a [x, y, z] tiles to stdout, respectively. 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). Examples: \b echo "[486, 332, 10]" | mercantile quadkey 0313102310 \b echo "0313102310" | mercantile quadkey [486, 332, 10] """ src = normalize_input(input) try: for line in iter_lines(src): if line[0] == "[": tile = json.loads(line)[:3] output = mercantile.quadkey(tile) else: tile = mercantile.quadkey_to_tile(line) output = json.dumps(tile) click.echo(output) except mercantile.QuadKeyError: raise click.BadParameter("{0}".format(input), param=input, param_hint="input")
def get_assets(url: str, x: int, y: int, z: int) -> Tuple[str]: """Get assets.""" mosaic_def = fetch_mosaic_definition(url) min_zoom = mosaic_def["minzoom"] max_zoom = mosaic_def["maxzoom"] if z > max_zoom or z < min_zoom: return [] # return empty asset mercator_tile = mercantile.Tile(x=x, y=y, z=z) quadkey_zoom = mosaic_def.get("quadkey_zoom", min_zoom) # 0.0.2 # get parent if mercator_tile.z > quadkey_zoom: depth = mercator_tile.z - quadkey_zoom for i in range(depth): mercator_tile = mercantile.parent(mercator_tile) quadkey = [mercantile.quadkey(*mercator_tile)] # get child elif mercator_tile.z < quadkey_zoom: depth = quadkey_zoom - mercator_tile.z mercator_tiles = [mercator_tile] for i in range(depth): mercator_tiles = sum([mercantile.children(t) for t in mercator_tiles], []) mercator_tiles = list(filter(lambda t: t.z == quadkey_zoom, mercator_tiles)) quadkey = [mercantile.quadkey(*tile) for tile in mercator_tiles] else: quadkey = [mercantile.quadkey(*mercator_tile)] assets = list( itertools.chain.from_iterable( [mosaic_def["tiles"].get(qk, []) for qk in quadkey] ) ) # check if we have a mosaic in the url (.json/.gz) return list( itertools.chain.from_iterable( [ get_assets(asset, x, y, z) if os.path.splitext(asset)[1] in [".json", ".gz"] else [asset] for asset in assets ] ) )
def quadkeys_to_poly(quadkeys): quadkeys = sorted(set(quadkeys)) tiles = [mercantile.quadkey_to_tile(qk) for qk in quadkeys] tiles = mercantile.simplify(tiles) quadkeys = [mercantile.quadkey(t) for t in tiles] polys = quadkeys_to_polys(quadkeys) poly = shapely.ops.unary_union(polys) return poly
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
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')
def __init__(self, *tile): if len(tile) == 1: tile = tile[0] else: tile = Tile(*tile) quadkey = mercantile.quadkey(tile) self.url_fmt = f'http://t0.tiles.virtualearth.net/tiles/a{quadkey}.jpeg?g=854&mkt=en-US&token='
def get_tile(self, tile): #======================== surface = skia.Surface(*self.__tile_size) ## In pixels... canvas = surface.getCanvas() canvas.clear(skia.Color4f(0xFFFFFFFF)) canvas.translate(self.__pixel_offset[0] + (self.__tile_origin[0] - tile.x)*self.__tile_size[0], self.__pixel_offset[1] + (self.__tile_origin[1] - tile.y)*self.__tile_size[1]) quadkey = mercantile.quadkey(tile) self.__svg_drawing.draw_element(canvas, self.__tile_bboxes.get(quadkey)) image = surface.makeImageSnapshot() return image.toarray(colorType=skia.kBGRA_8888_ColorType)
def find_quadkeys(mercator_tile: mercantile.Tile, quadkey_zoom: int) -> List[str]: """ Find quadkeys at desired zoom for tile Attributes ---------- mercator_tile: mercantile.Tile Input tile to use when searching for quadkeys quadkey_zoom: int Zoom level Returns ------- list List[str] of quadkeys """ # get parent if mercator_tile.z > quadkey_zoom: depth = mercator_tile.z - quadkey_zoom for i in range(depth): mercator_tile = mercantile.parent(mercator_tile) return [mercantile.quadkey(*mercator_tile)] # get child elif mercator_tile.z < quadkey_zoom: depth = quadkey_zoom - mercator_tile.z mercator_tiles = [mercator_tile] for i in range(depth): mercator_tiles = sum( [mercantile.children(t) for t in mercator_tiles], []) mercator_tiles = list( filter(lambda t: t.z == quadkey_zoom, mercator_tiles)) return [mercantile.quadkey(*tile) for tile in mercator_tiles] else: return [mercantile.quadkey(*mercator_tile)]
def __init__(self, raster_layer, tile_set): self.__svg = etree.parse(raster_layer.source_data).getroot() if 'viewBox' in self.__svg.attrib: self.__size = tuple( float(x) for x in self.__svg.attrib['viewBox'].split()[2:]) else: self.__size = (length_as_pixels(self.__svg.attrib['width']), length_as_pixels(self.__svg.attrib['height'])) self.__scaling = (tile_set.pixel_rect.width / self.__size[0], tile_set.pixel_rect.height / self.__size[1]) self.__definitions = DefinitionStore() defs = self.__svg.find(SVG_NS('defs')) if defs is not None: self.__definitions.add_definitions(defs) self.__style_matcher = StyleMatcher(self.__svg.find(SVG_NS('style'))) self.__first_scan = True # Transform from SVG pixels to tile pixels transform = Transform([[self.__scaling[0], 0.0, 0.0], [0.0, self.__scaling[1], 0.0], [0.0, 0.0, 1.0]]) self.__path_list = [] self.__draw_svg(transform, self.__path_list) # Transform from SVG pixels to world coordinates self.__image_to_world = (Transform([ [WORLD_METRES_PER_PIXEL / self.__scaling[0], 0, 0], [0, WORLD_METRES_PER_PIXEL / self.__scaling[1], 0], [0, 0, 1] ]) @ np.array([[1, 0, -self.__scaling[0] * self.__size[0] / 2.0], [0, -1, self.__scaling[1] * self.__size[1] / 2.0], [0, 0, 1.0]])) self.__tile_size = tile_set.tile_size self.__tile_origin = tile_set.start_coords self.__pixel_offset = tuple(tile_set.pixel_rect)[0:2] path_bounding_boxes = [(path, paint, shapely.geometry.box(*tuple(path.getBounds()))) for (path, paint) in self.__path_list] self.__tile_paths = {} for tile in tile_set: tile_set.tile_coords_to_pixels.transform_point((tile.x, tile.y)) x0 = (tile.x - self.__tile_origin[0] ) * self.__tile_size[0] - self.__pixel_offset[0] y0 = (tile.y - self.__tile_origin[1] ) * self.__tile_size[1] - self.__pixel_offset[1] tile_bbox = shapely.prepared.prep( shapely.geometry.box(x0, y0, x0 + self.__tile_size[0], y0 + self.__tile_size[0])) self.__tile_paths[mercantile.quadkey(tile)] = list( filter(lambda ppb: tile_bbox.intersects(ppb[2]), path_bounding_boxes))
def children(quadkeys, levels=1): if not type(quadkeys) is list: quadkeys = [ quadkeys, ] for level in range(levels): childrenKeys = [] for qk in quadkeys: childrenKeys.extend([ mercantile.quadkey(t) \ for t in mercantile.children(mercantile.quadkey_to_tile(qk)) ]) quadkeys = childrenKeys return quadkeys
def get_tile(self, tile): #======================== surface = skia.Surface(*self.__tile_size) canvas = surface.getCanvas() canvas.translate( self.__pixel_offset[0] + (self.__tile_origin[0] - tile.x) * self.__tile_size[0], self.__pixel_offset[1] + (self.__tile_origin[1] - tile.y) * self.__tile_size[1]) quadkey = mercantile.quadkey(tile) for path, paint, bbox in self.__tile_paths.get(quadkey, []): canvas.drawPath(path, paint) image = surface.makeImageSnapshot() return image.toarray(colorType=skia.kBGRA_8888_ColorType)
def od_post_prediction(self, payload: str, chips: List[dict], prediction_id: str) -> Dict[str, Any]: pred_list = []; for i in range(len(chips)): r = requests.post(self.prediction_endpoint + ":predict", data=json.dumps({ "instances": [ payload["instances"][i] ] })) r.raise_for_status() # We only post a single chip for od detection preds = r.json()["predictions"][0] if preds["num_detections"] == 0.0: continue # Create lists of num_detections length scores = preds['detection_scores'][:int(preds["num_detections"])] bboxes = preds['detection_boxes'][:int(preds["num_detections"])] bboxes_256 = [] for bbox in bboxes: bboxes_256.append([c * 256 for c in bbox]) for j in range(len(bboxes_256)): bbox = geojson.Feature( geometry=self.tf_bbox_geo(bboxes_256[j], chips[i].get('bounds')), properties={} ).geometry score = preds["detection_scores"][j] body = { "geom": bbox, "predictions": { "default": score }, "prediction_id": prediction_id } if chips[i].get('x') is not None and chips[i].get('y') is not None and chips[i].get('z') is not None: body['quadkey'] = mercantile.quadkey(chips[i].get('x'), chips[i].get('y'), chips[i].get('z')) pred_list.append(body) return { "predictionId": prediction_id, "predictions": pred_list }
def od_post_prediction(self, payload: str, tiles: List[Tile], prediction_id: str) -> Dict[str, Any]: pred_list = [] for i in range(len(tiles)): r = requests.post(self.prediction_endpoint + ":predict", data=json.dumps( {"instances": [payload["instances"][i]]})) r.raise_for_status() # We only post a single chip for od detection preds = r.json()["predictions"][0] if preds["num_detections"] == 0.0: continue # Create lists of num_detections length scores = preds['detection_scores'][:int(preds["num_detections"])] bboxes = preds['detection_boxes'][:int(preds["num_detections"])] bboxes_256 = [] for bbox in bboxes: bboxes_256.append([c * 256 for c in bbox]) print("BOUND: " + str(len(bboxes_256)) + " for " + str(tiles[i].x) + "/" + str(tiles[i].y) + "/" + str(tiles[i].z)) for j in range(len(bboxes_256)): bbox = geojson.Feature(geometry=self.tf_bbox_geo( bboxes_256[j], tiles[i]), properties={}).geometry score = preds["detection_scores"][j] pred_list.append({ "quadkey": mercantile.quadkey(tiles[i].x, tiles[i].y, tiles[i].z), "quadkey_geom": bbox, "predictions": { "default": score }, "prediction_id": prediction_id }) return {"predictionId": prediction_id, "predictions": pred_list}
def __init__(self, xtile, ytile, zoom, uri=None): super(Syncher, self).__init__() self.uri = uri or get_uri(xtile, ytile, zoom) self.tile = {'x': xtile, 'y': ytile, 'z': zoom} tile_bounds = mc.bounds(mc.quadkey_to_tile(mc.quadkey(xtile, ytile, zoom))) keys = ('w', 's', 'e', 'n',) self.bbox = dict(zip(keys, map(str, ( tile_bounds.west, tile_bounds.south, tile_bounds.east, tile_bounds.north, )))) # minx, miny, maxx, maxy self.base_query = { 'query': [[{"k": "qwertyuiop", "modv": "not", "regv": "."}]], 'bbox': self.bbox, 'gtypes': ['node', 'way', 'relation'], }
def __init__(self, raster_layer, tile_set): self.__bbox = shapely.geometry.box(*extent_to_bounds(raster_layer.extent)) self.__svg = etree.parse(raster_layer.source_data).getroot() self.__source = raster_layer.source_params.get('source') if 'viewBox' in self.__svg.attrib: self.__size = tuple(float(x) for x in self.__svg.attrib['viewBox'].split()[2:]) else: self.__size = (length_as_pixels(self.__svg.attrib['width']), length_as_pixels(self.__svg.attrib['height'])) self.__scaling = (tile_set.pixel_rect.width/self.__size[0], tile_set.pixel_rect.height/self.__size[1]) self.__definitions = DefinitionStore() self.__style_matcher = StyleMatcher(self.__svg.find(SVG_NS('style'))) self.__clip_paths = ObjectStore() # Transform from SVG pixels to tile pixels svg_to_tile_transform = Transform([[self.__scaling[0], 0.0, 0.0], [ 0.0, self.__scaling[1], 0.0], [ 0.0, 0.0, 1.0]]) self.__svg_drawing = self.__draw_svg(svg_to_tile_transform) # Transform from SVG pixels to world coordinates self.__image_to_world = (Transform([ [WORLD_METRES_PER_PIXEL/self.__scaling[0], 0, 0], [ 0, WORLD_METRES_PER_PIXEL/self.__scaling[1], 0], [ 0, 0, 1]]) @np.array([[1, 0, -self.__scaling[0]*self.__size[0]/2.0], [0, -1, self.__scaling[1]*self.__size[1]/2.0], [0, 0, 1.0]])) self.__tile_size = tile_set.tile_size self.__tile_origin = tile_set.start_coords self.__pixel_offset = tuple(tile_set.pixel_rect)[0:2] self.__tile_bboxes = {} for tile in tile_set: tile_set.tile_coords_to_pixels.transform_point((tile.x, tile.y)) x0 = (tile.x - self.__tile_origin[0])*self.__tile_size[0] - self.__pixel_offset[0] y0 = (tile.y - self.__tile_origin[1])*self.__tile_size[1] - self.__pixel_offset[1] tile_bbox = shapely.geometry.box(x0, y0, x0 + self.__tile_size[0], y0 + self.__tile_size[0]) self.__tile_bboxes[mercantile.quadkey(tile)] = tile_bbox
def save_to_db(self, tiles:List[Tile], results:List[Any], result_wrapper:Optional[Callable]=None) -> None: db = urlparse(self.db) conn = pg8000.connect( user=db.username, password=db.password, host=db.hostname, database=db.path[1:], port=db.port ) cursor = conn.cursor() for i, output in enumerate(results): quadkey = quadkey(tiles[i]) # centroid = db.Column(Geometry('POINT', srid=4326)) predictions = pg8000.PGJsonb(output) cursor.execute("INSERT INTO mlenabler VALUES (null, %s, %s, %s) ON CONFLICT (id) DO UPDATE SET output = %s", (self.prediction_id, quadkey, predictions, predictions)) conn.commit() conn.close()
def soil_hi(): with open('E:/project_use/geodata/soil_liq_hi.txt', 'r', encoding='utf-8') as f: t = json.load(f) '''把所有的物件只挑要的撈出來,另存成item''' item1 = [] for iii, it in enumerate(t['features']): area = it['properties']['area'] grade = it['properties']['分級'] codi = [] for jjj, it1 in enumerate(it['geometry']['coordinates']): for kkk, it2 in enumerate(it1): long = it2[0] lat = it2[1] codi.append((long, lat)) js = {'area': area, 'grade': grade, 'coodinates': codi} item1.append(js) # print(item) '''將經緯度轉換成quadkey值並存進原本的dict''' for mmm, each in enumerate(item1): each_tiles = [] for nnn, each_pt in enumerate(each['coodinates']): zoom_num = 16 aaa = mercantile.tile(each_pt[0], each_pt[1], zoom_num) each_tiles.append(aaa) # print(list(set(each_tiles))) each_tile = list(set(each_tiles)) each_quad = [] for o in range(len(each_tile)): b = mercantile.quadkey(each_tile[o]) each_quad.append(b) each['quad'] = each_quad '''把最終高潛勢的quadkey值append成一個list''' level_hi_quad = [] for ppp in range(len(item1)): each_quads = item1[ppp]['quad'] for rrr in range(len(each_quads)): ccc = each_quads[rrr] level_hi_quad.append(ccc) set(level_hi_quad) return list(set(level_hi_quad))
def missing_quadkeys(mosaic: Dict, shp_path: str, bounds: List[float] = None, simplify: bool = True) -> Dict: """Find quadkeys over land missing from mosaic Args: - mosaic: mosaic definition - shp_path: path to Natural Earth shapefile of land boundaries - bounds: force given bounds - simplify: reduce size of the tileset as much as possible by merging leaves into parents Returns: - GeoJSON FeatureCollection of missing tiles """ bounds = bounds or mosaic['bounds'] top_tile = mercantile.bounding_tile(*bounds) gdf = gpd.read_file(shp_path) quadkey_zoom = mosaic.get('quadkey_zoom', mosaic['minzoom']) # Remove null island # Keep the landmasses that are visible at given zoom gdf = gdf[gdf['max_zoom'] <= quadkey_zoom] land_tiles = find_child_land_tiles(top_tile, gdf, quadkey_zoom) quadkeys = {mercantile.quadkey(tile) for tile in land_tiles} mosaic_quadkeys = set(mosaic['tiles'].keys()) not_in_mosaic = quadkeys.difference(mosaic_quadkeys) not_in_mosaic = [mercantile.quadkey_to_tile(qk) for qk in not_in_mosaic] if simplify: not_in_mosaic = mercantile.simplify(not_in_mosaic) features = [mercantile.feature(tile) for tile in not_in_mosaic] return {'type': 'FeatureCollection', 'features': features}
def lnglat_to_Num(lon, lat, zoom): try: lat_deg = float(lat) lon_deg = float(lon) lat_rad = math.radians(lat_deg) n = 2.0**zoom xtile = int((lon_deg + 180.0) / 360.0 * n) ytile = int( (1.0 - math.log(math.tan(lat_rad) + (1 / math.cos(lat_rad))) / math.pi) / 2.0 * n) qk = mercantile.quadkey(xtile, ytile, zoom) number = 0 for i, digit in enumerate(qk): number |= int(digit) if i != len(qk) - 1: number = number << 2 return number except ValueError, e: print "error", e return None
def _create_mosaic( cls, features: Sequence[Dict], minzoom: int, maxzoom: int, quadkey_zoom: Optional[int] = None, accessor: Callable[[Dict], str] = default_accessor, asset_filter: Callable = default_filter, version: str = "0.0.2", quiet: bool = True, **kwargs, ): """Create mosaic definition content. Attributes: features (list): List of GeoJSON features. minzoom (int): Force mosaic min-zoom. maxzoom (int): Force mosaic max-zoom. quadkey_zoom (int): Force mosaic quadkey zoom (optional). accessor (callable): Function called on each feature to get its identifier (default is feature["properties"]["path"]). asset_filter (callable): Function to filter features. version (str): mosaicJSON definition version (default: 0.0.2). quiet (bool): Mask processing steps (default is True). kwargs (any): Options forwarded to `asset_filter` Returns: mosaic_definition (MosaicJSON): Mosaic definition. Examples: >>> MosaicJSON._create_mosaic([], 12, 14) """ quadkey_zoom = quadkey_zoom or minzoom if not quiet: click.echo(f"Get quadkey list for zoom: {quadkey_zoom}", err=True) # If Pygeos throws an error, fall back to non-vectorized operation # Ref: https://github.com/developmentseed/cogeo-mosaic/issues/81 try: dataset_geoms = polygons( [feat["geometry"]["coordinates"][0] for feat in features] ) except TypeError: dataset_geoms = [ polygons(feat["geometry"]["coordinates"][0]) for feat in features ] bounds = tuple(total_bounds(dataset_geoms)) tiles = burntiles.burn(features, quadkey_zoom) tiles = [mercantile.Tile(*tile) for tile in tiles] mosaic_definition: Dict[str, Any] = dict( mosaicjson=version, minzoom=minzoom, maxzoom=maxzoom, quadkey_zoom=quadkey_zoom, bounds=bounds, center=((bounds[0] + bounds[2]) / 2, (bounds[1] + bounds[3]) / 2, minzoom), tiles={}, version="1.0.0", ) if not quiet: click.echo("Feed Quadkey index", err=True) # Create tree and find assets that overlap each tile tree = STRtree(dataset_geoms) fout = os.devnull if quiet else sys.stderr with click.progressbar( # type: ignore tiles, file=fout, show_percent=True, label="Iterate over quadkeys" ) as bar: for tile in bar: quadkey = mercantile.quadkey(tile) tile_geom = polygons( mercantile.feature(tile)["geometry"]["coordinates"][0] ) # Find intersections from rtree intersections_idx = sorted( tree.query(tile_geom, predicate="intersects") ) if len(intersections_idx) == 0: continue intersect_dataset, intersect_geoms = zip( *[(features[idx], dataset_geoms[idx]) for idx in intersections_idx] ) dataset = asset_filter( tile, intersect_dataset, intersect_geoms, **kwargs ) if dataset: mosaic_definition["tiles"][quadkey] = [accessor(f) for f in dataset] return cls(**mosaic_definition)
def stac_to_mosaicJSON( query: Dict, minzoom: int = 7, maxzoom: int = 12, optimized_selection: bool = True, maximum_items_per_tile: int = 20, stac_collection_limit: int = 500, seasons: Tuple = ["spring", "summer", "autumn", "winter"], stac_url: str = os.environ.get("SATAPI_URL", "https://sat-api.developmentseed.org"), ) -> Dict: """ Create a mosaicJSON from a stac request. Attributes ---------- query : str sat-api query. minzoom : int, optional, (default: 7) Mosaic Min Zoom. maxzoom : int, optional (default: 12) Mosaic Max Zoom. optimized_selection : bool, optional (default: true) Limit one Path-Row scene per quadkey. maximum_items_per_tile : int, optional (default: 20) Limit number of scene per quadkey. Use 0 to use all items. stac_collection_limit : int, optional (default: None) Limits the number of items returned by sat-api stac_url : str, optional (default: from ENV) Returns ------- out : dict MosaicJSON definition. """ if stac_collection_limit: query.update(limit=stac_collection_limit) logger.debug(json.dumps(query)) def fetch_sat_api(query): headers = { "Content-Type": "application/json", "Accept-Encoding": "gzip", "Accept": "application/geo+json", } url = f"{stac_url}/stac/search" data = requests.post(url, headers=headers, json=query).json() error = data.get("message", "") if error: raise Exception(f"SAT-API failed and returned: {error}") meta = data.get("meta", {}) if not meta.get("found"): return [] logger.debug(json.dumps(meta)) features = data["features"] if data["links"]: curr_page = int(meta["page"]) query["page"] = curr_page + 1 query["limit"] = meta["limit"] features = list(itertools.chain(features, fetch_sat_api(query))) return features features = fetch_sat_api(query) if not features: raise Exception(f"No asset found for query '{json.dumps(query)}'") logger.debug(f"Found: {len(features)} scenes") features = list( filter( lambda x: _get_season(x["properties"]["datetime"], max(x["bbox"][1], x["bbox"][3])) in seasons, features, )) if optimized_selection: dataset = [] prs = [] for item in features: pr = item["properties"]["eo:column"] + "-" + item["properties"][ "eo:row"] if pr not in prs: prs.append(pr) dataset.append(item) else: dataset = features if query.get("bbox"): bounds = query["bbox"] else: bounds = burntiles.find_extrema(dataset) for i in range(len(dataset)): dataset[i]["geometry"] = shape(dataset[i]["geometry"]) tiles = burntiles.burn([bbox_to_geojson(bounds)], minzoom) tiles = list(set(["{2}-{0}-{1}".format(*tile.tolist()) for tile in tiles])) logger.debug(f"Number tiles: {len(tiles)}") mosaic_definition = dict( mosaicjson="0.0.1", minzoom=minzoom, maxzoom=maxzoom, bounds=bounds, center=[(bounds[0] + bounds[2]) / 2, (bounds[1] + bounds[3]) / 2, minzoom], tiles={}, ) for tile in tiles: z, x, y = list(map(int, tile.split("-"))) tile = mercantile.Tile(x=x, y=y, z=z) quadkey = mercantile.quadkey(*tile) geometry = box(*mercantile.bounds(tile)) intersect_dataset = list( filter(lambda x: geometry.intersects(x["geometry"]), dataset)) if len(intersect_dataset): # We limit the item per quadkey to 20 if maximum_items_per_tile: intersect_dataset = intersect_dataset[0:maximum_items_per_tile] mosaic_definition["tiles"][quadkey] = [ scene["properties"]["landsat:product_id"] for scene in intersect_dataset ] return mosaic_definition
def point_to_polygon(point, zoom): tile = mercantile.tile(*np.array(point), zoom) quadkey = mercantile.quadkey(tile) poly = quadkey_to_poly(quadkey) return poly
def get_quadkeys(totalBounds, zoom): allTiles = mercantile.tiles(*totalBounds, zoom) for tile in allTiles: yield mercantile.quadkey(tile)
def test_quadkey(): tile = mercantile.Tile(486, 332, 10) expected = "0313102310" assert mercantile.quadkey(tile) == expected
def do_GET(self): url = urlparse(self.path) if url.path == '/tile': query_components = parse_qs(urlparse(self.path).query) dataset = query_components["dataset"][0] level = query_components["level"][0] x = query_components["x"][0] y = query_components["y"][0] time_from = transToStamp(query_components["time_from"][0]) time_to = transToStamp(query_components["time_to"][0]) # start = time.time() tile_quadkey = mercantile.quadkey(int(x), int(y), int(level)) tile_id = quadkey_to_num(tile_quadkey) print tile_id, str(time_from), str(time_to) jpype.attachThreadToJVM() hbase_response = cp.spatialSum("nycTaxi", tile_id, str(time_from), str(time_to)) print hbase_response # end = time.time() # print "query_time" + ": " + str(end - start) # # # q_time1.append(end - start) self.send_response(200) self.send_header('Content-type', 'application/json') self.send_header('Access-Control-Allow-Origin', '*') self.end_headers() self.wfile.write(hbase_response) # if len(q_time1) == 20: # print "hundred" # plt.plot(range(len(q_time1)), q_time1) # plt.ylabel('tile query time') # plt.axis([1, 20, 0, 2]) # print float(sum(q_time1)) / len(q_time1) # plt.show() return if url.path == '/time_series': query_components = parse_qs(urlparse(self.path).query) dataset = query_components["dataset"][0] level = query_components["level"][0] bounds = query_components["bounds"][0] bounds = bounds.split(",") time_from = transToStamp(query_components["time_from"][0]) time_to = transToStamp(query_components["time_to"][0]) start = time.time() new_bounds = check_bounds(bounds) tiles = mercantile.tiles(new_bounds[0],new_bounds[1],new_bounds[2], \ new_bounds[3], [int(level), ]) tile_numbers = [] for tile in list(tiles): t_quadkey = mercantile.quadkey(tile) t_num = quadkey_to_num(t_quadkey) tile_numbers.append(t_num) tile_numbers = ' '.join(str(x) for x in tile_numbers) jpype.attachThreadToJVM() res = cp.timeSeriesCount(dataset, tile_numbers, str(time_from), str(time_to)) end = time.time() print "query_time" + ": " + str(end - start) # q_time2.append(end - start) self.send_response(200) self.send_header('Content-type', 'application/json') self.send_header('Access-Control-Allow-Origin', '*') self.end_headers() self.wfile.write(res) # if len(q_time2) == 20: # print "hundred" # plt.plot(range(len(q_time2)), q_time2) # plt.ylabel('timeseries query time') # plt.axis([1, 20, 0, 1]) # print float(sum(q_time2)) / len(q_time2) # plt.show() return
def _create_mosaic( cls, features: Sequence[Dict], minzoom: int, maxzoom: int, quadkey_zoom: Optional[int] = None, accessor: Callable[[Dict], str] = default_accessor, asset_filter: Callable = default_filter, version: str = "0.0.2", quiet: bool = True, **kwargs, ): """ Create mosaic definition content. Attributes ---------- features : List, required List of GeoJSON features. minzoom: int, required Force mosaic min-zoom. maxzoom: int, required Force mosaic max-zoom. quadkey_zoom: int, optional Force mosaic quadkey zoom. accessor: callable, required Function called on each feature to get its identifier (default is feature["properties"]["path"]). asset_filter: callable, required Function to filter features. version: str, optional mosaicJSON definition version (default: 0.0.2). quiet: bool, optional (default: True) Mask processing steps. kwargs: any Options forwarded to `asset_filter` Returns ------- mosaic_definition : MosaicJSON Mosaic definition. """ quadkey_zoom = quadkey_zoom or minzoom if not quiet: click.echo(f"Get quadkey list for zoom: {quadkey_zoom}", err=True) # Find dataset geometries dataset_geoms = polygons( [feat["geometry"]["coordinates"][0] for feat in features]) bounds = list(total_bounds(dataset_geoms)) tiles = burntiles.burn(features, quadkey_zoom) tiles = [mercantile.Tile(*tile) for tile in tiles] mosaic_definition: Dict[str, Any] = dict( mosaicjson=version, minzoom=minzoom, maxzoom=maxzoom, quadkey_zoom=quadkey_zoom, bounds=bounds, center=((bounds[0] + bounds[2]) / 2, (bounds[1] + bounds[3]) / 2, minzoom), tiles={}, version="1.0.0", ) if not quiet: click.echo(f"Feed Quadkey index", err=True) # Create tree and find assets that overlap each tile tree = STRtree(dataset_geoms) for tile in tiles: quadkey = mercantile.quadkey(tile) tile_geom = polygons( mercantile.feature(tile)["geometry"]["coordinates"][0]) # Find intersections from rtree intersections_idx = sorted( tree.query(tile_geom, predicate="intersects")) if len(intersections_idx) == 0: continue intersect_dataset, intersect_geoms = zip( *[(features[idx], dataset_geoms[idx]) for idx in intersections_idx]) dataset = asset_filter(tile, intersect_dataset, intersect_geoms, **kwargs) if dataset: mosaic_definition["tiles"][quadkey] = [ accessor(f) for f in dataset ] return cls(**mosaic_definition)