diff --git a/quadkey/__init__.py b/quadkey/__init__.py index 3bb4fb5..61f7a75 100644 --- a/quadkey/__init__.py +++ b/quadkey/__init__.py @@ -1,98 +1,113 @@ from util import precondition from tile_system import TileSystem, valid_key +LAT_STR = 'lat' +LON_STR = 'lon' + class QuadKey: - @precondition(lambda c, key: valid_key(key)) - def __init__(self, key): - """ - A quadkey must be between 1 and 23 digits and can only contain digit[0-3] - """ - self.key = key - self.level = len(key) - - def children(self): - if self.level >= 23: - return [] - return [QuadKey(self.key + str(k)) for k in [0, 1, 2, 3]] - - def parent(self): - return QuadKey(self.key[:-1]) - - def nearby(self): - tile, level = TileSystem.quadkey_to_tile(self.key) - 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)) - return [TileSystem.tile_to_quadkey(tile, level) for tile in tiles] - - def is_ancestor(self, node): - """ - If node is ancestor of self - Get the difference in level - If not, None - """ - if self.level <= node.level or self.key[:len(node.key)] != node.key: - return None - return self.level - node.level - - def is_descendent(self, node): - """ - If node is descendent of self - Get the difference in level - If not, None - """ - return node.is_ancestor(self) - - def area(self): - size = TileSystem.map_size(self.level) - LAT = 0 - res = TileSystem.ground_resolution(LAT, self.level) - side = (size / 2) * res - return side*side - - def difference(to): + @precondition(lambda c, key: valid_key(key)) + def __init__(self, key): + """ + A quadkey must be between 1 and 23 digits and can only contain digit[0-3] + """ + self.key = key + self.level = len(key) + + def children(self): + if self.level >= 23: + return [] + return [QuadKey(self.key + str(k)) for k in [0, 1, 2, 3]] + + def parent(self): + return QuadKey(self.key[:-1]) + + def nearby(self): + tile, level = TileSystem.quadkey_to_tile(self.key) + 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)) + return [TileSystem.tile_to_quadkey(tile, level) for tile in tiles] + + def is_ancestor(self, node): + """ + If node is ancestor of self + Get the difference in level + If not, None + """ + if self.level <= node.level or self.key[:len(node.key)] != node.key: + return None + return self.level - node.level + + def is_descendent(self, node): """ + If node is descendent of self + Get the difference in level + If not, None + """ + return node.is_ancestor(self) + + def area(self): + size = TileSystem.map_size(self.level) + LAT = 0 + res = TileSystem.ground_resolution(LAT, self.level) + side = (size / 2) * res + return side * side + + def xdifference(self, to): + """ 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 + 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, se_tile = self_tile, to_tile + if self_tile[x] >= to_tile[x] and self_tile[y] <= self_tile[y]: + ne_tile, sw_tile = self_tile, to_tile else: - se_tile, ne_tile = self_tile, to_tile + sw_tile, ne_tile = self_tile, to_tile cur = ne_tile[:] while cur[x] >= sw_tile[x]: while cur[y] <= sw_tile[y]: - yield QuadKey.from_tile(tuple(cur), self.level) + yield from_tile(tuple(cur), self.level) cur[y] += 1 cur[x] -= 1 cur[y] = ne_tile[y] - def to_tile(self): - return TileSystem.quadkey_to_tile(self.key) + def difference(self, to): + """ Non generator version of xdifference + """ + return [qk for qk in self.xdifference(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))) ] + + def to_tile(self): + return TileSystem.quadkey_to_tile(self.key) - def to_geo(self, centered=False): - ret = TileSystem.quadkey_to_tile(self.key) - tile = ret[0] - lvl = ret[1] - pixel = TileSystem.tile_to_pixel(tile, centered) - return TileSystem.pixel_to_geo(pixel, lvl) + def to_geo(self, centered=False): + ret = TileSystem.quadkey_to_tile(self.key) + tile = ret[0] + lvl = ret[1] + pixel = TileSystem.tile_to_pixel(tile, centered) + return TileSystem.pixel_to_geo(pixel, lvl) - def __eq__(self, other): - return self.key == other.key + def __eq__(self, other): + return self.key == other.key - def __ne__(self, other): - return not self.__eq__(other) + def __ne__(self, other): + return not self.__eq__(other) - def __str__(self): - return self.key + def __str__(self): + return self.key - def __repr__(self): - return self.key + def __repr__(self): + return self.key def from_geo(geo, level): """ @@ -112,3 +127,10 @@ def from_tile(tile, level): def from_str(qk_str): return QuadKey(qk_str) + +def geo_to_dict(geo): + """ Take a geo tuple and return a labeled dict + (lat, lon) -> {'lat': lat, 'lon', lon} + """ + return {LAT_STR: geo[0], LON_STR: geo[1]} + diff --git a/quadkey/tile_system.py b/quadkey/tile_system.py index 3088438..918b66a 100644 --- a/quadkey/tile_system.py +++ b/quadkey/tile_system.py @@ -1,128 +1,131 @@ from util import precondition from math import sin, cos, atan, exp, log, pi + def valid_level(level): - LEVEL_RANGE = (1,23) - return LEVEL_RANGE[0] <= level <= LEVEL_RANGE[1] + LEVEL_RANGE = (1, 23) + return LEVEL_RANGE[0] <= level <= LEVEL_RANGE[1] + @precondition(lambda key: valid_level(len(key))) def valid_key(key): - return TileSystem.KEY_PATTERN.match(key) is not None + return TileSystem.KEY_PATTERN.match(key) is not None + class TileSystem: - """ - Class with static method to build quadkeys from lat, lon, levels - see http://msdn.microsoft.com/en-us/library/bb259689.aspx - """ - import re - KEY_PATTERN = re.compile("^[0-3]+$") - - EARTH_RADIUS = 6378137 - LATITUDE_RANGE = (-85.05112878, 85.05112878) - LONGITUDE_RANGE = (-180., 180.) - - @staticmethod - @precondition(lambda n, minMax: minMax[0] <= minMax[1]) - def clip(n, minMax): - """ Clips number to specified values """ - return min(max(n, minMax[0]), minMax[1]) - - @staticmethod - @precondition(valid_level) - def map_size(level): - """Determines map height and width in pixel space at level""" - return 256 << level - - @staticmethod - @precondition(lambda lat, lvl: valid_level(lvl)) - def ground_resolution(lat, level): - """Gets ground res in meters / pixel""" - lat = TileSystem.clip(lat, TileSystem.LATITUDE_RANGE) - return cos(lat * pi / 180) * 2 * pi * TileSystem.EARTH_RADIUS / TileSystem.map_size(level) - - @staticmethod - @precondition(lambda lat, lvl, dpi: valid_level(lvl)) - def map_scale(lat, level, dpi): - """Gets the scale of the map expressed as ratio 1 : N. Returns N""" - return TileSystem.ground_resolution(lat, level) * dpi / 0.0254 - - @staticmethod - @precondition(lambda geo, lvl: valid_level(lvl)) - def geo_to_pixel(geo, level): - """Transform from geo coordinates to pixel coordinates""" - lat, lon = float(geo[0]), float(geo[1]) - lat = TileSystem.clip(lat, TileSystem.LATITUDE_RANGE) - lon = TileSystem.clip(lon, TileSystem.LONGITUDE_RANGE) - x = (lon + 180) / 360 - sin_lat = sin(lat * pi / 180) - y = 0.5 - log((1 + sin_lat) / (1 - sin_lat)) / (4 * pi) - # might need to cast to uint - map_size = TileSystem.map_size(level) - pixel_x = int(TileSystem.clip(x * map_size + 0.5, (0, map_size - 1))) - pixel_y = int(TileSystem.clip(y * map_size + 0.5, (0, map_size - 1))) - # print '\n'+str( ((lat, lon), sin_lat, (x, y), map_size, (pixel_x, pixel_y)) )+'\n' - return pixel_x, pixel_y - - @staticmethod - @precondition(lambda pix, lvl: valid_level(lvl)) - def pixel_to_geo(pixel, level): - """Transform from pixel to geo coordinates""" - pixel_x = pixel[0] - pixel_y = pixel[1] - map_size = float(TileSystem.map_size(level)) - x = (TileSystem.clip(pixel_x, (0, map_size - 1)) / map_size) - 0.5 - y = 0.5 - ( TileSystem.clip(pixel_y, (0, map_size - 1)) / map_size) - lat = 90 - 360 * atan(exp(-y * 2 * pi)) / pi - lon = 360 * x - return round(lat,6), round(lon,6) - - @staticmethod - def pixel_to_tile(pixel): - """Transform pixel to tile coordinates""" - return pixel[0] / 256, pixel[1] / 256 - - @staticmethod - def tile_to_pixel(tile, centered=False): - """Transform tile to pixel coordinates""" - pixel = [tile[0] * 256, tile[1] * 256] - if centered: - #should clip on max map size - pixel = [pix + 128 for pix in pixel] - return pixel[0], pixel[1] - - @staticmethod - @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] - quadkey = "" - for i in xrange(level): - bit = level - i - digit = ord('0') - mask = 1 << (bit - 1) #if (bit - 1) > 0 else 1 >> (bit - 1) - if (tile_x & mask) is not 0: - digit += 1 - if (tile_y & mask) is not 0: - digit += 2 - quadkey += chr(digit) - return quadkey - - @staticmethod - def quadkey_to_tile(quadkey): - """Transform quadkey to tile coordinates""" - tile_x, tile_y = (0,0) - level = len(quadkey) - for i in xrange(level): - bit = level - i - mask = 1 << (bit - 1) - if quadkey[level - bit] == '1': - tile_x |= mask - if quadkey[level - bit] == '2': - tile_y |= mask - if quadkey[level - bit] == '3': - tile_x |= mask - tile_y |= mask - return [(tile_x, tile_y), level] - - + + """ + Class with static method to build quadkeys from lat, lon, levels + see http://msdn.microsoft.com/en-us/library/bb259689.aspx + """ + import re + KEY_PATTERN = re.compile("^[0-3]+$") + + EARTH_RADIUS = 6378137 + LATITUDE_RANGE = (-85.05112878, 85.05112878) + LONGITUDE_RANGE = (-180., 180.) + + @staticmethod + @precondition(lambda n, minMax: minMax[0] <= minMax[1]) + def clip(n, minMax): + """ Clips number to specified values """ + return min(max(n, minMax[0]), minMax[1]) + + @staticmethod + @precondition(valid_level) + def map_size(level): + """Determines map height and width in pixel space at level""" + return 256 << level + + @staticmethod + @precondition(lambda lat, lvl: valid_level(lvl)) + def ground_resolution(lat, level): + """Gets ground res in meters / pixel""" + lat = TileSystem.clip(lat, TileSystem.LATITUDE_RANGE) + return cos(lat * pi / 180) * 2 * pi * TileSystem.EARTH_RADIUS / TileSystem.map_size(level) + + @staticmethod + @precondition(lambda lat, lvl, dpi: valid_level(lvl)) + def map_scale(lat, level, dpi): + """Gets the scale of the map expressed as ratio 1 : N. Returns N""" + return TileSystem.ground_resolution(lat, level) * dpi / 0.0254 + + @staticmethod + @precondition(lambda geo, lvl: valid_level(lvl)) + def geo_to_pixel(geo, level): + """Transform from geo coordinates to pixel coordinates""" + lat, lon = float(geo[0]), float(geo[1]) + lat = TileSystem.clip(lat, TileSystem.LATITUDE_RANGE) + lon = TileSystem.clip(lon, TileSystem.LONGITUDE_RANGE) + x = (lon + 180) / 360 + sin_lat = sin(lat * pi / 180) + y = 0.5 - log((1 + sin_lat) / (1 - sin_lat)) / (4 * pi) + # might need to cast to uint + map_size = TileSystem.map_size(level) + pixel_x = int(TileSystem.clip(x * map_size + 0.5, (0, map_size - 1))) + pixel_y = int(TileSystem.clip(y * map_size + 0.5, (0, map_size - 1))) + # print '\n'+str( ((lat, lon), sin_lat, (x, y), map_size, (pixel_x, + # pixel_y)) )+'\n' + return pixel_x, pixel_y + + @staticmethod + @precondition(lambda pix, lvl: valid_level(lvl)) + def pixel_to_geo(pixel, level): + """Transform from pixel to geo coordinates""" + pixel_x = pixel[0] + pixel_y = pixel[1] + map_size = float(TileSystem.map_size(level)) + x = (TileSystem.clip(pixel_x, (0, map_size - 1)) / map_size) - 0.5 + y = 0.5 - (TileSystem.clip(pixel_y, (0, map_size - 1)) / map_size) + lat = 90 - 360 * atan(exp(-y * 2 * pi)) / pi + lon = 360 * x + return round(lat, 6), round(lon, 6) + + @staticmethod + def pixel_to_tile(pixel): + """Transform pixel to tile coordinates""" + return pixel[0] / 256, pixel[1] / 256 + + @staticmethod + def tile_to_pixel(tile, centered=False): + """Transform tile to pixel coordinates""" + pixel = [tile[0] * 256, tile[1] * 256] + if centered: + # should clip on max map size + pixel = [pix + 128 for pix in pixel] + return pixel[0], pixel[1] + + @staticmethod + @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] + quadkey = "" + for i in xrange(level): + bit = level - i + digit = ord('0') + mask = 1 << (bit - 1) # if (bit - 1) > 0 else 1 >> (bit - 1) + if (tile_x & mask) is not 0: + digit += 1 + if (tile_y & mask) is not 0: + digit += 2 + quadkey += chr(digit) + return quadkey + + @staticmethod + def quadkey_to_tile(quadkey): + """Transform quadkey to tile coordinates""" + tile_x, tile_y = (0, 0) + level = len(quadkey) + for i in xrange(level): + bit = level - i + mask = 1 << (bit - 1) + if quadkey[level - bit] == '1': + tile_x |= mask + if quadkey[level - bit] == '2': + tile_y |= mask + if quadkey[level - bit] == '3': + tile_x |= mask + tile_y |= mask + return [(tile_x, tile_y), level] diff --git a/quadkey/util.py b/quadkey/util.py index 5d09271..495e72f 100644 --- a/quadkey/util.py +++ b/quadkey/util.py @@ -1,21 +1,23 @@ import functools + def condition(precondition=None, postcondition=None): def decorator(func): - @functools.wraps(func) # preserve name, docstring, etc - def wrapper(*args, **kwargs): #NOTE: no self + @functools.wraps(func) # preserve name, docstring, etc + def wrapper(*args, **kwargs): # NOTE: no self if precondition is not None: - assert precondition(*args, **kwargs) - retval = func(*args, **kwargs) # call original function or method + assert precondition(*args, **kwargs) + retval = func(*args, **kwargs) # call original function or method if postcondition is not None: - assert postcondition(retval) + assert postcondition(retval) return retval return wrapper return decorator + def precondition(check): return condition(precondition=check) + def postcondition(check): return condition(postcondition=check) - diff --git a/run_tests.py b/run_tests.py index 362006c..aa01587 100644 --- a/run_tests.py +++ b/run_tests.py @@ -1,5 +1,5 @@ import tests -from tests.quadkey_tests import QuadKeyTest +from tests.quadkey_tests import QuadkeyTest from tests.tile_system import TileSystemTest from tests.util import UtilTest diff --git a/setup.py b/setup.py index 0106ea6..d4320b8 100644 --- a/setup.py +++ b/setup.py @@ -3,9 +3,9 @@ from setuptools import setup setup(name="quadkey", - version="0.0.5", - description="Python Implementation for Geospatial Quadkeys", - author="Buck Heroux", - url="https://github.com/buckheroux/QuadKey", - packages=['quadkey'] - ) + version="0.0.5", + description="Python Implementation for Geospatial Quadkeys", + author="Buck Heroux", + url="https://github.com/buckheroux/QuadKey", + packages=['quadkey'] + ) diff --git a/tests/__init__.py b/tests/__init__.py index 929ff10..0295cc5 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -2,7 +2,8 @@ from unittest import TestCase if __name__ == '__main__': - unittest.main() + unittest.main() + def run(): - unittest.main() + unittest.main() diff --git a/tests/quadkey_tests.py b/tests/quadkey_tests.py index 18d2d64..1aab9ee 100644 --- a/tests/quadkey_tests.py +++ b/tests/quadkey_tests.py @@ -1,50 +1,65 @@ import unittest from unittest import TestCase -from quadkey import QuadKey - -class QuadKeyTest(TestCase): - - def testInit(self): - qk = QuadKey('0321201120') - with self.assertRaises(AssertionError): - qk = QuadKey('') - with self.assertRaises(AssertionError): - qk = QuadKey('0156510012') - - def testGetQuadKey(self): - geo = (40, -105) - level = 7 - key = QuadKey('0231010') - self.assertEqual(key, QuadKey.from_geo(geo, level)) - - def testEquality(self): - one = QuadKey('00') - two = QuadKey('00') - self.assertEqual(one, two) - three = QuadKey('0') - self.assertNotEqual(one, three) - - - def testChildren(self): - qk = QuadKey('0') - self.assertEqual([c.key for c in qk.children()], ['00','01', '02', '03']) - qk = QuadKey(''.join(['0' for x in xrange(23)])) - self.assertEqual(qk.children(), []) - - def testAncestry(self): - one = QuadKey('0') - two = QuadKey('0101') - self.assertEqual(3, one.is_descendent(two)) - self.assertIsNone(two.is_descendent(one)) - self.assertEqual(3, two.is_ancestor(one)) - three = QuadKey('1') - self.assertIsNone(three.is_ancestor(one)) - - def testNearby(self): - qk = QuadKey('0') - self.assertEqual(set(['1','2','3']), set(qk.nearby())) - qk = QuadKey('01') - print qk - print qk.nearby() - self.assertEqual(set(['00','10','02','03','13','33','32','23']), set(qk.nearby())) +import quadkey + +class QuadkeyTest(TestCase): + + def testInit(self): + qk = quadkey.from_str('0321201120') + with self.assertRaises(AssertionError): + qk = quadkey.from_str('') + with self.assertRaises(AssertionError): + qk = quadkey.from_str('0156510012') + + def testFromGeo(self): + geo = (40, -105) + level = 7 + key = quadkey.from_str('0231010') + self.assertEqual(key, quadkey.from_geo(geo, level)) + + def testEquality(self): + one = quadkey.from_str('00') + two = quadkey.from_str('00') + self.assertEqual(one, two) + three = quadkey.from_str('0') + self.assertNotEqual(one, three) + + 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)])) + self.assertEqual(qk.children(), []) + + def testAncestry(self): + one = quadkey.from_str('0') + two = quadkey.from_str('0101') + self.assertEqual(3, one.is_descendent(two)) + self.assertIsNone(two.is_descendent(one)) + self.assertEqual(3, two.is_ancestor(one)) + three = quadkey.from_str('1') + self.assertIsNone(three.is_ancestor(one)) + + def testNearby(self): + qk = quadkey.from_str('0') + self.assertEqual(set(['1', '2', '3']), set(qk.nearby())) + #qk = quadkey.from_str('01') + #self.assertEqual( + # set(['00', '10', '02', '03', '13', '33', '32', '23']), set(qk.nearby())) + + def testUnwind(self): + qk = quadkey.from_str('0123') + self.assertEqual( + ['0123', '012', '01', '0'], + [qk.key for qk in qk.unwind()] + ) + + def testDifference(self): + _from = quadkey.from_str('0320101102') + _to = quadkey.from_str('0320101110') + diff = set(['0320101102','0320101100','0320101103', '0320101101', '0320101112', '0320101110']) + self.assertEqual(diff, set([qk.key for qk in _to.difference(_from)])) + self.assertEqual(diff, set([qk.key for qk in _from.difference(_to)])) + + diff --git a/tests/tile_system.py b/tests/tile_system.py index 325fa13..62305e4 100644 --- a/tests/tile_system.py +++ b/tests/tile_system.py @@ -2,63 +2,63 @@ from unittest import TestCase from quadkey.tile_system import TileSystem -class TileSystemTest(TestCase): - def testClip(self): - self.assertEqual(1, TileSystem.clip(0, (1,5)) ) - self.assertEqual(5, TileSystem.clip(10, (1,5)) ) - self.assertEqual(3, TileSystem.clip(3, (1,5)) ) - with self.assertRaises(AssertionError): - TileSystem.clip(7, (5,1)) +class TileSystemTest(TestCase): + def testClip(self): + self.assertEqual(1, TileSystem.clip(0, (1, 5))) + self.assertEqual(5, TileSystem.clip(10, (1, 5))) + self.assertEqual(3, TileSystem.clip(3, (1, 5))) + with self.assertRaises(AssertionError): + TileSystem.clip(7, (5, 1)) - def testMapSize(self): - self.assertEqual(512, TileSystem.map_size(1)) - with self.assertRaises(AssertionError): - TileSystem.map_size(0) + def testMapSize(self): + self.assertEqual(512, TileSystem.map_size(1)) + with self.assertRaises(AssertionError): + TileSystem.map_size(0) - def testGroundResolution(self): - geo = (40., -105.) - res = 936.86657226219847 - TileSystem.ground_resolution(geo[0], 7) + def testGroundResolution(self): + geo = (40., -105.) + res = 936.86657226219847 + TileSystem.ground_resolution(geo[0], 7) - def testMapScale(self): - geo = (40., -105.) - level = 7 - dpi = 96 - scale = 3540913.0290224836 - self.assertEqual(scale, TileSystem.map_scale(geo[0], level, dpi)) + def testMapScale(self): + geo = (40., -105.) + level = 7 + dpi = 96 + scale = 3540913.0290224836 + self.assertEqual(scale, TileSystem.map_scale(geo[0], level, dpi)) - def testGeoToPixel(self): - geo = (40., -105.) - level = 7 - pixel = (6827, 12405) - self.assertEqual(pixel, TileSystem.geo_to_pixel(geo, level)) + def testGeoToPixel(self): + geo = (40., -105.) + level = 7 + pixel = (6827, 12405) + self.assertEqual(pixel, TileSystem.geo_to_pixel(geo, level)) - def testPixelToGeo(self): - pixel = (6827, 12405) - level = 7 - geo = (40.002372, -104.996338) - self.assertEqual(geo, TileSystem.pixel_to_geo(pixel, level)) + def testPixelToGeo(self): + pixel = (6827, 12405) + level = 7 + geo = (40.002372, -104.996338) + self.assertEqual(geo, TileSystem.pixel_to_geo(pixel, level)) - def testPixelToTile(self): - pixel = (6827, 12405) - tile = (26, 48) - self.assertEqual(tile, TileSystem.pixel_to_tile(pixel)) + def testPixelToTile(self): + pixel = (6827, 12405) + tile = (26, 48) + self.assertEqual(tile, TileSystem.pixel_to_tile(pixel)) - def testTileToPixel(self): - tile = (26, 48) - pixel = (6656, 12288) - self.assertEqual(pixel, TileSystem.tile_to_pixel(tile)) + def testTileToPixel(self): + tile = (26, 48) + pixel = (6656, 12288) + self.assertEqual(pixel, TileSystem.tile_to_pixel(tile)) - def testTileToQuadkey(self): - tile = (26, 48) - level = 7 - key = "0231010" - self.assertEqual(key, TileSystem.tile_to_quadkey(tile, level)) + def testTileToQuadkey(self): + tile = (26, 48) + level = 7 + key = "0231010" + self.assertEqual(key, TileSystem.tile_to_quadkey(tile, level)) - def testQuadkeyToTile(self): - tile = (26, 48) - level = 7 - key = "0231010" - self.assertEqual([tile, level], TileSystem.quadkey_to_tile(key)) + def testQuadkeyToTile(self): + tile = (26, 48) + level = 7 + key = "0231010" + self.assertEqual([tile, level], TileSystem.quadkey_to_tile(key)) diff --git a/tests/util.py b/tests/util.py index 285ef2a..bbfa335 100644 --- a/tests/util.py +++ b/tests/util.py @@ -1,18 +1,18 @@ import unittest from unittest import TestCase -from quadkey.util import * +from quadkey.util import * -class UtilTest(TestCase): - def testPrecondition(self): - self.assertTrue(self.pre(True)) - with self.assertRaises(AssertionError): - self.pre(False) +class UtilTest(TestCase): - def testPostcondition(self): - pass + def testPrecondition(self): + self.assertTrue(self.pre(True)) + with self.assertRaises(AssertionError): + self.pre(False) + def testPostcondition(self): + pass - @precondition(lambda c, x: x is True) - def pre(self, x): - return x + @precondition(lambda c, x: x is True) + def pre(self, x): + return x