Skip to content

Commit 9e1e9ef

Browse files
Merge pull request #23 from developmentseed/feature/add-tms-options
add tms options
2 parents 2a9b8a4 + ce9f545 commit 9e1e9ef

File tree

5 files changed

+102
-26
lines changed

5 files changed

+102
-26
lines changed

CHANGES.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11

2+
## 0.12.0 (2024-01-24)
3+
4+
* allow `tms` options in CLI (`profile`, `random` and `get-zooms`) to select TileMatrixSet
5+
26
## 0.11.0 (2023-10-18)
37

48
* update requirements

README.md

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,17 +40,18 @@ Note: In GDAL 3.2, logging capabilities for /vsicurl, /vsis3 and the like was ad
4040
You can install `tilebench` using pip
4141

4242
```bash
43-
$ pip install -U pip
44-
$ pip install -U tilebench
43+
$ python -m pip install -U pip
44+
$ python -m pip install -U tilebench
4545
```
4646

4747
or install from source:
4848

4949
```bash
50-
$ git clone https://github.com/developmentseed/tilebench.git
51-
$ cd tilebench
52-
$ pip install -U pip
53-
$ pip install -e .
50+
git clone https://github.com/developmentseed/tilebench.git
51+
cd tilebench
52+
53+
python -m pip install -U pip
54+
python -m pip install -e .
5455
```
5556

5657
## API

