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

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

allow brightness control (not that it should be needed on mobile device, but nice on my laptop)

File size: 5.2 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    self.lat = lat
52    self.lon = lon
53    if(zoom != None):
54      self.implementNewZoom(zoom)
55      # note: implementNewZoom calls findEdges, hence the else: statement
56    else:
57      self.findEdges()
58    self.llValid = True
59   
60  def setZoom(self, value, isAdjustment=False):
61    """Change the zoom level, keeping same map centre
62    if isAdjustment is true, then value is relative to current zoom
63    otherwise it's an absolute value"""
64    if(isAdjustment):
65      # TODO: maybe we don't want all zoom levels?
66      self.implementNewZoom(self.zoom + value)
67    else:
68      self.implementNewZoom(value)
69 
70  def limitZoom(self):
71    """Check the zoom level, and move it if necessary to one of
72    the 'allowed' zoom levels"""
73    if(self.zoom < 6):
74      self.zoom = 6
75    if(self.zoom > 17):
76      self.zoom = 17
77 
78  def implementNewZoom(self, zoom):
79    """Change the zoom level"""
80    self.zoom = int(zoom)
81    # Check it's valid
82    self.limitZoom()
83    # Update the projection
84    self.findEdges()
85 
86  def findEdges(self):
87    """Update the projection meta-info based on its fundamental parameters"""
88    if(not self.xyValid):
89      # If the display is not known yet, then we can't do anything, but we'll
90      # mark it as something that needs doing as soon as the display
91      # becomes valid
92      self.needsEdgeFind = True
93      return
94   
95    # Find the map centre in projection units
96    self.px, self.py = latlon2xy(self.lat,self.lon,self.zoom)
97   
98    # Find the map edges in projection units
99    self.px1 = self.px - 0.5 * self.w / self.scale
100    self.px2 = self.px + 0.5 * self.w / self.scale
101    self.py1 = self.py - 0.5 * self.h / self.scale
102    self.py2 = self.py + 0.5 * self.h / self.scale
103   
104    # Store width and height in projection units, just to save time later
105    self.pdx = self.px2 - self.px1
106    self.pdy = self.py2 - self.py1
107   
108    # Calculate the bounding box
109    # ASSUMPTION: (that the projection is regular and north-up)
110    self.N,self.W = xy2latlon(self.px1, self.py1, self.zoom)
111    self.S,self.E = xy2latlon(self.px2, self.py2, self.zoom)
112   
113    # Mark the meta-info as valid
114    self.needsEdgeFind = False
115 
116  def pxpy2xy(self,px,py):
117    """Convert projection units to display units"""
118    x = self.w * (px - self.px1) / self.pdx
119    y = self.h * (py - self.py1) / self.pdy
120    return(x,y)
121 
122  def nudge(self,dx,dy):
123    """Move the map by a number of pixels relative to its current position"""
124    if(dx == 0 and dy == 0):
125      return
126    # Calculate the lat/long of the pixel offset by dx,dy from the centre,
127    # and centre the map on that
128    newXC = self.px - dx / self.scale
129    newYC = self.py - dy / self.scale
130    self.lat,self.lon = xy2latlon(newXC,newYC, self.zoom)
131    self.findEdges()
132
133  def ll2xy(self,lat,lon):
134    """Convert geographic units to display units"""
135    px,py = latlon2xy(lat,lon,self.zoom)
136    x = (px - self.px1) * self.scale
137    y = (py - self.py1) * self.scale
138    return(x,y)
139 
140  def xy2ll(self,x,y):
141    """Convert display units to geographic units"""
142    px = self.px1 + x / self.scale
143    py = self.py1 + y / self.scale
144    lat,lon = xy2latlon(px, py, self.zoom)
145    return(lat,lon)
146 
147  def onscreen(self,x,y):
148    """Test if a position (in display units) is visible"""
149    return(x >= 0 and x < self.w and y >= 0 and y < self.h)
150 
151  def relXY(self,x,y):
152    return(x/self.w, y/self.h)
Note: See TracBrowser for help on using the repository browser.