def __init__(self, name): """ Load a MBTile file. If `name` is a valid filepath, it will load it. Else, it will attempt to load it within `settings.MBTILES_ROOT` folder. """ mbtiles_file = name if not os.path.exists(mbtiles_file): if not os.path.exists(app_settings.MBTILES_ROOT): raise MBTilesFolderError() mbtiles_file = os.path.join(app_settings.MBTILES_ROOT, name) if not os.path.exists(mbtiles_file): mbtiles_file = "%s.%s" % (mbtiles_file, app_settings.MBTILES_EXT) if not os.path.exists(mbtiles_file): raise MBTilesNotFoundError(_("'%s' not found") % mbtiles_file) self.fullpath = mbtiles_file self.basename = os.path.basename(self.fullpath) self._reader = MBTilesReader(self.fullpath, tilesize=app_settings.TILE_SIZE)
class MBTiles(object): """ Represent a MBTiles file """ objects = MBTilesManager() def __init__(self, name): """ Load a MBTile file. If `name` is a valid filepath, it will load it. Else, it will attempt to load it within `settings.MBTILES_ROOT` folder. """ mbtiles_file = name if not os.path.exists(mbtiles_file): if not os.path.exists(app_settings.MBTILES_ROOT): raise MBTilesFolderError() mbtiles_file = os.path.join(app_settings.MBTILES_ROOT, name) if not os.path.exists(mbtiles_file): mbtiles_file = "%s.%s" % (mbtiles_file, app_settings.MBTILES_EXT) if not os.path.exists(mbtiles_file): raise MBTilesNotFoundError(_("'%s' not found") % mbtiles_file) self.fullpath = mbtiles_file self.basename = os.path.basename(self.fullpath) self._reader = MBTilesReader(self.fullpath, tilesize=app_settings.TILE_SIZE) @property def id(self): iD, ext = os.path.splitext(self.basename) return iD @property def name(self): return self.metadata.get("name", self.id) @property def filesize(self): return os.path.getsize(self.fullpath) @reify def metadata(self): return self._reader.metadata() @reify def bounds(self): bounds = self.metadata.get("bounds", "").split(",") if len(bounds) != 4: logger.warning(_("Invalid bounds metadata in '%s', fallback to whole world.") % self.name) bounds = [-180, -90, 180, 90] return tuple(map(float, bounds)) @reify def center(self): """ Return the center (x,y) of the map at this zoom level. """ center = self.metadata.get("center", "").split(",") if len(center) == 3: lon, lat, zoom = map(float, center) zoom = int(zoom) if zoom not in self.zoomlevels: logger.warning(_("Invalid zoom level (%s), fallback to middle zoom (%s)") % (zoom, self.middlezoom)) zoom = self.middlezoom return (lon, lat, zoom) # Invalid center from metadata, guess center from bounds lat = self.bounds[1] + (self.bounds[3] - self.bounds[1]) / 2 lon = self.bounds[0] + (self.bounds[2] - self.bounds[0]) / 2 return (lon, lat, self.middlezoom) @property def minzoom(self): z = self.metadata.get("minzoom", self.zoomlevels[0]) return int(z) @property def maxzoom(self): z = self.metadata.get("maxzoom", self.zoomlevels[-1]) return int(z) @property def middlezoom(self): return self.zoomlevels[len(self.zoomlevels) / 2] @reify def zoomlevels(self): return self._reader.zoomlevels() def tile(self, z, x, y): try: return self._reader.tile(z, x, y) except ExtractionError: raise MissingTileError def center_tile(self): lon, lat, zoom = self.center proj = GoogleProjection(app_settings.TILE_SIZE, [zoom]) return proj.tile_at(zoom, (lon, lat)) def grid(self, z, x, y, callback=None): try: return self._reader.grid(z, x, y, callback) except ExtractionError: raise MissingTileError def jsonp(self, callback): # Raw metadata jsonp = dict(self.metadata) # Post-processed metadata jsonp.update(**{"bounds": self.bounds, "center": self.center, "minzoom": self.minzoom, "maxzoom": self.maxzoom}) # Additionnal info tilepattern = reverse("mbtilesmap:tile", kwargs=dict(name=self.id, x="{x}", y="{y}", z="{z}")) tilepattern = tilepattern.replace("%7B", "{").replace("%7D", "}") jsonp.update( **{ "id": self.id, "name": self.name, "scheme": "xyz", "basename": self.basename, "filesize": self.filesize, "tiles": [tilepattern], } ) return "%s(%s);" % (callback, simplejson.dumps(jsonp))