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))
示例#2
0
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