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

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

convert to an "integer zoom level" (so zooming isn't continuous, but must double or halve the detail in each step) -- this is to make the map images the same size as their original, so that cairo doesn't have to do any scaling

File size: 4.9 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   
109  def drawImage(self,cr, tile, bbox):
110    """Draw a tile image"""
111    name = self.imageName(tile[0],tile[1],tile[2], tile[3])
112    # If it's not in memory, then stop here
113    if not name in self.images.keys():
114      return
115    # Move the cairo projection onto the area where we want to draw the image
116    cr.save()
117    cr.translate(bbox[0],bbox[1])
118   
119    #cr.scale((bbox[2] - bbox[0]) / 256.0, (bbox[3] - bbox[1]) / 256.0)
120   
121    # Display the image
122    cr.set_source_surface(self.images[name],0,0)
123    cr.paint()
124   
125    # Return the cairo projection to what it was
126    cr.restore()
127   
128  def draw(self, cr):
129    """Draw all the map tiles that are in view"""
130    proj = self.m['projection']
131    layer = self.get("layer","tah")
132   
133    if(not proj.isValid()):
134      return;
135    # Pick a zoom level
136    z = proj.zoom
137   
138    # Loop through all tiles
139    for x in range(int(floor(proj.px1)), int(ceil(proj.px2))):
140      for y in range(int(floor(proj.py1)), int(ceil(proj.py2))):
141       
142       
143        if(1):
144          # Find the edges of the tile as lat/long
145          #S,W,N,E = tileEdges(x,y,z)
146         
147          # Convert those edges to screen coordinates
148          x1,y1 = proj.pxpy2xy(x,y)
149          x2,y2 = proj.pxpy2xy(x+1,y+1)
150         
151          #print "%d,%d,%d -> %1.1f-%1.1f"%(x,y,z,x1,x2)
152         
153          # Check that the image is available in the memory cache
154          # and start downloading it if it's not
155          self.loadImage(x,y,z,layer)
156         
157          # Draw the image
158          self.drawImage(cr,(x,y,z,layer),(x1,y1,x2,y2))
Note: See TracBrowser for help on using the repository browser.