root/trunk/py/ModestMaps/Geo.py

Revision 481, 4.7 kB (checked in by migurski, 10 months ago)

Added helpful transformation derivations

Line 
1 """
2 >>> t = Transformation(1, 0, 0, 0, 1, 0)
3 >>> p = Point(1, 1)
4 >>> p
5 (1.000, 1.000)
6 >>> p_ = t.transform(p)
7 >>> p_
8 (1.000, 1.000)
9 >>> p__ = t.untransform(p_)
10 >>> p__
11 (1.000, 1.000)
12
13 >>> t = Transformation(0, 1, 0, 1, 0, 0)
14 >>> p = Point(0, 1)
15 >>> p
16 (0.000, 1.000)
17 >>> p_ = t.transform(p)
18 >>> p_
19 (1.000, 0.000)
20 >>> p__ = t.untransform(p_)
21 >>> p__
22 (0.000, 1.000)
23
24 >>> t = Transformation(1, 0, 1, 0, 1, 1)
25 >>> p = Point(0, 0)
26 >>> p
27 (0.000, 0.000)
28 >>> p_ = t.transform(p)
29 >>> p_
30 (1.000, 1.000)
31 >>> p__ = t.untransform(p_)
32 >>> p__
33 (0.000, 0.000)
34
35 >>> m = MercatorProjection(10)
36 >>> m.locationCoordinate(Location(0, 0))
37 (-0.000, 0.000 @10.000)
38 >>> m.coordinateLocation(Coordinate(0, 0, 10))
39 (0.000, 0.000)
40 >>> m.locationCoordinate(Location(37, -122))
41 (0.696, -2.129 @10.000)
42 >>> m.coordinateLocation(Coordinate(0.696, -2.129, 10.000))
43 (37.001, -121.983)
44 """
45
46 import math
47 from Core import Point, Coordinate
48
49 class Location:
50     def __init__(self, lat, lon):
51         self.lat = lat
52         self.lon = lon
53        
54     def __repr__(self):
55         return '(%(lat).3f, %(lon).3f)' % self.__dict__
56
57 class Transformation:
58     def __init__(self, ax, bx, cx, ay, by, cy):
59         self.ax = ax
60         self.bx = bx
61         self.cx = cx
62         self.ay = ay
63         self.by = by
64         self.cy = cy
65    
66     def transform(self, point):
67         return Point(self.ax*point.x + self.bx*point.y + self.cx,
68                      self.ay*point.x + self.by*point.y + self.cy)
69                          
70     def untransform(self, point):
71         return Point((point.x*self.by - point.y*self.bx - self.cx*self.by + self.cy*self.bx) / (self.ax*self.by - self.ay*self.bx),
72                      (point.x*self.ay - point.y*self.ax - self.cx*self.ay + self.cy*self.ax) / (self.bx*self.ay - self.by*self.ax))
73
74 def deriveTransformation(a1x, a1y, a2x, a2y, b1x, b1y, b2x, b2y, c1x, c1y, c2x, c2y):
75     """ Generates a transform based on three pairs of points, a1 -> a2, b1 -> b2, c1 -> c2.
76     """
77     ax, bx, cx = linearSolution(a1x, a1y, a2x, b1x, b1y, b2x, c1x, c1y, c2x)
78     ay, by, cy = linearSolution(a1x, a1y, a2y, b1x, b1y, b2y, c1x, c1y, c2y)
79    
80     return Transformation(ax, bx, cx, ay, by, cy)
81
82 def linearSolution(r1, s1, t1, r2, s2, t2, r3, s3, t3):
83     """ Solves a system of linear equations.
84
85           t1 = (a * r1) + (b + s1) + c
86           t2 = (a * r2) + (b + s2) + c
87           t3 = (a * r3) + (b + s3) + c
88
89         r1 - t3 are the known values.
90         a, b, c are the unknowns to be solved.
91         returns the a, b, c coefficients.
92     """
93
94     # make them all floats
95     r1, s1, t1, r2, s2, t2, r3, s3, t3 = map(float, (r1, s1, t1, r2, s2, t2, r3, s3, t3))
96
97     a = (((t2 - t3) * (s1 - s2)) - ((t1 - t2) * (s2 - s3))) \
98       / (((r2 - r3) * (s1 - s2)) - ((r1 - r2) * (s2 - s3)))
99
100     b = (((t2 - t3) * (r1 - r2)) - ((t1 - t2) * (r2 - r3))) \
101       / (((s2 - s3) * (r1 - r2)) - ((s1 - s2) * (r2 - r3)))
102
103     c = t1 - (r1 * a) - (s1 * b)
104    
105     return a, b, c
106
107 class IProjection:
108     def __init__(self, zoom, transformation=Transformation(1, 0, 0, 0, 1, 0)):
109         self.zoom = zoom
110         self.transformation = transformation
111        
112     def rawProject(self, point):
113         raise NotImplementedError("Abstract method not implemented by subclass.")
114        
115     def rawUnproject(self, point):
116         raise NotImplementedError("Abstract method not implemented by subclass.")
117
118     def project(self, point):
119         point = self.rawProject(point)
120         if(self.transformation):
121             point = self.transformation.transform(point)
122         return point
123    
124     def unproject(self, point):
125         if(self.transformation):
126             point = self.transformation.untransform(point)
127         point = self.rawUnproject(point)
128         return point
129        
130     def locationCoordinate(self, location):
131         point = Point(math.pi * location.lon / 180.0, math.pi * location.lat / 180.0)
132         point = self.project(point)
133         return Coordinate(point.y, point.x, self.zoom)
134
135     def coordinateLocation(self, coordinate):
136         coordinate = coordinate.zoomTo(self.zoom)
137         point = Point(coordinate.column, coordinate.row)
138         point = self.unproject(point)
139         return Location(180.0 * point.y / math.pi, 180.0 * point.x / math.pi)
140
141 class LinearProjection(IProjection):
142     def rawProject(self, point):
143         return Point(point.x, point.y)
144
145     def rawUnproject(self, point):
146         return Point(point.x, point.y)
147
148 class MercatorProjection(IProjection):
149     def rawProject(self, point):
150         return Point(point.x,
151                      math.log(math.tan(0.25 * math.pi + 0.5 * point.y)))
152
153     def rawUnproject(self, point):
154         return Point(point.x,
155                      2 * math.atan(math.pow(math.e, point.y)) - 0.5 * math.pi)
156
157 if __name__ == '__main__':
158     import doctest
159     doctest.testmod()
Note: See TracBrowser for help on using the browser.