Skip to content

Commit

Permalink
Fix #4 and #14.
Browse files Browse the repository at this point in the history
Compatibility with Python 3.
Update Readme.
  • Loading branch information
muety committed Oct 7, 2019
1 parent 546338f commit 16c54cb
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 37 deletions.
11 changes: 7 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ Converts a lat,lon to pixel space to tile space to a quadkey
import quadkey

qk = quadkey.from_geo((-105, 40), 17)
print qk.key # => 02310101232121212
print(qk.key) # => 02310101232121212
assert qk.level is 17
tile = qk.to_tile() # => [(x, y), z]

Expand All @@ -24,7 +24,7 @@ Not a lot of documentation here, but the implementation has quite a bit, so look
Install
-------

The package on pypi is quadtweet, so the recommended installation is with pip
The package on PyPI is quadkey, so the recommended installation is with pip

pip install quadkey

Expand All @@ -38,16 +38,19 @@ There are many straightforward methods, so I'll only go into detail of the uniqu
* is_ancestor()
* is_descendent()
* area()
* side()
* nearby()
* to_geo()
* to_tile()
* to_pixel()

####difference(to)
#### difference(to)

Gets the quadkeys between self and to forming a rectangle, inclusive.

qk.difference(to) -> [qk,,,,,to]

####unwind()
#### unwind()

Gets a list of all ancestors in descending order by level, inclusive.

Expand Down
59 changes: 34 additions & 25 deletions quadkey/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from util import precondition
from tile_system import TileSystem, valid_key
from .util import precondition
from .tile_system import TileSystem, valid_key

LAT_STR = 'lat'
LON_STR = 'lon'
Expand Down Expand Up @@ -27,7 +27,7 @@ def nearby(self):
perms = [(-1, -1), (-1, 0), (-1, 1), (0, -1),
(0, 1), (1, -1), (1, 0), (1, 1)]
tiles = set(
map(lambda perm: (abs(tile[0] + perm[0]), abs(tile[1] + perm[1])), perms))
[(abs(tile[0] + perm[0]), abs(tile[1] + perm[1])) for perm in perms])
return [TileSystem.tile_to_quadkey(tile, level) for tile in tiles]

