diff --git a/python/pmtiles/tile.py b/python/pmtiles/tile.py index b8f6b00..692ef57 100644 --- a/python/pmtiles/tile.py +++ b/python/pmtiles/tile.py @@ -41,6 +41,10 @@ def t_on_level(z, pos): def zxy_to_tileid(z, x, y): + if z > 31: + raise OverflowError("tile zoom exceeds 64-bit limit") + if x > (1 << z) - 1 or y > (1 << z) - 1: + raise ValueError("tile x/y outside zoom level bounds") acc = 0 tz = 0 while tz < z: @@ -70,13 +74,12 @@ def zxy_to_tileid(z, x, y): def tileid_to_zxy(tile_id): num_tiles = 0 acc = 0 - z = 0 - while True: + for z in range(0,32): num_tiles = (1 << z) * (1 << z) if acc + num_tiles > tile_id: return t_on_level(z, tile_id - acc) acc += num_tiles - z += 1 + raise OverflowError("tile zoom exceeds 64-bit limit") def find_tile(entries, tile_id): diff --git a/python/test/test_tile.py b/python/test/test_tile.py index 08e5f53..5f5de22 100644 --- a/python/test/test_tile.py +++ b/python/test/test_tile.py @@ -52,6 +52,27 @@ class TestTileId(unittest.TestCase): self.assertEqual(x, rx) self.assertEqual(y, ry) + def test_tile_extremes(self): + for z in range(0,32): + dim = (1 << z) - 1 + tl = tileid_to_zxy(zxy_to_tileid(z,0,0)) + self.assertEqual(tl,(z,0,0)) + tr = tileid_to_zxy(zxy_to_tileid(z,dim,0)) + self.assertEqual(tr,(z,dim,0)) + bl = tileid_to_zxy(zxy_to_tileid(z,0,dim)) + self.assertEqual(bl,(z,0,dim)) + br = tileid_to_zxy(zxy_to_tileid(z,dim,dim)) + self.assertEqual(br,(z,dim,dim)) + + def test_invalid_tiles(self): + with self.assertRaises(Exception) as context: + tileid_to_zxy(18446744073709551615) + + with self.assertRaises(Exception) as context: + zxy_to_tileid(32,0,0) + + with self.assertRaises(Exception) as context: + zxy_to_tileid(0,1,1) class TestFindTile(unittest.TestCase): def test_find_tile_missing(self):