tests/fixtures/WGS1984Quad.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"title":"EPSG:4326 for the World","id":"WorldCRS84Quad","uri":"http://www.opengis.net/def/tilematrixset/OGC/1.0/WorldCRS84Quad","orderedAxes":["Lat","Lon"],"crs":"http://www.opengis.net/def/crs/EPSG/0/4326","wellKnownScaleSet":"http://www.opengis.net/def/wkss/OGC/1.0/GoogleCRS84Quad","tileMatrices":[{"id":"0","scaleDenominator":279541132.014358,"cellSize":0.703125,"cornerOfOrigin":"topLeft","pointOfOrigin":[90.0,-180.0],"tileWidth":256,"tileHeight":256,"matrixWidth":2,"matrixHeight":1},{"id":"1","scaleDenominator":139770566.007179,"cellSize":0.3515625,"cornerOfOrigin":"topLeft","pointOfOrigin":[90.0,-180.0],"tileWidth":256,"tileHeight":256,"matrixWidth":4,"matrixHeight":2},{"id":"2","scaleDenominator":69885283.0035897,"cellSize":0.17578125,"cornerOfOrigin":"topLeft","pointOfOrigin":[90.0,-180.0],"tileWidth":256,"tileHeight":256,"matrixWidth":8,"matrixHeight":4},{"id":"3","scaleDenominator":34942641.5017948,"cellSize":0.087890625,"cornerOfOrigin":"topLeft","pointOfOrigin":[90.0,-180.0],"tileWidth":256,"tileHeight":256,"matrixWidth":16,"matrixHeight":8},{"id":"4","scaleDenominator":17471320.7508974,"cellSize":0.0439453125,"cornerOfOrigin":"topLeft","pointOfOrigin":[90.0,-180.0],"tileWidth":256,"tileHeight":256,"matrixWidth":32,"matrixHeight":16},{"id":"5","scaleDenominator":8735660.37544871,"cellSize":0.02197265625,"cornerOfOrigin":"topLeft","pointOfOrigin":[90.0,-180.0],"tileWidth":256,"tileHeight":256,"matrixWidth":64,"matrixHeight":32},{"id":"6","scaleDenominator":4367830.18772435,"cellSize":0.010986328125,"cornerOfOrigin":"topLeft","pointOfOrigin":[90.0,-180.0],"tileWidth":256,"tileHeight":256,"matrixWidth":128,"matrixHeight":64},{"id":"7","scaleDenominator":2183915.09386217,"cellSize":0.0054931640625,"cornerOfOrigin":"topLeft","pointOfOrigin":[90.0,-180.0],"tileWidth":256,"tileHeight":256,"matrixWidth":256,"matrixHeight":128},{"id":"8","scaleDenominator":1091957.54693108,"cellSize":0.00274658203125,"cornerOfOrigin":"topLeft","pointOfOrigin":[90.0,-180.0],"tileWidth":256,"tileHeight":256,"matrixWidth":512,"matrixHeight":256},{"id":"9","scaleDenominator":545978.773465544,"cellSize":0.001373291015625,"cornerOfOrigin":"topLeft","pointOfOrigin":[90.0,-180.0],"tileWidth":256,"tileHeight":256,"matrixWidth":1024,"matrixHeight":512},{"id":"10","scaleDenominator":272989.386732772,"cellSize":0.0006866455078125,"cornerOfOrigin":"topLeft","pointOfOrigin":[90.0,-180.0],"tileWidth":256,"tileHeight":256,"matrixWidth":2048,"matrixHeight":1024},{"id":"11","scaleDenominator":136494.693366386,"cellSize":0.00034332275390625,"cornerOfOrigin":"topLeft","pointOfOrigin":[90.0,-180.0],"tileWidth":256,"tileHeight":256,"matrixWidth":4096,"matrixHeight":2048},{"id":"12","scaleDenominator":68247.346683193,"cellSize":0.000171661376953125,"cornerOfOrigin":"topLeft","pointOfOrigin":[90.0,-180.0],"tileWidth":256,"tileHeight":256,"matrixWidth":8192,"matrixHeight":4096},{"id":"13","scaleDenominator":34123.6733415964,"cellSize":0.0000858306884765625,"cornerOfOrigin":"topLeft","pointOfOrigin":[90.0,-180.0],"tileWidth":256,"tileHeight":256,"matrixWidth":16384,"matrixHeight":8192},{"id":"14","scaleDenominator":17061.8366707982,"cellSize":0.0000429153442382812,"cornerOfOrigin":"topLeft","pointOfOrigin":[90.0,-180.0],"tileWidth":256,"tileHeight":256,"matrixWidth":32768,"matrixHeight":16384},{"id":"15","scaleDenominator":8530.91833539913,"cellSize":0.0000214576721191406,"cornerOfOrigin":"topLeft","pointOfOrigin":[90.0,-180.0],"tileWidth":256,"tileHeight":256,"matrixWidth":65536,"matrixHeight":32768},{"id":"16","scaleDenominator":4265.45916769956,"cellSize":0.0000107288360595703,"cornerOfOrigin":"topLeft","pointOfOrigin":[90.0,-180.0],"tileWidth":256,"tileHeight":256,"matrixWidth":131072,"matrixHeight":65536},{"id":"17","scaleDenominator":2132.72958384978,"cellSize":5.36441802978515e-6,"cornerOfOrigin":"topLeft","pointOfOrigin":[90.0,-180.0],"tileWidth":256,"tileHeight":256,"matrixWidth":262144,"matrixHeight":131072},{"id":"18","scaleDenominator":1066.36479192489,"cellSize":2.68220901489258e-6,"cornerOfOrigin":"topLeft","pointOfOrigin":[90.0,-180.0],"tileWidth":256,"tileHeight":256,"matrixWidth":524288,"matrixHeight":262144},{"id":"19","scaleDenominator":533.182395962445,"cellSize":1.34110450744629e-6,"cornerOfOrigin":"topLeft","pointOfOrigin":[90.0,-180.0],"tileWidth":256,"tileHeight":256,"matrixWidth":1048576,"matrixHeight":524288},{"id":"20","scaleDenominator":266.591197981222,"cellSize":6.7055225372314e-7,"cornerOfOrigin":"topLeft","pointOfOrigin":[90.0,-180.0],"tileWidth":256,"tileHeight":256,"matrixWidth":2097152,"matrixHeight":1048576},{"id":"21","scaleDenominator":133.295598990611,"cellSize":3.3527612686157e-7,"cornerOfOrigin":"topLeft","pointOfOrigin":[90.0,-180.0],"tileWidth":256,"tileHeight":256,"matrixWidth":4194304,"matrixHeight":2097152},{"id":"22","scaleDenominator":66.6477994953056,"cellSize":1.6763806343079e-7,"cornerOfOrigin":"topLeft","pointOfOrigin":[90.0,-180.0],"tileWidth":256,"tileHeight":256,"matrixWidth":8388608,"matrixHeight":4194304},{"id":"23","scaleDenominator":33.3238997476528,"cellSize":8.381903171539e-8,"cornerOfOrigin":"topLeft","pointOfOrigin":[90.0,-180.0],"tileWidth":256,"tileHeight":256,"matrixWidth":16777216,"matrixHeight":8388608}]}

tests/test_cli.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"""Test CLI."""
22

33
import json
4+
import os
45
from unittest.mock import patch
56

67
from click.testing import CliRunner
@@ -9,6 +10,8 @@
910

