source: subversion/applications/routing/pyroute/projection.py @ 5864

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

tidy up

File size: 5.3 KB
Line 
1#!/usr/bin/python
2#-----------------------------------------------------------------------------
3# Projection code (lat/long to screen conversions)
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 tilenames import *
24
25class Projection:
26  def __init__(self):
27    self.xyValid = False
28    self.llValid = False
29    self.needsEdgeFind = False
30   
31    # Scale is the number of display pixels per projected unit
32    self.scale = tileSizePixels()
33   
34  def isValid(self):
35    """Test if the module contains all the information needed to do conversions"""
36    return(self.xyValid and self.llValid)
37 
38  def setView(self,x,y,w,h):
39    """Setup the display"""
40    self.w = w
41    self.h = h
42    self.xc = x + self.w
43    self.yc = y + self.h
44    self.xyValid = True
45    if(self.needsEdgeFind):
46      self.findEdges()
47   
48  def recentre(self,lat,lon,zoom = None):
49    """Move the projection to a particular geographic location
50    (with optional zoom level)"""
51    print "centering on %1.3f, %1.3f" % (lat,lon)
52    self.lat = lat
53    self.lon = lon
54    if(zoom != None):
55      self.implementNewZoom(zoom)
56      # note: implementNewZoom calls findEdges, hence the else: statement
57    else:
58      self.findEdges()
59    self.llValid = True
60   
61  def setZoom(self, value, isAdjustment=False):
62    """Change the zoom level, keeping same map centre
63    if isAdjustment is true, then value is relative to current zoom
64    otherwise it's an absolute value"""
65    if(isAdjustment):
66      # TODO: maybe we don't want all zoom levels?
67      self.implementNewZoom(self.zoom + value)
68    else:
69      self.implementNewZoom(value)
70 
71  def limitZoom(self):
72    """Check the zoom level, and move it if necessary to one of
73    the 'allowed' zoom levels"""
74    if(self.zoom < 6):
75      self.zoom = 6
76    if(self.zoom > 17):
77      self.zoom = 17
78 
79  def implementNewZoom(self, zoom):
80    """Change the zoom level"""
81    self.zoom = int(zoom)
82    # Check it's valid
83    self.limitZoom()
84    # Update the projection
85    self.findEdges()
86 
87  def findEdges(self):
88    """Update the projection meta-info based on its fundamental parameters"""
89    if(not self.xyValid):
90      # If the display is not known yet, then we can't do anything, but we'll
91      # mark it as something that needs doing as soon as the display
92      # becomes valid
93      print "Can't find edges"
94      self.needsEdgeFind = True
95      return
96   
97    # Find the map centre in projection units
98    self.px, self.py = latlon2xy(self.lat,self.lon,self.zoom)
99   
100    # Find the map edges in projection units
101    self.px1 = self.px - 0.5 * self.w / self.scale
102    self.px2 = self.px + 0.5 * self.w / self.scale
103    self.py1 = self.py - 0.5 * self.h / self.scale
104    self.py2 = self.py + 0.5 * self.h / self.scale
105   
106    # Store width and height in projection units, just to save time later
107    self.pdx = self.px2 - self.px1
108    self.pdy = self.py2 - self.py1
109   
110    # Calculate the bounding box
111    # ASSUMPTION: (that the projection is regular and north-up)
112    self.N,self.W = xy2latlon(self.px1, self.py1, self.zoom)
113    self.S,self.E = xy2latlon(self.px2, self.py2, self.zoom)
114   
115    # Mark the meta-info as valid
116    self.needsEdgeFind = False
117 
118  def pxpy2xy(self,px,py):
119    """Convert projection units to display units"""
120    x = self.w * (px - self.px1) / self.pdx
121    y = self.h * (py - self.py1) / self.pdy
122    return(x,y)
123 
124  def nudge(self,dx,dy):
125    """Move the map by a number of pixels relative to its current position"""
126    if(dx == 0 and dy == 0):
127      return
128    # Calculate the lat/long of the pixel offset by dx,dy from the centre,
129    # and centre the map on that
130    newXC = self.px - dx / self.scale
131    newYC = self.py - dy / self.scale
132    self.lat,self.lon = xy2latlon(newXC,newYC, self.zoom)
133    self.findEdges()
134
135  def ll2xy(self,lat,lon):
136    """Convert geographic units to display units"""
137    px,py = latlon2xy(lat,lon,self.zoom)
138    x = (px - self.px1) * self.scale
139    y = (py - self.py1) * self.scale
140    return(x,y)
141 
142  def xy2ll(self,x,y):
143    """Convert display units to geographic units"""
144    px = self.px1 + x / self.scale
145    py = self.py1 + y / self.scale
146    lat,lon = xy2latlon(px, py, self.zoom)
147    return(lat,lon)
148 
149  def onscreen(self,x,y):
150    """Test if a position (in display units) is visible"""
151    return(x >= 0 and x < self.w and y >= 0 and y < self.h)
152 
153  def relXY(self,x,y):
154    return(x/self.w, y/self.h)
Note: See TracBrowser for help on using the repository browser.