From c5b8194a6e3616f05edfe8e0639d8dafd58c4146 Mon Sep 17 00:00:00 2001 From: Kanahiro Date: Sun, 22 Oct 2023 12:02:22 +0900 Subject: [PATCH 1/3] enhance: support tms #8 --- tileget/__main__.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/tileget/__main__.py b/tileget/__main__.py index e40fdb8..902e8e0 100644 --- a/tileget/__main__.py +++ b/tileget/__main__.py @@ -39,6 +39,7 @@ def get_args(): help="wait response until this value, set as seconds in integer, default to 5", ) parser.add_argument("--parallel", default="1", help="num of parallel requests") + parser.add_argument("--tms", help="if set, parse z/x/y as TMS", action="store_true") args = parser.parse_args() verified_args = { @@ -52,6 +53,7 @@ def get_args(): "overwrite": args.overwrite, "timeout": int(args.timeout), "parallel": int(args.parallel), + "tms": args.tms, } if args.extent is None and args.geojson is None: @@ -128,7 +130,8 @@ def download(tile): write_dir = os.path.join(args["output_dir"], str(tile[2]), str(tile[0])) write_filepath = os.path.join(write_dir, str(tile[1]) + "." + ext) - if os.path.exists(write_filepath) and args["overwrite"] == False: + if not (os.path.exists(write_filepath) and args["overwrite"]): + # skip if already exists when not-overwrite mode return url = ( @@ -160,11 +163,15 @@ def download(tile): f.write(data.read()) time.sleep(args["interval"] / 1000) + tilescheme = ( + tiletanic.tileschemes.WebMercatorBL() + if args["tms"] + else tiletanic.tileschemes.WebMercator() + ) + with ThreadPoolExecutor(max_workers=args["parallel"]) as executor: for zoom in range(args["minzoom"], args["maxzoom"] + 1): - generator = tiletanic.tilecover.cover_geometry( - tiletanic.tileschemes.WebMercator(), geometry, zoom - ) + generator = tiletanic.tilecover.cover_geometry(tilescheme, geometry, zoom) for tile in generator: future = executor.submit(download, tile) if future.exception() is not None: From 1e01c3f959b0f31b371fa49b28831734081faacf Mon Sep 17 00:00:00 2001 From: Kanahiro Date: Sun, 22 Oct 2023 12:23:34 +0900 Subject: [PATCH 2/3] enhance: accept only EPSG:3857 GeoJSON --- tileget/__main__.py | 67 +++++++++++++++------------------------------ 1 file changed, 22 insertions(+), 45 deletions(-) diff --git a/tileget/__main__.py b/tileget/__main__.py index 902e8e0..3b3b796 100644 --- a/tileget/__main__.py +++ b/tileget/__main__.py @@ -1,6 +1,5 @@ import os import argparse -import math import time import urllib.request import json @@ -8,6 +7,7 @@ import tiletanic import shapely +from pyproj import Transformer def get_args(): @@ -21,7 +21,7 @@ def get_args(): ) parser.add_argument( "--geojson", - help="path to geojson which is Feature or FeatureCollection with geometry in EPSG:3857", + help="path to geojson file of Feature or FeatureCollection", ) parser.add_argument("--minzoom", default="0", help="default to 0") parser.add_argument("--maxzoom", default="16", help="default to 16") @@ -68,51 +68,24 @@ def get_args(): return verified_args -def lonlat_to_webmercator(lonlat: list): - return ( - lonlat[0] * 20037508.34 / 180, - math.log(math.tan((90 + lonlat[1]) * math.pi / 360)) - / (math.pi / 180) - * 20037508.34 - / 180, - ) - - -def get_geometry_as_3857(extent: list) -> dict: - """ - returns GeoJSON Polygon geometry dict - extent must be latitudes and longitudes and reprojected to WebMercator EPSG:3857 - - Args: - extent (list): [min_lon, min_lat, max_lon, max_lat] - - Returns: - dict: Polygon geometry - """ - return { - "type": "Polygon", - "coordinates": ( - tuple( - map( - lonlat_to_webmercator, - ( - (extent[0], extent[1]), - (extent[2], extent[1]), - (extent[2], extent[3]), - (extent[0], extent[3]), - (extent[0], extent[1]), - ), - ) - ), - ), - } - - def main(): args = get_args() if args["extent"] is not None: - geometry = shapely.geometry.shape(get_geometry_as_3857(args["extent"])) + geometry = shapely.geometry.shape( + { + "type": "Polygon", + "coordinates": [ + [ + (args["extent"][0], args["extent"][1]), + (args["extent"][2], args["extent"][1]), + (args["extent"][2], args["extent"][3]), + (args["extent"][0], args["extent"][3]), + (args["extent"][0], args["extent"][1]), + ], + ], + } + ) elif args["geojson"] is not None: with open(args["geojson"], mode="r") as f: geojson = json.load(f) @@ -125,12 +98,16 @@ def main(): ] geometry = shapely.ops.unary_union(geometries) + # tiletanic accept only EPSG:3857 shape, convert + transformer = Transformer.from_crs(4326, 3857, always_xy=True) + geom_3857 = shapely.ops.transform(transformer.transform, geometry) + def download(tile): ext = args["tileurl"].split(".")[-1] write_dir = os.path.join(args["output_dir"], str(tile[2]), str(tile[0])) write_filepath = os.path.join(write_dir, str(tile[1]) + "." + ext) - if not (os.path.exists(write_filepath) and args["overwrite"]): + if os.path.exists(write_filepath) and not args["overwrite"]: # skip if already exists when not-overwrite mode return @@ -171,7 +148,7 @@ def download(tile): with ThreadPoolExecutor(max_workers=args["parallel"]) as executor: for zoom in range(args["minzoom"], args["maxzoom"] + 1): - generator = tiletanic.tilecover.cover_geometry(tilescheme, geometry, zoom) + generator = tiletanic.tilecover.cover_geometry(tilescheme, geom_3857, zoom) for tile in generator: future = executor.submit(download, tile) if future.exception() is not None: From bbf60861bdf9c2b8009c0cd82f457bb39fc79c02 Mon Sep 17 00:00:00 2001 From: Kanahiro Date: Sun, 22 Oct 2023 12:27:13 +0900 Subject: [PATCH 3/3] v0.2.0, add dependency --- requirements.txt | 3 ++- setup.py | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index 147cfd1..bced1a0 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,3 @@ Shapely==1.8.5.post1 -tiletanic==1.1.0 \ No newline at end of file +tiletanic==1.1.0 +pyproj==3.4.1 \ No newline at end of file diff --git a/setup.py b/setup.py index a31e21a..72dec41 100644 --- a/setup.py +++ b/setup.py @@ -7,7 +7,7 @@ def _requires_from_file(filename): setup( name="tileget", - version="0.1.1", + version="0.2.0", description="Tile download utility - easily download xyz-tile data", author="Kanahiro Iguchi", license="MIT",