def test_coverage_empty(self): # an empty geometry should have no coverage from raw_tiles.tile import Tile, shape_tile_coverage from shapely.geometry.polygon import Polygon empty = Polygon() cov = shape_tile_coverage(empty, 16, Tile(0, 0, 0)) self.assertEquals(set([]), cov)
def test_coverage_trivial(self): # test that the trivial coverage - a tile's shape with itself as the # parent - returns that single tile. from raw_tiles.tile import Tile, shape_tile_coverage t = Tile(10, 255, 123) cov = shape_tile_coverage(t.as_shapely(), 10, t) self.assertEquals(1, len(cov)) self.assertEquals(set([t]), cov)
def insert_into_index(tile_pyramid, feature, tile_index, start_zoom=0, end_zoom=None): assert isinstance(feature, _Feature) layer_min_zooms = feature.layer_min_zooms # quick exit if the feature didn't have a min zoom in any layer. if not layer_min_zooms: return # lowest zoom that this feature appears in any layer. note that this # is clamped to the max zoom, so that all features that appear at some # zoom level appear at the max zoom. this is different from the min # zoom in layer_min_zooms, which is a property that will be injected # for each layer and is used by the _client_ to determine feature # visibility. min_zoom = min(tile_pyramid.max_z, min(layer_min_zooms.values())) # take the minimum integer zoom - this is the min zoom tile that the # feature should appear in, and a feature with min_zoom = 1.9 should # appear in a tile at z=1, not 2, since the tile at z=N is used for # the zoom range N to N+1. # # we cut this off at this index's min zoom, as we aren't interested # in any tiles outside of that, and the layer's start_zoom, since the # feature shouldn't appear outside that range. floor_zoom = max(tile_pyramid.z, int(floor(min_zoom)), start_zoom) # seed initial set of tiles at maximum zoom. all features appear at # least at the max zoom, even if the min_zoom function returns a # value larger than the max zoom. zoom = tile_pyramid.max_z # make sure that features aren't visible at or beyond the end_zoom # for the layer, if one was provided. if end_zoom is not None: # end_zoom is exclusive, so we have to back up one level. zoom = min(zoom, end_zoom - 1) # if the zoom ranges don't intersect, then this feature does not appear # in any zoom. if zoom < floor_zoom: return tiles = shape_tile_coverage(feature.shape, zoom, tile_pyramid.tile()) while zoom >= floor_zoom: parent_tiles = set() for tile in tiles: tile_index[tile].append(feature) parent_tiles.add(tile.parent()) zoom -= 1 tiles = parent_tiles
def insert_into_index(tile_pyramid, feature, tile_index, start_zoom=0, end_zoom=None): assert isinstance(feature, _Feature) layer_min_zooms = feature.layer_min_zooms # quick exit if the feature didn't have a min zoom in any layer. if not layer_min_zooms: return # lowest zoom that this feature appears in any layer. note that this # is clamped to the max zoom, so that all features that appear at some # zoom level appear at the max zoom. this is different from the min # zoom in layer_min_zooms, which is a property that will be injected # for each layer and is used by the _client_ to determine feature # visibility. min_zoom = min(tile_pyramid.max_z, min(layer_min_zooms.values())) # take the minimum integer zoom - this is the min zoom tile that the # feature should appear in, and a feature with min_zoom = 1.9 should # appear in a tile at z=1, not 2, since the tile at z=N is used for # the zoom range N to N+1. # # we cut this off at this index's min zoom, as we aren't interested # in any tiles outside of that, and the layer's start_zoom, since the # feature shouldn't appear outside that range. floor_zoom = max(tile_pyramid.z, int(floor(min_zoom)), start_zoom) # seed initial set of tiles at maximum zoom. all features appear at # least at the max zoom, even if the min_zoom function returns a # value larger than the max zoom. zoom = tile_pyramid.max_z # make sure that features aren't visible at or beyond the end_zoom # for the layer, if one was provided. if end_zoom is not None: # end_zoom is exclusive, so we have to back up one level. zoom = min(zoom, end_zoom - 1) # if the zoom ranges don't intersect, then this feature does not appear # in any zoom. if zoom < floor_zoom: return tiles = shape_tile_coverage(feature.shape, zoom, tile_pyramid.tile()) while zoom >= floor_zoom: parent_tiles = set() for tile in tiles: tile_index[tile].append(feature) parent_tiles.add(tile.parent()) zoom -= 1 tiles = parent_tiles
def test_coverage_point(self): # test the coverage of a simple point object, which will generally be # a single tile, unless it's on the border of two tiles, or the corner # of 4. from raw_tiles.tile import Tile, shape_tile_coverage from shapely.geometry.point import Point # -122.4112, 37.7454 pt = Point(-13626752.45, 4543521.54) cov = shape_tile_coverage(pt, 16, Tile(0, 0, 0)) self.assertEquals(1, len(cov)) self.assertEquals(set([Tile(16, 10483, 25337)]), cov)
def test_coverage_pyramid(self): # test that the coverage of a tile over its own shape at a different # zoom returns all the tiles at the base of the pyramid. from raw_tiles.tile import Tile, shape_tile_coverage t = Tile(10, 255, 123) cov = shape_tile_coverage(t.as_shapely(), 12, t) self.assertEquals(16, len(cov)) expected = set() for x in range(1020, 1024): for y in range(492, 496): expected.add(Tile(12, x, y)) self.assertEquals(expected, cov)
def test_coverage_null_island(self): # null island at (0, 0) should hit 4 tiles, since it's on the corner. from raw_tiles.tile import Tile, shape_tile_coverage from shapely.geometry.point import Point pt = Point(0, 0) cov = shape_tile_coverage(pt, 16, Tile(0, 0, 0)) self.assertEquals(4, len(cov)) expected = set([ Tile(16, 32767, 32767), Tile(16, 32767, 32768), Tile(16, 32768, 32767), Tile(16, 32768, 32768), ]) self.assertEquals(expected, cov)
def add_row(self, fid, shape_wkb, props): # the incoming shape will be WKB and we need to parse it. shape = _LazyShape(shape_wkb) # calculate min zoom for the feature. if the min zoom is None, that # indicates that the feature doesn't appear at all. min_zoom = self.min_zoom_fn(fid, shape, props) if min_zoom is None: return # merge min_zoom into the feature's properties. note that there's only # one copy of this, and the reference should be shared amongst many # entries in the tile index. feature = Feature(fid, shape, props.copy()) feature.properties['min_zoom'] = min_zoom # clamp to the min zoom. features with a min_zoom > max zoom should # appear in the max zoom, but not before. # # NOTE: this happens _after_ min_zoom is put into the feature # properties, because we want to retain the original min zoom in the # tile output. min_zoom = min(min_zoom, self.max_z) # take the minimum integer zoom - this is the min zoom tile that the # feature should appear in, and a feature with min_zoom = 1.9 should # appear in a tile at z=1, not 2, since the tile at z=N is used for # the zoom range N to N+1. # # we cut this off at this index's min zoom, as we aren't interested # in any tiles outside of that. floor_zoom = max(self.root_tile.z, int(floor(min_zoom))) # seed initial set of tiles at maximum zoom. all features appear at # least at the max zoom, even if the min_zoom function returns a # value larger than the max zoom. zoom = self.max_z tiles = shape_tile_coverage(shape, zoom, self.root_tile) while zoom >= floor_zoom: parent_tiles = set() for tile in tiles: self.tile_index[tile].append(feature) parent_tiles.add(tile.parent()) zoom -= 1 tiles = parent_tiles