629 lines
24 KiB
Python
629 lines
24 KiB
Python
#!/usr/bin/env python
|
|
# -*- coding: utf-8 -*-
|
|
#
|
|
"""
|
|
geo.osm (Open Streetmap)
|
|
========================
|
|
|
|
**Author:**
|
|
|
|
* Dirk Alders <sudo-dirk@mount-mockery.de>
|
|
|
|
**Description:**
|
|
|
|
This module is a submodule of :mod:`geo` and supports functions and classes for Open Streetmap.
|
|
|
|
**Contentlist:**
|
|
|
|
* :func:`geo.osm.landmark_link`
|
|
|
|
**Unittest:**
|
|
|
|
See also the :download:`unittest <../../geo/_testresults_/unittest.pdf>` documentation.
|
|
"""
|
|
|
|
|
|
MAP_STANDARD = 'N'
|
|
"""MAP definition for Standard Map"""
|
|
MAP_LOCAL_TRAFIC = 'TN'
|
|
"""MAP definition for Local Trafic Map"""
|
|
MAP_CYCLEMAP = 'CN'
|
|
"""MAP definition for Cyclemap"""
|
|
MAP_HUMANITARIAN = 'HN'
|
|
"""MAP definition for Humanitarian Map"""
|
|
|
|
|
|
def landmark_link(coord, zoom_level=13, map_code=MAP_STANDARD):
|
|
"""
|
|
:param coord: Target coordinate.
|
|
:type coord: geo.gps.coordinate
|
|
:param zoom_level: The zoom level of the map (see https://wiki.openstreetmap.org/wiki/Zoom_levels for more information)
|
|
:type zoom_level: int
|
|
:param map_code: One of the map_codes :class:`MAP_STANDARD`, :class:`MAP_LOCAL_TRAFIC`, :class:`MAP_CYCLEMAP`, :class:`MAP_HUMANITARIAN`.
|
|
:type map_code: str
|
|
:return: An openstreetmap-url for marking a position in a map.
|
|
:rtype: str
|
|
|
|
This Method generates an openstreetmap-url for marking a position in a map.
|
|
|
|
.. code-block:: python
|
|
|
|
>>> import geo
|
|
|
|
>>> gb = geo.gps.coordinate(lat=53.6908298,lon=12.1583252)
|
|
>>> geo.osm.landmark_link(gb)
|
|
'http://www.openstreetmap.org?mlat=53.690830&mlon=12.158325&zoom=13&layers=N'
|
|
"""
|
|
lon = coord[coord.LONGITUDE]
|
|
lat = coord[coord.LATITUDE]
|
|
#
|
|
if lon is not None and lat is not None:
|
|
link = 'http://www.openstreetmap.org?mlat=%(' + coord.LATITUDE + ')f&mlon=%(' + coord.LONGITUDE + ')f&zoom=%(zoom)d&layers=%(map)s'
|
|
return link % {coord.LATITUDE: lat,
|
|
coord.LONGITUDE: lon,
|
|
'zoom': zoom_level,
|
|
'map': map_code}
|
|
else:
|
|
return None
|
|
|
|
|
|
class map_spec(object):
|
|
def __init__(self, **kwargs):
|
|
coord1 = kwargs.get('coord1')
|
|
coord2 = kwargs.get('coord2')
|
|
zoom_level = kwargs.get('zoom_level')
|
|
x = kwargs.get('x')
|
|
y = kwargs.get('y')
|
|
|
|
def get_resolution(self):
|
|
pass
|
|
|
|
def get_coord_range(self):
|
|
pass
|
|
|
|
def get_map(self):
|
|
pass
|
|
|
|
def point_to_coord(self, xy):
|
|
pass
|
|
|
|
def coord_to_point(self, coord):
|
|
pass
|
|
|
|
class osm_map(object):
|
|
def __init__(self, **kwargs):
|
|
self.__map_spec__ = map_spec(kwargs)
|
|
map_code = kwargs.get('map_code')
|
|
|
|
|
|
'''
|
|
class get_from_web():
|
|
"""
|
|
Class to download images from web.
|
|
"""
|
|
def __init__(self, props=None):
|
|
"""
|
|
Init routine for class get_from_web.
|
|
@param props: myapptools.AppProp instance with proxy information. This has to be a dictionary (see self._set_props).
|
|
"""
|
|
self.props = props
|
|
if props != None:
|
|
# install a callback if property 'Proxy' had been changed. it will be called with the new proxy information.
|
|
props.InstallPostSetCallback('Proxy', self._props_callback)
|
|
|
|
def _props_callback(self, proxy):
|
|
"""
|
|
Routione which is called, if proxy information had been changed. It will set the new proxy information.
|
|
@param proxy: dictionary with proxy information
|
|
"""
|
|
self._set_props(**proxy)
|
|
|
|
def _set_props(self, use_proxy, host, port, use_user, user, use_passwd, passwd=None):
|
|
"""
|
|
Routine to set the proxy information.
|
|
@param host: host to connect to
|
|
@param port: port which is used to connect the proxy
|
|
@param user: username for proxy
|
|
@param passwd: password to be used for user
|
|
"""
|
|
proxy_str = None
|
|
if not use_proxy:
|
|
proxy_support = urllib2.ProxyHandler({})
|
|
opener = urllib2.build_opener(proxy_support, urllib2.HTTPHandler)
|
|
urllib2.install_opener(opener)
|
|
elif not use_user:
|
|
proxy_str = "http://%s:%d" % (host, port)
|
|
elif not use_passwd or passwd == None:
|
|
proxy_str = "http://%s@%s:%d" % (user, host, port)
|
|
else:
|
|
proxy_str = "http://%s:%s@%s:%d" % (user, passwd, host, port)
|
|
if proxy_str != None:
|
|
proxy_support = urllib2.ProxyHandler({"http": proxy_str})
|
|
opener = urllib2.build_opener(proxy_support, urllib2.HTTPHandler)
|
|
urllib2.install_opener(opener)
|
|
|
|
def get_image(self, url):
|
|
"""
|
|
Routine to download an image from web.
|
|
@param url: url to the image
|
|
@return: image (type: python Image)
|
|
"""
|
|
#try:
|
|
f = urllib2.urlopen(url)
|
|
im = Image.open(StringIO.StringIO(f.read()))
|
|
f.close()
|
|
return im
|
|
#except ???:
|
|
# print "exception in get_from_web().get_image('%s')" % url
|
|
# return None
|
|
|
|
|
|
class tile_handler(dict):
|
|
"""
|
|
Class to handle some tile_source classes and a default tile_source.
|
|
"""
|
|
TILE_SIZE = 256
|
|
|
|
class tile_source():
|
|
"""
|
|
Class to get tile by cache or url. It also stores the downloaded tiles to the cache directory.
|
|
"""
|
|
TILEPATH = 'osm_tiles'
|
|
|
|
def __init__(self, gfw, name, url, min_zoom, max_zoom):
|
|
"""
|
|
Init routine for class tile_source.
|
|
@param gfw: instance of get_from_web
|
|
@param name: name of tile_type
|
|
@param url: base url without zoom or tile information
|
|
@param min_zoom: minimum existing zoom level for this tile type
|
|
@param max_zoom: maximum existing zoom level for this tile type
|
|
"""
|
|
self.gfw = gfw
|
|
self._name = name
|
|
self._url = url
|
|
self._zooms = range(min_zoom, max_zoom + 1)
|
|
|
|
def get_path(self, x, y, zoom_lvl):
|
|
"""
|
|
Routine to get the tile-path information for a specific tile.
|
|
@param x: horizontal tile number
|
|
@param y: vertical tile number
|
|
@param zoom_lvl: zoom level for the tile
|
|
@return: path to tile as string
|
|
"""
|
|
def intstr(num):
|
|
return str(int(num))
|
|
return os.path.join(__basepath__, self.TILEPATH, self._name, intstr(zoom_lvl), intstr(x), intstr(y) + '.png')
|
|
|
|
def get_url(self, x, y, zoom_lvl):
|
|
"""
|
|
Routine to get the url information for a specific tile.
|
|
@param x: horizontal tile number
|
|
@param y: vertical tile number
|
|
@param zoom_lvl: zoom level for the tile
|
|
@return: url to tile as string
|
|
"""
|
|
def intstr(num):
|
|
return str(int(num))
|
|
return self._url + '/' + intstr(zoom_lvl) + '/' + intstr(x) + '/' + intstr(y) + '.png'
|
|
|
|
def get_zooms(self):
|
|
"""
|
|
Routine to get a list of available zoom levels for this source.
|
|
@return: zoom levels as a list (e.g. [0,1,2,3]).
|
|
"""
|
|
return self._zooms
|
|
|
|
def get_tile(self, x, y, zoom_lvl, max_age, from_cache):
|
|
"""
|
|
Routine to get a tile.
|
|
@param x: horizontal tile number
|
|
@param y: vertical tile number
|
|
@param zoom_lvl: zoom level for the tile
|
|
@param max_age: maximum age where no www-refresh is needed
|
|
@param from_cache: if True the tile is from cache
|
|
@return: tile as Image
|
|
"""
|
|
filename = self.get_path(x, y, zoom_lvl)
|
|
url = self.get_url(x, y, zoom_lvl)
|
|
if from_cache:
|
|
try:
|
|
return Image.open(filename)
|
|
except:
|
|
return None
|
|
else:
|
|
local_time = calendar.timegm(time.gmtime())
|
|
try:
|
|
tile_tm = os.path.getmtime(filename)
|
|
except:
|
|
tile_tm = local_time - max_age - 1
|
|
if local_time - tile_tm > max_age: # age depending refresh.
|
|
im = self.gfw.get_image(url)
|
|
try:
|
|
self.save(im, filename)
|
|
except:
|
|
print "exception in tile_handler().get_tile"
|
|
#TODO: exception handling.
|
|
pass
|
|
return im
|
|
else:
|
|
return None
|
|
|
|
def save(self, im, filename):
|
|
"""
|
|
Routine to save the image to cache (directory).
|
|
@param im: image to save (type: python Image)
|
|
@param filename: name of the file, which will be created
|
|
"""
|
|
dirname = os.path.dirname(filename)
|
|
if not os.path.exists(dirname):
|
|
os.makedirs(dirname)
|
|
im.save(filename)
|
|
|
|
def __init__(self, gfw, props=None):
|
|
"""
|
|
Init routine for class tile_handler
|
|
@param gfw: instance of get_from_web
|
|
@param props: myapptools.AppProp instance with tilehandler information. This has to be a dictionary (see self._set_proxy).
|
|
"""
|
|
dict.__init__(self)
|
|
self.gfw = gfw
|
|
self._active_tile_source = None
|
|
self._max_age = 3600
|
|
self._append_tile_source(u'OSM-Mapnik', u'http://tile.openstreetmap.org', 0, 18)
|
|
self._append_tile_source(u'OSM-CycleMap', u'http://c.tile.opencyclemap.org/cycle', 0, 18)
|
|
try:
|
|
# install a callback if property 'Tilehandler' had been changed. it will be called with the new tilehandler information.
|
|
props.InstallPostSetCallback('Tilehandler', self._props_callback)
|
|
except:
|
|
#TODO: exception handling
|
|
pass
|
|
|
|
def _props_callback(self, tilehandler):
|
|
"""
|
|
Routione which is called, if tilehandler information had been changed. It will set the new tilehandler information.
|
|
@param tilehandler: dictionary with tilehandler information
|
|
"""
|
|
self.set_props(**tilehandler)
|
|
|
|
def set_props(self, source, max_age):
|
|
"""
|
|
Routine to set the proxy information.
|
|
@param source: source for tiles.
|
|
@param max_age: maximum age for a tile till it will be refreshed.
|
|
"""
|
|
self._set_default(source)
|
|
self._max_age = max_age
|
|
|
|
def _append_tile_source(self, name, url, min_zoom, max_zoom):
|
|
"""
|
|
Routine to append a tilesource.
|
|
@param name: Name for this tilesource
|
|
@param url: URL for this tile source (without tile depending information e.g. zoom level, ...)
|
|
@param min_zoom: Minimum zoom level for this tilesource
|
|
@param max_zoom: Maximum zoom level for this tilesource
|
|
"""
|
|
self[name] = self.tile_source(self.gfw, name, url, min_zoom, max_zoom)
|
|
if self._active_tile_source == None:
|
|
self._set_default(name)
|
|
|
|
def _set_default(self, name):
|
|
"""
|
|
Routine to set the default tilesorce (by name).
|
|
@param name: Name for the default tilesource.
|
|
@return: True if name was available, False if not.
|
|
"""
|
|
if name in self.keys():
|
|
self._active_tile_source = name
|
|
return True
|
|
else:
|
|
return False
|
|
|
|
def get_active_source(self):
|
|
"""
|
|
Routine to get the Name of the active tile source.
|
|
@return: name of the active tile source
|
|
"""
|
|
return self._active_tile_source
|
|
|
|
def get_max_age(self):
|
|
return self._max_age
|
|
|
|
def get_choices(self):
|
|
"""
|
|
Routine to get the names of the possible tile sources.
|
|
@return: list of possible tile sources
|
|
"""
|
|
return self.keys()
|
|
|
|
def get_zooms(self):
|
|
"""
|
|
Routine to get a list of available zoom levels for this source.
|
|
@return: zoom levels as a list (e.g. [0,1,2,3]).
|
|
"""
|
|
return self[self._active_tile_source].get_zooms()
|
|
|
|
def get_url(self, x, y, zoom_lvl):
|
|
"""
|
|
Routine to get the url information for a specific tile.
|
|
@param x: horizontal tile number
|
|
@param y: vertical tile number
|
|
@param zoom_lvl: zoom level for the tile
|
|
@return: url to tile as string
|
|
"""
|
|
return self[self._active_tile_source].get_url(x, y, zoom_lvl)
|
|
|
|
def get_tile(self, x, y, zoom_lvl, from_cache):
|
|
"""
|
|
Routine to get a tile.
|
|
@param x: horizontal tile number
|
|
@param y: vertical tile number
|
|
@param zoom_lvl: zoom level for the tile
|
|
@param from_cache: if True the tile is from cache
|
|
@return: tile as Image
|
|
"""
|
|
return self[self._active_tile_source].get_tile(x, y, zoom_lvl, self._max_age, from_cache)
|
|
|
|
def tile_num(self, coordinate, zoom):
|
|
"""
|
|
Routine which calculates the needed tile for coordinates.
|
|
@param coordinate: geo.coordinate instance with geographic information.
|
|
@param zoom: zoom information for the needed tile
|
|
@return: return a tuple of two float values (x- and y-tile)
|
|
"""
|
|
lat_rad = math.radians(coordinate[pylibs.geo.coordinate.LATITUDE])
|
|
n = 2.0 ** zoom
|
|
xtile = (coordinate[pylibs.geo.coordinate.LONGITUDE] + 180.0) / 360.0 * n
|
|
ytile = (1.0 - math.log(math.tan(lat_rad) + (1 / math.cos(lat_rad))) / math.pi) / 2.0 * n
|
|
return (xtile, ytile)
|
|
|
|
def coordinate(self, xtile, ytile, zoom):
|
|
"""
|
|
Routine which calculates geographic information out of tile information.
|
|
@param xtile: number of the tile (x)
|
|
@param ytile: number of the tile (y)
|
|
@param zoom: zoom level
|
|
@return: geo.coordinate instance with the geographic information
|
|
"""
|
|
n = 2.0 ** zoom
|
|
lon_deg = xtile / n * 360.0 - 180.0
|
|
lat_rad = math.atan(math.sinh(math.pi * (1 - 2 * ytile / n)))
|
|
lat_deg = math.degrees(lat_rad)
|
|
return pylibs.geo.coordinate(lon=lon_deg, lat=lat_deg)
|
|
|
|
|
|
class osm_map():
|
|
"""
|
|
This is an Image including an osm map
|
|
"""
|
|
def __init__(self, th, callback_refresh):
|
|
"""
|
|
Init routine for osm_map
|
|
@param th: tile_handler class needed to get tiles
|
|
@param callback_refresh: function to call, if osm_map had been changed (for refresh view)
|
|
callback gets two arguments
|
|
* the image or None if no image is available yet
|
|
* a description text (of the finished issue)
|
|
@param border: additional border around specified area
|
|
@param vers: refresh behaviour as described in VER_*
|
|
"""
|
|
self.th = th
|
|
self.callback_refresh = callback_refresh
|
|
self._del_map_values()
|
|
|
|
self.running = False
|
|
self.stoprequest = False
|
|
|
|
def _del_map_values(self):
|
|
"""
|
|
routine to reset (to None) map definitions (e.g. map_resolution, zoom_lvl, view range
|
|
"""
|
|
self._image = None
|
|
self._map_resolution = None
|
|
self._zoom_lvl = None
|
|
self._center_coordinate = None
|
|
|
|
def _set_map_values(self, map_resolution, zoom_lvl, center_coordinate):
|
|
def zoom_limitation(th, zoom):
|
|
if zoom < min(th.get_zooms()):
|
|
return min(th.get_zooms())
|
|
if zoom > max(th.get_zooms()):
|
|
return max(th.get_zooms())
|
|
return zoom
|
|
self._image = Image.new('RGB', map_resolution, 'white')
|
|
self._map_resolution = map_resolution
|
|
self._zoom_lvl = zoom_limitation(self.th, zoom_lvl)
|
|
self._center_coordinate = center_coordinate
|
|
|
|
def disable(self):
|
|
self.stop_now()
|
|
self.callback_refresh = None
|
|
|
|
def get_image(self):
|
|
return self._image
|
|
|
|
def get_map_resolution(self):
|
|
return self._map_resolution
|
|
|
|
def get_zoom_lvl(self):
|
|
return self._zoom_lvl
|
|
|
|
def get_center_coordinate(self):
|
|
return self._center_coordinate
|
|
|
|
def _paste_tile(self, tile, xy):
|
|
"""
|
|
routine to paste a single tile at xy in the map image.
|
|
@param tile: tile to paste in the image
|
|
@param xy: position to paste the tile. also negative or too large values are
|
|
possible to paste just parts of a tile
|
|
"""
|
|
try:
|
|
self._image.paste(tile, xy)
|
|
except:
|
|
print "exception in osm_map()._paste_tile"
|
|
#TODO: exception handling
|
|
|
|
def create_map_by_res_n_centercoord_n_zoomlvl(self, max_x_res, max_y_res, center_coordinate, zoom_lvl, cache_only=False):
|
|
"""
|
|
routine to ...
|
|
@param max_x_res: maximum x resolution
|
|
@param max_y_res: maximum y resolution
|
|
@param center_coordinate: center coordinates (object of geo.coordinates)
|
|
@param zoom_lvl: zoom_level to use for d
|
|
"""
|
|
if center_coordinate is not None and zoom_lvl is not None:
|
|
self._del_map_values()
|
|
#
|
|
# needed values for further calculations and map creation
|
|
#
|
|
self._set_map_values((max_x_res, max_y_res), zoom_lvl, center_coordinate)
|
|
self._create_map(cache_only)
|
|
|
|
def create_map_by_coord_n_zoomlvl(self, tl_coord, br_coord, zoom_lvl, cache_only=False):
|
|
"""
|
|
@param tl_coord: top left coordinates (object of geo.coordinates)
|
|
@param br_coord: bottom right coordinates (object of geo.coordinates)
|
|
@param zoom_lvl: zoom_level to use for
|
|
"""
|
|
center_coordinate = pylibs.geo.area(tl_coord, br_coord).center_pos()
|
|
tl_tile = self.th.tile_num(tl_coord, zoom_lvl)
|
|
br_tile = self.th.tile_num(br_coord, zoom_lvl)
|
|
max_x_res = int((br_tile[0] - tl_tile[0]) * self.th.TILE_SIZE)
|
|
max_y_res = int((br_tile[1] - tl_tile[1]) * self.th.TILE_SIZE)
|
|
self.create_map_by_res_n_centercoord_n_zoomlvl(max_x_res, max_y_res, center_coordinate, zoom_lvl, cache_only)
|
|
|
|
def create_map_by_res_n_coord(self, max_x_res, max_y_res, tl_coord, br_coord, cache_only=False):
|
|
"""
|
|
@param max_x_res: maximum x resolution
|
|
@param max_y_res: maximum y resolution
|
|
@param tl_coord: top left coordinates (object of geo.coordinates)
|
|
@param br_coord: bottom right coordinates (object of geo.coordinates)
|
|
|
|
coord are not the used coordinated for the map corners, cause the zoom_lvl is quatisised
|
|
"""
|
|
def coordinates_in_map(max_x, max_y, p1, p2, center, zoom_lvl):
|
|
tl = self.get_coord_by_xy(0, 0, (max_x, max_y), center, zoom_lvl)
|
|
br = self.get_coord_by_xy(max_x, max_y, (max_x, max_y), center, zoom_lvl)
|
|
area = pylibs.geo.area(tl, br)
|
|
return area.coordinate_in_area(p1) and area.coordinate_in_area(p2)
|
|
center_coordinate = pylibs.geo.area(tl_coord, br_coord).center_pos()
|
|
zoom_lvl = max(self.th.get_zooms())
|
|
while not coordinates_in_map(max_x_res, max_y_res, tl_coord, br_coord, center_coordinate, zoom_lvl):
|
|
zoom_lvl -= 1
|
|
self.create_map_by_res_n_centercoord_n_zoomlvl(max_x_res, max_y_res, center_coordinate, zoom_lvl, cache_only)
|
|
|
|
def stop_now(self):
|
|
self.stoprequest = True
|
|
while self.running:
|
|
pass
|
|
self.stoprequest = False
|
|
|
|
def get_coord_by_xy(self, x, y, map_resolution=None, center_coordinate=None, zoom_lvl=None):
|
|
zoom_lvl = zoom_lvl or self._zoom_lvl
|
|
tl_tile = self._get_tl_tile_num(map_resolution, center_coordinate, zoom_lvl)
|
|
xy_tile = (tl_tile[0] + float(x) / self.th.TILE_SIZE, tl_tile[1] + float(y) / self.th.TILE_SIZE)
|
|
return self.th.coordinate(xy_tile[0], xy_tile[1], zoom_lvl)
|
|
|
|
def get_xy_by_coord(self, coord, map_resolution=None, center_coordinate=None, zoom_lvl=None):
|
|
tl_tile = self._get_tl_tile_num(map_resolution, center_coordinate, zoom_lvl)
|
|
xy_tile = self.th.tile_num(coord, self._zoom_lvl)
|
|
x = int((xy_tile[0] - tl_tile[0]) * self.th.TILE_SIZE)
|
|
y = int((xy_tile[1] - tl_tile[1]) * self.th.TILE_SIZE)
|
|
return (x, y)
|
|
|
|
def _get_map_res_tiles(self, map_resolution=None):
|
|
"""
|
|
returns the map resolution in number of tiles
|
|
"""
|
|
map_resolution = map_resolution or self._map_resolution
|
|
if map_resolution:
|
|
return (map_resolution[0] / float(self.th.TILE_SIZE), map_resolution[1] / float(self.th.TILE_SIZE))
|
|
else:
|
|
return None
|
|
|
|
def _get_tl_tile_num(self, map_resolution=None, center_coordinate=None, zoom_lvl=None):
|
|
map_resolution = map_resolution or self._map_resolution
|
|
center_coordinate = center_coordinate or self._center_coordinate
|
|
zoom_lvl = zoom_lvl or self._zoom_lvl
|
|
#
|
|
if (map_resolution and center_coordinate and zoom_lvl):
|
|
center_tile_num = self.th.tile_num(center_coordinate, zoom_lvl)
|
|
map_resolution_tiles = self._get_map_res_tiles(map_resolution)
|
|
topleft_tile_num = (center_tile_num[0] - map_resolution_tiles[0] / 2, center_tile_num[1] - map_resolution_tiles[1] / 2)
|
|
return topleft_tile_num
|
|
else:
|
|
return None
|
|
|
|
def _get_br_tile_num(self, map_resolution=None, center_coordinate=None, zoom_lvl=None):
|
|
topleft_tile_num = self._get_tl_tile_num(map_resolution, center_coordinate, zoom_lvl)
|
|
map_resolution_tiles = self._get_map_res_tiles(map_resolution)
|
|
bottomright_tile_num = (topleft_tile_num[0] + map_resolution_tiles[0], topleft_tile_num[1] + map_resolution_tiles[1])
|
|
return bottomright_tile_num
|
|
|
|
def _get_xy_offset(self):
|
|
tl_tile = self._get_tl_tile_num()
|
|
x_offs = -int(tl_tile[0] % 1 * self.th.TILE_SIZE)
|
|
y_offs = -int(tl_tile[1] % 1 * self.th.TILE_SIZE)
|
|
return (x_offs, y_offs)
|
|
|
|
def _get_tile_list(self):
|
|
tl_tile = self._get_tl_tile_num()
|
|
br_tile = self._get_br_tile_num()
|
|
tile_list = []
|
|
for x in range(int(tl_tile[0]), int(br_tile[0]) + 1):
|
|
for y in range(int(tl_tile[1]), int(br_tile[1]) + 1):
|
|
tile_list.append((x, y, self._zoom_lvl))
|
|
return tile_list
|
|
|
|
def _create_map(self, cache_only):
|
|
"""
|
|
@param resoultion: map target resolution
|
|
@param xy_offset: offset for top left tile (normally <= 0)
|
|
@param zoom_lvl: tile zoom_lvl
|
|
@param tile_list: list of tiles [[x1, x2, x3], [y1, y2]]
|
|
@param description: description text for callback function
|
|
"""
|
|
def create_map_by_(xy_offset, tile_list, by_path):
|
|
#
|
|
# create map from already stored tiles (...by_path)
|
|
#
|
|
num_tiles = len(tile_list)
|
|
x0, y0 = tile_list[0][:2]
|
|
num = 0
|
|
for x, y, z in tile_list:
|
|
num += 1
|
|
if self.stoprequest:
|
|
break
|
|
tile = self.th.get_tile(x, y, z, by_path)
|
|
if tile != None:
|
|
# paste tile only if tile was available
|
|
pos = (xy_offset[0] + (x - x0) * self.th.TILE_SIZE, xy_offset[1] + (y - y0) * self.th.TILE_SIZE)
|
|
self._paste_tile(tile, pos)
|
|
if not by_path:
|
|
desc = "Tile " + self.th.get_url(x, y, z) + " added to map."
|
|
prog = float(num) / num_tiles
|
|
if self.callback_refresh:
|
|
self.callback_refresh(self._image, desc, prog)
|
|
self.running = True
|
|
#TODO: ggf. Klasse um Uebersetzungen zu ermoeglichen.
|
|
|
|
create_map_by_(self._get_xy_offset(), self._get_tile_list(), by_path=True)
|
|
desc = 'Map creation from cache completeled.'
|
|
if self.callback_refresh:
|
|
self.callback_refresh(self._image, desc, 1.0)
|
|
if not cache_only:
|
|
create_map_by_(self._get_xy_offset(), self._get_tile_list(), by_path=False)
|
|
desc = 'Map creation completeled.'
|
|
if self.callback_refresh:
|
|
self.callback_refresh(self._image, desc, 1.0)
|
|
self.running = False
|
|
|
|
|
|
def show_map(image, description, progress):
|
|
print description, "%5.1f%%" % (progress * 100.)
|
|
if image != None:
|
|
image.show()
|
|
'''
|