def generateSubquads(row, column, zoom): row0, col0, row1, col1, zoom1 \ = row*2, column*2, row*2+1, column*2+1, zoom+1 count = 4 offset = 0 for r in range(2): for c in range(2): if r == 0 and c == 0: coord = Coordinate(row0, col0, zoom1) if r == 0 and c == 1: coord = Coordinate(row0, col1, zoom1) if r == 1 and c == 0: coord = Coordinate(row1, col0, zoom1) if r == 1 and c == 1: coord = Coordinate(row1, col1, zoom1) #print coord # Ensure we only yield coords in the area of interest #if extentContainsCoord( render_bbox, coord ): #print '\t', coord yield (offset, count, coord) #else: # continue offset += 1
def test_make_metatiles_multiple_coordinates(self): # we need to be able to handle this so that we can do "cut out" # overzoomed tiles at z>16. json = "{\"json\":true}" tiles = [ dict(tile=json, coord=Coordinate(17, 123, 456), format=json_format, layer='all'), dict(tile=json, coord=Coordinate(17, 123, 457), format=json_format, layer='all'), ] metatiles = make_metatiles(1, tiles) self.assertEqual(2, len(metatiles)) coords = set([Coordinate(17, 123, 456), Coordinate(17, 123, 457)]) for meta in metatiles: self.assertTrue(meta['coord'] in coords) coords.remove(meta['coord']) self.assertEqual('all', meta['layer']) self.assertEqual(zip_format, meta['format']) buf = StringIO.StringIO(meta['tile']) with zipfile.ZipFile(buf, mode='r') as z: self.assertEqual(json, z.open('0/0/0.json').read()) # check all coords were consumed self.assertEqual(0, len(coords))
def test_tilequeue_intersect_does_not_enqueue_coords(self): from mock import MagicMock from tilequeue.command import tilequeue_intersect from ModestMaps.Core import Coordinate from tilequeue.tile import serialize_coord cfg_mock = MagicMock() cfg_mock.queue_type = 'sqs' periperals_mock = MagicMock() c0 = Coordinate(row=0, column=0, zoom=0) c1 = Coordinate(row=1, column=1, zoom=1) periperals_mock.redis_cache_index = MagicMock( intersect=lambda x, y: ([])) queue_mock = MagicMock() periperals_mock.queue = queue_mock queue_mock.enqueue = self.fake_enqueue queue_mock.enqueue_batch = self.fake_enqueue_batch import os with tempdir() as expired_tiles_location: expected_file = os.path.join(expired_tiles_location, 'expire_list.txt') with open(expected_file, "w+") as fp: fp.write(serialize_coord(c0) + "\n" + serialize_coord(c1)) cfg_mock.intersect_expired_tiles_location = expired_tiles_location cfg_mock.logconfig = None tilequeue_intersect(cfg_mock, periperals_mock) self.assertNotIn(c0, self.enqueued_list) self.assertNotIn(c1, self.enqueued_list)
def test_2x2_tile_nominal_1(self): from tilequeue.process import metatile_children_with_size coord = Coordinate(zoom=0, column=0, row=0) result = metatile_children_with_size(coord, 1, 0, 256) self.assertEqual(set([ Coordinate(zoom=0, column=0, row=0), ]), set(result))
def test_tilequeue_intersect_enqueues_coords(self): from mock import MagicMock from tilequeue.command import tilequeue_intersect from ModestMaps.Core import Coordinate from tilequeue.tile import serialize_coord from tilequeue.tile import coord_marshall_int cfg_mock = MagicMock() cfg_mock.queue_type = 'sqs' periperals_mock = MagicMock() c0 = Coordinate(row=0, column=0, zoom=0) c1 = Coordinate(row=1, column=1, zoom=1) coords = (c0, c1) periperals_mock.redis_cache_index = MagicMock( fetch_tiles_of_interest=lambda: set( map(coord_marshall_int, coords))) queue_mock = MagicMock() periperals_mock.queue = queue_mock queue_mock.enqueue = self.fake_enqueue queue_mock.enqueue_batch = self.fake_enqueue_batch import os with tempdir() as expired_tiles_location: expected_file = os.path.join(expired_tiles_location, 'expire_list.txt') with open(expected_file, "w+") as fp: fp.write('\n'.join(map(serialize_coord, coords))) cfg_mock.intersect_expired_tiles_location = expired_tiles_location cfg_mock.logconfig = None tilequeue_intersect(cfg_mock, periperals_mock) self.assertIn(c0, self.enqueued_list) self.assertIn(c1, self.enqueued_list)
def tile(key, x, y, z): dbo = resolve_dbo(key) if key is None: return abort(404) start = time() # TODO Add z limit -> 204 No Content c = Coordinate(y, x, z) nw = OSM.coordinateLocation(c) se = OSM.coordinateLocation(c.down().right()) box = as_bbox(se, nw, 4326) query = dbo.Feature.query.filter(Feature.geom.intersects(box)) features = [] for f in query: feature = { 'type': 'Feature', 'id': f.id, 'properties': f.properties, 'geometry': f.shape.__geo_interface__ } features.append(feature) data_time = time() - start response = jsonify({ 'type': 'FeatureCollection', 'features': features }) serialize_time = time() - start - data_time # print (x,y,z), "Data:", data_time, "Serialize:", serialize_time return response
def tile(key, x, y, z): dbo = resolve_dbo(key) if key is None: return abort(404) start = time() # TODO Add z limit -> 204 No Content c = Coordinate(y, x, z) nw = OSM.coordinateLocation(c) se = OSM.coordinateLocation(c.down().right()) box = as_bbox(se, nw, 4326) query = dbo.Feature.query.filter(Feature.geom.intersects(box)) features = [] for f in query: feature = { 'type': 'Feature', 'id': f.id, 'properties': f.properties, 'geometry': f.shape.__geo_interface__ } features.append(feature) data_time = time() - start response = jsonify({'type': 'FeatureCollection', 'features': features}) serialize_time = time() - start - data_time # print (x,y,z), "Data:", data_time, "Serialize:", serialize_time return response
def tile(x, y, z): # start = time() # TODO Add z limit -> 204 No Content c = Coordinate(y, x, z) nw = OSM.coordinateLocation(c) se = OSM.coordinateLocation(c.down().right()) box = as_bbox(se, nw, 4326) query = Commune.query.filter(Commune.centroid.intersects(box)) features = [] for f in query: feature = { 'type': 'Feature', 'id': f.id, 'properties': f.properties, 'geometry': f.shape.__geo_interface__ } features.append(feature) # data_time = time() - start response = jsonify({ 'type': 'FeatureCollection', 'features': features }) # serialize_time = time() - start - data_time # print (x,y,z), "Data:", data_time, "Serialize:", serialize_time return response
def bounds_to_coords(bounds, zoom): minx, miny, maxx, maxy = bounds topleft_lng = minx topleft_lat = maxy bottomright_lat = miny bottomright_lng = maxx topleftx, toplefty = deg2num(topleft_lat, topleft_lng, zoom) bottomrightx, bottomrighty = deg2num(bottomright_lat, bottomright_lng, zoom) # clamp max values maxval = int(math.pow(2, zoom) - 1) bottomrightx = min(maxval, bottomrightx) bottomrighty = min(maxval, bottomrighty) topleftcoord = Coordinate(row=toplefty, column=topleftx, zoom=zoom) # check if one coordinate subsumes the whole bounds at this zoom if topleftx == bottomrightx and toplefty == bottomrighty: return [topleftcoord] # we have two inclusive coordinates representing the range bottomrightcoord = Coordinate(row=bottomrighty, column=bottomrightx, zoom=zoom) return topleftcoord, bottomrightcoord
def mercator_point_to_coord_fractional(z, x, y): coord = Coordinate( column=x + half_earth_circum, row=half_earth_circum - y, zoom=coord_mercator_point_zoom, ) coord = coord.zoomTo(z) return coord
def mercator_point_to_coord(z, x, y): coord = Coordinate( column=x + half_earth_circum, row=half_earth_circum - y, zoom=coord_mercator_point_zoom, ) coord = coord.zoomTo(z).container() return coord
def iterate_squares(ds, zoom): ''' ''' xoff, xstride, _, yoff, _, ystride = ds.GetGeoTransform() minlon, maxlat = xoff, yoff maxlon = xoff + ds.RasterXSize * xstride minlat = yoff + ds.RasterYSize * ystride if zoom > 11: maxlat = min(58, maxlat) osm = Provider() ul = osm.locationCoordinate(Location(maxlat, minlon)).zoomTo(zoom) lr = osm.locationCoordinate(Location(minlat, maxlon)).zoomTo(zoom) #lr = osm.locationCoordinate(Location(20, -60)).zoomTo(zoom) row = int(ul.row) while row < lr.row: lat = osm.coordinateLocation(Coordinate(row, 0, zoom)).lat print >> sys.stderr, 'lat:', round(lat, 2) col = int(ul.column) while col < lr.column: coord = Coordinate(row, col, zoom) sw = osm.coordinateLocation(coord.down()) ne = osm.coordinateLocation(coord.right()) west = max(minlon, sw.lon) north = min(maxlat, ne.lat) east = min(maxlon, ne.lon) south = max(minlat, sw.lat) left = round((west - xoff) / xstride) top = round((north - yoff) / ystride) width = round((east - xoff) / xstride) - left height = round((south - yoff) / ystride) - top yield (coord, south, north, int(left), int(top), int(width), int(height)) col += 1 row += 1 return x = xmin while x < xmax: print >> sys.stderr, 'lon:', x y = ymin while y < ymax: left = round((x - xoff) / xstride) top = round((y + size - yoff) / ystride) width, height = round(size / xstride), round(size / -ystride) yield (round(x, 2), round(y, 2), int(left), int(top), int(width), int(height)) y += size x += size
def test_tiles_children(self): from tilequeue.tile import coord_children from ModestMaps.Core import Coordinate coord = Coordinate(0, 0, 0) children = coord_children(coord) self.assertEqual(4, len(children)) self.assertEqual(Coordinate(0, 0, 1), children[0]) self.assertEqual(Coordinate(1, 0, 1), children[1]) self.assertEqual(Coordinate(0, 1, 1), children[2]) self.assertEqual(Coordinate(1, 1, 1), children[3])
def test_zoom_1(self): tiles = self._call_fut(1) self.assertEqual(5, len(tiles)) expected_tiles = [ Coordinate(0, 0, 0), Coordinate(0, 0, 1), Coordinate(1, 0, 1), Coordinate(0, 1, 1), Coordinate(1, 1, 1), ] self._assert_tilelist(expected_tiles, tiles)
def test_enqueue_batch_does_not_add_redundant_tile_in_flight(self): coords = [ Coordinate(row=1, column=1, zoom=1), Coordinate(row=2, column=2, zoom=2) ] mock = MagicMock() mock.side_effect = [True, False] self.mockRedis.sismember = mock self.sqs.enqueue_batch(coords) self.assertEqual(1, len(self.message_tuples)) self.assertEqual(self.message_tuples[0][1], "2/2/2")
def coordinates(zoom): """ """ osm = Provider() for (col, row) in product(range(2 ** zoom), range(2 ** zoom)): coord = Coordinate(row, col, zoom) sw = osm.coordinateLocation(coord.down()) ne = osm.coordinateLocation(coord.right()) yield coord, sw, ne
def test_make_metatiles_single(self): json = "{\"json\":true}" tiles = [dict(tile=json, coord=Coordinate(0, 0, 0), format=json_format, layer='all')] metatiles = make_metatiles(1, tiles) self.assertEqual(1, len(metatiles)) self.assertEqual(Coordinate(0, 0, 0), metatiles[0]['coord']) self.assertEqual('all', metatiles[0]['layer']) self.assertEqual(zip_format, metatiles[0]['format']) buf = StringIO.StringIO(metatiles[0]['tile']) with zipfile.ZipFile(buf, mode='r') as z: self.assertEqual(json, z.open('0/0/0.json').read())
def coordinates(zoom): ''' ''' osm = Provider() for (col, row) in product(range(2**zoom), range(2**zoom)): coord = Coordinate(row, col, zoom) sw = osm.coordinateLocation(coord.down()) ne = osm.coordinateLocation(coord.right()) yield coord, sw, ne
def test_enqueue_batch_adds_tiles(self): coords = [ Coordinate(row=1, column=1, zoom=1), Coordinate(row=2, column=2, zoom=2) ] mock = MagicMock() mock.side_effect = [False, False] self.mockRedis.sismember = mock self.sqs.enqueue_batch(coords) self.assertEqual(2, len(self.message_tuples)) self.assertEqual(self.message_tuples[0][1], "1/1/1") self.assertEqual(self.message_tuples[1][1], "2/2/2")
def projCoordinate(self, point): """ Convert from Point object in EPSG:3857 to a Coordinate object """ # the zoom at which we're dealing with meters on the ground diameter = 2 * _pi * 6378137 zoom = _log(diameter) / _log(2) # global offsets coord = Coordinate(point.y, point.x, zoom) coord.column = coord.column + diameter/2 coord.row = diameter/2 - coord.row return coord
def projCoordinate(self, point): """ Convert from Point object in EPSG:900913 to a Coordinate object """ # the zoom at which we're dealing with meters on the ground diameter = 2 * _pi * 6378137 zoom = _log(diameter) / _log(2) # global offsets coord = Coordinate(point.y, point.x, zoom) coord.column = coord.column + diameter/2 coord.row = diameter/2 - coord.row return coord
def test_enqueue_batch_adds_tiles_as_in_flight(self): from tilequeue.tile import coord_marshall_int coords = [ Coordinate(row=1, column=1, zoom=1), Coordinate(row=2, column=2, zoom=2) ] mock = MagicMock() mock.side_effect = [False, False] self.mockRedis.sismember = mock self.mockRedis.sadd = self.fake_sadd self.sqs.enqueue_batch(coords) self.assertEqual(self.key_name, self.sqs.inflight_key) exp_values = map(coord_marshall_int, coords) self.assertEqual(exp_values, self.values)
def bbox_polygon(bbox, provider, zoom): rectangle = bbox.envelope.exterior (x1, y1), (x2, y2) = rectangle.coords[0], rectangle.coords[2] coord1 = Coordinate(y1, x1, zoom + 8) coord2 = Coordinate(y2, x2, zoom + 8) location1 = provider.coordinateLocation(coord1) location2 = provider.coordinateLocation(coord2) lat1, lon1 = location1.lat, location1.lon lat2, lon2 = location2.lat, location2.lon return Polygon(((lon1, lat1), (lon1, lat2), (lon2, lat2), (lon2, lat1), (lon1, lat1)))
def test_roundtrip_serialization(self): from tilequeue.tile import coord_marshall_int from tilequeue.tile import coord_unmarshall_int from tilequeue.tile import seed_tiles from ModestMaps.Core import Coordinate from itertools import chain seed_coords = seed_tiles(0, 5) example_coords = [ Coordinate(zoom=20, column=1002463, row=312816), Coordinate(zoom=30, column=12345678, row=12345678), ] coords = chain(seed_coords, example_coords) for coord in coords: self.assertEquals(coord, coord_unmarshall_int(coord_marshall_int(coord)))
def get(self, kernel_id, layer_name, x, y, z, extension, **kwargs): config = self.ktile_config_manager[kernel_id] layer = config.layers[layer_name] coord = Coordinate(int(y), int(x), int(z)) # To run synchronously: # status_code, headers, content = layer.getTileResponse( # coord, extension) status_code, headers, content = yield self.client.getTileResponse( layer, coord, extension) if layer.max_cache_age is not None: expires = datetime.utcnow() + timedelta( seconds=layer.max_cache_age) headers['Expires'] = expires.strftime('%a %d %b %Y %H:%M:%S GMT') headers['Cache-Control'] = 'public, max-age=%d' \ % layer.max_cache_age else: headers['Cache-Control'] = 'no-cache, no-store, must-revalidate' headers['Pragma'] = 'no-cache' headers['Expires'] = '0' # Force allow cross origin access headers["Access-Control-Allow-Origin"] = "*" # Fill tornado handler properties with ktile code/header/content for k, v in headers.items(): self.set_header(k, v) self.set_status(status_code) self.write(content)
def doRequest(self): ''' http://localhost:8000/tms/test-client/qdjango/10/rt/15/17410/11915.png http://localhost:8000/tms/test-client/qdjango/10/rt/13/4348/2979.png :return: ''' configDict = settings.TILESTACHE_CONFIG_BASE configDict['layers'][self.layer_name] = Layer.objects.get(project_id=self.projectId, name=self.layer_name).tilestache_conf ''' configDict['layers']['rt'] = { "provider": { "name": "url template", "template": "http://www502.regione.toscana.it/wmsraster/com.rt.wms.RTmap/wms?map=wmspiapae&SERVICE=WMS&REQUEST=GetMap&VERSION=1.3.0&LAYERS=rt_piapae.carta_dei_caratteri_del_paesaggio.50k.ct.rt&STYLES=&FORMAT=image/png&TRANSPARENT=undefined&CRS=EPSG:3857&WIDTH=$width&HEIGHT=$height&bbox=$xmin,$ymin,$xmax,$ymax" }, "projection": "spherical mercator" } ''' config = Config.buildConfiguration(configDict) layer = config.layers[self.layer_name] coord = Coordinate(int(self.tile_row), int(self.tile_column), int(self.tile_zoom)) tile_mimetype, tile_content = getTile(layer, coord, self.tile_format, ignore_cached=False) return HttpResponse(content_type=tile_mimetype, content=tile_content)
def test_road_no_repeated_points(self): from ModestMaps.Core import Coordinate from tilequeue.tile import coord_to_bounds z, x, y = 16, 17885, 27755 coord = Coordinate(zoom=z, column=x, row=y) bounds = coord_to_bounds(coord) # have to reorder the bounds from conventional order to the unusual # scheme that overpass expects (south,west,north,east). bbox = "%f,%f,%f,%f" % (bounds[1], bounds[0], bounds[3], bounds[2]) overpass = "******" query = "way(" + bbox + ")[highway]%3B>%3B" self.load_fixtures([overpass + query]) num_tested = 0 with self.features_in_tile_layer(z, x, y, 'roads') as features: for feature in features: gtype = feature['geometry']['type'] if gtype == 'LineString': self._assert_no_repeated_points( feature['geometry']['coordinates']) num_tested += 1 elif gtype == 'MultiLineString': for linestring in feature['geometry']['coordinates']: self._assert_no_repeated_points(linestring) num_tested += 1 self.assertTrue(num_tested != 0, "Expected at least one testable feature.")
def _overpass_element(layer_name, query_fn, args): import json result = query_fn(args.query) pos = result.position x, y = tile.deg2num(pos[0], pos[1], args.zoom) coord = Coordinate(zoom=args.zoom, column=x, row=y) expect = json.loads(args.expect) if args.expect else None if expect: name = '_'.join(_make_ident(v) for v in expect.values()) else: name = 'FIXME' name = name + '_' + result.element_type() tags = result.tags tags['source'] = 'openstreetmap.org' params = dict( name=name, z=args.zoom, x=coord.column, y=coord.row, elt_id=result.element_id, tags=tags, expect=expect, layer_name=layer_name, geom_fn_name=result.geom_fn_name(), geom_fn_arg=result.geom_fn_arg(), elt_type=result.element_type(), ) output = _render_template('overpass_test', params) print output.encode('utf-8')
def way_full(way_id, zoom=16): url = 'https://api.openstreetmap.org/api/0.6/way/%d/full' % (way_id,) headers = {'user-agent': 'mktest.py/0.0.1 (https://github.com/tilezen)'} r = requests.get(url, headers=headers) root = ET.fromstring(r.content) assert root.tag == 'osm' nodes = {} nds = [] tags = {} for child in root: if child.tag == 'node': node_id = int(child.attrib['id']) nodes[node_id] = child elif child.tag == 'way': assert way_id == int(child.attrib['id']) for wchild in child: if wchild.tag == 'nd': nds.append(int(wchild.attrib['ref'])) elif wchild.tag == 'tag': k = wchild.attrib['k'] v = wchild.attrib['v'] tags[k] = v assert nds first_node = nodes[nds[0]] lat = float(first_node.attrib['lat']) lon = float(first_node.attrib['lon']) x, y = tile.deg2num(lat, lon, zoom) tags['source'] = 'openstreetmap.org' return Coordinate(zoom=zoom, column=x, row=y), tags
def node_test(args): import json position, node_tags = node(args.node_id, args.zoom) x, y = tile.deg2num(position[1], position[0], args.zoom) coord = Coordinate(zoom=args.zoom, column=x, row=y) expect = json.loads(args.expect) if args.expect else None if expect: name = '_'.join(_make_ident(v) for v in expect.values()) else: name = 'FIXME' args = dict( name=name, z=args.zoom, x=coord.column, y=coord.row, position=position, node_id=args.node_id, node_tags=node_tags, expect=expect, ) output = _render_template('node_test', args) print output.encode('utf-8')
def _areaQuads(self, area): """ """ xmin, ymin, xmax, ymax = area.bounds ul = Coordinate(ymin, xmin, self.zpixel).zoomTo(self.zgroup).container() lr = Coordinate(ymax, xmax, self.zpixel).zoomTo(self.zgroup).container() quads = set() for x in range(int(1 + lr.column - ul.column)): for y in range(int(1 + lr.row - ul.row)): coord = ul.right(x).down(y) quads.add(quadkey(coord)) return quads
def fit_in_tile(z, x, y, shape): """ Fit shape into the tile. Shape should be a Shapely geometry or WKT string with coordinates between 0 and 1. This unit square is then remapped into the tile z/x/y. """ from ModestMaps.Core import Coordinate from shapely.ops import transform from shapely.wkt import loads as wkt_loads from tilequeue.tile import coord_to_mercator_bounds from tilequeue.tile import reproject_mercator_to_lnglat bounds = coord_to_mercator_bounds(Coordinate(zoom=z, column=x, row=y)) if isinstance(shape, (str, unicode)): shape = wkt_loads(shape) # check shape fits within unit square, so we can transform it to fit # within the tile. assert shape.bounds[0] >= 0 assert shape.bounds[1] >= 0 assert shape.bounds[2] <= 1 assert shape.bounds[3] <= 1 def _transform(x, y, *unused_coords): return ( x * (bounds[2] - bounds[0]) + bounds[0], y * (bounds[3] - bounds[1]) + bounds[1], ) merc_shape = transform(_transform, shape) return transform(reproject_mercator_to_lnglat, merc_shape)
def test_metatile_file_timing(self): from time import gmtime, time from tilequeue.metatile import metatiles_are_equal # tilequeue's "GET before PUT" optimisation relies on being able to # fetch a tile from S3 and compare it to the one that was just # generated. to do this, we should try to make the tiles as similar # as possible across multiple runs. json = "{\"json\":true}" tiles = [ dict(tile=json, coord=Coordinate(0, 0, 0), format=json_format, layer='all') ] when_will_then_be_now = 10 t = time() now = gmtime(t)[0:6] then = gmtime(t - when_will_then_be_now)[0:6] metatile_1 = make_metatiles(1, tiles, then) metatile_2 = make_metatiles(1, tiles, now) self.assertTrue( metatiles_are_equal(metatile_1[0]['tile'], metatile_2[0]['tile']))
def request(config_content, layer_name, format, row, column, zoom): ''' Helper method to write config_file to disk and do request ''' if sys.version_info.major == 2: is_string = isinstance(config_content, str) else: is_string = isinstance(config_content, (str, bytes)) if is_string: absolute_file_name = create_temp_file(config_content) config = parseConfig(absolute_file_name) else: config = parseConfig(config_content) layer = config.layers[layer_name] coord = Coordinate(int(row), int(column), int(zoom)) mime_type, tile_content = getTile(layer, coord, format) if is_string: os.remove(absolute_file_name) return mime_type, tile_content
def generateCoordinates(ul, lr, zooms, padding): """ Generate a stream of (offset, count, coordinate) tuples for seeding. Flood-fill coordinates based on two corners, a list of zooms and padding. """ # start with a simple total of all the coordinates we will need. count = 0 for zoom in zooms: ul_ = ul.zoomTo(zoom).container().left(padding).up(padding) lr_ = lr.zoomTo(zoom).container().right(padding).down(padding) rows = lr_.row + 1 - ul_.row cols = lr_.column + 1 - ul_.column count += int(rows * cols) # now generate the actual coordinates. # offset starts at zero offset = 0 for zoom in zooms: ul_ = ul.zoomTo(zoom).container().left(padding).up(padding) lr_ = lr.zoomTo(zoom).container().right(padding).down(padding) range_ = xrange if PY2 else range for row in range_(int(ul_.row), int(lr_.row + 1)): for column in range_(int(ul_.column), int(lr_.column + 1)): coord = Coordinate(row, column, zoom) yield (offset, count, coord) offset += 1
def test_tilequeue_explode_and_intersect(self): from tilequeue.command import explode_and_intersect from tilequeue.tile import coord_marshall_int from tilequeue.tile import coord_unmarshall_int from ModestMaps.Core import Coordinate sample_coord = Coordinate(zoom=14, column=250, row=250) sample_coord_int = coord_marshall_int(sample_coord) tiles_of_interest = [sample_coord_int] for i in (10, 11, 12, 13): coord = sample_coord.zoomTo(i) coord_int = coord_marshall_int(coord) tiles_of_interest.append(coord_int) exploded, metrics = explode_and_intersect( [sample_coord_int], tiles_of_interest, until=11) coord_ints = list(exploded) for coord_int in coord_ints: coord = coord_unmarshall_int(coord_int) self.failUnless(coord.zoom > 10) self.assertEqual(4, len(coord_ints)) self.assertEqual(4, metrics['hits']) self.assertEqual(0, metrics['misses']) self.assertEqual(4, metrics['total'])
def renderTile(self, width, height, srs, coord): """ """ img = Image.new('RGB', (width, height), colors[0]) draw = ImageDraw(img) interactivity_array = [] base_zoom = coord.zoom base_row = coord.row base_column = coord.column #We're showing detail for three zooms in from here, as fat pixels (32 pix) #256 pixels / tile = 8 pixels / tile = 32 pixels (which is 2^5) tile_pixel_width = 256 #print 'coord:', coord #print 'base_zoom:', base_zoom # 256 pixel tile == 2^8 pixel tile, so this is a constant tile_power_of_two = 8 # we want 8x8 fatbits == 2^3 pixel fatbits #TODO: use self.cell_size to find log of 2 to x? pixel_power_of_two = int(log( self.cell_size, 2 )) fat_pixel_width = 2**pixel_power_of_two self.fat_pixel_count = 2**(tile_power_of_two - pixel_power_of_two) # adjust the coord to be the pixel zoom coord = coord.zoomBy(tile_power_of_two - pixel_power_of_two) #print "fat_pixel_count: ", fat_pixel_count #print "coord: ", coord #print 'over_sample_zoom_tile_width: ', over_sample_zoom_tile_width #find the fat_pixel with the maximum photo count max_count = 0 top_count = 0 top_margin = 0 #We should be seeing 64 cells (8x8) output image for row in range( self.fat_pixel_count ): for col in range( self.fat_pixel_count ): ul = coord.right(col).down(row) lr = ul.right().down() #Calculate key for the size dict subquad = Coordinate(ul.row, ul.column, ul.zoom) #print 'subquad:', subquad # these values should always be within (0, 256) x1 = col * fat_pixel_width x2 = (col + 1) * fat_pixel_width y1 = row * fat_pixel_width y2 = (row + 1) * fat_pixel_width #Draw fat pixel based on the returned color based on count (size) in that subquad in the dictionary #Implied that no-data is color[0], above where the img is instantiated enumeration = count_votes( self, subquad ) if max_count < enumeration["photo_count_total"]: max_count = enumeration["photo_count_total"] if top_count < enumeration["photo_count0"]: top_count = enumeration["photo_count0"] if self.output_format == "utf_grid": nw = osm.coordinateLocation(subquad) se = osm.coordinateLocation(subquad.right().down()) lat = (nw.lat - se.lat) / 2 + se.lat lon = (se.lon - nw.lon) / 2 + nw.lon interactivity_array.append( { "photo_count_total":enumeration["photo_count_total"], "woe_id":enumeration["woe_id0"], #"woe_id_lau":enumeration["woe_id0_lau"], #"woe_id_adm2":enumeration["woe_id0_adm2"], #"woe_id_adm1":enumeration["woe_id0_adm1"], "woe_id_adm0":enumeration["woe_id0_adm0"], "name":enumeration["name0"], "photo_count":enumeration["photo_count0"], "margin":enumeration["margin0"], "latitude":lat, "longitude":lon, "x1": str(nw.lon), "y1": str(se.lat), "x2": str(se.lon), "y2": str(nw.lat), "row":str(base_row + row), "col":str(base_column + col), "zoom": coord.zoom } ) elif self.method == "size_log": draw.rectangle((x1, y1, x2, y2), size_color_log(int( enumeration[self.input_field]) )) elif self.method == "size": draw.rectangle((x1, y1, x2, y2), size_color(int( enumeration[self.input_field]) )) elif self.method == "unique_id": draw.rectangle((x1, y1, x2, y2), size_color_unique_id(int( enumeration[self.input_field]) )) if self.output_format == "utf_grid": #print "interactivity_array: ", interactivity_array #grid_utf = create_utf_grid( self, interactivity_array ) grid_utf = { 'grid':['','.'] } if max_count == 0: raise NothingToSeeHere() is_saveable = False # Are we at the last requested zoom? if coord.zoom == self.max_zoom: is_saveable = True # Are we at the minimum viable zoom but with little to no data? if (coord.zoom >= self.min_zoom) and (max_count <= self.min_size): is_saveable = True # Are we viable zoom, viable count, and no ambiguity as to the 100% within margin the winner? if (coord.zoom >= (self.min_zoom + 2)) and (max_count > self.max_size) and ((top_count >= (max_count * self.margin_percent)) or ((max_count - top_count) < self.min_size)): is_saveable = True # Don't want to dig for needles #if coord.zoom == 17 and base_row == 50816 and base_column == 21045: # print '(coord.zoom >= (self.min_zoom + 1)) and ((max_count - top_count) < self.min_size):' # print coord.zoom,(self.min_zoom + 1),max_count, top_count, self.min_size if (coord.zoom >= (self.min_zoom + 1)) and ((max_count - top_count) < self.min_size): #(max_count > self.min_size) and is_saveable = True # and (interactivity_array["margin"] >= self.margin_percent) if is_saveable: #print "should save to DB" #print "interactivity_array: ", interactivity_array saveTileToDatabase( self, interactivity_array ) raise NothingMoreToSeeHere( SaveableResponse(json.dumps(grid_utf)) ) else: return SaveableResponse(json.dumps(grid_utf)) elif self.output_format == "geojson": grid_utf = create_utf_grid( self, interactivity_array ) return SaveableResponse(json.dumps(grid_utf)) else: return img
'http://b.tile.openstreetmap.org/6/22/22.png', 'http://c.tile.openstreetmap.org/6/15/28.png'] paths = [urlparse(href).path for href in hrefs] tiles = [splitext(path)[0].lstrip('/') for path in paths] values = [map(int, tile.split('/', 2)) for tile in tiles] rows, cols = zip(*[(y, x) for (z, x, y) in values]) rows_cols = [] for row in range(min(rows), max(rows) + 1): for col in range(min(cols), max(cols) + 1): rows_cols.append((row, col)) for (index, (row, col)) in enumerate(rows_cols): coord = Coordinate(row, col, zoom) filename = '%(output_dir)s/%(zoom)d-%(col)d-%(row)d.tif' % locals() print 'echo', '-' * 80, index, 'of', len(rows_cols), filename ll = mercator.coordinateProj(coord.down()) ur = mercator.coordinateProj(coord.right()) print 'gdalwarp', print '-t_srs "+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs +over"', print '-te', ll.x, ll.y, ur.x, ur.y, print '-tr', scale, scale, print '-tps -r cubicspline', print '-co COMPRESS=JPEG', print 'landcover-1km-to-merc.vrt', print filename