1011
COG_PATH = "https://noaa-eri-pds.s3.amazonaws.com/2022_Hurricane_Ian/20221002a_RGB/20221002aC0795145w325100n.tif"
1112

13+
TMS = os.path.join(os.path.dirname(__file__), "fixtures", "WGS1984Quad.json")
14+
1215

1316
def test_profile():
1417
"""Should work as expected."""
@@ -73,6 +76,8 @@ def test_get_zoom():
7376
assert result.exit_code == 0
7477
log = json.loads(result.output)
7578
assert ["minzoom", "maxzoom"] == list(log)
79+
assert log["minzoom"] == 14
80+
assert log["maxzoom"] == 19
7681

7782
result = runner.invoke(
7883
cli, ["get-zooms", COG_PATH, "--reader", "rio_tiler.io.Reader"]
@@ -118,3 +123,29 @@ def test_viz(launch):
118123
assert not result.exception
119124
assert result.exit_code == 0
120125
assert "14-" in result.output
126+
127+
128+
def test_tms():
129+
"""Should work as expected."""
130+
runner = CliRunner()
131+
132+
result = runner.invoke(cli, ["profile", COG_PATH, "--tms", TMS])
133+
assert not result.exception
134+
assert result.exit_code == 0
135+
log = json.loads(result.output)
136+
assert ["HEAD", "GET", "Timing"] == list(log)
137+
# Make sure we didn't cache any request when `--tile` is not provided
138+
assert "0-" in log["GET"]["ranges"][0]
139+
140+
result = runner.invoke(cli, ["get-zooms", COG_PATH, "--tms", TMS])
141+
assert not result.exception
142+
assert result.exit_code == 0
143+
log = json.loads(result.output)
144+
assert ["minzoom", "maxzoom"] == list(log)
145+
assert log["minzoom"] == 13
146+
assert log["maxzoom"] == 18
147+
148+
result = runner.invoke(cli, ["random", COG_PATH, "--tms", TMS])
149+
assert not result.exception
150+
assert result.exit_code == 0
151+
assert "-" in result.output

tilebench/scripts/cli.py

Lines changed: 59 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
from tilebench import profile as profiler
1717
from tilebench.viz import TileDebug
1818

19-
tms = morecantile.tms.get("WebMercatorQuad")
19+
default_tms = morecantile.tms.get("WebMercatorQuad")
2020

2121

2222
# The CLI command group.
@@ -53,6 +53,11 @@ def cli():
5353
type=str,
5454
help="rio-tiler Reader (BaseReader). Default is `rio_tiler.io.COGReader`",
5555
)
56+
@click.option(
57+
"--tms",
58+
help="Path to TileMatrixSet JSON file.",
59+
type=click.Path(),
60+
)
5661
@click.option(
5762
"--config",
5863
"config",
@@ -62,9 +67,23 @@ def cli():
6267
help="GDAL configuration options.",
6368
)
6469
def profile(
65-
input, tile, tilesize, zoom, add_kernels, add_stdout, add_cprofile, reader, config
70+
input,
71+
tile,
72+
tilesize,
73+
zoom,
74+
add_kernels,
75+
add_stdout,
76+
add_cprofile,
77+
reader,
78+
tms,
79+
config,
6680
):
6781
"""Profile COGReader Mercator Tile read."""
82+
tilematrixset = default_tms
83+
if tms:
84+
with open(tms, "r") as f:
85+
tilematrixset = morecantile.TileMatrixSet(**json.load(f))
86+
6887
if reader:
6988
module, classname = reader.rsplit(".", 1)
7089
reader = getattr(importlib.import_module(module), classname) # noqa
@@ -75,19 +94,19 @@ def profile(
7594

7695
if not tile:
7796
with rasterio.Env(CPL_VSIL_CURL_NON_CACHED=parse_path(input).as_vsi()):
78-
with Reader(input, tms=tms) as cog:
97+
with Reader(input, tms=tilematrixset) as cog:
7998
if zoom is None:
8099
zoom = randint(cog.minzoom, cog.maxzoom)
81100

82101
w, s, e, n = cog.geographic_bounds
83102
# Truncate BBox to the TMS bounds
84-
w = max(tms.bbox.left, w)
85-
s = max(tms.bbox.bottom, s)
86-
e = min(tms.bbox.right, e)
87-
n = min(tms.bbox.top, n)
103+
w = max(tilematrixset.bbox.left, w)
104+
s = max(tilematrixset.bbox.bottom, s)
105+
e = min(tilematrixset.bbox.right, e)
106+
n = min(tilematrixset.bbox.top, n)
88107

89-
ul_tile = tms.tile(w, n, zoom)
90-
lr_tile = tms.tile(e, s, zoom)
108+
ul_tile = tilematrixset.tile(w, n, zoom)
109+
lr_tile = tilematrixset.tile(e, s, zoom)
91110
extrema = {
92111
"x": {"min": ul_tile.x, "max": lr_tile.x + 1},
93112
"y": {"min": ul_tile.y, "max": lr_tile.y + 1},
@@ -109,7 +128,7 @@ def profile(
109128
config=config,
110129
)
111130
def _read_tile(src_path: str, x: int, y: int, z: int, tilesize: int = 256):
112-
with Reader(src_path) as cog:
131+
with Reader(src_path, tms=tilematrixset) as cog:
113132
return cog.tile(x, y, z, tilesize=tilesize)
114133

115134
(_, _), stats = _read_tile(input, tile_x, tile_y, tile_z, tilesize)
@@ -124,8 +143,18 @@ def _read_tile(src_path: str, x: int, y: int, z: int, tilesize: int = 256):
124143
type=str,
125144
help="rio-tiler Reader (BaseReader). Default is `rio_tiler.io.COGReader`",
126145
)
127-
def get_zooms(input, reader):
146+
@click.option(
147+
"--tms",
148+
help="Path to TileMatrixSet JSON file.",
149+
type=click.Path(),
150+
)
151+
def get_zooms(input, reader, tms):
128152
"""Get Mercator Zoom levels."""
153+
tilematrixset = default_tms
154+
if tms:
155+
with open(tms, "r") as f:
156+
tilematrixset = morecantile.TileMatrixSet(**json.load(f))
157+
129158
if reader:
130159
module, classname = reader.rsplit(".", 1)
131160
reader = getattr(importlib.import_module(module), classname) # noqa
@@ -134,7 +163,7 @@ def get_zooms(input, reader):
134163

135164
Reader = reader or COGReader
136165

137-
with Reader(input, tms=tms) as cog:
166+
with Reader(input, tms=tilematrixset) as cog:
138167
click.echo(json.dumps({"minzoom": cog.minzoom, "maxzoom": cog.maxzoom}))
139168

140169

@@ -146,8 +175,18 @@ def get_zooms(input, reader):
146175
type=str,
147176
help="rio-tiler Reader (BaseReader). Default is `rio_tiler.io.COGReader`",
148177
)
149-
def random(input, zoom, reader):
178+
@click.option(
179+
"--tms",
180+
help="Path to TileMatrixSet JSON file.",
181+
type=click.Path(),
182+
)
183+
def random(input, zoom, reader, tms):
150184
"""Get random tile."""
185+
tilematrixset = default_tms
186+
if tms:
187+
with open(tms, "r") as f:
188+
tilematrixset = morecantile.TileMatrixSet(**json.load(f))
189+
151190
if reader:
152191
module, classname = reader.rsplit(".", 1)
153192
reader = getattr(importlib.import_module(module), classname) # noqa
@@ -156,19 +195,19 @@ def random(input, zoom, reader):
156195