def is_ancestor(self, node):
Expand All @@ -48,44 +48,50 @@ def is_descendent(self, node):
"""
return node.is_ancestor(self)

def side(self):
return 256 * TileSystem.ground_resolution(0, self.level)

def area(self):
size = TileSystem.map_size(self.level)
LAT = 0
res = TileSystem.ground_resolution(LAT, self.level)
side = (size / 2) * res
side = self.side()
return side * side

def xdifference(self, to):
@staticmethod
def xdifference(first, second):
""" Generator
Gives the difference of quadkeys between self and to
Generator in case done on a low level
Only works with quadkeys of same level
"""
x,y = 0,1
assert self.level == to.level
self_tile = list(self.to_tile()[0])
to_tile = list(to.to_tile()[0])
if self_tile[x] >= to_tile[x] and self_tile[y] <= self_tile[y]:
ne_tile, sw_tile = self_tile, to_tile
else:
sw_tile, ne_tile = self_tile, to_tile
cur = ne_tile[:]
while cur[x] >= sw_tile[x]:
while cur[y] <= sw_tile[y]:
yield from_tile(tuple(cur), self.level)
cur[y] += 1
x, y = 0, 1
assert first.level == second.level
self_tile = list(first.to_tile()[0])
to_tile = list(second.to_tile()[0])
se, sw, ne, nw = None, None, None, None
if self_tile[x] >= to_tile[x] and self_tile[y] <= to_tile[y]:
ne, sw = self_tile, to_tile
elif self_tile[x] <= to_tile[x] and self_tile[y] >= to_tile[y]:
sw, ne = self_tile, to_tile
elif self_tile[x] <= to_tile[x] and self_tile[y] <= to_tile[y]:
nw, se = self_tile, to_tile
elif self_tile[x] >= to_tile[x] and self_tile[y] >= to_tile[y]:
se, nw = self_tile, to_tile
cur = ne[:] if ne else se[:]
while cur[x] >= (sw[x] if sw else nw[x]):
while (sw and cur[y] <= sw[y]) or (nw and cur[y] >= nw[y]):
yield from_tile(tuple(cur), first.level)
cur[y] += 1 if sw else -1
cur[x] -= 1
cur[y] = ne_tile[y]
cur[y] = ne[y] if ne else se[y]

def difference(self, to):
""" Non generator version of xdifference
"""
return [qk for qk in self.xdifference(to)]
return [qk for qk in self.xdifference(self, to)]

def unwind(self):
""" Get a list of all ancestors in descending order of level, including a new instance of self
"""
return [ QuadKey(self.key[:l+1]) for l in reversed(range(len(self.key))) ]
return [ QuadKey(self.key[:l+1]) for l in reversed(list(range(len(self.key)))) ]

def to_tile(self):
return TileSystem.quadkey_to_tile(self.key)
Expand All @@ -98,11 +104,14 @@ def to_geo(self, centered=False):
return TileSystem.pixel_to_geo(pixel, lvl)

def __eq__(self, other):
return self.key == other.key
return isinstance(other, QuadKey) and self.key == other.key

def __ne__(self, other):
return not self.__eq__(other)

def __lt__(self, other):
return self.key.__lt__(other.key)

def __str__(self):
return self.key

Expand Down
12 changes: 6 additions & 6 deletions quadkey/tile_system.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from util import precondition
from .util import precondition
from math import sin, cos, atan, exp, log, pi


Expand Down Expand Up @@ -84,7 +84,7 @@ def pixel_to_geo(pixel, level):
@staticmethod
def pixel_to_tile(pixel):
"""Transform pixel to tile coordinates"""
return pixel[0] / 256, pixel[1] / 256
return int(pixel[0] / 256), int(pixel[1] / 256)

@staticmethod
def tile_to_pixel(tile, centered=False):
Expand All @@ -99,10 +99,10 @@ def tile_to_pixel(tile, centered=False):
@precondition(lambda tile, lvl: valid_level(lvl))
def tile_to_quadkey(tile, level):
"""Transform tile coordinates to a quadkey"""
tile_x = tile[0]
tile_y = tile[1]
tile_x = int(tile[0])
tile_y = int(tile[1])
quadkey = ""
for i in xrange(level):
for i in range(level):
bit = level - i
digit = ord('0')
mask = 1 << (bit - 1) # if (bit - 1) > 0 else 1 >> (bit - 1)
Expand All @@ -118,7 +118,7 @@ def quadkey_to_tile(quadkey):
"""Transform quadkey to tile coordinates"""
tile_x, tile_y = (0, 0)
level = len(quadkey)
for i in xrange(level):
for i in range(level):
bit = level - i
mask = 1 << (bit - 1)
if quadkey[level - bit] == '1':
Expand Down
19 changes: 18 additions & 1 deletion tests/quadkey_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ def testChildren(self):
qk = quadkey.from_str('0')
self.assertEqual(
[c.key for c in qk.children()], ['00', '01', '02', '03'])
qk = quadkey.from_str(''.join(['0' for x in xrange(23)]))
qk = quadkey.from_str(''.join(['0' for x in range(23)]))
self.assertEqual(qk.children(), [])

def testAncestry(self):
Expand Down Expand Up @@ -61,5 +61,22 @@ def testDifference(self):
self.assertEqual(diff, set([qk.key for qk in _to.difference(_from)]))
self.assertEqual(diff, set([qk.key for qk in _from.difference(_to)]))

def testDifference2(self):
qk1 = quadkey.QuadKey('033')
qk2 = quadkey.QuadKey('003')
diff = [qk.key for qk in qk1.difference(qk2)]
self.assertEqual(set(diff), set(['033', '031', '013', '032', '030', '012', '023', '021', '003']))

def testDifference3(self):
qk1 = quadkey.QuadKey('021')
qk2 = quadkey.QuadKey('011')
diff = [qk.key for qk in qk1.difference(qk2)]
self.assertEqual(set(diff), set(['011', '013', '031', '010', '012', '030', '001', '003', '021']))

def testSide(self):
qk = quadkey.QuadKey(''.join(['0'] * 10))
self.assertEqual(int(qk.side()), 39135)

def testArea(self):
qk = quadkey.QuadKey(''.join(['0'] * 10))
self.assertEqual(int(qk.area()), 1531607591)
2 changes: 1 addition & 1 deletion tests/tile_system.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def testMapScale(self):
geo = (40., -105.)
level = 7
dpi = 96
scale = 3540913.0290224836
scale = 3540913.029022482
self.assertEqual(scale, TileSystem.map_scale(geo[0], level, dpi))

def testGeoToPixel(self):
Expand Down

0 comments on commit 16c54cb

Please sign in to comment.