class testCoverage(unittest.TestCase): def setUp(self): logging.basicConfig() #load the coverages self.coverageManager = coveragemanager.CoverageManager() self.coverageManager.load_coverage('../../../copyright_service_data/coverage/map/', False, 'map') self.coverageManager.load_coverage('../../../copyright_service_data/coverage/hyb/', False, 'hyb') self.coverageManager.load_coverage('../../../copyright_service_data/coverage/sat/', False, 'sat') self.coverageManager.load_coverage('../../../copyright_service_data/coverage/ter/', False, 'ter') #create a coverage checker config = { 'map': '../../../copyright_service_data/coverage/map/', 'hyb': '../../../copyright_service_data/coverage/hyb/', 'sat': '../../../copyright_service_data/coverage/sat/', 'ter': '../../../copyright_service_data/coverage/ter/' } self.checker = CoverageChecker(config) #locations whose coverages we should check self.locations = {} self.locations['north america'] = (40, -100) self.locations['south america'] = (-17, -55) self.locations['africa'] = (10, 20) self.locations['united kingdom'] = (55, -5) self.locations['western europe'] = (47, 5) self.locations['eastern europe'] = (50, 20) self.locations['asia'] = (45, 85) self.locations['ociana'] = (-25, 140) projection = Mercator(18+1) zooms = range(0, 19) #for each ll for name, location in self.locations.iteritems(): tiles = [] #through each zoom for zoom in zooms: #make a tile object x, y, z = xyFromLatLng(location, zoom, projection) tile = {"x": x, "y": y, "z": z, "gid": 0, "clientid": 0, "priority":0 , "style": 'map'} tiles.append(Tile(RenderTask.RenderTask(None, tile), projection)) #overwrite the ll with the list of tiles per zoom level self.locations[name] = tiles def showResult(self, scale, projection, points, name): #get the coverage coverage = self.coverageManager.get_coverage(name, False) #see what datasets support this scale and projection candidateDataSets = coverage.getDataSetsForScale(scale, projection) #make a polygon with coordinates in (lng, lat) format polygonPoints = [[points[1], points[0]], [points[1], points[2]], [points[3], points[2]], [points[3], points[0]]] #see which data sets this polygon intersects dataSetID = coverage.getIntersectingDataSets(candidateDataSets, polygonPoints, False, True) #get the data sets for that id dataSets = coverage.getDataSetsByID(dataSetID) print (name, dataSetID, dataSets) def testMap(self): #incoming request info scale = 54168 projection = 'MERCATOR' points = [40.446947059600483, -73.828125, 40.713955826286046, -73.4765625] self.showResult(scale, projection, points, 'map') def testHyb(self): #incoming request info scale = 54168 projection = 'MERCATOR' points = [40.446947059600483, -73.828125, 40.713955826286046, -73.4765625] self.showResult(scale, projection, points, 'hyb') def testSat(self): #incoming request info scale = 54168 projection = 'MERCATOR' points = [40.446947059600483, -73.828125, 40.713955826286046, -73.4765625] self.showResult(scale, projection, points, 'sat') def testTer(self): #incoming request info scale = 54168 projection = 'MERCATOR' points = [40.446947059600483, -73.828125, 40.713955826286046, -73.4765625] self.showResult(scale, projection, points, 'ter') def testChecker(self): #for each set of tiles per location for name, tiles in self.locations.iteritems(): print '\n' + name #for each tile for tile in tiles: #check the coverage for this tile coverage = self.checker.check(tile, True) print coverage def testCheckerSubTile(self): #for each set of tiles per location for name, tiles in self.locations.iteritems(): print '\n' + name #for each tile for tile in tiles: #check the coverage for this tile coverage, uniques = self.checker.checkSubTiles(tile, True) mixed = len(uniques) > 1 and 'OSM' in uniques print '%d : %s : %s' % (tile.z, 'Mixed' if mixed else 'Single', str(uniques)) for key, value in sorted(coverage.iteritems()): print ' %d, %d: %s' % (key[0] + tile.x, key[1] + tile.y, str(value))
class Renderer: def __init__( self, coverage_conf, coverages, factory ): # ensure that there are 'default' and 'missing; keys which # are used when the coverage can't be looked up, or coverage # isn't found for a particular style. if 'default' not in coverages: raise Exception("Required config 'default' not found.") if 'missing' not in coverages: raise Exception("Required config 'missing' not found.") self.coverages = coverages self.factory = factory self.coverageChecker = CoverageChecker(coverage_conf) def process(self, tile): #get the list of coverages per tile, and the set of them removing duplicates coverages, uniqueCoverages = self.coverageChecker.checkSubTiles(tile, True) #how many different styles do these coverages map to? # note - have to lowercase and check the coverage names here, or they'll be # missed out or potentially cause a KeyError at runtime. sanitisedNames = [] for coverage in uniqueCoverages: if coverage is not None and coverage.lower() in self.coverages: sanitisedNames.append(coverage.lower()) else: sanitisedNames.append('default') mixedCoverage = len(set([self.coverages[coverage] for coverage in sanitisedNames])) > 1 if mixedCoverage == True: mq_logging.info("Mixed coverage %s for style '%s' at metatile z=%s x=%s y=%s." % (uniqueCoverages, tile.style, tile.z, tile.x, tile.y)) renderers = self._update_coverages(coverages, mixedCoverage, tile) if mixedCoverage is True: #TODO: do these in parallel, especially since the mapware one is done on a remote machine results = [] for renderer in renderers: result = renderer.process(tile) if result is not None: results.append(result) else: results = [] break ret = self._combine(results, coverages) if len(results) > 0 else None else: ret = renderers[0].process(tile) if ret is None: raise "no image rendered for coverage(s) %s" % coverages else: return ret def _combine(self, results, coverages): # return one RenderResult combining all the results from the # different coverages. since RenderResult is already split into # tiles, this means just gathering the tiles from the input. data = {} meta = {} for tileXY in coverages: index = coverages[tileXY] data[tileXY] = results[index].data[tileXY] if results[index].meta is None: meta[tileXY] = FeatureCollection([]) else: meta[tileXY] = results[index].meta[tileXY] return RenderResult(data, meta) def _update_coverages(self, coverages, mixedCoverage, tile): renderer = [] indices = {} #make sure all of the tiles have at least some rendering system for tileXY, coverage in coverages.iteritems(): # did we have a coverage name. if not, then warn and # use the 'missing' one, which must exist as checked in the # constructor. if len(coverage) > 0: # stupid config file results in names which are all in # lower case, so we have to follow that convention here. vend_name = coverage[0].lower() else: mq_logging.warning("No coverage for style '%s' at sub tile z=%s x=%s y=%s." % (tile.style, tile.z, tile.x + tileXY[0], tile.y + tileXY[1])) vend_name = 'missing' # check that the coverage name exists, or use the 'default' # keyed one, again checked in the constructor. if vend_name in self.coverages: style_name = self.coverages[vend_name] else: style_name = self.coverages['default'] if style_name not in indices: indices[style_name] = len(renderer) rend = self.factory.renderer_for(style_name) if rend is None: raise Exception("Renderer for style name '%s' could not be retrieved." % style_name) renderer.append(rend) coverages[tileXY] = indices[style_name] #we are done if we dont need more than one renderer if mixedCoverage == False: break # return the list of renderers to use return renderer