| 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() |
|---|