157196
Reader = reader or COGReader
158197

159-
with Reader(input, tms=tms) as cog:
198+
with Reader(input, tms=tilematrixset) as cog:
160199
if zoom is None:
161200
zoom = randint(cog.minzoom, cog.maxzoom)
162201
w, s, e, n = cog.geographic_bounds
163202

164203
# Truncate BBox to the TMS bounds
165-
w = max(tms.bbox.left, w)
166-
s = max(tms.bbox.bottom, s)
167-
e = min(tms.bbox.right, e)
168-
n = min(tms.bbox.top, n)
204+
w = max(tilematrixset.bbox.left, w)
205+
s = max(tilematrixset.bbox.bottom, s)
206+
e = min(tilematrixset.bbox.right, e)
207+
n = min(tilematrixset.bbox.top, n)
169208

170-
ul_tile = tms.tile(w, n, zoom)
171-
lr_tile = tms.tile(e, s, zoom)
209+
ul_tile = tilematrixset.tile(w, n, zoom)
210+
lr_tile = tilematrixset.tile(e, s, zoom)
172211
extrema = {
173212
"x": {"min": ul_tile.x, "max": lr_tile.x + 1},
174213
"y": {"min": ul_tile.y, "max": lr_tile.y + 1},

0 commit comments

Comments
 (0)