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

Last change on this file since 8025 was 5889, checked in by ojw, 12 years ago

Fix "doesn't refresh after download" (I think)

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 = "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.