import wx from time import time class TileCoord: def __init__(self, x, y, zoom): self.x = x self.y = y self.zoom = zoom def __hash__(self): return hash(self.x) ^ hash(self.y) ^ hash(self.zoom) def __eq__(self, other): return self.x == other.x and self.y == other.y and self.zoom == other.zoom def __repr__(self): return "TileCoord(%d, %d, %d)" % (self.x, self.y, self.zoom) class TileCache: tilesize = None inithandlers = [cache_init] loadhandlers = [cache_gettile] savehandlers = [cache_addtile] def __init__(self, options = {}): self.emptytile = wx.EmptyImage(width = self.tilesize[0], height = self.tilesize[1]) for handler in self.inithandlers: handler(self, options) def getTile(self, coords, block = False): for loader in self.loadhandlers: image = loader(self, coords, block) if image: break else: return None for saver in self.savehandlers: if saver != loader: saver(self, coords, image) return image ##################################### # Caching in memory def cache_init(self, options): self.cache_tiles = {} self.cache_maxtiles = options.get('maxtiles', 256) def cache_gc(self): if len(self.tiles) > self.maxtiles: accesstimes = [tile[0] for tile in self.tiles.values()] accesstimes.sort(reverse = True) # oldest last keepcount = int(self.maxtiles * 0.8) # So that we won't have to clean up every time treshold = accesstimes[keepcount] for key, value in self.tiles.items(): # Can't use iter, as the size will change if value[0] < treshold: del self.tiles[key] def cache_addtile(self, coords, image): assert isinstance(coords, TileCoord) assert isinstance(image, wx.Image) accesstime = time() self.tiles[coords] = (accesstime, image) self.gc() def cache_gettile(self, coords, block): tile = self.tiles.get(coords) if tile: accesstime, image = tile self.tiles[coords] = (time(), image) return image else: return None