def run(self): while True: # get zoom level and tile coordinates to retrieve (level, x, y) = self.requests.get() # try to retrieve the image error = False pixmap = self.error_image try: tile_url = self.server + self.tilepath.format( Z=level, X=x, Y=y) response = request.urlopen(tile_url) content_type = response.info().get_content_type() if content_type == self.content_type: data = response.read() pixmap = QPixmap() pixmap.loadFromData(data) else: # show error, don't cache returned error tile error = True except Exception as e: error = True log('%s exception getting tile (%d,%d,%d)' % (type(e).__name__, level, x, y)) # call the callback function passing level, x, y and pixmap data # error is False if we want to cache this tile on-disk self.callback(level, x, y, pixmap, error) # finally, removes request from queue self.requests.task_done()
def excepthook(type, value, tb): msg = '\n' + '=' * 80 msg += '\nUncaught exception:\n' msg += ''.join(traceback.format_exception(type, value, tb)) msg += '=' * 80 + '\n' print(msg) log(msg) sys.exit(1)
def handle_button(self, event): """Handle button event.""" # get the button that was pressed sender_btn = self.sender() (posn, name) = self.buttons[sender_btn] log(f"Got button event, posn={posn}, name='{name}'") self.pyslipqt.GotoPosition(posn) if self.map_layer: # if there was a previous layer, delete it self.pyslipqt.DeleteLayer(self.map_layer) map_data = [posn] point_colour = '#0000ff40' self.map_layer = self.pyslipqt.AddPointLayer(map_data, map_rel=True, placement='cc', color=point_colour, radius=11, visible=True, name='map_layer') if self.view_layer: self.pyslipqt.DeleteLayer(self.view_layer) view_data = [( ((0, 0), (0, -10), (0, 0), (0, 10), (0, 0), (-10, 0), (0, 0), (10, 0)), { 'colour': '#ff0000ff' }, )] # poly_colour = '#ff0000ff' self.view_layer = self.pyslipqt.AddPolygonLayer( view_data, map_rel=False, placement='cc', # colour=poly_colour, closed=False, visible=True, width=2, name='view_layer')
def on_zoom(self, event): """Catch and undo a zoom. Simulate the amount of work a user handler might do before deciding to undo a zoom. We must check the level we are zooming to. If we don't, the GotoLevel() method below will trigger another exception, which we catch, etc, etc. """ log('Waiting a bit') for _ in range(1000000): pass l = [ InitViewLevel, InitViewLevel, InitViewLevel, InitViewLevel, InitViewLevel, InitViewLevel, InitViewLevel, InitViewLevel, InitViewLevel, InitViewLevel, InitViewLevel, InitViewLevel, InitViewLevel, InitViewLevel, InitViewLevel, InitViewLevel, InitViewLevel, InitViewLevel, InitViewLevel, InitViewLevel, ] log(f'Trying to zoom to level {event.level}, allowed level={InitViewLevel}' ) if event.level not in l: # undo zoom log('New level NOT in allowed list, undoing zoom') self.pyslipqt.GotoLevel(InitViewLevel)
tile_dir = 'test_tiles' tile_source = 'GMT' debug = False for (opt, param) in opts: if opt in ['-h', '--help']: usage() sys.exit(0) elif opt in ['-d', '--debug']: debug = True elif opt in ('-t', '--tiles'): tile_source = param tile_source = tile_source.lower() import pySlipQt.gmt_local as Tiles ## set up the appropriate tile source #if tile_source == 'gmt': # print('importing pySlipQt.gmt_local') # import pySlipQt.gmt_local as Tiles #elif tile_source == 'osm': # print('importing pySlipQt.open_street_map') # import pySlipQt.open_street_map as Tiles #else: # usage('Bad tile source: %s' % tile_source) # sys.exit(3) # start the app log(DemoName) app = QApplication(args) ex = TestPointPlacement(tile_dir) sys.exit(app.exec_())
def layer_select(self, select): print(f'Layer SELECT={select}') log(f'Layer SELECT={select}')
def layer_show(self, show): print(f'Layer SHOW={show}') log(f'Layer SHOW={show}')
def layer_add(self, add): print(f'Layer ADD={add}') log(f'Layer ADD={add}')
def __init__(self, levels, tile_width, tile_height, tiles_dir, max_lru, servers, url_path, max_server_requests, http_proxy, refetch_days=RefreshTilesAfterDays): """Initialise a Tiles instance. levels a list of level numbers that are to be served tile_width width of each tile in pixels tile_height height of each tile in pixels tiles_dir path to on-disk tile cache directory max_lru maximum number of cached in-memory tiles servers list of tile servers url_path path on server to each tile max_server_requests maximum number of requests per server http_proxy proxy to use if required refetch_days fetch new server tile if older than this in days (0 means don't ever update tiles) """ # prepare the tile cache directory, if required # we have to do this *before* the base class initialization! for level in levels: level_dir = os.path.join(tiles_dir, '%d' % level) if not os.path.isdir(level_dir): os.makedirs(level_dir) # perform the base class initialization super().__init__(levels, tile_width, tile_height, tiles_dir, max_lru) # save params not saved in super() self.servers = servers self.url_path = url_path self.max_requests = max_server_requests self.http_proxy = http_proxy # callback must be set by higher-level copde self.callback = None # calculate a re-request age, if specified self.rerequest_age = None if refetch_days: self.rerequest_age = (time.time() - refetch_days * self.SecondsInADay) # tiles extent for tile data (left, right, top, bottom) self.extent = (-180.0, 180.0, -85.0511, 85.0511) # figure out tile filename extension from 'url_path' tile_extension = os.path.splitext(url_path)[1][1:] tile_extension_lower = tile_extension.lower() # ensure lower case # determine the file bitmap type try: self.filetype = self.AllowedFileTypes[tile_extension_lower] except KeyError as e: raise TypeError("Bad tile_extension value, got '%s', " "expected one of %s" % (str(tile_extension), str(self.AllowedFileTypes.keys()))) from None # compose the expected 'Content-Type' string on request result # if we get here we know the extension is in self.AllowedFileTypes if tile_extension_lower == 'jpg': self.content_type = 'image/jpeg' elif tile_extension_lower == 'png': self.content_type = 'image/png' # set the list of queued unsatisfied requests to 'empty' self.queued_requests = {} # prepare the "pending" and "error" images self.pending_tile = QPixmap() self.pending_tile.loadFromData(std.getPendingImage()) self.error_tile = QPixmap() self.error_tile.loadFromData(std.getErrorImage()) # test for firewall - use proxy (if supplied) test_url = self.servers[0] + self.url_path.format(Z=0, X=0, Y=0) try: request.urlopen(test_url) except urllib.error.HTTPError as e: # if it's fatal, log it and die, otherwise try a proxy status_code = e.code log('Error: test_url=%s, status_code=%s' % (test_url, str(status_code))) error_msg = StatusError.get(status_code, None) if status_code: msg = '\n'.join([ 'You got a %d error from: %s' % (status_code, test_url), error_msg ]) log(msg) raise RuntimeError(msg) from None log('%s exception doing simple connection to: %s' % (type(e).__name__, test_url)) log(''.join(traceback.format_exc())) if http_proxy: proxy = request.ProxyHandler({'http': http_proxy}) opener = request.build_opener(proxy) request.install_opener(opener) try: request.urlopen(test_url) except: msg = ("Using HTTP proxy %s, " "but still can't get through a firewall!") raise Exception(msg) from None else: msg = ("There is a firewall but you didn't " "give me an HTTP proxy to get through it?") raise Exception(msg) from None # set up the request queue and worker threads self.request_queue = queue.Queue() # entries are (level, x, y) self.workers = [] for server in self.servers: for num_thread in range(self.max_requests): worker = TileWorker(num_thread, server, self.url_path, self.request_queue, self.tile_is_available, self.error_tile, self.content_type, self.rerequest_age, self.error_tile) self.workers.append(worker) worker.start()