source: subversion/applications/routing/pyroute/tiles.py @ 20924

Last change on this file since 20924 was 12252, checked in by jeansch, 11 years ago

Fixed 'tah' URL
Fixed starting from another directory
Implemented 'scroll' events to allow to change zoom from mouse-wheel
Implemented initial position

File size: 5.0 KB
Line 
1#!/usr/bin/python
2#-----------------------------------------------------------------------------
3# Tile image handler (download, cache, and display tiles)
4#
5# Usage:
6#   (library code for pyroute GUI, not for direct use)
7#-----------------------------------------------------------------------------
8# Copyright 2007, Oliver White
9#
10# This program is free software: you can redistribute it and/or modify
11# it under the terms of the GNU General Public License as published by
12# the Free Software Foundation, either version 3 of the License, or
13# (at your option) any later version.
14#
15# This program is distributed in the hope that it will be useful,
16# but WITHOUT ANY WARRANTY; without even the implied warranty of
17# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18# GNU General Public License for more details.
19#
20# You should have received a copy of the GNU General Public License
21# along with this program.  If not, see <http://www.gnu.org/licenses/>.
22#-----------------------------------------------------------------------------
23from base import pyrouteModule
24from tilenames import *
25import urllib
26import os
27import cairo
28from threading import Thread
29
30def downloadTile(x,y,z,layer,filename):
31  url = tileURL(x,y,z,layer)
32  if(tileLayerExt(layer) != "png"):
33    base,ext = os.path.splitext(filename)
34    tempFilename = "%s.%s" % (base, tileLayerExt(layer))
35    urllib.urlretrieve(url, tempFilename)
36    sys = "convert %s %s" % (tempFilename, filename)
37    print "Running \"%s\"" % sys
38    os.system(sys)
39    os.unlink(tempFilename)
40  else:
41    urllib.urlretrieve(url, filename)
42 
43class tileLoader(Thread):
44  """Downloads images in a separate thread"""
45  def __init__(self, x,y,z,layer,filename):
46    """Download a tile image"""
47    self.x = x
48    self.y = y
49    self.z = z
50    self.layer = layer
51    self.finished = 0
52    self.filename = filename
53    Thread.__init__(self)
54   
55  def run(self):
56    downloadTile( \
57      self.x,
58      self.y,
59      self.z,
60      self.layer,
61      self.filename)
62     
63    self.finished = 1
64
65class tileHandler(pyrouteModule):
66  """Loads and displays map tiles"""
67  def __init__(self, modules):
68    pyrouteModule.__init__(self, modules)
69    self.images = {}
70    self.threads = {}
71    self.downloadInThread = False
72   
73  def __del__(self):
74    print "Shutting-down tiles"
75    for name,thread in self.threads.items():
76      pass
77  def imageName(self,x,y,z,layer):
78    """Get a unique name for a tile image
79    (suitable for use as part of filenames, dictionary keys, etc)"""
80    return("%s_%d_%d_%d" % (layer,z,x,y))
81 
82  def loadImage(self,x,y,z, layer):
83    """Check that an image is loaded, and try to load it if not"""
84   
85    # First: is the image already in memory?
86    name = self.imageName(x,y,z,layer)
87    if name in self.images.keys():
88      return
89   
90    # Second, is it already in the process of being downloaded?
91    if name in self.threads.keys():
92      if(not self.threads[name].finished):
93        return
94   
95    # Third, is it in the disk cache?  (including ones recently-downloaded)
96    filename = os.path.join(os.path.dirname(__file__), "cache", "%s.png" % name)
97    if os.path.exists(filename):
98      self.images[name]  = cairo.ImageSurface.create_from_png(filename)
99      return
100   
101    # Image not found anywhere - resort to downloading it
102    print "Downloading %s" % (name)
103    if(self.downloadInThread):
104      self.threads[name] = tileLoader(x,y,z,layer,filename)
105      self.threads[name].start()
106    else:
107      downloadTile(x,y,z,layer,filename)
108    self.set("needRedraw", True)
109   
110  def drawImage(self,cr, tile, bbox):
111    """Draw a tile image"""
112    name = self.imageName(tile[0],tile[1],tile[2], tile[3])
113    # If it's not in memory, then stop here
114    if not name in self.images.keys():
115      return
116    # Move the cairo projection onto the area where we want to draw the image
117    cr.save()
118    cr.translate(bbox[0],bbox[1])
119   
120    #cr.scale((bbox[2] - bbox[0]) / 256.0, (bbox[3] - bbox[1]) / 256.0)
121   
122    # Display the image
123    cr.set_source_surface(self.images[name],0,0)
124    cr.paint()
125   
126    # Return the cairo projection to what it was
127    cr.restore()
128   
129  def draw(self, cr):
130    """Draw all the map tiles that are in view"""
131    proj = self.m['projection']
132    layer = self.get("layer","tah")
133   
134    if(not proj.isValid()):
135      return;
136    # Pick a zoom level
137    z = proj.zoom
138   
139    # Loop through all tiles
140    for x in range(int(floor(proj.px1)), int(ceil(proj.px2))):
141      for y in range(int(floor(proj.py1)), int(ceil(proj.py2))):
142       
143       
144        if(1):
145          # Find the edges of the tile as lat/long
146          #S,W,N,E = tileEdges(x,y,z)
147         
148          # Convert those edges to screen coordinates
149          x1,y1 = proj.pxpy2xy(x,y)
150          x2,y2 = proj.pxpy2xy(x+1,y+1)
151         
152          #print "%d,%d,%d -> %1.1f-%1.1f"%(x,y,z,x1,x2)
153         
154          # Check that the image is available in the memory cache
155          # and start downloading it if it's not
156          self.loadImage(x,y,z,layer)
157         
158          # Draw the image
159          self.drawImage(cr,(x,y,z,layer),(x1,y1,x2,y2))
Note: See TracBrowser for help on using the repository browser.